制作一支带旁白的视频
一个端到端示例:用 LLM 写脚本、生成视频片段、合成配音,再把它们合到一起——全程只用一把 API Key。
本教程在一个脚本里串起三类模型:语言模型写旁白,视频模型生成画面,语音模型把旁白读出来。它很好地说明了「一套 API、一个余额打通各类模型」的实际价值。
你需要准备: Python 3.9+、一把 API Key,以及 ffmpeg(如果最后想把音视频合流的话)。
本教程会真实提交生成任务并消耗真实额度。视频是最贵的一环——调试阶段先用较短的时长,如果想先算清楚具体花多少,可以参考价格估算。
准备工作
pip install requests
export ATLASCLOUD_API_KEY="your-api-key"第 1 步 —— 公共辅助函数
每个媒体任务都是「提交 + 轮询」这同一套流程,所以只写一次就够了。
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:
"""提交任务。注意参数是平铺的,不要包在 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:
"""轮询到终态,间隔逐步放大。"""
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"任务失败: {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 path第 2 步 —— 用 LLM 写旁白
语言模型用的是另一个 Base URL,而且是同步的,所以不走 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)第 3 步 —— 生成画面
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")视频生成耗时是分钟级,不是秒级。生产环境请注册 Webhook,让任务完成后回调你,而不是一直挂着一个轮询循环。
第 4 步 —— 合成配音
第 2 步生成的旁白在这里作为输入。语音、音乐和转写共用同一个端点——具体做哪件事由模型决定。
audio_id = submit(
"generateAudio",
"bytedance/seed-audio-1.0",
text=narration,
format="mp3",
sample_rate=44100,
speech_rate=-5, # 略慢一点,旁白更好懂
)
audio = wait(audio_id)
download(audio["outputs"][0], "voiceover.mp3")完整参数(包括音色参考)参见音频模型。
第 5 步 —— 合流
ffmpeg -i footage.mp4 -i voiceover.mp3 \
-c:v copy -c:a aac -shortest narrated.mp4可选 —— 生成字幕
把配音再送进一个转写模型,就能拿到词级时间戳,用来做字幕。
stt_id = submit(
"generateAudio",
"bytedance/seed-asr-2.0",
audio_url=audio["outputs"][0], # 注意字段名是 audio_url
enable_punc=True,
show_utterances=True,
)
stt = wait(stt_id)
# 转写模型的 outputs[0] 是文本本身,不是文件 URL
print(stt["outputs"][0])
for word in stt.get("stt_result", {}).get("words", [])[:10]:
print(word["start"], word["end"], word["text"])转写模型接收的是 audio_url,但另一些语音转文字模型接收的却是 audio。请查阅模型的 API 参考——字段名传错会直接校验失败。
接下来可以做什么
相关内容
Last updated on