¿Qué hace Douyin?
Tú (el agente) realizas el trabajo creativo — guion, desglose de escenas, palabras clave de búsqueda, elecciones de estilo y revisión de calidad. Los scripts en scripts/ realizan el trabajo mecánico — TTS con marcas de tiempo por palabra, búsqueda y descarga de activos, renderizado de subtítulos, composición con ffmpeg y normalización de volumen.
Todo funciona solo con ffmpeg básico (sin necesidad de libass/drawtext) más un entorno Python virtual. Funciona sin API keys; las variables de entorno PEXELS_API_KEY / PIXABAY_API_KEY desbloquean metraje real de stock (mejor) cuando están presentes.
Flujo de trabajo
0. Configuración inicial (omite si ya existen .venv/ y assets/fonts/)
bash scripts/setup.sh
1. VERIFICA LOS HECHOS PRIMERO, luego escribe el guion + storyboard
Tu conocimiento interno puede estar desactualizado o ser incorrecto — nunca pongas una afirmación no verificada en un video. Antes de escribir cualquier texto de escena, usa tu herramienta de búsqueda web para comprobar cada afirmación concreta: números, estadísticas, récords, precios, fechas, clasificaciones y cada declaración de "primero / más grande / único / más rápido" — y cualquier cosa sensible al tiempo (noticias, productos, versiones, "今年/最新") sin importar lo seguro que te sientas. Reglas:
- Una afirmación va al guion solo si una fuente la indica — ajusta tu redacción a la fuente, no al revés.
- ¿No puedes verificarla? Reemplázala por una afirmación que puedas verificar, o elimínala. Un número equivocado en un video publicado es peor que un gancho más débil.
- Registra las URLs en las que te basaste en
"sources": [...]del storyboard — se reflejan enreview/report.txtpara que el usuario pueda auditar el video. - Si realmente no tienes acceso a internet, cíñete a hechos establecidos desde hace tiempo en libros de texto, evita cifras específicas e informa al usuario que el video no está verificado.
Lee references/writing-guide.md para las fórmulas de guion (tipos de gancho, ritmo, estructura de escenas). Luego crea 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名"
}
]
}
Referencia de campos:
| campo | valores | notas |
|---|---|---|
lang | zh | en | define la agrupación de subtítulos + la voz predeterminada |
aspect | 9:16 (predeterminado) | 16:9 | 1:1 | |
voice | cualquier voz de edge-tts | zh: zh-CN-YunjianNeural(voz masculina magnética) zh-CN-XiaoxiaoNeural(voz femenina) zh-CN-YunxiNeural(voz masculina alegre); en: en-US-ChristopherNeural en-US-AriaNeural en-US-GuyNeural |
rate | ej. +10% | Ritmo de cuenta de marketing: zh +8%+15%, en +5%+10% |
caption_style | karaoke | pop | none | karaoke = resaltado palabra por palabra (recomendado) |
bgm | {"mood": ...} | {"query": "palabras de estilo"} | {"file": "ruta.mp3"} | {"mood":"none"} | Por defecto usa un mood: la tabla seleccionada (optimista divertido inspirador tranquilo tech misterioso épico triste terror) son los temas básicos de MacLeod que innumerables canales de marketing usan — probados, seguros, variados por proyecto. Usa query solo cuando ningún mood se ajuste al estilo del contenido (o el usuario nombre un género): busca música CC real (etiquetas de estilo ccMixter + Openverse/Jamendo; se excluyen ND/NC) y cada candidato es filtrado por el detector de ritmo — sin un ritmo seguro de 75–175 BPM, no se selecciona. Palabras de estilo que se asignan a etiquetas: trap/phonk, hip hop, lofi/chill, edm/dance, epic/cinematic, quirky. Puedes establecer ambos — query se prueba primero, mood es el respaldo. file = la propia pista del usuario |
bgm.vibe | "spedup" | "slowed" | sin establecer | Sonido característico de Douyin: spedup ≈ 1.25× con tono elevado (procesamiento común para videos de ritmo rápido); slowed = ralentizado con reverberación (para ambiente/atmósfera). Se aplica a cualquier fuente de bgm, incl. file; la cuadrícula de ritmo se vuelve a analizar después del procesamiento para que el ajuste al ritmo se mantenga preciso |
beat_sync | true (predeterminado) | false | el BGM se analiza rítmicamente y cada corte de escena/toma se ajusta a la cuadrícula de ritmo (卡点) cuando la cuadrícula es confiable; la VO nunca se trunca, solo se ajustan los silencios de respiración |
hook | {"text","seconds"} | tarjeta de título grande mostrada al inicio, ≤ 8 caracteres/palabras |
sticky_title | {"text": ...} | barra de tema persistente opcional en la parte superior; desactivada por defecto — agrega solo si el usuario lo solicita |
sfx | true (predeterminado) | false | sonido "whoosh" en las transiciones de escena |
keywords de escena | lista de consultas en inglés, con sustantivos concretos | cada entrada = una toma (visual); el video corta a una nueva imagen cada ~3s, así que da 2–3 consultas para escenas de más de ~4s (se agregan tomas adicionales automáticamente recorriendo tus consultas si das menos) |
badge de escena | ej. "第1名" / "TOP 1" | etiqueta grande estampada mostrada al inicio de la escena — úsalo para listas |
providers de escena | lista | imágenes sin clave: openverse wikimedia nasa; video real sin clave: wikimedia_video (clips de Commons, transcodificaciones del servidor) nasa_video (PD espacio/ciencia) archive_video (metraje histórico de dominio público de Prelinger); con claves: pexels_video pexels_photo pixabay_video |
effect de escena | auto kb_in kb_out pan_left pan_right static | movimiento Ken Burns de la primera toma; las tomas posteriores se recorren automáticamente |
emphasis de escena | lista de subcadenas | palabras resaltadas permanentemente (estilo pop) |
media de escena | ruta de archivo | omitir búsqueda, usar tu propio archivo (ej. uno que descargaste tú mismo) |
Reglas generales (estándar de publicación): total 45–75s, 6–9 escenas, una idea por escena, 2–3 tomas por escena. Texto de escena de 20–45 caracteres chinos / 14–30 palabras en inglés. Cualquier cosa de menos de ~40s o con tomas de una sola escena en todo el video se sentirá superficial — no lo publiques.
2. Ejecuta la pipeline
.venv/bin/python scripts/pipeline.py projects/<slug>
O etapa por etapa: tts.py → assets.py → bgm.py → compose.py → check.py.
3. REVISA — esto marca la diferencia (obligatorio)
La búsqueda de imágenes gratuitas es imperfecta. Mira siempre estos dos archivos con tu herramienta de imágenes y evalúalos como un editor humano:
-
projects/<slug>/media/assets_sheet.jpg— después de la etapa de activos. Las tomas están etiquetadas01a 01b 02a …. Para cada toma que no coincida claramente con la narración, vuelve a obtenerla:.venv/bin/python scripts/assets.py projects/<slug> --scene 3 --shot 2 --keywords "mejores sustantivos en inglés"(Volver a obtener automáticamente bloquea el activo rechazado. Repite hasta que todas las escenas coincidan. También puedes descargar una imagen tú mismo con tus propias herramientas y apuntar el campo
mediade la escena a ella.)La pipeline también audita el título de la fuente de cada toma en comparación con su consulta e imprime indicadores
[!] OFF-TOPIC. Si confirmaste visualmente que una toma marcada es correcta (ej. una foto perfecta pero sin título), establece"approved": trueen esa toma enmedia/manifest.jsonpara limpiarla — tus ojos están por encima de la auditoría de texto. Nunca apruebes a ciegas. -
projects/<slug>/review/contact_sheet.jpg— después de compose+check. Verifica: subtítulos legibles y sincronizados, sin fotogramas incorrectos/feos, gancho visible. Corrige problemas (edita storyboard → vuelve a ejecutar compose, es rápido) hasta que parezca un video que un editor de cuentas de marketing publicaría.
review/report.txt contiene comprobaciones de duración/volumen y un bloque de atribución listo para pegar (fuentes CC-BY + crédito musical) — entrégalo siempre al usuario junto con final.mp4.
Consejos de búsqueda de activos (la mayor palanca de calidad)
- Las palabras clave deben ser en inglés, de 1 a 4 palabras, sustantivos concretos visibles ("humpback anglerfish", "scuba diver silhouette"), nunca conceptos abstractos ("mystery", "success").
wikimediaes mejor para animales/ciencia/historia/lugares;openverse(Flickr, etc.) para estilo de vida/paisajes/ambiente;nasapara el espacio; las claves desbloqueanpexels_video/pixabay_videometraje real — prefiérelos cuando estén disponibles.- Agrega una palabra de contexto para desambiguar: "NOAA", "museum", "aquarium", "macro".
- Si una escena falla repetidamente, cambia el concepto visual, no solo las palabras (ej. para "explorado al 5%" muestra la silueta de un buzo, no "statistics").
- Las búsquedas en
wikimedia_videoadmiten términos negativos — las consultas de clima/espacio en Commons se inundan con bucles de satélite, así que escribe ej."lightning storm -CIRA -satellite -JPSS". Las palabras no inglesas desbloquean metraje adicional ("Blitz Gewitter", "tormenta rayos"). Prefiere temas nombrados ("Fagradalsfjall lava drone") sobre sustantivos genéricos, y siempre revisa visualmente las miniaturas de video en la hoja: cuidado con subtítulos incrustados, marcas de agua, tutoriales y promociones CGI.
Solución de problemas
- Errores de red de
edge-tts: reintenta 4 veces; vuelve a ejecutartts.pysi sigue fallando. - La descarga de BGM falla: vuelve a ejecutar
bgm.py(reintentos + caché), o usa--mood none, o coloca un mp3 enassets/bgm/y establecebgm.file. - El estilo del BGM no encaja: refina la consulta (
bgm.py <dir> --query "..."y luego vuelve a componer con--skip-tts --skip-assets). Para un sonido 流行的真正当下热门, entrega conmood: none(o ganancia baja) e indica al usuario que añada la pista de tendencia de la biblioteca de música con licencia integrada de TikTok/抖音 en el momento de la subida — eso es legal y favorecido por el algoritmo. El ritmo de los cortes seguirá siendo limpio porque el ritmo de las escenas no cambia. check.pyimprime una línea "los cortes caen en el ritmo" — si la sincronización de ritmo se omitió (baja confianza en la cuadrícula, ej. música ambiental sin ritmo), elige una pista más constante (--query "trap beat", etc.) y vuelve a componer.- Que un proveedor dé error o esté vacío no es problema — otros lo cubren; revisa los registros por escena.
- Volver a componer después de cualquier edición del storyboard es económico (
--skip-tts --skip-assetsa través de pipeline.py, o ejecuta compose.py directamente). Cambiar el texto de la escena requiere volver a ejecutartts.py. - Los emojis en los subtítulos se renderizan en macOS (Apple Color Emoji); en Linux se omiten a menos que NotoColorEmoji esté instalado. Nunca dependas de emojis para el significado.
Entrega
Entrega al usuario: final.mp4, el bloque de atribución de review/report.txt y (si se solicita) review/cover.jpg como imagen de portada.