Membuat Video Bernarasi
Panduan menyeluruh yang menulis naskah dengan LLM, membuat klip video, menyintesis sulih suara, lalu menggabungkan semuanya — hanya dengan satu API key.
Tutorial ini merangkai tiga jenis model dalam satu skrip: model bahasa menulis narasinya, model video membuat rekamannya, dan model suara membacakan naskah tersebut. Ini contoh nyata mengapa satu API dan satu saldo yang berlaku lintas jenis model itu bermanfaat.
Yang Anda butuhkan: Python 3.9+, sebuah API key, dan ffmpeg jika di akhir Anda ingin menggabungkan audio dengan videonya.
Langkah-langkah ini menjalankan tugas pembuatan yang sesungguhnya dan menghabiskan kredit sungguhan. Video adalah bagian yang mahal — mulailah dengan durasi pendek selama Anda masih bereksperimen, dan gunakan estimasi harga jika Anda ingin mengetahui angka pastinya lebih dulu.
Persiapan
pip install requests
export ATLASCLOUD_API_KEY="your-api-key"Langkah 1 — Fungsi bantu bersama
Setiap tugas media mengikuti pola kirim-lalu-polling yang sama, jadi definisikan sekali saja.
import os, time, requests
API_KEY = os.environ["ATLASCLOUD_API_KEY"]
BASE = "https://api.atlascloud.ai/api/v1"
HEADERS = {"Authorization": f"Bearer {API_KEY}"}
TERMINAL = {"completed", "succeeded", "failed", "timeout"}
def submit(endpoint: str, model: str, **params) -> str:
"""Kirim sebuah tugas. Parameternya rata — jangan membungkusnya dalam objek `input`."""
r = requests.post(f"{BASE}/model/{endpoint}",
headers=HEADERS, json={"model": model, **params}, timeout=60)
r.raise_for_status()
return r.json()["data"]["id"]
def wait(prediction_id: str, timeout: int = 900) -> dict:
"""Lakukan polling sampai status terminal, dengan backoff yang makin panjang."""
deadline, delay = time.time() + timeout, 2.0
while time.time() < deadline:
r = requests.get(f"{BASE}/model/prediction/{prediction_id}",
headers=HEADERS, timeout=30)
r.raise_for_status()
data = r.json()["data"]
if data.get("status") in TERMINAL:
if data["status"] in ("failed", "timeout"):
raise RuntimeError(f"Job failed: {data.get('error') or data['status']}")
return data
time.sleep(delay)
delay = min(delay * 1.5, 10.0)
raise TimeoutError(prediction_id)
def download(url: str, path: str) -> str:
r = requests.get(url, timeout=300)
r.raise_for_status()
with open(path, "wb") as f:
f.write(r.content)
return pathLangkah 2 — Menulis naskah dengan LLM
Model bahasa memakai base URL yang berbeda dan bersifat sinkron, sehingga tidak melewati submit/wait.
def write_narration(topic: str) -> str:
r = requests.post(
"https://api.atlascloud.ai/v1/chat/completions",
headers={**HEADERS, "Content-Type": "application/json"},
json={
"model": "deepseek-ai/deepseek-v3.2",
"messages": [
{"role": "system",
"content": "You write narration for short videos. "
"Reply with two sentences of spoken narration and nothing else."},
{"role": "user", "content": f"Topic: {topic}"},
],
"max_tokens": 200,
},
timeout=120,
)
r.raise_for_status()
return r.json()["choices"][0]["message"]["content"].strip()
narration = write_narration("how ocean waves shape a coastline")
print(narration)Langkah 3 — Membuat rekamannya
video_id = submit(
"generateVideo",
"alibaba/wan-2.5/text-to-video",
prompt="slow aerial shot of waves breaking against a rocky coastline at golden hour",
duration=5,
)
video = wait(video_id)
download(video["outputs"][0], "footage.mp4")Pembuatan video memakan waktu beberapa menit, bukan beberapa detik. Di produksi, daftarkan sebuah webhook dan biarkan tugas tersebut menghubungi Anda kembali, alih-alih membiarkan loop polling terus terbuka.
Langkah 4 — Menyintesis sulih suara
Narasi dari langkah 2 menjadi masukan di sini. Suara, musik, dan transkripsi memakai endpoint yang sama — modelnyalah yang menentukan hasil mana yang Anda dapatkan.
audio_id = submit(
"generateAudio",
"bytedance/seed-audio-1.0",
text=narration,
format="mp3",
sample_rate=44100,
speech_rate=-5, # Tempo yang sedikit lebih lambat terdengar lebih pas sebagai narasi
)
audio = wait(audio_id)
download(audio["outputs"][0], "voiceover.mp3")Lihat Model Audio untuk kumpulan parameter lengkapnya, termasuk rujukan suara.
Langkah 5 — Menggabungkan
ffmpeg -i footage.mp4 -i voiceover.mp3 \
-c:v copy -c:a aac -shortest narrated.mp4Opsional — Membuat subtitel
Umpankan kembali sulih suaranya ke model transkripsi untuk memperoleh waktu per kata bagi subtitel.
stt_id = submit(
"generateAudio",
"bytedance/seed-asr-2.0",
audio_url=audio["outputs"][0], # Perhatikan nama bidangnya: audio_url
enable_punc=True,
show_utterances=True,
)
stt = wait(stt_id)
# Pada model transkripsi, outputs[0] adalah teksnya sendiri, bukan URL berkas
print(stt["outputs"][0])
for word in stt.get("stt_result", {}).get("words", [])[:10]:
print(word["start"], word["end"], word["text"])Model transkripsi menerima audio_url, tetapi sebagian model speech-to-text lain justru menerima audio. Periksa referensi API model tersebut — mengirimkan nama bidang yang keliru akan gagal validasi.
Langkah berikutnya
- Ganti model videonya dengan model yang menerima gambar rujukan, lalu tentukan tampilannya dari gambar diam yang Anda sediakan
- Pindahkan polling ke webhook agar tugas yang lama tidak memblokir proses Anda
- Jalankan beberapa klip secara paralel lalu gabungkan menjadi rangkaian yang lebih panjang
- Tambahkan penanganan percobaan ulang dari Error & Batas Laju
Terkait
Last updated on