tuxwhisper 0.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,12 @@
1
+ .venv/
2
+ __pycache__/
3
+ recordings/
4
+ claude.txt
5
+ notes.md
6
+ vocab.txt
7
+ replacements.txt
8
+ modes.txt
9
+ PRODUCT.md
10
+ .impeccable/
11
+ dist/
12
+ *.egg-info/
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Ibrahim Almajai
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,58 @@
1
+ Metadata-Version: 2.5
2
+ Name: tuxwhisper
3
+ Version: 0.2.0
4
+ Summary: Private, offline push-to-talk dictation for Linux, on X11 and Wayland
5
+ Project-URL: Homepage, https://github.com/ialmajai/tuxwhisper
6
+ Project-URL: Documentation, https://github.com/ialmajai/tuxwhisper#readme
7
+ Project-URL: Issues, https://github.com/ialmajai/tuxwhisper/issues
8
+ Author: Ibrahim Almajai
9
+ License-Expression: MIT
10
+ License-File: LICENSE
11
+ Keywords: dictation,linux,speech-to-text,voice-typing,wayland,whisper
12
+ Classifier: Environment :: X11 Applications
13
+ Classifier: Operating System :: POSIX :: Linux
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Topic :: Multimedia :: Sound/Audio :: Speech
16
+ Requires-Python: <3.15,>=3.11
17
+ Requires-Dist: evdev-binary>=1.6
18
+ Requires-Dist: faster-whisper<2,>=1.2
19
+ Requires-Dist: numpy>=1.24
20
+ Requires-Dist: sounddevice>=0.5
21
+ Provides-Extra: cuda
22
+ Requires-Dist: nvidia-cublas-cu12; extra == 'cuda'
23
+ Requires-Dist: nvidia-cudnn-cu12==9.*; extra == 'cuda'
24
+ Provides-Extra: vulkan
25
+ Requires-Dist: pywhispercpp<2,>=1.5; extra == 'vulkan'
26
+ Description-Content-Type: text/markdown
27
+
28
+ # TuxWhisper
29
+
30
+ **Private, offline dictation for Linux.** Press a key, speak, and your words are typed wherever
31
+ your cursor is: a browser text box, an LLM chat prompt, your editor or your terminal. Speech
32
+ recognition ([faster-whisper](https://github.com/SYSTRAN/faster-whisper)) and the optional LLM
33
+ cleanup ([Ollama](https://ollama.com)) run on your own machine with free, open models.
34
+
35
+ ![TuxWhisper demo](https://raw.githubusercontent.com/ialmajai/tuxwhisper/main/docs/demo.gif)
36
+
37
+ ## Install
38
+
39
+ ```bash
40
+ uv tool install tuxwhisper # NVIDIA GPU: uv tool install 'tuxwhisper[cuda]'
41
+ tuxwhisper setup
42
+ ```
43
+
44
+ `tuxwhisper setup` installs the system packages it needs (Debian, Ubuntu, Fedora, Arch and
45
+ openSUSE), sets up the background service and, on GNOME, binds the keys. It says what each step
46
+ does and asks before anything that needs your password. On an AMD or Intel GPU, it builds the
47
+ Vulkan engine for you.
48
+
49
+ Then click into any text box, press F5, wait for the start sound, speak, and press F5 again.
50
+
51
+ | Key | Action |
52
+ |-----|--------|
53
+ | **F5** | Tap to start and stop, or hold to talk |
54
+ | **F3** | Same, with local LLM cleanup |
55
+ | **F4** | Save the last recording for fine-tuning |
56
+ | **Alt+F9** | Settings menu |
57
+
58
+ Documentation, other desktops and troubleshooting: <https://github.com/ialmajai/tuxwhisper>
@@ -0,0 +1,113 @@
1
+ # 🐧 TuxWhisper
2
+
3
+ **Private, offline dictation for Linux.** Press a key, speak, and your words are typed
4
+ wherever your cursor is: a browser text box, an LLM chat prompt, your editor or your
5
+ terminal. Everything runs on your own machine with free, open models. Your voice never
6
+ reaches a cloud service, and there's nothing to pay for.
7
+
8
+ [![CI](https://github.com/ialmajai/tuxwhisper/actions/workflows/ci.yml/badge.svg)](https://github.com/ialmajai/tuxwhisper/actions/workflows/ci.yml)
9
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
10
+ ![Platform: Linux](https://img.shields.io/badge/platform-Linux-blue?logo=linux&logoColor=white)
11
+ ![X11 | Wayland](https://img.shields.io/badge/display-X11%20%7C%20Wayland-555)
12
+
13
+ ![Animated re-enactment of TuxWhisper: tap the dictation key, speak, tap again, and the sentence is typed into Google's search box in Chrome; in a terminal running Claude Code, the cleanup key also removes filler words; the settings key opens the settings menu](docs/demo.gif)
14
+
15
+ <sub>Re-enactment over real screenshots; the cleaned-up sentence is a local LLM's actual output.</sub>
16
+
17
+ ## Features
18
+
19
+ - **Fast:** OpenAI's open Whisper model ([faster-whisper](https://github.com/SYSTRAN/faster-whisper))
20
+ types your words about half a second after you release the key, with an NVIDIA GPU. AMD
21
+ and Intel GPUs work through Vulkan.
22
+ - **Types anywhere:** browsers, editors, terminals, on X11 and Wayland (including GNOME).
23
+ - **LLM cleanup (optional):** F3 runs your words through a local [Ollama](https://ollama.com)
24
+ model (Meta's Llama 3.2 by default) that removes "um"s and fixes punctuation, or rewrites
25
+ them as an email, bullet points or your own mode. The model must fit in the GPU memory of
26
+ the machine running Ollama; otherwise F3 pastes the raw transcript.
27
+ - **Many languages:** dictate in any of Whisper's 100 languages. F3 replies in the language
28
+ you spoke; Llama 3.2 is weak outside English, so [pick a stronger model](docs/llm-cleanup.md)
29
+ for other languages.
30
+
31
+ **Also:** tap or hold to talk, a custom vocabulary for names and jargon, replacements such as
32
+ "new line" → line break, a settings menu with your last 20 transcripts, and
33
+ [saved recordings](docs/saving-takes.md) for fine-tuning Whisper to your voice and accent.
34
+ TuxWhisper types by pasting, then puts back the text you had copied.
35
+
36
+ Tested on GNOME (Wayland) with an NVIDIA GPU and in CPU mode, and on
37
+ [Sway 1.12 and i3 4.25](docs/other-desktops.md) in containers.
38
+
39
+ ## Usage
40
+
41
+ | Key | Action |
42
+ |-----|--------|
43
+ | **F5** | Tap to start, tap to stop, or hold to talk. The text is typed at your cursor. |
44
+ | **F3** | Same as F5, with [LLM cleanup](docs/llm-cleanup.md). |
45
+ | **F4** | [Save the last recording](docs/saving-takes.md) and its transcript for fine-tuning. |
46
+ | **Alt+F9** | Open the [settings menu](docs/configuration.md#settings-menu). |
47
+
48
+ The installer binds these keys on GNOME. Wait for the "🎙 Recording…" notification and the start
49
+ sound before speaking.
50
+
51
+ ## Install
52
+
53
+ You need Linux with systemd, [uv](https://docs.astral.sh/uv/), and a GPU with about 1.5 GB of
54
+ free memory: NVIDIA (CUDA), or AMD or Intel ([Vulkan](docs/configuration.md#amd-and-intel-gpus-vulkan),
55
+ not yet tested on those). No GPU? TuxWhisper runs on the CPU too, more slowly.
56
+ No uv yet? Its official installer:
57
+
58
+ ```bash
59
+ curl -LsSf https://astral.sh/uv/install.sh | sh
60
+ ```
61
+
62
+ Then:
63
+
64
+ ```bash
65
+ git clone https://github.com/ialmajai/tuxwhisper.git ~/tuxwhisper
66
+ cd ~/tuxwhisper
67
+ ./install.sh
68
+ ```
69
+
70
+ The installer says what each step does and asks before anything that needs your password.
71
+ It's safe to run again. [Read it](install.sh) first if you like. It installs system packages
72
+ on Debian, Ubuntu, Fedora, Arch and openSUSE; on other distros, use the manual install below.
73
+
74
+ **Advanced:** [Manual install](docs/manual-install.md) runs every step by hand.
75
+ [Other desktops](docs/other-desktops.md) covers KDE, Hyprland, Sway and i3.
76
+
77
+ ### Try it
78
+
79
+ Click into any text box, hold F5, wait for the start sound, speak, and release. Nothing
80
+ typed? See [Troubleshooting](docs/troubleshooting.md).
81
+
82
+ > [!TIP]
83
+ > F5 and F3 replace page refresh and find-next in browsers and many editors. Ctrl+R and Ctrl+G
84
+ > still do those.
85
+
86
+ ### Optional: LLM cleanup (F3)
87
+
88
+ F3 needs [Ollama](https://ollama.com) and about 2 GB more GPU memory:
89
+ [set it up](docs/llm-cleanup.md#install).
90
+
91
+ ## Uninstall
92
+
93
+ ```bash
94
+ ./uninstall.sh
95
+ ```
96
+
97
+ It asks before removing the virtual keyboard rule, and keeps your settings, saved recordings and
98
+ downloaded models, listing where they are.
99
+
100
+ ## Documentation
101
+
102
+ - [Manual install](docs/manual-install.md)
103
+ - [LLM cleanup (F3)](docs/llm-cleanup.md)
104
+ - [Saving recordings for fine-tuning (F4)](docs/saving-takes.md)
105
+ - [Configuration](docs/configuration.md): settings menu, custom vocabulary, replacements, GPU and CPU modes
106
+ - [Other desktops](docs/other-desktops.md)
107
+ - [How it works](docs/how-it-works.md)
108
+ - [Security](docs/security.md)
109
+ - [Troubleshooting](docs/troubleshooting.md)
110
+
111
+ ## License
112
+
113
+ [MIT](LICENSE) © 2026 Ibrahim Almajai
tuxwhisper-0.2.0/asr ADDED
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env bash
2
+ # Runs TuxWhisper from a git clone: the package in tuxwhisper/ with the clone's .venv.
3
+ # Also puts pip-installed cuDNN/cuBLAS and whisper.cpp libraries (if any) on the library path.
4
+ DIR="$(cd "$(dirname "$(readlink -f "$0")")" && pwd)"
5
+ for SITE in "$DIR"/.venv/lib/python3*/site-packages; do
6
+ [ -d "$SITE/nvidia" ] && export LD_LIBRARY_PATH="$SITE/nvidia/cudnn/lib:$SITE/nvidia/cublas/lib${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
7
+ [ -e "$SITE/libwhisper.so.1" ] && export LD_LIBRARY_PATH="$SITE${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
8
+ done
9
+ export TUXWHISPER_CMD="$DIR/asr" TUXWHISPER_LIBS_SET=1 PYTHONPATH="$DIR${PYTHONPATH:+:$PYTHONPATH}"
10
+ exec "$DIR/.venv/bin/python" -m tuxwhisper "$@"
@@ -0,0 +1,31 @@
1
+ # TuxWhisper
2
+
3
+ **Private, offline dictation for Linux.** Press a key, speak, and your words are typed wherever
4
+ your cursor is: a browser text box, an LLM chat prompt, your editor or your terminal. Speech
5
+ recognition ([faster-whisper](https://github.com/SYSTRAN/faster-whisper)) and the optional LLM
6
+ cleanup ([Ollama](https://ollama.com)) run on your own machine with free, open models.
7
+
8
+ ![TuxWhisper demo](https://raw.githubusercontent.com/ialmajai/tuxwhisper/main/docs/demo.gif)
9
+
10
+ ## Install
11
+
12
+ ```bash
13
+ uv tool install tuxwhisper # NVIDIA GPU: uv tool install 'tuxwhisper[cuda]'
14
+ tuxwhisper setup
15
+ ```
16
+
17
+ `tuxwhisper setup` installs the system packages it needs (Debian, Ubuntu, Fedora, Arch and
18
+ openSUSE), sets up the background service and, on GNOME, binds the keys. It says what each step
19
+ does and asks before anything that needs your password. On an AMD or Intel GPU, it builds the
20
+ Vulkan engine for you.
21
+
22
+ Then click into any text box, press F5, wait for the start sound, speak, and press F5 again.
23
+
24
+ | Key | Action |
25
+ |-----|--------|
26
+ | **F5** | Tap to start and stop, or hold to talk |
27
+ | **F3** | Same, with local LLM cleanup |
28
+ | **F4** | Save the last recording for fine-tuning |
29
+ | **Alt+F9** | Settings menu |
30
+
31
+ Documentation, other desktops and troubleshooting: <https://github.com/ialmajai/tuxwhisper>
@@ -0,0 +1,205 @@
1
+ #!/usr/bin/env bash
2
+ # TuxWhisper installer. Safe to run again: each step skips what is already done.
3
+ # Run it from a git clone (./install.sh), or as `tuxwhisper setup` after installing from PyPI.
4
+ # docs/manual-install.md does the same steps by hand.
5
+ # --yes answer yes to every question
6
+ # --packages-only install the system packages and stop (used by CI)
7
+ # --engine=E cuda (NVIDIA), vulkan (AMD/Intel GPUs) or cpu; detected when not given
8
+ set -euo pipefail
9
+
10
+ DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11
+ cd "$DIR"
12
+ # `tuxwhisper setup` runs this script from inside the installed package and passes its command;
13
+ # a git clone runs ./asr, which uses the clone's .venv.
14
+ PACKAGED="${TUXWHISPER_PACKAGED:-}"
15
+ CMD="${TUXWHISPER_CMD:-$DIR/asr}"
16
+ UNIT_DIR="${XDG_CONFIG_HOME:-$HOME/.config}/systemd/user"
17
+ APPS_DIR="${XDG_DATA_HOME:-$HOME/.local/share}/applications"
18
+ RULE=/etc/udev/rules.d/60-uinput.rules
19
+ RULE_TEXT='KERNEL=="uinput", TAG+="uaccess", OPTIONS+="static_node=uinput"'
20
+ YES=0 PACKAGES_ONLY=0 engine=
21
+ for arg in "$@"; do
22
+ case "$arg" in
23
+ --yes) YES=1 ;;
24
+ --packages-only) PACKAGES_ONLY=1 ;;
25
+ --engine=cuda|--engine=vulkan|--engine=cpu) engine=${arg#--engine=} ;;
26
+ *) echo "Unknown option: $arg" >&2; exit 2 ;;
27
+ esac
28
+ done
29
+ SUDO=sudo; [ "$(id -u)" = 0 ] && SUDO=
30
+
31
+ step() { printf '\n\033[1m%s\033[0m\n' "$*"; }
32
+ note() { printf ' %s\n' "$*"; }
33
+ ask() { local a; [ "$YES" = 1 ] && return 0; read -r -p " $1 [Y/n] " a; [[ -z $a || $a =~ ^[Yy] ]]; }
34
+
35
+ case "$DIR$CMD" in *[\"\|\&\\]*) echo "Move TuxWhisper to a path without \" | & or \\ characters." >&2; exit 1 ;; esac
36
+
37
+ # Speech engine: faster-whisper with CUDA on NVIDIA, whisper.cpp with Vulkan on AMD or Intel GPUs
38
+ # (PCI vendors 0x1002 and 0x8086), otherwise faster-whisper on the CPU.
39
+ if [ -z "$engine" ]; then
40
+ if command -v nvidia-smi >/dev/null && nvidia-smi -L >/dev/null 2>&1; then engine=cuda
41
+ elif grep -qsxE '0x(1002|8086)' /sys/class/drm/card*/device/vendor; then engine=vulkan
42
+ else engine=cpu; fi
43
+ fi
44
+
45
+ step "1/6 System packages"
46
+ # A compiler and kernel headers build the keyboard library; PortAudio reads the microphone.
47
+ # The rest are clipboard tools, the settings menu, notifications and the start/stop sounds.
48
+ # CI installs these lists on each distro; keep docs/manual-install.md in sync.
49
+ # shellcheck source=/dev/null
50
+ . /etc/os-release 2>/dev/null || true
51
+ case " ${ID:-} ${ID_LIKE:-} " in
52
+ *" debian "*|*" ubuntu "*) pm=(apt-get install -y) pkgs=(libportaudio2 xclip wl-clipboard zenity libnotify-bin sound-theme-freedesktop)
53
+ vulkan=(g++ cmake libvulkan-dev glslc spirv-headers glslang-tools mesa-vulkan-drivers) ;;
54
+ *" fedora "*) pm=(dnf install -y) pkgs=(portaudio xclip wl-clipboard zenity libnotify sound-theme-freedesktop)
55
+ vulkan=(gcc-c++ cmake vulkan-loader-devel glslc spirv-headers-devel glslang mesa-vulkan-drivers) ;;
56
+ *" arch "*) pm=(pacman -S --needed --noconfirm) pkgs=(portaudio xclip wl-clipboard zenity libnotify sound-theme-freedesktop)
57
+ vulkan=(gcc cmake vulkan-icd-loader vulkan-headers shaderc spirv-headers glslang vulkan-radeon vulkan-intel) ;;
58
+ *" suse "*|*" opensuse "*) pm=(zypper -n install) pkgs=(portaudio xclip wl-clipboard zenity libnotify-tools sound-theme-freedesktop)
59
+ vulkan=(gcc-c++ cmake vulkan-devel shaderc spirv-headers glslang-devel libvulkan_radeon libvulkan_intel) ;;
60
+ *) pm=() pkgs=() vulkan=() ;;
61
+ esac
62
+ # The Vulkan engine is compiled on install: a C++ compiler, CMake, Vulkan headers and shader tools.
63
+ [ "$engine" = vulkan ] && pkgs+=("${vulkan[@]}")
64
+ have_all() {
65
+ { command -v xclip || command -v wl-copy; } && command -v zenity && command -v notify-send &&
66
+ [ -f /usr/share/sounds/freedesktop/stereo/device-added.oga ] &&
67
+ { ldconfig -p 2>/dev/null || /sbin/ldconfig -p; } | grep libportaudio >/dev/null &&
68
+ { [ "$engine" != vulkan ] || { command -v g++ && command -v cmake && command -v glslc &&
69
+ command -v glslangValidator && [ -f /usr/include/vulkan/vulkan.h ]; }; }
70
+ } >/dev/null 2>&1
71
+ if have_all; then
72
+ note "Already installed."
73
+ elif [ ${#pm[@]} = 0 ]; then
74
+ note "Unknown distro (${ID:-?}). Install the packages listed in docs/manual-install.md, then run this again."
75
+ exit 1
76
+ else
77
+ note "This runs: ${SUDO:+sudo }${pm[*]} ${pkgs[*]}"
78
+ if ask "Install them?"; then
79
+ [ "${pm[0]}" = apt-get ] && $SUDO apt-get update -q
80
+ $SUDO "${pm[@]}" "${pkgs[@]}"
81
+ else
82
+ note "Skipped. Without them the Python packages may fail to build in the next step."
83
+ fi
84
+ fi
85
+ [ "$PACKAGES_ONLY" = 1 ] && exit 0
86
+
87
+ # uv's installer puts uv in ~/.local/bin, which a shell opened before it isn't searching yet.
88
+ command -v uv >/dev/null || PATH="${XDG_BIN_HOME:-$HOME/.local/bin}:$PATH"
89
+ command -v uv >/dev/null || { echo "Install uv first: https://docs.astral.sh/uv/getting-started/installation/" >&2; exit 1; }
90
+ command -v systemctl >/dev/null || { echo "TuxWhisper needs systemd. See docs/manual-install.md." >&2; exit 1; }
91
+
92
+ step "2/6 Python packages"
93
+ case "$engine" in
94
+ cuda) extra="[cuda]"; note "NVIDIA GPU: using the CUDA build." ;;
95
+ vulkan) extra="[vulkan]"
96
+ note "AMD or Intel GPU: using whisper.cpp with Vulkan, built here (a few minutes)."
97
+ note "Untested on AMD and Intel so far; if it's slow, run this again with --engine=cpu." ;;
98
+ cpu) extra=""; note "No supported GPU: using the CPU build (slower)." ;;
99
+ esac
100
+ build=(); [ "$engine" = vulkan ] && build=(env GGML_VULKAN=1)
101
+ if [ -n "$PACKAGED" ]; then
102
+ # Installed with uv or pip: add the GPU libraries if this install lacks them.
103
+ PY="$TUXWHISPER_PY"
104
+ case "$engine" in
105
+ cuda) check='import nvidia.cudnn, nvidia.cublas' ;;
106
+ vulkan) check='import os, sysconfig; assert os.path.exists(sysconfig.get_paths()["purelib"] + "/libggml-vulkan.so")' ;;
107
+ cpu) check='pass' ;;
108
+ esac
109
+ if "$PY" -c "$check" 2>/dev/null; then
110
+ note "Already installed."
111
+ else
112
+ spec="tuxwhisper$extra==$TUXWHISPER_VERSION"
113
+ nobin=(); [ "$engine" = vulkan ] && nobin=(--no-binary-package pywhispercpp)
114
+ note "This runs: ${build[*]} uv tool install --reinstall ${nobin[*]} '$spec'"
115
+ "${build[@]}" uv tool install -q --reinstall "${nobin[@]}" "$spec"
116
+ fi
117
+ else
118
+ [ -d .venv ] || uv venv -q --python 3.12 .venv
119
+ uv pip uninstall -q --python .venv evdev 2>/dev/null || true # replaced by evdev-binary in 0.2
120
+ nobin=(); [ "$engine" = vulkan ] && nobin=(--no-binary pywhispercpp)
121
+ "${build[@]}" uv pip install -q --python .venv "${nobin[@]}" -e ".$extra"
122
+ fi
123
+
124
+ step "3/6 Virtual keyboard (lets TuxWhisper type for you)"
125
+ if [ -f "$RULE" ] && grep -qF "$RULE_TEXT" "$RULE"; then
126
+ note "Already set up."
127
+ else
128
+ note "This writes one line to $RULE:"
129
+ note " $RULE_TEXT"
130
+ note "It lets any program you run send keystrokes, not only TuxWhisper (docs/security.md)."
131
+ if ask "Allow it? Needs your password once."; then
132
+ echo "$RULE_TEXT" | $SUDO tee "$RULE" >/dev/null
133
+ $SUDO udevadm control --reload
134
+ $SUDO udevadm trigger --name-match=uinput
135
+ else
136
+ note "Skipped: TuxWhisper will copy each transcript for you to paste with Ctrl+V."
137
+ fi
138
+ fi
139
+
140
+ step "4/6 Background service"
141
+ service=1
142
+ if ! systemctl --user is-active -q graphical-session.target; then
143
+ service=0
144
+ note "Your desktop doesn't start systemd's graphical session (common on i3 and Sway)."
145
+ note "Start TuxWhisper from your window manager's config instead, e.g.:"
146
+ note " exec \"$CMD\" serve"
147
+ note "See docs/other-desktops.md."
148
+ else
149
+ mkdir -p "$UNIT_DIR"
150
+ if [ -f "$UNIT_DIR/tuxwhisper.service" ]; then
151
+ note "Keeping your existing $UNIT_DIR/tuxwhisper.service."
152
+ else
153
+ sed "s|^ExecStart=.*|ExecStart=\"$CMD\" serve|" tuxwhisper.service > "$UNIT_DIR/tuxwhisper.service"
154
+ note "Installed $UNIT_DIR/tuxwhisper.service."
155
+ fi
156
+ # One drop-in file names the engine; NVIDIA needs none (cuda is the default).
157
+ rm -f "$UNIT_DIR/tuxwhisper.service.d/cpu.conf" "$UNIT_DIR/tuxwhisper.service.d/vulkan.conf"
158
+ if [ "$engine" != cuda ]; then
159
+ mkdir -p "$UNIT_DIR/tuxwhisper.service.d"
160
+ printf '[Service]\nEnvironment=ASR_DEVICE=%s\n' "$engine" > "$UNIT_DIR/tuxwhisper.service.d/$engine.conf"
161
+ note "Set ASR_DEVICE=$engine."
162
+ fi
163
+ systemctl --user daemon-reload
164
+ systemctl --user enable -q tuxwhisper
165
+ since="$(date '+%Y-%m-%d %H:%M:%S')"
166
+ systemctl --user restart tuxwhisper
167
+ note "Started; it also starts at every login."
168
+ fi
169
+
170
+ step "5/6 Keyboard shortcuts and app-grid launcher"
171
+ if [[ "${XDG_CURRENT_DESKTOP:-}" == *GNOME* ]]; then
172
+ "$CMD" bind | sed 's/^/ /'
173
+ note "F5 and F3 now replace page refresh and find-next in browsers; Ctrl+R and Ctrl+G still work."
174
+ else
175
+ note "Bind these in your desktop's shortcut settings (docs/other-desktops.md):"
176
+ note " F5 -> \"$CMD\" toggle F3 -> \"$CMD\" rewrite"
177
+ note " F4 -> \"$CMD\" save Alt+F9 -> \"$CMD\" settings"
178
+ fi
179
+ mkdir -p "$APPS_DIR"
180
+ sed "s|@CMD@|$CMD|" tuxwhisper-settings.desktop > "$APPS_DIR/tuxwhisper-settings.desktop"
181
+ note "Added \"TuxWhisper Settings\" to your app grid."
182
+
183
+ step "6/6 Loading the speech model"
184
+ if [ "$service" = 0 ]; then
185
+ note "Skipped: start TuxWhisper from your window manager (step 4), then press F5 to dictate."
186
+ exit 0
187
+ fi
188
+ note "The first start downloads it (about 1.5 GB; the CPU model is smaller). Later starts take about 15 s."
189
+ for _ in $(seq 1 600); do
190
+ log="$(journalctl --user -u tuxwhisper --since "$since" -o cat 2>/dev/null || true)"
191
+ if grep -qx "ready" <<<"$log"; then
192
+ step "Done. Click into any text box, hold F5, wait for the start sound, speak, and release."
193
+ note "Settings: Alt+F9. Optional LLM cleanup (F3): docs/llm-cleanup.md"
194
+ exit 0
195
+ fi
196
+ if ! systemctl --user is-active -q tuxwhisper && [ -n "$log" ]; then
197
+ echo "TuxWhisper stopped while starting. Last log lines:" >&2
198
+ tail -n 5 <<<"$log" >&2
199
+ echo "See docs/troubleshooting.md." >&2
200
+ exit 1
201
+ fi
202
+ sleep 2
203
+ done
204
+ echo "Still loading after 20 minutes. Watch it with: journalctl --user -u tuxwhisper -f" >&2
205
+ exit 1
@@ -0,0 +1,58 @@
1
+ [project]
2
+ name = "tuxwhisper"
3
+ dynamic = ["version"]
4
+ description = "Private, offline push-to-talk dictation for Linux, on X11 and Wayland"
5
+ readme = "docs/pypi.md"
6
+ license = "MIT"
7
+ license-files = ["LICENSE"]
8
+ authors = [{ name = "Ibrahim Almajai" }]
9
+ requires-python = ">=3.11,<3.15" # ctranslate2 (faster-whisper) has wheels up to 3.14
10
+ keywords = ["dictation", "speech-to-text", "whisper", "wayland", "linux", "voice-typing"]
11
+ classifiers = [
12
+ "Operating System :: POSIX :: Linux",
13
+ "Programming Language :: Python :: 3",
14
+ "Environment :: X11 Applications",
15
+ "Topic :: Multimedia :: Sound/Audio :: Speech",
16
+ ]
17
+ dependencies = [
18
+ "faster-whisper>=1.2,<2",
19
+ "numpy>=1.24",
20
+ "sounddevice>=0.5",
21
+ "evdev-binary>=1.6", # prebuilt evdev: no compiler or kernel headers needed
22
+ ]
23
+
24
+ [project.optional-dependencies]
25
+ # NVIDIA GPUs (ASR_DEVICE=cuda, the default): CUDA libraries for faster-whisper.
26
+ cuda = ["nvidia-cublas-cu12", "nvidia-cudnn-cu12==9.*"]
27
+ # AMD and Intel GPUs (ASR_DEVICE=vulkan): whisper.cpp. The PyPI wheels are CPU-only; build it
28
+ # with GGML_VULKAN=1 and --no-binary-package pywhispercpp (tuxwhisper setup does this).
29
+ vulkan = ["pywhispercpp>=1.5,<2"]
30
+
31
+ [project.scripts]
32
+ tuxwhisper = "tuxwhisper.asr:main"
33
+
34
+ [project.urls]
35
+ Homepage = "https://github.com/ialmajai/tuxwhisper"
36
+ Documentation = "https://github.com/ialmajai/tuxwhisper#readme"
37
+ Issues = "https://github.com/ialmajai/tuxwhisper/issues"
38
+
39
+ [build-system]
40
+ requires = ["hatchling"]
41
+ build-backend = "hatchling.build"
42
+
43
+ [tool.hatch.version]
44
+ path = "tuxwhisper/__init__.py"
45
+
46
+ [tool.hatch.build.targets.wheel]
47
+ packages = ["tuxwhisper"]
48
+
49
+ # `tuxwhisper setup` and `uninstall` run the same scripts as a git clone.
50
+ [tool.hatch.build.targets.wheel.force-include]
51
+ "install.sh" = "tuxwhisper/data/install.sh"
52
+ "uninstall.sh" = "tuxwhisper/data/uninstall.sh"
53
+ "tuxwhisper.service" = "tuxwhisper/data/tuxwhisper.service"
54
+ "tuxwhisper-settings.desktop" = "tuxwhisper/data/tuxwhisper-settings.desktop"
55
+
56
+ [tool.hatch.build.targets.sdist]
57
+ include = ["tuxwhisper", "install.sh", "uninstall.sh", "tuxwhisper.service",
58
+ "tuxwhisper-settings.desktop", "asr", "docs/pypi.md", "LICENSE", "README.md"]
@@ -0,0 +1,2 @@
1
+ """TuxWhisper: private, offline push-to-talk dictation for Linux."""
2
+ __version__ = "0.2.0"
@@ -0,0 +1,3 @@
1
+ from tuxwhisper.asr import main
2
+
3
+ main()