HiAPI
博客

教程

如何在 HiAPI 上调用 gpt-image-2/image-to-image:curl、Python 与一次可用的请求

面向开发者的图生图请求实操:提交参考图、轮询任务并下载结果

2026年10月31日
扁平流体形态交叠的封面图,墨黑底色上浮现青瓷绿与石板灰的克制波纹,呼应教程文章。

image-to-image 端点期望什么

HiAPI 上的 gpt-image-2/image-to-image 模型是一个异步图像生成端点。与阻塞等待图像返回的同步调用不同,这个端点会接收你的请求、将其排队,并返回一个任务句柄。随后你需要持续跟踪该任务,直到它完成。

在请求层面,你需要提供三样东西:

  • 模型 id:gpt-image-2/image-to-image。
  • 一张参考图:模型应基于其进行转换或构建的源图像。这是图生图模式的决定性输入——没有它,你做的就是文生图。
  • 提示词与选项:一段描述期望输出的文本指令,以及模型文档中列出的可选字段(例如尺寸或输出格式)。只发送模型文档列出的参数。

响应并不是图像本身,而是一个包含标识符和状态的任务对象。把这个状态当作唯一事实来源:pending 或 processing 表示继续等待,succeeded 表示结果已就绪,failed 表示出了问题,应当停止轮询。

从一开始就围绕这个生命周期设计你的客户端。本教程中的其他一切——curl、Python、轮询、下载——都建立在“提交与完成是两个独立时刻”这一事实之上。

准备你的 HiAPI 密钥与参考图

在写任何代码之前,先准备好两样东西。

一个 API 密钥。在 HiAPI 控制台创建一个,并将其存入环境变量,而不是直接粘贴到脚本中:

export HIAPI_API_KEY="your-key-here"

把密钥当作机密对待。不要提交到版本库,也不要在请求日志中记录它。

一张参考图。选一个你希望转换的本地图像文件。保持合理的尺寸——过大、高分辨率的源图是请求缓慢或被拒绝最常见的原因。把 PNG 或 JPEG 放在脚本所在目录下,第一次运行最省事:

ls -lh ./reference.png

记下文件路径;你将在 curl 和 Python 示例中都引用它。如果你打算从服务器调用该模型,请确认进程对该路径有读权限,并且文件是有效图像(不是扩展名错误的改名文件)。

密钥已导出、图像已在磁盘上,第一次请求所需的一切就齐了。

一个可用的 curl 请求

验证凭据和请求体结构最快的方式,是执行一次 curl 调用。它会提交任务并打印任务对象:

curl -sS https://api.hiapi.ai/v1/tasks \
  -H "Authorization: Bearer $HIAPI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-image-2/image-to-image",
    "input": {
      "image": "https://example.com/reference.png",
      "prompt": "Turn this photo into a watercolor illustration"
    }
  }'

关于这个示例有两点说明。第一,参考图通过 input.image 字段以 URL 形式传入;如果端点文档针对你的场景支持内联 base64 或 multipart 上传,请使用那种形式,但保持字段名一致。第二,提示词就是你描述转换的地方——要具体说明风格、构图以及哪些内容应保持不变。

运行它并读取响应。提交成功会返回一个任务 id 和一个非终态状态。如果得到 401,说明你的密钥缺失或错误。如果得到 422 或类似的验证错误,检查请求体——通常是模型 id 或 image 字段格式有误。

保存任务 id。后续步骤都依赖它。

用 Python 做同样的事

Python 版本应与 curl 调用完全对应,显式保留认证与请求体构建,避免任何东西被封装层隐藏。使用 requests:

import os
import requests

API_KEY = os.environ["HIAPI_API_KEY"]
BASE_URL = "https://api.hiapi.ai/v1"

headers = {
    "Authorization": f"Bearer {API_KEY}",
    "Content-Type": "application/json",
}

payload = {
    "model": "gpt-image-2/image-to-image",
    "input": {
        "image": "https://example.com/reference.png",
        "prompt": "Turn this photo into a watercolor illustration",
    },
}

