教程
如何通过 hiapi API 使用 flux-2-klein-9b/image-to-image:curl、Python 与可运行的请求
本教程展示如何通过 hiapi 统一任务 API 调用 flux-2-klein-9b 的 image-to-image 模式:精确的请求结构、可运行的 curl 命令、可直接放入后端的 Python 脚本,以及一个如果你从平台上的其他模型迁移过来就会踩到的 schema 怪癖。
读完后你将拥有一个脚本:它接收单个参考图片 URL 和编辑提示词,返回一个可下载的生成图片 URL。
你需要准备
- 一个 hiapi 账号和 API key。可从 hiapi 控制台获取。
- 恰好一张托管在公共 HTTPS URL 上的参考图片。与平台上某些接受多张参考图的 image-to-image 模型不同,flux-2-klein-9b 的
image_urls数组上限为一项——详情见下文。 - 一段描述编辑或变换的文本提示词。
所有请求都发往统一任务端点,密钥放在 Authorization 请求头中:
POST https://api.hiapi.ai/v1/tasks
Authorization: Bearer sk-<your-key>
Content-Type: application/json
请求结构(以及一个容易让人踩坑的字段)
模型 id 是 flux-2-klein-9b/image-to-image——直接原样传入,与 /v1/models 中列出的完全一致。它的 input schema 很严格:
| 字段 | 类型 | 是否必填 | 说明 |
|---|---|---|---|
prompt |
string | 是 | 编辑指令。 |
image_urls |
string[] | 是 | 恰好一个参考图片 URL——minItems 和 maxItems 都为 1。 |
aspect_ratio |
string | 否 | 可选值之一:1:1、4:3、3:4、16:9、9:16。 |
seed |
integer | 否 | 固定它可复现结果。 |
output_format |
string | 否 | 可选值之一:jpeg、png、webp。 |
在写任何代码之前,有两点值得了解:
image_urls只接受一个 URL,不是范围。如果你围绕某个接受 1–14 张参考图的模型构建了共享提交代码,在这里发送两个 URL 会被拒绝——maxItems: got 2, want 1。此模型执行单张图片编辑,而非多参考图融合。- 额外字段会被拒绝,而非忽略。
resolution、size、n、strength、image_size和num_images——这些在平台上其他图片模型中都常见——在这里都会返回400 INVALID_REQUEST: additional properties '<field>' not allowed。不要未检查此模型 schema 就复用另一个模型的 payload。
最小可运行示例:curl
创建任务:
curl -X POST https://api.hiapi.ai/v1/tasks \
-H "Authorization: Bearer sk-<your-key>" \
-H "Content-Type: application/json" \
-d '{
"model": "flux-2-klein-9b/image-to-image",
"input": {
"prompt": "Change the jacket to charcoal grey leather, keep the pose and background unchanged",
"image_urls": ["https://your-cdn.example.com/subject.png"],
"aspect_ratio": "3:4",
"output_format": "png"
}
}'
提交成功后会在 data 中返回一个任务 id:
{"code": 200, "data": {"taskId": "tk-hiapi-..."}}
轮询获取结果:
curl https://api.hiapi.ai/v1/tasks/tk-hiapi-... \
-H "Authorization: Bearer sk-<your-key>"
运行期间,data.status 会依次经过 queued → handling → archiving。完成后会翻转为 "success",图片出现在 data.output 中:
{
"code": 200,
"data": {
"status": "success",
"output": [{"url": "https://.../result.png", "expireAt": "..."}]
}
}
输出 URL 是短时效的(注意 expireAt)。请立即下载字节并自行存储——切勿热链或持久化原始 URL。
生产级 Python:提交、轮询、下载
import time
import requests
API_BASE = "https://api.hiapi.ai/v1/tasks"
API_KEY = "sk-<your-key>"
HEADERS = {"Authorization": f"Bearer {API_KEY}"}
def edit_image(prompt: str, image_url: str,
aspect_ratio: str = "1:1", output_format: str = "png") -> bytes:
# 1. 创建任务——此模型的 image_urls 只接受恰好一个 URL
resp = requests.post(API_BASE, headers=HEADERS, json={
"model": "flux-2-klein-9b/image-to-image",
"input": {
"prompt": prompt,
"image_urls": [image_url],
"aspect_ratio": aspect_ratio,
"output_format": output_format,
},
}, timeout=60)
body = resp.json()
if resp.status_code != 200 or not (body.get("data") or {}).get("taskId"):
raise RuntimeError(f"create failed [{resp.status_code}]: {body}")
task_id = body["data"]["taskId"]
# 2. 轮询直到终态
deadline = time.time() + 600
while time.time() < deadline:
task = requests.get(f"{API_BASE}/{task_id}", headers=HEADERS,
timeout=30).json().get("data") or {}
if task.get("status") == "success":
outputs = task.get("output") or []
if not outputs or not outputs[0].get("url"):
raise RuntimeError(f"task {task_id} succeeded but returned no output URL")
# 3. 立即下载——URL 会过期
img = requests.get(outputs[0]["url"], timeout=120)
img.raise_for_status()
return img.content
if task.get("status") == "fail":
err = task.get("error") or {}
raise RuntimeError(f"task failed: {err.get('code')} {err.get('message')}")
time.sleep(5)
raise TimeoutError(f"task {task_id} still running after 600s")
if __name__ == "__main__":
png = edit_image(
"Change the jacket to charcoal grey leather, keep the pose and background unchanged",
"https://your-cdn.example.com/subject.png",
aspect_ratio="3:4",
)
with open("edited.png", "wb") as f:
f.write(png)
print(f"saved edited.png ({len(png)} bytes)")
用 seed 实现可复现编辑
传入一个整数 seed,模型会在该次生成中复用它,这在你希望保持其他一切不变、对提示词措辞做 A/B 测试时很有用:
{
"model": "flux-2-klein-9b/image-to-image",
"input": {
"prompt": "Change the jacket to charcoal grey leather, keep the pose and background unchanged",
"image_urls": ["https://your-cdn.example.com/subject.png"],
"seed": 42
}
}
省略它,模型会在每次调用时随机选择 seed,这正是正常生产流量想要的——当你需要不同外观的输出时,改变提示词,而不是 seed。
用回调代替轮询
对于脚本和 worker 队列,轮询就可以了。对于 Web 后端,在创建任务时注册回调,让 hiapi 将终态推送给你——callback 对象位于请求顶层,与 model 同级:
{
"model": "flux-2-klein-9b/image-to-image",
"input": { "...": "..." },
"callback": {
"url": "https://your-app.example.com/hooks/hiapi",
"when": "final"
}
}
使用 "when": "final" 时,当任务达到成功或失败状态,你会恰好收到一次 POST。处理器有两条规则:
- 使其幂等。让你的处理逻辑以任务 id 为键,这样重投递的 webhook 不会重复处理。在提交时存储任务 id,将回调视为“去获取并终结”,而非唯一事实来源。
- 保留对账路径。如果回调触发时你的端点不可用,定期扫描未解决 id 并 GET
/v1/tasks/<id>,可以捕获任何遗漏。
如果你的回调似乎从未到达,请逐一排查为什么你的 hiapi 任务回调没有触发——文中按可能性顺序覆盖了常见故障模式。
错误处理:三个关键失败场景
创建时返回 401 permission_denied——你的密钥无法使用此模型。响应体如下:
{"error": {"code": "permission_denied", "message": "...", "request_id": "...", "type": "hiapi_error"}}
如果遇到此问题,请排查API key 无效,或在控制台中检查密钥的模型权限。
创建时返回 400 INVALID_REQUEST——你的 input 与此模型的 schema 不匹配。消息会直接指出违规字段(例如 <root>: additional properties 'resolution' not allowed,或 image_urls: maxItems: got 2, want 1)。这些是永久性错误——重试同样的 payload 会永远失败;修正字段后重新发送。
任务返回 status: "fail"——创建成功但生成失败(后端无法抓取的参考 URL、内容政策、上游容量)。任务的 error.code 和 error.message 会说明是哪一种。与 400 不同,其中一些是暂时性的,值得带退避重试一次。
另外值得了解:对不存在或已过期的任务 id 执行 GET 会返回 404 task not found——在对账扫描中应将其视为终态,而非“仍在等待”。
接下来去哪里
- flux-2-klein-9b/image-to-image 模型页——试玩场和每张图片定价。
- hiapi 定价——所有图片模型的当前费率。
- seedream-5.0-lite image-to-image 教程——相同的任务 API,schema 接受最多 14 张参考图而非 1 张;很好地说明了为什么 payload 不能在模型之间转移。
- hiapi 异步任务 API 文档——完整的创建/轮询/回调参考。
- hiapi 认证文档——API key 设置和请求头格式。
常见问题
我可以向 flux-2-klein-9b image-to-image 传递多张参考图片吗?
不可以。image_urls 的 minItems 和 maxItems 都设为 1——恰好一个 URL,不多不少。如果你需要多参考图融合,请查看 schema 记录了更宽范围的模型,例如 seedream-5.0-lite。
为什么我会收到“additional properties 'resolution' not allowed”?
任务 API 的 input schema 是按模型区分的。flux-2-klein-9b/image-to-image 根本不接受 resolution 或 size 字段——输出尺寸跟随输入图片和 aspect_ratio。请删除从其他模型 payload 带过来的任何尺寸字段。
我可以将参考图片以 base64 而非 URL 发送吗?
此模型的 schema 接受 image_urls——一个 URL 数组。请将图片托管在可访问的 HTTPS URL 上(任何 CDN、对象存储桶或预签名 URL 均可)并传递该 URL。
seed 实际控制什么?
使用相同的 seed、相同的 prompt 和参考图片会复现相同的生成结果,这对受控的提示词 A/B 测试很有用。正常流量中省略它,让每次调用获得自己的随机 seed。
同样的代码适用于 flux-2-klein-9b text-to-image 吗?
端点和流程相同,但 text-to-image 有自己的 input schema(没有 image_urls)。将模型 id 换成 flux-2-klein-9b/text-to-image 并去掉参考图片——然后用测试调用验证,因为必填字段因模式而异。
每张图片花费多少? 定价按每次生成的使用量计费。请查看定价页上的实时费率。