fix(story-summary): improve vector api provider state

This commit is contained in:
2026-04-03 17:01:05 +08:00
parent 7b921b80e0
commit 485016abdd
3 changed files with 193 additions and 44 deletions

View File

@@ -303,6 +303,18 @@ All checks passed. Beginning incremental extraction...
custom: { url: '', needKey: true, canFetch: true }
};
const VECTOR_API_SUPPORTED_PROVIDERS = {
l0: ['siliconflow', 'openrouter', 'custom'],
embedding: ['siliconflow', 'custom'],
rerank: ['siliconflow', 'custom'],
};
const VECTOR_API_DEFAULT_MODELS = {
l0: 'Qwen/Qwen3-8B',
embedding: 'BAAI/bge-m3',
rerank: 'BAAI/bge-reranker-v2-m3',
};
function setStatusText(el, message, kind = '') {
if (!el) return;
el.textContent = message || '';
@@ -315,6 +327,44 @@ All checks passed. Beginning incremental extraction...
: '';
}
function createDefaultProviderProfile(provider, model = '') {
const pv = VECTOR_PROVIDER_DEFAULTS[provider] || VECTOR_PROVIDER_DEFAULTS.custom;
return {
url: pv.url || '',
key: '',
model: model || '',
modelCache: [],
};
}
function normalizeProviderProfiles(prefix, apiCfg = {}) {
const supported = VECTOR_API_SUPPORTED_PROVIDERS[prefix] || ['custom'];
const model = apiCfg.model || VECTOR_API_DEFAULT_MODELS[prefix] || '';
const out = {};
supported.forEach(provider => {
const raw = apiCfg.providers?.[provider] || {};
const defaults = createDefaultProviderProfile(provider, model);
out[provider] = {
url: String(raw.url || defaults.url || '').trim(),
key: String(raw.key || '').trim(),
model: String(raw.model || defaults.model || '').trim(),
modelCache: Array.isArray(raw.modelCache) ? raw.modelCache.filter(Boolean) : [],
};
});
const currentProvider = String(apiCfg.provider || supported[0] || 'custom').toLowerCase();
if (out[currentProvider]) {
if (apiCfg.url && !out[currentProvider].url) out[currentProvider].url = String(apiCfg.url).trim();
if (apiCfg.key && !out[currentProvider].key) out[currentProvider].key = String(apiCfg.key).trim();
if (apiCfg.model && !out[currentProvider].model) out[currentProvider].model = String(apiCfg.model).trim();
if (Array.isArray(apiCfg.modelCache) && !out[currentProvider].modelCache.length) {
out[currentProvider].modelCache = apiCfg.modelCache.filter(Boolean);
}
}
return out;
}
const SECTION_META = {
keywords: { title: '编辑关键词', hint: '每行一个关键词,格式:关键词|权重(核心/重要/一般)' },
events: { title: '编辑事件时间线', hint: '编辑时,每个事件要素都应完整' },
@@ -365,9 +415,28 @@ All checks passed. Beginning incremental extraction...
enabled: false,
engine: 'online',
l0Concurrency: 10,
l0Api: { provider: 'siliconflow', url: 'https://api.siliconflow.cn/v1', key: '', model: 'Qwen/Qwen3-8B', modelCache: [] },
embeddingApi: { provider: 'siliconflow', url: 'https://api.siliconflow.cn/v1', key: '', model: 'BAAI/bge-m3', modelCache: [] },
rerankApi: { provider: 'siliconflow', url: 'https://api.siliconflow.cn/v1', key: '', model: 'BAAI/bge-reranker-v2-m3', modelCache: [] }
l0Api: {
provider: 'siliconflow', url: 'https://api.siliconflow.cn/v1', key: '', model: 'Qwen/Qwen3-8B', modelCache: [],
providers: {
siliconflow: createDefaultProviderProfile('siliconflow', 'Qwen/Qwen3-8B'),
openrouter: createDefaultProviderProfile('openrouter', 'Qwen/Qwen3-8B'),
custom: createDefaultProviderProfile('custom', 'Qwen/Qwen3-8B'),
}
},
embeddingApi: {
provider: 'siliconflow', url: 'https://api.siliconflow.cn/v1', key: '', model: 'BAAI/bge-m3', modelCache: [],
providers: {
siliconflow: createDefaultProviderProfile('siliconflow', 'BAAI/bge-m3'),
custom: createDefaultProviderProfile('custom', 'BAAI/bge-m3'),
}
},
rerankApi: {
provider: 'siliconflow', url: 'https://api.siliconflow.cn/v1', key: '', model: 'BAAI/bge-reranker-v2-m3', modelCache: [],
providers: {
siliconflow: createDefaultProviderProfile('siliconflow', 'BAAI/bge-reranker-v2-m3'),
custom: createDefaultProviderProfile('custom', 'BAAI/bge-reranker-v2-m3'),
}
}
}
};
@@ -409,6 +478,7 @@ All checks passed. Beginning incremental extraction...
key: raw.l0Api?.key || sharedKey || base.l0Api.key,
model: raw.l0Api?.model || base.l0Api.model,
modelCache: Array.isArray(raw.l0Api?.modelCache) ? raw.l0Api.modelCache : [],
providers: normalizeProviderProfiles('l0', raw.l0Api || {}),
});
Object.assign(base.embeddingApi, {
provider: raw.embeddingApi?.provider || base.embeddingApi.provider,
@@ -416,6 +486,7 @@ All checks passed. Beginning incremental extraction...
key: raw.embeddingApi?.key || sharedKey || base.embeddingApi.key,
model: raw.embeddingApi?.model || legacyOnline.model || base.embeddingApi.model,
modelCache: Array.isArray(raw.embeddingApi?.modelCache) ? raw.embeddingApi.modelCache : [],
providers: normalizeProviderProfiles('embedding', raw.embeddingApi || {}),
});
Object.assign(base.rerankApi, {
provider: raw.rerankApi?.provider || base.rerankApi.provider,
@@ -423,6 +494,7 @@ All checks passed. Beginning incremental extraction...
key: raw.rerankApi?.key || sharedKey || base.rerankApi.key,
model: raw.rerankApi?.model || base.rerankApi.model,
modelCache: Array.isArray(raw.rerankApi?.modelCache) ? raw.rerankApi.modelCache : [],
providers: normalizeProviderProfiles('rerank', raw.rerankApi || {}),
});
}
@@ -503,35 +575,65 @@ All checks passed. Beginning incremental extraction...
// ═══════════════════════════════════════════════════════════════════════════
function getVectorApiConfig(prefix) {
return {
provider: $(`${prefix}-api-provider`)?.value || 'siliconflow',
const provider = $(`${prefix}-api-provider`)?.value || 'siliconflow';
const providers = normalizeProviderProfiles(prefix, config.vector?.[`${prefix}Api`] || {});
providers[provider] = {
url: $(`${prefix}-api-url`)?.value?.trim() || '',
key: $(`${prefix}-api-key`)?.value?.trim() || '',
model: $(`${prefix}-api-model-text`)?.value?.trim() || '',
modelCache: Array.isArray(config.vector?.[`${prefix}Api`]?.modelCache)
? [...config.vector[`${prefix}Api`].modelCache]
modelCache: Array.isArray(config.vector?.[`${prefix}Api`]?.providers?.[provider]?.modelCache)
? [...config.vector[`${prefix}Api`].providers[provider].modelCache]
: [],
};
return {
provider,
url: providers[provider]?.url || '',
key: providers[provider]?.key || '',
model: providers[provider]?.model || '',
modelCache: Array.isArray(providers[provider]?.modelCache) ? [...providers[provider].modelCache] : [],
providers,
};
}
function loadVectorApiConfig(prefix, cfg) {
const next = cfg || {};
$(`${prefix}-api-provider`).value = next.provider || 'siliconflow';
$(`${prefix}-api-url`).value = next.url || '';
$(`${prefix}-api-key`).value = next.key || '';
$(`${prefix}-api-model-text`).value = next.model || '';
const provider = next.provider || 'siliconflow';
const profiles = normalizeProviderProfiles(prefix, next);
const profile = profiles[provider] || createDefaultProviderProfile(provider, VECTOR_API_DEFAULT_MODELS[prefix]);
$(`${prefix}-api-provider`).value = provider;
$(`${prefix}-api-url`).value = profile.url || '';
$(`${prefix}-api-key`).value = profile.key || '';
$(`${prefix}-api-model-text`).value = profile.model || '';
const cache = Array.isArray(next.modelCache) ? next.modelCache : [];
const cache = Array.isArray(profile.modelCache) ? profile.modelCache : [];
setSelectOptions($(`${prefix}-api-model-select`), cache, '请选择');
$(`${prefix}-api-model-select`).value = cache.includes(next.model) ? next.model : '';
updateVectorProviderUI(prefix, next.provider || 'siliconflow');
$(`${prefix}-api-model-select`).value = cache.includes(profile.model) ? profile.model : '';
updateVectorProviderUI(prefix, provider);
}
function saveCurrentVectorApiProfile(prefix) {
const apiCfg = config.vector[`${prefix}Api`] ||= {};
const provider = $(`${prefix}-api-provider`)?.value || apiCfg.provider || 'siliconflow';
apiCfg.providers = normalizeProviderProfiles(prefix, apiCfg);
apiCfg.providers[provider] = {
url: $(`${prefix}-api-url`)?.value?.trim() || '',
key: $(`${prefix}-api-key`)?.value?.trim() || '',
model: $(`${prefix}-api-model-text`)?.value?.trim() || '',
modelCache: Array.isArray(apiCfg.providers?.[provider]?.modelCache) ? [...apiCfg.providers[provider].modelCache] : [],
};
apiCfg.provider = provider;
apiCfg.url = apiCfg.providers[provider].url;
apiCfg.key = apiCfg.providers[provider].key;
apiCfg.model = apiCfg.providers[provider].model;
apiCfg.modelCache = [...apiCfg.providers[provider].modelCache];
}
function updateVectorProviderUI(prefix, provider) {
const pv = VECTOR_PROVIDER_DEFAULTS[provider] || VECTOR_PROVIDER_DEFAULTS.custom;
const cache = Array.isArray(config.vector?.[`${prefix}Api`]?.modelCache)
? config.vector[`${prefix}Api`].modelCache
: [];
const apiCfg = config.vector?.[`${prefix}Api`] || {};
apiCfg.providers = normalizeProviderProfiles(prefix, apiCfg);
const profile = apiCfg.providers[provider] || createDefaultProviderProfile(provider, VECTOR_API_DEFAULT_MODELS[prefix]);
const cache = Array.isArray(profile.modelCache) ? profile.modelCache : [];
const hasModelCache = cache.length > 0;
$(`${prefix}-api-url-row`).classList.toggle('hidden', false);
@@ -546,15 +648,17 @@ All checks passed. Beginning incremental extraction...
if (provider === 'custom') {
urlInput.readOnly = false;
urlInput.placeholder = 'https://your-openai-compatible-api/v1';
urlInput.value = profile.url || '';
} else {
urlInput.value = pv.url || '';
urlInput.readOnly = true;
urlInput.placeholder = pv.url || '';
if (config.vector?.[`${prefix}Api`]) {
config.vector[`${prefix}Api`].url = pv.url || '';
}
}
}
$(`${prefix}-api-key`).value = profile.key || '';
$(`${prefix}-api-model-text`).value = profile.model || '';
setSelectOptions($(`${prefix}-api-model-select`), cache, '请选择');
$(`${prefix}-api-model-select`).value = cache.includes(profile.model) ? profile.model : '';
}
async function fetchVectorModels(prefix) {
@@ -591,8 +695,11 @@ All checks passed. Beginning incremental extraction...
if (!models) models = await tryFetch(`${baseUrl}/models`);
if (!models?.length) throw new Error('未获取到模型列表');
config.vector[`${prefix}Api`].modelCache = [...new Set(models)];
setSelectOptions($(`${prefix}-api-model-select`), config.vector[`${prefix}Api`].modelCache, '请选择');
const apiCfg = config.vector[`${prefix}Api`] ||= {};
apiCfg.providers = normalizeProviderProfiles(prefix, apiCfg);
apiCfg.providers[provider] ||= createDefaultProviderProfile(provider, VECTOR_API_DEFAULT_MODELS[prefix]);
apiCfg.providers[provider].modelCache = [...new Set(models)];
setSelectOptions($(`${prefix}-api-model-select`), apiCfg.providers[provider].modelCache, '请选择');
$(`${prefix}-api-model-select-row`).classList.remove('hidden');
if (!$(`${prefix}-api-model-text`).value.trim()) {
$(`${prefix}-api-model-text`).value = models[0];
@@ -821,18 +928,11 @@ All checks passed. Beginning incremental extraction...
['l0', 'embedding', 'rerank'].forEach(prefix => {
$(`${prefix}-api-provider`).onchange = e => {
const oldProvider = config.vector[`${prefix}Api`]?.provider || 'siliconflow';
const pv = VECTOR_PROVIDER_DEFAULTS[e.target.value] || VECTOR_PROVIDER_DEFAULTS.custom;
const target = config.vector[`${prefix}Api`] ||= { modelCache: [] };
if (e.target.value === 'custom') {
if (target.url === (VECTOR_PROVIDER_DEFAULTS[oldProvider]?.url || '')) {
target.url = '';
}
} else {
target.url = pv.url || '';
}
saveCurrentVectorApiProfile(prefix);
const target = config.vector[`${prefix}Api`] ||= {};
target.providers = normalizeProviderProfiles(prefix, target);
target.provider = e.target.value;
if (!pv.canFetch) target.modelCache = [];
target.providers[e.target.value] ||= createDefaultProviderProfile(e.target.value, VECTOR_API_DEFAULT_MODELS[prefix]);
updateVectorProviderUI(prefix, e.target.value);
};