HomeBlogTranscribePlansAPI Keys

RAG over en YouTube-kanal: Fra RSS til svar med kildehenvisninger

Pipeline fra en YouTube-kanals RSS-feed gjennom transkripsjoner og embeddings til svar med kildehenvisninger

Å bygge RAG over en YouTube-kanal handler om å svare på «hva har denne skaperen sagt om X, og i hvilken video?» — på tvers av alt de har publisert. Pipelinen er fire steg: oppdag videoer via RSS, hent transkripsjoner, del opp og embed, svar med kildehenvisning. Her er hvert steg i kjørbar Python, inkludert delene de fleste artikler hopper over: kvotehåndtering og hvordan kildehenvisning ærlig talt ser ut uten tidsstempler.

Steg 1: video-ID-er fra kanalens RSS-feed

YouTube leverer fortsatt en ekte RSS-feed per kanal, ingen API-nøkkel nødvendig:

import requests
import xml.etree.ElementTree as ET

CHANNEL_ID = "UCxxxxxxxxxxxxxxxxxxxxxx"
NS = "{http://www.youtube.com/xml/schemas/2015}"

feed = requests.get(
    f"https://www.youtube.com/feeds/videos.xml?channel_id={CHANNEL_ID}",
    timeout=30,
).text
video_ids = [el.text for el in ET.fromstring(feed).iter(f"{NS}videoId")]

Forbehold: feeden returnerer bare de ~15 nyeste opplastingene. For en aktiv kanal bør du kjøre dette på et fast intervall og akkumulere ID-er i en fil eller tabell; bakkatalogen utover det krever YouTube Data API eller en manuell engangsliste. Til å holde en indeks fersk er RSS derimot perfekt — det er også ryggraden i kanal-til-nyhetsbrev-pipelinen.

Steg 2: hent transkripsjoner, respekter kvoten

import time

API_KEY = "yt_your_key_here"

def fetch(video_id: str) -> dict | None:
    resp = requests.get(
        "https://youtube2text.org/api/transcribe",
        params={"url": f"https://www.youtube.com/watch?v={video_id}"},
        headers={"x-api-key": API_KEY},
        timeout=90,
    )
    if resp.status_code == 404:
        return None  # TRANSCRIPT_UNAVAILABLE — no captions, skip
    if resp.status_code == 429:
        time.sleep(resp.json()["error"].get("retryAfterSeconds", 30))
        return fetch(video_id)
    resp.raise_for_status()
    return resp.json()["result"]

transcripts = [t for vid in video_ids if (t := fetch(vid))]

Gjør regnestykket på planen din før du looper over en kanal: gratisnivået er 5 videoer i måneden, som dekker et proof of concept og ikke noe mer. Basic ($5.99) gir 50, pro ($9.99) gir 500 — pro er det realistiske gulvet for å indeksere en kanal pluss de løpende opplastingene.

Steg 3: del opp og embed

Alle vektorlagre fungerer; Chroma holder eksempelet kort. Auto-undertekster mangler ofte tegnsetting, så jeg deler opp etter antall ord i stedet for setninger:

import chromadb

def chunk(text: str, size: int = 300, overlap: int = 50):
    words = text.split()
    for i in range(0, len(words), size - overlap):
        yield " ".join(words[i:i + size])

client = chromadb.PersistentClient(path="./channel_index")
col = client.get_or_create_collection("channel")

for t in transcripts:
    for i, piece in enumerate(chunk(t["content"])):
        col.add(
            ids=[f'{t["videoId"]}-{i}'],
            documents=[piece],
            metadatas=[{"videoId": t["videoId"], "title": t["title"]}],
        )

Steg 4: svar med kildehenvisninger — den ærlige versjonen

API-et returnerer ren tekst uten tidsstempler, så jeg skal være ærlig med deg: du kan ikke sitere «ved 23:41» fra disse dataene. Det du kan gjøre — og som vanligvis holder — er videoattribusjon på chunk-nivå: hver hentet chunk kjenner sin videoId og title, så svarene siterer hvilken video som sa det, med en fungerende lenke.

hits = col.query(query_texts=["what's their take on electric trucks?"], n_results=5)

context = "\n\n".join(
    f'[{m["title"]}] (https://www.youtube.com/watch?v={m["videoId"]})\n{doc}'
    for doc, m in zip(hits["documents"][0], hits["metadatas"][0])
)
prompt = (
    "Answer using only the excerpts below. After each claim, "
    f"cite the video title in brackets.\n\n{context}\n\nQuestion: ..."
)

Mat prompt til hvilken som helst LLM — en lokal modell fungerer fint her, samme oppsett som Ollama-oppsummeringsrøret.

Monteringsnotater

Rammeverksfolk: dette mapper én-til-én til LlamaIndex eller LangChain hvis du ikke vil håndrulle chunkingen. Uansett er transkripsjonslaget identisk, og det er den eneste delen med måler på — hent en nøkkel på youtube2text.org/app/keys og start med gratisnivået for å validere pipelinen før du peker den mot 300 videoer.