Traduction Vidéo (HeyGen)
Traduisez et doublez des vidéos existantes en plusieurs langues, en conservant la synchronisation labiale et les intonations naturelles. Fournissez une URL de vidéo ou un identifiant de vidéo HeyGen — pas besoin de créer la vidéo sur HeyGen au préalable.
Authentification
Toutes les requêtes nécessitent l'en-tête X-Api-Key. Définissez la variable d'environnement HEYGEN_API_KEY.
curl -X POST "https://api.heygen.com/v2/video_translate" \
-H "X-Api-Key: $HEYGEN_API_KEY" \
-H "Content-Type: application/json" \
-d '{"video_url": "https://exemple.com/video.mp4", "output_language": "es-ES"}'
Flux de travail par défaut
- Fournissez une URL de vidéo ou un identifiant de vidéo HeyGen
- Appelez
POST /v2/video_translateavec la langue cible - Interrogez
GET /v2/video_translate/{translate_id}jusqu'à ce que le statut soitcompleted - Téléchargez la vidéo traduite depuis l'URL renvoyée
Création d'une tâche de traduction
Champs de la requête
| Champ | Type | Oblig. | Description |
|---|---|---|---|
video_url | string | O* | URL de la vidéo à traduire (*ou video_id) |
video_id | string | O* | Identifiant HeyGen de la vidéo (*ou video_url) |
output_language | string | O | Code de la langue cible (p. ex., "es-ES") |
title | string | Nom de la vidéo traduite | |
translate_audio_only | boolean | Audio uniquement, pas de synchronisation labiale (plus rapide) | |
speaker_num | number | Nombre de locuteurs dans la vidéo | |
callback_id | string | Identifiant personnalisé pour le suivi webhook | |
callback_url | string | URL de notification de fin |
Il faut fournir video_url ou video_id.
curl
curl -X POST "https://api.heygen.com/v2/video_translate" \
-H "X-Api-Key: $HEYGEN_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"video_url": "https://exemple.com/video-originale.mp4",
"output_language": "es-ES",
"title": "Version Espagnole"
}'
TypeScript
interface VideoTranslateRequest {
video_url?: string;
video_id?: string;
output_language: string;
title?: string;
translate_audio_only?: boolean;
speaker_num?: number;
callback_id?: string;
callback_url?: string;
}
interface VideoTranslateResponse {
error: null | string;
data: {
video_translate_id: string;
};
}
async function translateVideo(config: VideoTranslateRequest): Promise<string> {
const response = await fetch("https://api.heygen.com/v2/video_translate", {
method: "POST",
headers: {
"X-Api-Key": process.env.HEYGEN_API_KEY!,
"Content-Type": "application/json",
},
body: JSON.stringify(config),
});
const json: VideoTranslateResponse = await response.json();
if (json.error) {
throw new Error(json.error);
}
return json.data.video_translate_id;
}
Python
import requests
import os
def translate_video(config: dict) -> str:
response = requests.post(
"https://api.heygen.com/v2/video_translate",
headers={
"X-Api-Key": os.environ["HEYGEN_API_KEY"],
"Content-Type": "application/json"
},
json=config
)
data = response.json()
if data.get("error"):
raise Exception(data["error"])
return data["data"]["video_translate_id"]
Langues prises en charge
| Langue | Code | Remarques |
|---|---|---|
| Anglais (États-Unis) | en-US | Source par défaut |
| Espagnol (Espagne) | es-ES | Espagnol européen |
| Espagnol (Mexique) | es-MX | Amérique latine |
| Français | fr-FR | Standard |
| Allemand | de-DE | Standard |
| Italien | it-IT | Standard |
| Portugais (Brésil) | pt-BR | Portugais brésilien |
| Japonais | ja-JP | Standard |
| Coréen | ko-KR | Standard |
| Chinois (Mandarin) | zh-CN | Chinois simplifié |
| Hindi | hi-IN | Standard |
| Arabe | ar-SA | Arabe standard moderne |
Options de traduction
Traduction de base (avec synchronisation labiale)
const config = {
video_url: "https://exemple.com/original.mp4",
output_language: "es-ES",
title: "Traduction Espagnole",
};
Traduction audio uniquement (plus rapide, sans synchronisation labiale)
const config = {
video_url: "https://exemple.com/original.mp4",
output_language: "es-ES",
translate_audio_only: true,
};
Vidéos à plusieurs locuteurs
const config = {
video_url: "https://exemple.com/interview.mp4",
output_language: "fr-FR",
speaker_num: 2,
};
Options avancées (API v4)
Pour un contrôle plus poussé de la traduction :
interface VideoTranslateV4Request {
input_video_id?: string;
google_url?: string;
output_languages: string[]; // Plusieurs langues en un seul appel
name: string;
srt_key?: string; // Sous-titres SRT personnalisés
instruction?: string;
vocabulary?: string[]; // Termes à conserver tels quels
brand_voice_id?: string;
speaker_num?: number;
keep_the_same_format?: boolean;
input_language?: string;
enable_video_stretching?: boolean;
disable_music_track?: boolean;
enable_speech_enhancement?: boolean;
srt_role?: "input" | "output";
translate_audio_only?: boolean;
}
Plusieurs langues de sortie
const config = {
input_video_id: "original_video_id",
output_languages: ["es-ES", "fr-FR", "de-DE"],
name: "Traductions multilingues",
};
Vocabulaire personnalisé (conserver des termes spécifiques)
const config = {
video_url: "https://exemple.com/demo-produit.mp4",
output_language: "ja-JP",
vocabulary: ["SuperWidget", "Pro Max", "TechCorp"],
};
Sous-titres SRT personnalisés
const config = {
video_url: "https://exemple.com/video.mp4",
output_language: "es-ES",
srt_key: "chemin/vers/sous-titres-personnalises.srt",
srt_role: "input",
};
Vérification du statut de la traduction
curl
curl -X GET "https://api.heygen.com/v2/video_translate/{translate_id}" \
-H "X-Api-Key: $HEYGEN_API_KEY"
TypeScript
interface TranslateStatusResponse {
error: null | string;
data: {
id: string;
status: "pending" | "processing" | "completed" | "failed";
video_url?: string;
message?: string;
};
}
async function getTranslateStatus(translateId: string): Promise<TranslateStatusResponse["data"]> {
const response = await fetch(
`https://api.heygen.com/v2/video_translate/${translateId}`,
{ headers: { "X-Api-Key": process.env.HEYGEN_API_KEY! } }
);
const json: TranslateStatusResponse = await response.json();
if (json.error) {
throw new Error(json.error);
}
return json.data;
}
Interrogation jusqu'à la fin
Les traductions prennent plus de temps que la génération vidéo standard — prévoyez jusqu'à 30 minutes.
async function waitForTranslation(
translateId: string,
maxWaitMs = 1800000,
pollIntervalMs = 30000
): Promise<string> {
const startTime = Date.now();
while (Date.now() - startTime < maxWaitMs) {
const status = await getTranslateStatus(translateId);
switch (status.status) {
case "completed":
return status.video_url!;
case "failed":
throw new Error(status.message || "Échec de la traduction");
default:
console.log(`Statut : ${status.status}...`);
await new Promise((r) => setTimeout(r, pollIntervalMs));
}
}
throw new Error("Délai d'attente de la traduction dépassé");
}
Flux de travail complet
async function translateAndDownload(
videoUrl: string,
targetLanguage: string
): Promise<string> {
console.log(`Début de la traduction vers ${targetLanguage}...`);
const translateId = await translateVideo({
video_url: videoUrl,
output_language: targetLanguage,
});
console.log(`ID de traduction : ${translateId}`);
console.log("Traitement de la traduction...");
const translatedVideoUrl = await waitForTranslation(translateId);
console.log(`Traduction terminée : ${translatedVideoUrl}`);
return translatedVideoUrl;
}
const spanishVideo = await translateAndDownload(
"https://exemple.com/ma-video.mp4",
"es-ES"
);
Traduction par lots
Traduire en plusieurs langues en parallèle :
async function translateToMultipleLanguages(
sourceVideoUrl: string,
targetLanguages: string[]
): Promise<Record<string, string>> {
const results: Record<string, string> = {};
const translatePromises = targetLanguages.map(async (lang) => {
const translateId = await translateVideo({
video_url: sourceVideoUrl,
output_language: lang,
});
return { lang, translateId };
});
const translationJobs = await Promise.all(translatePromises);
for (const job of translationJobs) {
try {
const videoUrl = await waitForTranslation(job.translateId);
results[job.lang] = videoUrl;
} catch (error) {
results[job.lang] = `erreur : ${error.message}`;
}
}
return results;
}
const translations = await translateToMultipleLanguages(
"https://exemple.com/original.mp4",
["es-ES", "fr-FR", "de-DE", "ja-JP"]
);
Fonctionnalités
- Synchronisation labiale — Ajuste automatiquement les mouvements des lèvres du locuteur pour correspondre à l'audio traduit
- Clonage vocal — L'audio traduit correspond aux caractéristiques vocales du locuteur d'origine
- Contrôle de la piste musicale — Option pour supprimer la musique de fond avec
disable_music_track: true - Amélioration de la parole — Améliore la qualité audio avec
enable_speech_enhancement: true
Bonnes pratiques
- La qualité de la source compte — Utilisez des vidéos sources de haute qualité pour de meilleurs résultats
- Audio clair — Les vidéos avec une parole claire se traduisent mieux
- Un seul locuteur — Meilleurs résultats avec un seul locuteur
- Rythme modéré — Un débit de parole très rapide peut affecter la qualité
- Testez d'abord — Essayez avec des clips courts avant de traduire des vidéos longues
- Prévoyez du temps supplémentaire — La traduction prend plus de temps que la génération vidéo (jusqu'à 30 minutes)
Gestion des erreurs
Erreurs courantes et comment les gérer :
async function safeTranslate(
videoUrl: string,
targetLanguage: string
): Promise<{ success: boolean; result?: string; error?: string }> {
try {
const url = await translateAndDownload(videoUrl, targetLanguage);
return { success: true, result: url };
} catch (error) {
if (error.message.includes("quota")) {
return { success: false, error: "Crédits insuffisants" };
}
if (error.message.includes("duration")) {
return { success: false, error: "Vidéo trop longue" };
}
if (error.message.includes("format")) {
return { success: false, error: "Format vidéo non pris en charge" };
}
return { success: false, error: error.message };
}
}