OpenShorts integrates ElevenLabs Dubbing API to translate video audio into 30+ languages while preserving voice characteristics, timing, and emotional tone. The system uses AI voice cloning to match the original speaker’s voice in the target language.
def get_dubbing_status(dubbing_id: str, api_key: str) -> dict: """ Check the status of a dubbing project. Returns: dict with status ('dubbing', 'dubbed', 'failed') and other metadata """ url = f"{ELEVENLABS_API_BASE}/dubbing/{dubbing_id}" headers = { "xi-api-key": api_key, } with httpx.Client(timeout=30.0) as client: response = client.get(url, headers=headers) return response.json()
def download_dubbed_video( dubbing_id: str, target_language: str, output_path: str, api_key: str) -> str: """ Download the dubbed video file. Returns: Path to the downloaded file """ url = f"{ELEVENLABS_API_BASE}/dubbing/{dubbing_id}/audio/{target_language}" headers = { "xi-api-key": api_key, } with httpx.Client(timeout=120.0) as client: with client.stream("GET", url, headers=headers) as response: with open(output_path, "wb") as f: for chunk in response.iter_bytes(chunk_size=8192): f.write(chunk) return output_path
The translate_video() function orchestrates the entire workflow:
translate.py
def translate_video( video_path: str, output_path: str, target_language: str, api_key: str, source_language: Optional[str] = None, max_wait_seconds: int = 600, poll_interval: int = 5,) -> str: """ Translate a video to a target language using ElevenLabs dubbing. This is a blocking call that waits for the dubbing to complete. Args: video_path: Path to input video output_path: Path to save translated video target_language: Target language code (e.g., 'es', 'fr', 'de') api_key: ElevenLabs API key source_language: Source language code (auto-detected if None) max_wait_seconds: Maximum time to wait for dubbing (default 10 min) poll_interval: Seconds between status checks Returns: Path to the translated video """ # Create dubbing project project = create_dubbing_project( video_path=video_path, target_language=target_language, api_key=api_key, source_language=source_language, ) dubbing_id = project["dubbing_id"] expected_duration = project.get("expected_duration_sec", 60) print(f"[ElevenLabs] Dubbing ID: {dubbing_id}, Expected duration: {expected_duration}s") # Poll for completion start_time = time.time() while True: elapsed = time.time() - start_time if elapsed > max_wait_seconds: raise Exception(f"Dubbing timed out after {max_wait_seconds} seconds") status = get_dubbing_status(dubbing_id, api_key) current_status = status.get("status", "unknown") print(f"[ElevenLabs] Status: {current_status} (elapsed: {int(elapsed)}s)") if current_status == "dubbed": # Download the result return download_dubbed_video( dubbing_id=dubbing_id, target_language=target_language, output_path=output_path, api_key=api_key, ) elif current_status == "failed": error = status.get("error", "Unknown error") raise Exception(f"Dubbing failed: {error}") # Still processing, wait and poll again time.sleep(poll_interval)
ElevenLabs automatically clones the original speaker’s voice:
Automatic Voice Matching: The mode: "automatic" parameter enables AI voice cloning that preserves:
Voice timbre and characteristics
Speaking pace and rhythm
Emotional tone and inflection
Lip sync timing (video only)
data = { "target_lang": target_language, "mode": "automatic", # AI voice cloning "num_speakers": "0", # Auto-detect number of speakers "watermark": "false",}