Bỏ qua tới nội dung
Track 07 · Hướng dẫn

Lồng tiếng video đa ngôn ngữ với skill ElevenLabs Dubbing

Tìm hiểu skill ElevenLabs Dubbing giúp agent lồng tiếng audio, video sang ngôn ngữ khác qua Dubbing Projects API mà vẫn giữ giọng người nói gốc.

Cơ bản@shine190410 phút đọc

Bài này giới thiệu skill dubbing của ElevenLabs: skill làm gì, khi nào agent dùng nó, và cách gọi Dubbing API (dubbing_v2) bằng Python, JavaScript hoặc CLI.

Skill này làm gì

Skill dubbing hướng dẫn agent lồng tiếng audio hoặc video sang ngôn ngữ khác mà vẫn giữ giọng của người nói gốc. Agent dùng skill khi bạn dịch video, podcast hoặc bản ghi âm sang ngôn ngữ khác, bản địa hoá nội dung media, xem lại hoặc sửa bản chép lời và bản dịch lồng tiếng, hoặc tạo lại bản lồng tiếng sau khi chỉnh sửa.

Quy trình (workflow) tổng quát: tạo một project từ file hoặc URL, xem lại và sửa bản chép lời nguồn, thêm một hoặc nhiều ngôn ngữ đích, tinh chỉnh bản dịch theo từng đoạn, rồi tạo lại output.

Thiết lập: xem Hướng dẫn cài đặt. CLI elevenlabs và các SDK tự đọc ELEVENLABS_API_KEY; base URL của REST là https://api.elevenlabs.io, với API key nằm trong header xi-api-key.

Khái niệm

Khái niệmÝ nghĩa
ProjectMột nguồn media (file hoặc URL) cùng bản chép lời nguồn của nó. Được chuẩn bị (chép lời) một lần, sau đó nằm ở trạng thái ready trong khi bạn thêm ngôn ngữ.
Bản chép lời nguồn (source transcript)Các đoạn sửa được (text, speaker, timing) chép lời từ nguồn. Là nguồn sự thật duy nhất để dịch sang mọi ngôn ngữ.
Ngôn ngữ (target)Một ngôn ngữ đầu ra được lồng tiếng. Mỗi ngôn ngữ có bản chép lời riêng (các đoạn nguồn + một bản dịch cho mỗi đoạn) và audio lồng tiếng riêng.
RevisionCác bộ đếm tăng dần độc lập. revision của project tăng khi bản chép lời nguồn bị sửa; revision của một ngôn ngữ tăng khi bản dịch bị sửa hoặc khi sửa nguồn ảnh hưởng tới nó. output_revision của một ngôn ngữ là revision mà audio hiện tại được tạo từ đó; khi nó nhỏ hơn revision, output đã lỗi thời.

Thứ tự thao tác khuyến nghị: chốt bản chép lời nguồn trước khi thêm ngôn ngữ nào. Bản dịch được tạo từ nguồn, nên sửa nguồn trước giúp mọi ngôn ngữ bắt đầu từ văn bản đúng. Sửa nguồn sau khi một ngôn ngữ đã hoàn tất sẽ đánh dấu ngôn ngữ đó stale và cần tạo lại (có tính phí).

Quy trình

  1. Tạo project từ file hoặc URL → queued
  2. Poll project cho tới khi ready
  3. Xem lại và chốt bản chép lời nguồn (sửa/thêm/xoá đoạn)
  4. Thêm một ngôn ngữ cho mỗi đích → queued → processing → completed
  5. Tải outputs.lossless_audio của từng ngôn ngữ khi completed
  6. Tinh chỉnh bản dịch theo từng đoạn nếu cần → ngôn ngữ chuyển sang stale
  7. Tạo lại ngôn ngữ → completed lần nữa với output mới

Bắt đầu nhanh (Python)

python
import os
import time
import requests
from elevenlabs.client import ElevenLabs

elevenlabs = ElevenLabs(api_key=os.getenv("ELEVENLABS_API_KEY"))

# 1. Create a project from a local file (or pass source_url=... instead of file)
with open("promo.mp4", "rb") as f:
    project = elevenlabs.dubbing.project.create(
        file=f,
        source_language="en",
        reference="Q3 marketing video",
    )

# 2. Wait for the source media to be transcribed
while True:
    project = elevenlabs.dubbing.project.get(project.project_id)
    if project.status == "ready":
        break
    if project.status == "failed":
        raise RuntimeError("Project preparation failed")
    time.sleep(5)

# 3. Add a Spanish language target
language = elevenlabs.dubbing.project.language.create(
    project.project_id,
    target_language="es",
)

