Remade model selector

This commit is contained in:
jeffser 2024-08-05 23:12:22 -06:00
parent 972c53000c
commit 416e97d488
5 changed files with 148 additions and 75 deletions

View File

@ -29,6 +29,7 @@
<file alias="icons/scalable/status/edit-symbolic.svg">icons/edit-symbolic.svg</file>
<file alias="icons/scalable/status/image-missing-symbolic.svg">icons/image-missing-symbolic.svg</file>
<file alias="icons/scalable/status/update-symbolic.svg">icons/update-symbolic.svg</file>
<file alias="icons/scalable/status/down-symbolic.svg">icons/down-symbolic.svg</file>
<file preprocess="xml-stripblanks">window.ui</file>
<file preprocess="xml-stripblanks">gtk/help-overlay.ui</file>
</gresource>

View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" height="16px" viewBox="0 0 16 16" width="16px"><path d="m 2.292969 6.707031 l 5 5 c 0.390625 0.390625 1.023437 0.390625 1.414062 0 l 5 -5 c 0.390625 -0.390625 0.390625 -1.023437 0 -1.414062 s -1.023437 -0.390625 -1.414062 0 l -4.292969 4.292969 l -4.292969 -4.292969 c -0.390625 -0.390625 -1.023437 -0.390625 -1.414062 0 s -0.390625 1.023437 0 1.414062 z m 0 0" fill="#222222" fill-rule="evenodd"/></svg>

After

Width:  |  Height:  |  Size: 484 B

View File

@ -12,3 +12,9 @@
border-radius: 5px;
padding: 5px;
}
.model_list_box {
padding: 0;
}
.model_list_box > * {
margin: 0;
}

View File

@ -107,8 +107,6 @@ class AlpacaWindow(Adw.ApplicationWindow):
file_filter_gguf = Gtk.Template.Child()
file_filter_attachments = Gtk.Template.Child()
attachment_button = Gtk.Template.Child()
model_drop_down = Gtk.Template.Child()
model_string_list = Gtk.Template.Child()
chat_right_click_menu = Gtk.Template.Child()
model_tag_list_box = Gtk.Template.Child()
navigation_view_manage_models = Gtk.Template.Child()
@ -118,6 +116,9 @@ class AlpacaWindow(Adw.ApplicationWindow):
model_searchbar = Gtk.Template.Child()
no_results_page = Gtk.Template.Child()
model_link_button = Gtk.Template.Child()
model_list_box = Gtk.Template.Child()
model_popover = Gtk.Template.Child()
model_selector_button = Gtk.Template.Child()
manage_models_dialog = Gtk.Template.Child()
pulling_model_list_box = Gtk.Template.Child()
@ -136,22 +137,6 @@ class AlpacaWindow(Adw.ApplicationWindow):
style_manager = Adw.StyleManager()
@Gtk.Template.Callback()
def verify_if_image_can_be_used(self, pspec=None, user_data=None):
logger.debug("Verifying if image can be used")
if self.model_drop_down.get_selected_item() == None:
return True
selected = self.convert_model_name(self.model_drop_down.get_selected_item().get_string(), 1).split(":")[0]
if selected in [key for key, value in self.available_models.items() if value["image"]]:
for name, content in self.attachments.items():
if content['type'] == 'image':
content['button'].set_css_classes(["flat"])
return True
for name, content in self.attachments.items():
if content['type'] == 'image':
content['button'].set_css_classes(["flat", "error"])
return False
@Gtk.Template.Callback()
def stop_message(self, button=None):
if self.loading_spinner:
@ -191,7 +176,7 @@ class AlpacaWindow(Adw.ApplicationWindow):
self.chats['order'].remove(self.chats['selected_chat'])
self.chats['order'].insert(0, self.chats['selected_chat'])
self.save_history()
current_model = self.convert_model_name(self.model_drop_down.get_selected_item().get_string(), 1)
current_model = self.get_current_model(1)
if current_model is None:
self.show_toast(_("Please select a model before chatting"), self.main_overlay)
return
@ -288,10 +273,9 @@ class AlpacaWindow(Adw.ApplicationWindow):
self.load_history_into_chat()
if len(self.chats["chats"][self.chats["selected_chat"]]["messages"].keys()) > 0:
last_model_used = self.chats["chats"][self.chats["selected_chat"]]["messages"][list(self.chats["chats"][self.chats["selected_chat"]]["messages"].keys())[-1]]["model"]
last_model_used = self.convert_model_name(last_model_used, 0)
for i in range(self.model_string_list.get_n_items()):
if self.model_string_list.get_string(i) == last_model_used:
self.model_drop_down.set_selected(i)
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
self.save_history()
@ -427,11 +411,69 @@ class AlpacaWindow(Adw.ApplicationWindow):
self.available_model_list_box.set_visible(True)
self.no_results_page.set_visible(False)
@Gtk.Template.Callback()
def close_model_popup(self, *_):
self.model_popover.hide()
@Gtk.Template.Callback()
def change_model(self, listbox=None, row=None):
if not row:
current_model = self.convert_model_name(self.model_selector_button.get_child().get_label(), 1)
print("c ", current_model)
for i, m in enumerate(self.local_models):
if m == current_model:
self.model_list_box.select_row(self.model_list_box.get_row_at_index(i))
return
self.model_list_box.select_row(self.model_list_box.get_row_at_index(0))
return
button_content = Gtk.Box(
spacing=10
)
button_content.append(
Gtk.Label(
label=row.get_child().get_label(),
ellipsize=2
)
)
button_content.append(
Gtk.Image.new_from_icon_name("down-symbolic")
)
self.model_selector_button.set_child(button_content)
self.close_model_popup()
self.verify_if_image_can_be_used()
def verify_if_image_can_be_used(self):
logger.debug("Verifying if image can be used")
selected = self.get_current_model(1)
if selected == None:
return True
selected = selected.split(":")[0]
if selected in [key for key, value in self.available_models.items() if value["image"]]:
for name, content in self.attachments.items():
if content['type'] == 'image':
content['button'].set_css_classes(["flat"])
return True
for name, content in self.attachments.items():
if content['type'] == 'image':
content['button'].set_css_classes(["flat", "error"])
return False
def convert_model_name(self, name:str, mode:int) -> str: # mode=0 name:tag -> Name (tag) | mode=1 Name (tag) -> name:tag
try:
if mode == 0:
return "{} ({})".format(name.split(":")[0].replace("-", " ").title(), name.split(":")[1])
if mode == 1:
return "{}:{}".format(name.split(" (")[0].replace(" ", "-").lower(), name.split(" (")[1][:-1])
except Exception as e:
pass
def get_current_model(self, mode:int) -> str:
if not self.model_list_box.get_selected_row():
return None
if mode == 0:
return "{} ({})".format(name.split(":")[0].replace("-", " ").title(), name.split(":")[1])
return self.model_list_box.get_selected_row().get_child().get_label()
if mode == 1:
return "{}:{}".format(name.split(" (")[0].replace(" ", "-").lower(), name.split(" (")[1][:-1])
return self.model_list_box.get_selected_row().get_name()
def check_alphanumeric(self, editable, text, length, position):
new_text = ''.join([char for char in text if char.isalnum() or char in ['-', '.', ':', '_']])
@ -593,7 +635,7 @@ Generate a title following these rules:
```PROMPT
{message['content']}
```"""
current_model = self.convert_model_name(self.model_drop_down.get_selected_item().get_string(), 1)
current_model = self.get_current_model(1)
data = {"model": current_model, "prompt": prompt, "stream": False}
if 'images' in message:
data["images"] = message['images']
@ -776,8 +818,7 @@ Generate a title following these rules:
logger.debug("Updating list of local models")
self.local_models = []
response = connection_handler.simple_get(f"{connection_handler.url}/api/tags")
for i in range(self.model_string_list.get_n_items() -1, -1, -1):
self.model_string_list.remove(i)
self.model_list_box.remove_all()
if response.status_code == 200:
self.local_model_list_box.remove_all()
if len(json.loads(response.text)['models']) == 0:
@ -801,9 +842,17 @@ Generate a title following these rules:
model_row.add_suffix(button)
self.local_model_list_box.append(model_row)
self.model_string_list.append(model_name)
selector_row = Gtk.ListBoxRow(
child = Gtk.Label(
label=model_name, halign=1, hexpand=True
),
halign=0,
hexpand=True,
name=model["name"],
tooltip_text=model_name
)
self.model_list_box.append(selector_row)
self.local_models.append(model["name"])
#self.verify_if_image_can_be_used()
else:
self.connection_error()
@ -1058,7 +1107,7 @@ Generate a title following these rules:
if message_id in self.chats["chats"][self.chats["selected_chat"]]["messages"]:
del self.chats["chats"][self.chats["selected_chat"]]["messages"][message_id]
data = {
"model": self.convert_model_name(self.model_drop_down.get_selected_item().get_string(), 1),
"model": self.get_current_model(1),
"messages": history,
"options": {"temperature": self.model_tweaks["temperature"], "seed": self.model_tweaks["seed"]},
"keep_alive": f"{self.model_tweaks['keep_alive']}m"
@ -1091,6 +1140,7 @@ Generate a title following these rules:
data = {"name": model}
response = connection_handler.stream_post(f"{connection_handler.url}/api/pull", data=json.dumps(data), callback=lambda data, model_name=model: self.pull_model_update(data, model_name))
GLib.idle_add(self.update_list_local_models)
GLib.idle_add(self.change_model)
if response.status_code == 200 and 'error' not in self.pulling_models[model]:
GLib.idle_add(self.show_notification, _("Task Complete"), _("Model '{}' pulled successfully.").format(model), Gio.ThemedIcon.new("emblem-ok-symbolic"))
@ -1239,10 +1289,9 @@ Generate a title following these rules:
self.chats["order"].append(chat_name)
if len(self.chats["chats"][self.chats["selected_chat"]]["messages"].keys()) > 0:
last_model_used = self.chats["chats"][self.chats["selected_chat"]]["messages"][list(self.chats["chats"][self.chats["selected_chat"]]["messages"].keys())[-1]]["model"]
last_model_used = self.convert_model_name(last_model_used, 0)
for i in range(self.model_string_list.get_n_items()):
if self.model_string_list.get_string(i) == last_model_used:
self.model_drop_down.set_selected(i)
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
except Exception as e:
logger.error(e)
@ -1322,6 +1371,7 @@ Generate a title following these rules:
self.update_list_local_models()
if response.status_code == 200:
self.show_toast(_("Model deleted successfully"), self.manage_models_overlay)
self.change_model()
else:
self.manage_models_dialog.close()
self.connection_error()
@ -1644,25 +1694,6 @@ Generate a title following these rules:
clipboard.read_text_async(None, self.cb_text_received)
clipboard.read_texture_async(None, self.cb_image_received)
def on_model_dropdown_setup(self, factory, list_item):
label = Gtk.Label()
label.set_ellipsize(2)
label.set_xalign(0)
list_item.set_child(label)
def on_model_dropdown_bind(self, factory, list_item):
label = list_item.get_child()
item = list_item.get_item()
label.set_text(item.get_string())
label.set_tooltip_text(item.get_string())
def setup_model_dropdown(self):
factory = Gtk.SignalListItemFactory()
factory.connect("setup", self.on_model_dropdown_setup)
factory.connect("bind", self.on_model_dropdown_bind)
self.model_drop_down.set_factory(factory)
def handle_enter_key(self):
self.send_message()
return True
@ -1701,7 +1732,6 @@ Generate a title following these rules:
self.remote_connection_entry.connect("entry-activated", lambda entry : entry.set_css_classes([]))
self.remote_connection_switch.connect("notify", lambda pspec, user_data : self.connection_switched())
self.background_switch.connect("notify", lambda pspec, user_data : self.switch_run_on_background())
self.setup_model_dropdown()
if os.path.exists(os.path.join(self.config_dir, "server.json")):
with open(os.path.join(self.config_dir, "server.json"), "r", encoding="utf-8") as f:
data = json.load(f)

View File

@ -76,30 +76,64 @@
<property name="orientation">0</property>
<property name="spacing">12</property>
<child>
<object class="GtkDropDown" id="model_drop_down">
<signal name="notify" handler="verify_if_image_can_be_used"/>
<property name="width-request">260</property>
<property name="enable-search">false</property>
<property name="tooltip-text">Select Model</property>
<property name="model">
<object class="GtkStringList" id="model_string_list">
<items>
</items>
<object class="GtkMenuButton" id="model_selector_button">
<property name="tooltip-text" translatable="yes">Select Model</property>
<property name="child">
<object class="GtkBox">
<child>
<object class="GtkLabel">
<property name="label">(None)</property>
<property name="ellipsize">2</property>
</object>
</child>
<child>
<object class="GtkImage">
<property name="icon-name">down-symbolic</property>
</object>
</child>
</object>
</property>
<property name="halign">1</property>
<style>
<class name="raised"/>
</style>
<property name="popover">
<object class="GtkPopover" id="model_popover">
<child>
<object class="GtkBox">
<property name="orientation">1</property>
<property name="spacing">10</property>
<child>
<object class="GtkButton">
<property name="hexpand">true</property>
<property name="label" translatable="yes">Manage Models</property>
<property name="tooltip-text" translatable="yes">Manage Models</property>
<property name="action-name">app.manage_models</property>
<signal name="clicked" handler="close_model_popup"/>
<style>
<class name="accent"/>
</style>
</object>
</child>
<child>
<object class="GtkSeparator"/>
</child>
<child>
<object class="GtkListBox" id="model_list_box">
<property name="hexpand">true</property>
<style>
<class name="navigation-sidebar"/>
<class name="model_list_box"/>
</style>
<signal name="row-selected" handler="change_model"/>
</object>
</child>
</object>
</child>
</object>
</property>
</object>
</child>
<!--<child>
<object class="GtkButton" id="manage_models_button">
<signal name="clicked" handler="manage_models_button_activate"/>
<property name="tooltip-text" translatable="yes">Manage Models</property>
<child>
<object class="AdwButtonContent">
<property name="icon-name">brain-augemnted-symbolic</property>
</object>
</child>
</object>
</child>-->
</object>
</property>
<child type="end">