100 Commits
1.0.3 ... 1.0.6

Author SHA1 Message Date
jeffser
fa22647acd Output Ollama version when it is launched 2024-08-04 23:29:32 -06:00
jeffser
dd5d82fe7a Updated spanish + prepared the other languages 2024-08-04 23:17:00 -06:00
jeffser
98b179aeb5 Preparing for 1.0.6 2024-08-04 22:57:52 -06:00
jeffser
e1f1c005a0 Changed model dropdown width and moved manage models button to primary menu 2024-08-04 22:49:43 -06:00
jeffser
6e226c5a4f Fixed selected model changes when entering manage models dialog 2024-08-04 22:42:49 -06:00
jeffser
7440fa5a37 Fixed GGUF support and enter key handling 2024-08-04 22:23:02 -06:00
jeffser
4fe204605a Linting code 2024-08-04 22:09:37 -06:00
jeffser
4446b42b82 Linting code 2024-08-04 21:57:57 -06:00
jeffser
4b6cd17d0a Linting code 2024-08-04 21:43:23 -06:00
jeffser
1a6e74271c Linting code 2024-08-04 21:27:12 -06:00
jeffser
6ba3719031 Linting code 2024-08-04 21:20:47 -06:00
jeffser
dd95e3df7e Linting code 2024-08-04 21:11:00 -06:00
jeffser
69fd7853c8 Added explanations 2024-08-04 21:03:26 -06:00
jeffser
c01c478ffe Fixed 2024-08-04 20:59:47 -06:00
jeffser
f8be1da83a Fixed 2024-08-04 20:54:59 -06:00
jeffser
3a7625486e Disable 'line is too long' message 2024-08-04 20:53:18 -06:00
jeffser
fdc3b6c573 Maybe this time 2024-08-04 20:51:56 -06:00
jeffser
76939ed51f Fixed 2024-08-04 20:49:44 -06:00
jeffser
b9cf761f4a Fixed 2024-08-04 20:47:54 -06:00
jeffser
4c515ba541 bruh 2024-08-04 20:44:47 -06:00
jeffser
d7c3595bf1 added rcfile 2024-08-04 20:43:11 -06:00
jeffser
1fbd6a0824 Lint fixes and added lint config file 2024-08-04 20:41:35 -06:00
jeffser
ccb59c7f02 Fix 2024-08-04 20:34:08 -06:00
jeffser
04bef3e82a Skip available_models_description.py 2024-08-04 20:33:39 -06:00
jeffser
17105b98ed Fix for lint 2024-08-04 20:31:40 -06:00
jeffser
4bff1515a9 Merge branch 'main' of github.com-jeffser:Jeffser/Alpaca 2024-08-04 20:30:30 -06:00
jeffser
0a75893346 Fix 2024-08-04 20:30:24 -06:00
Jeffry Samuel
2ed92467f9 Update pylint.yml 2024-08-04 20:28:47 -06:00
jeffser
634ac122d9 Fixed file so it passes the linter 2024-08-04 20:28:27 -06:00
Jeffry Samuel
44640b7e53 Create pylint.yml 2024-08-04 20:20:23 -06:00
jeffser
47e7b22a7e Merge branch 'main' of github.com-jeffser:Jeffser/Alpaca 2024-08-04 20:01:41 -06:00
jeffser
918928d4bb Fixed image tooltips 2024-08-04 20:01:34 -06:00
Jeffry Samuel
69fc172779 Update README.md 2024-08-04 19:54:25 -06:00
Jeffry Samuel
d84dabbe4d Update feature_request.md 2024-08-04 19:52:22 -06:00
Jeffry Samuel
23114210c4 Update bug_report.md 2024-08-04 19:52:12 -06:00
jeffser
ea80e5a223 Remade doap 2024-08-04 19:50:06 -06:00
jeffser
6087f31d41 Removed whitespace 2024-08-04 19:44:10 -06:00
jeffser
30ee292a32 Updated doap 2024-08-04 19:43:22 -06:00
Jeffry Samuel
705a9319f5 Update Alpaca.doap 2024-08-04 19:37:34 -06:00
jeffser
c789d9d87c Added doap 2024-08-04 19:36:41 -06:00
jeffser
a7681b5505 Removed that workflow 2024-08-04 19:21:58 -06:00
Jeffry Samuel
9e74d8af0b Create meson-build.yml 2024-08-04 19:21:04 -06:00
jeffser
b52061f849 Removed that workflow 2024-08-04 19:17:46 -06:00
Jeffry Samuel
01b875c283 Update flatpak-lint.yml 2024-08-04 19:15:06 -06:00
Jeffry Samuel
4cc3b78321 Update flatpak-lint.yml 2024-08-04 19:11:06 -06:00
Jeffry Samuel
6205db87e6 Update flatpak-lint.yml 2024-08-04 19:07:42 -06:00
Jeffry Samuel
518633b153 Update flatpak-lint.yml 2024-08-04 19:05:23 -06:00
Jeffry Samuel
988ee7b7e7 Update flatpak-lint.yml 2024-08-04 19:03:44 -06:00
Jeffry Samuel
cdadde60ce Update flatpak-lint.yml 2024-08-04 19:00:00 -06:00
Jeffry Samuel
4bb01d86d9 Update flatpak-lint.yml 2024-08-04 18:55:34 -06:00
Jeffry Samuel
4cac43520f Testing 2024-08-04 18:53:36 -06:00
Jeffry Samuel
d6dddd16f1 Update flatpak-builder.yml 2024-08-04 18:44:24 -06:00
Jeffry Samuel
c0da054635 Update flatpak-builder.yml 2024-08-04 18:43:13 -06:00
jeffser
2b4d94ca55 fixed logger in dialogs.py 2024-08-04 18:35:26 -06:00
Jeffry Samuel
e8e564738a Update com.jeffser.Alpaca.json 2024-08-04 18:26:06 -06:00
Jeffry Samuel
d48fbd8b62 Update and rename flatpak-build.yml to flatpak-builder.yml 2024-08-04 18:22:50 -06:00
Jeffry Samuel
c1f80f209e Update flatpak-build.yml 2024-08-04 18:18:44 -06:00
Jeffry Samuel
ed6b32c827 Update flatpak-build.yml 2024-08-04 18:16:50 -06:00
Jeffry Samuel
fc436fd352 Update flatpak-build.yml 2024-08-04 18:14:45 -06:00
Jeffry Samuel
ee6fdb1ca1 Update flatpak-build.yml 2024-08-04 18:12:37 -06:00
Jeffry Samuel
988db30355 Update flatpak-build.yml 2024-08-04 18:12:19 -06:00
Jeffry Samuel
ea98ee5e99 Update flatpak-build.yml 2024-08-04 18:10:29 -06:00
Jeffry Samuel
b8d1d43822 Testing 2024-08-04 18:07:27 -06:00
jeffser
0d017c6d14 Changed shortcuts to standards 2024-08-04 17:50:52 -06:00
jeffser
2825e9a003 Fixed window and elements dimensions 2024-08-04 17:41:19 -06:00
jeffser
6e9ddfcbf2 Added sponsor link to about dialog 2024-08-04 17:11:06 -06:00
jeffser
378689be39 Removed support dialog 2024-08-04 16:50:39 -06:00
jeffser
31858fad12 Merge branch 'main' of github.com-jeffser:Jeffser/Alpaca 2024-08-04 16:26:52 -06:00
jeffser
60351d629d Bettter handling of enter key on message entry 2024-08-04 16:26:46 -06:00
aritra saha
715a97159a small update (#190)
* Update bn.po

* Update bn.po

* Create hi.po

* Rename hi.po to po/hi.po

* Update hi.po

* Update hi.po
2024-08-04 14:24:58 -06:00
jeffser
b48ce28b35 Crediting every translator 2024-08-03 15:13:22 -06:00
Jeffry Samuel
7ab0448cd3 Better README !!! 2024-08-03 15:06:56 -06:00
Jeffry Samuel
5f6642fa63 Update README.md 2024-08-03 14:12:42 -06:00
Aleksana
5a0d1ed408 Better handling of standard paths (#187) 2024-08-03 14:07:14 -06:00
Aleksana
131e8fb6be Updated translations (#188) 2024-08-03 14:02:47 -06:00
jeffser
1c7fb8ef93 Updated translations 2024-08-03 00:43:10 -06:00
jeffser
8c0ec3957f Preparing for 1.0.5 2024-08-02 23:56:17 -06:00
jeffser
72063a15d9 Better check for message finishing 2024-08-02 23:48:03 -06:00
jeffser
0d1b15aafc New feature: Regenerate response 2024-08-02 23:42:35 -06:00
jeffser
ca10369bdc Added message to support dialog 2024-08-02 21:44:19 -06:00
jeffser
42af75d8d2 typo 2024-08-02 20:53:19 -06:00
jeffser
a02871dd28 'S fixed again :3 2024-08-02 20:50:04 -06:00
jeffser
e65a8bc648 Proper GGUF / name Model pulling 2024-08-02 20:47:04 -06:00
jeffser
b373b6a34f Sidebar button 2024-08-02 16:44:24 -06:00
jeffser
6d6a0255e2 Better model name handling internally 2024-08-02 16:00:47 -06:00
jeffser
003d6a3d5f Restore last model used 2024-08-02 15:30:03 -06:00
jeffser
77a2c60fe5 Fixed message entry shadow 2024-08-02 15:19:28 -06:00
jeffser
ac3bd699ee Changed width request for model dropdown 2024-08-02 14:51:08 -06:00
jeffser
596498c81e Fixed 'S problem with title generation 2024-08-02 14:42:11 -06:00
jeffser
c95f764c77 Merge branch 'main' of github.com-jeffser:Jeffser/Alpaca 2024-08-02 14:39:26 -06:00
jeffser
5c5be05843 Reverted back to standard styles 2024-08-02 14:39:19 -06:00
aritra saha
3fb26ec49e updated translation (#180)
* Update bn.po

* Update bn.po

* Update bn.po

* Update bn.po

* Update zh_CN.po
2024-08-02 11:19:23 -06:00
jeffser
3f767d22e9 New relase notes 2024-08-01 14:56:38 -06:00
jeffser
7f3fb0d82d Tweaks to chat title generation 2024-08-01 14:52:37 -06:00
jeffser
d56c132459 Fixed title of model tag selector dialog 2024-08-01 14:48:11 -06:00
jeffser
acdce762c9 Translations update 2024-08-01 14:37:06 -06:00
jeffser
bd557d9652 Preparing for 1.0.4 2024-08-01 14:21:55 -06:00
Jeffry Samuel
3363d13fa0 changed support dialog frequency 2024-08-01 14:03:38 -06:00
Jeffry Samuel
52ba44e260 Update README.md 2024-08-01 14:02:28 -06:00
Nokse22
f06c2dae23 Added tables (#179) 2024-08-01 13:44:56 -06:00
32 changed files with 11874 additions and 4974 deletions

View File

@@ -6,7 +6,7 @@ labels: bug
assignees: '' assignees: ''
--- ---
<!--Please be aware that GNOME Code of Conduct applies to Alpaca, https://conduct.gnome.org/-->
**Describe the bug** **Describe the bug**
A clear and concise description of what the bug is. A clear and concise description of what the bug is.

View File

@@ -6,7 +6,7 @@ labels: enhancement
assignees: '' assignees: ''
--- ---
<!--Please be aware that GNOME Code of Conduct applies to Alpaca, https://conduct.gnome.org/-->
**Is your feature request related to a problem? Please describe.** **Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]

18
.github/workflows/flatpak-builder.yml vendored Normal file
View File

@@ -0,0 +1,18 @@
# .github/workflows/flatpak-build.yml
on:
workflow_dispatch:
name: Flatpak Build
jobs:
flatpak:
name: "Flatpak"
runs-on: ubuntu-latest
container:
image: bilelmoussaoui/flatpak-github-actions:gnome-46
options: --privileged
steps:
- uses: actions/checkout@v4
- uses: flatpak/flatpak-github-actions/flatpak-builder@v6
with:
bundle: Alpaca.flatpak
manifest-path: com.jeffser.Alpaca.json
cache-key: flatpak-builder-${{ github.sha }}

24
.github/workflows/pylint.yml vendored Normal file
View File

@@ -0,0 +1,24 @@
name: Pylint
on:
workflow_dispatch:
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.11"]
steps:
- uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v3
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install pylint
- name: Analysing the code with pylint
run: |
pylint --rcfile=.pylintrc $(git ls-files '*.py' | grep -v 'src/available_models_descriptions.py')

14
.pylintrc Normal file
View File

@@ -0,0 +1,14 @@
[MASTER]
[MESSAGES CONTROL]
disable=undefined-variable, line-too-long, missing-function-docstring, consider-using-f-string, import-error
[FORMAT]
max-line-length=200
# Reasons for removing some checks:
# undefined-variable: _() is used by the translator on build time but it is not defined on the scripts
# line-too-long: I... I'm too lazy to make the lines shorter, maybe later
# missing-function-docstring I'm not adding a docstring to all the functions, most are self explanatory
# consider-using-f-string I can't use f-string because of the translator
# import-error The linter doesn't have access to all the libraries that the project itself does

34
Alpaca.doap Normal file
View File

@@ -0,0 +1,34 @@
<Project xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
xmlns:foaf="http://xmlns.com/foaf/0.1/"
xmlns:gnome="http://api.gnome.org/doap-extensions#"
xmlns="http://usefulinc.com/ns/doap#">
<name xml:lang="en">Alpaca</name>
<shortdesc xml:lang="en">An Ollama client made with GTK4 and Adwaita</shortdesc>
<homepage rdf:resource="https://jeffser.com/alpaca" />
<bug-database rdf:resource="https://github.com/Jeffser/Alpaca/issues"/>
<programming-language>Python</programming-language>
<platform>GTK 4</platform>
<platform>Libadwaita</platform>
<maintainer>
<foaf:Person>
<foaf:name>Jeffry Samuel</foaf:name>
<foaf:mbox rdf:resource="mailto:jeffrysamuer@gmail.com"/>
<foaf:account>
<foaf:OnlineAccount>
<foaf:accountServiceHomepage rdf:resource="https://github.com"/>
<foaf:accountName>jeffser</foaf:accountName>
</foaf:OnlineAccount>
</foaf:account>
<foaf:account>
<foaf:OnlineAccount>
<foaf:accountServiceHomepage rdf:resource="https://gitlab.gnome.org"/>
<foaf:accountName>jeffser</foaf:accountName>
</foaf:OnlineAccount>
</foaf:account>
</foaf:Person>
</maintainer>
</Project>

View File

@@ -11,7 +11,11 @@ Alpaca is an [Ollama](https://github.com/ollama/ollama) client where you can man
> [!WARNING] > [!WARNING]
> This project is not affiliated at all with Ollama, I'm not responsible for any damages to your device or software caused by running code given by any AI models. > This project is not affiliated at all with Ollama, I'm not responsible for any damages to your device or software caused by running code given by any AI models.
> [!IMPORTANT]
> Please be aware that [GNOME Code of Conduct](https://conduct.gnome.org) applies to Alpaca before interacting with this repository.
## Features! ## Features!
- Talk to multiple models in the same conversation - Talk to multiple models in the same conversation
- Pull and delete models from the app - Pull and delete models from the app
- Image recognition - Image recognition
@@ -21,47 +25,37 @@ Alpaca is an [Ollama](https://github.com/ollama/ollama) client where you can man
- Notifications - Notifications
- Import / Export chats - Import / Export chats
- Delete / Edit messages - Delete / Edit messages
- Regenerate 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 website 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
:--------------------:|:-----------------:|:----------------------:
![Screenshot from 2024-05-12 19-58-28](https://jeffser.com/images/alpaca/screenie1.png) | ![Screenshot from 2024-05-12 20-01-08](https://jeffser.com/images/alpaca/screenie2.png) | ![Screenshot from 2024-05-12 20-01-31](https://jeffser.com/images/alpaca/screenie3.png)
## Preview Normal conversation | Image recognition | Code highlighting | YouTube transcription | Model management
1. Clone repo using Gnome Builder :------------------:|:-----------------:|:-----------------:|:---------------------:|:----------------:
2. Press the `run` button ![screenie1](https://jeffser.com/images/alpaca/screenie1.png) | ![screenie2](https://jeffser.com/images/alpaca/screenie2.png) | ![screenie3](https://jeffser.com/images/alpaca/screenie3.png) | ![screenie4](https://jeffser.com/images/alpaca/screenie4.png) | ![screenie5](https://jeffser.com/images/alpaca/screenie5.png)
## Instalation ## Translators
1. Go to the `releases` page
2. Download the latest flatpak package
3. Open it
## Ollama session tips Language | Contributors
:----------------------|:-----------
### Change the port of the integrated Ollama instance 🇷🇺 Russian | [Alex K](https://github.com/alexkdeveloper)
Go to `~/.var/app/com.jeffser.Alpaca/config/server.json` and change the `"local_port"` value, by default it is `11435`. 🇪🇸 Spanish | [Jeffry Samuel](https://github.com/jeffser)
🇫🇷 French | [Louis Chauvet-Villaret](https://github.com/loulou64490) , [Théo FORTIN](https://github.com/topiga)
### Backup all the chats 🇧🇷 Brazilian Portuguese | [Daimar Stein](https://github.com/not-a-dev-stein)
The chat data is located in `~/.var/app/com.jeffser.Alpaca/data/chats` you can copy that directory wherever you want to. 🇳🇴 Norwegian | [CounterFlow64](https://github.com/CounterFlow64)
🇮🇳 Bengali | [Aritra Saha](https://github.com/olumolu)
### Force showing the welcome dialog 🇨🇳 Simplified Chinese | [Yuehao Sui](https://github.com/8ar10der) , [Aleksana](https://github.com/Aleksanaa)
To do that you just need to delete the file `~/.var/app/com.jeffser.Alpaca/config/server.json`, this won't affect your saved chats or models.
### Add/Change environment variables for Ollama
You can change anything except `$HOME` and `$OLLAMA_HOST`, to do this go to `~/.var/app/com.jeffser.Alpaca/config/server.json` and change `ollama_overrides` accordingly, some overrides are available to change on the GUI.
--- ---
## Thanks ## Thanks
- [not-a-dev-stein](https://github.com/not-a-dev-stein) for their help with requesting a new icon, bug reports and the translation to Brazilian Portuguese
- [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
- [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
## About forks - [not-a-dev-stein](https://github.com/not-a-dev-stein) for their help with requesting a new icon and bug reports
If you want to fork this... I mean, I think it would be better if you start from scratch, my code isn't well documented at all, but if you really want to, please give me some credit, that's all I ask for... And maybe a donation (joke) - [TylerLaBree](https://github.com/TylerLaBree) for their requests and ideas
- [Imbev](https://github.com/imbev) for their reports and suggestions
- [Nokse](https://github.com/Nokse22) for their contributions to the UI and table rendering
- [Louis Chauvet-Villaret](https://github.com/loulou64490) for their suggestions
- [Aleksana](https://github.com/Aleksanaa) for her help with better handling of directories
- Sponsors for giving me enough money to be able to take a ride to my campus every time I need to <3
- Everyone that has shared kind words of encouragement!

View File

@@ -122,16 +122,16 @@
"sources": [ "sources": [
{ {
"type": "file", "type": "file",
"url": "https://github.com/ollama/ollama/releases/download/v0.3.0/ollama-linux-amd64", "url": "https://github.com/ollama/ollama/releases/download/v0.3.3/ollama-linux-amd64",
"sha256": "b8817c34882c7ac138565836ac1995a2c61261a79315a13a0aebbfe5435da855", "sha256": "2b2a4ee4c86fa5b09503e95616bd1b3ee95238b1b3bf12488b9c27c66b84061a",
"only-arches": [ "only-arches": [
"x86_64" "x86_64"
] ]
}, },
{ {
"type": "file", "type": "file",
"url": "https://github.com/ollama/ollama/releases/download/v0.3.0/ollama-linux-arm64", "url": "https://github.com/ollama/ollama/releases/download/v0.3.3/ollama-linux-arm64",
"sha256": "64be908749212052146f1008dd3867359c776ac1766e8d86291886f53d294d4d", "sha256": "28fddbea0c161bc539fd08a3dc78d51413cfe8da97386cb39420f4f30667e22c",
"only-arches": [ "only-arches": [
"aarch64" "aarch64"
] ]
@@ -145,7 +145,7 @@
"sources" : [ "sources" : [
{ {
"type" : "git", "type" : "git",
"url" : "file:///home/tentri/Documents/Alpaca", "url": "https://github.com/Jeffser/Alpaca.git",
"branch" : "main" "branch" : "main"
} }
] ]

View File

@@ -80,6 +80,64 @@
<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.6" date="2024-08-04">
<url type="details">https://github.com/Jeffser/Alpaca/releases/tag/1.0.6</url>
<description>
<p>New</p>
<ul>
<li>Changed shortcuts to standards</li>
<li>Moved 'Manage Models' button to primary menu</li>
<li>Stable support for GGUF model files</li>
<li>General optimizations</li>
</ul>
<p>Fixes</p>
<ul>
<li>Better handling of enter key (important for Japanese input)</li>
<li>Removed sponsor dialog</li>
<li>Added sponsor link in about dialog</li>
<li>Changed window and elements dimensions</li>
<li>Selected model changes when entering model manager</li>
<li>Better image tooltips</li>
<li>GGUF Support</li>
</ul>
</description>
</release>
<release version="1.0.5" date="2024-08-02">
<url type="details">https://github.com/Jeffser/Alpaca/releases/tag/1.0.5</url>
<description>
<p>New</p>
<ul>
<li>Regenerate any response, even if they are incomplete</li>
<li>Support for pulling models by name:tag</li>
<li>Stable support for GGUF model files</li>
<li>Restored sidebar toggle button</li>
</ul>
<p>Fixes</p>
<ul>
<li>Reverted back to standard styles</li>
<li>Fixed generated titles having "'S" for some reason</li>
<li>Changed min width for model dropdown</li>
<li>Changed message entry shadow</li>
<li>The last model used is now restored when the user changes chat</li>
<li>Better check for message finishing</li>
</ul>
</description>
</release>
<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"> <release version="1.0.3" date="2024-08-01">
<url type="details">https://github.com/Jeffser/Alpaca/releases/tag/1.0.3</url> <url type="details">https://github.com/Jeffser/Alpaca/releases/tag/1.0.3</url>
<description> <description>

View File

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

File diff suppressed because it is too large Load Diff

1746
po/bn.po

File diff suppressed because it is too large Load Diff

1748
po/es.po

File diff suppressed because it is too large Load Diff

1579
po/fr.po

File diff suppressed because it is too large Load Diff

2169
po/hi.po Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

1680
po/ru.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -28,6 +28,7 @@
<file alias="icons/scalable/status/edit-find-symbolic.svg">icons/edit-find-symbolic.svg</file> <file alias="icons/scalable/status/edit-find-symbolic.svg">icons/edit-find-symbolic.svg</file>
<file alias="icons/scalable/status/edit-symbolic.svg">icons/edit-symbolic.svg</file> <file alias="icons/scalable/status/edit-symbolic.svg">icons/edit-symbolic.svg</file>
<file alias="icons/scalable/status/image-missing-symbolic.svg">icons/image-missing-symbolic.svg</file> <file alias="icons/scalable/status/image-missing-symbolic.svg">icons/image-missing-symbolic.svg</file>
<file alias="icons/scalable/status/update-symbolic.svg">icons/update-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>

View File

@@ -1,15 +1,19 @@
# connection_handler.py # connection_handler.py
import json, requests """
Handles requests to remote and integrated instances of Ollama
"""
import json
import requests
#OK=200 response.status_code #OK=200 response.status_code
url = None URL = None
bearer_token = None BEARER_TOKEN = None
def get_headers(include_json:bool) -> dict: def get_headers(include_json:bool) -> dict:
headers = {} headers = {}
if include_json: if include_json:
headers["Content-Type"] = "application/json" headers["Content-Type"] = "application/json"
if bearer_token: if BEARER_TOKEN:
headers["Authorization"] = "Bearer {}".format(bearer_token) headers["Authorization"] = "Bearer {}".format(BEARER_TOKEN)
return headers if len(headers.keys()) > 0 else None return headers if len(headers.keys()) > 0 else None
def simple_get(connection_url:str) -> dict: def simple_get(connection_url:str) -> dict:

View File

@@ -1,11 +1,15 @@
# dialogs.py # dialogs.py
"""
from gi.repository import Adw, Gtk, Gdk, GLib, GtkSource, Gio, GdkPixbuf Handles UI dialogs
"""
import os import os
import logging
from pytube import YouTube from pytube import YouTube
from html2text import html2text from html2text import html2text
from gi.repository import Adw, Gtk
from . import connection_handler from . import connection_handler
logger = logging.getLogger(__name__)
# CLEAR CHAT | WORKS # CLEAR CHAT | WORKS
def clear_chat_response(self, dialog, task): def clear_chat_response(self, dialog, task):
@@ -54,9 +58,11 @@ def delete_chat(self, chat_name):
# RENAME CHAT | WORKS # RENAME CHAT | WORKS
def rename_chat_response(self, dialog, task, old_chat_name, entry, label_element): def rename_chat_response(self, dialog, task, old_chat_name, entry, label_element):
if not entry: return if not entry:
return
new_chat_name = entry.get_text() new_chat_name = entry.get_text()
if old_chat_name == new_chat_name: return if old_chat_name == new_chat_name:
return
if new_chat_name and (task is None or dialog.choose_finish(task) == "rename"): if new_chat_name and (task is None or dialog.choose_finish(task) == "rename"):
self.rename_chat(old_chat_name, new_chat_name, label_element) self.rename_chat(old_chat_name, new_chat_name, label_element)
@@ -82,7 +88,8 @@ def rename_chat(self, chat_name, label_element):
def new_chat_response(self, dialog, task, entry): def new_chat_response(self, dialog, task, entry):
chat_name = _("New Chat") chat_name = _("New Chat")
if entry is not None and entry.get_text() != "": chat_name = entry.get_text() if entry is not None and entry.get_text() != "":
chat_name = entry.get_text()
if chat_name and (task is None or dialog.choose_finish(task) == "create"): if chat_name and (task is None or dialog.choose_finish(task) == "create"):
self.new_chat(chat_name) self.new_chat(chat_name)
@@ -224,7 +231,7 @@ def create_model_from_existing_response(self, dialog, task, dropdown):
def create_model_from_existing(self): def create_model_from_existing(self):
string_list = Gtk.StringList() string_list = Gtk.StringList()
for model in self.local_models: for model in self.local_models:
string_list.append(model) string_list.append(self.convert_model_name(model, 0))
dropdown = Gtk.DropDown() dropdown = Gtk.DropDown()
dropdown.set_model(string_list) dropdown.set_model(string_list)
@@ -243,20 +250,41 @@ def create_model_from_existing(self):
) )
def create_model_from_file_response(self, file_dialog, result): def create_model_from_file_response(self, file_dialog, result):
try: file = file_dialog.open_finish(result)
except:
self.logger.error(e)
return
try: try:
self.create_model(file.get_path(), True) file = file_dialog.open_finish(result)
try:
self.create_model(file.get_path(), True)
except Exception as e:
logger.error(e)
self.show_toast(_("An error occurred while creating the model"), self.main_overlay)
except Exception as e: except Exception as e:
self.logger.error(e) logger.error(e)
self.show_toast(_("An error occurred while creating the model"), self.main_overlay)
def create_model_from_file(self): def create_model_from_file(self):
file_dialog = Gtk.FileDialog(default_filter=self.file_filter_gguf) file_dialog = Gtk.FileDialog(default_filter=self.file_filter_gguf)
file_dialog.open(self, None, lambda file_dialog, result: create_model_from_file_response(self, file_dialog, result)) file_dialog.open(self, None, lambda file_dialog, result: create_model_from_file_response(self, file_dialog, result))
def create_model_from_name_response(self, dialog, task, entry):
model = entry.get_text().lower().strip()
if dialog.choose_finish(task) == 'accept' and model:
self.pull_model(model)
def create_model_from_name(self):
entry = Gtk.Entry()
entry.get_delegate().connect("insert-text", self.check_alphanumeric)
dialog = Adw.AlertDialog(
heading=_("Pull Model"),
body=_("Input the name of the model in this format\nname:tag"),
extra_child=entry
)
dialog.add_response("cancel", _("Cancel"))
dialog.add_response("accept", _("Accept"))
dialog.set_response_appearance("accept", Adw.ResponseAppearance.SUGGESTED)
dialog.choose(
parent = self,
cancellable = None,
callback = lambda dialog, task, entry=entry: create_model_from_name_response(self, dialog, task, entry)
)
# FILE CHOOSER | WORKS # FILE CHOOSER | WORKS
def attach_file_response(self, file_dialog, result): def attach_file_response(self, file_dialog, result):
@@ -265,24 +293,24 @@ def attach_file_response(self, file_dialog, result):
"image": ["png", "jpeg", "jpg", "webp", "gif"], "image": ["png", "jpeg", "jpg", "webp", "gif"],
"pdf": ["pdf"] "pdf": ["pdf"]
} }
try: file = file_dialog.open_finish(result) try:
except: file = file_dialog.open_finish(result)
self.logger.error(e) except Exception as e:
logger.error(e)
return return
extension = file.get_path().split(".")[-1] extension = file.get_path().split(".")[-1]
file_type = next(key for key, value in file_types.items() if extension in value) file_type = next(key for key, value in file_types.items() if extension in value)
if not file_type: return if not file_type:
return
if file_type == 'image' and not self.verify_if_image_can_be_used(): if file_type == 'image' and not self.verify_if_image_can_be_used():
self.show_toast(_("Image recognition is only available on specific models"), self.main_overlay) self.show_toast(_("Image recognition is only available on specific models"), self.main_overlay)
return return
self.attach_file(file.get_path(), file_type) self.attach_file(file.get_path(), file_type)
def attach_file(self, file_filter):
def attach_file(self, filter): file_dialog = Gtk.FileDialog(default_filter=file_filter)
file_dialog = Gtk.FileDialog(default_filter=filter)
file_dialog.open(self, None, lambda file_dialog, result: attach_file_response(self, file_dialog, result)) file_dialog.open(self, None, lambda file_dialog, result: attach_file_response(self, file_dialog, result))
# YouTube caption | WORKS # YouTube caption | WORKS
def youtube_caption_response(self, dialog, task, video_url, caption_drop_down): def youtube_caption_response(self, dialog, task, video_url, caption_drop_down):
@@ -300,7 +328,7 @@ def youtube_caption_response(self, dialog, task, video_url, caption_drop_down):
if not os.path.exists(os.path.join(self.cache_dir, 'tmp/youtube')): if not os.path.exists(os.path.join(self.cache_dir, 'tmp/youtube')):
os.makedirs(os.path.join(self.cache_dir, 'tmp/youtube')) os.makedirs(os.path.join(self.cache_dir, 'tmp/youtube'))
file_path = os.path.join(os.path.join(self.cache_dir, 'tmp/youtube'), f'{yt.title} ({selected_caption.split(" | ")[0]})') file_path = os.path.join(os.path.join(self.cache_dir, 'tmp/youtube'), f'{yt.title} ({selected_caption.split(" | ")[0]})')
with open(file_path, 'w+') as f: with open(file_path, 'w+', encoding="utf-8") as f:
f.write(text) f.write(text)
self.attach_file(file_path, 'youtube') self.attach_file(file_path, 'youtube')
@@ -312,7 +340,8 @@ def youtube_caption(self, video_url):
self.show_toast(_("This video does not have any transcriptions"), self.main_overlay) self.show_toast(_("This video does not have any transcriptions"), self.main_overlay)
return return
caption_list = Gtk.StringList() caption_list = Gtk.StringList()
for caption in captions: caption_list.append("{} | {}".format(caption.name, caption.code)) for caption in captions:
caption_list.append("{} | {}".format(caption.name, caption.code))
caption_drop_down = Gtk.DropDown( caption_drop_down = Gtk.DropDown(
enable_search=True, enable_search=True,
model=caption_list model=caption_list
@@ -348,7 +377,7 @@ def attach_website_response(self, dialog, task, url):
os.makedirs('/tmp/alpaca/websites/') os.makedirs('/tmp/alpaca/websites/')
md_name = self.generate_numbered_name('website.md', os.listdir('/tmp/alpaca/websites')) md_name = self.generate_numbered_name('website.md', os.listdir('/tmp/alpaca/websites'))
file_path = os.path.join('/tmp/alpaca/websites/', md_name) file_path = os.path.join('/tmp/alpaca/websites/', md_name)
with open(file_path, 'w+') as f: with open(file_path, 'w+', encoding="utf-8") as f:
f.write('{}\n\n{}'.format(url, md)) f.write('{}\n\n{}'.format(url, md))
self.attach_file(file_path, 'website') self.attach_file(file_path, 'website')
else: else:
@@ -369,31 +398,3 @@ 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

@@ -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 7.957031 2 c -0.082031 0 -0.164062 0.003906 -0.246093 0.007812 c -0.1875 0.011719 -0.375 0.03125 -0.5625 0.0625 c -1.582032 0.226563 -3.007813 1.070313 -3.96875 2.34375 c -0.804688 1.074219 -1.183594 2.332032 -1.179688 3.585938 h 2.003906 c 0 -0.832031 0.253906 -1.671875 0.796875 -2.398438 c 1.335938 -1.777343 3.820313 -2.113281 5.597657 -0.78125 c 0.429687 0.320313 0.769531 0.734376 1.03125 1.1875 h -1.4375 c -0.550782 0 -1 0.449219 -1 1 v 1 h 6 v -6 h -1 c -0.550782 0 -1 0.449219 -1 1 v 1.6875 c -1.113282 -1.695312 -3.007813 -2.710937 -5.039063 -2.695312 z m 0 0"/><path d="m 8.035156 15.007812 c 0.082032 0 0.164063 -0.003906 0.246094 -0.007812 c 0.1875 -0.011719 0.375 -0.03125 0.5625 -0.0625 c 1.582031 -0.226562 3.007812 -1.066406 3.96875 -2.34375 c 0.804688 -1.074219 1.183594 -2.332031 1.179688 -3.585938 h -2.003907 c -0.003906 0.832032 -0.257812 1.675782 -0.796875 2.398438 c -1.335937 1.777344 -3.820312 2.113281 -5.597656 0.78125 c -0.429688 -0.320312 -0.769531 -0.734375 -1.03125 -1.1875 h 1.4375 c 0.550781 0 1 -0.449219 1 -1 v -1 h -6 v 6 h 1 c 0.550781 0 1 -0.449219 1 -1 v -1.6875 c 1.113281 1.695312 3.007812 2.710938 5.035156 2.695312 z m 0 0"/></g></svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

25
src/internal.py Normal file
View File

@@ -0,0 +1,25 @@
# internal.py
"""
Handles paths, they can be different if the app is running as a Flatpak
"""
import os
APP_ID = "com.jeffser.Alpaca"
IN_FLATPAK = bool(os.getenv("FLATPAK_ID"))
def get_xdg_home(env, default):
if IN_FLATPAK:
return os.getenv(env)
base = os.getenv(env) or os.path.expanduser(default)
path = os.path.join(base, APP_ID)
if not os.path.exists(path):
os.makedirs(path)
return path
data_dir = get_xdg_home("XDG_DATA_HOME", "~/.local/share")
config_dir = get_xdg_home("XDG_CONFIG_HOME", "~/.config")
cache_dir = get_xdg_home("XDG_CACHE_HOME", "~/.cache")
source_dir = os.path.abspath(os.path.dirname(__file__))

View File

@@ -1,29 +1,35 @@
# local_instance.py # local_instance.py
import subprocess, os, threading """
Handles running, stopping and resetting the integrated Ollama instance
"""
import subprocess
import os
from time import sleep from time import sleep
from logging import getLogger from logging import getLogger
from .internal import data_dir, cache_dir
logger = getLogger(__name__) logger = getLogger(__name__)
instance = None instance = None
port = 11435 port = 11435
data_dir = os.getenv("XDG_DATA_HOME")
overrides = {} overrides = {}
def start(): def start():
if not os.path.isdir(os.path.join(os.getenv("XDG_CACHE_HOME"), 'tmp/ollama')): if not os.path.isdir(os.path.join(cache_dir, 'tmp/ollama')):
os.mkdir(os.path.join(os.getenv("XDG_CACHE_HOME"), 'tmp/ollama')) os.mkdir(os.path.join(cache_dir, 'tmp/ollama'))
global instance, overrides global instance
params = overrides.copy() params = overrides.copy()
params["OLLAMA_HOST"] = f"127.0.0.1:{port}" # You can't change this directly sorry :3 params["OLLAMA_HOST"] = f"127.0.0.1:{port}" # You can't change this directly sorry :3
params["HOME"] = data_dir params["HOME"] = data_dir
params["TMPDIR"] = os.path.join(os.getenv("XDG_CACHE_HOME"), 'tmp/ollama') params["TMPDIR"] = os.path.join(cache_dir, 'tmp/ollama')
instance = subprocess.Popen(["/app/bin/ollama", "serve"], env={**os.environ, **params}, stderr=subprocess.PIPE, text=True) instance = subprocess.Popen(["ollama", "serve"], env={**os.environ, **params}, stderr=subprocess.PIPE, text=True)
logger.info("Starting Alpaca's Ollama instance...") logger.info("Starting Alpaca's Ollama instance...")
logger.debug(params) logger.debug(params)
sleep(1) sleep(1)
logger.info("Started Alpaca's Ollama instance") logger.info("Started Alpaca's Ollama instance")
v_str = subprocess.check_output("ollama -v", shell=True).decode('utf-8')
logger.info('Ollama version: {}'.format(v_str.split('client version is ')[1].strip()))
def stop(): def stop():
logger.info("Stopping Alpaca's Ollama instance") logger.info("Stopping Alpaca's Ollama instance")
@@ -39,4 +45,3 @@ def reset():
stop() stop()
sleep(1) sleep(1)
start() start()

View File

@@ -16,21 +16,35 @@
# along with this program. If not, see <https://www.gnu.org/licenses/>. # along with this program. If not, see <https://www.gnu.org/licenses/>.
# #
# SPDX-License-Identifier: GPL-3.0-or-later # SPDX-License-Identifier: GPL-3.0-or-later
"""
Main script run at launch, handles actions, about dialog and the app itself (not the window)
"""
import gi
gi.require_version('Gtk', '4.0')
gi.require_version('Adw', '1')
from gi.repository import Gtk, Gio, Adw, GLib
from .window import AlpacaWindow
from .internal import cache_dir, data_dir
import sys import sys
import logging import logging
import gi
import os import os
gi.require_version('Gtk', '4.0')
gi.require_version('Adw', '1')
from gi.repository import Gtk, Gio, Adw, GLib
from .window import AlpacaWindow
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
translators = [
'Alex K (Russian) https://github.com/alexkdeveloper',
'Jeffry Samuel (Spanish) https://github.com/jeffser',
'Louis Chauvet-Villaret (French) https://github.com/loulou64490',
'Théo FORTIN (French) https://github.com/topiga',
'Daimar Stein (Brazilian Portuguese) https://github.com/not-a-dev-stein',
'CounterFlow64 (Norwegian) https://github.com/CounterFlow64',
'Aritra Saha (Bengali) https://github.com/olumolu',
'Yuehao Sui (Simplified Chinese) https://github.com/8ar10der',
'Aleksana (Simplified Chinese) https://github.com/Aleksanaa'
]
class AlpacaApplication(Adw.Application): class AlpacaApplication(Adw.Application):
"""The main application singleton class.""" """The main application singleton class."""
@@ -38,8 +52,8 @@ class AlpacaApplication(Adw.Application):
def __init__(self, version): def __init__(self, version):
super().__init__(application_id='com.jeffser.Alpaca', super().__init__(application_id='com.jeffser.Alpaca',
flags=Gio.ApplicationFlags.DEFAULT_FLAGS) flags=Gio.ApplicationFlags.DEFAULT_FLAGS)
self.create_action('quit', lambda *_: self.quit(), ['<primary>q']) self.create_action('quit', lambda *_: self.quit(), ['<primary>w'])
self.create_action('preferences', lambda *_: AlpacaWindow.show_preferences_dialog(self.props.active_window), ['<primary>p']) self.create_action('preferences', lambda *_: AlpacaWindow.show_preferences_dialog(self.props.active_window), ['<primary>comma'])
self.create_action('about', self.on_about_action) self.create_action('about', self.on_about_action)
self.version = version self.version = version
@@ -58,12 +72,13 @@ class AlpacaApplication(Adw.Application):
support_url="https://github.com/Jeffser/Alpaca/discussions/155", support_url="https://github.com/Jeffser/Alpaca/discussions/155",
developers=['Jeffser https://jeffser.com'], developers=['Jeffser https://jeffser.com'],
designers=['Jeffser https://jeffser.com', 'Tobias Bernard (App Icon) https://tobiasbernard.com/'], designers=['Jeffser https://jeffser.com', 'Tobias Bernard (App Icon) https://tobiasbernard.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\nCounterFlow64 (Norwegian) https://github.com/CounterFlow64\nAritra Saha (Bengali) https://github.com/olumolu\nYuehao Sui (Simplified Chinese) https://github.com/8ar10der', translator_credits='\n'.join(translators),
copyright='© 2024 Jeffser\n© 2024 Ollama', copyright='© 2024 Jeffser\n© 2024 Ollama',
issue_url='https://github.com/Jeffser/Alpaca/issues', issue_url='https://github.com/Jeffser/Alpaca/issues',
license_type=3, license_type=3,
website="https://jeffser.com/alpaca", website="https://jeffser.com/alpaca",
debug_info=open(os.path.join(os.getenv("XDG_DATA_HOME"), 'tmp.log'), 'r').read()) debug_info=open(os.path.join(data_dir, 'tmp.log'), 'r').read())
about.add_link("Become a Sponsor", "https://github.com/sponsors/Jeffser")
about.present(parent=self.props.active_window) about.present(parent=self.props.active_window)
def create_action(self, name, callback, shortcuts=None): def create_action(self, name, callback, shortcuts=None):
@@ -75,16 +90,16 @@ class AlpacaApplication(Adw.Application):
def main(version): def main(version):
if os.path.isfile(os.path.join(os.getenv("XDG_DATA_HOME"), 'tmp.log')): if os.path.isfile(os.path.join(data_dir, 'tmp.log')):
os.remove(os.path.join(os.getenv("XDG_DATA_HOME"), 'tmp.log')) os.remove(os.path.join(data_dir, 'tmp.log'))
if os.path.isdir(os.path.join(os.getenv("XDG_CACHE_HOME"), 'tmp')): if os.path.isdir(os.path.join(cache_dir, 'tmp')):
os.system('rm -rf ' + os.path.join(os.getenv("XDG_CACHE_HOME"), "tmp/*")) os.system('rm -rf ' + os.path.join(cache_dir, "tmp/*"))
else: else:
os.mkdir(os.path.join(os.getenv("XDG_CACHE_HOME"), 'tmp')) os.mkdir(os.path.join(cache_dir, 'tmp'))
logging.basicConfig( logging.basicConfig(
format="%(levelname)s\t[%(filename)s | %(funcName)s] %(message)s", format="%(levelname)s\t[%(filename)s | %(funcName)s] %(message)s",
level=logging.INFO, level=logging.INFO,
handlers=[logging.FileHandler(filename=os.path.join(os.getenv("XDG_DATA_HOME"), 'tmp.log')), logging.StreamHandler(stream=sys.stdout)] handlers=[logging.FileHandler(filename=os.path.join(data_dir, 'tmp.log')), logging.StreamHandler(stream=sys.stdout)]
) )
app = AlpacaApplication(version) app = AlpacaApplication(version)
logger.info(f"Alpaca version: {app.version}") logger.info(f"Alpaca version: {app.version}")

View File

@@ -43,7 +43,9 @@ alpaca_sources = [
'dialogs.py', 'dialogs.py',
'local_instance.py', 'local_instance.py',
'available_models.json', 'available_models.json',
'available_models_descriptions.py' 'available_models_descriptions.py',
'table_widget.py',
'internal.py'
] ]
install_data(alpaca_sources, install_dir: moduledir) install_data(alpaca_sources, install_dir: moduledir)

View File

@@ -2,7 +2,7 @@
box-shadow: none; box-shadow: none;
border-width: 0; border-width: 0;
} }
.message_text_view { .message_text_view, .modelfile_textview {
background-color: rgba(0,0,0,0); background-color: rgba(0,0,0,0);
} }
.chat_image_button { .chat_image_button {
@@ -12,7 +12,3 @@
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);
}

131
src/table_widget.py Normal file
View File

@@ -0,0 +1,131 @@
#table_widget.py
"""
Handles the table widget shown in chat responses
"""
import gi
gi.require_version('Gtk', '4.0')
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)

File diff suppressed because it is too large Load Diff

View File

@@ -5,7 +5,7 @@
<template class="AlpacaWindow" parent="AdwApplicationWindow"> <template class="AlpacaWindow" parent="AdwApplicationWindow">
<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">400</property>
<property name="height-request">400</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>
@@ -14,21 +14,6 @@
<object class="AdwBreakpoint"> <object class="AdwBreakpoint">
<condition>max-width: 800sp</condition> <condition>max-width: 800sp</condition>
<setter object="split_view_overlay" property="collapsed">true</setter> <setter object="split_view_overlay" property="collapsed">true</setter>
<setter object="show_sidebar_button" property="visible">true</setter>
</object>
</child>
<child>
</child>
<child>
<object class="AdwBreakpoint">
<condition>max-width: 500sp</condition>
<setter object="split_view_overlay" property="collapsed">true</setter>
<setter object="show_sidebar_button" property="visible">true</setter>
<setter object="welcome_dialog" property="width-request">360</setter>
<setter object="manage_models_dialog" property="width-request">360</setter>
<setter object="create_model_dialog" property="width-request">360</setter>
<setter object="preferences_dialog" property="width-request">360</setter>
<setter object="file_preview_dialog" property="width-request">360</setter>
</object> </object>
</child> </child>
<property name="content"> <property name="content">
@@ -80,7 +65,6 @@
<object class="AdwHeaderBar" id="header_bar"> <object class="AdwHeaderBar" id="header_bar">
<child type="start"> <child type="start">
<object class="GtkToggleButton" id="show_sidebar_button"> <object class="GtkToggleButton" id="show_sidebar_button">
<property name="visible">false</property>
<property name="icon-name">sidebar-show-symbolic</property> <property name="icon-name">sidebar-show-symbolic</property>
<property name="tooltip-text" translatable="yes">Toggle Sidebar</property> <property name="tooltip-text" translatable="yes">Toggle Sidebar</property>
<property name="active" bind-source="split_view_overlay" bind-property="show-sidebar" bind-flags="sync-create"/> <property name="active" bind-source="split_view_overlay" bind-property="show-sidebar" bind-flags="sync-create"/>
@@ -93,7 +77,7 @@
<child> <child>
<object class="GtkDropDown" id="model_drop_down"> <object class="GtkDropDown" id="model_drop_down">
<signal name="notify" handler="verify_if_image_can_be_used"/> <signal name="notify" handler="verify_if_image_can_be_used"/>
<property name="width-request">150</property> <property name="width-request">260</property>
<property name="enable-search">true</property> <property name="enable-search">true</property>
<property name="tooltip-text">Select Model</property> <property name="tooltip-text">Select Model</property>
<property name="model"> <property name="model">
@@ -104,7 +88,7 @@
</property> </property>
</object> </object>
</child> </child>
<child> <!--<child>
<object class="GtkButton" id="manage_models_button"> <object class="GtkButton" id="manage_models_button">
<signal name="clicked" handler="manage_models_button_activate"/> <signal name="clicked" handler="manage_models_button_activate"/>
<property name="tooltip-text" translatable="yes">Manage Models</property> <property name="tooltip-text" translatable="yes">Manage Models</property>
@@ -114,7 +98,7 @@
</object> </object>
</child> </child>
</object> </object>
</child> </child>-->
</object> </object>
</property> </property>
<child type="end"> <child type="end">
@@ -217,6 +201,8 @@
<object class="GtkScrolledWindow"> <object class="GtkScrolledWindow">
<property name="max-content-height">150</property> <property name="max-content-height">150</property>
<property name="propagate-natural-height">true</property> <property name="propagate-natural-height">true</property>
<property name="margin-start">10</property>
<property name="margin-end">10</property>
<style> <style>
<class name="message_input_scroll_window"/> <class name="message_input_scroll_window"/>
</style> </style>
@@ -226,8 +212,6 @@
<class name="message_text_view"/> <class name="message_text_view"/>
</style> </style>
<property name="wrap-mode">word</property> <property name="wrap-mode">word</property>
<property name="margin-start">10</property>
<property name="margin-end">10</property>
<property name="top-margin">10</property> <property name="top-margin">10</property>
<property name="bottom-margin">10</property> <property name="bottom-margin">10</property>
<property name="hexpand">true</property> <property name="hexpand">true</property>
@@ -246,6 +230,7 @@
<style> <style>
<class name="accent"/> <class name="accent"/>
<class name="circular"/> <class name="circular"/>
<class name="suggested-action"/>
</style> </style>
<child> <child>
<object class="AdwButtonContent"> <object class="AdwButtonContent">
@@ -456,127 +441,6 @@
</child> </child>
</object> </object>
<object class="AdwDialog" id="create_model_dialog">
<property name="can-close">true</property>
<property name="width-request">400</property>
<property name="height-request">600</property>
<child>
<object class="AdwToastOverlay" id="create_model_overlay">
<child>
<object class="AdwToolbarView">
<child type="bottom">
<object class="GtkActionBar">
<property name="revealed">true</property>
<child type="end">
<object class="GtkButton">
<property name="label" translatable="yes">Create</property>
<signal name="clicked" handler="create_model_start"/>
<style>
<class name="suggested-action"/>
</style>
</object>
</child>
</object>
</child>
<child type="top">
<object class="AdwHeaderBar">
<property name="title-widget">
<object class="AdwWindowTitle">
<property name="title" translatable="yes">Create Model</property>
</object>
</property>
</object>
</child>
<child>
<object class="GtkScrolledWindow">
<property name="vexpand">true</property>
<property name="hexpand">true</property>
<child>
<object class="GtkBox">
<property name="margin-start">12</property>
<property name="margin-end">12</property>
<property name="margin-top">12</property>
<property name="margin-bottom">12</property>
<property name="orientation">1</property>
<property name="spacing">12</property>
<child>
<object class="GtkListBox">
<style>
<class name="boxed-list"/>
<class name="card"/>
</style>
<property name="selection-mode">none</property>
<child>
<object class="AdwActionRow" id="create_model_base">
<property name="title" translatable="yes">Base</property>
<property name="subtitle"/>
<style>
<class name="property"/>
</style>
</object>
</child>
</object>
</child>
<child>
<object class="GtkListBox">
<style>
<class name="boxed-list"/>
<class name="card"/>
</style>
<property name="selection-mode">none</property>
<child>
<object class="AdwEntryRow" id="create_model_name">
<property name="title" translatable="yes">Name</property>
<property name="input-purpose">alpha</property>
</object>
</child>
<child>
<object class="AdwEntryRow" id="create_model_system">
<property name="title" translatable="yes">Context</property>
<property name="input-purpose">alpha</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkListBox">
<style>
<class name="boxed-list"/>
<class name="card"/>
</style>
<property name="selection-mode">none</property>
<child>
<object class="AdwEntryRow" id="create_model_template">
<property name="title" translatable="yes">Template</property>
<property name="input-purpose">alpha</property>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">Some models require a specific template. Please visit the model's website for more information if you're unsure.</property>
<property name="margin-start">12</property>
<property name="margin-end">12</property>
<property name="margin-top">12</property>
<property name="margin-bottom">12</property>
<property name="halign">1</property>
<property name="wrap">true</property>
<style>
<class name="caption"/>
</style>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
<object class="AdwDialog" id="manage_models_dialog"> <object class="AdwDialog" id="manage_models_dialog">
<property name="can-close">true</property> <property name="can-close">true</property>
<property name="width-request">400</property> <property name="width-request">400</property>
@@ -730,6 +594,143 @@
</property> </property>
</object> </object>
</child> </child>
<child>
<object class="AdwNavigationPage">
<property name="title" translatable="yes">Create Model</property>
<property name="tag">model_create_page</property>
<property name="child">
<object class="AdwToolbarView">
<child type="top">
<object class="AdwHeaderBar">
<child type="start">
<object class="GtkButton">
<signal name="clicked" handler="link_button_handler"/>
<property name="icon-name">globe-symbolic</property>
</object>
</child>
</object>
</child>
<property name="content">
<object class="GtkScrolledWindow">
<property name="vexpand">true</property>
<property name="hexpand">true</property>
<child>
<object class="GtkBox">
<property name="margin-start">12</property>
<property name="margin-end">12</property>
<property name="margin-top">12</property>
<property name="margin-bottom">12</property>
<property name="orientation">1</property>
<property name="spacing">12</property>
<child>
<object class="GtkListBox">
<style>
<class name="boxed-list"/>
<class name="card"/>
</style>
<property name="selection-mode">none</property>
<child>
<object class="AdwActionRow" id="create_model_base">
<property name="title" translatable="yes">Base</property>
<property name="sensitive">false</property>
<property name="subtitle"/>
<style>
<class name="property"/>
</style>
</object>
</child>
</object>
</child>
<child>
<object class="GtkListBox">
<style>
<class name="boxed-list"/>
<class name="card"/>
</style>
<property name="selection-mode">none</property>
<child>
<object class="AdwEntryRow" id="create_model_name">
<property name="title" translatable="yes">Name</property>
<property name="input-purpose">alpha</property>
</object>
</child>
<child>
<object class="AdwEntryRow" id="create_model_system">
<property name="title" translatable="yes">Context</property>
<property name="input-purpose">alpha</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkListBox">
<style>
<class name="boxed-list"/>
<class name="card"/>
</style>
<property name="selection-mode">none</property>
<child>
<object class="GtkBox">
<property name="height-request">140</property>
<property name="margin-top">10</property>
<property name="margin-bottom">10</property>
<property name="margin-start">10</property>
<property name="margin-end">10</property>
<style>
<class name="card"/>
</style>
<child>
<object class="GtkScrolledWindow">
<property name="margin-start">10</property>
<property name="margin-end">10</property>
<child>
<object class="GtkTextView" id="create_model_modelfile">
<style>
<class name="modelfile_textview"/>
</style>
<property name="wrap-mode">word</property>
<property name="top-margin">10</property>
<property name="bottom-margin">10</property>
<property name="hexpand">true</property>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">Some models require a modelfile, Alpaca fills FROM and SYSTEM (context) instructions automatically. Please visit the model's website or Ollama documentation for more information if you're unsure.</property>
<property name="margin-top">10</property>
<property name="margin-bottom">10</property>
<property name="margin-start">10</property>
<property name="margin-end">10</property>
<property name="halign">1</property>
<property name="wrap">true</property>
<style>
<class name="caption"/>
</style>
</object>
</child>
</object>
</child>
<child>
<object class="GtkButton">
<property name="label" translatable="yes">Create</property>
<signal name="clicked" handler="create_model_start"/>
<style>
<class name="suggested-action"/>
</style>
</object>
</child>
</object>
</child>
</object>
</property>
</object>
</property>
</object>
</child>
</object> </object>
</child> </child>
</object> </object>
@@ -1032,6 +1033,10 @@ By downloading any model you accept their license agreement available on the mod
<attribute name="label" translatable="yes">Import Chat</attribute> <attribute name="label" translatable="yes">Import Chat</attribute>
<attribute name="action">app.import_chat</attribute> <attribute name="action">app.import_chat</attribute>
</item> </item>
<item>
<attribute name="label" translatable="yes">Manage Models</attribute>
<attribute name="action">app.manage_models</attribute>
</item>
</section> </section>
<section> <section>
<item> <item>
@@ -1085,9 +1090,13 @@ By downloading any model you accept their license agreement available on the mod
<attribute name="action">app.create_model_from_existing</attribute> <attribute name="action">app.create_model_from_existing</attribute>
</item> </item>
<item> <item>
<attribute name="label" translatable="yes">From GGUF File (Experimental)</attribute> <attribute name="label" translatable="yes">From GGUF File</attribute>
<attribute name="action">app.create_model_from_file</attribute> <attribute name="action">app.create_model_from_file</attribute>
</item> </item>
<item>
<attribute name="label" translatable="yes">From Name</attribute>
<attribute name="action">app.create_model_from_name</attribute>
</item>
</section> </section>
</menu> </menu>
<object class="GtkFileFilter" id="file_filter_attachments"> <object class="GtkFileFilter" id="file_filter_attachments">
@@ -1130,7 +1139,7 @@ By downloading any model you accept their license agreement available on the mod
<property name="title" translatable="yes">General</property> <property name="title" translatable="yes">General</property>
<child> <child>
<object class="GtkShortcutsShortcut"> <object class="GtkShortcutsShortcut">
<property name="accelerator">&lt;ctrl&gt;Q</property> <property name="accelerator">&lt;ctrl&gt;W</property>
<property name="title" translatable="yes">Close application</property> <property name="title" translatable="yes">Close application</property>
</object> </object>
</child> </child>
@@ -1148,7 +1157,7 @@ By downloading any model you accept their license agreement available on the mod
</child> </child>
<child> <child>
<object class="GtkShortcutsShortcut"> <object class="GtkShortcutsShortcut">
<property name="accelerator">&lt;ctrl&gt;P</property> <property name="accelerator">&lt;ctrl&gt;comma</property>
<property name="title" translatable="yes">Preferences</property> <property name="title" translatable="yes">Preferences</property>
</object> </object>
</child> </child>
@@ -1164,6 +1173,18 @@ By downloading any model you accept their license agreement available on the mod
<property name="title" translatable="yes">Show shortcuts window</property> <property name="title" translatable="yes">Show shortcuts window</property>
</object> </object>
</child> </child>
<child>
<object class="GtkShortcutsShortcut">
<property name="accelerator">&lt;ctrl&gt;M</property>
<property name="title" translatable="yes">Manage models</property>
</object>
</child>
<child>
<object class="GtkShortcutsShortcut">
<property name="accelerator">F9</property>
<property name="title" translatable="yes">Toggle sidebar</property>
</object>
</child>
</object> </object>
</child> </child>
<child> <child>

View File

@@ -1,9 +1,15 @@
"""
Moves the descriptions of models to src/available_models_descriptions.py
so they can be translated
"""
import json import json
with open('src/available_models.json', 'r') as f:
data = json.load(f) if __name__ == "__main__":
results = 'descriptions = {\n' with open('src/available_models.json', 'r', encoding="utf-8") as f:
for key, value in data.items(): data = json.load(f)
results += f" '{key}': _(\"{value['description']}\"),\n" RESULTS = 'descriptions = {\n'
results += '}' for key, value in data.items():
with open('src/available_models_descriptions.py', 'w+') as f: RESULTS += f" '{key}': _(\"{value['description']}\"),\n"
f.write(results) RESULTS += '}'
with open('src/available_models_descriptions.py', 'w+', encoding="utf-8") as f:
f.write(RESULTS)