Seedance 2.0 : lip-sync, dialogue et 4 clips réels
La bouche suit le prompt, et notre enregistrement revient dans la piste.

Sur cette page
- Réponse courte
- Seedance 2.0 fait-il du lip-sync ?
- Comment écrire la réplique dans le prompt
- Peut-on envoyer son propre audio ?
- L'image vers vidéo change de plan tout seul
- La requête en Python
- Combien ça coûte
- Ce qui rate
- Questions fréquentes
- Si j'envoie un WAV, la bouche suit-elle mon enregistrement ?
- Pourquoi ma requête audio seule a-t-elle été refusée ?
- Faut-il activer l'audio pour une réplique ?
- Quelle longueur pour l'audio de référence ?
- Sources vérifiées
- Journal des modifications
Seedance 2.0 fait bouger la bouche selon le prompt. Deux clips de 5 secondes en 720P, identiques sauf l'audio activé ou coupé, ouvrent et ferment la bouche. Notre enregistrement de 1,8 seconde est passé par reference_to_video, et la phrase est revenue dans la piste de sortie. L'audio seul est refusé. BytePlus facture $0.15 par seconde en 720P, donc $0.75 pour 5 secondes.
Réponse courte
- La bouche vient du prompt. Deux clips de 5 secondes en 720P avec le même prompt, l'un avec audio généré, l'autre muet, sont passés par fermée → entrouverte → grande ouverte.
- L'audio seul ne passe pas. La série 2.0 exige au moins une image ou une vidéo de référence (API de création de tâche BytePlus, vérifiée le 3 novembre 2026).
- L'audio de référence accepte 3 clips au maximum, de 2 à 15 secondes chacun, 15 secondes au total, en wav ou mp3, 15 Mo par fichier.
- L'audio sert vraiment. Notre mp3 de 1,8 seconde est revenu dans la piste de sortie, la phrase est complète.
- Au prix à la seconde de BytePlus, 720P coûte $0.15 par seconde, soit $0.75 pour 5 secondes.
- Quatre clips du même jour : 720P avec audio, 720P muet, image vers vidéo en 720P carré, 480P avec audio de référence.
Seedance 2.0 fait-il du lip-sync ?
La documentation officielle n'emploie pas l'expression « lip-sync ». Elle décrit une génération conjointe de l'image et du son, puis conseille de mettre le dialogue entre guillemets doubles.
La page Seed de ByteDance présente Seedance 2.0 comme « a unified multimodal audio-video joint generation architecture that supports text, image, audio, and video inputs » (vérifiée le 3 novembre 2026). Le guide BytePlus ModelArk reprend la même idée et liste « Generate videos with audio » parmi les capacités (page mise à jour le 29 septembre 2026).
En cherchant dans ces pages, « lip sync » et « talking » n'apparaissent jamais. « mouth » apparaît une fois, dans un prompt d'exemple, et « dialogue » deux fois, toujours à propos de la génération audio. Le plus proche d'une consigne est cette phrase : « It is recommended to put dialogue content in double quotes to optimize the audio generation effect » (API de création de tâche, mise à jour le 28 octobre 2026).
La fonction se situe donc entre les deux : le modèle produit l'image et la piste audio, mais aucune page officielle ne promet que les lèvres suivent chaque syllabe. Sur nos quatre clips, la bouche a bougé avec et sans audio, ce qu'on attend d'un modèle vidéo dont le prompt dit que quelqu'un parle.
D'autres essaient. Un commentaire Hacker News du 18 février 2026 a envoyé une chanson avec la vidéo et conclut « the model did reference the singing music I provided, but it reinterpreted it on its own » (commentaire). Un ticket GitHub du 3 juin 2026 pose « Mouth movements match phoneme timing » comme condition de réussite, une mesure absente de la documentation (ticket).
Comment écrire la réplique dans le prompt
D'abord le personnage, ensuite la réplique entre guillemets doubles, enfin le mouvement de la bouche et du visage. Notre prompt décrivait le personnage et la bouche, mais avait oublié les guillemets : la réplique a donc été choisie par le modèle.
Notre méthode tient en cinq étapes.
- Le personnage en une phrase : stop-motion en pâte à modeler, grandes lunettes rondes, écharpe en laine, assis à une table de cuisine.
- Ce qu'il fait : dire une courte réplique face caméra.
- La réplique, telle quelle, entre guillemets doubles. C'est la recommandation de BytePlus.
- La bouche et le visage : les lèvres s'ouvrent et se ferment avec les mots, les sourcils suivent la phrase, la tête penche sur la syllabe accentuée.
- Caméra et lumière fixes, pour que seule la gestuelle bouge.
Voici le prompt envoyé, sans modification, pour les quatre 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.
Il manque la réplique. Le prompt disait seulement « une courte réplique », donc les mots viennent du modèle. Avec l'audio, il dit « You look like you could use a warm hug. », une phrase absente de la requête. Pour contrôler le dialogue, l'étape 3 doit être ajoutée avant l'envoi.
Nous avons regardé la bouche image par image, une toutes les 0,5 seconde. Le clip avec audio commence bouche fermée, reste entrouvert des images 2 à 7, s'ouvre grand à l'image 8, puis se referme. Le clip muet montre fermée, entrouverte, grande ouverte, entrouverte, grande ouverte, et les deux dernières images entrouvertes.


