diff --git a/com.jeffser.Alpaca.json b/com.jeffser.Alpaca.json index 51cd752..542a10a 100644 --- a/com.jeffser.Alpaca.json +++ b/com.jeffser.Alpaca.json @@ -71,6 +71,44 @@ } ] }, + { + "name": "python3-pypdf", + "buildsystem": "simple", + "build-commands": [ + "pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} \"pypdf\" --no-build-isolation" + ], + "sources": [ + { + "type": "file", + "url": "https://files.pythonhosted.org/packages/c9/d1/450b19bbdbb2c802f554312c62ce2a2c0d8744fe14735bc70ad2803578c7/pypdf-4.2.0-py3-none-any.whl", + "sha256": "dc035581664e0ad717e3492acebc1a5fc23dba759e788e3d4a9fc9b1a32e72c1" + } + ] + }, + { + "name": "python3-python-docx", + "buildsystem": "simple", + "build-commands": [ + "pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} \"python-docx\" --no-build-isolation" + ], + "sources": [ + { + "type": "file", + "url": "https://files.pythonhosted.org/packages/63/f7/ffbb6d2eb67b80a45b8a0834baa5557a14a5ffce0979439e7cd7f0c4055b/lxml-5.2.2.tar.gz", + "sha256": "bb2dc4898180bea79863d5487e5f9c7c34297414bad54bcd0f0852aee9cfdb87" + }, + { + "type": "file", + "url": "https://files.pythonhosted.org/packages/3e/3d/330d9efbdb816d3f60bf2ad92f05e1708e4a1b9abe80461ac3444c83f749/python_docx-1.1.2-py3-none-any.whl", + "sha256": "08c20d6058916fb19853fcf080f7f42b6270d89eac9fa5f8c15f691c0017fabe" + }, + { + "type": "file", + "url": "https://files.pythonhosted.org/packages/26/9f/ad63fc0248c5379346306f8668cda6e2e2e9c95e01216d2b8ffd9ff037d0/typing_extensions-4.12.2-py3-none-any.whl", + "sha256": "04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d" + } + ] + }, { "name": "ollama", "buildsystem": "simple", diff --git a/src/dialogs.py b/src/dialogs.py index 841e470..9069a7d 100644 --- a/src/dialogs.py +++ b/src/dialogs.py @@ -270,15 +270,24 @@ def create_model_from_file(self): # FILE CHOOSER | WORKS -def attach_file_response(self, file_dialog, result, file_type): +def attach_file_response(self, file_dialog, result): + file_types = { + "plain_text": ["txt", "md", "html", "css", "js", "py", "java", "json", "xml"], + "image": ["png", "jpeg", "jpg", "webp", "gif"], + "pdf": ["pdf"], + "docx": ["docx"] + } try: file = file_dialog.open_finish(result) except: return - self.attach_file(file.get_path(), file_type) - - -def attach_file(self, filter, file_type): + extension = file.get_path().split(".")[-1] + file_type = next(key for key, value in file_types.items() if extension in value) + if not file_type: return if file_type == 'image' and not self.verify_if_image_can_be_used(): self.show_toast('error', 8, self.main_overlay) return + self.attach_file(file.get_path(), file_type) + + +def attach_file(self, filter): file_dialog = Gtk.FileDialog(default_filter=filter) - file_dialog.open(self, None, lambda file_dialog, result, file_type=file_type: attach_file_response(self, file_dialog, result, file_type)) + file_dialog.open(self, None, lambda file_dialog, result: attach_file_response(self, file_dialog, result)) diff --git a/src/window.py b/src/window.py index 1c68f4a..09a9f8e 100644 --- a/src/window.py +++ b/src/window.py @@ -21,10 +21,11 @@ import gi gi.require_version('GtkSource', '5') gi.require_version('GdkPixbuf', '2.0') from gi.repository import Adw, Gtk, Gdk, GLib, GtkSource, Gio, GdkPixbuf -import json, requests, threading, os, re, base64, sys, gettext, locale, webbrowser, subprocess, uuid, shutil, tarfile, tempfile +import json, requests, threading, os, re, base64, sys, gettext, locale, webbrowser, subprocess, uuid, shutil, tarfile, tempfile, docx from time import sleep from io import BytesIO from PIL import Image +from pypdf import PdfReader from datetime import datetime from .available_models import available_models from . import dialogs, local_instance, connection_handler, update_history @@ -90,10 +91,10 @@ class AlpacaWindow(Adw.ApplicationWindow): chats_menu_button = Gtk.Template.Child() attachment_container = Gtk.Template.Child() attachment_box = Gtk.Template.Child() - file_filter_image = Gtk.Template.Child() file_filter_tar = Gtk.Template.Child() file_filter_gguf = Gtk.Template.Child() - file_filter_text = Gtk.Template.Child() + file_filter_attachments = Gtk.Template.Child() + attachment_button = Gtk.Template.Child() model_drop_down = Gtk.Template.Child() model_string_list = Gtk.Template.Child() @@ -1129,6 +1130,20 @@ class AlpacaWindow(Adw.ApplicationWindow): elif file_type == 'plain_text': with open(file_path, 'r') as f: return f.read() + elif file_type == 'pdf': + reader = PdfReader(file_path) + if len(reader.pages) == 0: return None + text = "" + for i, page in enumerate(reader.pages): + text += f"\n- Page {i}\n{page.extract_text()}\n" + return text + elif file_type == 'docx': + document = docx.Document(file_path) + if len(document.paragraphs) == 0: return None + text = "" + for paragraph in document.paragraphs: + text += f"{paragraph.text}\n" + return text def remove_attached_file(self, button): del self.attachments[button.get_name()] @@ -1143,7 +1158,12 @@ class AlpacaWindow(Adw.ApplicationWindow): button_content = Adw.ButtonContent( label=shown_name, - icon_name={"image": "image-x-generic-symbolic", "plain_text": "document-text-symbolic"}[file_type] + icon_name={ + "image": "image-x-generic-symbolic", + "plain_text": "document-text-symbolic", + "pdf": "document-text-symbolic", + "docx": "document-text-symbolic" + }[file_type] ) button = Gtk.Button( vexpand=True, @@ -1176,10 +1196,8 @@ class AlpacaWindow(Adw.ApplicationWindow): self.get_application().create_action('import_chat', lambda *_: self.import_chat()) self.get_application().create_action('create_model_from_existing', lambda *_: dialogs.create_model_from_existing(self)) self.get_application().create_action('create_model_from_file', lambda *_: dialogs.create_model_from_file(self)) - self.get_application().create_action('attach_image', lambda *_: dialogs.attach_file(self, self.file_filter_image, "image")) - self.get_application().create_action('attach_plain_text', lambda *_: dialogs.attach_file(self, self.file_filter_text, "plain_text")) self.add_chat_button.connect("clicked", lambda button : self.new_chat()) - + self.attachment_button.connect("clicked", lambda button, file_filter=self.file_filter_attachments: dialogs.attach_file(self, file_filter)) self.create_model_name.get_delegate().connect("insert-text", self.check_alphanumeric) 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()) diff --git a/src/window.ui b/src/window.ui index f77122e..dbc2080 100644 --- a/src/window.ui +++ b/src/window.ui @@ -189,9 +189,7 @@ 0 12 - - attachment_menu - 0 + false 3 Attach file @@ -903,21 +901,8 @@ - -
- - Plain text file - app.attach_plain_text - - - Image - app.attach_image - -
-
- + - txt md html @@ -927,17 +912,14 @@ java json xml + pdf + docx + png + jpeg + webp + gif - - - image/svg+xml - image/png - image/jpeg - image/webp - image/gif - - application/x-tar