銷豹 AI API 數字人口播影片實戰:用 Python 完成模板合成、異步輪詢與批量出片
数字人口播视频 API 实战:Python 跑通模板合成、异步轮询与批量出片
銷豹 AI API 可將已有真人或數字人口播影片提交至模板進行智能剪輯,並透過任務查詢取得成片連結;它不會直接把文案轉成數字人影片。文章以 Python 示範讀取模板、建立異步合成任務及輪詢狀態,並説明影片限制、輪詢注意事項和計費方式。720p 每輸入秒 3 點,1080p 每輸入秒 4 點。
简介: 本文详解如何用销豹AI API实现真人口播视频的自动化剪辑:将素材整理、字幕匹配、模板包装等重复环节封装为API,仅需维护文案、人物视频与模板,程序自动完成任务提交、状态轮询与成片归档。附Python完整示例与工程实践要点。(239字)
对于需要持续更新口播视频的团队,真正耗时的往往不是写文案,而是重复执行素材整理、字幕匹配、模板包装、导出和检查。
把这些重复环节封装成 API 后,内容人员只需要维护文案、人物视频和模板,程序负责提交任务、查询状态和归档成片。一个人管理多条内容生产线,才有了工程上的可行性。
本文以销豹 AI API 开放平台的智能剪辑能力为例,用 Python 跑通下面这条链路:
选择 realMan 模板
↓
读取模板详情,确认画布与图层
↓
提交已有真人/数字人口播视频
↓
realman_broadcast 创建异步合成任务
↓
task_query 轮询任务状态
↓
获取 video_url,归档成片
先说明一个容易混淆的概念:realman_broadcast 的作用是对已有真人或数字人口播视频进行模板化合成与包装,并不是把一段文案直接变成数字人的单接口。
如果当前只有文案,完整链路应当拆成:
文案 → TTS 语音合成 → 数字人合成 → 智能剪辑包装 → 成片
本文重点演示后半段的智能剪辑接入。接口信息核对日期为 2026 年 11 月 2 日,实际参数与计费请以官方文档和控制台为准。
一、接入前需要准备什么?
开始写代码前,需要准备四项内容:
- API Key:在平台控制台创建,只保存在服务端环境变量或密钥管理系统中。
- 人物视频地址:公网可访问的
mp4/mov文件,平台需要读取视频并探测时长。 - 模板 ID:通过模板列表接口获取,真人口播场景使用
scene=realMan。 - 回调地址:创建任务时需要提交
callback_url;同时建议保留任务轮询作为兜底。
人物视频的主要限制包括:
- 视频编码支持 H.264、HEVC/H.265;
- 帧率支持 10~60 fps,官方建议 25 fps;
- 单边分辨率小于 2000 px;
- 视频时长小于 5 分钟,文件小于 500 MB;
- 视频中的音频需要能够进行语音转文本。
建议在上传阶段完成格式、大小和时长校验,不要等到合成任务失败后再排查。
二、第一步:获取真人口播模板
不同剪辑模式对应不同 scene,不能混用:
| 业务模式 | scene | 最终合成接口 |
|---|---|---|
| 真人口播 | realMan |
realman_broadcast |
| 素材混剪 | oralMixCutting |
broadcast_mixcut |
| 新闻混剪 | newsMixCutting |
news_mixcut |
| 视频包装 | realMan |
realman_broadcast |
获取真人口播模板的请求如下:
curl -X POST "https://xiaoapis.com/api/smartclip/template" \
-H "Content-Type: application/json" \
-d '{
"key": "YOUR_API_KEY",
"scene": "realMan",
"pageSize": 10,
"sortBy": "desc"
}'
模板列表位于 data.result.data.results,重点字段如下:
{
"id": "6a2668a137004e003477b6ed",
"name": "双语大橙",
"coverUrl": "https://example.com/cover.jpg",
"scene": "realMan",
"demoUrl": "https://example.com/demo.mp4"
}
其中,id 就是创建合成任务时使用的 styleId。
生产环境中可以缓存模板列表,用户选中某个模板后,再调用模板详情接口读取画布和图层信息,不必每次打开页面都重新请求完整列表。
三、第二步:读取模板详情
curl -X POST "https://xiaoapis.com/api/smartclip/template_detail" \
-H "Content-Type: application/json" \
-d '{
"key": "YOUR_API_KEY",
"id": "6a2668a137004e003477b6ed"
}'
模板详情中的 videoStructInfo 描述了画布和图层结构。例如:
{
"videoStructInfo": {
"editInfo": {
"canvas": {
"width": 1080,
"height": 1920
}
}
}
}
如果只需要使用模板默认效果,可以不修改图层;如果需要调整标题、字幕等图层,再根据模板详情构造 structLayers。
四、第三步:创建异步合成任务
接口地址:
POST https://xiaoapis.com/api/smartclip/realman_broadcast?action=create
Content-Type: application/json
最小请求只需要四个业务字段。使用 POST + JSON 时,key 必须放在 JSON Body 中:
{
"key": "YOUR_API_KEY",
"styleId": "6a2668a137004e003477b6ed",
"videoUrl": "https://example.com/presenter.mp4",
"callback_url": "https://example.com/api/callbacks/smartclip",
"resolution": "720p"
}
其中,resolution 可选 720p 或 1080p,不传时默认为 720p。
创建成功返回的并不是成片地址,而是任务 ID:
{
"code": 200,
"msg": "success",
"data": {
"task_id": "task_6139c79459b9594a32f4737b",
"status": 1,
"progress": 0,
"api_type": "realman_broadcast",
"power_cost": 150
}
}
创建接口中的状态值为:1 处理中、2 完成、3 失败。业务代码应先保存 task_id,再进入回调处理或任务查询流程。
五、完整 Python 示例:创建任务并轮询成片
安装依赖:
pip install requests
设置环境变量:
export XIAOAPIS_API_KEY="你的_API_Key"
export XIAOAPIS_STYLE_ID="真实模板_ID"
export XIAOAPIS_VIDEO_URL="https://你的域名/presenter.mp4"
export XIAOAPIS_CALLBACK_URL="https://你的域名/api/callbacks/smartclip"
完整代码:
import os
import time
import requests
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
API_KEY = os.environ["XIAOAPIS_API_KEY"]
STYLE_ID = os.environ["XIAOAPIS_STYLE_ID"]
VIDEO_URL = os.environ["XIAOAPIS_VIDEO_URL"]
CALLBACK_URL = os.environ["XIAOAPIS_CALLBACK_URL"]
CREATE_URL = "https://xiaoapis.com/api/smartclip/realman_broadcast"
QUERY_URL = "https://xiaoapis.com/api/smartclip/task_query"
def build_session() -> requests.Session:
"""只对可重复执行的 GET 查询做自动重试,不自动重试创建任务。"""
retry = Retry(
total=3,
backoff_factor=1,
status_forcelist=(429, 500, 502, 503, 504),
allowed_methods=frozenset(["GET"]),
respect_retry_after_header=True,
)
session = requests.Session()
session.mount("https://", HTTPAdapter(max_retries=retry))
return session
def parse_response(response: requests.Response) -> dict:
response.raise_for_status()
payload = response.json()
if payload.get("code") != 200:
raise RuntimeError(
f"API 业务错误:code={payload.get('code')}, msg={payload.get('msg')}"
)
return payload
def create_task(session: requests.Session) -> str:
payload = {
"key": API_KEY,
"styleId": STYLE_ID,
"videoUrl": VIDEO_URL,
"callback_url": CALLBACK_URL,
"resolution": "720p",
"language": "zh-CN",
}
# 创建任务不自动重试,避免响应丢失时重复创建任务。
response = session.post(
CREATE_URL,
params={
"action": "create"},
json=payload,
timeout=(10, 60),
)
data = parse_response(response)["data"]
return data["task_id"]
def query_task(session: requests.Session, task_id: str) -> dict:
response = session.get(
QUERY_URL,
params={
"key": API_KEY, "task_id": task_id},
timeout=(5, 30),
)
return parse_response(response)["data"]
def wait_for_result(
session: requests.Session,
task_id: str,
timeout_seconds: int = 900,
) -> str:
deadline = time.monotonic() + timeout_seconds
time.sleep(2)
while time.monotonic() < deadline:
data = query_task(session, task_id)
status = data.get("status")
progress = data.get("progress", 0)
print(f"task_id={task_id}, status={status}, progress={progress}")
if status == "completed":
video_url = data.get("video_url") or (data.get("result") or {
}).get("video_url")
if not video_url:
raise RuntimeError("任务已完成,但响应中没有 video_url")
return video_url
if status == "failed":
reason = data.get("fail_reason") or data.get("error")
raise RuntimeError(f"合成失败:{reason}")
if status not in {
"pending", "processing"}:
raise RuntimeError(f"未知任务状态:{status}")
time.sleep(3)
raise TimeoutError(f"任务在 {timeout_seconds} 秒内未完成:{task_id}")
def main():
session = build_session()
task_id = create_task(session)
print(f"任务已创建:{task_id}")
video_url = wait_for_result(session, task_id)
print(f"成片地址:{video_url}")
if __name__ == "__main__":
main()
这里有两个细节值得注意:
- 创建与查询的状态格式不同:创建接口返回数字状态
1/2/3,独立任务查询接口返回pending/processing/completed/failed,不要混用判断逻辑。 - 查询可以重试,创建不能盲目重试:示例只对 GET 查询配置自动重试。如果创建请求超时,响应中的
task_id可能已经生成但客户端没有收到,立即重新 POST 可能造成重复任务。
官方建议提交后约 2 秒开始查询,轮询间隔设为 2~5 秒;任务查询不扣费。生产环境还应设置超时、告警和人工复核入口,不能写成无限循环。
六、单条视频成本怎么估算?
根据当前真人口播接口文档,智能剪辑按输出分辨率和输入视频秒数计费:
| 输出规格 | 文档列示单价 |
|---|---|
| 720p | 3 点/输入秒 |
| 1080p | 4 点/输入秒 |
计算公式:
智能剪辑消耗点数 = ceil(输入视频秒数) × 对应规格单价
例如,输入视频实际时长为 58.2 秒,按 59 秒计费:
720p:59 × 3 = 177 点
1080p:59 × 4 = 236 点
创建任务后,还应记录响应中的 power_cost,并与控制台账单核对。价格属于动态信息,批量运行前请重新查看接口文档与控制台,不要把文章中的示例单价写成长期报价。
如果从文案开始生产,完整成本还应包含 TTS、数字人合成、素材存储、带宽、失败重试和人工质检。比较人工流程与 API 流程时,建议统一使用下面的口径:
单条有效成片成本 =
(API 成本 + 存储与带宽成本 + 人工成本 + 失败重试成本)
÷ 验收通过的成片数量
相比笼统地宣称“效率提升多少倍”,用小样本记录单条人工分钟数、验收通过率、P50/P95 出片时长和单条有效成片成本,更有助于判断是否适合放量。
七、批量上线前的五个工程检查点
1. 不要把 API Key 放到前端
前端只调用自己的业务后端,由后端保存密钥并调用平台接口。任务查询需要把 key 放在 URL 查询参数中,因此还要检查网关、访问日志和 APM 是否会对敏感参数脱敏。
2. 给每个任务建立完整记录
至少保存:业务视频 ID、task_id、模板 ID、输入视频地址、任务状态、power_cost、失败原因和最终成片地址。日志中不要记录 API Key。
3. 回调与轮询要能做终态对账
收到回调后,可以根据 task_id 再查询一次任务状态,确认终态与成片地址。重复回调或重复查询不应导致业务系统重复发布同一条视频。
4. 在上传阶段校验素材
重点检查视频格式、编码、时长、文件大小和公网可访问性。模板要求的素材格式、数量、尺寸和时长,也应在提交任务前完成校验。
5. 把肖像、声音与素材授权纳入流程
数字人形象、真人视频、克隆音色、音乐和图片都可能涉及授权。批量生成之前,应确认使用权和内容合规要求,并为生成内容保留必要的审核环节。
八、常见问题
Q1:只有文案,可以直接调用 realman_broadcast 吗?
不能直接这样理解。该接口需要传入已有的 videoUrl。只有文案时,应先完成 TTS 和数字人合成,再把生成的人物视频交给智能剪辑接口包装。
Q2:配置了 callback_url,还需要轮询吗?
建议保留轮询作为补偿机制。回调用于及时接收终态,轮询用于处理回调未到达、业务服务重启等情况,两者都应以 task_id 关联同一条任务记录。
Q3:创建任务超时后,应该立即重试吗?
不建议直接重试。网络超时不等于任务未创建,盲目重试可能产生重复任务和重复计费。应先记录异常并进入人工或自动对账流程;对于已经拿到 task_id 的任务,查询接口可以安全重试。
Q4:如何评估是否真的降本提效?
先选一批相同时长、相同模板和相同分辨率的内容试跑,对比人工流程与 API 流程的单条人工分钟数、验收通过率、出片时长和有效成片成本,再决定是否扩大批量。
结语
数字人口播 API 的价值,不是把内容生产简化成一个“生成”按钮,而是把人物素材、模板、任务状态、计费和质检连接成可观测的生产流水线。
对开发者而言,最小可行路径也很清晰:先跑通一种 realMan 模板,再接入任务查询和业务对账,最后扩展批量队列。 相比一开始同时接入多种剪辑模式,这条路径更容易定位参数问题,也更容易核算真实成本。
來源:阿里雲開發者社區 AI · developer.aliyun.com