教程
如何通过 hiapi API 使用 gpt-image-2/text-to-image:参数、代码与可运行示例
本教程展示了通过 hiapi 统一任务 API 用 gpt-image-2/text-to-image 生成图像所需的最少代码量,然后逐一解释每个参数,以及代码跑通后应当采用的生产级模式(回调、幂等性、错误处理)。
前置条件
你需要一个 API 密钥。请从 hiapi 控制台的 API 密钥页面创建——密钥以 sk- 开头。gpt-image-2/text-to-image 的模型页面列出了当前的单张图像价格;完整明细见价格页面。
本指南中的所有调用都打到统一的异步任务端点:
POST https://api.hiapi.ai/v1/tasks——创建生成任务GET https://api.hiapi.ai/v1/tasks/{taskId}——轮询任务状态
平台通用参考文档位于 hiapi API 文档。
最小可运行示例(curl)
单次生成是一个两步交互:先创建任务,然后等待其完成。
# 1. Create the task
curl -s -X POST https://api.hiapi.ai/v1/tasks \
-H "Authorization: Bearer sk-YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-image-2/text-to-image",
"input": {
"prompt": "a calico cat curled up on a sunlit windowsill, soft focus background",
"aspect_ratio": "1:1",
"resolution": "1K"
}
}'
# => {"code":200,"data":{"taskId":"tk-hiapi-01KVY...."},"message":"success"}
# 2. Poll until status == "success"
TASK_ID="tk-hiapi-01KVY...."
curl -s "https://api.hiapi.ai/v1/tasks/$TASK_ID" \
-H "Authorization: Bearer sk-YOUR_KEY"
# => {"code":200,"data":{"status":"success","output":[{"url":"https://..."}], ...}}
图像 URL 位于 data.output[0].url。请立即下载——output[0].expireAt 很短,因此该 URL 只用于获取,不用于永久嵌入。
Python:创建 + 轮询 + 保存到磁盘
import os
import time
import urllib.request
import requests # pip install requests
API_BASE = "https://api.hiapi.ai/v1/tasks"
TOKEN = os.environ["HIAPI_API_KEY"] # sk-...
def create_task(prompt: str, aspect_ratio: str = "1:1", resolution: str = "1K") -> str:
payload = {
"model": "gpt-image-2/text-to-image",
"input": {
"prompt": prompt,
"aspect_ratio": aspect_ratio,
"resolution": resolution,
},
}
r = requests.post(API_BASE, json=payload,
headers={"Authorization": f"Bearer {TOKEN}"},
timeout=60)
r.raise_for_status()
body = r.json()
if body.get("error"):
raise RuntimeError(f"create failed: {body['error']}")
return body["data"]["taskId"]
def wait_task(task_id: str, timeout_s: int = 600, poll_s: int = 5) -> dict:
deadline = time.time() + timeout_s
while time.time() < deadline:
r = requests.get(f"{API_BASE}/{task_id}",
headers={"Authorization": f"Bearer {TOKEN}"},
timeout=30)
r.raise_for_status()
task = r.json().get("data") or {}
status = task.get("status")
if status == "success":
return task
if status == "fail":
raise RuntimeError(f"task failed: {task.get('error')}")
time.sleep(poll_s)
raise TimeoutError(f"task {task_id} did not finish in {timeout_s}s")
if __name__ == "__main__":
task_id = create_task(
"a calico cat curled up on a sunlit windowsill, soft focus background",
aspect_ratio="3:2",
resolution="1K",
)
task = wait_task(task_id)
url = task["output"][0]["url"]
urllib.request.urlretrieve(url, "cat.png")
print(f"saved cat.png from task {task_id}")
Node.js:使用 fetch 的相同流程
// Node 18+ has global fetch
const API_BASE = "https://api.hiapi.ai/v1/tasks";
const TOKEN = process.env.HIAPI_API_KEY;
async function createTask(prompt, aspectRatio = "1:1", resolution = "1K") {
const res = await fetch(API_BASE, {
method: "POST",
headers: {
"Authorization": `Bearer ${TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
model: "gpt-image-2/text-to-image",
input: { prompt, aspect_ratio: aspectRatio, resolution },
}),
});
const body = await res.json();
if (body.error) throw new Error(`create failed: ${body.error.code} ${body.error.message}`);
return body.data.taskId;
}
async function waitTask(taskId, { timeoutMs = 600_000, pollMs = 5_000 } = {}) {
const deadline = Date.now() + timeoutMs;
while (Date.now() < deadline) {
const res = await fetch(`${API_BASE}/${taskId}`, {
headers: { "Authorization": `Bearer ${TOKEN}` },
});
const task = (await res.json()).data || {};
if (task.status === "success") return task;
if (task.status === "fail") throw new Error(`task failed: ${JSON.stringify(task.error)}`);
await new Promise(r => setTimeout(r, pollMs));
}
throw new Error(`task ${taskId} timed out`);
}
(async () => {
const id = await createTask(
"a calico cat curled up on a sunlit windowsill, soft focus background",
"16:9",
"1K",
);
const task = await waitTask(id);
const url = task.output[0].url;
const img = await fetch(url).then(r => r.arrayBuffer());
const { writeFileSync } = await import("node:fs");
writeFileSync("cat.png", Buffer.from(img));
console.log(`saved cat.png from task ${id}`);
})();
参数参考
请求体始终包含两个顶层字段:model(字符串,裸模型 ID gpt-image-2/text-to-image)和 input(各模型专属的参数对象)。
input 字段 |
是否必填 | 类型 | 说明 |
|---|---|---|---|
prompt |
是 | string | 你想要的图像的文字描述。 |
aspect_ratio |
是 | string | 取值之一:1:1、3:2、2:3、4:3、3:4、5:4、4:5、16:9、9:16、21:9 或 auto。 |
resolution |
否 | string | 1K(默认)、2K 或 4K。像素尺寸随所选宽高比缩放。 |
callback |
否 | object | { "url": "https://yours.example/hook", "when": "final" }——见下一节。 |
创建成功返回 {"code":200, "data":{"taskId":"tk-hiapi-..."}, "message":"success"}。GET /v1/tasks/{taskId} 返回的 data.status 为 handling、success 或 fail 之一;成功时,data.output 是一个数组,其第一个元素包含图像的 url 和 expireAt 时间戳。
其他 hiapi 图像模型(例如
z-image、qwen-image)使用略有不同的input字段——aspect_ratio是gpt-image-2/text-to-image采用的约定。切换模型时,请查看模型页面以确认确切的input结构。
生产级模式
使用回调代替轮询
每 5 秒轮询一次对原型开发没问题,但对于生产流量,你希望 hiapi 把完成的任务推送给你,从而释放 worker。在 input 中添加一个 callback 块:
{
"model": "gpt-image-2/text-to-image",
"input": {
"prompt": "an astronaut sketching the moon",
"aspect_ratio": "3:2",
"resolution": "1K",
"callback": {
"url": "https://your-app.example.com/webhooks/hiapi",
"when": "final"
}
}
}
when: "final" 在任务达到终态(success 或 fail)时触发一次。你的端点收到的载荷结构与 GET /v1/tasks/{id} 相同,因此处理器可以复用轮询的解析逻辑。请将 taskId 与你创建任务时存储的 taskId 进行核对,从而知道回调属于哪个请求。
让创建操作具备幂等性
如果 worker 在 POST /v1/tasks 之后、存储 taskId 之前崩溃,你可能会把同一张图像生成两次。低成本的解决办法是:在收到创建响应的那一刻,在提交请求的同一事务中把 (your_request_id → taskId) 存入数据库。如果 worker 重试,它会找到已有的 taskId 并恢复轮询,而不是创建新任务。
正确处理鉴权错误
hiapi 鉴权失败会返回 HTTP 200,并在响应体内嵌错误载荷:
{"error":{"code":"permission_denied","message":"This API key cannot use the selected model. ...","type":"hiapi_error"}}
所以仅凭 200 状态码并不意味着成功。始终先检查 body.error;如果存在,查看 error.code(permission_denied、invalid_request 等)和 error.message。消息中的 request_id 就是你在需要帮助时粘贴到支持工单里的内容。
立即下载,自行重新托管
data.output[0].url 是一个短时效 URL——响应中包含 expireAt。不要把 hiapi 的 URL 直接放进你产品里的 <img src>;一旦任务成功就立刻下载字节流,上传到你自己的存储(S3、R2、Supabase Storage 等),然后从那里提供服务。
设置合理的超时
一个合理的默认值是:POST 请求超时 60 秒(创建任务很快——你实际上只是在等 API 确认收到),轮询循环总预算 10 分钟、轮询间隔 5 秒。耗时超过 10 分钟的任务几乎总是意味着任务已悄悄进入 fail 状态,因此超时并在日志中输出最后一次任务响应体,比无限等待更有用。
常见问题
gpt-image-2 和 gpt-image-2/text-to-image 有什么区别?
gpt-image-2 是模型系列;gpt-image-2/text-to-image 是你调用来将文本提示转换为新图像的特定端点。该系列中的其他变体暴露不同的 input 结构(例如,图像编辑接受参考图像)。如有疑问,请使用你在模型页面上看到的裸模型 ID。
aspect_ratio: auto 有什么作用?
auto 让模型根据提示决定宽高比。当你没有强烈的布局要求时使用它;否则请自行固定比例,以便下游裁剪可预测。
为什么我的请求返回 HTTP 200 却带有 permission_denied?
要么 API 密钥有误(拼写错误、已被撤销、缺少 sk- 前缀),要么该密钥的套餐不包含 gpt-image-2/text-to-image。打开 API 密钥控制台,确认密钥字符串,并在价格页面检查你的套餐。始终检查 body.error.code——绝不要只相信 HTTP 状态码。
我可以在一个请求中生成多张图像吗?
gpt-image-2/text-to-image 每个任务只生成一张图像——data.output 是数组,但对该模型来说长度始终为 1。要生成 N 个变体,请并发发起 N 个任务,并使用上面的 callback 模式,这样你就不会让 N 个工作线程一直挂着。
如何取消正在执行中的任务?
统一任务 API 目前不提供取消端点。最简单的缓解办法是让客户端 worker 在用户不再需要结果时丢弃它——已经执行的生成仍然会计费,因此强制执行取消的正确位置是在调用 POST /v1/tasks 之前。
如何切换到其他图像模型?
将 model 改为新的裸 ID(例如 z-image/text-to-image),并调整 input 以匹配该模型的结构。各模型的结构并不完全相同——有些接受 size,有些接受 aspect_ratio,还有少数不接受 resolution。模型目录列出了所有可用模型,每个模型页面都记录了其 input 字段。