feat: merge Elf into Bavarder
All checks were successful
ci/woodpecker/push/<no value> Pipeline was successful

This commit is contained in:
0xMRTT 2023-07-19 15:59:17 +02:00
parent 9803ab4f0c
commit 8e36bc22b8
97 changed files with 2488 additions and 4308 deletions

View file

@ -1,26 +0,0 @@
[package]
name = "bavarder"
version = "0.1.0"
edition = "2021"
[dependencies]
env_logger = "0.10.0"
[dependencies.gtk]
package = "gtk4"
version = "0.6.2"
features = ["v4_10", "xml_validation"]
[dependencies.gio]
package = "gio"
version = "0.17.0"
features = ["v2_74"]
[dependencies.adw]
package = "libadwaita"
version = "0.4.1"
features = ["v1_4"]
[dependencies.gettext-rs]
version = "0.7.0"
features = ["gettext-system"]

127
README.md
View file

@ -1,126 +1,3 @@
<a href="https://bavarder.codeberg.page">
<h1 align="center">
<img src="data/icons/hicolor/scalable/apps/io.github.Bavarder.Bavarder.svg" alt="Bavarder" width="192" height="192"/>
<br>
Bavarder
</h1>
# bavarder
<p align="center">
<strong>Chit-chat with an AI</strong>
</p>
</a>
<p align="center">
<a href="https://flathub.org/apps/details/io.github.Bavarder.Bavarder">
<img width="200" alt="Download on Flathub" src="https://dl.flathub.org/assets/badges/flathub-badge-i-en.svg"/>
</a>
<br>
</p>
<br>
<p align="center">
<a href="https://translate.codeberg.org/engage/bavarder/">
<img src="https://translate.codeberg.org/widgets/bavarder/-/svg-badge.svg" alt="Translation status" />
</a>
<a href="https://repology.org/project/bavarder/versions">
<img alt="Packaging status" src="https://repology.org/badge/tiny-repos/bavarder.svg">
</a>
<a href="https://snapcraft.io/bavarder">
<img alt="bavarder" src="https://snapcraft.io/bavarder/badge.svg" />
</a>
</p>
<p align="center">
<a href="https://stopthemingmy.app">
<img alt="Please do not theme this app" src="https://stopthemingmy.app/badge.svg"/>
</a>
</p>
<a href="https://bavarder.codeberg.page">
<p align="center">
<img src="./data/screenshots/preview.png" alt="Preview"/>
</p>
</a>
## Usage
Documentation is available [here](https://bavarder.codeberg.page)
## Installation
### Flatpak
You can either use your GNOME Software and search for "Bavarder" or you can run
``` shell
flatpak install io.github.Bavarder.Bavarder
```
### Latest
You can download a flatpak from the latest commit [here](https://codeberg.org/Bavarder/-/packages/generic/bavarder/). Run
``` shell
curl -s -o bavarder.flatpak https://codeberg.org/api/packages/Bavarder/generic/Bavarder/164/bavarder.flatpak && flatpak install --user bavarder.flatpak -y
```
#### From Source
### Flatpak-builder
Clone the repo and run `flatpak-builder`
``` shell
git clone https://codeberg.org/Bavarder/Bavarder # or https://github.com/Bavarder/Bavarder
cd Bavarder
flatpak-builder --install --user --force-clean repo/ build-aux/flatpak/io.github.Bavarder.Bavarder.json
```
### Meson
``` shell
git clone https://codeberg.org/Bavarder/Bavarder # or https://github.com/Bavarder/Bavarder
cd Bavarder
meson setup build # Configure the build environment in subdirectory 'build'
meson compile -C build
meson check -C build
meson install -C build
chmod 0755 /usr/local/bin/bavarder # Fix binary permissions
```
### Others
You can see more install methods on the [website](https://bavarder.codeberg.page/install/)
## Contribute
The [GNOME Code of Conduct](https://wiki.gnome.org/Foundation/CodeOfConduct) is applicable to this project
See [`SEEN.md`](./SEEN.md) for a list of articles and posts about Bavarder
### Translate
<a href="https://translate.codeberg.org/engage/bavarder/">
<img src="https://translate.codeberg.org/widgets/bavarder/-/multi-auto.svg" alt="Translation status" />
</a>
You can translate Bavarder using [Codeberg Translate](https://translate.codeberg.org/engage/bavarder/)
### Mirrors
- [GitHub](https://github.com/Bavarder/Bavarder)
- [GitLab](https://gitlab.com/Bavarder/Bavarder)
- [Codeberg](https://codeberg.org/Bavarder/Bavarder)
## About the name
Bavarder is a french word, the definiton of Bavarder is "Parler abondamment de choses sans grande portée" (Talking a lot about things that don't matter) (Larousse) which can be translated by Chit-Chat (informal conversation about matters that are not important). For non-french speakers, Bavarder can be hard to speak, it's prounouced as [bavaʀde]. Hear [here](https://youtu.be/9Qoogwxo5YA)
## See also
### [Imaginer : Imagine with AI](https://imaginer.codeberg.page)
A tool for generating pictures with AI (GNOME app)
- [GitHub](https://github.com/ImaginerApp/Imaginer)
- [Codeberg](https://codeberg.org/Imaginer/Imaginer)
A description of this project.

47
SEEN.md
View file

@ -1,47 +0,0 @@
# Where Bavarder has been seen
## Press
- https://www.omgubuntu.co.uk/2023/05/bavarder-chatgpt-linux-app
- https://gnulinux.ch/bavarder-chatgpt-ohne-account
- https://infoidevice.fr/bavarder-application-chatgpt-linux/
- https://sempreupdate.com.br/como-instalar-o-chat-bavarder-no-linux/
- https://www.linuxjournal.com/content/introducing-bavarder-user-friendly-linux-desktop-app-quick-chatgpt-interaction
- https://fostips.com/bavarder-open-source-ai-chat-linux/
- https://voyagerlive.org/voyager-chatgpt/
- https://plus.diolinux.com.br/t/bavarder-um-aplicativo-de-chatgpt-para-linux/53155
- https://mindaizer.com/chatgpt-et-linux-presentation-de-bavarder/
- https://wiredgorilla.com/introducing-bavarder-a-user-friendly-linux-desktop-app-for-quick-chatgpt-interaction/
- https://www.linuxconsultant.org/bavarder-is-a-chatgpt-app-for-linux-desktops/
- https://www.linuxlinks.com/machine-learning-linux-bavarder/
- https://www.root.cz/clanky/softwarova-sklizen-24-5-2023-organizace-casu-systemem-kanban/
- https://www.makeuseof.com/use-chatgpt-on-linux-with-bavarder/
## Youtube
- https://youtu.be/dtAi2ejMwrk
- https://youtu.be/bXcSEGb8IPE
## Fediverse
- https://bassam.social/notice/AVII4g9FPM0sD1bMWW
- https://pleroma.destroyallmachines.net/notice/AVHg9tnvMACshmHJL6
- https://floss.social/@omgubuntu/110304976747139717
- https://mastodon.social/@geekland/110305211402821977
- And more
## Twitter
- https://twitter.com/omgubuntu/status/1653752319660417024
- https://twitter.com/linuxern00b/status/1653754427373936645
- https://twitter.com/infoidevice/status/1653996236461023232
- https://twitter.com/search?q=bavarder%20linux&src=typed_query&f=top
- And more
## Misc
- https://alternativeto.net/software/bavarder/
- https://linuxphoneapps.org/apps/io.github.bavarder.bavarder/
- https://www.linuxquestions.org/questions/showthread.php?s=7c645a66bd3800801946c6f238e2ee25&p=6429159#post6429159
- http://lxer.com/module/newswire/view/329486/index.html
- https://www.prime-wow.com/?p=1136455

View file

@ -1,22 +0,0 @@
<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">Bavarder</name>
<shortdesc xml:lang="en">Chit-chat with an AI</shortdesc>
<homepage rdf:resource="https://github.com/Bavarder/Bavarder" />
<bug-database rdf:resource="https://github.com/Bavarder/Bavarder/issues"/>
<programming-language>Python</programming-language>
<platform>GTK 4</platform>
<platform>Libadwaita</platform>
<maintainer>
<foaf:Person>
<foaf:name>0xMRTT</foaf:name>
<foaf:mbox rdf:resource="mailto:0xMRTT@proton.me" />
</foaf:Person>
</maintainer>
</Project>

View file

@ -1,54 +0,0 @@
{
"app-id" : "io.github.Bavarder.Bavarder.Devel",
"runtime" : "org.gnome.Platform",
"runtime-version" : "master",
"sdk" : "org.gnome.Sdk",
"command" : "bavarder",
"finish-args" : [
"--share=network",
"--share=ipc",
"--socket=fallback-x11",
"--device=dri",
"--socket=wayland",
"--filesystem=xdg-config/gtk-4.0"
],
"cleanup" : [
"/include",
"/lib/pkgconfig",
"/man",
"/share/doc",
"/share/gtk-doc",
"/share/man",
"/share/pkgconfig",
"*.la",
"*.a"
],
"modules" : [
"pypi-dependencies.json",
{
"name" : "blueprint-compiler",
"buildsystem" : "meson",
"sources" : [
{
"type" : "git",
"url" : "https://gitlab.gnome.org/jwestman/blueprint-compiler.git",
"branch" : "main"
}
]
},
{
"name" : "bavarder",
"builddir" : true,
"buildsystem" : "meson",
"config-opts": [
"-Dbuildtype=debug"
],
"sources" : [
{
"type" : "dir",
"path" : "../../."
}
]
}
]
}

View file

@ -1,7 +1,7 @@
{
"app-id" : "io.github.Bavarder.Bavarder",
"runtime" : "org.gnome.Platform",
"runtime-version" : "44",
"runtime-version" : "master",
"sdk" : "org.gnome.Sdk",
"command" : "bavarder",
"finish-args" : [
@ -10,7 +10,7 @@
"--socket=fallback-x11",
"--device=dri",
"--socket=wayland",
"--filesystem=xdg-config/gtk-4.0"
"--talk-name=org.freedesktop.Flatpak"
],
"cleanup" : [
"/include",
@ -24,9 +24,7 @@
"*.a"
],
"modules" : [
"pypi-dependencies.json",
{
{
"name" : "blueprint-compiler",
"buildsystem" : "meson",
"sources" : [
@ -38,16 +36,47 @@
]
},
{
"name" : "bavarder",
"builddir" : true,
"name" : "libportal",
"buildsystem" : "meson",
"config-opts": [
"-Dbuildtype=release"
"-Dbackend-gtk4=enabled",
"-Dportal-tests=false",
"-Ddocs=false"
],
"sources" : [
{
"type" : "git",
"url" : "https://github.com/flatpak/libportal.git",
"branch": "main"
}
]
},
"pypi-dependencies.json",
{
"name": "gpt4all",
"buildsystem": "simple",
"build-commands": [
"cd gpt4all-backend/ && mkdir build && cd build && cmake .. && cmake --build . --parallel",
"cd gpt4all-bindings/python && pip wheel --no-deps -w dist . && ls && ls dist && pip3 install \"dist/gpt4all-1.0.6-py3-none-any.whl\" --verbose --exists-action=i --no-index --prefix=${FLATPAK_DEST} --no-build-isolation"
],
"sources": [
{
"type": "git",
"url": "https://github.com/nomic-ai/gpt4all",
"branch": "main"
}
]
},
{
"name" : "bavarder",
"builddir" : true,
"buildsystem" : "meson",
"sources" : [
{
"type" : "dir",
"path" : "../../."
"path" : "../../."
}
]
}

View file

@ -1,155 +0,0 @@
{
"app-id" : "io.github.Bavarder.Bavarder",
"runtime" : "org.gnome.Platform",
"runtime-version" : "44",
"sdk" : "org.gnome.Sdk",
"command" : "bavarder",
"finish-args" : [
"--share=network",
"--share=ipc",
"--socket=fallback-x11",
"--device=dri",
"--socket=wayland",
"--filesystem=xdg-config/gtk-4.0"
],
"cleanup" : [
"/include",
"/lib/pkgconfig",
"/man",
"/share/doc",
"/share/gtk-doc",
"/share/man",
"/share/pkgconfig",
"*.la",
"*.a"
],
"modules" : [
"pypi-dependencies.json",
{
"name" : "libsass",
"buildsystem" : "meson",
"sources" : [
{
"type" : "git",
"url" : "https://github.com/lazka/libsass.git",
"branch" : "meson"
}
]
},
{
"name" : "sassc",
"buildsystem" : "meson",
"sources" : [
{
"type" : "git",
"url" : "https://github.com/lazka/sassc.git",
"branch" : "meson"
}
]
},
{
"name": "libyaml",
"buildsystem": "autotools",
"builddir": true,
"config-opts": [
"--libdir=/app/lib"
],
"sources": [
{
"type": "git",
"url": "https://github.com/yaml/libyaml"
}
]
},
{
"name": "lmdb",
"buildsystem": "simple",
"subdir": "libraries/liblmdb",
"build-commands": [
"make install prefix=/ DESTDIR=/app"
],
"sources": [
{
"type": "git",
"url": "https://git.openldap.org/openldap/openldap.git"
}
]
},
{
"name": "libxmlb",
"buildsystem": "meson",
"config-opts": [
"-Dgtkdoc=false"
],
"sources": [
{
"type": "git",
"url": "https://github.com/hughsie/libxmlb.git",
"branch": "main"
}
]
},
{
"name": "appstream",
"buildsystem": "meson",
"config-opts": [
"-Dstemming=false",
"-Dapidocs=false"
],
"sources": [
{
"type": "git",
"url": "https://github.com/ximion/appstream.git/",
"branch": "main"
}
]
},
{
"name": "gtk",
"buildsystem": "meson",
"sources": [
{
"type": "git",
"url": "https://gitlab.gnome.org/GNOME/gtk.git",
"branch": "main"
}
]
},
{
"name": "libadwaita",
"buildsystem": "meson",
"sources": [
{
"type": "git",
"url": "https://gitlab.gnome.org/GNOME/libadwaita.git",
"branch": "main"
}
]
},
{
"name" : "blueprint-compiler",
"buildsystem" : "meson",
"sources" : [
{
"type" : "git",
"url" : "https://gitlab.gnome.org/jwestman/blueprint-compiler.git",
"tag" : "v0.8.1"
}
]
},
{
"name" : "bavarder",
"builddir" : true,
"buildsystem" : "meson",
"config-opts": [
"-Dbuildtype=release"
],
"sources" : [
{
"type" : "dir",
"path" : "../../."
}
]
}
]
}

View file

@ -3,177 +3,6 @@
"buildsystem": "simple",
"build-commands": [],
"modules": [
{
"name": "python3-baichat_py",
"buildsystem": "simple",
"build-commands": [
"pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} \"baichat_py\" --no-build-isolation"
],
"sources": [
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/6f/a9/aad1eb9134fe0574b281ad1308fe029cf4ec1ba49ba0a061a18dd3ced789/baichat_py-0.3.0-py3-none-any.whl",
"sha256": "aa641939844ea364dcee0c4f40cdca2c42b7d6ed5f0cb360c29f7e35300259d0"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/2b/a8/050ab4f0c3d4c1b8aaa805f70e26e84d0e27004907c5b8ecc1d31815f92a/cffi-1.15.1.tar.gz",
"sha256": "d400bfb9a37b1351253cb402671cea7e89bdecc294e8016a707f6d1d8ac934f9"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/d1/6f/5d591a5628423af4598e2d6ff0861fcbc554cc259590fac9f97d9c984611/curl_cffi-0.5.6-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
"sha256": "7a9df9fabff038f1ac9e7e6f32b5edb5d8df8c2eec64f53f513de1766c17ffdb"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/8d/f3/28e7af53e09c9218140901dc23fdd75cdaf3e64d1d06f61801cf2a841bcb/fake_useragent-1.1.3-py3-none-any.whl",
"sha256": "695d3b1bf7d11d04ab0f971fb73b0ca8de98b78bbadfbc8bacbc9a48423f7531"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/62/d5/5f610ebe421e85889f2e55e33b7f9a6795bd982198517d912eb1c76e1a53/pycparser-2.21-py2.py3-none-any.whl",
"sha256": "8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9"
}
]
},
{
"name": "python3-googlebardpy",
"buildsystem": "simple",
"build-commands": [
"pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} \"googlebardpy\" --no-build-isolation"
],
"sources": [
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/9d/19/59961b522e6757f0c9097e4493fa906031b95b3ebe9360b2c3083561a6b4/certifi-2023.5.7-py3-none-any.whl",
"sha256": "c6c2e98f5c7869efca1f8916fed228dd91539f9f1b444c314c06eef02980c716"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/ff/d7/8d757f8bd45be079d76309248845a04f09619a7b17d6dfc8c9ff6433cac2/charset-normalizer-3.1.0.tar.gz",
"sha256": "34e0a2f9c370eb95597aae63bf85eb5e96826d81e3dcf88b8886012906f509b5"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/a8/40/30a6440d5ceec49fc268710705b89e654fc854d9b8754850228deaf64892/googlebardpy-0.1.0-py3-none-any.whl",
"sha256": "12e65fdfe99392cbb5e8f93572340b757cd9d7aa83391316eaea3a1527995ef2"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/fc/34/3030de6f1370931b9dbb4dad48f6ab1015ab1d32447850b9fc94e60097be/idna-3.4-py3-none-any.whl",
"sha256": "90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/70/8e/0e2d847013cb52cd35b38c009bb167a1a26b2ce6cd6965bf26b47bc0bf44/requests-2.31.0-py3-none-any.whl",
"sha256": "58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/4b/1d/f8383ef593114755429c307449e7717b87044b3bcd5f7860b89b1f759e34/urllib3-2.0.2-py3-none-any.whl",
"sha256": "d055c2f9d38dc53c808f6fdc8eab7360b6fdbbde02340ed25cfbcd817c62469e"
}
]
},
{
"name": "python3-openai",
"buildsystem": "simple",
"build-commands": [
"pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} \"openai\" --no-build-isolation"
],
"sources": [
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/c2/fd/1ff4da09ca29d8933fda3f3514980357e25419ce5e0f689041edb8f17dab/aiohttp-3.8.4.tar.gz",
"sha256": "bf2e1a9162c1e441bf805a1fd166e249d574ca04e03b34f97e2928769e91ab5c"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/76/ac/a7305707cb852b7e16ff80eaf5692309bde30e2b1100a1fcacdc8f731d97/aiosignal-1.3.1-py3-none-any.whl",
"sha256": "f8376fb07dd1e86a584e4fcdec80b36b7f81aac666ebc724e2c090300dd83b17"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/d6/c1/8991e7c5385b897b8c020cdaad718c5b087a6626d1d11a23e1ea87e325a7/async_timeout-4.0.2-py3-none-any.whl",
"sha256": "8ca1e4fcf50d07413d66d1a5e416e42cfdf5851c981d679a09851a6853383b3c"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/f0/eb/fcb708c7bf5056045e9e98f62b93bd7467eb718b0202e7698eb11d66416c/attrs-23.1.0-py3-none-any.whl",
"sha256": "1f28b4522cdc2fb4256ac1a020c78acf9cba2c6b461ccd2c126f3aa8e8335d04"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/9d/19/59961b522e6757f0c9097e4493fa906031b95b3ebe9360b2c3083561a6b4/certifi-2023.5.7-py3-none-any.whl",
"sha256": "c6c2e98f5c7869efca1f8916fed228dd91539f9f1b444c314c06eef02980c716"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/ff/d7/8d757f8bd45be079d76309248845a04f09619a7b17d6dfc8c9ff6433cac2/charset-normalizer-3.1.0.tar.gz",
"sha256": "34e0a2f9c370eb95597aae63bf85eb5e96826d81e3dcf88b8886012906f509b5"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/e9/10/d629476346112b85c912527b9080944fd2c39a816c2225413dbc0bb6fcc0/frozenlist-1.3.3.tar.gz",
"sha256": "58bcc55721e8a90b88332d6cd441261ebb22342e238296bb330968952fbb3a6a"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/fc/34/3030de6f1370931b9dbb4dad48f6ab1015ab1d32447850b9fc94e60097be/idna-3.4-py3-none-any.whl",
"sha256": "90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/4a/15/bd620f7a6eb9aa5112c4ef93e7031bcd071e0611763d8e17706ef8ba65e0/multidict-6.0.4.tar.gz",
"sha256": "3666906492efb76453c0e7b97f2cf459b0682e7402c0489a95484965dbc1da49"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/35/c3/de7124146c3edbe8fd8163028d9ac998f2fd5dcda9225655f1d4ed684bbc/openai-0.27.7-py3-none-any.whl",
"sha256": "788fb7fa85bf7caac6c1ed7eea5984254a1bdaf09ef485acf0e5718c8b2dc25a"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/70/8e/0e2d847013cb52cd35b38c009bb167a1a26b2ce6cd6965bf26b47bc0bf44/requests-2.31.0-py3-none-any.whl",
"sha256": "58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/e6/02/a2cff6306177ae6bc73bc0665065de51dfb3b9db7373e122e2735faf0d97/tqdm-4.65.0-py3-none-any.whl",
"sha256": "c4f53a17fe37e132815abceec022631be8ffe1b9381c2e6e30aa70edc99e9671"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/4b/1d/f8383ef593114755429c307449e7717b87044b3bcd5f7860b89b1f759e34/urllib3-2.0.2-py3-none-any.whl",
"sha256": "d055c2f9d38dc53c808f6fdc8eab7360b6fdbbde02340ed25cfbcd817c62469e"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/5f/3f/04b3c5e57844fb9c034b09c5cb6d2b43de5d64a093c30529fd233e16cf09/yarl-1.9.2.tar.gz",
"sha256": "04ab9d4b9f587c06d801c2abfe9317b77cdf996c65a90d5e84ecc45010823571"
}
]
},
{
"name": "python3-pymdown-extensions",
"buildsystem": "simple",
"build-commands": [
"pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} \"pymdown-extensions\" --no-build-isolation"
],
"sources": [
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/36/2b/61d51a2c4f25ef062ae3f74576b01638bebad5e045f747ff12643df63844/PyYAML-6.0.tar.gz",
"sha256": "68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/a2/17/607fc71d709c0df9cca39ed57ed6f8b1cb77863073004c7def8a02a45fe2/pymdown_extensions-10.0.1-py3-none-any.whl",
"sha256": "ae66d84013c5d027ce055693e09a4628b67e9dec5bce05727e45b0918e36f274"
}
]
},
{
"name": "python3-requests",
"buildsystem": "simple",
@ -188,8 +17,8 @@
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/ff/d7/8d757f8bd45be079d76309248845a04f09619a7b17d6dfc8c9ff6433cac2/charset-normalizer-3.1.0.tar.gz",
"sha256": "34e0a2f9c370eb95597aae63bf85eb5e96826d81e3dcf88b8886012906f509b5"
"url": "https://files.pythonhosted.org/packages/2a/53/cf0a48de1bdcf6ff6e1c9a023f5f523dfe303e4024f216feac64b6eb7f67/charset-normalizer-3.2.0.tar.gz",
"sha256": "3bb3d25a8e6c0aedd251753a79ae98a093c7e7b471faa3aa9a93a81431987ace"
},
{
"type": "file",
@ -203,231 +32,64 @@
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/4b/1d/f8383ef593114755429c307449e7717b87044b3bcd5f7860b89b1f759e34/urllib3-2.0.2-py3-none-any.whl",
"sha256": "d055c2f9d38dc53c808f6fdc8eab7360b6fdbbde02340ed25cfbcd817c62469e"
"url": "https://files.pythonhosted.org/packages/8a/03/ad9306a50d05c166e3456fe810f33cee2b8b2a7a6818ec5d4908c4ec6b36/urllib3-2.0.3-py3-none-any.whl",
"sha256": "48e7fafa40319d358848e1bc6809b208340fafe2096f1725d05d67443d0483d1"
}
]
},
{
"name": "python3-text-generation",
"name": "python3-tqdm",
"buildsystem": "simple",
"build-commands": [
"pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} \"text-generation\" --no-build-isolation"
"pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} \"tqdm\" --no-build-isolation"
],
"sources": [
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/36/2b/61d51a2c4f25ef062ae3f74576b01638bebad5e045f747ff12643df63844/PyYAML-6.0.tar.gz",
"sha256": "68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/c2/fd/1ff4da09ca29d8933fda3f3514980357e25419ce5e0f689041edb8f17dab/aiohttp-3.8.4.tar.gz",
"sha256": "bf2e1a9162c1e441bf805a1fd166e249d574ca04e03b34f97e2928769e91ab5c"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/76/ac/a7305707cb852b7e16ff80eaf5692309bde30e2b1100a1fcacdc8f731d97/aiosignal-1.3.1-py3-none-any.whl",
"sha256": "f8376fb07dd1e86a584e4fcdec80b36b7f81aac666ebc724e2c090300dd83b17"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/d6/c1/8991e7c5385b897b8c020cdaad718c5b087a6626d1d11a23e1ea87e325a7/async_timeout-4.0.2-py3-none-any.whl",
"sha256": "8ca1e4fcf50d07413d66d1a5e416e42cfdf5851c981d679a09851a6853383b3c"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/f0/eb/fcb708c7bf5056045e9e98f62b93bd7467eb718b0202e7698eb11d66416c/attrs-23.1.0-py3-none-any.whl",
"sha256": "1f28b4522cdc2fb4256ac1a020c78acf9cba2c6b461ccd2c126f3aa8e8335d04"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/9d/19/59961b522e6757f0c9097e4493fa906031b95b3ebe9360b2c3083561a6b4/certifi-2023.5.7-py3-none-any.whl",
"sha256": "c6c2e98f5c7869efca1f8916fed228dd91539f9f1b444c314c06eef02980c716"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/ff/d7/8d757f8bd45be079d76309248845a04f09619a7b17d6dfc8c9ff6433cac2/charset-normalizer-3.1.0.tar.gz",
"sha256": "34e0a2f9c370eb95597aae63bf85eb5e96826d81e3dcf88b8886012906f509b5"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/ad/73/b094a662ae05cdc4ec95bc54e434e307986a5de5960166b8161b7c1373ee/filelock-3.12.0-py3-none-any.whl",
"sha256": "ad98852315c2ab702aeb628412cbf7e95b7ce8c3bf9565670b4eaecf1db370a9"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/e9/10/d629476346112b85c912527b9080944fd2c39a816c2225413dbc0bb6fcc0/frozenlist-1.3.3.tar.gz",
"sha256": "58bcc55721e8a90b88332d6cd441261ebb22342e238296bb330968952fbb3a6a"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/ec/4e/397b234a369df06ec782666fcdf9791d125ca6de48729814b381af8c6c03/fsspec-2023.5.0-py3-none-any.whl",
"sha256": "51a4ad01a5bb66fcc58036e288c0d53d3975a0df2a5dc59a93b59bade0391f2a"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/58/34/c57b951aecd0248845932c1cfc15721237c50e463f26b0536673bcb76f4f/huggingface_hub-0.14.1-py3-none-any.whl",
"sha256": "9fc619170d800ff3793ad37c9757c255c8783051e1b5b00501205eb43ccc4f27"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/fc/34/3030de6f1370931b9dbb4dad48f6ab1015ab1d32447850b9fc94e60097be/idna-3.4-py3-none-any.whl",
"sha256": "90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/4a/15/bd620f7a6eb9aa5112c4ef93e7031bcd071e0611763d8e17706ef8ba65e0/multidict-6.0.4.tar.gz",
"sha256": "3666906492efb76453c0e7b97f2cf459b0682e7402c0489a95484965dbc1da49"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/ab/c3/57f0601a2d4fe15de7a553c00adbc901425661bf048f2a22dfc500caf121/packaging-23.1-py3-none-any.whl",
"sha256": "994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/23/65/2aa13873e9e0084ecaec00fbe6c6096b65e1ab99ba66bdbf7e4e7c4cc915/pydantic-1.10.8.tar.gz",
"sha256": "1410275520dfa70effadf4c21811d755e7ef9bb1f1d077a21958153a92c8d9ca"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/70/8e/0e2d847013cb52cd35b38c009bb167a1a26b2ce6cd6965bf26b47bc0bf44/requests-2.31.0-py3-none-any.whl",
"sha256": "58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/83/14/643c55e7cf845db3c1ac96cd624511d56c50386f3760448e7dc2ff58f1c1/text_generation-0.5.2-py3-none-any.whl",
"sha256": "110dd5b05f8ec9cef00f3977001f1ce0464b133b14d4939b15260b0e863c942d"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/e6/02/a2cff6306177ae6bc73bc0665065de51dfb3b9db7373e122e2735faf0d97/tqdm-4.65.0-py3-none-any.whl",
"sha256": "c4f53a17fe37e132815abceec022631be8ffe1b9381c2e6e30aa70edc99e9671"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/38/60/300ad6f93adca578bf05d5f6cd1d854b7d140bebe2f9829561aa9977d9f3/typing_extensions-4.6.2-py3-none-any.whl",
"sha256": "3a8b36f13dd5fdc5d1b16fe317f5668545de77fa0b8e02006381fd49d731ab98"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/4b/1d/f8383ef593114755429c307449e7717b87044b3bcd5f7860b89b1f759e34/urllib3-2.0.2-py3-none-any.whl",
"sha256": "d055c2f9d38dc53c808f6fdc8eab7360b6fdbbde02340ed25cfbcd817c62469e"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/5f/3f/04b3c5e57844fb9c034b09c5cb6d2b43de5d64a093c30529fd233e16cf09/yarl-1.9.2.tar.gz",
"sha256": "04ab9d4b9f587c06d801c2abfe9317b77cdf996c65a90d5e84ecc45010823571"
}
]
},
{
"name": "python3-gradio_client",
"name": "python3-charset-normalizer",
"buildsystem": "simple",
"build-commands": [
"pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} \"gradio_client\" --no-build-isolation"
"pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} \"charset-normalizer\" --no-build-isolation"
],
"sources": [
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/36/2b/61d51a2c4f25ef062ae3f74576b01638bebad5e045f747ff12643df63844/PyYAML-6.0.tar.gz",
"sha256": "68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/68/fe/7ce1926952c8a403b35029e194555558514b365ad77d75125f521a2bec62/anyio-3.7.0-py3-none-any.whl",
"sha256": "eddca883c4175f14df8aedce21054bfca3adb70ffe76a9f607aef9d7fa2ea7f0"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/9d/19/59961b522e6757f0c9097e4493fa906031b95b3ebe9360b2c3083561a6b4/certifi-2023.5.7-py3-none-any.whl",
"sha256": "c6c2e98f5c7869efca1f8916fed228dd91539f9f1b444c314c06eef02980c716"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/ff/d7/8d757f8bd45be079d76309248845a04f09619a7b17d6dfc8c9ff6433cac2/charset-normalizer-3.1.0.tar.gz",
"sha256": "34e0a2f9c370eb95597aae63bf85eb5e96826d81e3dcf88b8886012906f509b5"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/61/97/17ed81b7a8d24d8f69b62c0db37abbd8c0042d4b3fc429c73dab986e7483/exceptiongroup-1.1.1-py3-none-any.whl",
"sha256": "232c37c63e4f682982c8b6459f33a8981039e5fb8756b2074364e5055c498c9e"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/ad/73/b094a662ae05cdc4ec95bc54e434e307986a5de5960166b8161b7c1373ee/filelock-3.12.0-py3-none-any.whl",
"sha256": "ad98852315c2ab702aeb628412cbf7e95b7ce8c3bf9565670b4eaecf1db370a9"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/ec/4e/397b234a369df06ec782666fcdf9791d125ca6de48729814b381af8c6c03/fsspec-2023.5.0-py3-none-any.whl",
"sha256": "51a4ad01a5bb66fcc58036e288c0d53d3975a0df2a5dc59a93b59bade0391f2a"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/86/ed/3b8b8df6c66f5fd8ab3e458e2086502d7208557e9bbc31592d4c732cf1d3/gradio_client-0.2.5-py3-none-any.whl",
"sha256": "922a5188c93797adce023b4caa655318b9c09834095d31763443c1e7a707e301"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/95/04/ff642e65ad6b90db43e668d70ffb6736436c7ce41fcc549f4e9472234127/h11-0.14.0-py3-none-any.whl",
"sha256": "e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/4d/32/b908f673ccef12b6425b848a541264ee3d95f5f571f18f6ab0d8c311442e/httpcore-0.17.2-py3-none-any.whl",
"sha256": "5581b9c12379c4288fe70f43c710d16060c10080617001e6b22a3b6dbcbefd36"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/ec/91/e41f64f03d2a13aee7e8c819d82ee3aa7cdc484d18c0ae859742597d5aa0/httpx-0.24.1-py3-none-any.whl",
"sha256": "06781eb9ac53cde990577af654bd990a4949de37a28bdb4a230d434f3a30b9bd"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/58/34/c57b951aecd0248845932c1cfc15721237c50e463f26b0536673bcb76f4f/huggingface_hub-0.14.1-py3-none-any.whl",
"sha256": "9fc619170d800ff3793ad37c9757c255c8783051e1b5b00501205eb43ccc4f27"
},
"url": "https://files.pythonhosted.org/packages/2a/53/cf0a48de1bdcf6ff6e1c9a023f5f523dfe303e4024f216feac64b6eb7f67/charset-normalizer-3.2.0.tar.gz",
"sha256": "3bb3d25a8e6c0aedd251753a79ae98a093c7e7b471faa3aa9a93a81431987ace"
}
]
},
{
"name": "python3-idna",
"buildsystem": "simple",
"build-commands": [
"pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} \"idna\" --no-build-isolation"
],
"sources": [
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/fc/34/3030de6f1370931b9dbb4dad48f6ab1015ab1d32447850b9fc94e60097be/idna-3.4-py3-none-any.whl",
"sha256": "90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"
},
}
]
},
{
"name": "python3-urllib3",
"buildsystem": "simple",
"build-commands": [
"pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} \"urllib3\" --no-build-isolation"
],
"sources": [
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/ab/c3/57f0601a2d4fe15de7a553c00adbc901425661bf048f2a22dfc500caf121/packaging-23.1-py3-none-any.whl",
"sha256": "994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/70/8e/0e2d847013cb52cd35b38c009bb167a1a26b2ce6cd6965bf26b47bc0bf44/requests-2.31.0-py3-none-any.whl",
"sha256": "58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/c3/a0/5dba8ed157b0136607c7f2151db695885606968d1fae123dc3391e0cfdbf/sniffio-1.3.0-py3-none-any.whl",
"sha256": "eecefdce1e5bbfb7ad2eeaabf7c1eeb404d7757c379bd1f7e5cce9d8bf425384"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/e6/02/a2cff6306177ae6bc73bc0665065de51dfb3b9db7373e122e2735faf0d97/tqdm-4.65.0-py3-none-any.whl",
"sha256": "c4f53a17fe37e132815abceec022631be8ffe1b9381c2e6e30aa70edc99e9671"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/38/60/300ad6f93adca578bf05d5f6cd1d854b7d140bebe2f9829561aa9977d9f3/typing_extensions-4.6.2-py3-none-any.whl",
"sha256": "3a8b36f13dd5fdc5d1b16fe317f5668545de77fa0b8e02006381fd49d731ab98"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/4b/1d/f8383ef593114755429c307449e7717b87044b3bcd5f7860b89b1f759e34/urllib3-2.0.2-py3-none-any.whl",
"sha256": "d055c2f9d38dc53c808f6fdc8eab7360b6fdbbde02340ed25cfbcd817c62469e"
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/d8/3b/2ed38e52eed4cf277f9df5f0463a99199a04d9e29c9e227cfafa57bd3993/websockets-11.0.3.tar.gz",
"sha256": "88fc51d9a26b10fc331be344f1781224a375b78488fc343620184e95a4b27016"
"url": "https://files.pythonhosted.org/packages/8a/03/ad9306a50d05c166e3456fe810f33cee2b8b2a7a6818ec5d4908c4ec6b36/urllib3-2.0.3-py3-none-any.whl",
"sha256": "48e7fafa40319d358848e1bc6809b208340fafe2096f1725d05d67443d0483d1"
}
]
}

View file

@ -1,14 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<gresources>
<gresource prefix="/io/github/Bavarder/Bavarder">
<file preprocess="xml-stripblanks">ui/window.ui</file>
<file preprocess="xml-stripblanks">ui/message_bubble.ui</file>
<file preprocess="xml-stripblanks" alias="gtk/help-overlay.ui">ui/help-overlay.ui</file>
<file preprocess="xml-stripblanks">ui/preferences.ui</file>
<file>style.css</file>
</gresource>
<gresource prefix="/io/github/Bavarder/Bavarder/icons/scalable/actions/">
<file preprocess="xml-stripblanks" alias="paper-plane-symbolic.svg">icons/scalable/actions/paper-plane-symbolic.svg</file>
<file preprocess="xml-stripblanks" alias="x-circular-symbolic.svg">icons/scalable/actions/x-circular-symbolic.svg</file>
</gresource>
</gresources>

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#222" d="M8.475 0a.497.497 0 0 0-.276.1L6.5 1.375 4.8.1a.5.5 0 0 0-.37-.094A.5.5 0 0 0 4.2.9L6 2.25V4H3C1.338 4 0 5.338 0 7v6c0 1.662 1.338 3 3 3h10c1.662 0 3-1.338 3-3V7c0-1.662-1.338-3-3-3H7V2.25L8.8.9a.5.5 0 0 0-.325-.9zM3 6h10c.554 0 1 .446 1 1v6c0 .554-.446 1-1 1H3c-.554 0-1-.446-1-1V7c0-.554.446-1 1-1zm2 1a2 2 0 0 0-2 2 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0-2-2zm6 0a2 2 0 0 0-2 2 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0-2-2zM5 8a1 1 0 0 1 1 1 1 1 0 0 1-1 1 1 1 0 0 1-1-1 1 1 0 0 1 1-1zm6 0a1 1 0 0 1 1 1 1 1 0 0 1-1 1 1 1 0 0 1-1-1 1 1 0 0 1 1-1zm-4.5 4a.499.499 0 1 0 0 1h3a.499.499 0 1 0 0-1z"/></svg>

After

Width:  |  Height:  |  Size: 685 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 5.976562 2 c 0.546876 0 1 0.453125 1 1 v 10 c 0 0.546875 -0.453124 1 -1 1 h -0.976562 c -1.652344 0 -3 -1.347656 -3 -3 v -6 c 0 -1.652344 1.347656 -3 3 -3 z m -5.976562 3 v 6 c 0 2.765625 2.234375 5 5 5 h 0.976562 c 1.660157 0 3 -1.339844 3 -3 v -10 c 0 -1.660156 -1.339843 -3 -3 -3 h -0.976562 c -2.765625 0 -5 2.234375 -5 5 z m 0 0"/><path d="m 1.488281 8.996094 h 1.511719 c 1.101562 0 1.988281 -0.886719 1.988281 -1.984375 v -0.515625 c 0 -0.273438 -0.222656 -0.5 -0.5 -0.5 c -0.273437 0 -0.5 0.226562 -0.5 0.5 v 0.515625 c 0 0.542969 -0.445312 0.984375 -0.988281 0.984375 h -1.511719 c -0.273437 0 -0.5 0.226562 -0.5 0.5 c 0 0.277344 0.226563 0.5 0.5 0.5 z m 0 0"/><path d="m 7.5 9.992188 h -1.511719 c -1.101562 0 -1.988281 0.886718 -1.988281 1.984374 v 0.515626 c 0 0.273437 0.222656 0.5 0.5 0.5 s 0.5 -0.226563 0.5 -0.5 v -0.515626 c 0 -0.539062 0.445312 -0.984374 0.988281 -0.984374 h 1.511719 c 0.277344 0 0.5 -0.226563 0.5 -0.5 c 0 -0.277344 -0.222656 -0.5 -0.5 -0.5 z m 0 0"/><path d="m 4.496094 4.980469 h 3 c 0.277344 0 0.5 -0.226563 0.5 -0.5 c 0 -0.277344 -0.222656 -0.5 -0.5 -0.5 h -3 c -0.277344 0 -0.5 0.222656 -0.5 0.5 c 0 0.273437 0.222656 0.5 0.5 0.5 z m 0 0"/><path d="m 11.015625 14 h -1.035156 c -0.546875 0 -1 -0.453125 -1 -1 v -10 c 0 -0.546875 0.453125 -1 1 -1 h 1.035156 v -2 h -1.035156 c -1.664063 0 -3 1.339844 -3 3 v 10 c 0 1.660156 1.335937 3 3 3 h 1.035156 z m 0 0"/><path d="m 10 8 l 3.5 -0.011719 v -1 l -3.5 0.011719 z m 0 0"/><path d="m 10 5 h 2.242188 l 2.148437 -2.6875 l -0.78125 -0.625 l -2 2.5 l 0.390625 -0.1875 h -2 z m 0 0"/><path d="m 10 11 h 2 l -0.390625 -0.1875 l 2 2.5 l 0.78125 -0.625 l -2.148437 -2.6875 h -2.242188 z m 0 0"/><path d="m 14.488281 1.976562 c -0.265625 0 -0.488281 -0.21875 -0.488281 -0.488281 c 0 -0.265625 0.222656 -0.488281 0.488281 -0.488281 c 0.269531 0 0.488281 0.222656 0.488281 0.488281 c 0 0.269531 -0.21875 0.488281 -0.488281 0.488281 z m 0 -1.976562 c -0.824219 0 -1.488281 0.664062 -1.488281 1.488281 s 0.664062 1.488281 1.488281 1.488281 s 1.488281 -0.664062 1.488281 -1.488281 s -0.664062 -1.488281 -1.488281 -1.488281 z m 0 0"/><path d="m 14.488281 13.976562 c -0.265625 0 -0.488281 -0.21875 -0.488281 -0.488281 c 0 -0.265625 0.222656 -0.488281 0.488281 -0.488281 c 0.269531 0 0.488281 0.222656 0.488281 0.488281 c 0 0.269531 -0.21875 0.488281 -0.488281 0.488281 z m 0 -1.976562 c -0.824219 0 -1.488281 0.664062 -1.488281 1.488281 s 0.664062 1.488281 1.488281 1.488281 s 1.488281 -0.664062 1.488281 -1.488281 s -0.664062 -1.488281 -1.488281 -1.488281 z m 0 0"/><path d="m 14.488281 7.976562 c -0.265625 0 -0.488281 -0.21875 -0.488281 -0.488281 c 0 -0.265625 0.222656 -0.488281 0.488281 -0.488281 c 0.269531 0 0.488281 0.222656 0.488281 0.488281 c 0 0.269531 -0.21875 0.488281 -0.488281 0.488281 z m 0 -1.976562 c -0.824219 0 -1.488281 0.664062 -1.488281 1.488281 s 0.664062 1.488281 1.488281 1.488281 s 1.488281 -0.664062 1.488281 -1.488281 s -0.664062 -1.488281 -1.488281 -1.488281 z m 0 0"/></svg>

After

Width:  |  Height:  |  Size: 3 KiB

View file

@ -0,0 +1,13 @@
<?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 5.976562 2 c 0.546876 0 1 0.453125 1 1 v 10 c 0 0.546875 -0.453124 1 -1 1 h -0.976562 c -1.652344 0 -3 -1.347656 -3 -3 v -6 c 0 -1.652344 1.347656 -3 3 -3 z m -5.976562 3 v 6 c 0 2.765625 2.234375 5 5 5 h 0.976562 c 1.660157 0 3 -1.339844 3 -3 v -10 c 0 -1.660156 -1.339843 -3 -3 -3 h -0.976562 c -2.765625 0 -5 2.234375 -5 5 z m 0 0"/>
<path d="m 7.5 9.992188 h -1.511719 c -1.101562 0 -1.988281 0.886718 -1.988281 1.984374 v 0.515626 c 0 0.273437 0.222656 0.5 0.5 0.5 s 0.5 -0.226563 0.5 -0.5 v -0.515626 c 0 -0.539062 0.445312 -0.984374 0.988281 -0.984374 h 1.511719 c 0.277344 0 0.5 -0.226563 0.5 -0.5 c 0 -0.277344 -0.222656 -0.5 -0.5 -0.5 z m 0 0"/>
<path d="m 4.496094 4.980469 h 3 c 0.277344 0 0.5 -0.226563 0.5 -0.5 c 0 -0.277344 -0.222656 -0.5 -0.5 -0.5 h -3 c -0.277344 0 -0.5 0.222656 -0.5 0.5 c 0 0.273437 0.222656 0.5 0.5 0.5 z m 0 0"/>
<path d="m 9.980469 14 c -0.546875 0 -1 -0.453125 -1 -1 v -10 c 0 -0.546875 0.453125 -1 1 -1 h 1.019531 c 1.652344 0 3 1.347656 3 3 v 6 c 0 1.652344 -1.347656 3 -3 3 z m 6.019531 -3 v -6 c 0 -2.765625 -2.234375 -5 -5 -5 h -1.019531 c -1.664063 0 -3 1.339844 -3 3 v 10 c 0 1.660156 1.335937 3 3 3 h 1.019531 c 2.765625 0 5 -2.234375 5 -5 z m 0 0"/>
<path d="m 8.523438 6.015625 h 1.511718 c 1.101563 0 1.988282 -0.886719 1.988282 -1.988281 v -0.511719 c 0 -0.277344 -0.222657 -0.5 -0.5 -0.5 c -0.277344 0 -0.5 0.222656 -0.5 0.5 v 0.511719 c 0 0.542968 -0.445313 0.988281 -0.988282 0.988281 h -1.511718 c -0.277344 0 -0.5 0.222656 -0.5 0.5 c 0 0.273437 0.222656 0.5 0.5 0.5 z m 0 0"/>
<path d="m 8.488281 10 h 1.511719 c 0.542969 0 0.988281 0.445312 0.988281 0.988281 v 0.511719 c 0 0.277344 0.222657 0.5 0.5 0.5 c 0.273438 0 0.5 -0.222656 0.5 -0.5 v -0.511719 c 0 -1.101562 -0.886719 -1.988281 -1.988281 -1.988281 h -1.511719 c -0.277343 0 -0.5 0.222656 -0.5 0.5 s 0.222657 0.5 0.5 0.5 z m 0 0"/>
<path d="m 15 10 h -1.523438 c -0.277343 0 -0.5 0.222656 -0.5 0.5 s 0.222657 0.5 0.5 0.5 h 1.523438 c 0.277344 0 0.5 -0.222656 0.5 -0.5 s -0.222656 -0.5 -0.5 -0.5 z m 0 0"/>
<path d="m 6.488281 8 h 5.042969 c 0.273438 0 0.5 -0.222656 0.5 -0.5 s -0.226562 -0.5 -0.5 -0.5 h -5.042969 c -0.277343 0 -0.5 0.222656 -0.5 0.5 s 0.222657 0.5 0.5 0.5 z m 0 0"/>
<path d="m 15.089844 6.015625 h -1.59375 c -0.277344 0 -0.5 0.222656 -0.5 0.5 c 0 0.273437 0.222656 0.5 0.5 0.5 h 1.59375 c 0.273437 0 0.5 -0.226563 0.5 -0.5 c 0 -0.277344 -0.226563 -0.5 -0.5 -0.5 z m 0 0"/>
<path d="m 1.488281 9.992188 h 1.511719 c 1.101562 0 1.988281 -0.886719 1.988281 -1.988282 v -0.511718 c 0 -0.277344 -0.222656 -0.5 -0.5 -0.5 c -0.277343 0 -0.5 0.222656 -0.5 0.5 v 0.511718 c 0 0.542969 -0.445312 0.988282 -0.988281 0.988282 h -1.511719 c -0.277343 0 -0.5 0.222656 -0.5 0.5 c 0 0.273437 0.222657 0.5 0.5 0.5 z m 0 0"/>
</svg>

After

Width:  |  Height:  |  Size: 2.9 KiB

View file

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" version="1.1">
<path style="fill:#dfdfdf" d="M 2.5 1 C 1.115 1 0 2.1162718 0 3.5039062 L 0 10.517578 C 0 11.905212 1.1150052 12.996222 2.5 13 L 10.875 13 L 12.953125 14.998047 L 14 15 L 14 13 C 15.14126 12.767208 16 11.731753 16 10.517578 L 16 3.5039062 C 16 2.1162718 14.885 1 13.5 1 L 2.5 1 z M 2.5 3 L 13.5 3 C 13.777 3 14 3.223 14 3.5 L 14 10.5 C 14 10.777 13.777 11 13.5 11 L 2.5 11 C 2.223 11 2 10.777 2 10.5 L 2 3.5 C 2 3.223 2.223 3 2.5 3 z M 7 4 L 7 6 L 5 6 L 5 8 L 7 8 L 7 10 L 9 10 L 9 8 L 11 8 L 11 6 L 9 6 L 9 4 L 7 4 z"/>
</svg>

After

Width:  |  Height:  |  Size: 607 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 9.492188 0.140625 c -0.851563 -0.1640625 -1.722657 -0.1835938 -2.574219 -0.0664062 c -1.699219 0.2304692 -3.328125 1.0078122 -4.601563 2.2929692 c -2.546875 2.566406 -3.050781 6.539062 -1.230468 9.664062 c 1.824218 3.121094 5.53125 4.636719 9.019531 3.683594 c 3.488281 -0.949219 5.90625 -4.132813 5.890625 -7.75 c 0 -0.550782 -0.453125 -1 -1.003906 -0.996094 c -0.550782 0.003906 -0.996094 0.453125 -0.996094 1.003906 c 0.015625 2.722656 -1.792969 5.097656 -4.417969 5.816406 c -2.625 0.714844 -5.390625 -0.417968 -6.761719 -2.765624 c -1.371094 -2.351563 -0.996094 -5.316407 0.921875 -7.25 c 1.914063 -1.929688 4.875 -2.335938 7.238281 -0.984376 c 0.476563 0.273438 1.089844 0.109376 1.363282 -0.371093 c 0.273437 -0.480469 0.109375 -1.089844 -0.371094 -1.367188 c -0.785156 -0.445312 -1.621094 -0.75 -2.476562 -0.910156 z m 0 0"/><path d="m 15.753906 3.65625 c 0.175782 -0.199219 0.261719 -0.460938 0.246094 -0.722656 c -0.019531 -0.265625 -0.140625 -0.511719 -0.339844 -0.6875 c -0.199218 -0.175782 -0.460937 -0.265625 -0.726562 -0.246094 c -0.265625 0.015625 -0.511719 0.140625 -0.6875 0.339844 l -6.296875 7.195312 l -2.242188 -2.246094 c -0.390625 -0.390624 -1.023437 -0.390624 -1.414062 0 c -0.1875 0.1875 -0.292969 0.445313 -0.292969 0.710938 s 0.105469 0.519531 0.292969 0.707031 l 3 3 c 0.195312 0.195313 0.464843 0.300781 0.742187 0.292969 c 0.277344 -0.011719 0.535156 -0.132812 0.71875 -0.34375 z m 0 0"/></svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View file

@ -0,0 +1,5 @@
<?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 10 3 c -1.5625 0.003906 -2.980469 0.914062 -3.628906 2.332031 c -0.425782 -0.214843 -0.894532 -0.332031 -1.371094 -0.332031 c -0.308594 0.007812 -0.613281 0.058594 -0.90625 0.160156 l 8.84375 8.839844 h 0.0625 c 1.65625 0 3 -1.34375 3 -3 c 0 -1.332031 -0.882812 -2.503906 -2.160156 -2.875 c 0.105468 -0.367188 0.160156 -0.746094 0.160156 -1.125 c 0 -2.210938 -1.789062 -4 -4 -4 z m -7.203125 2.984375 c -0.507813 0.550781 -0.792969 1.269531 -0.796875 2.015625 c 0 0.347656 0.0625 0.695312 0.183594 1.023438 c -1.25 0.160156 -2.183594 1.21875 -2.183594 2.476562 c 0 1.378906 1.121094 2.5 2.5 2.5 h 8.3125 z m 0 0"/>
<path d="m 1.519531 0.460938 l -1.0625 1.0625 l 14 14 l 1.0625 -1.0625 z m 0 0"/>
</svg>

After

Width:  |  Height:  |  Size: 850 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 10 3 c -1.5625 0.003906 -2.980469 0.914062 -3.628906 2.332031 c -0.425782 -0.214843 -0.894532 -0.332031 -1.371094 -0.332031 c -1.65625 0 -3 1.34375 -3 3 c 0 0.347656 0.0625 0.695312 0.183594 1.023438 c -1.25 0.160156 -2.183594 1.21875 -2.183594 2.476562 c 0 1.378906 1.121094 2.5 2.5 2.5 h 10.5 c 1.65625 0 3 -1.34375 3 -3 c 0 -1.332031 -0.882812 -2.503906 -2.160156 -2.875 c 0.105468 -0.367188 0.160156 -0.746094 0.160156 -1.125 c 0 -2.210938 -1.789062 -4 -4 -4 z m 0 0"/>
</svg>

After

Width:  |  Height:  |  Size: 623 B

View file

@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" version="1.1">
<path style="fill:#dfdfdf" d="M 11,11 V 12 C 11,12.28 11.1,12.54 11.28,12.72 L 12.06,13.5 11.28,14.28 C 11.1,14.47 11,14.73 11,15 V 16 H 12 C 12.28,16 12.54,15.9 12.72,15.72 L 13.5,14.94 14.28,15.72 C 14.46,15.9 14.73,16 15,16 H 16 V 15 C 16,14.73 15.9,14.47 15.72,14.28 L 14.94,13.5 15.72,12.72 C 15.9,12.54 16,12.28 16,12 V 11 H 15 C 14.73,11 14.46,11.1 14.28,11.28 L 13.5,12.07 12.72,11.28 C 12.54,11.1 12.28,11 12,11 Z"/>
<path style="fill:#dfdfdf;opacity:.35" d="M 10,9 15.5,4.5 10,0 C 10,0.01 10,1.34 10,2 9,2 8,2 7,2 7,3.67 7,5.34 7,7 8,7 9,7 10,7 10,7.67 10,9 10,9 Z"/>
<path style="fill:#dfdfdf;opacity:.35" d="M 6,6 0.5,10.5 6,15 V 13 H 9 V 8 H 6 Z"/>
</svg>

After

Width:  |  Height:  |  Size: 750 B

View file

@ -0,0 +1,5 @@
<?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 15 8 l -14 -7 v 6 l 8 1 l -8 1 v 6 z m 0 0" fill="#222222"/>
</svg>

After

Width:  |  Height:  |  Size: 209 B

View file

@ -0,0 +1,5 @@
<?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 2.199219 0 c -1.207031 0 -2.199219 1.007812 -2.199219 2.207031 v 10.585938 c 0 1.199219 0.992188 2.207031 2.199219 2.207031 h 11.601562 c 1.207031 0 2.199219 -1.007812 2.199219 -2.207031 v -10.585938 c 0 -1.199219 -0.992188 -2.207031 -2.199219 -2.207031 z m 0 2 h 11.601562 c 0.121094 0 0.199219 0.070312 0.199219 0.207031 v 10.585938 c 0 0.136719 -0.078125 0.207031 -0.199219 0.207031 h -11.601562 c -0.121094 0 -0.199219 -0.070312 -0.199219 -0.207031 v -10.585938 c 0 -0.136719 0.078125 -0.207031 0.199219 -0.207031 z m 0 0"/>
<path d="m 4.515625 5.898438 c -0.164063 -0.003907 -0.324219 0.0625 -0.441406 0.175781 c -0.230469 0.234375 -0.230469 0.617187 0 0.851562 l 1.578125 1.574219 l -1.578125 1.574219 c -0.230469 0.234375 -0.230469 0.617187 0 0.851562 c 0.234375 0.230469 0.617187 0.230469 0.851562 0 l 2 -2 c 0.230469 -0.234375 0.230469 -0.617187 0 -0.851562 l -2 -2 c -0.109375 -0.105469 -0.257812 -0.167969 -0.410156 -0.175781 z m 3.484375 4.101562 v 1 h 3 v -1 z m 0 0"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View file

@ -1,12 +1,13 @@
application_id = 'io.github.Bavarder.Bavarder'
scalable_dir = join_paths('hicolor', 'scalable', 'apps')
install_data(
join_paths(scalable_dir, ('@0@.svg').format(APPLICATION_ID)),
join_paths(scalable_dir, ('@0@.svg').format(application_id)),
install_dir: join_paths(get_option('datadir'), 'icons', scalable_dir)
)
symbolic_dir = join_paths('hicolor', 'symbolic', 'apps')
install_data(
join_paths(symbolic_dir, ('@0@-symbolic.svg').format(PROJECT_RDNN_NAME)),
install_dir: join_paths(get_option('datadir'), 'icons', symbolic_dir),
rename: '@0@-symbolic.svg'.format(APPLICATION_ID)
join_paths(symbolic_dir, ('@0@-symbolic.svg').format(application_id)),
install_dir: join_paths(get_option('datadir'), 'icons', symbolic_dir)
)

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"><path d="m 15 8 l -14 -7 v 6 l 8 1 l -8 1 v 6 z m 0 0" fill="#222222"/></svg>

Before

Width:  |  Height:  |  Size: 204 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 7.96875 1 c -3.851562 0 -6.96875 3.117188 -6.96875 6.96875 s 3.117188 6.96875 6.96875 6.96875 s 6.96875 -3.117188 6.96875 -6.96875 s -3.117188 -6.96875 -6.96875 -6.96875 z m -3 3.96875 h 1 h 0.03125 c 0.253906 0.011719 0.511719 0.128906 0.6875 0.3125 l 1.28125 1.28125 l 1.3125 -1.28125 c 0.265625 -0.230469 0.445312 -0.304688 0.6875 -0.3125 h 1 v 1 c 0 0.285156 -0.035156 0.550781 -0.25 0.75 l -1.28125 1.28125 l 1.25 1.25 c 0.1875 0.1875 0.28125 0.453125 0.28125 0.71875 v 1 h -1 c -0.265625 0 -0.53125 -0.09375 -0.71875 -0.28125 l -1.28125 -1.28125 l -1.28125 1.28125 c -0.1875 0.1875 -0.453125 0.28125 -0.71875 0.28125 h -1 v -1 c 0 -0.265625 0.09375 -0.53125 0.28125 -0.71875 l 1.28125 -1.25 l -1.28125 -1.28125 c -0.210938 -0.195312 -0.304688 -0.46875 -0.28125 -0.75 z m 0 0" fill="#2e3436"/>
</svg>

Before

Width:  |  Height:  |  Size: 948 B

View file

@ -1,179 +1,358 @@
<?xml version="1.0" encoding="UTF-8"?>
<component type="desktop">
<id>@APP_ID@</id>
<name>Bavarder</name>
<summary>Chit-chat with an AI</summary>
<developer_name>0xMRTT</developer_name>
<metadata_license>CC0-1.0</metadata_license>
<project_license>GPL-3.0-or-later</project_license>
<launchable type="desktop-id">@APP_ID@.desktop</launchable>
<content_rating type="oars-1.1"/>
<id>
@APP_ID@
</id>
<name>
Bavarder
</name>
<summary>
Chit-chat with an AI
</summary>
<developer_name>
0xMRTT
</developer_name>
<metadata_license>
CC0-1.0
</metadata_license>
<project_license>
GPL-3.0-or-later
</project_license>
<launchable type="desktop-id">
@APP_ID@.desktop
</launchable>
<content_rating type="oars-1.1" />
<description>
<p>Chit-chat with an AI</p>
<p>
Chit-chat with an AI
</p>
</description>
<screenshots>
<screenshot width="472" height="622">
<caption>Screenshot of Main UI</caption>
<image type="source">https://codeberg.org/Bavarder/Bavarder/raw/branch/main/data/screenshots/preview.png</image>
<screenshot width="472" height="622">
<caption>
Screenshot of Main UI
</caption>
<image type="source">
https://codeberg.org/Bavarder/Bavarder/raw/branch/main/data/screenshots/preview.png
</image>
</screenshot>
<screenshot width="724" height="732">
<caption>
Screenshot of Preferences UI
</caption>
<image type="source">
https://codeberg.org/Bavarder/Bavarder/raw/branch/main/data/screenshots/preferences.png
</image>
</screenshot>
<screenshot width="724" height="732">
<caption>Screenshot of Preferences UI</caption>
<image type="source">https://codeberg.org/Bavarder/Bavarder/raw/branch/main/data/screenshots/preferences.png</image>
</screenshot>
</screenshots>
<url type="homepage">@PROJECT_URL@</url>
<url type="bugtracker">@BUGTRACKER_URL@</url>
<url type="help">@HELP_URL@</url>
<url type="translate">@TRANSLATE_URL@</url>
<kudos>
<kudo>HiDpiIcon</kudo>
<kudo>ModernToolkit</kudo>
</kudos>
<custom>
<value key="Purism::form_factor">workstation</value>
<value key="Purism::form_factor">mobile</value>
</custom>
<requires>
<display_length compare="ge">360</display_length>
</requires>
<categories>
<category>Utility</category>
</categories>
<recommends>
<control>keyboard</control>
<control>pointing</control>
<control>touch</control>
</recommends>
<url type="homepage">
@PROJECT_URL@
</url>
<url type="bugtracker">
@BUGTRACKER_URL@
</url>
<url type="help">
@HELP_URL@
</url>
<url type="translate">
@TRANSLATE_URL@
</url>
<kudos>
<kudo>
HiDpiIcon
</kudo>
<kudo>
ModernToolkit
</kudo>
</kudos>
<custom>
<value key="Purism::form_factor">
workstation
</value>
<value key="Purism::form_factor">
mobile
</value>
</custom>
<requires>
<display_length compare="ge">
360
</display_length>
</requires>
<categories>
<category>
Utility
</category>
</categories>
<recommends>
<control>
keyboard
</control>
<control>
pointing
</control>
<control>
touch
</control>
</recommends>
<keywords>
<keyword>Bavarder</keyword>
<keyword>Chat</keyword>
<keyword>GPT</keyword>
<keyword>ChatGPT</keyword>
<keyword>AI</keyword>
<keyword>OpenAI</keyword>
<keyword>Open Assistant</keyword>
<keyword>HuggingFace</keyword>
<keyword>
Bavarder
</keyword>
<keyword>
Chat
</keyword>
<keyword>
GPT
</keyword>
<keyword>
ChatGPT
</keyword>
<keyword>
AI
</keyword>
<keyword>
OpenAI
</keyword>
<keyword>
Open Assistant
</keyword>
<keyword>
HuggingFace
</keyword>
</keywords>
<releases>
<release version="0.2.4" date="2023-6-16" type="stable">
<description>
<p>New UI</p>
<p>Faster BaiChat</p>
<p>Fix some bugs</p>
<p>Update translations</p>
<p>Add better error handling</p>
</description>
</release>
<release version="0.2.3" date="2023-5-21" type="stable">
<description>
<p>Add the ability to use local model</p>
<p>Add the ability to use custom model in OpenAI</p>
<p>Make loading mechanism faster</p>
<p>Fix some bugs</p>
<p>Update translations</p>
<p>Add CI</p>
<p>Add support for launching Bavarder offline</p>
<p>Update Blueprint to v0.8.0</p>
<p>Add better error handling</p>
</description>
</release>
<release version="0.2.2" date="2023-5-16" type="stable">
<description>
<p>Allow fetching news about providers and check if there is some issues about them</p>
<p>Hugging Chat is now disabled because of a change which require to login</p>
<p>Providers moved to the menu</p>
<p>Update screenshots</p>
<p>Fix some bugs</p>
<p>Update translations</p>
<p>Add CI</p>
<p>Add support for launching Bavarder offline</p>
<p>Update Blueprint to v0.8.0</p>
<p>Add better error handling</p>
</description>
</release>
<release version="0.2.1" date="2023-5-13" type="stable">
<description>
<p>Fix Theming support of the new render widget</p>
<p>Add the ability to have multiple windows open at the same time</p>
<p>Update preferences UI</p>
<p>Fix some bugs</p>
<p>Update translations</p>
<p>Add better error handling</p>
</description>
</release>
<release version="0.2.0" date="2023-5-11" type="stable">
<description>
<p>Add support of formatting in the response view using Markdown</p>
<p>Allow disabling the new render method </p>
<p>Add description of providers</p>
<p>Add help for getting a token for providers</p>
<p>New website including some help for providers</p>
<p>Fix an issue which caused the app to spin forever</p>
<p>Remove Quit entry in the app menu</p>
<p>Fix keyboard shortcuts</p>
<p>Fix some bugs</p>
<p>Update translations</p>
<p>Add better error handling</p>
</description>
</release>
<release version="0.1.7" date="2023-5-7" type="stable">
<description>
<p>Fix an issue which caused the app to crash randomly</p>
<p>Add the ability to enable/disable providers from the preferences</p>
<p>Add more keyboard shortcuts</p>
<p>Update translations</p>
<p>Add better error handling</p>
</description>
</release>
<release version="0.1.6" date="2023-5-6" type="stable">
<description>
<p>Fix an issue which caused the app to crash randomly</p>
<p>Add save/load of settings</p>
</description>
</release>
<release version="0.1.5" date="2023-5-4" type="stable">
<description>
<p>Fix HuggingChat (again)</p>
</description>
</release>
<release version="0.1.4" date="2023-5-4" type="stable">
<description>
<p>Fix HuggingChat</p>
</description>
</release>
<release version="0.1.3" date="2023-5-4" type="stable">
<description>
<p>Add multiple providers support</p>
<p>Make HuggingChat the default provider</p>
<p>Fix some bugs</p>
<p>Focus on the response entry</p>
<p>Update translations</p>
</description>
</release>
<release version="0.1.2" date="2023-4-27" type="stable">
<description>
<p>Fix appdata not having release tags</p>
</description>
</release>
<release version="0.1.1" date="2023-4-27" type="stable">
<description>
<p>Change app ID to io.github.Bavarder.Bavarder</p>
</description>
</release>
<release version="0.1.0" date="2023-4-27" type="stable">
<description>
<p>First release of Bavarder</p>
</description>
</release>
</releases>
<releases>
<release version="1.0.0" date="2023-7-19" type="stable">
<description>
<p>
Brand new UI
</p>
</description>
</release>
<release version="0.2.4" date="2023-6-16" type="stable">
<description>
<p>
New UI
</p>
<p>
Faster BaiChat
</p>
<p>
Fix some bugs
</p>
<p>
Update translations
</p>
<p>
Add better error handling
</p>
</description>
</release>
<release version="0.2.3" date="2023-5-21" type="stable">
<description>
<p>
Add the ability to use local model
</p>
<p>
Add the ability to use custom model in OpenAI
</p>
<p>
Make loading mechanism faster
</p>
<p>
Fix some bugs
</p>
<p>
Update translations
</p>
<p>
Add CI
</p>
<p>
Add support for launching Bavarder offline
</p>
<p>
Update Blueprint to v0.8.0
</p>
<p>
Add better error handling
</p>
</description>
</release>
<release version="0.2.2" date="2023-5-16" type="stable">
<description>
<p>
Allow fetching news about providers and check if there is some issues about them
</p>
<p>
Hugging Chat is now disabled because of a change which require to login
</p>
<p>
Providers moved to the menu
</p>
<p>
Update screenshots
</p>
<p>
Fix some bugs
</p>
<p>
Update translations
</p>
<p>
Add CI
</p>
<p>
Add support for launching Bavarder offline
</p>
<p>
Update Blueprint to v0.8.0
</p>
<p>
Add better error handling
</p>
</description>
</release>
<release version="0.2.1" date="2023-5-13" type="stable">
<description>
<p>
Fix Theming support of the new render widget
</p>
<p>
Add the ability to have multiple windows open at the same time
</p>
<p>
Update preferences UI
</p>
<p>
Fix some bugs
</p>
<p>
Update translations
</p>
<p>
Add better error handling
</p>
</description>
</release>
<release version="0.2.0" date="2023-5-11" type="stable">
<description>
<p>
Add support of formatting in the response view using Markdown
</p>
<p>
Allow disabling the new render method
</p>
<p>
Add description of providers
</p>
<p>
Add help for getting a token for providers
</p>
<p>
New website including some help for providers
</p>
<p>
Fix an issue which caused the app to spin forever
</p>
<p>
Remove Quit entry in the app menu
</p>
<p>
Fix keyboard shortcuts
</p>
<p>
Fix some bugs
</p>
<p>
Update translations
</p>
<p>
Add better error handling
</p>
</description>
</release>
<release version="0.1.7" date="2023-5-7" type="stable">
<description>
<p>
Fix an issue which caused the app to crash randomly
</p>
<p>
Add the ability to enable/disable providers from the preferences
</p>
<p>
Add more keyboard shortcuts
</p>
<p>
Update translations
</p>
<p>
Add better error handling
</p>
</description>
</release>
<release version="0.1.6" date="2023-5-6" type="stable">
<description>
<p>
Fix an issue which caused the app to crash randomly
</p>
<p>
Add save/load of settings
</p>
</description>
</release>
<release version="0.1.5" date="2023-5-4" type="stable">
<description>
<p>
Fix HuggingChat (again)
</p>
</description>
</release>
<release version="0.1.4" date="2023-5-4" type="stable">
<description>
<p>
Fix HuggingChat
</p>
</description>
</release>
<release version="0.1.3" date="2023-5-4" type="stable">
<description>
<p>
Add multiple providers support
</p>
<p>
Make HuggingChat the default provider
</p>
<p>
Fix some bugs
</p>
<p>
Focus on the response entry
</p>
<p>
Update translations
</p>
</description>
</release>
<release version="0.1.2" date="2023-4-27" type="stable">
<description>
<p>
Fix appdata not having release tags
</p>
</description>
</release>
<release version="0.1.1" date="2023-4-27" type="stable">
<description>
<p>
Change app ID to io.github.Bavarder.Bavarder
</p>
</description>
</release>
<release version="0.1.0" date="2023-4-27" type="stable">
<description>
<p>
First release of Bavarder
</p>
</description>
</release>
</releases>
</component>

View file

@ -1,6 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<schemalist gettext-domain="bavarder">
<schema id="@APP_ID@" path="/io/github/Bavarder/Bavarder/">
<key name="local-mode" type="b">
<default>true</default>
</key>
<key name="current-provider" type="s">
<default>'cat-gpt'</default>
</key>
<key name="model" type="s">
<default>'ggml-model-gpt4all-falcon-q4_0.bin'</default>
</key>
<key name="width" type="i">
<default>350</default>
</key>
@ -13,26 +22,6 @@
<key name="is-fullscreen" type="b">
<default>false</default>
</key>
<key name="clear-after-send" type="b">
<default>false</default>
</key>
<key name="enabled-providers" type="as">
<default>["baichat", "hfopenassistantsft1pythia12b", "catgpt", "openaigpt35turbo"]</default>
</key>
<key name="latest-provider" type="s">
<default>'hfopenassistantsft1pythia12b'</default>
</key>
<key name="providers-data" type="a{ss}">
<default>{}</default>
</key>
<key name="use-text-view" type="b">
<default>false</default>
</key>
<key name="close-all-without-dialog" type="b">
<default>false</default>
</key>
<key name="allow-remote-fetching" type="b">
<default>true</default>
</key>
</schema>
</schemalist>

View file

@ -1,7 +1,4 @@
gnome = import('gnome')
pkgdatadir = join_paths(get_option('prefix'), get_option('datadir'), meson.project_name())
subdir('ui')
desktop_file = i18n.merge_file(
input: configure_file(
@ -23,15 +20,6 @@ if desktop_utils.found()
)
endif
gnome.compile_resources('bavarder',
'bavarder.gresource.xml',
gresource_bundle: true,
source_dir: meson.current_build_dir(),
install: true,
install_dir: PKGDATA_DIR,
dependencies: blueprints
)
appstream_file = i18n.merge_file(
input: configure_file(
input: '@0@.appdata.xml.in.in'.format(PROJECT_RDNN_NAME),

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

View file

@ -1,44 +0,0 @@
.text-box textview,
.text-box text {
background: none;
color: inherit;
}
.scrolled-window undershoot.top {
box-shadow: inset 0 1px alpha(@shade_color, .75);
background: linear-gradient(to bottom, alpha(@shade_color, .75), transparent 4px);
}
.scrolled-window undershoot.bottom {
box-shadow: inset 0 -1px alpha(@shade_color, .75);
background: linear-gradient(to top, alpha(@shade_color, .75), transparent 4px);
}
/* Global */
scrolledwindow > viewport > clamp > box {
margin: 42px 12px;
border-spacing: 24px;
}
entry:disabled {
border-color: transparent;
color: @view_fg_color;
background: none;
}
entry textview {
color: @view_fg_color;
background: none;
}
entry text {
color: @view_fg_color;
background: none;
}
entry .inline-pill {
margin-bottom: -0.5em;
}

View file

@ -1,10 +0,0 @@
blueprints = custom_target('blueprints',
input: files(
'help-overlay.blp',
'preferences.blp',
'message_bubble.blp',
'window.blp',
),
output: '.',
command: [find_program('blueprint-compiler'), 'batch-compile', '@OUTPUT@', '@CURRENT_SOURCE_DIR@', '@INPUT@']
)

View file

@ -1,20 +0,0 @@
using Gtk 4.0;
using Adw 1;
template $MessageBubble: Gtk.Box {
orientation: vertical;
Label sender_label {
styles ["caption-heading"]
ellipsize: end;
xalign: 0;
}
Adw.Bin message_reply_bin {}
Adw.Bin prefix_bin {}
Label message_label {
}
}

View file

@ -1,55 +0,0 @@
using Gtk 4.0;
using Adw 1;
template $Preferences : Adw.PreferencesWindow {
title: _("Preferences");
default-height: 400;
default-width: 600;
modal: true;
Adw.PreferencesPage general_page {
Adw.PreferencesGroup prompt_group {
title: _("Prompt");
Adw.ActionRow {
title: _("Clear prompt after send");
subtitle: _("The prompt will be cleared after send");
activatable-widget: clear_after_send_switch;
Gtk.Switch clear_after_send_switch {
valign: center;
}
}
Adw.ActionRow {
title: _("Use plain text for output");
subtitle: _("The plain text without formatting will be used");
activatable-widget: use_text_view_switch;
Gtk.Switch use_text_view_switch {
valign: center;
}
}
Adw.ActionRow {
title: _("Close all windows without warning");
subtitle: _("All windows will be closed without warning, this can lead to data loss");
activatable-widget: close_all_without_dialog_switch;
Gtk.Switch close_all_without_dialog_switch {
valign: center;
}
}
Adw.ActionRow {
title: _("Look for provider news");
subtitle: _("News about issues with providers will be fetched from Bavarder website");
activatable-widget: allow_remote_fetching_switch;
Gtk.Switch allow_remote_fetching_switch {
valign: center;
}
}
}
Adw.PreferencesGroup provider_group {
title: _("Providers");
}
}
}

View file

@ -1,254 +0,0 @@
using Gtk 4.0;
using Adw 1;
using WebKit 6.0;
template $BavarderWindow : Adw.ApplicationWindow {
title: _("Bavarder");
default-width: 350;
default-height: 500;
ShortcutController {
Shortcut {
trigger: "<primary>q";
action: "action(window.close)";
}
}
Adw.ToastOverlay toast_overlay {
Box {
orientation: vertical;
vexpand: true;
hexpand: true;
Adw.HeaderBar {
MenuButton menu {
primary: true;
menu-model: main-menu;
icon-name: "open-menu-symbolic";
tooltip-text: _("Main Menu");
}
styles ["flat"]
}
Adw.Banner banner {
title: _("No network connection");
revealed: false;
}
Box main {
orientation: vertical;
vexpand: true;
hexpand: true;
margin-start: 24;
margin-end: 24;
spacing: 12;
Adw.Bin {
vexpand: true;
hexpand: true;
Box {
orientation: vertical;
Stack stack {
transition-type: crossfade;
styles [ "card"]
Gtk.StackPage {
name: "page_content";
child: Overlay overlay {
Adw.PreferencesGroup bot_group {
Box {
orientation: vertical;
hexpand: true;
vexpand: true;
styles [ "text-box"]
ScrolledWindow scrolled_response_window {
margin-top: 12;
margin-bottom: 0;
margin-start: 12;
margin-end: 12;
TextView bot_text_view {
wrap-mode: word_char;
hexpand: true;
vexpand: true;
editable: false;
}
}
Box {
hexpand: true;
halign: end;
styles ["toolbar"]
// Button speak {
// action-name: "app.speak";
// tooltip-text: _("Speak");
// icon-name: "audio-speakers-symbolic";
// }
// Button speak_wait {
// visible: false;
// sensitive: false;
// tooltip-text: _("Speaking");
// Spinner speak_spinner {
// margin-top: 8;
// margin-bottom: 8;
// margin-start: 8;
// margin-end: 8;
// }
// }
Button copy_bot {
sensitive: false;
icon-name: "edit-copy-symbolic";
tooltip-text: _("Copy to Clipboard");
hexpand: true;
halign: end;
action-name: "app.copy_bot";
}
Button stop_button {
visible: false;
sensitive: false;
icon-name: "x-circular-symbolic";
tooltip-text: _("Stop");
hexpand: true;
halign: end;
action-name: "app.stop";
styles ["suggested-action", "circular"]
}
}
}
}
};
}
Gtk.StackPage {
name: "page_loading";
child: Spinner {
valign: center;
halign: center;
vexpand: true;
};
}
Gtk.StackPage {
name: "page_error";
child: Adw.StatusPage error {
visible: true;
vexpand: true;
icon-name: "dialog-error-symbolic";
title: _("ERROR");
description: _("DESCRIPTION");
Button {
label: _("Try Again");
halign: center;
styles ["pill"]
}
};
}
}
// Separator {}
Adw.Clamp {
vexpand: false;
hexpand: true;
maximum-size: 750;
tightening-threshold: 550;
margin-top: 8;
margin-bottom: 8;
Box {
// Button {
// valign: end;
// icon-name: "mail-attachment-symbolic";
// }
ScrolledWindow {
vexpand: true;
hexpand: true;
vscrollbar-policy: external;
max-content-height: 200;
propagate-natural-height: true;
styles [ "scrolled-window" ]
TextView prompt_text_view {
styles [ "entry "]
hexpand: true;
accepts-tab: false;
top-margin: 7;
bottom-margin: 7;
left-margin: 5;
right-margin: 5;
wrap-mode: word;
buffer: TextBuffer { };
}
}
Button ask_button {
valign: end;
margin-start: 5;
icon-name: "paper-plane-symbolic";
tooltip-text: _("Ask");
halign: end;
action-name: "app.ask";
styles ["suggested-action", "circular"]
}
}
}
}
}
}
}
}
}
menu main-menu {
section {
item {
label: _("New window");
action: "app.new";
}
}
section {
item {
label: _("Preferences");
action: "app.preferences";
}
item {
label: _("Keyboard Shortcuts");
action: "win.show-help-overlay";
}
item {
label: _("About Bavarder");
action: "app.about";
}
}
}

View file

@ -1,5 +1,5 @@
project('bavarder',
version: '0.2.4',
version: '0.1.0',
meson_version: '>= 0.62.0',
default_options: [ 'warning_level=2', 'werror=false', ],
)
@ -10,11 +10,16 @@ python = import('python')
# Constants
PROJECT_RDNN_NAME = 'io.github.Bavarder.Bavarder'
BUGTRACKER_URL = 'https://codeberg.org/Bavarder/Bavarder/issues'
HELP_URL = 'https://codeberg.orgBavarder/Bavarder/issues'
TRANSLATE_URL = 'https://translate.codeberg.org/engage/bavarder/'
BUGTRACKER_URL = 'https://gnome.org'
HELP_URL = 'https://gnome.org'
TRANSLATE_URL = 'https://gnome.org'
PROJECT_URL = 'https://bavarder.codeberg.page'
PROJECT_URL = 'https://gnome.org'
dependency('gtk4', version: '>= 4.5.0')
dependency('libadwaita-1', version: '>= 1.3.99')
dependency('libportal', version: '>= 0.6')
dependency('gtksourceview-5', version: '>= 5')
git_bin = find_program('git', required: false)

View file

@ -1,11 +0,0 @@
option(
'profile',
type: 'combo',
description: 'The build profiles for the application. Use development or ci for the .Devel app ID. ci also produces optimized bundles.',
choices: [
'release',
'development',
'ci',
],
value: 'release'
)

View file

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-06-01 17:40+0000\n"
"POT-Creation-Date: 2023-07-19 12:39+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@ -17,175 +17,135 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: data/io.github.Bavarder.Bavarder.desktop.in.in:3 data/ui/window.blp:7
#: data/io.github.Bavarder.Bavarder.desktop.in.in:3 src/views/window.blp:6
#: src/views/window.blp:26
msgid "Bavarder"
msgstr ""
#: data/ui/preferences.blp:5 data/ui/window.blp:230 src/main.py:273
msgid "Preferences"
#: src/providers/catgpt.py:7
msgid "Chit-Chat with a Cat"
msgstr ""
#: data/ui/preferences.blp:12
msgid "Prompt"
msgstr ""
#: data/ui/preferences.blp:15
msgid "Clear prompt after send"
msgstr ""
#: data/ui/preferences.blp:16
msgid "The prompt will be cleared after send"
msgstr ""
#: data/ui/preferences.blp:24
msgid "Use plain text for output"
msgstr ""
#: data/ui/preferences.blp:25
msgid "The plain text without formatting will be used"
msgstr ""
#: data/ui/preferences.blp:33
msgid "Close all windows without warning"
msgstr ""
#: data/ui/preferences.blp:34
msgid "All windows will be closed without warning, this can lead to data loss"
msgstr ""
#: data/ui/preferences.blp:42
msgid "Look for provider news"
msgstr ""
#: data/ui/preferences.blp:43
msgid "News about issues with providers will be fetched from Bavarder website"
msgstr ""
#: data/ui/preferences.blp:52 src/main.py:271
msgid "Providers"
msgstr ""
#: data/ui/window.blp:28
msgid "Main Menu"
msgstr ""
#: data/ui/window.blp:34 src/providers/base.py:50
msgid "No network connection"
msgstr ""
#: data/ui/window.blp:61
msgid "Response"
msgstr ""
#: data/ui/window.blp:113
msgid "Copy to Clipboard"
msgstr ""
#: data/ui/window.blp:123
msgid "Stop"
msgstr ""
#: data/ui/window.blp:152
msgid "ERROR"
msgstr ""
#: data/ui/window.blp:153
msgid "DESCRIPTION"
msgstr ""
#: data/ui/window.blp:156
msgid "Try Again"
msgstr ""
#: data/ui/window.blp:205
msgid "Ask"
msgstr ""
#: data/ui/window.blp:224
msgid "New window"
msgstr ""
#: data/ui/window.blp:235 src/main.py:274
msgid "Keyboard Shortcuts"
msgstr ""
#: data/ui/window.blp:240 src/main.py:275
msgid "About Bavarder"
msgstr ""
#: src/providers/base.py:43
msgid "No API key provided, you can provide one in settings"
msgstr ""
#: src/providers/base.py:45
msgid "Open settings"
msgstr ""
#: src/providers/base.py:81
msgid "About provider"
msgstr ""
#: src/providers/base.py:95
msgid "How to get a token"
msgstr ""
#: src/providers/base.py:118
#: src/providers/provider_item.blp:12
msgid "No preferences available"
msgstr ""
#: src/providers/huggingface.py:73 src/providers/transformer.py:68
msgid "API Key"
msgstr ""
#: src/providers/openai.py:27
msgid "Prompt too long, splitting into chunks."
msgstr ""
#: src/providers/openai.py:49
msgid "You don't have access to this model"
msgstr ""
#: src/providers/openai.py:54
msgid ""
"You exceeded your current quota, please check your plan and billing details."
msgstr ""
#: src/providers/openai.py:59
msgid "API Error"
msgstr ""
#: src/providers/openai.py:70
msgid "No model selected, you can choose one in preferences"
msgstr ""
#: src/providers/openaicustom.py:33
msgid "API Url"
msgstr ""
#: src/providers/openaicustom.py:40
msgid "Model"
msgstr ""
#: src/providers/openaicustom.py:80
msgid "How to choose a model"
msgstr ""
#: src/views/about_window.py:12
msgid "translator-credits"
msgstr ""
#: src/views/about_window.py:26
msgid "0xMRTT"
msgid "Bavarder Developers"
msgstr ""
#: src/views/about_window.py:44
msgid "Copyright © 2023 0xMRTT"
msgid "Copyright © 2023 Bavarder Developers"
msgstr ""
#: src/main.py:124
msgid "New version available!"
#: src/views/preferences_window.py:47 src/views/preferences_window.blp:17
msgid "Models"
msgstr ""
#: src/main.py:240
msgid "New Window"
#: src/views/preferences_window.py:54
msgid "Download more models"
msgstr ""
#: src/views/preferences_window.blp:5 src/views/window.py:156
#: src/views/window.py:178 src/views/window.blp:218
msgid "Preferences"
msgstr ""
#: src/views/preferences_window.blp:13
msgid "Providers"
msgstr ""
#: src/views/window.py:227
msgid "Generating response"
msgstr ""
#: src/views/window.py:228
msgid "Cancel"
msgstr ""
#: src/views/window.blp:33 src/main.py:146
msgid "New Chat"
msgstr ""
#: src/views/window.blp:41
msgid "Main Menu"
msgstr ""
#: src/views/window.blp:57
msgid "Message"
msgstr ""
#: src/views/window.blp:69
msgid "Chat"
msgstr ""
#: src/views/window.blp:115
msgid "No Chat"
msgstr ""
#: src/views/window.blp:120
msgid "No Internet"
msgstr ""
#: src/views/window.blp:179
msgid "Ask"
msgstr ""
#: src/views/window.blp:223
msgid "Keyboard Shortcuts"
msgstr ""
#: src/views/window.blp:228
msgid "About Bavarder"
msgstr ""
#: src/widgets/download_row.py:29
#, python-format
msgid "Downloading model %s"
msgstr ""
#: src/widgets/download_row.py:45
#, python-format
msgid "Model %s downloaded!"
msgstr ""
#: src/widgets/item.blp:79
msgid "Edit"
msgstr ""
#: src/widgets/item.blp:85
msgid "Remove"
msgstr ""
#: src/widgets/item.py:137
msgid "User"
msgstr ""
#: src/widgets/item.py:141
msgid "Assistant"
msgstr ""
#: src/widgets/model_item.py:30
#, python-format
msgid "Model %s deleted!"
msgstr ""
#: src/widgets/thread_item.blp:29 src/widgets/thread_item.py:54
msgid "Edit Title"
msgstr ""
#: src/widgets/thread_item.py:46
msgid "Set Title"
msgstr ""
#: src/main.py:226
msgid "Please download a model from Preferences!"
msgstr ""
#: src/main.py:239
msgid "Please enable a provider from the Brain Menu"
msgstr ""

View file

@ -1,23 +1,23 @@
th
sv
fa
fi
ru
ta
nl
gl
es
fr
pt
hu
de
tr
pl
ar
it
zh_Hans
az
cs
uk
de
es
et
fa
fi
fr
gl
hu
it
nl
pl
pt
ru
sv
ta
th
tr
uk
zh_Hans
zh_Hant

View file

@ -1,39 +1,26 @@
data/io.github.Bavarder.Bavarder.desktop.in.in
data/io.github.Bavarder.Bavarder.gschema.xml.in
data/ui/help-overlay.blp
data/ui/preferences.blp
data/ui/window.blp
src/gtk/help-overlay.blp
src/providers/__init__.py
src/providers/alpacalora.py
src/providers/baichat.py
src/providers/bard.py
src/providers/base.py
src/providers/baseoffline.py
src/providers/catgpt.py
src/providers/gradio.py
src/providers/hfdialogpt.py
src/providers/hfgoogleflant5xxl.py
src/providers/hfgoogleflanu12.py
src/providers/hfgpt2.py
src/providers/hfgpt2large.py
src/providers/hfgpt2xl.py
src/providers/hfopenassistantsft1pythia12b.py
src/providers/huggingchat.py
src/providers/huggingchatbase.py
src/providers/huggingface.py
src/providers/openai.py
src/providers/openaicustom.py
src/providers/openaigpt4.py
src/providers/openaigpt35turbo.py
src/providers/openaitextdavinci003.py
src/providers/stablelm.py
src/providers/starcoder.py
src/providers/transformer.py
src/providers/provider_item.blp
src/providers/provider_item.py
src/views/__init__.py
src/views/about_window.py
src/views/main_window.py
src/views/preferences_window.py
src/views/preferences_window.blp
src/views/window.py
src/views/window.blp
src/widgets/__init__.py
src/widgets/download_row.blp
src/widgets/download_row.py
src/widgets/item.blp
src/widgets/item.py
src/widgets/model_item.blp
src/widgets/model_item.py
src/widgets/thread_item.blp
src/widgets/thread_item.py
src/__init__.py
src/threading.py
src/main.py
src/main.py
src/threading.py

0
po/update-pot.sh Normal file → Executable file
View file

View file

@ -2,25 +2,8 @@
# chmod +x flatpak-pip-generator
# ./flatpak-pip-generator --requirements-file=requirements.txt --output pypi-dependencies
# use https://johannesjh.github.io/req2flatpak/main/cli.html
# 1. pip-compile -o r.txt requirements.txt
# 2. ./req2flatpak.py --requirements-file requirements.txt --target-platforms 310-x86_64 310-aarch64 > build-aux/pypi-dependencies.json
Pygments
baichat_py
googlebardpy
markdown
openai
pymdown-extensions
requests
text-generation
gradio_client
# replace the curl-cffi entry with
# {
# "type": "file",
# "url": "https://files.pythonhosted.org/packages/d1/6f/5d591a5628423af4598e2d6ff0861fcbc554cc259590fac9f97d9c984611/curl_cffi-0.5.6-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
# "sha256": "7a9df9fabff038f1ac9e7e6f32b5edb5d8df8c2eec64f53f513de1766c17ffdb"
# },
#
tqdm
charset-normalizer
idna
urllib3

View file

@ -1,23 +0,0 @@
diff -Naur a/data/io.github.Bavarder.Bavarder.appdata.xml.in.in b/data/io.github.Bavarder.Bavarder.appdata.xml.in.in
--- a/data/io.github.Bavarder.Bavarder.appdata.xml.in.in 2023-06-24 00:43:11.699372881 +0530
+++ b/data/io.github.Bavarder.Bavarder.appdata.xml.in.in 2023-06-24 00:47:32.092750714 +0530
@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<component type="desktop">
<id>@APP_ID@</id>
+ <icon type="stock">snap.bavarder.@APP_ID@</icon>
<name>Bavarder</name>
<summary>Chit-chat with an AI</summary>
<developer_name>0xMRTT</developer_name>
diff -Naur a/data/io.github.Bavarder.Bavarder.desktop.in.in b/data/io.github.Bavarder.Bavarder.desktop.in.in
--- a/data/io.github.Bavarder.Bavarder.desktop.in.in 2023-06-24 00:43:11.699372881 +0530
+++ b/data/io.github.Bavarder.Bavarder.desktop.in.in 2023-06-24 00:47:54.940385267 +0530
@@ -1,7 +1,7 @@
[Desktop Entry]
Name=Bavarder
Exec=bavarder
-Icon=@APP_ID@
+Icon=snap.bavarder.@APP_ID@
Terminal=false
Type=Application
Categories=GTK;

View file

@ -1,98 +0,0 @@
name: bavarder # you probably want to 'snapcraft register <name>'
base: core22 # the base snap is the execution environment for this snap
adopt-info: bavarder
grade: stable # must be 'stable' to release into candidate/stable channels
confinement: strict # use 'strict' once you have the right plugs and slots
architectures:
- build-on: amd64
- build-on: arm64
layout:
/usr/lib/x86_64-linux-gnu/webkitgtk-6.0:
bind: $SNAP/webkitgtk-platform/usr/lib/x86_64-linux-gnu/webkitgtk-6.0
parts:
blueprint-compiler:
source: https://gitlab.gnome.org/jwestman/blueprint-compiler.git
source-tag: 'v0.8.1'
plugin: meson
meson-parameters:
- --prefix=/usr
override-prime: |
echo 'Skip'
bavarder:
after: [blueprint-compiler]
# See 'snapcraft plugins'
plugin: meson
source: https://github.com/Bavarder/Bavarder.git
source-tag: '0.2.4'
meson-parameters:
- --prefix=/snap/bavarder/current/usr
- -Dbuildtype=release
build-snaps:
- webkitgtk-6-gnome-2204-sdk/latest/stable
build-environment:
- LD_LIBRARY_PATH: /snap/webkitgtk-sdk/current/usr/lib:/snap/webkitgtk-sdk/current/usr/lib/$CRAFT_ARCH_TRIPLET:/snap/webkitgtk-sdk/current/usr/lib/webkitgtk-6.0:/snap/webkitgtk-sdk/current/usr/lib/$CRAFT_ARCH_TRIPLET/girepository-1.0:$LD_LIBRARY_PATH
- PYTHONPATH: $CRAFT_STAGE/usr/lib/python3/dist-packages:$CRAFT_PART_INSTALL/usr/local/lib/python3.10/dist-packages:$PYTHONPATH
- GI_TYPELIB_PATH: /snap/gnome-42-2204-sdk/current/usr/lib/$CRAFT_ARCH_TRIPLET/girepository-1.0:/snap/gnome-42-2204-sdk/current/usr/lib/girepository-1.0:/snap/webkitgtk-6-gnome-2204-sdk/current/usr/lib/$CRAFT_ARCH_TRIPLET/girepository-1.0
override-pull: |
craftctl default
patch -p1 < $CRAFT_PROJECT_DIR/snap/bavarder.patch
pip install --prefix=$CRAFT_PART_INSTALL/usr baichat-py==0.3.0 googlebardpy==0.1.0 openai==0.27.7 pymdown-extensions==10.0.1 requests==2.31.0 text-generation==0.5.2 gradio-client==0.2.5 lxml
override-build: |
craftctl default
mkdir -p $CRAFT_PART_INSTALL/meta/gui
cp -r $CRAFT_PART_INSTALL/snap/bavarder/current/usr/share/icons $CRAFT_PART_INSTALL/meta/gui/
find $CRAFT_PART_INSTALL/meta/gui/icons -type f -not -name 'io.github.Bavarder.Bavarder*' -exec rm {} + -o -type d -empty -exec rmdir {} +
for i in `find $CRAFT_PART_INSTALL/meta/gui/icons -name "*.svg" -o -name "*.png"`; do
mv $i "`dirname $i`/snap.$CRAFT_PROJECT_NAME.`basename $i`"
done
sed -e '1c#!/usr/bin/python3' -i $CRAFT_PART_INSTALL/usr/local/bin/*
sed -e '1c#!/usr/bin/env python3' -i $CRAFT_PART_INSTALL/snap/bavarder/current/usr/bin/bavarder
chmod +x $CRAFT_PART_INSTALL/snap/bavarder/current/usr/bin/bavarder
parse-info: [usr/share/appdata/io.github.Bavarder.Bavarder.appdata.xml]
organize:
snap/bavarder/current: .
usr/local: usr
prime:
- -snap/bavarder
gst:
after: [ bavarder ]
plugin: nil
stage-packages:
- gir1.2-gstreamer-1.0
prime:
- usr/lib/$CRAFT_ARCH_TRIPLET/girepository-1.0/Gst-1.0.typelib
- usr/lib/$CRAFT_ARCH_TRIPLET/girepository-1.0/GstBase-1.0.typelib
- usr/lib/$CRAFT_ARCH_TRIPLET/girepository-1.0/GstCheck-1.0.typelib
- usr/lib/$CRAFT_ARCH_TRIPLET/girepository-1.0/GstController-1.0.typelib
- usr/lib/$CRAFT_ARCH_TRIPLET/girepository-1.0/GstNet-1.0.typelib
plugs:
webkitgtk-6-gnome-2204:
interface: content
target: $SNAP/webkitgtk-platform
default-provider: webkitgtk-6-gnome-2204
slots:
bavarder:
interface: dbus
bus: session
name: io.github.Bavarder.Bavarder
apps:
bavarder:
command: usr/bin/bavarder
extensions: [gnome]
common-id: io.github.Bavarder.Bavarder
environment:
PYTHONPATH: $SNAP/usr/lib/python3.10/dist-packages:$PYTHONPATH
GI_TYPELIB_PATH: $SNAP/webkitgtk-platform/usr/lib/$CRAFT_ARCH_TRIPLET/girepository-1.0:$GI_TYPELIB_PATH
LD_LIBRARY_PATH: $SNAP/webkitgtk-platform/usr/lib/$SNAPCRAFT_ARCH_TRIPLET:$SNAP/webkitgtk-platform/usr/lib/$SNAPCRAFT_ARCH_TRIPLET/webkitgtk-6.0:$LD_LIBRARY_PATH
plugs:
- network
- network-status
- network-bind
- unity7

View file

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<gresources>
<gresource prefix="/io/github/Bavarder/Bavarder">
<file preprocess="xml-stripblanks" alias="ui/window.ui">views/window.ui</file>
<file preprocess="xml-stripblanks" alias="ui/preferences_window.ui">views/preferences_window.ui</file>
<file preprocess="xml-stripblanks" alias="ui/thread_item.ui">widgets/thread_item.ui</file>
<file preprocess="xml-stripblanks" alias="ui/item.ui">widgets/item.ui</file>
<file preprocess="xml-stripblanks" alias="ui/provider_item.ui">providers/provider_item.ui</file>
<file preprocess="xml-stripblanks" alias="ui/model_item.ui">widgets/model_item.ui</file>
<file preprocess="xml-stripblanks" alias="ui/download_row.ui">widgets/download_row.ui</file>
<file preprocess="xml-stripblanks" alias="ui/code_block.ui">widgets/code_block.ui</file>
<file preprocess="xml-stripblanks">gtk/help-overlay.ui</file>
<file>style.css</file>
</gresource>
<gresource prefix="/io/github/Bavarder/Bavarder/icons/scalable/actions/">
<file preprocess="xml-stripblanks" alias="check-round-outline-symbolic.svg">../data/icons/hicolor/scalable/actions/check-round-outline-symbolic.svg</file>
<file preprocess="xml-stripblanks" alias="paper-plane-symbolic.svg">../data/icons/hicolor/scalable/actions/paper-plane-symbolic.svg</file>
<file preprocess="xml-stripblanks" alias="cloud-disabled-symbolic.svg">../data/icons/hicolor/scalable/actions/cloud-disabled-symbolic.svg</file>
<file preprocess="xml-stripblanks" alias="cloud-filled-symbolic.svg">../data/icons/hicolor/scalable/actions/cloud-filled-symbolic.svg</file>
<file preprocess="xml-stripblanks" alias="brain-augemnted-symbolic.svg">../data/icons/hicolor/scalable/actions/brain-augemnted-symbolic.svg</file>
<file preprocess="xml-stripblanks" alias="chat-message-new-symbolic.svg">../data/icons/hicolor/scalable/actions/chat-message-new-symbolic.svg</file>
<file preprocess="xml-stripblanks" alias="network-disconnected-symbolic.svg">../data/icons/hicolor/scalable/actions/network-disconnected-symbolic.svg</file>
<file preprocess="xml-stripblanks" alias="bot-symbolic.svg">../data/icons/hicolor/scalable/actions/bot-symbolic.svg</file>
<file preprocess="xml-stripblanks" alias="terminal-symbolic.svg">../data/icons/hicolor/scalable/actions/terminal-symbolic.svg</file>
</gresource>
</gresources>

View file

@ -2,7 +2,7 @@
# bavarder.in
#
# Copyright 2023 Me
# Copyright 2023
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by

View file

@ -10,11 +10,6 @@ ShortcutsWindow help_overlay {
ShortcutsGroup {
title: C_("shortcut window", "General");
ShortcutsShortcut {
title: C_("shortcut window", "Ask");
action-name: "app.ask";
}
ShortcutsShortcut {
title: C_("shortcut window", "Show Shortcuts");
action-name: "win.show-help-overlay";
@ -31,18 +26,13 @@ ShortcutsWindow help_overlay {
}
ShortcutsShortcut {
title: C_("shortcut window", "Close all windows");
action-name: "app.quit_all";
title: C_("shortcut window", "Ask");
action-name: "app.ask";
}
ShortcutsShortcut {
title: C_("shortcut window", "Copy response");
action-name: "app.copy_bot";
}
ShortcutsShortcut {
title: C_("shortcut window", "Clear");
action-name: "app.clear";
title: C_("shortcut window", "Cancel Generation");
action-name: "win.cancel";
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -1,9 +1,31 @@
pkgdatadir = join_paths(get_option('prefix'), get_option('datadir'), meson.project_name())
moduledir = join_paths(pkgdatadir, 'bavarder')
gnome = import('gnome')
python = import('python')
blueprints = custom_target('blueprints',
input: files(
'gtk/help-overlay.blp',
'views/preferences_window.blp',
'views/window.blp',
'widgets/thread_item.blp',
'widgets/item.blp',
'widgets/model_item.blp',
'widgets/download_row.blp',
'widgets/code_block.blp',
'providers/provider_item.blp',
),
output: '.',
command: [find_program('blueprint-compiler'), 'batch-compile', '@OUTPUT@', '@CURRENT_SOURCE_DIR@', '@INPUT@']
)
gnome.compile_resources('bavarder',
'bavarder.gresource.xml',
gresource_bundle: true,
install: true,
install_dir: PKGDATA_DIR,
dependencies: blueprints
)
configure_file(
input: 'bavarder.in',
output: 'bavarder',
@ -18,17 +40,17 @@ configure_file(
output: 'constants.py',
configuration: conf,
install: true,
install_dir: moduledir
install_dir: MODULE_DIR
)
bavarder_sources = [
'__init__.py',
'main.py',
'threading.py',
'threading.py'
]
PY_INSTALLDIR.install_sources(bavarder_sources, subdir: moduledir)
PY_INSTALLDIR.install_sources(bavarder_sources, subdir: MODULE_DIR)
subdir('providers')
subdir('views')
subdir('widgets')
subdir('widgets')
subdir('providers')

View file

@ -1,38 +1,5 @@
# from .huggingchat import HuggingChatProvider
from .baichat import BAIChatProvider
from .openaigpt35turbo import OpenAIGPT35TurboProvider
from .openaigpt4 import OpenAIGPT4Provider
from .openaicustom import OpenAICustomProvider, LocalModel
from .catgpt import CatGPTProvider
from .openaitextdavinci003 import OpenAITextDavinci003
from .alpacalora import AlpacaLoRAProvider
from .hfgoogleflant5xxl import HuggingFaceGoogleFlanT5XXLProvider
from .hfgoogleflanu12 import HuggingFaceGoogleFlanU12Provider
from .hfopenassistantsft1pythia12b import HuggingFaceOpenAssistantSFT1PythiaProvider, HuggingChatMask
from .hfgpt2 import HuggingFaceGPT2Provider
from .hfdialogpt import HuggingFaceDialoGPTLargeProvider
# from .bard import BardProvider
from .hfgpt2large import HuggingFaceGPT2LargeProvider
from .hfgpt2xl import HuggingFaceGPT2XLProvider
from .stablelm import StableLMProvider
PROVIDERS = {
"alpacalora": AlpacaLoRAProvider,
"baichat": BAIChatProvider,
# "bard": BardProvider, # Disabled because we need more documentation on how to use it
"catgpt": CatGPTProvider,
"hfdialogpt": HuggingFaceDialoGPTLargeProvider,
"hfgoogleflant5xxl": HuggingFaceGoogleFlanT5XXLProvider,
"hfgoogleflanu12": HuggingFaceGoogleFlanU12Provider,
"hfgpt2": HuggingFaceGPT2Provider,
"hfgpt2large": HuggingFaceGPT2LargeProvider,
"hfgpt2xl": HuggingFaceGPT2XLProvider,
"hfopenassistantsft1pythia12b": HuggingFaceOpenAssistantSFT1PythiaProvider,
"huggingchat": HuggingChatMask, # hugging chat is replaced by open assistant
"local": LocalModel,
"openaicustom": OpenAICustomProvider,
"openaigpt35turbo": OpenAIGPT35TurboProvider,
"openaigpt4": OpenAIGPT4Provider,
"openaitextdavinci003": OpenAITextDavinci003,
"stablelm": StableLMProvider,
}
CatGPTProvider,
}

View file

@ -1,55 +0,0 @@
from .base import BavarderProvider
import socket
import requests
from gi.repository import Gtk, Adw, GLib
class AlpacaLoRAProvider(BavarderProvider):
name = "Alpaca-LoRA"
slug = "alpacalora"
def __init__(self, win, app, *args, **kwargs):
super().__init__(win, app, *args, **kwargs)
def ask(self, prompt):
try:
response = requests.post(
"https://tloen-alpaca-lora.hf.space/run/predict",
json={
"data": [
prompt,
prompt,
0.1,
0.75,
40,
4,
128,
]
},
).json()
except socket.gaierror:
self.no_connection()
return ""
else:
self.win.banner.set_revealed(False)
if "error" in response:
self.win.banner.props.title = response["error"]
self.win.banner.props.button_label = ""
self.win.banner.set_revealed(True)
return ""
else:
r = response["data"][0]
GLib.idle_add(self.update_response, r)
return r
@property
def require_api_key(self):
return False
def save(self):
return {}
def load(self, data):
pass

View file

@ -1,41 +0,0 @@
from .base import BavarderProvider
from baichat_py import Completion
import socket
from gi.repository import Gtk, Adw, GLib
class BAIChatProvider(BavarderProvider):
name = "BAI Chat"
slug = "baichat"
def __init__(self, win, app, *args, **kwargs):
super().__init__(win, app, *args, **kwargs)
def ask(self, prompt):
try:
response = ""
for token in Completion.create(prompt):
response += token
GLib.idle_add(self.update_response, response)
except KeyError:
self.win.banner.set_revealed(False)
return ""
except socket.gaierror:
self.no_connection()
return ""
else:
self.win.banner.set_revealed(False)
GLib.idle_add(self.update_response, response)
return response
@property
def require_api_key(self):
return False
def save(self):
return {}
def load(self, data):
pass

View file

@ -1,80 +0,0 @@
from .base import BavarderProvider
import socket
from googlebardpy import BardChat
from gi.repository import Gtk, Adw, GLib
class BardProvider(BavarderProvider):
name = "Bard"
slug = "bard"
version = "0.1.0"
url = "https://bavarder.codeberg.page/help/bavarder"
def __init__(self, win, app, *args, **kwargs):
super().__init__(win, app, *args, **kwargs)
self.pref_win = None
def ask(self, prompt):
try:
response = self.chat.ask(prompt)
response = response["content"]
except AttributeError:
self.no_api_key()
return ""
except socket.gaierror:
self.no_connection()
return ""
else:
self.hide_banner()
GLib.idle_add(self.update_response, response)
return response
@property
def require_api_key(self):
return True
def preferences(self, win):
self.pref_win = win
self.expander = Adw.ExpanderRow()
self.expander.props.title = self.name
self.expander.add_action(self.about())
self.expander.add_action(self.enable_switch())
self.api_row = Adw.PasswordEntryRow()
self.api_row.connect("apply", self.on_apply)
self.api_row.props.title = "__Secure-1PSID cookie"
self.api_row.set_show_apply_button(True)
self.api_row.add_suffix(self.how_to_get_a_token())
self.expander.add_row(self.api_row)
return self.expander
def on_apply(self, widget):
self.hide_banner()
api_key = self.api_row.get_text()
self.api_key = api_key
try:
self.chat = BardChat(api_key)
except AttributeError:
self.banner.props.title = "Invalid API key"
self.banner.props.button_label = ""
self.banner.set_revealed(True)
def save(self):
try:
return {"api_key": self.api_key}
except AttributeError: # no api key
return {}
def load(self, data):
try:
self.chat = BardChat(data["api_key"])
self.api_key = data["api_key"]
except AttributeError:
self.chat = None
self.api_key = None

View file

@ -1,140 +1,66 @@
from gettext import gettext as _
import unicodedata
import re
from typing import List, Dict
from gi.repository import Gtk, Adw, GLib
import json
class BavarderProvider:
name = None
slug = None
description = ""
languages = ""
version = "0.1.7"
developer_name = "0xMRTT"
class BaseProvider:
name: str
description: str = ""
languages: List[str] = []
developer_name: str = "0xMRTT"
developers = ["0xMRTT https://github.com/0xMRTT"]
license_type = Gtk.License.GPL_3_0
copyright = "© 2023 0xMRTT"
url = "https://bavarder.codeberg.page/help/bard"
data: Dict[str, str] = {}
has_auth: bool = False
require_authentification: bool = False
def __init__(self, app, window, providers):
self.slug = self.slugify(self.name)
self.copyright = f"© 2023 {self.developer_name}"
self.url = f"https://bavarder.codeberg.page/providers/{self.slug}"
def __init__(self, win, app, *args, **kwargs):
self.win = win
self.banner = win.banner
self.app = app
self.chat = None
self.update_response = app.update_response
self.window = window
def ask(self, prompt):
raise NotImplementedError()
self.providers = providers
try:
self.providers[self.slug]
except KeyError:
self.providers[self.slug] = {
"enabled": False,
"data": {
}
}
finally:
self.data = self.providers[self.slug]["data"]
@property
def require_api_key(self):
def enabled(self):
return self.providers[self.slug]["enabled"]
def set_enabled(self, status):
self.providers[self.slug]["enabled"] = status
def ask(self, prompt, chat):
raise NotImplementedError()
def preferences(self, win):
return self.no_preferences(win)
def no_api_key(self, title=None):
if title:
self.win.banner.props.title = title
else:
self.win.banner.props.title = _(
"No API key provided, you can provide one in settings"
)
self.win.banner.props.button_label = _("Open settings")
self.win.banner.connect("button-clicked", self.app.on_preferences_action)
self.win.banner.set_revealed(True)
def no_connection(self):
self.win.banner.props.title = _("No network connection")
self.win.banner.props.button_label = ""
self.win.banner.set_revealed(True)
def hide_banner(self):
self.win.banner.set_revealed(False)
def about(self, *args, **kwargs):
popover = Gtk.Popover()
vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
title = Gtk.Label()
title.set_markup(f"<b>{self.name}</b>\n<small>Version {self.version}</small>")
title.set_halign(Gtk.Align.CENTER)
title.set_valign(Gtk.Align.CENTER)
vbox.append(title)
if self.description:
description = Gtk.Label()
if self.languages:
description.set_markup(
f"<small>{self.description}</small>\n<small>Languages: {self.languages}</small>"
)
else:
description.set_markup(f"<small>{self.description}</small>")
description.set_halign(Gtk.Align.CENTER)
description.set_valign(Gtk.Align.CENTER)
vbox.append(description)
popover.set_child(vbox)
about_button = Gtk.MenuButton()
about_button.set_icon_name("help-about-symbolic")
about_button.set_tooltip_text(_("About provider"))
about_button.add_css_class("flat")
about_button.set_valign(Gtk.Align.CENTER)
about_button.set_popover(popover)
return about_button
def open_documentation(self, *args, **kwargs):
GLib.spawn_command_line_async(
f"xdg-open {self.url}"
)
def how_to_get_a_token(self):
about_button = Gtk.Button()
about_button.set_icon_name("dialog-information-symbolic")
about_button.set_tooltip_text(_("How to get a token"))
about_button.add_css_class("flat")
about_button.set_valign(Gtk.Align.CENTER)
about_button.connect("clicked", self.open_documentation)
return about_button
def enable_switch(self):
enabled = Gtk.Switch()
enabled.set_active(self.slug in self.app.enabled_providers)
enabled.connect("notify::active", self.on_enabled)
enabled.set_valign(Gtk.Align.CENTER)
return enabled
def no_preferences(self, win):
self.pref_win = win
self.expander = Adw.ExpanderRow()
self.expander.props.title = self.name
self.expander.add_action(self.about()) # TODO: in Adw 1.4, use add_suffix
self.expander.add_action(self.enable_switch())
self.no_pref_row = Adw.ActionRow()
self.no_pref_row.props.title = _("No preferences available")
self.expander.add_row(self.no_pref_row)
return self.expander
def save(self):
return {}
def load(self, data):
def load_authentification(self):
"""Must set self.has_auth to True when auth is done"""
raise NotImplementedError()
def get_settings_rows(self) -> list:
return []
# TOOLS
def slugify(self, value):
value = unicodedata.normalize('NFKD', value).encode('ascii', 'ignore').decode('ascii')
value = re.sub('[^\w\s-]', '', value).strip().lower()
return re.sub('[-\s]+', '-', value)
def chunk(self, prompt, n=4000):
if len(prompt) > n:
print("Chuncking prompt")
prompt = [(prompt[i : i + n]) for i in range(0, len(prompt), n)]
return prompt
def on_enabled(self, widget, *args):
if widget.get_active():
self.app.enabled_providers.append(self.slug)
else:
self.app.enabled_providers.remove(self.slug)
self.app.load_dropdown()

View file

@ -1,42 +0,0 @@
from .base import BavarderProvider
import requests
import shutil
class BaseOfflineProvider(BavarderProvider):
data = {
"setup": False,
"weight_path": "",
}
download_url = ""
def save(self):
return data
def load(self, data):
self.data = data
def download_file(self, url, filename=None):
if not filename:
filename = url.split('/')[-1]
with requests.get(url, stream=True) as r:
with open(filename, 'wb') as f:
shutil.copyfileobj(r.raw, f)
return filename
def setup(self):
if self.data["setup"]:
return
else:
self.data["setup"] = True
self.data["weight_path"] = self.download_file(self.download_url)
def ask(self, prompt):
self.setup()
return self._ask(prompt)
def _ask(self, prompt):
raise NotImplementedError()

View file

@ -1,24 +1,35 @@
from .base import BavarderProvider
from random import choice, randint
from gi.repository import Gtk, Adw, GLib
from .base import BaseProvider
class CatGPTProvider(BaseProvider):
name = "Cat GPT"
description = _("Chit-Chat with a Cat")
def ask(self, prompt, _):
return """
# H1
## H2
### H3
Alternatively, for H1 , an underline-ish style:
Alt-H1
======
class CatGPTProvider(BavarderProvider):
name = "CatGPT"
slug = "catgpt"
description = "🐱️"
version = "0.1.0"
developer_name = "Astrid Yu"
developers = ["Astrid Yu https://github.com/ifd3f"]
1. First ordered list item
2. Another item
def __init__(self, win, app, *args, **kwargs):
super().__init__(win, app, *args, **kwargs)
self.chat = None
* Unordered list can use asterisks
- Or minuses
+ Or pluses
def ask(self, prompt):
return " ".join([self.pick_generator()() for i in range(randint(1, 12))])
```
$ ls
```
"""
#return " ".join([self.pick_generator()() for i in range(randint(1, 12))])
def pick_generator(self):
if randint(1, 15) == 1:
@ -46,13 +57,3 @@ class CatGPTProvider(BavarderProvider):
lambda: "nya" * randint(1, 3) + "ny" + "a" * randint(1, 10),
]
)
@property
def require_api_key(self):
return False
def save(self):
return {}
def load(self, data):
pass

View file

@ -1,64 +0,0 @@
import requests
import json
from .base import BavarderProvider
import socket
from gi.repository import Gtk, Adw, GLib
from gradio_client import Client
class BaseGradioProvider(BavarderProvider):
name = None
slug = None
url = None
def __init__(self, win, app, *args, **kwargs):
super().__init__(win, app, *args, **kwargs)
self.client = Client(self.url)
def ask(self, prompt):
print("ASKING " + "="*100)
try:
response = self.client.predict(
prompt, # str representing string value in 'Chat Message Box' Textbox component
fn_index=0
)
print(response)
except Exception as e:
print(e)
self.win.banner.props.title = str(e)
self.win.banner.props.button_label = ""
self.win.banner.set_revealed(True)
else:
self.hide_banner()
GLib.idle_add(self.update_response, response)
return response
@property
def require_api_key(self):
return False
def preferences(self, win):
if self.require_api_key:
self.expander = Adw.ExpanderRow()
self.expander.props.title = self.name
self.expander.add_action(self.about())
self.expander.add_action(self.enable_switch())
# TODO: ADD DEVICE
return self.expander
else:
return self.no_preferences(win)
def on_apply(self, widget):
self.hide_banner()
def save(self):
return {}
def load(self, data):
pass

View file

@ -1,50 +0,0 @@
from .huggingface import BaseHFProvider
import json
import socket
import requests
from gi.repository import Gtk, Adw, GLib
class HuggingFaceDialoGPTLargeProvider(BaseHFProvider):
name = "DialoGPT"
slug = "hfdialogpt"
model = "microsoft/DialoGPT-large"
@property
def require_api_key(self):
return False
def ask(self, prompt):
try:
payload = json.dumps(
{
"inputs": {
# "past_user_inputs": ["Which movie is the best ?"],
# "generated_responses": ["It's Die Hard for sure."],
"text": prompt
},
}
)
headers = {"Content-Type": "application/json"}
if self.authorization:
headers["Authorization"] = f"Bearer {self.api_key}"
url = f"https://api-inference.huggingface.co/models/{self.model}"
print(url)
response = requests.request("POST", url, headers=headers, data=payload)
print(response.json())
response = response.json()["generated_text"]
# except NoApikey:
# self.no_api_key()
# return ""
except KeyError:
pass
except socket.gaierror:
self.no_connection()
return ""
else:
self.hide_banner()
print(response)
GLib.idle_add(self.update_response, response)
return response

View file

@ -1,11 +0,0 @@
from .huggingface import BaseHFProvider
class HuggingFaceGoogleFlanT5XXLProvider(BaseHFProvider):
name = "Google Flan T5 XXL"
slug = "hfgoogleflant5xxl"
model = "google/flan-t5-xxl"
@property
def require_api_key(self):
return False

View file

@ -1,11 +0,0 @@
from .huggingface import BaseHFProvider
class HuggingFaceGoogleFlanU12Provider(BaseHFProvider):
name = "Google Flan U12"
slug = "hfgoogleflanu12"
model = "google/flan-ul2"
@property
def require_api_key(self):
return False

View file

@ -1,13 +0,0 @@
from .huggingface import BaseHFProvider
class HuggingFaceGPT2Provider(BaseHFProvider):
name = "GPT 2"
slug = "hfgpt2"
model = "gpt2"
description = "GPT-2 is a transformers model pretrained on a very large corpus of English data \nin a self-supervised fashion. This means it was pretrained on the raw texts only,\n with no humans labelling them in any way (which is why it can use lots of publicly available data)\n with an automatic process to generate inputs and labels from those texts. More precisely,\n it was trained to guess the next word in sentences."
languages = "English"
@property
def require_api_key(self):
return False

View file

@ -1,13 +0,0 @@
from .huggingface import BaseHFProvider
class HuggingFaceGPT2LargeProvider(BaseHFProvider):
name = "GPT 2 Large"
slug = "hfgpt2large"
model = "gpt2-large"
description = "GPT-2 is a transformers model pretrained on a very large corpus of English data \nin a self-supervised fashion. This means it was pretrained on the raw texts only,\n with no humans labelling them in any way (which is why it can use lots of publicly available data)\n with an automatic process to generate inputs and labels from those texts. More precisely,\n it was trained to guess the next word in sentences."
languages = "English"
@property
def require_api_key(self):
return False

View file

@ -1,13 +0,0 @@
from .huggingface import BaseHFProvider
class HuggingFaceGPT2XLProvider(BaseHFProvider):
name = "GPT 2 XL"
slug = "hfgpt2"
model = "gpt2-xl"
description = "GPT-2 is a transformers model pretrained on a very large corpus of English data \nin a self-supervised fashion. This means it was pretrained on the raw texts only,\n with no humans labelling them in any way (which is why it can use lots of publicly available data)\n with an automatic process to generate inputs and labels from those texts. More precisely,\n it was trained to guess the next word in sentences."
languages = "English"
@property
def require_api_key(self):
return False

View file

@ -1,54 +0,0 @@
from .huggingface import BaseHFProvider
import requests
import json
import socket
from gi.repository import Gtk, Adw, GLib
class HuggingFaceOpenAssistantSFT1PythiaProvider(BaseHFProvider):
name = "Open-Assistant SFT-1 12B Model"
slug = "hfopenassistantsft1pythia12b"
model = "OpenAssistant/oasst-sft-4-pythia-12b-epoch-3.5"
@property
def require_api_key(self):
return False
def ask(self, prompt):
prompt = f"<|prompter|> {prompt}<|endoftext|><|assistant|>"
try:
payload = json.dumps({"inputs": prompt})
headers = {"Content-Type": "application/json"}
if self.require_api_key:
headers["Authorization"] = f"Bearer {self.api_key}"
url = f"https://api-inference.huggingface.co/models/{self.model}"
response = requests.request("POST", url, headers=headers, data=payload)
if response.status_code == 403:
self.no_api_key()
return ""
elif response.status_code != 200:
self.win.banner.props.title = response.json()["error"]
self.win.banner.props.button_label = ""
self.win.banner.set_revealed(True)
return ""
response = response.json()[0]["generated_text"].split("<|assistant|>")[1].strip()
# except NoApikey:
# self.no_api_key()
# return ""
except KeyError:
pass
except socket.gaierror:
self.no_connection()
return ""
else:
self.hide_banner()
print(response)
GLib.idle_add(self.update_response, response)
return response
class HuggingChatMask(HuggingFaceOpenAssistantSFT1PythiaProvider):
url = "https://bavarder.codeberg.page/help/huggingchat"
name = "Open-Assistant SFT-1 12B Model (HuggingChat)"
slug = "huggingchat"

View file

@ -1,7 +0,0 @@
from .huggingchatbase import BaseHuggingChatProvider
class HuggingChatProvider(BaseHuggingChatProvider):
name = "Hugging Chat"
slug = "huggingchat"
model = "OpenAssistant/oasst-sft-6-llama-30b-xor"

View file

@ -1,92 +0,0 @@
from .base import BavarderProvider
from hugchat import hugchat
import socket
import requests
import json
from gi.repository import Gtk, Adw, GLib
class BaseHuggingChatProvider(BavarderProvider):
name = "Hugging Chat"
slug = "huggingchat"
model = None
url = "https://bavarder.codeberg.page/help/huggingchat"
cookies = {}
def __init__(self, win, app, *args, **kwargs):
super().__init__(win, app, *args, **kwargs)
def ask(self, prompt):
print(self.cookies)
try:
self.chat = hugchat.ChatBot(cookies=self.cookies) # or cookies=[...]
print(self.chat)
print(self.cookies)
except Exception as e:
print(e)
self.win.banner.props.title = str(e)
self.win.banner.props.button_label = ""
self.win.banner.set_revealed(True)
return ""
else:
try:
response = self.chat.chat(prompt)
except socket.gaierror:
self.no_connection()
return ""
except Exception as e:
self.win.banner.props.title = str(e)
self.win.banner.props.button_label = ""
self.win.banner.set_revealed(True)
return ""
else:
self.win.banner.set_revealed(False)
r = ""
for i in response:
char = i["token"]["text"]
if char == "</s>":
r += "\n"
else:
r += char
GLib.idle_add(self.update_response, r)
return r
@property
def require_api_key(self):
return True
def preferences(self, win):
self.pref_win = win
self.expander = Adw.ExpanderRow()
self.expander.props.title = self.name
self.expander.add_action(self.about()) # TODO: in Adw 1.4, use add_suffix
self.expander.add_action(self.enable_switch())
self.api_row = Adw.EntryRow()
self.api_row.connect("apply", self.on_apply)
self.api_row.props.text = str(self.cookies) or ""
self.api_row.props.title = "Cookies"
self.api_row.set_show_apply_button(True)
self.api_row.add_suffix(self.how_to_get_a_token())
self.expander.add_row(self.api_row)
return self.expander
def on_apply(self, widget):
self.hide_banner()
cookies = self.api_row.get_text()
print("cookies", cookies)
self.cookies = json.loads(cookies)
print("Applied cookies", self.cookies)
def save(self):
print(self.cookies)
print("Saved cookies", self.cookies)
return self.cookies
def load(self, data):
self.cookies = data

View file

@ -1,95 +0,0 @@
import requests
import json
from .base import BavarderProvider
import socket
from gi.repository import Gtk, Adw, GLib
# from text_generation import InferenceAPIClient
class BaseHFProvider(BavarderProvider):
name = None
slug = None
model = None
url = "https://bavarder.codeberg.page/help/huggingface"
def __init__(self, win, app, *args, **kwargs):
super().__init__(win, app, *args, **kwargs)
self.api_key = None
# self.client = InferenceAPIClient(self.model)
def ask(self, prompt):
try:
payload = json.dumps({"inputs": prompt})
headers = {"Content-Type": "application/json"}
if self.require_api_key:
headers["Authorization"] = f"Bearer {self.api_key}"
url = f"https://api-inference.huggingface.co/models/{self.model}"
response = requests.request("POST", url, headers=headers, data=payload)
if response.status_code == 403:
self.no_api_key()
return ""
elif response.status_code != 200:
self.win.banner.props.title = response.json()["error"]
self.win.banner.props.button_label = ""
self.win.banner.set_revealed(True)
return ""
response = response.json()[0]["generated_text"]
# except NoApikey:
# self.no_api_key()
# return ""
except KeyError:
pass
except socket.gaierror:
self.no_connection()
return ""
except Exception as e:
print(e)
self.win.banner.props.title = str(e)
self.win.banner.props.button_label = ""
self.win.banner.set_revealed(True)
else:
self.hide_banner()
print(response)
GLib.idle_add(self.update_response, response)
return response
@property
def require_api_key(self):
return False
def preferences(self, win):
if self.require_api_key:
self.expander = Adw.ExpanderRow()
self.expander.props.title = self.name
self.expander.add_action(self.about())
self.expander.add_action(self.enable_switch())
self.api_row = Adw.PasswordEntryRow()
self.api_row.connect("apply", self.on_apply)
self.api_row.props.title = _("API Key")
self.api_row.props.text = self.api_key or ""
self.api_row.add_suffix(self.how_to_get_a_token())
self.api_row.set_show_apply_button(True)
self.expander.add_row(self.api_row)
return self.expander
else:
return self.no_preferences(win)
def on_apply(self, widget):
self.hide_banner()
self.api_key = self.api_row.get_text()
print(self.api_key)
def save(self):
if self.require_api_key:
return {"api_key": self.api_key}
return {}
def load(self, data):
if self.require_api_key:
self.api_key = data["api_key"]

View file

@ -1,32 +1,10 @@
providers_dir = join_paths(moduledir, 'providers')
providers_dir = join_paths(MODULE_DIR, 'providers')
providers_sources = [
'__init__.py',
'alpacalora.py',
'baichat.py',
# 'bard.py',
'base.py',
'catgpt.py',
'gradio.py',
'hfdialogpt.py',
'hfgoogleflant5xxl.py',
'hfgoogleflanu12.py',
'hfgpt2.py',
'hfgpt2large.py',
'hfgpt2xl.py',
'hfopenassistantsft1pythia12b.py',
# 'huggingchat.py',
# 'huggingchatbase.py',
'huggingface.py',
'openai.py',
'openaicustom.py',
'openaigpt4.py',
'openaigpt35turbo.py',
'openaitextdavinci003.py',
'stablelm.py',
'starcoder.py',
'transformer.py',
'provider_item.py',
]
PY_INSTALLDIR.install_sources(providers_sources, subdir: providers_dir)
PY_INSTALLDIR.install_sources(providers_sources, subdir: providers_dir)

View file

@ -1,130 +0,0 @@
from .base import BavarderProvider
import openai
import socket
from gi.repository import Gtk, Adw, GLib
class BaseOpenAIProvider(BavarderProvider):
name = None
slug = None
model = None
version = "0.1.0"
api_key_title = "API Key"
url = "https://bavarder.codeberg.page/help/openai"
def __init__(self, win, app, *args, **kwargs):
super().__init__(win, app, *args, **kwargs)
self.chat = openai.ChatCompletion
self.pref_win = None
def ask(self, prompt):
if self.model:
prompt = self.chunk(prompt)
try:
if isinstance(prompt, list):
self.win.banner.props.title = _("Prompt too long, splitting into chunks.")
self.win.banner.props.button_label = ""
self.win.banner.set_revealed(True)
response = ""
for chunk in prompt:
response += (
self.chat.create(
model=self.model,
messages=[{"role": "user", "content": chunk}],
)
.choices[0]
.message.content
)
else:
response = self.chat.create(
model=self.model, messages=[{"role": "user", "content": prompt}]
)
response = response.choices[0].message.content
except openai.error.AuthenticationError:
self.no_api_key()
return ""
except openai.error.InvalidRequestError:
self.win.banner.props.title = _("You don't have access to this model")
self.win.banner.props.button_label = ""
self.win.banner.set_revealed(True)
return ""
except openai.error.RateLimitError:
self.win.banner.props.title = _("You exceeded your current quota, please check your plan and billing details.")
self.win.banner.props.button_label = ""
self.win.banner.set_revealed(True)
return ""
except openai.error.APIError:
self.win.banner.props.title = _("API Error")
self.win.banner.props.button_label = ""
self.win.banner.set_revealed(True)
except socket.gaierror:
self.no_connection()
return ""
else:
self.hide_banner()
GLib.idle_add(self.update_response, response)
return response
else:
self.no_api_key(title=_("No model selected, you can choose one in preferences"))
return ""
@property
def require_api_key(self):
return True
def preferences(self, win):
self.pref_win = win
self.expander = Adw.ExpanderRow()
self.expander.props.title = self.name
self.expander.add_action(self.about()) # TODO: in Adw 1.4, use add_suffix
self.expander.add_action(self.enable_switch())
self.api_row = Adw.PasswordEntryRow()
self.api_row.connect("apply", self.on_apply)
self.api_row.props.text = openai.api_key or ""
self.api_row.props.title = self.api_key_title
self.api_row.set_show_apply_button(True)
self.api_row.add_suffix(self.how_to_get_a_token())
self.expander.add_row(self.api_row)
self.api_url_row = Adw.EntryRow()
self.api_url_row.connect("apply", self.on_apply)
self.api_url_row.props.text = openai.api_base or ""
self.api_url_row.props.title = "API Url"
self.api_url_row.set_show_apply_button(True)
self.api_url_row.add_suffix(self.how_to_get_base_url())
self.expander.add_row(self.api_url_row)
return self.expander
def on_apply(self, widget):
self.hide_banner()
api_key = self.api_row.get_text()
openai.api_key = api_key
openai.api_base = self.api_url_row.get_text()
def save(self):
return {
"api_key": openai.api_key,
"api_base": openai.api_base,
}
def load(self, data):
if data["api_key"]:
openai.api_key = data["api_key"]
if data["api_base"]:
openai.api_base = data["api_base"]
def how_to_get_base_url(self):
about_button = Gtk.Button()
about_button.set_icon_name("dialog-information-symbolic")
about_button.set_tooltip_text("How to choose base url")
about_button.add_css_class("flat")
about_button.set_valign(Gtk.Align.CENTER)
about_button.connect("clicked", self.open_documentation)
return about_button

View file

@ -1,89 +0,0 @@
from .openai import BaseOpenAIProvider
from gi.repository import Gtk, Adw, GLib
import openai
class OpenAICustomProvider(BaseOpenAIProvider):
name = "OpenAI Custom Model"
slug = "openaicustom"
api_base = ""
def preferences(self, win):
self.pref_win = win
self.expander = Adw.ExpanderRow()
self.expander.props.title = self.name
self.expander.add_action(self.about()) # TODO: in Adw 1.4, use add_suffix
self.expander.add_action(self.enable_switch())
self.api_row = Adw.PasswordEntryRow()
self.api_row.connect("apply", self.on_apply)
self.api_row.props.text = openai.api_key or ""
self.api_row.props.title = self.api_key_title
self.api_row.set_show_apply_button(True)
self.api_row.add_suffix(self.how_to_get_a_token())
self.expander.add_row(self.api_row)
self.api_url_row = Adw.EntryRow()
self.api_url_row.connect("apply", self.on_apply)
self.api_url_row.props.text = self.api_base or ""
self.api_url_row.props.title = _("API Url")
self.api_url_row.set_show_apply_button(True)
self.api_url_row.add_suffix(self.how_to_get_a_token())
self.expander.add_row(self.api_url_row)
self.model_row = Adw.EntryRow()
self.model_row.connect("apply", self.on_apply)
self.model_row.props.title = _("Model")
if self.model:
self.model_row.props.text = str(self.model)
else:
print("No model")
self.model_row.props.text = ""
self.model_row.add_suffix(self.how_to_choose_model())
self.model_row.set_show_apply_button(True)
self.expander.add_row(self.model_row)
return self.expander
def on_apply(self, widget):
self.hide_banner()
api_key = self.api_row.get_text()
openai.api_key = api_key
self.api_base = self.api_url_row.get_text()
openai.api_base = self.api_base
self.model = str(self.model_row.get_text())
def save(self):
return {
"api_key": openai.api_key,
"api_base": self.api_base,
"model": self.model,
}
def load(self, data):
if data["api_key"]:
openai.api_key = data["api_key"]
else:
openai.api_key = ""
if data["api_base"]:
self.api_base = data["api_base"]
openai.api_base = self.api_base
if data["model"]:
self.model = data["model"]
def how_to_choose_model(self):
about_button = Gtk.Button()
about_button.set_icon_name("dialog-information-symbolic")
about_button.set_tooltip_text(_("How to choose a model"))
about_button.add_css_class("flat")
about_button.set_valign(Gtk.Align.CENTER)
about_button.connect("clicked", self.open_documentation)
return about_button
class LocalModel(OpenAICustomProvider):
name = "Local Model"
slug = "local"
url = "https://bavarder.codeberg.page/help/local" # just for the url :)

View file

@ -1,7 +0,0 @@
from .openai import BaseOpenAIProvider
class OpenAIGPT35TurboProvider(BaseOpenAIProvider):
name = "OpenAI GPT 3.5 Turbo"
slug = "openaigpt35turbo"
model = "gpt-3.5-turbo"

View file

@ -1,8 +0,0 @@
from .openai import BaseOpenAIProvider
class OpenAIGPT4Provider(BaseOpenAIProvider):
name = "OpenAI GPT 4"
slug = "openaigpt4"
model = "gpt-4"
api_key_title = "API Key (Require a plan with access to the GPT-4 model)"

View file

@ -1,7 +0,0 @@
from .openai import BaseOpenAIProvider
class OpenAITextDavinci003(BaseOpenAIProvider):
name = "OpenAI Text Davinci 003"
slug = "openaitextdavinci003"
model = "text-davinci-003"

View file

@ -0,0 +1,15 @@
using Gtk 4.0;
using Adw 1;
template $Provider : Adw.ExpanderRow {
[suffix]
Switch enable_switch {
state-set => $on_switch_state_changed();
valign: center;
}
Adw.ActionRow no_preferences_available {
title: _("No preferences available");
}
}

View file

@ -0,0 +1,51 @@
import unicodedata
import re
from typing import List, Dict
from gi.repository import Gtk, Adw, GLib
from bavarder.constants import app_id, rootdir
@Gtk.Template(resource_path=f"{rootdir}/ui/provider_item.ui")
class Provider(Adw.ExpanderRow):
__gtype_name__ = "Provider"
enable_switch = Gtk.Template.Child()
no_preferences_available = Gtk.Template.Child()
def __init__(self, app, window, provider, **kwargs):
super().__init__(**kwargs)
self.app = app
self.window = window
self.provider = provider
self.setup()
def setup(self):
self.set_title(self.provider.name)
self.set_subtitle(self.provider.description)
self.enable_switch.set_active(self.provider.providers[self.provider.slug]["enabled"])
if self.provider.require_authentification:
self.no_preferences_available.set_visible(False)
for row in self.provider.get_settings_rows():
self.add(row)
# CALLBACKS
@Gtk.Template.Callback()
def on_switch_state_changed(self, widget, _):
self.provider.set_enabled(widget.get_active())
self.app.win.load_provider_selector()
# TOOLS
def slugify(self, value):
value = unicodedata.normalize('NFKD', value).encode('ascii', 'ignore').decode('ascii')
value = re.sub('[^\w\s-]', '', value).strip().lower()
return re.sub('[-\s]+', '-', value)
def chunk(self, prompt, n=4000):
if len(prompt) > n:
prompt = [(prompt[i : i + n]) for i in range(0, len(prompt), n)]
return prompt

View file

@ -1,6 +0,0 @@
from .huggingface import BaseHFProvider
class StableLMProvider(BaseHFProvider):
name = "StableLM"
slug = "stablelm"
model = "stabilityai/stablelm-tuned-alpha-3b"

View file

@ -1,7 +0,0 @@
from .transformer import BaseTransformerProvider
class StarCoderProvider(BaseTransformerProvider):
name = "Star Coder"
slug = "starcoder"
checkpoint = "bigcode/starcoder"

View file

@ -1,89 +0,0 @@
import requests
import json
from .base import BavarderProvider
import socket
from gi.repository import Gtk, Adw, GLib
from transformers import AutoModelForCausalLM, AutoTokenizer
class BaseTransformerProvider(BavarderProvider):
name = None
slug = None
checkpoint = None
device = "cpu"
is_setup = False
api_key = None
def __init__(self, win, app, *args, **kwargs):
super().__init__(win, app, *args, **kwargs)
def setup(self):
try:
if self.require_api_key:
self.tokenizer = AutoTokenizer.from_pretrained(self.checkpoint, use_auth_token=self.api_key)
else:
self.tokenizer = AutoTokenizer.from_pretrained(self.checkpoint)
self.model = AutoModelForCausalLM.from_pretrained(self.checkpoint).to(self.device)
except Exception as e:
print(e)
self.win.banner.props.title = str(e)
self.win.banner.props.button_label = ""
self.win.banner.set_revealed(True)
else:
self.is_setup = True
def ask(self, prompt):
self.setup()
if self.is_setup:
try:
inputs = self.tokenizer.encode(prompt, return_tensors="pt").to(self.device)
outputs = self.model.generate(inputs)
response = self.tokenizer.decode(outputs[0])
except Exception as e:
print(e)
self.win.banner.props.title = str(e)
self.win.banner.props.button_label = ""
self.win.banner.set_revealed(True)
else:
self.hide_banner()
GLib.idle_add(self.update_response, response)
return response
@property
def require_api_key(self):
return True
def preferences(self, win):
if self.require_api_key:
self.expander = Adw.ExpanderRow()
self.expander.props.title = self.name
self.expander.add_action(self.about())
self.expander.add_action(self.enable_switch())
self.api_row = Adw.PasswordEntryRow()
self.api_row.connect("apply", self.on_apply)
self.api_row.props.title = _("API Key")
self.api_row.props.text = self.api_key or ""
self.api_row.add_suffix(self.how_to_get_a_token())
self.api_row.set_show_apply_button(True)
self.expander.add_row(self.api_row)
return self.expander
else:
return self.no_preferences(win)
def on_apply(self, widget):
self.hide_banner()
self.api_key = self.api_row.get_text()
def save(self):
if self.require_api_key:
return {"api_key": self.api_key}
return {}
def load(self, data):
if self.require_api_key:
self.api_key = data["api_key"]

39
src/style.css Normal file
View file

@ -0,0 +1,39 @@
.small-pill {
border-radius: 18px;
}
.user{
background-color: rgba(61, 152, 255,0.03);
}
.assistant{
background-color: rgba(184, 134, 17,0.02);
}
.chat-entry > text { background: none; }
.message-bubble {
font-size: 16px;
color: @window_fg_color;
border-radius: 15px;
padding: 9px;
background-color: mix(@window_bg_color, @window_fg_color, .05);
}
.message-bubble-user {
background-color: alpha(@accent_bg_color, 0.3);
color: @card_fg_color;
}
.avatar-user {
opacity: 0;
}
.timestamp {
font-size: 12px;
padding-left: 6px;
}
.sourceview {
font-family: monospace;
}

View file

@ -5,28 +5,28 @@ class KillableThread(threading.Thread):
def __init__(self, *args, **keywords):
threading.Thread.__init__(self, *args, **keywords)
self.killed = False
def start(self):
self.__run_backup = self.run
self.run = self.__run
self.run = self.__run
threading.Thread.start(self)
def __run(self):
sys.settrace(self.globaltrace)
self.__run_backup()
self.run = self.__run_backup
def globaltrace(self, frame, event, arg):
if event == 'call':
return self.localtrace
else:
return None
def localtrace(self, frame, event, arg):
if self.killed:
if event == 'line':
raise SystemExit()
return self.localtrace
def kill(self):
self.killed = True
self.killed = True

View file

@ -11,7 +11,7 @@ import platform
# no quotes) and is not meant to be translated literally.
translator_credits = _("translator-credits")
class BavarderAboutWindow:
class AboutWindow:
def __init__(self, parent):
self.parent = parent
self.app = self.parent.get_application()
@ -23,7 +23,7 @@ class BavarderAboutWindow:
application_name="Bavarder",
transient_for=self.app.get_active_window(),
application_icon=constants.app_id,
developer_name=_("0xMRTT"),
developer_name="0xMRTT",
website=constants.project_url,
support_url=constants.help_url,
issue_url=constants.bugtracker_url,
@ -34,49 +34,31 @@ class BavarderAboutWindow:
"0xMRTT https://github.com/0xMRTT",
],
designers=[
"David Lapshin https://github.com/daudix-UFO"
],
artists=[
"David Lapshin https://github.com/daudix-UFO"
],
translator_credits=_(translator_credits),
translator_credits=translator_credits,
copyright=_("Copyright © 2023 0xMRTT"),
license_type=Gtk.License.GPL_3_0,
version=constants.version,
release_notes_version=constants.rel_ver,
)
self.about_window.add_acknowledgement_section(
"Special thanks to",
[
"Telegraph https://apps.gnome.org/app/io.github.fkinoshita.Telegraph",
"Apostrophe https://apps.gnome.org/app/org.gnome.gitlab.somas.Apostrophe",
],
)
self.about_window.add_credit_section(
_("Packaging"),
[
_("Soumyadeep Ghosh https://codeberg.org/soumyadghosh")
]
)
self.about_window.set_debug_info(
f"""{constants.app_id} {constants.version}
Environment: {os.environ.get("XDG_CURRENT_DESKTOP", "Unknown")}
Gtk: {Gtk.MAJOR_VERSION}.{Gtk.MINOR_VERSION}.{Gtk.MICRO_VERSION}
Python: {platform.python_version()}
OS: {platform.system()} {platform.release()} {platform.version()}
Providers: {self.app.enabled_providers}
Use Theme: {self.app.use_theme}
Use Text View: {self.app.use_text_view}
Clear After Send: {self.app.clear_after_send}
Close All Without Dialog: {self.app.close_all_without_dialog}
Current Provider: {self.app.provider}
"""
)
self.about_window.present()
def show_about(self):
def present(self):
self.about_window.present()

View file

@ -1,67 +0,0 @@
from gi.repository import Adw, Gtk, Gio
from bavarder.constants import app_id, build_type
@Gtk.Template(resource_path="/io/github/Bavarder/Bavarder/ui/window.ui")
class BavarderWindow(Adw.ApplicationWindow):
__gtype_name__ = "BavarderWindow"
toast_overlay = Gtk.Template.Child()
prompt_text_view = Gtk.Template.Child()
ask_button = Gtk.Template.Child()
scrolled_response_window = Gtk.Template.Child()
bot_text_view = Gtk.Template.Child()
banner = Gtk.Template.Child()
stop_button = Gtk.Template.Child()
# listen = Gtk.Template.Child()
# listen_wait = Gtk.Template.Child()
# listen_spinner = Gtk.Template.Child()
# speak = Gtk.Template.Child()
# speak_wait = Gtk.Template.Child()
# speak_spinner = Gtk.Template.Child()
menu = Gtk.Template.Child()
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.app = Gtk.Application.get_default()
self.settings = Gio.Settings(schema_id=app_id)
self.setup_signals()
self.setup_window_props()
self.setup()
def setup_window_props(self):
self.settings.bind(
"width", self, "default-width", Gio.SettingsBindFlags.DEFAULT
)
self.settings.bind(
"height", self, "default-height", Gio.SettingsBindFlags.DEFAULT
)
self.settings.bind(
"is-maximized", self, "maximized", Gio.SettingsBindFlags.DEFAULT
)
self.settings.bind(
"is-fullscreen", self, "fullscreened", Gio.SettingsBindFlags.DEFAULT
)
def setup_signals(self):
self.connect("close-request",
self.on_close_request)
def setup(self):
# Set devel style
if build_type == "debug":
self.get_style_context().add_class("devel")
def on_close_request(self, *args):
self.settings.set_strv("enabled-providers", list(self.app.enabled_providers))
self.settings.set_string("latest-provider", self.app.provider)
self.app.save_providers()
self.close()

View file

@ -1,11 +1,10 @@
views_dir = join_paths(moduledir, 'views')
views_dir = join_paths(MODULE_DIR, 'views')
views_sources = [
'__init__.py',
'about_window.py',
'main_window.py',
'preferences_window.py',
'window.py',
]
PY_INSTALLDIR.install_sources(views_sources, subdir: views_dir)
PY_INSTALLDIR.install_sources(views_sources, subdir: views_dir)

View file

@ -0,0 +1,21 @@
using Gtk 4.0;
using Adw 1;
template $Preferences : Adw.PreferencesWindow {
title: _("Preferences");
default-height: 400;
default-width: 600;
modal: true;
Adw.PreferencesPage general_page {
Adw.PreferencesGroup provider_group {
title: _("Providers");
}
Adw.PreferencesGroup model_group {
title: _("Models");
}
}
}

View file

@ -1,19 +1,19 @@
from gi.repository import Gtk, Adw, Gio
from bavarder.constants import app_id
from bavarder.constants import app_id, rootdir
from bavarder.providers.provider_item import Provider
from bavarder.widgets.model_item import Model
from bavarder.widgets.download_row import DownloadRow
from bavarder.providers import PROVIDERS
from gpt4all import GPT4All
@Gtk.Template(resource_path="/io/github/Bavarder/Bavarder/ui/preferences.ui")
class Preferences(Adw.PreferencesWindow):
@Gtk.Template(resource_path=f"{rootdir}/ui/preferences_window.ui")
class PreferencesWindow(Adw.PreferencesWindow):
__gtype_name__ = "Preferences"
clear_after_send_switch = Gtk.Template.Child()
provider_group = Gtk.Template.Child()
use_text_view_switch = Gtk.Template.Child()
close_all_without_dialog_switch = Gtk.Template.Child()
allow_remote_fetching_switch = Gtk.Template.Child()
general_page = Gtk.Template.Child()
model_group = Gtk.Template.Child()
def __init__(self, parent, **kwargs):
super().__init__(**kwargs)
@ -30,84 +30,32 @@ class Preferences(Adw.PreferencesWindow):
def setup(self):
self.setup_signals()
self.load_providers()
self.load_models()
def setup_signals(self):
pass
self.clear_after_send_switch.set_active(self.app.clear_after_send)
self.clear_after_send_switch.connect(
"notify::active", self.on_clear_after_send_switch_toggled
)
def load_providers(self):
for provider in self.app.providers.values():
p = Provider(self.app, self, provider)
self.provider_group.add(p)
self.use_text_view_switch.set_active(self.app.use_text_view)
self.use_text_view_switch.connect(
"notify::active", self.on_use_text_view_switch_toggled
)
self.close_all_without_dialog_switch.set_active(self.app.close_all_without_dialog)
self.close_all_without_dialog_switch.connect(
"notify::active", self.on_close_all_without_dialog_switch_toggled
)
self.allow_remote_fetching_switch.set_active(self.app.allow_remote_fetching)
self.allow_remote_fetching_switch.connect(
"notify::active", self.on_allow_remote_fetching_switch_toggled
)
self.setup_providers()
def on_clear_after_send_switch_toggled(self, widget, *args):
"""Callback for the clear_after_send_switch toggled event."""
if widget.get_active():
self.settings.set_boolean("clear-after-send", True)
self.app.clear_after_send = True
def load_models(self):
self.general_page.remove(self.model_group)
self.model_group = Adw.PreferencesGroup()
self.model_group.set_title(_("Models"))
for model in self.app.models:
p = Model(self.app, self, model)
self.model_group.add(p)
else:
self.settings.set_boolean("clear-after-send", False)
self.app.clear_after_send = False
self.no_models_available = Adw.ExpanderRow()
self.no_models_available.set_title(_("Download more models"))
def on_use_text_view_switch_toggled(self, widget, *args):
"""Callback for the use_text_view_switch toggled event."""
if widget.get_active():
self.settings.set_boolean("use-text-view", True)
self.app.use_text_view = True
else:
self.settings.set_boolean("use-text-view", False)
self.app.use_text_view = False
for model in GPT4All.list_models():
self.no_models_available.add_row(DownloadRow(self.app, self, model))
def on_close_all_without_dialog_switch_toggled(self, widget, *args):
"""Callback for the close_all_without_dialog_switch toggled event."""
if widget.get_active():
self.settings.set_boolean("close-all-without-dialog", True)
self.app.close_all_without_dialog = True
else:
self.settings.set_boolean("close-all-without-dialog", False)
self.app.close_all_without_dialog = False
self.model_group.add(self.no_models_available)
def on_allow_remote_fetching_switch_toggled(self, widget, *args):
"""Callback for the allow_remote_fetching_switch toggled event."""
if widget.get_active():
self.settings.set_boolean("allow-remote-fetching", True)
self.app.load_annoucements()
self.app.allow_remote_fetching = True
else:
self.settings.set_boolean("allow-remote-fetching", False)
self.app.allow_remote_fetching = False
def setup_providers(self):
# for provider in self.app.providers.values():
# try:
# self.provider_group.add(provider.preferences(self))
# except TypeError: # no prefs
# pass
# else:
# row = Adw.ActionRow()
# row.props.title = "No providers available"
# self.provider_group.add(row)
for provider in PROVIDERS.values():
if provider.slug in self.app.providers:
self.provider_group.add(
self.app.providers[provider.slug].preferences(win=self.app.win)
)
else:
self.provider_group.add(
provider(self.app.win, self.app).preferences(win=self.app.win)
)
self.general_page.add(self.model_group)

231
src/views/window.blp Normal file
View file

@ -0,0 +1,231 @@
using Gtk 4.0;
using Adw 1;
template $BavarderWindow : Adw.ApplicationWindow {
title: _("Bavarder");
default-width: 350;
default-height: 500;
width-request: 360;
height-request: 200;
ShortcutController {
Shortcut {
trigger: "<primary>q";
action: "action(window.close)";
}
}
Adw.ToastOverlay toast_overlay {
Adw.NavigationSplitView split_view {
max-sidebar-width: 260;
sidebar-width-fraction: 0.38;
sidebar: Adw.NavigationPage {
title: _("Bavarder");
child: Adw.ToolbarView {
[top]
Adw.HeaderBar {
[start]
Button new_chat {
icon-name: "chat-message-new-symbolic";
tooltip-text: _("New Chat");
clicked => $on_new_chat_action();
}
[end]
MenuButton menu_button {
primary: true;
menu-model: main-menu;
icon-name: "open-menu-symbolic";
tooltip-text: _("Main Menu");
}
}
content: Gtk.ScrolledWindow {
hscrollbar-policy: never;
child: Gtk.ListBox threads_list {
selection-mode: browse;
row-activated => $threads_row_activated_cb();
styles ["navigation-sidebar"]
};
};
};
};
content: Adw.NavigationPage message_page {
tag: "message";
title: _("Message");
child: Adw.ToolbarView {
[top]
Adw.HeaderBar {
[start]
Gtk.ToggleButton local_mode_toggle {
icon-name: 'cloud-disabled-symbolic';
toggled => $on_local_mode_toggled();
}
[title]
Adw.WindowTitle title {
title: _("Chat");
}
[end]
Button clear_all_button {
icon-name: 'edit-clear-all-symbolic';
clicked => $on_clear_all();
visible: false;
}
[end]
MenuButton model_selector_button {
icon-name: 'brain-augemnted-symbolic';
visible: false;
}
[end]
MenuButton provider_selector_button {
icon-name: 'brain-augemnted-symbolic';
visible: false;
}
}
[top]
Adw.Banner banner {
}
content: Overlay {
// [overlay]
// Button {
// styles [
// "circular",
// ]
// icon-name: "go-bottom-symbolic";
// halign: end;
// valign: end;
// margin-bottom: 7;
// margin-end: 7;
// clicked => $scroll_down();
// }
Stack stack {
Adw.StatusPage status_no_chat {
title: _("No Chat");
icon-name: "chat-message-new-symbolic";
}
Adw.StatusPage status_no_internet {
title: _("No Internet");
icon-name: "network-disconnect-symbolic";
}
// Message List
ScrolledWindow main {
//vexpand: true;
hscrollbar-policy: never;
//edge-overshot => $handle_edge_reached() swapped;
Adw.Clamp {
// vexpand: false;
// hexpand: true;
maximum-size: 1200;
// tightening-threshold: 550;
// margin-bottom: 4;
// margin-start: 12;
// margin-end: 12;
ListBox main_list {
styles [
"message-list",
"background"
]
selection-mode: none;
show-separators: false;
hexpand: true;
vexpand: false;
}
}
}
}
};
[bottom]
Gtk.Box toolbar {
orientation: vertical;
visible: true;
Gtk.Box {
orientation: horizontal;
ScrolledWindow scrolled_window {
vexpand: true;
hexpand: true;
vscrollbar-policy: external;
max-content-height: 100;
propagate-natural-height: true;
}
Button ask_button {
valign: end;
margin-start: 5;
icon-name: "paper-plane-symbolic";
tooltip-text: _("Ask");
halign: end;
clicked => $on_ask();
styles ["suggested-action", "circular"]
}
}
styles ["small-pill", "toolbar" ]
}
};
};
}
}
Adw.Breakpoint {
condition ("max-width: 400sp")
setters {
split_view.collapsed: true;
}
}
Adw.Breakpoint {
condition ("max-width: 500sp")
//unapply => $one_pane_unapply_cb();
setters {
split_view.sidebar-width-fraction: 0.33;
split_view.collapsed: true;
}
}
}
menu main-menu {
item {
label: _("Preferences");
action: "app.preferences";
}
item {
label: _("Keyboard Shortcuts");
action: "win.show-help-overlay";
}
item {
label: _("About Bavarder");
action: "app.about";
}
}

304
src/views/window.py Normal file
View file

@ -0,0 +1,304 @@
# window.py
#
# Copyright 2023
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# SPDX-License-Identifier: GPL-3.0-or-later
import time
from gi.repository import Gtk, Gio, Adw, GLib
from bavarder.constants import app_id, build_type, rootdir
from bavarder.widgets.thread_item import ThreadItem
from bavarder.widgets.item import Item
from bavarder.threading import KillableThread
class CustomEntry(Gtk.TextView):
def __init__(self, **kwargs):
super().__init__(**kwargs)
@Gtk.Template(resource_path=f'{rootdir}/ui/window.ui')
class BavarderWindow(Adw.ApplicationWindow):
__gtype_name__ = 'BavarderWindow'
split_view = Gtk.Template.Child()
threads_list = Gtk.Template.Child()
title = Gtk.Template.Child()
main_list = Gtk.Template.Child()
status_no_chat = Gtk.Template.Child()
status_no_internet = Gtk.Template.Child()
scrolled_window = Gtk.Template.Child()
local_mode_toggle = Gtk.Template.Child()
provider_selector_button = Gtk.Template.Child()
model_selector_button = Gtk.Template.Child()
clear_all_button = Gtk.Template.Child()
banner = Gtk.Template.Child()
toast_overlay = Gtk.Template.Child()
stack = Gtk.Template.Child()
main = Gtk.Template.Child()
threads = []
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.app = Gtk.Application.get_default()
self.settings = Gio.Settings(schema_id=app_id)
CustomEntry.set_css_name("entry")
self.message_entry = CustomEntry()
self.message_entry.set_hexpand(True)
self.message_entry.set_accepts_tab(False)
self.message_entry.set_margin_start(5)
self.message_entry.set_margin_end(5)
self.message_entry.set_wrap_mode(Gtk.WrapMode.WORD)
self.message_entry.add_css_class("chat-entry")
self.scrolled_window.set_child(self.message_entry)
self.load_threads()
self.local_mode_toggle.set_active(self.app.local_mode)
self.on_local_mode_toggled(self.local_mode_toggle)
self.create_action("cancel", self.cancel, ["<primary>Escape"])
self.settings.bind(
"width", self, "default-width", Gio.SettingsBindFlags.DEFAULT
)
self.settings.bind(
"height", self, "default-height", Gio.SettingsBindFlags.DEFAULT
)
self.settings.bind(
"is-maximized", self, "maximized", Gio.SettingsBindFlags.DEFAULT
)
self.settings.bind(
"is-fullscreen", self, "fullscreened", Gio.SettingsBindFlags.DEFAULT
)
@property
def chat(self):
try:
return self.threads_list.get_selected_row().get_child().chat
except AttributeError: # create a new chat
self.on_new_chat_action()
finally:
return self.threads_list.get_selected_row().get_child().chat
@property
def content(self):
try:
return self.chat["content"]
except KeyError: # no content
self.chat["content"] = []
finally:
return self.chat["content"]
def load_threads(self):
self.threads_list.remove_all()
if self.app.data["chats"]:
for chat in self.app.data["chats"]:
thread = ThreadItem(self, chat)
self.threads_list.append(thread)
self.threads.append(thread)
self.stack.set_visible_child(self.main)
else:
self.stack.set_visible_child(self.status_no_chat)
@Gtk.Template.Callback()
def threads_row_activated_cb(self, *args):
self.split_view.set_collapsed(True)
self.split_view.set_show_content(True)
self.title.set_title(self.chat["title"])
if self.content:
self.stack.set_visible_child(self.main)
self.main_list.remove_all()
for item in self.content:
i = Item(self, self.chat, item)
self.main_list.append(i)
else:
self.stack.set_visible_child(self.status_no_chat)
@Gtk.Template.Callback()
def on_new_chat_action(self, *args):
self.app.on_new_chat_action(_, _)
# @Gtk.Template.Callback()
# def scroll_down(self, *args):
# self.scrolled_window.emit("scroll-child", Gtk.ScrollType.END, False)
@Gtk.Template.Callback()
def on_clear_all(self, *args):
if self.content:
self.stack.set_visible_child(self.main)
self.main_list.remove_all()
del self.chat["content"]
else:
self.stack.set_visible_child(self.status_no_chat)
# PROVIDER - ONLINE
def load_provider_selector(self):
provider_menu = Gio.Menu()
for provider in self.app.providers.values():
if provider.enabled:
item_provider = Gio.MenuItem()
item_provider.set_label(provider.name)
item_provider.set_action_and_target_value(
"app.set_provider",
GLib.Variant("s", provider.slug))
provider_menu.append_item(item_provider)
else:
item_provider = Gio.MenuItem()
item_provider.set_label(_("Preferences"))
item_provider.set_action_and_target_value("app.preferences", None)
provider_menu.append_item(item_provider)
self.provider_selector_button.set_menu_model(provider_menu)
# MODEL - OFFLINE
def load_model_selector(self):
provider_menu = Gio.Menu()
if not self.app.models:
self.app.list_models()
for provider in self.app.models:
item_provider = Gio.MenuItem()
item_provider.set_label(provider)
item_provider.set_action_and_target_value(
"app.set_model",
GLib.Variant("s", provider))
provider_menu.append_item(item_provider)
else:
item_provider = Gio.MenuItem()
item_provider.set_label(_("Preferences"))
item_provider.set_action_and_target_value("app.preferences", None)
provider_menu.append_item(item_provider)
self.model_selector_button.set_menu_model(provider_menu)
@Gtk.Template.Callback()
def on_local_mode_toggled(self, widget):
self.app.local_mode = widget.get_active()
if self.app.local_mode:
self.local_mode_toggle.set_icon_name("cloud-disabled-symbolic")
self.model_selector_button.set_visible(True)
self.provider_selector_button.set_visible(False)
self.clear_all_button.set_visible(False)
else:
self.local_mode_toggle.set_icon_name("cloud-filled-symbolic")
self.provider_selector_button.set_visible(True)
self.model_selector_button.set_visible(False)
self.clear_all_button.set_visible(False)
def check_network(self):
if self.app.check_network(): # Internet
if not self.content:
self.status_no_chat.set_visible(True)
self.status_no_internet.set_visible(False)
else:
self.status_no_chat.set_visible(False)
self.status_no_internet.set_visible(False)
else:
self.status_no_chat.set_visible(False)
self.status_no_internet.set_visible(True)
@Gtk.Template.Callback()
def on_ask(self, *args):
if not self.threads: # no chat
self.on_new_chat_action()
self.threads_list.select_row(self.threads_list.get_row_at_index(0))
prompt = self.message_entry.get_buffer().props.text.strip()
if prompt:
self.message_entry.get_buffer().set_text("")
self.add_user_item(prompt)
def thread_run():
self.toast = Adw.Toast()
self.toast.set_title(_("Generating response"))
self.toast.set_button_label(_("Cancel"))
self.toast.set_action_name("win.cancel")
self.toast.set_timeout(0)
self.toast_overlay.add_toast(self.toast)
response = self.app.ask(prompt, self.chat)
GLib.idle_add(cleanup, response, self.toast)
def cleanup(response, toast):
self.t.join()
self.toast.dismiss()
self.add_assistant_item(response)
self.t = KillableThread(target=thread_run)
self.t.start()
def cancel(self, *args):
try:
self.t.kill()
self.t.join()
self.toast.dismiss()
except AttributeError: # nothing to stop
pass
def create_action(self, name, callback, shortcuts=None):
action = Gio.SimpleAction.new(name, None)
action.connect("activate", callback)
self.add_action(action)
if shortcuts:
self.app.set_accels_for_action(f"win.{name}", shortcuts)
def add_user_item(self, content):
self.content.append(
{
"role": "user",
"content": content,
"time": time.strftime("%X")
}
)
self.threads_row_activated_cb()
def add_assistant_item(self, content):
c = {
"role": "assistant",
"content": content,
"time": time.strftime("%X"),
}
if self.app.local_mode and self.app.model_name:
c["model"] = self.app.model_name
elif self.app.current_provider:
c["model"] = self.app.current_provider
self.content.append(c)
self.threads_row_activated_cb()

View file

@ -0,0 +1,75 @@
using Gtk 4.0;
using Adw 1;
using GtkSource 5;
template $CodeBlock : Gtk.Widget {
layout-manager: BinLayout {};
vexpand: true;
height-request: 50;
Overlay {
[overlay]
Button {
styles [
"circular",
]
icon-name: "terminal-symbolic";
halign: end;
valign: start;
margin-top: 7;
margin-end: 7;
clicked => $run();
}
Box box {
orientation: vertical;
vexpand: true;
hexpand: true;
Box view {
vexpand: true;
hexpand: true;
GtkSource.View source_view {
vexpand: true;
hexpand: true;
buffer: GtkSource.Buffer buffer {};
editable: true;
monospace: true;
show-line-marks: true;
show-line-numbers: true;
smart-backspace: true;
margin-top: 5;
margin-bottom: 5;
styles [ "codeview", "card" ]
}
}
Box output {
visible: false;
vexpand: true;
hexpand: true;
GtkSource.View output_source_view {
vexpand: true;
hexpand: true;
buffer: GtkSource.Buffer output_buffer {};
editable: false;
monospace: true;
show-line-marks: true;
show-line-numbers: true;
margin-top: 5;
margin-bottom: 5;
styles [ "codeview", "card" ]
}
}
}
}
}

76
src/widgets/code_block.py Normal file
View file

@ -0,0 +1,76 @@
from gi.repository import Gtk, GtkSource, Adw, Xdp
from bavarder.constants import app_id, rootdir
import subprocess
from subprocess import SubprocessError, CompletedProcess
import os
GtkSource.init()
@Gtk.Template(resource_path=f"{rootdir}/ui/code_block.ui")
class CodeBlock(Gtk.Widget):
__gtype_name__ = "CodeBlock"
buffer = Gtk.Template.Child()
source_view = Gtk.Template.Child()
output_buffer = Gtk.Template.Child()
output_source_view = Gtk.Template.Child()
view = Gtk.Template.Child()
box = Gtk.Template.Child()
output = Gtk.Template.Child()
def __init__(self, result, **kwargs):
super().__init__(**kwargs)
self.command = result
self.buffer.set_text(self.command)
if Adw.StyleManager().get_dark():
self.buffer.set_style_scheme(GtkSource.StyleSchemeManager().get_scheme("Adwaita-dark"))
else:
self.buffer.set_style_scheme(GtkSource.StyleSchemeManager().get_scheme("Adwaita"))
if Adw.StyleManager().get_dark():
self.output_buffer.set_style_scheme(GtkSource.StyleSchemeManager().get_scheme("Adwaita-dark"))
else:
self.output_buffer.set_style_scheme(GtkSource.StyleSchemeManager().get_scheme("Adwaita"))
@Gtk.Template.Callback()
def run(self, widget, *args):
command = self.buffer.props.text.split(" ")
if self.command.startswith("$"):
command.pop(0)
portal = Xdp.Portal()
is_sandboxed = portal.running_under_sandbox()
output = self._run(command, allow_escaping=is_sandboxed)
self.output_buffer.set_text(output)
self.output.set_visible(True)
def _run(self, command: list, timeout: int = None, allow_escaping: bool = False) -> CompletedProcess:
if allow_escaping and os.environ.get('FLATPAK_ID'):
command = ['flatpak-spawn', '--host'] + command
try:
process = subprocess.Popen(command, stdout=subprocess.PIPE,
stderr=subprocess.PIPE, shell=True)
except SubprocessError:
raise
except FileNotFoundError:
raise
stdout, stderr = process.communicate()
if process.returncode != 0:
output = stderr.decode()
else:
if stdout.decode() == "":
output = _("Done")
else:
output = stdout.decode()
return output

View file

@ -0,0 +1,11 @@
using Gtk 4.0;
using Adw 1;
template $DownloadRow : Adw.ActionRow {
[suffix]
Button download {
valign: center;
icon-name: "browser-download-symbolic";
clicked => $on_download_button_clicked();
}
}

View file

@ -0,0 +1,49 @@
from gi.repository import Gtk, Adw, GLib
from bavarder.constants import app_id, rootdir
from bavarder.threading import KillableThread
@Gtk.Template(resource_path=f"{rootdir}/ui/download_row.ui")
class DownloadRow(Adw.ActionRow):
__gtype_name__ = "DownloadRow"
def __init__(self, app, window, model, **kwargs):
super().__init__(**kwargs)
self.app = app
self.window = window
self.model = model
self.setup()
def setup(self):
self.set_title(self.model["name"])
self.set_subtitle(self.model["filename"])
@Gtk.Template.Callback()
def on_download_button_clicked(self, widget, *args):
def thread_run():
self.app.action_running_in_background = True
toast = Adw.Toast()
toast.set_timeout(0)
toast.set_title(_("Downloading model %s" % self.model["name"]) )
self.window.add_toast(toast)
self.app.download_model(self.model["filename"])
GLib.idle_add(cleanup, toast)
def cleanup(toast):
t.join()
toast.dismiss()
self.app.action_running_in_background = False
self.app.list_models()
self.window.load_models()
toast = Adw.Toast()
toast.set_title(_("Model %s downloaded!" % self.model["name"]) )
self.window.add_toast(toast)
t = KillableThread(target=thread_run)
t.start()

110
src/widgets/item.blp Normal file
View file

@ -0,0 +1,110 @@
using Gtk 4.0;
using Adw 1;
template $Item : Box {
margin-top: 10;
margin-bottom: 10;
spacing: 10;
Adw.Avatar avatar {
styles [
"avatar-other",
]
valign: start;
size: 36;
}
Box {
orientation: vertical;
Box message_bubble {
spacing: 2;
orientation: vertical;
styles [
"message-bubble",
]
Box header {
orientation: horizontal;
Label user {
hexpand: true;
halign: start;
ellipsize: end;
selectable: true;
margin-end: 15;
styles [ "heading" ]
}
}
Box message_box {
orientation: vertical;
Box content {
orientation: vertical;
}
Box {
vexpand: true;
hexpand: true;
valign: end;
Label model {
styles [
"dim-label",
"caption",
"timestamp",
]
justify: left;
vexpand: true;
hexpand: true;
halign: start;
}
// Timestamp label
Label timestamp {
styles [
"dim-label",
"caption",
"timestamp",
]
justify: right;
vexpand: true;
hexpand: true;
halign: end;
}
}
}
}
}
}
PopoverMenu popover {
menu-model: popover-model;
}
menu popover-model {
section {
item {
label: _("Edit");
action: "event.edit";
}
}
section {
item {
label: _("Remove");
action: "event.delete";
}
}
}

322
src/widgets/item.py Normal file
View file

@ -0,0 +1,322 @@
from gi.repository import Gtk, Adw, Gio, GLib, Pango, GtkSource
import re
from bavarder.constants import app_id, rootdir
from bavarder.widgets.code_block import CodeBlock
H1="H1"
H2="H2"
H3="H3"
UL="BULLET"
OL="LIST"
CODE="CODE"
BOLD="BOLD"
EMPH="EMPH"
PRE="PRE"
LINK="LINK"
m2p_sections = [
{ "name": H1, "re": re.compile(r"^(#\s+)(.*)(\s*)$"), "sub": r"<big><big><big>\2</big></big></big>" },
{ "name": H2, "re": re.compile(r"^(##\s+)(.*)(\s*)$"), "sub": r"<big><big>\2</big></big>" },
{ "name": H3, "re": re.compile(r"^(###\s+)(.*)(\s*)$"), "sub": r"<big>\2</big>" },
{ "name": UL, "re": re.compile(r"^(\s*[\*\-]\s)(.*)(\s*)$"), "sub": r"\2" },
{ "name": OL, "re": re.compile(r"^(\s*[0-9]+\.\s)(.*)(\s*)$"), "sub": r" \1\2" },
{ "name": CODE, "re": re.compile(r"^```[a-z_]*$"), "sub": "<tt>" },
]
m2p_styles = [
{ "name": BOLD, "re": re.compile(r"(^|[^\*])(\*\*)(.*)(\*\*)"), "sub": r"\1<b>\3</b>" },
{ "name": BOLD, "re": re.compile(r"(\*\*)(.*)(\*\*)([^\*]|$)"), "sub": r"<b>\3</b>\4" },
{ "name": EMPH, "re": re.compile(r"(^|[^\*])(\*)(.*)(\*)"), "sub": r"\1<i>\3</i>" },
{ "name": EMPH, "re": re.compile(r"(\*)(.*)(\*)([^\*]|$)"), "sub": r"<i>\3</i>\4" },
{ "name": PRE, "re": re.compile(r"(`)([^`]*)(`)"), "sub": r"<tt>\2</tt>" },
{ "name": LINK, "re": re.compile(r"(!)?(\[)(.*)(\]\()(.+)(\))"), "sub": r"<a href='\5'>\3</a>" },
{ "name": LINK, "re": re.compile(r"(!)?(\[)(.*)(\]\(\))"), "sub": r"<a href='\3'>\3</a>" },
]
re_comment = re.compile(r"^\s*<!--.*-->\s*$")
re_color = re.compile(r"^(\s*<!--\s*(fg|bg)=(#?[0-9a-z_A-Z-]*)\s*((fg|bg)=(#?[0-9a-z_A-Z-]*))?\s*-->\s*)$")
re_reset = re.compile(r"(<!--\/-->)")
re_uri = re.compile(r"http[s]?:\/\/[^\s']*")
re_href = re.compile(r"href='(http[s]?:\\/\\/[^\\s]*)'")
re_atag = re.compile(r"<a\s.*>.*(http[s]?:\\/\\/[^\\s]*).*</a>")
re_h1line = re.compile(r"^===+\s*$")
re_h2line = re.compile(r"^---+\s*$")
m2p_escapes = [
[re.compile(r"<!--.*-->"), ''],
[re.compile(r"&"), '&amp;'],
[re.compile(r"<"), '&lt;'],
[re.compile(r">"), '&gt;'],
]
@Gtk.Template(resource_path=f"{rootdir}/ui/item.ui")
class Item(Gtk.Box):
__gtype_name__ = "Item"
user = Gtk.Template.Child()
content = Gtk.Template.Child()
timestamp = Gtk.Template.Child()
popover = Gtk.Template.Child()
avatar = Gtk.Template.Child()
message_bubble = Gtk.Template.Child()
model = Gtk.Template.Child()
def __init__(self, parent, chat, item, **kwargs):
super().__init__(**kwargs)
self.chat = chat
self.item = item
self.content_text = self.item["content"]
self.convert_content_to_pango()
result = ""
for line in self.content_markup:
if isinstance(line, str):
result += f"{line}\n"
else: # code
label = Gtk.Label()
label.set_use_markup(True)
label.set_wrap(True)
label.set_xalign(0)
label.set_wrap_mode(Pango.WrapMode.WORD)
label.set_markup(result)
label.set_justify(Gtk.Justification.LEFT)
label.set_valign(Gtk.Align.START)
label.set_hexpand(True)
label.set_halign(Gtk.Align.START)
self.content.append(label)
result = "\n".join(line)
self.content.append(CodeBlock(result))
result = ""
else:
if not result.strip() == "<tt></tt>`":
label = Gtk.Label()
label.set_use_markup(True)
label.set_wrap(True)
label.set_xalign(0)
label.set_wrap_mode(Pango.WrapMode.WORD)
label.set_markup(result)
label.set_justify(Gtk.Justification.LEFT)
label.set_valign(Gtk.Align.START)
label.set_hexpand(True)
label.set_halign(Gtk.Align.START)
self.content.append(label)
t = self.item["role"].capitalize()
if t == "User":
self.message_bubble.add_css_class("message-bubble-user")
self.avatar.add_css_class("avatar-user")
role = _("User")
elif t == "Assistant":
self.avatar.set_icon_name("bot-symbolic")
self.user.add_css_class("warning")
role = _("Assistant")
else:
role = t
self.timestamp.set_text(self.item.get("time", ""))
self.model.set_text(self.item.get("model", ""))
self.avatar.set_text(role)
self.user.set_text(role)
self.parent = parent
self.settings = parent.settings
self.app = self.parent.get_application()
self.win = self.app.get_active_window()
self.setup()
def setup(self):
self.setup_signals()
evk = Gtk.GestureClick.new()
evk.connect("pressed", self.show_menu)
evk.set_button(3)
self.add_controller(evk)
def show_menu(self, gesture, data, x, y):
self.popover.set_parent(self)
self.popover.popup()
def setup_signals(self):
self.action_group = Gio.SimpleActionGroup()
self.create_action("delete", self.on_delete)
self.create_action("edit", self.on_edit)
self.insert_action_group("event", self.action_group);
def create_action(self, name, callback, shortcuts=None):
action = Gio.SimpleAction.new(name, None)
action.connect("activate", callback)
self.action_group.add_action(action)
if shortcuts:
self.set_accels_for_action(f"app.{name}", shortcuts)
def on_delete(self, *args, **kwargs):
self.chat["content"].remove(self.item)
self.win.threads_row_activated_cb()
def on_edit(self, *args):
self.win.message_entry.get_buffer().set_text(self.item["content"])
def convert_content_to_pango(self):
lines = self.content_text.split("\n")
is_code = False
code_lines = []
output = []
self.color_span_open = False
tt_must_close = False
def try_close_span():
if self.color_span_open:
output.append('</span>')
self.color_span_open = False
def try_open_span():
if not self.color_span_open:
output.append('</span>')
self.color_span_open = False
def escape_line(line):
for escape in m2p_escapes:
line = re.sub(escape[0], escape[1], line)
return line
# def pad(lines, start=1, end=1):
# length = 0
# for line in lines:
# if len(line) > 0:
# length += len(line)
# else:
# length += 0
# for line in lines:
# line.rjust()
# return lines.map((l) => l.padEnd(len + end, ' ').padStart(len + end + start, ' '))
for line in lines:
if not is_code:
colors = re_color.match(line)
if colors or re_reset.match(line):
try_close_span()
if colors:
try_close_span()
if self.color_span_open:
try_close_span()
if colors[2] == 'fg':
fg = colors[3]
elif colors[5] == 'fg':
fg = colors[6]
else:
fg = ""
if colors[2] == 'bg':
fg = colors[3]
elif colors[5] == 'bg':
fg = colors[6]
else:
fg = ""
attrs = ''
if fg != '':
attrs += f" foreground='{fg}'"
if bg != '':
attrs += f" background='{bg}'"
if attrs != '':
output.append("<span {attrs}>")
self.color_span_open = True
if re_comment.match(line):
continue
code_start = False
if is_code:
result = line
else:
result = escape_line(line)
for exp in m2p_sections:
name = exp["name"]
regexp = exp["re"]
sub = exp["sub"]
if regexp.match(line):
if name == CODE:
if not is_code:
code_start = True
is_code = True
result = ""
#if self.color_span_open:
# result = '<tt>'
# tt_must_close = False
#else:
# result = "<span foreground='#bbb' background='#222'>" + '<tt>'
# tt_must_close = True
else:
is_code = False
#output.append(...pad(code_lines).map(escape_line))
output.append(code_lines)
code_lines = []
#result = '</tt>'
if tt_must_close:
result += '</span>'
tt_must_close = False
else:
if is_code:
result = line
else:
result = re.sub(regexp, sub, line)
if is_code and not code_start:
code_lines.append(result)
continue
if re_h1line.match(line):
output.append(re.sub(m2p_sections[0]["re"], m2p_sections[0]["sub"], f"# {output.pop()}"))
continue
if re_h2line.match(line):
output.append(re.sub(m2p_sections[1]["re"], m2p_sections[1]["sub"], f"# {output.pop()}"))
continue
for style in m2p_styles:
regexp = style["re"]
sub = style["sub"]
result = re.sub(regexp, sub, result)
uri = re_uri.match(result) # look for any URI
href = re_href.match(result) # and for URIs in href=''
atag = re_atag.match(result) # and for URIs in <a></a>
if uri and (href or atag):
result = result.replace(uri, f"<a href='{uri}'>{uri}</a>")
output.append(result)
try_close_span()
self.content_markup = output

View file

@ -1,9 +1,12 @@
widgets_dir = join_paths(moduledir, 'widgets')
widgets_dir = join_paths(MODULE_DIR, 'widgets')
widgets_sources = [
'__init__.py',
'message_bubble.py',
'code_block.py',
'item.py',
'thread_item.py',
'download_row.py',
'model_item.py',
]
PY_INSTALLDIR.install_sources(widgets_sources, subdir: widgets_dir)
PY_INSTALLDIR.install_sources(widgets_sources, subdir: widgets_dir)

View file

@ -1,59 +0,0 @@
from gi.repository import Adw, Gtk, Gio
from bavarder.constants import app_id, build_type
MAX_WIDTH = 400
@Gtk.Template(resource_path="/io/github/Bavarder/Bavarder/ui/message_bubble.ui")
class MessageBubble(Gtk.Box):
__gtype_name__ = "MessageBubble"
sender_label = Gtk.Template.Child()
message_reply_bin = Gtk.Template.Child()
prefix_bin = Gtk.Template.Child()
message_label = Gtk.Template.Child()
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.app = Gtk.Application.get_default()
# def measure(self, orientation, , for_size):
# # Limit the widget width
# if orientation == Gtk.Orientation.HORIZONTAL:
# minimum, natural, minimum_baseline, natural_baseline = \
# self.overlay.measure(orientation, for_size)
# return (
# minimum.min(MAX_WIDTH),
# natural.min(MAX_WIDTH),
# minimum_baseline,
# natural_baseline,
# )
# else:
# adjusted_for_size = for_size.min(MAX_WIDTH);
# self.overlay.measure(orientation, adjusted_for_size)
#
#
# def size_allocate(self, width, height, baseline):
# self.overlay.allocate(width, height, baseline, None)
#
# def request_mode(self):
# return Gtk.SizeRequestMode.HEIGHT_FOR_WIDTH
def set_label(self, label):
if label.is_empty():
self.message_label.set_label("")
self..message_label.set_visible(false)
self.remove_css_class("with-label")
else:
self.message_label.set_label(label)
self.message_label.set_visible(true)
self.add_css_class("with-label")

View file

@ -0,0 +1,11 @@
using Gtk 4.0;
using Adw 1;
template $Model : Adw.ActionRow {
[suffix]
Button delete_button {
valign: center;
icon-name: "user-trash-symbolic";
clicked => $on_delete_button_clicked();
}
}

32
src/widgets/model_item.py Normal file
View file

@ -0,0 +1,32 @@
import unicodedata
import re
from typing import List, Dict
from gi.repository import Gtk, Adw, GLib
from bavarder.constants import app_id, rootdir
@Gtk.Template(resource_path=f"{rootdir}/ui/model_item.ui")
class Model(Adw.ActionRow):
__gtype_name__ = "Model"
def __init__(self, app, window, model, **kwargs):
super().__init__(**kwargs)
self.app = app
self.window = window
self.model = model
self.setup()
def setup(self):
self.set_title(self.model)
self.app.win.load_model_selector()
@Gtk.Template.Callback()
def on_delete_button_clicked(self, widget, *args):
self.app.delete_model(self.model)
self.window.load_models()
toast = Adw.Toast()
toast.set_title(_("Model %s deleted!" % self.model) )
self.window.add_toast(toast)

View file

@ -0,0 +1,46 @@
using Gtk 4.0;
using Adw 1;
template $ThreadItem : Box {
orientation: horizontal;
styles ["flat"]
Stack value-stack {
styles ["flat"]
valign: center;
hhomogeneous: false;
interpolate-size: true;
transition-type: crossfade;
Gtk.Inscription label {
hexpand: true;
xalign: 0;
text-overflow: ellipsize_end;
}
Entry text-value {
styles ["flat"]
}
}
ToggleButton text-value-toggle {
valign: center;
icon-name: "document-edit-symbolic";
tooltip-text: _("Edit Title");
styles ["flat"]
toggled => $on_text_value_toggled();
}
Button delete_button {
styles ["flat"]
icon-name: "user-trash-symbolic";
clicked => $on_delete_button_clicked();
}
Button star_button {
styles ["flat"]
icon-name: "non-starred-symbolic"; // starred-symbolic
clicked => $on_star_button_clicked();
}
}

View file

@ -0,0 +1,81 @@
from gi.repository import Gtk, Adw, Gio, GLib
from bavarder.constants import app_id, rootdir
@Gtk.Template(resource_path=f"{rootdir}/ui/thread_item.ui")
class ThreadItem(Gtk.Box):
__gtype_name__ = "ThreadItem"
label = Gtk.Template.Child()
text_value = Gtk.Template.Child("text-value")
value_stack = Gtk.Template.Child("value-stack")
text_value_toggle = Gtk.Template.Child("text-value-toggle")
star_button = Gtk.Template.Child()
def __init__(self, parent, chat, **kwargs):
super().__init__(**kwargs)
self.chat = chat
self.id = chat["id"]
self.label_text = chat["title"]
self.is_starred = chat.get("starred", False)
self.label.set_text(self.label_text)
self.parent = parent
self.settings = parent.settings
self.app = self.parent.get_application()
self.win = self.app.get_active_window()
self.setup()
def setup(self):
self.setup_signals()
self.update_star()
def setup_signals(self):
pass
@Gtk.Template.Callback()
def on_text_value_toggled(self, *args):
if self.text_value_toggle.get_active():
self.text_value_toggle.set_icon_name("check-round-outline-symbolic")
self.text_value.set_text(self.label_text)
widget = self.text_value
tooltip = _("Set Title")
else:
self.text_value_toggle.set_icon_name("document-edit-symbolic")
self.label_text = self.text_value.get_text()
self.chat["title"] = self.label_text
self.text_value.set_text(self.label_text)
self.win.title.set_title(self.label_text)
tooltip = _("Edit Title")
widget = self.label
self.value_stack.set_visible_child(widget)
self.text_value_toggle.set_tooltip_text(tooltip)
self.label.set_text(self.label_text)
@Gtk.Template.Callback()
def on_star_button_clicked(self, *args):
self.is_starred = not self.is_starred
self.update_star()
def update_star(self):
self.chat["starred"] = self.is_starred
if self.is_starred:
self.star_button.set_icon_name("starred-symbolic")
self.label.set_css_classes(["accent"])
else:
self.star_button.set_icon_name("non-starred-symbolic")
self.label.set_css_classes([])
@Gtk.Template.Callback()
def on_delete_button_clicked(self, *args):
self.app.data["chats"].remove(self.chat)
self.win.load_threads()