Passer à la navigation

Traitement batch

Traiter efficacement plusieurs générations lipsync

L’API Batch de Sync Labs traite jusqu’à 500 générations de lip sync dans une seule requête, envoyées sous forme de fichier JSONL ou de tableau JSON de lignes. Elle est conçue pour de grands volumes de clips courts, comme les campagnes vidéo personnalisées ou la localisation de contenu, dont les résultats peuvent arriver sur plusieurs heures.

Qui peut utiliser l’API Batch ?

L’API Batch nécessite un plan Scale ou supérieur et une approbation pour votre organisation. L’accès est désactivé par défaut, y compris pour les nouveaux abonnements Scale. Contactez le support pour demander l’accès. Les utilisateurs existants doivent aussi obtenir une approbation après un examen de leur utilisation et de leur facturation.

Sans approbation, l’organisation reçoit 403 avec errorCode: batch_access_not_enabled, y compris avec dry_run. Après approbation, les autres plans et les comptes gratuits reçoivent 402 avec errorCode: plan_feature_unavailable. requiredPlan vaut scale, ou enterprise sur les plans à crédits.

Le retrait de l’accès à la création n’arrête pas les batchs acceptés. Vous pouvez consulter leur statut et télécharger les résultats disponibles.

  • Un batch contient de 20 à 500 enregistrements par défaut, ou la limite propre à votre compte.
  • Chaque batch actif occupe un emplacement de votre limite de batchs, égale à la limite de concurrence de votre plan. Ses enregistrements ne comptent pas dans la concurrence de /v2/generate.
  • La sortie estimée de chaque enregistrement peut durer au plus 30 secondes. Un enregistrement plus long échoue dans le fichier de résultats avec Input files exceed 30s duration, which is not supported in batch mode, tandis que le reste du batch s’exécute.
  • Chaque enregistrement est facturé comme la génération qu’il exécute.

Pour une requête multipart, envoyez exactement un fichier JSONL dans le champ input (file fonctionne aussi). Les autres champs de fichier ou plusieurs fichiers renvoient 400. Une erreur 503 upload_capacity_unavailable ne crée aucun batch. Renvoyez la même requête après le délai indiqué par Retry-After, ou envoyez un corps JSON avec rows.

Quand utiliser le batch, et quand ne pas l’utiliser

Un batch est un pipeline en file d’attente. Tous les enregistrements sont téléchargés et vérifiés avant qu’aucun ne démarre, et les résultats peuvent prendre des heures, avec un délai cible allant jusqu’à 24 heures. Utilisez-le pour de grands volumes de clips courts qui n’ont pas besoin d’être terminés tout de suite.

Ce n’est pas la façon d’envoyer quelques générations à la fois. Pour cela :

  • Envoyez des requêtes POST /v2/generate normales en parallèle, dans la limite de votre concurrence. Chacune démarre dès qu’elle est admise.
  • Ou laissez un agent utiliser l’outil jobs_create-many du serveur MCP sync. labs, qui lance plusieurs jobs à la fois via l’API normale.

Limites de concurrence batch

Quand vous exécutez déjà autant de batchs que la limite de concurrence de votre plan, l’API renvoie 429 Too Many Requests avec errorCode: concurrency_limit_reached :

{
"statusCode": 429,
"error": "Too Many Requests",
"errorCode": "concurrency_limit_reached",
"message": "Batch concurrency limit reached. You have 3 active batches and your plan allows 3. Please wait for existing batches to complete or upgrade your plan for higher limits.",
"activeBatches": 3,
"concurrencyLimit": 3,
"retryAfterSeconds": 20
}

La réponse inclut un en-tête Retry-After (en secondes) et un en-tête X-Sync-Concurrency-Limit. Plutôt que de réessayer immédiatement, attendez retryAfterSeconds ou la fin de l’un de vos batchs actifs.

Comment créer un job batch ?

1

Préparer votre fichier d'entrée

Créez un fichier JSON Lines (.jsonl) avec vos requêtes de génération. Chaque ligne doit contenir un request_id unique, l’endpoint (doit être "/v2/generate"), et un payload avec le format standard de requête de génération (identique à celui de la API de génération). Le fichier doit être au format JSON Lines (.jsonl) avec une taille maximale de 5MB, et contenir 20 à 500 enregistrements par défaut.

input.jsonl
{"request_id": "request-1", "endpoint": "/v2/generate", "payload": {"model": "lipsync-2", "input": [{"type": "video", "url": "https://assets.sync.so/docs/example-video.mp4"}, {"type": "audio", "url": "https://assets.sync.so/docs/example-audio.wav"}]}}
{"request_id": "request-2", "endpoint": "/v2/generate", "payload": {"model": "lipsync-2", "input": [{"type": "video", "url": "https://assets.sync.so/docs/example-video.mp4"}, {"type": "audio", "url": "https://assets.sync.so/docs/example-audio.wav"}]}}
2

Créer un batch

from sync import Sync
sync = Sync()
batch = sync.batch.create(
input=open("input.jsonl", "rb")
)
print(f"Batch created with ID: {batch.id}")

