diff --git a/src/window.py b/src/window.py index 600a878..339be18 100644 --- a/src/window.py +++ b/src/window.py @@ -19,7 +19,7 @@ """ Handles the main window """ -import json, threading, os, re, base64, sys, gettext, uuid, shutil, tarfile, tempfile, logging +import json, threading, os, re, base64, sys, gettext, uuid, shutil, tarfile, tempfile, logging, random from io import BytesIO from PIL import Image from pypdf import PdfReader @@ -119,6 +119,7 @@ class AlpacaWindow(Adw.ApplicationWindow): model_list_box = Gtk.Template.Child() model_popover = Gtk.Template.Child() model_selector_button = Gtk.Template.Child() + chat_welcome_screen : Adw.StatusPage = None manage_models_dialog = Gtk.Template.Child() pulling_model_list_box = Gtk.Template.Child() @@ -142,7 +143,7 @@ class AlpacaWindow(Adw.ApplicationWindow): if self.loading_spinner: self.chat_container.remove(self.loading_spinner) self.toggle_ui_sensitive(True) - self.switch_send_stop_button() + self.switch_send_stop_button(True) self.bot_message = None self.bot_message_box = None self.bot_message_view = None @@ -164,8 +165,6 @@ class AlpacaWindow(Adw.ApplicationWindow): self.save_history() self.show_toast(_("Message edited successfully"), self.main_overlay) - if self.bot_message or self.get_focus() not in (self.message_text_view, self.send_button): - return if not self.message_text_view.get_buffer().get_text(self.message_text_view.get_buffer().get_start_iter(), self.message_text_view.get_buffer().get_end_iter(), False): return current_chat_row = self.chat_list_box.get_selected_row() @@ -217,7 +216,7 @@ class AlpacaWindow(Adw.ApplicationWindow): "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.switch_send_stop_button(False) self.toggle_ui_sensitive(False) #self.attachments[name] = {"path": file_path, "type": file_type, "content": content} @@ -230,6 +229,9 @@ class AlpacaWindow(Adw.ApplicationWindow): bot_id=self.generate_uuid() self.show_message("", True, message_id=bot_id) + if self.chat_welcome_screen: + self.chat_container.remove(self.chat_welcome_screen) + thread = threading.Thread(target=self.run_message, args=(data['messages'], data['model'], bot_id)) thread.start() if len(data['messages']) == 1: @@ -271,12 +273,14 @@ class AlpacaWindow(Adw.ApplicationWindow): if row and row.get_child().get_name() != self.chats["selected_chat"]: self.chats["selected_chat"] = row.get_child().get_name() self.load_history_into_chat() - if len(self.chats["chats"][self.chats["selected_chat"]]["messages"].keys()) > 0: + if len(self.chats["chats"][self.chats["selected_chat"]]["messages"]) > 0: last_model_used = self.chats["chats"][self.chats["selected_chat"]]["messages"][list(self.chats["chats"][self.chats["selected_chat"]]["messages"].keys())[-1]]["model"] for i, m in enumerate(self.local_models): if m == last_model_used: self.model_list_box.select_row(self.model_list_box.get_row_at_index(i)) break + else: + self.load_history_into_chat() self.save_history() @Gtk.Template.Callback() @@ -536,6 +540,8 @@ class AlpacaWindow(Adw.ApplicationWindow): if os.path.exists(os.path.join(self.data_dir, "chats", self.chats['selected_chat'], message_id)): shutil.rmtree(os.path.join(self.data_dir, "chats", self.chats['selected_chat'], message_id)) self.save_history() + if len(self.chats["chats"][self.chats["selected_chat"]]["messages"]) == 0: + self.load_history_into_chat() def copy_message(self, message_element): logger.debug("Copying message") @@ -594,7 +600,7 @@ class AlpacaWindow(Adw.ApplicationWindow): self.file_preview_text_view.set_visible(True) buffer = self.file_preview_text_view.get_buffer() buffer.delete(buffer.get_start_iter(), buffer.get_end_iter()) - buffer.insert(buffer.get_start_iter(), content, len(content)) + buffer.insert(buffer.get_start_iter(), content, len(content.encode('utf-8'))) if file_type == 'youtube': self.file_preview_dialog.set_title(content.split('\n')[0]) self.file_preview_open_button.set_name(content.split('\n')[2]) @@ -1055,9 +1061,9 @@ Generate a title following these rules: for element in [self.chat_list_box, self.add_chat_button, self.secondary_menu_button]: element.set_sensitive(status) - def switch_send_stop_button(self): - self.stop_button.set_visible(self.send_button.get_visible()) - self.send_button.set_visible(not self.send_button.get_visible()) + def switch_send_stop_button(self, send:bool): + self.stop_button.set_visible(not send) + self.send_button.set_visible(send) def run_message(self, messages, model, message_id): logger.debug("Running message") @@ -1088,7 +1094,7 @@ Generate a title following these rules: GLib.idle_add(self.chat_container.append, self.regenerate_button) self.regenerate_button.connect('clicked', lambda button, message_id=message_id, bot_message_box=self.bot_message_box, bot_message_button_container=self.bot_message_button_container : self.regenerate_message(message_id, bot_message_box, bot_message_button_container)) finally: - GLib.idle_add(self.switch_send_stop_button) + GLib.idle_add(self.switch_send_stop_button, True) GLib.idle_add(self.toggle_ui_sensitive, True) if self.loading_spinner: GLib.idle_add(self.chat_container.remove, self.loading_spinner) @@ -1118,7 +1124,7 @@ Generate a title following these rules: "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.switch_send_stop_button(False) self.toggle_ui_sensitive(False) thread = threading.Thread(target=self.run_message, args=(data['messages'], data['model'], message_id)) thread.start() @@ -1267,17 +1273,51 @@ Generate a title following these rules: with open(os.path.join(self.data_dir, "chats", "chats.json"), "w+", encoding="utf-8") as f: json.dump(self.chats, f, indent=4) + def send_sample_prompt(self, prompt): + buffer = self.message_text_view.get_buffer() + buffer.delete(buffer.get_start_iter(), buffer.get_end_iter()) + buffer.insert(buffer.get_start_iter(), prompt, len(prompt.encode('utf-8'))) + self.send_message() + def load_history_into_chat(self): for widget in list(self.chat_container): self.chat_container.remove(widget) - for key, message in self.chats['chats'][self.chats["selected_chat"]]['messages'].items(): - if message: - formated_date = GLib.markup_escape_text(self.generate_datetime_format(datetime.strptime(message['date'] + (":00" if message['date'].count(":") == 1 else ""), '%Y/%m/%d %H:%M:%S'))) - if message['role'] == 'user': - self.show_message(message['content'], False, f"\n\n{formated_date}", message['images'] if 'images' in message else None, message['files'] if 'files' in message else None, message_id=key) - else: - self.show_message(message['content'], True, f"\n\n{self.convert_model_name(message['model'], 0)}\n{formated_date}", message_id=key) - self.add_code_blocks() - self.bot_message = None + self.chat_welcome_screen = None + if len(self.chats['chats'][self.chats["selected_chat"]]['messages']) > 0: + for key, message in self.chats['chats'][self.chats["selected_chat"]]['messages'].items(): + if message: + formated_date = GLib.markup_escape_text(self.generate_datetime_format(datetime.strptime(message['date'] + (":00" if message['date'].count(":") == 1 else ""), '%Y/%m/%d %H:%M:%S'))) + if message['role'] == 'user': + self.show_message(message['content'], False, f"\n\n{formated_date}", message['images'] if 'images' in message else None, message['files'] if 'files' in message else None, message_id=key) + else: + self.show_message(message['content'], True, f"\n\n{self.convert_model_name(message['model'], 0)}\n{formated_date}", message_id=key) + self.add_code_blocks() + self.bot_message = None + else: + possible_prompts = [ + "What can you do?", + "Give me a pancake recipe", + "Why is the sky blue?" + ] + prompt_container = Gtk.Box( + orientation = 1, + spacing = 10, + halign = 3 + ) + for prompt in random.sample(possible_prompts, 3): + prompt_button = Gtk.Button( + label=prompt + ) + prompt_button.connect('clicked', lambda *_, prompt=prompt : self.send_sample_prompt(prompt)) + prompt_container.append(prompt_button) + self.chat_welcome_screen = Adw.StatusPage( + icon_name="com.jeffser.Alpaca", + title="Alpaca", + description="Try one of these prompts", + child=prompt_container, + vexpand=True + ) + self.chat_container.append(self.chat_welcome_screen) + def load_history(self): logger.debug("Loading history")