diff --git a/src/alpaca.gresource.xml b/src/alpaca.gresource.xml index 788a94d..4a6b21e 100644 --- a/src/alpaca.gresource.xml +++ b/src/alpaca.gresource.xml @@ -28,6 +28,7 @@ icons/edit-find-symbolic.svg icons/edit-symbolic.svg icons/image-missing-symbolic.svg + icons/update-symbolic.svg window.ui gtk/help-overlay.ui diff --git a/src/icons/update-symbolic.svg b/src/icons/update-symbolic.svg new file mode 100644 index 0000000..8366791 --- /dev/null +++ b/src/icons/update-symbolic.svg @@ -0,0 +1,2 @@ + + diff --git a/src/window.py b/src/window.py index 8cf7691..8577356 100644 --- a/src/window.py +++ b/src/window.py @@ -68,6 +68,7 @@ class AlpacaWindow(Adw.ApplicationWindow): override_HIP_VISIBLE_DEVICES = Gtk.Template.Child() #Elements + regenerate_button : Gtk.Button = None create_model_base = Gtk.Template.Child() create_model_name = Gtk.Template.Child() create_model_system = Gtk.Template.Child() @@ -613,6 +614,11 @@ Generate a title following these rules: css_classes = ["flat", "circular"], tooltip_text = _("Edit Message") ) + regenerate_button = Gtk.Button( + icon_name = "update-symbolic", + css_classes = ["flat", "circular"], + tooltip_text = _("Regenerate Message") + ) button_container = Gtk.Box( orientation=0, @@ -728,9 +734,10 @@ Generate a title following these rules: delete_button.connect("clicked", lambda button, element=overlay: self.delete_message(element)) copy_button.connect("clicked", lambda button, element=overlay: self.copy_message(element)) edit_button.connect("clicked", lambda button, element=overlay, textview=message_text, button_container=button_container: self.edit_message(element, textview, button_container)) + regenerate_button.connect('clicked', lambda button, id=id, bot_message_box=message_box, bot_message_button_container=button_container : self.regenerate_message(id, bot_message_box, bot_message_button_container)) button_container.append(delete_button) button_container.append(copy_button) - if not bot: button_container.append(edit_button) + button_container.append(regenerate_button if bot else edit_button) overlay.add_overlay(button_container) self.chat_container.append(overlay) @@ -955,15 +962,9 @@ Generate a title following these rules: first_paragraph = self.bot_message.get_text(self.bot_message.get_start_iter(), self.bot_message.get_end_iter(), False).split("\n")[0] GLib.idle_add(self.show_notification, self.chats["selected_chat"], first_paragraph[:100] + (first_paragraph[100:] and '...'), Gio.ThemedIcon.new("chat-message-new-symbolic")) else: - if id not in self.chats["chats"][self.chats["selected_chat"]]["messages"]: + if not self.chats["chats"][self.chats["selected_chat"]]["messages"][id]["content"] and self.loading_spinner: GLib.idle_add(self.chat_container.remove, self.loading_spinner) self.loading_spinner = None - self.chats["chats"][self.chats["selected_chat"]]["messages"][id] = { - "role": "assistant", - "model": data['model'], - "date": datetime.now().strftime("%Y/%m/%d %H:%M:%S"), - "content": '' - } GLib.idle_add(self.bot_message.insert, self.bot_message.get_end_iter(), data['message']['content']) self.chats["chats"][self.chats["selected_chat"]]["messages"][id]['content'] += data['message']['content'] @@ -978,15 +979,64 @@ Generate a title following these rules: def run_message(self, messages, model, id): logger.debug("Running message") self.bot_message_button_container.set_visible(False) - response = connection_handler.stream_post(f"{connection_handler.url}/api/chat", data=json.dumps({"model": model, "messages": messages}), callback=lambda data, id=id: self.update_bot_message(data, id)) - GLib.idle_add(self.add_code_blocks) - GLib.idle_add(self.switch_send_stop_button) - GLib.idle_add(self.toggle_ui_sensitive, True) - if self.loading_spinner: - GLib.idle_add(self.chat_container.remove, self.loading_spinner) - self.loading_spinner = None - if response.status_code != 200: + self.chats["chats"][self.chats["selected_chat"]]["messages"][id] = { + "role": "assistant", + "model": model, + "date": datetime.now().strftime("%Y/%m/%d %H:%M:%S"), + "content": '' + } + if self.regenerate_button: + GLib.idle_add(self.chat_container.remove, self.regenerate_button) + try: + response = connection_handler.stream_post(f"{connection_handler.url}/api/chat", data=json.dumps({"model": model, "messages": messages}), callback=lambda data, id=id: self.update_bot_message(data, id)) + if response.status_code != 200: raise Exception('Network Error') + GLib.idle_add(self.add_code_blocks) + except Exception as e: GLib.idle_add(self.connection_error) + self.regenerate_button = Gtk.Button( + child=Adw.ButtonContent( + icon_name='update-symbolic', + label=_('Regenerate Response') + ), + css_classes=["suggested-action"], + halign=3 + ) + GLib.idle_add(self.chat_container.append, self.regenerate_button) + self.regenerate_button.connect('clicked', lambda button, id=id, bot_message_box=self.bot_message_box, bot_message_button_container=self.bot_message_button_container : self.regenerate_message(id, bot_message_box, bot_message_button_container)) + finally: + GLib.idle_add(self.switch_send_stop_button) + GLib.idle_add(self.toggle_ui_sensitive, True) + if self.loading_spinner: + GLib.idle_add(self.chat_container.remove, self.loading_spinner) + self.loading_spinner = None + + def regenerate_message(self, id, bot_message_box, bot_message_button_container): + self.bot_message_button_container = bot_message_button_container + self.bot_message_view = Gtk.TextView( + editable=False, + focusable=True, + wrap_mode= Gtk.WrapMode.WORD, + margin_top=12, + margin_bottom=12, + hexpand=True, + css_classes=["flat"] + ) + self.bot_message = self.bot_message_view.get_buffer() + for widget in list(bot_message_box): bot_message_box.remove(widget) + bot_message_box.append(self.bot_message_view) + history = self.convert_history_to_ollama()[:list(self.chats["chats"][self.chats["selected_chat"]]["messages"].keys()).index(id)] + if id in self.chats["chats"][self.chats["selected_chat"]]["messages"]: + del self.chats["chats"][self.chats["selected_chat"]]["messages"][id] + data = { + "model": self.convert_model_name(self.model_drop_down.get_selected_item().get_string(), 1), + "messages": history, + "options": {"temperature": self.model_tweaks["temperature"], "seed": self.model_tweaks["seed"]}, + "keep_alive": f"{self.model_tweaks['keep_alive']}m" + } + self.switch_send_stop_button() + self.toggle_ui_sensitive(False) + thread = threading.Thread(target=self.run_message, args=(data['messages'], data['model'], id)) + thread.start() def pull_model_update(self, data, model_name): if 'error' in data: