Skip to content

Commit b7ebf34

Browse files
nodeeeeeeclaude
andcommitted
Fix slide-transcript mismatch: add frame extraction to pipeline, skip screenshare videos in alignment
Three fixes for the screenshare/slide mismatch: 1. Pipeline now runs frame_extractor.py between Transcribe and Align. Previously frame extraction was never called, so screenshare (SS) videos always fell through to PDF-based slide matching. 2. semantic_alignment.py now checks each caption's existing alignment before attempting slide matching. If the alignment has source="screenshare" (produced by frame_extractor), the caption is skipped — preventing PDF matching from overwriting frame alignment. 3. frame_extractor.py skip logic now checks if existing alignment is frame-based before skipping. If a slide-based alignment exists but the video is a screen recording, frame extraction still runs and produces the correct frame-based alignment. Pipeline flow is now: Download → Transcribe → Extract Frames → Align → Generate Notes Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent f8b2b6f commit b7ebf34

3 files changed

Lines changed: 26 additions & 4 deletions

File tree

electron/renderer/app.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1495,6 +1495,8 @@ async function attachPageHandlers() {
14951495
chain.push(['Transcribe', c]);
14961496
}
14971497
if (steps.includes('align')) {
1498+
// Extract frames from screenshare videos before slide-based alignment
1499+
chain.push(['Extract frames', [python, paths.frame_extractor, '--course', cid, '--path', outDir]]);
14981500
const c = [python, paths.align, '--course', cid];
14991501
if (force) c.push('--force');
15001502
chain.push(['Align', c]);

frame_extractor.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -632,11 +632,17 @@ def process_course(course_id: str, base_dir: Path) -> int:
632632
frame_dir = course_dir / "frames" / video_stem
633633
align_file = course_dir / "alignment" / f"{video_stem}.json"
634634

635-
# Skip if already processed
635+
# Skip if already has frame-based alignment
636636
if align_file.exists():
637-
print(f" [skip] Already extracted: {video_stem}")
638-
processed += 1
639-
continue
637+
try:
638+
with open(align_file, encoding="utf-8") as _af:
639+
if json.load(_af).get("source") == "screenshare":
640+
print(f" [skip] Already extracted: {video_stem}")
641+
processed += 1
642+
continue
643+
# Existing alignment is slide-based — re-extract frames
644+
except Exception:
645+
pass
640646

641647
# Find matching caption
642648
caption_path = course_dir / "captions" / f"{video_stem}.json"

semantic_alignment.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1684,6 +1684,20 @@ def process_course(course_id: int | str, use_jina: bool = False,
16841684
except Exception:
16851685
pass # can't read → proceed and let align() handle it
16861686

1687+
# Skip captions that already have frame-based (screenshare) alignment.
1688+
# Those were produced by frame_extractor.py and should not be overwritten
1689+
# with slide-based alignment.
1690+
_existing_align = out_dir / f"{cap.stem}.json"
1691+
if _existing_align.exists():
1692+
try:
1693+
with open(_existing_align, encoding="utf-8") as _af:
1694+
_align_data = json.load(_af)
1695+
if _align_data.get("source") == "screenshare":
1696+
print(f" [skip] Screenshare alignment exists: {cap.stem} (use frames)")
1697+
continue
1698+
except Exception:
1699+
pass
1700+
16871701
# ── Priority 1: user-supplied mapping ────────────────────────────────
16881702
slide_group: list[Path] = []
16891703
if cap.stem in user_mapping:

0 commit comments

Comments
 (0)