Linting code
This commit is contained in:
parent
1a6e74271c
commit
4b6cd17d0a
@ -20,6 +20,7 @@
|
||||
Main script run at launch, handles actions, about dialog and the app itself (not the window)
|
||||
"""
|
||||
|
||||
import gi
|
||||
gi.require_version('Gtk', '4.0')
|
||||
gi.require_version('Adw', '1')
|
||||
from gi.repository import Gtk, Gio, Adw, GLib
|
||||
@ -29,7 +30,6 @@ from .internal import cache_dir, data_dir
|
||||
|
||||
import sys
|
||||
import logging
|
||||
import gi
|
||||
import os
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
228
src/window.py
228
src/window.py
@ -38,7 +38,6 @@ from .internal import config_dir, data_dir, cache_dir, source_dir
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@Gtk.Template(resource_path='/com/jeffser/Alpaca/window.ui')
|
||||
class AlpacaWindow(Adw.ApplicationWindow):
|
||||
app_dir = os.getenv("FLATPAK_DEST")
|
||||
@ -140,7 +139,8 @@ class AlpacaWindow(Adw.ApplicationWindow):
|
||||
@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
|
||||
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():
|
||||
@ -155,7 +155,8 @@ class AlpacaWindow(Adw.ApplicationWindow):
|
||||
|
||||
@Gtk.Template.Callback()
|
||||
def stop_message(self, button=None):
|
||||
if self.loading_spinner: self.chat_container.remove(self.loading_spinner)
|
||||
if self.loading_spinner:
|
||||
self.chat_container.remove(self.loading_spinner)
|
||||
self.toggle_ui_sensitive(True)
|
||||
self.switch_send_stop_button()
|
||||
self.bot_message = None
|
||||
@ -179,8 +180,10 @@ 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
|
||||
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()
|
||||
self.chat_list_box.unselect_all()
|
||||
self.chat_list_box.remove(current_chat_row)
|
||||
@ -193,18 +196,19 @@ class AlpacaWindow(Adw.ApplicationWindow):
|
||||
if current_model is None:
|
||||
self.show_toast(_("Please select a model before chatting"), self.main_overlay)
|
||||
return
|
||||
id = self.generate_uuid()
|
||||
message_id = self.generate_uuid()
|
||||
|
||||
attached_images = []
|
||||
attached_files = {}
|
||||
can_use_images = self.verify_if_image_can_be_used()
|
||||
for name, content in self.attachments.items():
|
||||
if content["type"] == 'image' and can_use_images: attached_images.append(name)
|
||||
if content["type"] == 'image' and can_use_images:
|
||||
attached_images.append(name)
|
||||
else:
|
||||
attached_files[name] = content['type']
|
||||
if not os.path.exists(os.path.join(self.data_dir, "chats", self.chats['selected_chat'], id)):
|
||||
os.makedirs(os.path.join(self.data_dir, "chats", self.chats['selected_chat'], id))
|
||||
shutil.copy(content['path'], os.path.join(self.data_dir, "chats", self.chats['selected_chat'], id, name))
|
||||
if not os.path.exists(os.path.join(self.data_dir, "chats", self.chats['selected_chat'], message_id)):
|
||||
os.makedirs(os.path.join(self.data_dir, "chats", self.chats['selected_chat'], message_id))
|
||||
shutil.copy(content['path'], os.path.join(self.data_dir, "chats", self.chats['selected_chat'], message_id, name))
|
||||
content["button"].get_parent().remove(content["button"])
|
||||
self.attachments = {}
|
||||
self.attachment_box.set_visible(False)
|
||||
@ -213,16 +217,16 @@ class AlpacaWindow(Adw.ApplicationWindow):
|
||||
|
||||
current_datetime = datetime.now()
|
||||
|
||||
self.chats["chats"][self.chats["selected_chat"]]["messages"][id] = {
|
||||
self.chats["chats"][self.chats["selected_chat"]]["messages"][message_id] = {
|
||||
"role": "user",
|
||||
"model": "User",
|
||||
"date": current_datetime.strftime("%Y/%m/%d %H:%M:%S"),
|
||||
"content": 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)
|
||||
}
|
||||
if len(attached_images) > 0:
|
||||
self.chats["chats"][self.chats["selected_chat"]]["messages"][id]['images'] = attached_images
|
||||
self.chats["chats"][self.chats["selected_chat"]]["messages"][message_id]['images'] = attached_images
|
||||
if len(attached_files.keys()) > 0:
|
||||
self.chats["chats"][self.chats["selected_chat"]]["messages"][id]['files'] = attached_files
|
||||
self.chats["chats"][self.chats["selected_chat"]]["messages"][message_id]['files'] = attached_files
|
||||
data = {
|
||||
"model": current_model,
|
||||
"messages": self.convert_history_to_ollama(),
|
||||
@ -235,12 +239,12 @@ class AlpacaWindow(Adw.ApplicationWindow):
|
||||
#self.attachments[name] = {"path": file_path, "type": file_type, "content": content}
|
||||
raw_message = 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)
|
||||
formated_date = GLib.markup_escape_text(self.generate_datetime_format(current_datetime))
|
||||
self.show_message(raw_message, False, f"\n\n<small>{formated_date}</small>", attached_images, attached_files, id=id)
|
||||
self.show_message(raw_message, False, f"\n\n<small>{formated_date}</small>", attached_images, attached_files, message_id=message_id)
|
||||
self.message_text_view.get_buffer().set_text("", 0)
|
||||
self.loading_spinner = Gtk.Spinner(spinning=True, margin_top=12, margin_bottom=12, hexpand=True)
|
||||
self.chat_container.append(self.loading_spinner)
|
||||
bot_id=self.generate_uuid()
|
||||
self.show_message("", True, id=bot_id)
|
||||
self.show_message("", True, message_id=bot_id)
|
||||
|
||||
thread = threading.Thread(target=self.run_message, args=(data['messages'], data['model'], bot_id))
|
||||
thread.start()
|
||||
@ -259,8 +263,10 @@ class AlpacaWindow(Adw.ApplicationWindow):
|
||||
@Gtk.Template.Callback()
|
||||
def welcome_carousel_page_changed(self, carousel, index):
|
||||
logger.debug("Showing welcome carousel")
|
||||
if index == 0: self.welcome_previous_button.set_sensitive(False)
|
||||
else: self.welcome_previous_button.set_sensitive(True)
|
||||
if index == 0:
|
||||
self.welcome_previous_button.set_sensitive(False)
|
||||
else:
|
||||
self.welcome_previous_button.set_sensitive(True)
|
||||
if index == carousel.get_n_pages()-1:
|
||||
self.welcome_next_button.set_label(_("Close"))
|
||||
self.welcome_next_button.set_tooltip_text(_("Close"))
|
||||
@ -274,7 +280,8 @@ class AlpacaWindow(Adw.ApplicationWindow):
|
||||
|
||||
@Gtk.Template.Callback()
|
||||
def welcome_next_button_activate(self, button):
|
||||
if button.get_label() == "Next": self.welcome_carousel.scroll_to(self.welcome_carousel.get_nth_page(self.welcome_carousel.get_position()+1), True)
|
||||
if button.get_label() == "Next":
|
||||
self.welcome_carousel.scroll_to(self.welcome_carousel.get_nth_page(self.welcome_carousel.get_position()+1), True)
|
||||
else:
|
||||
self.welcome_dialog.force_close()
|
||||
if not self.verify_connection():
|
||||
@ -342,8 +349,10 @@ class AlpacaWindow(Adw.ApplicationWindow):
|
||||
@Gtk.Template.Callback()
|
||||
def model_spin_changed(self, spin):
|
||||
value = spin.get_value()
|
||||
if spin.get_name() != "temperature": value = round(value)
|
||||
else: value = round(value, 1)
|
||||
if spin.get_name() != "temperature":
|
||||
value = round(value)
|
||||
else:
|
||||
value = round(value, 1)
|
||||
if self.model_tweaks[spin.get_name()] is not None and self.model_tweaks[spin.get_name()] != value:
|
||||
self.model_tweaks[spin.get_name()] = value
|
||||
self.save_server_config()
|
||||
@ -391,11 +400,15 @@ class AlpacaWindow(Adw.ApplicationWindow):
|
||||
def override_changed(self, entry):
|
||||
name = entry.get_name()
|
||||
value = entry.get_text()
|
||||
if (not value and name not in local_instance.overrides) or (value and value in local_instance.overrides and local_instance.overrides[name] == value): return
|
||||
if not value: del local_instance.overrides[name]
|
||||
else: local_instance.overrides[name] = value
|
||||
if (not value and name not in local_instance.overrides) or (value and value in local_instance.overrides and local_instance.overrides[name] == value):
|
||||
return
|
||||
if not value:
|
||||
del local_instance.overrides[name]
|
||||
else:
|
||||
local_instance.overrides[name] = value
|
||||
self.save_server_config()
|
||||
if not self.run_remote: local_instance.reset()
|
||||
if not self.run_remote:
|
||||
local_instance.reset()
|
||||
|
||||
@Gtk.Template.Callback()
|
||||
def link_button_handler(self, button):
|
||||
@ -413,7 +426,8 @@ class AlpacaWindow(Adw.ApplicationWindow):
|
||||
for i, key in enumerate(self.available_models.keys()):
|
||||
row = self.available_model_list_box.get_row_at_index(i)
|
||||
row.set_visible(re.search(entry.get_text(), '{} {} {}'.format(row.get_title(), (_("image") if self.available_models[key]['image'] else " "), row.get_subtitle()), re.IGNORECASE))
|
||||
if row.get_visible(): results += 1
|
||||
if row.get_visible():
|
||||
results += 1
|
||||
if entry.get_text() and results == 0:
|
||||
self.available_model_list_box.set_visible(False)
|
||||
self.no_results_page.set_visible(True)
|
||||
@ -422,12 +436,15 @@ class AlpacaWindow(Adw.ApplicationWindow):
|
||||
self.no_results_page.set_visible(False)
|
||||
|
||||
def convert_model_name(self, name:str, mode:int) -> str: # mode=0 name:tag -> Name (tag) | mode=1 Name (tag) -> name:tag
|
||||
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])
|
||||
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])
|
||||
|
||||
def check_alphanumeric(self, editable, text, length, position):
|
||||
new_text = ''.join([char for char in text if char.isalnum() or char in ['-', '.', ':']])
|
||||
if new_text != text: editable.stop_emission_by_name("insert-text")
|
||||
if new_text != text:
|
||||
editable.stop_emission_by_name("insert-text")
|
||||
|
||||
def create_model(self, model:str, file:bool):
|
||||
modelfile_buffer = self.create_model_modelfile.get_buffer()
|
||||
@ -466,31 +483,33 @@ class AlpacaWindow(Adw.ApplicationWindow):
|
||||
logger.info(f"{title}, {body}")
|
||||
notification = Gio.Notification.new(title)
|
||||
notification.set_body(body)
|
||||
if icon: notification.set_icon(icon)
|
||||
if icon:
|
||||
notification.set_icon(icon)
|
||||
self.get_application().send_notification(None, notification)
|
||||
|
||||
def delete_message(self, message_element):
|
||||
logger.debug("Deleting message")
|
||||
id = message_element.get_name()
|
||||
del self.chats["chats"][self.chats["selected_chat"]]["messages"][id]
|
||||
message_id = message_element.get_name()
|
||||
del self.chats["chats"][self.chats["selected_chat"]]["messages"][message_id]
|
||||
self.chat_container.remove(message_element)
|
||||
if os.path.exists(os.path.join(self.data_dir, "chats", self.chats['selected_chat'], id)):
|
||||
shutil.rmtree(os.path.join(self.data_dir, "chats", self.chats['selected_chat'], id))
|
||||
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()
|
||||
|
||||
def copy_message(self, message_element):
|
||||
logger.debug("Copying message")
|
||||
id = message_element.get_name()
|
||||
message_id = message_element.get_name()
|
||||
clipboard = Gdk.Display().get_default().get_clipboard()
|
||||
clipboard.set(self.chats["chats"][self.chats["selected_chat"]]["messages"][id]["content"])
|
||||
clipboard.set(self.chats["chats"][self.chats["selected_chat"]]["messages"][message_id]["content"])
|
||||
self.show_toast(_("Message copied to the clipboard"), self.main_overlay)
|
||||
|
||||
def edit_message(self, message_element, text_view, button_container):
|
||||
logger.debug("Editing message")
|
||||
if self.editing_message: self.send_message()
|
||||
if self.editing_message:
|
||||
self.send_message()
|
||||
|
||||
button_container.set_visible(False)
|
||||
id = message_element.get_name()
|
||||
message_id = message_element.get_name()
|
||||
|
||||
text_buffer = text_view.get_buffer()
|
||||
end_iter = text_buffer.get_end_iter()
|
||||
@ -504,7 +523,7 @@ class AlpacaWindow(Adw.ApplicationWindow):
|
||||
text_view.set_css_classes(["view", "editing_message_textview"])
|
||||
text_view.set_cursor_visible(True)
|
||||
|
||||
self.editing_message = {"text_view": text_view, "id": id, "button_container": button_container, "footer": footer}
|
||||
self.editing_message = {"text_view": text_view, "id": message_id, "button_container": button_container, "footer": footer}
|
||||
|
||||
def preview_file(self, file_path, file_type, presend_name):
|
||||
logger.debug(f"Previewing file: {file_path}")
|
||||
@ -547,22 +566,24 @@ class AlpacaWindow(Adw.ApplicationWindow):
|
||||
|
||||
def convert_history_to_ollama(self):
|
||||
messages = []
|
||||
for id, message in self.chats["chats"][self.chats["selected_chat"]]["messages"].items():
|
||||
for message_id, message in self.chats["chats"][self.chats["selected_chat"]]["messages"].items():
|
||||
new_message = message.copy()
|
||||
if 'files' in message and len(message['files']) > 0:
|
||||
del new_message['files']
|
||||
new_message['content'] = ''
|
||||
for name, file_type in message['files'].items():
|
||||
file_path = os.path.join(self.data_dir, "chats", self.chats['selected_chat'], id, name)
|
||||
file_path = os.path.join(self.data_dir, "chats", self.chats['selected_chat'], message_id, name)
|
||||
file_data = self.get_content_of_file(file_path, file_type)
|
||||
if file_data: new_message['content'] += f"```[{name}]\n{file_data}\n```"
|
||||
if file_data:
|
||||
new_message['content'] += f"```[{name}]\n{file_data}\n```"
|
||||
new_message['content'] += message['content']
|
||||
if 'images' in message and len(message['images']) > 0:
|
||||
new_message['images'] = []
|
||||
for name in message['images']:
|
||||
file_path = os.path.join(self.data_dir, "chats", self.chats['selected_chat'], id, name)
|
||||
file_path = os.path.join(self.data_dir, "chats", self.chats['selected_chat'], message_id, name)
|
||||
image_data = self.get_content_of_file(file_path, 'image')
|
||||
if image_data: new_message['images'].append(image_data)
|
||||
if image_data:
|
||||
new_message['images'].append(image_data)
|
||||
messages.append(new_message)
|
||||
return messages
|
||||
|
||||
@ -581,14 +602,15 @@ Generate a title following these rules:
|
||||
```"""
|
||||
current_model = self.convert_model_name(self.model_drop_down.get_selected_item().get_string(), 1)
|
||||
data = {"model": current_model, "prompt": prompt, "stream": False}
|
||||
if 'images' in message: data["images"] = message['images']
|
||||
if 'images' in message:
|
||||
data["images"] = message['images']
|
||||
response = connection_handler.simple_post(f"{connection_handler.url}/api/generate", data=json.dumps(data))
|
||||
|
||||
new_chat_name = json.loads(response.text)["response"].strip().removeprefix("Title: ").removeprefix("title: ").strip('\'"').replace('\n', ' ').title().replace('\'S', '\'s')
|
||||
new_chat_name = new_chat_name[:50] + (new_chat_name[50:] and '...')
|
||||
self.rename_chat(label_element.get_name(), new_chat_name, label_element)
|
||||
|
||||
def show_message(self, msg:str, bot:bool, footer:str=None, images:list=None, files:dict=None, id:str=None):
|
||||
def show_message(self, msg:str, bot:bool, footer:str=None, images:list=None, files:dict=None, message_id:str=None):
|
||||
message_text = Gtk.TextView(
|
||||
editable=False,
|
||||
focusable=True,
|
||||
@ -603,7 +625,8 @@ Generate a title following these rules:
|
||||
)
|
||||
message_buffer = message_text.get_buffer()
|
||||
message_buffer.insert(message_buffer.get_end_iter(), msg)
|
||||
if footer is not None: message_buffer.insert_markup(message_buffer.get_end_iter(), footer, len(footer.encode('utf-8')))
|
||||
if footer is not None:
|
||||
message_buffer.insert_markup(message_buffer.get_end_iter(), footer, len(footer.encode('utf-8')))
|
||||
|
||||
delete_button = Gtk.Button(
|
||||
icon_name = "user-trash-symbolic",
|
||||
@ -656,7 +679,7 @@ Generate a title following these rules:
|
||||
child=image_container
|
||||
)
|
||||
for image in images:
|
||||
path = os.path.join(self.data_dir, "chats", self.chats['selected_chat'], id, image)
|
||||
path = os.path.join(self.data_dir, "chats", self.chats['selected_chat'], message_id, image)
|
||||
try:
|
||||
if not os.path.isfile(path):
|
||||
raise FileNotFoundError("'{}' was not found or is a directory".format(path))
|
||||
@ -665,7 +688,7 @@ Generate a title following these rules:
|
||||
button = Gtk.Button(
|
||||
child=image_element,
|
||||
css_classes=["flat", "chat_image_button"],
|
||||
name=os.path.join(self.data_dir, "chats", "{selected_chat}", id, image),
|
||||
name=os.path.join(self.data_dir, "chats", "{selected_chat}", message_id, image),
|
||||
tooltip_text=_("Image")
|
||||
)
|
||||
button.connect("clicked", lambda button, file_path=path: self.preview_file(file_path, 'image', None))
|
||||
@ -728,19 +751,19 @@ Generate a title following these rules:
|
||||
tooltip_text=name,
|
||||
child=button_content
|
||||
)
|
||||
file_path = os.path.join(self.data_dir, "chats", "{selected_chat}", id, name)
|
||||
file_path = os.path.join(self.data_dir, "chats", "{selected_chat}", message_id, name)
|
||||
button.connect("clicked", lambda button, file_path=file_path, file_type=file_type: self.preview_file(file_path, file_type, None))
|
||||
file_container.append(button)
|
||||
message_box.append(file_scroller)
|
||||
|
||||
message_box.append(message_text)
|
||||
overlay = Gtk.Overlay(css_classes=["message"], name=id)
|
||||
overlay = Gtk.Overlay(css_classes=["message"], name=message_id)
|
||||
overlay.set_child(message_box)
|
||||
|
||||
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))
|
||||
regenerate_button.connect('clicked', lambda button, message_id=message_id, bot_message_box=message_box, bot_message_button_container=button_container : self.regenerate_message(message_id, bot_message_box, bot_message_button_container))
|
||||
button_container.append(delete_button)
|
||||
button_container.append(copy_button)
|
||||
button_container.append(regenerate_button if bot else edit_button)
|
||||
@ -947,19 +970,22 @@ Generate a title following these rules:
|
||||
def generate_datetime_format(self, dt:datetime) -> str:
|
||||
date = GLib.DateTime.new(GLib.DateTime.new_now_local().get_timezone(), dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second)
|
||||
current_date = GLib.DateTime.new_now_local()
|
||||
if date.format("%Y/%m/%d") == current_date.format("%Y/%m/%d"): return date.format("%H:%M %p")
|
||||
elif date.format("%Y") == current_date.format("%Y"): return date.format("%b %d, %H:%M %p")
|
||||
else: return date.format("%b %d %Y, %H:%M %p")
|
||||
if date.format("%Y/%m/%d") == current_date.format("%Y/%m/%d"):
|
||||
return date.format("%H:%M %p")
|
||||
elif date.format("%Y") == current_date.format("%Y"):
|
||||
return date.format("%b %d, %H:%M %p")
|
||||
else:
|
||||
return date.format("%b %d %Y, %H:%M %p")
|
||||
|
||||
def update_bot_message(self, data, id):
|
||||
def update_bot_message(self, data, message_id):
|
||||
if self.bot_message is None:
|
||||
self.save_history()
|
||||
sys.exit()
|
||||
vadjustment = self.chat_window.get_vadjustment()
|
||||
if id not in self.chats["chats"][self.chats["selected_chat"]]["messages"] or vadjustment.get_value() + 50 >= vadjustment.get_upper() - vadjustment.get_page_size():
|
||||
if message_id not in self.chats["chats"][self.chats["selected_chat"]]["messages"] or vadjustment.get_value() + 50 >= vadjustment.get_upper() - vadjustment.get_page_size():
|
||||
GLib.idle_add(vadjustment.set_value, vadjustment.get_upper())
|
||||
if 'done' in data and data['done']:
|
||||
formated_date = GLib.markup_escape_text(self.generate_datetime_format(datetime.strptime(self.chats["chats"][self.chats["selected_chat"]]["messages"][id]["date"], '%Y/%m/%d %H:%M:%S')))
|
||||
formated_date = GLib.markup_escape_text(self.generate_datetime_format(datetime.strptime(self.chats["chats"][self.chats["selected_chat"]]["messages"][message_id]["date"], '%Y/%m/%d %H:%M:%S')))
|
||||
text = f"\n\n{self.convert_model_name(data['model'], 0)}\n<small>{formated_date}</small>"
|
||||
GLib.idle_add(self.bot_message.insert_markup, self.bot_message.get_end_iter(), text, len(text.encode('utf-8')))
|
||||
self.save_history()
|
||||
@ -968,11 +994,11 @@ 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 not self.chats["chats"][self.chats["selected_chat"]]["messages"][id]["content"] and self.loading_spinner:
|
||||
if not self.chats["chats"][self.chats["selected_chat"]]["messages"][message_id]["content"] and self.loading_spinner:
|
||||
GLib.idle_add(self.chat_container.remove, self.loading_spinner)
|
||||
self.loading_spinner = None
|
||||
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']
|
||||
self.chats["chats"][self.chats["selected_chat"]]["messages"][message_id]['content'] += data['message']['content']
|
||||
|
||||
def toggle_ui_sensitive(self, status):
|
||||
for element in [self.chat_list_box, self.add_chat_button, self.secondary_menu_button]:
|
||||
@ -982,10 +1008,10 @@ Generate a title following these rules:
|
||||
self.stop_button.set_visible(self.send_button.get_visible())
|
||||
self.send_button.set_visible(not self.send_button.get_visible())
|
||||
|
||||
def run_message(self, messages, model, id):
|
||||
def run_message(self, messages, model, message_id):
|
||||
logger.debug("Running message")
|
||||
self.bot_message_button_container.set_visible(False)
|
||||
self.chats["chats"][self.chats["selected_chat"]]["messages"][id] = {
|
||||
self.chats["chats"][self.chats["selected_chat"]]["messages"][message_id] = {
|
||||
"role": "assistant",
|
||||
"model": model,
|
||||
"date": datetime.now().strftime("%Y/%m/%d %H:%M:%S"),
|
||||
@ -994,8 +1020,9 @@ Generate a title following these rules:
|
||||
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')
|
||||
response = connection_handler.stream_post(f"{connection_handler.url}/api/chat", data=json.dumps({"model": model, "messages": messages}), callback=lambda data, message_id=message_id: self.update_bot_message(data, message_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)
|
||||
@ -1008,7 +1035,7 @@ Generate a title following these rules:
|
||||
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))
|
||||
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.toggle_ui_sensitive, True)
|
||||
@ -1016,7 +1043,7 @@ Generate a title following these rules:
|
||||
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):
|
||||
def regenerate_message(self, message_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,
|
||||
@ -1028,11 +1055,12 @@ Generate a title following these rules:
|
||||
css_classes=["flat"]
|
||||
)
|
||||
self.bot_message = self.bot_message_view.get_buffer()
|
||||
for widget in list(bot_message_box): bot_message_box.remove(widget)
|
||||
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]
|
||||
history = self.convert_history_to_ollama()[:list(self.chats["chats"][self.chats["selected_chat"]]["messages"].keys()).index(message_id)]
|
||||
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),
|
||||
"messages": history,
|
||||
@ -1041,7 +1069,7 @@ Generate a title following these rules:
|
||||
}
|
||||
self.switch_send_stop_button()
|
||||
self.toggle_ui_sensitive(False)
|
||||
thread = threading.Thread(target=self.run_message, args=(data['messages'], data['model'], id))
|
||||
thread = threading.Thread(target=self.run_message, args=(data['messages'], data['model'], message_id))
|
||||
thread.start()
|
||||
|
||||
def pull_model_update(self, data, model_name):
|
||||
@ -1086,7 +1114,8 @@ Generate a title following these rules:
|
||||
GLib.idle_add(self.pulling_model_list_box.set_visible, False)
|
||||
|
||||
def pull_model(self, model):
|
||||
if model in list(self.pulling_models.keys()) or model in self.local_models or ":" not in model: return
|
||||
if model in list(self.pulling_models.keys()) or model in self.local_models or ":" not in model:
|
||||
return
|
||||
logger.info("Pulling model")
|
||||
self.pulling_model_list_box.set_visible(True)
|
||||
#self.pulling_model_list_box.connect('row_selected', lambda list_box, row: dialogs.stop_pull_model(self, row.get_name()) if row else None) #It isn't working for some reason
|
||||
@ -1175,9 +1204,9 @@ Generate a title following these rules:
|
||||
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<small>{formated_date}</small>", message['images'] if 'images' in message else None, message['files'] if 'files' in message else None, id=key)
|
||||
self.show_message(message['content'], False, f"\n\n<small>{formated_date}</small>", 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<small>{formated_date}</small>", id=key)
|
||||
self.show_message(message['content'], True, f"\n\n{self.convert_model_name(message['model'], 0)}\n<small>{formated_date}</small>", message_id=key)
|
||||
self.add_code_blocks()
|
||||
self.bot_message = None
|
||||
|
||||
@ -1187,8 +1216,10 @@ Generate a title following these rules:
|
||||
try:
|
||||
with open(os.path.join(self.data_dir, "chats", "chats.json"), "r", encoding="utf-8") as f:
|
||||
self.chats = json.load(f)
|
||||
if len(list(self.chats["chats"].keys())) == 0: self.chats["chats"][_("New Chat")] = {"messages": {}}
|
||||
if "selected_chat" not in self.chats or self.chats["selected_chat"] not in self.chats["chats"]: self.chats["selected_chat"] = list(self.chats["chats"].keys())[0]
|
||||
if len(list(self.chats["chats"].keys())) == 0:
|
||||
self.chats["chats"][_("New Chat")] = {"messages": {}}
|
||||
if "selected_chat" not in self.chats or self.chats["selected_chat"] not in self.chats["chats"]:
|
||||
self.chats["selected_chat"] = list(self.chats["chats"].keys())[0]
|
||||
if "order" not in self.chats:
|
||||
self.chats["order"] = []
|
||||
for chat_name in self.chats["chats"].keys():
|
||||
@ -1218,7 +1249,7 @@ Generate a title following these rules:
|
||||
chat_name = f"{'.'.join(chat_name.split('.')[:-1])} {i+1}.{chat_name.split('.')[-1]}"
|
||||
break
|
||||
else:
|
||||
if f"{chat_name} {i+1}" not in compare_list:
|
||||
if f"{chat_name} {i+1}" not in compare_list:
|
||||
chat_name = f"{chat_name} {i+1}"
|
||||
break
|
||||
return chat_name
|
||||
@ -1248,7 +1279,8 @@ Generate a title following these rules:
|
||||
def rename_chat(self, old_chat_name, new_chat_name, label_element):
|
||||
logger.info(f"Renaming chat \"{old_chat_name}\" -> \"{new_chat_name}\"")
|
||||
new_chat_name = self.generate_numbered_name(new_chat_name, self.chats["chats"].keys())
|
||||
if self.chats["selected_chat"] == old_chat_name: self.chats["selected_chat"] = new_chat_name
|
||||
if self.chats["selected_chat"] == old_chat_name:
|
||||
self.chats["selected_chat"] = new_chat_name
|
||||
self.chats["chats"][new_chat_name] = self.chats["chats"][old_chat_name]
|
||||
self.chats["order"][self.chats["order"].index(old_chat_name)] = new_chat_name
|
||||
del self.chats["chats"][old_chat_name]
|
||||
@ -1318,9 +1350,12 @@ Generate a title following these rules:
|
||||
gesture.connect("released", self.chat_click_handler)
|
||||
chat_row.add_controller(gesture)
|
||||
|
||||
if append: self.chat_list_box.append(chat_row)
|
||||
else: self.chat_list_box.prepend(chat_row)
|
||||
if select: self.chat_list_box.select_row(chat_row)
|
||||
if append:
|
||||
self.chat_list_box.append(chat_row)
|
||||
else:
|
||||
self.chat_list_box.prepend(chat_row)
|
||||
if select:
|
||||
self.chat_list_box.select_row(chat_row)
|
||||
|
||||
def update_chat_list(self):
|
||||
self.chat_list_box.remove_all()
|
||||
@ -1346,8 +1381,10 @@ Generate a title following these rules:
|
||||
connection_handler.bearer_token = None
|
||||
connection_handler.url = f"http://127.0.0.1:{local_instance.port}"
|
||||
local_instance.start()
|
||||
if self.verify_connection() == False: self.connection_error()
|
||||
else: self.remote_connection_switch.set_active(False)
|
||||
if self.verify_connection() == False:
|
||||
self.connection_error()
|
||||
else:
|
||||
self.remote_connection_switch.set_active(False)
|
||||
|
||||
def connection_error(self):
|
||||
logger.error("Connection error")
|
||||
@ -1365,13 +1402,16 @@ Generate a title following these rules:
|
||||
if self.run_remote:
|
||||
connection_handler.bearer_token = self.remote_bearer_token
|
||||
connection_handler.url = self.remote_url
|
||||
if self.verify_connection() == False: self.connection_error()
|
||||
else: local_instance.stop()
|
||||
if self.verify_connection() == False:
|
||||
self.connection_error()
|
||||
else:
|
||||
local_instance.stop()
|
||||
else:
|
||||
connection_handler.bearer_token = None
|
||||
connection_handler.url = f"http://127.0.0.1:{local_instance.port}"
|
||||
local_instance.start()
|
||||
if self.verify_connection() == False: self.connection_error()
|
||||
if self.verify_connection() == False:
|
||||
self.connection_error()
|
||||
|
||||
def on_replace_contents(self, file, result):
|
||||
file.replace_contents_finish(result)
|
||||
@ -1379,7 +1419,8 @@ Generate a title following these rules:
|
||||
|
||||
def on_export_chat(self, file_dialog, result, chat_name):
|
||||
file = file_dialog.save_finish(result)
|
||||
if not file: return
|
||||
if not file:
|
||||
return
|
||||
json_data = json.dumps({chat_name: self.chats["chats"][chat_name]}, indent=4).encode("UTF-8")
|
||||
|
||||
with tempfile.TemporaryDirectory() as temp_dir:
|
||||
@ -1413,7 +1454,8 @@ Generate a title following these rules:
|
||||
|
||||
def on_chat_imported(self, file_dialog, result):
|
||||
file = file_dialog.open_finish(result)
|
||||
if not file: return
|
||||
if not file:
|
||||
return
|
||||
stream = file.read(None)
|
||||
data_stream = Gio.DataInputStream.new(stream)
|
||||
tar_content = data_stream.read_bytes(1024 * 1024, None)
|
||||
@ -1483,7 +1525,8 @@ Generate a title following these rules:
|
||||
return f.read()
|
||||
elif file_type == 'pdf':
|
||||
reader = PdfReader(file_path)
|
||||
if len(reader.pages) == 0: return None
|
||||
if len(reader.pages) == 0:
|
||||
return None
|
||||
text = ""
|
||||
for i, page in enumerate(reader.pages):
|
||||
text += f"\n- Page {i}\n{page.extract_text(extraction_mode='layout', layout_mode_space_vertically=False)}\n"
|
||||
@ -1494,7 +1537,8 @@ Generate a title following these rules:
|
||||
button = self.attachments[name]['button']
|
||||
button.get_parent().remove(button)
|
||||
del self.attachments[name]
|
||||
if len(self.attachments) == 0: self.attachment_box.set_visible(False)
|
||||
if len(self.attachments) == 0:
|
||||
self.attachment_box.set_visible(False)
|
||||
|
||||
def attach_file(self, file_path, file_type):
|
||||
logger.debug(f"Attaching file: {file_path}")
|
||||
@ -1652,7 +1696,8 @@ Generate a title following these rules:
|
||||
self.seed_spin.set_value(self.model_tweaks['seed'])
|
||||
self.keep_alive_spin.set_value(self.model_tweaks['keep_alive'])
|
||||
#Overrides
|
||||
if "ollama_overrides" in data: local_instance.overrides = data['ollama_overrides']
|
||||
if "ollama_overrides" in data:
|
||||
local_instance.overrides = data['ollama_overrides']
|
||||
for element in [
|
||||
self.override_HSA_OVERRIDE_GFX_VERSION,
|
||||
self.override_CUDA_VISIBLE_DEVICES,
|
||||
@ -1678,7 +1723,8 @@ Generate a title following these rules:
|
||||
local_instance.start()
|
||||
connection_handler.url = f"http://127.0.0.1:{local_instance.port}"
|
||||
self.welcome_dialog.present(self)
|
||||
if self.verify_connection() is False: self.connection_error()
|
||||
if self.verify_connection() is False:
|
||||
self.connection_error()
|
||||
self.update_list_available_models()
|
||||
self.load_history()
|
||||
self.update_chat_list()
|
||||
|
Loading…
x
Reference in New Issue
Block a user