Files
cmshoppe/docs/tasks/T-678.md
T
chengmaandClaude Fable 5 cd2dfe97ef docs(tasks): add custom gateway OpenAI lock and suite integration
拆成两个任务,T-678 是可独立发布的破坏性变更,T-679 依赖它。

T-678 自定义网关锁定 OpenAI 图片接口规范并支持多图输入:
- 记录当前 chat 接口类型并非 OpenAI 规范的证据(_find_image_ref 的
  跨结构搜刮器只为非标准中转网关而存在),收敛 API_TYPES 并删除
  chat/auto 请求构造。
- _image_edit_body 与 _multipart_body 支持有序多图,为 T-679 铺路;
  ②生图行为与计费口径不变。
- 记录迁移窗口:T-529 起自定义模型 UI 被硬藏,T-677 才放出,当前
  装机量几乎没有 chat 配置,现在收敛成本接近零,晚做则成为真正的
  破坏性变更。
- 存量 chat/auto 模型标记不可用而非静默改写,避免把请求打到不支持
  的端点。

T-679 商品套图接入自定义网关(主图 + 参考图):
- 指明来源耦合只有 _runtime() 与 _submit_or_resume_job() 两处接缝,
  direct 为同步路径,是跳过 submit/poll 而非补齐异步状态机。
- 记录回收守卫按 task_id 判断,direct job 天然不被拦,无需修改即可
  继续保护已扣点的 cmhub 任务;create_generation_jobs 需改写真实来源。
- 明确主体保留在 OpenAI 侧只能靠提示词,与 cmhub 服务端强制契约不
  等价,UI 须如实说明而非宣称同等效果。
- 记录三个实际问题:同步请求导致停止迟钝、超时常量需改用模型配置、
  aspect_ratio 到尺寸需换算。
- AI 帮写仍为默认网关独占(CATEGORIES 无 vision 类别)。
- 关联中写明本任务有意放宽 T-677 的边界及理由。

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

