Add logging (#142)
* Configure logger * Add logging at various points * Add logging to window verify_if_image_can_be_used
This commit is contained in:
parent
c8ace20e60
commit
92f1b62f8c
@ -1,6 +1,10 @@
|
||||
# local_instance.py
|
||||
import subprocess, os, threading
|
||||
from time import sleep
|
||||
from logging import getLogger
|
||||
|
||||
|
||||
logger = getLogger(__name__)
|
||||
|
||||
instance = None
|
||||
port = 11435
|
||||
@ -13,19 +17,22 @@ def start():
|
||||
params["OLLAMA_HOST"] = f"127.0.0.1:{port}" # You can't change this directly sorry :3
|
||||
params["HOME"] = data_dir
|
||||
instance = subprocess.Popen(["/app/bin/ollama", "serve"], env={**os.environ, **params}, stderr=subprocess.PIPE, text=True)
|
||||
print("Starting Alpaca's Ollama instance...")
|
||||
logger.info("Starting Alpaca's Ollama instance...")
|
||||
logger.debug(params)
|
||||
sleep(1)
|
||||
print("Started Alpaca's Ollama instance")
|
||||
logger.info("Started Alpaca's Ollama instance")
|
||||
|
||||
def stop():
|
||||
logger.info("Stopping Alpaca's Ollama instance")
|
||||
global instance
|
||||
if instance:
|
||||
instance.terminate()
|
||||
instance.wait()
|
||||
instance = None
|
||||
print("Stopped Alpaca's Ollama instance")
|
||||
logger.info("Stopped Alpaca's Ollama instance")
|
||||
|
||||
def reset():
|
||||
logger.info("Resetting Alpaca's Ollama instance")
|
||||
stop()
|
||||
sleep(1)
|
||||
start()
|
||||
|
13
src/main.py
13
src/main.py
@ -18,6 +18,7 @@
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
import sys
|
||||
import logging
|
||||
import gi
|
||||
|
||||
gi.require_version('Gtk', '4.0')
|
||||
@ -26,6 +27,10 @@ gi.require_version('Adw', '1')
|
||||
from gi.repository import Gtk, Gio, Adw, GLib
|
||||
from .window import AlpacaWindow
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class AlpacaApplication(Adw.Application):
|
||||
"""The main application singleton class."""
|
||||
|
||||
@ -35,6 +40,7 @@ class AlpacaApplication(Adw.Application):
|
||||
self.create_action('quit', lambda *_: self.quit(), ['<primary>q'])
|
||||
self.create_action('preferences', lambda *_: AlpacaWindow.show_preferences_dialog(self.props.active_window), ['<primary>p'])
|
||||
self.create_action('about', self.on_about_action)
|
||||
self.version = '0.9.6.1'
|
||||
|
||||
def do_activate(self):
|
||||
win = self.props.active_window
|
||||
@ -47,7 +53,7 @@ class AlpacaApplication(Adw.Application):
|
||||
application_name='Alpaca',
|
||||
application_icon='com.jeffser.Alpaca',
|
||||
developer_name='Jeffry Samuel Eduarte Rojas',
|
||||
version='0.9.6.1',
|
||||
version=self.version,
|
||||
developers=['Jeffser https://jeffser.com'],
|
||||
designers=['Jeffser https://jeffser.com', 'Tobias Bernard (App Icon) https://tobiasbernard.com/'],
|
||||
translator_credits='Alex K (Russian) https://github.com/alexkdeveloper\nJeffser (Spanish) https://jeffser.com\nDaimar Stein (Brazilian Portuguese) https://github.com/not-a-dev-stein\nLouis Chauvet-Villaret (French) https://github.com/loulou64490\nCounterFlow64 (Norwegian) https://github.com/CounterFlow64',
|
||||
@ -64,5 +70,10 @@ class AlpacaApplication(Adw.Application):
|
||||
|
||||
|
||||
def main(version):
|
||||
logging.basicConfig(
|
||||
format="%(levelname)s\t[%(filename)s | %(funcName)s] %(message)s",
|
||||
level=logging.INFO
|
||||
)
|
||||
app = AlpacaApplication()
|
||||
logger.info(f"Alpaca version: {app.version}")
|
||||
return app.run(sys.argv)
|
||||
|
@ -29,6 +29,10 @@ from pypdf import PdfReader
|
||||
from datetime import datetime
|
||||
from . import dialogs, local_instance, connection_handler, available_models_descriptions
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@Gtk.Template(resource_path='/com/jeffser/Alpaca/window.ui')
|
||||
class AlpacaWindow(Adw.ApplicationWindow):
|
||||
config_dir = os.getenv("XDG_CONFIG_HOME")
|
||||
@ -45,10 +49,6 @@ class AlpacaWindow(Adw.ApplicationWindow):
|
||||
gettext.textdomain('com.jeffser.Alpaca')
|
||||
_ = gettext.gettext
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
logging.basicConfig(format="%(levelname)s\t[%(filename)s | %(funcName)s] %(message)s")
|
||||
logger.setLevel(logging.ERROR)
|
||||
|
||||
#Variables
|
||||
editing_message = None
|
||||
available_models = None
|
||||
@ -133,6 +133,7 @@ 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
|
||||
selected = self.model_drop_down.get_selected_item().get_string().split(" (")[0].lower()
|
||||
if selected in [key for key, value in self.available_models.items() if value["image"]]:
|
||||
@ -246,11 +247,13 @@ class AlpacaWindow(Adw.ApplicationWindow):
|
||||
|
||||
@Gtk.Template.Callback()
|
||||
def manage_models_button_activate(self, button=None):
|
||||
logger.debug(f"Managing models")
|
||||
self.update_list_local_models()
|
||||
self.manage_models_dialog.present(self)
|
||||
|
||||
@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 == carousel.get_n_pages()-1:
|
||||
@ -274,6 +277,7 @@ class AlpacaWindow(Adw.ApplicationWindow):
|
||||
|
||||
@Gtk.Template.Callback()
|
||||
def chat_changed(self, listbox, row):
|
||||
logger.debug("Changing selected chat")
|
||||
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()
|
||||
@ -287,6 +291,7 @@ class AlpacaWindow(Adw.ApplicationWindow):
|
||||
@Gtk.Template.Callback()
|
||||
def change_remote_url(self, entry):
|
||||
self.remote_url = entry.get_text()
|
||||
logger.debug(f"Changing remote url: {self.remote_url}")
|
||||
if self.run_remote:
|
||||
connection_handler.url = self.remote_url
|
||||
if self.verify_connection() == False:
|
||||
@ -319,9 +324,9 @@ class AlpacaWindow(Adw.ApplicationWindow):
|
||||
@Gtk.Template.Callback()
|
||||
def closing_app(self, user_data):
|
||||
if self.get_hide_on_close():
|
||||
print("Hiding app...")
|
||||
logger.info("Hiding app...")
|
||||
else:
|
||||
print("Closing app...")
|
||||
logger.info("Closing app...")
|
||||
local_instance.stop()
|
||||
|
||||
@Gtk.Template.Callback()
|
||||
@ -441,6 +446,7 @@ class AlpacaWindow(Adw.ApplicationWindow):
|
||||
|
||||
|
||||
def show_toast(self, message:str, overlay):
|
||||
logger.info(message)
|
||||
toast = Adw.Toast(
|
||||
title=message,
|
||||
timeout=2
|
||||
@ -449,12 +455,14 @@ class AlpacaWindow(Adw.ApplicationWindow):
|
||||
|
||||
def show_notification(self, title:str, body:str, icon:Gio.ThemedIcon=None):
|
||||
if not self.is_active():
|
||||
logger.info(f"{title}, {body}")
|
||||
notification = Gio.Notification.new(title)
|
||||
notification.set_body(body)
|
||||
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]
|
||||
self.chat_container.remove(message_element)
|
||||
@ -463,12 +471,14 @@ class AlpacaWindow(Adw.ApplicationWindow):
|
||||
self.save_history()
|
||||
|
||||
def copy_message(self, message_element):
|
||||
logger.debug("Copying 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"])
|
||||
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()
|
||||
|
||||
button_container.set_visible(False)
|
||||
@ -489,6 +499,7 @@ class AlpacaWindow(Adw.ApplicationWindow):
|
||||
self.editing_message = {"text_view": text_view, "id": id, "button_container": button_container, "footer": footer}
|
||||
|
||||
def preview_file(self, file_path, file_type, presend_name):
|
||||
logger.debug(f"Previewing file: {file_path}")
|
||||
file_path = file_path.replace("{selected_chat}", self.chats["selected_chat"])
|
||||
content = self.get_content_of_file(file_path, file_type)
|
||||
if presend_name:
|
||||
@ -548,6 +559,7 @@ class AlpacaWindow(Adw.ApplicationWindow):
|
||||
return messages
|
||||
|
||||
def generate_chat_title(self, message, label_element):
|
||||
logger.debug("Generating chat title")
|
||||
prompt = f"""
|
||||
Generate a title following these rules:
|
||||
- The title should be based on the prompt at the end
|
||||
@ -728,6 +740,7 @@ Generate a title following these rules:
|
||||
self.bot_message_button_container = button_container
|
||||
|
||||
def update_list_local_models(self):
|
||||
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):
|
||||
@ -874,6 +887,7 @@ Generate a title following these rules:
|
||||
self.bot_message_box = None
|
||||
|
||||
def on_theme_changed(self, manager, dark, buffer):
|
||||
logger.debug("Theme changed")
|
||||
if manager.get_dark():
|
||||
source_style = GtkSource.StyleSchemeManager.get_default().get_scheme('Adwaita-dark')
|
||||
else:
|
||||
@ -881,6 +895,7 @@ Generate a title following these rules:
|
||||
buffer.set_style_scheme(source_style)
|
||||
|
||||
def on_copy_code_clicked(self, btn, text_buffer):
|
||||
logger.debug("Copying code")
|
||||
clipboard = Gdk.Display().get_default().get_clipboard()
|
||||
start = text_buffer.get_start_iter()
|
||||
end = text_buffer.get_end_iter()
|
||||
@ -933,6 +948,7 @@ Generate a title following these rules:
|
||||
self.send_button.set_visible(not self.send_button.get_visible())
|
||||
|
||||
def run_message(self, messages, model, id):
|
||||
logger.debug("Running message")
|
||||
self.bot_message_button_container.set_visible(False)
|
||||
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))
|
||||
GLib.idle_add(self.add_code_blocks)
|
||||
@ -980,6 +996,7 @@ Generate a title following these rules:
|
||||
GLib.idle_add(self.pulling_model_list_box.set_visible, False)
|
||||
|
||||
def pull_model(self, model):
|
||||
logger.info("Pulling model")
|
||||
if model in list(self.pulling_models.keys()) or model in self.local_models:
|
||||
return
|
||||
self.pulling_model_list_box.set_visible(True)
|
||||
@ -1013,11 +1030,13 @@ Generate a title following these rules:
|
||||
thread.start()
|
||||
|
||||
def confirm_pull_model(self, model_name):
|
||||
logger.debug("Confirming pull model")
|
||||
self.navigation_view_manage_models.pop()
|
||||
self.model_tag_list_box.unselect_all()
|
||||
self.pull_model(model_name)
|
||||
|
||||
def list_available_model_tags(self, model_name):
|
||||
logger.debug("Listing available model tags")
|
||||
self.navigation_view_manage_models.push_by_tag('model_tags_page')
|
||||
self.navigation_view_manage_models.find_page('model_tags_page').set_title(model_name.capitalize())
|
||||
self.model_link_button.set_name(self.available_models[model_name]['url'])
|
||||
@ -1037,6 +1056,7 @@ Generate a title following these rules:
|
||||
self.model_tag_list_box.append(tag_row)
|
||||
|
||||
def update_list_available_models(self):
|
||||
logger.debug("Updating list of available models")
|
||||
self.available_model_list_box.connect('row_selected', lambda list_box, row: self.list_available_model_tags(row.get_name()) if row else None)
|
||||
self.available_model_list_box.remove_all()
|
||||
for name, model_info in self.available_models.items():
|
||||
@ -1055,6 +1075,7 @@ Generate a title following these rules:
|
||||
self.available_model_list_box.append(model)
|
||||
|
||||
def save_history(self):
|
||||
logger.debug("Saving history")
|
||||
with open(os.path.join(self.data_dir, "chats", "chats.json"), "w+") as f:
|
||||
json.dump(self.chats, f, indent=4)
|
||||
|
||||
@ -1071,6 +1092,7 @@ Generate a title following these rules:
|
||||
self.bot_message = None
|
||||
|
||||
def load_history(self):
|
||||
logger.debug("Loading history")
|
||||
if os.path.exists(os.path.join(self.data_dir, "chats", "chats.json")):
|
||||
try:
|
||||
with open(os.path.join(self.data_dir, "chats", "chats.json"), "r") as f:
|
||||
@ -1108,11 +1130,13 @@ Generate a title following these rules:
|
||||
return f"{datetime.today().strftime('%Y%m%d%H%M%S%f')}{uuid.uuid4().hex}"
|
||||
|
||||
def clear_chat(self):
|
||||
logger.info("Clearing chat")
|
||||
for widget in list(self.chat_container): self.chat_container.remove(widget)
|
||||
self.chats["chats"][self.chats["selected_chat"]]["messages"] = []
|
||||
self.save_history()
|
||||
|
||||
def delete_chat(self, chat_name):
|
||||
logger.info("Deleting chat")
|
||||
del self.chats['chats'][chat_name]
|
||||
self.chats['order'].remove(chat_name)
|
||||
if os.path.exists(os.path.join(self.data_dir, "chats", chat_name)):
|
||||
@ -1125,6 +1149,7 @@ Generate a title following these rules:
|
||||
self.chat_list_box.select_row(self.chat_list_box.get_row_at_index(0))
|
||||
|
||||
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
|
||||
self.chats["chats"][new_chat_name] = self.chats["chats"][old_chat_name]
|
||||
@ -1145,10 +1170,12 @@ Generate a title following these rules:
|
||||
self.new_chat_element(chat_name, True, False)
|
||||
|
||||
def stop_pull_model(self, model_name):
|
||||
logger.debug("Stopping model pull")
|
||||
self.pulling_models[model_name]['overlay'].get_parent().get_parent().remove(self.pulling_models[model_name]['overlay'].get_parent())
|
||||
del self.pulling_models[model_name]
|
||||
|
||||
def delete_model(self, model_name):
|
||||
logger.debug("Deleting model")
|
||||
response = connection_handler.simple_delete(f"{connection_handler.url}/api/delete", data={"name": model_name})
|
||||
self.update_list_local_models()
|
||||
if response.status_code == 200:
|
||||
@ -1205,15 +1232,18 @@ Generate a title following these rules:
|
||||
self.new_chat_element(name, self.chats["selected_chat"] == name, True)
|
||||
|
||||
def show_preferences_dialog(self):
|
||||
logger.debug("Showing preferences dialog")
|
||||
self.preferences_dialog.present(self)
|
||||
|
||||
def connect_remote(self, url):
|
||||
logger.debug(f"Connecting to remote: {url}")
|
||||
connection_handler.url = url
|
||||
self.remote_url = connection_handler.url
|
||||
self.remote_connection_entry.set_text(self.remote_url)
|
||||
if self.verify_connection() == False: self.connection_error()
|
||||
|
||||
def connect_local(self):
|
||||
logger.debug("Connecting to Alpaca's Ollama instance")
|
||||
self.run_remote = False
|
||||
connection_handler.bearer_token = None
|
||||
connection_handler.url = f"http://127.0.0.1:{local_instance.port}"
|
||||
@ -1222,6 +1252,7 @@ Generate a title following these rules:
|
||||
else: self.remote_connection_switch.set_active(False)
|
||||
|
||||
def connection_error(self):
|
||||
logger.error("Connection error")
|
||||
if self.run_remote:
|
||||
dialogs.reconnect_remote(self, connection_handler.url)
|
||||
else:
|
||||
@ -1229,6 +1260,7 @@ Generate a title following these rules:
|
||||
self.show_toast(_("There was an error with the local Ollama instance, so it has been reset"), self.main_overlay)
|
||||
|
||||
def connection_switched(self):
|
||||
logger.debug("Connection switched")
|
||||
new_value = self.remote_connection_switch.get_active()
|
||||
if new_value != self.run_remote:
|
||||
self.run_remote = new_value
|
||||
@ -1277,6 +1309,7 @@ Generate a title following these rules:
|
||||
)
|
||||
|
||||
def export_chat(self, chat_name):
|
||||
logger.info("Exporting chat")
|
||||
file_dialog = Gtk.FileDialog(initial_name=f"{chat_name}.tar")
|
||||
file_dialog.save(parent=self, cancellable=None, callback=lambda file_dialog, result, chat_name=chat_name: self.on_export_chat(file_dialog, result, chat_name))
|
||||
|
||||
@ -1316,10 +1349,12 @@ Generate a title following these rules:
|
||||
self.show_toast(_("Chat imported successfully"), self.main_overlay)
|
||||
|
||||
def import_chat(self):
|
||||
logger.info("Importing chat")
|
||||
file_dialog = Gtk.FileDialog(default_filter=self.file_filter_tar)
|
||||
file_dialog.open(self, None, self.on_chat_imported)
|
||||
|
||||
def switch_run_on_background(self):
|
||||
logger.debug("Switching run on background")
|
||||
self.run_on_background = self.background_switch.get_active()
|
||||
self.set_hide_on_close(self.run_on_background)
|
||||
self.verify_connection()
|
||||
@ -1357,12 +1392,14 @@ Generate a title following these rules:
|
||||
return text
|
||||
|
||||
def remove_attached_file(self, name):
|
||||
logger.debug("Removing attached file")
|
||||
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)
|
||||
|
||||
def attach_file(self, file_path, file_type):
|
||||
logger.debug(f"Attaching file: {file_path}")
|
||||
file_name = self.generate_numbered_name(os.path.basename(file_path), self.attachments.keys())
|
||||
content = self.get_content_of_file(file_path, file_type)
|
||||
if content:
|
||||
@ -1446,6 +1483,7 @@ Generate a title following these rules:
|
||||
except Exception as e: 'huh'
|
||||
|
||||
def on_clipboard_paste(self, textview):
|
||||
logger.debug("Pasting from clipboard")
|
||||
clipboard = Gdk.Display.get_default().get_clipboard()
|
||||
clipboard.read_text_async(None, self.cb_text_received)
|
||||
clipboard.read_texture_async(None, self.cb_image_received)
|
||||
|
Loading…
x
Reference in New Issue
Block a user