Permalink to 图片图片

两条路由,都是异步的:

路由用途
POST /v1/images/generations文生图
POST /v1/images/edits图生图,可带蒙版

两者都返回 202 Accepted 加一个 Job 信封,成品从 GET /v1/jobs/{job_id}/assets 取。

`client.images.generate()` 用不了

OpenAI SDK 的这个封装期待同步的 {"data": [{"url": …}]} 响应体,而我们返回的是 Job。这两条路由 请用普通 HTTP 调用。

Permalink to 生成生成

bash
curl https://hypit.ai/v1/images/generations \
  -H "Authorization: Bearer $HYPIT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "nano-banana-pro",
    "prompt": "一只纸船顺着雨水沟漂走,浅景深",
    "n": 1,
    "aspect_ratio": "16:9",
    "resolution": "1k"
  }'
json
{
  "id": "job_5a0ce31f78b246d9c0117e42",
  "status": "queued",
  "kind": "image",
  "model": "nano-banana-pro",
  "progress": 0,
  "created_at": 1787824589,
  "dispatch_deadline_at": 1787825189
}

Permalink to 请求体请求体

字段类型说明
modelstring必填
promptstring必填
ninteger1–10,默认 1。每张图对应一个产物序号
sizestring"1024x1024",或 "auto"
resolutionstring模型公布的输出档位,如 "1k""2k""4k";与宽高比独立
qualitystringlowmediumhighhdstandardauto
stylestring各厂商自定义
aspect_ratiostring"16:9"
negative_promptstring
backgroundstringtransparentopaqueauto
output_formatstringpngjpegwebp
response_formatstringurlb64_json,其余值返回 400
seedinteger
watermarkboolean
reference_imagesarray见下;images 是兼容别名
maskstring 或 object见下

支持档位的图片模型推荐传 aspect_ratio + resolution4k 不是固定的 3840x2160,实际像素尺寸由模型和比例决定。旧的 size 像素写法仍可用于支持它的模型;如果同时填写 aspect_ratio,两者必须一致。metadata.resolution 作为兼容别名仍然接受,与顶层 resolution 不一致时返回 400

网关会在创建任务、冻结额度前检查可用渠道是否支持所选档位和比例;不支持的组合返回明确的参数错误,不会悄悄改用默认值。计价使用同一分辨率档位,具体价格见模型卡片pricing.resolution_ratiopricing.media_rates

`response_format` 不影响你怎么取结果

它会被校验并转发给上游,但 Job 的产物一律通过 assets 接口以签名链接交付,没有任何路径会在响应里 直接返回 base64。

Permalink to 厂商透传厂商透传

上表没有建模的字段会原样转发给上游。这是为了让只在某一家上游存在的功能仍然可达。两条限制:整个 额外字段块在体积和嵌套深度上有上限;任何看起来像媒体 URL 的字符串必须是真实的 http(s)data: URL——从额外字段里夹带的 URL 会被 url_in_extra 拒绝,而不是被悄悄抓取。

Permalink to json-里的参考图JSON 里的参考图

reference_images(以及兼容别名 images)用于在 JSON 请求里附带素材。每一项要么是裸 URL 字符串,要么是一个对象:

json
{
  "model": "nano-banana-pro",
  "prompt": "把这只船放进暴风雪里",
  "reference_images": [
    { "url": "https://example.com/boat.png" },
    { "b64": "iVBORw0KGgo…", "mime_type": "image/png", "filename": "boat.png" }
  ]
}

mask 接受同样的对象,也接受普通 URL 或 data: URL 字符串。

你提供的每个 URL 都走受保护的抓取器:只允许 httphttpsdata:,拒绝内网与链路本地地址, 并逐跳复核重定向。校验不过就是 400invalid_media_urlunsupported_media_url_schemeinvalid_input_url),不会产生任何扣费。

Permalink to 编辑编辑

POST /v1/images/edits 接受 multipart/form-data 的真实文件分片,也接受上面那种带 reference_images 的 JSON 请求体。至少要有一张源图。

bash
curl https://hypit.ai/v1/images/edits \
  -H "Authorization: Bearer $HYPIT_API_KEY" \
  -F model=nano-banana-pro \
  -F 'prompt=把天空改成阴天' \
  -F image=@boat.png \
  -F mask=@sky-mask.png

multipart 字段名:

分片类型说明
imageimage[]文件一张或多张源图,按发送顺序
mask文件最多一个
modelpromptnsizeresolutionqualitystyleresponse_formatbackgroundoutput_formatnegative_promptaspect_ratioseedwatermark语义与 JSON 字段一致

限制:

  • 单个上传文件 25 MiB
  • 整个 multipart 请求体 100 MiB
  • /v1/images/generations 的 JSON 请求体 10 MiB
  • 单个 multipart 标量字段 64 KiB

上传声明的 Content-Type 会被忽略——我们嗅探字节内容,只接受 PNG、JPEG 和 WebP,其余一律 400 unsupported_image_format

Permalink to 完整流程完整流程

python
import os, time, httpx

BASE = os.environ.get("HYPIT_BASE_URL", "https://hypit.ai/v1")
AUTH = {"Authorization": f"Bearer {os.environ['HYPIT_API_KEY']}"}

job = httpx.post(
    f"{BASE}/images/generations",
    headers=AUTH,
    json={
        "model": "nano-banana-pro",
        "prompt": "一只纸船顺着雨水沟漂走",
        "n": 1,
        "aspect_ratio": "16:9",
        "resolution": "1k",
    },
    timeout=60,
)
job.raise_for_status()
job_id = job.json()["id"]

while True:
    state = httpx.get(f"{BASE}/jobs/{job_id}", headers=AUTH, timeout=30).json()
    if state["status"] in {"succeeded", "failed", "queue_expired"}:
        break
    time.sleep(3)

if state["status"] != "succeeded":
    raise RuntimeError(f"{state['status']}: {state.get('error_code')} {state.get('error')}")

for a in httpx.get(f"{BASE}/jobs/{job_id}/assets", headers=AUTH, timeout=30).json()["items"]:
    data = httpx.get(a["url"], follow_redirects=True, timeout=None).content
    open(f"image-{a['ordinal']}.png", "wb").write(data)
js
import { writeFile } from "node:fs/promises";

const BASE = process.env.HYPIT_BASE_URL ?? "https://hypit.ai/v1";
const AUTH = { Authorization: `Bearer ${process.env.HYPIT_API_KEY}` };
const TERMINAL = new Set(["succeeded", "failed", "queue_expired"]);

const created = await fetch(`${BASE}/images/generations`, {
  method: "POST",
  headers: { ...AUTH, "Content-Type": "application/json" },
  body: JSON.stringify({
    model: "nano-banana-pro",
    prompt: "一只纸船顺着雨水沟漂走",
    n: 1,
    aspect_ratio: "16:9",
    resolution: "1k",
  }),
});
if (!created.ok) throw new Error(`${created.status} ${await created.text()}`);
const { id } = await created.json();

let job;
do {
  await new Promise((r) => setTimeout(r, 3_000));
  job = await (await fetch(`${BASE}/jobs/${id}`, { headers: AUTH })).json();
} while (!TERMINAL.has(job.status));

if (job.status !== "succeeded") throw new Error(`${job.status}: ${job.error_code} ${job.error}`);

const { items } = await (await fetch(`${BASE}/jobs/${id}/assets`, { headers: AUTH })).json();
for (const a of items) {
  const bytes = Buffer.from(await (await fetch(a.url)).arrayBuffer());
  await writeFile(`image-${a.ordinal}.png`, bytes);
}

Permalink to 这两条路由特有的错误这两条路由特有的错误

状态code含义
400missing_model / missing_prompt两者都必填
400invalid_nn 必须在 1–10 之间
400invalid_response_format不是 urlb64_json
400missing_image/v1/images/edits 没有提供源图
400invalid_multipartmultipart 请求体无法解析
400unexpected_file出现了 imageimage[]mask 之外的文件分片
400invalid_mask / empty_maskmask 既不是 URL 也不是 {b64|url} 对象
400unsupported_image_format字节内容不是 PNG、JPEG 或 WebP
400empty_image / unreadable_image文件分片里没有可用内容
413image_too_large单个文件超过 25 MiB
413body_too_largeJSON 超过 10 MiB,或 multipart 超过 100 MiB
413form_field_too_large单个标量字段超过 64 KiB
404model_not_found没有启用的上游为这个模型提供图片能力

任务、计费和限流相关的公共错误见错误与限流