feat(desktop): add local voice dictation - #3759
Conversation
4d18f5b to
efbc63d
Compare
Co-authored-by: Kenny Lopez <klopez4212@gmail.com> Signed-off-by: John Tennant <jtennant@squareup.com>
Co-authored-by: Kenny Lopez <klopez4212@gmail.com> Signed-off-by: John Tennant <jtennant@squareup.com>
Co-authored-by: Kenny Lopez <klopez4212@gmail.com> Signed-off-by: John Tennant <jtennant@squareup.com>
Co-authored-by: Kenny Lopez <klopez4212@gmail.com> Signed-off-by: John Tennant <jtennant@squareup.com>
Co-authored-by: Kenny Lopez <klopez4212@gmail.com> Signed-off-by: John Tennant <jtennant@squareup.com>
Co-authored-by: Kenny Lopez <klopez4212@gmail.com> Signed-off-by: John Tennant <jtennant@squareup.com>
Co-authored-by: Kenny Lopez <klopez4212@gmail.com> Signed-off-by: John Tennant <jtennant@squareup.com>
Signed-off-by: John Tennant <jtennant@squareup.com>
Signed-off-by: John Tennant <jtennant@squareup.com>
Signed-off-by: John Tennant <jtennant@squareup.com>
Signed-off-by: John Tennant <jtennant@squareup.com>
a083f05 to
c831ebe
Compare
Signed-off-by: John Tennant <jtennant@squareup.com>
Signed-off-by: John Tennant <jtennant@squareup.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e43ef004eb
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
|
||
| try { | ||
| // 1. Start the native STT engine — returns the session ID used to tag events. | ||
| const sessionId = await invoke<number>("start_dictation"); |
There was a problem hiding this comment.
Register the stop listener before starting the native session
When two mounted composers start dictation close together, the second native start can replace this session after start_dictation returns but before the dictation-state listener is registered below. The native forwarder then emits this session's one-shot stopped event with no listener present, yet this hook continues opening the microphone; subsequent session-scoped stops cannot affect the replacement engine, leaving this composer stuck in isTranscribing and unable to start dictation again until it is remounted. Register the state listener before creating the session, or otherwise reconcile native state after listener registration.
Useful? React with 👍 / 👎.
|
on-device dictation via parakeet (instead of huddle→relay) is a nice split — session_id on the events is a good guard against stale transcripts. |


Context
Buzz already runs Parakeet locally for huddle transcription, but message composers cannot use it. This adds an experiment-gated dictation path that keeps microphone audio and transcription on-device.
Summary
Add local voice dictation to desktop message composers. Users can click the microphone or hold Cmd+D (Ctrl+D on non-Mac platforms), speak into the local Parakeet pipeline, and receive the final transcript in the current draft.
Changes
Related issue
Related: #1511 and #2742.
Testing
Screenshots
Idle composer:
Recording:
Reviewer-reproducible examples
From a fresh checkout of the PR, launch the native app:
git fetch origin pull/3759/head:pr-3759 git switch pr-3759 . ./bin/activate-hermit just devThen:
Observed on the exact PR build: transcript text appeared in the active draft, quick shortcut release stopped capture, context changes rejected late transcript text, and one Send click produced one message with the final words included.