Transcribe during recording with recoverable chunks and microphone activity icon

This commit is contained in:
2026-09-07 21:52:50 -04:00
parent 82bc350521
commit f30fbdfce8
13 changed files with 2277 additions and 35 deletions
+44 -30
View File
@@ -50,38 +50,52 @@ Set from the tray menu, or via files / env vars:
Devices that refuse 16 kHz (raw ALSA and PipeWire's JACK endpoints do) are
captured at their native rate and resampled.
Every clip is conditioned before upload — the stream-open click is trimmed off
the front (only as much of it as is actually there, up to 150 ms), DC bias is
filtered out, and the level is normalised towards -20 dBFS. Near-silent clips
are refused instead of being sent, since transcription models answer silence
with confident hallucinations.
By default, Blurt transcribes while you speak. It conditions the incoming audio,
then seals and uploads phrases as pauses provide natural boundaries. A chunk is
at least about 8 seconds long; early cuts require roughly 800 ms of quiet, while
the required pause falls towards 500 ms as the chunk approaches the 20-second
target. After 45 seconds it uses the quietest recent point even without a full
pause, so one uninterrupted passage cannot hold up the whole recording. Pause
detection follows the microphone's noise floor and only skips near-digital
silence; ordinary quiet speech and the silence around phrase boundaries remain
in the audio.
Every clip is written to `spool/` (gitignored) before it is uploaded, and
deleted again as soon as its text reaches the clipboard. If transcription fails —
timeout, connection error, server error, empty response — the WAV stays there
and the notification says so; **Retry failed transcriptions (N)** in the tray
menu re-uploads the spooled clips oldest first, so a network hiccup never costs
you the words. A rejected request (any 4xx other than 408 and 429) is the
exception: the same audio can only be rejected again, so it is not kept, and the
notification says that too. Retried transcripts are copied to the clipboard
together, oldest first, once the whole run is done — and never dispatched to an
agent, since a spooled clip may be one part of a longer recording. The upload
timeout scales with the clip: 30 s plus 30 s per minute of audio, capped at
5 minutes. Clips longer than 5 minutes are split into chunks of about
4 minutes — each cut lands in a pause, not mid-word — and the chunks are
uploaded in parallel and stitched back together in order. The tray icon fills
clockwise as each chunk comes back, so you can see how far along the clip is.
If only some chunks come back, the transcript is copied with ` […] ` where the
gaps are, and just the failed chunks are kept in the spool as `…-partNN.wav`
for the retry.
Up to three chunks are transcribed concurrently. Their results are retained by
position and delivered once, in recording order, after you stop and the final
chunk finishes. Starting another recording does not mix the two sessions, and
each session keeps the model, language, provider, and API key selection it had
when recording began even if you change the tray settings meanwhile. The tray
icon shows progress as chunks finish.
While recording, the red icon brightens and its three level bars rise with
microphone volume, settling back down during pauses. This shows incoming audio
activity; it does not indicate that the transcription service has recognized words.
Nothing else is cut: every second of the recording is uploaded. If a transcript comes
back missing words, check `blurt.log` — each clip logs its length, speech level,
noise floor, and `dead=`, the longest run of digital silence inside it. A
non-zero `dead=` means the input dropped out mid-clip, which is what following
the system default source invites; pin a device instead. Set
`BLURT_SAVE_CAPTURES=1` (or to a directory) to keep the raw and uploaded WAVs
for every clip and hear exactly what the API got.
Each session has a recovery directory under `spool/` (gitignored). Sealed chunks,
completed text, and a checkpoint of the unsealed tail are kept there until the
complete transcript reaches the clipboard or agent. The tail is checkpointed
about once a second; an abrupt crash can lose audio since the last checkpoint.
**Retry failed transcriptions (N)** re-uploads unfinished chunks and reconstructs
the saved recording, including text that succeeded before a network error,
timeout, server error, or empty response. A partial result is copied with ` […] `
and retained for retry; retried results are
copied rather than dispatched to an agent. The upload timeout scales with each
chunk: 30 seconds plus 30 seconds per minute of audio, capped at five minutes.
Set `BLURT_STREAMING=0` before starting Blurt to use the legacy whole-clip flow.
That mode trims up to 150 ms of stream-open click, filters DC bias, normalises
towards -20 dBFS, and rejects near-silent clips. It spools the complete clip
before upload, splits recordings longer than five minutes near pauses into
roughly four-minute parallel uploads, retains retryable failures, and marks
missing chunks with ` […] `. Rejected requests (4xx other than 408 and 429) are
discarded because retrying the same request cannot fix them.
If a transcript comes back missing words, check `blurt.log`; streaming mode logs
chunk boundaries, noise floor, and `dead=`, the longest run of digital silence
per chunk, plus the time from Stop to delivery. A non-zero `dead=` can indicate
an input dropout. Pinning an
input device avoids the system default moving between sources. In legacy mode,
set `BLURT_SAVE_CAPTURES=1` (or to a directory) to retain raw and uploaded WAVs
and hear exactly what the API received.
## Checking the microphone