Geração de clipes de vídeo (imagem para clipe, depois sincronia labial)
Visão geral
Uma imagem finalizada se torna um clipe de 4 a 9 segundos com um modelo de imagem para vídeo. Em seguida, se um personagem fala na tela, um modelo de sincronia labial ajusta o movimento da boca ao seu próprio diálogo. Você não pode assistir ao resultado: julgue cada clipe a partir de frames extraídos (scripts/take_sheet.py e o skill visualizar-vídeos), e deixe o humano ter a palavra final sobre o movimento.
Requisitos: Python 3 (apenas stdlib) e ffmpeg/ffprobe. As chaves vão em variáveis de ambiente: GEMINI_API_KEY (uma chave do Google AI Studio; uma chave com escopo de imagem funciona, e GEMINI_IMAGE_API_KEY é lida como fallback) para Omni, e FAL_KEY (a chave completa exatamente como o fal a mostra) para sincronia labial. Nunca as imprima.
Escolha o modelo
| Modelo | Acessado por | Use para | Observações |
|---|---|---|---|
Gemini Omni Flash 1.1 (gemini-omni-1.1-flash) | Google Interactions API, chave AI Studio | Padrão para ilustrações, anime e cartoons; também funcionou em uma imagem fotorrealista (um teste) | Mantém o estilo artístico e os rostos; qualquer proporção de entrada (uma imagem 2:3 resultou em 9:16 limpo, sem necessidade de expandir ou cortar); 720p 9:16 ou 16:9; síncrono, ~25-35 s por clipe; adiciona seu próprio áudio (silencie-o) |
| Veo 3.1 / Veo 3.1 Fast | Gemini API, imagem como frame inicial | imagens fotorrealistas | não usado em nossas execuções; verifique a documentação atual primeiro |
| Seedance 2.5 | ElevenLabs Flows, ou ByteDance diretamente | visual alternativo | precisou de aprovação de conta quando testado |
| Qualquer modelo dentro do ElevenLabs Flows | ElevenLabs API | uma chave para tudo | O acesso à API precisa do plano Pro (402 paid_plan_required) e da permissão image_video_generation da chave (401 sem ela); Omni lá é apenas para aplicativo |
Para sincronia labial, Sync 3 no fal (fal-ai/sync-lipsync/v3) é o padrão. Funciona vídeo a vídeo, então mantém o movimento do clipe e ajusta apenas a boca. Comparação e preços: references/providers.md.
Animar uma imagem
python3 <diretório-deste-skill>/scripts/omni_generate.py jobs.json clips/ [--takes 3] [--only S05]
{"base": "Dê vida a esta imagem como ela é: mesmo estilo de arte, paleta, luz e layout, e cada personagem mantém o rosto, cabelo, físico e roupas que tem nela. Movimento natural e fluido. Nada escrito na tela, sem balões de fala, ninguém novo, um único plano contínuo.",
"jobs": {"S05": {"image": "painéis/p05.png",
"prompt": "[0-3s] A mulher de jaqueta vermelha levanta o telefone e fala, animada. [3-6s] A amiga de moletom verde se reclina no sofá e ri. Câmera aproxima lentamente."}}}
Como escrever o prompt (guia completo com exemplos em references/gemini-omni.md):
- Uma linha do tempo por segundo, um momento por colchete. O clipe dura aproximadamente o tempo da linha do tempo.
- Nomeie as pessoas pelo que vestem, nunca pelo nome: o modelo não sabe quem é "Dana".
- Diga "fala" para quem será sincronizado labialmente, para que a boca já se mova.
- Fixe o que não pode mudar: "a câmera fica parada", "uma única janela na parede esquerda", "exatamente UMA figura encapuzada", "as mãos dela ficam apoiadas na mesa". Cada fixação em
references/failure-modes.mdveio de uma falha real.
Revise cada take antes de usar
python3 <diretório-deste-skill>/scripts/take_sheet.py sheet revisão/S09.jpg clips/S09_t1.mp4 clips/S09_t2.mp4 clips/S09_t3.mp4 --times 0.3,1,2,3,4,5,6
Leia a folha: linhas são takes, colunas são tempos. Procure por objetos que duplicam, portas ou pessoas que aparecem, mãos cruzando corpos, rostos que se desviam e um gesto feito duas vezes. Nomeie o segundo exato de cada problema, porque a correção depende de onde ele está.
Um corte brusco é fácil de perder entre frames amostrados. Liste-os diretamente; nenhuma saída significa um único plano contínuo:
ffmpeg -i clips/S09_t1.mp4 -vf "select='gt(scene,0.3)',showinfo" -an -f null - 2>&1 | grep pts_time
Ajustar um clipe ao seu plano
Uma edição precisa de um clipe que preencha exatamente seu plano, na taxa de quadros da edição:
| Problema | Correção |
|---|---|
| Início ruim (um gesto feito antes de sua fala, um objeto duplicado no primeiro segundo) | Comece mais tarde: --off 1.5. |
| Muito curto após o corte | Desacelere com --speed 1.22 (até ~1.25 é lido bem); o último frame é mantido. |
| Meio ruim | Divida o plano: reproduza a primeira fala em um recorte que mantenha o problema fora do quadro, depois corte de volta após ele. |
| Irrecuperável (uma porta aparece, uma segunda pessoa entra) | Regere com um prompt fixado, 2-3 takes, e escolha em uma folha. |
lipsync_parts.py normalize clipe.mp4 plano.mp4 --frames N --off S --speed K faz o offset, velocidade, fps, escala (cobrir e centralizar, nunca esticar) e retenção do último frame em uma única etapa, e sempre retorna exatamente N frames.
Sincronizar diálogo labial
- Normalizar o clipe para o plano:
python3 <diretório-deste-skill>/scripts/lipsync_parts.py normalize clipe.mp4 plano.mp4 --frames 132 --off 1.5 --speed 1.22. - Dividir nos limites das falas para que cada parte tenha um falante.
- Escreva
plano.json: cada fala com seu início/fim no plano (segundos) e seu falante;framesé igual ao--framesque você normalizou. Adicione"skip": truepara um falante visto de costas, fora da tela, ou um grito de multidão:{"id": "S05", "video": "plano.mp4", "fps": 24, "frames": 132, "falas": [{"id": "05-1", "audio": "falas/05-1.mp3", "start": 0.72, "end": 2.31, "speaker": "maya"}, {"id": "05-2", "audio": "falas/05-2.mp3", "start": 2.43, "end": 4.10, "speaker": "ido"}]} - Execute
lipsync_parts.py split plano.json parts/. Além das partes, ele escreveparts/S05_lipsync_jobs.json: uma entrada para cada parte não pulada, com caminhos absolutos,outjá nomeado como o join espera (synced/S05_<k>.mp4), eface: null.
- Escreva
- Apontar para o falante em cada parte e escreva no arquivo de jobs como
"face": "x,y@<mid>"(midestá em cada entrada).- Escolha um pixel no rosto dele no frame do meio da parte.
- Confirme:
take_sheet.py point parts/S05_1.mp4 check.jpg --frame 30 --xy 410,560, depois leia a imagem. - Detectores faciais são pouco confiáveis em rostos desenhados, então escolha e confirme visualmente. Deixe
nullapenas quando um único rosto estiver visível.
- Sync:
lipsync_fal.py --jobs parts/S05_lipsync_jobs.json. Espere ~$0.13 por segundo e ~70-150 s por parte; 6 rodam em paralelo. Saídas existentes são puladas. Para refazer uma parte após corrigir seu rosto, rode essa parte sozinha:lipsync_fal.py parts/S05_1.mp4 parts/S05_1.wav synced/S05_1.mp4 --face 410,560@30 --force(--forcecom--jobsrefaria todas as partes). - Juntar:
lipsync_parts.py join parts/S05_plan.json synced/ final/S05.mp4. Cada parte é forçada a sua contagem exata de frames, partes puladas mantêm seus frames originais, uma parte sem arquivo sincronizado é reportada (--stricttorna isso um erro), e a contagem total de frames é verificada.
Detalhes, escolha de modelo e casos de falha: references/lipsync.md.
Custos e tempos (medidos em 2026-10)
| Etapa | Contagem | Custo | Tempo |
|---|---|---|---|
| Clipe Omni | por segundo de vídeo de saída (um clipe de 6 s é ~$0.60; planeje ~1.5 chamadas por plano para retakes) | ~$0.10 | ~30 s por chamada, 4 em paralelo |
| Sync 3 lip-sync | por segundo de saída (uma parte tem tipicamente 3-6 s) | ~$0.13 | ~70-150 s por parte, 6 em paralelo |
Erros comuns
| Erro | Resultado | Correção |
|---|---|---|
| Nomear personagens no prompt de vídeo | a pessoa errada se move | descreva-os pelas roupas |
| Manter o áudio do Omni | vozes e música inventadas sob seu diálogo | silencie-o (-an) |
| Usar um take sem uma folha | objetos duplicados e novas portas vão para o ar | faça folha de cada take |
| Regenerar o clipe inteiro por um primeiro segundo ruim | novos problemas em outros lugares | offset mais desaceleração |
| Sincronizar labialmente um plano inteiro com dois falantes | uma boca se move para ambas as falas | divida nos limites das falas, um falante por parte |
| Deixar o modelo escolher o falante | o rosto errado fala | --face X,Y@FRAME |
| Encurtar a chave fal | 401 | passe a chave exatamente como o fal a mostra |
| Juntar partes sem corrigir as contagens de frames | o plano perde sincronia com a edição | lipsync_parts.py join |
Skills relacionados
- geração-de-imagens: as imagens (fichas de personagem, painéis).
- elevenlabs-tts: o diálogo ao qual as bocas sincronizam.
- visualizar-vídeos: extração de frames para revisão de clipes.
- produção-de-episódios-animados: o fluxo de trabalho completo do episódio que usa esses clipes.