Added basic shortcuts

This commit is contained in:
jeffser 2024-05-19 12:10:14 -06:00
parent 9f00890f46
commit adef5b5671
3 changed files with 86 additions and 17 deletions

View File

@ -33,7 +33,7 @@ class AlpacaApplication(Adw.Application):
super().__init__(application_id='com.jeffser.Alpaca', super().__init__(application_id='com.jeffser.Alpaca',
flags=Gio.ApplicationFlags.DEFAULT_FLAGS) flags=Gio.ApplicationFlags.DEFAULT_FLAGS)
self.create_action('quit', lambda *_: self.quit(), ['<primary>q']) self.create_action('quit', lambda *_: self.quit(), ['<primary>q'])
self.create_action('clear', lambda *_: AlpacaWindow.clear_conversation_dialog(self.props.active_window), ['<primary>e']) self.create_action('clear', lambda *_: AlpacaWindow.clear_chat_dialog(self.props.active_window), ['<primary>e'])
self.create_action('reconnect', lambda *_: AlpacaWindow.show_connection_dialog(self.props.active_window), ['<primary>r']) self.create_action('reconnect', lambda *_: AlpacaWindow.show_connection_dialog(self.props.active_window), ['<primary>r'])
self.create_action('about', self.on_about_action) self.create_action('about', self.on_about_action)

View File

