Skip to content

Commit

Permalink
Model profile pictures, better model creator, new design for messages
Browse files Browse the repository at this point in the history
  • Loading branch information
Jeffser committed Dec 27, 2024
1 parent f8f1731 commit ec8bf9c
Show file tree
Hide file tree
Showing 6 changed files with 221 additions and 73 deletions.
5 changes: 5 additions & 0 deletions src/custom_widgets/chat_widget.py
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,11 @@ def __init__(self):
self.connect("row-selected", lambda listbox, row: self.chat_changed(row))
self.tab_list = []

def update_profile_pictures(self):
for tab in self.tab_list:
for message in tab.chat_window.messages.values():
message.update_profile_picture()

def update_welcome_screens(self, show_prompts:bool):
for tab in self.tab_list:
if tab.chat_window.welcome_screen:
Expand Down
86 changes: 71 additions & 15 deletions src/custom_widgets/message_widget.py
Original file line number Diff line number Diff line change
Expand Up @@ -425,7 +425,7 @@ def regenerate_message(self):
class footer(Gtk.Box):
__gtype_name__ = 'AlpacaMessageFooter'

def __init__(self, dt:datetime.datetime, model:str=None, system:bool=False):
def __init__(self, dt:datetime.datetime, message_element, model:str=None, system:bool=False):
super().__init__(
orientation=0,
hexpand=True,
Expand All @@ -439,16 +439,24 @@ def __init__(self, dt:datetime.datetime, model:str=None, system:bool=False):
ellipsize=3,
wrap_mode=2,
margin_end=10,
margin_start=10 if message_element.profile_picture_data else 0,
xalign=0,
focusable=True,
css_classes=['dim-label']
css_classes=[] if message_element.profile_picture_data else ['dim-label']
)
message_author = ""
if model:
message_author = window.convert_model_name(model, 0) + " • "
model_name = window.convert_model_name(model, 0).rstrip(" (latest)")
if message_element.profile_picture_data:
message_author = model_name
else:
message_author = "{} • ".format(model_name)
if system:
message_author = "{} • ".format(_("System"))
label.set_markup("<small>{}{}</small>".format(message_author, GLib.markup_escape_text(self.format_datetime(dt))))
if message_element.profile_picture_data:
label.set_markup("<span weight='bold'>{}</span>\n<small>{}</small>".format(message_author, GLib.markup_escape_text(self.format_datetime(dt))))
else:
label.set_markup("<small>{}{}</small>".format(message_author, GLib.markup_escape_text(self.format_datetime(dt))))
self.append(label)

def format_datetime(self, dt:datetime) -> str:
Expand All @@ -462,14 +470,44 @@ def format_datetime(self, dt:datetime) -> str:

def add_options_button(self):
self.popup = option_popup(self.get_parent().get_parent())
self.options_button = Gtk.MenuButton(
icon_name='view-more-horizontal-symbolic',
css_classes=['message_options_button', 'flat', 'circular', 'dim-label'],
popover=self.popup
)
self.prepend(self.options_button)
message_element = self.get_parent().get_parent()

if self.options_button:
self.options_button.get_parent().remove(self.options_button)

if message_element.profile_picture_data:
image_data = base64.b64decode(message_element.profile_picture_data)
loader = GdkPixbuf.PixbufLoader.new()
loader.write(image_data)
loader.close()
pixbuf = loader.get_pixbuf()
texture = Gdk.Texture.new_for_pixbuf(pixbuf)
message_element.profile_picture = Gtk.Image.new_from_paintable(texture)
message_element.profile_picture.set_size_request(40, 40)
self.options_button = Gtk.MenuButton(
width_request=40,
height_request=40,
css_classes=['circular'],
valign=1,
popover=self.popup,
margin_top=5
)
self.options_button.set_overflow(1)
self.options_button.set_child(message_element.profile_picture)
list(self.options_button)[0].add_css_class('circular')
list(self.options_button)[0].set_overflow(1)
message_element.prepend(self.options_button)

if not self.options_button:
self.options_button = Gtk.MenuButton(
icon_name='view-more-horizontal-symbolic',
css_classes=['message_options_button', 'flat', 'circular', 'dim-label'],
popover=self.popup
)
self.prepend(self.options_button)


class message(Adw.Bin):
class message(Gtk.Box):
__gtype_name__ = 'AlpacaMessage'

def __init__(self, message_id:str, model:str=None, system:bool=False):
Expand All @@ -484,12 +522,18 @@ def __init__(self, message_id:str, model:str=None, system:bool=False):
self.attachment_c = None
self.spinner = None
self.text = None
self.profile_picture_data = None
self.profile_picture = None
if self.bot and self.model:
model_row = window.model_manager.model_selector.get_model_by_name(self.model)
if model_row:
self.profile_picture_data = model_row.profile_picture_data

self.container = Gtk.Box(
orientation=1,
halign='fill',
css_classes=["response_message"] if self.bot or self.system else ["card", "user_message"],
spacing=10,
spacing=5,
width_request=-1 if self.bot or self.system else 100
)

Expand All @@ -498,7 +542,17 @@ def __init__(self, message_id:str, model:str=None, system:bool=False):
name=message_id,
halign=0 if self.bot or self.system else 2
)
self.set_child(self.container)

self.append(self.container)

def update_profile_picture(self):
if self.bot and self.model:
model_row = window.model_manager.model_selector.get_model_by_name(self.model)
if model_row:
new_profile_picture_data = model_row.profile_picture_data
if new_profile_picture_data != self.profile_picture_data:
self.profile_picture_data = new_profile_picture_data
self.add_footer(self.dt)

def add_attachment(self, name:str, attachment_type:str, content:str):
if attachment_type == 'image':
Expand All @@ -514,8 +568,10 @@ def add_attachment(self, name:str, attachment_type:str, content:str):

def add_footer(self, dt:datetime.datetime):
self.dt = dt
self.footer = footer(self.dt, self.model, self.system)
self.container.append(self.footer)
if self.footer:
self.container.remove(self.footer)
self.footer = footer(self.dt, self, self.model, self.system)
self.container.prepend(self.footer)
self.footer.add_options_button()

def update_message(self, data:dict):
Expand Down
130 changes: 87 additions & 43 deletions src/custom_widgets/model_widget.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
import gi
gi.require_version('Gtk', '4.0')
gi.require_version('GtkSource', '5')
from gi.repository import Gtk, GObject, Gio, Adw, GtkSource, GLib, Gdk
import logging, os, datetime, re, shutil, threading, json, sys, glob, icu
from gi.repository import Gtk, GObject, Gio, Adw, GtkSource, GLib, Gdk, GdkPixbuf
import logging, os, datetime, re, shutil, threading, json, sys, glob, icu, base64, sqlite3
from ..internal import config_dir, data_dir, cache_dir, source_dir
from .. import available_models_descriptions
from . import dialog_widget
Expand Down Expand Up @@ -72,6 +72,13 @@ def __init__(self, model_name:str, data:dict):
)
self.data = data
self.image_recognition = 'projector_info' in self.data
self.profile_picture_data = None
sqlite_con = sqlite3.connect(window.sqlite_path)
cursor = sqlite_con.cursor()
picture = cursor.execute("SELECT picture FROM model WHERE id=?", (self.get_name(),)).fetchone()
if picture:
self.profile_picture_data = picture[0]
sqlite_con.close()

class model_selector_button(Gtk.MenuButton):
__gtype_name__ = 'AlpacaModelSelectorButton'
Expand Down Expand Up @@ -119,10 +126,19 @@ def remove_model(self, model_name:str):
self.get_popover().model_list_box.remove(next((model for model in list(self.get_popover().model_list_box) if model.get_name() == model_name), None))
self.model_changed(self.get_popover().model_list_box)
window.title_stack.set_visible_child_name('model_selector' if len(window.model_manager.get_model_list()) > 0 else 'no_models')
sqlite_con = sqlite3.connect(window.sqlite_path)
cursor = sqlite_con.cursor()
cursor.execute("DELETE FROM model WHERE id=?", (self.get_name(),))
sqlite_con.commit()
sqlite_con.close()
window.chat_list_box.update_profile_pictures()

def clear_list(self):
self.get_popover().model_list_box.remove_all()

def get_model_by_name(self, model_name:str) -> object:
return next((model for model in list(self.get_popover().model_list_box) if model.get_name() == model_name), None)

class pulling_model(Gtk.ListBoxRow):
__gtype_name__ = 'AlpacaPullingModel'

Expand Down Expand Up @@ -377,23 +393,73 @@ def __init__(self, model_name:str, categories:list):
name=model_name
)

def change_pfp(self, file_dialog, result, button, model):
file = file_dialog.open_finish(result)
if file:
model.profile_picture_data = window.get_content_of_file(file.get_path(), 'image')
image_data = base64.b64decode(model.profile_picture_data)
loader = GdkPixbuf.PixbufLoader.new()
loader.write(image_data)
loader.close()
pixbuf = loader.get_pixbuf()
texture = Gdk.Texture.new_for_pixbuf(pixbuf)
image = Gtk.Image.new_from_paintable(texture)
image.set_size_request(64, 64)
button.set_overflow(1)
button.set_child(image)
sqlite_con = sqlite3.connect(window.sqlite_path)
cursor = sqlite_con.cursor()
if cursor.execute("SELECT picture FROM model WHERE id=?", (self.get_name(),)).fetchone():
cursor.execute("UPDATE model SET picture=? WHERE id=?", (model.profile_picture_data, self.get_name()))
else:
cursor.execute("INSERT INTO model (id, picture) VALUES (?, ?)", (self.get_name(), model.profile_picture_data))
sqlite_con.commit()
sqlite_con.close()
window.chat_list_box.update_profile_pictures()

def show_information(self, button):
model = next((element for element in list(window.model_manager.model_selector.get_popover().model_list_box) if element.get_name() == self.get_name()), None)
model_name = model.get_child().get_label()

window.model_detail_page.set_title(' ('.join(model_name.split(' (')[:-1]))
window.model_detail_page.set_description(' ('.join(model_name.split(' (')[-1:])[:-1])
window.model_detail_create_button.set_name(model_name)
window.model_detail_create_button.set_tooltip_text(_("Create Model Based on '{}'").format(model_name))

details_flow_box = Gtk.FlowBox(
valign=1,
hexpand=True,
vexpand=False,
selection_mode=0,
max_children_per_line=2,
min_children_per_line=1,
)
actionrow = Adw.ActionRow(
title="<big>{}</big>".format(' ('.join(model_name.split(' (')[:-1])),
subtitle=' ('.join(model_name.split(' (')[-1:])[:-1],
css_classes=["card"]
)
pfp_button = Gtk.Button(
css_classes=['circular'],
valign=3,
icon_name='brain-augemnted-symbolic',
width_request=64,
height_request=64,
margin_top=10,
margin_bottom=10,
tooltip_text=_("Change Model Picture")
)
if model.profile_picture_data:
image_data = base64.b64decode(model.profile_picture_data)
loader = GdkPixbuf.PixbufLoader.new()
loader.write(image_data)
loader.close()
pixbuf = loader.get_pixbuf()
texture = Gdk.Texture.new_for_pixbuf(pixbuf)
image = Gtk.Image.new_from_paintable(texture)
image.set_size_request(64, 64)
pfp_button.set_overflow(1)
pfp_button.set_child(image)

file_filter = Gtk.FileFilter()
file_filter.add_suffix('png')
file_filter.add_suffix('jpg')
file_filter.add_suffix('jpeg')
file_filter.add_suffix('webp')

pfp_button.connect('clicked', lambda button: Gtk.FileDialog(default_filter=file_filter).open(window, None, lambda file_dialog, result, button=button, model=model: self.change_pfp(file_dialog, result, button, model)))

actionrow.add_prefix(pfp_button)
window.model_detail_header.set_child(actionrow)

translation_strings={
'modified_at': _('Modified At'),
Expand All @@ -403,53 +469,31 @@ def show_information(self, button):
'parameter_size': _('Parameter Size'),
'quantization_level': _('Quantization Level')
}

window.model_detail_system.set_label(model.data['system'] if 'system' in model.data else '')
window.model_detail_information.remove_all()
if 'modified_at' in model.data and model.data['modified_at']:
details_flow_box.append(information_bow(
window.model_detail_information.append(information_bow(
title=translation_strings['modified_at'],
subtitle=datetime.datetime.strptime(':'.join(model.data['modified_at'].split(':')[:2]), '%Y-%m-%dT%H:%M').strftime('%Y-%m-%d %H:%M')
))

for name, value in model.data['details'].items():
if isinstance(value, str):
details_flow_box.append(information_bow(
window.model_detail_information.append(information_bow(
title=translation_strings[name] if name in translation_strings else name.replace('_', ' ').title(),
subtitle=value
))

categories_box = Gtk.FlowBox(
hexpand=True,
vexpand=False,
orientation=0,
selection_mode=0,
valign=1,
halign=0
)
window.model_detail_categories.remove_all()
languages = ['en']
if self.get_name() in available_models:
languages = available_models[self.get_name()]['languages']

for category in self.categories + ['language:' + icu.Locale(lan).getDisplayLanguage(icu.Locale(lan)).title() for lan in languages]:
categories_box.append(category_pill(category, True))
window.model_detail_categories.append(category_pill(category, True))

if 'multilingual' in self.categories and len(languages) == 1:
window.model_tag_flow_box.append(category_pill('language:Others...', True))

container_box = Gtk.Box(
orientation=1,
spacing=10,
hexpand=True,
vexpand=True,
margin_top=12,
margin_bottom=12,
margin_start=12,
margin_end=12
)

container_box.append(details_flow_box)
container_box.append(categories_box)

window.model_detail_page.set_child(container_box)
window.navigation_view_manage_models.push_by_tag('model_information')

class local_model_list(Gtk.ListBox):
Expand Down Expand Up @@ -739,8 +783,8 @@ def update_local_list(self):
logger.error(e)
window.connection_error()
window.title_stack.set_visible_child_name('model_selector' if len(window.model_manager.get_model_list()) > 0 else 'no_models')
#window.title_stack.set_visible_child_name('model_selector')
window.chat_list_box.update_welcome_screens(len(self.get_model_list()) > 0)
GLib.idle_add(window.chat_list_box.update_profile_pictures)
#GLib.idle_add(self.chat_list_box.update_welcome_screens, len(self.model_manager.get_model_list()) > 0)

#Should only be called when the app starts
def update_available_list(self):
Expand Down
2 changes: 1 addition & 1 deletion src/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ stacksidebar {
min-height: 20px;
}
.message > box {
padding: 5px 5px 10px 5px;
padding: 5px 5px 5px 5px;
}


Expand Down
Loading

0 comments on commit ec8bf9c

Please sign in to comment.