教程
如何使用 Ray 3.2 文生视频 API:curl、Python 与一个可直接运行的请求
Ray 3.2 是 hiapi 模型目录中的一款文生视频模型,它和其他所有视频模型一样,通过统一的异步任务 API 调用——模型 id 为 ray-3.2/text-to-video,提交到 POST /v1/tasks。有些视频模型唯一的调节项只有提示词,Ray 3.2 不同,它提供三个真正可用的输出控制项——duration、resolution 和 aspect_ratio——每一个都在服务端严格校验。
本指南让你一次就发出能成功的请求:精确的输入 schema(已于 2026-10-19 对照线上 API 验证)、可直接复制粘贴的 curl 调用、完整的 Python 提交/轮询/下载脚本,以及生产环境细节——回调、幂等重试,以及你实际会看到的错误响应。
你将构建什么,以及需要准备什么
目标:提交一段文本提示词,轮询任务,并下载一段无声的 .mp4 片段(5 秒或 10 秒)。
前置条件:
- 一个 hiapi API 密钥——从你的控制台获取。密钥形如
sk-...,放在Authorization: Bearer请求头中。刚接触任务 API?请先从快速开始入手。 - 任意 HTTP 客户端。我们会展示
curl和 Python(requests)。
Ray 3.2 的输出按片段计费,而且价格会随你的选择大幅上升——当前费率见定价页。在迭代提示词时,从 540p / 5 秒起步;一段 1080p 10 秒的片段可能比一次预算规模的图像渲染贵很多倍,所以别让你的开发循环一直跑在最高设置上。
精确的输入 schema(一个必填字段,三个严格枚举)
所有内容都放在一个 input 对象里。已对照线上 API 逐字段验证:
| 字段 | 类型 | 必填 | 允许值 | 默认值 |
|---|---|---|---|---|
prompt |
string | 是 | 场景描述,最多 6000 个字符 | — |
duration |
integer | 否 | 5 或 10 |
5 |
resolution |
string | 否 | 540p、720p、1080p |
540p |
aspect_ratio |
string | 否 | 16:9、9:16、1:1、4:3、3:4、21:9 |
16:9 |
写代码之前,有三件事值得牢记:
duration是整数,不是字符串。发送裸数字——"duration": 5。这与其他一些任务 API 视频模型相反(例如 hailuo-2.3 要求"duration": "6"作为字符串)。如果你要把请求体从一个模型移植到另一个模型,请重新检查这个字段;这是最常见的跨模型错误。- 枚举值是被校验的,不是被截断的。超出范围的值会以
400被拒绝,而不是被静默取整。没有2k,没有480p,没有2:1。 - 没有
prompt_optimizer、seed或negative_prompt。构图完全通过aspect_ratio加提示词来控制。如果你发送 schema 不认识的字段,预期会收到 400——/v1/tasks的输入 schema 因模型而异,所以不要假设在别处有效的键能沿用过来。
校验实际返回什么
以下是线上端点的真实响应(故意提交无效值,不创建任务,不计费):
// POST with "resolution": "2k"
{"code":400,"data":null,"error_code":"INVALID_REQUEST",
"message":"invalid input: resolution: value must be one of '540p', '720p', '1080p'"}
// POST with "duration": 7
{"code":400,"data":null,"error_code":"INVALID_REQUEST",
"message":"invalid input: duration: value must be one of 5, 10"}
// POST with "aspect_ratio": "2:1"
{"code":400,"data":null,"error_code":"INVALID_REQUEST",
"message":"invalid input: aspect_ratio: value must be one of '16:9', '9:16', '1:1', '4:3', '3:4', '21:9'"}
message 会指出确切的字段和确切允许的集合——所以如果你忘了某个枚举值,API 会告诉你。注意 duration 的 5, 10 没有引号(数字),而 resolution 的 '540p' 是带引号的字符串:这个引号差异就是提醒你哪个字段是整数。
最小可运行示例:curl
创建任务:
curl -s -X POST https://api.hiapi.ai/v1/tasks \
-H "Authorization: Bearer sk-YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "ray-3.2/text-to-video",
"input": {
"prompt": "雨夜中,一名街头舞者在霓虹灯下旋转,水洼倒映着粉色和蓝色灯光,她的夹克随着旋转翻飞,镜头低角度环绕她,电影感",
"duration": 5,
"resolution": "540p",
"aspect_ratio": "9:16"
}
}'
创建响应会带一个任务 id(已截断):
{ "data": { "taskId": "task_01k..." } }
轮询它,直到进入终态:
curl -s https://api.hiapi.ai/v1/tasks/task_01k... \
-H "Authorization: Bearer sk-YOUR_KEY"
任务运行期间,data.status 会报告一个进行中的状态。两个终态是 success 和 fail。成功时(已截断):
{
"data": {
"taskId": "task_01k...",
"status": "success",
"output": [ { "url": "https://.../clip.mp4" } ]
}
}
立即下载 data.output[0].url。输出 URL 是签名的,会过期——把字节保存到你自己的存储中,而不是直接热链任务 URL。Ray 3.2 返回的是无声 MP4(没有音轨),所以不要等待一个永远不会来的音频流。
完整的 Python 脚本(提交 → 轮询 → 下载)
import time
import requests
API_BASE = "https://api.hiapi.ai/v1"
API_KEY = "sk-YOUR_KEY"
HEADERS = {"Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json"}
def create_task(prompt: str, duration: int = 5,
resolution: str = "540p", aspect_ratio: str = "9:16") -> str:
resp = requests.post(
f"{API_BASE}/tasks",
headers=HEADERS,
json={
"model": "ray-3.2/text-to-video",
"input": {
"prompt": prompt,
"duration": duration, # 5 or 10 — an INTEGER, not a string
"resolution": resolution, # "540p" | "720p" | "1080p"
"aspect_ratio": aspect_ratio, # "16:9" | "9:16" | "1:1" | "4:3" | "3:4" | "21:9"
},
},
timeout=30,
)
resp.raise_for_status()
return resp.json()["data"]["taskId"]
def wait_task(task_id: str, timeout_s: int = 900, poll_interval: int = 5) -> dict:
deadline = time.time() + timeout_s
while time.time() < deadline:
resp = requests.get(f"{API_BASE}/tasks/{task_id}", headers=HEADERS, timeout=30)
resp.raise_for_status()
task = resp.json()["data"]
if task["status"] == "success":
return task
if task["status"] == "fail":
err = task.get("error") or {}
raise RuntimeError(f"task failed: {err.get('code')}: {err.get('message')}")
time.sleep(poll_interval) # any non-terminal status = still running
raise TimeoutError(f"task {task_id} not finished after {timeout_s}s")
task_id = create_task(
"一只纸船顺着积满雨水的排水沟漂流,水滴在水面荡起涟漪,"
"秋叶打着旋漂过,低机位贴近水面拍摄,柔和的阴天光线"
)
print("task created:", task_id)
task = wait_task(task_id)
video_url = task["output"][0]["url"]
# Output URLs expire — download right away and store the bytes yourself.
video = requests.get(video_url, timeout=120).content
with open("ray32-clip.mp4", "wb") as f:
f.write(video)
print(f"saved ray32-clip.mp4 ({len(video) / 1e6:.1f} MB)")
用 pip install requests 安装依赖,换上你的密钥,任务完成时磁盘上就会有一个 .mp4。视频任务需要几分钟,而不是几秒——给你的轮询循环一个宽松的截止时间(上面是 15 分钟),而不是假设它会快速返回。
生产环境注意事项:回调、幂等性、错误
优先使用回调而不是轮询
对于脚本以外的任何用途,在创建任务时注册 webhook,而不是轮询:
{
"model": "ray-3.2/text-to-video",
"input": { "prompt": "...", "duration": 10, "resolution": "720p" },
"callback": { "url": "https://your-app.example.com/hooks/hiapi", "when": "final" }
}
使用 "when": "final" 时,hiapi 会在任务进入终态时调用你的端点一次——没有轮询流量,也不会在两次间隔之间错过完成通知。你的处理器随后执行 GET /v1/tasks/<id>(或读取投递的响应体)来获取 output[0].url。对于无法暴露 HTTPS 端点的 CLI 和 notebook,轮询仍然可以。
让重试保持幂等
在创建调用返回的那一刻就持久化 taskId。如果你的进程在生成中途崩溃,通过轮询已存储的 id 来恢复——不要重新创建任务,否则你会为第二次渲染付费。只有当原始创建请求本身在返回任务 id 之前失败时,才重新创建。由于 Ray 3.2 按片段计费,而且高分辨率下的片段并不便宜,重复创建是实实在在的成本错误,而不只是浪费时间。
你实际会看到的错误
下面每一行都是经过验证的线上响应形状:
| 症状 | 响应 | 修复方法 |
|---|---|---|
| 密钥缺失/无效 | 401,嵌套 {"error":{"code":"permission_denied","type":"hiapi_error","request_id":"..."}} |
检查 Authorization: Bearer sk-... 请求头以及密钥是否有访问权限。联系支持时请提供 request_id。 |
| 枚举值错误 | 400 INVALID_REQUEST,扁平 {"code":400,"error_code":"INVALID_REQUEST","message":"invalid input: <field>: value must be one of ..."} |
阅读 message 中指定的字段;它会列出确切的允许集合。 |
duration 以字符串发送 |
400 INVALID_REQUEST |
发送裸整数 5 或 10,而不是 "5"。 |
| 未知模型 id | 400,error_code: "MODEL_UNAVAILABLE","model not available via /v1/tasks" |
严格使用 ray-3.2/text-to-video——到模型页面查看规范 id。 |
| 轮询时任务 id 错误 | 404,扁平 {"code":404,"data":null,"message":"task not found"}(注意:404 上没有 error_code) |
id 错误,或者你用了另一个账户的密钥来查询。 |
轮询时 status: "fail" |
任务终态,详情在 data.error |
阅读 data.error.code / data.error.message。失败任务会退款;内容策略标记和上游容量问题会在这里暴露——对于内容标记,用改写后的提示词重试。 |
相关资源
- Ray 3.2 文生视频模型页面——在线体验、实时状态和完整价格表
- Ray 3.2 图生视频 API——同一模型系列,但它是对参考帧做动画,而不是从文本开始(输入 schema 不同——复用本请求体之前先探测一下)
- 如何使用 Hailuo 2.3 文生视频 API——一个同类配方,它的
duration是字符串,与 Ray 的整数形成有用对比 - hiapi 定价——按分辨率和时长列出的按片段视频费率
常见问题
模型 id 是什么,我该调用哪个端点?
ray-3.2/text-to-video,作为顶层 model 提交到 POST https://api.hiapi.ai/v1/tasks,参数放在 input 下。它是异步的——你会拿回一个 taskId,然后轮询 GET /v1/tasks/<id>(或注册回调)。
duration 以秒为单位吗,为什么 "5" 会失败?
片段为 5 秒或 10 秒,该字段是整数:发送 5 或 10。带引号的字符串,或任何其他数字如 7,都会失败并返回 400 INVALID_REQUEST: duration: value must be one of 5, 10。
我可以设置分辨率和宽高比吗?
可以——这正是 Ray 3.2 与仅支持提示词的视频模型的不同之处。resolution 为 540p、720p 或 1080p;aspect_ratio 为 16:9、9:16、1:1、4:3、3:4、21:9 之一。两者都是可选的(默认 540p 和 16:9),且都会以 400 拒绝超出范围的值。
一段片段多少钱?
Ray 3.2 按片段计费,分辨率是最大的杠杆——同样长度下,1080p 片段的成本是 540p 的几倍,而 10 秒片段的成本大约是 5 秒片段的三倍。费率会变化,所以请查看定价页,而不是硬编码一个数字,并在 540p/5 秒下做原型。
片段有音频吗? 没有——Ray 3.2 文生视频返回的是无声 MP4。如果你需要声音,请在后期添加,或使用单独的音频模型。
Ray 3.2 支持图生视频吗?
支持,作为同一任务 API 上的单独模型 id:ray-3.2/image-to-video。它的输入 schema 不同(它接收一张参考图),所以复用本请求体之前先探测一下——见图生视频模型页面。
我的生成很慢或看起来卡住了。什么情况算正常?
视频任务会运行几分钟。在你的轮询循环中保留非终态的 data.status 并等待——预留 10–15 分钟的截止时间,或者使用带 "when": "final" 的 callback,让 hiapi 在终态时通知你,而不是你自己猜一个间隔。