Skip to content

feat: make STT binaries (whisper/ffmpeg) platform-configurable#7

Merged
maciek-hyperdev merged 2 commits into
mainfrom
feature/configurable-stt-binaries
Jun 9, 2026
Merged

feat: make STT binaries (whisper/ffmpeg) platform-configurable#7
maciek-hyperdev merged 2 commits into
mainfrom
feature/configurable-stt-binaries

Conversation

@maciek-hyperdev

Copy link
Copy Markdown
Contributor

Motivation

The speech-to-text path hardcodes whisper and ffmpeg by literal binary name. Anyone whose platform has a differently-named binary — whisper.cpp, faster-whisper, a venv path, Homebrew vs pip installs, a NAS with a non-standard location — has to edit source and recompile to swap the engine. (This is the exact pain hit running hdcd-telegram across Mac + NAS.)

This makes the STT backend a config change, not a code change.

What changed

  • TranscribeConfig gains whisper_bin / ffmpeg_bin, read in from_env() from new env vars WHISPER_BIN (default whisper) and FFMPEG_BIN (default ffmpeg). Empty/whitespace-only values fall back to the default with a warn! (mirrors the existing WHISPER_MODEL style).
  • check_transcribe_support() now takes the config, so the startup availability check resolves the same binaries that transcribe will actually invoke (and logs the resolved binaries).
  • find_executable() resolves an explicit absolute/relative path to an existing executable directly (existence + Unix exec-bit check), falling back to which/where for bare names in PATH.
  • transcribe_inner() invokes config.ffmpeg_bin / config.whisper_bin instead of literals.
  • README: new WHISPER_BIN / FFMPEG_BIN rows in the env-var table.
  • Added unit tests for default / override / empty-fallback / trim behaviour.

Security note

These values are trusted operator config (same trust level as WHISPER_MODEL) and invocation is exec-direct via Command::new — no shell, so no escaping/sanitisation is needed.

Backward compatibility

Defaults are whisper / ffmpegidentical to current behaviour. No action needed for existing users.

Verification (observed locally)

  • cargo build — Finished, clean.
  • cargo test — 51 + 6 + 1 tests pass (incl. 4 new transcribe-config tests). One integration test (router_ipc_test, unrelated IPC timing) flaked once then passed consistently on re-run.
  • cargo fmt --check — clean.
  • cargo clippy --all-targets — no warnings.

Co-authored-by: Agis (agent) agis@hyperdev.local

🤖 Generated with Claude Code

Agis and others added 2 commits June 9, 2026 08:51
Add WHISPER_BIN and FFMPEG_BIN env overrides so the speech-to-text engine
can be swapped without editing source. Previously `whisper` and `ffmpeg`
were invoked by literal binary name, forcing anyone with a differently-named
binary (whisper.cpp, faster-whisper, a venv path, Homebrew vs pip) to patch
the code.

- TranscribeConfig gains `whisper_bin` / `ffmpeg_bin`, read in from_env()
  (default `whisper` / `ffmpeg`; empty/whitespace falls back to default).
- check_transcribe_support() takes the config so the startup availability
  check resolves the same binaries that will actually be invoked.
- find_executable() now resolves an explicit path to an existing executable
  directly, falling back to which/where for bare names.
- transcribe_inner() invokes the configured binaries.
- README: document WHISPER_BIN / FFMPEG_BIN.

Values are trusted operator config (like WHISPER_MODEL) and invoked
exec-direct (no shell), so no escaping is needed. Defaults preserve current
behaviour — fully backward compatible.

Co-authored-by: Agis (agent) <agis@hyperdev.local>
…w nit)

Pin the actual voice-transcription invocation to the absolute paths that
check_transcribe_support() resolved at startup, instead of letting
transcribe_inner() re-resolve the bare WHISPER_BIN/FFMPEG_BIN name via PATH
at exec time. This closes a TOCTOU / PATH-drift gap where the startup
availability check and the real invocation could resolve to different
binaries.

- main.rs: after a successful support check, write the resolved
  whisper_path/ffmpeg_path back into transcribe_config (kept as the
  configured name when a path didn't resolve, preserving fallback).
  transcribe_inner() is unchanged — it now spawns the resolved path.
- Add a test asserting check_transcribe_support resolves a real executable
  path for an existing binary.

Backward compatible: with no env set, the binaries still resolve to
whisper/ffmpeg via PATH exactly as before.

Addresses cross-model review nit (b) on PR #7.

Co-authored-by: Agis (agent) <agis@hyperdev.local>
@maciek-hyperdev
maciek-hyperdev merged commit c8b9b88 into main Jun 9, 2026
2 of 3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant