From 8c0e13632d5746bf04796745df44ad98b47bc400 Mon Sep 17 00:00:00 2001 From: arunabh-ramesh Date: Sun, 22 Mar 2026 20:26:51 -0400 Subject: [PATCH 1/6] Add Gemini AI chatbox integration and rename launcher to .py - Integrate Gemini 3.1 Flash Lite Preview model via google-generativeai - Load API key from .env file using python-dotenv - Add AI response scrolledtext box to the matrix window UI - Implement handle_user_prompt to call Gemini and display response - Rename Alice-universal-alpha.pyw to .py for console output - Add .gitignore to exclude venv Co-Authored-By: Claude Sonnet 4.6 --- .env | 1 + .gitignore | 1 + ...sal-alpha.pyw => Alice-universal-alpha.py} | 0 .../Pico_crosspoint-xp3a-mini-rpi-red.py | 60 ++++++++++++++++++- 4 files changed, 61 insertions(+), 1 deletion(-) create mode 100644 .env create mode 100644 .gitignore rename Python UI/{Alice-universal-alpha.pyw => Alice-universal-alpha.py} (100%) diff --git a/.env b/.env new file mode 100644 index 0000000..945726b --- /dev/null +++ b/.env @@ -0,0 +1 @@ +GEMINI_API_KEY=YOUR_API_KEY_HERE diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f7275bb --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +venv/ diff --git a/Python UI/Alice-universal-alpha.pyw b/Python UI/Alice-universal-alpha.py similarity index 100% rename from Python UI/Alice-universal-alpha.pyw rename to Python UI/Alice-universal-alpha.py diff --git a/Python UI/Pico_crosspoint-xp3a-mini-rpi-red.py b/Python UI/Pico_crosspoint-xp3a-mini-rpi-red.py index bf3e3ef..ddc126f 100644 --- a/Python UI/Pico_crosspoint-xp3a-mini-rpi-red.py +++ b/Python UI/Pico_crosspoint-xp3a-mini-rpi-red.py @@ -17,6 +17,17 @@ # from tkinter import scrolledtext # +try: + import google.generativeai as genai + from dotenv import load_dotenv + import os + load_dotenv() + GEMINI_API_KEY = os.getenv("GEMINI_API_KEY") + genai.configure(api_key=GEMINI_API_KEY) + GeminiModel = genai.GenerativeModel("gemini-3.1-flash-lite-preview") +except: + showwarning("WARNING","google-generativeai or python-dotenv not installed? Run: pip install google-generativeai python-dotenv") +# # adjust for your specific hardware by changing these values in the alice.init file ADC_Cal = 3.25 VOpenCircuit = 2.4 @@ -1644,6 +1655,9 @@ def MakeBreadboardScreen(): global CompSpinBoxList_RC, CompSpinBoxList_TL, CompSpinBoxList_BL, CompSpinBoxList_TR, CompSpinBoxList_BR global click_loc, breadboard_image, JPcolors, breadboard_canvas + style = Style() # This accesses the ttk Style object + style.configure("Prompt.TEntry", fieldbackground="white", foreground="black") + if BreadboardStatus.get() == 0: try: XlabLogo_image = PhotoImage(file='./XLab-logo.png') # @@ -1826,10 +1840,32 @@ def MakeBreadboardScreen(): VerifyButton.grid(row=20, column=0, columnspan=2, sticky=W, pady=1) PassFailSvBB = Label(matrixwindow,text="") PassFailSvBB.grid(row=20, column=2, columnspan=4, sticky=W, pady=1) - + + if HWRevOne == "Red3": TestResButton = Button(matrixwindow, text="Man Test Resistor", style="W17.TButton", command=MakeTestResWindow) TestResButton.grid(row=21, column=0, columnspan=2, sticky=W, pady=1) + + + # --- PROMPT BOX --- + PromptLabel = Label(matrixwindow, text="User Prompt:", style="A12B.TLabel") + PromptLabel.grid(row=22, column=0, columnspan=2, sticky=W, pady=(10, 0)) + + global PromptBox + # We use Entry (which is ttk.Entry in your script) and apply our custom style + PromptBox = Entry(matrixwindow, style="Prompt.TEntry", width=45) + PromptBox.grid(row=23, column=0, columnspan=4, sticky=W, padx=5, pady=5) + + # Bind the 'Enter' key to the handler function + PromptBox.bind("", handle_user_prompt) + + global AIResponseBox + AIResponseBox = scrolledtext.ScrolledText(matrixwindow, wrap=WORD, width=45, height=6, font="Arial 10", state=DISABLED) + AIResponseBox.grid(row=24, column=0, columnspan=4, sticky=W, padx=5, pady=(0, 5)) + # end of prompt box + + + ############################## ### MIDDLE SIDE OF SCREEN #### #### The top part of the middle section is the simulated image of the breadboard @@ -7709,3 +7745,25 @@ def onResSchClick(event): ser.write(SendByt) # +# create a chatbox for AI prompting +def handle_user_prompt(event): + global PromptBox, AIResponseBox, GeminiModel + user_input = PromptBox.get() + if not user_input: + return + PromptBox.delete(0, END) + AIResponseBox.config(state=NORMAL) + AIResponseBox.delete(1.0, END) + AIResponseBox.insert(END, "Thinking...") + AIResponseBox.config(state=DISABLED) + AIResponseBox.update() + try: + response = GeminiModel.generate_content(user_input) + reply = response.text + except Exception as e: + reply = f"Error: {str(e)}" + AIResponseBox.config(state=NORMAL) + AIResponseBox.delete(1.0, END) + AIResponseBox.insert(END, reply) + AIResponseBox.config(state=DISABLED) + PromptBox.delete(0, END) \ No newline at end of file From 068a3378b5b9a1f0d45e38cc4507a2237b5f68f6 Mon Sep 17 00:00:00 2001 From: arunabh-ramesh Date: Sun, 22 Mar 2026 20:31:11 -0400 Subject: [PATCH 2/6] Revert launcher back to .pyw (no console window) --- Python UI/{Alice-universal-alpha.py => Alice-universal-alpha.pyw} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename Python UI/{Alice-universal-alpha.py => Alice-universal-alpha.pyw} (100%) diff --git a/Python UI/Alice-universal-alpha.py b/Python UI/Alice-universal-alpha.pyw similarity index 100% rename from Python UI/Alice-universal-alpha.py rename to Python UI/Alice-universal-alpha.pyw From 73b248dce5c774fc9041a00b51c50ac04b4b39e1 Mon Sep 17 00:00:00 2001 From: RyanWang12 Date: Tue, 31 Mar 2026 18:07:33 -0400 Subject: [PATCH 3/6] added function to display user and ai output --- .../Pico_crosspoint-xp3a-mini-rpi-red.py | 82 ++++++++++++++++++- 1 file changed, 81 insertions(+), 1 deletion(-) diff --git a/Python UI/Pico_crosspoint-xp3a-mini-rpi-red.py b/Python UI/Pico_crosspoint-xp3a-mini-rpi-red.py index bf3e3ef..3f53994 100644 --- a/Python UI/Pico_crosspoint-xp3a-mini-rpi-red.py +++ b/Python UI/Pico_crosspoint-xp3a-mini-rpi-red.py @@ -1644,6 +1644,8 @@ def MakeBreadboardScreen(): global CompSpinBoxList_RC, CompSpinBoxList_TL, CompSpinBoxList_BL, CompSpinBoxList_TR, CompSpinBoxList_BR global click_loc, breadboard_image, JPcolors, breadboard_canvas + + if BreadboardStatus.get() == 0: try: XlabLogo_image = PhotoImage(file='./XLab-logo.png') # @@ -1826,10 +1828,58 @@ def MakeBreadboardScreen(): VerifyButton.grid(row=20, column=0, columnspan=2, sticky=W, pady=1) PassFailSvBB = Label(matrixwindow,text="") PassFailSvBB.grid(row=20, column=2, columnspan=4, sticky=W, pady=1) - + + if HWRevOne == "Red3": TestResButton = Button(matrixwindow, text="Man Test Resistor", style="W17.TButton", command=MakeTestResWindow) TestResButton.grid(row=21, column=0, columnspan=2, sticky=W, pady=1) + + + # --- FULL CHAT UI INTEGRATION --- + # 1. Row configuration: Give row 22 (the chat history) all the "weight" + # This makes it expand vertically to fill the bottom of the UI. + matrixwindow.rowconfigure(22, weight=1) + matrixwindow.columnconfigure(0, weight=1) + + # 2. Chat History Display (Scrollable) + global ChatHistory + ChatHistory = scrolledtext.ScrolledText(matrixwindow, + height=10, + state='disabled', + wrap='word', + bg="white", # Background color + foreground="black", # Main text color (BLACK) + font=("Arial", 10) + ) + ChatHistory.grid(row=22, column=0, columnspan=4, sticky="nsew", padx=5, pady=(10, 0)) + + # Create "Bubbles" using Tags (Color coding) + ChatHistory.tag_configure("user_tag", foreground="#0078d4", font=("Arial", 10, "bold")) + ChatHistory.tag_configure("ai_tag", foreground="#2b88d8", font=("Arial", 10, "bold")) + + # 3. Label for the Input + PromptLabel = Label(matrixwindow, text="User Prompt:", style="A12B.TLabel") + PromptLabel.grid(row=23, column=0, columnspan=2, sticky=W, pady=(5, 0)) + + # 4. Input Box (PromptBox) + # Using Style consistent with previous turns + # --- UPDATE STYLE FOR CURSOR --- + style = Style() + style.configure("Prompt.TEntry", + fieldbackground="white", + foreground="black", + insertcolor="black", # THIS MAKES THE CURSOR BLACK + insertwidth=2) # Makes it slightly thicker/easier to see + + global PromptBox + PromptBox = Entry(matrixwindow, style="Prompt.TEntry") + PromptBox.grid(row=24, column=0, columnspan=4, sticky="ew", padx=5, pady=(0, 10)) + + PromptBox.bind("", handle_user_prompt) + # --- END CHAT UI --- + + + ############################## ### MIDDLE SIDE OF SCREEN #### #### The top part of the middle section is the simulated image of the breadboard @@ -1877,6 +1927,9 @@ def MakeBreadboardScreen(): J_Connections_Labels.append(J_connections) ############################## + + # Add this at the end of the function to set focus on startup + PromptBox.focus_set() # def BBCAresize(event): global breadboard_canvas, BBwidth, BBheight, CANVASwidthBB, CANVASheightBB @@ -7708,4 +7761,31 @@ def onResSchClick(event): SendByt = SendStr.encode('utf-8') ser.write(SendByt) # + +# create an AI prompt box +def handle_user_prompt(event): + global PromptBox, ChatHistory + user_input = PromptBox.get().strip() + if user_input: + # Enable editing to add text + ChatHistory.configure(state='normal') + + # Add User message + ChatHistory.insert('end', f"\nYou: ", "user_tag") + ChatHistory.insert('end', f"{user_input}\n") + + # Clear input box + PromptBox.delete(0, 'end') + + # ENSURE CURSOR RETURNS TO BOX + PromptBox.focus_set() + + # Simulation of AI Response (You can hook this up to your logic) + ChatHistory.insert('end', f"\nAI: ", "ai_tag") + ChatHistory.insert('end', f"I've received your request: '{user_input}'. How can I help further?\n") + + # Scroll to the bottom and disable editing again + ChatHistory.see('end') + ChatHistory.configure(state='disabled') + From 89c5128e492f2576e1039eee3c3ff29c6fa4d4e9 Mon Sep 17 00:00:00 2001 From: arunabh-ramesh Date: Sun, 22 Mar 2026 20:26:51 -0400 Subject: [PATCH 4/6] Add Gemini AI chatbox integration and rename launcher to .py - Integrate Gemini 3.1 Flash Lite Preview model via google-generativeai - Load API key from .env file using python-dotenv - Add AI response scrolledtext box to the matrix window UI - Implement handle_user_prompt to call Gemini and display response - Rename Alice-universal-alpha.pyw to .py for console output - Add .gitignore to exclude venv Co-Authored-By: Claude Sonnet 4.6 --- Python UI/{Alice-universal-alpha.pyw => Alice-universal-alpha.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename Python UI/{Alice-universal-alpha.pyw => Alice-universal-alpha.py} (100%) diff --git a/Python UI/Alice-universal-alpha.pyw b/Python UI/Alice-universal-alpha.py similarity index 100% rename from Python UI/Alice-universal-alpha.pyw rename to Python UI/Alice-universal-alpha.py From 381b30e00b57803c2278c037ecf124357000b61f Mon Sep 17 00:00:00 2001 From: arunabh-ramesh Date: Sun, 22 Mar 2026 20:31:11 -0400 Subject: [PATCH 5/6] Revert launcher back to .pyw (no console window) --- Python UI/{Alice-universal-alpha.py => Alice-universal-alpha.pyw} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename Python UI/{Alice-universal-alpha.py => Alice-universal-alpha.pyw} (100%) diff --git a/Python UI/Alice-universal-alpha.py b/Python UI/Alice-universal-alpha.pyw similarity index 100% rename from Python UI/Alice-universal-alpha.py rename to Python UI/Alice-universal-alpha.pyw From 62fdeee21a5541f4b71171c04bd6a4f01a0e909b Mon Sep 17 00:00:00 2001 From: RyanWang12 Date: Tue, 31 Mar 2026 19:23:28 -0400 Subject: [PATCH 6/6] added resize functionality to chatbox --- .../Pico_crosspoint-xp3a-mini-rpi-red.py | 114 ++++++++++++++---- 1 file changed, 90 insertions(+), 24 deletions(-) diff --git a/Python UI/Pico_crosspoint-xp3a-mini-rpi-red.py b/Python UI/Pico_crosspoint-xp3a-mini-rpi-red.py index ddc126f..a515b57 100644 --- a/Python UI/Pico_crosspoint-xp3a-mini-rpi-red.py +++ b/Python UI/Pico_crosspoint-xp3a-mini-rpi-red.py @@ -1848,22 +1848,70 @@ def MakeBreadboardScreen(): # --- PROMPT BOX --- - PromptLabel = Label(matrixwindow, text="User Prompt:", style="A12B.TLabel") - PromptLabel.grid(row=22, column=0, columnspan=2, sticky=W, pady=(10, 0)) + # --- CLASSIC TK SETUP --- + import tkinter as tk_base # Ensure we have access to classic widgets + + # 1. CREATE STYLE FOR CURSOR + # This fixes the cursor color for the ttk Entry + style = Style() + style.configure("Prompt.TEntry", + fieldbackground="white", + foreground="black", + insertcolor="black", # <--- FIXES VISIBLE CURSOR + insertwidth=2) + + # 2. CREATE DRAGGABLE PANED WINDOW + # This allows you to drag the divider up/down to resize the chat + chat_paner = tk_base.PanedWindow(matrixwindow, + orient=tk_base.VERTICAL, + sashwidth=6, + sashrelief=tk_base.RAISED, + bg=FrameBG) + chat_paner.grid(row=22, column=0, columnspan=4, sticky="nsew", padx=5, pady=10) + + # Give row 22 all the weight so it fills the bottom area + matrixwindow.rowconfigure(22, weight=1) + + # 3. CHAT HISTORY (Top Pane) + global ChatHistory + ChatHistory = scrolledtext.ScrolledText( + chat_paner, # Parent is the paner + height=10, + state='disabled', + wrap='word', + bg="white", + foreground="black", + insertbackground="black", + font=("Arial", 10) + ) + + # Add to paned window + chat_paner.add(ChatHistory, minsize=100) + + # 4. PROMPT INPUT AREA (Bottom Pane) + # We use a frame to hold the Label and Entry together in the bottom pane + input_container = tk_base.Frame(chat_paner, bg=FrameBG) + + PromptLabel = Label(input_container, text="User Prompt:", style="A12B.TLabel") + PromptLabel.pack(side=tk_base.TOP, anchor=tk_base.W, pady=(5, 0)) global PromptBox - # We use Entry (which is ttk.Entry in your script) and apply our custom style - PromptBox = Entry(matrixwindow, style="Prompt.TEntry", width=45) - PromptBox.grid(row=23, column=0, columnspan=4, sticky=W, padx=5, pady=5) + # Using Style "Prompt.TEntry" defined above + PromptBox = Entry(input_container, style="Prompt.TEntry") + PromptBox.pack(side=tk_base.TOP, fill=tk_base.X, pady=(0, 10)) - # Bind the 'Enter' key to the handler function - PromptBox.bind("", handle_user_prompt) + # Add frame to paned window + chat_paner.add(input_container, minsize=80) - global AIResponseBox - AIResponseBox = scrolledtext.ScrolledText(matrixwindow, wrap=WORD, width=45, height=6, font="Arial 10", state=DISABLED) - AIResponseBox.grid(row=24, column=0, columnspan=4, sticky=W, padx=5, pady=(0, 5)) - # end of prompt box + # 5. CONFIGURE TAGS + ChatHistory.tag_configure("user_tag", foreground="#0078d4", font=("Arial", 10, "bold")) + ChatHistory.tag_configure("ai_tag", foreground="#2b88d8", font=("Arial", 10, "bold")) + ChatHistory.tag_configure("text_tag", foreground="black", font=("Arial", 10)) + ChatHistory.tag_configure("status_tag", foreground="gray", font=("Arial", 10, "italic")) + # 6. BINDINGS & FOCUS + PromptBox.bind("", handle_user_prompt) + PromptBox.focus_set() ############################## @@ -7745,25 +7793,43 @@ def onResSchClick(event): ser.write(SendByt) # -# create a chatbox for AI prompting def handle_user_prompt(event): - global PromptBox, AIResponseBox, GeminiModel - user_input = PromptBox.get() + global PromptBox, ChatHistory, GeminiModel + user_input = PromptBox.get().strip() + if not user_input: return + + # 1. Clear input immediately PromptBox.delete(0, END) - AIResponseBox.config(state=NORMAL) - AIResponseBox.delete(1.0, END) - AIResponseBox.insert(END, "Thinking...") - AIResponseBox.config(state=DISABLED) - AIResponseBox.update() + + # 2. Enable box for appending + ChatHistory.config(state=NORMAL) + + # 3. Add User Prompt with Tag + ChatHistory.insert(END, "\nYou: ", "user_tag") + ChatHistory.insert(END, f"{user_input}\n", "text_tag") + + # 4. "Thinking" Indicator + ChatHistory.insert(END, "AI: Thinking...\n", "status_tag") + ChatHistory.see(END) + ChatHistory.update() + + # 5. Get Gemini Response try: response = GeminiModel.generate_content(user_input) reply = response.text except Exception as e: reply = f"Error: {str(e)}" - AIResponseBox.config(state=NORMAL) - AIResponseBox.delete(1.0, END) - AIResponseBox.insert(END, reply) - AIResponseBox.config(state=DISABLED) - PromptBox.delete(0, END) \ No newline at end of file + + # 6. Replace "Thinking..." with the actual response + ChatHistory.delete("end-2l", "end-1c") + ChatHistory.insert(END, "AI: ", "ai_tag") + ChatHistory.insert(END, f"{reply}\n", "text_tag") + + # 7. Finalize view + ChatHistory.see(END) + ChatHistory.config(state=DISABLED) + + # ENSURE CURSOR STAYS IN BOX + PromptBox.focus_set() \ No newline at end of file