跳转到内容
中文

SDK

HiAPI 官方 SDK 帮你走完生成任务的整个流程:提交任务、轮询进度,最后返回一个任务对象,里面带着产出内容的 URL。幂等重试(可选开启)、类型化错误、webhook 验签这些都已经内置好了,不用自己再写轮询、退避重试或响应解析的逻辑。

Python

Python 3.8+。完整类型标注(内置 py.typed),run() 方法一次调用就能拿到最终结果——适用于 Web 后端、Notebook、自动化脚本。

pip install hiapi · v0.2.1 · PyPI · GitHub

Go

Go 1.21+。纯标准库客户端;每个任务 API 方法都接受 context.Context,支持多个 goroutine 并发调用。

go get github.com/HiAPIAI/hiapi-go · v0.2.1 · pkg.go.dev · GitHub

Java

Java 11+。仅用 JDK 自带能力(java.net.http.HttpClient)的客户端,响应对象不可变,无需管理任何运行时依赖。

ai.hiapi:hiapi · v0.2.1 · Maven Central · GitHub

Node.js

Node.js 18.17+。零依赖客户端,基于全局 fetch 构建;TypeScript 优先,完整类型声明,同时提供 ESM 和 CommonJS 入口。

npm install hiapi_ai · v0.2.1 · npm · GitHub

没有你需要的语言?用任意 HTTP 客户端直接调统一异步接口即可——这正是每个 SDK 底层封装的内容。

  • 一次调用,从提交到完成。 run 提交任务并替你轮询——想自己接管每一步,就直接用 create / retrieve / list / wait(Java 里叫 waitFor)。
  • 幂等重试(可选开启)。 传入幂等键后,连接中断的重试就变得安全,不会有重复创建(和重复计费)任务的风险;不传就是默认关闭,由你决定何时启用。
  • 模型线路,无需手动拼接字符串。 遇到提供多个处理选项的模型时,用一个普通参数选择,不用手动拼接 model@route 名称。
  • 类型化错误。 认证失败、模型不可用、超时、幂等键冲突这些常见失败,在各语言里都映射为独立可捕获的错误类型,常见情况不用再解析通用 HTTP 异常。
  • Webhook 验签辅助。 一个方法替你校验回调的签名与时间戳——不用自己写 HMAC 比对逻辑。

开始前:先按上面的方式装好 SDK,然后去 HiAPI 账户拿一个 API Key 并确保有余额——生成请求会扣费,先去对应的模型页看一眼价格。

提交任务、跟踪进度、读取结果:

from hiapi import HiAPI
# 这里直接写 api_key 是为了示例清晰;生产环境建议从环境变量
# (HIAPI_API_KEY)读取,不要硬编码。
client = HiAPI(api_key="sk-...")
task = client.tasks.run(
model="happyhorse-1-0",
input={"prompt": "a cyan glass data center entrance", "duration": 5, "resolution": "720p"},
on_update=lambda t: print("status:", t.status),
)
for out in task.output:
print(out.type, out.url)

run 会一直轮询,直到任务成功、失败,或客户端超时(默认 10 分钟)。超时只是让 SDK 停止轮询——不会取消任务,任务仍可能在后台跑完并产生费用。遇到超时,用任务 id 调 retrieve 去查结果,不要重新提交同一个请求。若需要生命周期的完全控制,直接用 create / retrieve / list / wait(Java 里叫 waitFor)——详见各 SDK 的 README:Python · Go · Java · Node.js

上面拿到的 output URL 是临时的——HiAPI 大约在创建后 7 天自动删除。Node.js SDK 可以在创建任务时传 storage: "persistent" 直接指定长期存储(按大小计费;余额不足会静默降级为 "temp",实际使用的档位以 task.storage 为准);Python、Go、Java 三个 SDK 暂未提供创建时指定的方式,想在到期前留住某个产物,需要转为持久存储(也可以在控制台里操作)。存储档位与计费详见产物存储