Au lieu de téléverser un fichier, vous pouvez envoyer un corps application/json avec les enregistrements dans rows. Chaque ligne de rows est le même objet qu’une ligne JSONL, et les deux formes sont validées de la même façon : les limites d’enregistrements ci-dessus, 5 MB maximum une fois écrites en JSONL, et des valeurs request_id uniques. Quand un enregistrement est refusé, l’erreur indique sa ligne. Les refus d’édition de dialogue la renvoient dans un champ lineNumber ; les autres erreurs d’enregistrement, comme un JSON invalide ou un request_id manquant, ne l’indiquent que dans message (par exemple Record at line 4: payload is required). Les lignes comptent les enregistrements non vides, pas les lignes physiques : les lignes vides d’un fichier JSONL sont ignorées ; avec un corps JSON, la ligne N correspond à rows[N-1]. Les exemples ci-dessus montrent deux enregistrements par souci de concision ; un batch en nécessite au moins 20.

Paramètres optionnels :

  • webhook_url: Recevoir des notifications quand le batch est terminé
  • dry_run: Définir true pour valider votre entrée sans lancer le traitement. Une entrée valide renvoie {"status": "VALIDATED"} et ne crée aucun batch.

La création de batch n’est pas couverte par les requêtes idempotentes. Si une requête de création expire, listez vos batchs avec GET /v2/batch avant de renvoyer la requête, afin de ne pas exécuter deux fois les mêmes lignes.

3

Vérifier le statut du batch

Suivez la progression de votre batch en interrogeant son statut :

batch = sync.batch.get(batch_id)
print(f"Status: {batch.status}")
print(f"Progress: {batch.metrics}")

Un batch peut avoir l’un des statuts suivants :

  1. PENDING: Batch créé, en attente de démarrage du traitement
  2. PROCESSING: Les générations sont en cours de traitement
  3. COMPLETED: Toutes les générations sont terminées (avec succès ou échec)
  4. FAILED: Le traitement batch a totalement échoué
4

Vérifier les résultats du batch

Quand un batch se termine, les résultats sont disponibles sous forme de fichier JSON Lines à l’adresse outputUrl de la réponse get batch. Un GET vers cette URL renvoie une redirection 302 vers un fichier de résultats signé, les clients qui suivent automatiquement les redirections peuvent lire directement la réponse JSONL. Chaque ligne contient :

output.jsonl
{"request_id": "request-1", "endpoint": "/v2/generate", "payload": {...}, "status": "COMPLETED", "error": null, "response": {...}, "updated_at": "2024-01-15T10:35:00Z"}
{"request_id": "request-2", "endpoint": "/v2/generate", "payload": {...}, "status": "FAILED", "error": {"code": "INVALID_INPUT", "message": "..."}, "response": null, "updated_at": "2024-01-15T10:35:00Z"}

Le champ response contient les mêmes données que les réponses individuelles de la API de génération. Les noms de champs du fichier de résultats sont en snake_case : la vidéo d’une ligne terminée se trouve donc à response.output_url et son ID de génération à response.id. Associez chaque ligne à votre entrée grâce à request_id.

Pour un exemple complet et fonctionnel, consultez l’exemple de traitement batch dans notre dépôt d’exemples.

Notifications webhook

Lorsque vous fournissez un webhook_url, vous recevrez une notification POST quand le batch se termine ou échoue. Elle est signée avec un header Sync-Signature comme les webhooks de génération et suit la même politique de relance : jusqu’à 6 tentatives sur environ 2 heures, avec le même header Sync-Delivery-Id à chaque tentative.

Contrairement à la réponse de Get Batch, le payload du webhook utilise des noms de champs en camelCase :

webhook_payload.json
{
"id": "batch_abc123",
"createdAt": "2024-01-15T10:30:00Z",
"status": "COMPLETED",
"webhookUrl": "https://your-webhook-url.com/batch-webhook",
"metrics": {
"totalGenerations": 5,
"successCount": 4,
"failedCount": 1,
"pendingCount": 0
},
"options": {},
"outputUrl": "https://api.sync.so/v2/batches/batch_abc123/result"
}

Le webhook de fin de batch peut être livré plusieurs fois pour un même batch. Utilisez le header Sync-Delivery-Id ou l’id du batch pour ignorer les notifications que vous avez déjà traitées.

Lignes d’édition de dialogue (accès anticipé)

Une ligne de batch peut produire le rendu d’un aperçu d’édition de dialogue terminé, au lieu d’associer une vidéo à un nouvel audio. Utilisez-la pour transformer une vidéo enregistrée en de nombreuses variantes, par exemple une par nom de destinataire. Le tutoriel Messages vidéo personnalisés propose un script complet.

Les lignes d’édition de dialogue sont en accès anticipé et s’activent par organisation. Contactez-nous pour les activer. D’ici là, les lignes qui contiennent dialogueEdit sont refusées à l’envoi.

