feat(settings): clarify custom gateway format
This commit is contained in:
@@ -67,7 +67,10 @@ class SettingsTab(QWidget):
|
||||
|
||||
settingsSaved = Signal(str)
|
||||
|
||||
BACKEND_ITEMS = [("默认网关", "cmhub"), ("自定义网关", "direct")]
|
||||
BACKEND_ITEMS = [
|
||||
("默认网关", "cmhub"),
|
||||
("自定义网关(仅支持 OpenAI 格式)", "direct"),
|
||||
]
|
||||
CATEGORY_ITEMS = [("文本", "text"), ("图像", "image")]
|
||||
API_TYPE_ITEMS = [("chat", "chat"), ("images_edits", "images_edits"), ("auto", "auto")]
|
||||
IMAGE_API_TYPE_ITEMS = [("OpenAI 图片编辑接口", "images_edits")]
|
||||
@@ -118,8 +121,11 @@ class SettingsTab(QWidget):
|
||||
self.backend_combo.setVisible(False)
|
||||
self.gateway_default_button = QRadioButton("默认网关")
|
||||
self.gateway_default_button.setObjectName("gatewayDefaultButton")
|
||||
self.gateway_custom_button = QRadioButton("自定义网关")
|
||||
self.gateway_custom_button = QRadioButton("自定义网关(仅支持 OpenAI 格式)")
|
||||
self.gateway_custom_button.setObjectName("gatewayCustomButton")
|
||||
self.gateway_custom_button.setToolTip(
|
||||
"仅支持 OpenAI 格式的文本接口和图片编辑接口。"
|
||||
)
|
||||
self.gateway_button_group = QButtonGroup(self)
|
||||
self.gateway_button_group.setExclusive(True)
|
||||
self.gateway_button_group.addButton(self.gateway_default_button)
|
||||
@@ -138,6 +144,13 @@ class SettingsTab(QWidget):
|
||||
"QRadioButton:focus { border: 1px solid #0969da; border-radius: 4px; }"
|
||||
"QRadioButton::indicator { width: 15px; height: 15px; }"
|
||||
)
|
||||
self.custom_gateway_hint_label = QLabel(
|
||||
"只有服务商明确说明“支持 OpenAI 格式接口”时才选择此项。"
|
||||
)
|
||||
self.custom_gateway_hint_label.setObjectName("customGatewayFormatHintLabel")
|
||||
self.custom_gateway_hint_label.setStyleSheet("color: #57606a; padding: 0 12px;")
|
||||
self.custom_gateway_hint_label.setWordWrap(True)
|
||||
self.custom_gateway_hint_label.setVisible(False)
|
||||
self.cmhub_base_url_edit = QLineEdit()
|
||||
self.cmhub_base_url_edit.setObjectName("cmhubBaseUrlEdit")
|
||||
self.cmhub_base_url_edit.setPlaceholderText("https://host(不要带 /api 或 /api/v1)")
|
||||
@@ -419,6 +432,7 @@ class SettingsTab(QWidget):
|
||||
)
|
||||
panel_layout.addWidget(self.ai_model_section_title)
|
||||
panel_layout.addWidget(self.gateway_selector)
|
||||
panel_layout.addWidget(self.custom_gateway_hint_label)
|
||||
panel_layout.addSpacing(8)
|
||||
panel_layout.addWidget(self.model_picker_panel)
|
||||
panel_layout.addSpacing(8)
|
||||
@@ -674,6 +688,7 @@ class SettingsTab(QWidget):
|
||||
self.backend_combo.blockSignals(previous)
|
||||
self.backend_combo.setVisible(False)
|
||||
is_direct = backend == "direct"
|
||||
self.custom_gateway_hint_label.setVisible(is_direct)
|
||||
self.model_picker_panel.setVisible(is_direct)
|
||||
self.model_detail_panel.setVisible(is_direct)
|
||||
self.direct_role_panel.setVisible(is_direct)
|
||||
|
||||
+1
-1
@@ -171,7 +171,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` 始终并存,模型新增、保存、删除仍立即写盘,不受来源待保存语义影响。除这两个选择控件外,不改变设置页其它组件、表单布局或业务逻辑。
|
||||
- 生成网关(T-677/T-680/T-684):在原「AI 模型配置」标题下使用同行标准单选框「默认网关 / 自定义网关(仅支持 OpenAI 格式)」替代历史「AI 后端」下拉和不明显的分段按钮;选中自定义网关时,在其下显示“只有服务商明确说明‘支持 OpenAI 格式接口’时才选择此项。”,并提供同义 tooltip。启动/放弃未保存更改时按已保存的 `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 打码显示,不进入日志或导出。
|
||||
- 自定义网关复用既有模型列表、其下紧凑显示的模型配置字段、默认文本模型与默认图像模型;不再显示重复的“模型详情”标题,模型选择区到配置表单保留 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 和接口类型,失败提示去⑤补齐且不发请求、不改任务状态;自定义网关不显示默认网关余额,运行日志和状态栏说明“不计点数,费用由服务商收取”。
|
||||
|
||||
+5
-2
@@ -3,7 +3,7 @@ id: T-684
|
||||
title: 明确自定义网关接口格式限制
|
||||
phase: 5
|
||||
deps: [T-680, T-681]
|
||||
status: TODO
|
||||
status: DONE
|
||||
created: 2026-07-21
|
||||
---
|
||||
|
||||
@@ -60,4 +60,7 @@ git diff --check
|
||||
|
||||
## 执行记录
|
||||
|
||||
- 待实现。
|
||||
- 将自定义来源单选项和内部兼容下拉标签统一改为“自定义网关(仅支持 OpenAI 格式)”;配置值仍为 `direct`,保存成功状态仍使用简洁的“自定义网关”。
|
||||
- 增加仅在 `direct` 选中时可见的说明“只有服务商明确说明‘支持 OpenAI 格式接口’时才选择此项。”,同时为单选项增加中文 tooltip;说明显隐不接入 dirty 信号。
|
||||
- 更新设置路由说明及 GUI 回归,覆盖单选项文字、tooltip、默认/自定义来源说明显隐和既有切换保存行为。
|
||||
- 验证通过:`py -3.10 -m unittest tests.test_gui`(213 项)、`py -3.10 -m unittest discover -s tests`(654 项)、`py -3.10 -m ruff check app tests main.py`、`py -3.10 -m compileall app main.py`、`git diff --check`。
|
||||
|
||||
@@ -3139,6 +3139,12 @@ class GuiTests(TempDirMixin, unittest.TestCase):
|
||||
|
||||
self.assertIsInstance(tab.gateway_default_button, QRadioButton)
|
||||
self.assertIsInstance(tab.gateway_custom_button, QRadioButton)
|
||||
self.assertEqual("默认网关", tab.gateway_default_button.text())
|
||||
self.assertEqual(
|
||||
"自定义网关(仅支持 OpenAI 格式)",
|
||||
tab.gateway_custom_button.text(),
|
||||
)
|
||||
self.assertIn("OpenAI 格式", tab.gateway_custom_button.toolTip())
|
||||
self.assertEqual(0, tab.gateway_selector.layout().spacing())
|
||||
self.assertEqual(2, tab.gateway_selector.layout().count())
|
||||
self.assertTrue(tab.gateway_default_button.isChecked())
|
||||
@@ -3146,6 +3152,7 @@ class GuiTests(TempDirMixin, unittest.TestCase):
|
||||
self.assertFalse(tab.cmhub_panel.isHidden())
|
||||
self.assertTrue(tab.model_picker_panel.isHidden())
|
||||
self.assertTrue(tab.model_detail_panel.isHidden())
|
||||
self.assertTrue(tab.custom_gateway_hint_label.isHidden())
|
||||
self.assertNotIn(
|
||||
"模型详情",
|
||||
[label.text() for label in tab.findChildren(QLabel)],
|
||||
@@ -3164,6 +3171,11 @@ class GuiTests(TempDirMixin, unittest.TestCase):
|
||||
self.assertTrue(tab.cmhub_panel.isHidden())
|
||||
self.assertFalse(tab.model_picker_panel.isHidden())
|
||||
self.assertFalse(tab.model_detail_panel.isHidden())
|
||||
self.assertFalse(tab.custom_gateway_hint_label.isHidden())
|
||||
self.assertEqual(
|
||||
"只有服务商明确说明“支持 OpenAI 格式接口”时才选择此项。",
|
||||
tab.custom_gateway_hint_label.text(),
|
||||
)
|
||||
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)
|
||||
|
||||
Reference in New Issue
Block a user