From 359ac2af5edbefc385a3f0bc0dba688acc597223 Mon Sep 17 00:00:00 2001 From: wizardchen Date: Thu, 20 Aug 2026 14:49:47 +0800 Subject: [PATCH] fix(frontend): narrow VLLM model filter to vision-capable chat models Restrict supports_vision inclusion to KnowledgeQA models, extract filterModelsByType for unit tests, and re-filter when modelType changes. --- frontend/src/components/ModelSelector.vue | 17 +++----- .../components/modelSelectorFilter.test.ts | 39 +++++++++++++++++++ .../src/components/modelSelectorFilter.ts | 18 +++++++++ 3 files changed, 62 insertions(+), 12 deletions(-) create mode 100644 frontend/src/components/modelSelectorFilter.test.ts create mode 100644 frontend/src/components/modelSelectorFilter.ts diff --git a/frontend/src/components/ModelSelector.vue b/frontend/src/components/ModelSelector.vue index d7023a3e6..70af4e793 100644 --- a/frontend/src/components/ModelSelector.vue +++ b/frontend/src/components/ModelSelector.vue @@ -47,6 +47,7 @@ import { ref, computed, watch, onMounted } from 'vue' import { listModels, type ModelConfig } from '@/api/model' import { MessagePlugin } from 'tdesign-vue-next' import { useI18n } from 'vue-i18n' +import { filterModelsByType } from './modelSelectorFilter' interface Props { modelType: 'KnowledgeQA' | 'Embedding' | 'Rerank' | 'VLLM' | 'ASR' @@ -84,18 +85,10 @@ const modelDisplayName = (model: ModelConfig) => { return displayName || model.name } -const filterModels = (allModels: ModelConfig[]) => { - if (props.modelType === 'VLLM') { - return allModels.filter(m => (m.type === props.modelType || m.parameters.supports_vision === true)) - } - - return allModels.filter(m => m.type === props.modelType) -} - -// 监听 allModels 变化,自动过滤当前类型的模型 -watch(() => props.allModels, (newModels) => { +// 监听 allModels / modelType 变化,自动过滤当前类型的模型 +watch(() => [props.allModels, props.modelType] as const, ([newModels]) => { if (newModels && Array.isArray(newModels)) { - models.value = filterModels(newModels) + models.value = filterModelsByType(newModels, props.modelType) } }, { immediate: true }) @@ -116,7 +109,7 @@ const loadModels = async () => { const result = await listModels() // 前端按类型筛选模型 if (result && Array.isArray(result)) { - models.value = filterModels(result) + models.value = filterModelsByType(result, props.modelType) } else { models.value = [] } diff --git a/frontend/src/components/modelSelectorFilter.test.ts b/frontend/src/components/modelSelectorFilter.test.ts new file mode 100644 index 000000000..3397af189 --- /dev/null +++ b/frontend/src/components/modelSelectorFilter.test.ts @@ -0,0 +1,39 @@ +import assert from 'node:assert/strict' +import test from 'node:test' + +import type { ModelConfig } from '@/api/model' + +import { filterModelsByType } from './modelSelectorFilter.ts' + +function model(overrides: Partial & Pick): ModelConfig { + return { + name: overrides.name ?? overrides.id!, + source: 'remote', + parameters: {}, + ...overrides, + } +} + +const fixtures: ModelConfig[] = [ + model({ id: 'vllm-1', type: 'VLLM' }), + model({ id: 'chat-vision', type: 'KnowledgeQA', parameters: { supports_vision: true } }), + model({ id: 'chat-text', type: 'KnowledgeQA' }), + model({ id: 'embed-vision', type: 'Embedding', parameters: { supports_vision: true } }), + model({ id: 'embed-1', type: 'Embedding' }), +] + +test('VLLM selector includes native VLLM and vision-capable chat models', () => { + const ids = filterModelsByType(fixtures, 'VLLM').map((m) => m.id) + assert.deepEqual(ids, ['vllm-1', 'chat-vision']) +}) + +test('VLLM selector excludes non-vision chat and other types even with supports_vision', () => { + const ids = filterModelsByType(fixtures, 'VLLM') + assert.ok(!ids.some((m) => m.id === 'chat-text')) + assert.ok(!ids.some((m) => m.id === 'embed-vision')) +}) + +test('non-VLLM selectors still filter strictly by type', () => { + const ids = filterModelsByType(fixtures, 'KnowledgeQA').map((m) => m.id) + assert.deepEqual(ids, ['chat-vision', 'chat-text']) +}) diff --git a/frontend/src/components/modelSelectorFilter.ts b/frontend/src/components/modelSelectorFilter.ts new file mode 100644 index 000000000..c7f642743 --- /dev/null +++ b/frontend/src/components/modelSelectorFilter.ts @@ -0,0 +1,18 @@ +import type { ModelConfig } from '@/api/model' + +export type ModelSelectorType = ModelConfig['type'] + +export function filterModelsByType( + allModels: ModelConfig[], + modelType: ModelSelectorType, +): ModelConfig[] { + if (modelType === 'VLLM') { + return allModels.filter( + (m) => + m.type === 'VLLM' || + (m.type === 'KnowledgeQA' && m.parameters?.supports_vision === true), + ) + } + + return allModels.filter((m) => m.type === modelType) +}