85 lines
2.8 KiB
JavaScript
85 lines
2.8 KiB
JavaScript
// ═══════════════════════════════════════════════════════════════════════════
|
||
// vector/llm/llm-service.js
|
||
// ═══════════════════════════════════════════════════════════════════════════
|
||
import { xbLog } from '../../../../core/debug-core.js';
|
||
import { getVectorConfig } from '../../data/config.js';
|
||
|
||
const MODULE_ID = 'vector-llm-service';
|
||
const SILICONFLOW_API_URL = 'https://api.siliconflow.cn';
|
||
const DEFAULT_L0_MODEL = 'Qwen/Qwen3-8B';
|
||
|
||
// 唯一 ID 计数器
|
||
let callCounter = 0;
|
||
|
||
function getStreamingModule() {
|
||
const mod = window.xiaobaixStreamingGeneration;
|
||
return mod?.xbgenrawCommand ? mod : null;
|
||
}
|
||
|
||
function generateUniqueId(prefix = 'llm') {
|
||
callCounter = (callCounter + 1) % 100000;
|
||
return `${prefix}-${callCounter}-${Date.now().toString(36)}`;
|
||
}
|
||
|
||
function b64UrlEncode(str) {
|
||
const utf8 = new TextEncoder().encode(String(str));
|
||
let bin = '';
|
||
utf8.forEach(b => bin += String.fromCharCode(b));
|
||
return btoa(bin).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
|
||
}
|
||
|
||
/**
|
||
* 统一LLM调用 - 走酒馆后端(非流式)
|
||
*/
|
||
export async function callLLM(messages, options = {}) {
|
||
const {
|
||
temperature = 0.2,
|
||
max_tokens = 500,
|
||
} = options;
|
||
|
||
const mod = getStreamingModule();
|
||
if (!mod) throw new Error('Streaming module not ready');
|
||
|
||
const cfg = getVectorConfig();
|
||
const apiKey = cfg?.online?.key || '';
|
||
if (!apiKey) {
|
||
throw new Error('L0 requires siliconflow API key');
|
||
}
|
||
|
||
const top64 = b64UrlEncode(JSON.stringify(messages));
|
||
|
||
// 每次调用用唯一 ID,避免 session 冲突
|
||
const uniqueId = generateUniqueId('l0');
|
||
|
||
const args = {
|
||
as: 'user',
|
||
nonstream: 'true',
|
||
top64,
|
||
id: uniqueId,
|
||
temperature: String(temperature),
|
||
max_tokens: String(max_tokens),
|
||
api: 'openai',
|
||
apiurl: SILICONFLOW_API_URL,
|
||
apipassword: apiKey,
|
||
model: DEFAULT_L0_MODEL,
|
||
};
|
||
|
||
try {
|
||
// 非流式直接返回结果
|
||
const result = await mod.xbgenrawCommand(args, '');
|
||
return String(result ?? '');
|
||
} catch (e) {
|
||
xbLog.error(MODULE_ID, 'LLM调用失败', e);
|
||
throw e;
|
||
}
|
||
}
|
||
|
||
export function parseJson(text) {
|
||
if (!text) return null;
|
||
let s = text.trim().replace(/^```(?:json)?\s*/i, '').replace(/\s*```$/i, '').trim();
|
||
try { return JSON.parse(s); } catch { }
|
||
const i = s.indexOf('{'), j = s.lastIndexOf('}');
|
||
if (i !== -1 && j > i) try { return JSON.parse(s.slice(i, j + 1)); } catch { }
|
||
return null;
|
||
}
|