Commit Graph

143 Commits

Author SHA1 Message Date
Hermes Agent
f678d7d20f security: add path validation for user-configured sound files
Some checks failed
CI / Test Linux app (push) Has been cancelled
Adds validate_sound_path() that checks file type, allowed directories, and known audio extensions. Updates play() to use validation before passing paths to audio players.
2026-06-15 07:38:05 +00:00
8f056e8cf0 feat: cancel button during transcription and rewriting (v2.03.41)
- overlay: show × button in busy state (transcribing/rewriting), not only
  while recording — updates hit-region, draw call, and label layout
- daemon: cancel_dictation() now handles _busy via threading.Event
  (_abort_event); _process() clears the event at start, checks after STT
  returns and after LLM rewrite completes, skipping delivery if set
- llm: chat() and _read_stream() accept abort_event; streaming loop breaks
  immediately when the event is set so cancellation is near-instant

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-10 17:57:41 +02:00
e053719c59 docs: screenshots, README and MANUAL overhaul (v2.03.40)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-10 17:26:19 +02:00
4b8b9db43e docs: add screenshots to README and MANUAL, rename screenshot files
- Renamed 21 raw screenshots to meaningful filenames under Screenshots/
- Updated README.md and linux/README.md: added organized screenshot
  sections (Main panel & overlay, Settings pages, Setup wizard) using
  new filenames with click-to-enlarge links
- Updated MANUAL.md: rewrote intro to reflect new sidebar navigation
  (Presets · General · Keyboard · Wakeword · STT Engines · LLM Engines ·
  Benchmark — STT · Benchmark — Wakeword · Log · Manual · About);
  renamed section headers to match; added screenshot at each section

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-10 17:22:34 +02:00
a9c08a54c8 fix: eliminate remaining horizontal scrollbars, split kw rows, fix WW benchmark layout (v2.03.39)
Scrollbar root causes:
- infobox max_width_chars 72→58 (72 chars × 9px/char > 677px content area)
- engine selector combos (stt/llm/ww) lacked CellRendererText ellipsize;
  long engine names drove combo natural width; add _ellipsize_combo() helper
  (ellipsize=END, max-width-chars=28) applied to _combo() and all 3 engine combos
- _STT_TYPES/_LLM_TYPES/_DEVICE_OPTIONS/_COMPUTE_OPTIONS labels shortened to ≤27 chars

UX:
- _kw_shortcut_row: split into two ListBox rows (keywords / shortcut)
- Benchmark WW: move Run button to top of results pane, paned 390→340px

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-10 17:01:22 +02:00
125bd17713 fix: entry natural width causes scrollbars in STT Engines and Wakeword (v2.03.38)
Gtk.Entry reports its placeholder text width as natural width. Without
set_width_chars(1), entries can't shrink below that, so pages with long
placeholders (URL fields, keyword rows) ended up wider than the dialog.

Added set_width_chars(1) to _entry(), _url_field(), ModelPicker,
_kw_shortcut_row, and _sound_field. Also added set_max_width_chars(50)
to the stt_result wrapping label for the same reason.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-10 15:28:44 +02:00
0500b24900 fix: horizontal scrollbars and empty STT Engines page in settings (v2.03.37)
- Guard _refresh_status() with hasattr checks so opening STT Engines
  before LLM Engines page is built no longer crashes the builder silently
- ww_status label: add max_width_chars(30) + ellipsize END so long model
  lists don't widen the Wakeword page
- Benchmark STT sel_sw: NEVER→AUTOMATIC horizontal policy so wide engine
  names scroll internally instead of propagating to the dialog
- _combo()/_type_combo(): set_size_request(10,-1) so ComboBoxText widgets
  (e.g. long microphone names) can shrink below natural width

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-10 15:16:49 +02:00
8181ad75f9 feat(2.03.36): split STT Engines / LLM Engines into separate sidebar pages
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-10 14:54:19 +02:00
79d6020fc6 fix(2.03.35): settings pages no longer widen the dialog
_switch_row description labels had set_line_wrap(True) but no
set_max_width_chars, so GTK computed their natural width as the full
un-wrapped text (~700px for 87-char descriptions). With NEVER horizontal
policy on the page ScrolledWindow this propagated to the dialog, making
Keyboard/Wakeword/Engines/Benchmark pages 1000–1360px wide.

Fix: add set_max_width_chars(50) to description labels, and change the
page SW horizontal policy from NEVER to AUTOMATIC as a safety net.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-10 14:52:28 +02:00
1f3bbf2668 fix(2.03.34): stop settings window growing wide/tall between pages
Stack.set_homogeneous(True) was requesting the max natural size of all
children (incl. wide Benchmark TreeViews) and forcing the dialog to 1000+px
wide for every page. Reverted to False so the window stays at 860×700 and
pages scroll if taller than the viewport.

Also removed the NEVER/NEVER ScrolledWindow policy on both benchmark pages —
it was propagating natural TreeView width up to the Stack, amplifying the
homogeneous bug.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-10 14:40:42 +02:00
5cd31c8385 fix(2.03.33): stable window size between pages, fix benchmark-ww controls clipped
- Stack.set_homogeneous(True) keeps dialog height constant when switching pages
- Benchmark WW paned position raised 260→390 so all TTS config, engine
  checkboxes, wakeword/samples/run fields are visible without scrolling
- Both benchmark pages disable their page-level ScrolledWindow so the
  Paned fills the viewport rather than growing to natural height

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-10 12:56:39 +02:00
af34360caa feat(2.03.32): replace Notebook with sidebar+Stack, split Input and Benchmark pages
Settings dialog navigation redesigned — Gtk.Notebook replaced with a 170px
left sidebar (section headers + flat nav buttons) + Gtk.Stack content area
(860×700 default). Lazy-loading preserved.

Input tab split into Keyboard (hotkeys, quality gate, audio cues) and
Wakeword (engine config, cancel/send words, wakeword sound cues).

Benchmark tab split into Benchmark — STT and Benchmark — Wakeword.
All field names and collect logic unchanged.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-10 12:46:33 +02:00
d45ab4e91d feat(2.03.32): replace Notebook with sidebar+Stack, split Input and Benchmark pages
- Replace Gtk.Notebook tab bar with a 170px left sidebar (flat buttons,
  section headers) + Gtk.Stack navigation; dialog widened to 860×700
- Split "Input" page into "Keyboard" (keys, quality gate, audio cues)
  and "Wakeword" (enable switch, mic level, test, engine CRUD, sound cues)
- Split "Benchmark" page into "Benchmark — STT" and "Benchmark — Wakeword"
- Remove _page() helper and bt-nb CSS; add .bt-sidebar-active + .sidebar CSS
- Lazy-loading preserved via _pending_pages dict + _show_page/_build_page
- Meter start guard kept in both _build_keyboard and _build_wakeword

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-10 12:42:08 +02:00
ca1f408876 feat: first-run setup wizard for new users (v2.03.31)
Paged GTK dialog guides through trigger method, keyboard shortcuts,
wakeword server, STT engine, and optional LLM setup. Shows automatically
on first launch, re-openable via Settings → "Setup Wizard…". Sets
setup_complete in config so it doesn't reappear.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-10 12:14:06 +02:00
5aafb572ed feat: dedicated wakeword models for cancel and send actions (v2.03.30)
WakewordActionListener opens a second Wyoming connection during active
wakeword recording, listening for the configured cancel/send models. When
either fires it immediately calls cancel_dictation() or finish_dictation()
without any silence timer or Whisper pass. Settings UI adds Cancel model
and Send model pickers to the wakeword config card, populated from the
same server model list as the trigger model.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-10 12:07:03 +02:00
a77b15ccaf feat: real-time cancel keyword detection during wakeword recording (v2.03.29)
CancelWatcher accumulates raw PCM from the VAD LevelMeter (via new
on_chunk callback) and runs a fast beam_size=1 transcription check every
~0.6s. When a cancel keyword is detected it immediately calls
cancel_dictation() without waiting for the silence timer to expire or
a full transcription to complete.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-10 11:47:10 +02:00
1c276e767b fix: block scroll-wheel changes on all ComboBoxText dropdowns (v2.03.28)
Hovering over a combo and scrolling could silently change the selection.
All ComboBoxText widgets now return True from their scroll-event handler,
swallowing the event before GTK's default handler can act on it.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-10 11:38:48 +02:00
016ffe0390 feat: overlay × cancel button + wakeword shortcut fields inline (v2.03.27)
- Overlay HUD shows a × button in the top-right corner during recording/
  streaming; clicking it cancels dictation. The button area is the only
  clickable region — rest stays fully click-through.
