feat(youtube): extract transcript highlights like Reddit comment gems

Add extract_transcript_highlights() that scores sentences by specificity
(numbers, proper nouns, topic relevance) and filters YouTube filler
(subscribe, welcome back, etc). Top 5 highlights shown as structured
bullets in compact output. Full transcript moved to collapsible <details>
block so the LLM reads highlights first, full text on demand.

SKILL.md updated to instruct the judge agent to quote highlights
directly in synthesis, same as Reddit top comments.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Matt Van Horn
2026-03-23 17:49:38 -07:00
parent 499074b564
commit 4d6224f79a
6 changed files with 99 additions and 6 deletions
+1
View File
@@ -193,6 +193,7 @@ def normalize_youtube_items(
date_confidence="high",
engagement=engagement,
transcript_snippet=item.get("transcript_snippet", ""),
transcript_highlights=item.get("transcript_highlights", []),
relevance=item.get("relevance", 0.7),
why_relevant=item.get("why_relevant", ""),
))
+8 -1
View File
@@ -257,8 +257,15 @@ def render_compact(report: schema.Report, limit: int = 15, missing_keys: str = "
lines.append(f"**{item.id}** (score:{item.score}) {item.channel_name}{date_str}{eng_str}{_xref_tag(item)}")
lines.append(f" {item.title}")
lines.append(f" {item.url}")
if item.transcript_highlights:
lines.append(" Highlights:")
for hl in item.transcript_highlights[:5]:
lines.append(f' - "{hl}"')
if item.transcript_snippet:
lines.append(f" Transcript: {item.transcript_snippet}")
word_count = len(item.transcript_snippet.split())
lines.append(f" <details><summary>Full transcript ({word_count} words)</summary>")
lines.append(f" {item.transcript_snippet}")
lines.append(" </details>")
lines.append(f" *{item.why_relevant}*")
lines.append("")
+3
View File
@@ -210,6 +210,7 @@ class YouTubeItem:
date_confidence: str = "high" # YouTube dates are always reliable
engagement: Optional[Engagement] = None
transcript_snippet: str = ""
transcript_highlights: List[str] = field(default_factory=list)
relevance: float = 0.7
why_relevant: str = ""
subs: SubScores = field(default_factory=SubScores)
@@ -226,6 +227,7 @@ class YouTubeItem:
'date_confidence': self.date_confidence,
'engagement': self.engagement.to_dict() if self.engagement else None,
'transcript_snippet': self.transcript_snippet,
'transcript_highlights': self.transcript_highlights,
'relevance': self.relevance,
'why_relevant': self.why_relevant,
'subs': self.subs.to_dict(),
@@ -655,6 +657,7 @@ class Report:
date_confidence=y.get('date_confidence', 'high'),
engagement=eng,
transcript_snippet=y.get('transcript_snippet', ''),
transcript_highlights=y.get('transcript_highlights', []),
relevance=y.get('relevance', 0.7),
why_relevant=y.get('why_relevant', ''),
subs=subs,
+51 -1
View File
@@ -38,6 +38,52 @@ TRANSCRIPT_MAX_WORDS = 5000
from .relevance import token_overlap_relevance as _compute_relevance
def extract_transcript_highlights(transcript: str, topic: str, limit: int = 5) -> List[str]:
"""Extract quotable highlights from a YouTube transcript.
Similar to reddit_enrich.extract_comment_insights() but for
continuous speech-to-text rather than threaded comments.
"""
if not transcript:
return []
sentences = re.split(r'(?<=[.!?])\s+', transcript)
filler = [
r"^(hey |hi |what's up|welcome back|in today's video|don't forget to)",
r"(subscribe|like and comment|hit the bell|check out the link|down below)",
r"^(so |and |but |okay |alright |um |uh )",
r"(thanks for watching|see you (next|in the)|bye)",
]
topic_words = [w.lower() for w in topic.lower().split() if len(w) > 2]
candidates = []
for sent in sentences:
sent = sent.strip()
words = sent.split()
if len(words) < 8 or len(words) > 50:
continue
if any(re.search(p, sent, re.IGNORECASE) for p in filler):
continue
score = 0
if re.search(r'\d', sent):
score += 2
if re.search(r'[A-Z][a-z]+', sent):
score += 1
if '?' in sent:
score += 1
sent_lower = sent.lower()
if any(w in sent_lower for w in topic_words):
score += 2
candidates.append((score, sent))
candidates.sort(key=lambda x: -x[0])
return [sent for _, sent in candidates[:limit]]
def _log(msg: str):
"""Log to stderr."""
sys.stderr.write(f"[YouTube] {msg}\n")
@@ -345,11 +391,15 @@ def search_and_transcribe(
top_ids = [item["video_id"] for item in items[:transcript_limit]]
transcripts = fetch_transcripts_parallel(top_ids)
# Step 3: Attach transcripts to items
# Step 3: Attach transcripts and extract highlights
core_topic = _extract_core_subject(topic)
for item in items:
vid = item["video_id"]
transcript = transcripts.get(vid)
item["transcript_snippet"] = transcript or ""
item["transcript_highlights"] = extract_transcript_highlights(
transcript or "", core_topic,
)
return {"items": items}