Skip to content

Commit 4dded07

Browse files
nodeeeeeeclaude
andcommitted
Fix language misdetection; generate notes per-video by default
Language detection: When Whisper auto-detect returns a non-English language, re-probe the same clip with language="en" and compare avg_logprob. The model's own confidence reliably distinguishes correct transcription from hallucinated output (e.g. accented English misidentified as Malay: en=-0.36 vs ms=-0.62). Tested against 3 previously misdetected CS2105 lectures — all now correctly resolve to English. Notes: Add --per-video flag to Electron pipeline so notes are generated per lecture instead of one merged file. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 94cdd07 commit 4dded07

2 files changed

Lines changed: 29 additions & 5 deletions

File tree

electron/renderer/app.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1393,7 +1393,7 @@ async function attachPageHandlers() {
13931393
chain.push(['Align', [python, paths.align, '--course', cid]]);
13941394
}
13951395
if (steps.includes('generate')) {
1396-
const c = [python, paths.generate, '--course', cid, '--course-name', name || courseNameFromId(cid), '--detail', detail];
1396+
const c = [python, paths.generate, '--course', cid, '--course-name', name || courseNameFromId(cid), '--detail', detail, '--per-video'];
13971397
if (lf) c.push('--lectures', lf);
13981398
if (force) c.push('--force');
13991399
chain.push(['Generate notes', c]);

extract_caption.py

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -281,9 +281,12 @@ def transcribe_api(video_path: Path, caption_path: Path) -> bool:
281281

282282
with tempfile.TemporaryDirectory() as tmp:
283283
# ── Language detection: probe from mid-audio ─────────────────────────
284-
# Lecture beginnings often have intro music, silence, or greetings in
285-
# another language, which confuse Whisper's 30-second language detector.
286-
# A clip from the middle of the recording is far more representative.
284+
# Whisper's auto-detect can misidentify accented English as another
285+
# language (e.g. Malay, Welsh). We probe from the middle of the
286+
# recording (avoiding intro music / silence) and, when the result is
287+
# not English, re-probe with language="en" and compare avg_logprob.
288+
# The model's own confidence reliably distinguishes correct from
289+
# hallucinated transcriptions.
287290
if not WHISPER_LANGUAGE:
288291
_PROBE_SEC = 30
289292
probe_start = max(0, total_dur / 2 - _PROBE_SEC / 2)
@@ -301,7 +304,28 @@ def transcribe_api(video_path: Path, caption_path: Path) -> bool:
301304
)
302305
lang_full = getattr(probe_resp, "language", "english") or "english"
303306
detected_lang = _LANG_NAMES.get(lang_full.lower(), lang_full[:2].lower())
304-
print(f" '{detected_lang}'")
307+
print(f" '{detected_lang}'", end="", flush=True)
308+
309+
# If auto-detect chose a non-English language, verify by comparing
310+
# model confidence (avg_logprob) between the two.
311+
if detected_lang != "en":
312+
auto_segs = (probe_resp.model_dump().get("segments") or [])
313+
auto_lp = (sum(s.get("avg_logprob", 0) for s in auto_segs)
314+
/ max(len(auto_segs), 1))
315+
with open(probe_file, "rb") as f:
316+
en_resp = client.audio.transcriptions.create(
317+
model="whisper-1", file=f,
318+
response_format="verbose_json",
319+
language="en",
320+
)
321+
en_segs = (en_resp.model_dump().get("segments") or [])
322+
en_lp = (sum(s.get("avg_logprob", 0) for s in en_segs)
323+
/ max(len(en_segs), 1))
324+
if en_lp > auto_lp:
325+
print(f" → English wins (en={en_lp:.3f} vs {detected_lang}={auto_lp:.3f})")
326+
detected_lang = "en"
327+
else:
328+
print(f" → confirmed (en={en_lp:.3f} vs {detected_lang}={auto_lp:.3f})")
305329

306330
print(f" Using language: '{detected_lang}'")
307331

0 commit comments

Comments
 (0)