Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
56064831d3 | ||
|
|
4bdb813b64 | ||
|
|
ad69887e4a | ||
|
|
c8f148d1f8 | ||
|
|
365e39a20a | ||
|
|
48c2fd2e81 | ||
|
|
3a5dc568c5 | ||
|
|
a180f7a46c | ||
|
|
07a12ba41f | ||
|
|
dd5351a3de | ||
|
|
ae48a17301 |
@@ -63,6 +63,19 @@
|
|||||||
<url type="homepage">https://github.com/Jeffser/Alpaca</url>
|
<url type="homepage">https://github.com/Jeffser/Alpaca</url>
|
||||||
<url type="donation">https://github.com/sponsors/Jeffser</url>
|
<url type="donation">https://github.com/sponsors/Jeffser</url>
|
||||||
<releases>
|
<releases>
|
||||||
|
<release version="0.9.1" date="2024-05-29">
|
||||||
|
<url type="details">https://github.com/Jeffser/Alpaca/releases/tag/0.9.1</url>
|
||||||
|
<description>
|
||||||
|
<p>Big Update</p>
|
||||||
|
<ul>
|
||||||
|
<li>Changed multiple icons (paper airplane for the send button)</li>
|
||||||
|
<li>Combined export / import chat buttons into a menu</li>
|
||||||
|
<li>Added 'model tweaks' (temperature, seed, keep_alive)</li>
|
||||||
|
<li>Fixed send / stop button</li>
|
||||||
|
<li>Fixed app not checking if remote connection works when starting</li>
|
||||||
|
</ul>
|
||||||
|
</description>
|
||||||
|
</release>
|
||||||
<release version="0.9.0" date="2024-05-29">
|
<release version="0.9.0" date="2024-05-29">
|
||||||
<url type="details">https://github.com/Jeffser/Alpaca/releases/tag/0.9.0</url>
|
<url type="details">https://github.com/Jeffser/Alpaca/releases/tag/0.9.0</url>
|
||||||
<description>
|
<description>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
project('Alpaca',
|
project('Alpaca',
|
||||||
version: '0.9.0',
|
version: '0.9.1',
|
||||||
meson_version: '>= 0.62.0',
|
meson_version: '>= 0.62.0',
|
||||||
default_options: [ 'warning_level=2', 'werror=false', ],
|
default_options: [ 'warning_level=2', 'werror=false', ],
|
||||||
)
|
)
|
||||||
|
|||||||
468
po/alpaca.pot
468
po/alpaca.pot
File diff suppressed because it is too large
Load Diff
476
po/pt_BR.po
476
po/pt_BR.po
File diff suppressed because it is too large
Load Diff
507
po/pt_BR.po~
507
po/pt_BR.po~
File diff suppressed because it is too large
Load Diff
@@ -3,6 +3,10 @@
|
|||||||
<gresource prefix="/com/jeffser/Alpaca">
|
<gresource prefix="/com/jeffser/Alpaca">
|
||||||
<file>style.css</file>
|
<file>style.css</file>
|
||||||
<file>style-dark.css</file>
|
<file>style-dark.css</file>
|
||||||
|
<file alias="icons/scalable/status/library-symbolic.svg">icons/library-symbolic.svg</file>
|
||||||
|
<file alias="icons/scalable/status/paper-plane-symbolic.svg">icons/paper-plane-symbolic.svg</file>
|
||||||
|
<file alias="icons/scalable/status/globe-symbolic.svg">icons/globe-symbolic.svg</file>
|
||||||
|
<file alias="icons/scalable/status/controls-big-symbolic.svg">icons/controls-big-symbolic.svg</file>
|
||||||
<file preprocess="xml-stripblanks">window.ui</file>
|
<file preprocess="xml-stripblanks">window.ui</file>
|
||||||
<file preprocess="xml-stripblanks">gtk/help-overlay.ui</file>
|
<file preprocess="xml-stripblanks">gtk/help-overlay.ui</file>
|
||||||
</gresource>
|
</gresource>
|
||||||
|
|||||||
2
src/icons/controls-big-symbolic.svg
Normal file
2
src/icons/controls-big-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"><g fill="#222222"><path d="m 4.550781 1 c -1.9375 0 -3.5 1.5625 -3.5 3.5 s 1.5625 3.5 3.5 3.5 h 7 c 1.941407 0 3.5 -1.5625 3.5 -3.5 s -1.558593 -3.5 -3.5 -3.5 z m 7 1 c 1.386719 0 2.5 1.113281 2.5 2.5 c 0 1.382812 -1.113281 2.5 -2.5 2.5 c -1.382812 0 -2.5 -1.117188 -2.5 -2.5 c 0 -1.386719 1.117188 -2.5 2.5 -2.5 z m 0 0"/><path d="m 4.550781 9 c -1.9375 0 -3.5 1.5625 -3.5 3.5 s 1.5625 3.5 3.5 3.5 h 7 c 1.941407 0 3.5 -1.5625 3.5 -3.5 s -1.558593 -3.5 -3.5 -3.5 z m 0 1 c 1.386719 0 2.5 1.113281 2.5 2.5 c 0 1.382812 -1.113281 2.5 -2.5 2.5 c -1.382812 0 -2.5 -1.117188 -2.5 -2.5 c 0 -1.386719 1.117188 -2.5 2.5 -2.5 z m 0 0" fill-opacity="0.35"/></g></svg>
|
||||||
|
After Width: | Height: | Size: 785 B |
2
src/icons/globe-symbolic.svg
Normal file
2
src/icons/globe-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 7.5 0 c -4.128906 0 -7.5 3.371094 -7.5 7.5 s 3.371094 7.5 7.5 7.5 s 7.5 -3.371094 7.5 -7.5 s -3.371094 -7.5 -7.5 -7.5 z m 0 2 c 0.257812 0 0.503906 0.023438 0.75 0.054688 c 0.191406 0.261718 0.382812 0.59375 0.550781 1.027343 c 0.105469 0.277344 0.203125 0.585938 0.289063 0.917969 h -3.179688 c 0.085938 -0.332031 0.183594 -0.640625 0.289063 -0.917969 c 0.167969 -0.433593 0.359375 -0.765625 0.550781 -1.027343 c 0.246094 -0.03125 0.492188 -0.054688 0.75 -0.054688 z m -2.085938 0.40625 c -0.050781 0.109375 -0.105468 0.203125 -0.148437 0.316406 c -0.148437 0.386719 -0.269531 0.820313 -0.378906 1.277344 h -1.617188 c 0.570313 -0.691406 1.296875 -1.246094 2.144531 -1.59375 z m 4.171876 0 c 0.847656 0.347656 1.574218 0.902344 2.144531 1.59375 h -1.617188 c -0.109375 -0.457031 -0.230469 -0.890625 -0.378906 -1.277344 c -0.042969 -0.113281 -0.097656 -0.207031 -0.148437 -0.316406 z m -6.980469 2.59375 h 2.082031 c -0.097656 0.628906 -0.148438 1.300781 -0.167969 2 h -2.480469 c 0.0625 -0.714844 0.253907 -1.390625 0.566407 -2 z m 3.09375 0 h 3.601562 c 0.101563 0.617188 0.15625 1.292969 0.179688 2 h -3.960938 c 0.023438 -0.707031 0.078125 -1.382812 0.179688 -2 z m 4.613281 0 h 2.082031 c 0.3125 0.609375 0.503907 1.285156 0.566407 2 h -2.480469 c -0.019531 -0.699219 -0.070313 -1.371094 -0.167969 -2 z m -8.273438 3 h 2.480469 c 0.019531 0.699219 0.070313 1.375 0.167969 2 h -2.082031 c -0.3125 -0.609375 -0.503907 -1.285156 -0.566407 -2 z m 3.480469 0 h 3.960938 c -0.023438 0.707031 -0.078125 1.382812 -0.179688 2 h -3.601562 c -0.101563 -0.617188 -0.15625 -1.292969 -0.179688 -2 z m 4.960938 0 h 2.480469 c -0.0625 0.714844 -0.253907 1.390625 -0.566407 2 h -2.082031 c 0.097656 -0.625 0.148438 -1.300781 0.167969 -2 z m -7.210938 3 h 1.617188 c 0.109375 0.457031 0.230469 0.890625 0.378906 1.273438 c 0.042969 0.117187 0.097656 0.210937 0.148437 0.320312 c -0.847656 -0.347656 -1.574218 -0.902344 -2.144531 -1.59375 z m 2.640625 0 h 3.179688 c -0.085938 0.332031 -0.183594 0.640625 -0.289063 0.917969 c -0.167969 0.433593 -0.359375 0.765625 -0.550781 1.027343 c -0.246094 0.03125 -0.496094 0.054688 -0.75 0.054688 s -0.503906 -0.023438 -0.75 -0.054688 c -0.191406 -0.261718 -0.382812 -0.59375 -0.550781 -1.027343 c -0.105469 -0.277344 -0.203125 -0.585938 -0.289063 -0.917969 z m 4.203125 0 h 1.617188 c -0.570313 0.691406 -1.296875 1.246094 -2.144531 1.59375 c 0.050781 -0.109375 0.105468 -0.203125 0.148437 -0.320312 c 0.148437 -0.382813 0.269531 -0.816407 0.378906 -1.273438 z m 0 0" fill="#222222"/></svg>
|
||||||
|
After Width: | Height: | Size: 2.6 KiB |
2
src/icons/library-symbolic.svg
Normal file
2
src/icons/library-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"><g fill="#222222"><path d="m 1.5 2 h 2 c 0.277344 0 0.5 0.222656 0.5 0.5 v 12 c 0 0.277344 -0.222656 0.5 -0.5 0.5 h -2 c -0.277344 0 -0.5 -0.222656 -0.5 -0.5 v -12 c 0 -0.277344 0.222656 -0.5 0.5 -0.5 z m 0 0"/><path d="m 5.5 4 h 1 c 0.277344 0 0.5 0.222656 0.5 0.5 v 10 c 0 0.277344 -0.222656 0.5 -0.5 0.5 h -1 c -0.277344 0 -0.5 -0.222656 -0.5 -0.5 v -10 c 0 -0.277344 0.222656 -0.5 0.5 -0.5 z m 0 0"/><path d="m 8.5 3 h 1 c 0.277344 0 0.5 0.222656 0.5 0.5 v 11 c 0 0.277344 -0.222656 0.5 -0.5 0.5 h -1 c -0.277344 0 -0.5 -0.222656 -0.5 -0.5 v -11 c 0 -0.277344 0.222656 -0.5 0.5 -0.5 z m 0 0"/><path d="m 10.707031 1.460938 l 0.964844 -0.261719 c 0.265625 -0.070313 0.539063 0.089843 0.613281 0.355469 l 3.363282 12.558593 c 0.070312 0.265625 -0.085938 0.539063 -0.351563 0.609375 l -0.96875 0.261719 c -0.265625 0.070313 -0.539063 -0.089844 -0.613281 -0.355469 l -3.363282 -12.554687 c -0.070312 -0.269531 0.085938 -0.542969 0.355469 -0.613281 z m 0 0"/></g></svg>
|
||||||
|
After Width: | Height: | Size: 1.1 KiB |
2
src/icons/paper-plane-symbolic.svg
Normal file
2
src/icons/paper-plane-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 15 8 l -14 -7 v 6 l 8 1 l -8 1 v 6 z m 0 0" fill="#222222"/></svg>
|
||||||
|
After Width: | Height: | Size: 204 B |
@@ -47,7 +47,7 @@ class AlpacaApplication(Adw.Application):
|
|||||||
application_name='Alpaca',
|
application_name='Alpaca',
|
||||||
application_icon='com.jeffser.Alpaca',
|
application_icon='com.jeffser.Alpaca',
|
||||||
developer_name='Jeffry Samuel Eduarte Rojas',
|
developer_name='Jeffry Samuel Eduarte Rojas',
|
||||||
version='0.9.0',
|
version='0.9.1',
|
||||||
developers=['Jeffser https://jeffser.com'],
|
developers=['Jeffser https://jeffser.com'],
|
||||||
designers=['Jeffser https://jeffser.com'],
|
designers=['Jeffser https://jeffser.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',
|
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',
|
||||||
|
|||||||
177
src/window.py
177
src/window.py
@@ -47,13 +47,16 @@ class AlpacaWindow(Adw.ApplicationWindow):
|
|||||||
run_on_background = False
|
run_on_background = False
|
||||||
remote_url = ""
|
remote_url = ""
|
||||||
run_remote = False
|
run_remote = False
|
||||||
|
model_tweaks = {"temperature": 0.7, "seed": 0, "keep_alive": 5}
|
||||||
local_models = []
|
local_models = []
|
||||||
pulling_models = {}
|
pulling_models = {}
|
||||||
current_chat_elements = [] #Used for deleting
|
|
||||||
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}
|
||||||
|
|
||||||
#Elements
|
#Elements
|
||||||
|
temperature_spin = Gtk.Template.Child()
|
||||||
|
seed_spin = Gtk.Template.Child()
|
||||||
|
keep_alive_spin = Gtk.Template.Child()
|
||||||
preferences_dialog = Gtk.Template.Child()
|
preferences_dialog = Gtk.Template.Child()
|
||||||
shortcut_window : Gtk.ShortcutsWindow = Gtk.Template.Child()
|
shortcut_window : Gtk.ShortcutsWindow = Gtk.Template.Child()
|
||||||
bot_message : Gtk.TextBuffer = None
|
bot_message : Gtk.TextBuffer = None
|
||||||
@@ -69,6 +72,7 @@ class AlpacaWindow(Adw.ApplicationWindow):
|
|||||||
chat_window = Gtk.Template.Child()
|
chat_window = Gtk.Template.Child()
|
||||||
message_text_view = Gtk.Template.Child()
|
message_text_view = Gtk.Template.Child()
|
||||||
send_button = Gtk.Template.Child()
|
send_button = Gtk.Template.Child()
|
||||||
|
stop_button = Gtk.Template.Child()
|
||||||
image_button = Gtk.Template.Child()
|
image_button = Gtk.Template.Child()
|
||||||
file_filter_image = Gtk.Template.Child()
|
file_filter_image = Gtk.Template.Child()
|
||||||
file_filter_json = Gtk.Template.Child()
|
file_filter_json = Gtk.Template.Child()
|
||||||
@@ -82,8 +86,6 @@ class AlpacaWindow(Adw.ApplicationWindow):
|
|||||||
|
|
||||||
chat_list_box = Gtk.Template.Child()
|
chat_list_box = Gtk.Template.Child()
|
||||||
add_chat_button = Gtk.Template.Child()
|
add_chat_button = Gtk.Template.Child()
|
||||||
export_chat_button = Gtk.Template.Child()
|
|
||||||
import_chat_button = Gtk.Template.Child()
|
|
||||||
|
|
||||||
loading_spinner = None
|
loading_spinner = None
|
||||||
|
|
||||||
@@ -131,58 +133,55 @@ class AlpacaWindow(Adw.ApplicationWindow):
|
|||||||
self.image_button.set_sensitive(False)
|
self.image_button.set_sensitive(False)
|
||||||
self.image_button.set_tooltip_text(_("Only available on selected models"))
|
self.image_button.set_tooltip_text(_("Only available on selected models"))
|
||||||
self.image_button.set_css_classes(["circular"])
|
self.image_button.set_css_classes(["circular"])
|
||||||
self.image_button.get_child().set_icon_name("image-x-generic-symbolic")
|
|
||||||
self.attached_image = {"path": None, "base64": None}
|
self.attached_image = {"path": None, "base64": None}
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
@Gtk.Template.Callback()
|
||||||
|
def stop_message(self, button=None):
|
||||||
|
if self.loading_spinner: self.chat_container.remove(self.loading_spinner)
|
||||||
|
if self.verify_if_image_can_be_used(): self.image_button.set_sensitive(True)
|
||||||
|
self.image_button.set_css_classes(["circular"])
|
||||||
|
self.attached_image = {"path": None, "base64": None}
|
||||||
|
self.toggle_ui_sensitive(True)
|
||||||
|
self.switch_send_stop_button()
|
||||||
|
self.bot_message = None
|
||||||
|
self.bot_message_box = None
|
||||||
|
self.bot_message_view = None
|
||||||
|
|
||||||
@Gtk.Template.Callback()
|
@Gtk.Template.Callback()
|
||||||
def send_message(self, button=None):
|
def send_message(self, button=None):
|
||||||
if button and self.bot_message: #STOP BUTTON
|
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.loading_spinner: self.chat_container.remove(self.loading_spinner)
|
current_model = self.model_drop_down.get_selected_item()
|
||||||
if self.verify_if_image_can_be_used(): self.image_button.set_sensitive(True)
|
if current_model is None:
|
||||||
self.image_button.set_css_classes(["circular"])
|
self.show_toast("info", 0, self.main_overlay)
|
||||||
self.image_button.get_child().set_icon_name("image-x-generic-symbolic")
|
return
|
||||||
self.attached_image = {"path": None, "base64": None}
|
formated_datetime = datetime.now().strftime("%Y/%m/%d %H:%M")
|
||||||
self.toggle_ui_sensitive(True)
|
self.chats["chats"][self.chats["selected_chat"]]["messages"].append({
|
||||||
self.send_button.set_css_classes(["suggested-action"])
|
"role": "user",
|
||||||
self.send_button.get_child().set_label("Send")
|
"model": "User",
|
||||||
self.send_button.get_child().set_icon_name("send-to-symbolic")
|
"date": formated_datetime,
|
||||||
self.bot_message = None
|
"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)
|
||||||
self.bot_message_box = None
|
})
|
||||||
self.bot_message_view = None
|
data = {
|
||||||
else:
|
"model": current_model.get_string(),
|
||||||
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
|
"messages": self.chats["chats"][self.chats["selected_chat"]]["messages"],
|
||||||
current_model = self.model_drop_down.get_selected_item()
|
"options": {"temperature": self.model_tweaks["temperature"], "seed": self.model_tweaks["seed"]},
|
||||||
if current_model is None:
|
"keep_alive": f"{self.model_tweaks['keep_alive']}m"
|
||||||
self.show_toast("info", 0, self.main_overlay)
|
}
|
||||||
return
|
if self.verify_if_image_can_be_used() and self.attached_image["base64"] is not None:
|
||||||
formated_datetime = datetime.now().strftime("%Y/%m/%d %H:%M")
|
data["messages"][-1]["images"] = [self.attached_image["base64"]]
|
||||||
self.chats["chats"][self.chats["selected_chat"]]["messages"].append({
|
self.switch_send_stop_button()
|
||||||
"role": "user",
|
self.toggle_ui_sensitive(False)
|
||||||
"model": "User",
|
self.image_button.set_sensitive(False)
|
||||||
"date": formated_datetime,
|
|
||||||
"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)
|
|
||||||
})
|
|
||||||
data = {
|
|
||||||
"model": current_model.get_string(),
|
|
||||||
"messages": self.chats["chats"][self.chats["selected_chat"]]["messages"]
|
|
||||||
}
|
|
||||||
if self.verify_if_image_can_be_used() and self.attached_image["base64"] is not None:
|
|
||||||
data["messages"][-1]["images"] = [self.attached_image["base64"]]
|
|
||||||
self.send_button.set_css_classes(["destructive-action"])
|
|
||||||
self.send_button.get_child().set_label("Stop")
|
|
||||||
self.send_button.get_child().set_icon_name("edit-delete-symbolic")
|
|
||||||
self.toggle_ui_sensitive(False)
|
|
||||||
self.image_button.set_sensitive(False)
|
|
||||||
|
|
||||||
self.show_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), False, f"\n\n<small>{formated_datetime}</small>", self.attached_image["base64"])
|
self.show_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), False, f"\n\n<small>{formated_datetime}</small>", self.attached_image["base64"])
|
||||||
self.message_text_view.get_buffer().set_text("", 0)
|
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.loading_spinner = Gtk.Spinner(spinning=True, margin_top=12, margin_bottom=12, hexpand=True)
|
||||||
self.chat_container.append(self.loading_spinner)
|
self.chat_container.append(self.loading_spinner)
|
||||||
self.show_message("", True)
|
self.show_message("", True)
|
||||||
|
|
||||||
thread = threading.Thread(target=self.run_message, args=(data['messages'], data['model']))
|
thread = threading.Thread(target=self.run_message, args=(data['messages'], data['model']))
|
||||||
thread.start()
|
thread.start()
|
||||||
|
|
||||||
@Gtk.Template.Callback()
|
@Gtk.Template.Callback()
|
||||||
def manage_models_button_activate(self, button=None):
|
def manage_models_button_activate(self, button=None):
|
||||||
@@ -256,6 +255,16 @@ class AlpacaWindow(Adw.ApplicationWindow):
|
|||||||
print("Closing app...")
|
print("Closing app...")
|
||||||
local_instance.stop()
|
local_instance.stop()
|
||||||
|
|
||||||
|
@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 self.model_tweaks[spin.get_name()] is not None and self.model_tweaks[spin.get_name()] != value:
|
||||||
|
self.model_tweaks[spin.get_name()] = value
|
||||||
|
print(self.model_tweaks)
|
||||||
|
self.save_server_config()
|
||||||
|
|
||||||
def show_toast(self, message_type:str, message_id:int, overlay):
|
def show_toast(self, message_type:str, message_id:int, overlay):
|
||||||
if message_type not in self.toast_messages or message_id > len(self.toast_messages[message_type] or message_id < 0):
|
if message_type not in self.toast_messages or message_id > len(self.toast_messages[message_type] or message_id < 0):
|
||||||
message_type = "error"
|
message_type = "error"
|
||||||
@@ -274,11 +283,11 @@ class AlpacaWindow(Adw.ApplicationWindow):
|
|||||||
self.get_application().send_notification(None, notification)
|
self.get_application().send_notification(None, notification)
|
||||||
|
|
||||||
def delete_message(self, message_element):
|
def delete_message(self, message_element):
|
||||||
message_index = self.current_chat_elements.index(message_element)
|
message_index = int(message_element.get_name())
|
||||||
del self.chats["chats"][self.chats["selected_chat"]]["messages"][message_index]
|
if message_index < len(self.chats["chats"][self.chats["selected_chat"]]["messages"]):
|
||||||
self.chat_container.remove(message_element)
|
self.chats["chats"][self.chats["selected_chat"]]["messages"][message_index] = None
|
||||||
del self.current_chat_elements[message_index]
|
self.chat_container.remove(message_element)
|
||||||
self.save_history()
|
self.save_history()
|
||||||
|
|
||||||
def show_message(self, msg:str, bot:bool, footer:str=None, image_base64:str=None):
|
def show_message(self, msg:str, bot:bool, footer:str=None, image_base64:str=None):
|
||||||
message_text = Gtk.TextView(
|
message_text = Gtk.TextView(
|
||||||
@@ -332,12 +341,12 @@ class AlpacaWindow(Adw.ApplicationWindow):
|
|||||||
message_box.append(image)
|
message_box.append(image)
|
||||||
|
|
||||||
message_box.append(message_text)
|
message_box.append(message_text)
|
||||||
self.current_chat_elements.append(Gtk.Overlay(css_classes=["message"]))
|
overlay = Gtk.Overlay(css_classes=["message"], name=str(len(self.chats["chats"][self.chats["selected_chat"]]["messages"])-1))
|
||||||
self.current_chat_elements[-1].set_child(message_box)
|
overlay.set_child(message_box)
|
||||||
|
|
||||||
delete_button.connect("clicked", lambda button, element=self.current_chat_elements[-1]: self.delete_message(element))
|
delete_button.connect("clicked", lambda button, element=overlay: self.delete_message(element))
|
||||||
self.current_chat_elements[-1].add_overlay(delete_button)
|
overlay.add_overlay(delete_button)
|
||||||
self.chat_container.append(self.current_chat_elements[-1])
|
self.chat_container.append(overlay)
|
||||||
|
|
||||||
if bot:
|
if bot:
|
||||||
self.bot_message = message_buffer
|
self.bot_message = message_buffer
|
||||||
@@ -378,12 +387,15 @@ class AlpacaWindow(Adw.ApplicationWindow):
|
|||||||
else:
|
else:
|
||||||
self.connection_error()
|
self.connection_error()
|
||||||
|
|
||||||
|
def save_server_config(self):
|
||||||
|
with open(os.path.join(self.config_dir, "server.json"), "w+") as f:
|
||||||
|
json.dump({'remote_url': self.remote_url, 'run_remote': self.run_remote, 'local_port': local_instance.port, 'run_on_background': self.run_on_background, 'model_tweaks': self.model_tweaks}, f)
|
||||||
|
|
||||||
def verify_connection(self):
|
def verify_connection(self):
|
||||||
response = connection_handler.simple_get(connection_handler.url)
|
response = connection_handler.simple_get(connection_handler.url)
|
||||||
if response['status'] == 'ok':
|
if response['status'] == 'ok':
|
||||||
if "Ollama is running" in response['text']:
|
if "Ollama is running" in response['text']:
|
||||||
with open(os.path.join(self.config_dir, "server.json"), "w+") as f:
|
self.save_server_config()
|
||||||
json.dump({'remote_url': self.remote_url, 'run_remote': self.run_remote, 'local_port': local_instance.port, 'run_on_background': self.run_on_background}, f)
|
|
||||||
self.update_list_local_models()
|
self.update_list_local_models()
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
@@ -527,22 +539,24 @@ class AlpacaWindow(Adw.ApplicationWindow):
|
|||||||
self.chats["chats"][self.chats["selected_chat"]]["messages"][-1]['content'] += data['message']['content']
|
self.chats["chats"][self.chats["selected_chat"]]["messages"][-1]['content'] += data['message']['content']
|
||||||
|
|
||||||
def toggle_ui_sensitive(self, status):
|
def toggle_ui_sensitive(self, status):
|
||||||
for element in [self.chat_list_box, self.export_chat_button, self.import_chat_button, self.add_chat_button]:
|
for element in [self.chat_list_box, self.add_chat_button]:
|
||||||
element.set_sensitive(status)
|
element.set_sensitive(status)
|
||||||
|
|
||||||
|
def switch_send_stop_button(self):
|
||||||
|
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):
|
def run_message(self, messages, model):
|
||||||
response = connection_handler.stream_post(f"{connection_handler.url}/api/chat", data=json.dumps({"model": model, "messages": messages}), callback=self.update_bot_message)
|
response = connection_handler.stream_post(f"{connection_handler.url}/api/chat", data=json.dumps({"model": model, "messages": messages}), callback=self.update_bot_message)
|
||||||
GLib.idle_add(self.add_code_blocks)
|
GLib.idle_add(self.add_code_blocks)
|
||||||
GLib.idle_add(self.send_button.set_css_classes, ["suggested-action"])
|
GLib.idle_add(self.switch_send_stop_button)
|
||||||
GLib.idle_add(self.send_button.get_child().set_label, "Send")
|
|
||||||
GLib.idle_add(self.send_button.get_child().set_icon_name, "send-to-symbolic")
|
|
||||||
GLib.idle_add(self.toggle_ui_sensitive, True)
|
GLib.idle_add(self.toggle_ui_sensitive, True)
|
||||||
if self.verify_if_image_can_be_used(): GLib.idle_add(self.image_button.set_sensitive, True)
|
if self.verify_if_image_can_be_used(): GLib.idle_add(self.image_button.set_sensitive, True)
|
||||||
GLib.idle_add(self.image_button.set_css_classes, ["circular"])
|
GLib.idle_add(self.image_button.set_css_classes, ["circular"])
|
||||||
GLib.idle_add(self.image_button.get_child().set_icon_name, "image-x-generic-symbolic")
|
|
||||||
self.attached_image = {"path": None, "base64": None}
|
self.attached_image = {"path": None, "base64": None}
|
||||||
if response['status'] == 'error':
|
if response['status'] == 'error':
|
||||||
GLib.idle_add(self.connection_error)
|
GLib.idle_add(self.connection_error)
|
||||||
|
print(response)
|
||||||
|
|
||||||
def pull_model_update(self, data, model_name):
|
def pull_model_update(self, data, model_name):
|
||||||
if model_name in list(self.pulling_models.keys()):
|
if model_name in list(self.pulling_models.keys()):
|
||||||
@@ -615,7 +629,7 @@ class AlpacaWindow(Adw.ApplicationWindow):
|
|||||||
subtitle = "Image recognition" if model_info["image"] else None
|
subtitle = "Image recognition" if model_info["image"] else None
|
||||||
)
|
)
|
||||||
link_button = Gtk.Button(
|
link_button = Gtk.Button(
|
||||||
icon_name = "web-browser-symbolic",
|
icon_name = "globe-symbolic",
|
||||||
vexpand = False,
|
vexpand = False,
|
||||||
valign = 3,
|
valign = 3,
|
||||||
css_classes = ["success"]
|
css_classes = ["success"]
|
||||||
@@ -639,12 +653,13 @@ class AlpacaWindow(Adw.ApplicationWindow):
|
|||||||
def load_history_into_chat(self):
|
def load_history_into_chat(self):
|
||||||
for widget in list(self.chat_container): self.chat_container.remove(widget)
|
for widget in list(self.chat_container): self.chat_container.remove(widget)
|
||||||
for message in self.chats['chats'][self.chats["selected_chat"]]['messages']:
|
for message in self.chats['chats'][self.chats["selected_chat"]]['messages']:
|
||||||
if message['role'] == 'user':
|
if message:
|
||||||
self.show_message(message['content'], False, f"\n\n<small>{message['date']}</small>", message['images'][0] if 'images' in message and len(message['images']) > 0 else None)
|
if message['role'] == 'user':
|
||||||
else:
|
self.show_message(message['content'], False, f"\n\n<small>{message['date']}</small>", message['images'][0] if 'images' in message and len(message['images']) > 0 else None)
|
||||||
self.show_message(message['content'], True, f"\n\n<small>{message['model']}\t|\t{message['date']}</small>")
|
else:
|
||||||
self.add_code_blocks()
|
self.show_message(message['content'], True, f"\n\n<small>{message['model']}\t|\t{message['date']}</small>")
|
||||||
self.bot_message = None
|
self.add_code_blocks()
|
||||||
|
self.bot_message = None
|
||||||
|
|
||||||
def load_history(self):
|
def load_history(self):
|
||||||
if os.path.exists(os.path.join(self.config_dir, "chats.json")):
|
if os.path.exists(os.path.join(self.config_dir, "chats.json")):
|
||||||
@@ -653,6 +668,9 @@ class AlpacaWindow(Adw.ApplicationWindow):
|
|||||||
self.chats = json.load(f)
|
self.chats = json.load(f)
|
||||||
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 "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 len(list(self.chats["chats"].keys())) == 0: self.chats["chats"][_("New Chat")] = {"messages": []}
|
||||||
|
for chat_name, content in self.chats['chats'].items():
|
||||||
|
for i, content in enumerate(content['messages']):
|
||||||
|
if not content: del self.chats['chats'][chat_name]['messages'][i]
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.chats = {"chats": {_("New Chat"): {"messages": []}}, "selected_chat": _("New Chat")}
|
self.chats = {"chats": {_("New Chat"): {"messages": []}}, "selected_chat": _("New Chat")}
|
||||||
self.load_history_into_chat()
|
self.load_history_into_chat()
|
||||||
@@ -678,13 +696,11 @@ class AlpacaWindow(Adw.ApplicationWindow):
|
|||||||
self.attached_image["base64"] = base64.b64encode(image_data).decode("utf-8")
|
self.attached_image["base64"] = base64.b64encode(image_data).decode("utf-8")
|
||||||
|
|
||||||
self.image_button.set_css_classes(["destructive-action", "circular"])
|
self.image_button.set_css_classes(["destructive-action", "circular"])
|
||||||
self.image_button.get_child().set_icon_name("edit-delete-symbolic")
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.show_toast("error", 5, self.main_overlay)
|
self.show_toast("error", 5, self.main_overlay)
|
||||||
|
|
||||||
def remove_image(self):
|
def remove_image(self):
|
||||||
self.image_button.set_css_classes(["circular"])
|
self.image_button.set_css_classes(["circular"])
|
||||||
self.image_button.get_child().set_icon_name("image-x-generic-symbolic")
|
|
||||||
self.attached_image = {"path": None, "base64": None}
|
self.attached_image = {"path": None, "base64": None}
|
||||||
|
|
||||||
def generate_numbered_chat_name(self, chat_name) -> str:
|
def generate_numbered_chat_name(self, chat_name) -> str:
|
||||||
@@ -867,11 +883,10 @@ class AlpacaWindow(Adw.ApplicationWindow):
|
|||||||
self.get_application().create_action('new_chat', lambda *_: self.new_chat(), ['<primary>n'])
|
self.get_application().create_action('new_chat', lambda *_: self.new_chat(), ['<primary>n'])
|
||||||
self.get_application().create_action('clear', lambda *_: dialogs.clear_chat(self), ['<primary>e'])
|
self.get_application().create_action('clear', lambda *_: dialogs.clear_chat(self), ['<primary>e'])
|
||||||
self.get_application().create_action('send', lambda *_: self.send_message(self), ['Return'])
|
self.get_application().create_action('send', lambda *_: self.send_message(self), ['Return'])
|
||||||
|
self.get_application().create_action('export_current_chat', lambda *_: self.export_current_chat())
|
||||||
|
self.get_application().create_action('import_chat', lambda *_: self.import_chat())
|
||||||
self.add_chat_button.connect("clicked", lambda button : self.new_chat())
|
self.add_chat_button.connect("clicked", lambda button : self.new_chat())
|
||||||
|
|
||||||
self.export_chat_button.connect("clicked", lambda button : self.export_current_chat())
|
|
||||||
self.import_chat_button.connect("clicked", lambda button : self.import_chat())
|
|
||||||
|
|
||||||
self.remote_connection_entry.connect("entry-activated", lambda entry : entry.set_css_classes([]))
|
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.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.background_switch.connect("notify", lambda pspec, user_data : self.switch_run_on_background())
|
||||||
@@ -882,6 +897,12 @@ class AlpacaWindow(Adw.ApplicationWindow):
|
|||||||
local_instance.port = data['local_port']
|
local_instance.port = data['local_port']
|
||||||
self.remote_url = data['remote_url']
|
self.remote_url = data['remote_url']
|
||||||
self.run_on_background = data['run_on_background']
|
self.run_on_background = data['run_on_background']
|
||||||
|
#Model Tweaks
|
||||||
|
if "model_tweaks" in data: self.model_tweaks = data['model_tweaks']
|
||||||
|
self.temperature_spin.set_value(data['model_tweaks']['temperature'])
|
||||||
|
self.seed_spin.set_value(data['model_tweaks']['seed'])
|
||||||
|
self.keep_alive_spin.set_value(data['model_tweaks']['keep_alive'])
|
||||||
|
|
||||||
self.background_switch.set_active(self.run_on_background)
|
self.background_switch.set_active(self.run_on_background)
|
||||||
self.set_hide_on_close(self.run_on_background)
|
self.set_hide_on_close(self.run_on_background)
|
||||||
self.remote_connection_entry.set_text(self.remote_url)
|
self.remote_connection_entry.set_text(self.remote_url)
|
||||||
@@ -896,7 +917,7 @@ class AlpacaWindow(Adw.ApplicationWindow):
|
|||||||
local_instance.start()
|
local_instance.start()
|
||||||
connection_handler.url = f"http://127.0.0.1:{local_instance.port}"
|
connection_handler.url = f"http://127.0.0.1:{local_instance.port}"
|
||||||
self.welcome_dialog.present(self)
|
self.welcome_dialog.present(self)
|
||||||
if self.verify_connection() is False and self.run_remote == False: self.connection_error()
|
if self.verify_connection() is False: self.connection_error()
|
||||||
self.update_list_available_models()
|
self.update_list_available_models()
|
||||||
self.load_history()
|
self.load_history()
|
||||||
self.update_chat_list()
|
self.update_chat_list()
|
||||||
|
|||||||
104
src/window.ui
104
src/window.ui
@@ -44,21 +44,11 @@
|
|||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
<child type="end">
|
<child type="end">
|
||||||
<object class="GtkButton" id="import_chat_button">
|
<object class="GtkMenuButton" id="chats_menu_button">
|
||||||
<property name="tooltip-text" translatable="yes">Import chat</property>
|
<property name="direction">1</property>
|
||||||
<property name="icon-name">document-open-symbolic</property>
|
<property name="halign">3</property>
|
||||||
<style>
|
<property name="menu-model">chats_button_menu</property>
|
||||||
<class name="flat"/>
|
<property name="icon-name">view-more-symbolic</property>
|
||||||
</style>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
<child type="end">
|
|
||||||
<object class="GtkButton" id="export_chat_button">
|
|
||||||
<property name="tooltip-text" translatable="yes">Export chat</property>
|
|
||||||
<property name="icon-name">folder-download-symbolic</property>
|
|
||||||
<style>
|
|
||||||
<class name="flat"/>
|
|
||||||
</style>
|
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
</object>
|
</object>
|
||||||
@@ -113,7 +103,7 @@
|
|||||||
<property name="tooltip-text" translatable="yes">Manage models</property>
|
<property name="tooltip-text" translatable="yes">Manage models</property>
|
||||||
<child>
|
<child>
|
||||||
<object class="AdwButtonContent">
|
<object class="AdwButtonContent">
|
||||||
<property name="icon-name">package-x-generic-symbolic</property>
|
<property name="icon-name">library-symbolic</property>
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
</object>
|
</object>
|
||||||
@@ -235,7 +225,24 @@
|
|||||||
</style>
|
</style>
|
||||||
<child>
|
<child>
|
||||||
<object class="AdwButtonContent">
|
<object class="AdwButtonContent">
|
||||||
<property name="icon-name">send-to-symbolic</property>
|
<property name="icon-name">paper-plane-symbolic</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkButton" id="stop_button">
|
||||||
|
<signal name="clicked" handler="stop_message"/>
|
||||||
|
<property name="vexpand">false</property>
|
||||||
|
<property name="valign">3</property>
|
||||||
|
<property name="visible">false</property>
|
||||||
|
<style>
|
||||||
|
<class name="destructive-action"/>
|
||||||
|
<class name="circular"/>
|
||||||
|
</style>
|
||||||
|
<child>
|
||||||
|
<object class="AdwButtonContent">
|
||||||
|
<property name="icon-name">media-playback-stop-symbolic</property>
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
</object>
|
</object>
|
||||||
@@ -260,7 +267,7 @@
|
|||||||
<child>
|
<child>
|
||||||
<object class="AdwPreferencesPage" id="general_page">
|
<object class="AdwPreferencesPage" id="general_page">
|
||||||
<property name="title" translatable="yes">General</property>
|
<property name="title" translatable="yes">General</property>
|
||||||
<property name="icon-name">insert-link-symbolic</property>
|
<property name="icon-name">preferences-system-symbolic</property>
|
||||||
<child>
|
<child>
|
||||||
<object class="AdwPreferencesGroup">
|
<object class="AdwPreferencesGroup">
|
||||||
<property name="title" translatable="yes">Remote Connection</property>
|
<property name="title" translatable="yes">Remote Connection</property>
|
||||||
@@ -292,18 +299,64 @@
|
|||||||
</child>
|
</child>
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
<!--<child>
|
<child>
|
||||||
<object class="AdwPreferencesPage" id="model_page">
|
<object class="AdwPreferencesPage" id="model_page">
|
||||||
<property name="title" translatable="yes">Advanced Model Settings</property>
|
<property name="title" translatable="yes">Advanced Model Settings</property>
|
||||||
<property name="icon-name">preferences-system-symbolic</property>
|
<property name="icon-name">preferences-other-symbolic</property>
|
||||||
<child>
|
<child>
|
||||||
<object class="AdwPreferencesGroup">
|
<object class="AdwPreferencesGroup">
|
||||||
<property name="title" translatable="yes">Model Tweaks</property>
|
<property name="title" translatable="yes">Model Tweaks</property>
|
||||||
<property name="description" translatable="yes">Manage the behavior of the AI models</property>
|
<property name="description" translatable="yes">Manage the behavior of the AI models</property>
|
||||||
|
<child>
|
||||||
|
<object class="AdwSpinRow" id="temperature_spin">
|
||||||
|
<signal name="changed" handler="model_spin_changed"/>
|
||||||
|
<property name="name">temperature</property>
|
||||||
|
<property name="title" translatable="yes">Temperature</property>
|
||||||
|
<property name="subtitle" translatable="yes">The temperature of the model. Increasing the temperature will make the model answer more creatively. (Default: 0.8)</property>
|
||||||
|
<property name="digits">1</property>
|
||||||
|
<property name="adjustment">
|
||||||
|
<object class="GtkAdjustment">
|
||||||
|
<property name="lower">0</property>
|
||||||
|
<property name="upper">1</property>
|
||||||
|
<property name="step-increment">0.1</property>
|
||||||
|
</object>
|
||||||
|
</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="AdwSpinRow" id="seed_spin">
|
||||||
|
<signal name="changed" handler="model_spin_changed"/>
|
||||||
|
<property name="name">seed</property>
|
||||||
|
<property name="title" translatable="yes">Seed</property>
|
||||||
|
<property name="subtitle" translatable="yes">Sets the random number seed to use for generation. Setting this to a specific number will make the model generate the same text for the same prompt. (Default: 0 (random))</property>
|
||||||
|
<property name="adjustment">
|
||||||
|
<object class="GtkAdjustment">
|
||||||
|
<property name="lower">0</property>
|
||||||
|
<property name="upper">999999</property>
|
||||||
|
<property name="step-increment">1</property>
|
||||||
|
</object>
|
||||||
|
</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="AdwSpinRow" id="keep_alive_spin">
|
||||||
|
<signal name="changed" handler="model_spin_changed"/>
|
||||||
|
<property name="name">keep_alive</property>
|
||||||
|
<property name="title" translatable="yes">Keep Alive Time</property>
|
||||||
|
<property name="subtitle" translatable="yes">Controls how long the model will stay loaded into memory following the request in minutes (default: 5)</property>
|
||||||
|
<property name="adjustment">
|
||||||
|
<object class="GtkAdjustment">
|
||||||
|
<property name="lower">0</property>
|
||||||
|
<property name="upper">999999</property>
|
||||||
|
<property name="step-increment">1</property>
|
||||||
|
</object>
|
||||||
|
</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
</object>
|
</object>
|
||||||
</child>-->
|
</child>
|
||||||
</object>
|
</object>
|
||||||
|
|
||||||
<object class="AdwDialog" id="manage_models_dialog">
|
<object class="AdwDialog" id="manage_models_dialog">
|
||||||
@@ -569,10 +622,15 @@
|
|||||||
</item>
|
</item>
|
||||||
</section>
|
</section>
|
||||||
</menu>
|
</menu>
|
||||||
<menu id="chat_context_menu">
|
<menu id="chats_button_menu">
|
||||||
<section>
|
<section>
|
||||||
<item>
|
<item>
|
||||||
<attribute name="label" translatable="yes">Remove</attribute>
|
<attribute name="label" translatable="yes">Export current chat</attribute>
|
||||||
|
<attribute name="action">app.export_current_chat</attribute>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<attribute name="label" translatable="yes">Import chat</attribute>
|
||||||
|
<attribute name="action">app.import_chat</attribute>
|
||||||
</item>
|
</item>
|
||||||
</section>
|
</section>
|
||||||
</menu>
|
</menu>
|
||||||
|
|||||||
Reference in New Issue
Block a user