教程
如何通过 HiAPI API 使用 gpt-image-2.5-sunburst/image-to-image:curl 与 Python
面向开发者的可运行请求、参考图上传流程与错误排查
本页内容
该端点上图生图的能力
gpt-image-2.5-sunburst/image-to-image 端点遵循一条简单的约定:你发送一张参考图外加一段自然语言编辑指令,模型返回一张应用了该指令、同时又锚定参考图的新图。与文生图不同——文生图从零开始、完全依赖你的提示词——图生图把参考图当作视觉上下文:构图、主体、风格和色彩线索都会被继承下来,除非你的指令明确要求改变它们。
这使它成为这样的场景下的正确选择:你已有现成素材,希望进行受控的变换,例如为产品照片换风格、改变光线或背景、调整主体的外观,或为已有概念生成变体。当你没有源素材、且希望获得最大创作自由度时,选择文生图;当对既有图像的保真度比新颖性更重要时,选择图生图。
开发者需要记住的关键心智模型:参考图是输入约束,编辑指令则是增量。好的指令描述应该改变什么,而不是所有应该存在的东西。“把背景换成干净的工作室渐变,保留主体及其阴影”比一段完整的场景描述效果更好,因为参考图已经提供了场景。阅读下文请求结构说明时请牢记这一点——请求体很小,但指令质量决定输出质量。
前置准备与请求结构
首次调用之前,请确认已准备好三样东西:
- API 密钥,由你的 HiAPI 账户签发。请将其放在环境变量中,而非源码里。
- 基础 URL,即 HiAPI API 的 base URL,参见你的仪表盘或 API 参考文档。
- 端点路径:
gpt-image-2.5-sunburst/image-to-image。
每个请求都是一个携带 JSON 请求体和 Authorization 请求头的 POST 请求。从概念上讲,请求体包含三个逻辑部分:
- 模型选择——该端点的模型标识符,以便网关正确路由调用。
- 输入——参考图(托管 URL 或 base64 数据字符串)以及编辑指令文本。
- 输出控制——端点文档中列出的任何可选参数,例如尺寸或数量。只使用官方参考文档中出现的参数;不要猜测名称。
关于纪律的一点提示:由于这是托管端点,具体接受哪些字段由当前 API 参考文档定义,而非从其他图像 API 推断。拿不准时,先发送最小合法请求体(model、image、prompt),确认返回 200 响应,再逐个添加可选字段。这样每个故障都能归因于单一改动,而不是一次性拼装的请求体。
发送参考图与编辑指令
参考图有两种受支持的提供方式,取舍主要在于图像字节存放在哪里。
托管 URL
如果图像已可公开访问,直接传入其 URL。这样请求体很小、序列化快速,也是开发阶段最简便的选择。URL 必须能被服务直接抓取——不能位于鉴权之后,不能是重定向链,也不能是一个恰好包含图片的 HTML 页面。
Base64 数据
如果图像在本地或属于私有资源,将其编码后内联发送。Base64 会使请求体膨胀约三分之一,因此源图较大时可能逼近大小限制。若接近上限,请先降采样再编码。
格式与大小陷阱
- 坚持使用主流格式(PNG、JPEG、WebP),并确保文件扩展名与实际字节一致。
- 过大的图像是请求被拒最常见的原因。尽量选用尺寸合理的源图;驱动一次编辑通常不需要全分辨率素材。
- 如果你自行拼接 base64 字符串,仅当 API 参考文档的示例中包含 data URI 前缀时才加上它,否则应去掉。混用这两种约定是“invalid image”错误的常见来源。
撰写编辑指令
输出质量的成败在于指令。要具体说明改什么,并明确说明保留什么。写明目标(“夹克”)、变换(“重新上色为深海军蓝”)以及约束(“保持模特姿势和现有阴影”)。避免在一条指令中堆叠多个无关编辑——如果需要相互独立的改动,就拆成多次调用,这样每个结果也更容易评估。
一个可运行的 curl 请求
下面是一个可在终端中完整运行的请求。请将密钥和图像占位符替换为你自己的值。
curl -X POST "$HIAPI_BASE_URL/gpt-image-2.5-sunburst/image-to-image" \
-H "Authorization: Bearer $HIAPI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-image-2.5-sunburst/image-to-image",
"image": "https://your-cdn.example.com/reference.png",
"prompt": "将背景替换为柔和的中性工作室渐变;保持主体、其姿势以及现有阴影不变。"
}'
逐项说明:
-X POST——该操作会创建新图像,因此使用 POST。- URL 由基础 URL 与端点路径拼接而成;把基础 URL 放在环境变量中便于切换环境。
Authorization: Bearer ...——你的 API 密钥。请将其导出为HIAPI_API_KEY,这样它就不会出现在 shell 历史或日志中。Content-Type: application/json——请求体是 JSON;遗漏该请求头是导致令人困惑的 4xx 响应的常见原因。model——端点的标识符。请与文档保持完全一致。image——参考图,此处为托管 URL。若要改用 base64,请替换为数据字符串或本地编码变量。prompt——编辑指令。保持只写改动内容以及需要保留的内容。
如果想用本地文件测试又不想手动编码,大多数 shell 都可以用小脚本或 jq 来构造 JSON;关键是最终请求体是包含这些字段的合法 JSON。
同样的请求用 Python 实现
Python 版本保持请求体完全一致,便于并排对比响应。使用 requests:
import os
import requests
base_url = os.environ["HIAPI_BASE_URL"]
api_key = os.environ["HIAPI_API_KEY"]
payload = {
"model": "gpt-image-2.5-sunburst/image-to-image",
"image": "https://your-cdn.example.com/reference.png",
"prompt": (
"将背景替换为柔和的中性工作室渐变;"
"保持主体、其姿势以及现有阴影不变。"
),
}
response = requests.post(
f"{base_url}/gpt-image-2.5-sunburst/image-to-image",
headers={
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json",
},
json=payload,
timeout=120,
)
response.raise_for_status()
print(response.json())
有两点值得注意。第一,json=payload 会设置内容类型并替你序列化请求体,从而消除一整类手工拼接 JSON 的错误。第二,timeout=120 是有意为之:图像生成并非瞬时完成,永远等待的客户端比干净失败的客户端更糟。请按你的工作负载调整超时,但一定要设置。
要改用本地文件,读取其字节、进行 base64 编码,把结果赋给 image。使用托管 URL 时则保持字符串原样。一旦 curl 与 Python 调用返回相同结构,你就确认了两者行为一致,可基于任一方式继续构建。
排查常见请求失败
大多数失败可归为四类。请按以下顺序逐一排查,因为每一类都可能伪装成下一类。
鉴权错误
401 或 403 几乎总是意味着密钥缺失、格式错误或已过期。检查请求头是否严格为 Authorization: Bearer <key>,确认没有因复制粘贴带入的多余引号或换行,并确认运行请求的 shell 或进程中确实设置了该环境变量。在 curl 中可用、在 Python 中却不可用的密钥,通常指向未设置的变量,而非坏掉的密钥。
请求体格式错误
带有校验信息的 400 通常意味着 JSON 非法或缺少必填字段。发送前先美化打印请求体,确认 model 与端点标识符一致,并确认编辑指令字段的名称与文档一致。在 curl 中手写 JSON 时,尾随逗号和单引号是经典元凶;Python 的 json= 可避免这些问题。
图像输入非法或过大
如果服务拒绝该图像,请核实三件事:URL 可公开抓取且返回的是图像(而不是重定向或错误页)、格式受支持、请求体不超过文档规定的大小限制。对于 base64 输入,确认编码干净且 data URI 前缀约定与参考示例一致。拿不准时,先降采样再重试——更小的源图能解决其中相当一部分错误。
超时与瞬时故障
耗时较长的生成可能超出客户端超时,而 429 或 5xx 响应表示触发了限流或遇到瞬时服务器问题。要把它们与客户端错误区分开:不要原样重试 400,但 429 或 503 适合做退避重试。为每次失败记录状态码和响应体——清晰的错误日志能把排查从猜测变成逐项核对。
从脚本到可复用客户端
一次性脚本能证明端点可用;一个小小的封装能让它在流水线中稳定运行。用一个函数把调用包装起来,由它负责三件事:请求、超时以及有界重试策略。
import os
import time
import requests
class ImageEditClient:
def __init__(self, base_url: str, api_key: str, timeout: int = 120):
self.base_url = base_url.rstrip("/")
self.api_key = api_key
self.timeout = timeout
def edit(self, image: str, prompt: str, retries: int = 3):
url = f"{self.base_url}/gpt-image-2.5-sunburst/image-to-image"
headers = {
"Authorization": f"Bearer {self.api_key}",
"Content-Type": "application/json",
}
payload = {
"model": "gpt-image-2.5-sunburst/image-to-image",
"image": image,
"prompt": prompt,
}
last_error = None
for attempt in range(retries):
try:
resp = requests.post(
url, headers=headers, json=payload, timeout=self.timeout
)
except requests.Timeout as err:
last_error = err
time.sleep(2 ** attempt)
continue
if resp.status_code in (429, 500, 502, 503, 504):
last_error = RuntimeError(f"transient {resp.status_code}: {resp.text}")
time.sleep(2 ** attempt)
continue
if resp.status_code >= 400:
raise RuntimeError(f"request failed {resp.status_code}: {resp.text}")
return resp.json()
raise RuntimeError(f"exhausted retries: {last_error}")
设计选择比代码本身更重要。重试只适用于超时和瞬时状态码,绝不适用于 4xx 客户端错误,因为重试格式错误的请求体只会浪费配额。指数退避可防止被限流的流水线反复冲击端点。客户端错误会立即抛出并附带响应体,使调用方准确看到服务反对的是什么。而把模型标识符集中在一处,意味着未来切换到其他图像端点只需改一行,而无需在整个代码库中四处搜寻。
在此基础上,为每次尝试添加结构化日志,并在下游消费者使用响应前先做尺寸/形状检查。当你准备探索同一网关上的其他图像模型时,HiAPI 模型目录正是无需重写客户端即可对比各端点的好去处。