Le payload de chaque ligne contient :

  • model, par exemple sync-3.
  • input avec exactement une vidéo : la même vidéo source que celle à partir de laquelle l’aperçu a été créé.
  • dialogueEdit: {"id": "..."} : l’ID d’un aperçu terminé issu de POST /v2/dialogue-edits dans votre organisation.

N’ajoutez pas d’entrées audio ou texte, ni segments, ni dubParams ; l’aperçu fournit l’audio.

{
"rows": [
{
"request_id": "line-2",
"endpoint": "/v2/generate",
"payload": {
"model": "sync-3",
"input": [{"type": "video", "url": "https://assets.sync.so/docs/example-video.mp4"}],
"dialogueEdit": {"id": "7644754c-bdfc-4d51-a78f-e0cb0cbbd40f"}
}
}
],
"dry_run": true
}

Les mêmes objets de ligne fonctionnent aussi comme lignes d’un fichier JSONL téléversé.

À l’envoi, chaque ligne d’édition de dialogue est développée exactement en la requête que POST /v2/generate construit pour cet aperçu, et elle est facturée comme cette génération. Le payload du fichier de résultats montre la requête développée (la vidéo, l’audio de l’aperçu et les segments modifiés), et non la ligne que vous avez envoyée. Envoyez d’abord le batch avec dry_run: true : il exécute toutes les vérifications ci-dessous, y compris le développement, sans effectuer aucun rendu.

  • Toutes les lignes d’édition de dialogue d’un même batch doivent utiliser des aperçus créés à partir de la même vidéo source. Pour plusieurs vidéos, envoyez un batch par vidéo.
  • Les limites habituelles des batchs s’appliquent : 20 à 500 enregistrements par défaut et 5 MB. L’expansion ajoute l’audio de prévisualisation et les segments modifiés à chaque ligne. La limite de 5 MB s’applique aussi au batch développé. Un batch de moins de 5 MB à l’envoi peut donc être refusé avec une erreur de taille de fichier et le statut 400. Une simulation signale aussi cette erreur. Dans ce cas, répartissez les lignes dans des batchs plus petits.
  • La plupart des aperçus sont rendus sous forme de segments modifiés de la vidéo. Un aperçu qui ne peut être rendu qu’en lip sync sur la vidéo entière n’est accepté dans un batch que si ce rendu dure 30 secondes ou moins ; générez les plus longs avec POST /v2/generate.

Refus des lignes d’édition de dialogue

Si une ligne d’édition de dialogue ne peut pas être rendue, toute la requête est refusée et aucun batch n’est créé. La réponse contient l’errorCode que POST /v2/generate renverrait pour cet aperçu, ainsi que le lineNumber de la première ligne en échec :

{
"statusCode": 422,
"errorCode": "dialogue_edit_not_found",
"lineNumber": 3,
"message": "Record at line 3: The dialogue edit was not found in this organization."
}
errorCodeStatutCauseCorrection
dialogue_edit_not_found422L’ID est inconnu ou appartient à une autre organisation.Utilisez un aperçu créé par votre organisation.
dialogue_edit_not_completed422L’aperçu est encore PENDING ou PROCESSING, ou il est FAILED.Tant qu’il est en attente ou en cours, interrogez GET /v2/dialogue-edits/{id} jusqu’à ce qu’il soit terminé, puis envoyez le batch. Un aperçu FAILED est définitif : créez-en un nouveau.
dialogue_edit_source_mismatch422La vidéo de la ligne n’est pas celle à partir de laquelle l’aperçu a été créé.Envoyez la vidéo source d’origine de l’aperçu.
dialogue_edit_retime_required422Il manque à l’aperçu le recalage temporel nécessaire à son rendu (segmentLipsyncEnabled ou sectionExpansionEnabled vaut false pour cet aperçu).Créez un nouvel aperçu. S’il indique toujours false, contactez-nous.
dialogue_edit_removal_too_large422La modification supprime plus de parole que les images environnantes ne peuvent en absorber.Restaurez certains mots et créez un nouvel aperçu.
dialogue_edit_audio_conflict422La ligne contient aussi une entrée audio ou texte, segments ou dubParams.N’envoyez que l’entrée vidéo et dialogueEdit.
dialogue_edit_unsupported422L’API ne peut pas rendre cet aperçu, y compris un rendu de la vidéo entière de plus de 30 secondes.Créez un nouvel aperçu de la vidéo entière avec une clé API, ou rendez celui-ci avec POST /v2/generate.
dialogue_edit_batch_mixed_sources422Les aperçus du batch proviennent de vidéos sources différentes.Envoyez un batch par vidéo source.
generation_input_validation_failed400dialogueEdit n’est pas un objet avec un id UUID, ou input ne contient pas exactement une vidéo.Corrigez la structure de la ligne.

Seule la première ligne en échec est signalée. Corrigez-la et relancez le dry run jusqu’à ce qu’il renvoie {"status": "VALIDATED"}.

Ressources associées

  • Rate Limits — comprendre le rate limiting API pour planifier efficacement vos tailles de batch
  • Webhooks Guide — configurer les notifications webhook pour les événements de fin de batch
  • gestion des erreurs — référence des codes d’erreur spécifiques au batch et dépannage