Skip to content

Commit

Permalink
Add python example for dubbing a video (elevenlabs#25)
Browse files Browse the repository at this point in the history
* fix: Handle by pre-commit

* fix: Do ruff fix
  • Loading branch information
devman0129 authored May 8, 2024
1 parent 22dc216 commit ab9c050
Show file tree
Hide file tree
Showing 4 changed files with 207 additions and 82 deletions.
82 changes: 0 additions & 82 deletions examples/dubbing/python/create_a_dub.py

This file was deleted.

71 changes: 71 additions & 0 deletions examples/dubbing/python/create_a_dub_from_file.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import os
from typing import Optional

from dotenv import load_dotenv
from dubbing_utils import download_dubbed_file, wait_for_dubbing_completion
from elevenlabs.client import ElevenLabs

# Load environment variables
load_dotenv()

# Retrieve the API key
ELEVENLABS_API_KEY = os.getenv("ELEVENLABS_API_KEY")
if not ELEVENLABS_API_KEY:
raise ValueError(
"ELEVENLABS_API_KEY environment variable not found. "
"Please set the API key in your environment variables."
)

client = ElevenLabs(api_key=ELEVENLABS_API_KEY)


def create_dub_from_file(
input_file_path: str,
file_format: str,
source_language: str,
target_language: str,
) -> Optional[str]:
"""
Dubs an audio or video file from one language to another and saves the output.
Args:
input_file_path (str): The file path of the audio or video to dub.
file_format (str): The file format of the input file.
source_language (str): The language of the input file.
target_language (str): The target language to dub into.
Returns:
Optional[str]: The file path of the dubbed file or None if operation failed.
"""
if not os.path.isfile(input_file_path):
raise FileNotFoundError(f"The input file does not exist: {input_file_path}")

with open(input_file_path, "rb") as audio_file:
response = client.dubbing.dub_a_video_or_an_audio_file(
file=(os.path.basename(input_file_path), audio_file, file_format),
target_lang=target_language,
mode="automatic",
source_lang=source_language,
num_speakers=1,
watermark=False, # reduces the characters used if enabled, only works for videos not audio
)

dubbing_id = response.dubbing_id
if wait_for_dubbing_completion(dubbing_id):
output_file_path = download_dubbed_file(dubbing_id, target_language)
return output_file_path
else:
return None


if __name__ == "__main__":
result = create_dub_from_file(
"../example_speech.mp3", # Input file path
"audio/mpeg", # File format
"en", # Source language
"es", # Target language
)
if result:
print("Dubbing was successful! File saved at:", result)
else:
print("Dubbing failed or timed out.")
64 changes: 64 additions & 0 deletions examples/dubbing/python/create_a_dub_from_url.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import os
from typing import Optional

from dotenv import load_dotenv
from dubbing_utils import download_dubbed_file, wait_for_dubbing_completion
from elevenlabs.client import ElevenLabs

# Load environment variables
load_dotenv()

# Retrieve the API key
ELEVENLABS_API_KEY = os.getenv("ELEVENLABS_API_KEY")
if not ELEVENLABS_API_KEY:
raise ValueError(
"ELEVENLABS_API_KEY environment variable not found. "
"Please set the API key in your environment variables."
)

client = ElevenLabs(api_key=ELEVENLABS_API_KEY)


def create_dub_from_url(
source_url: str,
source_language: str,
target_language: str,
) -> Optional[str]:
"""
Downloads a video from a URL, and creates a dubbed version in the target language.
Args:
source_url (str): The URL of the source video to dub. Can be a YouTube link, TikTok, X (Twitter) or a Vimeo link.
source_language (str): The language of the source video.
target_language (str): The target language to dub into.
Returns:
Optional[str]: The file path of the dubbed file or None if operation failed.
"""

response = client.dubbing.dub_a_video_or_an_audio_file(
source_url=source_url,
target_lang=target_language,
mode="automatic",
source_lang=source_language,
num_speakers=1,
watermark=True, # reduces the characters used
)

dubbing_id = response.dubbing_id
if wait_for_dubbing_completion(dubbing_id):
output_file_path = download_dubbed_file(dubbing_id, target_language)
return output_file_path
else:
return None


if __name__ == "__main__":
source_url = "https://www.youtube.com/watch?v=0EqSXDwTq6U" # Charlie bit my finger
source_language = "en"
target_language = "fr"
result = create_dub_from_url(source_url, source_language, target_language)
if result:
print("Dubbing was successful! File saved at:", result)
else:
print("Dubbing failed or timed out.")
72 changes: 72 additions & 0 deletions examples/dubbing/python/dubbing_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import os
import time

from dotenv import load_dotenv
from elevenlabs.client import ElevenLabs

# Load environment variables
load_dotenv()

# Retrieve the API key
ELEVENLABS_API_KEY = os.getenv("ELEVENLABS_API_KEY")
if not ELEVENLABS_API_KEY:
raise ValueError(
"ELEVENLABS_API_KEY environment variable not found. "
"Please set the API key in your environment variables."
)

client = ElevenLabs(api_key=ELEVENLABS_API_KEY)


def download_dubbed_file(dubbing_id: str, language_code: str) -> str:
"""
Downloads the dubbed file for a given dubbing ID and language code.
Args:
dubbing_id: The ID of the dubbing project.
language_code: The language code for the dubbing.
Returns:
The file path to the downloaded dubbed file.
"""
dir_path = f"data/{dubbing_id}"
os.makedirs(dir_path, exist_ok=True)

file_path = f"{dir_path}/{language_code}.mp4"
with open(file_path, "wb") as file:
for chunk in client.dubbing.get_dubbed_file(dubbing_id, language_code):
file.write(chunk)

return file_path


def wait_for_dubbing_completion(dubbing_id: str) -> bool:
"""
Waits for the dubbing process to complete by periodically checking the status.
Args:
dubbing_id (str): The dubbing project id.
Returns:
bool: True if the dubbing is successful, False otherwise.
"""
MAX_ATTEMPTS = 120
CHECK_INTERVAL = 10 # In seconds

for _ in range(MAX_ATTEMPTS):
metadata = client.dubbing.get_dubbing_project_metadata(dubbing_id)
if metadata.status == "dubbed":
return True
elif metadata.status == "dubbing":
print(
"Dubbing in progress... Will check status again in",
CHECK_INTERVAL,
"seconds.",
)
time.sleep(CHECK_INTERVAL)
else:
print("Dubbing failed:", metadata.error_message)
return False

print("Dubbing timed out")
return False

0 comments on commit ab9c050

Please sign in to comment.