Commit Graph

74 Commits

Author SHA1 Message Date
d00064b6cd routing by preset name; right-aligned General switches; About copyright
- Spoken presets: route() now also matches a preset's name as an implicit
  keyword, so presets with no configured keywords (Nicer email, Calm down,
  Add emojis) are triggerable by voice — say the name. Explicit keywords still
  win; names are added to STT hotwords too. Tests added.
- General tab: switches moved to the far right of each row with an inline
  grey description (new _switch_row helper) so each toggle is self-explanatory.
- About tab: add "Copyright: 2026 mARTin Bierschenk - Design".
- MANUAL + CHANGELOG updated.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 11:48:22 +02:00
227e4407c4 routing: announce which preset/keyword you triggered (incl. hands-free)
The matched-preset feedback used _dnotify, which is suppressed for hands-free
sessions — so wakeword users never saw which keyword/preset fired.

- Add a dedicated "Announce matched preset" notification (_rnotify), gated by
  a new [general] notify_routing flag (default on) and independent of the
  hands-free silence, so it shows for wakeword commands too. It only fires on a
  real routing match, so it never spams when nothing is said.
- Show each preset's emoji in that notification; add a per-preset "Icon (emoji)"
  field to the Presets editor so matches are visually distinct.
- General-tab toggle; MANUAL + CHANGELOG updated. Adds a test that the match is
  announced even when _session_silent is set.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 10:43:08 +02:00
ce0079e728 wakeword: independent cues + configurable auto-stop silence; add MANUAL.md
Reported issues from hands-free use:

- Wakeword WAVs didn't play: the new "Play audio cues" master switch
  ([sounds] enabled) also gated the hands-free Sound: detected/captured cues,
  so enabled=false silenced them. The cues live in a separate UI section, so
  this was surprising. Wakeword cues are now independent of that switch: they
  play whenever a file is set, and an empty field means silent (no system-chime
  fallback) — which is also how you turn a hands-free cue off. The master switch
  now governs only the manual (keyboard) before/after chimes.

- Clarified the four sound fields' tooltips/labels (detected/captured = hands-free
  only; before/after = manual only) and the empty-field behaviour.

- New "Silence to stop (s)" setting (Settings → Input → Hands-free, or
  [wakeword] silence_seconds, default 2.0): user-defined trailing-silence
  timeout for hands-free auto-stop (was hard-coded to 2.5 s).

- Add MANUAL.md documenting every setting in every tab; link it from the README.

Tests: cue independence + manual-gating + roundtrip (17 passed).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 08:36:35 +02:00
436076620c audio cues: add master on/off switch; silence PortAudio teardown noise
Two follow-ups from hands-free testing:

- Audio cues had no off-switch: empty sound fields fall back to the freedesktop
  system chime, so wakeword/recording always made noise. Add a [sounds] enabled
  master flag (default true) exposed as "Play audio cues" in Settings → Input.
  When off, _play_cue/_play_sound are no-ops — fully silent operation.

- The VAD level meter (sounddevice/PortAudio) leaked harmless thread-teardown
  errors ("pthread_join ... failed", "PaUnixThread_Terminate ... failed") to the
  terminal on every clip end. PortAudio writes these straight to fd 2, so wrap
  the stream open/close in a fd-level stderr suppressor (_quiet_c_stderr).

Tests: cue gating respects the master switch (16 passed).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 23:45:47 +02:00
8e1419e828 Add wakeword-specific audio cues (detected / captured)
Two optional WAVs in the Hands-free section: "Sound: detected" plays when the
wakeword fires (your cue to speak now) and "Sound: captured" plays when the
command is taken (silence/stop). For hands-free sessions these take precedence
over the general [sounds] cues, falling back to them and then to the built-in
system sound. The general cues are relabelled "Audio cues (manual dictation)".

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 14:34:49 +02:00
2d777382f5 Settings accessibility: per-tab info boxes + tooltips; complete 1.2.0 changelog
Add a plain-language info box to the top of every Settings tab (Presets,
Engines, Input, General, Benchmark, Log, About), exposed to screen readers, and
tooltips (wired to ATK descriptions) on the preset, general, and input-mode
controls — for non-technical and blind users (barrierefrei).

Complete the unreleased 1.2.0 changelog with the engine manager, Benchmark tab,
custom audio cues, Log tab, click-to-bind hotkeys, the GTK rebuild, voice
routing, the modifier hotkey scheme, and the quality gate.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 09:48:35 +02:00
209b4ef259 Add custom WAV audio cues for recording start/stop
New sound.py plays a user WAV (or a built-in system sound) without blocking.
Config gains [sounds] before/after paths. The daemon plays the "before" cue when
recording starts and the "after" cue on every stop (stop+paste, stop+paste+Enter,
or auto-stop on silence — all funnel through finish_dictation). Input tab gets an
Audio cues section: file pickers with play-test and clear-to-default buttons.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 09:40:09 +02:00
da5593cb08 Auto-fill benchmark reference text file on audio select 2026-06-05 19:32:19 +02:00
90887afffb Add tooltips and ATK screen reader accessibility properties 2026-06-05 19:28:19 +02:00
192c09bb70 Add Wakeword mic meter, model loading, and testing UI 2026-06-05 18:08:00 +02:00
3dad1082e4 Add Wakeword connection test to GUI before saving 2026-06-05 17:26:08 +02:00
5484bc6a1b Add Wayland, Tests, CI, and OpenWakeword integration
- Wayland support: text delivery using wtype or ydotool (paste.py)
- Testing: added Pytest coverage for routing, quality, and config logic
- CI/CD: added test-linux job to .github/workflows/ci.yml
- Feature: Hands-free dictation using an external wyoming-openwakeword
  server, respecting the /tmp/wake_muted toggle.
