From 79f51d9b91b6838d32c40955c23ee5ba4ec7db34 Mon Sep 17 00:00:00 2001 From: chengma Date: Mon, 20 Jul 2026 15:17:48 +0800 Subject: [PATCH] docs(tasks): refine gateway source switch scope --- docs/tasks/T-677.md | 46 +++++++++++++++++++++++++++++---------------- 1 file changed, 30 insertions(+), 16 deletions(-) diff --git a/docs/tasks/T-677.md b/docs/tasks/T-677.md index 300b94d..23b9180 100644 --- a/docs/tasks/T-677.md +++ b/docs/tasks/T-677.md @@ -15,16 +15,16 @@ T-529 把普通用户的 AI 后端收口为 cmhub:⑤ 隐藏「AI 后端」下 现在需要给用户一条自定义(OpenAI 兼容)网关的逃生口,用于 cmhub 托管上游不稳或用户自备算力的场景。相关代码事实: -- `direct` 路径并未删除,且本身就是 OpenAI 规范:`app/ai.py` 生文走 `chat/completions`,生图支持 `api_type` = `chat` / `images_edits` / `auto`(`app/appconfig.py:41`),`appconfig` 会自动补 endpoint;配置 schema 与校验在 `app/appconfig.py`(`list_ai_models` / 模型规范化)。 +- `direct` 路径并未删除,当前按既有 OpenAI 兼容请求形式工作:`app/ai.py` 生文走 `chat/completions`,生图支持 `api_type` = `chat` / `images_edits` / `auto`(`app/appconfig.py:41`),`appconfig` 会自动补 endpoint;配置 schema 与校验在 `app/appconfig.py`(`list_ai_models` / 模型规范化)。 - ⑤ 的自定义模型 UI(模型列表、模型详情、direct 角色选择)也都还在,只是被 `_on_backend_changed()` 无条件 `setVisible(False)` 硬藏(`app/gui/tabs/settings.py:580-584`),`backend_combo` 同样常隐。 - 因此本任务的主要工作是**恢复并规范双面板切换**,不是新建自定义配置体系。 -覆盖面不对称是本任务最大的风险点:cmhub 有生文/生图/图片理解三个角色,外加 AI工场;`direct` 只有生文、生图两条路径。 +覆盖面不对称是本任务最大的风险点:默认网关有生文/生图/图片理解三个角色,外加商品套图;`direct` 只有生文、生图两条路径。当前正式第六 Tab 是「商品套图」,旧 `ImageStudioTab` 仅作内部兼容,不能只写“AI工场入口拦截”而遗漏真实可见入口。 - `app/ai.py` 的 `analyze_product_images()` 在非 cmhub 时直接抛错(⑥商品套图AI帮写); - `app/image_studio_generation.py` 全文只有 cmhub 分支,其 `_runtime()` 直接取 `ai._cmhub_runtime()`,**完全不看 `ai.backend`**。 -若只改 UI 不补联动,用户切到「自定义网关」后 AI工场仍会用 cmhub Key 继续跑、继续扣点——用户以为切走了而费用照扣,属于资金口径错误,必须在本任务同版本内处理。 +若只改 UI 不补联动,用户切到「自定义网关」后商品套图仍会用默认网关 Key 继续跑、继续扣点——用户以为切走了而费用照扣,属于资金口径错误,必须在本任务同版本内处理。 ## 方案 @@ -53,17 +53,27 @@ T-529 把普通用户的 AI 后端收口为 cmhub:⑤ 隐藏「AI 后端」下 - **两套配置并存、切换不清空**:`data/config/cmhub.json` 与 `data/config/ai_models.json` 互不影响,来回切换后原配置仍在。 - 存量迁移天然成立:老配置 `backend=direct` 载入后选中「自定义网关」,`backend=cmhub` 或缺失按现状选中「默认网关」。 - 沿用 v3.1 约定:**允许先保存不完整配置**,②生成时再提示"去⑤补齐",切换来源时不弹阻断式校验。 +- 保存语义必须明确且不混淆:来源选择器仅修改待保存状态,只有点击「保存设置」才切换运行来源;既有「新增 / 保存 / 删除模型」仍立即写入 `ai_models.json`,不会等待「保存设置」。用户点击放弃设置时,只恢复来源和普通设置字段,不回滚已经单独保存的模型 CRUD。 +- `api_type=auto` 不是自动探测接口:当前 direct 实现只有 `images_edits` 走图片编辑请求,`chat` 与 `auto` 都走对话请求。本任务不新增 `images/generations`、provider 适配或接口探测;自定义网关 UI 应将用户可见字段改为「接口类型」,并在帮助文案中按现有三种行为说明,不得泛称所有 OpenAI 兼容服务均可用。 -### 4. 必须同版本处理的四个联动 +### 3a. 运行配置冻结与保存竞争 -1. **AI工场入口拦截**:`ai.backend != "cmhub"` 时,AI工场(⑥)生成入口置灰或拦截并提示「AI工场仅支持默认网关」,**禁止在自定义网关下继续用 cmhub Key 提交任务扣点**。 -2. **⑥商品套图AI帮写**:`analyze_product_images()` 的现有抛错行为保持(不会静默扣费),但⑤自定义面板需增加说明行,明确「图片理解与AI工场仅默认网关支持」,避免用户切换后靠报错才发现。 -3. **「批量生成前检查余额」**(`cmhub_check_balance_checkbox`):自定义网关下隐藏——点数余额是默认网关概念。 -4. **点数展示文案**:②运行日志/状态栏在自定义网关下不得显示 `0 点`或空白,应显示「自定义网关(不计点数,费用由服务商收取)」;默认网关下 `points_cost` / `points_balance` 展示保持不变。 +- ② `GenerateWorker`、⑥商品套图生成与 AI 帮写开始时必须冻结本轮 AI 配置快照;运行中打开⑤并保存来源切换,不得让同一批任务前后混用默认网关和自定义网关。 +- ⑤保存来源成功后,主窗口需通知⑥刷新来源能力状态;⑥再次显示时也应重新检查当前来源。可以用 `SettingsTab` 的保存成功 signal/callback 与 `MainWindow` 转发实现,但不得依赖用户重启程序。 +- 即使 UI 刷新遗漏,worker/service 层仍必须按创建时的冻结来源执行,不能读取被后续保存原地修改的共享 `config`。 + +### 4. 必须同版本处理的六个联动 + +1. **⑥商品套图入口拦截**:`ai.backend != "cmhub"` 时,正式可见的 `ProductSuiteTab`「生成套图」、图片重试和「AI帮写」入口置灰并说明「商品套图仅支持默认网关」;保存来源切换后立即刷新,切入⑥时也再次刷新。旧 `ImageStudioTab` 即使不在主 Tab 栏,也不得绕过该限制。 +2. **⑥防御性服务拦截**:UI 置灰不足以作为费用边界。`ProductSuiteGenerateWorker` 必须在创建 job 前拒绝非默认网关;`image_studio_generation.run_jobs()` 也要在实际取默认网关 runtime 前拒绝非默认网关,确保内部调用、迟到回调或未来入口不能用默认网关 Key 提交任务。`ProductSuiteAiWriteWorker` 与 `analyze_product_images()` 保持非默认网关不可用;UI 必须在读取默认网关模型目录、展示扣点确认、提交图片理解前拦截,而不是等待运行后报错。 +3. **⑥商品套图说明**:⑤自定义面板增加说明行,明确「图片理解与商品套图仅默认网关支持」;拦截提示使用同一中文口径,不显示技术实现或 cmhub Key 信息。 +4. **②自定义网关预检**:允许保存不完整配置,但点击②开始生成时、创建 `GenerateWorker` 前按本轮“只生成标题 / 只生成封面 / 生成图文”检查所需 direct 模型是否已启用、类别匹配、模型地址、模型 ID、API Key、接口类型齐全。失败时中文提示去⑤补齐,且不创建 worker、不发请求、不逐条改任务状态。不要等 `_role_model()` 在批量运行中逐条失败。 +5. **「批量生成前检查余额」**(`cmhub_check_balance_checkbox`):自定义网关下隐藏——点数余额是默认网关概念。 +6. **点数展示文案**:②自定义网关每轮开始时在运行日志和状态栏各明确一次显示「自定义网关(不计点数,费用由服务商收取)」,并清空/隐藏上轮默认网关余额;不得显示 `0 点`、空白余额或沿用旧余额。默认网关下 `points_cost` / `points_balance` 展示保持不变。 ### 5. ⑤ 面板内文案收敛 -⑤ 面板内用户可见文案中的 `cmhub` 字样收敛为「默认网关」口径,包括分区标题、测试按钮与结果提示、明文保存警告(`PLAINTEXT_CMHUB_API_KEY_WARNING`,`app/gui/tabs/settings.py:17`)。`app/ai.py` 中的中文错误消息(如"连接 cmhub 超时")数量多、属于另一层,本任务不改。 +⑤ 面板内以及⑤触发的状态栏用户可见文案中的 `cmhub` 字样收敛为「默认网关」口径,包括分区标题、Base URL/API Key placeholder 与帮助、刷新/测试按钮、连接中/成功/失败结果、明文保存警告(`PLAINTEXT_CMHUB_API_KEY_WARNING`,`app/gui/tabs/settings.py:17`)。内部类名、`objectName`、配置键、日志字段和 `app/ai.py` 的中文错误消息(如"连接 cmhub 超时")不改。 ### 6. 效果图 @@ -73,14 +83,17 @@ T-529 把普通用户的 AI 后端收口为 cmhub:⑤ 隐藏「AI 后端」下 - [ ] ⑤ 生成网关分区显示互斥选中态的「默认网关」/「自定义网关」,当前选中项视觉可辨;两者均有 `objectName`。 - [ ] 切换来源立即切面板显隐并标记未保存;未点「保存设置」时不落盘,取消/重新载入后恢复原选择。 -- [ ] 选默认网关时只显示 cmhub 配置(Base URL / API Key / 三个别名 / 连接超时 / 检查余额 / 测试连接·查余额);选自定义网关时只显示自定义模型列表、模型详情与默认文本/图像模型选择。 +- [ ] 选默认网关时只显示默认网关配置(Base URL / API Key / 三个别名 / 连接超时 / 检查余额 / 测试连接·查余额);选自定义网关时只显示自定义模型列表、模型详情与默认文本/图像模型选择。 - [ ] 保存后 `config.json` 的 `ai.backend` 正确写入 `cmhub` / `direct`;`cmhub.json` 与 `ai_models.json` 在来回切换保存后内容均不丢失。 - [ ] 载入 `backend=direct` 的存量配置时选中「自定义网关」并正确回填自定义模型;缺失或 `cmhub` 时选中「默认网关」。 -- [ ] 自定义网关下②生文、②生图可用;⑥AI工场入口被拦截并提示仅默认网关支持,**不会用 cmhub Key 提交任务或扣点**。 -- [ ] 自定义网关下「批量生成前检查余额」不可见;②日志/状态栏显示"不计点数"口径而非 `0 点`;默认网关下点数与余额展示不回归。 -- [ ] 自定义配置不完整时可保存,②生成时给出"去⑤补齐"的可读提示,不崩溃。 -- [ ] ⑤ 面板内可见文案不再出现 `cmhub` 字样(`app/ai.py` 错误消息不在本次范围)。 -- [ ] `tests/test_gui.py` 覆盖:选择器互斥与默认选中、面板显隐、dirty 与保存生效、存量 `backend=direct` 载入、AI工场拦截、余额控件显隐、点数文案分支;现有 backend 相关断言同步更新不回归。 +- [ ] 自定义网关下②生文、②生图可用;⑥商品套图的生成、重试和 AI 帮写入口被拦截并提示仅默认网关支持,旧 `ImageStudioTab` 也不能绕过;worker/service 防线证明非默认网关不会创建默认网关 job、读取默认网关模型目录、提交请求或扣点。 +- [ ] ②/⑥运行开始后保存来源切换,不影响已启动任务的来源快照;保存完成后⑥按钮状态立即刷新,重新进入⑥时也正确刷新。 +- [ ] 自定义网关下「批量生成前检查余额」不可见;②日志/状态栏显示"不计点数"口径而非 `0 点`,且清除旧余额;默认网关下点数与余额展示不回归。 +- [ ] 自定义配置不完整时可保存;②按本轮生成内容在创建 worker 前给出"去⑤补齐"的可读提示,不发请求、不改任务状态、不崩溃。 +- [ ] 自定义模型 CRUD 的立即保存与来源选择的待保存语义均有明确中文反馈;放弃设置不回滚已保存模型,但恢复未保存来源选择。 +- [ ] `auto` 接口类型的实际请求行为有测试覆盖,不宣称自动探测或未实现的 `images/generations` 支持。 +- [ ] ⑤ 面板及⑤触发的状态栏可见文案不再出现 `cmhub` 字样;内部标识和 `app/ai.py` 错误消息不在本次范围。 +- [ ] `tests/test_gui.py` 覆盖:选择器互斥与默认选中、面板显隐、dirty 与保存生效、存量 `backend=direct` 载入、模型立即保存与来源待保存语义、②预检、⑥入口/worker拦截、余额控件显隐、点数文案分支、运行配置快照;`tests/test_ai.py` 覆盖 direct 文本/图片、`auto` 的既有请求路径与缺配置报错;现有 backend 相关断言同步更新不回归。 - [ ] `docs/ui/tab5-settings-T677.svg` 已产出并在 `docs/ui/README.md` 登记。 ## 测试与文档 @@ -99,11 +112,12 @@ git diff --check ## 边界(不改什么) -- 不给 AI工场(`app/image_studio_generation.py`)和图片理解(`analyze_product_images()`)新增自定义网关路径;本任务只做入口拦截与提示。 +- 不给商品套图(`app/image_studio_generation.py`)和图片理解(`analyze_product_images()`)新增自定义网关路径;本任务只做入口拦截与提示。 - 不实现方案中经 cmhub 代理透传的正式 BYOK(T-596 / T-599~T-602 仍按其门禁推进);本任务的自定义网关是**客户端直连的过渡形态**,正式商业版需迁移到网关代理并重新收口 direct 入口。 - 不修改 `ai_models.json` 的 schema 与 `API_TYPES` 取值,不新增 provider 适配。 - 不改 `app/ai.py` 的 cmhub 请求协议、重试与超时策略、异步 submit/poll 状态机、幂等键。 - 不改 `app/ai.py` 中文错误消息里的 `cmhub` 字样。 +- 不新增 `images/generations`、接口自动探测或 provider 专用适配;自定义网关仅覆盖现有 direct 文本/图片请求能力。 - 不改 SQLite schema、Chrome/CDP、Excel 回写、蝦皮更新流程。 - 不涉及卡密、设备绑定、订阅授权(见 Obsidian《卡密设备绑定与套餐授权方案》,另行拆任务)。