HiAPI
博客

教程

如何通过 hiapi API 使用 flux-2-klein-9b/image-to-image:curl、Python 与可运行的请求

2026年11月3日
如何通过 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。

在写任何代码之前,有两点值得了解:

  1. image_urls 只接受一个 URL,不是范围。如果你围绕某个接受 1–14 张参考图的模型构建了共享提交代码,在这里发送两个 URL 会被拒绝——maxItems: got 2, want 1。此模型执行单张图片编辑,而非多参考图融合。
  2. 额外字段会被拒绝,而非忽略。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 传递多张参考图片吗? 不可以。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 并去掉参考图片——然后用测试调用验证,因为必填字段因模式而异。

每张图片花费多少? 定价按每次生成的使用量计费。请查看定价页上的实时费率。

立即开始构建持久 AI 产物

获取 API 密钥,通过一个基于任务(task)的 API 调用图像、视频和音频模型。

阅读 API 文档