fix(story-summary): unify vector api test actions
This commit is contained in:
@@ -916,16 +916,6 @@ All checks passed. Beginning incremental extraction...
|
||||
$('vector-config-area').classList.toggle('hidden', !e.target.checked);
|
||||
};
|
||||
|
||||
$('btn-test-vector-api').onclick = () => {
|
||||
$('btn-test-vector-api').disabled = true;
|
||||
setStatusText($('embedding-api-connect-status'), '测试中...', 'loading');
|
||||
saveConfig(); // 先保存新 Key 到 localStorage
|
||||
postMsg('VECTOR_TEST_ONLINE', {
|
||||
provider: getVectorConfig().embeddingApi.provider,
|
||||
config: getVectorConfig().embeddingApi
|
||||
});
|
||||
};
|
||||
|
||||
['l0', 'embedding', 'rerank'].forEach(prefix => {
|
||||
$(`${prefix}-api-provider`).onchange = e => {
|
||||
saveCurrentVectorApiProfile(prefix);
|
||||
@@ -941,6 +931,18 @@ All checks passed. Beginning incremental extraction...
|
||||
};
|
||||
|
||||
$(`${prefix}-btn-connect`).onclick = () => fetchVectorModels(prefix);
|
||||
$(`${prefix}-btn-test`).onclick = () => {
|
||||
const btn = $(`${prefix}-btn-test`);
|
||||
if (btn) btn.disabled = true;
|
||||
setStatusText($(`${prefix}-api-connect-status`), '测试中...', 'loading');
|
||||
saveConfig();
|
||||
const cfg = getVectorConfig();
|
||||
postMsg('VECTOR_TEST_ONLINE', {
|
||||
target: prefix,
|
||||
provider: cfg[`${prefix}Api`].provider,
|
||||
config: cfg[`${prefix}Api`],
|
||||
});
|
||||
};
|
||||
});
|
||||
|
||||
$('btn-add-filter-rule').onclick = addFilterRule;
|
||||
@@ -987,11 +989,12 @@ All checks passed. Beginning incremental extraction...
|
||||
postMsg('REQUEST_ANCHOR_STATS');
|
||||
}
|
||||
|
||||
function updateVectorOnlineStatus(status, message) {
|
||||
const btn = $('btn-test-vector-api');
|
||||
function updateVectorOnlineStatus(target, status, message) {
|
||||
const prefix = target || 'embedding';
|
||||
const btn = $(`${prefix}-btn-test`);
|
||||
if (btn) btn.disabled = false;
|
||||
setStatusText(
|
||||
$('embedding-api-connect-status'),
|
||||
$(`${prefix}-api-connect-status`),
|
||||
message || '',
|
||||
status === 'error' ? 'error' : status === 'success' ? 'success' : 'loading'
|
||||
);
|
||||
@@ -2099,7 +2102,7 @@ All checks passed. Beginning incremental extraction...
|
||||
break;
|
||||
|
||||
case 'VECTOR_ONLINE_STATUS':
|
||||
updateVectorOnlineStatus(d.status, d.message);
|
||||
updateVectorOnlineStatus(d.target, d.status, d.message);
|
||||
break;
|
||||
|
||||
case 'VECTOR_STATS':
|
||||
|
||||
@@ -472,6 +472,7 @@
|
||||
</div>
|
||||
<div class="settings-btn-row" id="l0-api-connect-row" style="margin-bottom:8px;">
|
||||
<button class="btn btn-sm" id="l0-btn-connect" style="flex:1">连接 / 拉取模型列表</button>
|
||||
<button class="btn btn-sm" id="l0-btn-test" style="flex:1">测试</button>
|
||||
</div>
|
||||
<div class="settings-hint" id="l0-api-connect-status" style="margin-bottom:16px;"></div>
|
||||
</div>
|
||||
@@ -520,7 +521,7 @@
|
||||
</div>
|
||||
<div class="settings-btn-row" id="embedding-api-connect-row" style="margin-bottom:8px;">
|
||||
<button class="btn btn-sm" id="embedding-btn-connect" style="flex:1">连接 / 拉取模型列表</button>
|
||||
<button class="btn btn-sm" id="btn-test-vector-api" style="flex:1">测试 Embedding</button>
|
||||
<button class="btn btn-sm" id="embedding-btn-test" style="flex:1">测试</button>
|
||||
</div>
|
||||
<div class="settings-hint" id="embedding-api-connect-status" style="margin-bottom:16px;"></div>
|
||||
</div>
|
||||
@@ -569,6 +570,7 @@
|
||||
</div>
|
||||
<div class="settings-btn-row" id="rerank-api-connect-row">
|
||||
<button class="btn btn-sm" id="rerank-btn-connect" style="flex:1">连接 / 拉取模型列表</button>
|
||||
<button class="btn btn-sm" id="rerank-btn-test" style="flex:1">测试</button>
|
||||
</div>
|
||||
<div class="settings-hint" id="rerank-api-connect-status"></div>
|
||||
</div>
|
||||
|
||||
@@ -43,6 +43,8 @@ import { runSummaryGeneration } from "./generate/generator.js";
|
||||
|
||||
// vector service
|
||||
import { embed, getEngineFingerprint, testOnlineService } from "./vector/utils/embedder.js";
|
||||
import { testL0Service } from "./vector/llm/llm-service.js";
|
||||
import { testRerankService } from "./vector/llm/reranker.js";
|
||||
|
||||
// tokenizer
|
||||
import { preload as preloadTokenizer, injectEntities, isReady as isTokenizerReady } from "./vector/utils/tokenizer.js";
|
||||
@@ -421,17 +423,23 @@ function handleAnchorCancel() {
|
||||
postToFrame({ type: "ANCHOR_GEN_PROGRESS", current: -1, total: 0 });
|
||||
}
|
||||
|
||||
async function handleTestOnlineService(provider, config) {
|
||||
async function handleTestOnlineService(provider, config, target = "embedding") {
|
||||
try {
|
||||
postToFrame({ type: "VECTOR_ONLINE_STATUS", status: "downloading", message: "连接中..." });
|
||||
const result = await testOnlineService(provider, config);
|
||||
postToFrame({ type: "VECTOR_ONLINE_STATUS", target, status: "downloading", message: "连接中..." });
|
||||
let result;
|
||||
if (target === "l0") result = await testL0Service(config);
|
||||
else if (target === "rerank") result = await testRerankService(config);
|
||||
else result = await testOnlineService(provider, config);
|
||||
postToFrame({
|
||||
type: "VECTOR_ONLINE_STATUS",
|
||||
target,
|
||||
status: "success",
|
||||
message: `连接成功 (${result.dims}维)`,
|
||||
message: target === "embedding"
|
||||
? `连接成功 (${result.dims}维)`
|
||||
: (result.message || "连接成功"),
|
||||
});
|
||||
} catch (e) {
|
||||
postToFrame({ type: "VECTOR_ONLINE_STATUS", status: "error", message: e.message });
|
||||
postToFrame({ type: "VECTOR_ONLINE_STATUS", target, status: "error", message: e.message });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1631,7 +1639,7 @@ async function handleFrameMessage(event) {
|
||||
break;
|
||||
|
||||
case "VECTOR_TEST_ONLINE":
|
||||
handleTestOnlineService(data.provider, data.config);
|
||||
handleTestOnlineService(data.provider, data.config, data.target || "embedding");
|
||||
break;
|
||||
|
||||
case "VECTOR_GENERATE":
|
||||
|
||||
@@ -39,6 +39,17 @@ function getL0ApiConfig() {
|
||||
};
|
||||
}
|
||||
|
||||
function normalizeL0ApiConfig(apiConfig = null) {
|
||||
const fallback = getL0ApiConfig();
|
||||
const next = apiConfig || {};
|
||||
return {
|
||||
provider: String(next.provider || fallback.provider || 'siliconflow').trim(),
|
||||
url: String(next.url || fallback.url || DEFAULT_L0_API_URL).trim(),
|
||||
key: String(next.key || fallback.key || '').trim(),
|
||||
model: String(next.model || fallback.model || DEFAULT_L0_MODEL).trim(),
|
||||
};
|
||||
}
|
||||
|
||||
function getNextKey(rawKey) {
|
||||
const keys = String(rawKey || '')
|
||||
.split(/[,;|\n]+/)
|
||||
@@ -60,12 +71,13 @@ export async function callLLM(messages, options = {}) {
|
||||
temperature = 0.2,
|
||||
max_tokens = 500,
|
||||
timeout = 40000,
|
||||
apiConfig = null,
|
||||
} = options;
|
||||
|
||||
const mod = getStreamingModule();
|
||||
if (!mod) throw new Error('Streaming module not ready');
|
||||
|
||||
const apiCfg = getL0ApiConfig();
|
||||
const apiCfg = normalizeL0ApiConfig(apiConfig);
|
||||
const apiKey = getNextKey(apiCfg.key);
|
||||
if (!apiKey) {
|
||||
throw new Error('L0 requires siliconflow API key');
|
||||
@@ -111,6 +123,24 @@ export async function callLLM(messages, options = {}) {
|
||||
}
|
||||
}
|
||||
|
||||
export async function testL0Service(apiConfig = {}) {
|
||||
if (!apiConfig?.key) {
|
||||
throw new Error('请配置 L0 API Key');
|
||||
}
|
||||
const result = await callLLM([
|
||||
{ role: 'system', content: '你是一个测试助手。请只输出 OK。' },
|
||||
{ role: 'user', content: '只输出 OK' },
|
||||
], {
|
||||
apiConfig,
|
||||
temperature: 0,
|
||||
max_tokens: 16,
|
||||
timeout: 15000,
|
||||
});
|
||||
const text = String(result || '').trim();
|
||||
if (!text) throw new Error('返回为空');
|
||||
return { success: true, message: `连接成功:${text.slice(0, 60)}` };
|
||||
}
|
||||
|
||||
export function cancelAllL0Requests() {
|
||||
const mod = getStreamingModule();
|
||||
if (!mod?.cancel) return;
|
||||
|
||||
@@ -273,19 +273,51 @@ export async function rerankChunks(query, chunks, options = {}) {
|
||||
/**
|
||||
* 测试 Rerank 服务连接
|
||||
*/
|
||||
export async function testRerankService() {
|
||||
const key = getApiKey();
|
||||
if (!key) {
|
||||
throw new Error('请配置硅基 API Key');
|
||||
export async function testRerankService(apiConfig = {}) {
|
||||
const next = {
|
||||
provider: String(apiConfig.provider || 'siliconflow').trim(),
|
||||
url: String(apiConfig.url || DEFAULT_RERANK_URL).trim(),
|
||||
key: String(apiConfig.key || '').trim(),
|
||||
model: String(apiConfig.model || RERANK_MODEL).trim(),
|
||||
};
|
||||
if (!next.key) {
|
||||
throw new Error('请配置 Rerank API Key');
|
||||
}
|
||||
|
||||
const key = getNextRerankKey(next.key);
|
||||
const controller = new AbortController();
|
||||
const timeoutId = setTimeout(() => controller.abort(), 15000);
|
||||
try {
|
||||
const { results } = await rerank('测试查询', ['测试文档1', '测试文档2'], { topN: 2 });
|
||||
return {
|
||||
success: true,
|
||||
message: `连接成功,返回 ${results.length} 个结果`,
|
||||
const baseUrl = String(next.url || DEFAULT_RERANK_URL).replace(/\/+$/, '');
|
||||
const response = await fetch(`${baseUrl}/rerank`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${key}`,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
model: next.model,
|
||||
query: '测试查询',
|
||||
documents: ['测试文档1', '测试文档2'],
|
||||
top_n: 2,
|
||||
return_documents: false,
|
||||
}),
|
||||
signal: controller.signal,
|
||||
});
|
||||
clearTimeout(timeoutId);
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text().catch(() => '');
|
||||
throw new Error(`Rerank API ${response.status}: ${errorText.slice(0, 200)}`);
|
||||
}
|
||||
const data = await response.json();
|
||||
const results = Array.isArray(data.results) ? data.results : [];
|
||||
return {
|
||||
success: true,
|
||||
message: `连接成功:返回 ${results.length} 个结果`,
|
||||
};
|
||||
} catch (e) {
|
||||
throw new Error(`连接失败: ${e.message}`);
|
||||
} finally {
|
||||
clearTimeout(timeoutId);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user