用 pixverse-v6/text-to-video 在 hiapi 生成一段视频,本质上就是一次 POST /v1/tasks 加一轮轮询——和平台上每一个生成类模型用的异步任务模式完全一样。本文给你可直接复制的 curl 和 Python 示例、端点真正会校验的输入字段,以及我实际跑通一次生成时记录下来的任务生命周期和踩的坑。
开始前需要什么
- 一个 hiapi API key。在控制台里创建,然后用请求头
Authorization: Bearer sk-<你的 key>带上。请求头格式见鉴权文档。 - model id 是
pixverse-v6/text-to-video。保留中间的斜杠——它是 id 的一部分,不是 URL 路径。 - curl 不需要装任何东西;Python 示例只用到标准库加
requests。
PixVerse V6 文生视频把一段文本提示词变成 1–15 秒、360p–1080p 的视频片段。它走统一的异步任务接口:提交任务 → 轮询结果 → 在输出 URL 过期前把视频下载走。
最小可跑请求(curl)
把任务提交到 POST /v1/tasks:
curl -s -X POST https://api.hiapi.ai/v1/tasks \
-H "Authorization: Bearer sk-<你的 key>" \
-H "Content-Type: application/json" \
-d '{
"model": "pixverse-v6/text-to-video",
"input": {
"prompt": "清晨阳光下,一只红色的狐狸小跑着穿过新雪,电影质感,慢动作",
"aspect_ratio": "16:9",
"duration": 5,
"resolution": "720p"
}
}'
返回里拿到一个任务 id:
{ "code": 200, "data": { "taskId": "tk-hiapi-...." }, "message": "success" }
然后轮询 GET /v1/tasks/<taskId>,直到 data.status 变成 success:
curl -s https://api.hiapi.ai/v1/tasks/tk-hiapi-.... \
-H "Authorization: Bearer sk-<你的 key>"
成功后,成品视频的 URL 在 data.output[0].url:
{
"code": 200,
"data": {
"status": "success",
"storage": "temp",
"output": [
{ "type": "video", "url": "https://temp.hiapi.ai/....mp4", "expireAt": 1793036664 }
]
},
"message": "success"
}
这个输出 URL 是临时的——它带一个 expireAt 时间戳(实测是生成后 7 天)。请立刻把 .mp4 下载下来、存到你自己的对象存储,不要直接热链这个地址。
同样的流程(Python)
import time, requests
BASE = "https://api.hiapi.ai/v1/tasks"
HEADERS = {"Authorization": "Bearer sk-<你的 key>", "Content-Type": "application/json"}
def create_task():
payload = {
"model": "pixverse-v6/text-to-video",
"input": {
"prompt": "清晨阳光下,一只红色的狐狸小跑着穿过新雪,电影质感,慢动作",
"aspect_ratio": "16:9",
"duration": 5,
"resolution": "720p",
},
}
r = requests.post(BASE, json=payload, headers=HEADERS, timeout=60)
r.raise_for_status()
data = r.json()
task_id = (data.get("data") or {}).get("taskId")
if not task_id:
raise RuntimeError(f"创建失败: {data}")
return task_id
def wait_for(task_id, timeout_s=600):
deadline = time.time() + timeout_s
while time.time() < deadline:
try:
r = requests.get(f"{BASE}/{task_id}", headers=HEADERS, timeout=30)
task = (r.json().get("data") or {})
except requests.RequestException:
time.sleep(5) # 单次网络抖动不该让整个轮询中止
continue
status = task.get("status")
if status == "success":
return task["output"][0]["url"]
if status == "fail":
raise RuntimeError(f"任务失败: {task.get('error')}")
time.sleep(5) # 还在排队/渲染——用同一个 task_id 继续轮询
raise TimeoutError(task_id)
task_id = create_task()
url = wait_for(task_id)
video = requests.get(url, timeout=120).content
open("out.mp4", "wb").write(video)
print("已保存 out.mp4")
轮询循环只对 success 和 fail 两个终态做判断,其它状态一律继续等——这样无论渲染途中报告的是 handling 还是 archiving,代码都不会误判。关键一点:如果某一次轮询请求本身报错,睡一下再用保存好的同一个 task_id 重新查,不要重新提交任务——重新提交会再渲染一次、再扣一次费。
pixverse-v6/text-to-video 真正校验的参数
下面这些是端点实际接受的字段。每一个我都通过给它发一个非法值、读回它自己的校验报错来确认过,并和模型文档做了交叉核对:
| 字段 | 类型 | 取值 / 范围 | 默认值 | 说明 |
|---|---|---|---|---|
prompt | string | 1–2048 字节 UTF-8(1 个汉字 = 3 字节,约 682 字) | — | 必填。 |
aspect_ratio | enum | 16:9、4:3、1:1、3:4、9:16、2:3、3:2、21:9 | 16:9 | 注意它支持 21:9(超宽)和 2:3/3:2。 |
duration | integer | 1–15 | 5 | 单位秒,必须是整数,不能是字符串。 |
resolution | enum | 360p、540p、720p、1080p | 720p | 输出分辨率。 |
generate_audio | boolean | true / false | false | 是否同时生成背景音乐、音效和对白;默认关闭,要音频得显式打开。 |
negative_prompt | string | 最多 2048 字节 UTF-8 | — | 可选;想要避开的内容。 |
seed | integer | 任意整数 | — | 可选;同 seed + 同 prompt 可复现同一结果。 |
style | enum | anime、3d_animation、clay、comic、cyberpunk | 无 | 可选的风格预设,留空保持自然画风。 |
如果要用回调而不是轮询,input 同级还可以带一个 callback 对象:url(HTTPS 回调地址)+ when(目前只有 final,即任务终态时回调)。
生产环境写法
- 这是一个封闭 schema。 任何不在上表里的字段都会被直接拒绝,报
invalid input: <root>: additional properties '<字段>' not allowed。这其实是好事:拼错或臆想出来的字段会在提交时就响亮地失败,而不是被悄悄忽略。 duration是整数,这点和平台上某些收字符串("6")的视频模型不一样。发"5"会得到invalid input: duration: got string, want integer;越界值会直接把边界告诉你,比如duration: maximum: got 999, want 15、duration: minimum: got 0, want 1。- 报错一次只报一个字段,envelope 是扁平的:
{"code":400,"error_code":"INVALID_REQUEST","message":"invalid input: aspect_ratio: value must be one of ..."}。修掉它报的字段再重发,下一个非法字段(如果有)会在下一次调用时冒出来。 - 任务失败时 HTTP 仍然是 200。 失败信息在响应体的
data.status: "fail"里,要判断的是这个 status 字段,而不是 HTTP 状态码。 - 轮询还是回调? 轻量脚本用轮询最简单;要规模化、不想一直挂着连接,就用
callback。无论哪种,拿到output[0].url都要立刻下载——URL 带expireAt,过期后会变成 404。
实测记录:我真的跑了一次
这篇不是只做了只读探针——我用一个真实请求把完整生命周期跑通了一遍,记录如下:
- 创建:上面那个 720p / 5 秒 / 16:9 的请求发出去,立刻返回
{"code":200,"data":{"taskId":"tk-hiapi-01M5AM..."},"message":"success"}。注意 taskId 是tk-hiapi-前缀的字符串,不是 UUID。 - 轮询:
GET /v1/tasks/<id>的data.status依次经过handling→archiving→success,整条 5 秒片子从创建到完成大约 74 秒。 - 输出:终态里
data.output[0]是{"type":"video","url":"https://temp.hiapi.ai/....mp4","expireAt":...,"artifactId":"...","storage":"temp"}。expireAt减去创建时间正好是 604800 秒,也就是 7 天。 - 产物:对那个输出 URL 做 HEAD,拿到
content-type: video/mp4、大小约 2.2 MB,确认是一个有效的 mp4 文件。
关于音频的一个纠正值得单独记:我分别用非法值探过几个相邻字段名——generate_audio 报 got string, want boolean(说明它是一个合法的布尔字段),而 sound、audio 都报 additional properties not allowed(不存在)。也就是说,音频是通过 generate_audio 这个开关控制的,默认 false;定价页上也相应有「Sound On / Sound Off」两档。本次实测我没有打开 generate_audio,所以产出的是一段无声片。
我没有对画面质量做主观评价(本次只核实了请求契约、任务生命周期和产物是合法 mp4),这部分请你用自己的提示词实际生成后判断。
费用怎么算
pixverse-v6/text-to-video 按秒计费(计费因子就是 duration),时长越长越贵;分辨率越高、以及打开 generate_audio 走「Sound On」档,每秒单价都会更高。具体的每秒费率以定价页上的实时数据为准,批量生成前先过一眼。
相关链接
- PixVerse V6 文生视频 —— 模型页
- PixVerse V6 文生视频 —— API 文档
- 创建任务 与 查询任务详情 接口参考
- 快速开始 与 鉴权
- 想从一张图开始做视频?看 PixVerse V6 图生视频
- 定价
常见问题
duration 是秒还是帧? 秒——1 到 15 之间的任意整数,默认 5。
能生成带声音的视频吗? 能。把 generate_audio 设为 true,模型会连背景音乐、音效和对白一起生成;默认是 false(无声)。开启音频会走更贵的计费档,详见定价页。
提示词能写多长? 上限是 2048 字节 UTF-8。中文一个字算 3 字节,所以大约 682 个汉字封顶。
它和图生视频有什么区别? 本端点(pixverse-v6/text-to-video)只从文本提示词出发。图生视频是另一个 model id,接收一张起始图、把它动起来——想让一张现成画面动起来而不是凭空生成,就用那个。
为什么我的请求报 "additional properties not allowed"? 你传了一个不在 schema 里的字段。输入只接受 prompt、aspect_ratio、duration、resolution、generate_audio、negative_prompt、seed、style 这几个。




