feat(voice): sync overlay orb with chat voice button state (#487)#490
feat(voice): sync overlay orb with chat voice button state (#487)#490graycyrus merged 2 commits intotinyhumansai:mainfrom
Conversation
…sai#487) The overlay orb already reacts to hotkey-based dictation via Socket.IO events, but the chat "Start Talking" button used local React state only. Add a new RPC method `openhuman.overlay_stt_notify` that the chat button calls at each voice state transition, which publishes to the existing DICTATION_BUS / TRANSCRIPTION_BUS broadcast channels — so the overlay reflects recording/transcribing/idle from both input paths with zero changes to the Socket.IO bridge or overlay event handlers. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (4)
✅ Files skipped from review due to trivial changes (2)
🚧 Files skipped from review as they are similar to previous changes (2)
📝 WalkthroughWalkthroughAdds frontend notifications and dynamic aria-labels for overlay STT state, a new tauri command Changes
Sequence DiagramsequenceDiagram
actor User
participant UI as Frontend\n(Conversations / Overlay)
participant Tauri as Tauri Bridge
participant Backend as voice.overlay_stt_notify
participant EventBus as dictation_listener
User->>UI: trigger voice record / stop
UI->>Tauri: notifyOverlaySttState('recording_started')
Tauri->>Backend: openhuman.overlay_stt_notify {state:"recording_started"}
Backend->>EventBus: publish_dictation_event("pressed")
EventBus->>UI: delivery -> overlay updates aria-label/state
UI->>Tauri: notifyOverlaySttState('transcription_done', text)
Tauri->>Backend: openhuman.overlay_stt_notify {state:"transcription_done", text}
Backend->>EventBus: publish_transcription(text)
Backend->>EventBus: publish_dictation_event("released")
EventBus->>UI: delivery -> overlay resets aria-label/state
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 5
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@app/src/overlay/OverlayApp.tsx`:
- Line 408: The aria-label currently uses a recording-specific string when mode
=== 'stt' which is inaccurate for final/linger states; update the aria-label
expression in OverlayApp (the JSX element that sets aria-label based on mode) to
use a neutral STT-active label (e.g., "Speech recognition active" or "STT
active") instead of "Recording speech", while keeping the existing labels for
'attention' and default cases.
In `@app/src/utils/tauriCommands/voice.ts`:
- Around line 178-185: The exported helper notifyOverlaySttState is using a
function declaration with a promise .catch chain; convert it to an arrow async
function that awaits callCoreRpc and handles errors with try/catch to comply
with the repo TypeScript style. Specifically, replace the function declaration
notifyOverlaySttState(...) with a const notifyOverlaySttState = async (...) :
Promise<void> => { try { await callCoreRpc({ method:
'openhuman.overlay_stt_notify', params: { state, text } }) } catch (err:
unknown) { console.debug('[overlay_stt_notify] fire-and-forget error:', err) } }
so the implementation uses async/await and try/catch while still calling
callCoreRpc and preserving the same types and exported name.
In `@src/openhuman/voice/schemas.rs`:
- Around line 47-54: The OverlaySttNotifyParams struct accepts arbitrary or
incomplete states; update the handler that deserializes OverlaySttNotifyParams
to validate the state string against the expected set ("recording_started",
"transcription_done", "cancelled", "error") and return a non-OK error (e.g.,
HTTP 400) for unknown values, and additionally enforce that when state ==
"transcription_done" the text Option is Some(non-empty) otherwise reject the
request; implement these checks immediately after deserialization (in the
function handling the overlay STT notify request) and include clear error
messages in the response so partial/invalid payloads are not treated as success.
- Around line 200-213: The formatting for the ControllerSchema entry named
"overlay_stt_notify" is failing rustfmt; open the block that constructs
ControllerSchema for namespace "voice" / function "overlay_stt_notify" (the call
site using required_string, optional_string, and json_output) and run rustfmt
(cargo fmt --all) or manually reformat the tuple/struct literal to match rustfmt
conventions (align commas, trailing commas, indentation for multi-line string
and vec![] elements) so the file src/openhuman/voice/schemas.rs passes cargo fmt
--all -- --check.
- Around line 409-413: The debug log in overlay_stt_notify currently prints raw
transcript text via p.text; change it to avoid logging sensitive contents and
instead log presence and length metadata (e.g., whether p.text.is_some() and
p.text.as_ref().map(|s| s.len())) along with the state (p.state) so the log
shows something like state, text_present=true/false, text_length=N rather than
the transcript itself; update the log call in overlay_stt_notify to use those
computed metadata values from p.text and remove the raw p.text output.
🪄 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: defaults
Review profile: CHILL
Plan: Pro
Run ID: ee41ba3f-1bb4-4802-b5b3-5da4f1097cd0
⛔ Files ignored due to path filters (1)
Cargo.lockis excluded by!**/*.lock
📒 Files selected for processing (5)
app/src/overlay/OverlayApp.tsxapp/src/pages/Conversations.tsxapp/src/utils/tauriCommands/voice.tssrc/openhuman/voice/dictation_listener.rssrc/openhuman/voice/schemas.rs
- Run cargo fmt and prettier to fix formatting violations - Use typed enum OverlaySttState instead of raw String for state param (serde rejects invalid states at deserialization, eliminating the unknown state branch) - Require `text` field for transcription_done state (return error if missing instead of silently ignoring) - Replace raw transcript logging with metadata-only (has_text, text_len) to avoid logging sensitive user speech content - Use "Voice input active" aria-label (covers recording + linger phases) - Convert notifyOverlaySttState to arrow function with async/await per repo TS conventions Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Summary
openhuman.overlay_stt_notifyso the chat voice button can signal the overlay orbProblem
DICTATION_BUS/TRANSCRIPTION_BUS→ Socket.IO events, but the chat prompt's "Start Talking" button uses browserMediaRecorderwith local React state onlySolution
overlay_stt_notifyinsrc/openhuman/voice/schemas.rs): accepts{ state, text? }and calls the existingpublish_dictation_event()/publish_transcription()functions — reusing 100% of existing broadcast infrastructurenotifyOverlaySttStateinapp/src/utils/tauriCommands/voice.ts): fire-and-forget RPC call at each voice state transitionConversations.tsx:recording_started,transcription_done, 2×cancelled, 3×errorsocketio.rs(existing bridge forwards broadcasts) orOverlayApp.tsxevent handlers (already handledictation:toggle+dictation:transcription)aria-labelon overlay orb button reflects current mode (stt/attention/idle)Submission Checklist
dictation_listener.rs+ schema stability test updated inschemas.rs; all 59 voice tests passImpact
Related
Summary by CodeRabbit
New Features
Tests