Le même texte choisit aussi un autre personnage : le clip muet est revenu avec un corps orange, une raie châtain gris et une écharpe vert foncé. La phrase du personnage est à écrire comme une suggestion. Sur les deux clips la caméra n'a pas bougé, c'est l'effet de « Fixed camera ».
Peut-on envoyer son propre audio ?
Oui, avec une image ou une vidéo de référence dans la même requête. Notre mp3 de 1,8 seconde est passé comme audio de référence, et ses mots sont revenus dans la piste de sortie.
Nous avons utilisé reference_to_video avec trois pièces : l'image fixe en pâte à modeler comme image de référence, notre enregistrement comme audio de référence, et le prompt ci-dessus. Les paramètres étaient 480P, 5 secondes et audio activé. OmniaKey a répondu 202, la tâche task_3Ay0Ktf2mbYXh9GNZpZ5j9kGyOIzz8Pv a réussi, et 120,2 secondes plus tard un MP4 de 864×496 est arrivé avec une piste aac de 5.06 secondes.
La transcription de cette piste donne une seule phrase : « Why tow it? I told you the keys were in the drawer. » La seconde moitié est exactement notre enregistrement, mot pour mot. Les trois premiers mots ne venaient pas de notre fichier ; la transcription ne distingue pas notre respiration d'un ajout du modèle, donc nous laissons ce qui s'entend.

Dix images à 0,5 seconde d'intervalle montrent seulement que la bouche bouge. Pour l'alignement par phonème, il faudrait des images plus denses et une mesure dédiée, ce que nous n'avons pas fait : les lèvres ne peuvent donc pas être dites synchrones de chaque son.
Les limites viennent de l'API de création de tâche BytePlus (vérifiée le 3 novembre 2026). L'audio accepte 3 clips, de 2 à 15 secondes chacun, 15 secondes au total, en wav ou mp3, 15 Mo par fichier. Un clip peut arriver en URL publique, en chaîne Base64 ou en identifiant de ressource. L'audio seul est refusé : « Audio-only input is not supported; include at least one reference image or video. »
L'image vers vidéo change de plan tout seul
Notre clip image vers vidéo est passé d'un plan large debout à un plan rapproché assis dans la cuisine à l'image 4, alors que le prompt ne demandait ni coupe ni mouvement de caméra.
La première image est un fixe généré pour cet essai : le personnage debout devant un mur blanc chaud, bras le long du corps, en pied, 1254×1254 pixels. Le prompt est celui du dessus, qui l'assied à une table de cuisine. Les images 1 à 3 restent debout, la 4 saute au plan rapproché assis et s'y tient. La bouche est fermée jusqu'à l'image 7, entrouverte à la 8, grande ouverte aux images 9 et 10. La bande-son contient « Well, what do you think? » et des froissements de tissu.