到这里已经跑通了一次调用。下面几节讲的是正式上线后你会用到的东西:选择模型线路、让重试变得安全、验签 webhook 回调,以及处理错误。

部分模型页会列出不止一个处理选项——比如 ext——对应不同价格或可用性。把那个页面上显示的线路值原样传进参数,不用手动拼接 model@route 名称:

created = client.tasks.create(
model="gpt-image-2/text-to-image",
route="ext", # 优先于旧的 "model@ext" 后缀写法
input={"prompt": "..."},
)

省略线路参数(或传 "default")会使用模型的默认线路。未知线路会在任务创建、计费之前就被拒绝,返回 400 并列出可用线路。旧代码里的 x@ext 后缀写法仍然可用。

设置幂等键(作为 Idempotency-Key 请求头发送,≤255 字节),重试提交就不会创建第二个、被重复计费的任务。每个业务任务用一个稳定的键——比如从你自己的订单号或任务 ID 派生:

created = client.tasks.create(
model="seedance-2.0",
input={"prompt": "..."},
idempotency_key="order-8472:video", # 按任务派生出的稳定键
)
if created.idempotent_replay:
print("命中了更早那次请求创建的任务,本次没有新建任务")

这个保证具体是怎么回事: 同一个键第一次被接受的请求会创建并计费一个任务。用同一个键、同一个请求体重试,都会返回那同一个任务(idempotent_replaytrue),不会再创建或计费第二个。这个键会在创建后大约 24 小时被清理掉——把它当成”大概一天”,不要当成一个可以精确掐点的边界——清理之后同样的请求会创建一个新任务。键要选和这个任务唯一绑定的值,不要选一个你打算无限期复用的值。

设置了幂等键后,SDK 还会在网络错误时自动重试提交,也会重试 409 IDEMPOTENCY_KEY_PROCESSING(同一个键的首个请求仍在处理中)——但重试次数受客户端配置的重试上限约束,不是无限等待。用同一个键携带不同请求体,会命中下方表格里独立的、不可重试的错误:这说明幂等键的生成逻辑有问题,需要修复,而不是原样重试。

创建任务时传 callback.url(一个公网可访问的 HTTPS 地址),任务无论成功还是失败结束,HiAPI 都会向这个地址发一个 POST——不需要轮询。如果你还在 HiAPI 账户设置里配置了 webhook 签名密钥,这个请求会带签名;在信任它之前,对照原始请求体验签:

# Flask 示例
from flask import Flask, request
from hiapi import HiAPI, WebhookVerificationError
app = Flask(__name__)
app.config["MAX_CONTENT_LENGTH"] = 1024 * 1024 # 1 MiB——读取之前先拒绝超大请求体
client = HiAPI(api_key="sk-...", webhook_secret="whsec_...")
@app.post("/hiapi/callback")
def callback():
try:
task = client.webhooks.verify(request.get_data(), request.headers)
except WebhookVerificationError:
return "", 400
# 幂等地处理——比如按 task.task_id upsert 你自己的业务记录,
# 这样同一事件的重复投递就是无害的。
if task.succeeded and task.output:
print(task.output[0].url)
return "", 200 # 副作用成功之后再回 2xx

verify 只检查签名、拒绝时间戳超出 300 秒窗口的请求——不会帮你去重。回调按至少一次投递,也可能并发到达,所以要像上面示例那样让处理器本身幂等:副作用按任务 id 落库(比如 upsert),并且副作用成功之后才回 2xx。这样重复投递是无害的,处理失败或进程崩溃则会被自动重投——重投就是你的重试。

有一种写法要避免:处理之前先写一个永久的”已处理”标记,看起来是干净的去重,实际会丢事件——标记写完、处理做完之前进程崩溃,重投会看到”已处理”而永久跳过这个事件。如果确实需要防止两次并发投递重复执行昂贵的副作用,用带过期/租约的”处理中”状态、成功后才标记完成,而不是先写死一个永久标记。

