Gerador de Vídeos Educacionais
Documento → mapa de escopo → plano → roteiro → teste de escopo → storyboard → narração → vídeo → verificação → entrega. Sem necessidade de GPU ou API paga. Código: https://github.com/alpay-web/egitim-videosu
0. Preparação
Versão: cat $R/VERSION (mudanças em CHANGELOG.md). A cada push, o job Test (testes unitários + vídeo curto)
é executado; se estiver vermelho, corrija-o primeiro. Erros de roteiro (tipo incorreto, estouro de goster, cevap_cumle fora do escopo) são capturados antes da renderização em cada comando.
Ao fazer uma melhoria permanente no pacote: atualize VERSION e CHANGELOG.md, faça push, execute o job surum.yml.
[ -d /tmp/egitim-videosu ] || git clone --depth 1 https://github.com/alpay-web/egitim-videosu /tmp/egitim-videosu
R=/tmp/egitim-videosu
pip install -q -r $R/requirements.txt 2>/dev/null || pip install -q --break-system-packages -r $R/requirements.txt
1. Entender o documento → mapa de escopo
python $R/scripts/belge_oku.py belge.pdf -o belge.md # PDF/Word/PowerPoint/Excel/HTML/EPUB → belge.md + belge_harita.md
Ordem de leitura: markitdown (MIT) → pandoc → pdftotext. belge_harita.md fornece a contagem de palavras, número de tabelas e sugestão de cena para cada título; alerta sobre PDFs escaneados (pouco texto por página) — nesse caso, solicite OCR, não invente.
Claude Doc / link de artefato: leia com ferramentas de docs, salve o texto como .md e execute o mesmo comando.
Cada linha no mapa deve ser mapeada para uma cena ou anotada como "deixado de fora: motivo".
Velocidade de fala ≈ 130 palavras/min; duração estimada de narração = palavras de conteúdo ÷ 130 × 0,6 (margem de sumarização).
2. Plano e aprovação (antes de etapas caras)
- Padrão: DOCUMENTO INTEIRO EM UM ÚNICO VÍDEO (o usuário prefere isso). Pode ter 30–40 min em documento longo; navega-se com carimbos de data/hora (capítulos) do YouTube. Ordem: gancho + roteiro → estratégia → aulas de tópicos (cada aula: cena de regra + pergunta "Teste-se") → vocabulário → exemplos de leitura/audição/fala → simulado → encerramento. Nem todos os exercícios são lidos; selecione 1–2 perguntas representativas de cada bloco, para os demais diga "exercícios no guia".
- Série (vídeos de 5–8 min) apenas se o usuário solicitar. Narrações anteriores são automaticamente reutilizadas (veja "Cache de áudio" abaixo).
- Apresente um breve plano ao usuário (seções, duração estimada, tipos de cena) e mostre que nenhum título foi omitido silenciosamente. Não prossiga para a narração sem aprovação (se o usuário disser "continue", prossiga diretamente).
3. Escrever roteiro → senaryo.json (exemplo: $R/ornek/senaryo_b1.json)
Arte do roteiro (obrigatório):
- Abrir com gancho (primeiros 5 seg): um fato surpreendente, risco ou pergunta; adicione
"kanca": "frase curta impactante"à primeira cena — ela será exibida em letras grandes no quadro até o primeiro item (o quadro nunca fica vazio). Aberturas PROIBIDAS: "Olá, neste vídeo…", "Hoje aprenderemos…". Gancho → por que é importante → roteiro. - Estrutura: gancho → configuração (por que se importar) → desenvolvimento → clímax (momento "ahá") → encerramento (resumo de uma frase + chamada para ação). Transição entre cenas não é "e depois", mas "por isso / mas".
- Orçamento de palavras: ~130 palavras/min; 50–110 palavras por cena. Frases curtas, tratamento "você", linguagem falada.
- Evento visual a cada 8–10 seg: novo item/linha/cartão/passo ou pergunta.
- Performance de voz: adicione
"ton"à cena:"merakli"(introdução),"canli"(tática),"ciddi"(aviso),"sakin"(encerramento). Após uma frase importante, coloque[dur](0,9 seg de silêncio). Frases interrogativas/exclamativas duram naturalmente mais. - Fidelidade: apenas informações do documento; não invente números/regras.
Tipos de cena — escolha de acordo com a forma do conteúdo (não use o mesmo tipo 3 vezes seguidas):
{"baslik": "...", "maddeler": ["≤40 caracteres", "..."], "anlatim": "...", "goster": [0, 2, 3]}
{"baslik": "...", "tur": "tablo", "tablo": {"basliklar": ["Se vir", "Resposta"], "satirlar": [["since", "have + V3"]], "stil": "yanlis-dogru"}}
{"baslik": "...", "tur": "rakam", "kartlar": [{"deger": "30", "birim": "minutos", "etiket": "Duração da prova"}]}
{"baslik": "...", "tur": "karsilastirma", "sol": {"baslik": "Na audição", "renk": "mavi"}, "sag": {"baslik": "Na leitura", "renk": "yesil"}, "satirlar": [["esquerda", "direita"]]}
{"baslik": "...", "tur": "zaman", "adimlar": [{"baslik": "Dia 1", "metin": "Gramática"}]}
{"baslik": "...", "tur": "ipucu", "ipucu": {"tip": "ipucu|uyari|not", "metin": "Mensagem forte única"}}
{"baslik": "Teste-se 1/3", "tur": "soru", "soru": {"metin": "Sim, ___.", "secenekler": ["Estou", "Eu sou", "Eu faço"], "dogru": 1, "cevap_cumle": 2, "bekle": 4}}
- maddeler: lista/resumo. tablo: tabelas do documento, "se vir → resposta", listas de errado/certo.
rakam: 1–3 números impressionantes (duração, pontuação, quantidade). karsilastirma: dois lados (primeiro coluna esquerda, depois direita abre;
goster= linhas esquerda + linhas direita, respectivamente). zaman: passos/plano/processo (vertical em ≥4 passos). ipucu: mensagem única impactante. soru: de exercícios; LEIA EM VOZ ALTA a pergunta e as opções ("{O museu} lacuna {em 1890}. Opções: A, {construído}; B, {foi construído}; C, {tem construído}."),cevap_cumle= índice da frase "Resposta correta…"; antes, contagem regressiva, depois opção correta em verde + "ding". - TUDO QUE ESTÁ NA TELA É LIDO (obrigatório): ambas as colunas da tabela, ambos os lados da comparação, o rótulo do cartão numérico, a pergunta e as opções devem estar na narração. Reserve uma frase separada para cada item (ritmo de itens). Se
--kontrolder aviso "não lido", corrija a narração. Escrita degoster: o vídeo abre cada item na frase em que ele é lido, na palavra que está sendo dita (oto_goster); há pelo menos 1,2 seg entre dois itens consecutivos. - Inglês entre
{chaves}(obrigatório): "{had better}", "{I'm late, aren't I?}". Dentro das chaves, o Chatterbox gera em inglês (en), fora em turco; mesma voz de referência, níveis igualados (Chatterbox não pode alternar idiomas em uma única chamada: resemble-ai/chatterbox#346). Não coloque sufixo turco em palavra inglesa (não "{had better}'dan", sim "{had better} kalıbından"). Para marcar automaticamente o rascunho, use--ingilizce-isaretle(wordfreq), depois revise: palavras turcas como "not", "on" podem ser marcadas incorretamente; adicione manualmente trechos curtos como "{at}", "{I am}". goster: em qual frase (a partir de 0) cada item será aberto; o ponteiro se move para o item naquele momento (se--tikfor fornecido, um leve som de clique). Sincronia de palavras (padrão): o item abre não no início da frase, mas quando a primeira palavra significativa do item é dita (se o tempo da palavra WhisperSS_CC.jsonexistir, exato; senão, com base na posição na frase). Âncora manual:"3:enough"(na palavra "enough" da 3ª frase) ou2.5(metade da 2ª frase). Desativar:--kelime-senkron-yok.- A tela vai à frente da voz (regra de vídeo explicativo): a fala não deve começar com o quadro vazio; não fique mais de 14 seg sem nada de novo no quadro. Se o primeiro item chegar tarde, o vídeo exibe a primeira frase em letras grandes como texto de abertura no quadro (forneça o texto com o campo
"giris"; desativar:--giris-yok). bolum: escreva"bolum": "Gramática 5: Passiva"na cena que inicia um capítulo. Aparece na parte inferior do quadro, uma linha de capítulo cai na barra de progresso e a lista de capítulos do YouTube é gerada automaticamente. Adicione tambémyoutube_baslik(≤100 caracteres) eetiketlerao roteiro.telaffuz: nomes de abreviaturas/níveis em letras turcas ("B1": "be bir", "C1": "se bir", "IELTS": "ay elts", "A": "a", "B": "be"). NÃO escreva pronúncia para palavras inglesas, use{…}.telaffuz_kok: {"fiil": "fiyil"}. Para palavras que o Chatterbox tem dificuldade, como "şık", escreva "seçenek" em vez disso.
4. Teste de escopo (ideia PresentQuiz)
A partir da fonte, extraia 8–10 perguntas críticas das seções cobertas pelo vídeo (baseadas apenas no documento). Marque uma a uma se a resposta está no roteiro. Se houver um tópico crítico sem resposta, adicione ao roteiro ou explique conscientemente na entrega por que foi omitido.
5. Storyboard + verificação (portão de aprovação)
python $R/scripts/video_uret.py senaryo.json --kontrol [--ses-dizini sesler] # relatório de uniformidade + LAYOUT + SINCRONIA
python $R/scripts/video_uret.py senaryo.json --storyboard storyboard.png # estado final de cada cena, imagem única
Relatórios de --kontrol: layout (texto estourado/cortado, fonte menor que 30 px, opção/cartão que não cabe) e sincronia (ar morto: fala começou mas quadro vazio; tela parada: 14 seg+ sem novo item). Execute novamente com durações reais após a geração de áudio, usando --ses-dizini. Não deixe avisos de layout.
Olhe o storyboard: estouro, sobreposição, quadro vazio, tipo errado. Corrija, mostre ao usuário, obtenha aprovação.
6. Narração (Chatterbox, MIT) — portão Whisper --kalite 3 verifica cada frase
A) GitHub Actions (rápido, paralelo; requer acesso de escrita ao repositório): faça commit do roteiro como senaryolar/<nome>.json, depois:
curl -X POST -H "Accept: application/vnd.github+json" -H "Content-Type: application/json" \
https://api.github.com/repos/alpay-web/egitim-videosu/actions/workflows/ses_uret.yml/dispatches \
-d '{"ref":"main","inputs":{"senaryo":"senaryolar/<nome>.json","etiket":"ses-<nome>","parcalar":"[\"1-3\",\"4-6\",\"7-9\",\"10-12\",\"13-15\"]"}}'
curl -fsSL -o sesler.zip https://github.com/alpay-web/egitim-videosu/releases/download/ses-<nome>/sesler.zip && unzip -q sesler.zip -d sesler
Cache de áudio (endereçado por conteúdo, ideia manim-voiceover): cada pasta de áudio mantém um dizin.json com mapeamento frase → resumo do texto. Adicionar/excluir/reordenar cenas não invalida áudios antigos; se o texto de uma frase mudar, o áudio antigo nunca é usado. Fluxo:
python $R/scripts/video_uret.py senaryo.json --eksik --ses-dizini antigo1,antigo2 # quais frases estão faltando? fornece partes + --cumleler
No workflow, forneça entrada "taban":"ses-b1-tam-kurs,ses-<nome>": se o mesmo texto existir nesses releases, ele é copiado; apenas frases novas/alteradas são sintetizadas. Na renderização, várias pastas podem ser fornecidas: --ses-dizini sesler,ses_antigos. Para rotular uma pasta antiga (sem dizin.json): --dizin-olustir KLASOR (se você tiver certeza de que a pasta pertence a este roteiro).
Rascunho: para verificar temporização/visual sem esperar pela narração, use --ses sessiz para gerar um vídeo de rascunho 720p.
B) Neste ambiente (lento, ~10 min/1 min de vídeo): python $R/scripts/video_uret.py senaryo.json --sadece-ses sesler --ses chatterbox --kalite 3
(execute em segundo plano). No kalite_raporu.txt, para frases com pontuação < 0,8, corrija a pronúncia e reproduza apenas elas com --cumleler 04_05,06_07.
7. Vídeo
python $R/scripts/video_uret.py senaryo.json -o video.mp4 --ses-dizini sesler # 1080p + video_kapak.jpg
Padrão: professor de desenho simples (no pódio), câmera lenta, ponteiro, "ding" apenas na resposta correta, sem música.
Áudio limpo (sem ruído de microfone/clique): clipes de frase se juntam com fade-in/out suave; a cadeia inclui adeclick, afftdn (redução de ruído leve) e deesser; o efeito de "clique" sobre a fala está desligado por padrão.
Ruído (solução geral, em camadas): (1) o job de narração limpa cada frase com DeepFilterNet3 (scripts/ses_temizle.py, supressão máxima de 30 dB; para áudios antigos, ses_temizle.yml), (2) klip_temizle corta caudas no início/fim da frase e regiões longas de chiado, (3) na cadeia de renderização, agate suprime o resíduo entre as palavras.
Limpeza de respiração/chiado (padrão): o Chatterbox adiciona uma cauda de respiração/atrito de baixo nível e agudo (4–7 kHz) de 0,5–2 seg no final de algumas frases; klip_temizle corta caudas não sonoras abaixo de 24 dB do pico da fala e reduz respirações ≥150 ms dentro da frase em 24 dB. Sons como "s/ş" no final são preservados por serem mais altos. Desativar: --temizleme-yok.
Sincronia labial: a boca do professor de desenho não apenas abre e fecha; a forma é selecionada a partir das bandas de formante do áudio para cada quadro: 'a' (aberto), 'o' (arredondado) e 'i' (estendido, dentes visíveis). Não requer modelo, não afeta o tempo de renderização. (Rostos falantes realistas como SadTalker/Wav2Lip/LivePortrait exigem GPU e tornam a produção muito lenta.)
Opções: --tik, --muzik, --efekt-yok, --kamera-yok, --altyazi-yok, --karakter yolu.json (personagem fotográfico), --sahne 2-3 --cozunurluk 720 (teste rápido).
8. Verificação (obrigatória antes da entrega, no máximo 2 rodadas de correção)
python $R/scripts/kalite_raporu.py video.mp4 # duração, LUFS/pico, silêncio, quadro preto/congelado + tabela de quadros
Olhe a tabela de quadros. Escreva os achados com seriedade (crítico / sugestão) e para cada um coloque uma correção concreta ("Cena 6, títulos da tabela sobrepostos → encurtar títulos"); não escreva achados vagos como "pode estar um pouco longo". Avalie a tabela de quadros com 5 critérios do TheoremExplainAgent, nota 1–5: precisão (fiel ao documento?), interesse visual (o quadro mostra o que está sendo explicado?), fluxo (os tópicos estão em ordem lógica?), layout (há estouro/sobreposição?), consistência (cores, fonte, estilo são os mesmos?). Para cada critério abaixo de 4, faça uma correção concreta. Corrija os críticos, regenere; após 2 rodadas, informe claramente os restantes na entrega.
9. Entrega
O vídeo também escreve o pacote de publicação a cada renderização: video.srt (legenda do YouTube; ≤2 linhas × 42 caracteres) e video_youtube.txt (título, descrição com capítulos, tags, nota de IA). Envie MP4 + capa + .srt + youtube.txt; informe a duração, o número de cenas e as seções cobertas. Lembre-se de que o SRT será enviado ao YouTube Studio > Legendas e que a caixa "conteúdo modificado/gerado por IA" será marcada.