How to Build a RAG Pipeline with YouTube Transcripts
A working RAG pipeline over YouTube video transcripts: collect transcripts across a video list, chunk them, embed and store the vectors, retrieve the relevant chunks, and generate a cited answer - full code for every step, plus how to keep the index fresh.
00:09:00 · SEP 27, 2026
त्वरित उत्तर
ट्रांसक्रिप्ट इकट्ठा करें
डैशबोर्ड से एक key लें (100 मुफ़्त क्रेडिट, कोई कार्ड ज़रूरी नहीं) और हर वीडियो का ट्रांसक्रिप्ट उसकी id से लाएं। क्रेडिट हर रिक्वेस्ट पर लगते हैं, वीडियो के मिनट पर नहीं - इसलिए 3 घंटे का लेक्चर उतना ही 1 क्रेडिट लेता है जितना 2 मिनट का क्लिप, जो तब मायने रखता है जब आप किसी चैनल का पूरा पुराना संग्रह इनजेस्ट कर रहे हों:
async function fetchTranscript(videoId: string) {
const res = await fetch(
`https://getyoutubetranscript.com/api/v1/transcript?v=${videoId}`,
{ headers: { Authorization: `Bearer ${process.env.GETYOUTUBETRANSCRIPT_API_KEY}` } }
);
const json = await res.json();
if (!json.success) throw new Error(json.message);
return json.data as { video_id: string; title: string; transcript: string; word_count: number };
}
const videoIds = ['dQw4w9WgXcQ', 'jNQXAC9IVRw' /* ... */];
const videos = await Promise.all(videoIds.map(fetchTranscript));video_id और title ट्रांसक्रिप्ट टेक्स्ट के साथ ही वापस आते हैं - बाद में स्टेप 5 में जवाब का हवाला देने के लिए इन्हीं का इस्तेमाल होता है।
ट्रांसक्रिप्ट को टुकड़ों में बांटें
एम्बेड करने से पहले हर ट्रांसक्रिप्ट को ओवरलैपिंग विंडो में बांटें - पूरे वीडियो को एक साथ एम्बेड करना किसी खास सवाल का जवाब रिट्रीव करने के लिए बहुत मोटा (coarse) होता है, और इसके लिए किसी लाइब्रेरी की ज़रूरत नहीं:
function chunkText(text: string, size = 1200, overlap = 200) {
const chunks: string[] = [];
let start = 0;
while (start < text.length) {
const end = Math.min(start + size, text.length);
chunks.push(text.slice(start, end));
start += size - overlap;
}
return chunks;
}
const records = videos.flatMap((video) =>
chunkText(video.transcript).map((text, chunkIndex) => ({
videoId: video.video_id,
title: video.title,
chunkIndex,
text,
}))
);बोले गए शब्दों वाले ट्रांसक्रिप्ट के लिए 1,200 अक्षरों की विंडो और 200 अक्षरों का ओवरलैप एक ठीक-ठाक डिफ़ॉल्ट है - छोटे, सघन क्लिप्स के लिए इसे घटाएं, लेक्चर जैसी लंबी सामग्री के लिए बढ़ाएं जहां आस-पास का ज़्यादा संदर्भ मदद करता है।
एम्बेड करें और स्टोर करें
हर टुकड़े को एम्बेड करें और वेक्टर के साथ वीडियो की id और title भी रखें, क्योंकि बाद में यही एक रिट्रीव किए गए टुकड़े को हवाले में बदलता है:
import OpenAI from 'openai';
const openai = new OpenAI();
async function embed(text: string) {
const res = await openai.embeddings.create({ model: 'text-embedding-3-small', input: text });
return res.data[0].embedding;
}
const index = await Promise.all(
records.map(async (r) => ({ ...r, embedding: await embed(r.text) }))
);स्पष्टता के लिए यह वेक्टर्स को मेमोरी में रखता है। कुछ सौ टुकड़ों के बाद, array को pgvector, Pinecone, या किसी और vector store से बदल दें - नीचे दिया गया रिट्रीवल स्टेप सिर्फ एक ऐसा फ़ंक्शन चाहता है जो सबसे नज़दीकी k वेक्टर लौटाए, ठीक यही आकार नहीं।
प्रासंगिक टुकड़े रिट्रीव करें
क्वेरी के समय, सवाल को उसी मॉडल से एम्बेड करें और स्टोर किए गए टुकड़ों को cosine similarity से रैंक करें:
function cosineSimilarity(a: number[], b: number[]) {
let dot = 0, normA = 0, normB = 0;
for (let i = 0; i < a.length; i++) {
dot += a[i] * b[i];
normA += a[i] ** 2;
normB += b[i] ** 2;
}
return dot / (Math.sqrt(normA) * Math.sqrt(normB));
}
async function retrieve(query: string, k = 5) {
const queryEmbedding = await embed(query);
return index
.map((r) => ({ ...r, score: cosineSimilarity(r.embedding, queryEmbedding) }))
.sort((a, b) => b.score - a.score)
.slice(0, k);
}k=5 एक शुरुआती बिंदु है - बहुत कम टुकड़ों से मॉडल के पास पूरा जवाब देने लायक संदर्भ नहीं होता, और बहुत ज़्यादा से अप्रासंगिक टुकड़े जवाब को कमज़ोर करने लगते हैं।
एक ठोस (grounded) जवाब जनरेट करें
रिट्रीव किए गए टुकड़ों को मॉडल को क्रमांकित संदर्भ के रूप में दें और उसे निर्देश दें कि सिर्फ वहीं से जवाब दे और अपने स्रोतों का हवाला दे - यही चीज़ जवाब को मॉडल के अपने सामान्य ज्ञान की बजाय किसी असली वीडियो तक ट्रेस करने लायक बनाए रखती है:
async function answer(query: string) {
const matches = await retrieve(query);
const context = matches
.map((m, i) => `[${i + 1}] From "${m.title}":\n${m.text}`)
.join('\n\n');
const completion = await openai.chat.completions.create({
model: 'gpt-4.1-mini',
messages: [
{
role: 'system',
content:
"Answer only using the numbered transcript excerpts below. Cite sources as [1], [2], etc. " +
"If the excerpts don't contain the answer, say so.",
},
{ role: 'user', content: `${context}\n\nQuestion: ${query}` },
],
});
return completion.choices[0].message.content;
}कोई timestamp गढ़ने की बजाय वीडियो के title से हवाला देना उससे मेल खाता है जो transcript API असल में लौटाती है - मॉडल को कभी ऐसा timestamp मत बनाने दें जो उसे दिया ही नहीं गया।
इंडेक्स को ताज़ा रखें
किसी ऐसे चैनल के लिए जो लगातार पब्लिश करता रहता है, मुफ़्त /channel/latest endpoint (0 क्रेडिट) से समय-समय पर नए अपलोड चेक करें, जिन video id को पहले ही इंडेक्स कर चुके हैं उन्हें छोड़ दें, और सिर्फ नए वाले लाएं, बांटें, और एम्बेड करें। इससे इनजेशन की लागत हर बार पूरा दोबारा इंडेक्स करने की बजाय सिर्फ नई सामग्री के अनुपात में रहती है।
ट्रांसक्रिप्ट RAG के लिए अच्छे क्यों काम करते हैं
वीडियो उन फ़ॉर्मैट में से एक है जिन पर रिट्रीवल बनाना सबसे मुश्किल है - आप किसी वीडियो पर grep नहीं कर सकते। एक ट्रांसक्रिप्ट उसे वापस टेक्स्ट में बदल देती है, जिसे आपका मौजूदा embedding और retrieval स्टैक पहले से संभालना जानता है, बिना अपना खुद का speech-to-text काम चलाए। और चूंकि per-request चार्ज करने वाली API वीडियो की लंबाई के हिसाब से मीटर नहीं करती, long-form सामग्री (podcasts, lectures, कई घंटों के streams) का बैकलॉग इनजेस्ट करना छोटे क्लिप्स इनजेस्ट करने से व्यवस्थित रूप से महंगा नहीं होता - जो कि बिल्कुल वही तरह का संग्रह है जिसके लिए आमतौर पर एक RAG pipeline बनाई जाती है।
पूरा endpoint reference, authentication, और rate limits API docs में हैं। इसे शुरू से आखिर तक आज़माने के लिए 100 मुफ़्त क्रेडिट के साथ डैशबोर्ड से एक key लें।
RAG pipeline से जुड़े सवाल
क्या इसे फ़ॉलो करने के लिए एक असली vector database चाहिए?
नहीं - इस गाइड का in-memory array कुछ सौ टुकड़ों तक ठीक काम करता है और पूरे pipeline को शुरू से आखिर तक वेरिफ़ाई करने का सबसे तेज़ तरीका है। जब उससे ज़्यादा इंडेक्स करने लगें, या इंडेक्स को रीस्टार्ट के बीच बनाए रखना हो, तब pgvector या किसी managed vector store पर शिफ़्ट करें।
मुझे कौन सा embedding मॉडल इस्तेमाल करना चाहिए?
text-embedding-3-small एक ठीक-ठाक डिफ़ॉल्ट है - सस्ता और ज़्यादातर ट्रांसक्रिप्ट रिट्रीवल के लिए काफी अच्छा। text-embedding-3-large पर तभी जाएं जब रिट्रीवल क्वालिटी में ऐसी दिक्कतें दिखें जिन्हें यह वाकई ठीक कर सके; यह हर कॉल पर ज़्यादा महंगा है।
अगर किसी वीडियो का कोई ट्रांसक्रिप्ट ही न हो तो क्या होता है?
ट्रांसक्रिप्ट endpoint खाली स्ट्रिंग की बजाय एक स्पष्ट एरर कोड लौटाता है (TRANSCRIPT_DISABLED या TRANSCRIPT_NOT_FOUND) - success: false चेक करें और उस वीडियो को छोड़ दें, बजाय इसके कि खाली स्ट्रिंग को असली कॉन्टेंट मानकर एम्बेड कर दें।
मान लीजिए 200 वीडियो इंडेक्स करने में कितना खर्च आता है?
ट्रांसक्रिप्ट लाने के लिए 200 क्रेडिट, चाहे वे 2 मिनट के क्लिप हों या 2 घंटे के वीडियो - साइनअप के 100 मुफ़्त क्रेडिट अकेले ही 200 वीडियो के बैकलॉग का लगभग आधा हिस्सा कवर कर देते हैं। एम्बेडिंग की लागत अलग है और आपका embedding प्रोवाइडर उसे बिल करता है।
क्या मैं सिर्फ वीडियो के title की बजाय exact timestamp का हवाला दे सकता हूं?
इस endpoint के साथ नहीं - सार्वजनिक transcript API प्लेन टेक्स्ट लौटाती है, timestamped segments नहीं, इसलिए इस गाइड के उदाहरण वीडियो के title और id से हवाला देते हैं। अगर आपके इस्तेमाल के लिए timestamp-level हवाला ज़रूरी है, तो chunk का आकार चुनते वक्त इसका ध्यान रखें: छोटे टुकड़े वीडियो-लेवल हवाले को जितना हो सके उतना सटीक बनाते हैं।
संबंधित
- YouTube API Quota Exceeded: Causes and Fixes
- YouTube Transcript API Rate Limit: What It Is and How to Handle 429s
- YouTube Transcript MCP Server: Setup Guide for Claude and Other AI Tools
- YouTube Transcripts in n8n: HTTP Request Workflow Guide
- Migrating from Supadata: A Field Guide
- How to Get YouTube Transcripts in Python
- Migrating from TranscriptAPI.com: A Field Guide
- Build an AI YouTube Video Summarizer with LangChain and Next.js
- The Best YouTube Transcript APIs in 2026
- GetYouTubeTranscript बनाम TranscriptAPI
- GetYouTubeTranscript बनाम youtubetotranscript.com
- GetYouTubeTranscript बनाम youtube-transcript.io
- GetYouTubeTranscript बनाम NoteGPT