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:
+31
-2
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user