# 4. Wait for the dub to finish generating
while True:
    language = elevenlabs.dubbing.project.language.get(
        project.project_id, language.language_id
    )
    if language.status == "completed":
        break
    if language.status == "failed":
        raise RuntimeError("Dub generation failed")
    time.sleep(5)

# 5. Download the dubbed audio (signed URL, valid ~1 hour — re-fetch the language for a fresh one)
audio = requests.get(language.outputs.lossless_audio)
with open("promo_es.wav", "wb") as f:
    f.write(audio.content)

Bắt đầu nhanh (JavaScript)

typescript
import { ElevenLabsClient } from "@elevenlabs/elevenlabs-js";
import { writeFile } from "fs/promises";

const elevenlabs = new ElevenLabsClient();

// 1. Create a project (sourceUrl shown; file upload is also supported)
let project = await elevenlabs.dubbing.project.create({
  sourceUrl: "https://example.com/promo.mp4",
  sourceLanguage: "en",
  reference: "Q3 marketing video",
});

// 2. Wait for the source media to be transcribed
while (true) {
  project = await elevenlabs.dubbing.project.get(project.projectId);
  if (project.status === "ready") break;
  if (project.status === "failed") throw new Error("Project preparation failed");
  await new Promise((resolve) => setTimeout(resolve, 5000));
}

// 3. Add a Spanish language target
let language = await elevenlabs.dubbing.project.language.create(project.projectId, {
  targetLanguage: "es",
});

// 4. Wait for the dub to finish generating
while (true) {
  language = await elevenlabs.dubbing.project.language.get(project.projectId, language.languageId);
  if (language.status === "completed") break;
  if (language.status === "failed") throw new Error("Dub generation failed");
  await new Promise((resolve) => setTimeout(resolve, 5000));
}

// 5. Download the dubbed audio from the signed URL
const response = await fetch(language.outputs!.losslessAudio!);
await writeFile("promo_es.wav", Buffer.from(await response.arrayBuffer()));

Bắt đầu nhanh (CLI)

CLI elevenlabs tự đọc ELEVENLABS_API_KEY từ môi trường.

bash
# 1. Create a project (use --source-url "https://..." instead of --file to dub from a URL)
elevenlabs dubbing project create --file promo.mp4 --source-language en
# → {"project_id": "proj_...", "status": "queued", ...}

# 2. Poll until status is "ready"
elevenlabs dubbing project get --project-id proj_...

# 3. Add a target language
elevenlabs dubbing project language create --project-id proj_... --target-language es

# 4. Poll the language until "completed", then download outputs.lossless_audio
elevenlabs dubbing project language get --project-id proj_... --language-id lang_...

Tùy chọn khi tạo project

elevenlabs dubbing project create (REST: POST /v1/dubbing/project, multipart/form-data) nhận hoặc file hoặc source_url (không nhận cả hai):

TrườngBắt buộcGhi chú
filemột trong file/source_urlMedia nguồn cần lồng tiếng (audio hoặc video), tối đa 3 GiB
source_urlmột trong file/source_urlURL công khai để lấy media nguồn
source_languagekhôngMã ISO 639 (ví dụ en). Bỏ trống để tự phát hiện; ngôn ngữ phát hiện được nằm ở trường language của bản chép lời nguồn
referencekhôngNhãn tự do để bạn nhận diện project (tối đa 500 ký tự)
model_idkhôngdubbing_v2 (mặc định)
target_languagekhôngTùy chọn xếp hàng ngôn ngữ đích đầu tiên ngay khi tạo; thêm ngôn ngữ khác bằng language.create
keytermskhôngCác thuật ngữ để ưu tiên khi chép lời/dịch (tên sản phẩm/thương hiệu). Tối đa 1000 thuật ngữ; mỗi thuật ngữ tối đa 50 ký tự và 5 từ; không được chứa <>{}[]\. Trong multipart, lặp lại trường này một lần cho mỗi thuật ngữ

Sửa bản chép lời nguồn

Khi project đã ready, hãy đọc bản chép lời rồi sửa trước khi thêm ngôn ngữ. Mỗi lần sửa làm tăng revision của project. Mỗi đoạn có một id cố định dùng để sửa hoặc xoá. (Chỉ workspace enterprise.)

python
# Read the source transcript
transcript = elevenlabs.dubbing.project.transcript.get(project_id)

# Correct a segment's text — send only the fields to change (text, speaker_id, start_s, end_s)
elevenlabs.dubbing.project.transcript.update_segment(
    project_id,
    segment_id=transcript.segments[0].id,
    text="Welcome to our latest product demo.",
)

# Add a segment (reuse an existing speaker_id so it's dubbed with that speaker's voice)
added = elevenlabs.dubbing.project.transcript.create_segment(
    project_id,
    text="Thanks for watching.",
    speaker_id=transcript.segments[0].speaker_id,
    start_s=40.0,
    end_s=42.0,
)

# Delete a segment
elevenlabs.dubbing.project.transcript.delete_segment(project_id, segment_id=added.segment.id)

Qua CLI: chạy elevenlabs dubbing project transcript get --project-id proj_..., rồi sửa một đoạn chỉ với các trường thay đổi (--text, --speaker-id, --start-s, --end-s):

bash
elevenlabs dubbing project transcript update_segment \
  --project-id proj_... --segment-id seg_... \
  --text "Welcome to our latest product demo."

Tinh chỉnh bản dịch và tạo lại

Bản chép lời của một ngôn ngữ ghép mỗi đoạn nguồn với translation của nó (null = chưa dịch; id đoạn trùng với nguồn). Sửa một bản dịch, rồi tạo lại. (Chỉ workspace enterprise.)

python
# Read the language's translations
target = elevenlabs.dubbing.project.language.transcript.get(project_id, language_id)

# Refine a single translation (pass translation=None to clear it and mark for re-translation)
elevenlabs.dubbing.project.language.transcript.update_segment(
    project_id,
    language_id,
    segment_id=target.segments[0].id,
    translation="Bienvenido a nuestra última demostración de producto.",
)

# Regenerate the dub from the current transcript (charged like a generation)
elevenlabs.dubbing.project.language.transcript.regenerate(project_id, language_id)

Qua CLI: elevenlabs dubbing project language transcript update_segment --project-id proj_... --language-id lang_... --segment-id seg_... --translation "...", rồi elevenlabs dubbing project language transcript regenerate --project-id proj_... --language-id lang_... (trả về 202 Accepted).

Sửa bản dịch chỉ ảnh hưởng tới ngôn ngữ đó. Sau khi sửa, ngôn ngữ đang completed chuyển sang stale, và vẫn phục vụ output cũ cho tới khi bạn tạo lại. Poll cho tới khi completed; lúc đó output_revision bằng revision và outputs.lossless_audio phản ánh bản chép lời hiện tại.

Lồng tiếng sang nhiều ngôn ngữ

Thêm một ngôn ngữ đích cho mỗi ngôn ngữ; mỗi cái được tạo độc lập. Theo dõi tất cả bằng language.list thay vì poll từng cái:

python
for lang in ["es", "fr", "de", "ja"]:
    elevenlabs.dubbing.project.language.create(project_id, target_language=lang)

while True:
    result = elevenlabs.dubbing.project.language.list(project_id)
    if not any(l.status in ("queued", "processing") for l in result.languages):
        break
    time.sleep(5)

Trạng thái

Project:

Trạng tháiÝ nghĩa
queuedĐã tạo; việc lấy nguồn và chuẩn bị đã được xếp hàng
preparingĐang chuẩn bị (chép lời)
readyĐã có bản chép lời nguồn; thêm/tạo ngôn ngữ. Project giữ nguyên ready, tiến độ của từng ngôn ngữ nằm ở chính ngôn ngữ đó
failedChuẩn bị thất bại (ví dụ không lấy được hoặc không giải mã được nguồn)

Ngôn ngữ:

Trạng tháiÝ nghĩa
queuedĐang chờ project chuyển sang ready, hoặc chờ worker tạo bản lồng tiếng
processingĐang tạo bản lồng tiếng
completedHoàn tất; outputs có URL tải đã ký (hiệu lực khoảng 1 giờ, lấy lại để có URL mới)
staleĐã từng hoàn tất nhưng bản chép lời đã thay đổi; giữ output cũ cho tới khi tạo lại
failedTạo thất bại

Bạn có thể thêm ngôn ngữ trước khi project ready: nó ở trạng thái queued và tự bắt đầu khi project ready. Khi thêm ngôn ngữ, bạn có thể truyền model_id (mặc định theo project) và voice_settings (ví dụ {"cloning_strength": 7}, khoảng 0–10, mặc định 7, điều chỉnh mức độ giọng lồng tiếng nhân bản giọng nguồn).

Xử lý lỗi

  • 401: API key không hợp lệ.
  • 409 Conflict khi tạo lại: project chưa ready hoặc ngôn ngữ chưa ổn định (ví dụ đang tạo), hãy chờ rồi thử lại.
  • URL tải hết hạn: outputs.lossless_audio được ký và có hiệu lực khoảng 1 giờ; lấy lại ngôn ngữ để có URL mới.
  • Không dùng được sửa bản chép lời / tạo lại: các endpoint này chỉ dành cho enterprise. Ở gói khác, hãy tạo project với nguồn đã chốt và thêm ngôn ngữ trực tiếp.

Tham khảo

Nguồn

Viết thêm guide cho track này