517 Commits

Author SHA1 Message Date
Jeffry Samuel
f4f91d9aa1 Update README.md 2024-09-10 00:12:30 -06:00
YusaBecerikli
ad5f73e985 Update tr.po (#290)
* Update tr.po

* Update tr.po

I deleted line 5 and revised line 10.

---------

Co-authored-by: Jeffry Samuel <jeffrysamuer@gmail.com>
2024-09-10 00:10:04 -06:00
aritra saha
d06ac2c2eb Update bn.po (#286)
* Update bn.po

* Update bn.po
2024-09-05 15:13:08 -06:00
aritra saha
343411cd8c Update hi.po (#287) 2024-09-05 10:45:23 -06:00
Simon
e14750db44 Update uk.po (#288) 2024-09-05 10:44:49 -06:00
Marcel Margenberg
3be3b21f93 Additional German Translation (#285)
* Updated de.po for v2.0.0

Translated for the new update

* Update de.po

Fixed typo

* Update de.po
2024-09-04 19:15:35 -06:00
jeffser
5c28245ff3 Spanish update 2024-09-04 15:45:39 -06:00
jeffser
b433091e90 Updated translations 2024-09-04 15:44:29 -06:00
jeffser
fe22f34a3d Updated copyright info 2024-09-04 15:32:01 -06:00
jeffser
ef395a27a3 Added Polish template 2024-09-04 15:31:45 -06:00
jeffser
362e62ee36 Fixed welcome dialog not baing able to close after initial load 2024-09-04 15:18:37 -06:00
jeffser
80aabcb805 Fixed error on config save 2024-09-04 15:16:46 -06:00
jeffser
c283f3f1d2 Fixed translation updater with new Simplified Chinese locale 2024-09-04 15:09:06 -06:00
mags0ft
603fdb8150 Add an option to hide the power save warning at startup (#282)
* add an option to hide the power save warning at startup

* Fixed stuff and made it positive

* Changed description and name of switch

* Fixed tab

* Fixed name of element (my bad)

* Check power saver mode state when switching

* Warning set to true by default

---------

Co-authored-by: Jeffry Samuel <jeffrysamuer@gmail.com>
2024-09-04 15:05:16 -06:00
mags0ft
6e0ae393a4 made font family of code blocks monospace (#284) 2024-09-04 14:23:32 -06:00
Yuehao Sui
abbdbf1abe Update Simplified Chinese Translation (#279) 2024-09-04 09:26:20 -06:00
Louis Chauvet-Villaret
a68973ece6 French update (#278) 2024-09-04 09:20:54 -06:00
jeffser
50aad8cb6d even better checker 2024-09-03 22:06:23 -06:00
jeffser
79a7840f24 Better checker for Ollama instance missing 2024-09-03 21:56:37 -06:00
jeffser
19a8aade60 Fixed remote connection and added checker for Ollama missing 2024-09-03 21:52:14 -06:00
jeffser
a591270d58 Removed prints 2024-09-02 18:40:23 -06:00
jeffser
1087d3e336 Fixed run on background 2024-09-02 18:18:49 -06:00
jeffser
fb7393fe5c Fixed crash at close 2024-09-02 17:57:48 -06:00
jeffser
d3159ae6ea Fixed regeneration 2024-09-02 17:22:54 -06:00
jeffser
c2c047d8b7 Save at send message and fixed copy button on code blocks 2024-09-02 17:00:35 -06:00
jeffser
e897d6c931 Removed unnecesary line 2024-09-02 16:33:13 -06:00
jeffser
3ceb25ccc6 Fixed YouTube integration 2024-09-02 16:31:27 -06:00
jeffser
9d740a7db9 Modified logging 2024-09-02 16:18:23 -06:00
jeffser
4e77898487 Fixed export chat 2024-09-02 16:16:27 -06:00
jeffser
c913a25679 Fixed app not launching when there are too many messages 2024-09-02 16:12:49 -06:00
jeffser
758e055f1c Added save on rename, duplicate and import of chats 2024-09-02 16:10:53 -06:00
jeffser
a08be7351c Fixed model pull by name 2024-09-02 16:04:17 -06:00
jeffser
08c0c54b98 Fixed extension 2024-09-02 14:51:53 -06:00
jeffser
687b99f9ab Update welcome screen when a model is pulled / created / deleted 2024-09-02 13:36:17 -06:00
jeffser
5801d43af9 Fixed delete model 2024-09-02 13:15:44 -06:00
jeffser
5a28a16119 Fixed pull model 2024-09-02 12:52:15 -06:00
jeffser
47e58d2ccd Welcome dialog now waits for the app to be fully loaded 2024-09-02 12:50:19 -06:00
jeffser
d33e9c53d8 Removed unnecesary code 2024-09-02 12:43:41 -06:00
aritra saha
8869296aed Update hi.po and bn.po (#274)
* Update hi.po

* Update bn.po

* Update es.po

* Update fr.po

* Update de.po
2024-09-02 12:16:58 -06:00
Marcel Margenberg
da4dd3341a Updated de.po for v2.0.0 (#275)
* Updated de.po for v2.0.0

Translated for the new update

* Update de.po

Fixed typo
2024-09-02 12:16:42 -06:00
Simon
15aa7fb844 Updating the Ukrainian translation to the latest version (#276) 2024-09-02 12:16:07 -06:00
Jeffry Samuel
d74f535968 Changed extension name 2024-09-02 04:24:00 -06:00
jeffser
521a95fc6b Fixed rare crash at launch 2024-09-02 03:17:23 -06:00
jeffser
9548e2ec40 Updated spanish translation 2024-09-02 03:13:50 -06:00
jeffser
f1a3c7136f Updated languages 2024-09-02 03:00:45 -06:00
jeffser
4542f26bb7 Updated release notes 2024-09-02 03:00:06 -06:00
jeffser
4926cb157e Removed unnecesary timer start and added *60 to make it minutes 2024-09-02 02:56:57 -06:00
jeffser
0d3b544a73 Finished timer implementation 2024-09-02 02:55:02 -06:00
jeffser
daf56c2de4 Added inactive timer 2024-09-02 02:38:03 -06:00
jeffser
46e3921585 Added version notes (the update is still not ready) 2024-09-02 01:35:52 -06:00
jeffser
707984e20d New model list 2024-09-02 01:08:15 -06:00
jeffser
cfb79a70be Moved description extractor to internal tooling 2024-09-02 01:06:44 -06:00
jeffser
c32d0acfd4 Added back chat notifications 2024-09-02 00:43:49 -06:00
jeffser
38de4ac18e Fixed extension 2024-09-01 23:36:25 -06:00
jeffser
923c0e52e2 Added AMD extension 2024-09-01 19:10:27 -06:00
jeffser
e753591b45 Properly written module 2024-09-01 18:21:24 -06:00
jeffser
12e754e4bc Updated Ollama to v0.3.9 2024-09-01 18:12:01 -06:00
jeffser
eb3919ad63 Adding /sys/module/amdgpu to filesystem 2024-09-01 17:46:50 -06:00
jeffser
1b94864422 Added new message indicator 2024-09-01 16:56:18 -06:00
jeffser
51a90e0b79 Merge branch 'main' of github.com-jeffser:Jeffser/Alpaca 2024-09-01 16:56:00 -06:00
jeffser
7264902199 Added Ollama debug 2024-09-01 16:55:53 -06:00
Allie
f08b03308e Add keywords to .desktop file (#271)
* add keywords to .desktop file

This allows for easier searching for the app

* Update com.jeffser.Alpaca.desktop.in

---------

Co-authored-by: Jeffry Samuel <jeffrysamuer@gmail.com>
2024-09-01 14:28:20 -06:00
jeffser
f831466d87 Better handling of focus with messages 2024-08-31 22:00:57 -06:00
jeffser
a54ec6fa9d Added spinner for chats receiving messages 2024-08-31 22:00:42 -06:00
jeffser
ed3136cffd Reverting that 2024-08-31 20:42:34 -06:00
jeffser
e37c5acbf9 Save selected chat when chat is changed 2024-08-31 20:41:50 -06:00
jeffser
9d2ad2eb3a Scroll to bottom when chat is changed 2024-08-31 20:37:35 -06:00
jeffser
d1a0d6375b Fixed reconnect dialog and made it so that the launch dialog doesn't appear with remote connections 2024-08-31 20:03:19 -06:00
jeffser
ebf3af38c8 Fixed name 2024-08-31 19:29:08 -06:00
jeffser
80b433e7a4 Code cleaning 2024-08-31 19:23:50 -06:00
jeffser
5da5c2c702 Code cleaning 2024-08-31 19:09:46 -06:00
jeffser
fe8626f650 Changed string 2024-08-31 18:26:59 -06:00
jeffser
ee998d978f Instant launch! 2024-08-31 18:24:53 -06:00
jeffser
cee360d5a2 Better remote instance switcher 2024-08-31 17:35:25 -06:00
jeffser
5098babfd2 Clean code 2024-08-31 17:27:04 -06:00
jeffser
7026655116 New instance manager 'ollama_instance' 2024-08-31 17:14:39 -06:00
jeffser
01ba38a23b Added new files to translation list 2024-08-31 16:51:16 -06:00
jeffser
ef2c2650b0 Added drag and drop to text entry 2024-08-30 21:48:50 -06:00
jeffser
a7d955a5bf Check for power saver at start 2024-08-30 20:41:29 -06:00
jeffser
129677d27c Warning banner is now hidden by default 2024-08-30 20:40:00 -06:00
jeffser
9ae011a31b fixed tabbing 2024-08-30 20:36:01 -06:00
jeffser
abf1253980 Remove unused variables 2024-08-30 20:34:05 -06:00
jeffser
e0c7e9c771 Remove unnecesary code 2024-08-30 20:30:37 -06:00
jeffser
6a4c98ef18 Added warning for power saver 2024-08-30 20:29:23 -06:00
jeffser
809e23fb9c Added autoscrolling 2024-08-30 20:10:31 -06:00
jeffser
69eaa56240 Fixed attachments 2024-08-30 14:12:01 -06:00
jeffser
df2a9d7b26 Tweaked model selector appearance 2024-08-30 13:42:52 -06:00
jeffser
da97a7c6ee Fixed YouTube integration 2024-08-30 13:39:10 -06:00
jeffser
bb7a8b659a Removed unnecesary method 2024-08-30 13:38:56 -06:00
jeffser
0999a64356 Restored image recognition 2024-08-30 12:42:48 -06:00
jeffser
4647e1ba47 Merge branch 'main' of github.com-jeffser:Jeffser/Alpaca 2024-08-30 12:42:30 -06:00
jeffser
ea0caf03d6 Fixed copy code block button 2024-08-30 12:42:24 -06:00
Marcel Margenberg
1c9ce2a117 Update main.py (#269)
Added Ukrainian & German Contributors
2024-08-28 14:29:35 -06:00
jeffser
01b38fa37a Added back support for creating models 2024-08-28 11:51:12 -06:00
Jeffry Samuel
80d1149932 Update README.md 2024-08-28 10:34:35 -06:00
Marcel Margenberg
cc1500f007 Fixed formatting conflicts (#267)
* Update de.po

Fixed string errors

* Update de.po

Fixed all string errors

* Update de.po

fixed
2024-08-28 10:24:17 -06:00
jeffser
d0735de129 New model manager (create model doesn't work yet) 2024-08-27 23:25:58 -06:00
jeffser
bbf678cb75 Added German to translations update script 2024-08-27 15:10:16 -06:00
jeffser
a44a7b5044 Added Ukrainian and German to the list of available languages 2024-08-27 15:09:25 -06:00
Jeffry Samuel
427ecd4499 Update README.md 2024-08-27 15:07:20 -06:00
Marcel Margenberg
0a5bb0b97f Full German Translation (#265) 2024-08-27 15:05:55 -06:00
jeffser
252b76e7eb Merge branch 'main' of github.com-jeffser:Jeffser/Alpaca 2024-08-26 23:16:57 -06:00
jeffser
5cf2be2b7d Actually stop the thread when the message generation stops 2024-08-26 23:16:49 -06:00
aritra saha
7f9a5eb516 Update hi.po (#263) 2024-08-26 17:49:44 -06:00
aritra saha
9ecfbe8c3f Update bn.po (#262) 2024-08-26 17:49:27 -06:00
jeffser
377adc8699 Updated translation files 2024-08-26 15:10:03 -06:00
jeffser
8598f73be7 Changed text and tooltip for button 2024-08-26 14:28:13 -06:00
jeffser
6f9b3b7c02 Changed message footer format 2024-08-26 14:26:13 -06:00
jeffser
db198e10c0 Added back regenerate button 2024-08-26 14:05:42 -06:00
jeffser
d2271a7ade Changed master to 46 2024-08-26 13:17:54 -06:00
jeffser
8d3d650ecf Merge branch 'main' of github.com-jeffser:Jeffser/Alpaca 2024-08-26 13:17:03 -06:00
jeffser
4545f5a1b2 Rewrite of Chat / Message / Model selector systems 2024-08-26 13:16:55 -06:00
Jeffry Samuel
62c1354f8b Update README.md 2024-08-26 12:54:23 -06:00
Simon
2bd99860f2 Added translation into Ukrainian language. (#256)
* Added Ukrainian translation

* Clearing the translation

* standardisation
2024-08-26 12:52:58 -06:00
jeffser
8026550f7a Added Ukrainian file 2024-08-25 11:57:48 -06:00
jeffser
68c03176d4 Made directory for custom widgets 2024-08-23 13:52:43 -06:00
jeffser
ed54b2846a Added exception catch to Ollama's output in case it can't decode message 2024-08-19 23:06:58 -06:00
jeffser
ff927d6c77 Merge branch 'main' of github.com-jeffser:Jeffser/Alpaca 2024-08-19 23:01:49 -06:00
jeffser
bd006da0c1 Added check for title generation 2024-08-19 23:01:40 -06:00
YusaBecerikli
a409800279 Lines 389 and 390 have been changed (#250) 2024-08-15 23:39:05 -06:00
Jeffser
5d89ccc729 Added Turkish credits 2024-08-15 23:38:27 -06:00
Jeffser
fef3926ce3 Added Turkish officially 2024-08-15 23:37:02 -06:00
Jeffry Samuel
c95be9611d added turkish credits 2024-08-15 23:36:04 -06:00
YusaBecerikli
1c4fc4341e Update tr.po (#249) 2024-08-15 23:29:55 -06:00
Jeffser
3ddc172437 Changed .accent for .suggested-action 2024-08-15 00:19:55 -06:00
Jeffser
0d65cf1cbc Added turkish template 2024-08-15 00:02:35 -06:00
aritra saha
cddcf496b2 update (#241)
* Update bn.po

* Update hi.po
2024-08-13 16:22:45 -06:00
Louis Chauvet-Villaret
9333b31444 French update (#244) 2024-08-13 16:22:27 -06:00
Jeffry Samuel
cbd3e90073 Update bug_report.md 2024-08-12 23:59:10 -06:00
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
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
jeffser
55a636f4d1 typo 2024-08-01 01:30:20 -06:00
jeffser
0fc8730272 dialog added to version notes 2024-08-01 01:27:49 -06:00
jeffser
61a2bc466e Changed content rating because of the donation dialog 2024-08-01 01:13:14 -06:00
jeffser
62b1923bf4 Added support dialog 2024-08-01 01:11:27 -06:00
jeffser
8e25376a12 Merge branch 'main' of github.com-jeffser:Jeffser/Alpaca 2024-08-01 00:49:26 -06:00
jeffser
a9ab5d45a4 Preparing for 1.0.3 2024-08-01 00:49:19 -06:00
Jeffry Samuel
ce2a2f0b93 :) 2024-08-01 00:40:45 -06:00
jeffser
9cb6b0b665 Code block and markup fixes 2024-08-01 00:33:26 -06:00
jeffser
dfc21fc0e9 Fixed date format for Chinese translation 2024-07-31 23:32:49 -06:00
jeffser
19b089e6c6 Fixed problems with localization 2024-07-31 22:36:39 -06:00
jeffser
02aa2734e0 Changed window min height 2024-07-31 22:08:48 -06:00
jeffser
66f9fd7231 better check for connection 2024-07-31 21:17:31 -06:00
jeffser
1b125cb704 Appearance changes 2024-07-31 21:13:23 -06:00
jeffser
29f5d85c7b Added string to translation list 2024-07-31 19:55:30 -06:00
jeffser
c192a1f31c Added compatibility with generic code blocks without explicit language 2024-07-31 19:54:47 -06:00
jeffser
3b20daf807 Added bearer token entry to connection error dialog 2024-07-31 19:42:46 -06:00
jeffser
760c00e8ae Added German template 2024-07-30 12:48:20 -06:00
jeffser
6d8d3788a6 Added new models 2024-07-29 02:06:06 -06:00
jeffser
98e23e0033 Updated Ollama to v0.3.0 2024-07-29 01:50:52 -06:00
jeffser
4d7aff3458 Preparing for 1.0.2 2024-07-29 01:47:32 -06:00
jeffser
33e47696dc Fixed: Models with capital letters on the tag don't work 2024-07-29 01:41:22 -06:00
jeffser
c0f8825f83 Logging to file / about dialog, youtube transcripts are downloaded on the right folder, fixed Ollama not running sometimes 2024-07-29 01:35:07 -06:00
jeffser
7c26956cd4 Autodetect version 2024-07-23 21:53:52 -06:00
jeffser
52f02cd5d0 Preparing for 1.0.1 2024-07-23 21:45:48 -06:00
jeffser
0df6b20147 Removed AMD stuff for now 2024-07-23 21:43:23 -06:00
jeffser
253a2dda7d Removed filesystem permissions 2024-07-23 20:30:52 -06:00
jeffser
d762a85130 ROCM fix (maybe) 2024-07-23 20:03:27 -06:00
jeffser
a765e8cf2e Better verification for instance connection 2024-07-23 19:20:27 -06:00
jeffser
3e7fd1140c Merge branch 'main' of github.com-jeffser:Jeffser/Alpaca 2024-07-23 19:16:55 -06:00
jeffser
a56631510d Fixed models with '-' in their names don't work 2024-07-23 19:16:40 -06:00
Jeffry Samuel
a042dfee50 Screenies labels fixed 2024-07-22 22:54:57 -06:00
jeffser
976fe138f7 New screenies 2024-07-22 22:51:33 -06:00
jeffser
88ff7c4dda Better progressbar 2024-07-22 22:26:39 -06:00
jeffser
f51d01b618 New models added! 2024-07-22 22:19:47 -06:00
jeffser
6122b732a3 Fixed logging bug 2024-07-22 22:03:44 -06:00
jeffser
818b88c94c Changed Ollama version to 0.2.8 2024-07-22 22:00:03 -06:00
jeffser
5ba1ba7823 Removed line I was using for testing 2024-07-22 21:52:29 -06:00
jeffser
dd1bf5118d It's comming! 2024-07-22 21:51:41 -06:00
jeffser
2462220e18 Merge branch 'main' of github.com-jeffser:Jeffser/Alpaca 2024-07-22 20:21:40 -06:00
jeffser
f40260608f Added credits to simplified chinese translator 2024-07-22 20:21:37 -06:00
aritra saha
a319b9572f some fix (#151)
* Update bn.po

* Update bn.po

* Update bn.po

* Update bn.po

* Update bn.po

* Update bn.po

* Update bn.po

* Update bn.po

* Update bn.po

* Update bn.po

* Update bn.po

* Update bn.po

* Update bn.po

* Update bn.po

* Update bn.po

---------

Co-authored-by: aritra saha <162728301+botollama@users.noreply.github.com>
Co-authored-by: Jeffry Samuel <69224322+Jeffser@users.noreply.github.com>
2024-07-22 17:41:25 -06:00
jeffser
8b704fba47 Translation updates 2024-07-21 18:28:44 -06:00
jeffser
69ecd7ff6e Updated languages 2024-07-21 18:18:46 -06:00
Yuehao Sui
423a258d27 Add Simplified Chinese localization (#150)
* Add Simplified Chinese localization

* Edit the header of zh_CN.po
2024-07-21 17:26:42 -06:00
jeffser
c7c1909fe7 Merge branch 'main' of github.com-jeffser:Jeffser/Alpaca 2024-07-21 17:19:14 -06:00
jeffser
0be53dba98 Fixed toast notification 2024-07-21 17:17:37 -06:00
aritra saha
01c9bf3d1c small fix (#146)
* Update bn.po

* Update bn.po

* Update bn.po

* Update bn.po

* Update bn.po

* Update bn.po

* Update bn.po

* Update bn.po

* Update bn.po

* Update bn.po

* Update bn.po

* Update bn.po

* Update bn.po

* Update bn.po

---------

Co-authored-by: aritra saha <162728301+botollama@users.noreply.github.com>
Co-authored-by: Jeffry Samuel <69224322+Jeffser@users.noreply.github.com>
2024-07-19 12:41:32 -06:00
aritra saha
619b404fd3 minor fixes (#143)
* Update bn.po

* Update bn.po

* Update bn.po

* Update bn.po

* Update bn.po

* Update bn.po

* Update bn.po

* Update bn.po

* Update bn.po

* Update bn.po

* Update bn.po

* Update bn.po

* Update bn.po

---------

Co-authored-by: aritra saha <162728301+botollama@users.noreply.github.com>
Co-authored-by: Jeffry Samuel <69224322+Jeffser@users.noreply.github.com>
2024-07-18 16:55:03 -06:00
jeffser
d73389d889 Better about dialog 2024-07-17 21:12:22 -06:00
jeffser
b8796f4e4f Added credit for Bengali translation 2024-07-17 21:00:29 -06:00
aritra saha
a5fa7d4692 some fixes and some rephrase (#140)
* Update bn.po

* Update bn.po

* Update bn.po

* Update bn.po

* Update bn.po

* Update bn.po

* Update bn.po

* Update bn.po

* Update bn.po

* Update bn.po

* Update bn.po

---------

Co-authored-by: aritra saha <162728301+botollama@users.noreply.github.com>
Co-authored-by: Jeffry Samuel <69224322+Jeffser@users.noreply.github.com>
2024-07-17 20:50:32 -06:00
imbev
92f1b62f8c Add logging (#142)
* Configure logger

* Add logging at various points

* Add logging to window verify_if_image_can_be_used
2024-07-17 20:49:55 -06:00
jeffser
c8ace20e60 Fixed messages not using standard datetime format 2024-07-10 21:32:49 -06:00
jeffser
f6920bf423 Fixed small bug 2024-07-10 21:15:11 -06:00
jeffser
09fee716f7 Better format for timestamps 2024-07-10 21:10:25 -06:00
jeffser
dc8a6ae1ec Hide 'Toggle Sidebar' button when window is wide enough 2024-07-10 20:49:59 -06:00
jeffser
173f08ba11 Fixed footer format 2024-07-10 16:21:44 -06:00
jeffser
2aa39e86d7 Better PDF extraction 2024-07-10 16:20:40 -06:00
jeffser
840a3030f7 New icon for manage models 2024-07-10 16:19:38 -06:00
jeffser
510fe83b6f Better format for date on footer of messages 2024-07-08 19:41:31 -06:00
jeffser
e7f04bbb1a Added error logging, removed debug messages 2024-07-08 16:55:04 -06:00
jeffser
efafdcc15e Merge branch 'main' of github.com-jeffser:Jeffser/Alpaca 2024-07-08 16:48:21 -06:00
jeffser
86c329982c Removed legacy chat updater (pre 0.9.4) 2024-07-08 16:48:14 -06:00
Jeffry Samuel
87b9fe6e62 Removed Ko_fi 2024-07-08 16:41:19 -06:00
jeffser
32d16a1e61 Better image rendering for previous messages 2024-07-08 16:31:39 -06:00
jeffser
e0e2b5c3c2 Added image previews before sending! + Fixed sintaxis in nb_NO and fr translations 2024-07-08 13:33:02 -06:00
jeffser
0d725d430b Merge branch 'main' of github.com-jeffser:Jeffser/Alpaca 2024-07-08 13:08:16 -06:00
jeffser
9ccf46663d Added file preview before sending message 2024-07-08 13:08:10 -06:00
jeffser
5420bcb92d Fixed welcome dialog 2024-07-08 11:41:20 -06:00
jeffser
8158026d96 Better welcome dialog 2024-07-08 11:37:16 -06:00
CounterFlow64
989c634907 Translated model descriptions to Norwegian (#133) 2024-07-08 10:39:11 -06:00
Louis Chauvet-Villaret
5397be92fe French update (#134) 2024-07-08 10:38:47 -06:00
aritra saha
9897eaf18a bengali translation (#136)
* Update bn.po

* Update bn.po

* Update bn.po

* Update bn.po

* Update bn.po

* Update bn.po

* Update bn.po

* Update bn.po

* Update bn.po

---------

Co-authored-by: Jeffry Samuel <69224322+Jeffser@users.noreply.github.com>
2024-07-08 10:38:07 -06:00
Alex K
5a7990ad3b Update Russian translation (#135)
* Add files via upload

* Add files via upload
2024-07-08 10:36:54 -06:00
jeffser
a516db63b3 Changed tmp directory 2024-07-07 21:53:38 -06:00
jeffser
a723deaa00 Fixed connection handler 2024-07-07 21:49:04 -06:00
jeffser
215f7251d1 Starting to implement logging 2024-07-07 21:35:41 -06:00
jeffser
86c81cf7f0 Better padding for disclaimer 2024-07-07 21:04:08 -06:00
jeffser
57e23ce272 Updated spanish 2024-07-07 20:51:49 -06:00
jeffser
0d375a8418 Updated languages again 2024-07-07 20:45:48 -06:00
jeffser
b0453d645c Updated languages 2024-07-07 20:43:15 -06:00
jeffser
6cd813c146 Simplified connection_handler 2024-07-07 20:41:25 -06:00
jeffser
35869c0fbf Better system for toast messages 2024-07-07 20:24:29 -06:00
jeffser
93893ff95a Finished Spanish translation 2024-07-07 20:04:49 -06:00
jeffser
815587e8b3 Fix spanish translation 2024-07-07 19:50:39 -06:00
jeffser
0e4b216df0 Better image recognition indicator 2024-07-07 19:42:23 -06:00
jeffser
2ab830367c Removed residual files 2024-07-07 18:29:44 -06:00
jeffser
57fbf397c3 Updated Spanish translation 2024-07-07 18:21:10 -06:00
jeffser
6c851784e2 Added model descriptions to localization process 2024-07-07 17:41:01 -06:00
jeffser
04c47554b7 Fixed nb_NO.po on update script 2024-07-07 17:30:50 -06:00
jeffser
e4879bd29e Fixed nb_NO 2024-07-07 17:01:03 -06:00
jeffser
783d0f6032 Fixed syntaxis errors on nb language file 2024-07-07 16:08:18 -06:00
jeffser
28be73b25b Changed no to nb 2024-07-07 15:56:29 -06:00
jeffser
c359b68635 Fixed bengali 2024-07-07 15:33:19 -06:00
jeffser
448d212621 Added new language files 2024-07-07 15:22:33 -06:00
jeffser
5c29ba4ae6 Added Bengali language template and fixed metadata for every language 2024-07-07 15:22:16 -06:00
Louis Chauvet-Villaret
1969672460 Pre-1.0 FR translation (#127) 2024-07-07 15:09:23 -06:00
jeffser
d81596b8e4 Added a disclaimer when downloading models, replaced the library icon for a download icon 2024-07-07 14:58:29 -06:00
jeffser
4dd67f9d71 Hide text cursor on previous messages (except when editing) 2024-07-05 13:22:25 -06:00
jeffser
f3550eebd3 Better message editing textview 2024-07-05 13:19:51 -06:00
jeffser
12bc3cfba7 Merge branch 'main' of github.com-jeffser:Jeffser/Alpaca 2024-07-04 19:47:16 -06:00
jeffser
489d5208af Added 'Tobias Bernard' to the credits 2024-07-04 19:47:09 -06:00
Jeffry Samuel
db749c9d00 Credits for Norwegian translation 2024-07-04 18:27:49 -06:00
Jeffry Samuel
57932a8013 Update README.md 2024-07-04 18:26:25 -06:00
jeffser
7bdbd875b8 Added credits for Norwegian translation 2024-07-04 18:25:00 -06:00
jeffser
7c4434d3d9 Merge branch 'main' of github.com-jeffser:Jeffser/Alpaca 2024-07-04 18:21:49 -06:00
jeffser
4665e9419b Better margins for message textview 2024-07-04 18:21:40 -06:00
CounterFlow64
6f004b3597 Complete Norwegian translation (#124)
* Complete Norwegian translation

* Update no_NO.po

Fixed spelling mistake for python-lxml
2024-07-04 12:51:34 -06:00
jeffser
e4c77698bb Visually replaced '-' for a space on everywhere a model title is shown 2024-07-04 11:56:45 -06:00
jeffser
83949e3698 Merged general / model settings into one page and changed the icons 2024-07-04 11:47:29 -06:00
jeffser
637ab030b2 Tweaked max auto title length 2024-07-04 11:43:54 -06:00
jeffser
3795de4ae9 removed unnecesary lines 2024-07-04 11:43:07 -06:00
jeffser
c75556346a Better chat notification 2024-07-04 11:42:35 -06:00
jeffser
91f203fc23 Removed unused files 2024-07-03 21:25:29 -06:00
jeffser
e2c7961a2a Autoscroll when message is received 2024-07-03 20:53:25 -06:00
jeffser
6531ee8e8e Removed test print lines 2024-07-03 20:47:29 -06:00
jeffser
66b35078b9 Even better chat title generator 2024-07-03 20:46:48 -06:00
jeffser
1a6287ba73 Fixed small bug 2024-07-03 20:43:35 -06:00
jeffser
4a11833206 New icon 2024-07-03 18:02:07 -06:00
jeffser
20b5722c17 Added 'missing image' indicator in chat 2024-07-03 18:01:51 -06:00
jeffser
ac8439fe6c Fixed auto scroll when receiving message and save last used chat 2024-07-03 17:43:56 -06:00
jeffser
e81d918675 Changed code so that Ollama closes gracefully 2024-07-03 17:12:31 -06:00
jeffser
cf4a17b6eb Better message entry 2024-07-03 13:13:48 -06:00
BurntSouls
ccc92bd541 Added dynamic height to text box (#112)
Co-authored-by: Jeffry Samuel <69224322+Jeffser@users.noreply.github.com>
2024-07-03 13:03:31 -06:00
jeffser
1598e1e60a Added no_NO.po 2024-07-03 11:49:51 -06:00
jeffser
9a77ea6f9c Updated languages, added no_NO.po 2024-07-03 11:49:30 -06:00
jeffser
c731e68e3f Added '?' to dialogs 2024-07-02 18:03:04 -06:00
jeffser
b66a3ab380 New 'image reconition' indicator for available models 2024-07-02 17:44:48 -06:00
jeffser
a296e38fa1 Tweaks to stop downloading dialog 2024-07-01 20:19:14 -06:00
jeffser
073754f1f3 Fixed title generation 2024-07-01 20:15:33 -06:00
jeffser
b60e01ee98 Changed Gemma to Gemma2 on featured models at welcome dialog 2024-06-30 23:54:00 -06:00
jeffser
0ae9e65f38 Changed how title generation works 2024-06-30 23:27:23 -06:00
jeffser
2ded3c72fd New big feature: Attach website (experimental) 2024-06-30 23:24:29 -06:00
jeffser
2c2a1ac2bc Verify if image can be used when pasting it 2024-06-30 22:12:46 -06:00
jeffser
ff8b20df98 Fixed: Can't preview files if chat is renamed 2024-06-30 22:10:02 -06:00
jeffser
18bd8f48be New feature: Keep most recent chat on top 2024-06-30 21:52:52 -06:00
jeffser
c98eac246d New icon 2024-06-30 20:51:37 -06:00
jeffser
7e4f1b25ee New feature: Edit messages! 2024-06-30 20:45:22 -06:00
jeffser
e735d45d09 Tweak to how attachments are displayed 2024-06-30 19:23:26 -06:00
jeffser
b45344b08e tweak to title generation 2024-06-30 19:15:52 -06:00
jeffser
43af2b2425 Small tweaks on how images arer shown 2024-06-30 19:14:30 -06:00
jeffser
151303d8b4 New feature, open sent images in default image viewer 2024-06-30 18:58:45 -06:00
jeffser
90bcf687cc Added 'no results' indicator 2024-06-30 18:31:10 -06:00
jeffser
992193e719 Better model search algorithm 2024-06-30 18:16:17 -06:00
jeffser
380ec93c6a Redesign for pulling model 2024-06-30 18:09:06 -06:00
jeffser
4994f6d177 New feature: Attach image straight from clipboard 2024-06-30 17:45:03 -06:00
jeffser
1da347ff2f Fix: first chat was not shown 2024-06-30 17:11:40 -06:00
jeffser
80fea3a3b5 Removed DOCX, I don't think it is going to work 2024-06-30 16:57:36 -06:00
jeffser
9967ea3249 Added chat message notification 2024-06-30 16:56:28 -06:00
jeffser
39b65d5576 Fixed a little bug in chat title generation + small UI tweak 2024-06-30 16:13:36 -06:00
jeffser
02e2448001 Restored support for DOCX 2024-06-30 16:04:29 -06:00
jeffser
4e64ce8f43 changed capitalize to title for chat title generation 2024-06-30 15:10:52 -06:00
jeffser
8ad1ec0a21 Much better chat title generation (includes image recognition) 2024-06-30 15:06:02 -06:00
jeffser
b6a180080f Fixed chat title generation and image recognition (+ added support for jpg) 2024-06-30 14:43:12 -06:00
jeffser
c6110e8cde Updated Ollama to 0.1.48 and added Gemma 2 2024-06-30 14:10:02 -06:00
jeffser
04fb59ef5c UI Tweaks (more :3) 2024-06-30 13:28:08 -06:00
Louis Chauvet-Villaret
dcc8ffb5b7 French update🥖🥖🥖 (#115) 2024-06-30 13:12:28 -06:00
jeffser
eae71dae16 Model searchbar (WIP) 2024-06-29 11:10:31 -06:00
jeffser
bf9042f9aa Fixed url label 2024-06-29 09:43:01 -06:00
jeffser
28eb62346c Even better UI (no way) 2024-06-28 21:56:15 -06:00
jeffser
527f7b4452 Added bearer token 2024-06-28 21:29:36 -06:00
jeffser
0fbde265ef UI Tweaks 2024-06-28 20:46:31 -06:00
jeffser
a532b018bc Visual tweaks 2024-06-28 18:51:08 -06:00
jeffser
073a63fb2d Added secondary_menu_button to the list of elements that become inactive when a message is being generated 2024-06-28 16:42:58 -06:00
jeffser
665f6eb872 ...and spaces 2024-06-28 16:36:04 -06:00
jeffser
9c0779a0c7 Chat title generation! (yes finally) 2024-06-28 16:30:47 -06:00
jeffser
107ef2c3d0 New chat order backend system / fixed secondary menu not working if context menu was cancelled 2024-06-28 15:39:26 -06:00
jeffser
6a825f534f UI Tweaks to manage models 2024-06-28 14:40:32 -06:00
jeffser
5bf77d6b97 Fixes to UI 2024-06-27 22:48:02 -06:00
jeffser
898c64ce35 Fixed message entry color 2024-06-27 21:53:04 -06:00
jeffser
efcc8512c1 tweaks 2024-06-26 17:14:23 -06:00
jeffser
52449243ed UI tweaks 2024-06-26 16:38:00 -06:00
jeffser
d457a1cfb8 Added new button to open file in default app 2024-06-26 16:03:44 -06:00
jeffser
4a9349769a Quick fix to youtube integration 2024-06-26 15:44:04 -06:00
jeffser
3dccba943e Fixed copy/delete message buttons 2024-06-26 15:35:59 -06:00
jeffser
bd146bdfb3 Better YouTube integration 2024-06-26 14:26:41 -06:00
jeffser
f150aa24ab New icon 2024-06-26 13:13:16 -06:00
jeffser
084b230383 New icon and quick capitalization fix 2024-06-26 13:11:19 -06:00
jeffser
69b550b70f Added back button to Manage Models Dialog 2024-06-26 13:07:23 -06:00
jeffser
191feb7299 Capitalized tooltip text 2024-06-26 00:38:09 -06:00
jeffser
f49b68f1a6 New manage models interface and new metadata for available models 2024-06-26 00:34:05 -06:00
jeffser
ade0b3735e New pull model menu 2024-06-25 23:32:09 -06:00
jeffser
ce3dce4c67 Added description to model list and change it to JSON file 2024-06-25 00:36:02 -06:00
jeffser
8bf8ca1b90 Tweaks 2024-06-24 23:13:17 -06:00
Tobias Bernard
22d52f76d1 app icon: new, more HIG-compliant alpaca (#114) 2024-06-24 22:26:38 -06:00
jeffser
ab720278cd Fixed, deleting chat doesn't change actual selected chat 2024-06-24 22:22:46 -06:00
jeffser
f9b3f91d3f Fixed chat context menu and added stuff to secondary menu 2024-06-24 22:08:05 -06:00
jeffser
dd20ff78c4 Fixed, can't fit long names on model switcher 2024-06-24 21:14:29 -06:00
jeffser
862d377ead Fixed capitalization 2024-06-24 00:44:15 -06:00
jeffser
219843d6d2 Changed footer for new bot messages 2024-06-24 00:23:32 -06:00
jeffser
01608696d6 Added YouTube integration (yeah) 2024-06-24 00:18:55 -06:00
jeffser
9d332a0d1d Removed leftover code 2024-06-23 21:47:54 -06:00
jeffser
6ba790416c } 2024-06-23 20:51:47 -06:00
jeffser
262988d4c8 Removed references to style-dark.css 2024-06-23 20:27:17 -06:00
jeffser
b8c420526c Added shortcut to import chat, moved option to primary menu and moved primary menu to sidebar 2024-06-23 20:17:45 -06:00
jeffser
39691cc83c Moved chat options to conext menu (right click) 2024-06-23 20:07:27 -06:00
jeffser
2dae041efa Added tooltips and small tweaks to message entry 2024-06-23 18:00:54 -06:00
jeffser
c0a0ca7f39 Tweaked how model names are displayed on selector 2024-06-23 17:34:41 -06:00
76 changed files with 62874 additions and 7937 deletions

2
.github/FUNDING.yml vendored
View File

@@ -1,7 +1,7 @@
# These are supported funding model platforms
github: jeffser # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
ko_fi: jeffser
#ko_fi: jeffser
#patreon: # Replace with a single Patreon username
#open_collective: # Replace with a single Open Collective username
#ko_fi: # Replace with a single Ko-fi username

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.
@@ -16,5 +16,7 @@ A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Additional context**
Add any other context about the problem here.
**Debugging information**
```
Please paste here the debugging information available at 'About Alpaca' > 'Troubleshooting' > 'Debugging Information'
```

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
@@ -20,50 +24,62 @@ Alpaca is an [Ollama](https://github.com/ollama/ollama) client where you can man
- Multiple conversations
- Notifications
- Import / Export chats
- Delete messages
## Future features!
- Delete / Edit messages
- Regenerate messages
- YouTube recognition (Ask questions about a YouTube video using the transcript)
- Edit messages
- Snap Package (maybe)
- Website recognition (Ask questions about a certain website by parsing the url)
## Screenies
Code highlighting | Chatting with models | Managing models
:-------------------------:|:-------------------------:|:-------------------------:
![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
## Installation
## Ollama session tips
### Flathub
### 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`.
You can find the latest stable version of the app on [Flathub](https://flathub.org/apps/com.jeffser.Alpaca)
### 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.
### Flatpak Package
### 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.
Everytime a new version is published they become available on the [releases page](https://github.com/Jeffser/Alpaca/releases) of the repository
### 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.
### Building Git Version
Note: This is not recommended since the prerelease versions of the app often present errors and general instability.
1. Clone the project
2. Open with Gnome Builder
3. Press the run button (or export if you want to build a Flatpak package)
## Translators
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)
🇹🇷 Turkish | [YusaBecerikli](https://github.com/YusaBecerikli)
🇺🇦 Ukrainian | [Simon](https://github.com/OriginalSimon)
🇩🇪 German | [Marcel Margenberg](https://github.com/MehrzweckMandala)
Want to add a language? Visit [this discussion](https://github.com/Jeffser/Alpaca/discussions/153) to get started!
---
## 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
## 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)
- [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
- [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!

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

@@ -9,8 +9,20 @@
"--share=ipc",
"--socket=fallback-x11",
"--device=dri",
"--socket=wayland"
"--socket=wayland",
"--filesystem=/sys/module/amdgpu:ro",
"--env=LD_LIBRARY_PATH=/app/lib:/usr/lib/x86_64-linux-gnu/GL/default/lib:/usr/lib/x86_64-linux-gnu/openh264/extra:/usr/lib/x86_64-linux-gnu/openh264/extra:/usr/lib/sdk/llvm15/lib:/usr/lib/x86_64-linux-gnu/GL/default/lib:/usr/lib/ollama:/app/plugins/AMD/lib/ollama"
],
"add-extensions": {
"com.jeffser.Alpaca.Plugins": {
"version": "1.0",
"add-ld-path": "/app/plugins/AMD/lib/ollama",
"directory": "plugins",
"no-autodownload": true,
"autodelete": true,
"subdirectories": true
}
},
"cleanup" : [
"/include",
"/lib/pkgconfig",
@@ -85,25 +97,54 @@
}
]
},
{
"name": "python3-pytube",
"buildsystem": "simple",
"build-commands": [
"pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} \"pytube\" --no-build-isolation"
],
"sources": [
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/51/64/bcf8632ed2b7a36bbf84a0544885ffa1d0b4bcf25cc0903dba66ec5fdad9/pytube-15.0.0-py3-none-any.whl",
"sha256": "07b9904749e213485780d7eb606e5e5b8e4341aa4dccf699160876da00e12d78"
}
]
},
{
"name": "python3-html2text",
"buildsystem": "simple",
"build-commands": [
"pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} \"html2text\" --no-build-isolation"
],
"sources": [
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/1a/43/e1d53588561e533212117750ee79ad0ba02a41f52a08c1df3396bd466c05/html2text-2024.2.26.tar.gz",
"sha256": "05f8e367d15aaabc96415376776cdd11afd5127a77fce6e36afc60c563ca2c32"
}
]
},
{
"name": "ollama",
"buildsystem": "simple",
"build-commands": [
"install -Dm0755 ollama* ${FLATPAK_DEST}/bin/ollama"
"cp -r --remove-destination * ${FLATPAK_DEST}/",
"mkdir ${FLATPAK_DEST}/plugins"
],
"sources": [
{
"type": "file",
"url": "https://github.com/ollama/ollama/releases/download/v0.1.39/ollama-linux-amd64",
"sha256": "4d19be355842a6297c93ab5ada139fe396126736bf3c3882a879dc245dffe3af",
"type": "archive",
"url": "https://github.com/ollama/ollama/releases/download/v0.3.9/ollama-linux-amd64.tgz",
"sha256": "b0062fbccd46134818d9d59cfa3867ad6849163653cb1171bc852c5f379b0851",
"only-arches": [
"x86_64"
]
},
{
"type": "file",
"url": "https://github.com/ollama/ollama/releases/download/v0.1.39/ollama-linux-arm64",
"sha256": "60ec2d36928c11d6c6d84fe91451308a46aafaedbdba44664e5a6080009ce097",
"type": "archive",
"url": "https://github.com/ollama/ollama/releases/download/v0.3.9/ollama-linux-arm64.tgz",
"sha256": "8979484bcb1448ab9b45107fbcb3b9f43c2af46f961487449b9ebf3518cd70eb",
"only-arches": [
"aarch64"
]
@@ -117,7 +158,7 @@
"sources" : [
{
"type" : "git",
"url" : "file:///home/tentri/Documents/Alpaca",
"url": "https://github.com/Jeffser/Alpaca.git",
"branch" : "main"
}
]

View File

@@ -1,6 +0,0 @@
[Shell Search Provider]
DesktopId=@appid@.desktop
BusName=@appid@.SearchProvider
ObjectPath=/com/jeffser/Alpaca/SearchProvider
Version=2

View File

@@ -1,3 +0,0 @@
[D-BUS Service]
Name=@appid@.SearchProvider
Exec=@libexecdir@/alpaca_search_provider

View File

@@ -5,5 +5,6 @@ Icon=com.jeffser.Alpaca
Terminal=false
Type=Application
Categories=Utility;Development;Chat;
Keywords=ai;ollama;llm
StartupNotify=true
X-Purism-FormFactor=Workstation;Mobile;
X-Purism-FormFactor=Workstation;Mobile;

View File

@@ -17,6 +17,9 @@
<li>Image recognition (Only available with compatible models)</li>
<li>Plain text documents recognition</li>
<li>Import and export chats</li>
<li>Append YouTube transcripts to the prompt</li>
<li>Append text from a website to the prompt</li>
<li>PDF recognition</li>
</ul>
<p>Disclaimer</p>
<p>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 models.</p>
@@ -48,22 +51,274 @@
<screenshots>
<screenshot type="default">
<image>https://jeffser.com/images/alpaca/screenie1.png</image>
<caption>A conversation showing code highlight</caption>
<caption>A normal conversation with an AI Model</caption>
</screenshot>
<screenshot>
<image>https://jeffser.com/images/alpaca/screenie2.png</image>
<caption>A conversation involving multiple models</caption>
<caption>A conversation involving image recognition</caption>
</screenshot>
<screenshot>
<image>https://jeffser.com/images/alpaca/screenie3.png</image>
<caption>Managing models</caption>
<caption>A conversation showing code highlighting</caption>
</screenshot>
<screenshot>
<image>https://jeffser.com/images/alpaca/screenie4.png</image>
<caption>A conversation involving a YouTube video transcript</caption>
</screenshot>
<screenshot>
<image>https://jeffser.com/images/alpaca/screenie5.png</image>
<caption>Multiple models being downloaded</caption>
</screenshot>
</screenshots>
<content_rating type="oars-1.1" />
<url type="bugtracker">https://github.com/Jeffser/Alpaca/issues</url>
<url type="homepage">https://github.com/Jeffser/Alpaca</url>
<url type="homepage">https://jeffser.com/alpaca/</url>
<url type="donation">https://github.com/sponsors/Jeffser</url>
<url type="translate">https://github.com/Jeffser/Alpaca/discussions/153</url>
<url type="contribute">https://github.com/Jeffser/Alpaca/discussions/154</url>
<url type="vcs-browser">https://github.com/Jeffser/Alpaca</url>
<releases>
<release version="2.0.0" date="2024-09-01">
<url type="details">https://github.com/Jeffser/Alpaca/releases/tag/2.0.0</url>
<description>
<p>New</p>
<ul>
<li>Model, message and chat systems have been rewritten</li>
<li>New models are available</li>
<li>Ollama updated to v0.3.9</li>
<li>Added support for multiple chat generations simultaneously</li>
<li>Added experimental AMD GPU support</li>
<li>Added message loading spinner and new message indicator to chat tab</li>
<li>Added animations</li>
<li>Changed model manager / model selector appearance</li>
<li>Changed message appearance</li>
<li>Added markdown and code blocks to user messages</li>
<li>Added loading dialog at launch so the app opens faster</li>
<li>Added warning when device is on 'battery saver' mode</li>
<li>Added inactivity timer to integrated instance</li>
</ul>
<ul>
<li>The chat is now scrolled to the bottom when it's changed</li>
<li>Better handling of focus on messages</li>
<li>Better general performance on the app</li>
</ul>
</description>
</release>
<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>
<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">
<url type="details">https://github.com/Jeffser/Alpaca/releases/tag/1.0.3</url>
<description>
<p>New</p>
<ul>
<li>Bearer Token entry on connection error dialog</li>
<li>Small appearance changes</li>
<li>Compatibility with code blocks without explicit language</li>
<li>Rare, optional and dismissible support dialog</li>
</ul>
<p>Fixes</p>
<ul>
<li>Date format for Simplified Chinese translation</li>
<li>Bug with unsupported localizations</li>
<li>Min height being too large to be used on mobile</li>
<li>Remote connection checker bug</li>
</ul>
</description>
</release>
<release version="1.0.2" date="2024-07-29">
<url type="details">https://github.com/Jeffser/Alpaca/releases/tag/1.0.2</url>
<description>
<p>Fixes</p>
<ul>
<li>Models with capital letters on their tag don't work</li>
<li>Ollama fails to launch on some systems</li>
<li>YouTube transcripts are not being saved in the right TMP directory</li>
</ul>
<p>New</p>
<ul>
<li>Debug messages are now shown on the 'About Alpaca' dialog</li>
<li>Updated Ollama to v0.3.0 (new models)</li>
</ul>
</description>
</release>
<release version="1.0.1" date="2024-07-23">
<url type="details">https://github.com/Jeffser/Alpaca/releases/tag/1.0.1</url>
<description>
<p>Fixes</p>
<ul>
<li>Models with '-' in their names didn't work properly, this is now fixed</li>
<li>Better connection check for Ollama</li>
</ul>
</description>
</release>
<release version="1.0.0" date="2024-07-22">
<url type="details">https://github.com/Jeffser/Alpaca/releases/tag/1.0.0</url>
<description>
<p>Stable Release</p>
<p>The new icon was made by Tobias Bernard over the Gnome Gitlab, thanks for the great icon!</p>
<p>Features and fixes</p>
<ul>
<li>Updated Ollama instance to 0.2.8</li>
<li>Better model selector</li>
<li>Model manager redesign</li>
<li>Better tag selector when pulling a model</li>
<li>Model search</li>
<li>Added support for bearer tokens on remote instances</li>
<li>Preferences dialog redesign</li>
<li>Added context menus to interact with a chat</li>
<li>Redesigned primary and secondary menus</li>
<li>YouTube integration: Paste the URL of a video with a transcript and it will be added to the prompt</li>
<li>Website integration (Experimental): Extract the text from the body of a website by adding it's URL to the prompt</li>
<li>Chat title generation</li>
<li>Auto resizing of message entry</li>
<li>Chat notifications</li>
<li>Added indicator when an image is missing</li>
<li>Auto rearrange the order of chats when a message is received</li>
<li>Redesigned file preview dialog</li>
<li>Credited new contributors</li>
<li>Better stability and optimization</li>
<li>Edit messages to change the context of a conversation</li>
<li>Added disclaimers when pulling models</li>
<li>Preview files before sending a message</li>
<li>Better format for date and time on messages</li>
<li>Error and debug logging on terminal</li>
<li>Auto-hiding sidebar button</li>
<li>Various UI tweaks</li>
</ul>
<p>New Models</p>
<ul>
<li>Gemma2</li>
<li>GLM4</li>
<li>Codegeex4</li>
<li>InternLM2</li>
<li>Llama3-groq-tool-use</li>
<li>Mathstral</li>
<li>Mistral-nemo</li>
<li>Firefunction-v2</li>
<li>Nuextract</li>
</ul>
<p>Translations</p>
<p>These are all the available translations on 1.0.0, thanks to all the contributors!</p>
<ul>
<li>Russian: Alex K</li>
<li>Spanish: Jeffser</li>
<li>Brazilian Portuguese: Daimar Stein</li>
<li>French: Louis Chauvet-Villaret</li>
<li>Norwegian: CounterFlow64</li>
<li>Bengali: Aritra Saha</li>
<li>Simplified Chinese: Yuehao Sui</li>
</ul>
</description>
</release>
<release version="0.9.6.1" date="2024-06-22">
<url type="details">https://github.com/Jeffser/Alpaca/releases/tag/0.9.6.1</url>
<description>

View File

@@ -0,0 +1,677 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
inkscape:export-ydpi="96"
inkscape:export-xdpi="96"
inkscape:export-filename="Template.png"
width="192"
height="152"
id="svg11300"
sodipodi:version="0.32"
inkscape:version="1.3.2 (091e20ef0f, 2023-11-25)"
sodipodi:docname="com.jeffser.Alpaca.Source.svg"
inkscape:output_extension="org.inkscape.output.svg.inkscape"
version="1.0"
style="display:inline;enable-background:new"
viewBox="0 0 192 152"
xml:space="preserve"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/"><title
id="title4162">Adwaita Icon Template</title><defs
id="defs3"><linearGradient
id="linearGradient74"
inkscape:collect="always"><stop
style="stop-color:#b6d1f2;stop-opacity:1"
offset="0"
id="stop73" /><stop
style="stop-color:#e9eef4;stop-opacity:1"
offset="1"
id="stop74" /></linearGradient><inkscape:path-effect
effect="fillet_chamfer"
id="path-effect10"
is_visible="true"
lpeversion="1"
nodesatellites_param="F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,1.0001776,0,1 @ F,0,0,1,0,1.9999911,0,1 @ F,0,1,1,0,0,0,1"
radius="4"
unit="px"
method="auto"
mode="F"
chamfer_steps="1"
flexible="false"
use_knot_distance="true"
apply_no_radius="true"
apply_with_radius="true"
only_selected="false"
hide_knots="false" /><inkscape:path-effect
effect="fillet_chamfer"
id="path-effect203"
is_visible="true"
lpeversion="1"
nodesatellites_param="F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,1.0001776,0,1 @ F,0,0,1,0,1.9999911,0,1 @ F,0,1,1,0,0,0,1"
radius="4"
unit="px"
method="auto"
mode="F"
chamfer_steps="1"
flexible="false"
use_knot_distance="true"
apply_no_radius="true"
apply_with_radius="true"
only_selected="false"
hide_knots="false" /><linearGradient
inkscape:collect="always"
xlink:href="#linearGradient74"
id="linearGradient243"
gradientUnits="userSpaceOnUse"
x1="48"
y1="260"
x2="48"
y2="220" /></defs><sodipodi:namedview
stroke="#ef2929"
fill="#f57900"
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="0.25490196"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="2.3650602"
inkscape:cx="28.5405"
inkscape:cy="77.376467"
inkscape:current-layer="layer9"
showgrid="false"
inkscape:grid-bbox="true"
inkscape:document-units="px"
inkscape:showpageshadow="false"
inkscape:window-width="1920"
inkscape:window-height="1011"
inkscape:window-x="0"
inkscape:window-y="0"
width="400px"
height="300px"
inkscape:snap-nodes="true"
inkscape:snap-bbox="true"
objecttolerance="7"
gridtolerance="12"
guidetolerance="13"
inkscape:window-maximized="1"
inkscape:pagecheckerboard="false"
showguides="false"
inkscape:guide-bbox="true"
inkscape:locked="false"
inkscape:measure-start="0,0"
inkscape:measure-end="0,0"
inkscape:object-nodes="true"
inkscape:bbox-nodes="true"
inkscape:snap-global="true"
inkscape:object-paths="true"
inkscape:snap-intersection-paths="true"
inkscape:snap-bbox-edge-midpoints="true"
inkscape:snap-bbox-midpoints="true"
showborder="true"
inkscape:snap-center="true"
inkscape:snap-object-midpoints="true"
inkscape:snap-midpoints="true"
inkscape:snap-smooth-nodes="true"
inkscape:snap-text-baseline="true"
borderlayer="true"
inkscape:deskcolor="#d1d1d1"><inkscape:grid
type="xygrid"
id="grid5883"
spacingx="2"
spacingy="2"
enabled="true"
visible="false"
empspacing="4"
originx="8"
originy="8"
units="px" /><sodipodi:guide
position="72,16"
orientation="0,1"
id="guide1073"
inkscape:locked="false"
inkscape:label=""
inkscape:color="rgb(0,0,255)" /><sodipodi:guide
position="20,72"
orientation="1,0"
id="guide1075"
inkscape:locked="false"
inkscape:label=""
inkscape:color="rgb(0,0,255)" /><sodipodi:guide
position="72,112"
orientation="0,1"
id="guide1099"
inkscape:locked="false"
inkscape:label=""
inkscape:color="rgb(0,0,255)" /><sodipodi:guide
position="72,136"
orientation="0,1"
id="guide993"
inkscape:locked="false"
inkscape:label=""
inkscape:color="rgb(0,0,255)" /><sodipodi:guide
position="112,72"
orientation="1,0"
id="guide995"
inkscape:locked="false"
inkscape:label=""
inkscape:color="rgb(0,0,255)" /><sodipodi:guide
position="8.0000001,72"
orientation="1,0"
id="guide867"
inkscape:locked="false"
inkscape:label=""
inkscape:color="rgb(0,0,255)" /><sodipodi:guide
position="128,72"
orientation="1,0"
id="guide869"
inkscape:locked="false"
inkscape:label=""
inkscape:color="rgb(0,0,255)" /><sodipodi:guide
position="72,124"
orientation="0,1"
id="guide871"
inkscape:locked="false"
inkscape:label=""
inkscape:color="rgb(0,0,255)" /><inkscape:grid
type="xygrid"
id="grid873"
spacingx="1"
spacingy="1"
empspacing="8"
color="#000000"
opacity="0.49019608"
empcolor="#000000"
empopacity="0.08627451"
dotted="true"
originx="8"
originy="8"
units="px"
visible="false" /><sodipodi:guide
position="32,72"
orientation="1,0"
id="guide877"
inkscape:locked="false"
inkscape:label=""
inkscape:color="rgb(0,0,255)" /><sodipodi:guide
position="124,72"
orientation="1,0"
id="guide879"
inkscape:locked="false"
inkscape:label=""
inkscape:color="rgb(0,0,255)" /><sodipodi:guide
position="72,128"
orientation="0,1"
id="guide881"
inkscape:locked="false"
inkscape:label=""
inkscape:color="rgb(0,0,255)" /><sodipodi:guide
position="72,20"
orientation="0,1"
id="guide883"
inkscape:locked="false"
inkscape:label=""
inkscape:color="rgb(0,0,255)" /><sodipodi:guide
position="16,72"
orientation="1,0"
id="guide885"
inkscape:locked="false"
inkscape:label=""
inkscape:color="rgb(0,0,255)" /><sodipodi:guide
position="136,72"
orientation="1,0"
id="guide887"
inkscape:locked="false"
inkscape:label=""
inkscape:color="rgb(0,0,255)" /><sodipodi:guide
position="72,8"
orientation="0,1"
id="guide897"
inkscape:locked="false"
inkscape:label=""
inkscape:color="rgb(0,0,255)" /><sodipodi:guide
position="72,32"
orientation="0,1"
id="guide899"
inkscape:locked="false"
inkscape:label=""
inkscape:color="rgb(0,0,255)" /><sodipodi:guide
position="264,264"
orientation="-0.70710678,0.70710678"
id="guide950"
inkscape:locked="false"
inkscape:label=""
inkscape:color="rgb(0,0,255)" /><sodipodi:guide
position="72,72"
orientation="0.70710678,0.70710678"
id="guide952"
inkscape:locked="false"
inkscape:label=""
inkscape:color="rgb(0,0,255)" /></sodipodi:namedview><metadata
id="metadata4"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:creator><cc:Agent><dc:title>GNOME Design Team</dc:title></cc:Agent></dc:creator><dc:source /><cc:license
rdf:resource="http://creativecommons.org/licenses/by-sa/4.0/" /><dc:title>Adwaita Icon Template</dc:title><dc:subject><rdf:Bag /></dc:subject><dc:date /><dc:rights><cc:Agent><dc:title /></cc:Agent></dc:rights><dc:publisher><cc:Agent><dc:title /></cc:Agent></dc:publisher><dc:identifier /><dc:relation /><dc:language /><dc:coverage /><dc:description /><dc:contributor><cc:Agent><dc:title /></cc:Agent></dc:contributor></cc:Work><cc:License
rdf:about="http://creativecommons.org/licenses/by-sa/4.0/"><cc:permits
rdf:resource="http://creativecommons.org/ns#Reproduction" /><cc:permits
rdf:resource="http://creativecommons.org/ns#Distribution" /><cc:requires
rdf:resource="http://creativecommons.org/ns#Notice" /><cc:requires
rdf:resource="http://creativecommons.org/ns#Attribution" /><cc:permits
rdf:resource="http://creativecommons.org/ns#DerivativeWorks" /><cc:requires
rdf:resource="http://creativecommons.org/ns#ShareAlike" /></cc:License></rdf:RDF></metadata><g
id="layer1"
inkscape:label="App Icon"
inkscape:groupmode="layer"
style="display:inline"
transform="translate(8,-156)"><g
inkscape:groupmode="layer"
id="layer4"
inkscape:label="template"
style="display:inline"
sodipodi:insensitive="true"><rect
inkscape:label="0"
y="172"
x="9.2651362e-08"
height="128"
width="128"
id="hicolor"
style="display:inline;overflow:visible;visibility:visible;fill:#f0f0f0;fill-opacity:0;fill-rule:nonzero;stroke:none;stroke-width:0.5;marker:none;enable-background:accumulate" /><rect
style="display:inline;overflow:visible;visibility:visible;fill:#f0f0f0;fill-opacity:0;fill-rule:nonzero;stroke:none;stroke-width:0.5;marker:none;enable-background:accumulate"
id="symbolic"
width="16"
height="16"
x="160"
y="172"
inkscape:label="0" /></g><g
inkscape:groupmode="layer"
id="layer2"
inkscape:label="baseplate"
style="display:none"
sodipodi:insensitive="true"><g
style="display:inline;fill:#000000;enable-background:new"
transform="matrix(7.9911709,0,0,8.0036407,-167.7909,-4846.0776)"
id="g12027"
inkscape:export-xdpi="12"
inkscape:export-ydpi="12" /><rect
style="display:inline;overflow:visible;visibility:visible;fill:#f0f0f0;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.5;marker:none;enable-background:accumulate"
id="128"
width="128"
height="128"
x="9.2651362e-08"
y="172"
inkscape:label="0" /><g
id="g883"
style="fill:none;fill-opacity:0.25098;stroke:#a579b3;stroke-opacity:1"
transform="translate(-24,24)" /><g
id="g900"
style="fill:none;fill-opacity:0.25098;stroke:#a579b3;stroke-opacity:1"
transform="translate(-24,24)" /><rect
inkscape:label=""
y="172"
x="160"
height="16"
width="16"
id="16"
style="display:inline;overflow:visible;visibility:visible;fill:#f0f0f0;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.5;marker:none;enable-background:accumulate" /><text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:4px;line-height:125%;font-family:Cantarell;-inkscape-font-specification:'Cantarell, Bold';text-align:start;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.332649;enable-background:new"
x="0"
y="167"
id="text863"
inkscape:label="icon-name"><tspan
style="font-size:4px;stroke-width:0.332649"
sodipodi:role="line"
id="tspan861"
x="0"
y="167">Hicolor</tspan></text><text
inkscape:label="icon-name"
id="text867"
y="167"
x="160"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:4px;line-height:125%;font-family:Cantarell;-inkscape-font-specification:'Cantarell, Bold';text-align:start;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.332649;enable-background:new"
xml:space="preserve"><tspan
y="167"
x="160"
id="tspan865"
sodipodi:role="line"
style="font-size:4px;stroke-width:0.332649">Symbolic</tspan></text></g><g
inkscape:groupmode="layer"
id="layer9"
inkscape:label="icons"
style="display:inline"><path
sodipodi:type="star"
style="display:none;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.377953;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
id="path7608"
inkscape:flatsided="true"
sodipodi:sides="6"
sodipodi:cx="88"
sodipodi:cy="80"
sodipodi:r1="24"
sodipodi:r2="22.173109"
sodipodi:arg1="-1.5707963"
sodipodi:arg2="-1.0471975"
inkscape:rounded="-3.469447e-18"
inkscape:randomized="0"
d="m 88.000001,56 20.784609,12.000001 0,24 L 87.999999,104 67.21539,91.999999 l 10e-7,-24 z"
transform="matrix(1.0672586,0,0,1.0932338,-15.01003,148.2195)" /><g
id="g157"
transform="matrix(0.37500254,0,0,0.37500254,131.62469,107.4995)"
style="display:inline;fill:#241f31;enable-background:new" /><g
id="g158"
transform="translate(-70)" /><g
id="g162"
style="display:inline;fill:#241f31;fill-opacity:1;stroke:#241f31;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;enable-background:new"
transform="matrix(0.37500254,0,0,0.37500254,121.49966,106.7495)" /><path
style="color:#000000;fill:#241f31;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.1;-inkscape-stroke:none"
d="m 172.5,175 a 1,1 0 0 0 -1,1 1,1 0 0 0 1,1 c 0.28799,0 0.5,0.21201 0.5,0.5 a 1,1 0 0 0 1,1 1,1 0 0 0 1,-1 c 0,-1.36887 -1.13113,-2.5 -2.5,-2.5 z"
id="path178" /><path
style="color:#000000;fill:#241f31;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.1;-inkscape-stroke:none"
d="m 162,175 a 1,1 0 0 0 -1,1 v 11 a 1,1 0 0 0 1,1 1,1 0 0 0 1,-1 v -11 a 1,1 0 0 0 -1,-1 z m 10,6 a 1,1 0 0 0 -1,1 v 5 a 1,1 0 0 0 1,1 1,1 0 0 0 1,-1 v -5 a 1,1 0 0 0 -1,-1 z"
id="path164" /><path
style="color:#000000;fill:#241f31;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.1;-inkscape-stroke:none"
d="m 165,172 c -2.19729,0 -4,1.80271 -4,4 a 1,1 0 0 0 1,1 1,1 0 0 0 1,-1 c 0,-0.72279 0.43588,-1.23883 1,-1.58984 V 176 a 1,1 0 0 0 1,1 1,1 0 0 0 1,-1 v -3 a 1.0001,1.0001 0 0 0 -1,-1 z"
id="path19-0" /><path
style="color:#000000;fill:#241f31;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.1;-inkscape-stroke:none"
d="m 170,172 c -2.19729,0 -4,1.80271 -4,4 a 1,1 0 0 0 1,1 1,1 0 0 0 1,-1 c 0,-0.72279 0.43588,-1.23883 1,-1.58984 V 176 a 1,1 0 0 0 1,1 1,1 0 0 0 1,-1 v -3 a 1.0001,1.0001 0 0 0 -1,-1 z"
id="path166" /><path
style="color:#000000;fill:#241f31;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.1;-inkscape-stroke:none"
d="m 165,175 a 1,1 0 0 0 -1,1 1,1 0 0 0 1,1 h 2 a 1,1 0 0 0 1,-1 1,1 0 0 0 -1,-1 z"
id="path167" /><path
style="color:#000000;fill:#241f31;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.1;-inkscape-stroke:none"
d="M 170.00586,175 A 1,1 0 0 0 169,175.99414 1,1 0 0 0 169.99414,177 l 2.52539,0.0156 a 1,1 0 0 0 1.00586,-0.99414 1,1 0 0 0 -0.99414,-1.00586 z"
id="path168" /><path
style="color:#000000;fill:#241f31;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.1;-inkscape-stroke:none"
d="m 174.01953,176.47461 a 1,1 0 0 0 -1.00391,0.99609 L 173,180.99609 A 1,1 0 0 0 173.99609,182 1,1 0 0 0 175,181.00391 l 0.0156,-3.52539 a 1,1 0 0 0 -0.99609,-1.00391 z"
id="path179" /><path
id="path192"
style="display:inline;fill:#241f31;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.1;stroke-dasharray:none;stroke-opacity:1;enable-background:new"
d="m 176,180 v 2 c -3.53529,0.2145 -4.23624,2.44366 -5.64991,3.08535 -0.49735,0.22576 -1.42294,0.16467 -1.97533,0.16465 l -0.37477,-1e-5 A 2.0000622,2.0000622 45.001019 0 1 166,183.24993 V 180"
sodipodi:nodetypes="ccccc"
inkscape:path-effect="#path-effect203"
inkscape:original-d="m 176,180 v 2 c -4.25068,0.2579 -4.40387,3.42834 -6.62506,3.25004 L 166,185.24992 V 180" /><g
id="g10"
transform="translate(50)"><g
id="g2"
transform="translate(-1,2)"><path
style="fill:none;fill-opacity:1;stroke:#241f31;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.1;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="path2"
sodipodi:type="arc"
sodipodi:cx="173.5"
sodipodi:cy="175.5"
sodipodi:rx="1.4999994"
sodipodi:ry="1.4999994"
sodipodi:start="4.712389"
sodipodi:end="0"
sodipodi:open="true"
sodipodi:arc-type="arc"
d="m 173.5,174 a 1.4999994,1.4999994 0 0 1 1.5,1.5" /></g><path
style="opacity:1;fill:none;fill-opacity:1;stroke:#241f31;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.1;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
d="m 162,176 v 11 m 10,0 v -5"
id="path3"
sodipodi:nodetypes="cccc" /><path
id="path4"
style="display:inline;fill:none;stroke:#241f31;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.1;enable-background:new"
d="m 162,176 c 0,-1.65685 1.34315,-3 3,-3 v 3"
sodipodi:nodetypes="ccc" /><path
id="path5"
style="display:inline;fill:none;stroke:#241f31;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.1;enable-background:new"
d="m 167,176 c 0,-1.65685 1.34315,-3 3,-3 v 3"
sodipodi:nodetypes="ccc" /><path
style="opacity:1;fill:none;fill-opacity:1;stroke:#241f31;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.1;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
d="m 165,176 h 2"
id="path6"
sodipodi:nodetypes="cc" /><path
style="opacity:1;fill:none;fill-opacity:1;stroke:#241f31;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.1;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
d="m 170,176 2.52556,0.0158"
id="path7"
sodipodi:nodetypes="cc" /><path
style="opacity:1;fill:none;fill-opacity:1;stroke:#241f31;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.1;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
d="M 174.0158,177.47444 174,181"
id="path8"
sodipodi:nodetypes="cc" /><path
id="path9"
style="display:inline;fill:#241f31;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.1;stroke-dasharray:none;stroke-opacity:1;enable-background:new"
d="m 176,180 v 2 c -3.53529,0.2145 -4.23624,2.44366 -5.64991,3.08535 -0.49735,0.22576 -1.42294,0.16467 -1.97533,0.16465 l -0.37477,-1e-5 A 2.0000622,2.0000622 45.001019 0 1 166,183.24993 V 180"
sodipodi:nodetypes="ccccc"
inkscape:path-effect="#path-effect10"
inkscape:original-d="m 176,180 v 2 c -4.25068,0.2579 -4.40387,3.42834 -6.62506,3.25004 L 166,185.24992 V 180" /></g><g
id="g243"><g
id="g224"
style="fill:#99c1f1;fill-opacity:1"><g
id="g223"
style="fill:#99c1f1;fill-opacity:1"><rect
style="opacity:1;fill:#99c1f1;fill-opacity:1;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.1;stroke-dasharray:4, 12"
id="rect222"
width="24"
height="12"
x="2.000001"
y="238" /><rect
style="opacity:1;fill:#99c1f1;fill-opacity:1;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.1;stroke-dasharray:4, 12"
id="rect223"
width="24"
height="22"
x="2.000001"
y="228"
rx="10.323593"
ry="10.323593" /></g></g><rect
style="opacity:1;fill:#5e5c64;fill-opacity:1;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.1;stroke-dasharray:4, 12"
id="rect224"
width="8.0000019"
height="23"
x="82"
y="273" /><rect
style="opacity:1;fill:#5e5c64;fill-opacity:1;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.1;stroke-dasharray:4, 12"
id="rect225"
width="8.0000019"
height="23"
x="100"
y="273" /><rect
style="opacity:1;fill:#5e5c64;fill-opacity:1;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.1;stroke-dasharray:4, 12"
id="rect226"
width="7.9999981"
height="23"
x="20.000002"
y="273" /><rect
style="opacity:1;fill:#5e5c64;fill-opacity:1;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.1;stroke-dasharray:4, 12"
id="rect227"
width="7.999999"
height="23"
x="38"
y="273" /><g
id="g229"
style="fill:#1c71d8"><rect
style="display:inline;fill:#6b9bd2;fill-opacity:1;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.1;stroke-dasharray:4, 12;enable-background:new"
id="rect228"
width="24"
height="38"
x="30"
y="252"
rx="10.323593"
ry="10.323593" /><rect
style="display:inline;fill:#6b9bd2;fill-opacity:1;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.1;stroke-dasharray:4, 12;enable-background:new"
id="rect229"
width="24"
height="38"
x="92"
y="252"
rx="10.323593"
ry="10.323593" /></g><g
id="g231"
style="fill:#3584e4"><rect
style="fill:#82adde;fill-opacity:1;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.1;stroke-dasharray:4, 12"
id="rect230"
width="24"
height="38"
x="30"
y="248"
rx="10.323593"
ry="10.323593" /><rect
style="fill:#82adde;fill-opacity:1;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.1;stroke-dasharray:4, 12"
id="rect231"
width="24"
height="38"
x="92"
y="248"
rx="10.323593"
ry="10.323593" /></g><g
id="g234"
style="fill:#62a0ea;fill-opacity:1"><rect
style="opacity:1;fill:#99c1f1;fill-opacity:1;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.1;stroke-dasharray:4, 12"
id="rect232"
width="24"
height="38"
x="12.000001"
y="252"
rx="10.323593"
ry="10.323593" /><rect
style="fill:#99c1f1;fill-opacity:1;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.1;stroke-dasharray:4, 12"
id="rect233"
width="24"
height="38"
x="74"
y="252"
rx="10.323593"
ry="10.323593" /><rect
style="opacity:1;fill:#99c1f1;fill-opacity:1;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.1;stroke-dasharray:4, 12"
id="rect234"
width="104.00044"
height="50"
x="12.000001"
y="230"
rx="16"
ry="16" /></g><rect
style="fill:#b6d1f2;fill-opacity:1;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.1;stroke-dasharray:4, 12"
id="rect235"
width="24"
height="38"
x="12.000001"
y="248"
rx="10.323593"
ry="10.323593" /><rect
style="fill:#b6d1f2;fill-opacity:1;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.1;stroke-dasharray:4, 12"
id="rect236"
width="24"
height="38"
x="74"
y="248"
rx="10.323593"
ry="10.323593" /><g
id="g237"
transform="translate(11)"
style="fill:#99c1f1;fill-opacity:1"><path
style="opacity:1;fill:#bbd6f6;fill-opacity:1;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.1;stroke-dasharray:4, 12"
id="path236"
sodipodi:type="arc"
sodipodi:cx="100.00001"
sodipodi:cy="180.00003"
sodipodi:rx="8"
sodipodi:ry="8"
sodipodi:start="1.5707963"
sodipodi:end="4.712389"
sodipodi:arc-type="arc"
d="m 100.00001,188.00003 a 8,8 0 0 1 -6.928206,-4 8,8 0 0 1 0,-8 8,8 0 0 1 6.928206,-4"
sodipodi:open="true" /><rect
style="opacity:1;fill:#99c1f1;fill-opacity:1;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.1;stroke-dasharray:4, 12"
id="rect237"
width="7.9999995"
height="16"
x="92"
y="180" /></g><rect
style="fill:#e9eef4;fill-opacity:1;stroke-width:1.99999;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.1;stroke-dasharray:4.00002, 12"
id="rect238"
width="25.999989"
height="14"
x="92.000427"
y="180"
ry="4"
rx="4" /><path
style="fill:#e9eef4;fill-opacity:1;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.1;stroke-dasharray:4, 12"
id="path238"
sodipodi:type="arc"
sodipodi:cx="100.00001"
sodipodi:cy="180.00003"
sodipodi:rx="8"
sodipodi:ry="8"
sodipodi:start="1.5707963"
sodipodi:end="4.712389"
sodipodi:arc-type="arc"
d="m 100.00001,188.00003 a 8,8 0 0 1 -6.928206,-4 8,8 0 0 1 0,-8 8,8 0 0 1 6.928206,-4"
sodipodi:open="true" /><g
id="g239"
style="fill:#e2eaf3;fill-opacity:1"><path
id="path239"
style="opacity:1;fill:url(#linearGradient243);fill-opacity:1;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.1;stroke-dasharray:4, 12"
d="m 92,188 v 16 5.67578 C 92,215.39505 87.395036,220 81.675781,220 H 80 28 c -8.863991,0 -16,7.13601 -16,16 v 24 c 0,8.86399 7.136009,16 16,16 h 72 c 8.86399,0 16,-7.13601 16,-16 V 243.67578 236 188 Z" /><rect
style="fill:#e9eef4;fill-opacity:1;stroke-width:1.99999;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.1;stroke-dasharray:4.00002, 12"
id="rect239"
width="12.999992"
height="16"
x="92.000427"
y="180" /></g><path
id="path240"
style="opacity:1;fill:#5e5c64;fill-opacity:1;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.1;stroke-dasharray:4, 12"
d="m 104,186 h 21.99978 v 5.99969 C 114.66472,192.68742 114.92314,200.47547 109,200 l -5,-3.1e-4 z"
sodipodi:nodetypes="cccccc" /><g
id="g242"
style="fill:#e9eef4;fill-opacity:1"
transform="translate(0,-2)"><circle
style="opacity:1;fill:#e9eef4;fill-opacity:1;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.1;stroke-dasharray:4, 12"
id="circle240"
cx="115.50021"
cy="188"
r="2.5002136" /><circle
style="opacity:1;fill:#e9eef4;fill-opacity:1;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.1;stroke-dasharray:4, 12"
id="circle241"
cx="110.49979"
cy="188"
r="2.5002136" /><circle
style="opacity:1;fill:#e9eef4;fill-opacity:1;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.1;stroke-dasharray:4, 12"
id="circle242"
cx="105.50021"
cy="188"
r="2.5002136" /></g></g></g><g
inkscape:groupmode="layer"
id="layer3"
inkscape:label="grid"
style="display:none"
sodipodi:insensitive="true"><circle
cx="64.000031"
cy="236"
r="59.504131"
id="circle2892"
style="display:inline;opacity:0.1;vector-effect:none;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.99;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:0.99, 0.99;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;enable-background:new" /><rect
ry="7.9292889"
rx="8.701004"
y="180.49496"
x="20.495007"
height="111.01005"
width="87.009987"
id="rect2894"
style="display:inline;opacity:0.1;vector-effect:none;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.99;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:0.99, 0.99;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;enable-background:new" /><rect
ry="7.9238095"
rx="7.9238095"
y="184.49524"
x="12.495266"
height="103.00952"
width="103.00952"
id="rect2896"
style="display:inline;opacity:0.1;vector-effect:none;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.99;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:0.99, 0.99;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;enable-background:new" /><rect
ry="8.701005"
rx="7.9292889"
y="200.49496"
x="8.4950066"
height="87.010048"
width="111.01004"
id="rect2898"
style="display:inline;opacity:0.1;vector-effect:none;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.99;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:0.99, 0.99;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;enable-background:new" /><path
inkscape:connector-curvature="0"
id="path2900"
d="M 2.6203015e-5,288.99999 H 128.00003"
style="display:inline;fill:none;stroke:#62a0ea;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;enable-background:new" /></g></g></svg>

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 10 KiB

View File

@@ -0,0 +1,101 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg height="128px" viewBox="0 0 128 128" width="128px" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<filter id="a" height="100%" width="100%" x="0%" y="0%">
<feColorMatrix color-interpolation-filters="sRGB" values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0"/>
</filter>
<linearGradient id="b" gradientUnits="userSpaceOnUse" x1="48" x2="48" y1="88" y2="48">
<stop offset="0" stop-color="#b6d1f2"/>
<stop offset="1" stop-color="#e9eef4"/>
</linearGradient>
<clipPath id="c">
<rect height="128" width="128"/>
</clipPath>
<clipPath id="d">
<rect height="128" width="128"/>
</clipPath>
<mask id="e">
<g filter="url(#a)">
<g clip-path="url(#d)" filter="url(#a)">
<g clip-path="url(#c)">
<path d="m 2 66 h 24 v 12 h -24 z m 0 0" fill="#99c1f1"/>
<path d="m 12.324219 56 h 3.351562 c 5.703125 0 10.324219 4.621094 10.324219 10.324219 v 1.351562 c 0 5.703125 -4.621094 10.324219 -10.324219 10.324219 h -3.351562 c -5.703125 0 -10.324219 -4.621094 -10.324219 -10.324219 v -1.351562 c 0 -5.703125 4.621094 -10.324219 10.324219 -10.324219 z m 0 0" fill="#99c1f1"/>
<path d="m 82 101 h 8 v 23 h -8 z m 0 0" fill="#5e5c64"/>
<path d="m 100 101 h 8 v 23 h -8 z m 0 0" fill="#5e5c64"/>
<path d="m 20 101 h 8 v 23 h -8 z m 0 0" fill="#5e5c64"/>
<path d="m 38 101 h 8 v 23 h -8 z m 0 0" fill="#5e5c64"/>
<path d="m 40.324219 80 h 3.351562 c 5.703125 0 10.324219 4.621094 10.324219 10.324219 v 17.351562 c 0 5.703125 -4.621094 10.324219 -10.324219 10.324219 h -3.351562 c -5.703125 0 -10.324219 -4.621094 -10.324219 -10.324219 v -17.351562 c 0 -5.703125 4.621094 -10.324219 10.324219 -10.324219 z m 0 0" fill="#6b9bd2"/>
<path d="m 102.324219 80 h 3.351562 c 5.703125 0 10.324219 4.621094 10.324219 10.324219 v 17.351562 c 0 5.703125 -4.621094 10.324219 -10.324219 10.324219 h -3.351562 c -5.703125 0 -10.324219 -4.621094 -10.324219 -10.324219 v -17.351562 c 0 -5.703125 4.621094 -10.324219 10.324219 -10.324219 z m 0 0" fill="#6b9bd2"/>
<path d="m 40.324219 76 h 3.351562 c 5.703125 0 10.324219 4.621094 10.324219 10.324219 v 17.351562 c 0 5.703125 -4.621094 10.324219 -10.324219 10.324219 h -3.351562 c -5.703125 0 -10.324219 -4.621094 -10.324219 -10.324219 v -17.351562 c 0 -5.703125 4.621094 -10.324219 10.324219 -10.324219 z m 0 0" fill="#82adde"/>
<path d="m 102.324219 76 h 3.351562 c 5.703125 0 10.324219 4.621094 10.324219 10.324219 v 17.351562 c 0 5.703125 -4.621094 10.324219 -10.324219 10.324219 h -3.351562 c -5.703125 0 -10.324219 -4.621094 -10.324219 -10.324219 v -17.351562 c 0 -5.703125 4.621094 -10.324219 10.324219 -10.324219 z m 0 0" fill="#82adde"/>
<path d="m 22.324219 80 h 3.351562 c 5.703125 0 10.324219 4.621094 10.324219 10.324219 v 17.351562 c 0 5.703125 -4.621094 10.324219 -10.324219 10.324219 h -3.351562 c -5.703125 0 -10.324219 -4.621094 -10.324219 -10.324219 v -17.351562 c 0 -5.703125 4.621094 -10.324219 10.324219 -10.324219 z m 0 0" fill="#99c1f1"/>
<path d="m 84.324219 80 h 3.351562 c 5.703125 0 10.324219 4.621094 10.324219 10.324219 v 17.351562 c 0 5.703125 -4.621094 10.324219 -10.324219 10.324219 h -3.351562 c -5.703125 0 -10.324219 -4.621094 -10.324219 -10.324219 v -17.351562 c 0 -5.703125 4.621094 -10.324219 10.324219 -10.324219 z m 0 0" fill="#99c1f1"/>
<path d="m 28 58 h 72 c 8.835938 0 16 7.164062 16 16 v 18 c 0 8.835938 -7.164062 16 -16 16 h -72 c -8.835938 0 -16 -7.164062 -16 -16 v -18 c 0 -8.835938 7.164062 -16 16 -16 z m 0 0" fill="#99c1f1"/>
<path d="m 22.324219 76 h 3.351562 c 5.703125 0 10.324219 4.621094 10.324219 10.324219 v 17.351562 c 0 5.703125 -4.621094 10.324219 -10.324219 10.324219 h -3.351562 c -5.703125 0 -10.324219 -4.621094 -10.324219 -10.324219 v -17.351562 c 0 -5.703125 4.621094 -10.324219 10.324219 -10.324219 z m 0 0" fill="#b6d1f2"/>
<path d="m 84.324219 76 h 3.351562 c 5.703125 0 10.324219 4.621094 10.324219 10.324219 v 17.351562 c 0 5.703125 -4.621094 10.324219 -10.324219 10.324219 h -3.351562 c -5.703125 0 -10.324219 -4.621094 -10.324219 -10.324219 v -17.351562 c 0 -5.703125 4.621094 -10.324219 10.324219 -10.324219 z m 0 0" fill="#b6d1f2"/>
<path d="m 111 16 c -2.859375 0 -5.5 -1.523438 -6.929688 -4 c -1.425781 -2.476562 -1.425781 -5.523438 0 -8 c 1.429688 -2.476562 4.070313 -4 6.929688 -4" fill="#bbd6f6"/>
<path d="m 103 8 h 8 v 16 h -8 z m 0 0" fill="#99c1f1"/>
<path d="m 96 8 h 18 c 2.210938 0 4 1.789062 4 4 v 6 c 0 2.210938 -1.789062 4 -4 4 h -18 c -2.207031 0 -4 -1.789062 -4 -4 v -6 c 0 -2.210938 1.792969 -4 4 -4 z m 0 0" fill="#e9eef4"/>
<path d="m 100 16 c -2.859375 0 -5.5 -1.523438 -6.929688 -4 c -1.425781 -2.476562 -1.425781 -5.523438 0 -8 c 1.429688 -2.476562 4.070313 -4 6.929688 -4" fill="#e9eef4"/>
<path d="m 92 16 v 21.675781 c 0 5.71875 -4.605469 10.324219 -10.324219 10.324219 h -53.675781 c -8.863281 0 -16 7.136719 -16 16 v 24 c 0 8.863281 7.136719 16 16 16 h 72 c 8.863281 0 16 -7.136719 16 -16 v -72 z m 0 0" fill="url(#b)"/>
<path d="m 92 8 h 13 v 16 h -13 z m 0 0" fill="#e9eef4"/>
<path d="m 104 14 h 22 v 6 c -11.335938 0.6875 -11.078125 8.476562 -17 8 h -5 z m 0 0" fill="#5e5c64"/>
<path d="m 118 14 c 0 1.378906 -1.117188 2.5 -2.5 2.5 c -1.378906 0 -2.5 -1.121094 -2.5 -2.5 s 1.121094 -2.5 2.5 -2.5 c 1.382812 0 2.5 1.121094 2.5 2.5 z m 0 0" fill="#e9eef4"/>
<path d="m 113 14 c 0 1.378906 -1.121094 2.5 -2.5 2.5 c -1.382812 0 -2.5 -1.121094 -2.5 -2.5 s 1.117188 -2.5 2.5 -2.5 c 1.378906 0 2.5 1.121094 2.5 2.5 z m 0 0" fill="#e9eef4"/>
<path d="m 108 14 c 0 1.378906 -1.117188 2.5 -2.5 2.5 c -1.378906 0 -2.5 -1.121094 -2.5 -2.5 s 1.121094 -2.5 2.5 -2.5 c 1.382812 0 2.5 1.121094 2.5 2.5 z m 0 0" fill="#e9eef4"/>
</g>
</g>
</g>
</mask>
<mask id="f">
<g filter="url(#a)">
<rect fill-opacity="0.8" height="184.32" width="184.32" x="-28.16" y="-28.16"/>
</g>
</mask>
<linearGradient id="g" gradientTransform="matrix(0 0.37 -0.98462 0 295.38501 -30.360001)" gradientUnits="userSpaceOnUse" x1="300" x2="428" y1="235" y2="235">
<stop offset="0" stop-color="#f9f06b"/>
<stop offset="1" stop-color="#f5c211"/>
</linearGradient>
<clipPath id="h">
<rect height="128" width="128"/>
</clipPath>
<clipPath id="i">
<rect height="128" width="128"/>
</clipPath>
<path d="m 2 66 h 24 v 12 h -24 z m 0 0" fill="#99c1f1"/>
<path d="m 12.324219 56 h 3.351562 c 5.703125 0 10.324219 4.621094 10.324219 10.324219 v 1.351562 c 0 5.703125 -4.621094 10.324219 -10.324219 10.324219 h -3.351562 c -5.703125 0 -10.324219 -4.621094 -10.324219 -10.324219 v -1.351562 c 0 -5.703125 4.621094 -10.324219 10.324219 -10.324219 z m 0 0" fill="#99c1f1"/>
<g fill="#5e5c64">
<path d="m 82 101 h 8 v 23 h -8 z m 0 0"/>
<path d="m 100 101 h 8 v 23 h -8 z m 0 0"/>
<path d="m 20 101 h 8 v 23 h -8 z m 0 0"/>
<path d="m 38 101 h 8 v 23 h -8 z m 0 0"/>
</g>
<path d="m 40.324219 80 h 3.351562 c 5.703125 0 10.324219 4.621094 10.324219 10.324219 v 17.351562 c 0 5.703125 -4.621094 10.324219 -10.324219 10.324219 h -3.351562 c -5.703125 0 -10.324219 -4.621094 -10.324219 -10.324219 v -17.351562 c 0 -5.703125 4.621094 -10.324219 10.324219 -10.324219 z m 0 0" fill="#6b9bd2"/>
<path d="m 102.324219 80 h 3.351562 c 5.703125 0 10.324219 4.621094 10.324219 10.324219 v 17.351562 c 0 5.703125 -4.621094 10.324219 -10.324219 10.324219 h -3.351562 c -5.703125 0 -10.324219 -4.621094 -10.324219 -10.324219 v -17.351562 c 0 -5.703125 4.621094 -10.324219 10.324219 -10.324219 z m 0 0" fill="#6b9bd2"/>
<path d="m 40.324219 76 h 3.351562 c 5.703125 0 10.324219 4.621094 10.324219 10.324219 v 17.351562 c 0 5.703125 -4.621094 10.324219 -10.324219 10.324219 h -3.351562 c -5.703125 0 -10.324219 -4.621094 -10.324219 -10.324219 v -17.351562 c 0 -5.703125 4.621094 -10.324219 10.324219 -10.324219 z m 0 0" fill="#82adde"/>
<path d="m 102.324219 76 h 3.351562 c 5.703125 0 10.324219 4.621094 10.324219 10.324219 v 17.351562 c 0 5.703125 -4.621094 10.324219 -10.324219 10.324219 h -3.351562 c -5.703125 0 -10.324219 -4.621094 -10.324219 -10.324219 v -17.351562 c 0 -5.703125 4.621094 -10.324219 10.324219 -10.324219 z m 0 0" fill="#82adde"/>
<path d="m 22.324219 80 h 3.351562 c 5.703125 0 10.324219 4.621094 10.324219 10.324219 v 17.351562 c 0 5.703125 -4.621094 10.324219 -10.324219 10.324219 h -3.351562 c -5.703125 0 -10.324219 -4.621094 -10.324219 -10.324219 v -17.351562 c 0 -5.703125 4.621094 -10.324219 10.324219 -10.324219 z m 0 0" fill="#99c1f1"/>
<path d="m 84.324219 80 h 3.351562 c 5.703125 0 10.324219 4.621094 10.324219 10.324219 v 17.351562 c 0 5.703125 -4.621094 10.324219 -10.324219 10.324219 h -3.351562 c -5.703125 0 -10.324219 -4.621094 -10.324219 -10.324219 v -17.351562 c 0 -5.703125 4.621094 -10.324219 10.324219 -10.324219 z m 0 0" fill="#99c1f1"/>
<path d="m 28 58 h 72 c 8.835938 0 16 7.164062 16 16 v 18 c 0 8.835938 -7.164062 16 -16 16 h -72 c -8.835938 0 -16 -7.164062 -16 -16 v -18 c 0 -8.835938 7.164062 -16 16 -16 z m 0 0" fill="#99c1f1"/>
<path d="m 22.324219 76 h 3.351562 c 5.703125 0 10.324219 4.621094 10.324219 10.324219 v 17.351562 c 0 5.703125 -4.621094 10.324219 -10.324219 10.324219 h -3.351562 c -5.703125 0 -10.324219 -4.621094 -10.324219 -10.324219 v -17.351562 c 0 -5.703125 4.621094 -10.324219 10.324219 -10.324219 z m 0 0" fill="#b6d1f2"/>
<path d="m 84.324219 76 h 3.351562 c 5.703125 0 10.324219 4.621094 10.324219 10.324219 v 17.351562 c 0 5.703125 -4.621094 10.324219 -10.324219 10.324219 h -3.351562 c -5.703125 0 -10.324219 -4.621094 -10.324219 -10.324219 v -17.351562 c 0 -5.703125 4.621094 -10.324219 10.324219 -10.324219 z m 0 0" fill="#b6d1f2"/>
<path d="m 111 16 c -2.859375 0 -5.5 -1.523438 -6.929688 -4 c -1.425781 -2.476562 -1.425781 -5.523438 0 -8 c 1.429688 -2.476562 4.070313 -4 6.929688 -4" fill="#bbd6f6"/>
<path d="m 103 8 h 8 v 16 h -8 z m 0 0" fill="#99c1f1"/>
<path d="m 96 8 h 18 c 2.210938 0 4 1.789062 4 4 v 6 c 0 2.210938 -1.789062 4 -4 4 h -18 c -2.207031 0 -4 -1.789062 -4 -4 v -6 c 0 -2.210938 1.792969 -4 4 -4 z m 0 0" fill="#e9eef4"/>
<path d="m 100 16 c -2.859375 0 -5.5 -1.523438 -6.929688 -4 c -1.425781 -2.476562 -1.425781 -5.523438 0 -8 c 1.429688 -2.476562 4.070313 -4 6.929688 -4" fill="#e9eef4"/>
<path d="m 92 16 v 21.675781 c 0 5.71875 -4.605469 10.324219 -10.324219 10.324219 h -53.675781 c -8.863281 0 -16 7.136719 -16 16 v 24 c 0 8.863281 7.136719 16 16 16 h 72 c 8.863281 0 16 -7.136719 16 -16 v -72 z m 0 0" fill="url(#b)"/>
<path d="m 92 8 h 13 v 16 h -13 z m 0 0" fill="#e9eef4"/>
<path d="m 104 14 h 22 v 6 c -11.335938 0.6875 -11.078125 8.476562 -17 8 h -5 z m 0 0" fill="#5e5c64"/>
<path d="m 118 14 c 0 1.378906 -1.117188 2.5 -2.5 2.5 c -1.378906 0 -2.5 -1.121094 -2.5 -2.5 s 1.121094 -2.5 2.5 -2.5 c 1.382812 0 2.5 1.121094 2.5 2.5 z m 0 0" fill="#e9eef4"/>
<path d="m 113 14 c 0 1.378906 -1.121094 2.5 -2.5 2.5 c -1.382812 0 -2.5 -1.121094 -2.5 -2.5 s 1.117188 -2.5 2.5 -2.5 c 1.378906 0 2.5 1.121094 2.5 2.5 z m 0 0" fill="#e9eef4"/>
<path d="m 108 14 c 0 1.378906 -1.117188 2.5 -2.5 2.5 c -1.378906 0 -2.5 -1.121094 -2.5 -2.5 s 1.121094 -2.5 2.5 -2.5 c 1.382812 0 2.5 1.121094 2.5 2.5 z m 0 0" fill="#e9eef4"/>
<g mask="url(#e)">
<g clip-path="url(#i)">
<g mask="url(#f)">
<g clip-path="url(#h)">
<path d="m 128 80.640625 v 47.359375 h -128 v -47.359375 z m 0 0" fill="url(#g)"/>
<path d="m 13.308594 80.640625 l 47.355468 47.359375 h 21.214844 l -47.359375 -47.359375 z m 42.421875 0 l 47.363281 47.359375 h 21.214844 l -47.363282 -47.359375 z m 42.429687 0 l 29.839844 29.839844 v -21.210938 l -8.628906 -8.628906 z m -98.160156 7.90625 v 21.214844 l 18.238281 18.238281 h 21.214844 z m 0 0"/>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 12 KiB

View File

@@ -1,272 +1,150 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="128"
height="128"
id="svg11300"
version="1.0"
style="display:inline;enable-background:new"
height="128px"
viewBox="0 0 128 128"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="128px"
version="1.1"
id="svg26"
sodipodi:docname="com.jeffser.Alpaca.svg"
inkscape:version="1.3.2 (091e20ef0f, 2023-11-25)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<title
id="title4162">Adwaita Icon Template</title>
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs3">
<linearGradient
id="linearGradient35">
<stop
style="stop-color:#3d3846;stop-opacity:1;"
offset="0"
id="stop35" />
<stop
style="stop-color:#241f31;stop-opacity:1;"
offset="1"
id="stop36" />
</linearGradient>
<linearGradient
id="linearGradient33">
<stop
style="stop-color:#99c1ff;stop-opacity:1;"
offset="0"
id="stop33" />
<stop
style="stop-color:#62a0ea;stop-opacity:1;"
offset="1"
id="stop34" />
</linearGradient>
<linearGradient
id="linearGradient31">
<stop
style="stop-color:#deddda;stop-opacity:1;"
offset="0"
id="stop31" />
<stop
style="stop-color:#f6f5f4;stop-opacity:1;"
offset="1"
id="stop32" />
</linearGradient>
<linearGradient
id="linearGradient24">
<stop
style="stop-color:#f6f5f4;stop-opacity:1;"
offset="0"
id="stop24" />
<stop
style="stop-color:#deddda;stop-opacity:1;"
offset="1"
id="stop23" />
</linearGradient>
<linearGradient
id="linearGradient12">
<stop
style="stop-color:#000000;stop-opacity:0;"
offset="0"
id="stop12" />
<stop
style="stop-color:#000000;stop-opacity:0;"
offset="1"
id="stop13" />
</linearGradient>
<linearGradient
xlink:href="#linearGradient12"
id="linearGradient13"
x1="40.888428"
y1="205.03607"
x2="40.90649"
y2="212.09515"
gradientUnits="userSpaceOnUse" />
<linearGradient
xlink:href="#linearGradient24"
id="linearGradient23"
x1="40.888428"
y1="205.03607"
x2="40.90649"
y2="212.09515"
gradientUnits="userSpaceOnUse" />
<linearGradient
xlink:href="#linearGradient24"
id="linearGradient29"
gradientUnits="userSpaceOnUse"
x1="40.888428"
y1="205.03607"
x2="40.90649"
y2="212.09515"
gradientTransform="matrix(-1,0,0,1,127.14843,2.8384866e-4)" />
<linearGradient
xlink:href="#linearGradient12"
id="linearGradient30"
gradientUnits="userSpaceOnUse"
x1="40.888428"
y1="205.03607"
x2="40.90649"
y2="212.09515"
gradientTransform="matrix(-1,0,0,1,127.14843,2.8384866e-4)" />
<linearGradient
xlink:href="#linearGradient31"
id="linearGradient32"
x1="63.552597"
y1="214.19464"
x2="63.552597"
y2="241.24492"
gradientUnits="userSpaceOnUse" />
<linearGradient
xlink:href="#linearGradient33"
id="linearGradient34"
x1="64.683159"
y1="267.04626"
x2="64.895935"
y2="278.69958"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.99245101,0,0,1.1818075,0.48386604,-51.63542)" />
<linearGradient
xlink:href="#linearGradient35"
id="linearGradient36"
x1="45.111782"
y1="235.32567"
x2="45.111782"
y2="229.17581"
gradientUnits="userSpaceOnUse" />
<linearGradient
xlink:href="#linearGradient35"
id="linearGradient37"
gradientUnits="userSpaceOnUse"
x1="45.111782"
y1="235.32567"
x2="45.111782"
y2="229.17581"
gradientTransform="translate(36.957243,0.15686125)" />
</defs>
<metadata
id="metadata4">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:creator>
<cc:Agent>
<dc:title>GNOME Design Team</dc:title>
</cc:Agent>
</dc:creator>
<dc:source />
<cc:license
rdf:resource="http://creativecommons.org/licenses/by-sa/4.0/" />
<dc:title>Adwaita Icon Template</dc:title>
<dc:subject>
<rdf:Bag />
</dc:subject>
<dc:date />
<dc:rights>
<cc:Agent>
<dc:title />
</cc:Agent>
</dc:rights>
<dc:publisher>
<cc:Agent>
<dc:title />
</cc:Agent>
</dc:publisher>
<dc:identifier />
<dc:relation />
<dc:language />
<dc:coverage />
<dc:description />
<dc:contributor>
<cc:Agent>
<dc:title />
</cc:Agent>
</dc:contributor>
</cc:Work>
<cc:License
rdf:about="http://creativecommons.org/licenses/by-sa/4.0/">
<cc:permits
rdf:resource="http://creativecommons.org/ns#Reproduction" />
<cc:permits
rdf:resource="http://creativecommons.org/ns#Distribution" />
<cc:requires
rdf:resource="http://creativecommons.org/ns#Notice" />
<cc:requires
rdf:resource="http://creativecommons.org/ns#Attribution" />
<cc:permits
rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
<cc:requires
rdf:resource="http://creativecommons.org/ns#ShareAlike" />
</cc:License>
</rdf:RDF>
</metadata>
id="defs26" />
<sodipodi:namedview
id="namedview26"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:zoom="6.65625"
inkscape:cx="64"
inkscape:cy="64"
inkscape:window-width="1920"
inkscape:window-height="1011"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg26" />
<linearGradient
id="a"
gradientUnits="userSpaceOnUse"
x1="48"
x2="48"
y1="88"
y2="48">
<stop
offset="0"
stop-color="#b6d1f2"
id="stop1" />
<stop
offset="1"
stop-color="#e9eef4"
id="stop2" />
</linearGradient>
<path
d="m 2 66 h 24 v 12 h -24 z m 0 0"
fill="#99c1f1"
id="path2" />
<path
d="m 12.324219 56 h 3.351562 c 5.703125 0 10.324219 4.621094 10.324219 10.324219 v 1.351562 c 0 5.703125 -4.621094 10.324219 -10.324219 10.324219 h -3.351562 c -5.703125 0 -10.324219 -4.621094 -10.324219 -10.324219 v -1.351562 c 0 -5.703125 4.621094 -10.324219 10.324219 -10.324219 z m 0 0"
fill="#99c1f1"
id="path3" />
<g
id="layer1"
style="display:inline"
transform="translate(0,-172)">
<g
id="layer4"
transform="matrix(1.2477821,0,0,1.2477821,-15.858054,-61.000241)">
<rect
style="display:inline;fill:url(#linearGradient32);fill-opacity:1;stroke:#000000;stroke-width:2.91036;stroke-dasharray:none;stroke-opacity:0;enable-background:new"
id="rect1"
width="81.276649"
height="56.210243"
x="23.361675"
y="213.42638"
ry="13.680508" />
<path
style="display:inline;fill:url(#linearGradient23);fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient13);stroke-width:3;stroke-linecap:round;stroke-dasharray:none;stroke-opacity:0;enable-background:new"
d="m 32.848631,215.48926 c 0,0 0.309082,-16.43408 7.036621,-19.01123 6.727539,-2.57715 10.409179,18.9375 10.409179,18.9375"
id="path1" />
<path
style="display:inline;fill:url(#linearGradient29);fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient30);stroke-width:3;stroke-linecap:round;stroke-dasharray:none;stroke-opacity:0;enable-background:new"
d="m 94.2998,215.48954 c 0,0 -0.309082,-16.43408 -7.036621,-19.01123 C 80.53564,193.90116 76.854,215.41581 76.854,215.41581"
id="path1-7" />
<circle
style="display:inline;fill:url(#linearGradient36);fill-opacity:1;stroke:none;stroke-width:3;stroke-linecap:round;stroke-dasharray:none;enable-background:new"
id="path3"
cx="45.129391"
cy="235.05762"
r="5.8994136" />
<circle
style="display:inline;fill:url(#linearGradient37);fill-opacity:1;stroke:none;stroke-width:3;stroke-linecap:round;stroke-dasharray:none;enable-background:new"
id="path3-6"
cx="82.086639"
cy="235.21448"
r="5.8994136" />
<path
style="display:inline;fill:none;stroke:#241f31;stroke-width:3;stroke-linecap:round;stroke-dasharray:none;stroke-opacity:1;enable-background:new"
d="m 32.392577,229.59423 c 0,0 25.649412,1.06983 24.62744,-3.62353"
id="path4" />
<path
style="display:inline;fill:none;stroke:#241f31;stroke-width:2.99972;stroke-linecap:round;stroke-dasharray:none;stroke-opacity:1;enable-background:new"
d="m 94.823791,229.75097 c 0,0 -25.649412,1.06983 -24.62744,-3.62353"
id="path4-5" />
<path
style="display:inline;fill:url(#linearGradient34);fill-opacity:1;stroke:none;stroke-width:3.24899;stroke-linecap:round;stroke-dasharray:none;enable-background:new"
d="m 23.60202,258.09454 c 1.243956,12.49842 3.858832,15.67625 12.858734,14.90301 8.999901,-0.77326 9.384671,10.27444 19.65082,5.37353 10.266149,-4.90093 14.08815,-3.56159 14.703102,-3.63198 0.614951,-0.0704 15.397528,10.41294 20.253656,3.89337 4.856129,-6.51955 7.043107,-1.94985 9.232508,-4.41272 2.1894,-2.46288 4.89442,-9.45966 3.87579,-16.22158"
id="path8-0" />
<path
style="display:inline;fill:#f6f5f4;fill-opacity:1;stroke:none;stroke-width:2.99884;stroke-linecap:round;stroke-dasharray:none;enable-background:new"
d="m 23.389225,256.86198 c 1.25195,10.5799 3.883629,13.26993 12.941363,12.61538 9.057733,-0.65456 9.444975,8.6973 19.777093,4.54868 10.332117,-4.14862 14.178679,-3.01487 14.797582,-3.07446 0.618903,-0.0596 15.49647,8.81454 20.383803,3.29574 4.887333,-5.5188 7.088365,-1.65056 9.291844,-3.73537 2.20346,-2.08482 4.92586,-8.00759 3.90069,-13.73155"
id="path8" />
<path
style="display:inline;fill:none;stroke:#241f31;stroke-width:2.99972;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1;enable-background:new"
d="m 63.095594,248.37344 c 0,0 10.15573,26.47309 21.090617,10.976"
id="path2" />
<path
style="display:inline;fill:none;stroke:#241f31;stroke-width:2.99972;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1;enable-background:new"
d="m 64.150661,248.40941 c 0,0 -10.15573,26.47309 -21.090617,10.976"
id="path2-6" />
<ellipse
style="display:inline;fill:#000000;stroke:none;stroke-width:1.29382;stroke-linecap:round;stroke-dasharray:none;enable-background:new"
id="path5"
cx="63.564262"
cy="248.16406"
rx="4.5169015"
ry="4.2407222" />
</g>
fill="#5e5c64"
id="g7">
<path
d="m 82 101 h 8 v 23 h -8 z m 0 0"
id="path4" />
<path
d="m 100 101 h 8 v 23 h -8 z m 0 0"
id="path5" />
<path
d="m 20 101 h 8 v 23 h -8 z m 0 0"
id="path6" />
<path
d="m 38 101 h 8 v 23 h -8 z m 0 0"
id="path7" />
</g>
<path
d="m 40.324219 80 h 3.351562 c 5.703125 0 10.324219 4.621094 10.324219 10.324219 v 17.351562 c 0 5.703125 -4.621094 10.324219 -10.324219 10.324219 h -3.351562 c -5.703125 0 -10.324219 -4.621094 -10.324219 -10.324219 v -17.351562 c 0 -5.703125 4.621094 -10.324219 10.324219 -10.324219 z m 0 0"
fill="#6b9bd2"
id="path8" />
<path
d="m 102.324219 80 h 3.351562 c 5.703125 0 10.324219 4.621094 10.324219 10.324219 v 17.351562 c 0 5.703125 -4.621094 10.324219 -10.324219 10.324219 h -3.351562 c -5.703125 0 -10.324219 -4.621094 -10.324219 -10.324219 v -17.351562 c 0 -5.703125 4.621094 -10.324219 10.324219 -10.324219 z m 0 0"
fill="#6b9bd2"
id="path9" />
<path
d="m 40.324219 76 h 3.351562 c 5.703125 0 10.324219 4.621094 10.324219 10.324219 v 17.351562 c 0 5.703125 -4.621094 10.324219 -10.324219 10.324219 h -3.351562 c -5.703125 0 -10.324219 -4.621094 -10.324219 -10.324219 v -17.351562 c 0 -5.703125 4.621094 -10.324219 10.324219 -10.324219 z m 0 0"
fill="#82adde"
id="path10" />
<path
d="m 102.324219 76 h 3.351562 c 5.703125 0 10.324219 4.621094 10.324219 10.324219 v 17.351562 c 0 5.703125 -4.621094 10.324219 -10.324219 10.324219 h -3.351562 c -5.703125 0 -10.324219 -4.621094 -10.324219 -10.324219 v -17.351562 c 0 -5.703125 4.621094 -10.324219 10.324219 -10.324219 z m 0 0"
fill="#82adde"
id="path11" />
<path
d="m 22.324219 80 h 3.351562 c 5.703125 0 10.324219 4.621094 10.324219 10.324219 v 17.351562 c 0 5.703125 -4.621094 10.324219 -10.324219 10.324219 h -3.351562 c -5.703125 0 -10.324219 -4.621094 -10.324219 -10.324219 v -17.351562 c 0 -5.703125 4.621094 -10.324219 10.324219 -10.324219 z m 0 0"
fill="#99c1f1"
id="path12" />
<path
d="m 84.324219 80 h 3.351562 c 5.703125 0 10.324219 4.621094 10.324219 10.324219 v 17.351562 c 0 5.703125 -4.621094 10.324219 -10.324219 10.324219 h -3.351562 c -5.703125 0 -10.324219 -4.621094 -10.324219 -10.324219 v -17.351562 c 0 -5.703125 4.621094 -10.324219 10.324219 -10.324219 z m 0 0"
fill="#99c1f1"
id="path13" />
<path
d="m 28 58 h 72 c 8.835938 0 16 7.164062 16 16 v 18 c 0 8.835938 -7.164062 16 -16 16 h -72 c -8.835938 0 -16 -7.164062 -16 -16 v -18 c 0 -8.835938 7.164062 -16 16 -16 z m 0 0"
fill="#99c1f1"
id="path14" />
<path
d="m 22.324219 76 h 3.351562 c 5.703125 0 10.324219 4.621094 10.324219 10.324219 v 17.351562 c 0 5.703125 -4.621094 10.324219 -10.324219 10.324219 h -3.351562 c -5.703125 0 -10.324219 -4.621094 -10.324219 -10.324219 v -17.351562 c 0 -5.703125 4.621094 -10.324219 10.324219 -10.324219 z m 0 0"
fill="#b6d1f2"
id="path15" />
<path
d="m 84.324219 76 h 3.351562 c 5.703125 0 10.324219 4.621094 10.324219 10.324219 v 17.351562 c 0 5.703125 -4.621094 10.324219 -10.324219 10.324219 h -3.351562 c -5.703125 0 -10.324219 -4.621094 -10.324219 -10.324219 v -17.351562 c 0 -5.703125 4.621094 -10.324219 10.324219 -10.324219 z m 0 0"
fill="#b6d1f2"
id="path16" />
<path
d="m 111 16 c -2.859375 0 -5.5 -1.523438 -6.929688 -4 c -1.425781 -2.476562 -1.425781 -5.523438 0 -8 c 1.429688 -2.476562 4.070313 -4 6.929688 -4"
fill="#bbd6f6"
id="path17" />
<path
d="m 103 8 h 8 v 16 h -8 z m 0 0"
fill="#99c1f1"
id="path18" />
<path
d="m 96 8 h 18 c 2.210938 0 4 1.789062 4 4 v 6 c 0 2.210938 -1.789062 4 -4 4 h -18 c -2.207031 0 -4 -1.789062 -4 -4 v -6 c 0 -2.210938 1.792969 -4 4 -4 z m 0 0"
fill="#e9eef4"
id="path19" />
<path
d="m 100 16 c -2.859375 0 -5.5 -1.523438 -6.929688 -4 c -1.425781 -2.476562 -1.425781 -5.523438 0 -8 c 1.429688 -2.476562 4.070313 -4 6.929688 -4"
fill="#e9eef4"
id="path20" />
<path
d="m 92 16 v 21.675781 c 0 5.71875 -4.605469 10.324219 -10.324219 10.324219 h -53.675781 c -8.863281 0 -16 7.136719 -16 16 v 24 c 0 8.863281 7.136719 16 16 16 h 72 c 8.863281 0 16 -7.136719 16 -16 v -72 z m 0 0"
fill="url(#a)"
id="path21" />
<path
d="m 92 8 h 13 v 16 h -13 z m 0 0"
fill="#e9eef4"
id="path22" />
<path
d="m 104 14 h 22 v 6 c -11.335938 0.6875 -11.078125 8.476562 -17 8 h -5 z m 0 0"
fill="#5e5c64"
id="path23" />
<path
d="m 118 14 c 0 1.378906 -1.117188 2.5 -2.5 2.5 c -1.378906 0 -2.5 -1.121094 -2.5 -2.5 s 1.121094 -2.5 2.5 -2.5 c 1.382812 0 2.5 1.121094 2.5 2.5 z m 0 0"
fill="#e9eef4"
id="path24" />
<path
d="m 113 14 c 0 1.378906 -1.121094 2.5 -2.5 2.5 c -1.382812 0 -2.5 -1.121094 -2.5 -2.5 s 1.117188 -2.5 2.5 -2.5 c 1.378906 0 2.5 1.121094 2.5 2.5 z m 0 0"
fill="#e9eef4"
id="path25" />
<path
d="m 108 14 c 0 1.378906 -1.117188 2.5 -2.5 2.5 c -1.378906 0 -2.5 -1.121094 -2.5 -2.5 s 1.121094 -2.5 2.5 -2.5 c 1.382812 0 2.5 1.121094 2.5 2.5 z m 0 0"
fill="#e9eef4"
id="path26" />
</svg>

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 6.7 KiB

View File

@@ -1,2 +1,13 @@
<?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 14 3.175781 v 3.824219 c 0 2.179688 -1.820312 4 -4 4 h -3.585938 l -2 2 h 5.585938 l 3 3 v -3 c 1.644531 0 3 -1.355469 3 -3 v -4 c 0 -1.292969 -0.839844 -2.40625 -2 -2.824219 z m 0 0"/><path d="m 3 0 c -1.644531 0 -3 1.355469 -3 3 v 4 c 0 1.644531 1.355469 3 3 3 v 3 l 3 -3 h 4 c 1.644531 0 3 -1.355469 3 -3 v -4 c 0 -1.644531 -1.355469 -3 -3 -3 z m 0 0"/></g></svg>
<svg height="16px" viewBox="0 0 16 16" width="16px" xmlns="http://www.w3.org/2000/svg">
<g fill="#241f31">
<path d="m 12.5 3 c -0.550781 0 -1 0.449219 -1 1 s 0.449219 1 1 1 c 0.289062 0 0.5 0.210938 0.5 0.5 c 0 0.550781 0.449219 1 1 1 s 1 -0.449219 1 -1 c 0 -1.367188 -1.132812 -2.5 -2.5 -2.5 z m 0 0"/>
<path d="m 2 3 c -0.550781 0 -1 0.449219 -1 1 v 11 c 0 0.550781 0.449219 1 1 1 s 1 -0.449219 1 -1 v -11 c 0 -0.550781 -0.449219 -1 -1 -1 z m 10 6 c -0.550781 0 -1 0.449219 -1 1 v 5 c 0 0.550781 0.449219 1 1 1 s 1 -0.449219 1 -1 v -5 c 0 -0.550781 -0.449219 -1 -1 -1 z m 0 0"/>
<path d="m 5 0 c -2.199219 0 -4 1.800781 -4 4 c 0 0.550781 0.449219 1 1 1 s 1 -0.449219 1 -1 c 0 -0.722656 0.4375 -1.238281 1 -1.589844 v 1.589844 c 0 0.550781 0.449219 1 1 1 s 1 -0.449219 1 -1 v -3 c 0 -0.550781 -0.449219 -1 -1 -1 z m 0 0"/>
<path d="m 10 0 c -2.199219 0 -4 1.800781 -4 4 c 0 0.550781 0.449219 1 1 1 s 1 -0.449219 1 -1 c 0 -0.722656 0.4375 -1.238281 1 -1.589844 v 1.589844 c 0 0.550781 0.449219 1 1 1 s 1 -0.449219 1 -1 v -3 c 0 -0.550781 -0.449219 -1 -1 -1 z m 0 0"/>
<path d="m 5 3 c -0.550781 0 -1 0.449219 -1 1 s 0.449219 1 1 1 h 2 c 0.550781 0 1 -0.449219 1 -1 s -0.449219 -1 -1 -1 z m 0 0"/>
<path d="m 10.007812 3 c -0.554687 -0.003906 -1.003906 0.441406 -1.007812 0.992188 c -0.003906 0.554687 0.441406 1.003906 0.992188 1.007812 l 2.527343 0.015625 c 0.550781 0.003906 1.003907 -0.441406 1.003907 -0.996094 c 0.003906 -0.550781 -0.441407 -1 -0.992188 -1.003906 z m 0 0"/>
<path d="m 14.019531 4.476562 c -0.550781 -0.003906 -1 0.441407 -1.003906 0.992188 l -0.015625 3.527344 c -0.003906 0.550781 0.445312 1 0.996094 1.003906 c 0.550781 0.003906 1 -0.445312 1.003906 -0.996094 l 0.015625 -3.523437 c 0.003906 -0.554688 -0.445313 -1.003907 -0.996094 -1.003907 z m 0 0"/>
<path d="m 16 8 v 2 c -3.535156 0.214844 -4.234375 2.445312 -5.648438 3.085938 c -0.5 0.226562 -1.425781 0.164062 -1.976562 0.164062 h -0.375 c -1.105469 0 -2 -0.894531 -2 -2 v -3.25"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 522 B

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

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

View File

@@ -1,4 +1,11 @@
ru
es
pt_BR
fr
fr
nb_NO
bn
zh_Hans
hi
tr
uk
de

View File

@@ -3,4 +3,11 @@ data/com.jeffser.Alpaca.metainfo.xml.in
data/com.jeffser.Alpaca.gschema.xml
src/main.py
src/window.py
src/available_models_descriptions.py
src/connection_handler.py
src/dialogs.py
src/window.ui
src/custom_widgets/chat_widget.py
src/custom_widgets/message_widget.py
src/custom_widgets/model_widget.py
src/custom_widgets/table_widget.py

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

2891
po/bn.po Normal file

File diff suppressed because it is too large Load Diff

2893
po/de.po Normal file

File diff suppressed because it is too large Load Diff

2807
po/es.po

File diff suppressed because it is too large Load Diff

1242
po/es.po~

File diff suppressed because it is too large Load Diff

2829
po/fr.po

File diff suppressed because it is too large Load Diff

1101
po/fr.po~

File diff suppressed because it is too large Load Diff

2814
po/hi.po Normal file

File diff suppressed because it is too large Load Diff

2808
po/nb_NO.po Normal file

File diff suppressed because it is too large Load Diff

2527
po/pl.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

2935
po/ru.po

File diff suppressed because it is too large Load Diff

2838
po/tr.po Normal file

File diff suppressed because it is too large Load Diff

2822
po/uk.po Normal file

File diff suppressed because it is too large Load Diff

2704
po/zh_Hans.po Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -2,8 +2,6 @@
<gresources>
<gresource prefix="/com/jeffser/Alpaca">
<file>style.css</file>
<file>style-dark.css</file>
<file alias="icons/scalable/status/library-symbolic.svg">icons/library-symbolic.svg</file>
<file alias="icons/scalable/status/paper-plane-symbolic.svg">icons/paper-plane-symbolic.svg</file>
<file alias="icons/scalable/status/globe-symbolic.svg">icons/globe-symbolic.svg</file>
<file alias="icons/scalable/status/chat-message-new-symbolic.svg">icons/chat-message-new-symbolic.svg</file>
@@ -13,9 +11,8 @@
<file alias="icons/scalable/status/folder-download-symbolic.svg">icons/folder-download-symbolic.svg</file>
<file alias="icons/scalable/status/image-x-generic-symbolic.svg">icons/image-x-generic-symbolic.svg</file>
<file alias="icons/scalable/status/media-playback-stop-symbolic.svg">icons/media-playback-stop-symbolic.svg</file>
<file alias="icons/scalable/status/open-menu-symbolicsvg">icons/open-menu-symbolic.svg</file>
<file alias="icons/scalable/status/preferences-other-symbolic.svg">icons/preferences-other-symbolic.svg</file>
<file alias="icons/scalable/status/preferences-system-symbolic.svg">icons/preferences-system-symbolic.svg</file>
<file alias="icons/scalable/status/open-menu-symbolic.svg">icons/open-menu-symbolic.svg</file>
<file alias="icons/scalable/status/settings-symbolic.svg">icons/settings-symbolic.svg</file>
<file alias="icons/scalable/status/sidebar-show-symbolic.svg">icons/sidebar-show-symbolic.svg</file>
<file alias="icons/scalable/status/user-trash-symbolic.svg">icons/user-trash-symbolic.svg</file>
<file alias="icons/scalable/status/view-more-symbolic.svg">icons/view-more-symbolic.svg</file>
@@ -24,6 +21,16 @@
<file alias="icons/scalable/status/brain-augemnted-symbolic.svg">icons/brain-augemnted-symbolic.svg</file>
<file alias="icons/scalable/status/chain-link-loose-symbolic.svg">icons/chain-link-loose-symbolic.svg</file>
<file alias="icons/scalable/status/document-text-symbolic.svg">icons/document-text-symbolic.svg</file>
<file alias="icons/scalable/status/play-symbolic.svg">icons/play-symbolic.svg</file>
<file alias="icons/scalable/status/step-back-symbolic.svg">icons/step-back-symbolic.svg</file>
<file alias="icons/scalable/status/step-over-symbolic.svg">icons/step-over-symbolic.svg</file>
<file alias="icons/scalable/status/share-symbolic.svg">icons/share-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/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 alias="icons/scalable/status/chat-bubble-text-symbolic.svg">icons/chat-bubble-text-symbolic.svg</file>
<file preprocess="xml-stripblanks">window.ui</file>
<file preprocess="xml-stripblanks">gtk/help-overlay.ui</file>
</gresource>

View File

@@ -1,127 +0,0 @@
#!@PYTHON@
import sys
from gi.repository import Gio, GLib
DBUS_NAME = "com.jeffser.Alpaca.SearchProvider"
DBUS_OBJECT_PATH = "/com/jeffser/Alpaca/SearchProvider"
DBUS_INTERFACE = "org.gnome.Shell.SearchProvider2"
class SearchProvider:
def __init__(self):
print("ALPACA __init__")
self.connection = Gio.bus_get_sync(Gio.BusType.SESSION, None)
if not self.connection:
print("ALPACA Failed to get D-Bus connection")
return
print("ALPACA D-Bus connection obtained")
interface_info = self.get_interface_info()
self.registration_id = self.connection.register_object(
DBUS_OBJECT_PATH,
interface_info,
self.handle_method_call,
None,
None
)
if self.registration_id > 0:
print(f"ALPACA Object registered with ID: {self.registration_id}")
else:
print("ALPACA Failed to register object")
def get_interface_info(self):
print("ALPACA get_interface_info")
xml = """
<node>
<interface name="org.gnome.Shell.SearchProvider2">
<method name="GetInitialResultSet">
<arg type="as" name="terms" direction="in" />
<arg type="as" name="results" direction="out" />
</method>
<method name="GetSubsearchResultSet">
<arg type="as" name="previous_results" direction="in" />
<arg type="as" name="terms" direction="in" />
<arg type="as" name="results" direction="out" />
</method>
<method name="GetResultMetas">
<arg type="as" name="identifiers" direction="in" />
<arg type="aa{sv}" name="metas" direction="out" />
</method>
<method name="ActivateResult">
<arg type="s" name="identifier" direction="in" />
<arg type="as" name="terms" direction="in" />
<arg type="u" name="timestamp" direction="in" />
</method>
<method name="LaunchSearch">
<arg type="as" name="terms" direction="in" />
<arg type="u" name="timestamp" direction="in" />
</method>
</interface>
</node>
"""
return Gio.DBusNodeInfo.new_for_xml(xml).interfaces[0]
def handle_method_call(self, connection, sender, object_path, interface_name, method_name, parameters, invocation):
print(f"ALPACA handle_method_call: {method_name}")
if method_name == "GetInitialResultSet":
self.handle_get_initial_result_set(invocation, parameters)
elif method_name == "GetSubsearchResultSet":
self.handle_get_subsearch_result_set(invocation, parameters)
elif method_name == "GetResultMetas":
self.handle_get_result_metas(invocation, parameters)
elif method_name == "ActivateResult":
self.handle_activate_result(invocation, parameters)
def handle_get_initial_result_set(self, invocation, parameters):
print("ALPACA handle_get_initial_result_set")
terms = parameters.unpack()[0]
print(f"Initial search terms: {terms}")
results = ["result1", "result2"]
if "Alpaca" in terms:
results.append("alpaca_placeholder_result")
print(f"Returning results: {results}")
invocation.return_value(GLib.Variant("(as)", [results]))
def handle_get_subsearch_result_set(self, invocation, parameters):
print("ALPACA handle_get_subsearch_result_set")
previous_results, terms = parameters.unpack()
print(f"Subsearch terms: {terms}, previous results: {previous_results}")
results = ["result3", "result4"]
if "Alpaca" in terms:
results.append("sub_alpaca_placeholder_result")
print(f"Returning subsearch results: {results}")
invocation.return_value(GLib.Variant("(as)", [results]))
def handle_get_result_metas(self, invocation, parameters):
print("ALPACA handle_get_result_metas")
identifiers = parameters.unpack()[0]
print(f"Result metas for identifiers: {identifiers}")
metas = []
for identifier in identifiers:
meta = {"name": GLib.Variant("s", "Placeholder result for " + identifier)}
metas.append(GLib.Variant("a{sv}", meta))
print(f"Returning metas: {metas}")
invocation.return_value(GLib.Variant("(a{sv})", [metas]))
def handle_activate_result(self, invocation, parameters):
print("ALPACA handle_activate_result")
identifier, terms, timestamp = parameters.unpack()
print(f"Activated result: {identifier}, terms: {terms}, timestamp: {timestamp}")
invocation.return_value(None)
if __name__ == "__main__":
provider = SearchProvider()
if provider.registration_id > 0:
loop = GLib.MainLoop()
print("ALPACA Running main loop")
loop.run()
else:
print("ALPACA Failed to start main loop due to object registration failure")

22126
src/available_models.json Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,112 @@
descriptions = {
'llama3.1': _("Llama 3.1 is a new state-of-the-art model from Meta available in 8B, 70B and 405B parameter sizes."),
'gemma2': _("Google Gemma 2 is a high-performing and efficient model by now available in three sizes: 2B, 9B, and 27B."),
'mistral-nemo': _("A state-of-the-art 12B model with 128k context length, built by Mistral AI in collaboration with NVIDIA."),
'mistral-large': _("Mistral Large 2 is Mistral's new flagship model that is significantly more capable in code generation, mathematics, and reasoning with 128k context window and support for dozens of languages."),
'qwen2': _("Qwen2 is a new series of large language models from Alibaba group"),
'deepseek-coder-v2': _("An open-source Mixture-of-Experts code language model that achieves performance comparable to GPT4-Turbo in code-specific tasks."),
'phi3': _("Phi-3 is a family of lightweight 3B (Mini) and 14B (Medium) state-of-the-art open models by Microsoft."),
'mistral': _("The 7B model released by Mistral AI, updated to version 0.3."),
'mixtral': _("A set of Mixture of Experts (MoE) model with open weights by Mistral AI in 8x7b and 8x22b parameter sizes."),
'codegemma': _("CodeGemma is a collection of powerful, lightweight models that can perform a variety of coding tasks like fill-in-the-middle code completion, code generation, natural language understanding, mathematical reasoning, and instruction following."),
'command-r': _("Command R is a Large Language Model optimized for conversational interaction and long context tasks."),
'command-r-plus': _("Command R+ is a powerful, scalable large language model purpose-built to excel at real-world enterprise use cases."),
'llava': _("🌋 LLaVA is a novel end-to-end trained large multimodal model that combines a vision encoder and Vicuna for general-purpose visual and language understanding. Updated to version 1.6."),
'llama3': _("Meta Llama 3: The most capable openly available LLM to date"),
'gemma': _("Gemma is a family of lightweight, state-of-the-art open models built by Google DeepMind. Updated to version 1.1"),
'qwen': _("Qwen 1.5 is a series of large language models by Alibaba Cloud spanning from 0.5B to 110B parameters"),
'llama2': _("Llama 2 is a collection of foundation language models ranging from 7B to 70B parameters."),
'codellama': _("A large language model that can use text prompts to generate and discuss code."),
'nomic-embed-text': _("A high-performing open embedding model with a large token context window."),
'dolphin-mixtral': _("Uncensored, 8x7b and 8x22b fine-tuned models based on the Mixtral mixture of experts models that excels at coding tasks. Created by Eric Hartford."),
'phi': _("Phi-2: a 2.7B language model by Microsoft Research that demonstrates outstanding reasoning and language understanding capabilities."),
'llama2-uncensored': _("Uncensored Llama 2 model by George Sung and Jarrad Hope."),
'deepseek-coder': _("DeepSeek Coder is a capable coding model trained on two trillion code and natural language tokens."),
'mxbai-embed-large': _("State-of-the-art large embedding model from mixedbread.ai"),
'zephyr': _("Zephyr is a series of fine-tuned versions of the Mistral and Mixtral models that are trained to act as helpful assistants."),
'dolphin-mistral': _("The uncensored Dolphin model based on Mistral that excels at coding tasks. Updated to version 2.8."),
'starcoder2': _("StarCoder2 is the next generation of transparently trained open code LLMs that comes in three sizes: 3B, 7B and 15B parameters."),
'orca-mini': _("A general-purpose model ranging from 3 billion parameters to 70 billion, suitable for entry-level hardware."),
'dolphin-llama3': _("Dolphin 2.9 is a new model with 8B and 70B sizes by Eric Hartford based on Llama 3 that has a variety of instruction, conversational, and coding skills."),
'yi': _("Yi 1.5 is a high-performing, bilingual language model."),
'mistral-openorca': _("Mistral OpenOrca is a 7 billion parameter model, fine-tuned on top of the Mistral 7B model using the OpenOrca dataset."),
'llava-llama3': _("A LLaVA model fine-tuned from Llama 3 Instruct with better scores in several benchmarks."),
'starcoder': _("StarCoder is a code generation model trained on 80+ programming languages."),
'llama2-chinese': _("Llama 2 based model fine tuned to improve Chinese dialogue ability."),
'vicuna': _("General use chat model based on Llama and Llama 2 with 2K to 16K context sizes."),
'tinyllama': _("The TinyLlama project is an open endeavor to train a compact 1.1B Llama model on 3 trillion tokens."),
'codestral': _("Codestral is Mistral AIs first-ever code model designed for code generation tasks."),
'wizard-vicuna-uncensored': _("Wizard Vicuna Uncensored is a 7B, 13B, and 30B parameter model based on Llama 2 uncensored by Eric Hartford."),
'nous-hermes2': _("The powerful family of models by Nous Research that excels at scientific discussion and coding tasks."),
'openchat': _("A family of open-source models trained on a wide variety of data, surpassing ChatGPT on various benchmarks. Updated to version 3.5-0106."),
'aya': _("Aya 23, released by Cohere, is a new family of state-of-the-art, multilingual models that support 23 languages."),
'wizardlm2': _("State of the art large language model from Microsoft AI with improved performance on complex chat, multilingual, reasoning and agent use cases."),
'tinydolphin': _("An experimental 1.1B parameter model trained on the new Dolphin 2.8 dataset by Eric Hartford and based on TinyLlama."),
'granite-code': _("A family of open foundation models by IBM for Code Intelligence"),
'wizardcoder': _("State-of-the-art code generation model"),
'stable-code': _("Stable Code 3B is a coding model with instruct and code completion variants on par with models such as Code Llama 7B that are 2.5x larger."),
'openhermes': _("OpenHermes 2.5 is a 7B model fine-tuned by Teknium on Mistral with fully open datasets."),
'all-minilm': _("Embedding models on very large sentence level datasets."),
'codeqwen': _("CodeQwen1.5 is a large language model pretrained on a large amount of code data."),
'stablelm2': _("Stable LM 2 is a state-of-the-art 1.6B and 12B parameter language model trained on multilingual data in English, Spanish, German, Italian, French, Portuguese, and Dutch."),
'wizard-math': _("Model focused on math and logic problems"),
'neural-chat': _("A fine-tuned model based on Mistral with good coverage of domain and language."),
'llama3-gradient': _("This model extends LLama-3 8B's context length from 8k to over 1m tokens."),
'phind-codellama': _("Code generation model based on Code Llama."),
'nous-hermes': _("General use models based on Llama and Llama 2 from Nous Research."),
'dolphincoder': _("A 7B and 15B uncensored variant of the Dolphin model family that excels at coding, based on StarCoder2."),
'sqlcoder': _("SQLCoder is a code completion model fined-tuned on StarCoder for SQL generation tasks"),
'xwinlm': _("Conversational model based on Llama 2 that performs competitively on various benchmarks."),
'deepseek-llm': _("An advanced language model crafted with 2 trillion bilingual tokens."),
'yarn-llama2': _("An extension of Llama 2 that supports a context of up to 128k tokens."),
'llama3-chatqa': _("A model from NVIDIA based on Llama 3 that excels at conversational question answering (QA) and retrieval-augmented generation (RAG)."),
'wizardlm': _("General use model based on Llama 2."),
'starling-lm': _("Starling is a large language model trained by reinforcement learning from AI feedback focused on improving chatbot helpfulness."),
'codegeex4': _("A versatile model for AI software development scenarios, including code completion."),
'snowflake-arctic-embed': _("A suite of text embedding models by Snowflake, optimized for performance."),
'orca2': _("Orca 2 is built by Microsoft research, and are a fine-tuned version of Meta's Llama 2 models. The model is designed to excel particularly in reasoning."),
'solar': _("A compact, yet powerful 10.7B large language model designed for single-turn conversation."),
'samantha-mistral': _("A companion assistant trained in philosophy, psychology, and personal relationships. Based on Mistral."),
'moondream': _("moondream2 is a small vision language model designed to run efficiently on edge devices."),
'smollm': _("🪐 A family of small models with 135M, 360M, and 1.7B parameters, trained on a new high-quality dataset."),
'stable-beluga': _("🪐 A family of small models with 135M, 360M, and 1.7B parameters, trained on a new high-quality dataset."),
'qwen2-math': _("Qwen2 Math is a series of specialized math language models built upon the Qwen2 LLMs, which significantly outperforms the mathematical capabilities of open-source models and even closed-source models (e.g., GPT4o)."),
'dolphin-phi': _("2.7B uncensored Dolphin model by Eric Hartford, based on the Phi language model by Microsoft Research."),
'deepseek-v2': _("A strong, economical, and efficient Mixture-of-Experts language model."),
'bakllava': _("BakLLaVA is a multimodal model consisting of the Mistral 7B base model augmented with the LLaVA architecture."),
'glm4': _("A strong multi-lingual general language model with competitive performance to Llama 3."),
'wizardlm-uncensored': _("Uncensored version of Wizard LM model"),
'yarn-mistral': _("An extension of Mistral to support context windows of 64K or 128K."),
'phi3.5': _("A lightweight AI model with 3.8 billion parameters with performance overtaking similarly and larger sized models."),
'medllama2': _("Fine-tuned Llama 2 model to answer medical questions based on an open source medical dataset."),
'llama-pro': _("An expansion of Llama 2 that specializes in integrating both general language understanding and domain-specific knowledge, particularly in programming and mathematics."),
'llava-phi3': _("A new small LLaVA model fine-tuned from Phi 3 Mini."),
'meditron': _("Open-source medical large language model adapted from Llama 2 to the medical domain."),
'nous-hermes2-mixtral': _("The Nous Hermes 2 model from Nous Research, now trained over Mixtral."),
'nexusraven': _("Nexus Raven is a 13B instruction tuned model for function calling tasks."),
'codeup': _("Great code generation model based on Llama2."),
'everythinglm': _("Uncensored Llama2 based model with support for a 16K context window."),
'hermes3': _("Hermes 3 is the latest version of the flagship Hermes series of LLMs by Nous Research"),
'internlm2': _("InternLM2.5 is a 7B parameter model tailored for practical scenarios with outstanding reasoning capability."),
'magicoder': _("🎩 Magicoder is a family of 7B parameter models trained on 75K synthetic instruction data using OSS-Instruct, a novel approach to enlightening LLMs with open-source code snippets."),
'stablelm-zephyr': _("A lightweight chat model allowing accurate, and responsive output without requiring high-end hardware."),
'codebooga': _("A high-performing code instruct model created by merging two existing code models."),
'mistrallite': _("MistralLite is a fine-tuned model based on Mistral with enhanced capabilities of processing long contexts."),
'llama3-groq-tool-use': _("A series of models from Groq that represent a significant advancement in open-source AI capabilities for tool use/function calling."),
'falcon2': _("Falcon2 is an 11B parameters causal decoder-only model built by TII and trained over 5T tokens."),
'wizard-vicuna': _("Wizard Vicuna is a 13B parameter model based on Llama 2 trained by MelodysDreamj."),
'duckdb-nsql': _("7B parameter text-to-SQL model made by MotherDuck and Numbers Station."),
'megadolphin': _("MegaDolphin-2.2-120b is a transformation of Dolphin-2.2-70b created by interleaving the model with itself."),
'notux': _("A top-performing mixture of experts model, fine-tuned with high-quality data."),
'goliath': _("A language model created by combining two fine-tuned Llama 2 70B models into one."),
'open-orca-platypus2': _("Merge of the Open Orca OpenChat model and the Garage-bAInd Platypus 2 model. Designed for chat and code generation."),
'notus': _("A 7B chat model fine-tuned with high-quality data and based on Zephyr."),
'dbrx': _("DBRX is an open, general-purpose LLM created by Databricks."),
'mathstral': _("MathΣtral: a 7B model designed for math reasoning and scientific discovery by Mistral AI."),
'bge-m3': _("BGE-M3 is a new model from BAAI distinguished for its versatility in Multi-Functionality, Multi-Linguality, and Multi-Granularity."),
'alfred': _("A robust conversational model designed to be used for both chat and instruct use cases."),
'firefunction-v2': _("An open weights function calling model based on Llama 3, competitive with GPT-4o function calling capabilities."),
'nuextract': _("A 3.8B model fine-tuned on a private high-quality synthetic dataset for information extraction, based on Phi-3."),
'bge-large': _("Embedding model from BAAI mapping texts to vectors."),
'paraphrase-multilingual': _("Sentence-transformers model that can be used for tasks like clustering or semantic search."),
}

View File

@@ -1,53 +1,137 @@
# connectionhandler.py
import json, requests
# connection_handler.py
"""
Handles requests to remote and integrated instances of Ollama
"""
import json, os, requests, subprocess, threading, shutil
from .internal import data_dir, cache_dir
from logging import getLogger
from time import sleep
url = None
logger = getLogger(__name__)
def simple_get(connection_url:str) -> dict:
try:
response = requests.get(connection_url)
if response.status_code == 200:
return {"status": "ok", "text": response.text, "status_code": response.status_code}
window = None
def log_output(pipe):
with open(os.path.join(data_dir, 'tmp.log'), 'a') as f:
with pipe:
try:
for line in iter(pipe.readline, ''):
print(line, end='')
f.write(line)
f.flush()
except:
pass
class instance():
def __init__(self, local_port:int, remote_url:str, remote:bool, tweaks:dict, overrides:dict, bearer_token:str, idle_timer_delay:int):
self.local_port=local_port
self.remote_url=remote_url
self.remote=remote
self.tweaks=tweaks
self.overrides=overrides
self.bearer_token=bearer_token
self.idle_timer_delay=idle_timer_delay
self.idle_timer_stop_event=threading.Event()
self.idle_timer=None
self.instance=None
self.busy=0
if not self.remote:
self.start()
def get_headers(self, include_json:bool) -> dict:
headers = {}
if include_json:
headers["Content-Type"] = "application/json"
if self.bearer_token and self.remote:
headers["Authorization"] = "Bearer " + self.bearer_token
return headers if len(headers.keys()) > 0 else None
def request(self, connection_type:str, connection_url:str, data:dict=None, callback:callable=None) -> requests.models.Response:
self.busy += 1
if self.idle_timer and not self.remote:
self.idle_timer_stop_event.set()
self.idle_timer=None
if not self.instance and not self.remote:
self.start()
connection_url = '{}/{}'.format(self.remote_url if self.remote else 'http://127.0.0.1:{}'.format(self.local_port), connection_url)
logger.info('{} : {}'.format(connection_type, connection_url))
response = None
match connection_type:
case "GET":
response = requests.get(connection_url, headers=self.get_headers(False))
case "POST":
if callback:
response = requests.post(connection_url, headers=self.get_headers(True), data=data, stream=True)
if response.status_code == 200:
for line in response.iter_lines():
if line:
callback(json.loads(line.decode("utf-8")))
else:
response = requests.post(connection_url, headers=self.get_headers(True), data=data, stream=False)
case "DELETE":
response = requests.delete(connection_url, headers=self.get_headers(False), data=data)
self.busy -= 1
if not self.idle_timer and not self.remote:
self.start_timer()
return response
def run_timer(self):
if not self.idle_timer_stop_event.wait(self.idle_timer_delay*60):
window.show_toast(_("Ollama instance was shut down due to inactivity"), window.main_overlay)
self.stop()
def start_timer(self):
if self.busy == 0:
if self.idle_timer:
self.idle_timer_stop_event.set()
self.idle_timer=None
if self.idle_timer_delay > 0 and self.busy == 0:
self.idle_timer_stop_event.clear()
self.idle_timer = threading.Thread(target=self.run_timer)
self.idle_timer.start()
def start(self):
if shutil.which('ollama'):
if not os.path.isdir(os.path.join(cache_dir, 'tmp/ollama')):
os.mkdir(os.path.join(cache_dir, 'tmp/ollama'))
self.instance = None
params = self.overrides.copy()
params["OLLAMA_DEBUG"] = "1"
params["OLLAMA_HOST"] = f"127.0.0.1:{self.local_port}" # You can't change this directly sorry :3
params["HOME"] = data_dir
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)
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()))
self.instance = instance
if not self.idle_timer:
self.start_timer()
else:
return {"status": "error", "status_code": response.status_code}
except Exception as e:
return {"status": "error", "status_code": 0}
self.remote = True
if not self.remote_url:
window.remote_connection_entry.set_text('http://0.0.0.0:11434')
window.remote_connection_switch.set_sensitive(True)
window.remote_connection_switch.set_active(True)
def simple_post(connection_url:str, data) -> dict:
try:
headers = {
"Content-Type": "application/json"
}
response = requests.post(connection_url, headers=headers, data=data, stream=False)
if response.status_code == 200:
return {"status": "ok", "text": response.text, "status_code": response.status_code}
else:
return {"status": "error", "status_code": response.status_code}
except Exception as e:
return {"status": "error", "status_code": 0}
def stop(self):
if self.idle_timer:
self.idle_timer_stop_event.set()
self.idle_timer=None
if self.instance:
logger.info("Stopping Alpaca's Ollama instance")
self.instance.terminate()
self.instance.wait()
self.instance = None
logger.info("Stopped Alpaca's Ollama instance")
def simple_delete(connection_url:str, data) -> dict:
try:
response = requests.delete(connection_url, json=data)
if response.status_code == 200:
return {"status": "ok", "status_code": response.status_code}
else:
return {"status": "error", "text": "Failed to delete", "status_code": response.status_code}
except Exception as e:
return {"status": "error", "status_code": 0}
def stream_post(connection_url:str, data, callback:callable) -> dict:
try:
headers = {
"Content-Type": "application/json"
}
response = requests.post(connection_url, headers=headers, data=data, stream=True)
if response.status_code == 200:
for line in response.iter_lines():
if line:
callback(json.loads(line.decode("utf-8")))
return {"status": "ok", "status_code": response.status_code}
else:
return {"status": "error", "status_code": response.status_code}
except Exception as e:
return {"status": "error", "status_code": 0}
def reset(self):
logger.info("Resetting Alpaca's Ollama instance")
self.stop()
sleep(1)
self.start()

View File

@@ -0,0 +1,446 @@
#chat_widget.py
"""
Handles the chat widget (testing)
"""
import gi
gi.require_version('Gtk', '4.0')
gi.require_version('GtkSource', '5')
from gi.repository import Gtk, Gio, Adw, Gdk
import logging, os, datetime, shutil, random, tempfile, tarfile, json
from ..internal import data_dir
from .message_widget import message
logger = logging.getLogger(__name__)
window = None
possible_prompts = [
"What can you do?",
"Give me a pancake recipe",
"Why is the sky blue?",
"Can you tell me a joke?",
"Give me a healthy breakfast recipe",
"How to make a pizza",
"Can you write a poem?",
"Can you write a story?",
"What is GNU-Linux?",
"Which is the best Linux distro?",
"Why is Pluto not a planet?",
"What is a black-hole?",
"Tell me how to stay fit",
"Write a conversation between sun and Earth",
"Why is the grass green?",
"Write an Haïku about AI",
"What is the meaning of life?",
"Explain quantum physics in simple terms",
"Explain the theory of relativity",
"Explain how photosynthesis works",
"Recommend a film about nature",
"What is nostalgia?"
]
class chat(Gtk.ScrolledWindow):
__gtype_name__ = 'AlpacaChat'
def __init__(self, name:str):
self.container = Gtk.Box(
orientation=1,
hexpand=True,
vexpand=True,
spacing=12,
margin_top=12,
margin_bottom=12,
margin_start=12,
margin_end=12
)
self.clamp = Adw.Clamp(
maximum_size=1000,
tightening_threshold=800,
child=self.container
)
super().__init__(
child=self.clamp,
propagate_natural_height=True,
kinetic_scrolling=True,
vexpand=True,
hexpand=True,
css_classes=["undershoot-bottom"],
name=name
)
self.messages = {}
self.welcome_screen = None
self.regenerate_button = None
self.busy = False
self.get_vadjustment().connect('notify::page-size', lambda va, *_: va.set_value(va.get_upper() - va.get_page_size()) if va.get_value() == 0 else None)
def stop_message(self):
self.busy = False
window.switch_send_stop_button(True)
def clear_chat(self):
if self.busy:
self.stop_message()
self.message = {}
self.stop_message()
for widget in list(self.container):
self.container.remove(widget)
def add_message(self, message_id:str, model:str=None):
msg = message(message_id, model)
self.messages[message_id] = msg
self.container.append(msg)
def send_sample_prompt(self, prompt):
buffer = window.message_text_view.get_buffer()
buffer.delete(buffer.get_start_iter(), buffer.get_end_iter())
buffer.insert(buffer.get_start_iter(), prompt, len(prompt.encode('utf-8')))
window.send_message()
def show_welcome_screen(self, show_prompts:bool):
if self.welcome_screen:
self.container.remove(self.welcome_screen)
self.welcome_screen = None
self.clear_chat()
button_container = Gtk.Box(
orientation=1,
spacing=10,
halign=3
)
if show_prompts:
for prompt in random.sample(possible_prompts, 3):
prompt_button = Gtk.Button(
label=prompt,
tooltip_text=_("Send prompt: '{}'").format(prompt)
)
prompt_button.connect('clicked', lambda *_, prompt=prompt : self.send_sample_prompt(prompt))
button_container.append(prompt_button)
else:
button = Gtk.Button(
label=_("Open Model Manager"),
tooltip_text=_("Open Model Manager"),
css_classes=["suggested-action", "pill"]
)
button.connect('clicked', lambda *_ : window.manage_models_dialog.present(window))
button_container.append(button)
self.welcome_screen = Adw.StatusPage(
icon_name="com.jeffser.Alpaca",
title="Alpaca",
description=_("Try one of these prompts") if show_prompts else _("It looks like you don't have any models downloaded yet. Download models to get started!"),
child=button_container,
vexpand=True
)
self.container.append(self.welcome_screen)
def load_chat_messages(self, messages:dict):
if len(messages.keys()) > 0:
if self.welcome_screen:
self.container.remove(self.welcome_screen)
self.welcome_screen = None
for message_id, message_data in messages.items():
if message_data['content']:
self.add_message(message_id, message_data['model'] if message_data['role'] == 'assistant' else None)
message_element = self.messages[message_id]
if 'images' in message_data:
images=[]
for image in message_data['images']:
images.append(os.path.join(data_dir, "chats", self.get_name(), message_id, image))
message_element.add_images(images)
if 'files' in message_data:
files={}
for file_name, file_type in message_data['files'].items():
files[os.path.join(data_dir, "chats", self.get_name(), message_id, file_name)] = file_type
message_element.add_attachments(files)
message_element.set_text(message_data['content'])
message_element.add_footer(datetime.datetime.strptime(message_data['date'] + (":00" if message_data['date'].count(":") == 1 else ""), '%Y/%m/%d %H:%M:%S'))
else:
self.show_welcome_screen(len(window.model_manager.get_model_list()) > 0)
def messages_to_dict(self) -> dict:
messages_dict = {}
for message_id, message_element in self.messages.items():
if message_element.text and message_element.dt:
messages_dict[message_id] = {
'role': 'assistant' if message_element.bot else 'user',
'model': message_element.model,
'date': message_element.dt.strftime("%Y/%m/%d %H:%M:%S"),
'content': message_element.text
}
if message_element.image_c:
images = []
for file in message_element.image_c.files:
images.append(file.image_name)
messages_dict[message_id]['images'] = images
if message_element.attachment_c:
files = {}
for file in message_element.attachment_c.files:
files[file.file_name] = file.file_type
messages_dict[message_id]['files'] = files
return messages_dict
def show_regenerate_button(self, msg:message):
if self.regenerate_button:
self.remove(self.regenerate_button)
self.regenerate_button = Gtk.Button(
child=Adw.ButtonContent(
icon_name='update-symbolic',
label=_('Regenerate Response')
),
css_classes=["suggested-action"],
halign=3
)
self.regenerate_button.connect('clicked', lambda *_: msg.action_buttons.regenerate_message())
self.container.append(self.regenerate_button)
class chat_tab(Gtk.ListBoxRow):
__gtype_name__ = 'AlpacaChatTab'
def __init__(self, chat_window:chat):
self.chat_window=chat_window
self.spinner = Gtk.Spinner(
spinning=True,
visible=False
)
self.label = Gtk.Label(
label=self.chat_window.get_name(),
tooltip_text=self.chat_window.get_name(),
hexpand=True,
halign=0,
wrap=True,
ellipsize=3,
wrap_mode=2,
xalign=0
)
self.indicator = Gtk.Image.new_from_icon_name("chat-bubble-text-symbolic")
self.indicator.set_visible(False)
self.indicator.set_css_classes(['accent'])
container = Gtk.Box(
orientation=0,
spacing=5
)
container.append(self.label)
container.append(self.spinner)
container.append(self.indicator)
super().__init__(
css_classes = ["chat_row"],
height_request = 45,
child = container
)
self.gesture = Gtk.GestureClick(button=3)
self.gesture.connect("released", self.chat_click_handler)
self.add_controller(self.gesture)
def chat_click_handler(self, gesture, n_press, x, y):
chat_row = gesture.get_widget()
popover = Gtk.PopoverMenu(
menu_model=window.chat_right_click_menu,
has_arrow=False,
halign=1,
height_request=155
)
window.selected_chat_row = chat_row
position = Gdk.Rectangle()
position.x = x
position.y = y
popover.set_parent(chat_row.get_child())
popover.set_pointing_to(position)
popover.popup()
class chat_list(Gtk.ListBox):
__gtype_name__ = 'AlpacaChatList'
def __init__(self):
super().__init__(
selection_mode=1,
css_classes=["navigation-sidebar"]
)
self.connect("row-selected", lambda listbox, row: self.chat_changed(row))
self.tab_list = []
def update_welcome_screens(self, show_prompts:bool):
for tab in self.tab_list:
if tab.chat_window.welcome_screen:
tab.chat_window.show_welcome_screen(show_prompts)
def get_tab_by_name(self, chat_name:str) -> chat_tab:
for tab in self.tab_list:
if tab.chat_window.get_name() == chat_name:
return tab
def get_chat_by_name(self, chat_name:str) -> chat:
tab = self.get_tab_by_name(chat_name)
if tab:
return tab.chat_window
def get_current_chat(self) -> chat:
row = self.get_selected_row()
if row:
return self.get_selected_row().chat_window
def send_tab_to_top(self, tab:chat_tab):
self.unselect_all()
self.tab_list.remove(tab)
self.tab_list.insert(0, tab)
self.remove(tab)
self.prepend(tab)
self.select_row(tab)
def append_chat(self, chat_name:str) -> chat:
chat_name = window.generate_numbered_name(chat_name, [tab.chat_window.get_name() for tab in self.tab_list])
chat_window = chat(chat_name)
tab = chat_tab(chat_window)
self.append(tab)
self.tab_list.append(tab)
window.chat_stack.add_child(chat_window)
return chat_window
def prepend_chat(self, chat_name:str) -> chat:
chat_name = window.generate_numbered_name(chat_name, [tab.chat_window.get_name() for tab in self.tab_list])
chat_window = chat(chat_name)
tab = chat_tab(chat_window)
self.prepend(tab)
self.tab_list.insert(0, tab)
chat_window.show_welcome_screen(len(window.model_manager.get_model_list()) > 0)
window.chat_stack.add_child(chat_window)
window.chat_list_box.select_row(tab)
return chat_window
def new_chat(self):
window.save_history(self.prepend_chat(_("New Chat")))
def delete_chat(self, chat_name:str):
chat_tab = None
for c in self.tab_list:
if c.chat_window.get_name() == chat_name:
chat_tab = c
if chat_tab:
chat_tab.chat_window.stop_message()
window.chat_stack.remove(chat_tab.chat_window)
self.tab_list.remove(chat_tab)
self.remove(chat_tab)
if os.path.exists(os.path.join(data_dir, "chats", chat_name)):
shutil.rmtree(os.path.join(data_dir, "chats", chat_name))
if len(self.tab_list) == 0:
self.new_chat()
if not self.get_current_chat() or self.get_current_chat() == chat_tab.chat_window:
self.select_row(self.get_row_at_index(0))
window.save_history()
def rename_chat(self, old_chat_name:str, new_chat_name:str):
tab = self.get_tab_by_name(old_chat_name)
if tab:
new_chat_name = window.generate_numbered_name(new_chat_name, [tab.chat_window.get_name() for tab in self.tab_list])
tab.label.set_label(new_chat_name)
tab.label.set_tooltip_text(new_chat_name)
tab.chat_window.set_name(new_chat_name)
if os.path.exists(os.path.join(data_dir, "chats", old_chat_name)):
shutil.move(os.path.join(data_dir, "chats", old_chat_name), os.path.join(data_dir, "chats", new_chat_name))
window.save_history(tab.chat_window)
def duplicate_chat(self, chat_name:str):
new_chat_name = window.generate_numbered_name(_("Copy of {}").format(chat_name), [tab.chat_window.get_name() for tab in self.tab_list])
try:
shutil.copytree(os.path.join(data_dir, "chats", chat_name), os.path.join(data_dir, "chats", new_chat_name))
except Exception as e:
logger.error(e)
self.prepend_chat(new_chat_name)
created_chat = self.get_tab_by_name(new_chat_name).chat_window
created_chat.load_chat_messages(self.get_tab_by_name(chat_name).chat_window.messages_to_dict())
window.save_history(created_chat)
def on_replace_contents(self, file, result):
file.replace_contents_finish(result)
window.show_toast(_("Chat exported successfully"), window.main_overlay)
def on_export_chat(self, file_dialog, result, chat_name):
file = file_dialog.save_finish(result)
if not file:
return
json_data = json.dumps({chat_name: {"messages": self.get_chat_by_name(chat_name).messages_to_dict()}}, indent=4).encode("UTF-8")
with tempfile.TemporaryDirectory() as temp_dir:
json_path = os.path.join(temp_dir, "data.json")
with open(json_path, "wb") as json_file:
json_file.write(json_data)
tar_path = os.path.join(temp_dir, chat_name)
with tarfile.open(tar_path, "w") as tar:
tar.add(json_path, arcname="data.json")
directory = os.path.join(data_dir, "chats", chat_name)
if os.path.exists(directory) and os.path.isdir(directory):
tar.add(directory, arcname=os.path.basename(directory))
with open(tar_path, "rb") as tar:
tar_content = tar.read()
file.replace_contents_async(
tar_content,
etag=None,
make_backup=False,
flags=Gio.FileCreateFlags.NONE,
cancellable=None,
callback=self.on_replace_contents
)
def export_chat(self, chat_name:str):
logger.info("Exporting chat")
file_dialog = Gtk.FileDialog(initial_name=f"{chat_name}.tar")
file_dialog.save(parent=window, cancellable=None, callback=lambda file_dialog, result, chat_name=chat_name: self.on_export_chat(file_dialog, result, chat_name))
def on_chat_imported(self, file_dialog, result):
file = file_dialog.open_finish(result)
if not file:
return
stream = file.read(None)
data_stream = Gio.DataInputStream.new(stream)
tar_content = data_stream.read_bytes(1024 * 1024, None)
with tempfile.TemporaryDirectory() as temp_dir:
tar_filename = os.path.join(temp_dir, "imported_chat.tar")
with open(tar_filename, "wb") as tar_file:
tar_file.write(tar_content.get_data())
with tarfile.open(tar_filename, "r") as tar:
tar.extractall(path=temp_dir)
chat_name = None
chat_content = None
for member in tar.getmembers():
if member.name == "data.json":
json_filepath = os.path.join(temp_dir, member.name)
with open(json_filepath, "r", encoding="utf-8") as json_file:
data = json.load(json_file)
for chat_name, chat_content in data.items():
new_chat_name = window.generate_numbered_name(chat_name, [tab.chat_window.get_name() for tab in self.tab_list])
src_path = os.path.join(temp_dir, chat_name)
dest_path = os.path.join(data_dir, "chats", new_chat_name)
if os.path.exists(src_path) and os.path.isdir(src_path) and not os.path.exists(dest_path):
shutil.copytree(src_path, dest_path)
created_chat = self.prepend_chat(new_chat_name)
created_chat.load_chat_messages(chat_content['messages'])
window.save_history(created_chat)
window.show_toast(_("Chat imported successfully"), window.main_overlay)
def import_chat(self):
logger.info("Importing chat")
file_dialog = Gtk.FileDialog(default_filter=window.file_filter_tar)
file_dialog.open(window, None, self.on_chat_imported)
def chat_changed(self, row):
if row:
current_tab_i = next((i for i, t in enumerate(self.tab_list) if t.chat_window == window.chat_stack.get_visible_child()), -1)
if self.tab_list.index(row) != current_tab_i:
window.chat_stack.set_transition_type(4 if self.tab_list.index(row) > current_tab_i else 5)
window.chat_stack.set_visible_child(row.chat_window)
window.switch_send_stop_button(not row.chat_window.busy)
if len(row.chat_window.messages) > 0:
last_model_used = row.chat_window.messages[list(row.chat_window.messages)[-1]].model
window.model_manager.change_model(last_model_used)
if row.indicator.get_visible():
row.indicator.set_visible(False)

View File

@@ -0,0 +1,545 @@
#message_widget.py
"""
Handles the message widget (testing)
"""
import gi
gi.require_version('Gtk', '4.0')
gi.require_version('GtkSource', '5')
from gi.repository import Gtk, GObject, Gio, Adw, GtkSource, GLib, Gdk
import logging, os, datetime, re, shutil, threading, sys
from ..internal import config_dir, data_dir, cache_dir, source_dir
from .table_widget import TableWidget
logger = logging.getLogger(__name__)
window = None
class edit_text_block(Gtk.TextView):
__gtype_name__ = 'AlpacaEditTextBlock'
def __init__(self, text:str):
super().__init__(
hexpand=True,
halign=0,
margin_top=5,
margin_bottom=5,
margin_start=5,
margin_end=5,
css_classes=["view", "editing_message_textview"]
)
self.get_buffer().insert(self.get_buffer().get_start_iter(), text, len(text.encode('utf-8')))
enter_key_controller = Gtk.EventControllerKey.new()
enter_key_controller.connect("key-pressed", lambda controller, keyval, keycode, state: self.edit_message() if keyval==Gdk.KEY_Return and not (state & Gdk.ModifierType.SHIFT_MASK) else None)
self.add_controller(enter_key_controller)
def edit_message(self):
self.get_parent().get_parent().action_buttons.set_visible(True)
self.get_parent().get_parent().set_text(self.get_buffer().get_text(self.get_buffer().get_start_iter(), self.get_buffer().get_end_iter(), False))
self.get_parent().get_parent().add_footer(self.get_parent().get_parent().dt)
window.save_history(self.get_parent().get_parent().get_parent().get_parent().get_parent().get_parent())
self.get_parent().remove(self)
window.show_toast(_("Message edited successfully"), window.main_overlay)
return True
class text_block(Gtk.Label):
__gtype_name__ = 'AlpacaTextBlock'
def __init__(self, bot:bool):
super().__init__(
hexpand=True,
halign=0,
wrap=True,
wrap_mode=0,
xalign=0,
margin_top=5,
margin_start=5,
margin_end=5,
focusable=True,
selectable=True
)
self.update_property([4, 7], [_("Response message") if bot else _("User message"), False])
self.connect('notify::has-focus', lambda *_: None if self.has_focus() else self.remove_selection() )
def remove_selection(self):
self.set_selectable(False)
self.set_selectable(True)
def insert_at_end(self, text:str, markdown:bool):
if markdown:
self.set_markup(self.get_text() + text)
else:
self.set_text(self.get_text() + text)
self.update_property([1], [self.get_text()])
def clear_text(self):
self.buffer.delete(self.textbuffer.get_start_iter(), self.textbuffer.get_end_iter())
self.update_property([1], [""])
class code_block(Gtk.Box):
__gtype_name__ = 'AlpacaCodeBlock'
def __init__(self, text:str, language_name:str=None):
super().__init__(
css_classes=["card", "code_block"],
orientation=1,
overflow=1,
margin_start=5,
margin_end=5
)
self.language = None
if language_name:
self.language = GtkSource.LanguageManager.get_default().get_language(language_name)
if self.language:
self.buffer = GtkSource.Buffer.new_with_language(self.language)
else:
self.buffer = GtkSource.Buffer()
self.buffer.set_style_scheme(GtkSource.StyleSchemeManager.get_default().get_scheme('Adwaita-dark'))
self.source_view = GtkSource.View(
auto_indent=True, indent_width=4, buffer=self.buffer, show_line_numbers=True, editable=None,
top_margin=6, bottom_margin=6, left_margin=12, right_margin=12, css_classes=["code_block"]
)
self.source_view.update_property([4], [_("{}Code Block").format('{} '.format(self.language.get_name()) if self.language else "")])
title_box = Gtk.Box(margin_start=12, margin_top=3, margin_bottom=3, margin_end=3)
title_box.append(Gtk.Label(label=self.language.get_name() if self.language else _("Code Block"), hexpand=True, xalign=0))
copy_button = Gtk.Button(icon_name="edit-copy-symbolic", css_classes=["flat", "circular"], tooltip_text=_("Copy Message"))
copy_button.connect("clicked", lambda *_: self.on_copy())
title_box.append(copy_button)
self.append(title_box)
self.append(Gtk.Separator())
self.append(self.source_view)
self.buffer.set_text(text)
def on_copy(self):
logger.debug("Copying code")
clipboard = Gdk.Display().get_default().get_clipboard()
start = self.buffer.get_start_iter()
end = self.buffer.get_end_iter()
text = self.buffer.get_text(start, end, False)
clipboard.set(text)
window.show_toast(_("Code copied to the clipboard"), window.main_overlay)
class attachment(Gtk.Button):
__gtype_name__ = 'AlpacaAttachment'
def __init__(self, file_name:str, file_path:str, file_type:str):
self.file_name = file_name
self.file_path = file_path
self.file_type = file_type
directory, file_name = os.path.split(self.file_path)
head, last_dir = os.path.split(directory)
head, second_last_dir = os.path.split(head)
self.file_path = os.path.join(head, '{selected_chat}', last_dir, file_name)
button_content = Adw.ButtonContent(
label=self.file_name,
icon_name={
"plain_text": "document-text-symbolic",
"pdf": "document-text-symbolic",
"youtube": "play-symbolic",
"website": "globe-symbolic"
}[self.file_type]
)
super().__init__(
vexpand=False,
valign=3,
name=self.file_name,
css_classes=["flat"],
tooltip_text=self.file_name,
child=button_content
)
self.connect("clicked", lambda button, file_path=self.file_path, file_type=self.file_type: window.preview_file(file_path, file_type, None))
class attachment_container(Gtk.ScrolledWindow):
__gtype_name__ = 'AlpacaAttachmentContainer'
def __init__(self):
self.files = []
self.container = Gtk.Box(
orientation=0,
spacing=12
)
super().__init__(
margin_top=10,
margin_start=10,
margin_end=10,
hexpand=True,
child=self.container
)
def add_file(self, file:attachment):
self.container.append(file)
self.files.append(file)
class image(Gtk.Button):
__gtype_name__ = 'AlpacaImage'
def __init__(self, image_path:str):
self.image_path = image_path
self.image_name = os.path.basename(self.image_path)
directory, file_name = os.path.split(self.image_path)
head, last_dir = os.path.split(directory)
head, second_last_dir = os.path.split(head)
try:
if not os.path.isfile(self.image_path):
raise FileNotFoundError("'{}' was not found or is a directory".format(self.image_path))
image = Gtk.Image.new_from_file(self.image_path)
image.set_size_request(240, 240)
super().__init__(
child=image,
css_classes=["flat", "chat_image_button"],
name=self.image_name,
tooltip_text=_("Image")
)
image.update_property([4], [_("Image")])
except Exception as e:
logger.error(e)
image_texture = Gtk.Image.new_from_icon_name("image-missing-symbolic")
image_texture.set_icon_size(2)
image_texture.set_vexpand(True)
image_texture.set_pixel_size(120)
image_label = Gtk.Label(
label=_("Missing Image"),
)
image_box = Gtk.Box(
spacing=10,
orientation=1,
margin_top=10,
margin_bottom=10,
margin_start=10,
margin_end=10
)
image_box.append(image_texture)
image_box.append(image_label)
image_box.set_size_request(220, 220)
super().__init__(
child=image_box,
css_classes=["flat", "chat_image_button"],
tooltip_text=_("Missing Image")
)
image_texture.update_property([4], [_("Missing image")])
self.connect("clicked", lambda button, file_path=os.path.join(head, '{selected_chat}', last_dir, file_name): window.preview_file(file_path, 'image', None))
class image_container(Gtk.ScrolledWindow):
__gtype_name__ = 'AlpacaImageContainer'
def __init__(self):
self.files = []
self.container = Gtk.Box(
orientation=0,
spacing=12
)
super().__init__(
margin_top=10,
margin_start=10,
margin_end=10,
hexpand=True,
height_request = 240,
child=self.container
)
def add_image(self, img:image):
self.container.append(img)
self.files.append(img)
class footer(Gtk.Label):
__gtype_name__ = 'AlpacaMessageFooter'
def __init__(self, dt:datetime.datetime, model:str=None):
super().__init__(
hexpand=False,
halign=0,
wrap=True,
ellipsize=3,
wrap_mode=2,
xalign=0,
margin_bottom=5,
margin_start=5,
focusable=True
)
self.set_markup("<small>{}{}</small>".format((window.convert_model_name(model, 0) + "") if model else "", GLib.markup_escape_text(self.format_datetime(dt))))
def format_datetime(self, dt:datetime) -> str:
date = GLib.DateTime.new(GLib.DateTime.new_now_local().get_timezone(), dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second)
current_date = GLib.DateTime.new_now_local()
if date.format("%Y/%m/%d") == current_date.format("%Y/%m/%d"):
return date.format("%H:%M %p")
if date.format("%Y") == current_date.format("%Y"):
return date.format("%b %d, %H:%M %p")
return date.format("%b %d %Y, %H:%M %p")
class action_buttons(Gtk.Box):
__gtype_name__ = 'AlpacaActionButtonContainer'
def __init__(self, bot:bool):
super().__init__(
orientation=0,
spacing=6,
margin_end=6,
margin_bottom=6,
valign="end",
halign="end"
)
self.delete_button = Gtk.Button(
icon_name = "user-trash-symbolic",
css_classes = ["flat", "circular"],
tooltip_text = _("Remove Message")
)
self.delete_button.connect('clicked', lambda *_: self.delete_message())
self.append(self.delete_button)
self.copy_button = Gtk.Button(
icon_name = "edit-copy-symbolic",
css_classes = ["flat", "circular"],
tooltip_text = _("Copy Message")
)
self.copy_button.connect('clicked', lambda *_: self.copy_message())
self.append(self.copy_button)
self.regenerate_button = Gtk.Button(
icon_name = "update-symbolic",
css_classes = ["flat", "circular"],
tooltip_text = _("Regenerate Message")
)
self.regenerate_button.connect('clicked', lambda *_: self.regenerate_message())
self.edit_button = Gtk.Button(
icon_name = "edit-symbolic",
css_classes = ["flat", "circular"],
tooltip_text = _("Edit Message")
)
self.edit_button.connect('clicked', lambda *_: self.edit_message())
self.append(self.regenerate_button if bot else self.edit_button)
def delete_message(self):
logger.debug("Deleting message")
chat = self.get_parent().get_parent().get_parent().get_parent().get_parent()
message_id = self.get_parent().message_id
self.get_parent().get_parent().remove(self.get_parent())
if os.path.exists(os.path.join(data_dir, "chats", window.chat_list_box.get_current_chat().get_name(), self.get_parent().message_id)):
shutil.rmtree(os.path.join(data_dir, "chats", window.chat_list_box.get_current_chat().get_name(), self.get_parent().message_id))
del chat.messages[message_id]
window.save_history(chat)
if len(chat.messages) == 0:
chat.show_welcome_screen(len(window.model_manager.get_model_list()) > 0)
def copy_message(self):
logger.debug("Copying message")
clipboard = Gdk.Display().get_default().get_clipboard()
clipboard.set(self.get_parent().text)
window.show_toast(_("Message copied to the clipboard"), window.main_overlay)
def regenerate_message(self):
chat = self.get_parent().get_parent().get_parent().get_parent().get_parent()
message_element = self.get_parent()
if not chat.busy:
message_element.set_text()
if message_element.footer:
message_element.container.remove(message_element.footer)
message_element.remove_overlay(self)
message_element.action_buttons = None
history = window.convert_history_to_ollama(chat)[:list(chat.messages).index(message_element.message_id)]
data = {
"model": window.model_manager.get_selected_model(),
"messages": history,
"options": {"temperature": window.ollama_instance.tweaks["temperature"], "seed": window.ollama_instance.tweaks["seed"]},
"keep_alive": f"{window.ollama_instance.tweaks['keep_alive']}m"
}
thread = threading.Thread(target=window.run_message, args=(data, message_element, chat))
thread.start()
else:
window.show_toast(_("Message cannot be regenerated while receiving a response"), window.main_overlay)
def edit_message(self):
logger.debug("Editing message")
self.get_parent().action_buttons.set_visible(False)
for child in self.get_parent().content_children:
self.get_parent().container.remove(child)
self.get_parent().content_children = []
self.get_parent().container.remove(self.get_parent().footer)
self.get_parent().footer = None
edit_text_b = edit_text_block(self.get_parent().text)
self.get_parent().container.append(edit_text_b)
window.set_focus(edit_text_b)
class message(Gtk.Overlay):
__gtype_name__ = 'AlpacaMessage'
def __init__(self, message_id:str, model:str=None):
self.message_id = message_id
self.bot = model != None
self.dt = None
self.model = model
self.action_buttons = None
self.content_children = [] #These are the code blocks, text blocks and tables
self.footer = None
self.image_c = None
self.attachment_c = None
self.spinner = None
self.text = None
self.container = Gtk.Box(
orientation=1,
halign='fill',
css_classes=["response_message"] if self.bot else ["card", "user_message"],
spacing=12
)
super().__init__(css_classes=["message"], name=message_id)
self.set_child(self.container)
def add_attachments(self, attachments:dict):
self.attachment_c = attachment_container()
self.container.append(self.attachment_c)
for file_path, file_type in attachments.items():
file = attachment(os.path.basename(file_path), file_path, file_type)
self.attachment_c.add_file(file)
def add_images(self, images:list):
self.image_c = image_container()
self.container.append(self.image_c)
for image_path in images:
image_element = image(image_path)
self.image_c.add_image(image_element)
def add_footer(self, dt:datetime.datetime):
self.dt = dt
self.footer = footer(self.dt, self.model)
self.container.append(self.footer)
def add_action_buttons(self):
if not self.action_buttons:
self.action_buttons = action_buttons(self.bot)
self.add_overlay(self.action_buttons)
def update_message(self, data:dict):
chat = self.get_parent().get_parent().get_parent().get_parent()
if chat.busy:
vadjustment = chat.get_vadjustment()
if self.spinner:
self.container.remove(self.spinner)
self.spinner = None
self.content_children[-1].set_visible(True)
GLib.idle_add(vadjustment.set_value, vadjustment.get_upper())
elif vadjustment.get_value() + 50 >= vadjustment.get_upper() - vadjustment.get_page_size():
GLib.idle_add(vadjustment.set_value, vadjustment.get_upper() - vadjustment.get_page_size())
self.content_children[-1].insert_at_end(data['message']['content'], False)
if 'done' in data and data['done']:
window.chat_list_box.get_tab_by_name(chat.get_name()).spinner.set_visible(False)
if window.chat_list_box.get_current_chat().get_name() != chat.get_name():
window.chat_list_box.get_tab_by_name(chat.get_name()).indicator.set_visible(True)
if chat.welcome_screen:
chat.container.remove(chat.welcome_screen)
chat.welcome_screen = None
chat.stop_message()
self.set_text(self.content_children[-1].get_label())
self.dt = datetime.datetime.now()
self.add_footer(self.dt)
window.show_notification(chat.get_name(), self.text[:200] + (self.text[200:] and '...'), Gio.ThemedIcon.new("chat-message-new-symbolic"))
window.save_history(chat)
else:
sys.exit()
def set_text(self, text:str=None):
self.text = text
for child in self.content_children:
self.container.remove(child)
self.content_children = []
if text:
self.content_children = []
code_block_pattern = re.compile(r'```(\w+)\n(.*?)\n```', re.DOTALL)
no_lang_code_block_pattern = re.compile(r'`\n(.*?)\n`', re.DOTALL)
table_pattern = re.compile(r'((\r?\n){2}|^)([^\r\n]*\|[^\r\n]*(\r?\n)?)+(?=(\r?\n){2}|$)', re.MULTILINE)
bold_pattern = re.compile(r'\*\*(.*?)\*\*') #"**text**"
code_pattern = re.compile(r'`([^`\n]*?)`') #"`text`"
h1_pattern = re.compile(r'^#\s(.*)$') #"# text"
h2_pattern = re.compile(r'^##\s(.*)$') #"## text"
markup_pattern = re.compile(r'<(b|u|tt|span.*)>(.*?)<\/(b|u|tt|span)>') #heh butt span, I'm so funny
parts = []
pos = 0
# Code blocks
for match in code_block_pattern.finditer(self.text):
start, end = match.span()
if pos < start:
normal_text = self.text[pos:start]
parts.append({"type": "normal", "text": normal_text.strip()})
language = match.group(1)
code_text = match.group(2)
parts.append({"type": "code", "text": code_text, "language": 'python3' if language == 'python' else language})
pos = end
# Code blocks (No language)
for match in no_lang_code_block_pattern.finditer(self.text):
start, end = match.span()
if pos < start:
normal_text = self.text[pos:start]
parts.append({"type": "normal", "text": normal_text.strip()})
code_text = match.group(1)
parts.append({"type": "code", "text": code_text, "language": None})
pos = end
# Tables
for match in table_pattern.finditer(self.text):
start, end = match.span()
if pos < start:
normal_text = self.text[pos:start]
parts.append({"type": "normal", "text": normal_text.strip()})
table_text = match.group(0)
parts.append({"type": "table", "text": table_text})
pos = end
# Text blocks
if pos < len(text):
normal_text = text[pos:]
if normal_text.strip():
parts.append({"type": "normal", "text": normal_text.strip()})
for part in parts:
if part['type'] == 'normal':
text_b = text_block(self.bot)
part['text'] = part['text'].replace("\n* ", "\n")
part['text'] = code_pattern.sub(r'<tt>\1</tt>', part['text'])
part['text'] = bold_pattern.sub(r'<b>\1</b>', part['text'])
part['text'] = h1_pattern.sub(r'<span size="x-large">\1</span>', part['text'])
part['text'] = h2_pattern.sub(r'<span size="large">\1</span>', part['text'])
pos = 0
for match in markup_pattern.finditer(part['text']):
start, end = match.span()
if pos < start:
text_b.insert_at_end(part['text'][pos:start], False)
text_b.insert_at_end(match.group(0), True)
pos = end
if pos < len(part['text']):
text_b.insert_at_end(part['text'][pos:], False)
self.content_children.append(text_b)
self.container.append(text_b)
elif part['type'] == 'code':
code_b = code_block(part['text'], part['language'])
self.content_children.append(code_b)
self.container.append(code_b)
elif part['type'] == 'table':
table_w = TableWidget(part['text'])
self.content_children.append(table_w)
self.container.append(table_w)
self.add_action_buttons()
else:
text_b = text_block(self.bot)
text_b.set_visible(False)
self.content_children.append(text_b)
self.spinner = Gtk.Spinner(spinning=True, margin_top=12, margin_bottom=12, hexpand=True)
self.container.append(self.spinner)
self.container.append(text_b)
self.container.queue_draw()

View File

@@ -0,0 +1,532 @@
#model_widget.py
"""
Handles the model widget (testing)
"""
import gi
gi.require_version('Gtk', '4.0')
gi.require_version('GtkSource', '5')
from gi.repository import Gtk, GObject, Gio, Adw, GtkSource, GLib, Gdk
import logging, os, datetime, re, shutil, threading, json, sys
from ..internal import config_dir, data_dir, cache_dir, source_dir
from .. import available_models_descriptions, dialogs
logger = logging.getLogger(__name__)
window = None
class model_selector_popup(Gtk.Popover):
__gtype_name__ = 'AlpacaModelSelectorPopup'
def __init__(self):
manage_models_button = Gtk.Button(
tooltip_text=_('Manage Models'),
child=Gtk.Label(label=_('Manage Models'), halign=1),
hexpand=True,
css_classes=['manage_models_button', 'flat']
)
manage_models_button.set_action_name("app.manage_models")
manage_models_button.connect("clicked", lambda *_: self.hide())
self.model_list_box = Gtk.ListBox(
css_classes=['navigation-sidebar', 'model_list_box'],
height_request=0
)
container = Gtk.Box(
orientation=1,
spacing=5
)
container.append(self.model_list_box)
container.append(Gtk.Separator())
container.append(manage_models_button)
scroller = Gtk.ScrolledWindow(
max_content_height=300,
propagate_natural_width=True,
propagate_natural_height=True,
child=container
)
super().__init__(
css_classes=['model_popover'],
has_arrow=False,
child=scroller
)
class model_selector_button(Gtk.MenuButton):
__gtype_name__ = 'AlpacaModelSelectorButton'
def __init__(self):
self.popover = model_selector_popup()
self.popover.model_list_box.connect('selected-rows-changed', self.model_changed)
self.popover.model_list_box.connect('row-activated', lambda *_: self.get_popover().hide())
container = Gtk.Box(
orientation=0,
spacing=5
)
self.label = Gtk.Label(label=_('Select a Model'))
container.append(self.label)
container.append(Gtk.Image.new_from_icon_name("down-symbolic"))
super().__init__(
tooltip_text=_('Select a Model'),
child=container,
popover=self.popover
)
def change_model(self, model_name:str):
for model_row in list(self.get_popover().model_list_box):
if model_name == model_row.get_name():
self.get_popover().model_list_box.select_row(model_row)
break
def model_changed(self, listbox:Gtk.ListBox):
row = listbox.get_selected_row()
if row:
model_name = row.get_name()
self.label.set_label(window.convert_model_name(model_name, 0))
self.set_tooltip_text(window.convert_model_name(model_name, 0))
elif len(list(listbox)) == 0:
self.label.set_label(_("Select a Model"))
self.set_tooltip_text(_("Select a Model"))
window.model_manager.verify_if_image_can_be_used()
def add_model(self, model_name:str):
model_row = Gtk.ListBoxRow(
child = Gtk.Label(
label=window.convert_model_name(model_name, 0),
halign=1,
hexpand=True
),
halign=0,
hexpand=True,
name=model_name,
tooltip_text=window.convert_model_name(model_name, 0)
)
self.get_popover().model_list_box.append(model_row)
self.change_model(model_name)
def remove_model(self, model_name:str):
self.get_popover().model_list_box.remove(next((model for model in list(self.get_popover().model_list_box) if model.get_name() == model_name), None))
self.model_changed(self.get_popover().model_list_box)
def clear_list(self):
self.get_popover().model_list_box.remove_all()
class pulling_model(Gtk.ListBoxRow):
__gtype_name__ = 'AlpacaPullingModel'
def __init__(self, model_name:str):
model_label = Gtk.Label(
css_classes=["heading"],
label=model_name.split(":")[0].replace("-", " ").title(),
hexpand=True,
halign=1
)
tag_label = Gtk.Label(
css_classes=["subtitle"],
label=model_name.split(":")[1]
)
self.prc_label = Gtk.Label(
css_classes=["subtitle", "numeric"],
label='50%',
hexpand=True,
halign=2
)
subtitle_box = Gtk.Box(
hexpand=True,
spacing=5,
orientation=0
)
subtitle_box.append(tag_label)
subtitle_box.append(self.prc_label)
self.progress_bar = Gtk.ProgressBar(
valign=2,
show_text=False,
css_classes=["horizontal"],
fraction=.5
)
description_box = Gtk.Box(
hexpand=True,
vexpand=True,
spacing=5,
orientation=1
)
description_box.append(model_label)
description_box.append(subtitle_box)
description_box.append(self.progress_bar)
stop_button = Gtk.Button(
icon_name = "media-playback-stop-symbolic",
vexpand = False,
valign = 3,
css_classes = ["destructive-action", "circular"],
tooltip_text = _("Stop Pulling '{}'").format(window.convert_model_name(model_name, 0))
)
stop_button.connect('clicked', lambda *_: dialogs.stop_pull_model(window, self))
container_box = Gtk.Box(
hexpand=True,
vexpand=True,
spacing=10,
orientation=0,
margin_top=10,
margin_bottom=10,
margin_start=10,
margin_end=10
)
container_box.append(description_box)
container_box.append(stop_button)
super().__init__(
child=container_box,
name=model_name
)
self.error = None
def update(self, data):
if not self.get_parent():
sys.exit()
if 'error' in data:
self.error = data['error']
if 'total' in data and 'completed' in data:
fraction = round(data['completed'] / data['total'], 4)
GLib.idle_add(self.prc_label.set_label, f"{fraction:05.2%}")
GLib.idle_add(self.progress_bar.set_fraction, fraction)
else:
GLib.idle_add(self.prc_label.set_label, data['status'])
GLib.idle_add(self.progress_bar.pulse)
class pulling_model_list(Gtk.ListBox):
__gtype_name__ = 'AlpacaPullingModelList'
def __init__(self):
super().__init__(
selection_mode=0,
css_classes=["boxed-list"],
visible=False
)
class local_model(Gtk.ListBoxRow):
__gtype_name__ = 'AlpacaLocalModel'
def __init__(self, model_name:str):
model_title = window.convert_model_name(model_name, 0)
model_label = Gtk.Label(
css_classes=["heading"],
label=model_title.split(" (")[0],
hexpand=True,
halign=1
)
tag_label = Gtk.Label(
css_classes=["subtitle"],
label=model_title.split(" (")[1][:-1],
hexpand=True,
halign=1
)
description_box = Gtk.Box(
hexpand=True,
vexpand=True,
spacing=5,
orientation=1
)
description_box.append(model_label)
description_box.append(tag_label)
delete_button = Gtk.Button(
icon_name = "user-trash-symbolic",
vexpand = False,
valign = 3,
css_classes = ["destructive-action", "circular"],
tooltip_text = _("Remove '{}'").format(window.convert_model_name(model_name, 0))
)
delete_button.connect('clicked', lambda *_, model_name=model_name: dialogs.delete_model(window, model_name))
container_box = Gtk.Box(
hexpand=True,
vexpand=True,
spacing=10,
orientation=0,
margin_top=10,
margin_bottom=10,
margin_start=10,
margin_end=10
)
container_box.append(description_box)
container_box.append(delete_button)
super().__init__(
child=container_box,
name=model_name
)
class local_model_list(Gtk.ListBox):
__gtype_name__ = 'AlpacaLocalModelList'
def __init__(self):
super().__init__(
selection_mode=0,
css_classes=["boxed-list"],
visible=False
)
def add_model(self, model_name:str):
model = local_model(model_name)
self.append(model)
if not self.get_visible():
self.set_visible(True)
def remove_model(self, model_name:str):
self.remove(next((model for model in list(self) if model.get_name() == model_name), None))
class available_model(Gtk.ListBoxRow):
__gtype_name__ = 'AlpacaAvailableModel'
def __init__(self, model_name:str, model_author:str, model_description:str, image_recognition:bool):
self.model_description = model_description
self.model_title = model_name.replace("-", " ").title()
self.model_author = model_author
self.image_recognition = image_recognition
model_label = Gtk.Label(
css_classes=["heading"],
label="<b>{}</b> <small>by {}</small>".format(self.model_title, self.model_author),
hexpand=True,
halign=1,
use_markup=True
)
description_label = Gtk.Label(
css_classes=["subtitle"],
label=self.model_description,
hexpand=True,
halign=1,
wrap=True,
wrap_mode=0,
)
image_recognition_indicator = Gtk.Button(
css_classes=["success", "pill", "image_recognition_indicator"],
child=Gtk.Label(
label=_("Image Recognition"),
css_classes=["subtitle"]
),
halign=1
)
description_box = Gtk.Box(
hexpand=True,
vexpand=True,
spacing=5,
orientation=1
)
description_box.append(model_label)
description_box.append(description_label)
if self.image_recognition: description_box.append(image_recognition_indicator)
container_box = Gtk.Box(
hexpand=True,
vexpand=True,
spacing=10,
orientation=0,
margin_top=10,
margin_bottom=10,
margin_start=10,
margin_end=10
)
next_icon = Gtk.Image.new_from_icon_name("go-next")
next_icon.update_property([4], [_("Enter download menu for {}").format(self.model_title)])
container_box.append(description_box)
container_box.append(next_icon)
super().__init__(
child=container_box,
name=model_name
)
gesture_click = Gtk.GestureClick.new()
gesture_click.connect("pressed", lambda *_: self.show_pull_menu())
event_controller_key = Gtk.EventControllerKey.new()
event_controller_key.connect("key-pressed", lambda controller, key, *_: self.show_pull_menu() if key in (Gdk.KEY_space, Gdk.KEY_Return) else None)
self.add_controller(gesture_click)
self.add_controller(event_controller_key)
def confirm_pull_model(self, model_name):
threading.Thread(target=window.model_manager.pull_model, args=(model_name,)).start()
window.navigation_view_manage_models.pop()
def show_pull_menu(self):
with open(os.path.join(source_dir, 'available_models.json'), 'r', encoding="utf-8") as f:
data = json.load(f)
window.navigation_view_manage_models.push_by_tag('model_tags_page')
window.navigation_view_manage_models.find_page('model_tags_page').set_title(self.get_name().replace("-", " ").title())
window.model_link_button.set_name(data[self.get_name()]['url'])
window.model_link_button.set_tooltip_text(data[self.get_name()]['url'])
window.model_tag_list_box.remove_all()
tags = data[self.get_name()]['tags']
for tag_data in tags:
if f"{self.get_name()}:{tag_data[0]}" not in window.model_manager.get_model_list():
tag_row = Adw.ActionRow(
title = tag_data[0],
subtitle = tag_data[1],
name = f"{self.get_name()}:{tag_data[0]}"
)
download_icon = Gtk.Image.new_from_icon_name("folder-download-symbolic")
tag_row.add_suffix(download_icon)
download_icon.update_property([4], [_("Download {}:{}").format(self.get_name(), tag_data[0])])
gesture_click = Gtk.GestureClick.new()
gesture_click.connect("pressed", lambda *_, name=f"{self.get_name()}:{tag_data[0]}" : self.confirm_pull_model(name))
event_controller_key = Gtk.EventControllerKey.new()
event_controller_key.connect("key-pressed", lambda controller, key, *_, name=f"{self.get_name()}:{tag_data[0]}" : self.confirm_pull_model(name) if key in (Gdk.KEY_space, Gdk.KEY_Return) else None)
tag_row.add_controller(gesture_click)
tag_row.add_controller(event_controller_key)
window.model_tag_list_box.append(tag_row)
class available_model_list(Gtk.ListBox):
__gtype_name__ = 'AlpacaAvailableModelList'
def __init__(self):
super().__init__(
selection_mode=0,
css_classes=["boxed-list"],
visible=False
)
def add_model(self, model_name:str, model_author:str, model_description:str, image_recognition:bool):
model = available_model(model_name, model_author, model_description, image_recognition)
self.append(model)
if not self.get_visible():
self.set_visible(True)
class model_manager_container(Gtk.Box):
__gtype_name__ = 'AlpacaModelManagerContainer'
def __init__(self):
super().__init__(
margin_top=12,
margin_bottom=12,
margin_start=12,
margin_end=12,
spacing=12,
orientation=1
)
self.pulling_list = pulling_model_list()
self.append(self.pulling_list)
self.local_list = local_model_list()
self.append(self.local_list)
self.available_list = available_model_list()
self.append(self.available_list)
self.model_selector = model_selector_button()
window.header_bar.set_title_widget(self.model_selector)
def add_local_model(self, model_name:str):
self.local_list.add_model(model_name)
if not self.local_list.get_visible():
self.local_list.set_visible(True)
self.model_selector.add_model(model_name)
def remove_local_model(self, model_name:str):
logger.debug("Deleting model")
response = window.ollama_instance.request("DELETE", "api/delete", json.dumps({"name": model_name}))
if response.status_code == 200:
self.local_list.remove_model(model_name)
self.model_selector.remove_model(model_name)
if len(self.get_model_list()) == 0:
self.local_list.set_visible(False)
window.chat_list_box.update_welcome_screens(False)
window.show_toast(_("Model deleted successfully"), window.manage_models_overlay)
else:
window.manage_models_dialog.close()
window.connection_error()
def get_selected_model(self) -> str:
row = self.model_selector.get_popover().model_list_box.get_selected_row()
if row:
return row.get_name()
def get_model_list(self) -> list:
return [model.get_name() for model in list(self.model_selector.get_popover().model_list_box)]
#Should only be called when the app starts
def update_local_list(self):
try:
response = window.ollama_instance.request("GET", "api/tags")
if response.status_code == 200:
self.local_list.remove_all()
data = json.loads(response.text)
if len(data['models']) == 0:
self.local_list.set_visible(False)
else:
self.local_list.set_visible(True)
for model in data['models']:
self.add_local_model(model['name'])
else:
window.connection_error()
except Exception as e:
logger.error(e)
window.connection_error()
#Should only be called when the app starts
def update_available_list(self):
with open(os.path.join(source_dir, 'available_models.json'), 'r', encoding="utf-8") as f:
for name, model_info in json.load(f).items():
self.available_list.add_model(name, model_info['author'], available_models_descriptions.descriptions[name], model_info['image'])
def change_model(self, model_name:str):
self.model_selector.change_model(model_name)
def verify_if_image_can_be_used(self):
logger.debug("Verifying if image can be used")
selected = self.get_selected_model()
if selected == None:
return False
selected = selected.split(":")[0]
with open(os.path.join(source_dir, 'available_models.json'), 'r', encoding="utf-8") as f:
if selected in [key for key, value in json.load(f).items() if value["image"]]:
for name, content in window.attachments.items():
if content['type'] == 'image':
content['button'].set_css_classes(["flat"])
return True
for name, content in window.attachments.items():
if content['type'] == 'image':
content['button'].set_css_classes(["flat", "error"])
return False
def pull_model(self, model_name:str, modelfile:str=None):
if ':' not in model_name:
model_name += ':latest'
if model_name not in [model.get_name() for model in list(self.pulling_list)] and model_name not in [model.get_name() for model in list(self.local_list)]:
logger.info("Pulling model: {}".format(model_name))
model = pulling_model(model_name)
self.pulling_list.append(model)
if not self.pulling_list.get_visible():
GLib.idle_add(self.pulling_list.set_visible, True)
if modelfile:
response = window.ollama_instance.request("POST", "api/create", json.dumps({"name": model_name, "modelfile": modelfile}), lambda data: model.update(data))
else:
response = window.ollama_instance.request("POST", "api/pull", json.dumps({"name": model_name}), lambda data: model.update(data))
if response.status_code == 200 and not model.error:
GLib.idle_add(window.show_notification, _("Task Complete"), _("Model '{}' pulled successfully.").format(model_name), Gio.ThemedIcon.new("emblem-ok-symbolic"))
GLib.idle_add(window.show_toast, _("Model '{}' pulled successfully.").format(model_name), window.manage_models_overlay)
self.add_local_model(model_name)
elif response.status_code == 200:
GLib.idle_add(window.show_notification, _("Pull Model Error"), _("Failed to pull model '{}': {}").format(model_name, model.error), Gio.ThemedIcon.new("dialog-error-symbolic"))
GLib.idle_add(window.show_toast, _("Error pulling '{}': {}").format(model_name, model.error), window.manage_models_overlay)
else:
GLib.idle_add(window.show_notification, _("Pull Model Error"), _("Failed to pull model '{}' due to network error.").format(model_name), Gio.ThemedIcon.new("dialog-error-symbolic"))
GLib.idle_add(window.show_toast, _("Error pulling '{}'").format(model_name), window.manage_models_overlay)
GLib.idle_add(window.manage_models_dialog.close)
GLib.idle_add(window.connection_error)
self.pulling_list.remove(model)
GLib.idle_add(window.chat_list_box.update_welcome_screens, len(self.get_model_list()) > 0)
if len(list(self.pulling_list)) == 0:
GLib.idle_add(self.pulling_list.set_visible, False)

View File

@@ -0,0 +1,132 @@
#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.set_margin_start(5)
self.set_margin_end(5)
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)

View File

@@ -1,26 +1,34 @@
# dialogs.py
"""
Handles UI dialogs
"""
import os
import logging, requests, threading, shutil
from pytube import YouTube
from html2text import html2text
from gi.repository import Adw, Gtk
from .internal import cache_dir
from gi.repository import Adw, Gtk, Gdk, GLib, GtkSource, Gio, GdkPixbuf
from .available_models import available_models
logger = logging.getLogger(__name__)
# CLEAR CHAT | WORKS
def clear_chat_response(self, dialog, task):
if dialog.choose_finish(task) == "clear":
self.clear_chat()
self.chat_list_box.get_current_chat().clear_chat()
def clear_chat(self):
if self.bot_message is not None:
self.show_toast("info", 1, self.main_overlay)
self.show_toast(_("Chat cannot be cleared while receiving a message"), self.main_overlay)
return
dialog = Adw.AlertDialog(
heading=_("Clear Chat"),
heading=_("Clear Chat?"),
body=_("Are you sure you want to clear the chat?"),
close_response="cancel"
)
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,
@@ -31,17 +39,18 @@ def clear_chat(self):
def delete_chat_response(self, dialog, task, chat_name):
if dialog.choose_finish(task) == "delete":
self.delete_chat(chat_name)
self.chat_list_box.delete_chat(chat_name)
def delete_chat(self, chat_name):
dialog = Adw.AlertDialog(
heading=_("Delete Chat"),
heading=_("Delete Chat?"),
body=_("Are you sure you want to delete '{}'?").format(chat_name),
close_response="cancel"
)
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,
@@ -50,37 +59,39 @@ 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
def rename_chat_response(self, dialog, task, old_chat_name, entry):
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)
self.chat_list_box.rename_chat(old_chat_name, new_chat_name)
def rename_chat(self, label_element):
chat_name = label_element.get_parent().get_name()
def rename_chat(self, chat_name):
entry = Gtk.Entry()
dialog = Adw.AlertDialog(
heading=_("Rename Chat"),
heading=_("Rename Chat?"),
body=_("Renaming '{}'").format(chat_name),
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,
callback = lambda dialog, task, old_chat_name=chat_name, entry=entry, label_element=label_element: rename_chat_response(self, dialog, task, old_chat_name, entry, label_element)
callback = lambda dialog, task, old_chat_name=chat_name, entry=entry: rename_chat_response(self, dialog, task, old_chat_name, entry)
)
# NEW CHAT | WORKS | UNUSED REASON: The 'Add Chat' button now creates a chat without a name AKA "New Chat"
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)
@@ -88,15 +99,15 @@ def new_chat_response(self, dialog, task, entry):
def new_chat(self):
entry = Gtk.Entry()
dialog = Adw.AlertDialog(
heading=_("Create Chat"),
heading=_("Create Chat?"),
body=_("Enter name for new chat"),
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,
@@ -105,127 +116,122 @@ def new_chat(self):
# STOP PULL MODEL | WORKS
def stop_pull_model_response(self, dialog, task, model_name):
def stop_pull_model_response(self, dialog, task, pulling_model):
if dialog.choose_finish(task) == "stop":
self.stop_pull_model(model_name)
if len(list(pulling_model.get_parent())) == 1:
pulling_model.get_parent().set_visible(False)
pulling_model.get_parent().remove(pulling_model)
def stop_pull_model(self, model_name):
def stop_pull_model(self, pulling_model):
dialog = Adw.AlertDialog(
heading=_("Stop Model"),
body=_("Are you sure you want to stop pulling '{}'?").format(model_name),
heading=_("Stop Download?"),
body=_("Are you sure you want to stop pulling '{}'?").format(self.convert_model_name(pulling_model.get_name(), 0)),
close_response="cancel"
)
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,
callback = lambda dialog, task, model_name = model_name: stop_pull_model_response(self, dialog, task, model_name)
callback = lambda dialog, task, model=pulling_model: stop_pull_model_response(self, dialog, task, model)
)
# DELETE MODEL | WORKS
def delete_model_response(self, dialog, task, model_name):
if dialog.choose_finish(task) == "delete":
self.delete_model(model_name)
self.model_manager.remove_local_model(model_name)
def delete_model(self, model_name):
dialog = Adw.AlertDialog(
heading=_("Delete Model"),
body=_("Are you sure you want to delete '{}'?").format(model_name),
heading=_("Delete Model?"),
body=_("Are you sure you want to delete '{}'?").format(self.convert_model_name(model_name, 0)),
close_response="cancel"
)
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,
callback = lambda dialog, task, model_name = model_name: delete_model_response(self, dialog, task, model_name)
)
# PULL MODEL | WORKS
def pull_model_response(self, dialog, task, model_name, tag_drop_down):
if dialog.choose_finish(task) == "pull":
model = f"{model_name}:{tag_drop_down.get_selected_item().get_string().split(' | ')[0]}"
self.pull_model(model)
def pull_model(self, model_name):
tag_list = Gtk.StringList()
for tag in available_models[model_name]['tags']:
tag_list.append(f"{tag[0]} | {tag[1]}")
tag_drop_down = Gtk.DropDown(
enable_search=True,
model=tag_list
)
dialog = Adw.AlertDialog(
heading=_("Pull Model"),
body=_("Please select a tag to pull '{}'").format(model_name),
extra_child=tag_drop_down,
close_response="cancel"
)
dialog.add_response("cancel", _("Cancel"))
dialog.add_response("pull", _("Pull"))
dialog.set_response_appearance("pull", Adw.ResponseAppearance.SUGGESTED)
dialog.choose(
parent = self.manage_models_dialog,
cancellable = None,
callback = lambda dialog, task, model_name = model_name, tag_drop_down = tag_drop_down: pull_model_response(self, dialog, task, model_name, tag_drop_down)
)
# REMOVE IMAGE | WORKS
def remove_attached_file_response(self, dialog, task, button):
def remove_attached_file_response(self, dialog, task, name):
if dialog.choose_finish(task) == 'remove':
self.remove_attached_file(button)
self.file_preview_dialog.close()
self.remove_attached_file(name)
def remove_attached_file(self, button):
def remove_attached_file(self, name):
dialog = Adw.AlertDialog(
heading=_("Remove File"),
body=_("Are you sure you want to remove file?"),
heading=_("Remove Attachment?"),
body=_("Are you sure you want to remove attachment?"),
close_response="cancel"
)
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,
callback = lambda dialog, task, button=button: remove_attached_file_response(self, dialog, task, button)
callback = lambda dialog, task, name=name: remove_attached_file_response(self, dialog, task, name)
)
# RECONNECT REMOTE | WORKS
def reconnect_remote_response(self, dialog, task, entry):
def reconnect_remote_response(self, dialog, task, url_entry, bearer_entry):
response = dialog.choose_finish(task)
if not task or response == "remote":
self.connect_remote(entry.get_text())
self.remote_connection_entry.set_text(url_entry.get_text())
self.remote_connection_switch.set_sensitive(url_entry.get_text())
self.remote_bearer_token_entry.set_text(bearer_entry.get_text())
self.remote_connection_switch.set_active(True)
self.model_manager.update_local_list()
elif response == "local":
self.connect_local()
self.ollama_instance.remote = False
self.ollama_instance.start()
self.model_manager.update_local_list()
elif response == "close":
self.destroy()
def reconnect_remote(self, current_url):
entry = Gtk.Entry(
def reconnect_remote(self):
entry_url = Gtk.Entry(
css_classes = ["error"],
text = current_url
text = self.ollama_instance.remote_url,
placeholder_text = "URL"
)
entry_bearer_token = Gtk.Entry(
css_classes = ["error"] if self.ollama_instance.bearer_token else None,
text = self.ollama_instance.bearer_token,
placeholder_text = "Bearer Token (Optional)"
)
container = Gtk.Box(
orientation = 1,
spacing = 10
)
container.append(entry_url)
container.append(entry_bearer_token)
dialog = Adw.AlertDialog(
heading=_("Connection Error"),
body=_("The remote instance has disconnected"),
extra_child=entry
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"))
if shutil.which('ollama'):
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,
callback = lambda dialog, task, entry=entry: reconnect_remote_response(self, dialog, task, entry)
callback = lambda dialog, task, url_entry=entry_url, bearer_entry=entry_bearer_token: reconnect_remote_response(self, dialog, task, url_entry, bearer_entry)
)
# CREATE MODEL | WORKS
@@ -237,8 +243,8 @@ def create_model_from_existing_response(self, dialog, task, dropdown):
def create_model_from_existing(self):
string_list = Gtk.StringList()
for model in self.local_models:
string_list.append(model)
for model in self.model_manager.get_model_list():
string_list.append(self.convert_model_name(model, 0))
dropdown = Gtk.DropDown()
dropdown.set_model(string_list)
@@ -250,6 +256,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,
@@ -257,37 +264,154 @@ def create_model_from_existing(self):
)
def create_model_from_file_response(self, file_dialog, result):
try: file = file_dialog.open_finish(result)
except: 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.show_toast("error", 5, self.main_overlay) ##TODO NEW ERROR MESSAGE
logger.error(e)
def create_model_from_file(self):
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))
def create_model_from_name_response(self, dialog, task, entry):
model = entry.get_text().lower().strip()
if dialog.choose_finish(task) == 'accept' and model:
threading.Thread(target=self.model_manager.pull_model, kwargs={"model_name": model}).start()
def create_model_from_name(self):
entry = Gtk.Entry()
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"),
extra_child=entry
)
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, entry=entry: create_model_from_name_response(self, dialog, task, entry)
)
# FILE CHOOSER | WORKS
def attach_file_response(self, file_dialog, result):
file_types = {
"plain_text": ["txt", "md", "html", "css", "js", "py", "java", "json", "xml"],
"image": ["png", "jpeg", "jpg", "webp", "gif"],
"pdf": ["pdf"],
"docx": ["docx"]
"pdf": ["pdf"]
}
try: file = file_dialog.open_finish(result)
except: return
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('error', 8, self.main_overlay)
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):
if dialog.choose_finish(task) == "accept":
buffer = self.message_text_view.get_buffer()
text = buffer.get_text(buffer.get_start_iter(), buffer.get_end_iter(), False).replace(video_url, "")
buffer.delete(buffer.get_start_iter(), buffer.get_end_iter())
buffer.insert(buffer.get_start_iter(), text, len(text))
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][:-1]].json_captions['events']:
text += "{}\n".format(event['segs'][0]['utf8'].replace('\n', '\\n'))
if not os.path.exists(os.path.join(cache_dir, 'tmp/youtube')):
os.makedirs(os.path.join(cache_dir, 'tmp/youtube'))
file_path = os.path.join(os.path.join(cache_dir, 'tmp/youtube'), f'{yt.title} ({selected_caption.split(" (")[0]})')
with open(file_path, 'w+', encoding="utf-8") as f:
f.write(text)
self.attach_file(file_path, 'youtube')
def youtube_caption(self, video_url):
yt = YouTube(video_url)
video_title = yt.title
captions = yt.captions
if len(captions) == 0:
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.title(), caption.code))
caption_drop_down = Gtk.DropDown(
enable_search=len(captions) > 10,
model=caption_list
)
dialog = Adw.AlertDialog(
heading=_("Attach YouTube Video?"),
body=_("{}\n\nPlease select a transcript to include").format(video_title),
extra_child=caption_drop_down,
close_response="cancel"
)
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, video_url = video_url, caption_drop_down = caption_drop_down: youtube_caption_response(self, dialog, task, video_url, caption_drop_down)
)
# Website extraction |
def attach_website_response(self, dialog, task, url):
if dialog.choose_finish(task) == "accept":
response = requests.get(url)
if response.status_code == 200:
html = response.text
md = html2text(html)
buffer = self.message_text_view.get_buffer()
textview_text = buffer.get_text(buffer.get_start_iter(), buffer.get_end_iter(), False).replace(url, "")
buffer.delete(buffer.get_start_iter(), buffer.get_end_iter())
buffer.insert(buffer.get_start_iter(), textview_text, len(textview_text))
if not os.path.exists('/tmp/alpaca/websites/'):
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+', encoding="utf-8") as f:
f.write('{}\n\n{}'.format(url, md))
self.attach_file(file_path, 'website')
else:
self.show_toast(_("An error occurred while extracting text from the website"), self.main_overlay)
def attach_website(self, url):
dialog = Adw.AlertDialog(
heading=_("Attach Website? (Experimental)"),
body=_("Are you sure you want to attach\n'{}'?").format(url),
close_response="cancel"
)
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)
)

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 3 0 c -1.644531 0 -3 1.355469 -3 3 v 6 c 0 1.644531 1.355469 3 3 3 h 1 v 4 l 4 -4 h 5 c 1.644531 0 3 -1.355469 3 -3 v -6 c 0 -1.644531 -1.355469 -3 -3 -3 z m 0 2 h 10 c 0.570312 0 1 0.429688 1 1 v 6 c 0 0.570312 -0.429688 1 -1 1 h -10 c -0.570312 0 -1 -0.429688 -1 -1 v -6 c 0 -0.570312 0.429688 -1 1 -1 z m 0 0"/><path d="m 3 3 h 9 v 2 h -9 z m 0 0"/><path d="m 3 6 h 6 v 2 h -6 z m 0 0"/></g></svg>

After

Width:  |  Height:  |  Size: 556 B

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

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg height="16px" viewBox="0 0 16 16" width="16px" xmlns="http://www.w3.org/2000/svg">
<path d="m 6.5 0 c -3.578125 0 -6.5 2.921875 -6.5 6.5 s 2.921875 6.5 6.5 6.5 c 1.429688 0 2.753906 -0.46875 3.828125 -1.257812 l 2.945313 2.945312 c 0.957031 0.9375 2.363281 -0.5 1.40625 -1.4375 l -2.929688 -2.929688 c 0.785156 -1.074218 1.25 -2.394531 1.25 -3.820312 c 0 -3.578125 -2.921875 -6.5 -6.5 -6.5 z m 0 2 c 2.496094 0 4.5 2.003906 4.5 4.5 s -2.003906 4.5 -4.5 4.5 s -4.5 -2.003906 -4.5 -4.5 s 2.003906 -4.5 4.5 -4.5 z m 0 0" fill="#2e3436"/>
</svg>

After

Width:  |  Height:  |  Size: 590 B

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 12.277344 0.832031 c -0.578125 0.007813 -1.167969 0.230469 -1.691406 0.753907 l -9 9 c -0.375 0.375 -0.585938 0.882812 -0.585938 1.414062 v 3 h 3 c 0.53125 0 1.039062 -0.210938 1.414062 -0.585938 l 9 -9 c 1.789063 -1.789062 0.082032 -4.390624 -1.890624 -4.570312 c -0.082032 -0.011719 -0.164063 -0.011719 -0.246094 -0.011719 z m -1.777344 3.605469 l 1.0625 1.0625 l -7.0625 7.0625 l -1.0625 -1.0625 z m 0 0" fill="#222222"/></svg>

After

Width:  |  Height:  |  Size: 568 B

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg height="16px" viewBox="0 0 16 16" width="16px" xmlns="http://www.w3.org/2000/svg">
<path d="m 4 1 c -1.644531 0 -3 1.355469 -3 3 v 1 h 1 v -1 c 0 -1.109375 0.890625 -2 2 -2 h 1 v -1 z m 2 0 v 1 h 4 v -1 z m 5 0 v 1 h 1 c 1.109375 0 2 0.890625 2 2 v 1 h 1 v -1 c 0 -1.644531 -1.355469 -3 -3 -3 z m -5 4 c -0.550781 0 -1 0.449219 -1 1 s 0.449219 1 1 1 s 1 -0.449219 1 -1 s -0.449219 -1 -1 -1 z m -5 1 v 4 h 1 v -4 z m 13 0 v 4 h 1 v -4 z m -4.5 2 l -2 2 l -1.5 -1 l -2 2 v 0.5 c 0 0.5 0.5 0.5 0.5 0.5 h 7 s 0.472656 -0.035156 0.5 -0.5 v -1 z m -8.5 3 v 1 c 0 1.644531 1.355469 3 3 3 h 1 v -1 h -1 c -1.109375 0 -2 -0.890625 -2 -2 v -1 z m 13 0 v 1 c 0 1.109375 -0.890625 2 -2 2 h -1 v 1 h 1 c 1.644531 0 3 -1.355469 3 -3 v -1 z m -8 3 v 1 h 4 v -1 z m 0 0" fill="#2e3434" fill-opacity="0.34902"/>
</svg>

After

Width:  |  Height:  |  Size: 850 B

View File

@@ -1,2 +0,0 @@
<?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 1.5 2 h 2 c 0.277344 0 0.5 0.222656 0.5 0.5 v 12 c 0 0.277344 -0.222656 0.5 -0.5 0.5 h -2 c -0.277344 0 -0.5 -0.222656 -0.5 -0.5 v -12 c 0 -0.277344 0.222656 -0.5 0.5 -0.5 z m 0 0"/><path d="m 5.5 4 h 1 c 0.277344 0 0.5 0.222656 0.5 0.5 v 10 c 0 0.277344 -0.222656 0.5 -0.5 0.5 h -1 c -0.277344 0 -0.5 -0.222656 -0.5 -0.5 v -10 c 0 -0.277344 0.222656 -0.5 0.5 -0.5 z m 0 0"/><path d="m 8.5 3 h 1 c 0.277344 0 0.5 0.222656 0.5 0.5 v 11 c 0 0.277344 -0.222656 0.5 -0.5 0.5 h -1 c -0.277344 0 -0.5 -0.222656 -0.5 -0.5 v -11 c 0 -0.277344 0.222656 -0.5 0.5 -0.5 z m 0 0"/><path d="m 10.707031 1.460938 l 0.964844 -0.261719 c 0.265625 -0.070313 0.539063 0.089843 0.613281 0.355469 l 3.363282 12.558593 c 0.070312 0.265625 -0.085938 0.539063 -0.351563 0.609375 l -0.96875 0.261719 c -0.265625 0.070313 -0.539063 -0.089844 -0.613281 -0.355469 l -3.363282 -12.554687 c -0.070312 -0.269531 0.085938 -0.542969 0.355469 -0.613281 z m 0 0"/></g></svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

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 4.003906 4.070312 v 7.859376 c 0 1.070312 0.90625 1.066406 0.90625 1.066406 h 0.09375 c 0.171875 0 0.347656 -0.039063 0.5 -0.125 l 7 -4 c 0.308594 -0.171875 0.46875 -0.523438 0.46875 -0.875 c 0 -0.351563 -0.160156 -0.703125 -0.46875 -0.875 l -7 -4 c -0.152344 -0.085938 -0.328125 -0.125 -0.5 -0.125 h -0.09375 s -0.90625 0 -0.90625 1.074218 z m 0 0" fill="#222222"/></svg>

After

Width:  |  Height:  |  Size: 510 B

View File

@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg height="16px" viewBox="0 0 16 16" width="16px" xmlns="http://www.w3.org/2000/svg">
<path d="m 12.5 0.0234375 c -0.292969 -0.0039063 -0.59375 0.0195313 -0.882812 0.0937505 c -1.867188 0.488281 -2.984376 2.382812 -2.496094 4.234374 c 0.101562 0.386719 0.289062 0.742188 0.5 1.054688 c -0.109375 0.015625 -1.625 2.59375 -1.625 2.59375 l 3.410156 0.023438 l 0.800781 -1.117188 c 0.378907 0.03125 0.78125 0.023438 1.171875 -0.078125 c 1.863282 -0.484375 2.980469 -2.382813 2.496094 -4.234375 c -0.105469 -0.386719 -0.292969 -0.738281 -0.503906 -1.054688 l -1.359375 2.304688 c -0.28125 0.476562 -0.882813 0.632812 -1.355469 0.355469 l -0.875 -0.507813 c -0.476562 -0.277344 -0.636719 -0.875 -0.355469 -1.347656 l 1.363281 -2.3085938 c -0.097656 -0.0039062 -0.195312 -0.0117187 -0.289062 -0.0117187 z m -8.875 0.6914065 c -0.011719 0 -0.019531 0 -0.027344 0.003906 c -0.230468 0.046875 -0.445312 0.132812 -0.65625 0.21875 c -0.019531 0.625 0.085938 1.441406 -0.15625 1.65625 c -0.242187 0.210938 -1.039062 0.035156 -1.652344 -0.03125 c -0.132812 0.238281 -0.238281 0.484375 -0.3125 0.75 c 0.476563 0.394531 1.136719 0.839844 1.152344 1.15625 c 0.015625 0.320312 -0.625 0.804688 -1.058594 1.25 c 0.101563 0.257812 0.25 0.492188 0.40625 0.71875 c 0.605469 -0.125 1.359376 -0.375 1.621094 -0.1875 c 0.261719 0.1875 0.261719 1.003906 0.34375 1.625 c 0.246094 0.074219 0.507813 0.105469 0.777344 0.125 c 0.28125 -0.554688 0.566406 -1.320312 0.875 -1.40625 c 0.316406 -0.089844 0.960938 0.457031 1.5 0.78125 c 0.214844 -0.152344 0.410156 -0.335938 0.589844 -0.53125 c -0.253906 -0.574219 -0.71875 -1.292969 -0.589844 -1.59375 c 0.125 -0.300781 0.96875 -0.46875 1.558594 -0.6875 c 0.003906 -0.074219 0.03125 -0.144531 0.03125 -0.21875 c 0 -0.191406 -0.035156 -0.378906 -0.0625 -0.5625 c -0.605469 -0.160156 -1.464844 -0.242188 -1.621094 -0.53125 c -0.160156 -0.289062 0.238281 -1.0625 0.433594 -1.65625 c -0.199219 -0.179688 -0.417969 -0.335938 -0.652344 -0.46875 c -0.503906 0.375 -1.085938 0.996094 -1.40625 0.9375 c -0.316406 -0.054688 -0.660156 -0.820312 -0.996094 -1.34375 c -0.03125 0.003906 -0.066406 0 -0.097656 -0.003906 z m 0.59375 1.878906 c 0.929688 0 1.6875 0.753906 1.6875 1.6875 s -0.757812 1.6875 -1.6875 1.6875 s -1.683594 -0.753906 -1.683594 -1.6875 s 0.753906 -1.6875 1.683594 -1.6875 z m 8.621094 6.332031 c -0.144532 0 -0.273438 0.023438 -0.359375 0.074219 h -9.050781 c -0.246094 -0.105469 -0.746094 -0.046875 -0.964844 0.179688 l -2.160156 2.113281 c -0.191407 0.175781 -0.30078175 0.484375 -0.304688 0.707031 c -0.0546875 0.886719 1 1.320312 1.636719 0.792969 l 1.363281 -1.332031 l 0.003906 3.539062 c 0 0.570312 0.457032 1 0.996094 1 h 7.992188 c 0.523437 0 0.996093 -0.445312 0.996093 -0.9375 l -0.003906 -3.601562 l 1.335937 1.308593 c 0.636719 0.527344 1.6875 0.09375 1.636719 -0.792969 c -0.003906 -0.222656 -0.113281 -0.53125 -0.300781 -0.703124 l -2.164062 -2.117188 c -0.144532 -0.152344 -0.417969 -0.226562 -0.652344 -0.230469 z m 0 0" fill="#2e3436"/>
</svg>

Before

Width:  |  Height:  |  Size: 3.0 KiB

View File

@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg height="16px" viewBox="0 0 16 16" width="16px" xmlns="http://www.w3.org/2000/svg">
<path d="m 13.855469 0 l -1.539063 1.4375 c -0.453125 0.421875 -0.53125 1.148438 -0.269531 1.707031 l -5.886719 5.996094 c -0.011718 0 -0.019531 0 -0.03125 0 c -0.257812 -0.128906 -0.550781 -0.183594 -0.839844 -0.148437 c -0.328124 0.046874 -0.632812 0.199218 -0.867187 0.441406 l -3.945313 3.996094 c -0.3906245 0.375 -0.5468745 0.933593 -0.4062495 1.457031 c 0.1406255 0.523437 0.5546875 0.929687 1.0820315 1.058593 c 0.527344 0.132813 1.082031 -0.03125 1.453125 -0.425781 l 3.945312 -3.996093 c 0.472657 -0.453126 0.59375 -1.15625 0.296875 -1.738282 l 5.890625 -5.964844 c 0.558594 0.25 1.273438 0.148438 1.707031 -0.289062 l 1.414063 -1.5625 z m -10.308594 0.0898438 c -0.398437 0 -0.785156 0.0937502 -1.140625 0.2187502 l 1.882812 1.878906 c 0.390626 0.382812 0.390626 1 0 1.386719 l -0.710937 0.707031 c -0.386719 0.386719 -1 0.386719 -1.390625 0 l -1.882812 -1.878906 c -0.125 0.355468 -0.2187505 0.742187 -0.2187505 1.140625 c 0 1.90625 1.5507815 3.453125 3.4609375 3.453125 c 0.402344 0 0.789063 -0.09375 1.144531 -0.21875 l 1.175782 1.171875 h 0.058593 l 2.070313 -2.0625 l -1.203125 -1.203125 c 0.125 -0.359375 0.214843 -0.742188 0.214843 -1.140625 c 0 -1.90625 -1.546874 -3.4531252 -3.460937 -3.4531252 z m 6.550781 7.8906252 l -2.070312 2.066406 c 0.011718 0.027344 0.023437 0.058594 0.03125 0.089844 l 1.144531 1.140625 c -0.125 0.355468 -0.21875 0.742187 -0.21875 1.140625 c 0 1.902343 1.550781 3.449219 3.460937 3.449219 c 0.433594 0 0.855469 -0.101563 1.238282 -0.246094 l -2.007813 -2 c -0.386719 -0.386719 -0.386719 -1.035156 0 -1.417969 l 0.679688 -0.679687 c 0.195312 -0.191407 0.457031 -0.308594 0.710937 -0.308594 s 0.515625 0.117187 0.710938 0.308594 l 1.945312 1.941406 c 0.105469 -0.328125 0.183594 -0.683594 0.183594 -1.046875 c 0 -1.90625 -1.546875 -3.453125 -3.460938 -3.453125 c -0.398437 0 -0.785156 0.09375 -1.140624 0.21875 z m 0 0" fill="#2e3436"/>
</svg>

Before

Width:  |  Height:  |  Size: 2.0 KiB

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 7.5 1.019531 c -0.550781 0 -0.996094 0.445313 -0.996094 0.996094 v 0.453125 c -0.472656 0.128906 -0.929687 0.320312 -1.355468 0.566406 l -0.324219 -0.324218 c -0.390625 -0.390626 -1.019531 -0.390626 -1.410157 0 l -0.703124 0.707031 c -0.390626 0.390625 -0.390626 1.019531 0 1.410156 l 0.320312 0.320313 c -0.246094 0.425781 -0.433594 0.882812 -0.5625 1.355468 h -0.453125 c -0.550781 0 -0.996094 0.445313 -0.996094 0.996094 v 1 c 0 0.550781 0.445313 0.996094 0.996094 0.996094 h 0.449219 c 0.132812 0.472656 0.320312 0.929687 0.566406 1.355468 l -0.320312 0.320313 c -0.390626 0.390625 -0.390626 1.019531 0 1.410156 l 0.703124 0.707031 c 0.390626 0.390626 1.019532 0.390626 1.410157 0 l 0.320312 -0.320312 c 0.429688 0.242188 0.882813 0.433594 1.359375 0.558594 v 0.457031 c 0 0.550781 0.445313 0.996094 0.996094 0.996094 h 0.996094 c 0.554687 0 1 -0.445313 1 -0.996094 v -0.453125 c 0.472656 -0.128906 0.929687 -0.320312 1.355468 -0.566406 l 0.320313 0.324218 c 0.390625 0.390626 1.019531 0.390626 1.410156 0 l 0.707031 -0.707031 c 0.390626 -0.390625 0.390626 -1.019531 0 -1.410156 l -0.320312 -0.320313 c 0.242188 -0.425781 0.433594 -0.882812 0.558594 -1.355468 h 0.453125 c 0.554687 0 1 -0.445313 1 -0.996094 v -1 c 0 -0.550781 -0.445313 -0.996094 -1 -0.996094 h -0.449219 c -0.128906 -0.472656 -0.320312 -0.929687 -0.566406 -1.355468 l 0.324218 -0.320313 c 0.390626 -0.390625 0.390626 -1.019531 0 -1.410156 l -0.707031 -0.707031 c -0.390625 -0.390626 -1.019531 -0.390626 -1.410156 0 l -0.320313 0.320312 c -0.425781 -0.242188 -0.882812 -0.429688 -1.355468 -0.558594 v -0.457031 c 0 -0.550781 -0.445313 -0.996094 -1 -0.996094 z m 0.515625 3.976563 c 1.660156 0 3 1.34375 3 3 s -1.339844 3 -3 3 c -1.65625 0 -3 -1.34375 -3 -3 s 1.34375 -3 3 -3 z m 0 0" fill="#222222"/></svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

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 4 6 h 1 c 0.257812 0 0.527344 -0.128906 0.71875 -0.3125 l 1.28125 -1.28125 v 6.59375 h 2 v -6.59375 l 1.28125 1.28125 c 0.191406 0.183594 0.410156 0.3125 0.71875 0.3125 h 1 v -1 c 0 -0.308594 -0.089844 -0.550781 -0.28125 -0.75 l -3.71875 -3.65625 l -3.71875 3.65625 c -0.191406 0.199219 -0.28125 0.441406 -0.28125 0.75 z m 0 0"/><path d="m 1.007812 11.972656 c 0 1.664063 1.367188 3.035156 3.03125 3.035156 h 7.917969 c 1.664063 0 3.03125 -1.371093 3.03125 -3.035156 v -1.972656 h -2 v 1.972656 c 0 0.589844 -0.441406 1.035156 -1.03125 1.035156 h -7.917969 c -0.589843 0 -1.03125 -0.445312 -1.03125 -1.035156 v -1.972656 h -2 z m 0 0"/><path d="m 4.039062 6.96875 c -1.664062 0 -3.03125 1.367188 -3.03125 3.03125 v 1.976562 h 2 v -1.976562 c 0 -0.589844 0.441407 -1.03125 1.03125 -1.03125 h 0.960938 v -2 z m 6.960938 0 v 2 h 0.957031 c 0.589844 0 1.03125 0.441406 1.03125 1.03125 v 1.976562 h 2 v -1.976562 c 0 -1.664062 -1.367187 -3.03125 -3.03125 -3.03125 z m 0 0"/></g></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

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 9 2.933594 c 4.042969 0 5.890625 3.613281 5.890625 3.613281 l -1.785156 0.902344 s -1.246094 -2.515625 -4.105469 -2.515625 c -2.054688 0 -3.097656 1.394531 -3.484375 2.074218 h 0.910156 c 1.332031 0 1.574219 1.253907 1.574219 2.035157 l -6 -0.046875 l -0.046875 -6 c 1.046875 0 2.035156 0.523437 2.035156 1.667968 v 0.929688 l 0.0625 0.0625 c 0.757813 -1.089844 2.3125 -2.722656 4.949219 -2.722656 z m 0 0"/><path d="m 13.617188 8.996094 c 0.683593 0 1.265624 0.582031 1.265624 1.265625 v 3.46875 c 0 0.683593 -0.582031 1.265625 -1.265624 1.265625 h -3.46875 c -0.683594 0 -1.265626 -0.582032 -1.265626 -1.265625 v -3.46875 c 0 -0.683594 0.582032 -1.265625 1.265626 -1.265625 z m -0.734376 2 h -2 v 2 h 2 z m 0 0"/></g></svg>

After

Width:  |  Height:  |  Size: 881 B

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 2.933594 c -4.042969 0 -5.894531 3.613281 -5.894531 3.613281 l 1.785156 0.902344 s 1.25 -2.515625 4.109375 -2.515625 c 2.054688 0 3.097656 1.394531 3.484375 2.074218 h -0.910156 c -1.332031 0 -1.574219 1.253907 -1.574219 2.035157 l 6 -0.046875 l 0.042969 -6 c -1.042969 0 -2.03125 0.523437 -2.03125 1.667968 v 0.929688 l -0.0625 0.0625 c -0.757813 -1.089844 -2.316407 -2.722656 -4.949219 -2.722656 z m 0 0"/><path d="m 2.382812 8.996094 c -0.683593 0 -1.265624 0.582031 -1.265624 1.265625 v 3.46875 c 0 0.683593 0.582031 1.265625 1.265624 1.265625 h 3.46875 c 0.683594 0 1.265626 -0.582032 1.265626 -1.265625 v -3.46875 c 0 -0.683594 -0.582032 -1.265625 -1.265626 -1.265625 z m 0.734376 2 h 2 v 2 h -2 z m 0 0"/></g></svg>

After

Width:  |  Height:  |  Size: 880 B

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,32 +0,0 @@
# local_instance.py
import subprocess, os, threading
from time import sleep
instance = None
port = 11435
data_dir = os.getenv("XDG_DATA_HOME")
overrides = {}
def start():
global instance, overrides
params = overrides.copy()
params["OLLAMA_HOST"] = f"127.0.0.1:{port}" # You can't change this directly sorry :3
params["HOME"] = data_dir
instance = subprocess.Popen(["/app/bin/ollama", "serve"], env={**os.environ, **params}, stderr=subprocess.PIPE, text=True)
print("Starting Alpaca's Ollama instance...")
sleep(1)
print("Started Alpaca's Ollama instance")
def stop():
global instance
if instance:
instance.kill()
instance.wait()
instance = None
print("Stopped Alpaca's Ollama instance")
def reset():
stop()
sleep(1)
start()

View File

@@ -16,25 +16,51 @@
# 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 sys
import gi
gi.require_version('Gtk', '4.0')
gi.require_version('Adw', '1')
from gi.repository import Gtk, Gio, Adw, GLib
from gi.repository import Gtk, Gio, Adw
from .window import AlpacaWindow
from .internal import cache_dir, data_dir
import sys
import logging
import os
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',
'YusaBecerikli (Turkish) https://github.com/YusaBecerikli',
'Simon (Ukrainian) https://github.com/OriginalSimon',
'Marcel Margenberg (German) https://github.com/MehrzweckMandala'
]
class AlpacaApplication(Adw.Application):
"""The main application singleton class."""
def __init__(self):
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 *_: self.props.active_window.preferences_dialog.present(self.props.active_window), ['<primary>comma'])
self.create_action('about', self.on_about_action)
self.set_accels_for_action("win.show-help-overlay", ['<primary>slash'])
self.version = version
def do_activate(self):
win = self.props.active_window
@@ -47,12 +73,17 @@ class AlpacaApplication(Adw.Application):
application_name='Alpaca',
application_icon='com.jeffser.Alpaca',
developer_name='Jeffry Samuel Eduarte Rojas',
version='0.9.6.1',
version=self.version,
support_url="https://github.com/Jeffser/Alpaca/discussions/155",
developers=['Jeffser https://jeffser.com'],
designers=['Jeffser https://jeffser.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',
designers=['Jeffser https://jeffser.com', 'Tobias Bernard (App Icon) https://tobiasbernard.com/'],
translator_credits='\n'.join(translators),
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,
website="https://jeffser.com/alpaca",
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):
@@ -64,5 +95,17 @@ class AlpacaApplication(Adw.Application):
def main(version):
app = AlpacaApplication()
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(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(data_dir, 'tmp.log')), logging.StreamHandler(stream=sys.stdout)]
)
app = AlpacaApplication(version)
logger.info(f"Alpaca version: {app.version}")
return app.run(sys.argv)

View File

@@ -40,10 +40,18 @@ alpaca_sources = [
'main.py',
'window.py',
'connection_handler.py',
'available_models.py',
'dialogs.py',
'local_instance.py',
'update_history.py'
'available_models.json',
'available_models_descriptions.py',
'internal.py'
]
custom_widgets = [
'custom_widgets/table_widget.py',
'custom_widgets/message_widget.py',
'custom_widgets/chat_widget.py',
'custom_widgets/model_widget.py'
]
install_data(alpaca_sources, install_dir: moduledir)
install_data(custom_widgets, install_dir: moduledir / 'custom_widgets')

View File

@@ -1,4 +0,0 @@
.message-input {
background-color: #343434;
}

View File

@@ -1,24 +1,39 @@
.message-input {
background-color: #EBEBEB;
.message_text_view, .modelfile_textview {
background-color: rgba(0,0,0,0);
}
.chat_row box.header {
font-size: 14px;
.chat_image_button {
padding: 0;
}
.chat_row box {
margin: 0;
.editing_message_textview {
border-radius: 5px;
padding: 5px;
}
.chat_row button {
opacity: 0;
transition: opacity .05s;
.model_list_box {
padding: 0;
}
.chat_row:hover button {
opacity: 1;
.manage_models_button {
padding: 6px 8px 6px 8px;
font-weight: 400;
}
.message .delete-message-button {
opacity: 0;
transition: opacity .05s;
.model_list_box > * {
margin: 0;
}
.message:hover .delete-message-button {
opacity: 1;
.user_message > label, .response_message > label {
padding: 7px;
border-radius: 10px;
}
.user_message label:focus, .response_message label: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;
}
stacksidebar {
border: none;
}
.image_recognition_indicator {
padding: 0px 10px;
}
.code_block {
font-family: monospace;
}

View File

@@ -1,39 +0,0 @@
# update_history.py
# This script updates the old chats.json file to the structure needed for the new version
import os, json, base64
from PIL import Image
import io
def update(self):
old_data = None
new_data = {"chats": {}}
with open(os.path.join(self.config_dir, "chats.json"), 'r') as f:
old_data = json.load(f)["chats"]
for chat_name, content in old_data.items():
directory = os.path.join(self.data_dir, "chats", chat_name)
if not os.path.exists(directory): os.makedirs(directory)
new_messages = {}
for message in content['messages']:
if message:
message_id = self.generate_uuid()
if 'images' in message:
if not os.path.exists(os.path.join(directory, message_id)): os.makedirs(os.path.join(directory, message_id))
new_images = []
for image in message['images']:
file_name = f"{self.generate_uuid()}.png"
decoded = base64.b64decode(image)
buffer = io.BytesIO(decoded)
im = Image.open(buffer)
im.save(os.path.join(directory, message_id, file_name))
new_images.append(file_name)
message['images'] = new_images
new_messages[message_id] = message
new_data['chats'][chat_name] = {}
new_data['chats'][chat_name]['messages'] = new_messages
with open(os.path.join(self.data_dir, "chats", "chats.json"), "w+") as f:
json.dump(new_data, f, indent=6)
os.remove(os.path.join(self.config_dir, "chats.json"))

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -3,10 +3,24 @@ cd "$(dirname "$0")"
echo "Preparing template..."
xgettext --output=po/alpaca.pot --files-from=po/POTFILES
echo "Updating Spanish..."
msgmerge -U po/es.po po/alpaca.pot
#echo "Updating Russian..."
#msgmerge -U po/ru.po po/alpaca.pot
msgmerge --no-fuzzy-matching -U po/es.po po/alpaca.pot
echo "Updating Russian..."
msgmerge --no-fuzzy-matching -U po/ru.po po/alpaca.pot
echo "Updating French"
msgmerge -U po/fr.po po/alpaca.pot
msgmerge --no-fuzzy-matching -U po/fr.po po/alpaca.pot
echo "Updating Brazilian Portuguese"
msgmerge -U po/pt_BR.po po/alpaca.pot
msgmerge --no-fuzzy-matching -U po/pt_BR.po po/alpaca.pot
echo "Updating Norwegian"
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_Hans.po po/alpaca.pot
echo "Updating Hindi"
msgmerge --no-fuzzy-matching -U po/hi.po po/alpaca.pot
echo "Updating Turkish"
msgmerge --no-fuzzy-matching -U po/tr.po po/alpaca.pot
echo "Updating Ukrainian"
msgmerge --no-fuzzy-matching -U po/uk.po po/alpaca.pot
echo "Updating German"
msgmerge --no-fuzzy-matching -U po/de.po po/alpaca.pot