Repository navigation
Description
Summary
media-use/audio/references/transcribe.md:43 states the word id (w0, w1, …) "is added during normalization for stable references in caption overrides."
For the JSON transcripts the CLI itself produces, it never is. Per-word caption overrides have nothing to key on.
Environment
- hyperframes 0.8.10, installed globally via npm
- macOS 15, Apple M5 Pro
- whisper-cpp
small.envia Homebrewwhisper-cli - Independently reproduced on WSL2 / Ubuntu
Measured
hyperframes transcribe probe.wav --model small.en on 1.7 s of speech:
[
{ "text": "The", "start": 0.01, "end": 0.16 },
{ "text": "pipeline", "start": 0.16, "end": 0.6 },
{ "text": "is", "start": 0.6, "end": 0.68 },
{ "text": "proven", "start": 0.82, "end": 1.04 },
{ "text": "end-to-end.", "start": 1.04, "end": 1.74 }
]Zero id fields across all 5 words.
Where it is and is not assigned
loadTranscript (dist/cli.js:97787) branches on file type:
| input | id assigned? |
|---|---|
.srt |
yes — id: w.id ?? "w" + i |
.vtt |
yes — id: w.id ?? "w" + i |
| JSON, whisper-cpp shape | no — parseWhisperCpp emits {text,start,end} only |
| JSON, openai shape | no — parseOpenAI emits {text,start,end} only |
| JSON, flat array | id: w.id ?? "" — empty string, not "w" + i |
The flat-array branch is the one that looks like the documented normalization and is not: a missing id becomes "", so every word ends up sharing the same empty key.
Since the branch is chosen by file format rather than by caller, going through the skill-driven flow instead of the CLI does not change the result — it is the same loadTranscript.
Workaround (verified, no code change)
Round-trip through SRT with --preserve-cues on both legs:
hyperframes transcribe audio.wav --model small.en # -> transcript.json, no ids
hyperframes transcribe transcript.json --to srt -o w.srt --preserve-cues
hyperframes transcribe w.srt --preserve-cues # -> transcript.json WITH idsResult: 5 entries, word-level timings preserved, id w0…w4 present.
--preserve-cues is required on the export leg too. Without it the export groups all 5 words into a single cue, and the word granularity is gone before the id assignment ever runs — the re-import then yields one entry, id: "w0", text "The pipeline is proven end-to-end.".
The CLI help describes --preserve-cues purely in import terms ("Keep each transcript entry as its own caption cue"), which gives no hint that it is load-bearing on export.
Suggested fixes
- Assign
"w" + iinparseWhisperCpp/parseOpenAI, or in the flat-array branch ofloadTranscriptinstead of defaulting to"". - Correct
transcribe.md:43— as written it promises ids on the path that never produces them. - Document
--preserve-cuesas applying to export as well as import.
Activity