Build an AI YouTube Video Summarizer with LangChain and Next.js
A working YouTube summarizer built with LangChain and Next.js: fetch the transcript, chunk it with a text splitter, summarize each chunk, then combine the results into one final summary - full code for every step.
00:08:00 · SEP 26, 2026
Краткий ответ
Установите LangChain
В этом руководстве используется текущее разделение пакетов LangChain JS - базовые примитивы, интеграция с OpenAI и text splitter'ы живут каждый в своём собственном пакете:
npm install langchain @langchain/core @langchain/openai @langchain/textsplittersПолучите расшифровку
Получите ключ в панели управления (100 бесплатных кредитов, без карты), затем вызовите эндпоинт расшифровки из route handler в Next.js:
// app/api/summarize/route.ts
import { NextResponse } from 'next/server';
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);
// json.data.transcript is the full plain-text transcript,
// json.data.word_count is its length in words.
return json.data as { transcript: string; word_count: number; title: string };
}transcript - это полная расшифровка в виде обычного текста, а word_count - её длина в словах, что полезно, чтобы решить, можно ли вообще пропустить этап разбиения на части для короткого видео.
Разбейте расшифровку на части
Длинная расшифровка легко может превысить объём, который комфортно отправить в LLM за один промпт, поэтому сначала разбейте её. RecursiveCharacterTextSplitter пытается разбивать сначала по абзацам, затем по предложениям, затем по словам, именно в этом порядке, чтобы части оставались читаемыми, а не обрывались посреди предложения:
import { RecursiveCharacterTextSplitter } from '@langchain/textsplitters';
const splitter = new RecursiveCharacterTextSplitter({
chunkSize: 4000,
chunkOverlap: 200,
});
const chunks = await splitter.splitText(transcript);
// A 20-minute video is usually 1-2 chunks; a 2-hour one might be 8-10.chunkOverlap сохраняет немного контекста из конца одной части в начале следующей, чтобы предложение, разделённое на границе, не терялось ни в одной из частей.
Суммируйте каждую часть
ChatPromptTemplate + модель + StringOutputParser, соединённые через pipe (язык выражений LangChain, LCEL) - это текущий, стабильный способ построения цепочки: каждая часть параллельно получает своё короткое краткое содержание:
import { ChatOpenAI } from '@langchain/openai';
import { ChatPromptTemplate } from '@langchain/core/prompts';
import { StringOutputParser } from '@langchain/core/output_parsers';
const model = new ChatOpenAI({ model: 'gpt-4.1-mini', temperature: 0 });
const chunkPrompt = ChatPromptTemplate.fromTemplate(
'Summarize this part of a video transcript in 3-4 sentences, keeping any concrete facts, numbers, or names:\n\n{chunk}'
);
const chunkChain = chunkPrompt.pipe(model).pipe(new StringOutputParser());
const chunkSummaries = await Promise.all(
chunks.map((chunk) => chunkChain.invoke({ chunk }))
);Запуск их параллельно через Promise.all важен для задержки: расшифровка из 10 частей, суммируемая по одной, займёт в 10 раз больше времени, чем суммирование всех 10 одновременно.
Объедините краткие содержания частей в одно
Краткие содержания частей теперь достаточно коротки, чтобы поместиться вместе в один промпт, поэтому вторая цепочка объединяет их в итоговый результат:
const finalPrompt = ChatPromptTemplate.fromTemplate(
'These are summaries of consecutive parts of the same video transcript, titled "{title}".\n' +
'Combine them into one coherent summary (a short paragraph, then 3-5 key takeaways as bullet points):\n\n{summaries}'
);
const finalChain = finalPrompt.pipe(model).pipe(new StringOutputParser());
const summary = await finalChain.invoke({
title,
summaries: chunkSummaries.join('\n\n'),
});
return NextResponse.json({ summary });Эта двухэтапная структура (сначала суммировать части, затем суммировать краткие содержания) - именно то, что делает под капотом собственная схема map-reduce в LangChain - здесь она написана явно вместо использования устаревшей вспомогательной цепочки, поскольку API вспомогательных цепочек суммирования менялись между версиями LangChain, а простые примитивы LCEL - более стабильная основа для построения.
Почему получать расшифровку через API, а не парсить самостоятельно
Описанный выше шаг получения расшифровки - единственная часть этого пайплайна, которая по-настоящему усложняется в продакшене - самостоятельно размещённые библиотеки парсинга часто блокируются сразу после развёртывания на облачном сервере. Размещённый API расшифровок YouTube создан специально для того, чтобы этот шаг продолжал работать, и остальной части пайплайна не нужно об этом беспокоиться.
Полный справочник по эндпоинтам, аутентификации и лимитам запросов есть в документации API. Получите ключ с 100 бесплатными кредитами в панели управления, чтобы протестировать всё от начала до конца.
Частые вопросы о суммаризаторе на LangChain
Нужно ли разбивать на части и короткие видео?
Не обязательно - сначала проверьте word_count в ответе с расшифровкой. Расшифровка 10-минутного видео обычно значительно меньше того, что помещается в один промпт современной LLM, так что можно сразу перейти к одному вызову суммирования и полностью пропустить этапы разбиения/объединения.
Почему RecursiveCharacterTextSplitter, а не разбиение по фиксированному числу символов?
Фиксированное разбиение режет там, где попадёт счётчик символов, возможно, посреди предложения или слова. RecursiveCharacterTextSplitter сначала пробует разрывы по абзацам, затем по предложениям, затем по словам, прибегая к жёсткому разрезу только в крайнем случае - так части остаются связными для суммирования моделью.
Могу ли я использовать другого поставщика LLM вместо OpenAI?
Да - классы чат-моделей LangChain используют один и тот же интерфейс, так что замена ChatOpenAI на интеграцию LangChain другого поставщика (Anthropic, Google и т.д.) не меняет ничего другого в пайплайне.
Почему соединять промпт, модель и парсер вывода через pipe, а не использовать LLMChain?
LLMChain - это более старый API построения цепочек в LangChain. Стиль pipe/LCEL (prompt.pipe(model).pipe(parser)) - это текущий рекомендуемый шаблон: он собирается более предсказуемо, и именно на нём построена более новая документация LangChain.
Сколько стоит это запустить?
Есть две статьи расходов: вызовы LLM (один на часть, плюс один на объединение - оплачивается вашим поставщиком модели) и 1 кредит за каждое получение расшифровки через API. 100 бесплатных кредитов покрывают сторону получения данных во время тестирования.
Что произойдёт, если у видео вообще нет расшифровки?
Эндпоинт расшифровки возвращает понятный код ошибки (TRANSCRIPT_DISABLED или TRANSCRIPT_NOT_FOUND) вместо пустой строки - проверяйте success: false, прежде чем передавать что-либо в text splitter, поскольку суммирование пустой расшифровки впустую тратит вызов LLM.
Похожие материалы
- 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
- GetYouTubeTranscript против TranscriptAPI
- GetYouTubeTranscript против youtubetotranscript.com
- GetYouTubeTranscript против youtube-transcript.io
- GetYouTubeTranscript против NoteGPT