diff --git a/js/components/kb-modal.js b/js/components/kb-modal.js index 7f4a146..b3f48f8 100644 --- a/js/components/kb-modal.js +++ b/js/components/kb-modal.js @@ -291,7 +291,7 @@ async function handleDocUpload(e) { } /** - * 填充嵌入模型下拉(仅显示嵌入模型) + * 填充嵌入模型下拉(通过 /api/show 检测 embedding 能力) */ async function populateEmbedModels() { const select = document.querySelector('#selectEmbedModel'); @@ -301,23 +301,34 @@ async function populateEmbedModels() { try { const data = await api.listModels(); select.innerHTML = ''; - if (data.models) { - const embedKeywords = ['embed', 'nomic', 'mxbai', 'bge', 'e5', 'snowflake', 'arctic']; - const embedModels = data.models.filter(m => - embedKeywords.some(kw => m.name.toLowerCase().includes(kw)) - ); + if (!data.models || data.models.length === 0) { + select.innerHTML = ''; + return; + } - embedModels.forEach(m => { - const opt = document.createElement('option'); - opt.value = m.name; - const size = m.size ? ` (${formatSize(m.size)})` : ''; - opt.textContent = m.name + size; - select.appendChild(opt); - }); + // 并发检测每个模型的 capabilities + const checks = await Promise.allSettled( + data.models.map(async (m) => { + const info = await api.showModel(m.name); + const caps = info.capabilities || []; + return { name: m.name, size: m.size, isEmbed: caps.includes('embedding') }; + }) + ); - if (embedModels.length === 0) { - select.innerHTML = ''; - } + const embedModels = checks + .filter(r => r.status === 'fulfilled' && r.value.isEmbed) + .map(r => r.value); + + embedModels.forEach(m => { + const opt = document.createElement('option'); + opt.value = m.name; + const size = m.size ? ` (${formatSize(m.size)})` : ''; + opt.textContent = m.name + size; + select.appendChild(opt); + }); + + if (embedModels.length === 0) { + select.innerHTML = ''; } } catch (err) { console.warn('[KB] 加载模型列表失败:', err);