From a3f1d96e55969b8a5604ac7844aa467a141114a7 Mon Sep 17 00:00:00 2001 From: Emil Kosz Date: Sat, 21 Mar 2026 08:33:12 +0100 Subject: [PATCH] Some async stuff --- main.py | 64 +++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 39 insertions(+), 25 deletions(-) diff --git a/main.py b/main.py index 6c3efe9..8a3df53 100644 --- a/main.py +++ b/main.py @@ -1,9 +1,7 @@ -import gi +import gi, ollama, asyncio gi.require_version("Gtk", "4.0") from gi.repository import GLib, Gtk -import ollama - def set_margin_all(widget, m): widget.set_margin_start(m) widget.set_margin_top(m) @@ -24,7 +22,7 @@ class PyLlamaWindow(Gtk.ApplicationWindow): header = Gtk.HeaderBar() header.set_show_title_buttons(True) - header.set_title_widget(self.model_dropdown) + header.pack_start(self.model_dropdown) self.set_titlebar(header) @@ -33,21 +31,24 @@ class PyLlamaWindow(Gtk.ApplicationWindow): self.listbox = Gtk.ListBox.new() self.listbox.set_selection_mode(Gtk.SelectionMode.NONE) - + self.listbox.set_focusable(True) + scrolled = Gtk.ScrolledWindow() scrolled.set_vexpand(True) scrolled.set_child(self.listbox) vbox.append(scrolled) - - entry = Gtk.Entry() - entry_buffer = entry.get_buffer() - entry.set_placeholder_text("Type message and press Enter...") - entry.set_hexpand(True) - entry.set_icon_from_icon_name(Gtk.EntryIconPosition.SECONDARY, "go-next-symbolic") - entry.connect("activate", self.send_message) - entry.connect("icon_press", self.send_message) - vbox.append(entry) + # self.prompt = Gtk.TextView() + # self.prompt.set_hexpand(True) + + self.entry = Gtk.Entry() + self.entry.set_placeholder_text("Type message and press Enter...") + self.entry.set_hexpand(True) + self.entry.set_icon_from_icon_name(Gtk.EntryIconPosition.SECONDARY, "go-next-symbolic") + self.entry.connect("activate", self.send_message) + self.entry.connect("icon_press", self.send_message) + + vbox.append(self.entry) self.set_child(vbox) self.current_model = None @@ -95,26 +96,39 @@ class PyLlamaWindow(Gtk.ApplicationWindow): buffer.delete_text(0, -1) # Delete all text self.add_message(text=text) self.cur_ai_response = self.add_message(text=None, sender=False) - self.get_application().send_prompt(self.model_dropdown.get_selected_item().get_string(), text) + + self.listbox.grab_focus() + self.entry.set_sensitive(False) + + app = self.get_application() + model = self.model_dropdown.get_selected_item().get_string() + app.loop.call_soon_threadsafe(lambda: asyncio.create_task( + app.send_prompt(model, text) + )) class PyLlama(Gtk.Application): def __init__(self): super().__init__(application_id="eur.cfpi-fpsi.pyllama") GLib.set_application_name("PyLlama") - + + self.client = ollama.AsyncClient() + self.loop = asyncio.new_event_loop() + GLib.timeout_add(100, self.run_asyncio_loop) + def do_activate(self): - self.client = ollama.Client() self.window = PyLlamaWindow(application=self, title="PyLlama") self.window.present() - def send_prompt(self, model, text): - messages = [{ - "role": "user", - "content": text - }] - - for part in self.client.chat(model, messages=messages, stream=True): - self.window.add_response_part(part.message.content) + def run_asyncio_loop(self): + self.loop.stop() + self.loop.run_forever() + return True + + async def send_prompt(self, model, text): + messages = [{ "role": "user", "content": text, "options": { "num_gpu": 100, "main_gpu": 0 } }] + async for part in await self.client.chat(model=model, messages=messages, stream=True): + GLib.idle_add(self.window.add_response_part, part.message.content) + GLib.idle_add(self.window.entry.set_sensitive, True) if __name__ == "__main__": app = PyLlama()