Files
cmshoppe/docs/tasks/T-678.md
T
chengmaandClaude Fable 5 34c7a2e148 docs(tasks): close review gaps in custom gateway suite split
对 T-678 细化与 T-679a/b/c 拆分的全栈复核结果:

T-678:修正背景中不准确的收敛理由。api_type 在 app/ai.py 只有 :348、
:350 两处使用且都在图片路径内,文字路径从不读取该字段;不能全局收敛
的真实原因是 appconfig.py:881 对所有模型统一校验,收窄取值集合会让
存量文字模型在载入与保存时抛 ConfigError。方案首条同步改为按校验口径
表述,避免实现时去找不存在的文字侧分支。

T-679a/b/c:三处补加发布门禁,说明三者未全部完成前不得发布。拆分只为
控制改动面,不构成可独立发布的中间态——重复计费的二次确认定义在
T-679c,若 a/b 先上线,用户已能创建并失败 direct 任务却在无提示情况下
重试,属资金口径缺口而非体验缺陷。

T-679a:补记本任务组有意放宽 T-677「不给商品套图新增自定义网关路径」
的边界及理由(套图是来源切换后唯一完全断链的模块,图片理解不在放宽
范围内),避免后续回看误判两者矛盾。

T-679a:比例近似映射改为同时记录用户选择的比例与实际输出尺寸。原方案
只存原始比例会让 DB 记 9:16 而文件实际为 1024x1536;当前 add_asset 的
aspect_ratio 只写入无消费者(app/image_studio.py:707-731)故暂不可见,
但历史展示或导出一旦信任该字段即出错。新增字段迁移须附加式且幂等。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-20 17:30:08 +08:00

6.7 KiB

id, title, phase, deps, status, created
id title phase deps status created
T-678 自定义网关图片模型锁定 OpenAI 图片编辑接口并支持多图输入 7
T-677
TODO 2026-07-20

T-678 自定义网关图片模型锁定 OpenAI 图片编辑接口并支持多图输入

问题 / 背景

T-677 恢复了⑤的自定义网关(ai.backend=direct)。图片模型的 chat / auto 分支依赖非标准聚合网关把生成图塞进对话响应,不符合 OpenAI 规范,需要收敛。

但不能全局收敛 appconfig.API_TYPES。 代码事实是:api_type 在 app/ai.py 全文只有 :348、:350 两处使用,都在图片路径内,文字生成路径从不读取该字段;然而 appconfig.py:881 的 if normalized["api_type"] not in API_TYPES 对所有模型统一校验,不分 category。因此收窄全局取值集合的后果不是文字请求走错接口,而是存量文字模型(api_type: "chat")在载入与保存时直接抛 ConfigError,自定义网关生文全部不可用。收敛必须按模型类别做,不能动全局集合。

当前 direct 图片编辑也只能提交单张图:_image_edit_body() 的 files 是单键字典,_multipart_body() 不能表达重复字段。商品套图需要按顺序提交“主体图 + 参考图”,其前置能力应在本任务完成。

本任务锁定的外部契约是 OpenAI Image API 的图片编辑接口:POST /v1/images/edits、multipart 重复 image[] 文件字段、响应从 data[0].b64_json 或 data[0].url 读取。第一张为主体图是本项目的业务约定;OpenAI 文档只明确多图及遮罩作用于首图,不能据此声称模型一定保持主体一致性。

方案

1. 按类别收敛模型接口

  • 保留全局 API_TYPES = {"chat", "images_edits", "auto"},使 category=text 的既有模型配置仍能通过 appconfig.py:881 的校验正常载入与保存。
  • 新增“图片编辑能力”校验:仅 category=image 且 api_type=images_edits 的模型可用于②生成封面与后续⑥商品套图;文字模型保持既有 chat / auto 行为。
  • 图片模型的 chat / auto 存量配置原样保存、可查看,但在⑤显示“当前图片模型不支持 OpenAI 图片编辑接口”的中文状态,并在②、⑥预检中阻止提交。不得静默迁移、禁用或删除,避免触发“至少一个 image 模型启用”的既有校验冲突。
  • ⑤根据模型类别展示接口类型:文字模型保留现有可选项;图片模型只允许选择并显示“OpenAI 图片编辑接口”。不再以全局文案宣称 chat/completions 永远不能生成图片,而是说明其不符合本项目锁定的图片编辑响应契约。