response = requests.post(f"{BASE_URL}/tasks", json=payload, headers=headers, timeout=30)
response.raise_for_status()
task = response.json()
print(task["id"], task["status"])

如果你的集成发送的是本地文件而非 URL,请按端点文档编码并附加图像,而不是自创字段。纪律与 curl 中相同:把请求体构建为普通字典、发送、在解析之前检查 HTTP 状态。

把提交逻辑封装到一个返回任务 id 的函数中。这样下一节的轮询代码就与任务如何创建无关了。

轮询异步任务直至完成

提交调用在图像仍生成时就已经返回。要拿到结果,就轮询任务状态端点,直到任务进入终态。一个健壮的循环具备三个特性:轮询之间的延迟、最大等待时间,以及对失败状态的明确处理。

import time

def wait_for_task(task_id, headers, base_url, timeout=300, interval=3):
    deadline = time.time() + timeout
    while time.time() < deadline:
        r = requests.get(f"{base_url}/tasks/{task_id}", headers=headers, timeout=30)
        r.raise_for_status()
        task = r.json()
        status = task["status"]
        if status == "succeeded":
            return task
        if status == "failed":
            raise RuntimeError(f"Task failed: {task}")
        time.sleep(interval)
    raise TimeoutError(f"Task {task_id} did not finish within {timeout}s")

几点实用的改进:

  • 退避:以较短的间隔开始并逐渐增大,或者保持一个足够宽裕的固定间隔,以免频繁冲击 API。图像生成并非瞬时完成。
  • 超时:始终为总等待时间设上限。否则一个卡住的任务会无限期挂起你的 worker。
  • 终态:只把 succeeded 和 failed 视为终态。任何其他状态都意味着继续轮询。如果 API 将来新增中间状态,你的循环仍能正确运行。

如果你要运行大量任务,请在后台 worker 或队列中轮询,而不是阻塞一个 Web 请求。生命周期相同,只是并发模型不同。

下载并验证结果

一旦任务报告成功,任务对象中会包含生成图像的位置——通常是输出字段中的一个 URL。下载它并写入磁盘:

task = wait_for_task(task_id, headers, BASE_URL)
image_url = task["output"]["image"]

img = requests.get(image_url, timeout=60)
img.raise_for_status()

with open("result.png", "wb") as f:
    f.write(img.content)

如果签名 URL 有有效期,请在完成后立即下载,或直接持久化文件,而不是把 URL 存起来以后再用。如果你的端点返回 base64 而非 URL,请先解码再写入。

一次快速的完整性检查可以避免令人困惑的下游故障:

from PIL import Image

with Image.open("result.png") as im:
    im.verify()
print("valid image, bytes:", os.path.getsize("result.png"))

如果文件不是可解码的图像,verify() 会抛出异常,这能捕获被截断的下载以及被保存成图像的错误页面。检查字节大小也能告诉你响应是否合理。至此循环完成:提交、轮询、下载、验证。

排查常见故障

大多数首次集成会以几种可预见的方式失败。按以下顺序诊断。

认证错误(401/403)。密钥缺失、格式错误或缺少权限。确认环境变量已在执行请求的 shell 或进程中导出,并且 Authorization 头使用了 API 期望的确切前缀。

参考图无效或过大(400/422)。图像 URL 可能从 API 一侧不可达,文件可能损坏,或者尺寸与文件大小超出限制。先用一张小巧、确认可用的 PNG 测试。如果传 URL,确保它可公开获取;如果传内联数据,确认编码正确。

轮询超时。如果任务持续触达你的超时,请增大上限、延长间隔,或检查任务是否实际已失败,只是你没有把原因展示出来。在抛出异常前记录最后一个任务对象,以便查看状态。

速率限制(429)。进行退避并带抖动重试,而不是立即重试。如果你大量并行提交,请限制并发以免突发流量触发限制,并通过记录任务 id 让重试具备幂等性。

对于任何错误类别,记录 HTTP 状态、截断的响应体和任务 id——这三样通常就足以判断问题出在认证、请求体还是时序。先用 curl 示例隔离问题是在你的代码还是输入,然后把修复移植回 Python。

立即开始构建持久 AI 产物

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

阅读 API 文档