2026-06-05 17:16:05 +02:00
457835929e Add realtime streaming and Linux app docs 2026-06-05 15:06:17 +02:00
4667144b72 Benchmark: add Device column (CPU/GPU/remote); case-sensitive accuracy
- BenchRow gains a device field; Transcriber records its resolved device, so
  local engines report CPU or GPU and remote engines show "remote". New Device
  column in the results table.
- Accuracy is now case-sensitive by default (capitalisation counts) so an
  all-lowercase transcript no longer scores 100%. Punctuation is still ignored.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 14:12:16 +02:00
1b0b4bbc1f Add Benchmark tab (WAV + reference -> fastest & most accurate); fix STT Test
New benchmark.py: word-error-rate accuracy + a run() that times each STT engine
on a reference clip. Settings gains a Benchmark tab: pick a .wav and a matching
.txt, run all STT engines, see Time + Accuracy per engine and a summary of the
fastest and most accurate. Add presets for each model you want compared.

Fix "Local engine selected but the model isn't loaded." on Test: a cached
_transcriber_for() loads the local model on demand (the daemon only preloads it
when a local engine is active). Tested: local small 2.17s/100% vs remote :8010.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 11:11:50 +02:00
db387cab78 Add Name field to engine editors so engines can be renamed
Both STT and LLM engine editors gain a Name field (first field). Editing it
renames the engine and updates the dropdown on commit; Save persists it. Fixes
the inability to rename "New STT"/"New LLM" after Add.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 10:23:36 +02:00
f1ee4bd4c5 Move Whisper device/compute into Engines→STT; add LLM Type (local/cloud)
- Local-Whisper Device + Compute type now live under the STT engine section
  ("Local engine — device & precision"), removed from the General tab. The
  local engine's Model field shows the effective whisper size.
- LLM engines gain a Type field (local | cloud), mirroring STT, stored in config.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 09:48:26 +02:00
78350bdb99 Add Log tab + in-memory log buffer
New logbuffer.py captures app messages (log()) and library logs (faster-whisper,
huggingface_hub) into a ring buffer, mirrored to stderr. Settings gains a Log
tab: monospace view, 1s refresh, auto-scroll, Copy, Clear — so model
download/load progress is visible instead of an opaque "Loading…". transcribe
and daemon now log via the buffer.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 09:42:48 +02:00
a508ecc69c Searchable model dropdown with a top search bar + URL reload button
Replace the model combo with a ModelPicker: an editable field plus a ▾ button
that opens a popover with a SearchEntry on top and a scrollable, filtered list
of models (HuggingFace-style). Add a refresh icon next to each engine URL that
loads models from {url}/models on demand. Verified: 8010 -> 428 models, typing
"turbo" filters to the turbo variants. You can still type a custom model name.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 09:13:50 +02:00
09e3f58ba8 Add click-to-bind "Set" buttons for hotkey fields
Each key field (Start/Stop+paste/Stop+paste+Enter/Cancel, and the preset
Hotkey) gets a Set button that captures the next keypress and writes it in the
config format. Captures modifier-only chords (e.g. Ctrl+Win -> <ctrl>+<cmd>) by
accumulating pressed keys and finalising on first release; key events are
swallowed while binding so they don't leak into the UI. Tested: token mapping,
combo formatting, and the bind flow.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 09:07:11 +02:00
b42f526ca3 Searchable model dropdown fetched from {url}/models
The engine Model field is now an editable combo with a type-to-search
EntryCompletion (substring match). When you enter a remote engine URL it fetches
the model list from {url}/models (OpenAI `data[].id` or Ollama `models[].name`)
and fills the dropdown; local STT offers the whisper sizes. stt.list_models
added; tested live (8010 -> 428 models, 28080 -> 18, 19001 -> 1). You can still
type a custom model name.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 09:02:14 +02:00
8d2bae0a27 Add grey placeholder hints to settings fields
set_placeholder_text on the preset and engine entries (URL, model, API key env,
keywords, hotkey, temperature, language) so empty fields show light-grey
examples of what to enter.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 08:55:07 +02:00
44ca0feabd Redesign Settings: preset/engine managers, mic + level meter, autostart
New GTK settings with a dropdown+editor pattern across four tabs:
- Presets: select/add/delete prompt presets; edit name, keywords, hotkey, mode,
  per-preset model/temperature, and a clearly-bordered prompt textfield.
- Engines: STT and LLM engine managers with green/red online-offline status
  dots, add/edit/delete, active selector, and an STT record-and-benchmark Test.
- Input: input scheme + keys + quality-gate settings.
- General: microphone picker with a live sounddevice level meter, output,
  language, notifications, launch-on-login toggle, and local-Whisper settings.

Adds audio.py (mic enumeration via pactl + LevelMeter) and autostart.py
(~/.config/autostart entry). Recorder + daemon honour the selected mic.
Requirements gain sounddevice + tomli-w.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-04 23:13:36 +02:00
3cbea06e6c Rebuild GUI in GTK3 (native panel, unified with tray)
Replace the tkinter panel with a GTK3 control panel (gtkui.py) + settings
dialog (gtksettings.py): rounded CSD window, gradient background, circular icon
avatars, hotkey pills, hover states, Ubuntu font. Runs on the GTK main loop,
unified with the AppIndicator tray (no tkinter event-loop pump). Status updates
marshalled via GLib.idle_add. Removes the old tkinter gui.py.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-04 09:40:24 +02:00