Ici c'est le cadrage qui compte, pas la bouche. Sur ce modèle, le prompt décide où se trouve le personnage et comment bouge la caméra, et la première image décide de son apparence. Un plan important s'écrit dans le prompt.
Le fichier est arrivé en 960×960, pas en 1280×720. La cause : une image carrée en première image et aucune proportion envoyée, et l'API suit alors l'image par défaut. Pour choisir un format, écrivez ratio au lieu de le déduire du nom de la résolution.
La requête en Python
Créer la tâche, interroger l'identifiant, télécharger le MP4 : trois requêtes, bibliothèque standard seule. Le même utilitaire sert aux trois étapes.
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 Mo pour une image, 15 Mo pour l'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"] # expire, donc on télécharge tout de suite
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"))
Trois détails méritent de rester. La clé Idempotency-Key est un UUID neuf par requête : un renvoi récupère la tâche d'origine au lieu de payer deux fois. La boucle d'attente s'arrête au bout de 15 minutes avec une exception, car un délai dépassé signifie que le clip rend encore et un nouvel envoi en achète un second. Le téléchargement se fait au premier succeeded, parce que assets[0].url est un lien signé qui expire.
Les deux autres opérations changent seulement le corps, les utilitaires restent :
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 liste des champs est courte : model, type, operation, input.prompt, input.media[] avec type à first_frame, reference_image, reference_video ou reference_audio, puis parameters.duration, resolution, ratio, generate_audio, watermark. La même forme se trouve dans la documentation de l'API vidéo d'OmniaKey, et le cycle création, interrogation, téléchargement est décrit dans la vue d'ensemble de l'API média. Ce modèle s'essaie depuis la page du modèle Seedance 2.0.
Combien ça coûte
BytePlus facture à la seconde. Le tarif public pour 5 secondes en 16:9 sans entrée vidéo est celui-ci (page des prix ModelArk, vérifiée le 3 novembre 2026) :
| Sortie | Par seconde | Clip de 5 s |
|---|---|---|
| 480p | $0.07 | $0.35 |
| 720p | $0.15 | $0.76 |
| 1080p | $0.37 | $1.87 |
| 4K | $0.78 | $3.89 |
Le calcul à partir de la colonne par seconde donne le même résultat, à un centime d'arrondi près sur la page : 5 secondes × $0.15 = $0.75, contre $0.76 sur la ligne 720p. Nos deux clips texte vers vidéo étaient en 720P sur 5 secondes, donc chacun se situe à ces $0.75.
Une requête avec vidéo en entrée est facturée autrement, et plus cher : une tâche avec vidéo de référence ne rentre pas dans ce tableau (page des prix ModelArk, vérifiée le 3 novembre 2026). OmniaKey facture à la seconde générée et rembourse quand une tâche finit en failed ou canceled (vue d'ensemble de l'API média, vérifiée le 3 novembre 2026) ; le tarif en vigueur est sur la page du modèle.
Ce qui rate
- L'audio seul est refusé. Ajoutez au moins une image ou une vidéo de référence à côté de la piste.
- Les vrais visages sont bloqués. Une image ou une vidéo de référence avec une personne réelle ne passe pas : prenez un personnage en pâte à modeler, dessiné ou en images de synthèse.
generate_audioest actif par défaut. Pour un fichier muet il faut le désactiver ; pour une réplique, on le laisse et le prompt dit que quelqu'un parle.- La taille livrée suit
ratio. 720P a donné 1280×720 depuis du texte, 960×960 depuis un fixe carré sans proportion, et 864×496 en 480P avec 16:9. - La vitesse varie. Quatre tâches de 5 secondes ont pris 259,0, 202,0, 155,3 et 120,2 secondes : comptez deux à cinq minutes et interrogez l'état.
- La durée va de 4 à 15 secondes en sortie, les clips de référence de 2 à 15 secondes chacun, 15 au total. Les quatre fichiers sont revenus à 24 fps.
Questions fréquentes
Si j'envoie un WAV, la bouche suit-elle mon enregistrement ?
Oui, avec une image de référence, et le modèle l'utilise : notre enregistrement est revenu dans la piste de sortie. Savoir si les lèvres tombent sur chaque son du fichier, nos images ne le montrent pas ; une image toutes les 0,5 seconde montre que la bouche bouge, pas une correspondance mesurée.
Pourquoi ma requête audio seule a-t-elle été refusée ?
La série 2.0 n'accepte pas l'audio comme seule entrée. Ajoutez une image ou une vidéo de référence à la même requête et la piste passe avec.
Faut-il activer l'audio pour une réplique ?
Laissez-le actif, c'est la valeur par défaut. Avec false, le fichier n'a aucune piste audio et le personnage ouvre quand même la bouche si le prompt dit qu'il parle, comme notre clip muet.
Quelle longueur pour l'audio de référence ?
Chaque clip fait 2 à 15 secondes, 3 clips au maximum, 15 secondes au total, en wav ou mp3 et 15 Mo par fichier (API de création de tâche BytePlus, vérifiée le 3 novembre 2026). Le nôtre faisait 1,8 seconde, moins que ce minimum, et est quand même passé en URL de données Base64.
Sources vérifiées
- ByteDance Seed : Seedance 2.0, vérifiée le 3 novembre 2026
- BytePlus ModelArk : guide Seedance 2.0, vérifié le 3 novembre 2026
- BytePlus ModelArk : API de création de tâche vidéo, vérifiée le 3 novembre 2026
- BytePlus ModelArk : prix des modèles, vérifiés le 3 novembre 2026
Journal des modifications
- 3 novembre 2026 : première version, les quatre clips ont été générés ce jour-là.
Modèles cités dans cet article
Articles similaires
API Seedance 2.0 : texte-vidéo et image-vidéo en Python
Un seul script crée la tâche, interroge son état et enregistre le MP4. Voici les champs, les limites et deux clips de 5 secondes produits le 30 octobre 2026.
Guide des prompts Seedance 2.5 : structure, exemples et vrais clips
Six prompts, six vrais clips : ce que Seedance 2.5 a suivi, ce qu'il a changé et comment corriger.
Avis Seedance 2.5
La mise à niveau significative réside dans la narration et le contrôle de la production en une seconde 30, et non dans les gros titres non vérifiés de 4K qui circulent autour de lui.
