{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "Import tkinter and ollama to create the app" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [], "source": [ "import ollama\n", "import tkinter as tk\n", "from tkinter import ttk" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Basic configuration parameters for the Ollama API:" ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [], "source": [ "OLLAMA_API = \"http://localhost:11434/api/chat\"\n", "HEADERS = {\"Content-Type\":\"application/json\"}\n", "MODEL = \"llama3.2\"\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Initialize conversation history." ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [], "source": [ "conversation_history = []" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Defining the key presses. If user presses shit + enter then simply go to the next line. \n", "\n", "If user presses only enter then submit the question." ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [], "source": [ "def handle_keypress(event):\n", " if event.state & 0x1: # Check if Shift is pressed\n", " return\n", " else:\n", " display_answer()\n", " return 'break'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Defining the function that will display answers using Ollama.\n", "\n", "\n", "To turn it into a chatbot we simply append user's question and Ollama's response to our conversation history and pass that into Ollama as our next question." ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [], "source": [ "def display_answer(event=None):\n", " question_text['state'] = 'disabled'\n", " question_text['bg'] = '#F0F0F0'\n", " status_label.config(text=\"Looking for an answer...\")\n", " root.update()\n", "\n", " # Get question text and prepare message\n", " question = question_text.get(\"1.0\", tk.END).strip()\n", " if question:\n", " # Append the user's question to the conversation history\n", " conversation_history.append({\"role\": \"user\", \"content\": question})\n", "\n", " # Pass the entire conversation history to Ollama\n", " try:\n", " # Get the answer\n", " response = ollama.chat(model=MODEL, messages=conversation_history)\n", " answer = response[\"message\"][\"content\"]\n", "\n", " # Append the assistant's answer to the conversation history\n", " conversation_history.append({\"role\": \"assistant\", \"content\": answer})\n", "\n", " # Update the text widget with the answer\n", " answer_text.configure(state='normal')\n", " answer_text.delete(1.0, tk.END)\n", " answer_text.insert(tk.END, answer)\n", " answer_text.configure(state='disabled')\n", "\n", " status_label.config(text=\"Answered\")\n", " except Exception as e:\n", " answer_text.configure(state='normal')\n", " answer_text.delete(1.0, tk.END)\n", " answer_text.insert(tk.END, f\"Error: {str(e)}\")\n", " answer_text.configure(state='disabled')\n", " status_label.config(text=\"Error\")\n", " else:\n", " # If empty question string was received\n", " answer_text.configure(state='normal')\n", " answer_text.delete(1.0, tk.END)\n", " answer_text.insert(tk.END, \"Please enter a question.\")\n", " answer_text.configure(state='disabled')\n", " status_label.config(text=\"\")\n", "\n", " # Re-enable question input and restore normal background\n", " question_text['state'] = 'normal'\n", " question_text['bg'] = 'white'\n", " root.update()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A button to remove the conversation history and start all over again." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def remove_all():\n", " \"\"\"Clears the conversation history and resets the interface.\"\"\"\n", " global conversation_history\n", " conversation_history = [] # Clear conversation history\n", "\n", " # Reset text widgets\n", " question_text.delete(1.0, tk.END)\n", " answer_text.configure(state='normal')\n", " answer_text.delete(1.0, tk.END)\n", " answer_text.insert(tk.END, \"Your answer will appear here.\")\n", " answer_text.configure(state='disabled')\n", "\n", " # Reset status label\n", " status_label.config(text=\"\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Creating the app window using tkinter." ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [], "source": [ "# Create the main window\n", "root = tk.Tk()\n", "root.title(\"Ollama with GUI\")\n", "root.geometry(\"500x800\")\n", "\n", "# Create and configure the Questions window\n", "question_frame = ttk.LabelFrame(root, text=\"Questions\", padding=(10, 10))\n", "question_frame.pack(fill=\"both\", expand=True, padx=10, pady=10)\n", "\n", "question_label = ttk.Label(question_frame, text=\"Enter your question:\")\n", "question_label.pack(anchor=\"w\", pady=5)\n", "\n", "# Replace Entry with Text widget for questions\n", "question_text = tk.Text(question_frame, wrap=tk.WORD, width=50, height=4)\n", "question_text.pack(anchor=\"w\", pady=5)\n", "question_text.bind(\"\", handle_keypress)\n", "\n", "# Add status label\n", "status_label = ttk.Label(question_frame, text=\"\")\n", "status_label.pack(anchor=\"w\", pady=5)\n", "\n", "# Add Remove All button\n", "remove_all_button = ttk.Button(question_frame, text=\"Remove All\", command=remove_all)\n", "remove_all_button.pack(anchor=\"e\", pady=5)\n", "\n", "# Create and configure the Answers window\n", "answer_frame = ttk.LabelFrame(root, text=\"Answer\", padding=(10, 10))\n", "answer_frame.pack(fill=\"both\", expand=True, padx=10, pady=10)\n", "\n", "# Create a frame to hold the text widget and scrollbar\n", "text_frame = ttk.Frame(answer_frame)\n", "text_frame.pack(fill=\"both\", expand=True)\n", "\n", "# Create the text widget and scrollbar\n", "answer_text = tk.Text(text_frame, wrap=tk.WORD, width=70, height=100)\n", "scrollbar = ttk.Scrollbar(text_frame, orient=\"vertical\", command=answer_text.yview)\n", "answer_text.configure(yscrollcommand=scrollbar.set)\n", "\n", "# Pack the text widget and scrollbar\n", "answer_text.pack(side=\"left\", fill=\"both\", expand=True)\n", "scrollbar.pack(side=\"right\", fill=\"y\")\n", "\n", "# Set initial text and disable editing\n", "answer_text.insert(tk.END, \"Your answer will appear here.\")\n", "answer_text.configure(state='disabled')\n", "\n", "# Run the main event loop\n", "root.mainloop()\n" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.11.11" } }, "nbformat": 4, "nbformat_minor": 4 }