HomeBlogTranscribePlansAPI Keys

LangChain YouTube Transcript Loader Che Sopravvive in Produzione

Pipeline LangChain che trasforma un video YouTube in oggetti Document e una catena di riassunto

Ogni tutorial di trascrizione YouTube di LangChain mostra le stesse tre righe: YoutubeLoader.from_youtube_url(), carica, fatto. Poi distribuisci in un box cloud e restituisce silenziosamente nulla. Di seguito è un loader che restituisce oggetti Document propri da un'API ospitata invece — circa 20 righe, più una catena di riassunto per provare che funziona end-to-end.

Perché YoutubeLoader integrato muore sui server

YoutubeLoader non chiama un'API ufficiale. Raschia gli endpoint delle didascalie interne di YouTube dalla macchina su cui viene eseguito il codice. Da un IP residenziale che per lo più funziona. Da un AWS, GCP o IP Hetzner viene bloccato o servito risposte vuote, perché YouTube tratta il traffico del datacenter come traffico bot. Ho scritto i dettagli in perché lo scraping della trascrizione YouTube si rompe su IP cloud — la versione breve è che il fallimento è ambientale, quindi passa ogni test locale e muore esattamente dove conta.

youtube2text.org fa il recupero dal suo lato e ti passa JSON, che trasforma il tuo loader in una semplice chiamata HTTP.

Il loader

import requests
from langchain_core.documents import Document

API_KEY = "yt_your_key_here"

def load_youtube_transcript(url: str, max_chars: int = 150000) -> Document:
    resp = requests.get(
        "https://youtube2text.org/api/transcribe",
        params={"url": url, "maxChars": max_chars},
        headers={"x-api-key": API_KEY},
        timeout=90,
    )
    resp.raise_for_status()
    r = resp.json()["result"]
    return Document(
        page_content=r["content"],
        metadata={
            "videoId": r["videoId"],
            "title": r["title"],
            "pubDate": r["pubDate"],
            "source": url,
        },
    )

L'API restituisce videoId, title, pubDate, content, contentSize e un flag truncated. Il testo della trascrizione va in page_content, tutto il resto in metadata — esattamente la forma che catene a valle e vector store si aspettano.

Non hai ancora una chiave? Afferra la chiave demo condivisa:

curl https://youtube2text.org/api/demo-key

È limitata a 5 video al mese per IP, il che è abbastanza per testare il loader.

Una catena di riassunto

from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain.chains.combine_documents import create_stuff_documents_chain

llm = ChatOpenAI(model="gpt-4o-mini")
prompt = ChatPromptTemplate.from_template(
    "Summarize this video transcript in five bullet points:\n\n{context}"
)
chain = create_stuff_documents_chain(llm, prompt)

doc = load_youtube_transcript("https://www.youtube.com/watch?v=dQw4w9WgXcQ")
print(chain.invoke({"context": [doc]}))

create_stuff_documents_chain mette tutta la trascrizione in un prompt, che funziona perché maxChars limita il carico a 150.000 caratteri per impostazione predefinita. Per podcast di ore su modelli di piccolo contesto, passa un maxChars più basso al loader o passa a uno schema map-reduce.

Cosa gestire nel codice reale

Due modalità di errore meritano di essere catturate esplicitamente. Un video con didascalie disabilitate restituisce HTTP 404 con codice di errore TRANSCRIPT_UNAVAILABLE — nessun ritentativo o cambio di libreria lo risolve, il testo semplicemente non esiste. E RATE_LIMIT_EXCEEDED (429) include retryAfterSeconds nel JSON di errore, quindi leggilo e recedi invece di martellare:

if resp.status_code == 429:
    wait = resp.json()["error"].get("retryAfterSeconds", 60)

Una limitazione onesta: content è testo semplice senza timestamp. Va bene per il riassunto e il recupero, ma se hai bisogno di link profondi "salta a 12:34", dovrai accontentarti dell'attribuzione a livello di video tramite videoId in metadata.

Dove andare da qui

Gli stessi oggetti Document si inseriscono direttamente in un vector store — mi muovo nella pipeline completa in RAG su un intero canale YouTube. Se il tuo stack è LlamaIndex piuttosto che LangChain, la configurazione equivalente è altrettanto breve.

Quando i 5 video della chiave demo smettono di essere sufficienti, ottieni la tua chiave — livello gratuito incluso, piani a pagamento da $ 5,99 per 50 video al mese.