图像生成 API

Upthos Relay 提供两套图像生成入口,共用同一套鉴权、同一份价格表、同一个上游账号池。按客户端形态二选一:

路径 模式 适用场景
/v1/images/generations + /v1/images/edits 同步透传 用 OpenAI 官方 SDK,或任何期望标准 {data: [...]} 返回结构的客户端。HTTP 请求阻塞直到上游返回。
/v1/images/tasks/* 异步任务 需要中途取消、持久可分享 URL(我们存 R2)、按需开启的流式 partial preview(partial_preview: true),或客户端在 Cloudflare 100s idle 超时墙后面。

两条路径完全等价计费:USD 单价 × 图片数 × fx_rate,不打 group_rate —— 订阅档位的折扣(如 Codex Pro 0.5x)不下沉到图像,无论用哪条路径或哪个订阅档位都一样。

鉴权

和其他网关端点一致。Key 通过下面任一 header 传入:

Authorization: Bearer sk-...
x-api-key: sk-...
x-goog-api-key: sk-...

Key 必须挂在 OpenAI 平台分组下(Codex Lite / Pro / Max 等)。Anthropic / Gemini 平台的 key 打这两条路径都会返 404 not_found_error。


同步 API

POST /v1/images/generations

OpenAI Images API 直接兼容。返回上游原生结构(账号选择 + failover 在网关层完成)。

请求体(JSON):

{
  "model": "gpt-image-2",
  "prompt": "一只赛博朋克风格的猫,霓虹背光",
  "n": 1,
  "size": "1024x1024",
  "quality": "high",
  "response_format": "url"
}
字段 类型 说明
model string gpt-image-2(推荐、默认)、gpt-image-2.5-flare、gpt-image-2.5-sunburst、gpt-image-1.5、gpt-image-1、gpt-image-1-mini、chatgpt-image-latest、dall-e-3
prompt string 图像描述,支持 UTF-8
n int 张数,默认 1
size string 1024x1024 / 1024x1536 / 1536x1024 / auto,按 1K / 2K 档计费
quality string low / medium / high / auto,auto 按 medium 查矩阵
response_format string url(默认)或 b64_json

响应(200):标准 OpenAI 结构:

{
  "created": 1715478000,
  "data": [
    { "url": "https://oaidalleapiprodscus.blob.core.windows.net/private/..." }
  ]
}

OpenAI Python SDK 示例:

from openai import OpenAI

client = OpenAI(
    api_key="sk-...",
    base_url="https://relay.upthos.com/v1",
)

resp = client.images.generate(
    model="gpt-image-2",
    prompt="一只赛博朋克风格的猫,霓虹背光",
    size="1024x1024",
    quality="high",
    n=1,
)
print(resp.data[0].url)

POST /v1/images/edits

同样的鉴权,multipart 请求体。源图通过 image 字段传入(PNG/JPEG/WebP,单 part 上限 4 MB)。可选 mask。其他字段同 /generations:

curl -sS -X POST https://relay.upthos.com/v1/images/edits \
  -H "Authorization: Bearer $UPTHOS_API_KEY" \
  -F "model=gpt-image-2" \
  -F "prompt=把背景换成森林" \
  -F "size=1024x1024" \
  -F "[email protected]"

什么时候不该用同步

  • 长任务(gpt-image-2 在 high 质量下 60–120s)。Cloudflare 100s idle 超时会先把连接踹掉,看不到上游结果。走异步。
  • 移动端,应用进后台就丢连接。走异步 + 轮询。
  • 要可分享 URL。OpenAI 返的 URL 几小时就过期;异步路径上传 R2,默认保留 30 天。

异步任务 API

任务模型:submit → 立刻拿 task_id → 轮询进度 → status: completed 时拿到 R2 持久 URL。任务能熬过客户端断开、可中途取消,传 partial_preview: true 时还会暴露 partial preview。

POST /v1/images/tasks

提交任务,立刻返回。

curl -sS -X POST https://relay.upthos.com/v1/images/tasks \
  -H "Authorization: Bearer $UPTHOS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-image-2",
    "prompt": "一只赛博朋克风格的猫,霓虹背光",
    "size": "1:1",
    "resolution": "1k",
    "n": 1
  }'

请求字段:

字段 类型 说明
model string 同同步 API 的模型集
prompt string UTF-8 描述文本
n int 默认 1,支持 1..4。单任务可一次生成多张,前端会渐进交付
size string 比例:1:1 / 16:9 / 9:16 / 3:2 / 2:3 / auto
resolution string 1k(默认)/ 2k / 4k
image_urls string[] 可选。img2img 参考图,配合 /v1/images/uploads。
partial_preview bool 可选,缺省 false。传 true 才向上游请求 partial 帧,并在任务处理中把最新一帧暴露成 progress_image_url。同一张成品图,开预览会让我们从上游拉的字节数约翻三倍,所以只有真的要渲染预览再开。

响应(200):

{
  "code": 200,
  "data": [
    { "status": "submitted", "task_id": "task_01HZQ3R..." }
  ]
}

Submit 端做余额预检:估算 max cost 超过 key 可用余额时,入队前返 402 INSUFFICIENT_BALANCE。

GET /v1/images/tasks/:id

轮询单个任务。建议节奏:每 3-5 秒一次。

curl -sS https://relay.upthos.com/v1/images/tasks/task_01HZQ3R... \
  -H "Authorization: Bearer $UPTHOS_API_KEY"

响应结构:

{
  "code": 200,
  "data": {
    "id": "task_01HZQ3R...",
    "status": "completed",
    "progress": 100,
    "created": 1715478000,
    "completed": 1715478060,
    "actual_time": 58000,
    "estimated_time": 100000,
    "result": {
      "images": [
        {
          "url": ["https://r2.upthos.com/..."],
          "expires_at": 1718070000
        }
      ]
    },
    "progress_image_url": null
  }
}

status 取值:submitted / processing / completed / failed。

当 status === "processing" 时,progress_image_url 可能带一个中间 preview URL —— 仅限提交时传了 partial_preview: true 的任务。这类任务上游会流式推 partial image,我们逐帧上传 R2 并把最新一帧暴露在这里,前端拿来做渐进式预览,不需要改轮询逻辑。没传这个标志的任务,该字段全程为 null。

失败时 result 改为 error: { code, message, type }:

{
  "code": 200,
  "data": {
    "id": "task_01HZQ3R...",
    "status": "failed",
    "error": {
      "code": "upstream_rate_limit",
      "message": "Upstream returned 429 after 3 retries",
      "type": "upstream_error"
    }
  }
}

常见 error.code:

Code 含义
client_cancelled 用户调了 /cancel
worker_timeout 上游调用超过 worker 单任务超时(默认 15 分钟)
upstream_rate_limit 上游 429 多次重试后失败
upstream_overload 上游 529 多次重试后失败
upstream_error 上游通用错误
internal_error 网关侧错误,请提 issue

POST /v1/images/tasks/batch

最多一次轮 100 个任务。

curl -sS -X POST https://relay.upthos.com/v1/images/tasks/batch \
  -H "Authorization: Bearer $UPTHOS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "ids": ["task_01HZQ3R...", "task_01HZQ4S..."] }'

返回单任务接口的同款结构组成的数组,顺序与入参一致。

POST /v1/images/tasks/:id/cancel

幂等。如果任务还在执行中,会中断上游 HTTP 调用,然后把任务标记 failed,error.code = client_cancelled。对已终止的任务再调没副作用,返 200。

curl -sS -X POST https://relay.upthos.com/v1/images/tasks/task_01HZQ3R.../cancel \
  -H "Authorization: Bearer $UPTHOS_API_KEY"

POST /v1/images/uploads —— img2img 参考图上传

把参考图存到 R2,给后续 submit 通过 image_urls[] 引用。返回短期公开 URL(24h TTL)。

curl -sS -X POST https://relay.upthos.com/v1/images/uploads \
  -H "Authorization: Bearer $UPTHOS_API_KEY" \
  -F "[email protected]"

响应:

{
  "code": 200,
  "data": {
    "url": "https://r2.upthos.com/inputs/...",
    "expires_at": 1715564400
  }
}

注意:

  • 单次单文件。PNG / JPEG / WebP。
  • 服务端校验上限 2 MiB。建议客户端先压一下,几百 KB 是甜点区。
  • URL 公开,别上传你不想分享的东西。
  • 拿到 url 通过 image_urls: ["..."] 传给下一个 submit。

什么时候应该用异步

  • 长任务会被 CF 100s idle 超时砍掉
  • 移动端会进后台
  • 要可分享 URL(画廊、历史、社交嵌入)
  • 要 partial 预览(progress_image_url,需显式传 partial_preview: true)
  • 要中途取消(UX 成本:一个按钮)

价格

图像价格按 resolution → 真实 USD 配在「渠道管理 → 渠道定价 → 按图计费」里,乘以图片数和展示 fx_rate(约 6.82 CNY/USD)。结果就是 CNY 零售价。跨分组完全一致,订阅档位的折扣不影响 —— 订阅折扣只作用在文本/代码 token 上。

gpt-image-2 标准价:

分辨率 实际尺寸 单张价格(CNY)
1K 1024×1024 ¥0.041
2K 1024×1536 或 1536×1024 ¥0.082
4K (支持时) ¥0.123

gpt-image-2.5-flare 与 gpt-image-2.5-sunburst 与上表 完全同价(官方 token 费率与 gpt-image-2 一致),同样只看 resolution。

quality 是上游识别字段(low / medium / high / auto),不影响计费,价格只看 resolution。默认开 high 就好。

如果你传的 model 没在渠道定价里配,会回落到老的 image_price_{1k|2k|4k} 分组配置(这条老路径仍然打 group_rate,是历史兼容包袱)。目前所有 gpt-image-* 模型都已在渠道定价里。


错误码对照

HTTP Body 含义
401 authentication_error 没传 / 传了无效 API key
402 INSUFFICIENT_BALANCE 估算 cost 超过可用余额(队列前预检)
403 permission_error 保留位,目前图生没在用
404 not_found_error Key 所在分组不是 OpenAI 平台(比如挂在 Anthropic / Gemini 上)
413 request_entity_too_large 请求体 > 10 MB。注意部分上游有更紧的 5 MB 墙,base64 大图会先触发——建议先走 /v1/images/uploads 再用 image_urls 引用。
429 rate_limit_error 网关层限流命中。退避。
503 service_unavailable Image generation is not enabled on this server —— 异步 worker 没启动;同步路径还能跑。

已废弃端点

下面的路径还在工作,但响应带 Deprecation: true + Link: rel="successor-version" header。未来版本会移除,方便时迁一下:

已废弃 改用
GET /v1/tasks/:id GET /v1/images/tasks/:id
POST /v1/tasks/batch POST /v1/images/tasks/batch
POST /v1/tasks/:id/cancel POST /v1/images/tasks/:id/cancel

路径选择速查表

  • OpenAI SDK / 标准工具 → 同步 /v1/images/generations。openai-python / openai-node 现成代码零改动。
  • Codex CLI slash command → 异步 /v1/images/tasks。详见 Codex 图像生成指南。
  • Web UI / 带进度条的聊天应用 → 异步 + progress_image_url 轮询。
  • 移动端 → 一定异步。
  • 后台批量 → 异步 + /tasks/batch 廉价轮询。

两条路径共用上游池,共用价目表 —— 图像本身没有任何差异。