Add Desktop microphone picker and STT diagnostics - #46916
Conversation
teknium1
left a comment
There was a problem hiding this comment.
Thanks for tackling a real Desktop voice-input gap: current main still records from the default device at apps/desktop/src/app/chat/composer/hooks/use-mic-recorder.ts:187-189 and has no /api/audio/status route.
Problems
apps/desktop/src/hermes.ts:735sets a 120-second transcription timeout, but remote-profile and global-remote requests are intercepted before the generic IPC handler reads it (apps/desktop/electron/main.ts:7801-7826,7903-7923). Those paths callrequestJsonForProfile(), which fixes the timeout atDEFAULT_FETCH_TIMEOUT_MS(apps/desktop/electron/main.ts:6172-6177), currently 15 seconds (electron/hardening.ts:6).tools/transcription_tools.py:223reports every non-hard-coded provider unavailable. Main supports user-declared command providers attools/transcription_tools.py:1697-1711and plugin providers at1713-1737; valid configurations on either path would receive a false-negative diagnostic.
Suggested changes
- Propagate
request.timeoutMsthrough remote request helpers and cover remote transcription timeout routing. - Resolve diagnostics through the existing command-provider/plugin availability mechanisms, with tests for each extension path.
- Add route and renderer compatibility tests for
/api/audio/statusand the old-backend 404 fallback.
Automated hermes-sweeper review.
| return window.hermesDesktop.api<AudioTranscriptionResponse>({ | ||
| path: '/api/audio/transcribe', | ||
| method: 'POST', | ||
| timeoutMs: 120_000, |
There was a problem hiding this comment.
This reaches the normal IPC handler, but remote-profile/global-remote requests are intercepted first and routed through requestJsonForProfile(), which currently hard-codes the 15-second default. Please thread this timeout through the remote routing helpers too, or remote STT still times out after 15 seconds.
| if name == "elevenlabs": | ||
| return bool(get_env_value("ELEVENLABS_API_KEY")) | ||
|
|
||
| return False |
There was a problem hiding this comment.
This marks all custom command and plugin-backed STT providers unavailable. transcribe_audio() already dispatches configured command providers and registered plugins after the built-in branches, so the diagnostics should consult those existing availability paths rather than returning false for every unknown name.
Review note: complementary failure mode in
|
|
Vox Lockin lane 09 verification receipt (feature PR for #46337):
|
Summary
Adds a proper Hermes Desktop voice input settings surface so users can choose which local microphone the Desktop app uses for dictation and voice conversations, and can understand where speech-to-text is being processed.
This PR is intentionally independent of PR #46458. It is based on current upstream
mainand does not include the profile-scoped settings routing changes from that PR.What changed
voiceconfig section.navigator.mediaDevices.enumerateDevices().getUserMedia()for voice recording.GET /api/audio/statusfor non-mutating STT readiness diagnostics./api/audio/status, the UI shows a friendly unsupported-diagnostics message instead of a raw IPC/404 error.Root cause / motivation
Hermes Desktop voice capture used the browser/Electron default input device with no user-visible picker. On systems with multiple microphones, users could not tell which microphone was active and could not choose the intended device.
The investigation also found that Desktop voice capture is local to the Desktop app, but transcription is performed by the connected Hermes backend:
/api/audio/transcribe.The new settings text makes this explicit so users can distinguish microphone selection from STT backend location.
Dependency findings
Desktop microphone capture itself does not require
faster_whisper,sounddevice, ornumpy; capture is handled by Electron/browser APIs.Those Python packages are relevant to backend-side local STT support. The new status helper reports their availability without triggering lazy installs. It also detects command-based local STT, such as an installed
whisperbinary, as a valid local transcription backend.During local testing on macOS, backend status reported:
faster_whisper_available: falsesounddevice_available: falsenumpy_available: falselocal_command_available: trueavailable: trueSo the Desktop app did not need those packages to capture audio, and this PR does not install them automatically.
Backward compatibility
A newer Desktop app may connect to an older remote Hermes backend that does not yet have
/api/audio/status. In that case the settings panel now treats the specific404 /api/audio/status / No such API endpointresponse as unsupported diagnostics and displays:Other status failures still surface as real errors.
Validation
npm ci --workspace apps/desktopnpm run typecheckinapps/desktopscripts/run_tests.sh tests/tools/test_transcription.pypython -m py_compile tools/transcription_tools.py hermes_cli/web_server.pytools.transcription_tools.transcription_status()codesign --verify --deep --stricton the built app bundleNote: the local macOS test build skipped notarization because Apple notarization environment variables were not configured. Codesign verification passed.