- Wakeword tab "Cancel words" and "Send words" rows now include an inline
  keyboard shortcut entry + Set button, so key_cancel / key_send can be
  configured right next to the spoken-word equivalents.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-10 04:00:23 +02:00
834cc20553 fix: cancel recording works in wakeword mode + tray Cancel item (v2.03.26)
- Cancel hotkey now fires even when wakeword triggered the recording
  (ModifierScheme state was "idle" so the key was silently ignored)
- Tray menu: "✕ Cancel recording" — always visible, enabled while recording,
  grayed out at idle; works for both wakeword and manual recordings

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-10 03:44:14 +02:00
599eb08c5a feat: smart Save — inline status, no restart for safe changes (v2.03.25)
Save now diffs old vs new config. Safe changes (language, sounds, LLM,
keywords, overlay) show "✓ Applied" in the header for 4s. Restart-required
changes (STT engine, hotkeys, mic, wakeword) show "⚠ restart needed for: …"
and highlight Save & Restart. No modal popup on Save.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-10 03:29:27 +02:00
9c812a960e fix: Input level meter works without visiting General first (v2.03.24)
_start_meter() was only called from _build_general() and referenced
self.mic_level unconditionally. Now _build_input() also starts the meter
when it's not already running, and both level bars are updated via hasattr.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-10 02:48:55 +02:00
8301cbb457 fix: wakeword pane actually resizable — wrap controls in ScrolledWindow (v2.03.23)
The controls pane now has shrink=True and a ScrolledWindow wrapper, so
dragging the divider upward collapses the controls and expands the table.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-10 02:26:32 +02:00
012a069ad0 feat: wakeword benchmark — draggable split pane for results table (v2.03.22)
Controls (TTS config, engine checkboxes, run button) are in the top pane;
the results table is in the bottom pane. Drag the divider to see more rows.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-10 01:57:31 +02:00
8b26bc3379 feat: wakeword results table — sortable columns + CSV export (v2.03.21)
- All columns sortable by clicking header; numeric cols sort numerically
- "Copy as CSV" → clipboard; "Save CSV…" → file chooser

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-10 01:47:47 +02:00
6f133771e7 fix: icon vertical centering + wakeword results table (v2.03.20)
- Section header icons were pushed down by bt-section CSS margin-top;
  now only applied to the row container, not the image widget
- Wakeword benchmark shows a full TreeView table: per-voice Detected/Total/
  Recall%/False-fires/Time with colour coding, plus aggregate row per engine

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-10 01:25:14 +02:00
66e431f50a feat: wakeword engine checkboxes + wakeword model selector in benchmark (v2.03.19)
- Engine checkboxes let you pick which wakeword servers to include in the run
- Wakeword combo selects which model/phrase to test; leave empty for each
  engine's own, pick a specific one (e.g. okay_computer) to override all
- Also fixes: TTS ⟳ no longer fills model combo with Kokoro voice names

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-10 01:13:54 +02:00
b20aa31261 feat: TTS model fix + per-engine wakeword benchmark results (v2.03.18)
- TTS ⟳ no longer floods model combo with voice names (Kokoro exposes
  voices as /models entries — detected and skipped automatically)
- Wakeword benchmark now shows per-engine Recall/False-fires/time results;
  fixes progress callback signature mismatch that crashed multi-engine runs
- Wakeword fetch feedback: ⟳ shows "Connecting…" then model count/names
- Wakeword Quickstart expanded to ports 10400–10403 + hey_jarvis/alexa
- Wakeword info box added explaining model directory setup

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-10 00:59:28 +02:00
7a9dc5a2f7 feat: MP3/OGG/FLAC sound support + browse dialog with auto-preview (v2.03.16)
Sound fields accept WAV/MP3/OGG/FLAC/M4A/AAC/AIFF/Opus. Browse dialog
auto-plays each file on selection so you can preview before confirming.
sound.py falls back to ffplay/gst-play-1.0 for formats not supported
by pw-play/paplay.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-10 00:37:07 +02:00
571dae7cc9 feat: full CRUD for wakeword engine presets (v2.03.15)
Add/Quickstart/Reload/Delete buttons + Name field mirror the STT engines UI.
Four quickstart templates for common wyoming-openwakeword setups.
Migration: existing wakeword_uri/model auto-promoted to first preset.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-10 00:32:17 +02:00
e831d7f1e6 fix: remove Internal engine section header in Engines tab (v2.03.14)
Device/Compute rows already only show for local engines; the titled section
break was redundant and visually separated fields that belong together.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-10 00:24:42 +02:00
34f75844c1 feat: Save buttons in header bar, remove Close button, center section icons (v2.03.13)
HeaderBar replaces bottom button row — Save and Save & Restart appear in the
title bar on the right, X button closes. Section header icons vertically
centered using SMALL_TOOLBAR size and valign=CENTER.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-10 00:22:53 +02:00
ccf3801545 feat: icons on all settings tabs and section headers (v2.03.12)
GTK symbolic icons on every tab label and every section/card header.
Also fixes the resize grip landing in the tab bar instead of the bottom-right corner.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-10 00:07:41 +02:00
efa44c8872 feat: resize grip indicator on settings window (v2.03.11)
Draws a classic dotted SE-corner grip overlaid on the bottom-right of the
notebook so users know the settings dialog is resizable.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-09 23:50:20 +02:00
c292ff2242 fix: probe Prometheus /metrics at server root, not under /v1 (v2.03.10)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-09 23:30:33 +02:00
c3cf123afe feat: server RAM via Prometheus /metrics in benchmark (v2.03.09)
Probe remote engines' /metrics for process_resident_memory_bytes or
container_memory_rss; show actual server-side MB in RAM column.
Falls back to "server" when the endpoint is not exposed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-09 23:24:40 +02:00
86632e1918 fix: hide Internal Engine section for remote/streaming engines (v2.03.08)
Removes whitespace gap between STT config card and device/precision card
by hiding the latter when a Server or Realtime engine type is selected.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-09 23:06:32 +02:00
d5e512a812 feat: per-engine timeout field, WhisperX default 120s (v2.03.07)
- STTEngine gains timeout: int = 30 field; used as HTTP timeout per engine
- Engines tab shows "Timeout (s)" field; blank = 30s default
- WhisperX quickstart template pre-sets 120s (diarization is slow)
- config load/save: only written when != 30 to keep config clean
- RAM column header tooltip explains "server" for Docker/remote engines

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-09 22:48:53 +02:00
2326f20a28 fix: numeric sort for Time, Accuracy, RAM columns (v2.03.06)
String sort put "14.85" before "2.47". Now uses a custom comparator
that strips % and non-numeric markers before comparing as float.
Non-numeric values ("—", "server") sort to the bottom.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-09 22:37:17 +02:00
05ccfbdeb4 fix: RAM column shows "server" for remote engines (v2.03.05)
Remote engines run models server-side so local RSS never changes.
Show "server" instead of "—" to make the reason clear.
Local engines show measured MB; local already-loaded shows "—".

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-09 22:34:41 +02:00
d40721dd3d fix: reduce transcription timeout to 30s (v2.03.04)
300s was too long; nobody waits 5 min for a result.
30s gives slow remote servers a fair window while still failing fast.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-09 22:25:17 +02:00
79f3b5cdab fix: API probe URLs, 5min timeout for slow engines like WhisperX (v2.03.03)
- Add _api_base() to strip endpoint-specific path suffixes before probing
  /models, /metadata, /info — fixes /transcribe/models 404 spam when URL
  ends with a custom path like /v1/transcribe
