Skip to content

[Bug] 图片生成错误 #73

Description

@YuKeeH99

Bug Description

RedInk 图片生成在 OpenAI 兼容接口下存在参数兼容、批量稳定性与历史状态覆盖问题

摘要

RedInk 使用 OpenAI 兼容图片接口(当前为 https://4sapi.com/v1/images/generations,模型 gpt-image-2)时,单张图片可以生成,但批量生成、刷新页面、重新打开历史记录时会出现多类问题:

  1. 图片生成请求强制携带 response_format: b64_json,部分兼容接口不支持该参数,导致 400。
  2. 批量生成时后续图片请求容易出现 SSL 连接中断。
  3. 高并发/批量重试路径会同时请求图片上游,容易触发上游连接失败或限流。
  4. 刷新页面或重新打开生成页时,前端会把历史记录里的图片状态覆盖为空,并再次触发生成,造成重复消耗 API 额度。

环境

  • 应用:RedInk Docker 镜像 histonemax/redink:latest
  • 后端:Flask
  • 图片服务商类型:OpenAI 兼容接口 / Image API
  • 图片接口:/v1/images/generations
  • 模型:gpt-image-2
  • 部署方式:Docker 单容器

现象

1. API Key 测试通过,但正式图片生成失败

配置页测试 API Key 显示正常,但生成图片时报错:

Unknown parameter: 'response_format'

后端日志显示请求失败:

Image API 请求失败: status=400
error={"error":{"message":"Unknown parameter: 'response_format' ...}}

2. 第一张图生成成功,后续多张图片失败

第一张图片可正常生成并保存,后续图片生成时出现:

SSLError: [SSL] record layer failure

原因与后续图片带封面参考图、请求体变大、连续/并发请求图片上游有关。

3. 刷新页面或关闭后重新打开,会自动重新生成

图片文件已经保存在历史目录中,例如:

/app/history/task_xxx/0.png

但历史记录 JSON 仍可能是:

"images": {
  "task_id": "旧 task_id",
  "generated": []
},
"status": "generating"

刷新页面后,前端会先 PUT /api/history/<id>,把 images.generated 写成空数组,再调用 POST /api/generate,导致重复生成。

预期行为

  1. OpenAI 兼容接口不应假设所有服务商都支持 response_format
  2. 如果接口返回图片 url,后端应能下载并保存,而不是只接受 b64_json
  3. 批量生成应支持保守串行模式,避免同时打爆图片上游。
  4. 已生成图片应稳定写入历史记录。
  5. 刷新页面、重新打开历史详情页时,应优先读取已保存图片,不应自动重新生成。
  6. 前端传入空 images.generated=[] 时,不应覆盖已有图片状态。

已验证的临时修复

当前容器内已做热修,验证有效:

backend/generators/image_api.py

  • 4sapi.com 默认不再发送 response_format
  • 如果上游返回 Unknown parameter: response_format,自动移除该参数重试。
  • 支持从响应中的 url 下载图片。
  • 对 SSL、连接失败、超时增加退避重试。

backend/services/image.py

  • 将图片上游请求串行化。
  • MAX_CONCURRENT = 1
  • 连续图片请求之间等待 3 秒。
  • 失败批量重试也受同一个串行队列限制。

backend/services/history.py

  • 如果历史记录已有 images.generated,前端传入空数组时不覆盖已有图片。
  • 防止 partial/completed 状态被回退为 generating

backend/routes/image_routes.py

  • 重复生成请求会尝试匹配已有历史记录。
  • 如果已有图片,返回 cached SSE 事件,不再调用图片上游。

建议的正式修复

  1. 在图片服务商配置中增加能力开关:
supports_response_format: false
supports_image_url_response: true
max_concurrent: 1
request_interval_seconds: 3
  1. 图片生成器根据服务商能力动态组装 payload,不要硬编码 response_format

  2. 批量生成与失败重试共用同一个队列/限速器。

  3. 图片生成每完成一张,就立即把 task_id 和文件名写入历史记录。

  4. 前端刷新恢复时:

    • 如果历史记录已有图片,直接展示;
    • 如果状态是 partial,显示“继续生成/重试失败项”按钮;
    • 不要自动重新生成全部图片。
  5. 后端历史更新接口增加状态保护:

    • 禁止空图片数组覆盖非空图片数组;
    • 禁止无明确用户操作时从 partial/completed 回退到 generating

验收标准

  • API Key 测试通过后,正式生成不因 response_format 失败。
  • 单图生成成功。
  • 多图生成不会同时请求上游,按配置串行或限流执行。
  • 第一张图生成后刷新页面,不会重新生成第一张图。
  • 已生成图片在历史记录中可见,刷新后仍可见。
  • 前端重复 PUT /api/history/<id> 不会清空已有图片列表。
  • 历史详情页打开时不自动消耗图片 API 额度。

风险说明

当前修复是在运行中 Docker 容器内的热修,不是镜像级修复。若删除并重建容器,修复会丢失,需要合入源码、重新构建镜像或制作自定义镜像。

Steps to Reproduce

请看上面内容

Expected Behavior

验收标准
API Key 测试通过后,正式生成不因 response_format 失败。
单图生成成功。
多图生成不会同时请求上游,按配置串行或限流执行。
第一张图生成后刷新页面,不会重新生成第一张图。
已生成图片在历史记录中可见,刷新后仍可见。
前端重复 PUT /api/history/ 不会清空已有图片列表。
历史详情页打开时不自动消耗图片 API 额度。

Screenshots

No response

Deployment Method

Docker

Operating System

No response

Browser

No response

Logs

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions