O que Douyin faz?
Você (o agente) realiza o trabalho criativo — roteiro, divisão de cenas, palavras-chave de busca, escolhas de estilo e revisão de qualidade. Os scripts em scripts/ realizam o trabalho mecânico — TTS com timestamps por palavra, busca e download de assets, renderização de legendas, composição ffmpeg, normalização de volume.
Tudo funciona apenas com o ffmpeg básico (sem necessidade de libass/drawtext) mais um ambiente virtual Python. Funciona sem chaves de API; as variáveis de ambiente PEXELS_API_KEY / PIXABAY_API_KEY ativam o download de clipes de vídeo reais (melhores) quando presentes.
Fluxo de trabalho
0. Configuração única (pule se .venv/ e assets/fonts/ existirem)
bash scripts/setup.sh
1. VERIFIQUE OS FATOS PRIMEIRO, depois escreva o roteiro + storyboard
Seu conhecimento interno pode estar desatualizado ou errado — nunca coloque uma afirmação não verificada em um vídeo. Antes de escrever qualquer texto de cena, use sua ferramenta de busca na web para verificar cada afirmação concreta: números, estatísticas, recordes, preços, datas, classificações e toda declaração do tipo "primeiro / maior / único / mais rápido" — e qualquer coisa sensível ao tempo (notícias, produtos, versões, "este ano / o mais recente"), independentemente de quão confiante você se sinta. Regras:
- Uma afirmação vai para o roteiro apenas conforme uma fonte a apresenta — ajuste sua redação à fonte, não o contrário.
- Não consegue verificar? Substitua por uma afirmação que você consiga, ou remova-a. Um número errado em um vídeo publicado é pior do que um gancho mais fraco.
- Registre as URLs em que você se baseou no campo
"sources": [...]do storyboard — elas são ecoadas emreview/report.txtpara que o usuário possa auditar o vídeo. - Se você genuinamente não tiver acesso à web, limite-se a fatos de livros-texto bem estabelecidos, evite números específicos e avise ao usuário que o vídeo não foi verificado.
Leia references/writing-guide.md para as fórmulas de roteiro (tipos de gancho, ritmo, estrutura de cena). Em seguida, crie projects/<slug>/storyboard.json:
{
"title": "深海里最诡异的5种生物",
"lang": "zh",
"aspect": "9:16",
"voice": "zh-CN-YunjianNeural",
"rate": "+10%",
"caption_style": "karaoke",
"bgm": {"mood": "mystery", "gain_db": -16},
"hook": {"text": "深海禁区", "seconds": 2.3},
"scenes": [
{
"text": "你知道吗?在阳光永远照不到的深海,藏着比科幻电影更诡异的生物。",
"keywords": ["deep sea NOAA ocean exploration", "submarine dark ocean"],
"providers": ["openverse", "wikimedia"],
"badge": null,
"effect": "kb_in"
},
{
"text": "第一名,鮟鱇鱼……",
"keywords": ["humpback anglerfish", "anglerfish museum"],
"badge": "第1名"
}
]
}
Referência de campos:
| campo | valores | notas |
|---|---|---|
lang | zh | en | define o agrupamento de legendas + voz padrão |
aspect | 9:16 (padrão) | 16:9 | 1:1 | |
voice | qualquer voz edge-tts | zh: zh-CN-YunjianNeural (voz masculina magnética) zh-CN-XiaoxiaoNeural (voz feminina) zh-CN-YunxiNeural (voz masculina ensolarada); en: en-US-ChristopherNeural en-US-AriaNeural en-US-GuyNeural |
rate | ex.: +10% | ritmo de caça-níqueis: zh +8%+15%, en +5%+10% |
caption_style | karaoke | pop | none | karaokê = destaque palavra por palavra (recomendado) |
bgm | {"mood": ...} | {"query": "palavras de estilo"} | {"file": "caminho.mp3"} | {"mood":"none"} | Padrão para um mood: a tabela curada (upbeat, funny, inspiring, chill, tech, mystery, epic, sad, horror) são os MacLeod standards que inúmeros canais de caça-níqueis usam — comprovado, seguro, variado por projeto. Recorra a query apenas quando nenhum mood se adequar ao estilo do conteúdo (ou o usuário nomear um gênero): ela busca música CC real (estilo ccMixter + Openverse/Jamendo; ND/NC excluídos) e cada candidato é filtrado pelo detector de batida — sem um groove confiante de 75–175 BPM, não é selecionado. Palavras de estilo que mapeiam para tags: trap/phonk, hip hop, lofi/chill, edm/dance, epic/cinematic, quirky. Você pode definir ambos — query é tentada primeiro, mood é o fallback. file = a própria faixa do usuário |
bgm.vibe | "spedup" | "slowed" | não definido | som característico do Douyin: spedup ≈ 1,25× com tom elevado (processamento principal de vídeos de listas/卡点), slowed = desacelerado + reverberação (clima/atmosfera). Aplicado a qualquer fonte de BGM, incl. file; a grade de batidas é reanalisada após o processamento para que o 卡点 permaneça preciso |
beat_sync | true (padrão) | false | o BGM é analisado por batida e cada corte de cena/cena se encaixa na grade de batidas (卡点) quando a grade é confiante; a narração nunca é truncada, apenas as pausas para respiração flexibilizam |
hook | {"text","seconds"} | cartão de título grande no início, ≤ 8 caracteres/palavras |
sticky_title | {"text": ...} | barra de tópico persistente opcional no topo; desligado por padrão — adicione apenas se o usuário solicitar |
sfx | true (padrão) | false | som de whoosh nas transições de cena |
cena keywords | lista de consultas em inglês, substantivos concretos | cada entrada = um take (visual); o vídeo corta para um novo visual a cada ~3s, então forneça 2–3 consultas para cenas com mais de ~4s (takes extras são adicionados automaticamente, ciclando suas consultas se você fornecer menos) |
cena badge | ex.: "第1名" / "TOP 1" | rótulo grande carimbado mostrado no início da cena — use para listas |
cena providers | lista | imagens sem chave: openverse wikimedia nasa; vídeos reais sem chave: wikimedia_video (clipes do Commons, transcodificados pelo servidor) nasa_video (PD espaço/ciência) archive_video (filmes históricos de domínio público do Prelinger); com chaves: pexels_video pexels_photo pixabay_video |
cena effect | auto kb_in kb_out pan_left pan_right static | movimento Ken Burns do primeiro take; takes posteriores ciclam automaticamente |
cena emphasis | lista de substrings | palavras permanentemente destacadas (estilo pop) |
cena media | caminho do arquivo | ignore a busca, use seu próprio arquivo (por exemplo, um que você mesmo baixou) |
Regras básicas (padrão de publicação): total 45–75s, 6–9 cenas, uma ideia por cena, 2–3 takes por cena. Texto da cena: 20–45 caracteres chineses / 14–30 palavras em inglês. Qualquer coisa abaixo de ~40s ou com cenas de take único ao longo do vídeo parecerá superficial — não publique.
2. Execute o pipeline
.venv/bin/python scripts/pipeline.py projects/<slug>
Ou estágio por estágio: tts.py → assets.py → bgm.py → compose.py → check.py.
3. REVISÃO — isso é o que faz a diferença (obrigatório)
A busca de imagens gratuitas é imperfeita. Sempre visualize estes dois arquivos com sua ferramenta de imagem e julgue-os como um editor humano:
-
projects/<slug>/media/assets_sheet.jpg— após o estágio de assets. Os takes são rotulados01a 01b 02a …. Para cada take que não corresponda claramente à narração, faça uma nova busca:.venv/bin/python scripts/assets.py projects/<slug> --scene 3 --shot 2 --keywords "substantivos ingleses melhores"(A nova busca adiciona automaticamente o asset rejeitado a uma lista negra. Repita até que todas as cenas correspondam. Você também pode baixar uma imagem você mesmo com suas próprias ferramentas e apontar o campo
mediada cena para ela.)O pipeline também audita o texto do título de cada take em relação à sua consulta e imprime flags
[!] OFF-TOPIC. Se você confirmou visualmente que um take sinalizado está realmente correto (por exemplo, uma foto sem título, mas perfeita), defina"approved": truenesse take emmedia/manifest.jsonpara limpar a flag — seus olhos têm precedência sobre a auditoria de texto. Nunca aprove cegamente. -
projects/<slug>/review/contact_sheet.jpg— após compose+check. Verifique: legendas legíveis e sincronizadas, sem quadros errados/feios, gancho visível. Corrija problemas (edite o storyboard → execute compose novamente, é rápido) até que pareça um vídeo que um editor de caça-níqueis realmente publicaria.
review/report.txt contém verificações de duração/volume e um bloco de atribuição pronto para colar (fontes CC-BY + crédito musical) — sempre entregue-o ao usuário junto com final.mp4.
Dicas de busca de assets (maior alavanca de qualidade)
- As palavras-chave devem ser em inglês, 1–4 palavras, substantivos concretos visíveis ("humpback anglerfish", "scuba diver silhouette"), nunca conceitos abstratos ("mystery", "success").
wikimediaé melhor para animais/ciência/história/lugares;openverse(Flickr etc.) para estilo de vida/paisagem/clima;nasapara espaço; chaves desbloqueiampexels_video/pixabay_videocom filmagens reais — prefira estas quando disponíveis.- Adicione uma palavra de contexto para desambiguar: "NOAA", "museum", "aquarium", "macro".
- Se uma cena continuar falhando, mude o conceito visual, não apenas as palavras (por exemplo, para "5% explorado" mostre uma silhueta de mergulhador, não "estatísticas").
- As buscas
wikimedia_videosuportam termos negativos — consultas de clima/espaço no Commons se afogam em loops de satélite, então escreva ex.:"lightning storm -CIRA -satellite -JPSS". Palavras não inglesas desbloqueiam filmagens extras ("Blitz Gewitter", "tormenta rayos"). Prefira assuntos nomeados ("Fagradalsfjall lava drone") a substantivos genéricos, e sempre examine as miniaturas de vídeo na folha: cuidado com legendas queimadas, marcas d'água, tutoriais e promos CGI.
Solução de problemas
- Erros de rede
edge-tts: ele tenta novamente 4×; executetts.pynovamente se ainda falhar. - Falha no download de BGM: execute
bgm.pynovamente (novas tentativas + cache), ou--mood none, ou coloque um mp3 emassets/bgm/e definabgm.file. - O estilo de BGM não combina: refine a consulta (
bgm.py <dir> --query "..."e depois recomponha com--skip-tts --skip-assets). Para um som 真正の当下热门, entregue commood: none(ou ganho baixo) e diga ao usuário para adicionar a faixa em alta da biblioteca de música licenciada do TikTok/Douyin no momento do upload — isso é legal e favorecido pelo algoritmo. O corte temporal ainda ficará limpo, pois o ritmo da cena não é alterado. check.pyimprime uma linha "cortes caem na batida" — se a sincronização de batida foi pulada (baixa confiança na grade, ex.: música ambiente sem batida), escolha uma faixa mais estável (--query "trap beat"etc.) e recomponha.- Um provedor com erro/vazio é normal — outros cobrem; verifique os logs por cena.
- Recompor após qualquer edição no storyboard é barato (
--skip-tts --skip-assetsvia pipeline.py, ou execute compose.py diretamente). Alterar o texto da cena requer executartts.pynovamente. - Emojis em legendas renderizam no macOS (Apple Color Emoji); no Linux, são descartados a menos que o NotoColorEmoji esteja instalado. Nunca dependa de emoji para transmitir significado.
Entrega
Entregue ao usuário: final.mp4, o bloco de atribuição de review/report.txt e (se solicitado) review/cover.jpg como imagem de capa.