Remade model selector
This commit is contained in:
parent
972c53000c
commit
416e97d488
@ -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>
|
||||
|
2
src/icons/down-symbolic.svg
Normal file
2
src/icons/down-symbolic.svg
Normal 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 |
@ -12,3 +12,9 @@
|
||||
border-radius: 5px;
|
||||
padding: 5px;
|
||||
}
|
||||
.model_list_box {
|
||||
padding: 0;
|
||||
}
|
||||
.model_list_box > * {
|
||||
margin: 0;
|
||||
}
|
||||
|
140
src/window.py
140
src/window.py
@ -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)
|
||||
|
@ -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">
|
||||
|
Loading…
x
Reference in New Issue
Block a user