Skip to content

Latest commit

 

History

2 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 

Repository files navigation

yt_sumarios

Pequena ferramenta de linha de comando que baixa legendas automáticas em português de vídeos do YouTube, transforma-as em texto corrido legível, detecta o formato do vídeo (filme / entrevista / outro) e prepara um sumário — usando um LLM (qualquer endpoint compatível com a API da OpenAI) ou, na falta de credenciais, um template para preenchimento manual.

Pensado para apoiar trabalho de sala de aula, pesquisa e arquivamento de conteúdo audiovisual: a partir de uma URL, o usuário obtém uma transcrição limpa em prosa e um sumário (automático ou template) estruturado conforme o formato detectado.

Idiomas de legenda configuráveis (pt por padrão). O texto de saída acompanha o idioma da legenda.

O que cada estágio faz

O pipeline tem quatro estágios independentes — cada um pode ser executado isoladamente e re-aproveita artefatos já baixados.

Estágio Entrada Saída Descrição
download URL do YouTube output/<ID>.<lang>.vtt Baixa apenas as legendas (automáticas ou manuais, sem o vídeo), via yt-dlp. Se nenhuma legenda existir no idioma pedido, cai para o fallback de transcrição local de áudio (ver abaixo).
clean .vtt output/<ID>.<lang>.txt Limpa marcações VTT, remove duplicatas de rolagem, une linhas curtas em parágrafos legíveis.
detect metadados do vídeo rótulo filme / entrevista / outro Heurística por palavras-chave em título e descrição, com regra especial para transmissões ao vivo.
summarise metadados + formato + texto output/<ID>.<lang>.summary.md Se um endpoint LLM compatível com OpenAI estiver configurado, gera o sumário final via API; caso contrário, emite um template com placeholders para preenchimento manual.

ℹ️ Sobre o estágio summarise: quando o LLM está configurado (OPENAI_BASE_URL + OPENAI_API_KEY, ou as flags --llm-base-url/--llm-api-key), o sumário é produzido automaticamente. Sem credenciais, o estágio emite um template com marcadores a preencher. As regras de conteúdo por formato estão descritas abaixo.

Regras de conteúdo por formato

  • Entrevista: resumo dos principais pontos levantados, com contexto dos entrevistados e do meio de comunicação (canal do vídeo).
  • Filme: busca externa de sinopses e críticas; levantamento de pontos para uso em sala de aula e de fragilidades/críticas a pontos fracos.
  • Outro: sem template específico; revisão manual.

Requisitos

  • Python 3.10+ (usa list[str], Path | None, from __future__ import annotations).
  • yt-dlp — recomendada a versão mais recente (via pip/conda). Versões antigas, como a empacotada em algumas distribuições Linux, falham em vídeos atuais do YouTube com erros do tipo Requested format is not available ou Did not get any data blocks, causados pelo novo streaming SABR e pela flag xpe do timedtext.
  • Navegador com sessão ativa no YouTube (opcional, mas necessário para muitos vídeos). O padrão é ler cookies do Chrome (--cookies-from-browser chrome); Firefox também funciona.
  • ffmpeg e um backend Whisper — apenas para o fallback de transcrição local (opcional): whisper-cli (whisper.cpp) ou o CLI do openai-whisper. Sem eles, vídeos sem legenda apenas geram um aviso.

Versões antigas do yt-dlp (como as empacotadas em algumas distribuições Linux via apt) falham em vídeos atuais do YouTube com erros do tipo Requested format is not available ou Did not get any data blocks, causados pelo novo streaming SABR e pela flag xpe do timedtext. Por isso, prefira instalar a versão mais recente por um gerenciador atualizado:

# Via pip (qualquer ambiente)
pip install -U yt-dlp

# Via conda
conda install -c conda-forge yt-dlp

LLM para o estágio summarise (opcional)

O estágio summarise produz o sumário automaticamente se houver um endpoint LLM compatível com a API Chat Completions da OpenAI configurado. Funciona com a própria OpenAI, com serviços autodomesticáveis (Ollama, vLLM, LM Studio), com provedores nacionais/regionais e com qualquer gateway que fale esse protocolo. Sem credenciais, cai graciosamente num template para preenchimento manual.

A configuração pode ser feita por variáveis de ambiente (recomendado) ou por flags na linha de comando:

Item Variável de ambiente Flag CLI Padrão
URL-base da API OPENAI_BASE_URL --llm-base-url vazio (ex.: https://api.openai.com/v1)
Chave de API OPENAI_API_KEY --llm-api-key vazio
Modelo OPENAI_MODEL --llm-model gpt-4o-mini
Máx. de tokens da resposta OPENAI_MAX_TOKENS --llm-max-tokens 2000
Timeout (s) OPENAI_TIMEOUT --llm-timeout 180

Exemplos:

# OpenAI oficial
export OPENAI_API_KEY="sk-..."
python3 yt_sumarios.py "<url>" --stage summarise

# Provedor compatível qualquer
export OPENAI_BASE_URL="https://llm.exemplo.com/v1"
export OPENAI_API_KEY="..."
export OPENAI_MODEL="meu-modelo"
python3 yt_sumarios.py "<url>"

# Tudo via flags (sem alterar o ambiente)
python3 yt_sumarios.py "<url>" --stage summarise \
  --llm-base-url "https://llm.exemplo.com/v1" \
  --llm-api-key "..." \
  --llm-model "meu-modelo"

A implementação usa apenas a stdlib (urllib.request), sem nenhuma dependência adicional. As instruções enviadas ao modelo variam conforme o formato detectado (entrevista/filme/outro), conforme as regras abaixo. Se a chamada ao LLM falhar (rede, auth, contexto excedido), o estágio avisa no stderr e grava o template.

⚠️ Vídeos longos: um vídeo de ~107 min gera ~90 KB de transcrição. Verifique se o modelo escolhido tem janela de contexto suficiente, ou use um modelo de contexto longo.

Fallback: transcrição local de áudio (sem legendas)

Quando o vídeo não tem legenda alguma no idioma pedido, o estágio download emite um aviso (não um erro) e, se um backend de transcrição estiver disponível, baixa apenas o áudio (bestaudio, sem vídeo) e transcreve localmente com Whisper. O resultado é gravado como output/<ID>.whisper.txt e segue direto para o estágio summarise (não passa pelo clean, que é específico de VTT).

O backend é detectado automaticamente: prefere whisper-cli/whisper-cpp (whisper.cpp) e, na ausência deste, usa o CLI whisper do pacote openai-whisper. Ambos são invocados como binários externos via subprocess, como o yt-dlp — o projeto continua sem dependências Python.

Item Variável de ambiente Flag CLI Padrão
Binário do Whisper WHISPER_BIN --whisper-bin auto-detetado
Modelo WHISPER_MODEL --whisper-model large-v3-turbo (CUDA) / small (CPU)
Dispositivo WHISPER_DEVICE --whisper-device auto
Desativar fallback --no-whisper fallback ativo

Sobre o modelo padrão: large-v3-turbo (809M parâmetros, ~3 GB de VRAM em fp16) é o maior modelo que cabe com folga numa GPU NVIDIA de 4 GB — o medium da mesma família precisa de ~5 GB e estoura. Em CPU, o padrão cai para small (244M), o teto razoável para transcrição em tempo aceitável. Para pinar um modelo fixo:

# Sempre usar turbo (baixa sozinho na primeira execução, se necessário)
export WHISPER_MODEL=large-v3-turbo

# Ou via flag
python3 yt_sumarios.py "<url>" --whisper-model small

# Desligar o fallback por completo
python3 yt_sumarios.py "<url>" --no-whisper

Uso

Pipeline completo

python3 yt_sumarios.py "https://www.youtube.com/watch?v=<ID>"

Executa os quatro estágios em sequência e grava os três artefatos em output/.

Estágios individuais (idempotentes)

python3 yt_sumarios.py "<url>" --stage download   # só baixa a legenda
python3 yt_sumarios.py "<url>" --stage clean       # limpa o .vtt existente
python3 yt_sumarios.py "<url>" --stage detect      # só classifica o formato
python3 yt_sumarios.py "<url>" --stage summarise   # gera o sumário (LLM) ou template .md

Outras opções

# Mudar o idioma da legenda (default: pt)
python3 yt_sumarios.py "<url>" --lang en

# Mudar o diretório de saída (default: output/)
python3 yt_sumarios.py "<url>" --work /tmp/yt

Limpeza autônoma de VTT

O módulo clean_subtitle.py também roda sozinho sobre qualquer arquivo .vtt:

python3 clean_subtitle.py entrada.vtt -o saida.txt

Arquitetura

yt_sumarios.py      # Orquestrador com 4 estágios, cada um executável isoladamente
└── clean_subtitle.py   # Limpeza pura de VTT -> texto corrido (importado pelo orquestrador)
output/              # Artefatos por vídeo: <ID>.<lang>.vtt, .<lang>.txt, .<lang>.summary.md

Fluxo de dados

  1. fetch_metadata(url)VideoInfo (título, canal, duração, categorias, descrição, idiomas de legenda disponíveis)
  2. download_subs(url)output/<ID>.<lang>.vtt — tenta o cliente padrão do yt-dlp e, se necessário, o cliente embutido (web_embedded), que serve legendas automáticas bloqueadas por PO token; sem legendas no idioma, retorna aviso
  3. transcribe_audio(url) (fallback)output/<ID>.whisper.txt quando não há legendas
  4. clean_vtt_file(vtt)output/<ID>.<lang>.txt (prosa corrida, parágrafos por minuto)
  5. detect_format(info)"filme" | "entrevista" | "outro"
  6. summarise(info, fmt, txt)output/<ID>.<lang>.summary.md (sumário via LLM, se configurado; caso contrário, template)

Limpeza de VTT (clean_subtitle.py)

Legendas automáticas do YouTube vêm com:

  • marcações de karaokê (<c>...</c>, timestamps inline);
  • linhas duplicadas a cada rolagem (scroll-in: cada cue repete a linha anterior e acrescenta conteúdo novo);
  • marcadores de mudança de locutor (&gt;&gt;, >>).

O limpador, em ordem: remove marcações, converte linhas de timestamp HH:MM:SS.mmm --> ... em marcadores HH:MM, descarta o cabeçalho VTT, remove duplicatas atravessando fronteiras de timestamp e une parágrafos curtos em blocos legíveis (~320 caracteres), preferindo pontos de fim de frase.

Saídas

Para cada vídeo, em output/:

Arquivo Conteúdo
<ID>.<lang>.vtt Legenda original baixada.
<ID>.<lang>.txt Transcrição limpa em prosa corrida (produto principal).
<ID>.whisper.txt Transcrição local via Whisper (fallback, quando não há legendas).
<ID>.<lang>.summary.md Sumário (via LLM, se configurado) ou template estruturado pelo formato detectado.

Detalhes e armadilhas

  • Chrome fechado: em alguns sistemas o --cookies-from-browser chrome precisa que o Chrome esteja fechado (o yt-dlp lê o banco SQLite de cookies). Se falhar, tente firefox — perfis do Firefox também funcionam.
  • Legendas bloqueadas por PO token: alguns vídeos anunciam legendas automáticas no idioma pedido, mas o YouTube recusa entregá-las ao cliente padrão (aviso missing subtitles languages because a PO token was not provided). O pipeline tenta automaticamente o cliente web_embedded, que costuma contornar a restrição; se mesmo assim não houver legenda, entra o fallback de transcrição local.
  • Qualidade das legendas automáticas: legendas kind=asr (reconhecimento de fala) têm qualidade variável; espere erros de transcrição (nomes próprios, siglas). O limpador não faz correção ortográfica. A transcrição via Whisper tende a ser mais precisa que as legendas asr, a custo de tempo de processamento.
  • Vídeos longos: um vídeo de ~107 min gera ~90 KB de .txt. Para sumarização por LLM considere chunking ou um modelo de contexto longo. No fallback de transcrição, o áudio baixado e o WAV 16 kHz intermediário são apagados ao final; reste só o .txt.
  • Detecção de formato: heurística por palavras-chave (listas FILME_KEYWORDS, ENTREVISTA_KEYWORDS no topo de yt_sumarios.py). Transmissões ao vivo nunca são classificadas como filme. Para melhorar a detecção, estenda as listas em vez de adicionar checagens inline.

Licença

Distribuído sob a licença MIT. Veja o arquivo LICENSE.

A única dependência externa em runtime é o yt-dlp, que é Unlicense (domínio público) e é invocado via subprocess — portanto sem acoplamento de licença. Todo o código do projeto usa apenas a biblioteca padrão do Python (licença PSF).

About

CLI que baixa legendas automáticas do YouTube, limpa em texto corrido, detecta o formato (filme/entrevista/outro) e sumariza via LLM OpenAI-compatível. Zero dependências Python além da stdlib.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages