9898bb8dd9 feat(ui): in-app Dictation Pad for Wayland-safe dictation (#887)
* feat(ui): add in-app Dictation Pad for Wayland-safe dictation

Dictated text can now be routed into a text box inside Vocalinux's own
window instead of being injected into other applications — an explicit
fallback for desktops where cross-app injection is unreliable or blocked
(notably Wayland). The pad opens from the tray menu, captures dictation
when enabled via Settings or its own checkbox, and lets the user copy
text out by hand. 'delete that' removes the last segment in-pad.

Closes #726.

* fix(ui): consult live config for pad auto-reveal and Copy All

The reveal gate used the controller's enabled flag, which only syncs on
pad show or its own checkbox — enabling capture via the Settings switch
while the pad was closed silently buffered dictation with no reveal.
_apply_append now reads dictate_to_pad from the shared config.

Also: Copy All copies the widget text (dictation plus in-pad edits), and
re-showing the pad no longer does a wholesale set_text — the view stays
incrementally in sync, so manual edits survive hide/reopen.

* fix(ui): keep dictation pad capture and commands inside the pad

Address all Greptile findings on PR #887:

- Read the capture toggle from the shared ConfigManager instead of
  re-parsing config.json per segment, so a torn mid-write read can no
  longer fail-open and send dictation to the focused app
- Sync edits made directly in the pad widget back into the controller,
  keeping delete semantics consistent with the visible text
- Stamp queued widget operations with a generation tag so a Clear drops
  appends still sitting in the GTK idle queue
- Route undo/redo, select all/line/word/paragraph and cut/copy/paste to
  pad-local implementations while capturing, so their shortcuts never
  reach whichever application holds focus
- Track where the last segment was delivered so "delete that" follows
  the text rather than the current capture toggle
- Annotate every new signature and add callback-level tests that pin the
  routing, queue, and undo behavior

* fix(ui): keep pad controller, queued ops, and delete target in sync

Manual edits could overwrite queued dictation in the controller because
GTK input events outrank idle callbacks; the changed handler now replays
pending widget ops before syncing the view. The controller also tracks
dictated segments across undo snapshots, so a pad undo pops the "delete
that" target instead of leaving a stale length. Catches in the pad are
narrowed to the GTK/config error set per repo style, and missing type
annotations are added.

* fix(ui): close flush races in pad idle queue and delete retarget

Flushed idle ops stayed scheduled with GLib and ran a second time,
duplicating appends; each queued op now only acts while its entry is
still pending. A queued full-view refresh could also erase a manual
edit that landed first, so the changed-handler flush now drops stale
set-text ops instead of replaying them. And clearing the pad
destination on undo-to-empty kept a redo from restoring the "delete
that" target; the destination flag is preserved so redo re-arms it.

* fix(ui): replay pad idle ops before edits land, not after

Flushing in the changed handler still let queued appends leapfrog the
keystroke that fired it, and a stale dispatch could cancel a later
queued op with identical text. Pending entries now match by identity,
and the replay moved to insert-text/delete-range — signals that fire
before the edit is applied — so queued dictation and deletes keep true
chronological order against manual edits.

* fix(history): target late segments to their own snippet by id

A straggler from a just-ended session could merge into whichever snippet
was newest when it arrived, and audio captured before a session opened
was attributed to that session while decoding on its worker.

- TranscriptionHistory.add returns the snippet id and the new
  extend_entry() extends a specific entry, replacing the positional
  extend_latest target in the late-segment path
- session_started_floor stamps when a session opens; in-session
  attribution also requires the capture to postdate it
- test_capture_ceiling closes the mic-test window at callback restore so
  test speech still decoding can no longer leak into history

* fix(settings): keep deferred edits from overwriting a newer choice

The deferred-persist filter treated "config still equals the baseline" as
untouched, so a reopened dialog that applied a key back to its baseline
value could still lose it to the closed dialog worker.

- Record the generation of the apply that last wrote each advanced key;
  a pending edit now survives only when no newer apply wrote that key
- A worker apply whose snapshot a newer apply predates now skips its
  reconfigure and save entirely, so collection order — not lock order —
  decides which snapshot wins

* fix(settings): skip stale applies before stopping dictation

The superseded-apply check ran after stop_recognition, so a stale worker still interrupted a live dictation session. Recognition now stops inside the apply lock, after the generation check.

* fix(shortcuts): keep language edits from breaking dictation

Two per-language shortcut fixes (#805):

- A binding edit landing while a session is live no longer stops
  recognition. The dialog's per-keystroke persist still saves the new
  binding, but the tray defers the listener rebuild to the next IDLE
  transition, so a held push-to-talk keeps its release callback and a
  toggle session is never cut off mid-utterance.
- A row edited onto a key another row holds can no longer displace that
  row's binding. Each row's remembered shortcut is reserved for its own
  row before claims run in row order, so the stealing edit is rejected
  and the held binding survives.
- Persists that resolve to the already-saved bindings (mid-edit
  keystrokes, rejected duplicates, reverted fields) skip the save and
  the listener rebuild entirely.

---------

Co-authored-by: Jatin K Malik <jatinkrmalik@gmail.com>
2026-09-30 01:35:21 -07:00
2026-09-16 00:18:09 -07:00
2025-05-25 23:20:08 -05:00
2026-09-16 00:18:09 -07:00

Vocalinux

Vocalinux

Voice dictation for Linux

Ubuntu Debian Fedora Arch openSUSE

Privacy: on-device X11 & Wayland License: AGPL-3.0 Python 3.11+ PRs Welcome

Discord VocaHQ Follow on X GitHub release PyPI AUR

Website · Install · Docs · Releases

Vocalinux turns speech into typed text in whatever app has focus. It is a free, AGPL-3.0-licensed desktop app for X11 and Wayland. After you download a model, local engines (whisper.cpp by default, plus OpenAI Whisper, Faster Whisper, VOSK, and Parakeet) run speech-to-text on your machine. An optional remote HTTP API is off unless you configure it.

No Voca account is required. Models download once. After that, speech-to-text stays on your machine.

Current release: v0.17.0. Minor: Faster Whisper and Parakeet engines, Speech Model simple setup, first-run system language, Snap with native Wayland typing, Flatpak bundles on the GitHub Release. Details: docs/UPDATE.md.

Features

  • On-device after model download: Local engines; speech-to-text stays on your machine
  • X11 and Wayland: Text injection via xdotool, IBus, wtype, ydotool, or clipboard fallback
  • Several engines: whisper.cpp (default), OpenAI Whisper, Faster Whisper, VOSK, Parakeet, plus optional remote HTTP API or local VocaGateway from Settings (not on-device)
  • GPU acceleration: Vulkan for AMD, Intel, and NVIDIA with whisper.cpp
  • Toggle or push-to-talk: New installs default to hold Right Alt; existing configs keep their shortcut
  • System tray + settings: Searchable sidebar, Speech Model simple setup with Advanced as an island, status icons, audio feedback
  • Start on login: XDG autostart (desktop session, not a systemd service)
  • Packaging: install script, AppImage, AUR, PyPI, Snap (--edge), Flatpak (release bundles and local build; not on Flathub)

Screenshots

Vocalinux in action. Full gallery on the website screenshots page.

Product

Transcription in Action
Real-time voice-to-text transcription
System Tray
System tray with listening indicator
About View
About & Updates in Settings
Log Viewer
Log viewer for debugging

Settings

Speech Engine settings
Speech Engine
Recognition settings
Recognition
Audio settings
Audio
Performance settings
Performance
General settings
General
Advanced tuning and settings
Advanced
Dictation overlay listening
Floating overlay while listening (green)
Dictation overlay processing
Floating overlay while processing (amber)

Install

curl -fsSL https://raw.githubusercontent.com/VocaHQ/vocalinux/main/install.sh -o /tmp/vl.sh
bash /tmp/vl.sh

Prefer to review the script first: open /tmp/vl.sh before running it, or clone the repo and run ./install.sh locally.

The installer detects hardware, recommends an engine, downloads a default model (~74MB for whisper.cpp tiny), installs neural VAD when ONNX Runtime is available, and sets up desktop integration. Typical install time with whisper.cpp is about 1-2 minutes.

Engine When to use
whisper.cpp (default) Best default; Vulkan GPU on AMD, Intel, and NVIDIA
Whisper (OpenAI) PyTorch path; NVIDIA/CUDA
Faster Whisper CPU-friendly Whisper via CTranslate2 / INT8
VOSK Low RAM / minimal footprint
Parakeet CPU; NVIDIA NeMo ASR via sherpa-onnx; 25 European languages
Remote API Offload to a server you configure

Non-interactive options:

bash /tmp/vl.sh --auto                              # whisper.cpp defaults
bash /tmp/vl.sh --auto --engine=whisper             # OpenAI Whisper
bash /tmp/vl.sh --auto --engine=faster_whisper      # Faster Whisper (CPU)
bash /tmp/vl.sh --auto --engine=vosk                # VOSK only
bash /tmp/vl.sh --auto --engine=parakeet            # Parakeet (CPU)

For a specific release tag, see GitHub Releases or ./install.sh --tag=v0.17.0.

Arch Linux (AUR)

yay -S vocalinux

See docs/AUR.md.

AppImage

Download the x86_64 or aarch64 AppImage from Releases, mark it executable, and run it. Built against glibc 2.35 (Debian 12+, Ubuntu 22.04+, Fedora 36+, Arch, Tumbleweed). Host text-injection tools (xdotool on X11; wtype / ydotool / clipboard tools on Wayland) are still required. Current AppImages rebuild whisper.cpp with Vulkan and use the host GPU driver. Prefer the installer when you want system deps, a CUDA build, and models set up automatically.

Flatpak (any distro)

Install and auto-update via the self-hosted VocaHQ remote (flatpak update picks up each release):

flatpak install https://vocahq.github.io/vocalinux-flatpak/com.vocalinux.Vocalinux.flatpakref

The .flatpakref adds the vocahq remote and resolves the GNOME runtime through Flathub. Manually instead:

flatpak remote-add --if-not-exists flathub https://dl.flathub.org/repo/flathub.flatpakrepo
flatpak remote-add --if-not-exists vocahq https://vocahq.github.io/vocalinux-flatpak/vocahq.flatpakrepo
flatpak install vocahq com.vocalinux.Vocalinux

Or sideload a GitHub Release bundle (Vocalinux-<version>-x86_64.flatpak or -aarch64.flatpak) after the Flathub GNOME runtime is present — bundles do not auto-update:

flatpak install --user ./Vocalinux-<version>-x86_64.flatpak

Local build:

flatpak install flathub org.gnome.Platform//50 org.gnome.Sdk//50
flatpak-builder --user --install --force-clean build-dir \
  packaging/flatpak/com.vocalinux.Vocalinux.yml
flatpak run com.vocalinux.Vocalinux

Ships whisper.cpp with Vulkan. It is not on Flathub (submission flathub#9368 closed 2026-07-23 on policy grounds). Details: packaging/flatpak/README.md.

Snap (Ubuntu Snap Store)

Listing: snapcraft.io/vocalinux. stable is promoted from candidate after QA. Tagged releases also attach vocalinux_<version>_amd64.snap on GitHub.

sudo snap install vocalinux --edge
sudo snap connect vocalinux:audio-record   # if mic is not auto-connected
sudo snap connect vocalinux:raw-input      # global keyboard shortcuts (evdev)
sudo snap connect vocalinux:hardware-observe  # list keyboards (/proc/bus/input/devices)
sudo snap connect vocalinux:uinput         # native Wayland typing (ydotool)

v0.17.0 includes ydotool and the uinput plug. The Store still has to finish review of that plug, so snap info vocalinux may still show v0.16.2 (rev 7) on edge. That revision has no uinput plug; snap connect vocalinux:uinput fails until a 0.17.0+ revision is listed.

Until then, sideload the GitHub file:

sudo snap install --dangerous ./vocalinux_0.17.0_amd64.snap
sudo snap connect vocalinux:uinput

From source

git clone https://github.com/VocaHQ/vocalinux.git
cd vocalinux
./install.sh
# or pick the engine up front
./install.sh --engine=whisper_cpp
./install.sh --engine=vosk
./install.sh --engine=parakeet --auto

After installation

vocalinux                 # if ~/.local/bin is on PATH
# or
~/.local/share/vocalinux/venv/bin/vocalinux

You can also launch Vocalinux from your application menu.

Nightly builds

Daily builds from main appear on Releases. Use the latest stable or beta release for production; nightlies are untested.

Requirements

OS Linux (Ubuntu 24.04+, Debian 12+, Fedora 42+, Arch, openSUSE Tumbleweed)
Python 3.11 or newer
Display X11 or Wayland
Hardware Microphone; GPU optional (Vulkan)

The distro must ship Python 3.11+ because Vocalinux uses distro PyGObject (python3-gi). Ubuntu 22.04 (Python 3.10) and Debian 11 (3.9) are below that floor. Distribution notes: docs/DISTRO_COMPATIBILITY.md.

Usage

Dictation

  1. Push-to-talk (default on new installs): hold Right Alt (Option on Mac-layout keyboards) and speak
  2. Speak into the microphone
  3. Release to stop, or switch to Toggle mode in Settings (double-tap a key to start/stop)

Existing configs keep their saved shortcut.

Voice commands

English phrases always work. With a non-English recognition language, matching punctuation / line-break phrases in that language are also recognized (Italian virgola / punto, French virgule / point, etc.).

Command Action
"new line" Line break
"period" / "full stop" / "dot" .
"comma" ,
"question mark" ?
"exclamation mark" !
"delete that" Delete last sentence
"capitalize" Capitalize next word

CLI

vocalinux --help
vocalinux --version
vocalinux --debug
vocalinux --engine whisper_cpp    # default
vocalinux --engine whisper
vocalinux --engine faster_whisper
vocalinux --engine vosk
vocalinux --engine parakeet
vocalinux --engine remote_api
vocalinux --model medium
vocalinux --model medium.en-q5_0  # exact whisper.cpp variant
vocalinux --model large-v3-turbo
vocalinux --wayland
vocalinux --start-minimized

Autostart

Start on Login creates an XDG autostart desktop entry (~/.config/autostart/). It does not install a systemd unit. Enable from the first-run dialog, tray menu, or Settings.

Configuration

Stored at ~/.config/vocalinux/config.json. Prefer the Settings dialog for day-to-day changes. Settings → Speech Model starts with a simple setup; expand Advanced for engine, size, and specialization.

Neural VAD (Silero) is used when onnxruntime is available; install via pip install "vocalinux[vad]" for manual/PyPI installs. The installer attempts this automatically.

Documentation

Document Description
Installation Installer, AppImage, AUR, Flatpak, Snap, running
Manual / PyPI install Package lists and pip workflows
Troubleshooting Common failures
User guide Dictation, engines, models, tips
Update guide Upgrade steps and release notes
Changelog Release history pointers
Support Where to get help
Distribution compatibility Distro matrix and session notes
Remote HTTP API Offload transcription to a server
Local VocaGateway (optional) Start a local gateway from Settings; not on-device
Contributing Dev setup, style, PR process
Security Supported versions and vulnerability reporting
Docs index Full documentation map

Privacy and security

  • Local engines process audio on-device after you download a model; no Voca account required
  • Optional remote API is off by default and only used when you configure a server
  • Model downloads are checked against pinned checksums

Report vulnerabilities privately per SECURITY.md.

Development

git clone https://github.com/VocaHQ/vocalinux.git
cd vocalinux
./install.sh --dev
source venv/bin/activate
pytest
python -m vocalinux.main --debug

See CONTRIBUTING.md for the two-venv layout, just recipes, and PR guidelines.

Roadmap

Shipped: graphical settings, multi-language support, whisper.cpp default, Vulkan GPU, Wayland/IBus, Flatpak packaging, AppImage, in-app update checker, Parakeet and Faster Whisper engines, Snap recipe.

Planned:

  • Application-specific voice commands
  • Debian/Ubuntu package (.deb)
  • User-customizable voice command map
  • Flathub publication (not currently listed; see #167)

Voca ecosystem

Vocalinux is part of VocaHQ. On-device speech-to-text first, one app per platform. Optional VocaGateway is self-hosted and not on-device.

Platform Project Website GitHub
Linux VocaLinux vocalinux.com VocaHQ/vocalinux
macOS VocaMac vocamac.com VocaHQ/vocamac
Windows VocaWin vocawin.com VocaHQ/vocawin
Phone VocaPhone vocaphone.vocahq.com VocaHQ/vocaphone
Gateway VocaGateway vocagateway.vocahq.com VocaHQ/vocagateway

Talk to us: Discord · X @vocahq · hello@vocahq.com

Contributing

Bug reports, docs, and code are welcome. Start with CONTRIBUTING.md and good first issues.

Contributors

Thanks to everyone who has contributed code, docs, or fixes:

Vocalinux contributors

Repository mirrors

GitHub is the primary forge for issues, PRs, CI, and releases.

Role URL
Primary https://github.com/VocaHQ/vocalinux
Read-only mirror (Codeberg) https://codeberg.org/jatinkrmalik/vocalinux

Open issues and pull requests on GitHub only.

License

This project is licensed under the GNU Affero General Public License v3.0 (AGPL-3.0), aligning with the other VocaHQ distribution projects.

You may use, study, modify, and redistribute the software under AGPL-3.0. If you run a modified version as a network service, AGPL also requires that you make the corresponding source available.

Star Chart

Star History Chart

Optional Orukeet model

With the Parakeet engine installed, Settings → Speech Model → Parakeet also offers orukeet-v0.1.0. It uses the existing local sherpa-onnx recognizer for 25 European languages; the recommended Parakeet model and default whisper.cpp engine stay unchanged.

The download comes from a pinned revision of oruk/orukeet on Hugging Face. Vocalinux checks every file against its bundled SHA-256 pins and checks the publisher's release manifest against those same pins. The manifest download participates in Hugging Face's normal model-download accounting. Cached recognition works offline and does not send audio or usage events. The model occupies about 641 MiB; its CC BY-SA 4.0 weights license and NVIDIA attribution are included.

S
Description
Free, offline voice dictation for Void Linux and niri. Vulkan GPU acceleration, signed xbps repository.
Readme AGPL-3.0
35 MiB
v0.19.1
Latest
2026-11-06 21:18:19 +00:00
Languages
Python 84.5%
TypeScript 8.6%
Shell 5.6%
CSS 0.6%
Just 0.2%
Other 0.4%