Better translation support, adding dialogs
This commit is contained in:
parent
15fdd0ae1a
commit
6fbf6e139b
116
src/window.py
116
src/window.py
@ -21,7 +21,7 @@ import gi
|
|||||||
gi.require_version('GtkSource', '5')
|
gi.require_version('GtkSource', '5')
|
||||||
gi.require_version('GdkPixbuf', '2.0')
|
gi.require_version('GdkPixbuf', '2.0')
|
||||||
from gi.repository import Adw, Gtk, Gdk, GLib, GtkSource, Gio, GdkPixbuf
|
from gi.repository import Adw, Gtk, Gdk, GLib, GtkSource, Gio, GdkPixbuf
|
||||||
import json, requests, threading, os, re, base64, sys
|
import json, requests, threading, os, re, base64, sys, gettext, locale
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
@ -32,11 +32,19 @@ from .available_models import available_models
|
|||||||
class AlpacaWindow(Adw.ApplicationWindow):
|
class AlpacaWindow(Adw.ApplicationWindow):
|
||||||
config_dir = os.path.join(os.getenv("XDG_CONFIG_HOME"), "/", os.path.expanduser("~/.var/app/com.jeffser.Alpaca/config"))
|
config_dir = os.path.join(os.getenv("XDG_CONFIG_HOME"), "/", os.path.expanduser("~/.var/app/com.jeffser.Alpaca/config"))
|
||||||
__gtype_name__ = 'AlpacaWindow'
|
__gtype_name__ = 'AlpacaWindow'
|
||||||
|
|
||||||
|
localedir = os.path.join(os.path.abspath(os.path.dirname(__file__)), 'locale')
|
||||||
|
|
||||||
|
locale.setlocale(locale.LC_ALL, '')
|
||||||
|
gettext.bindtextdomain('com.jeffser.Alpaca', localedir)
|
||||||
|
gettext.textdomain('com.jeffser.Alpaca')
|
||||||
|
_ = gettext.gettext
|
||||||
|
|
||||||
#Variables
|
#Variables
|
||||||
ollama_url = None
|
ollama_url = None
|
||||||
local_models = []
|
local_models = []
|
||||||
pulling_models = {}
|
pulling_models = {}
|
||||||
chats = {"chats": {"New Chat": {"messages": []}}, "selected_chat": "New Chat"}
|
chats = {"chats": {_("New Chat"): {"messages": []}}, "selected_chat": "New Chat"}
|
||||||
attached_image = {"path": None, "base64": None}
|
attached_image = {"path": None, "base64": None}
|
||||||
first_time_setup = False
|
first_time_setup = False
|
||||||
|
|
||||||
@ -75,21 +83,21 @@ class AlpacaWindow(Adw.ApplicationWindow):
|
|||||||
|
|
||||||
toast_messages = {
|
toast_messages = {
|
||||||
"error": [
|
"error": [
|
||||||
"An error occurred",
|
_("An error occurred"),
|
||||||
"Failed to connect to server",
|
_("Failed to connect to server"),
|
||||||
"Could not list local models",
|
_("Could not list local models"),
|
||||||
"Could not delete model",
|
_("Could not delete model"),
|
||||||
"Could not pull model",
|
_("Could not pull model"),
|
||||||
"Cannot open image",
|
_("Cannot open image"),
|
||||||
"Cannot delete chat because it's the only one left"
|
_("Cannot delete chat because it's the only one left")
|
||||||
],
|
],
|
||||||
"info": [
|
"info": [
|
||||||
"Please select a model before chatting",
|
_("Please select a model before chatting"),
|
||||||
"Chat cannot be cleared while receiving a message"
|
_("Chat cannot be cleared while receiving a message")
|
||||||
],
|
],
|
||||||
"good": [
|
"good": [
|
||||||
"Model deleted successfully",
|
_("Model deleted successfully"),
|
||||||
"Model pulled successfully"
|
_("Model pulled successfully")
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -407,13 +415,13 @@ class AlpacaWindow(Adw.ApplicationWindow):
|
|||||||
response = stream_post(f"{self.ollama_url}/api/pull", data=json.dumps(data), callback=lambda data, model_name=f"{model_name}:{tag}": self.pull_model_update(data, model_name))
|
response = stream_post(f"{self.ollama_url}/api/pull", data=json.dumps(data), callback=lambda data, model_name=f"{model_name}:{tag}": self.pull_model_update(data, model_name))
|
||||||
GLib.idle_add(self.update_list_local_models)
|
GLib.idle_add(self.update_list_local_models)
|
||||||
if response['status'] == 'ok':
|
if response['status'] == 'ok':
|
||||||
GLib.idle_add(self.show_notification, "Task Complete", f"Model '{model_name}:{tag}' pulled successfully.", True, Gio.ThemedIcon.new("emblem-ok-symbolic"))
|
GLib.idle_add(self.show_notification, _("Task Complete"), _("Model '{}' pulled successfully.").format(f"{model_name}:{tag}"), True, Gio.ThemedIcon.new("emblem-ok-symbolic"))
|
||||||
GLib.idle_add(self.show_toast, "good", 1, self.manage_models_overlay)
|
GLib.idle_add(self.show_toast, "good", 1, self.manage_models_overlay)
|
||||||
GLib.idle_add(self.pulling_models[f"{model_name}:{tag}"].get_parent().remove, self.pulling_models[f"{model_name}:{tag}"])
|
GLib.idle_add(self.pulling_models[f"{model_name}:{tag}"].get_parent().remove, self.pulling_models[f"{model_name}:{tag}"])
|
||||||
del self.pulling_models[f"{model_name}:{tag}"]
|
del self.pulling_models[f"{model_name}:{tag}"]
|
||||||
|
|
||||||
else:
|
else:
|
||||||
GLib.idle_add(self.show_notification, "Pull Model Error", f"Failed to pull model '{model_name}:{tag}' due to network error.", True, Gio.ThemedIcon.new("dialog-error-symbolic"))
|
GLib.idle_add(self.show_notification, _("Pull Model Error"), _("Failed to pull model '{}' due to network error.").format(f"{model_name}:{tag}"), True, Gio.ThemedIcon.new("dialog-error-symbolic"))
|
||||||
GLib.idle_add(self.show_toast, "error", 4, self.connection_overlay)
|
GLib.idle_add(self.show_toast, "error", 4, self.connection_overlay)
|
||||||
GLib.idle_add(self.manage_models_dialog.close)
|
GLib.idle_add(self.manage_models_dialog.close)
|
||||||
GLib.idle_add(self.show_connection_dialog, True)
|
GLib.idle_add(self.show_connection_dialog, True)
|
||||||
@ -425,12 +433,12 @@ class AlpacaWindow(Adw.ApplicationWindow):
|
|||||||
|
|
||||||
def stop_pull_model_dialog(self, model_name):
|
def stop_pull_model_dialog(self, model_name):
|
||||||
dialog = Adw.AlertDialog(
|
dialog = Adw.AlertDialog(
|
||||||
heading="Stop Model",
|
heading=_("Stop Model"),
|
||||||
body=f"Are you sure you want to stop pulling '{model_name}'?",
|
body=_("Are you sure you want to stop pulling '{}'?").format(model_name),
|
||||||
close_response="cancel"
|
close_response="cancel"
|
||||||
)
|
)
|
||||||
dialog.add_response("cancel", "Cancel")
|
dialog.add_response("cancel", _("Cancel"))
|
||||||
dialog.add_response("stop", "Stop")
|
dialog.add_response("stop", _("Stop"))
|
||||||
dialog.set_response_appearance("stop", Adw.ResponseAppearance.DESTRUCTIVE)
|
dialog.set_response_appearance("stop", Adw.ResponseAppearance.DESTRUCTIVE)
|
||||||
dialog.choose(
|
dialog.choose(
|
||||||
parent = self.manage_models_dialog,
|
parent = self.manage_models_dialog,
|
||||||
@ -463,12 +471,12 @@ class AlpacaWindow(Adw.ApplicationWindow):
|
|||||||
|
|
||||||
def model_delete_button_activate(self, model_name):
|
def model_delete_button_activate(self, model_name):
|
||||||
dialog = Adw.AlertDialog(
|
dialog = Adw.AlertDialog(
|
||||||
heading="Delete Model",
|
heading=_("Delete Model"),
|
||||||
body=f"Are you sure you want to delete '{model_name}'?",
|
body=_("Are you sure you want to delete '{}'?").format(model_name),
|
||||||
close_response="cancel"
|
close_response="cancel"
|
||||||
)
|
)
|
||||||
dialog.add_response("cancel", "Cancel")
|
dialog.add_response("cancel", _("Cancel"))
|
||||||
dialog.add_response("delete", "Delete")
|
dialog.add_response("delete", _("Delete"))
|
||||||
dialog.set_response_appearance("delete", Adw.ResponseAppearance.DESTRUCTIVE)
|
dialog.set_response_appearance("delete", Adw.ResponseAppearance.DESTRUCTIVE)
|
||||||
dialog.choose(
|
dialog.choose(
|
||||||
parent = self.manage_models_dialog,
|
parent = self.manage_models_dialog,
|
||||||
@ -485,13 +493,13 @@ class AlpacaWindow(Adw.ApplicationWindow):
|
|||||||
model=tag_list
|
model=tag_list
|
||||||
)
|
)
|
||||||
dialog = Adw.AlertDialog(
|
dialog = Adw.AlertDialog(
|
||||||
heading="Pull Model",
|
heading=_("Pull Model"),
|
||||||
body=f"Please select a tag to pull '{model_name}'",
|
body=_("Please select a tag to pull '{}'").format(model_name),
|
||||||
extra_child=tag_drop_down,
|
extra_child=tag_drop_down,
|
||||||
close_response="cancel"
|
close_response="cancel"
|
||||||
)
|
)
|
||||||
dialog.add_response("cancel", "Cancel")
|
dialog.add_response("cancel", _("Cancel"))
|
||||||
dialog.add_response("pull", "Pull")
|
dialog.add_response("pull", _("Pull"))
|
||||||
dialog.set_response_appearance("pull", Adw.ResponseAppearance.SUGGESTED)
|
dialog.set_response_appearance("pull", Adw.ResponseAppearance.SUGGESTED)
|
||||||
dialog.choose(
|
dialog.choose(
|
||||||
parent = self.manage_models_dialog,
|
parent = self.manage_models_dialog,
|
||||||
@ -551,7 +559,7 @@ class AlpacaWindow(Adw.ApplicationWindow):
|
|||||||
self.chats["chats"][self.chats["selected_chat"]]["messages"] = []
|
self.chats["chats"][self.chats["selected_chat"]]["messages"] = []
|
||||||
|
|
||||||
def clear_chat_dialog_response(self, dialog, task):
|
def clear_chat_dialog_response(self, dialog, task):
|
||||||
if dialog.choose_finish(task) == "empty":
|
if dialog.choose_finish(task) == "clear":
|
||||||
self.clear_chat()
|
self.clear_chat()
|
||||||
self.save_history()
|
self.save_history()
|
||||||
|
|
||||||
@ -560,13 +568,13 @@ class AlpacaWindow(Adw.ApplicationWindow):
|
|||||||
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 Chat",
|
heading=_("Clear Chat"),
|
||||||
body=f"Are you sure you want to clear the chat?",
|
body=_("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"))
|
||||||
dialog.add_response("empty", "Empty")
|
dialog.add_response("clear", _("Clear"))
|
||||||
dialog.set_response_appearance("empty", Adw.ResponseAppearance.DESTRUCTIVE)
|
dialog.set_response_appearance("clear", Adw.ResponseAppearance.DESTRUCTIVE)
|
||||||
dialog.choose(
|
dialog.choose(
|
||||||
parent = self,
|
parent = self,
|
||||||
cancellable = None,
|
cancellable = None,
|
||||||
@ -621,13 +629,13 @@ class AlpacaWindow(Adw.ApplicationWindow):
|
|||||||
else: self.first_time_setup = False
|
else: self.first_time_setup = False
|
||||||
return
|
return
|
||||||
dialog = Adw.AlertDialog(
|
dialog = Adw.AlertDialog(
|
||||||
heading=f"Save Changes?",
|
heading=_("Save Changes?"),
|
||||||
body=f"Do you want to save the URL change?",
|
body=_("Do you want to save the URL change?"),
|
||||||
close_response="cancel"
|
close_response="cancel"
|
||||||
)
|
)
|
||||||
dialog.add_response("cancel", "Cancel")
|
dialog.add_response("cancel", _("Cancel"))
|
||||||
dialog.add_response("discard", "Discard")
|
dialog.add_response("discard", _("Discard"))
|
||||||
dialog.add_response("save", "Save")
|
dialog.add_response("save", _("Save"))
|
||||||
dialog.set_response_appearance("discard", Adw.ResponseAppearance.DESTRUCTIVE)
|
dialog.set_response_appearance("discard", Adw.ResponseAppearance.DESTRUCTIVE)
|
||||||
dialog.set_response_appearance("save", Adw.ResponseAppearance.SUGGESTED)
|
dialog.set_response_appearance("save", Adw.ResponseAppearance.SUGGESTED)
|
||||||
dialog.choose(
|
dialog.choose(
|
||||||
@ -641,8 +649,6 @@ class AlpacaWindow(Adw.ApplicationWindow):
|
|||||||
except: return
|
except: return
|
||||||
try:
|
try:
|
||||||
self.attached_image["path"] = file.get_path()
|
self.attached_image["path"] = file.get_path()
|
||||||
'''with open(self.attached_image["path"], "rb") as image_file:
|
|
||||||
self.attached_image["base64"] = base64.b64encode(image_file.read()).decode("utf-8")'''
|
|
||||||
with Image.open(self.attached_image["path"]) as img:
|
with Image.open(self.attached_image["path"]) as img:
|
||||||
width, height = img.size
|
width, height = img.size
|
||||||
max_size = 240
|
max_size = 240
|
||||||
@ -672,12 +678,12 @@ class AlpacaWindow(Adw.ApplicationWindow):
|
|||||||
def open_image(self, button):
|
def open_image(self, button):
|
||||||
if "destructive-action" in button.get_css_classes():
|
if "destructive-action" in button.get_css_classes():
|
||||||
dialog = Adw.AlertDialog(
|
dialog = Adw.AlertDialog(
|
||||||
heading=f"Remove Image?",
|
heading=_("Remove Image?"),
|
||||||
body=f"Are you sure you want to remove image?",
|
body=_("Are you sure you want to remove image?"),
|
||||||
close_response="cancel"
|
close_response="cancel"
|
||||||
)
|
)
|
||||||
dialog.add_response("cancel", "Cancel")
|
dialog.add_response("cancel", _("Cancel"))
|
||||||
dialog.add_response("remove", "Remove")
|
dialog.add_response("remove", _("Remove"))
|
||||||
dialog.set_response_appearance("remove", Adw.ResponseAppearance.DESTRUCTIVE)
|
dialog.set_response_appearance("remove", Adw.ResponseAppearance.DESTRUCTIVE)
|
||||||
dialog.choose(
|
dialog.choose(
|
||||||
parent = self,
|
parent = self,
|
||||||
@ -699,12 +705,12 @@ class AlpacaWindow(Adw.ApplicationWindow):
|
|||||||
self.show_toast("error", 6, self.main_overlay)
|
self.show_toast("error", 6, self.main_overlay)
|
||||||
return
|
return
|
||||||
dialog = Adw.AlertDialog(
|
dialog = Adw.AlertDialog(
|
||||||
heading=f"Delete Chat",
|
heading=_("Delete Chat"),
|
||||||
body=f"Are you sure you want to delete '{chat_name}'?",
|
body=_("Are you sure you want to delete '{}'?").format(chat_name),
|
||||||
close_response="cancel"
|
close_response="cancel"
|
||||||
)
|
)
|
||||||
dialog.add_response("cancel", "Cancel")
|
dialog.add_response("cancel", _("Cancel"))
|
||||||
dialog.add_response("delete", "Delete")
|
dialog.add_response("delete", _("Delete"))
|
||||||
dialog.set_response_appearance("delete", Adw.ResponseAppearance.DESTRUCTIVE)
|
dialog.set_response_appearance("delete", Adw.ResponseAppearance.DESTRUCTIVE)
|
||||||
dialog.choose(
|
dialog.choose(
|
||||||
parent = self,
|
parent = self,
|
||||||
@ -730,14 +736,14 @@ class AlpacaWindow(Adw.ApplicationWindow):
|
|||||||
css_classes = ["error"] if error else None
|
css_classes = ["error"] if error else None
|
||||||
)
|
)
|
||||||
dialog = Adw.AlertDialog(
|
dialog = Adw.AlertDialog(
|
||||||
heading=f"Rename Chat",
|
heading=_("Rename Chat"),
|
||||||
body=body,
|
body=body,
|
||||||
extra_child=entry,
|
extra_child=entry,
|
||||||
close_response="cancel"
|
close_response="cancel"
|
||||||
)
|
)
|
||||||
entry.connect("activate", lambda entry, dialog=dialog, old_chat_name=chat_name: self.chat_rename(dialog=dialog, old_chat_name=old_chat_name, entry=entry))
|
entry.connect("activate", lambda entry, dialog=dialog, old_chat_name=chat_name: self.chat_rename(dialog=dialog, old_chat_name=old_chat_name, entry=entry))
|
||||||
dialog.add_response("cancel", "Cancel")
|
dialog.add_response("cancel", _("Cancel"))
|
||||||
dialog.add_response("rename", "Rename")
|
dialog.add_response("rename", _("Rename"))
|
||||||
dialog.set_response_appearance("rename", Adw.ResponseAppearance.SUGGESTED)
|
dialog.set_response_appearance("rename", Adw.ResponseAppearance.SUGGESTED)
|
||||||
dialog.choose(
|
dialog.choose(
|
||||||
parent = self,
|
parent = self,
|
||||||
@ -750,7 +756,7 @@ class AlpacaWindow(Adw.ApplicationWindow):
|
|||||||
chat_name = entry.get_text()
|
chat_name = entry.get_text()
|
||||||
if chat_name and (not task or dialog.choose_finish(task) == "create"):
|
if chat_name and (not task or dialog.choose_finish(task) == "create"):
|
||||||
dialog.force_close()
|
dialog.force_close()
|
||||||
if chat_name in self.chats["chats"]: self.chat_new_dialog(f"The name '{chat_name}' is already in use", True)
|
if chat_name in self.chats["chats"]: self.chat_new_dialog(_("The name '{}' is already in use").format(chat_name), True)
|
||||||
else:
|
else:
|
||||||
self.chats["chats"][chat_name] = {"messages": []}
|
self.chats["chats"][chat_name] = {"messages": []}
|
||||||
self.chats["selected_chat"] = chat_name
|
self.chats["selected_chat"] = chat_name
|
||||||
@ -763,14 +769,14 @@ class AlpacaWindow(Adw.ApplicationWindow):
|
|||||||
css_classes = ["error"] if error else None
|
css_classes = ["error"] if error else None
|
||||||
)
|
)
|
||||||
dialog = Adw.AlertDialog(
|
dialog = Adw.AlertDialog(
|
||||||
heading=f"Create Chat",
|
heading=_("Create Chat"),
|
||||||
body=body,
|
body=body,
|
||||||
extra_child=entry,
|
extra_child=entry,
|
||||||
close_response="cancel"
|
close_response="cancel"
|
||||||
)
|
)
|
||||||
entry.connect("activate", lambda entry, dialog=dialog: self.chat_new(dialog=dialog, entry=entry))
|
entry.connect("activate", lambda entry, dialog=dialog: self.chat_new(dialog=dialog, entry=entry))
|
||||||
dialog.add_response("cancel", "Cancel")
|
dialog.add_response("cancel", _("Cancel"))
|
||||||
dialog.add_response("create", "Create")
|
dialog.add_response("create", _("Create"))
|
||||||
dialog.set_response_appearance("rename", Adw.ResponseAppearance.SUGGESTED)
|
dialog.set_response_appearance("rename", Adw.ResponseAppearance.SUGGESTED)
|
||||||
dialog.choose(
|
dialog.choose(
|
||||||
parent = self,
|
parent = self,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user