Retry transcription for a memo that has audio and no transcript #57

Open
opened 2026-08-10 15:24:25 -04:00 by agent · 0 comments
Member

A memo with audio and no transcript is currently a dead end. The detail screen explains the situation and offers no way out of it. Add a way to run the audio back through the speech engine.

Where it goes

MemoDetailView.swift:299 — the .absent case, which renders "No Transcript" with a waveform.slash symbol and one of two explanatory messages. Below that description, a control to retry transcription.

Both .absent branches want it, for different reasons:

  • Parts on disk, no transcript ("This recording ended before its transcript could be assembled"). The launch sweep already retries this on every open. A manual retry is a convenience, and the button should say that it is re-running assembly rather than re-transcribing, because those are different operations with different costs.
  • Nothing on disk ("Nothing was transcribed for this memo"). This is the case that has no recovery path at all today, and it is the one that matters. The audio is sitting right there and the app will not look at it again.

Worth considering whether .unreadable should offer it too — a transcript that fails to parse is also a memo whose audio is intact.

Why now

Filed after issue #56, where a 62-minute recording produced audio and a track but no .vtt. That memo had to be recovered by pulling the .m4a off the phone and running it through the retired whisper-cpp pipeline on a Mac. The words were recoverable the whole time — the app just had no way to ask for them again.

Once retry exists, the recovery for a bug like #56 is one tap instead of a cable and an hour of CPU.

What it has to do

Transcription today runs live off the capture stream: LiveTranscriber receives buffers as the recording happens, RecordingTranscription.begin() sets up the writer and parts directory, cues arrive over transcriber.cues, and assembly runs at end(). There is no path that transcribes an existing file. That is the substance of this issue — reading the .m4a back and driving the speech engine from it is new capability, not a button wired to something that already exists.

Requirements:

  • Feed the memo's audio file through the speech engine and produce a .vtt beside it, in the same format the live path produces, with the same cue timing semantics. A retried transcript and a live one must be indistinguishable to every reader — the detail screen, the seek-from-cue behaviour, and the vault.
  • Progress while it runs. A 62-minute memo is not instant and a spinner with no indication of progress reads as a hang.
  • Cancellable.
  • Failure states that say what happened, and are the same vocabulary the live path uses — the speech model not being present is the most likely one and it is actionable, since the app already knows how to offer the download.
  • Do not touch the audio. Retry is read-only with respect to the .m4a, the .gpx and any existing parts folder.
  • Retry must not run while a recording is in progress. Playback and recording already take turns with the audio session; this is a third claimant and it should refuse rather than interfere with a capture in flight.
  • Decide what happens if the retry also produces nothing. Overwriting a real transcript with an empty one would be worse than the current behaviour.
  • #56 — the bug that produced the untranscribable memo, and the argument that the failure reason should be persisted. If that lands, retry can say what went wrong the first time.
A memo with audio and no transcript is currently a dead end. The detail screen explains the situation and offers no way out of it. Add a way to run the audio back through the speech engine. ## Where it goes `MemoDetailView.swift:299` — the `.absent` case, which renders "No Transcript" with a `waveform.slash` symbol and one of two explanatory messages. Below that description, a control to retry transcription. Both `.absent` branches want it, for different reasons: - **Parts on disk, no transcript** ("This recording ended before its transcript could be assembled"). The launch sweep already retries this on every open. A manual retry is a convenience, and the button should say that it is re-running assembly rather than re-transcribing, because those are different operations with different costs. - **Nothing on disk** ("Nothing was transcribed for this memo"). This is the case that has no recovery path at all today, and it is the one that matters. The audio is sitting right there and the app will not look at it again. Worth considering whether `.unreadable` should offer it too — a transcript that fails to parse is also a memo whose audio is intact. ## Why now Filed after issue #56, where a 62-minute recording produced audio and a track but no `.vtt`. That memo had to be recovered by pulling the `.m4a` off the phone and running it through the retired whisper-cpp pipeline on a Mac. The words were recoverable the whole time — the app just had no way to ask for them again. Once retry exists, the recovery for a bug like #56 is one tap instead of a cable and an hour of CPU. ## What it has to do Transcription today runs live off the capture stream: `LiveTranscriber` receives buffers as the recording happens, `RecordingTranscription.begin()` sets up the writer and parts directory, cues arrive over `transcriber.cues`, and assembly runs at `end()`. **There is no path that transcribes an existing file.** That is the substance of this issue — reading the `.m4a` back and driving the speech engine from it is new capability, not a button wired to something that already exists. Requirements: - Feed the memo's audio file through the speech engine and produce a `.vtt` beside it, in the same format the live path produces, with the same cue timing semantics. A retried transcript and a live one must be indistinguishable to every reader — the detail screen, the seek-from-cue behaviour, and the vault. - Progress while it runs. A 62-minute memo is not instant and a spinner with no indication of progress reads as a hang. - Cancellable. - Failure states that say what happened, and are the same vocabulary the live path uses — the speech model not being present is the most likely one and it is actionable, since the app already knows how to offer the download. - Do not touch the audio. Retry is read-only with respect to the `.m4a`, the `.gpx` and any existing parts folder. - Retry must not run while a recording is in progress. Playback and recording already take turns with the audio session; this is a third claimant and it should refuse rather than interfere with a capture in flight. - Decide what happens if the retry also produces nothing. Overwriting a real transcript with an empty one would be worse than the current behaviour. ## Related - #56 — the bug that produced the untranscribable memo, and the argument that the failure reason should be persisted. If that lands, retry can say what went wrong the first time.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
Stash/stash-ios#57
No description provided.