From 78cc2aab56ca7b37c69cead7641e4842a2c53703 Mon Sep 17 00:00:00 2001 From: Wang Defa <1+wangdefa@noreply.gitea.bcde.io> Date: Tue, 14 Jul 2026 19:33:55 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B8=A0=E9=81=93=E6=A8=A1=E5=9E=8B=E5=88=97?= =?UTF-8?q?=E8=A1=A8=E5=BC=B9=E7=AA=97=E4=B8=8E=E6=A8=A1=E5=9E=8B=E6=95=B0?= =?UTF-8?q?=E9=87=8F=E5=88=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 7 + src/api/aigateway.ts | 9 + src/components/ai/AiChannelModelsModal.vue | 201 +++++++++++++++++++++ src/components/ai/AiChannelPanel.vue | 32 ++-- src/composables/useActionLabel.ts | 1 + src/types/api.ts | 7 + 6 files changed, 246 insertions(+), 11 deletions(-) create mode 100644 src/components/ai/AiChannelModelsModal.vue diff --git a/CHANGELOG.md b/CHANGELOG.md index 3320c6e..a172edd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ 格式参考 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.1.0/)(版本段不记日期),版本号遵循语义化版本。 +## [0.6.0] + +### Added + +- AI 网关渠道表格新增「模型数量」列(与模型列表同口径:排除黑名单、随「过滤弃用」开关) +- 渠道「模型列表」弹窗(替代原「同步模型」按钮,同步入口迁入弹窗):模型按能力分组展示(对话 / 向量 / 重排 / 语音),支持关键字过滤;每行可「测试」(通过即标记「验证模型」徽章并置渠道可用,后续探测优先使用)与「拉黑」(全局黑名单);弃用模型降灰标注,非对话模型不提供测试;操作按钮悬停行时着色,保持列表安静 + ## [0.5.1] ### Changed diff --git a/src/api/aigateway.ts b/src/api/aigateway.ts index 4d637c2..f334013 100644 --- a/src/api/aigateway.ts +++ b/src/api/aigateway.ts @@ -83,6 +83,15 @@ export function syncAiChannelModels(id: number): Promise { }).then((r) => r.items) } +export function listAiChannelModels(id: number): Promise { + return request<{ items: AiModelCacheItem[] }>(`/ai-channels/${id}/models`).then((r) => r.items) +} + +/** 单模型 max_tokens=16 试调;通过即设为该渠道探测验证模型并按需置渠道可用 */ +export function testAiChannelModel(id: number, model: string): Promise { + return request(`/ai-channels/${id}/test-model`, { method: 'POST', body: { model } }) +} + // ---- 聚合模型与调用日志 ---- export function listAiModels(): Promise { diff --git a/src/components/ai/AiChannelModelsModal.vue b/src/components/ai/AiChannelModelsModal.vue new file mode 100644 index 0000000..2780f82 --- /dev/null +++ b/src/components/ai/AiChannelModelsModal.vue @@ -0,0 +1,201 @@ + + + diff --git a/src/components/ai/AiChannelPanel.vue b/src/components/ai/AiChannelPanel.vue index c907e70..a664bd5 100644 --- a/src/components/ai/AiChannelPanel.vue +++ b/src/components/ai/AiChannelPanel.vue @@ -2,8 +2,9 @@ import { NButton, NDataTable, NInput, NSelect, NTooltip, useDialog, type DataTableColumns } from 'naive-ui' import { computed, h, reactive, ref } from 'vue' -import { createAiChannel, deleteAiChannel, probeAiChannel, syncAiChannelModels, updateAiChannel } from '@/api/aigateway' +import { createAiChannel, deleteAiChannel, probeAiChannel, updateAiChannel } from '@/api/aigateway' import { listCachedRegions } from '@/api/configs' +import AiChannelModelsModal from '@/components/ai/AiChannelModelsModal.vue' import GroupChips from '@/components/ai/GroupChips.vue' import AppInputNumber from '@/components/AppInputNumber.vue' import FormField from '@/components/FormField.vue' @@ -109,14 +110,13 @@ async function doProbe(id: number) { } } -async function doSync(id: number) { - try { - const models = await syncAiChannelModels(id) - toast.success(`已同步 ${models.length} 个模型`) - emit('changed') - } catch (e) { - toast.error(e instanceof Error ? e.message : '同步失败') - } +// ---- 模型列表弹窗 ---- +const showModels = ref(false) +const modelsChannel = ref(null) + +function openModels(ch: AiChannel) { + modelsChannel.value = ch + showModels.value = true } async function toggle(ch: AiChannel) { @@ -178,12 +178,16 @@ const columns = computed>(() => [ }, { title: '优先级', key: 'priority', width: 76, render: (r) => h('span', { class: 'mono text-[13px]' }, String(r.priority)) }, { title: '权重', key: 'weight', width: 66, render: (r) => h('span', { class: 'mono text-[13px]' }, String(r.weight)) }, + { + title: '模型数量', key: 'modelCount', width: 86, + render: (r) => h('span', { class: r.modelCount ? 'mono text-[13px]' : 'text-xs text-ink-3' }, String(r.modelCount ?? 0)), + }, { title: '探测状态', key: 'probeStatus', width: 120, render: probeCell }, { title: '操作', key: 'actions', width: 250, render: (r) => h('div', { class: 'flex items-center gap-0.5' }, [ h(NButton, { size: 'tiny', quaternary: true, type: 'primary', loading: probing.value.has(r.id), onClick: () => doProbe(r.id) }, { default: () => '探测' }), - h(NButton, { size: 'tiny', quaternary: true, type: 'primary', onClick: () => doSync(r.id) }, { default: () => '同步模型' }), + h(NButton, { size: 'tiny', quaternary: true, type: 'primary', onClick: () => openModels(r) }, { default: () => '模型列表' }), h(NButton, { size: 'tiny', quaternary: true, onClick: () => toggle(r) }, { default: () => (r.enabled ? '停用' : '启用') }), h(NButton, { size: 'tiny', quaternary: true, type: 'primary', onClick: () => openEdit(r) }, { default: () => '编辑' }), h(NButton, { size: 'tiny', quaternary: true, type: 'error', onClick: () => confirmRemove(r) }, { default: () => '删除' }), @@ -205,10 +209,16 @@ const columns = computed>(() => [
- 探测三步:列模型(服务可见性)→ 同步模型缓存 → max_tokens=1 试调(配额)· 探测成功自动复位熔断 · + 探测三步:列模型(服务可见性)→ 同步模型缓存 → max_tokens=16 试调(配额)· 探测成功自动复位熔断 · 有渠道时系统自动维护「AI渠道探测」后台任务(每天 00:00 逐渠道探测,渠道清空自动暂停)
+ + = { 'DELETE /api/v1/ai-channels/:id': '删除网关渠道', 'POST /api/v1/ai-channels/:id/probe': '探测网关渠道', 'POST /api/v1/ai-channels/:id/sync-models': '同步渠道模型', + 'POST /api/v1/ai-channels/:id/test-model': '测试渠道模型', 'POST /api/v1/ai-blacklist': '拉黑模型', 'DELETE /api/v1/ai-blacklist/:id': '移出模型黑名单', 'PUT /api/v1/ai-settings': '保存网关设置', diff --git a/src/types/api.ts b/src/types/api.ts index 29b1f6e..7f87a83 100644 --- a/src/types/api.ts +++ b/src/types/api.ts @@ -946,8 +946,12 @@ export interface AiChannel { lastProbeAt: string | null probeStatus: AiProbeStatus probeError: string + /** 用户测试通过后固定的探测验证模型;探测时置于候选首位 */ + probeModel: string createdAt: string updatedAt: string + /** 渠道模型缓存计数(列表查询回填) */ + modelCount: number } /** 聚合可用模型(OpenAI /models 形态) */ @@ -964,7 +968,10 @@ export interface AiModelCacheItem { modelOcid: string name: string vendor: string + capability: string syncedAt: string + deprecatedAt: string | null + retiredAt: string | null } /** 模型黑名单条目:拉黑即全渠道剔除,同步 / 探测不再入库 */