blitztext-app-linux/linux/CHANGELOG.md
mARTin-B78 48be824a50 settings: emoji search, Manual tab fix, readable infobox (v1.9.5)
- Emoji picker: SearchEntry at top filters all categories via unicodedata.name()
  in real time; category view hides while searching, restores on clear
- Manual tab: add pkg_dir/MANUAL.md to _app_paths() search list so it works in
  both venv and deb installs (MANUAL.md deployed alongside the package)
- bt-infobox CSS: replace @theme_selected_bg_color (saturated blue) with a
  neutral 5% mix of fg/bg so banner text is always readable

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-09 13:09:42 +02:00

405 lines
22 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Changelog
All notable changes to **Blitztext for Linux** (the native dictation tool in
`linux/`) are documented here. The format follows
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project
adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
The version is defined in [`blitztext/__init__.py`](blitztext/__init__.py).
## [Unreleased]
## [1.9.5] - 2026-06-09
### Added
- **Emoji picker search.** A search field at the top of the emoji picker filters
all categories in real time using Unicode character names (e.g. "fire", "dog",
"heart"). Typing hides the category bar and shows matching results; clearing
restores the category view.
### Fixed
- **Manual tab now shows content.** `MANUAL.md` is copied next to the package
module so the Manual tab finds it in both venv and deb installs.
- **Info banner no longer bright blue.** The `.bt-infobox` background now uses
a neutral 5 % tint of the foreground colour instead of the theme accent
colour, so text stays readable on any theme.
## [1.9.4] - 2026-06-09
### Changed
- **Settings UI completely redesigned.** All six settings tabs (Presets, Engines,
Input, General, Input, General) now use a card-based layout following GTK3 best
practices: related fields are grouped inside visually distinct cards with bold
section titles. CSS is injected at start-up to give cards a consistent rounded
border (`boxed-list` + `bt-card`) and a styled info banner at the top of each
tab.
- **Dialog is larger (740×700 px) and every tab scrolls.** The notebook pages
now wrap their content in a `Gtk.ScrolledWindow` so no fields are ever clipped,
even on small screens.
- **Engines toolbar reorganised.** Creation actions (+ Add, + Stream, Quickstart)
are left-aligned; destructive/status actions (Delete, Test, ⟳) are
right-aligned via `pack_end`, making the bar scannable at a glance.
- **Section titles replace plain separators.** The old `Gtk.Separator` +
unstyled `Gtk.Label` pattern is gone; every section now has a small, dimmed,
bold all-caps header rendered with markup.
- **Cleaner section names.** "WW - Wakeword (Hands-free)" → "Hands-free
wakeword"; "Audio cues (manual dictation)" → "Audio cues (keyboard / hotkey
dictation)"; "Local engine … device & precision" → "Internal engine — device &
precision".
## [1.9.3] - 2026-06-09
### Added
- **ⓘ info buttons on every settings field.** Each field in every tab now has a
small information icon that opens a plain-language help popover when clicked —
so non-technical users can understand what each setting does without hovering
or reading the manual.
- **Manual tab in Settings.** A new "Manual" tab shows the full `MANUAL.md`
reference doc directly inside the Settings window.
- **Quickstart templates for engines.** A "Quickstart ▾" button in the STT and
LLM engine toolbars opens a menu of common services (OpenAI, Groq, OpenRouter,
Ollama, LM Studio, vLLM, llama-swap, faster-whisper-server, NVIDIA Riva) and
pre-fills the form — one click to configure a provider.
### Changed
- **Engine type names are now human-readable.** STT types now read "Internal —
faster-whisper, runs inside the app", "Server — OpenAI-compatible API (LAN or
cloud)", and "Realtime — NVIDIA Riva / NIM streaming" instead of the raw
identifiers. LLM types read "LAN server — runs on your machine or local
network" and "Cloud service — OpenAI, Groq, OpenRouter, …".
- **Device selector now shows "GPU (CUDA)" instead of "cuda"**, and compute
types have plain-language descriptions (e.g. "int8 — fast, less memory").
## [1.9.2] - 2026-06-09
### Added
- **Emoji picker for preset icons.** The "Icon (emoji)" field in Settings →
Presets now has a 😀 button that opens a scrollable emoji grid (60 common
emojis across six categories). Click any emoji to insert it — or keep typing
directly into the field as before.
## [1.9.1] - 2026-06-08
### Changed
- **Settings opens instantly.** Each tab's contents are now built the first time
you view it instead of all up front, so the dialog no longer pauses ~1.3s
constructing the file-choosers in the Input/Benchmark tabs. Saving force-builds
any tab you didn't visit first, so no field is ever missed.
- **Connection dots moved beside their field.** The Wakeword and TTS reachability
dots now sit just left of the URL entry (matching the Engines tab) instead of
at the far right of the row.
### Fixed
- **Settings could be opened more than once.** Choosing Settings while it's
already open now raises the existing window instead of stacking a second copy.
## [1.9.0] - 2026-06-08
### Added
- **Connection indicators** for remote endpoints. The **Wakeword engine** field
(Input tab — renamed from "Wyoming URI" to read more generally) and the **TTS
URL** field (Benchmark tab) now show a coloured dot: green when the server is
reachable, red when it's configured but unreachable, grey when blank — mirroring
the STT/LLM engine dots. It's a lightweight background TCP probe, refreshed when
the dialog opens, when you press ⟳, and when you leave the field.
## [1.8.1] - 2026-06-08
### Fixed
- **Settings dialog and control panel wouldn't open on some desktops.** When the
gvfs `org.gtk.vfs.UDisks2VolumeMonitor` dbus service fails to activate (common
on headless or minimal sessions), every `Gtk.FileChooserButton` blocked ~25s on
a `StartServiceByName` timeout while realizing — so the Settings dialog never
finished appearing, and the stalled GTK main loop froze the panel too. Blitztext
now selects GIO's native `/proc/mounts` volume monitor
(`GIO_USE_VOLUME_MONITOR=unix`) before any window is realized, so file choosers
open instantly with no dbus dependency.
## [1.8.0] - 2026-06-08
### Added
- **Send by voice**: say a distinctive phrase like **"computer send"** at the
start or end of a clip and the word is stripped, then the rest is typed **and
submitted with Enter** — the spoken equivalent of "stop + paste + Enter".
Mainly for hands-free use, where you can't press a key. Configure under
Settings → Input → "Send words", or `[routing] send_keywords`. Off by default;
because it presses Enter, use a multi-word phrase (e.g. your wakeword + "send")
so a sentence that merely ends in "send" doesn't submit by accident. Matched
the same edge-anchored, ASR-tolerant way as routing/cancel keywords.
- **Wakeword benchmark** (Settings → Benchmark): stress-test hands-free
detection. It synthesizes short sentences with your wake phrase spoken in
random voices (plus pure-filler utterances with none), streams them to your
wyoming-openwakeword server, and reports **recall** (how reliably it fires),
**false fires**, and a **per-voice** breakdown. Speech comes from any
OpenAI-compatible TTS server (Kokoro-FastAPI, XTTS, OpenAI, …): set its URL,
optional API-key env var, model, and voices under the new `[tts]` config / the
Benchmark tab, and use **Connect** to test it (it auto-fills the voice list
when the server exposes one).
## [1.7.1] - 2026-06-08
### Fixed
- **Overlay waveform and silence countdown ring never appeared** on systems
where PortAudio/`sounddevice` can't open the default input — notably PipeWire
boxes, where opening an input stream simply hangs. Both the live waveform and
the auto-stop countdown are driven by a single level meter, which was the only
part of the app still using `sounddevice` (everything else records via
`pw-record`). The meter now streams raw PCM from the **same system recorder as
the WAV recorder** (`pw-record`/`parecord`/`arecord`) and computes the level
itself, so it works wherever recording works — on both the hotkey and
hands-free (wakeword) paths, plus the mic-level preview in Settings. No more
PortAudio dependency for metering.
- **App reported itself as "`__main__.py`"** in the taskbar and in GNOME's
"… is not responding" dialog. Launched via `python -m blitztext`, GTK's default
program name is `argv[0]`'s basename. It now sets `prgname`/application name to
**Blitztext** before any window is realized (and the desktop file gains
`StartupWMClass=blitztext` for the .desktop match + icon), without touching the
`-m blitztext` entry point.
## [1.7.0] - 2026-06-07
### Added
- **Spoken cancel keyword**: say a word like **"abbrechen"** (or "cancel") at the
start or end of a clip and the whole dictation is **discarded** — it is never
routed, rewritten, or typed anywhere. Mainly rescues an accidentally triggered
(e.g. wakeword) recording. Configure under Settings → Mic/Cues → "Cancel words",
or `[routing] cancel_keywords` (default `["abbrechen", "cancel"]`; empty list
disables it). Matched the same edge-anchored, ASR-tolerant way as routing
keywords, so the word buried mid-sentence won't trip it.
## [1.6.0] - 2026-06-07
### Fixed
- **Session freeze when the overlay's caret tracking was active** (could lock up
the whole GNOME/X11 desktop, forcing a logout/reboot). The AT-SPI caret tracker
subscribed to the high-frequency `object:text-caret-moved` signal and made
**synchronous, blocking AT-SPI reads from inside the event handler** — which
re-enters the accessibility dispatcher and is stormed by the app's *own*
`xdotool` typing (one event per character), congesting the a11y bus until the
desktop stopped responding. It now tracks **focus changes only** and reads the
caret rectangle lazily (once, when the overlay shows), never from inside an
event dispatch.
### Changed
- **Matched preset is fused into the overlay instead of a desktop notification**:
when voice routing picks a preset, the overlay shows its emoji icon, name, and
the spoken keyword on a banner, and narrates the phase ("Transcribing…" →
"Rewriting…"). With the overlay on, the redundant per-dictation notifications
are suppressed (errors still notify); headless/overlay-off keeps notifications.
### Added
- **Live LLM rewrite in the overlay**: rewrite presets now stream the model's
output into the bubble token-by-token, so you watch it write. The delivered
text is still the complete result, typed once the rewrite finishes.
## [1.5.1] - 2026-06-07
### Added
- **Silence auto-stop countdown ring** on the dictation overlay: when you stop
speaking, a full circle wrapping the microphone glyph drains clockwise as the
trailing-silence timer runs out, recolouring from calm cyan to an urgent red
and emptying exactly as the recording auto-stops. It spans the configured
"Silence to stop (s)" window (`[wakeword] silence_seconds`), fades back in/out
as you pause and resume, and so finally makes the hands-free auto-stop visible
instead of a silent surprise.
## [1.5.0] - 2026-06-07
### Added
- **On-screen dictation overlay** (Settings → General → "Visual overlay", or
`[general] overlay_enabled`, default on): the moment recording starts — by
hotkey **or** wakeword — a translucent bubble appears at the cursor showing a
pulsing **microphone**, a **live waveform** of your mic level, and the
**recognised text** (word-by-word with a realtime streaming STT engine, or the
final result as a brief confirmation otherwise). Its tail points at where the
text will land: it follows the **text caret** when the focused app exposes it
over accessibility (AT-SPI), otherwise the **mouse pointer**, otherwise a
screen corner — tune via `[general] overlay_anchor = "caret" | "pointer" |
"corner"`. The window is click-through and never takes focus, and it finally
gives **hands-free wakeword sessions** visible feedback (their notifications
are suppressed by design). X11 only; falls back to a corner where the cursor
can't be located.
### Changed
- **Presets are speakable by name**: voice routing now matches a preset's *name*
as an implicit keyword, so a preset works by voice even with no keywords
configured (e.g. just say "nicer email …"). Explicit keywords still take
precedence, and preset names also bias the STT for better recognition.
- **General settings switches** moved to the far right of each row, each with an
inline description so it's clear what the toggle does without hovering.
- **About**: added a "Copyright: 2026 mARTin Bierschenk - Design" line.
## [1.4.0] - 2026-06-07
### Added
- **"Announce matched preset" notification** (Settings → General, or
`[general] notify_routing`, default on): after a voice command, a notification
shows which preset and spoken keyword matched — **shown even for hands-free
wakeword sessions**, so you can see what you triggered. It only fires on a real
match, so it never spams when nothing is said.
- **Per-preset emoji icon** (Presets → "Icon (emoji)"): give each preset a
distinct emoji, shown in the matched-preset notification so you can tell at a
glance which fired.
### Fixed
- **Voice-routing default went to a rewrite**: when no `[routing] default` preset
is set, the no-keyword fallback used the *first* preset — which, if that happened
to be an LLM rewrite (e.g. "Improve text"), sent every unrouted wakeword command
to the language model (and failed when the LLM was down). The fallback now
prefers a `transcribe` preset, so the default action is plain transcription.
## [1.3.0] - 2026-06-07
### Added
- **Pause wakeword (tray)**: a reversible "Pause wakeword" toggle appears in the
system-tray menu when the wakeword is enabled. It pauses/resumes hands-free
detection by toggling the `/tmp/wake_muted` flag (external scripts may toggle
the same file).
- **"Play audio cues" switch** (Settings → Input → Audio cues, or
`[sounds] enabled`): on/off for the **manual** (keyboard/hotkey) start/stop
chimes. Defaults to on. The hands-free wakeword sounds are independent of it.
- **Configurable wakeword auto-stop silence** (Settings → Input → Hands-free →
"Silence to stop (s)", or `[wakeword] silence_seconds`): end a hands-free
recording this many seconds after you stop speaking. Defaults to `2.0`
(previously hard-coded to 2.5 s).
### Fixed
- **Wakeword sounds silenced by the manual cue switch**: the "Play audio cues"
master switch wrongly muted the hands-free *Sound: detected/captured* cues too.
Wakeword cues are now independent — they play whenever a file is set and stay
silent when cleared (no surprise system-chime fallback), regardless of the
manual switch.
- **PortAudio/ALSA teardown noise**: the level meter no longer leaks
`pthread_join ... failed` / `PaUnixThread_Terminate ... failed` lines to the
terminal when a clip ends — that C-library chatter (written straight to fd 2)
is now suppressed around the stream open/close.
- **Wakeword stuck muted**: a leftover `/tmp/wake_muted` flag silently disabled
detection with no in-app way to clear it. The state is now exposed and
reversible from the tray, so a stale flag no longer kills hands-free use. The
daemon also logs a clear `Starting PAUSED` warning when it boots muted.
- **Away-from-keyboard "Busy" storm**: a wakeword hit arriving while the previous
clip was still transcribing went through `toggle()` and popped a "Busy"
notification. Wakeword triggers now go straight to `start_dictation()`, so a
busy/not-ready state is ignored silently instead.
- **Quiet hands-free errors**: transcription/rewrite failures during a
wakeword-triggered session no longer raise critical desktop notifications —
they are logged instead, keeping background sessions silent.
- **Notification storm / lock-screen pile-up**: desktop notifications are now
sent as transient with a short expiry and reuse a single bubble, so they no
longer stack in the notification log or persist on the lock screen.
- **Quiet hands-free sessions**: per-dictation notifications are suppressed for
wakeword-triggered sessions (audio cues are used instead).
## [1.2.0] - 2026-06-05
### Added
- **Wyoming Wakeword Support**: Complete hands-free integration via Wyoming protocol (e.g., openWakeWord), with live configuration testing and model fetching in the UI.
- **ATK Screen Reader Accessibility**: Fully mapped GTK labels, inputs, tooltips, and properties to the ATK bridge, enabling seamless navigation for blind users via screen readers like Orca.
- **Drag-and-Drop Workflow Ordering**: Workflows in the main tray menu can now be reordered via native drag-and-drop.
- **Voice Activity Detection (VAD) Auto-Stop**: Dictation now automatically stops after detecting 2.5 seconds of silence, removing the need to manually click Stop.
- **Audio Feedback**: Added audible start/stop/cancel chimes mapping to system-native alert sounds.
- **Benchmark Autocomplete**: The Benchmark UI automatically fills in the reference `.txt` transcript if it matches the selected audio file.
- **Realtime STT streaming mode**: new `mode = "stream"` workflow support and a
`riva_realtime` STT engine for Riva/NIM WebSocket transcription, including a
Settings shortcut for Nemotron ASR Streaming on `http://127.0.0.1:8006/v1`.
- **Settings About tab** with the app version, source link, changelog, and
license text.
- **STT & LLM engine manager**: add, rename, and delete engine presets, each
with an online/offline status dot, a per-engine type (local/cloud), and a
**searchable model dropdown** populated from the server's `/models` (with a
reload button). Local Whisper device/precision now live with the STT engine.
- **Benchmark tab**: run a reference clip through every STT engine and compare
**time**, **case-sensitive accuracy** (WER), and a **CPU/GPU/remote device**
column, with the fastest and most accurate highlighted.
- **Custom audio cues**: pick your own WAV files to play when recording starts
and stops (covers stop+paste, stop+paste+Enter, and silence auto-stop), each
with play-test and clear-to-default buttons. Built-in system sounds otherwise.
- **Settings Log tab**: a live activity log (model load/download, transcriptions,
errors) with Copy and Clear, so a long "Loading…" is no longer opaque.
- **Per-tab info boxes** and expanded **tooltips** across Settings, written in
plain language and exposed to screen readers (ATK) — for non-technical and
blind users (barrierefrei).
- **Click-to-bind hotkeys**: a *Set* button captures the next keypress (including
modifier-only chords like Ctrl+Win) into any hotkey field.
### Changed
- **GUI rebuilt in GTK 3** (replacing tkinter): a native GNOME panel unified with
the tray, with the Ubuntu font and a dropdown+editor pattern in Settings.
- **Voice-keyword routing** and a **modifier hotkey scheme** (Ctrl+Win start,
Ctrl stop+paste, Alt stop+paste+Enter, Esc cancel) replace per-preset combos as
the default way to dictate.
- **Quality gate** rejects silent/too-short clips and stock Whisper
hallucinations before they reach the screen.
## [1.1.0] - 2026-06-04
### Added
- **Debian package** (`packaging/build-deb.sh`) producing an installable
`blitztext_<ver>_arm64.deb` with a desktop entry, app icon, and a `blitztext`
launcher. Installs via the Software app or `apt install ./…deb`. Bundles a
relocatable venv with all Python deps (no pip/network at install) and declares
system deps (python3-gi, xdotool, libnotify-bin, a recorder) so they pull in
automatically. The bundled venv is built on the system `/usr/bin/python3`, so
the tray works out of the box.
### Notes
- `python3-gi` is already present on a standard Ubuntu GNOME install; the tray
only seemed unavailable from source when the project venv was built from a
non-system Python (e.g. conda/miniforge). The `.deb` avoids this entirely.
## [1.0.1] - 2026-06-03
### Changed
- Redesigned the control-panel window: minimal flat layout, Ubuntu font
throughout, clickable workflow rows with hover (click to record / stop),
subtle dividers, and text-style Settings/Quit actions. Dropped the monogram
avatars and per-row buttons in favour of a cleaner, simpler look. The Settings
window picks up the same font and styling.
## [1.0.0] - 2026-06-03
First release of the Linux port. The upstream project is a macOS-only menu-bar
app (Swift/SwiftUI, CoreML/WhisperKit) that cannot run on Linux or in a
container; this is a native host tool that reproduces the workflow — focus any
text field, press a hotkey, speak, and the (optionally rewritten) text is typed
into that field.
### Added
- **Native dictation engine** (`daemon.py`): global hotkeys via pynput, each
hotkey toggles record → transcribe → optional rewrite → deliver.
- **Local transcription** via faster-whisper (`transcribe.py`); `device="auto"`
tries CUDA and falls back to CPU `int8` (CPU-only on this arm64 host).
- **Microphone recording** (`recorder.py`) through pw-record / parecord /
arecord — 16 kHz mono WAV, no Python audio bindings required.
- **Optional LLM rewrite** (`rewrite.py`) against any OpenAI-compatible endpoint
(OpenAI, or a local vLLM / llama-swap), configurable per workflow.
- **Typing into the focused window** via xdotool (`paste.py`): `type` directly
or `paste` through the clipboard; re-activates the target window first.
- **Configurable workflows** (`config.py`) in `~/.config/blitztext/config.toml`,
with five defaults (Transcribe, Nicer email, Improve text, Calm down, Add
emojis), per-workflow prompt/model/temperature overrides, and a TOML writer.
- **Control-panel window** (`gui.py`, tkinter): workflow rows with monogram
avatars, hotkey badges, per-row Record buttons, a live status dot, and a
Settings window that edits config and can Save & Restart.
- **System-tray mode** (`tray.py`, AppIndicator): macOS-menu-bar-style status
icon with a menu to trigger each workflow, Show panel, Settings…, and Quit;
shares one daemon/model/hotkey set with the window. Falls back to the window
with an install hint when PyGObject is absent.
- **CLI** (`__main__.py`): `tray` (default), `gui`, `run`, `transcribe`,
`config-path`, and `--version`.
- **Packaging**: `install.sh` (venv with `--system-site-packages`),
`requirements.txt`, and a `blitztext.service` systemd user unit.
### Notes
- Targets an **X11** session (uses xdotool); Wayland would need ydotool/wtype.
- System tray requires a one-time `sudo apt install python3-gi` (the GTK /
AppIndicator typelibs and GNOME `ubuntu-appindicators` extension are already
present on the target host).
[Unreleased]: https://github.com/mARTin-B78/blitztext-app-linux/compare/v1.5.1...HEAD
[1.5.1]: https://github.com/mARTin-B78/blitztext-app-linux/compare/v1.5.0...v1.5.1
[1.5.0]: https://github.com/mARTin-B78/blitztext-app-linux/compare/v1.4.0...v1.5.0
[1.1.0]: https://github.com/mARTin-B78/blitztext-app-linux/compare/v1.0.1...v1.1.0
[1.0.1]: https://github.com/mARTin-B78/blitztext-app-linux/compare/v1.0.0...v1.0.1
[1.0.0]: https://github.com/mARTin-B78/blitztext-app-linux/releases/tag/v1.0.0