17 Commits
1.0.2 ... 1.0.3

Author SHA1 Message Date
jeffser
55a636f4d1 typo 2024-08-01 01:30:20 -06:00
jeffser
0fc8730272 dialog added to version notes 2024-08-01 01:27:49 -06:00
jeffser
61a2bc466e Changed content rating because of the donation dialog 2024-08-01 01:13:14 -06:00
jeffser
62b1923bf4 Added support dialog 2024-08-01 01:11:27 -06:00
jeffser
8e25376a12 Merge branch 'main' of github.com-jeffser:Jeffser/Alpaca 2024-08-01 00:49:26 -06:00
jeffser
a9ab5d45a4 Preparing for 1.0.3 2024-08-01 00:49:19 -06:00
Jeffry Samuel
ce2a2f0b93 :) 2024-08-01 00:40:45 -06:00
jeffser
9cb6b0b665 Code block and markup fixes 2024-08-01 00:33:26 -06:00
jeffser
dfc21fc0e9 Fixed date format for Chinese translation 2024-07-31 23:32:49 -06:00
jeffser
19b089e6c6 Fixed problems with localization 2024-07-31 22:36:39 -06:00
jeffser
02aa2734e0 Changed window min height 2024-07-31 22:08:48 -06:00
jeffser
66f9fd7231 better check for connection 2024-07-31 21:17:31 -06:00
jeffser
1b125cb704 Appearance changes 2024-07-31 21:13:23 -06:00
jeffser
29f5d85c7b Added string to translation list 2024-07-31 19:55:30 -06:00
jeffser
c192a1f31c Added compatibility with generic code blocks without explicit language 2024-07-31 19:54:47 -06:00
jeffser
3b20daf807 Added bearer token entry to connection error dialog 2024-07-31 19:42:46 -06:00
jeffser
760c00e8ae Added German template 2024-07-30 12:48:20 -06:00
8 changed files with 1823 additions and 37 deletions

View File

@@ -22,7 +22,7 @@ Alpaca is an [Ollama](https://github.com/ollama/ollama) client where you can man
- Import / Export chats - Import / Export chats
- Delete / Edit messages - Delete / Edit messages
- YouTube recognition (Ask questions about a YouTube video using the transcript) - YouTube recognition (Ask questions about a YouTube video using the transcript)
- Website recognition (Ask questions about a certain question by parsing the url) - Website recognition (Ask questions about a certain website by parsing the url)
## Screenies ## Screenies
Chatting with a model | Image recognition | Code highlighting Chatting with a model | Image recognition | Code highlighting

View File

@@ -70,7 +70,9 @@
<caption>Multiple models being downloaded</caption> <caption>Multiple models being downloaded</caption>
</screenshot> </screenshot>
</screenshots> </screenshots>
<content_rating type="oars-1.1" /> <content_rating type="oars-1.1">
<content_attribute id="money-purchasing">mild</content_attribute>
</content_rating>
<url type="bugtracker">https://github.com/Jeffser/Alpaca/issues</url> <url type="bugtracker">https://github.com/Jeffser/Alpaca/issues</url>
<url type="homepage">https://jeffser.com/alpaca/</url> <url type="homepage">https://jeffser.com/alpaca/</url>
<url type="donation">https://github.com/sponsors/Jeffser</url> <url type="donation">https://github.com/sponsors/Jeffser</url>
@@ -78,6 +80,25 @@
<url type="contribute">https://github.com/Jeffser/Alpaca/discussions/154</url> <url type="contribute">https://github.com/Jeffser/Alpaca/discussions/154</url>
<url type="vcs-browser">https://github.com/Jeffser/Alpaca</url> <url type="vcs-browser">https://github.com/Jeffser/Alpaca</url>
<releases> <releases>
<release version="1.0.3" date="2024-08-01">
<url type="details">https://github.com/Jeffser/Alpaca/releases/tag/1.0.3</url>
<description>
<p>New</p>
<ul>
<li>Bearer Token entry on connection error dialog</li>
<li>Small appearance changes</li>
<li>Compatibility with code blocks without explicit language</li>
<li>Rare, optional and dismissible support dialog</li>
</ul>
<p>Fixes</p>
<ul>
<li>Date format for Simplified Chinese translation</li>
<li>Bug with unsupported localizations</li>
<li>Min height being too large to be used on mobile</li>
<li>Remote connection checker bug</li>
</ul>
</description>
</release>
<release version="1.0.2" date="2024-07-29"> <release version="1.0.2" date="2024-07-29">
<url type="details">https://github.com/Jeffser/Alpaca/releases/tag/1.0.2</url> <url type="details">https://github.com/Jeffser/Alpaca/releases/tag/1.0.2</url>
<description> <description>

View File

@@ -1,5 +1,5 @@
project('Alpaca', 'c', project('Alpaca', 'c',
version: '1.0.2', version: '1.0.3',
meson_version: '>= 0.62.0', meson_version: '>= 0.62.0',
default_options: [ 'warning_level=2', 'werror=false', ], default_options: [ 'warning_level=2', 'werror=false', ],
) )

1697
po/de.po Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -172,26 +172,38 @@ def remove_attached_file(self, name):
# RECONNECT REMOTE | WORKS # RECONNECT REMOTE | WORKS
def reconnect_remote_response(self, dialog, task, entry): def reconnect_remote_response(self, dialog, task, url_entry, bearer_entry):
response = dialog.choose_finish(task) response = dialog.choose_finish(task)
if not task or response == "remote": if not task or response == "remote":
self.connect_remote(entry.get_text()) self.connect_remote(url_entry.get_text(), bearer_entry.get_text())
elif response == "local": elif response == "local":
self.connect_local() self.connect_local()
elif response == "close": elif response == "close":
self.destroy() self.destroy()
def reconnect_remote(self, current_url): def reconnect_remote(self, current_url, current_bearer_token):
entry = Gtk.Entry( entry_url = Gtk.Entry(
css_classes = ["error"], css_classes = ["error"],
text = current_url text = current_url,
placeholder_text = "URL"
) )
entry_bearer_token = Gtk.Entry(
css_classes = ["error"] if current_bearer_token else None,
text = current_bearer_token,
placeholder_text = "Bearer Token (Optional)"
)
container = Gtk.Box(
orientation = 1,
spacing = 10
)
container.append(entry_url)
container.append(entry_bearer_token)
dialog = Adw.AlertDialog( dialog = Adw.AlertDialog(
heading=_("Connection Error"), heading=_("Connection Error"),
body=_("The remote instance has disconnected"), body=_("The remote instance has disconnected"),
extra_child=entry extra_child=container
) )
entry.connect("activate", lambda entry, dialog: reconnect_remote_response(self, dialog, None, entry)) #entry.connect("activate", lambda entry, dialog: reconnect_remote_response(self, dialog, None, entry))
dialog.add_response("close", _("Close Alpaca")) dialog.add_response("close", _("Close Alpaca"))
dialog.add_response("local", _("Use local instance")) dialog.add_response("local", _("Use local instance"))
dialog.add_response("remote", _("Connect")) dialog.add_response("remote", _("Connect"))
@@ -199,7 +211,7 @@ def reconnect_remote(self, current_url):
dialog.choose( dialog.choose(
parent = self, parent = self,
cancellable = None, cancellable = None,
callback = lambda dialog, task, entry=entry: reconnect_remote_response(self, dialog, task, entry) callback = lambda dialog, task, url_entry=entry_url, bearer_entry=entry_bearer_token: reconnect_remote_response(self, dialog, task, url_entry, bearer_entry)
) )
# CREATE MODEL | WORKS # CREATE MODEL | WORKS
@@ -357,3 +369,31 @@ def attach_website(self, url):
cancellable = None, cancellable = None,
callback = lambda dialog, task, url=url: attach_website_response(self, dialog, task, url) callback = lambda dialog, task, url=url: attach_website_response(self, dialog, task, url)
) )
# Begging for money :3
def support_response(self, dialog, task):
res = dialog.choose_finish(task)
if res == 'later': return
elif res == 'support':
self.show_toast(_("Thank you!"), self.main_overlay)
os.system('xdg-open https://github.com/sponsors/Jeffser')
self.show_support = False
self.save_server_config()
def support(self):
dialog = Adw.AlertDialog(
heading=_("Support"),
body=_("Are you enjoying Alpaca? Consider sponsoring the project!"),
close_response="nope"
)
dialog.add_response("nope", _("Don't show again"))
dialog.set_response_appearance("nope", Adw.ResponseAppearance.DESTRUCTIVE)
dialog.add_response("later", _("Later"))
dialog.add_response("support", _("Support"))
dialog.set_response_appearance("support", Adw.ResponseAppearance.SUGGESTED)
dialog.choose(
parent = self,
cancellable = None,
callback = lambda dialog, task: support_response(self, dialog, task)
)

View File

@@ -12,3 +12,7 @@
border-radius: 5px; border-radius: 5px;
padding: 5px; padding: 5px;
} }
.chat_row:selected {
background: mix(@theme_bg_color, @theme_selected_bg_color, 0.3);
color: mix(@window_fg_color, @theme_selected_bg_color, 0.5);
}

View File

@@ -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, gettext, locale, subprocess, uuid, shutil, tarfile, tempfile, logging import json, requests, threading, os, re, base64, sys, gettext, locale, subprocess, uuid, shutil, tarfile, tempfile, logging, random
from time import sleep from time import sleep
from io import BytesIO from io import BytesIO
from PIL import Image from PIL import Image
@@ -44,7 +44,6 @@ class AlpacaWindow(Adw.ApplicationWindow):
localedir = os.path.join(os.path.abspath(os.path.dirname(__file__)), 'locale') localedir = os.path.join(os.path.abspath(os.path.dirname(__file__)), 'locale')
locale.setlocale(locale.LC_ALL, '')
gettext.bindtextdomain('com.jeffser.Alpaca', localedir) gettext.bindtextdomain('com.jeffser.Alpaca', localedir)
gettext.textdomain('com.jeffser.Alpaca') gettext.textdomain('com.jeffser.Alpaca')
_ = gettext.gettext _ = gettext.gettext
@@ -61,6 +60,7 @@ class AlpacaWindow(Adw.ApplicationWindow):
pulling_models = {} pulling_models = {}
chats = {"chats": {_("New Chat"): {"messages": {}}}, "selected_chat": "New Chat", "order": []} chats = {"chats": {_("New Chat"): {"messages": {}}}, "selected_chat": "New Chat", "order": []}
attachments = {} attachments = {}
show_support = True
#Override elements #Override elements
override_HSA_OVERRIDE_GFX_VERSION = Gtk.Template.Child() override_HSA_OVERRIDE_GFX_VERSION = Gtk.Template.Child()
@@ -167,7 +167,7 @@ class AlpacaWindow(Adw.ApplicationWindow):
buffer = self.editing_message["text_view"].get_buffer() buffer = self.editing_message["text_view"].get_buffer()
text = buffer.get_text(buffer.get_start_iter(), buffer.get_end_iter(), False).rstrip('\n') text = buffer.get_text(buffer.get_start_iter(), buffer.get_end_iter(), False).rstrip('\n')
footer = "<small>" + self.editing_message["footer"] + "</small>" footer = "<small>" + self.editing_message["footer"] + "</small>"
buffer.insert_markup(buffer.get_end_iter(), footer, len(footer)) buffer.insert_markup(buffer.get_end_iter(), footer, len(footer.encode('utf-8')))
self.chats["chats"][self.chats["selected_chat"]]["messages"][self.editing_message["id"]]["content"] = text self.chats["chats"][self.chats["selected_chat"]]["messages"][self.editing_message["id"]]["content"] = text
self.editing_message = None self.editing_message = None
self.save_history() self.save_history()
@@ -229,7 +229,7 @@ class AlpacaWindow(Adw.ApplicationWindow):
#self.attachments[name] = {"path": file_path, "type": file_type, "content": content} #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) 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 = self.generate_datetime_format(current_datetime) 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, id=id)
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)
@@ -290,6 +290,9 @@ class AlpacaWindow(Adw.ApplicationWindow):
@Gtk.Template.Callback() @Gtk.Template.Callback()
def change_remote_url(self, entry): def change_remote_url(self, entry):
if not entry.get_text().startswith("http"):
entry.set_text("http://{}".format(entry.get_text()))
return
self.remote_url = entry.get_text() self.remote_url = entry.get_text()
logger.debug(f"Changing remote url: {self.remote_url}") logger.debug(f"Changing remote url: {self.remote_url}")
if self.run_remote: if self.run_remote:
@@ -596,7 +599,7 @@ Generate a title following these rules:
) )
message_buffer = message_text.get_buffer() message_buffer = message_text.get_buffer()
message_buffer.insert(message_buffer.get_end_iter(), msg) 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)) if footer is not None: message_buffer.insert_markup(message_buffer.get_end_iter(), footer, len(footer.encode('utf-8')))
delete_button = Gtk.Button( delete_button = Gtk.Button(
icon_name = "user-trash-symbolic", icon_name = "user-trash-symbolic",
@@ -778,14 +781,18 @@ Generate a title following these rules:
def save_server_config(self): def save_server_config(self):
with open(os.path.join(self.config_dir, "server.json"), "w+") as f: with open(os.path.join(self.config_dir, "server.json"), "w+") as f:
json.dump({'remote_url': self.remote_url, 'remote_bearer_token': self.remote_bearer_token, 'run_remote': self.run_remote, 'local_port': local_instance.port, 'run_on_background': self.run_on_background, 'model_tweaks': self.model_tweaks, 'ollama_overrides': local_instance.overrides}, f, indent=6) json.dump({'remote_url': self.remote_url, 'remote_bearer_token': self.remote_bearer_token, 'run_remote': self.run_remote, 'local_port': local_instance.port, 'run_on_background': self.run_on_background, 'model_tweaks': self.model_tweaks, 'ollama_overrides': local_instance.overrides, 'show_support': self.show_support}, f, indent=6)
def verify_connection(self): def verify_connection(self):
response = connection_handler.simple_get(f"{connection_handler.url}/api/tags") try:
if response.status_code == 200: response = connection_handler.simple_get(f"{connection_handler.url}/api/tags")
self.save_server_config() if response.status_code == 200:
self.update_list_local_models() self.save_server_config()
return response.status_code == 200 self.update_list_local_models()
return response.status_code == 200
except Exception as e:
logger.error(e)
return False
def add_code_blocks(self): def add_code_blocks(self):
text = self.bot_message.get_text(self.bot_message.get_start_iter(), self.bot_message.get_end_iter(), True) text = self.bot_message.get_text(self.bot_message.get_start_iter(), self.bot_message.get_end_iter(), True)
@@ -803,13 +810,23 @@ Generate a title following these rules:
code_text = match.group(2) code_text = match.group(2)
parts.append({"type": "code", "text": code_text, "language": language}) parts.append({"type": "code", "text": code_text, "language": language})
pos = end pos = end
# Match code blocks without language
no_lang_code_block_pattern = re.compile(r'`\n(.*?)\n`', re.DOTALL)
for match in no_lang_code_block_pattern.finditer(text):
start, end = match.span()
if pos < start:
normal_text = text[pos:start]
parts.append({"type": "normal", "text": normal_text.strip()})
code_text = match.group(1)
parts.append({"type": "code", "text": code_text, "language": None})
pos = end
# Extract any remaining normal text after the last code block # Extract any remaining normal text after the last code block
if pos < len(text): if pos < len(text):
normal_text = text[pos:] normal_text = text[pos:]
if normal_text.strip(): if normal_text.strip():
parts.append({"type": "normal", "text": normal_text.strip()}) parts.append({"type": "normal", "text": normal_text.strip()})
bold_pattern = re.compile(r'\*\*(.*?)\*\*') #"**text**" bold_pattern = re.compile(r'\*\*(.*?)\*\*') #"**text**"
code_pattern = re.compile(r'`(.*?)`') #"`text`" code_pattern = re.compile(r'`([^`\n]*?)`') #"`text`"
h1_pattern = re.compile(r'^#\s(.*)$') #"# text" h1_pattern = re.compile(r'^#\s(.*)$') #"# text"
h2_pattern = re.compile(r'^##\s(.*)$') #"## text" h2_pattern = re.compile(r'^##\s(.*)$') #"## text"
markup_pattern = re.compile(r'<(b|u|tt|span.*)>(.*?)<\/(b|u|tt|span)>') #heh butt span, I'm so funny markup_pattern = re.compile(r'<(b|u|tt|span.*)>(.*?)<\/(b|u|tt|span)>') #heh butt span, I'm so funny
@@ -843,17 +860,19 @@ Generate a title following these rules:
start, end = match.span() start, end = match.span()
if position < start: if position < start:
message_buffer.insert(message_buffer.get_end_iter(), part['text'][position:start]) message_buffer.insert(message_buffer.get_end_iter(), part['text'][position:start])
message_buffer.insert_markup(message_buffer.get_end_iter(), match.group(0), len(match.group(0))) message_buffer.insert_markup(message_buffer.get_end_iter(), match.group(0), len(match.group(0).encode('utf-8')))
position = end position = end
if position < len(part['text']): if position < len(part['text']):
message_buffer.insert(message_buffer.get_end_iter(), part['text'][position:]) message_buffer.insert(message_buffer.get_end_iter(), part['text'][position:])
if footer: message_buffer.insert_markup(message_buffer.get_end_iter(), footer, len(footer)) if footer: message_buffer.insert_markup(message_buffer.get_end_iter(), footer, len(footer.encode('utf-8')))
self.bot_message_box.append(message_text) self.bot_message_box.append(message_text)
else: else:
language = GtkSource.LanguageManager.get_default().get_language(part['language']) language = None
if part['language']:
language = GtkSource.LanguageManager.get_default().get_language(part['language'])
if language: if language:
buffer = GtkSource.Buffer.new_with_language(language) buffer = GtkSource.Buffer.new_with_language(language)
else: else:
@@ -871,7 +890,7 @@ Generate a title following these rules:
source_view.set_editable(False) source_view.set_editable(False)
code_block_box = Gtk.Box(css_classes=["card"], orientation=1, overflow=1) code_block_box = Gtk.Box(css_classes=["card"], orientation=1, overflow=1)
title_box = Gtk.Box(margin_start=12, margin_top=3, margin_bottom=3, margin_end=3) title_box = Gtk.Box(margin_start=12, margin_top=3, margin_bottom=3, margin_end=3)
title_box.append(Gtk.Label(label=language.get_name() if language else part['language'], hexpand=True, xalign=0)) title_box.append(Gtk.Label(label=language.get_name() if language else _("Code Block"), hexpand=True, xalign=0))
copy_button = Gtk.Button(icon_name="edit-copy-symbolic", css_classes=["flat", "circular"], tooltip_text=_("Copy Message")) copy_button = Gtk.Button(icon_name="edit-copy-symbolic", css_classes=["flat", "circular"], tooltip_text=_("Copy Message"))
copy_button.connect("clicked", self.on_copy_code_clicked, buffer) copy_button.connect("clicked", self.on_copy_code_clicked, buffer)
title_box.append(copy_button) title_box.append(copy_button)
@@ -917,9 +936,9 @@ Generate a title following these rules:
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 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()) GLib.idle_add(vadjustment.set_value, vadjustment.get_upper())
if data['done']: if data['done']:
formated_date = 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"][id]["date"], '%Y/%m/%d %H:%M:%S')))
text = f"\n\n<small>{data['model'].split(':')[0].replace('-', ' ').title()} ({data['model'].split(':')[1]})\n{formated_date}</small>" text = f"\n\n{data['model'].split(':')[0].replace('-', ' ').title()} ({data['model'].split(':')[1]})\n<small>{formated_date}</small>"
GLib.idle_add(self.bot_message.insert_markup, self.bot_message.get_end_iter(), text, len(text)) GLib.idle_add(self.bot_message.insert_markup, self.bot_message.get_end_iter(), text, len(text.encode('utf-8')))
self.save_history() self.save_history()
GLib.idle_add(self.bot_message_button_container.set_visible, True) GLib.idle_add(self.bot_message_button_container.set_visible, True)
#Notification #Notification
@@ -1082,11 +1101,11 @@ Generate a title following these rules:
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 key, message in self.chats['chats'][self.chats["selected_chat"]]['messages'].items(): for key, message in self.chats['chats'][self.chats["selected_chat"]]['messages'].items():
if message: if message:
formated_date = self.generate_datetime_format(datetime.strptime(message['date'] + (":00" if message['date'].count(":") == 1 else ""), '%Y/%m/%d %H:%M:%S')) 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': 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, id=key)
else: else:
self.show_message(message['content'], True, f"\n\n<small>{message['model'].split(':')[0].replace('-', ' ').title()} ({message['model'].split(':')[1]})\n{formated_date}</small>", id=key) self.show_message(message['content'], True, f"\n\n{message['model'].split(':')[0].replace('-', ' ').title()} ({message['model'].split(':')[1]})\n<small>{formated_date}</small>", id=key)
self.add_code_blocks() self.add_code_blocks()
self.bot_message = None self.bot_message = None
@@ -1234,9 +1253,10 @@ Generate a title following these rules:
logger.debug("Showing preferences dialog") logger.debug("Showing preferences dialog")
self.preferences_dialog.present(self) self.preferences_dialog.present(self)
def connect_remote(self, url): def connect_remote(self, url, bearer_token):
logger.debug(f"Connecting to remote: {url}") logger.debug(f"Connecting to remote: {url}")
connection_handler.url = url connection_handler.url = url
connection_handler.bearer_token = bearer_token
self.remote_url = connection_handler.url self.remote_url = connection_handler.url
self.remote_connection_entry.set_text(self.remote_url) self.remote_connection_entry.set_text(self.remote_url)
if self.verify_connection() == False: self.connection_error() if self.verify_connection() == False: self.connection_error()
@@ -1253,7 +1273,7 @@ Generate a title following these rules:
def connection_error(self): def connection_error(self):
logger.error("Connection error") logger.error("Connection error")
if self.run_remote: if self.run_remote:
dialogs.reconnect_remote(self, connection_handler.url) dialogs.reconnect_remote(self, connection_handler.url, connection_handler.bearer_token)
else: else:
local_instance.reset() local_instance.reset()
self.show_toast(_("There was an error with the local Ollama instance, so it has been reset"), self.main_overlay) self.show_toast(_("There was an error with the local Ollama instance, so it has been reset"), self.main_overlay)
@@ -1558,7 +1578,11 @@ Generate a title following these rules:
if override in local_instance.overrides: if override in local_instance.overrides:
element.set_text(local_instance.overrides[override]) element.set_text(local_instance.overrides[override])
#Support dialog
if 'show_support' not in data or data['show_support']:
if random.randint(0, 99) == 0:
dialogs.support(self)
if 'show_support' in data: self.show_support = data['show_support']
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)

View File

@@ -6,7 +6,7 @@
<signal name="close-request" handler="closing_app"/> <signal name="close-request" handler="closing_app"/>
<property name="resizable">True</property> <property name="resizable">True</property>
<property name="width-request">360</property> <property name="width-request">360</property>
<property name="height-request">700</property> <property name="height-request">400</property>
<property name="default-width">1300</property> <property name="default-width">1300</property>
<property name="default-height">800</property> <property name="default-height">800</property>
<property name="title">Alpaca</property> <property name="title">Alpaca</property>
@@ -244,7 +244,7 @@
<property name="valign">3</property> <property name="valign">3</property>
<property name="tooltip-text" translatable="yes">Send Message</property> <property name="tooltip-text" translatable="yes">Send Message</property>
<style> <style>
<class name="suggested-action"/> <class name="accent"/>
<class name="circular"/> <class name="circular"/>
</style> </style>
<child> <child>