2. 图片编辑请求与响应契约

  • 删除 direct 图片生成的 _image_chat_payload() 分支;category=image 的 direct 请求一律走 /v1/images/edits multipart,文字请求不在本任务范围内。
  • _image_edit_body() 接受有序本地路径序列;multipart 用重复的 image[] 字段提交,首项为主体图,其余为参考图。保留单图入口,②仍只提交一张图。
  • 请求体固定一张输出(n=1);套图数量仍由“一个 job 一次请求”表达,不能让一次响应内的多图破坏单 job 历史、重试与计费语义。
  • _find_image_ref() 收敛为只读取标准 data 数组中的 b64_json / url。保留合法 data URL、base64 和 HTTP(S) URL 下载分支;非标准响应必须给出中文错误,不能递归猜测 choices、message 等字段。
  • 继续使用现有 URL 安全校验;不得因兼容自定义网关放开 file:、本地路径或其他非 HTTP(S) 返回地址。

3. 配置、预检与回归

  • 使用图片模型前,预检同时检查启用状态、images_edits 接口类型、URL、模型名、密钥和超时;错误只给中文可操作说明,不暴露密钥、完整上游 URL 或原始响应体。
  • ②已有的重试、并发、日志、“自定义网关不计点数”口径不变;本任务不改变默认网关及其 cmhub 生图路径。
  • 在执行记录中记录 OpenAI 官方文档核实日期、image[] 字段、标准响应字段和支持的尺寸范围;外部兼容服务若不满足该契约,第一版明确不支持,不做自动探测或私有适配。

验收要点

  • 自定义网关文字模型仍可走原有 chat / auto 生文路径;全局 API_TYPES 未被收窄。
  • category=image 仅在 api_type=images_edits 时可提交图片生成;存量 chat / auto 图片模型保留且不被静默改写。
  • multipart 使用有序重复 image[] 字段;单图与多图均有字段、顺序与首图主体的单元测试。
  • 图片响应仅接受 data[].b64_json / data[].url;非标准响应有可读中文错误,非法 URL 不会下载。
  • ②单图生成的结果、重试、并发、日志和不计点数口径不回归。
  • ⑤的图片模型限制和②预检均为中文,不泄露密钥、完整上游 URL 或原始响应体。
  • 默认网关的生文、生图、图片理解、异步 submit/poll、幂等键、计费与③更新蝦皮不受影响。

测试与文档

  • tests/test_ai.py:文字 chat / auto 回归、图片 images_edits 单图与多图 image[] 请求、n=1、标准响应和非法/非标准响应错误路径。
  • tests/test_appconfig.py:按类别的可用性校验、存量 chat / auto 图片模型不被改写、文字模型保存与加载不回归。
  • tests/test_gui.py:⑤按类别显示接口类型、②预检拦截不可用图片模型且文案中文。
  • 更新 docs/cmhub-integration-design.md、docs/routes.md、docs/api.md,标明图片编辑的固定契约和 T-679 的依赖关系。

验证

py -3.10 -m unittest tests.test_ai tests.test_appconfig tests.test_gui
py -3.10 -m unittest discover -s tests
py -3.10 -m ruff check app tests main.py
py -3.10 -m compileall app main.py
git diff --check

边界(不改什么)

  • 不改商品套图;其接入拆分为 T-679a、T-679b、T-679c,由 T-679 集成验收。
  • 不新增 provider 私有适配、接口自动探测、任意 URL 放行或图片理解的自定义网关路径。
  • 不改 SQLite schema、Chrome/CDP、Excel 回写、蝦皮更新流程。
  • 不改 cmhub 的请求协议、重试与超时策略、异步 submit/poll 状态机、幂等键、预扣退点账本。
  • 不解除 T-596 的 BYOK 门禁;本任务仍属客户端直连的过渡形态。

关联

  • T-677:⑤生成网关来源切换。
  • T-679a:套图多来源任务状态机,依赖本任务的多图请求能力。
  • T-596:BYOK 总设计与启动门禁。

执行记录

(做完在这里写:改了什么文件、跑了什么验证命令及结果、官方接口契约核实来源与日期、遇到的阻塞和关键决策。)