Merge branch 'main' of github.com-jeffser:Jeffser/Alpaca
This commit is contained in:
commit
c95f764c77
@ -59,7 +59,7 @@ You can change anything except `$HOME` and `$OLLAMA_HOST`, to do this go to `~/.
|
||||
- [TylerLaBree](https://github.com/TylerLaBree) for their requests and ideas
|
||||
- [Alexkdeveloper](https://github.com/alexkdeveloper) for their help translating the app to Russian
|
||||
- [Imbev](https://github.com/imbev) for their reports and suggestions
|
||||
- [Nokse](https://github.com/Nokse22) for their contributions to the UI
|
||||
- [Nokse](https://github.com/Nokse22) for their contributions to the UI and table rendering
|
||||
- [Louis Chauvet-Villaret](https://github.com/loulou64490) for their suggestions and help translating the app to French
|
||||
- [CounterFlow64](https://github.com/CounterFlow64) for their help translating the app to Norwegian
|
||||
|
||||
|
@ -80,6 +80,21 @@
|
||||
<url type="contribute">https://github.com/Jeffser/Alpaca/discussions/154</url>
|
||||
<url type="vcs-browser">https://github.com/Jeffser/Alpaca</url>
|
||||
<releases>
|
||||
<release version="1.0.4" date="2024-08-01">
|
||||
<url type="details">https://github.com/Jeffser/Alpaca/releases/tag/1.0.4</url>
|
||||
<description>
|
||||
<p>New</p>
|
||||
<ul>
|
||||
<li>Added table rendering (Thanks Nokse)</li>
|
||||
</ul>
|
||||
<p>Fixes</p>
|
||||
<ul>
|
||||
<li>Made support dialog more common</li>
|
||||
<li>Dialog title on tag chooser when downloading models didn't display properly</li>
|
||||
<li>Prevent chat generation from generating a title with multiple lines</li>
|
||||
</ul>
|
||||
</description>
|
||||
</release>
|
||||
<release version="1.0.3" date="2024-08-01">
|
||||
<url type="details">https://github.com/Jeffser/Alpaca/releases/tag/1.0.3</url>
|
||||
<description>
|
||||
|
@ -1,5 +1,5 @@
|
||||
project('Alpaca', 'c',
|
||||
version: '1.0.3',
|
||||
version: '1.0.4',
|
||||
meson_version: '>= 0.62.0',
|
||||
default_options: [ 'warning_level=2', 'werror=false', ],
|
||||
)
|
||||
|
1218
po/alpaca.pot
1218
po/alpaca.pot
File diff suppressed because it is too large
Load Diff
1303
po/nb_NO.po
1303
po/nb_NO.po
File diff suppressed because it is too large
Load Diff
1235
po/pt_BR.po
1235
po/pt_BR.po
File diff suppressed because it is too large
Load Diff
1247
po/zh_CN.po
1247
po/zh_CN.po
File diff suppressed because it is too large
Load Diff
@ -43,7 +43,8 @@ alpaca_sources = [
|
||||
'dialogs.py',
|
||||
'local_instance.py',
|
||||
'available_models.json',
|
||||
'available_models_descriptions.py'
|
||||
'available_models_descriptions.py',
|
||||
'table_widget.py'
|
||||
]
|
||||
|
||||
install_data(alpaca_sources, install_dir: moduledir)
|
||||
|
126
src/table_widget.py
Normal file
126
src/table_widget.py
Normal file
@ -0,0 +1,126 @@
|
||||
import gi
|
||||
from gi.repository import Adw
|
||||
from gi.repository import Gtk, GObject, Gio
|
||||
|
||||
import re
|
||||
|
||||
class MarkdownTable:
|
||||
def __init__(self):
|
||||
self.headers = []
|
||||
self.rows = Gio.ListStore()
|
||||
self.alignments = []
|
||||
|
||||
def __repr__(self):
|
||||
table_repr = 'Headers: {}\n'.format(self.headers)
|
||||
table_repr += 'Alignments: {}\n'.format(self.alignments)
|
||||
table_repr += 'Rows:\n'
|
||||
for row in self.rows:
|
||||
table_repr += ' | '.join(row) + '\n'
|
||||
return table_repr
|
||||
|
||||
class Row(GObject.GObject):
|
||||
def __init__(self, _values):
|
||||
super().__init__()
|
||||
|
||||
self.values = _values
|
||||
|
||||
def get_column_value(self, index):
|
||||
return self.values[index]
|
||||
|
||||
class TableWidget(Gtk.Frame):
|
||||
__gtype_name__ = 'TableWidget'
|
||||
|
||||
def __init__(self, markdown):
|
||||
super().__init__()
|
||||
|
||||
self.table = MarkdownTable()
|
||||
|
||||
self.set_halign(Gtk.Align.START)
|
||||
|
||||
self.table_widget = Gtk.ColumnView(
|
||||
show_column_separators=True,
|
||||
show_row_separators=True,
|
||||
reorderable=False,
|
||||
)
|
||||
scrolled_window = Gtk.ScrolledWindow(
|
||||
vscrollbar_policy=Gtk.PolicyType.NEVER,
|
||||
propagate_natural_width=True
|
||||
)
|
||||
self.set_child(scrolled_window)
|
||||
|
||||
try:
|
||||
self.parse_markdown_table(markdown)
|
||||
self.make_table()
|
||||
scrolled_window.set_child(self.table_widget)
|
||||
except:
|
||||
label = Gtk.Label(
|
||||
label=markdown.lstrip('\n').rstrip('\n'),
|
||||
selectable=True,
|
||||
margin_top=6,
|
||||
margin_bottom=6,
|
||||
margin_start=6,
|
||||
margin_end=6
|
||||
)
|
||||
scrolled_window.set_child(label)
|
||||
|
||||
def parse_markdown_table(self, markdown_text):
|
||||
# Define regex patterns for matching the table components
|
||||
header_pattern = r'^\|(.+?)\|$'
|
||||
separator_pattern = r'^\|(\s*[:-]+:?\s*\|)+$'
|
||||
row_pattern = r'^\|(.+?)\|$'
|
||||
|
||||
# Split the text into lines
|
||||
lines = markdown_text.strip().split('\n')
|
||||
|
||||
# Extract headers
|
||||
header_match = re.match(header_pattern, lines[0], re.MULTILINE)
|
||||
if header_match:
|
||||
headers = [header.strip() for header in header_match.group(1).replace("*", "").split('|') if header.strip()]
|
||||
self.table.headers = headers
|
||||
|
||||
# Extract alignments
|
||||
separator_match = re.match(separator_pattern, lines[1], re.MULTILINE)
|
||||
if separator_match:
|
||||
alignments = []
|
||||
separator_columns = lines[1].replace(" ", "").split('|')[1:-1]
|
||||
for sep in separator_columns:
|
||||
if ':' in sep:
|
||||
if sep.startswith('-') and sep.endswith(':'):
|
||||
alignments.append(1)
|
||||
elif sep.startswith(':') and sep.endswith('-'):
|
||||
alignments.append(0)
|
||||
else:
|
||||
alignments.append(0.5)
|
||||
else:
|
||||
alignments.append(0) # Default alignment is start
|
||||
self.table.alignments = alignments
|
||||
|
||||
# Extract rows
|
||||
for line in lines[2:]:
|
||||
row_match = re.match(row_pattern, line, re.MULTILINE)
|
||||
if row_match:
|
||||
rows = line.split('|')[1:-1]
|
||||
row = Row(rows)
|
||||
self.table.rows.append(row)
|
||||
|
||||
def make_table(self):
|
||||
|
||||
def _on_factory_setup(_factory, list_item, align):
|
||||
label = Gtk.Label(xalign=align, ellipsize=3, selectable=True)
|
||||
list_item.set_child(label)
|
||||
|
||||
def _on_factory_bind(_factory, list_item, index):
|
||||
label_widget = list_item.get_child()
|
||||
row = list_item.get_item()
|
||||
label_widget.set_label(row.get_column_value(index))
|
||||
|
||||
for index, column_name in enumerate(self.table.headers):
|
||||
column = Gtk.ColumnViewColumn(title=column_name, expand=True)
|
||||
factory = Gtk.SignalListItemFactory()
|
||||
factory.connect("setup", _on_factory_setup, self.table.alignments[index])
|
||||
factory.connect("bind", _on_factory_bind, index)
|
||||
column.set_factory(factory)
|
||||
self.table_widget.append_column(column)
|
||||
|
||||
selection = Gtk.NoSelection.new(model=self.table.rows)
|
||||
self.table_widget.set_model(model=selection)
|
@ -28,7 +28,7 @@ from PIL import Image
|
||||
from pypdf import PdfReader
|
||||
from datetime import datetime
|
||||
from . import dialogs, local_instance, connection_handler, available_models_descriptions
|
||||
|
||||
from .table_widget import TableWidget
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@ -580,7 +580,7 @@ Generate a title following these rules:
|
||||
if 'images' in message: data["images"] = message['images']
|
||||
response = connection_handler.simple_post(f"{connection_handler.url}/api/generate", data=json.dumps(data))
|
||||
|
||||
new_chat_name = json.loads(response.text)["response"].strip().removeprefix("Title: ").removeprefix("title: ").strip('\'"').title()
|
||||
new_chat_name = json.loads(response.text)["response"].strip().removeprefix("Title: ").removeprefix("title: ").strip('\'"').replace('\n', ' ').title()
|
||||
new_chat_name = new_chat_name[:50] + (new_chat_name[50:] and '...')
|
||||
self.rename_chat(label_element.get_name(), new_chat_name, label_element)
|
||||
|
||||
@ -820,6 +820,16 @@ Generate a title following these rules:
|
||||
code_text = match.group(1)
|
||||
parts.append({"type": "code", "text": code_text, "language": None})
|
||||
pos = end
|
||||
# Match tables
|
||||
table_pattern = re.compile(r'((\r?\n){2}|^)([^\r\n]*\|[^\r\n]*(\r?\n)?)+(?=(\r?\n){2}|$)', re.MULTILINE)
|
||||
for match in table_pattern.finditer(text):
|
||||
start, end = match.span()
|
||||
if pos < start:
|
||||
normal_text = text[pos:start]
|
||||
parts.append({"type": "normal", "text": normal_text.strip()})
|
||||
table_text = match.group(0)
|
||||
parts.append({"type": "table", "text": table_text})
|
||||
pos = end
|
||||
# Extract any remaining normal text after the last code block
|
||||
if pos < len(text):
|
||||
normal_text = text[pos:]
|
||||
@ -869,7 +879,7 @@ Generate a title following these rules:
|
||||
if footer: message_buffer.insert_markup(message_buffer.get_end_iter(), footer, len(footer.encode('utf-8')))
|
||||
|
||||
self.bot_message_box.append(message_text)
|
||||
else:
|
||||
elif part['type'] == 'code':
|
||||
language = None
|
||||
if part['language']:
|
||||
language = GtkSource.LanguageManager.get_default().get_language(part['language'])
|
||||
@ -899,6 +909,9 @@ Generate a title following these rules:
|
||||
code_block_box.append(source_view)
|
||||
self.bot_message_box.append(code_block_box)
|
||||
self.style_manager.connect("notify::dark", self.on_theme_changed, buffer)
|
||||
elif part['type'] == 'table':
|
||||
table = TableWidget(part['text'])
|
||||
self.bot_message_box.append(table)
|
||||
vadjustment = self.chat_window.get_vadjustment()
|
||||
vadjustment.set_value(vadjustment.get_upper())
|
||||
self.bot_message = None
|
||||
@ -1056,7 +1069,7 @@ Generate a title following these rules:
|
||||
def list_available_model_tags(self, model_name):
|
||||
logger.debug("Listing available model tags")
|
||||
self.navigation_view_manage_models.push_by_tag('model_tags_page')
|
||||
self.navigation_view_manage_models.find_page('model_tags_page').set_title(model_name.capitalize())
|
||||
self.navigation_view_manage_models.find_page('model_tags_page').set_title(model_name.replace("-", " ").title())
|
||||
self.model_link_button.set_name(self.available_models[model_name]['url'])
|
||||
self.model_link_button.set_tooltip_text(self.available_models[model_name]['url'])
|
||||
self.available_model_list_box.unselect_all()
|
||||
@ -1580,7 +1593,7 @@ Generate a title following these rules:
|
||||
|
||||
#Support dialog
|
||||
if 'show_support' not in data or data['show_support']:
|
||||
if random.randint(0, 99) == 0:
|
||||
if random.randint(0, 49) == 0:
|
||||
dialogs.support(self)
|
||||
if 'show_support' in data: self.show_support = data['show_support']
|
||||
self.background_switch.set_active(self.run_on_background)
|
||||
|
Loading…
x
Reference in New Issue
Block a user