- Increase default transcribe() timeout 60s → 300s — WhisperX with speaker
  diarization (pyannote) takes 2-5 min and was always timing out

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-09 22:23:13 +02:00
766002a478 fix: WhisperX URL — add template, tooltip clarifying /transcribe path (v2.03.02)
- Add "WhisperX server" quickstart template pre-filled with /transcribe endpoint
- Add tooltip to STT URL field explaining that non-standard servers (WhisperX)
  should use the full endpoint as the URL, not /v1
- _url_field_lb accepts optional tooltip= kwarg

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-09 22:16:21 +02:00
d9603c98bf feat: RAM usage column in benchmark, docs update (v2.03.01)
- benchmark.py: measure RSS delta via /proc/self/status before/after each
  transcription; add ram_mb field to BenchRow
- gtksettings.py: add RAM (MB) column to results table (index 8); tooltip
  column shifted to index 10
- CHANGELOG.md: full history from v2.02.00 through v2.03.01
- README.md: benchmark description updated to mention RAM column
- MANUAL.md: benchmark result columns as table; Log tab documents
  level filter dropdown

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-09 22:11:38 +02:00
f5f65ffba9 fix: stability, WhisperX 404, log levels (v2.03.00)
- Stability: remove blocking TCP socket call from _collect() — was
  freezing the GTK main thread on Save when wakeword server unreachable;
  now checks async in background and logs result
- Thread safety: fix _ww_load() reading GTK widget from background thread;
  capture URI on main thread before spawning
- WhisperX 404: _transcribe_remote now detects non-standard paths
  (anything other than /v1) and uses the URL as the full endpoint,
  so http://host/transcribe works without /audio/transcriptions appended
- Log levels: logbuffer stores (ts, level, msg) tuples; log() accepts
  level= (DEBUG/INFO/WARNING/ERROR); Log tab gets a Level dropdown
  (Verbose/Info/Warning/Error) that filters displayed entries live

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-09 22:01:14 +02:00
6fb41d5a9b feat: wakeword server preset dropdown in Input tab (v2.02.03)
Adds a "Server preset" combo in the Hands-free wakeword card that lists
all configured wakeword engines by name. Selecting one auto-fills the
URI and model fields and re-probes the connection. Selection persists
via wakeword_active in config.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-09 21:01:57 +02:00
48014ae662 fix: license in md style, benchmark pane minimum height (v2.02.02)
- About tab: render License with _md_panel instead of _text_panel
- Benchmark pane: set_size_request 320px min, shrink=False on both sides
  so the engine list and results table are always visible

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-09 20:55:57 +02:00
9b95c632fa feat: show last benchmark time+accuracy on selected STT engine (v2.02.01)
After running a benchmark, each engine's best result (time, accuracy)
is persisted to config and shown as a small info line in the Engines tab
when that engine is selected. Updates live as the benchmark runs.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-09 20:42:22 +02:00
2df5be3212 feat: language metadata in benchmark — Lang column, filter support (v2.02.00)
- stt.py: add ModelMeta dataclass, fmt_languages(), list_models_meta(),
  detect_remote_device(); refactor list_models() to delegate
- benchmark.py: add languages field to BenchRow; fetch via _get_langs()
  with URL-level caching using list_models_meta()
- gtksettings.py: show language labels per engine in checkbox list;
  add language codes to search filter; add Lang column to results table

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-09 20:02:12 +02:00
51ab6d5aff ui: larger, more visible tab labels (v2.01.03)
- Tab font-size 12px → 14px (matches body text)
- Inactive tabs: muted foreground color so they're clearly readable
  but visually distinct from the active tab
- Active tab: bold + blue (#1a73e8), slightly more padding (8px 18px)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-09 19:34:48 +02:00
8d79c84a8f chore: adopt x.xx.xx versioning schema (v2.01.02)
Schema: MAJOR.FEATURE.FIX
  MAJOR  — breaking changes / major redesign
  FEATURE — two-digit, new user-visible features (00-99)
  FIX     — two-digit, bug fixes within a feature release (00-99)

Renamed 2.1.2 → 2.01.02 to start the new format.

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