diff --git a/app/gui/tabs/settings.py b/app/gui/tabs/settings.py index c72766c..391e134 100644 --- a/app/gui/tabs/settings.py +++ b/app/gui/tabs/settings.py @@ -371,10 +371,6 @@ class SettingsTab(QWidget): "生成网关", "settingsAiModelSectionTitle", ) - self.model_detail_section_title = self._section_title( - "模型详情", - "settingsModelDetailSectionTitle", - ) self.generation_section_title = self._section_title( "角色与生成参数", "settingsGenerationSectionTitle", @@ -391,8 +387,7 @@ class SettingsTab(QWidget): panel_layout.addWidget(self.gateway_selector) panel_layout.addSpacing(8) panel_layout.addWidget(self.model_picker_panel) - panel_layout.addSpacing(14) - panel_layout.addWidget(self.model_detail_section_title) + panel_layout.addSpacing(8) panel_layout.addWidget(self.model_detail_panel) panel_layout.addWidget(self.cmhub_panel) panel_layout.addSpacing(18) @@ -645,7 +640,6 @@ class SettingsTab(QWidget): self.backend_combo.setVisible(False) is_direct = backend == "direct" self.model_picker_panel.setVisible(is_direct) - self.model_detail_section_title.setVisible(is_direct) self.model_detail_panel.setVisible(is_direct) self.direct_role_panel.setVisible(is_direct) self.cmhub_panel.setVisible(not is_direct) diff --git a/docs/routes.md b/docs/routes.md index 4fd6ef7..c89ed2b 100644 --- a/docs/routes.md +++ b/docs/routes.md @@ -173,7 +173,7 @@ - 设置页整体布局:内容区居中,左右留白已从 T-506 初始实现缩短到约 40%;实现上用最大内容宽度 + 自适应 margin,而不是写死窗口像素。所有设置组默认响应式 3 列表单:短字段占 1 格,URL/API Key/路径等长字段跨 2 格或 3 格;窄窗口自动降为 2 列/1 列。点击「保存设置」成功后,状态栏显示“设置已保存”,并弹出轻量提示框。T-531 已完成:保存成功会清除未保存标记;保存失败时保留未保存标记并阻止离开。 - 生成网关(T-677/T-680):在原「AI 模型配置」标题下使用同行标准单选框「默认网关 / 自定义网关」替代历史「AI 后端」下拉和不明显的分段按钮;启动/放弃未保存更改时按已保存的 `ai.backend=cmhub/direct` 自动勾选对应项,圆点与焦点状态表达当前选择。切换只改变待保存状态并立即切换原有面板,点击「保存设置」才写入配置;默认网关的 `data/config/cmhub.json` 与自定义模型的 `data/config/ai_models.json` 始终并存,模型新增、保存、删除仍立即写盘,不受来源待保存语义影响。除这两个选择控件外,不改变设置页其它组件、表单布局或业务逻辑。 - 默认网关面板展示 Base URL、API Key、生文/生图/图片理解别名、连接超时、批量生成前检查余额、刷新别名和测试连接/查余额;Base URL 输入框旁提示“只填网关根,如 https://host”,保存/刷新前规整掉 `/api`、`/api/v1` 或其它路径。测试连接成功优先显示 `账号「<账号名>」连接默认网关成功`,邮箱脱敏;没有账号信息时显示「默认网关连接成功」。Key 只本地明文保存、UI 打码显示,不进入日志或导出。 - - 自定义网关复用既有模型列表、模型详情、默认文本模型与默认图像模型。文本模型保留 `chat` / `auto`;图片模型固定使用「OpenAI 图片编辑接口」(`images_edits`),②和⑥通过 `/v1/images/edits` 以有序重复 `image[]` 上传,第一张是商品主体图、每次只请求 `n=1` 输出。历史 `chat` / `auto` 图片模型不会被改写或隐藏,但会标示「图片接口不支持」,生成前会被拦截。图片响应只接受 `data[].b64_json` / `data[].url`,不适配聊天响应或服务商私有结构。说明行明确「图片理解仅支持默认网关」。 + - 自定义网关复用既有模型列表、其下紧凑显示的模型配置字段、默认文本模型与默认图像模型;不再显示重复的“模型详情”标题,模型选择区到配置表单保留 8px 间距。文本模型保留 `chat` / `auto`;图片模型固定使用「OpenAI 图片编辑接口」(`images_edits`),②和⑥通过 `/v1/images/edits` 以有序重复 `image[]` 上传,第一张是商品主体图、每次只请求 `n=1` 输出。历史 `chat` / `auto` 图片模型不会被改写或隐藏,但会标示「图片接口不支持」,生成前会被拦截。图片响应只接受 `data[].b64_json` / `data[].url`,不适配聊天响应或服务商私有结构。说明行明确「图片理解仅支持默认网关」。 - 图片模型按钮显示「检查图片配置」,只在本地检查接口类型、URL、模型 ID、密钥和超时,绝不对 `/images/edits` 发送无图片的测试请求;实际可用性必须以②或后续⑥的正常生成确认判断。允许保存不完整配置。②点击生成后、自定义 worker 创建前按本轮标题/封面选择校验所需模型的启用状态、类别、地址、模型 ID、API Key 和接口类型,失败提示去⑤补齐且不发请求、不改任务状态;自定义网关不显示默认网关余额,运行日志和状态栏说明“不计点数,费用由服务商收取”。 - T-679b 后,⑥商品套图在自定义网关下先本地校验已启用的图片模型、接口类型、网址、模型 ID、密钥与连接超时;不合格时阻止创建 job 并引导到⑤补齐。合格后可创建同步直连 job,确认框显示数量、主图/参考图、逐图模式、比例映射与“自定义网关不计点数,实际费用以服务商为准”,并说明首图为主要商品参考、主体一致性可能弱于默认网关;不请求 cmhub 模型目录、余额或价格。AI帮写仍禁用并说明仅默认网关可用。已有 `generation_source=cmhub`、`provider=cmhub` 且 `task_id` 非空的可恢复任务仍显示「继续查询已提交图片」,仅轮询、下载和保存,不新建 job 或重复扣点。所有②/⑥ worker 开始时冻结来源、实际模型和密钥的仅内存快照,保存设置不会改变正在执行的一轮。 - T-679c 后,「继续查询已提交图片」只显示并处理 `generation_source=cmhub`、`provider=cmhub` 且 `task_id` 非空的任务,切换到自定义网关后仍可继续查询旧默认网关任务;direct job 永不进入该入口。结果卡、项目历史和全局历史固定显示 job 已保存的“默认网关 / 自定义网关”,不因⑤设置切换改写;同轮混合来源显示“默认网关、自定义网关”。direct 失败只能手动“重新生成”,并再次显示完整生成确认及“服务商可能已对上次未确认请求计费,本次可能再次收费”的默认取消警告。确认后新建 job,不自动重试或复用旧 job;默认网关历史、导出、删除撤销和继续查询保持原有行为。 diff --git a/docs/tasks/T-682.md b/docs/tasks/T-682.md index 2ea9dae..75b0e34 100644 --- a/docs/tasks/T-682.md +++ b/docs/tasks/T-682.md @@ -3,7 +3,7 @@ id: T-682 title: 收紧自定义网关模型配置区间距 phase: 5 deps: [T-680, T-681] -status: TODO +status: DONE created: 2026-07-21 --- @@ -56,4 +56,7 @@ git diff --check ## 执行记录 -- 待实现。 +- 删除自定义网关专用的“模型详情”标题组件及其显隐逻辑;模型选择区后的固定间距由 14px 标题间隔收紧为 8px,模型配置表单随之上移,原有字段、保存/测试按钮和结果区域不变。 +- 更新设置页路由说明,明确自定义网关直接在模型列表下显示紧凑配置字段。 +- 更新 GUI 回归:默认网关隐藏模型选择与配置面板,自定义网关显示两者;不存在“模型详情”文字,并验证选择区与配置表单之间保留 8px 间距。 +- 验证通过:`py -3.10 -m unittest tests.test_gui`(212 项)、`py -3.10 -m unittest discover -s tests`(653 项)、`py -3.10 -m ruff check app tests main.py`、`py -3.10 -m compileall app main.py`、`git diff --check`。 diff --git a/tests/test_gui.py b/tests/test_gui.py index 8b90872..23471b6 100644 --- a/tests/test_gui.py +++ b/tests/test_gui.py @@ -3143,6 +3143,11 @@ class GuiTests(TempDirMixin, unittest.TestCase): self.assertFalse(tab.gateway_custom_button.isChecked()) self.assertFalse(tab.cmhub_panel.isHidden()) self.assertTrue(tab.model_picker_panel.isHidden()) + self.assertTrue(tab.model_detail_panel.isHidden()) + self.assertNotIn( + "模型详情", + [label.text() for label in tab.findChildren(QLabel)], + ) tab.show() self.app.processEvents() @@ -3156,7 +3161,18 @@ class GuiTests(TempDirMixin, unittest.TestCase): self.assertFalse(tab.gateway_default_button.isChecked()) self.assertTrue(tab.cmhub_panel.isHidden()) self.assertFalse(tab.model_picker_panel.isHidden()) + self.assertFalse(tab.model_detail_panel.isHidden()) self.assertFalse(tab.direct_role_panel.isHidden()) + picker_index = tab.settings_panel_layout.indexOf(tab.model_picker_panel) + detail_index = tab.settings_panel_layout.indexOf(tab.model_detail_panel) + self.assertEqual(picker_index + 2, detail_index) + self.assertEqual( + 8, + tab.settings_panel_layout.itemAt(picker_index + 1) + .spacerItem() + .sizeHint() + .height(), + ) self.assertTrue(tab.is_dirty()) self.assertEqual("cmhub", appconfig.load_config(cfg["config_path"])["ai"]["backend"])