Skip to content

feat(web): live-preview transcription while recording - #124

Merged
adityak74 merged 1 commit into
mainfrom
feat/voice-live-preview
Aug 25, 2026
Merged

feat(web): live-preview transcription while recording#124
adityak74 merged 1 commit into
mainfrom
feat/voice-live-preview

Conversation

@adityak74

Copy link
Copy Markdown
Contributor

Summary

  • The voice composer now shows an updating interim transcript while a recording is still in progress, instead of only a result after stop. MediaRecorder.start() now uses a 3 second timeslice, and each periodic dataavailable re-transcribes the growing clip through the existing VoiceApi.transcribe() call.
  • Interim results splice into the composer in place (tracked as a {start, end, text} span), rather than appending on every tick. If the user edits that span, live preview is abandoned for the rest of the recording and the final transcribe falls back to inserting at the cursor exactly as it did before this change. Cancel splices out a still-untouched live span the same way.
  • Live ticks are best-effort: failures are swallowed silently (no console.error, no status change), a request already in flight suppresses the next tick instead of queuing it, and the final, stop-triggered transcribe keeps its existing messages and error handling unchanged.
  • Only touches web/src/voice-input.ts and web/test/voice-input.test.ts. No Rust changes, no other frontend files. zorp-voice's transcription endpoint is already stateless per-request and needed no changes to support repeated calls.

Test plan

  • npm run check (from web/) — passes clean
  • npm test (from web/) — all 282 tests pass, including 6 new live-preview tests and 3 existing tests adjusted to seed recorded audio via a new FakeRecorder.finalData fixture field instead of a mid-recording dataavailable dispatch (which now also triggers a live tick)
  • npm run build (from web/) — passes clean

Claude-Session: https://claude.ai/code/session_01KGPVQ8wUG7h36zashWYCp4

The voice composer only ever showed a transcript after a recording
finished. Start MediaRecorder with a 3 second timeslice so it now fires
periodic dataavailable events during recording, and re-transcribe the
growing clip on each one to keep an interim result visible while the
person is still talking.

Each live tick is tracked as a span in the textarea (start, end, and
the text it holds), so the next tick can replace it in place instead
of appending. If the person edits that span themselves, live preview
is abandoned for the rest of the recording rather than clobbering
their edit, and the final stop-triggered transcribe falls back to
inserting at the cursor exactly as it does today. A live request in
flight suppresses the next tick rather than queuing it, and a failing
tick is silent since only the final transcribe is meant to surface
errors.

insertTranscript now returns the span it just inserted so both the
first live insert and the final commit can share the same
span-tracking logic. Cancelling a recording splices out an
still-untouched live span the same way.

Refactored voice-input.test.ts's FakeRecorder to attach data to the
dataavailable stop() fires on its own (finalData), so tests that only
need a non-empty recording no longer have to dispatch a mid-recording
dataavailable, which now also means a live-preview tick. Added tests
for periodic replacement, abandonment on edit, span removal on cancel,
silent tick failures, in-flight suppression, and unchanged
final-transcribe behavior.

Claude-Session: https://claude.ai/code/session_01KGPVQ8wUG7h36zashWYCp4
@adityak74
adityak74 merged commit 88a3859 into main Aug 25, 2026
7 checks passed
@adityak74
adityak74 deleted the feat/voice-live-preview branch August 25, 2026 06:03
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