教程
如何在 HiAPI 上调用 kling-4.0/image-to-video:curl、Python 与轮询
kling-4.0/image-to-video 端点的作用
kling-4.0/image-to-video 可将单张静态图片转换为一段较短的生成视频。在 HiAPI 上,它作为基于任务的端点提供:你提交一张图片,以及一段提示词风格的描述,说明你希望画面如何运动,API 会立即返回一个任务句柄,而不是最终完成的视频。
在请求层面,调用方需要提供:
- 模型标识符(
kling-4.0/image-to-video), - 源图片(通常是可公开访问的图片 URL),
- 一段文本描述,用于指导图片如何运动,或场景中应该发生什么,
- 该端点为此模型记录的所有额外生成选项。
返回的并不是视频本身。提交响应会携带一个任务标识符和一个初始状态。真正的视频片段会在生成任务完成之后才可用,届时你可以通过引用该标识符来获取。
这种拆分正是该端点的完整心智模型:提交 → 获取任务 id → 轮询状态 → 下载结果。下文每一节都是这个循环的变体。
由于该端点是异步的,你的集成代码有两项职责,而不是一项:它必须发送格式正确的提交请求,并且必须管理后续流程,直到任务进入终止状态。处理好这两点,剩下的只是常规衔接工作。
前置条件与认证
在任何调用之前,你需要两样东西:一个拥有该模型访问权限的 HiAPI 账户,以及一个从控制台签发的 API 密钥。
认证是按请求进行的。每次调用 API 都会在 HTTP 头中包含你的密钥——标准模式是 bearer 风格的授权头:
Authorization: Bearer <YOUR_HIAPI_API_KEY>
不要让密钥进入源代码管理。通常的做法如下:
- 将它存储在环境变量中(例如
HIAPI_API_KEY),并在运行时读取。 - 绝不要将它粘贴到客户端代码中,也不要粘贴到你之后会提交到仓库的 curl 命令中。
- 一旦密钥泄露,请从控制台轮换它。
在 shell 中导出它,以便下面的 curl 和 Python 示例都能读取:
export HIAPI_API_KEY="your-key-here"
你还需要一个可访问的图片 URL。该端点通过引用来使用图片,因此你笔记本电脑上的本地文件路径不可行——请将图片托管在具有稳定 HTTPS URL 的位置,或者如果平台提供资源机制,则上传图片并使用返回的引用。
密钥导出且图片可访问后,你就可以提交任务了。
逐步解析 curl 请求
一个完整的提交请求如下所示:
curl -X POST "https://api.hiapi.ai/v1/tasks" \
-H "Authorization: Bearer $HIAPI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "kling-4.0/image-to-video",
"input": {
"image": "https://example.com/your-image.jpg",
"prompt": "A slow camera push-in as the subject turns toward the light; soft afternoon shadows"
}
}'
逐部分解读:
-X POST— 任务创建是 POST,而不是 GET。请求携带描述作业的正文。- URL — 统一的 HiAPI 任务端点。对于基于任务的模型,这是同一条路由;模型是在正文中选择的,而不是在路径中。
Authorization— 你的密钥,如上一节所述。Content-Type: application/json— 正文是 JSON;省略或拼错这个头,服务器通常会在请求到达模型之前就拒绝它。model— 字面字符串kling-4.0/image-to-video。请将其视为精确且区分大小写;拼写错误会产生模型未找到错误,而不是有用的提示。input.image— 源静态图片,以 URL 形式提供。这是模型要使其动起来的帧,因此请选择清晰且构图明确的图片。input.prompt— 自然语言指导。描述运动和镜头行为(推近、平移、主体移动)以及整体氛围。模糊的提示词会产生模糊的运动。
即时响应是一个任务对象,而不是视频。它包含作业的标识符和一个状态字段——提交后通常类似于排队或待处理状态。保存该标识符;这是你之后检查作业所需的唯一信息。
此时视频片段尚不存在。这是预期行为,下一节将展示如何处理。
Python 中的相同调用
Python 版本做的事情完全相同——相同的端点、相同的头、相同的正文——因此你选择的工具不会改变协议。
import os
import requests
API_KEY = os.environ["HIAPI_API_KEY"]
payload = {
"model": "kling-4.0/image-to-video",
"input": {
"image": "https://example.com/your-image.jpg",
"prompt": "A slow camera push-in as the subject turns toward the light; "
"soft afternoon shadows",
},
}
resp = requests.post(
"https://api.hiapi.ai/v1/tasks",
headers={
"Authorization": f"Bearer {API_KEY}",
"Content-Type": "application/json",
},
json=payload,
timeout=60,
)
resp.raise_for_status()
task = resp.json()
task_id = task["id"]
print("submitted:", task_id, task.get("status"))
实践中需要注意的几点:
- 使用
json=payload,而不是手工序列化字符串。它会为你设置内容类型,并避免引号错误。 - 将提交请求和后续操作放在同一个函数或类中,这样任务 id 不会在步骤之间丢失。
- 设置明确的超时时间。提交调用应快速返回;它只是创建作业,而不是等待视频。
- 不要调用
raise_for_status()后还继续假定任务存在——非 2xx 响应意味着没有创建任务,错误正文通常会告诉你哪个字段有误。
如果你在构建服务,请将此调用包装在一个小型客户端中,一个方法用于提交,一个方法用于检查状态。这样可以将重试、日志记录和密钥处理集中在一处,而不是分散在各调用点。
轮询异步任务直至完成
图生视频的生成比聊天补全耗时明显更长——模型必须合成许多帧、对其进行编码并存储结果。如果不在提交响应中保持连接长时间打开,就无法返回视频片段,因此该端点在设计上就是异步的。
如何检查状态
使用 GET 请求按标识符轮询任务:
curl "https://api.hiapi.ai/v1/tasks/$TASK_ID" \
-H "Authorization: Bearer $HIAPI_API_KEY"
响应会描述作业:其状态,以及完成后的输出。状态通常从排队状态经过运行状态进入终止状态——例如成功,或因错误消息而失败。
Python 中的简单轮询循环
import time
def wait_for_task(session, base_url, task_id, timeout=900):
deadline = time.time() + timeout
delay = 2.0
while time.time() < deadline:
r = session.get(f"{base_url}/tasks/{task_id}", timeout=30)
r.raise_for_status()
data = r.json()
status = data.get("status")
if status in ("succeeded", "failed"):
return data
time.sleep(delay)
delay = min(delay * 1.5, 15.0) # gentle backoff, capped
raise TimeoutError(f"task {task_id} did not finish in time")
退避指导
- 从较短的间隔开始并逐渐增大。生成不会在第一秒完成,因此频繁请求端点只会浪费配额和触发速率限制。
- 限制间隔,以便及时注意到已完成的作业——稳定状态下几秒钟即可。
- 始终设置硬性截止时间。除非你设定边界,否则永远无法完成的任务与耗时异常长的任务无法区分。
- 从后台工作进程或定时作业中轮询,而不是阻塞 Web 请求。如果用户在 UI 中等待,让前端轮询你自己的状态端点。
- 对状态调用中的瞬时网络错误进行重试,但不要重试已经报告
failed的任务——此时正确的操作是提交一个新任务。
检索并存储返回的视频片段
当轮询返回终止成功状态时,任务对象包含生成视频的输出引用——一个指向已完成视频的资源 URL 或等效引用。
result = wait_for_task(session, "https://api.hiapi.ai/v1", task_id)
if result["status"] != "succeeded":
raise RuntimeError(result.get("error") or "generation failed")
video_url = result["output"]["video_url"]
with session.get(video_url, stream=True, timeout=120) as r:
r.raise_for_status()
with open(f"{task_id}.mp4", "wb") as f:
for chunk in r.iter_content(chunk_size=1 << 16):
f.write(chunk)
这里通常会出现两个设计决策。
及时下载。 输出 URL 通常有时间限制。如果你打算保留视频片段,请将其复制到你自己的存储中,而不是将原始 URL 交给用户并希望它保持有效。
将元数据与文件一起存储。 将任务 id、提示词、源图片引用和创建时间与视频一起持久化保存。当以后有人问为什么视频片段看起来是这样时,该记录就是答案。
对于提供服务,常见模式是:在后端生成,将文件存储在对象存储中,并向客户端返回你自己的稳定 URL。这样你的应用就能控制访问、过期和缓存,而不是依赖生成资源的生命周期。
如果你想用不同的运动重新生成,请提交一个调整了提示词的新任务——每个任务都是独立的,无需修改已完成的任务。
排查失败的请求
出现问题时,从请求结构向外排查。大多数失败都归结为少数几种原因。
提交调用返回错误
- 模型字符串错误。
kling-4.0/image-to-video必须完全匹配,包括大小写和斜杠。打印你实际发送的字符串,而不是信任源文件。 - 认证被拒绝。 确认头是
Authorization: Bearer <key>——不是裸密钥,不是查询参数——并且环境变量在运行请求的同一 shell 或进程中已设置。 - 图片无法访问。 图片必须能被平台通过 HTTPS 获取。localhost URL、私有存储桶或防盗链的主机都会失败。在无痕浏览器中打开 URL,验证它无需认证即可解析。
- 字段缺失或命名错误。 正文将模型输入嵌套在
input下。将prompt或image放在顶层而不是input内是常见失误,验证错误通常会指出字段名。 - 内容类型。 发送 JSON 正文而不带
Content-Type: application/json会在涉及模型之前就被拒绝。
任务已创建但从未成功
- 轮询太少或根本没有轮询。 检查你的循环是否真的在运行,以及它比较的状态值是否与 API 返回的一致。终止状态检查中的拼写错误会导致无限循环。
- 任务变为
failed。 阅读任务对象中的错误消息;它通常指向输入——例如无法解码的图片。 - 你触及了截止时间。 如果作业在超时附近仍在运行,请提高上限,而不是反复重新提交,后者只会增加负载和成本。
- 输出链接已过期。 如果任务成功但下载返回 404,说明完成与检索之间经过了太多时间。成功后立即下载。
一个快速诊断习惯:在最初几次集成时,逐字记录提交响应正文。它会告诉你任务 id、初始状态以及该端点返回的确切字段名,从而消除之后每次失败中的猜测。