96 lines
7.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
id: T-678
title: 自定义网关锁定 OpenAI 图片接口规范并支持多图输入
phase: 7
deps: [T-677]
status: TODO
created: 2026-07-20
---
# T-678 自定义网关锁定 OpenAI 图片接口规范并支持多图输入
## 问题 / 背景
T-677 把⑤的自定义网关(`ai.backend=direct`)重新放出来后,暴露了 direct 生图路径的两个结构问题。
**当前的 `chat` 接口类型并不是 OpenAI 规范。** 标准 OpenAI 的 `chat/completions` 不返回生成的图片。本项目的 chat 生图之所以能工作,是因为 `_find_image_ref()`(`app/ai.py:2667`)是一个非常宽容的递归搜刮器,会在 `choices`、`message`、`content`、`data`、`images`、`files` 等结构里到处寻找 `b64_json` / `image_base64` / `url`。这套逻辑是为把生成图塞进 chat 响应的**非标准中转聚合网关**准备的。`api_type=auto` 同样不做接口探测,`chat` 与 `auto` 实际走同一条对话请求,T-677 只能在 UI 上写一段"自动不会探测接口"的说明来遮盖这个事实。
**direct 只能提交单张输入图。** `_image_chat_payload()`(`app/ai.py:2557`)的 `content` 数组只放一个 `image_url`;`_image_edit_body()`(`app/ai.py:2569`)的 `files` 是字典且只有一个 `"image"` 键,`_multipart_body()` 按字典遍历,结构上无法发送重复字段名。因此 T-679 要让商品套图在自定义网关下使用「主图 + 参考图」时,无法复用现有请求构造。
**本任务存在时间窗口,晚做代价显著上升。** T-529 之后⑤的自定义模型 UI 被 `_on_backend_changed()` 无条件 `setVisible(False)` 硬藏,普通用户没有入口配置 `chat` 类型模型;该入口在 T-677(2026-07-20)才重新放出。因此当前装机量中几乎不存在可用的 `chat`/`auto` 直连配置,收敛接口规范的迁移成本接近于零。等 T-677 上线一段时间、用户配出一批 chat 模型后再收敛,就会变成真正的破坏性变更。
## 方案
### 1. 接口规范收敛
- 自定义网关只支持 OpenAI 图片编辑接口(`/v1/images/edits` 形式的 multipart 请求)。`appconfig.API_TYPES`(`app/appconfig.py:41`)由 `{"chat", "images_edits", "auto"}` 收敛为单一取值。
- 实现前必须按当前 OpenAI 官方文档核实多图输入字段名与模型支持范围(预期为 `image[]` 配合 `gpt-image-1`),并把核实结果与文档版本写入执行记录。**文档与实现不一致时不得猜字段**,按 T-596 既有约定停下并记录缺口。
- 删除 `_image_chat_payload()`(`app/ai.py:2557`)及其在 `gen_cover` 中的分支(`app/ai.py:348-386`)。
- `_find_image_ref()`(`app/ai.py:2667`)收敛为按标准响应结构取图(`data[].b64_json` / `data[].url`),不再跨 `choices`/`message`/`content` 递归搜刮。保留 data URL 与 base64 的解码分支和 `_download_image()` 回退。
### 2. 多图输入能力
- `_image_edit_body()` 接受有序图片路径列表而不是单个路径:第一张为主体图,其余为参考图,按核实后的字段名发送。
- `_multipart_body()`(`app/ai.py:2586`)的 `files` 由字典改为有序序列,支持同名重复字段。
- 保留单图调用形式:②生成封面继续只发一张图,请求形式收敛但**行为不变**,不得因本任务改变②的生图结果口径或计费口径。
- 本任务只提供多图能力,**不改商品套图**;套图接入由 T-679 完成。
### 3. 存量配置迁移
- `ai_models.json` 中 `api_type` 为 `chat` 或 `auto` 的存量模型不得静默改写为新取值——请求形式不同,静默迁移会让用户在不知情的情况下把请求打到不支持的端点。
- 载入时把这类模型标记为不可用,在⑤模型列表中以中文说明其原因(如「接口类型已不再支持,请改为 OpenAI 图片编辑接口并确认服务商支持」),并在②的自定义网关预检中作为"去⑤补齐"的一种原因。
- 沿用 v3.1 约定:允许先保存不完整或不可用配置,不在切换来源或保存时弹阻断式校验。
### 4. ⑤ UI 与文案
- 移除或降级 T-677 新增的「接口类型」下拉:只剩一种取值时不应继续以可选控件呈现。同步删除 T-677 为 `auto` 写的"不会探测接口"帮助文案。
- ⑤自定义面板补充说明:自定义网关只支持 OpenAI 图片编辑接口,只做 chat 生图的中转聚合服务不可用。文案不得暴露内部实现细节或密钥。
- 保留既有 `objectName`、配置键、日志字段和 `app/ai.py` 中文错误消息中的 `cmhub` 字样(沿用 T-677 第 5 节边界)。
## 验收要点
- [ ] `API_TYPES` 只剩 OpenAI 图片编辑接口一种取值;`chat` 与 `auto` 的请求构造代码已删除,不留死分支。
- [ ] `_find_image_ref()` 只按标准响应结构取图,不再跨 `choices`/`message` 搜刮;非标准响应给出可读中文错误而不是静默取错字段。
- [ ] `_image_edit_body()` 与 `_multipart_body()` 支持有序多图,第一张为主体图;单图调用路径行为不变。
- [ ] ②自定义网关生成封面的结果、重试、并发、日志和"不计点数"文案不回归。
- [ ] 存量 `chat`/`auto` 模型不被静默改写,在⑤显示不可用原因,在②预检中作为补齐提示出现。
- [ ] ⑤不再显示多取值的接口类型控件与 `auto` 帮助文案;新增的规范限制说明为中文且不暴露实现细节。
- [ ] 默认网关(cmhub)的生文、生图、图片理解、异步 submit/poll、幂等键、计费与③更新蝦皮全部不受影响。
## 测试与文档
- `tests/test_ai.py`:现有 4 处 `api_type` 断言(:63、:75、:307、:348)改为新规范;新增多图请求体断言(字段名、顺序、主体图在首位)与非标准响应的错误路径。
- `tests/test_appconfig.py`:现有 10 处 `api_type` 断言(:542 起)改为新取值;补存量 `chat`/`auto` 模型载入后标记不可用且不被改写的用例。
- `tests/test_gui.py`:⑤接口类型控件移除、不可用模型的中文提示、②预检把不可用模型作为补齐原因。
- 更新 `docs/cmhub-integration-design.md` 修订说明(T-677 有限放开 direct,本任务进一步把 direct 收敛到 OpenAI 规范)、`docs/routes.md`、`docs/api.md`。
## 验证
```bash
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
```
## 边界(不改什么)
- 不改商品套图(`app/image_studio_generation.py`)与图片理解(`analyze_product_images()`),套图接入见 T-679。
- 不新增 vision 类别,`appconfig.CATEGORIES` 保持 `{"text", "image"}`;⑥「AI 帮写」在自定义网关下继续不可用。
- 不改 cmhub 的请求协议、重试与超时策略、异步 submit/poll 状态机、幂等键、预扣退点账本。
- 不新增 provider 适配、接口自动探测或任意上游 URL 放行。
- 不改 SQLite schema、Chrome/CDP、Excel 回写、蝦皮更新流程。
- 不解除 T-596 的 BYOK 门禁;本任务仍属 direct 过渡形态范围内。
## 关联
- T-677:⑤生成网关来源切换(本任务收敛其放出的 direct 接口形态)。
- T-679:商品套图接入自定义网关(依赖本任务的多图能力)。
- T-529:默认 cmhub 网关并隐藏 AI 后端选择(其隐藏期造就了本任务的低成本迁移窗口)。
- T-596:BYOK 总设计与启动门禁(`status: BLOCKED`;正式形态仍要求经 cmhub 代理,本任务不解除该门禁)。
## 执行记录
(做完在这里写:改了什么文件、跑了什么验证命令及结果、遇到的阻塞、关键决策;务必记录 OpenAI 多图字段名的核实来源与文档日期。)