166 Commits
1.0.5 ... 1.1.1

Author SHA1 Message Date
Jeffry Samuel
a7b6e6bbce Update flatpak-builder.yml 2024-08-12 23:15:53 -06:00
aritra saha
801c10fb77 Update hi.po (#240) 2024-08-12 22:58:04 -06:00
aritra saha
50520b8474 Update bn.po (#239) 2024-08-12 22:53:43 -06:00
jeffser
b66e2102d3 Spanish update 2024-08-12 22:21:32 -06:00
jeffser
8c0f1fd4d5 Updated languages 2024-08-12 22:17:35 -06:00
jeffser
8b851d1b56 Preparing for 1.1.1 2024-08-12 22:16:47 -06:00
jeffser
f36d6e1b29 Removed bugged imported chats 2024-08-12 22:12:09 -06:00
jeffser
eecac162ef Update translations 2024-08-12 22:03:47 -06:00
jeffser
82e7a3a9e1 Better caption names on dropdown 2024-08-12 18:57:17 -06:00
jeffser
f0505a0242 Only enable youtube caption search when there's more than 10 captions 2024-08-12 18:55:06 -06:00
jeffser
11dd13b430 Added ollama debbugging messages to about dialog 2024-08-11 22:30:56 -06:00
jeffser
b8fe222052 Added duplicate chat option 2024-08-11 22:11:17 -06:00
jeffser
47d19a58aa Give message focus when editing it 2024-08-11 21:50:50 -06:00
jeffser
fd67afbf33 Fixed message editor 2024-08-11 21:48:31 -06:00
jeffser
d06e08a64e Fix message regeneration 2024-08-11 21:36:31 -06:00
jeffser
77b08d9e52 Added loading spinner to regenerating message 2024-08-11 21:15:26 -06:00
jeffser
9451bf88d0 Removed french language set 2024-08-11 16:02:30 -06:00
jeffser
82bb50d663 Merge branch 'main' of github.com-jeffser:Jeffser/Alpaca 2024-08-11 16:01:14 -06:00
jeffser
edc3053774 Focus message entry when creating a new chat 2024-08-11 15:59:39 -06:00
Louis Chauvet-Villaret
1320ddb7d4 Hola Jeffry, traduje la aplicacion, buen dia (#236) 2024-08-11 15:37:51 -06:00
jeffser
d95f06a230 Make buttons visible when stopping message 2024-08-11 15:08:26 -06:00
jeffser
938ace91c1 Fixed import chat 2024-08-11 14:55:18 -06:00
jeffser
175cfad81c Welcome screen appears when clearing chat 2024-08-11 14:49:12 -06:00
jeffser
2f399dbb64 Removed bold from manage button label 2024-08-11 14:44:19 -06:00
jeffser
27558b85af Added top margin to model selector 2024-08-11 14:23:30 -06:00
jeffser
bcc1f3fa65 Changed 'Open Model Manager' to pill button on welcome screen 2024-08-11 14:19:00 -06:00
jeffser
fd92a86c5e CTRL+W and CTRL+Q stops local instance before closing the app 2024-08-11 13:23:34 -06:00
jeffser
3b95d369b8 Added Azerbaijani template 2024-08-11 01:45:57 -06:00
Jeffry Samuel
a12920d801 Update SECURITY.md 2024-08-11 00:47:58 -06:00
Jeffry Samuel
2dd63df533 Create SECURITY.md 2024-08-11 00:44:49 -06:00
Jeffry Samuel
cea1aa5028 Update CODE_OF_CONDUCT.md 2024-08-11 00:40:27 -06:00
Jeffry Samuel
54b96d4e3a Update CODE_OF_CONDUCT.md 2024-08-11 00:40:04 -06:00
Jeffry Samuel
a470136476 Create CODE_OF_CONDUCT.md 2024-08-11 00:37:44 -06:00
Jeffry Samuel
7d35cb08dd Create CONTRIBUTING.md 2024-08-11 00:32:55 -06:00
aritra saha
1f03f1032e Update bn.po and hipo (#223)
* Update bn.po

* Update hi.po
2024-08-11 00:14:48 -06:00
jeffser
9e2b55a249 Spanish update 2024-08-10 21:32:19 -06:00
jeffser
0fbb94cd72 Updated languages again 2024-08-10 21:32:10 -06:00
jeffser
004b3f8574 Preparing for 1.1.0 2024-08-10 21:26:33 -06:00
jeffser
7d1931dd17 Updated languages 2024-08-10 21:18:22 -06:00
jeffser
8b7f41afa7 Fixed codeblocks spacing 2024-08-10 21:10:23 -06:00
jeffser
4bc0832865 Better padding for focus border on messages 2024-08-10 21:03:19 -06:00
jeffser
a66c6d5f40 Fixed nasty clear chat glitch 2024-08-10 20:37:51 -06:00
jeffser
33b7cae24d Show date on stopped messages 2024-08-10 20:31:03 -06:00
jeffser
47f5c88ef2 Don't regenerate title when there's a custom chat title 2024-08-10 20:22:39 -06:00
jeffser
ffe382aee2 Added default buttons to dialogs 2024-08-10 20:14:51 -06:00
jeffser
919f71ee78 Fixed regenerate button 2024-08-10 20:05:41 -06:00
jeffser
404d4476ae Fixed import export 2024-08-10 19:27:03 -06:00
jeffser
f2b243cd5f Changed python 2 to python from codeblocks 2024-08-10 19:23:11 -06:00
Louis Chauvet-Villaret
c2fae41355 Complete french translation (#210)
Model description translated with ChatGPT, and it's work really well
2024-08-08 14:13:54 -06:00
jeffser
8fda2cde9e Fixed return + shift should make a new line 2024-08-08 10:56:45 -06:00
jeffser
930380cdce Fixed Hindi 2024-08-08 10:56:22 -06:00
jeffser
5b788ffe15 Missed a comma 2024-08-07 23:58:58 -06:00
jeffser
521c2bdde5 Fixed syntax 2024-08-07 23:57:23 -06:00
aritra saha
eee73b1218 some update and fix for welcome screen. (#206)
* Update bn.po

* Update hi.po

* Update window.py

* Update window.py

* Update window.py

* Update window.py

* Update window.py

I removed some and added commas

---------

Co-authored-by: Jeffry Samuel <69224322+Jeffser@users.noreply.github.com>
2024-08-07 23:54:34 -06:00
jeffser
87d6da26c9 Merge branch 'main' of github.com-jeffser:Jeffser/Alpaca 2024-08-07 21:37:39 -06:00
jeffser
2029cd5cd2 Added Hindi credits 2024-08-07 21:37:32 -06:00
Jeffry Samuel
36be752ee6 Update README.md 2024-08-07 21:34:48 -06:00
jeffser
5b3586789f Spanish Update 2024-08-07 21:32:57 -06:00
jeffser
6ce670e643 Updated translations 2024-08-07 21:27:08 -06:00
jeffser
dd70e8139c Give textview focus at launch 2024-08-07 21:21:26 -06:00
jeffser
3ac0936d1a Prevent enter key send when a response is being received 2024-08-07 21:20:03 -06:00
jeffser
1477bacf6a Removed 'Featured models' from welcome dialog, added 'Open Model Manager' button in welcome screen if the user doesn't have models 2024-08-07 21:02:29 -06:00
jeffser
d339a18901 Fixed toast message 2024-08-07 20:43:23 -06:00
jeffser
f9460416d9 Prevent regenerating message whilst receiving a response 2024-08-07 20:41:49 -06:00
jeffser
a9112cf3da Added welcome screen 2024-08-07 20:39:46 -06:00
jeffser
c873b49700 Merge branch 'main' of github.com-jeffser:Jeffser/Alpaca 2024-08-07 19:41:58 -06:00
jeffser
3c553e37d8 Fixed pull by name feature 2024-08-07 19:41:34 -06:00
aritra saha
0c47fbb1f7 update hi (#200)
* Update hi.po

* Update hi.po

* Update LINGUAS

* Update update_translation_files.sh

* Update hi.po

* Update hi.po

* Update hi.po
2024-08-07 19:35:18 -06:00
jeffser
476138ef53 Changed oars rating 2024-08-06 23:54:15 -06:00
jeffser
385ca4f0fa Added focus indicator for message being edited 2024-08-06 17:12:46 -06:00
jeffser
46fd642789 Merge branch 'main' of github.com-jeffser:Jeffser/Alpaca 2024-08-06 17:08:56 -06:00
jeffser
e48249c7c9 Focus indicators on messages 2024-08-06 17:08:50 -06:00
aritra saha
9e8535e97e Update bn.po (#198) 2024-08-06 14:42:40 -06:00
jeffser
a794c63a5a Fixed url 2024-08-06 13:49:22 -06:00
ProjectMoon
f3610a46a2 Fix bearer token use for remote ollama APIs. (#197) 2024-08-06 13:48:05 -06:00
aritra saha
20fd2cf6e3 hi updTe (#195)
* Update bn.po

* Update hi.po

* Update hi.po
2024-08-06 13:40:24 -06:00
jeffser
7bf345d09d Updated language files 2024-08-06 13:39:54 -06:00
jeffser
17e9560449 Fixed (none) in model selector problem 2024-08-06 13:15:15 -06:00
jeffser
c02e6a565e New model selector design + moved around the delete chat option on menus 2024-08-06 12:59:41 -06:00
jeffser
7fbc9b9bde Merge branch 'main' of github.com-jeffser:Jeffser/Alpaca 2024-08-05 23:12:29 -06:00
jeffser
416e97d488 Remade model selector 2024-08-05 23:12:22 -06:00
aritra saha
753060d9f3 another small fix (#194)
* Update bn.po

* Update hi.po
2024-08-05 17:52:38 -06:00
jeffser
972c53000c Changed splitview collapsing behaviour 2024-08-05 17:46:01 -06:00
jeffser
2b948a49a0 Made model manager navigatable by keyboard 2024-08-05 16:45:26 -06:00
jeffser
7999548738 Added fixes for accessibility / screen reader fixes (tested on Orca) 2024-08-05 16:07:49 -06:00
jeffser
d4d13b793f Fixed width of dialogs 2024-08-05 13:59:11 -06:00
jeffser
210b6f0d89 Removed search from model dropdown 2024-08-05 13:51:31 -06:00
jeffser
7f5894b274 Added delete chat option in secondary menu 2024-08-05 13:50:42 -06:00
jeffser
2dc24ab945 Made manage models dialog appear faster 2024-08-05 13:45:18 -06:00
jeffser
2f153c9974 Added ctrl+q shortcut to close app 2024-08-05 13:45:02 -06:00
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
38 changed files with 12649 additions and 4438 deletions

View File

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

View File

@@ -6,7 +6,7 @@ labels: enhancement
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.**
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: com.jeffser.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>

4
CODE_OF_CONDUCT.md Normal file
View File

@@ -0,0 +1,4 @@
Alpaca follows [GNOME's code of conduct](https://conduct.gnome.org/), please make sure to read it before interacting in any way with this repository.
To report any misconduct please reach out via private message on
- X (formally Twitter): [@jeffrysamuer](https://x.com/jeffrysamuer)
- Mastodon: [@jeffser@floss.social](https://floss.social/@jeffser)

30
CONTRIBUTING.md Normal file
View File

@@ -0,0 +1,30 @@
# Contributing Rules
## Translations
If you want to translate or contribute on existing translations please read [this discussion](https://github.com/Jeffser/Alpaca/discussions/153).
## Code
1) Before contributing code make sure there's an open [issue](https://github.com/Jeffser/Alpaca/issues) for that particular problem or feature.
2) Ask to contribute on the responses to the issue.
3) Wait for [my](https://github.com/Jeffser) approval, I might have already started working on that issue.
4) Test your code before submitting a pull request.
## Q&A
### Do I need to comment my code?
There's no need to add comments if the code is easy to read by itself.
### What if I need help or I don't understand the existing code?
You can reach out on the issue, I'll try to answer as soon as possible.
### What IDE should I use?
I use Gnome Builder but you can use whatever you want.
### Can I be credited?
You might be credited on the GitHub repository in the [thanks](https://github.com/Jeffser/Alpaca/blob/main/README.md#thanks) section of the README.

View File

@@ -11,7 +11,11 @@ Alpaca is an [Ollama](https://github.com/ollama/ollama) client where you can man
> [!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.
> [!IMPORTANT]
> Please be aware that [GNOME Code of Conduct](https://conduct.gnome.org) applies to Alpaca before interacting with this repository.
## Features!
- Talk to multiple models in the same conversation
- Pull and delete models from the app
- Image recognition
@@ -21,47 +25,38 @@ Alpaca is an [Ollama](https://github.com/ollama/ollama) client where you can man
- Notifications
- Import / Export chats
- Delete / Edit messages
- Regenerate messages
- YouTube recognition (Ask questions about a YouTube video using the transcript)
- Website recognition (Ask questions about a certain website by parsing the url)
## 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
1. Clone repo using Gnome Builder
2. Press the `run` button
Normal conversation | Image recognition | Code highlighting | YouTube transcription | Model management
:------------------:|:-----------------:|:-----------------:|:---------------------:|:----------------:
![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
1. Go to the `releases` page
2. Download the latest flatpak package
3. Open it
## Translators
## Ollama session tips
### Change the port of the integrated Ollama instance
Go to `~/.var/app/com.jeffser.Alpaca/config/server.json` and change the `"local_port"` value, by default it is `11435`.
### Backup all the chats
The chat data is located in `~/.var/app/com.jeffser.Alpaca/data/chats` you can copy that directory wherever you want to.
### Force showing the welcome dialog
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.
Language | Contributors
:----------------------|:-----------
🇷🇺 Russian | [Alex K](https://github.com/alexkdeveloper)
🇪🇸 Spanish | [Jeffry Samuel](https://github.com/jeffser)
🇫🇷 French | [Louis Chauvet-Villaret](https://github.com/loulou64490) , [Théo FORTIN](https://github.com/topiga)
🇧🇷 Brazilian Portuguese | [Daimar Stein](https://github.com/not-a-dev-stein)
🇳🇴 Norwegian | [CounterFlow64](https://github.com/CounterFlow64)
🇮🇳 Bengali | [Aritra Saha](https://github.com/olumolu)
🇨🇳 Simplified Chinese | [Yuehao Sui](https://github.com/8ar10der) , [Aleksana](https://github.com/Aleksanaa)
🇮🇳 Hindi | [Aritra Saha](https://github.com/olumolu)
---
## 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
- [not-a-dev-stein](https://github.com/not-a-dev-stein) for their help with requesting a new icon and bug reports
- [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 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
## About forks
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)
- [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!

12
SECURITY.md Normal file
View File

@@ -0,0 +1,12 @@
# Security Policy
## Supported Packaging
Alpaca only supports [Flatpak](https://flatpak.org/) packaging officially, any other packaging methods might not behave as expected.
## Official Versions
The only ways Alpaca is being distributed officially are:
- [Alpaca's GitHub Repository Releases Page](https://github.com/Jeffser/Alpaca/releases)
- [Flathub](https://flathub.org/apps/com.jeffser.Alpaca)

View File

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

View File

@@ -70,9 +70,7 @@
<caption>Multiple models being downloaded</caption>
</screenshot>
</screenshots>
<content_rating type="oars-1.1">
<content_attribute id="money-purchasing">mild</content_attribute>
</content_rating>
<content_rating type="oars-1.1" />
<url type="bugtracker">https://github.com/Jeffser/Alpaca/issues</url>
<url type="homepage">https://jeffser.com/alpaca/</url>
<url type="donation">https://github.com/sponsors/Jeffser</url>
@@ -80,6 +78,81 @@
<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.1.1" date="2024-08-12">
<url type="details">https://github.com/Jeffser/Alpaca/releases/tag/1.1.1</url>
<description>
<p>New</p>
<ul>
<li>New duplicate chat option</li>
<li>Changed model selector appearance</li>
<li>Message entry is focused on launch and chat change</li>
<li>Message is focused when it's being edited</li>
<li>Added loading spinner when regenerating a message</li>
<li>Added Ollama debugging to 'About Alpaca' dialog</li>
<li>Changed YouTube transcription dialog appearance and behavior</li>
</ul>
<p>Fixes</p>
<ul>
<li>CTRL+W and CTRL+Q stops local instance before closing the app</li>
<li>Changed appearance of 'Open Model Manager' button on welcome screen</li>
<li>Fixed message generation not working consistently</li>
<li>Fixed message edition not working consistently</li>
</ul>
</description>
</release>
<release version="1.1.0" date="2024-08-10">
<url type="details">https://github.com/Jeffser/Alpaca/releases/tag/1.1.0</url>
<description>
<p>New</p>
<ul>
<li>Model manager opens faster</li>
<li>Delete chat option in secondary menu</li>
<li>New model selector popup</li>
<li>Standard shortcuts</li>
<li>Model manager is navigable with keyboard</li>
<li>Changed sidebar collapsing behavior</li>
<li>Focus indicators on messages</li>
<li>Welcome screen</li>
<li>Give message entry focus at launch</li>
<li>Generally better code</li>
</ul>
<p>Fixes</p>
<ul>
<li>Better width for dialogs</li>
<li>Better compatibility with screen readers</li>
<li>Fixed message regenerator</li>
<li>Removed 'Featured models' from welcome dialog</li>
<li>Added default buttons to dialogs</li>
<li>Fixed import / export of chats</li>
<li>Changed Python2 title to Python on code blocks</li>
<li>Prevent regeneration of title when the user changed it to a custom title</li>
<li>Show date on stopped messages</li>
<li>Fix clear chat error</li>
</ul>
</description>
</release>
<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>

View File

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

View File

@@ -4,4 +4,5 @@ pt_BR
fr
nb_NO
bn
zh_CN
zh_CN
hi

File diff suppressed because it is too large Load Diff

2306
po/az.po Normal file

File diff suppressed because it is too large Load Diff

1268
po/bn.po

File diff suppressed because it is too large Load Diff

1412
po/es.po

File diff suppressed because it is too large Load Diff

1903
po/fr.po

File diff suppressed because it is too large Load Diff

2608
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

1183
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

@@ -29,6 +29,7 @@
<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/update-symbolic.svg">icons/update-symbolic.svg</file>
<file alias="icons/scalable/status/down-symbolic.svg">icons/down-symbolic.svg</file>
<file preprocess="xml-stripblanks">window.ui</file>
<file preprocess="xml-stripblanks">gtk/help-overlay.ui</file>
</gresource>

View File

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

View File

@@ -1,11 +1,15 @@
# dialogs.py
from gi.repository import Adw, Gtk, Gdk, GLib, GtkSource, Gio, GdkPixbuf
"""
Handles UI dialogs
"""
import os
import logging
from pytube import YouTube
from html2text import html2text
from gi.repository import Adw, Gtk
from . import connection_handler
logger = logging.getLogger(__name__)
# CLEAR CHAT | WORKS
def clear_chat_response(self, dialog, task):
@@ -24,6 +28,7 @@ def clear_chat(self):
dialog.add_response("cancel", _("Cancel"))
dialog.add_response("clear", _("Clear"))
dialog.set_response_appearance("clear", Adw.ResponseAppearance.DESTRUCTIVE)
dialog.set_default_response("clear")
dialog.choose(
parent = self,
cancellable = None,
@@ -45,6 +50,7 @@ def delete_chat(self, chat_name):
dialog.add_response("cancel", _("Cancel"))
dialog.add_response("delete", _("Delete"))
dialog.set_response_appearance("delete", Adw.ResponseAppearance.DESTRUCTIVE)
dialog.set_default_response("delete")
dialog.choose(
parent = self,
cancellable = None,
@@ -54,9 +60,11 @@ def delete_chat(self, chat_name):
# RENAME CHAT | WORKS
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()
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"):
self.rename_chat(old_chat_name, new_chat_name, label_element)
@@ -68,10 +76,10 @@ def rename_chat(self, chat_name, label_element):
extra_child=entry,
close_response="cancel"
)
entry.connect("activate", lambda dialog, old_chat_name=chat_name, entry=entry, label_element=label_element: rename_chat_response(self, dialog, None, old_chat_name, entry, label_element))
dialog.add_response("cancel", _("Cancel"))
dialog.add_response("rename", _("Rename"))
dialog.set_response_appearance("rename", Adw.ResponseAppearance.SUGGESTED)
dialog.set_default_response("rename")
dialog.choose(
parent = self,
cancellable = None,
@@ -82,7 +90,8 @@ def rename_chat(self, chat_name, label_element):
def new_chat_response(self, dialog, task, entry):
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"):
self.new_chat(chat_name)
@@ -95,10 +104,10 @@ def new_chat(self):
extra_child=entry,
close_response="cancel"
)
entry.connect("activate", lambda dialog, entry: new_chat_response(self, dialog, None, entry))
dialog.add_response("cancel", _("Cancel"))
dialog.add_response("create", _("Create"))
dialog.set_response_appearance("create", Adw.ResponseAppearance.SUGGESTED)
dialog.set_default_response("create")
dialog.choose(
parent = self,
cancellable = None,
@@ -121,6 +130,7 @@ def stop_pull_model(self, model_name):
dialog.add_response("cancel", _("Cancel"))
dialog.add_response("stop", _("Stop"))
dialog.set_response_appearance("stop", Adw.ResponseAppearance.DESTRUCTIVE)
dialog.set_default_response("stop")
dialog.choose(
parent = self.manage_models_dialog,
cancellable = None,
@@ -142,6 +152,7 @@ def delete_model(self, model_name):
dialog.add_response("cancel", _("Cancel"))
dialog.add_response("delete", _("Delete"))
dialog.set_response_appearance("delete", Adw.ResponseAppearance.DESTRUCTIVE)
dialog.set_default_response("delete")
dialog.choose(
parent = self.manage_models_dialog,
cancellable = None,
@@ -164,6 +175,7 @@ def remove_attached_file(self, name):
dialog.add_response("cancel", _("Cancel"))
dialog.add_response("remove", _("Remove"))
dialog.set_response_appearance("remove", Adw.ResponseAppearance.DESTRUCTIVE)
dialog.set_default_response("remove")
dialog.choose(
parent = self,
cancellable = None,
@@ -203,11 +215,11 @@ def reconnect_remote(self, current_url, current_bearer_token):
body=_("The remote instance has disconnected"),
extra_child=container
)
#entry.connect("activate", lambda entry, dialog: reconnect_remote_response(self, dialog, None, entry))
dialog.add_response("close", _("Close Alpaca"))
dialog.add_response("local", _("Use local instance"))
dialog.add_response("remote", _("Connect"))
dialog.set_response_appearance("remote", Adw.ResponseAppearance.SUGGESTED)
dialog.set_default_response("remote")
dialog.choose(
parent = self,
cancellable = None,
@@ -236,6 +248,7 @@ def create_model_from_existing(self):
dialog.add_response("cancel", _("Cancel"))
dialog.add_response("accept", _("Accept"))
dialog.set_response_appearance("accept", Adw.ResponseAppearance.SUGGESTED)
dialog.set_default_response("accept")
dialog.choose(
parent = self,
cancellable = None,
@@ -243,15 +256,15 @@ def create_model_from_existing(self):
)
def create_model_from_file_response(self, file_dialog, result):
try: file = file_dialog.open_finish(result)
except:
self.logger.error(e)
return
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:
self.logger.error(e)
self.show_toast(_("An error occurred while creating the model"), self.main_overlay)
logger.error(e)
def create_model_from_file(self):
file_dialog = Gtk.FileDialog(default_filter=self.file_filter_gguf)
@@ -264,7 +277,7 @@ def create_model_from_name_response(self, dialog, task, entry):
def create_model_from_name(self):
entry = Gtk.Entry()
entry.get_delegate().connect("insert-text", self.check_alphanumeric)
entry.get_delegate().connect("insert-text", lambda *_ : self.check_alphanumeric(*_, ['-', '.', ':', '_', '/']))
dialog = Adw.AlertDialog(
heading=_("Pull Model"),
body=_("Input the name of the model in this format\nname:tag"),
@@ -273,6 +286,7 @@ def create_model_from_name(self):
dialog.add_response("cancel", _("Cancel"))
dialog.add_response("accept", _("Accept"))
dialog.set_response_appearance("accept", Adw.ResponseAppearance.SUGGESTED)
dialog.set_default_response("accept")
dialog.choose(
parent = self,
cancellable = None,
@@ -286,24 +300,24 @@ def attach_file_response(self, file_dialog, result):
"image": ["png", "jpeg", "jpg", "webp", "gif"],
"pdf": ["pdf"]
}
try: file = file_dialog.open_finish(result)
except:
self.logger.error(e)
try:
file = file_dialog.open_finish(result)
except Exception as e:
logger.error(e)
return
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 not file_type:
return
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)
return
self.attach_file(file.get_path(), file_type)
def attach_file(self, filter):
file_dialog = Gtk.FileDialog(default_filter=filter)
def attach_file(self, file_filter):
file_dialog = Gtk.FileDialog(default_filter=file_filter)
file_dialog.open(self, None, lambda file_dialog, result: attach_file_response(self, file_dialog, result))
# YouTube caption | WORKS
def youtube_caption_response(self, dialog, task, video_url, caption_drop_down):
@@ -316,12 +330,12 @@ def youtube_caption_response(self, dialog, task, video_url, caption_drop_down):
yt = YouTube(video_url)
text = "{}\n{}\n{}\n\n".format(yt.title, yt.author, yt.watch_url)
selected_caption = caption_drop_down.get_selected_item().get_string()
for event in yt.captions[selected_caption.split(' | ')[1]].json_captions['events']:
for event in yt.captions[selected_caption.split('(')[1][:-1]].json_captions['events']:
text += "{}\n".format(event['segs'][0]['utf8'].replace('\n', '\\n'))
if not os.path.exists(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]})')
with open(file_path, 'w+') as f:
with open(file_path, 'w+', encoding="utf-8") as f:
f.write(text)
self.attach_file(file_path, 'youtube')
@@ -333,9 +347,10 @@ def youtube_caption(self, video_url):
self.show_toast(_("This video does not have any transcriptions"), self.main_overlay)
return
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.title(), caption.code))
caption_drop_down = Gtk.DropDown(
enable_search=True,
enable_search=len(captions) > 10,
model=caption_list
)
dialog = Adw.AlertDialog(
@@ -347,6 +362,7 @@ def youtube_caption(self, video_url):
dialog.add_response("cancel", _("Cancel"))
dialog.add_response("accept", _("Accept"))
dialog.set_response_appearance("accept", Adw.ResponseAppearance.SUGGESTED)
dialog.set_default_response("accept")
dialog.choose(
parent = self,
cancellable = None,
@@ -369,7 +385,7 @@ def attach_website_response(self, dialog, task, url):
os.makedirs('/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)
with open(file_path, 'w+') as f:
with open(file_path, 'w+', encoding="utf-8") as f:
f.write('{}\n\n{}'.format(url, md))
self.attach_file(file_path, 'website')
else:
@@ -385,38 +401,9 @@ def attach_website(self, url):
dialog.add_response("cancel", _("Cancel"))
dialog.add_response("accept", _("Accept"))
dialog.set_response_appearance("accept", Adw.ResponseAppearance.SUGGESTED)
dialog.set_default_response("accept")
dialog.choose(
parent = self,
cancellable = None,
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')
elif res == 'nope':
self.show_toast(_("Visit Alpaca's website if you change your mind!"), self.main_overlay)
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"><path d="m 2.292969 6.707031 l 5 5 c 0.390625 0.390625 1.023437 0.390625 1.414062 0 l 5 -5 c 0.390625 -0.390625 0.390625 -1.023437 0 -1.414062 s -1.023437 -0.390625 -1.414062 0 l -4.292969 4.292969 l -4.292969 -4.292969 c -0.390625 -0.390625 -1.023437 -0.390625 -1.414062 0 s -0.390625 1.023437 0 1.414062 z m 0 0" fill="#222222" fill-rule="evenodd"/></svg>

After

Width:  |  Height:  |  Size: 484 B

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,46 @@
# local_instance.py
import subprocess, os, threading
"""
Handles running, stopping and resetting the integrated Ollama instance
"""
import subprocess
import threading
import os
from time import sleep
from logging import getLogger
from .internal import data_dir, cache_dir
logger = getLogger(__name__)
instance = None
port = 11435
data_dir = os.getenv("XDG_DATA_HOME")
overrides = {}
def log_output(pipe):
with open(os.path.join(data_dir, 'tmp.log'), 'a') as f:
with pipe:
for line in iter(pipe.readline, ''):
print(line, end='')
f.write(line)
f.flush()
def start():
if not os.path.isdir(os.path.join(os.getenv("XDG_CACHE_HOME"), 'tmp/ollama')):
os.mkdir(os.path.join(os.getenv("XDG_CACHE_HOME"), 'tmp/ollama'))
global instance, overrides
if not os.path.isdir(os.path.join(cache_dir, 'tmp/ollama')):
os.mkdir(os.path.join(cache_dir, 'tmp/ollama'))
global instance
params = overrides.copy()
params["OLLAMA_HOST"] = f"127.0.0.1:{port}" # You can't change this directly sorry :3
params["HOME"] = data_dir
params["TMPDIR"] = os.path.join(os.getenv("XDG_CACHE_HOME"), 'tmp/ollama')
instance = subprocess.Popen(["/app/bin/ollama", "serve"], env={**os.environ, **params}, stderr=subprocess.PIPE, text=True)
params["TMPDIR"] = os.path.join(cache_dir, 'tmp/ollama')
instance = subprocess.Popen(["ollama", "serve"], env={**os.environ, **params}, stderr=subprocess.PIPE, stdout=subprocess.PIPE, text=True)
threading.Thread(target=log_output, args=(instance.stdout,)).start()
threading.Thread(target=log_output, args=(instance.stderr,)).start()
logger.info("Starting Alpaca's Ollama instance...")
logger.debug(params)
sleep(1)
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():
logger.info("Stopping Alpaca's Ollama instance")
@@ -39,4 +56,3 @@ def reset():
stop()
sleep(1)
start()

View File

@@ -16,21 +16,36 @@
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#
# 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 logging
import gi
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__)
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',
'Aritra Saha (Hindi) https://github.com/olumolu'
]
class AlpacaApplication(Adw.Application):
"""The main application singleton class."""
@@ -38,8 +53,8 @@ class AlpacaApplication(Adw.Application):
def __init__(self, version):
super().__init__(application_id='com.jeffser.Alpaca',
flags=Gio.ApplicationFlags.DEFAULT_FLAGS)
self.create_action('quit', lambda *_: self.quit(), ['<primary>q'])
self.create_action('preferences', lambda *_: AlpacaWindow.show_preferences_dialog(self.props.active_window), ['<primary>p'])
self.create_action('quit', lambda *_: self.props.active_window.closing_app(None), ['<primary>w', '<primary>q'])
self.create_action('preferences', lambda *_: AlpacaWindow.show_preferences_dialog(self.props.active_window), ['<primary>comma'])
self.create_action('about', self.on_about_action)
self.version = version
@@ -58,12 +73,13 @@ class AlpacaApplication(Adw.Application):
support_url="https://github.com/Jeffser/Alpaca/discussions/155",
developers=['Jeffser https://jeffser.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',
issue_url='https://github.com/Jeffser/Alpaca/issues',
license_type=3,
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)
def create_action(self, name, callback, shortcuts=None):
@@ -75,16 +91,16 @@ class AlpacaApplication(Adw.Application):
def main(version):
if os.path.isfile(os.path.join(os.getenv("XDG_DATA_HOME"), 'tmp.log')):
os.remove(os.path.join(os.getenv("XDG_DATA_HOME"), 'tmp.log'))
if os.path.isdir(os.path.join(os.getenv("XDG_CACHE_HOME"), 'tmp')):
os.system('rm -rf ' + os.path.join(os.getenv("XDG_CACHE_HOME"), "tmp/*"))
if os.path.isfile(os.path.join(data_dir, 'tmp.log')):
os.remove(os.path.join(data_dir, 'tmp.log'))
if os.path.isdir(os.path.join(cache_dir, 'tmp')):
os.system('rm -rf ' + os.path.join(cache_dir, "tmp/*"))
else:
os.mkdir(os.path.join(os.getenv("XDG_CACHE_HOME"), 'tmp'))
os.mkdir(os.path.join(cache_dir, 'tmp'))
logging.basicConfig(
format="%(levelname)s\t[%(filename)s | %(funcName)s] %(message)s",
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)
logger.info(f"Alpaca version: {app.version}")

View File

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

View File

@@ -1,7 +1,3 @@
.message_input_scroll_window > * {
box-shadow: none;
border-width: 0;
}
.message_text_view, .modelfile_textview {
background-color: rgba(0,0,0,0);
}
@@ -12,3 +8,23 @@
border-radius: 5px;
padding: 5px;
}
.model_list_box {
padding: 0;
}
.manage_models_button {
padding: 6px 8px 6px 8px;
font-weight: 400;
}
.model_list_box > * {
margin: 0;
}
.user_message, .response_message {
padding: 12px;
border-radius: 10px;
}
.user_message:focus, .response_message:focus, .editing_message_textview:focus, .code_block:focus {
box-shadow: 0 0 1px 2px mix(@accent_color, @window_bg_color, 0.5);
}
.model_popover {
margin-top: 6px;
}

View File

@@ -1,5 +1,10 @@
#table_widget.py
"""
Handles the table widget shown in chat responses
"""
import gi
from gi.repository import Adw
gi.require_version('Gtk', '4.0')
from gi.repository import Gtk, GObject, Gio
import re

File diff suppressed because it is too large Load Diff

View File

@@ -5,32 +5,21 @@
<template class="AlpacaWindow" parent="AdwApplicationWindow">
<signal name="close-request" handler="closing_app"/>
<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="default-width">1300</property>
<property name="default-height">800</property>
<property name="title">Alpaca</property>
<child>
<object class="AdwBreakpoint">
<condition>max-width: 800sp</condition>
<condition>max-width: 690sp</condition>
<setter object="split_view_overlay" property="collapsed">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="welcome_dialog" property="width-request">360</setter>
<setter object="manage_models_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>
</child>
<property name="content">
<object class="AdwOverlaySplitView" id="split_view_overlay">
<property name="show-sidebar" bind-source="show_sidebar_button" bind-property="active" bind-flags="sync-create"/>
<property name="sidebar-width-fraction">0.4</property>
<property name="sidebar">
<object class="AdwToolbarView">
<child type="top">
@@ -87,28 +76,82 @@
<property name="orientation">0</property>
<property name="spacing">12</property>
<child>
<object class="GtkDropDown" id="model_drop_down">
<signal name="notify" handler="verify_if_image_can_be_used"/>
<property name="width-request">175</property>
<property name="enable-search">true</property>
<property name="tooltip-text">Select Model</property>
<property name="model">
<object class="GtkStringList" id="model_string_list">
<items>
</items>
<object class="GtkMenuButton" id="model_selector_button">
<property name="tooltip-text" translatable="yes">Select Model</property>
<property name="child">
<object class="GtkBox">
<property name="spacing">10</property>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">Select a Model</property>
<property name="ellipsize">2</property>
</object>
</child>
<child>
<object class="GtkImage">
<property name="icon-name">down-symbolic</property>
</object>
</child>
</object>
</property>
</object>
</child>
<child>
<object class="GtkButton" id="manage_models_button">
<signal name="clicked" handler="manage_models_button_activate"/>
<property name="tooltip-text" translatable="yes">Manage Models</property>
<child>
<object class="AdwButtonContent">
<property name="icon-name">brain-augemnted-symbolic</property>
<property name="halign">1</property>
<style>
<class name="raised"/>
</style>
<property name="popover">
<object class="GtkPopover" id="model_popover">
<style>
<class name="model_popover"/>
</style>
<property name="has-arrow">false</property>
<child>
<object class="GtkBox">
<property name="orientation">1</property>
<property name="spacing">5</property>
<child>
<object class="GtkButton">
<property name="child">
<object class="GtkLabel">
<property name="label" translatable="yes">Manage Models</property>
<property name="justify">left</property>
<property name="halign">1</property>
</object>
</property>
<property name="hexpand">true</property>
<property name="tooltip-text" translatable="yes">Manage Models</property>
<property name="action-name">app.manage_models</property>
<signal name="clicked" handler="close_model_popup"/>
<style>
<class name="flat"/>
<class name="manage_models_button"/>
</style>
</object>
</child>
<child>
<object class="GtkSeparator"/>
</child>
<child>
<object class="GtkScrolledWindow">
<property name="max-content-height">300</property>
<property name="propagate-natural-width">true</property>
<property name="propagate-natural-height">true</property>
<child>
<object class="GtkListBox" id="model_list_box">
<property name="hexpand">true</property>
<style>
<class name="navigation-sidebar"/>
<class name="model_list_box"/>
</style>
<signal name="row-selected" handler="change_model"/>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</child>
</property>
</object>
</child>
</object>
@@ -227,6 +270,10 @@
<property name="top-margin">10</property>
<property name="bottom-margin">10</property>
<property name="hexpand">true</property>
<property name="input-hints">spellcheck</property>
<accessibility>
<property name="label" translatable="yes">Message text box</property>
</accessibility>
</object>
</child>
</object>
@@ -454,6 +501,9 @@
</object>
<object class="AdwDialog" id="manage_models_dialog">
<accessibility>
<property name="label" translatable="yes">Manage models dialog</property>
</accessibility>
<property name="can-close">true</property>
<property name="width-request">400</property>
<property name="height-request">600</property>
@@ -488,12 +538,18 @@
</child>
<child type="top">
<object class="GtkSearchBar" id="model_searchbar">
<accessibility>
<property name="label" translatable="yes">Model search bar</property>
</accessibility>
<property name="key-capture-widget">AlpacaWindow</property>
<child>
<object class="GtkSearchEntry" id="searchentry">
<signal name="search-changed" handler="model_search_changed"/>
<property name="search-delay">100</property>
<property name="placeholder-text" translatable="yes">Search models</property>
<accessibility>
<property name="label" translatable="yes">Search models</property>
</accessibility>
</object>
</child>
</object>
@@ -529,7 +585,7 @@
</child>
<child>
<object class="GtkListBox" id="available_model_list_box">
<property name="selection-mode">single</property>
<property name="selection-mode">none</property>
<style>
<class name="boxed-list"/>
</style>
@@ -592,7 +648,7 @@
<child>
<object class="GtkListBox" id="model_tag_list_box">
<property name="valign">1</property>
<property name="selection-mode">single</property>
<property name="selection-mode">none</property>
<style>
<class name="boxed-list"/>
</style>
@@ -750,9 +806,12 @@
</object>
<object class="AdwDialog" id="file_preview_dialog">
<accessibility>
<property name="label" translatable="yes">File preview dialog</property>
</accessibility>
<property name="can-close">true</property>
<property name="width-request">450</property>
<property name="height-request">450</property>
<property name="width-request">400</property>
<property name="height-request">600</property>
<child>
<object class="AdwToolbarView">
<child type="top">
@@ -817,8 +876,8 @@
<object class="AdwDialog" id="welcome_dialog">
<property name="can-close">false</property>
<property name="width-request">450</property>
<property name="height-request">450</property>
<property name="width-request">400</property>
<property name="height-request">600</property>
<child>
<object class="AdwToolbarView">
<child type="bottom">
@@ -897,141 +956,6 @@
<property name="description" translatable="yes">Alpaca and its developers are not liable for any damages to devices or software resulting from the execution of code generated by an AI model. Please exercise caution and review the code carefully before running it.</property>
</object>
</child>
<child>
<object class="AdwStatusPage">
<property name="hexpand">true</property>
<property name="vexpand">true</property>
<property name="margin-top">12</property>
<property name="margin-bottom">12</property>
<property name="margin-start">12</property>
<property name="margin-end">12</property>
<property name="title" translatable="yes">Featured Models</property>
<property name="description" translatable="yes">Alpaca works locally on your device, to start chatting you'll need an AI model, you can either pull models from this list or the 'Manage Models' menu later.
By downloading any model you accept their license agreement available on the model's website.
</property>
<child>
<object class="GtkListBox">
<property name="selection-mode">none</property>
<style>
<class name="boxed-list"/>
</style>
<child>
<object class="AdwActionRow">
<property name="title" translatable="no">Llama3</property>
<property name="subtitle" translatable="yes">Built by Meta</property>
<child type="suffix">
<object class="GtkButton">
<signal name="clicked" handler="link_button_handler"/>
<property name="vexpand">false</property>
<property name="icon-name">globe-symbolic</property>
<property name="valign">3</property>
<property name="name">https://ollama.com/library/llama3</property>
<property name="tooltip-text">https://ollama.com/library/llama3</property>
</object>
</child>
<child type="suffix">
<object class="GtkButton">
<signal name="clicked" handler="pull_featured_model"/>
<property name="vexpand">false</property>
<property name="icon-name">folder-download-symbolic</property>
<property name="valign">3</property>
<property name="tooltip-text">Pull 'Llama3 (latest)'</property>
<style>
<class name="accent"/>
</style>
</object>
</child>
</object>
</child>
<child>
<object class="AdwActionRow">
<property name="title" translatable="no">Gemma2</property>
<property name="subtitle" translatable="yes">Built by Google DeepMind</property>
<child type="suffix">
<object class="GtkButton">
<signal name="clicked" handler="link_button_handler"/>
<property name="vexpand">false</property>
<property name="icon-name">globe-symbolic</property>
<property name="valign">3</property>
<property name="name">https://ollama.com/library/gemma2</property>
<property name="tooltip-text">https://ollama.com/library/gemma2</property>
</object>
</child>
<child type="suffix">
<object class="GtkButton">
<signal name="clicked" handler="pull_featured_model"/>
<property name="vexpand">false</property>
<property name="icon-name">folder-download-symbolic</property>
<property name="valign">3</property>
<property name="tooltip-text">Pull 'Gemma2 (latest)'</property>
<style>
<class name="accent"/>
</style>
</object>
</child>
</object>
</child>
<child>
<object class="AdwActionRow">
<property name="title" translatable="no">Phi3</property>
<property name="subtitle" translatable="yes">Built by Microsoft</property>
<child type="suffix">
<object class="GtkButton">
<signal name="clicked" handler="link_button_handler"/>
<property name="vexpand">false</property>
<property name="icon-name">globe-symbolic</property>
<property name="valign">3</property>
<property name="name">https://ollama.com/library/phi3</property>
<property name="tooltip-text">https://ollama.com/library/phi3</property>
</object>
</child>
<child type="suffix">
<object class="GtkButton">
<signal name="clicked" handler="pull_featured_model"/>
<property name="vexpand">false</property>
<property name="icon-name">folder-download-symbolic</property>
<property name="valign">3</property>
<property name="tooltip-text">Pull 'Phi3 (latest)'</property>
<style>
<class name="accent"/>
</style>
</object>
</child>
</object>
</child>
<child>
<object class="AdwActionRow">
<property name="title" translatable="no">Llava</property>
<property name="subtitle" translatable="yes">Multimodal AI with image recognition</property>
<child type="suffix">
<object class="GtkButton">
<signal name="clicked" handler="link_button_handler"/>
<property name="vexpand">false</property>
<property name="icon-name">globe-symbolic</property>
<property name="valign">3</property>
<property name="name">https://ollama.com/library/llava</property>
<property name="tooltip-text">https://ollama.com/library/llava</property>
</object>
</child>
<child type="suffix">
<object class="GtkButton">
<signal name="clicked" handler="pull_featured_model"/>
<property name="vexpand">false</property>
<property name="icon-name">folder-download-symbolic</property>
<property name="valign">3</property>
<property name="tooltip-text">Pull 'Llava (latest)'</property>
<style>
<class name="accent"/>
</style>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
@@ -1045,6 +969,10 @@ By downloading any model you accept their license agreement available on the mod
<attribute name="label" translatable="yes">Import Chat</attribute>
<attribute name="action">app.import_chat</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Manage Models</attribute>
<attribute name="action">app.manage_models</attribute>
</item>
</section>
<section>
<item>
@@ -1062,34 +990,52 @@ By downloading any model you accept their license agreement available on the mod
</section>
</menu>
<menu id="secondary_menu">
<item>
<attribute name="label" translatable="yes">Rename Chat</attribute>
<attribute name="action">app.rename_current_chat</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Export Chat</attribute>
<attribute name="action">app.export_current_chat</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Clear Chat</attribute>
<attribute name="action">app.clear</attribute>
</item>
</menu>
<menu id="chat_right_click_menu">
<section>
<item>
<attribute name="label" translatable="yes">Rename Chat</attribute>
<attribute name="action">app.rename_current_chat</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Duplicate Chat</attribute>
<attribute name="action">app.duplicate_current_chat</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Export Chat</attribute>
<attribute name="action">app.export_current_chat</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Clear Chat</attribute>
<attribute name="action">app.clear</attribute>
</item>
</section>
<section>
<item>
<attribute name="label" translatable="yes">Delete Chat</attribute>
<attribute name="action">app.delete_chat</attribute>
<attribute name="action">app.delete_current_chat</attribute>
</item>
</section>
</menu>
<menu id="chat_right_click_menu">
<section>
<item>
<attribute name="label" translatable="yes">Rename Chat</attribute>
<attribute name="action">app.rename_chat</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Duplicate Chat</attribute>
<attribute name="action">app.duplicate_chat</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Export Chat</attribute>
<attribute name="action">app.export_chat</attribute>
</item>
</section>
<section>
<item>
<attribute name="label" translatable="yes">Delete Chat</attribute>
<attribute name="action">app.delete_chat</attribute>
</item>
</section>
</menu>
<menu id="create_model_menu">
<section>
@@ -1147,7 +1093,7 @@ By downloading any model you accept their license agreement available on the mod
<property name="title" translatable="yes">General</property>
<child>
<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>
</object>
</child>
@@ -1165,7 +1111,7 @@ By downloading any model you accept their license agreement available on the mod
</child>
<child>
<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>
</object>
</child>
@@ -1181,6 +1127,18 @@ By downloading any model you accept their license agreement available on the mod
<property name="title" translatable="yes">Show shortcuts window</property>
</object>
</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>
</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
with open('src/available_models.json', 'r') as f:
data = json.load(f)
results = 'descriptions = {\n'
for key, value in data.items():
results += f" '{key}': _(\"{value['description']}\"),\n"
results += '}'
with open('src/available_models_descriptions.py', 'w+') as f:
f.write(results)
if __name__ == "__main__":
with open('src/available_models.json', 'r', encoding="utf-8") as f:
data = json.load(f)
RESULTS = 'descriptions = {\n'
for key, value in data.items():
RESULTS += f" '{key}': _(\"{value['description']}\"),\n"
RESULTS += '}'
with open('src/available_models_descriptions.py', 'w+', encoding="utf-8") as f:
f.write(RESULTS)

View File

@@ -15,4 +15,6 @@ msgmerge --no-fuzzy-matching -U po/nb_NO.po po/alpaca.pot
echo "Updating Bengali"
msgmerge --no-fuzzy-matching -U po/bn.po po/alpaca.pot
echo "Updating Simplified Chinese"
msgmerge --no-fuzzy-matching -U po/zh_CN.po po/alpaca.pot
msgmerge --no-fuzzy-matching -U po/zh_CN.po po/alpaca.pot
echo "Updating Hindi"
msgmerge --no-fuzzy-matching -U po/hi.po po/alpaca.pot