Appearance
图片生成 POST /v1/images/generations
异步图片生成端点。兼容 OpenAI Images API 规范,支持文生图(txt2img)与图生图(img2img / image edit)统一入口。
兼容入口:
POST /v1/images/edits是图生图编辑的传统 OpenAI 入口(2026-09-07 合并改造保留),JSON 模式跟本接口在参数层面兼容。响应形态取决于上游适配器:openai / anthropic 同步适配器返回 OpenAI 原生ImageResponse,comfyui / s65535 异步适配器同样返回 202 + task_id。multipart 模式只支持image/mask文件上传。所有图片生成的 Base64 自动落库能力(下文)在两个入口同样生效。
端点
POST https://api.imodel.space/v1/images/generations
Authorization: Bearer YOUR_API_KEY
Content-Type: application/json请求参数
| 字段 | 位置 | 类型 | 必传 | 默认 | 说明 |
|---|---|---|---|---|---|
model | body | string | ✅ | — | 模型代号(如 gpt-image-2 / dall-e-3 / dall-e-2),决定调用的上游实现与计费档位 |
prompt | body | string | ✅ | — | 文本提示词。无 image / image_urls 时为文生图;有参考图时为图生图编辑 |
n | body | integer | ❌ | 1 | 生成数量,部分模型(如 dall-e-3)仅支持 n=1 |
quality | body | string | ❌ | — | standard / hd (dall-e-3);low / medium / high (gpt-image-2)。具体取值范围以模型 cost_config 为准 |
size | body | string | ❌ | — | 比例或像素字符串。优先使用 resolution + aspect(见下方「size 与 resolution/aspect」章节),此字段保留 OpenAI 协议兼容 |
style | body | string | ❌ | — | vivid / natural,仅 dall-e-3 支持 |
response_format | body | string | ❌ | url | url / b64_json,异步模式下忽略(始终走 outputs[] 轮询) |
user | body | string | ❌ | — | 透传用户标识,用于风控审计 |
background | body | string | ❌ | — | transparent / opaque / auto,仅 gpt-image-2 |
output_format | body | string | ❌ | — | png / jpeg / webp,仅 gpt-image-2 |
output_compression | body | integer | ❌ | — | 0-100,仅 jpeg / webp 模式生效 |
moderation | body | string | ❌ | auto | auto / low,仅 gpt-image-2 |
image | body | string | ❌ | — | 单张参考图 URL。传值即视为图生图编辑,与 image_urls 二选一 |
image_urls | body | string[] | ❌ | — | 多张参考图 URL 数组,上限 10 张(超过返回 too_many_images) |
mask | body | string | ❌ | — | 蒙版 URL,JSON 模式局部编辑场景 |
resolution | body | string | ❌ | — | 网关扩展字段。清晰度档位(1K / 2K / 4K),按档位查 cost_config.rates 计费。详见下方「size 与 resolution/aspect」章节 |
aspect | body | string | ❌ | — | 网关扩展字段。画面比例(1:1 / 16:9 / 9:16 / 4:3 / 3:4),与 resolution 共同决定实际像素 |
请求示例
文生图(无参考图)
json
{
"model": "gpt-image-2",
"prompt": "一只猫在花园里晒太阳",
"resolution": "1K",
"aspect": "16:9",
"n": 1
}图生图编辑(多张参考图融合)
json
{
"model": "gpt-image-2",
"prompt": "将参考图 1 的主体与参考图 2 的背景融合,生成黄昏氛围的合成图",
"image_urls": [
"https://cdn.example.com/ref_subject.jpg",
"https://cdn.example.com/ref_background.jpg"
],
"resolution": "2K",
"aspect": "16:9"
}局部编辑(蒙版)
json
{
"model": "gpt-image-2",
"prompt": "把蒙版区域内的椅子替换为盆栽",
"image": "https://cdn.example.com/room.jpg",
"mask": "https://cdn.example.com/room_mask.png",
"resolution": "1K",
"aspect": "16:9"
}图生图编辑(base64 内嵌图 + URL 混传)
json
{
"model": "gpt-image-2",
"prompt": "将参考图 1 的人物换到参考图 2 的场景里",
"image_urls": [
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUg...用户拍照的 base64",
"https://cdn.example.com/ref_background.jpg"
],
"resolution": "2K",
"aspect": "16:9"
}服务端会把 base64 自动上传到 COS + 落素材表,image_urls[0] 在落库前替换为 CDN 公开直链;image_urls[1] 是公网 URL 原样保留,worker 直接 GET 拉取。
MIME 白名单:png / jpeg / jpg(jpeg 的别名) / gif。webp 不在白名单(标准库不支持解码,避免引入额外依赖),如需 webp 参考图请先自行上传 CDN 再传 URL。
参考图来源
image / image_urls 字段不强制使用本平台素材上传。任何公网可访问的 URL 都行(不限域名)。四种典型来源:
- 本平台素材库:API Key 上传 后用返回的
cdn_url—— 自动入库、可在素材管理页查/改/删、跨任务复用 - 自有图床:阿里云 OSS / 腾讯云 COS / 七牛 / 又拍云 / 自建 nginx 等任何公网可访问的存储
- 公共 CDN:Unsplash / 公司 CDN / 图床服务等
- Base64 内嵌图(
data:image/png;base64,...,2026-09-11 新增支持):见下方「Base64 内嵌图自动落库」章节
只要 URL 返回 200 且能识别扩展名(Content-Type 或 URL 后缀),后端 worker 直接 GET 拉取。
Base64 内嵌图自动落库(2026-09-11 新增)
背景
靓仔要求支持客户端把参考图以 base64 内嵌在请求 body 里(避免前端先上传 COS 再发请求的两步流程,比如移动端拍照后立刻编辑的场景)。
image / image_urls / mask 三个字段都接受 data:image/<sub>;base64,<payload> 形式的字符串,与公网 URL 混传也支持(比如 image_urls 数组里前 3 张是 base64、后 2 张是 https URL)。
后端处理流程
- 解码校验:服务端拿到 base64 后,先
base64.StdEncoding.DecodeString解码字节,再做image.DecodeConfig校验是否是合法图片(png/jpeg/gif)。任一步失败 → 返回 400image_materialize_failed - 大小限制:单张 base64 解码后 ≤ 16 MB(防止恶意大文件撑爆 COS / DB)
- 上传 COS:用现有
pkg/cos走 server 端永久密钥,文件 key 遵循users/{group}/{userId}/images/{timestamp}_{hex8}.{ext}命名规范(跟POST /api/asset/upload_cos一致) - 入素材表:
assets表新增一条source_type=local/file_type=image记录,用户在素材管理页可见这张图(后续跨任务复用、重新生成都可) - 替换 URL:原始
image_urls[i]字符串替换为 CDN 公开直链(https://<CDN_BASE_URL>/<file_key>或 COS 默认域名)。/v1/images/edits同步路径直接把替换后的 URL 调上游;异步路径落库tasks.request_params.image_urls也是替换后的 URL,绝不会让 base64 进 DB
失败语义
任一环节失败(解码失败 / 非合法图 / COS 没配置 / 上传失败 / 素材落库失败),任务整体不入库,直接返回 400:
json
{
"error": {
"code": "image_materialize_failed",
"message": "decoded image too large: 18874368 bytes (max 16777216)"
}
}这样设计的理由:不让脏数据进 DB 是关键。2026-09-11 admin_task_search 列表接口超时的根因就是 base64 进 tasks.request_params 撑到 7MB+,列表一次拉 20 条响应体 14MB+。自动 materialize 后这个隐患被堵在 controller 入口。
配置要求
服务端必须配置 configs/tencent.yaml 的 cos 段(SecretID / SecretKey / BucketName / Region)。未配置时 base64 入参会返回 400 cos not configured。
历史兼容
存量 tasks 表里如果有 base64 残留在 request_params(2026-09-11 之前的脏数据),/api/server/schedule/admin_task_search 列表接口做了字段白名单剥离,默认不返回 request_params 列,详情接口(/api/server/schedule/admin_task_search?task_no=xxx,后续补)按需返回。已对云端 2 条 7MB 记录做了一次清理(UPDATE id IN (930, 931) → {"_cleaned":{"reason":"2026-09-11 admin_task_search 性能清理"}})。
size 与 resolution / aspect
三类写法
靓仔要求图片生成支持以下三种参数写法,优先级依次为:
| 优先级 | 写法 | 示例 | 说明 |
|---|---|---|---|
| 1 | 比例 + 档位 | { "size": "16:9", "resolution": "2K" } | 推荐。size 传比例,resolution 传档位,后端按模型映射表查实际像素 |
| 2 | 显式像素 | { "size": "1376x768" } | 仅 size,按 W×H 直查模型 cost_config.rates;miss 时按 height 反推 P 数 |
| 3 | 预设名 + 档位 | { "size": "landscape_16_9", "resolution": "2K" } | 预设名走模型侧映射(各模型不同),resolution 用于计费档位 |
resolution 档位(2026-09-07 按档位计价)
resolution 是网关扩展字段,OpenAI Images API 标准未定义。本系统对齐模型 cost_config.rates 的键:
- 档位典型取值:
1K/2K/4K(具体由模型管理员在 管理后台计费配置 配置) - 计费逻辑:优先按
rates[resolution]查单价;miss 时回退fixed_price兜底 - 单位:每次请求(
unit=request,按次计费),与duration/size无关 - 前端
useGenerationPricecomposable 会按当前模型meta.rates自动计算价格
aspect 比例
仅支持白名单内的取值,具体由各模型的 meta.aspect_whitelist 配置决定。常见白名单:1:1 / 16:9 / 9:16 / 4:3 / 3:4。
响应
按上游适配器类型分流:
- 异步(comfyui / s65535):202 Accepted,客户端用返回的
task_id调 任务查询GET /v1/tasks/{task_no}拿产物 - 同步(openai / anthropic):200 OK,直接返回 OpenAI Images 协议
ImageResponse(created+data[].url|b64_json|revised_prompt)
异步响应(202 Accepted)
http
HTTP/1.1 202 Accepted
Content-Type: application/json
{
"task_id": "TASK-7f9c1d3a-1b2c-4d5e-8a9f-0c1d2e3f4a5b",
"status": "running",
"created_at": 1763692800,
"poll_url": "/v1/tasks/TASK-7f9c1d3a-1b2c-4d5e-8a9f-0c1d2e3f4a5b"
}| 字段 | 类型 | 说明 |
|---|---|---|
task_id | string | 任务编号(task_no),后续轮询用 |
status | string | 提交后的初始状态:有 self 上游(comfyui 自建场景)走 Redis 队列 → 返回 queued;纯三方模型(controller 内直派三方异步上游,如 65535)→ 返回 running。终态为 succeeded / failed / cancelled / timeout(完整枚举见 任务查询) |
created_at | integer | 任务创建时间(Unix 秒) |
poll_url | string | 轮询路径,模板为 /v1/tasks/{task_id} |
同步响应(200 OK,OpenAI Images 协议)
仅当上游适配器是 openai / anthropic 形状时(controller 第 124 行 IsAsyncAdapter == false):
http
HTTP/1.1 200 OK
Content-Type: application/json
{
"created": 1763692800,
"data": [
{
"url": "https://cdn.example.com/output_0.png",
"revised_prompt": "A cat basking in the sunlight in a garden"
}
]
}| 字段 | 类型 | 说明 |
|---|---|---|
created | integer | 创建时间(Unix 秒) |
data[].url | string | 产物图片 URL(response_format=url,默认) |
data[].b64_json | string | 产物 base64 编码(response_format=b64_json) |
data[].revised_prompt | string | dall-e-3 自动改写后的 prompt |
异步兜底语义:Redis 队列入队失败
submitImageAsync 落库后调 squeue.Enqueue 把任务推进 Redis 队列。若此时 Redis 异常(controller 第 220 行 ⚠️ 路径),任务已落库,接口仍然返回 202 + task_id,由后台 RebuildAll worker 兜底补单 + 派发,客户端轮询 poll_url 仍可拿到结果。这是有意的兜底,不会让接口因 Redis 抖动整体 5xx。
任务列表
按模型分页拉取当前用户的图片任务历史,用于前端 omni-generate 工作台历史展示。
GET https://api.imodel.space/v1/images/generations/list?model=gpt-image-2&page=1&page_size=6&status=active
Authorization: Bearer YOUR_API_KEY| 参数 | 位置 | 类型 | 必传 | 默认 | 说明 |
|---|---|---|---|---|---|
model | query | string | ✅ | — | 模型代号(过滤该模型下的任务) |
page | query | integer | ❌ | 1 | 页码,从 1 开始 |
page_size | query | integer | ❌ | 6 | 单页条数,最大 100 |
status | query | string | ❌ | — | 状态过滤:active(进行中,含 queued/scaling/running)/ done(已成功)/ failed(已失败/取消/超时)。省略时返回全部 |
响应
json
{
"data": [
{
"id": "TASK-7f9c1d3a-1b2c-4d5e-8a9f-0c1d2e3f4a5b",
"task_id": 644,
"status": "succeeded",
"progress": 100,
"created_at": 1763692800,
"started_at": 1763692800,
"finished_at": 1763692850,
"outputs": [
"/api/asset/image/TASK-7f9c1d3a-1b2c-4d5e-8a9f-0c1d2e3f4a5b?index=0"
],
"params": {
"prompt": "一只猫在花园里晒太阳",
"size": "16:9",
"resolution": "1K",
"n": 1,
"task_kind": "txt2img"
},
"cost_lingshi": 8,
"billing_state": "consumed"
}
],
"page": 1,
"page_size": 6,
"total": 1
}| 字段 | 类型 | 说明 |
|---|---|---|
data[].id | string | 任务编号(task_no)。列表响应字段名是 id(历史兼容),提交接口响应字段名是 task_id,两个返回路径不同 |
data[].task_id | integer | 数据库数字主键,任务详情弹窗展示用 |
data[].status | string | OpenAI 风格状态字符串:queued / scaling / running / succeeded / failed / cancelled / timeout |
data[].progress | integer | 进度百分比(0-100),仅 running 时实时更新 |
data[].created_at / started_at / finished_at | integer | 各阶段 Unix 时间戳,前端用于计算排队/生成耗时 |
data[].outputs[] | string[] | 产物 URL 数组(每张图一项),路径走 gapi 代理(不会暴露上游 ComfyUI 地址) |
data[].params | object | 任务参数快照(提交时的 prompt / size / resolution / n / task_kind) |
data[].cost_lingshi | integer | 实际消费灵石数 |
data[].billing_state | string | 账单状态:frozen(冻结中)/ consumed(已扣除)/ refunded(已退还) |
total | integer | 满足过滤条件的总条数,前端 el-pagination 总页数计算用 |
文档更新记录
| 日期 | 更新内容 |
|---|---|
| 2026-09-17 | 与 image_generations.a.go 校对补齐:① 异步响应字段名纠正为 task_id(不是 id);② status 分支说明 — 有 self 上游返 queued、纯三方返 running;③ 新增同步返回 ImageResponse 章节(openai/anthropic 适配器直接 200 OK);④ 补全缺失错误码 required_missing / unauthorized / no_auth / affordability_check_failed / enqueue_failed;⑤ base64 MIME 白名单补充 jpg 别名、明确不支持 webp;⑥ 补充 Redis 队列入队失败的兜底语义(仍返回 202);⑦ 兼容入口 /v1/images/edits 响应形态澄清为跟上游适配器走 |
| 2026-09-11 | 新增「Base64 内嵌图自动落库」章节(image / image_urls / mask 支持 data:image/...;base64,... 自动落 COS + 素材表 + 替换为 CDN URL,2026-09-11 修复 admin_task_search 列表超时的根因);错误码表加 image_materialize_failed |
| 2026-09-08 | 新增图片生成接口文档。补充 resolution / aspect 网关扩展字段、三类写法、按档位计费说明、status 直接返回 running 而非 queued 的改造说明 |
错误码表
4xx — 客户端请求问题
| HTTP | code | 说明 | 解决建议 |
|---|---|---|---|
| 400 | invalid_request_error | JSON 解析失败 | 检查 body 是否合法 JSON |
| 400 | required_missing | prompt / model 必填项缺失 | 对照「请求参数表」补必传项 |
| 400 | too_many_images | image_urls 数量超 10 张上限 | 减少参考图数量至 ≤10 张 |
| 400 | image_materialize_failed | image / image_urls / mask 含 base64 内嵌图,但解码失败 / 非合法图 / MIME 不在白名单(png/jpeg/jpg/gif) / COS 没配 / 上传失败 / 素材落库失败 | 见「Base64 内嵌图自动落库」章节的「失败语义」段落;服务端需要配 cos,客户端需要保证 base64 是合法 png/jpeg/gif |
| 400 | estimate_failed | 计费配置校验失败(如 unit=request 但 rates 与 fixed_price 都为 0) | 管理员在 管理后台计费配置 配置 rates 或 fixed_price |
| 401 | unauthorized | 未登录用户调用,网关拿不到 uid | 携带有效登录态(前端会话)调用 |
| 401 | authentication_error (no_auth) | API Key 鉴权失败 | 检查请求 Authorization: Bearer ... 是否正确,Key 是否过期 |
| 403 | model_not_allowed | API Key 无权访问该模型(权限管控) | 在 API Key 管理页添加该模型权限 |
| 402 | insufficient_quota | 账户灵石不足,无法生成 | 在控制台「灵石充值」购买后重试 |
| 402 | daily_cost_limit_exceeded | API Key 单日消费上限 | 调高 Key 日限额,或等待次日重置 |
| 500 | freeze_failed | 余额冻结失败 | 重试;持续失败请检查账户状态 |
| 500 | affordability_check_failed | 余额乐观预检失败(只读 SELECT 阶段异常,非真正余额不足) | 重试;持续失败附 task_no 联系客服 |
| 500 | enqueue_failed | 任务落库失败,或纯三方模型落库阶段失败 | 重试;持续失败附 task_no 联系客服 |
| 502 | upstream_error | 三方上游服务异常(网络/超时/上游 5xx) | 稍后重试 |
| 502 | submit_failed | 上游任务提交失败(签名/鉴权/上游拒收 / 返回空 upstream_task_id) | 检查 API Key 权限与上游账号状态 |
5xx — 服务端问题
| HTTP | code | 说明 | 解决建议 |
|---|---|---|---|
| 500 | internal_error | 网关内部异常(落库失败 / Redis 队列入队异常外的兜底) | 重试;持续失败请附 task_no 联系客服 |
Redis 队列入队异常不视为错误:controller 第 220 行路径会落库成功但 Redis 写失败,接口仍返回 202 + task_id,由
RebuildAllworker 兜底补单,无需前端处理。
通用 4xx/5xx 见 错误码总表。