Seedance 2.0: lip sync con diálogo y 4 clips reales
La boca sigue al prompt y nuestra grabación volvió en la pista de audio.

En esta página
- Respuesta corta
- ¿Seedance 2.0 hace lip sync?
- Cómo se escribe el diálogo en el prompt
- ¿Puedo enviar mi propio audio?
- Imagen a vídeo cambia el plano por su cuenta
- La petición en Python
- Cuánto cuesta
- Qué suele fallar
- Preguntas frecuentes
- Si subo un WAV, ¿la boca sigue mi grabación?
- ¿Por qué rechazaron mi petición de solo audio?
- ¿Genero audio o no para una frase hablada?
- ¿Cuánto puede durar el audio de referencia?
- Fuentes consultadas
- Historial de cambios
Seedance 2.0 mueve la boca según el prompt. Dos clips de 5 segundos y 720P, iguales salvo el audio activado o desactivado, abrieron y cerraron la boca. Nuestra grabación de 1,8 segundos pasó por reference_to_video y la frase volvió en la pista de audio. El audio solo se rechaza. BytePlus cobra $0.15 por segundo en 720P, así que 5 segundos son $0.75.
Respuesta corta
- La boca sale del prompt. Dos clips de 5 segundos en 720P con el mismo prompt, uno con audio generado y otro en silencio, pasaron por cerrada → entreabierta → muy abierta.
- El audio solo no entra. La serie 2.0 pide al menos una imagen o un vídeo de referencia (API de creación de tareas de BytePlus, consultada el 3 de noviembre de 2026).
- El audio de referencia admite 3 clips como máximo, de 2 a 15 segundos cada uno, 15 segundos en total, en wav o mp3, 15 MB por archivo.
- El audio se usa. Nuestro mp3 de 1,8 segundos volvió en la pista de salida y la frase llegó completa.
- Con el precio por segundo de BytePlus, 720P cuesta $0.15 por segundo y 5 segundos son $0.75.
- Cuatro clips del mismo día: 720P con audio, 720P sin audio, imagen a vídeo en 720P cuadrado y 480P con audio de referencia.
¿Seedance 2.0 hace lip sync?
En la documentación oficial no aparece la expresión «lip sync». Lo que describen es la generación conjunta de imagen y sonido, más un consejo: escribir el diálogo entre comillas dobles.
La página de Seed de ByteDance dice que Seedance 2.0 es «a unified multimodal audio-video joint generation architecture that supports text, image, audio, and video inputs» (consultada el 3 de noviembre de 2026). La guía de BytePlus ModelArk repite la idea y lista «Generate videos with audio» entre sus capacidades (página actualizada el 29 de septiembre de 2026).
Buscando en esas páginas, «lip sync» y «talking» no aparecen nunca. «mouth» sale una vez, dentro de un prompt de ejemplo, y «dialogue» dos veces, las dos hablando de generar audio. Lo más cercano a una instrucción es esta frase: «It is recommended to put dialogue content in double quotes to optimize the audio generation effect» (API de creación de tareas, actualizada el 28 de octubre de 2026).
O sea que la función vive en el hueco entre las dos cosas: el modelo entrega imagen y pista de audio, pero ninguna página oficial promete que los labios sigan cada sílaba. En nuestros cuatro clips la boca se movió con el audio encendido y apagado, que es lo esperable de un modelo de vídeo al que el prompt le dice que alguien habla.
Hay gente probándolo. Un comentario de Hacker News del 18 de febrero de 2026 envió una canción junto al vídeo y concluyó que «the model did reference the singing music I provided, but it reinterpreted it on its own» (comentario). Un issue de GitHub del 3 de junio de 2026 pone «Mouth movements match phoneme timing» como condición para aprobar, una medición que la documentación no menciona (issue).
Cómo se escribe el diálogo en el prompt
Primero el personaje, después la frase entre comillas dobles y al final cómo se mueven la boca y la cara. Nuestro prompt describía al personaje y el movimiento de la boca, pero se dejó las comillas: la frase la eligió el modelo.
La receta que usamos tiene cinco pasos.
- El personaje en una frase: stop-motion de plastilina, gafas redondas grandes, bufanda de punto, sentado a una mesa de cocina.
- Qué hace: dice una frase corta mirando a cámara.
- La frase, tal cual, entre comillas dobles. Es la recomendación de BytePlus.
- La boca y la cara: los labios se abren y se cierran con las palabras, las cejas acompañan la frase, la cabeza se inclina en la sílaba tónica.
- Cámara y luz fijas, para que lo único que se mueva sea la interpretación.
Este es el prompt que enviamos, sin cambios, en los cuatro clips:
A stop-motion clay character with big round glasses and a knitted scarf sits at a kitchen table, looks straight into the camera, and speaks one short line to the viewer. The mouth opens and closes in time with the words, the eyebrows move with the sentence, and the head tilts slightly on the stressed word. Fixed camera, warm lamp light, a mug of tea in front of them, gentle 24 fps stop-motion feel.
Lo que falta es la frase. El prompt solo decía «una frase corta», así que las palabras las puso el modelo. Con el audio encendido dice «You look like you could use a warm hug.», una línea que no estaba en ninguna parte de la petición. Para controlar el diálogo, el paso 3 tiene que estar antes de enviar.
Miramos la boca con un fotograma cada 0,5 segundos. El clip con audio empieza con la boca cerrada, del fotograma 2 al 7 está entreabierta, en el 8 se abre del todo y luego vuelve a entreabrirse hasta cerrarse. El clip sin audio va cerrada, entreabierta, abierta, entreabierta, abierta, y los dos últimos fotogramas entreabierta.


El mismo texto también elige otro personaje: el clip sin audio salió con el cuerpo naranja, raya al medio castaño grisácea y bufanda verde oscuro. Conviene escribir la frase del personaje como sugerencia. En los dos clips la cámara no se movió, que es lo que consigue «Fixed camera».
¿Puedo enviar mi propio audio?
Sí, con una imagen o un vídeo de referencia en la misma petición. Nuestro mp3 de 1,8 segundos viajó como audio de referencia y sus palabras volvieron en la pista de salida.
Usamos reference_to_video con tres piezas: el fotograma fijo de plastilina como imagen de referencia, nuestra grabación como audio de referencia y el prompt de arriba. Los parámetros fueron 480P, 5 segundos y audio generado activado. OmniaKey devolvió 202, la tarea task_3Ay0Ktf2mbYXh9GNZpZ5j9kGyOIzz8Pv terminó bien y a los 120,2 segundos llegó un MP4 de 864×496 con una pista aac de 5.06 segundos.
La transcripción de esa pista es una sola frase: «Why tow it? I told you the keys were in the drawer.». La segunda mitad es exactamente lo que grabamos, palabra por palabra. Las tres primeras palabras no estaban en nuestro archivo; la transcripción no distingue si son nuestra respiración o algo que añadió el modelo, así que dejamos lo que se oye.

Diez fotogramas, uno cada 0,5 segundos, solo muestran que la boca se mueve. Para ver el ajuste por fonema hacen falta fotogramas más densos y una medición aparte, y eso no lo hicimos, así que no podemos decir que los labios sigan cada sonido.
Los límites vienen de la API de creación de tareas de BytePlus (consultada el 3 de noviembre de 2026). El audio admite 3 clips, de 2 a 15 segundos cada uno, 15 segundos en total, en wav o mp3, 15 MB por archivo. Se puede enviar como URL pública, cadena Base64 o id de recurso. Solo audio no: «Audio-only input is not supported; include at least one reference image or video.»
Imagen a vídeo cambia el plano por su cuenta
Nuestro imagen a vídeo pasó de un plano entero de pie a un plano medio sentado en la cocina en el fotograma 4, y el prompt no pedía ni corte ni movimiento de cámara.
El primer fotograma es un fijo que generamos para esta prueba: el personaje de pie ante una pared blanca cálida, con los brazos caídos, cuerpo entero y 1254×1254 píxeles. El prompt es el de arriba, que lo sienta a una mesa de cocina. Los fotogramas 1 a 3 mantienen la pose de pie, en el 4 salta al plano medio sentado y sigue así. La boca está cerrada hasta el fotograma 7, se entreabre en el 8 y se abre en el 9 y el 10. En el audio suena «Well, what do you think?» y roces de tela.