常见失败在各语言里都映射为独立可捕获的错误类型——对照上面选的语言查具体类型名。两条边界要记住:

  • 下表的错误码行对应的是同步非 2xx API 响应。任务在轮询过程中失败,永远以轮询失败错误的形式出现——Python 是 TaskFailed,Go 是 *TaskFailedError,Java 是 TaskFailedException,Node.js 是 TaskFailedError——具体原因读它的 code 字段(可能是 TASK_TIMEOUTSTORAGE_UNAVAILABLE 等)。
  • 没有专属类型的少见响应——比如 402 余额不足、403、或重试耗尽后的 429——以各 SDK 的基础 API 错误形式出现,带着 HTTP 状态码和原始响应体。
场景PythonGoJavaNode.js
401——API Key 缺失或错误AuthenticationErrorErrAuthenticationAuthenticationExceptionAuthenticationError
404——任务不存在,或不属于你NotFoundErrorErrNotFoundNotFoundExceptionNotFoundError
INVALID_REQUEST——请检查请求参数InvalidRequestErrorErrInvalidRequestInvalidRequestExceptionInvalidRequestError
MODEL_UNAVAILABLE——重试或换模型ModelUnavailableErrorErrModelUnavailableModelUnavailableExceptionModelUnavailableError
TASK_FAILED——提交被同步拒绝TaskFailedErrorErrTaskFailedSyncAPIException(用 getErrorCode() 判别)TaskFailedSyncError
TASK_TIMEOUT——上游任务本身超时(服务端)TaskTimeoutErrorErrTaskTimeoutTaskTimeoutExceptionTaskTimeoutError
STORAGE_UNAVAILABLE——产物存储出错StorageUnavailableErrorErrStorageUnavailableStorageUnavailableExceptionStorageUnavailableError
503——平台繁忙(自动重试)ServiceUnavailableErrorErrServiceUnavailableServiceUnavailableExceptionServiceUnavailableError
409——同一幂等键仍在处理中(在重试上限内自动重试)IdempotencyKeyProcessingErrorErrIdempotencyKeyProcessingIdempotencyKeyProcessingExceptionIdempotencyKeyProcessingError
422——同键携带不同请求体(不可重试)IdempotencyKeyMismatchErrorErrIdempotencyKeyMismatchIdempotencyKeyMismatchExceptionIdempotencyKeyMismatchError
轮询到的任务终态为 status=failTaskFailed*TaskFailedErrorTaskFailedExceptionTaskFailedError
run / wait 超过客户端超时时间PollTimeout*PollTimeoutErrorPollTimeoutExceptionPollTimeoutError
网络故障(仅读取类调用自动重试——非幂等提交不重试)APIConnectionError*ConnectionErrorAPIConnectionExceptionAPIConnectionError
run 创建任务后立即被中止RunAbortedError
run 创建任务后在轮询或执行 onUpdate 时失败RunFailedError

Go 里的 Err* 是配合 errors.Is 使用的哨兵值(sentinel),按这个方式匹配错误类别;需要完整的 *APIError(状态码、错误码、原始响应体)时用 errors.As 取。Node.js 里要注意两个相近的类名:TaskFailedSyncError 是提交被同步拒绝的 TASK_FAILEDTaskFailedError 是轮询到的任务终态为 fail——和 Python 正好相反(Python 里 TaskFailedError 是同步拒绝那个)。Node.js 的 RunAbortedErrorRunFailedError 都带着已创建任务的 taskId;这个任务可能仍会继续运行并计费,因此要稍后调用 retrieve(taskId),不要重新提交。RunFailedError.cause 会保留打断 run 的轮询、回调或中止错误。429/503 响应,以及幂等调用上的网络错误,都会自动按退避策略重试。完整错误层级与客户端配置详见各 SDK 的 README:Python · Go · Java · Node.js

  • 认证 —— 获取 API Key,了解请求认证方式。
  • 模型目录 —— 浏览模型、参数与各模型的计费。
  • 统一异步接口 —— 每个 SDK 底层封装的 /v1/tasks 契约。