Voltar ao blogIntegrações

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

Resposta rápida

Busque a transcrição via uma API hospedada, divida-a em blocos com o text splitter do LangChain, resuma cada bloco e depois combine os resumos em um resumo final - o mesmo padrão map-reduce que continua funcionando em um vídeo de 3 horas, não só um de 5 minutos.
01

Instale o LangChain

Este tutorial usa a divisão atual de pacotes do LangChain JS - as primitivas principais, a integração com a OpenAI e os text splitters vivem cada um em seu próprio pacote:

npm install langchain @langchain/core @langchain/openai @langchain/textsplitters
02

Busque a transcrição

Consiga uma chave no painel (100 créditos grátis, sem cartão), depois chame o endpoint de transcrição a partir de um route handler do 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 é a transcrição completa em texto puro e word_count é o seu tamanho - útil para decidir se você pode pular totalmente a etapa de divisão em um vídeo curto.

03

Divida a transcrição em blocos

Uma transcrição longa pode facilmente ultrapassar o que é confortável enviar a um LLM em um único prompt, então divida-a primeiro. O RecursiveCharacterTextSplitter tenta cortar por parágrafo, depois por frase, depois por palavra, nessa ordem, para que os blocos continuem legíveis em vez de cortar no meio de uma frase:

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 mantém um pouco de contexto do final de um bloco no início do próximo, para que uma frase dividida na fronteira não se perca em nenhum dos dois.

04

Resuma cada bloco

ChatPromptTemplate + um modelo + StringOutputParser encadeados (a linguagem de expressão do LangChain, LCEL) é a forma atual e estável de construir uma cadeia - cada bloco recebe seu próprio resumo curto em paralelo:

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 }))
);

Rodar isso em paralelo com Promise.all importa para a latência: uma transcrição de 10 blocos resumida um por um leva 10 vezes mais tempo do que resumir os 10 de uma vez.

05

Combine os resumos dos blocos em um só

Os resumos dos blocos agora são curtos o suficiente para caber juntos em um único prompt, então uma segunda cadeia os combina no resultado final:

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 });

Essa estrutura de duas passagens (resumir os blocos, depois resumir os resumos) é o que o próprio padrão map-reduce do LangChain faz por baixo dos panos - escrito aqui explicitamente em vez de usar uma chain auxiliar legada, já que as APIs de chains de resumo mudaram entre versões do LangChain e as primitivas LCEL simples são uma base mais estável para construir em cima.

06

Por que buscar a transcrição de uma API em vez de fazer scraping você mesmo

A etapa de buscar a transcrição acima é a única parte deste pipeline que fica genuinamente mais difícil em produção - bibliotecas de scraping autohospedadas costumam ser bloqueadas assim que implantadas em um servidor na nuvem. Uma API de Transcrições do YouTube hospedada é construída especificamente para manter essa etapa funcionando, para que o resto deste pipeline não precise se preocupar com isso.

A referência completa de endpoints, autenticação e limites de taxa está na documentação da API. Consiga uma chave com 100 créditos grátis no painel para testar isso de ponta a ponta.

Perguntas frequentes do resumidor com LangChain

Q01

Também preciso dividir vídeos curtos em blocos?

Não necessariamente - primeiro verifique o word_count na resposta da transcrição. A transcrição de um vídeo de 10 minutos geralmente fica bem abaixo do que um único prompt de LLM moderno aguenta, então você pode ir direto para uma única chamada de resumo e pular totalmente as etapas de divisão/combinação.

Q02

Por que RecursiveCharacterTextSplitter em vez de um corte fixo por caracteres?

Um corte fixo corta onde a contagem de caracteres cair, possivelmente no meio de uma frase ou palavra. O RecursiveCharacterTextSplitter tenta primeiro quebras de parágrafo, depois frases, depois palavras, só recorrendo a um corte bruto se não tiver escolha - assim os blocos continuam coerentes para o modelo resumir.

Q03

Posso usar um provedor de LLM diferente da OpenAI?

Sim - as classes de chat model do LangChain compartilham a mesma interface, então trocar o ChatOpenAI pela integração LangChain de outro provedor (Anthropic, Google, etc.) não muda mais nada no pipeline.

Q04

Por que encadear um prompt, um modelo e um output parser em vez de usar LLMChain?

LLMChain é a API mais antiga do LangChain para construir chains. O estilo encadeado/LCEL (prompt.pipe(model).pipe(parser)) é o padrão atualmente recomendado - ele compõe de forma mais previsível e é o que a documentação mais recente do LangChain usa como base.

Q05

Quanto custa rodar isso?

Dois custos: as chamadas ao LLM (uma por bloco, mais uma para combinar - cobradas pelo seu provedor de modelo), e 1 crédito por busca de transcrição na API. 100 créditos grátis cobrem o lado da busca enquanto você testa.

Q06

O que acontece se o vídeo não tiver nenhuma transcrição?

O endpoint de transcrição retorna um código de erro claro (TRANSCRIPT_DISABLED ou TRANSCRIPT_NOT_FOUND) em vez de uma string vazia - verifique success: false antes de passar qualquer coisa para o text splitter, já que resumir uma transcrição vazia desperdiça uma chamada ao LLM à toa.

Relacionados