@ -35,11 +35,11 @@ class AlpacaWindow(Adw.ApplicationWindow):
#Variables #Variables
ollama_url = None ollama_url = None
local_models = [] local_models = []
#In the future I will at multiple chats, for now I'll save it like this so that past chats don't break in the future chats = {"chats": {"New Chat": {"messages": []}}, "selected_chat": "New Chat"}
chats = {"chats": {"0": {"messages": []}}, "selected_chat": "0"}
attached_image = {"path": None, "base64": None} attached_image = {"path": None, "base64": None}
#Elements #Elements
shortcut_window : Gtk.ShortcutsWindow = Gtk.Template.Child()
bot_message : Gtk.TextBuffer = None bot_message : Gtk.TextBuffer = None
bot_message_box : Gtk.Box = None bot_message_box : Gtk.Box = None
bot_message_view : Gtk.TextView = None bot_message_view : Gtk.TextView = None
@ -87,7 +87,7 @@ class AlpacaWindow(Adw.ApplicationWindow):
], ],
"info": [ "info": [
"Please select a model before chatting", "Please select a model before chatting",
"Conversation cannot be cleared while receiving a message" "Chat cannot be cleared while receiving a message"
], ],
"good": [ "good": [
"Model deleted successfully", "Model deleted successfully",
@ -115,7 +115,7 @@ class AlpacaWindow(Adw.ApplicationWindow):
def show_message(self, msg:str, bot:bool, footer:str=None, image_base64:str=None): def show_message(self, msg:str, bot:bool, footer:str=None, image_base64:str=None):
message_text = Gtk.TextView( message_text = Gtk.TextView(
editable=False, editable=False,
focusable=False, focusable=True,
wrap_mode= Gtk.WrapMode.WORD, wrap_mode= Gtk.WrapMode.WORD,
margin_top=12, margin_top=12,
margin_bottom=12, margin_bottom=12,
@ -229,7 +229,7 @@ class AlpacaWindow(Adw.ApplicationWindow):
if part['type'] == 'normal': if part['type'] == 'normal':
message_text = Gtk.TextView( message_text = Gtk.TextView(
editable=False, editable=False,
focusable=False, focusable=True,
wrap_mode= Gtk.WrapMode.WORD, wrap_mode= Gtk.WrapMode.WORD,
margin_top=12, margin_top=12,
margin_bottom=12, margin_bottom=12,
@ -315,7 +315,7 @@ class AlpacaWindow(Adw.ApplicationWindow):
GLib.idle_add(self.show_toast, 'error', 1, self.connection_overlay) GLib.idle_add(self.show_toast, 'error', 1, self.connection_overlay)
GLib.idle_add(self.show_connection_dialog, True) GLib.idle_add(self.show_connection_dialog, True)
def send_message(self, button): def send_message(self, button=None):
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 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_model = self.model_drop_down.get_selected_item() current_model = self.model_drop_down.get_selected_item()
if current_model is None: if current_model is None:
@ -512,22 +512,22 @@ class AlpacaWindow(Adw.ApplicationWindow):
else: self.connection_url_entry.set_css_classes([]) else: self.connection_url_entry.set_css_classes([])
self.connection_dialog.present(self) self.connection_dialog.present(self)
def clear_conversation(self): def clear_chat(self):
for widget in list(self.chat_container): self.chat_container.remove(widget) for widget in list(self.chat_container): self.chat_container.remove(widget)
self.chats["chats"][self.chats["selected_chat"]]["messages"] = [] self.chats["chats"][self.chats["selected_chat"]]["messages"] = []
def clear_conversation_dialog_response(self, dialog, task): def clear_chat_dialog_response(self, dialog, task):
if dialog.choose_finish(task) == "empty": if dialog.choose_finish(task) == "empty":
self.clear_conversation() self.clear_chat()
self.save_history() self.save_history()
def clear_conversation_dialog(self): def clear_chat_dialog(self):
if self.bot_message is not None: if self.bot_message is not None:
self.show_toast("info", 1, self.main_overlay) self.show_toast("info", 1, self.main_overlay)
return return
dialog = Adw.AlertDialog( dialog = Adw.AlertDialog(
heading=f"Clear Conversation", heading=f"Clear Chat",
body=f"Are you sure you want to clear the conversation?", body=f"Are you sure you want to clear the chat?",
close_response="cancel" close_response="cancel"
) )
dialog.add_response("cancel", "Cancel") dialog.add_response("cancel", "Cancel")
@ -536,7 +536,7 @@ class AlpacaWindow(Adw.ApplicationWindow):
dialog.choose( dialog.choose(
parent = self, parent = self,
cancellable = None, cancellable = None,
callback = self.clear_conversation_dialog_response callback = self.clear_chat_dialog_response
) )
def save_history(self): def save_history(self):
@ -555,7 +555,7 @@ class AlpacaWindow(Adw.ApplicationWindow):
def load_history(self): def load_history(self):
if os.path.exists(os.path.join(self.config_dir, "chats.json")): if os.path.exists(os.path.join(self.config_dir, "chats.json")):
self.clear_conversation() self.clear_chat()
try: try:
with open(os.path.join(self.config_dir, "chats.json"), "r") as f: with open(os.path.join(self.config_dir, "chats.json"), "r") as f:
self.chats = json.load(f) self.chats = json.load(f)
@ -754,7 +754,7 @@ class AlpacaWindow(Adw.ApplicationWindow):
css_classes = ["card"] css_classes = ["card"]
) )
button_delete = Gtk.Button( button_delete = Gtk.Button(
icon_name = "edit-delete-symbolic", icon_name = "user-trash-symbolic",
vexpand = False, vexpand = False,
valign = 3, valign = 3,
css_classes = ["error", "flat"] css_classes = ["error", "flat"]
@ -783,13 +783,17 @@ class AlpacaWindow(Adw.ApplicationWindow):
self.model_drop_down.set_selected(i) self.model_drop_down.set_selected(i)
break break
def selected_model_changed(self, pspec=None, user_data=None): def selected_model_changed(self, pspec=None, user_data=None):
self.verify_if_image_can_be_used() self.verify_if_image_can_be_used()
def __init__(self, **kwargs): def __init__(self, **kwargs):
super().__init__(**kwargs) super().__init__(**kwargs)
GtkSource.init() GtkSource.init()
self.set_help_overlay(self.shortcut_window)
self.get_application().set_accels_for_action("win.show-help-overlay", ['<primary>slash'])
self.get_application().create_action('send', lambda *_: self.send_message(self), ['<primary>Return'])
self.manage_models_button.connect("clicked", self.manage_models_button_activate) self.manage_models_button.connect("clicked", self.manage_models_button_activate)
self.send_button.connect("clicked", self.send_message) self.send_button.connect("clicked", self.send_message)
self.image_button.connect("clicked", self.open_image) self.image_button.connect("clicked", self.open_image)

View File

@ -444,6 +444,10 @@
<attribute name="label" translatable="yes">_Change Server</attribute> <attribute name="label" translatable="yes">_Change Server</attribute>
<attribute name="action">app.reconnect</attribute> <attribute name="action">app.reconnect</attribute>
</item> </item>
<item>
<attribute name="label" translatable="yes">_Keyboard Shortcuts</attribute>
<attribute name="action">win.show-help-overlay</attribute>
</item>
<item> <item>
<attribute name="label" translatable="yes">_About Alpaca</attribute> <attribute name="label" translatable="yes">_About Alpaca</attribute>
<attribute name="action">app.about</attribute> <attribute name="action">app.about</attribute>
@ -459,4 +463,65 @@
<mime-type>image/gif</mime-type> <mime-type>image/gif</mime-type>
</mime-types> </mime-types>
</object> </object>
<object class="GtkShortcutsWindow" id="shortcut_window">
<property name="modal">1</property>
<child>
<object class="GtkShortcutsSection">
<property name="section-name">shortcuts</property>
<property name="max-height">10</property>
<child>
<object class="GtkShortcutsGroup">
<property name="title" translatable="yes">General</property>
<child>
<object class="GtkShortcutsShortcut">
<property name="accelerator">&lt;ctrl&gt;Q</property>
<property name="title" translatable="yes">Close application</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="accelerator">&lt;ctrl&gt;E</property>
<property name="title" translatable="yes">Clear chat</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="accelerator">&lt;ctrl&gt;R</property>
<property name="title" translatable="yes">Change server</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="accelerator">&lt;ctrl&gt;slash</property>
<property name="title" translatable="yes">Show shortcuts window</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkShortcutsGroup">
<property name="title" translatable="yes">Editor</property>
<child>
<object class="GtkShortcutsShortcut">
<property name="accelerator">&lt;ctrl&gt;C</property>
<property name="title" translatable="yes">Copy</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="accelerator">&lt;ctrl&gt;V</property>
<property name="title" translatable="yes">Paste</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="accelerator">&lt;ctrl&gt;Return</property>
<property name="title" translatable="yes">Send Message</property>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</interface> </interface>