fix(voice): make Whisper/Piper chips reachable from Voice settings#2821
Conversation
The chip-based Voice settings panel introduced in tinyhumansai#2586 hardcoded the local Whisper and Piper chips as disabled 'coming soon' switches with no install button and no entry in the Voice Routing dropdowns. The backend RPCs (voice_install_whisper, voice_install_piper, voice_status, voice_update_provider_settings) and the install/enable modal at the bottom of VoicePanel were already wired — only the chips themselves gated the path. Replace the disabled blocks with active chips that mirror the external provider chip behaviour: clicking an off chip opens the existing modal (which still drives the install RPCs and routes via voice_update_provider_settings on Enable), clicking an on chip routes the STT/TTS slot back to the managed cloud provider. The Voice Routing dropdowns already conditionally render the local options when sttProvider==='whisper' / ttsProvider==='piper', so no change is needed there. Closes tinyhumansai#2788.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthroughVoicePanel replaces disabled "coming soon" Whisper/Piper chips with functional local provider toggles that reflect routing state, disable during installation, route back to cloud on disable, and open the provider key/install modal; tests cover enabled state, click-to-open modal, and routing-bound checked state. ChangesLocal Whisper and Piper Provider Routing
Sequence DiagramsequenceDiagram
participant User
participant VoicePanel
participant ProviderModal
User->>VoicePanel: click Whisper/Piper chip
VoicePanel->>ProviderModal: set pendingKeySlug ('whisper'/'piper') and open
ProviderModal-->>VoicePanel: provide key / initiate install
VoicePanel->>VoicePanel: update provider routing and install state
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 ESLint
ESLint skipped: no ESLint configuration detected in root package.json. To enable, add Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@app/src/components/settings/panels/VoicePanel.tsx`:
- Around line 542-543: The toggles in VoicePanel.tsx are only disabled during
the short RPC kickoff (isInstallingWhisper / isInstalling*), but remain enabled
while polling reports installStatus.state === 'installing', allowing routing
changes mid-install; update the disabled props for the Whisper and the other
install-related toggles to combine both conditions (e.g.,
disabled={isInstallingWhisper || installStatus?.state === 'installing'}) so they
stay disabled for the full install-in-flight window, and make the same change
for the other toggle(s) referenced around the other occurrence (the lines using
isInstalling* / disabled).
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 70bbe0a2-4f76-40d3-83f6-e0a3776d317e
📒 Files selected for processing (2)
app/src/components/settings/panels/VoicePanel.tsxapp/src/components/settings/panels/__tests__/VoicePanel.test.tsx
The Whisper / Piper chip toggles were disabled only during the short
RPC kickoff (isInstalling{Whisper,Piper}), which clears as soon as
voice_install_{whisper,piper} returns. The actual install continues
until voice_install_status reports 'installed' / 'error', so the
chips become re-clickable mid-install and a user could route STT/TTS
away from the engine that is still being staged.
Disable the chips whenever either the RPC kickoff is in flight OR the
polled install state is 'installing'.
|
Addressed in |
graycyrus
left a comment
There was a problem hiding this comment.
@obchain hey! the code looks good to me — clean fix, exactly the right scope, and CodeRabbit's install-window guard concern was addressed nicely. CI has a few checks still pending (Build Tauri App, Rust Tauri Shell Tests, E2E on Windows/macOS), so i'll hold off on approving until those finish. once they're green, i'll come back and approve this.
One minor observation while i was reading the tests: the new chip-on-when-routed test only covers the Whisper/STT case. Since the Piper/TTS chip follows the exact same logic, a symmetric test (renders the Piper chip as on when TTS routing is set to piper) would round out the coverage — not blocking, but worth adding.
Let me know if you need any help with the CI failures!
graycyrus
left a comment
There was a problem hiding this comment.
Summary
Re-enables Whisper (Local) and Piper (Local) chips in Voice settings panel, wiring them to the existing install/enable modal. Fixes regression from #2586 where both chips were hardcoded disabled/"coming soon", making free self-hosted STT/TTS inaccessible from the UI despite backend RPC + factory being intact.
What it does: Drops hardcoded disabled blocks, wires onClick handlers to existing install modal.
Breaking risk: Zero. UI-only change; no backend, RPC, shared type, or config format changes. Existing cloud-routing users see no behavioural change.
Security risk: Zero. No new permission surface — the local install RPCs were already callable. No secrets, injection surfaces, or auth changes.
Code Review
- Two-file change: VoicePanel.tsx (removes "coming soon" badges, adds onClick handlers with install guard), VoicePanel.test.tsx (regression test + 3 new tests)
- Install guard logic: Both chips disabled during full install window—catching both the kickoff flag (
isInstallingWhisper) and the polling state (whisperInstall?.state === "installing") - Test coverage: Good—regression assertion (chips now enabled), modal-open tests (×2), chip-on-when-routed test (whisper)
- CodeRabbit dedup: CodeRabbit flagged install window guard; already addressed with the combined state check
Minor Finding
[minor] Test asymmetry: Missing symmetric renders the Piper chip as on when TTS routing is set to piper test (only Whisper routing test present). Non-blocking.
All else clean. CI pending (Build Tauri App, Rust Core Coverage, E2E Windows/macOS)—code is ready to ship. Will approve once CI is green.
|
@graycyrus added the symmetric Piper assertion in |
sanil-23
left a comment
There was a problem hiding this comment.
Whisper/Piper chip reachability fix verified — 26/0 CI green, CodeRabbit APPROVED, graycyrus's Piper symmetry test landed. LGTM.
Summary
Re-enables the Whisper (Local) and Piper (Local) chips in the Voice settings panel so users can install and route to local STT/TTS without editing
~/.openhuman/users/<user-id>/config.tomlby hand.disabled"coming soon" Whisper / Piper chip blocks inVoicePanel.tsx(lines 521–573 onmain).No backend, RPC, or capability-catalog changes.
voice_install_whisper,voice_install_piper,voice_status, andvoice_update_provider_settingswere already live; the routing dropdowns already conditionally renderwhisper/piperoptions whensttProvider === 'whisper'/ttsProvider === 'piper'.Problem
Closes #2788.
Starting in v0.55.0 (and still in v0.56.0), the new chip-based Voice settings UI introduced in #2586 ships
Whisper (Local)andPiper (Local)as disabled "coming soon" chips with no install button and no entry in the Voice Routing dropdowns. The previous release (v0.54.x) had functionalLocal Whisper/Local Piperdropdowns with one-clickInstall / Reinstall locally. From the user's perspective, free self-hosted STT/TTS is no longer reachable from the UI, even though the backend factory (voice/factory.rs), install RPCs, capability catalog, and the panel's own install modal are all intact. #2586 explicitly named this as a known follow-up that never landed.The manual workaround — editing
config.toml[local_ai] stt_provider="whisper"/tts_provider="piper"— is honoured at runtime but gets overwritten the moment the user touches the Voice Routing Save button.Solution
app/src/components/settings/panels/VoicePanel.tsxaria-checkedreflectssttProvider==='whisper'/ttsProvider==='piper'. Disabled only while the corresponding install is in flight.app/src/components/settings/panels/__tests__/VoicePanel.test.tsxchips are disabled (coming soon)assertion to its inverse, plus three new tests: click-opens-modal (Whisper), click-opens-modal (Piper), chip-on when routing is set towhisper.The local-provider modal that handles install + enable already lives in
VoicePanel.tsx:650–797and is unchanged — it drivesvoice_install_whisper/voice_install_piper, surfaces thevoice_statusinstall state, and callsvoice_update_provider_settingswith the literal"whisper"/"piper"strings (already accepted byvalidate_stt_provider/validate_tts_provider).Submission Checklist
sttProvider.kind === 'local').loadVoiceSettingstests.N/A:the affected feature row already covers the Voice settings panel; the matrix is keyed at panel granularity, not per-chip.## Related—N/A:chip-level change inside an existing covered feature.voiceInstallApimocks (whisperInstallStatus,piperInstallStatus,installWhisper,installPiper).N/A:Voice settings panel is not on the release-cut smoke path.Closes #NNNin the## Relatedsection.Impact
cloudrouting as today; users who upgraded from v0.54.x withstt_provider="whisper"/tts_provider="piper"already in their config see the chip turn on automatically.Related
docs/TEST-COVERAGE-MATRIX.md(Voice / Dictation) — unchanged at panel granularity.AI Authored PR Metadata (required for Codex/Linear PRs)
Linear Issue
Commit & Branch
Validation Run
pnpm --filter openhuman-app format:check— Prettier ran clean on both touched files (prettier --writereportedunchanged).pnpm typecheck—tsc --noEmitpasses from the repo root (afterpnpm installto pick up the newrecharts/rehype-katex/remark-mathdeps merged intomainvia feat(cost): add settings cost dashboard with global tracker, dashboard RPCs, and charts #2762 / feat(chat): render agent-bubble LaTeX with KaTeX and safe math detection #2697).pnpm exec vitest run --config test/vitest.config.ts src/components/settings/panels/__tests__/VoicePanel.test.tsx→ 19/19 passed (14.78s), including the new chip-clickable / modal-opens / chip-on-when-routed cases.N/A— no Rust code changed.N/A— no Tauri shell code changed.Validation Blocked
command:N/Aerror:N/Aimpact:N/ABehavior Changes
voice_install_whisper/voice_install_piperand finalises viavoice_update_provider_settings. Clicking an on chip routes the slot back to managed cloud.Settings → AI → Voiceagain on v0.55+, restoring parity with v0.54.x.Parity Contract
voice_update_provider_settingsvalidation are unchanged. Users oncloudrouting see no behavioural change.effective_stt_provider/effective_tts_providerprecedence (config.stt_provider → config.local_ai.stt_provider → "cloud") is unchanged.Duplicate / Superseded PR Handling
Summary by CodeRabbit