HeyGen Avatar V 选一个预置数字人,输入台词或音频,就能生成口型同步视频。HiAPI 按输出时长收费,每秒 $0.15,10 秒视频 $1.50。
HeyGen Avatar V 已在 HiAPI 上线,打开模型页先选形象和声音,再接 API。下面这条商务讲解就是已有成片:
Brandon Office Sitting Front、Dexter - Professional;16:9,成片 1280×720、约 8 秒。原请求为1080p,本页为720p网页版本。
Hi, I'm Daniel. Send me your quarterly numbers, and I'll walk your team through what changed and what to do next.
用这个提示词生成 → 台词已填好;手选上面的形象、声音、1080p 和 16:9,输出选 MP4。
在线怎么试?
- 打开预填链接,保留这句短台词。
- 选择形象和声音;这些参数需要手选,链接只带入台词。
- 设置画幅、分辨率和格式,首次可用上面的组合。
- 生成后试听配音、检查口型,下载成片,再换成自己的文案。
记下这次试用的形象、声音和画幅,批量生成时沿用,只换台词,出镜人和声音就能保持一致。
V 从预置形象中选择出镜人;要让自己的照片出镜,选 Avatar IV。
所有分辨率都按实际输出秒数收费,失败全额退款;完整费用见 价格与预算表。
API 要准备什么?
在控制台创建 API key。请求中明确写 model、必填的 input.avatar,再从 prompt 与 audio_url 中选一个。形象和声音用文档卡片的英文请求值,中文名只用于辨认。
台词直接读出,镜头指令别放进 prompt。音频驱动传可访问的 HTTP(S) 地址,并移除 prompt 和 voice。无需传 duration,时长由台词朗读或音频决定。
| 手里有什么 | 传哪些驱动字段 |
|---|---|
| 要读出的台词 | avatar + prompt;voice 可选 |
| 已录好的声音 | avatar + audio_url;省略 prompt 和 voice |
形象查值:参数文档 → 数字人形象,展开全部后搜索并复制英文「请求值」;声音同样在 预置声音 查找。英文页对应 Request value,不要把中文展示名放入请求。
**音频驱动最小完整请求:**把占位地址换成自己的公开可访问音频 URL。省略的画幅、分辨率和格式使用文档默认值;音频最长600秒、最大32 MiB。
{
"model": "heygen-avatar-v",
"input": {
"avatar": "Brandon Office Sitting Front",
"audio_url": "https://example.com/your-recording.mp3"
}
}
用 cURL 创建和查询任务
把 Key 占位符换成自己的值;这个请求沿用商务案例参数:
export HIAPI_API_KEY="sk-YOUR_KEY"
curl --fail-with-body --connect-timeout 10 --max-time 60 \
-X POST https://api.hiapi.ai/v1/tasks \
-H "Authorization: Bearer $HIAPI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "heygen-avatar-v",
"input": {
"avatar": "Brandon Office Sitting Front",
"prompt": "Hi, I\u0027m Daniel. Send me your quarterly numbers, and I\u0027ll walk your team through what changed and what to do next.",
"voice": "Dexter - Professional",
"aspect_ratio": "16:9",
"resolution": "1080p",
"caption": false,
"output_format": "mp4"
}
}'
检查 HTTP 状态与 JSON 的 code,成功创建后保存 data.taskId。随后只查询同一个任务:
TASK_ID="REPLACE_WITH_data.taskId"
curl --fail-with-body --connect-timeout 10 --max-time 60 \
"https://api.hiapi.ai/v1/tasks/$TASK_ID" \
-H "Authorization: Bearer $HIAPI_API_KEY"
queued、handling、archiving 表示处理中;终态是 success 或 fail。成功后按 data.output[].type 找 video,启用字幕时再找 caption。读取产物 url,按 expireAt 及时下载。
**响应结构示例:**第一段为创建成功,第二段为启用字幕后的成功查询;任务 ID、URL 和过期时间都是示意值;expireAt 是数字,单位为 Unix 秒。POST 超时或响应丢失时,先查任务记录,禁止盲目再次 POST;有 ID 就继续 GET。
{
"code": 200,
"data": {"taskId": "TASK_ID_FROM_CREATE"}
}
{
"code": 200,
"data": {
"taskId": "TASK_ID_FROM_CREATE",
"status": "success",
"output": [
{"type": "video", "url": "https://example.com/result.mp4", "expireAt": 4070908800},
{"type": "caption", "url": "https://example.com/result.srt", "expireAt": 4070908800}
]
}
}
Python:创建、有限轮询、下载
先安装 requests,在环境变量 HIAPI_API_KEY 中设置 Key。代码只提交一次,轮询最多 30 分钟;超时保留任务 ID 继续查询。
import os
import time
from pathlib import Path
import requests
API = "https://api.hiapi.ai/v1/tasks"
HEADERS = {"Authorization": f"Bearer {os.environ['HIAPI_API_KEY']}"}
payload = {
"model": "heygen-avatar-v",
"input": {
"avatar": "Brandon Office Sitting Front",
"prompt": "Hi, I'm Daniel. Send me your quarterly numbers, and I'll walk your team through what changed and what to do next.",
"voice": "Dexter - Professional",
"aspect_ratio": "16:9",
"resolution": "1080p",
"caption": False,
"output_format": "mp4",
},
}
def api_request(method, url, **kwargs):
advice = (
"Submission state may be unknown; check task history before another POST."
if method == "POST"
else f"Continue GET with the saved task ID: {url.rsplit('/', 1)[-1]}."
)
try:
response = requests.request(
method, url, headers=HEADERS, timeout=(10, 30), **kwargs
)
except requests.RequestException:
raise RuntimeError(f"Network error. {advice}") from None
if not response.ok:
raise RuntimeError(f"HTTP {response.status_code}. {advice}")
try:
body = response.json()
except ValueError:
raise RuntimeError(f"Response is not JSON. {advice}") from None
if not isinstance(body, dict):
raise RuntimeError(f"Unexpected response shape. {advice}")
if body.get("code") != 200 or not isinstance(body.get("data"), dict):
raise RuntimeError(f"API error: code={body.get('code')}. {advice}")
return body["data"]
# Submit once. No automatic POST retries.
created = api_request("POST", API, json=payload)
task_id = created.get("taskId")
if not isinstance(task_id, str) or not task_id:
raise RuntimeError("Missing taskId; check task history before resubmitting.")
print("taskId:", task_id) # Keep this ID to resume GET queries.
deadline = time.monotonic() + 1800
while time.monotonic() < deadline:
data = api_request("GET", f"{API}/{task_id}")
status = data.get("status")
if status == "fail":
raise RuntimeError(f"Task failed: {task_id}; inspect its task record.")
if status == "success":
break
if status not in ("queued", "handling", "archiving"):
raise RuntimeError(f"Unexpected task status: {status}")
time.sleep(8)
else:
raise TimeoutError(f"Polling timed out; continue GET for taskId={task_id}.")
raw_outputs = data.get("output")
if not isinstance(raw_outputs, list):
raise RuntimeError(f"Missing output list; inspect taskId={task_id}.")
outputs = {
item["type"]: item
for item in raw_outputs
if isinstance(item, dict) and item.get("type") in ("video", "caption")
}
if "video" not in outputs:
raise RuntimeError("Successful task has no video artifact.")
for kind, artifact in outputs.items():
if not isinstance(artifact.get("url"), str) or not artifact["url"]:
raise RuntimeError(f"Missing {kind} URL; inspect taskId={task_id}.")
suffix = payload["input"]["output_format"] if kind == "video" else "srt"
target = Path(f"avatar-v.{suffix}")
# Artifact downloads do not need the API Authorization header.
with requests.get(artifact["url"], stream=True, timeout=(10, 120)) as response:
response.raise_for_status()
with target.open("wb") as file:
for chunk in response.iter_content(chunk_size=1024 * 1024):
if chunk:
file.write(chunk)
print("saved:", target)
哪些参数需要显式设置?
| 字段 | 规则与默认值 |
|---|---|
avatar | 必填,英文形象请求值 |
prompt / audio_url | 二选一;台词最多 5,000 字符,音频最长 600 秒、最大 32 MiB |
voice | 台词路径可选,默认 Warm Pro Narrator |
resolution | 默认 720p,可选 1080p、小写 4k |
aspect_ratio | 默认 16:9;另有 9:16、4:5、5:4、1:1、auto |
fit | 默认 cover,可选 contain |
caption | 默认 false;true 返回独立 SRT |
output_format | 默认 mp4,可选 webm |
remove_background | 默认 false;透明用途选 true 配合 webm,先用短片检查所选形象 |
background | 对象;type 为 color 或 image,value 填十六进制颜色或 HTTP(S) 图片 URL |
分辨率和画幅是两个参数:横版讲解用 16:9,竖屏口播用 9:16,都在请求里写明。下载后看一眼文件实际尺寸。透明 WebM 先确认所选形象的去背景效果,再导入剪辑软件。
字幕不烧进画面,要在播放器或剪辑软件里叠加。下面的竖屏案例设了 caption=true,返回独立 SRT;视频 1080×1920、6.52 秒,请求为1080p、9:16。独立 SRT 字幕 可在剪辑时导入。
New drop just landed: our travel mug keeps coffee hot for twelve hours. Swipe up and grab yours today!
用这个提示词生成 → 台词已填好;手选 Riley Casual Front、Charming Charles - Friendly、9:16 和 1080p,开启字幕,输出选 MP4。
上线前检查哪四项?
- 验证输入:形象、驱动方式、英文请求值和长度限制。
- 保存任务 ID:查询失败或超时后用同一个 ID 继续 GET。
- 找齐产物:成功后按
type找 video,开启字幕时找 caption。 - 下载检查:确认实际尺寸、声音和字幕文件,再交付。
常见问题怎么处理?
- **输入校验有问题:**检查
avatar、二选一驱动字段、英文请求值、台词与音频上限;分辨率写4k,删除duration。 - **POST 超时:**先查任务记录;已有
taskId就继续 GET,每次 POST 都创建新任务。 - **任务
fail:**查看任务记录里的错误原因,修改相应输入后再提交。 - **下载链接过期:**成功后及时保存产物;字幕从
type=caption读取。
服务端可在 input 同级加 "callback": {"url": "https://yourapp.com/webhook", "when": "final"},接收终态任务对象,并用 GET 补偿查询。
价格细节见秒单价和预算表,换形象参考两个案例,完整取值见API 参数文档。
用这个提示词生成 → 台词已填好;手选商务形象和声音、1080p、16:9、MP4,先生成一句,再接入完整脚本。