Aquí lo que importa es la composición, no la boca. En este modelo el prompt decide dónde está el personaje y cómo se mueve la cámara, y el primer fotograma decide su aspecto. El plano que importe va escrito en el prompt.
El archivo llegó en 960×960, no en 1280×720. La causa es que usamos una imagen cuadrada como primer fotograma y no enviamos proporción, y la API toma por defecto la de la imagen. Si quieres una proporción concreta, escribe ratio en lugar de deducirla del nombre de la resolución.
La petición en Python
Crear la tarea, consultar el id y descargar el MP4: tres peticiones y solo la biblioteca estándar. El mismo ayudante sirve para las tres operaciones.
import base64
import json
import os
import time
import urllib.error
import urllib.request
import uuid
API = "https://api.omniakey.com/v1/media/tasks"
KEY = os.environ["OMNIAKEY_API_KEY"]
MODEL = "dreamina-seedance-2-0-260128"
PROMPT = (
"A stop-motion clay character with big round glasses and a knitted scarf sits at a kitchen table, "
"looks straight into the camera, and speaks one short line to the viewer. The mouth opens and closes "
"in time with the words, the eyebrows move with the sentence, and the head tilts slightly on the "
"stressed word. Fixed camera, warm lamp light, a mug of tea in front of them, gentle 24 fps "
"stop-motion feel."
)
MIME = {".png": "image/png", ".jpg": "image/jpeg", ".jpeg": "image/jpeg",
".webp": "image/webp", ".mp3": "audio/mpeg", ".wav": "audio/wav"}
def call(method, url, body=None, idempotency_key=None):
headers = {"Authorization": f"Bearer {KEY}", "User-Agent": "omniakey-example/1"}
data = None
if body is not None:
headers["Content-Type"] = "application/json"
data = json.dumps(body).encode()
if idempotency_key:
headers["Idempotency-Key"] = idempotency_key
req = urllib.request.Request(url, data=data, headers=headers, method=method)
with urllib.request.urlopen(req, timeout=120) as resp:
return json.load(resp)
def data_url(path, limit_mb):
raw = open(path, "rb").read()
if len(raw) > limit_mb * 1024 * 1024: # 30 MB para imagen, 15 MB para audio
raise ValueError(f"{path} is over {limit_mb} MB, the limit for this input type")
mime = MIME[os.path.splitext(path)[1].lower()]
return f"data:{mime};base64," + base64.b64encode(raw).decode()
def wait(task_id, timeout=900, step=5):
deadline = time.time() + timeout
while time.time() < deadline:
state = call("GET", f"{API}/{task_id}")
if state["status"] not in ("queued", "processing"):
return state
time.sleep(step)
raise TimeoutError(f"{task_id} is still running: poll it again, do not resubmit")
def run(body, out_path):
task_id = call("POST", API, body, str(uuid.uuid4()))["id"]
print("task", task_id, flush=True)
state = wait(task_id)
if state["status"] != "succeeded":
raise RuntimeError(state.get("error") or state["status"])
signed = state["assets"][0]["url"] # caduca, así que se descarga al momento
req = urllib.request.Request(signed, headers={"User-Agent": "omniakey-example/1"})
with urllib.request.urlopen(req, timeout=300) as resp, open(out_path, "wb") as f:
f.write(resp.read())
return task_id
def reference_to_video(prompt, image_path, audio_path, out_path):
body = {
"model": MODEL,
"type": "video",
"operation": "reference_to_video",
"input": {
"prompt": prompt,
"media": [
{"type": "reference_image", "url": data_url(image_path, 30)},
{"type": "reference_audio", "url": data_url(audio_path, 15)},
],
},
"parameters": {"duration": 5, "resolution": "480P", "ratio": "16:9",
"generate_audio": True, "watermark": False},
}
return run(body, out_path)
if __name__ == "__main__":
print("done", reference_to_video(PROMPT, "character.png", "line.mp3", "line-clip.mp4"))
Tres detalles del código merecen quedarse. La Idempotency-Key es un UUID nuevo por cuerpo, así que un reintento devuelve la tarea original en vez de cobrar dos veces. El bucle de espera corta a los 15 minutos con una excepción, porque un tiempo agotado significa que el clip sigue renderizando y reenviarlo compra otro. La descarga ocurre en el primer succeeded, porque assets[0].url es un enlace firmado que caduca.
Las otras dos operaciones cambian el cuerpo y conservan los ayudantes:
def text_to_video(prompt, out_path):
body = {
"model": MODEL,
"type": "video",
"operation": "text_to_video",
"input": {"prompt": prompt},
"parameters": {"duration": 5, "resolution": "720P", "ratio": "16:9",
"generate_audio": True, "watermark": False},
}
return run(body, out_path)
def image_to_video(prompt, image_path, out_path):
body = {
"model": MODEL,
"type": "video",
"operation": "image_to_video",
"input": {"prompt": prompt,
"media": [{"type": "first_frame", "url": data_url(image_path, 30)}]},
"parameters": {"duration": 5, "resolution": "720P", "ratio": "adaptive",
"generate_audio": True, "watermark": False},
}
return run(body, out_path)
La lista de campos es corta: model, type, operation, input.prompt, input.media[] con type en first_frame, reference_image, reference_video o reference_audio, y parameters.duration, resolution, ratio, generate_audio, watermark. La misma forma está en la documentación de la API de vídeo de OmniaKey, y el ciclo de crear, consultar y descargar en la descripción general de la API de medios. Este modelo se prueba desde la página del modelo Seedance 2.0.
Cuánto cuesta
BytePlus cobra por segundo. El precio de lista para 5 segundos en 16:9 sin vídeo de entrada es este (página de precios de ModelArk, consultada el 3 de noviembre de 2026):
| Salida | Por segundo | Clip de 5 s |
|---|---|---|
| 480p | $0.07 | $0.35 |
| 720p | $0.15 | $0.76 |
| 1080p | $0.37 | $1.87 |
| 4K | $0.78 | $3.89 |
Si lo calculas con la columna por segundo sale lo mismo con un céntimo de redondeo en la página: 5 segundos × $0.15 = $0.75, frente a los 0.76 de la fila de 720p. Nuestros dos clips de texto a vídeo fueron 720P y 5 segundos, así que cada uno queda en esos $0.75.
Una petición con vídeo de entrada se factura de otra forma y más caro, así que una tarea con vídeo de referencia no encaja en esta tabla (página de precios de ModelArk, consultada el 3 de noviembre de 2026). OmniaKey cobra por segundo generado y devuelve el cargo cuando la tarea acaba en failed o canceled (descripción general de la API de medios, consultada el 3 de noviembre de 2026); el precio actual está en la página del modelo.
Qué suele fallar
- El audio solo se rechaza. Añade al menos una imagen o un vídeo de referencia junto a la pista.
- Las caras reales no pasan. Una imagen o un vídeo de referencia con una persona real se bloquea, así que usa un personaje de plastilina, dibujo o CG.
generate_audioviene activado. Para un archivo mudo hay que ponerlo enfalse; para una frase, se deja por defecto y el prompt dice que alguien habla.- El tamaño entregado sigue a
ratio. 720P dio 1280×720 desde texto, 960×960 desde un fijo cuadrado sin proporción y 864×496 en 480P con 16:9. - La velocidad varía. Cuatro tareas de 5 segundos tardaron 259,0, 202,0, 155,3 y 120,2 segundos, así que cuenta con dos a cinco minutos y consulta el estado.
- La duración va de 4 a 15 segundos de salida y los clips de referencia de 2 a 15 segundos cada uno, 15 en total. Los cuatro archivos llegaron a 24 fps.
Preguntas frecuentes
Si subo un WAV, ¿la boca sigue mi grabación?
Sí, junto con una imagen de referencia, y el modelo lo usa: nuestra grabación volvió en el audio de salida. Si los labios caen en cada sonido del archivo es algo que nuestros fotogramas no pueden mostrar; uno cada medio segundo enseña que la boca se mueve, no una coincidencia medida.
¿Por qué rechazaron mi petición de solo audio?
La serie 2.0 no acepta audio como único dato de entrada. Añade una imagen o un vídeo de referencia a la misma petición y el audio entra con ellos.
¿Genero audio o no para una frase hablada?
Déjalo activado, que es el valor por defecto. Con false el archivo no tiene pista de audio, y el personaje igual abre la boca si el prompt dice que habla, como en nuestro clip mudo.
¿Cuánto puede durar el audio de referencia?
Cada clip va de 2 a 15 segundos, hasta 3 clips, 15 segundos en total, en wav o mp3 y 15 MB por archivo (API de creación de tareas de BytePlus, consultada el 3 de noviembre de 2026). El nuestro duraba 1,8 segundos, menos que ese mínimo, y aun así viajó como URL de datos Base64.
Fuentes consultadas
- ByteDance Seed: Seedance 2.0, consultada el 3 de noviembre de 2026
- BytePlus ModelArk: guía de Seedance 2.0, consultada el 3 de noviembre de 2026
- BytePlus ModelArk: API de creación de tareas de vídeo, consultada el 3 de noviembre de 2026
- BytePlus ModelArk: precios de los modelos, consultada el 3 de noviembre de 2026
Historial de cambios
- 3 de noviembre de 2026: primera versión, con cuatro clips creados ese mismo día.
Modelos de este artículo
Artículos relacionados
API de Seedance 2.0: de texto a video y de imagen a video con Python
Un script crea la tarea, consulta su estado y guarda el MP4. Aquí están los campos, los límites y dos clips de 5 segundos que hicimos el 30 de octubre de 2026.
Guía de prompts de Seedance 2.5: estructura, ejemplos y clips reales
Seis prompts y seis clips reales: qué siguió Seedance 2.5, qué cambió y cómo corregirlo.
Análisis de Seedance 2.5
La mejora importante es la narración de 30 segundos y el control de producción, no los titulares de 4K aún sin confirmar.
