Stop Whisper misspelling the intern's name as Devin

The intern reached 21 of 58 published transcripts as "Devin". The obvious fix —
seed his name in the Whisper initial prompt — only works for one of the two
transcription paths:

- backend/services/transcription.py (live show) uses mlx_whisper and does take
  an initial_prompt. Added Devon there. This also picks up the Big Bend prompt
  rewrite from the relocation work, which was sitting uncommitted.
- publish_episode.py, which actually produces the published transcripts, uses
  LightningWhisperMLX, whose transcribe() signature is (audio_path, language).
  It accepts no initial_prompt at all, so there is nothing to seed.

So the published path gets a deterministic correction pass instead:
fix_proper_nouns() rewrites known mishearings after transcription, preserving
casing (Devin/DEVIN/devin -> Devon/DEVON/devon) and matching whole words only,
so "Devinshire" is left alone. Verified against the real episode 58 transcript:
24 occurrences to 0, output byte-identical to the manual relabel in bf1afef.

Swapping the publish path to mlx_whisper would allow a real prompt, but that
changes the transcription engine for every episode and is a bigger call than
this warrants.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-14 04:20:22 -05:00
co-authored by Claude Opus 5
parent 5f6429e6da
commit 2901e5f4fb
3 changed files with 84 additions and 3 deletions
+31 -2
View File
@@ -244,6 +244,34 @@ TRANSCRIPT:
return result
# Recurring show names Whisper reliably mishears. LightningWhisperMLX takes no
# initial_prompt (its transcribe() signature is just audio_path + language), so
# unlike make_clips.py we cannot condition the model on these up front — they
# have to be corrected afterwards. "Devin" reached 21 of 58 published
# transcripts before this existed.
PROPER_NOUN_FIXES = {
"devin": "Devon",
}
def fix_proper_nouns(text: str) -> str:
"""Correct known Whisper mishearings, preserving the original casing style."""
if not text:
return ""
def _sub(match):
word = match.group(0)
correct = PROPER_NOUN_FIXES[word.lower()]
if word.isupper():
return correct.upper()
if word.islower():
return correct.lower()
return correct
pattern = r"\b(" + "|".join(PROPER_NOUN_FIXES) + r")\b"
return re.sub(pattern, _sub, text, flags=re.IGNORECASE)
def transcribe_audio(audio_path: str) -> dict:
"""Transcribe audio using Lightning Whisper MLX (Apple Silicon GPU)."""
print(f"[1/5] Transcribing {audio_path} (MLX GPU)...")
@@ -268,12 +296,13 @@ def transcribe_audio(audio_path: str) -> dict:
for segment in result.get("segments", []):
start_ms, end_ms, text = segment[0], segment[1], segment[2]
text = fix_proper_nouns(text.strip())
transcript_segments.append({
"start": start_ms / 1000.0,
"end": end_ms / 1000.0,
"text": text.strip()
"text": text
})
full_text.append(text.strip())
full_text.append(text)
print(f" Transcribed {duration} seconds of audio ({len(transcript_segments)} segments)")
return {