diff --git a/scripts/package-kylin-arm64-deb.sh b/scripts/package-kylin-arm64-deb.sh index 4c96cf0..a230421 100755 --- a/scripts/package-kylin-arm64-deb.sh +++ b/scripts/package-kylin-arm64-deb.sh @@ -29,7 +29,7 @@ fi # 的解析逻辑保持一致,确保三处版本号(deb 文件名、界面显示、控制文件)永远一致。 VERSION=$(git describe --tags --abbrev=0 2>/dev/null | sed 's/^v//') || true if [ -z "$VERSION" ] && [ -f .app-version ]; then - VERSION=$(cat .app-version | tr -d '[:space:]') + VERSION=$(cat .app-version | tr -d '[:space:]' | sed 's/^v//') fi if [ -z "$VERSION" ]; then VERSION=$(node -p "require('./package.json').version") diff --git a/src/main/config.ts b/src/main/config.ts index c331c24..a6b3d76 100644 --- a/src/main/config.ts +++ b/src/main/config.ts @@ -2,11 +2,14 @@ import { app } from 'electron' import { join } from 'path' import { existsSync, readFileSync, writeFileSync } from 'fs' +// 推理请求统一走 er_backend 代理(管理面端口,/v1/* 由后端转发到其实际管理的 llama-server) +export const ER_BACKEND_URL = 'http://127.0.0.1:17700' + export interface AppConfig { embed: { provider: 'local' | 'llamacpp' localModelPath: string - baseUrl: string // 由 applyPlatformOverrides 自动推导,不对用户暴露 + baseUrl: string // 由 applyPlatformOverrides 固定为 er_backend 代理地址,不对用户暴露 } rag: { chunkSize: number @@ -14,6 +17,7 @@ export interface AppConfig { topK: number systemPrompt: string } + // 服务的启动参数/端口由 er_backend 统一管理,以下字段仅为历史配置保留,前端不再用于路由 llamacppServer: { executablePath: string modelPath: string @@ -60,7 +64,7 @@ export const DEFAULT_CONFIG: AppConfig = { embed: { provider: 'llamacpp', localModelPath: '', - baseUrl: 'http://127.0.0.1:17701' + baseUrl: ER_BACKEND_URL }, llamacppServer: { executablePath: '', @@ -206,19 +210,18 @@ export function getConfig(): AppConfig { } // 按计算卡型号覆盖 embed provider 和默认启动参数 +// 推理请求统一走 er_backend 代理(ER_BACKEND_URL),服务端口以后端配置为准,前端不再维护 function applyPlatformOverrides(config: AppConfig): void { const card = config.hardware.cardType if (card === 'er25') { // ER25:嵌入固定本地 CPU,无嵌入服务进程 config.embed.provider = 'local' - config.llamacppServer.port = 8080 if (!config.llamacppServer.extraArgs.trim()) { config.llamacppServer.extraArgs = '--port 8080 --ctk bf16 --ctv bf16 --no-warmup -ub 128' } } else { // ER160:嵌入默认 llamacpp NPU(local 保持不变) if (config.embed.provider !== 'local') config.embed.provider = 'llamacpp' - config.llamacppServer.port = 8081 if (!config.llamacppServer.extraArgs.trim()) { config.llamacppServer.extraArgs = '--port 8081 --presence_penalty 1.5' } @@ -226,8 +229,8 @@ function applyPlatformOverrides(config: AppConfig): void { config.llamacppEmbed.extraArgs = DEFAULT_CONFIG.llamacppEmbed.extraArgs } } - // 嵌入服务地址跟随端口 - config.embed.baseUrl = `http://127.0.0.1:${config.llamacppEmbed.port}` + // 嵌入/生成服务地址固定为 er_backend 代理 + config.embed.baseUrl = ER_BACKEND_URL } export function saveConfig(config: AppConfig): void { diff --git a/src/main/ipc/erBackendHandler.ts b/src/main/ipc/erBackendHandler.ts index 69c4360..d85ff28 100644 --- a/src/main/ipc/erBackendHandler.ts +++ b/src/main/ipc/erBackendHandler.ts @@ -1,7 +1,6 @@ import { ipcMain } from 'electron' import { execFile } from 'child_process' - -const ER_BACKEND_URL = 'http://localhost:17700' +import { ER_BACKEND_URL } from '../config' async function isRunning(): Promise { try { diff --git a/src/main/ipc/queryHandler.ts b/src/main/ipc/queryHandler.ts index 6d93a55..d8ee487 100644 --- a/src/main/ipc/queryHandler.ts +++ b/src/main/ipc/queryHandler.ts @@ -16,7 +16,7 @@ export function registerQueryHandlers(getWin: () => BrowserWindow | null): void console.log(`\n${'='.repeat(60)}`) console.log('[query] 问题:', payload.question) console.log('[query] topK:', payload.topK) - console.log('[query] 向量化方式:', config.embed.provider, '生成服务端口:', config.llamacppServer.port) + console.log('[query] 向量化方式:', config.embed.provider, '生成/嵌入服务:er_backend 代理(127.0.0.1:17700)') const send = (channel: string, data: unknown): void => { getWin()?.webContents.send(channel, data) @@ -50,7 +50,6 @@ export function registerQueryHandlers(getWin: () => BrowserWindow | null): void payload.question, chunks, payload.systemPrompt, - config.llamacppServer, { onDelta: (delta) => send('query:delta', { delta }), onDone: (stats) => send('query:done', { stats: stats ?? null }), diff --git a/src/main/ipc/statusHandler.ts b/src/main/ipc/statusHandler.ts index ebae3c7..805032d 100644 --- a/src/main/ipc/statusHandler.ts +++ b/src/main/ipc/statusHandler.ts @@ -2,7 +2,7 @@ import { ipcMain, dialog } from 'electron' import type { BrowserWindow } from 'electron' import { existsSync, readFileSync, writeFileSync } from 'fs' import { join } from 'path' -import { getConfig, saveConfig, getDbPath, AppConfig } from '../config' +import { getConfig, saveConfig, getDbPath, AppConfig, ER_BACKEND_URL } from '../config' import { getDocCount } from '../db/lancedb' import { embedOneLocal, resolveLocalModelPath } from '../rag/localEmbedder' import { syncNpuPolling } from './npuHandler' @@ -100,11 +100,12 @@ export function registerStatusHandlers(getWin: () => BrowserWindow | null): void } }) - ipcMain.handle('chat-test', async (_event, llamacppConfig: AppConfig['llamacppServer']): Promise => { + // 生成服务连接测试(经 er_backend 代理转发到 llama-server) + ipcMain.handle('chat-test', async (_event, _llamacppConfig: AppConfig['llamacppServer']): Promise => { const start = Date.now() const elapsed = (): string => `${Date.now() - start}ms` try { - const res = await fetch(`http://127.0.0.1:${llamacppConfig.port}/v1/chat/completions`, { + const res = await fetch(`${ER_BACKEND_URL}/v1/chat/completions`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ diff --git a/src/main/rag/generator.ts b/src/main/rag/generator.ts index 0adf92a..c8e4a6a 100644 --- a/src/main/rag/generator.ts +++ b/src/main/rag/generator.ts @@ -1,5 +1,5 @@ import type { SearchResult } from '../db/lancedb' -import type { AppConfig } from '../config' +import { ER_BACKEND_URL } from '../config' export interface GeneratorStats { tokensPerSecond: number @@ -14,12 +14,11 @@ export interface GeneratorCallbacks { onError: (message: string) => void } -// 生成服务固定使用 llamacpp(ER160/ER25 均通过 er_backend 管理的 llama-server) +// 生成服务经 er_backend 代理访问其管理的 llama-server(OpenAI 兼容接口,SSE 流式) export async function streamGenerate( question: string, chunks: SearchResult[], systemPrompt: string, - llamacppConfig: AppConfig['llamacppServer'], callbacks: GeneratorCallbacks ): Promise { const context = chunks @@ -33,22 +32,21 @@ ${context} 请回答以下问题:${question}` console.log('\n[generator] ---- 发送给 LLM 的完整消息 ----') - console.log(`[generator] 服务地址:http://127.0.0.1:${llamacppConfig.port}`) + console.log(`[generator] 服务地址:${ER_BACKEND_URL}(er_backend 代理)`) console.log('[generator] system prompt:\n', systemPrompt) console.log('[generator] user message:\n', userMessage) console.log('[generator] ---- 消息结束 ----\n') - await streamGenerateLlamaCpp(userMessage, systemPrompt, llamacppConfig, callbacks) + await streamGenerateLlamaCpp(userMessage, systemPrompt, callbacks) } // llama.cpp server OpenAI 兼容接口(/v1/chat/completions),SSE 格式 async function streamGenerateLlamaCpp( userMessage: string, systemPrompt: string, - llamacppConfig: AppConfig['llamacppServer'], callbacks: GeneratorCallbacks ): Promise { - const baseUrl = `http://127.0.0.1:${llamacppConfig.port}` + const baseUrl = ER_BACKEND_URL let fullResponse = '' let thinkOpen = false const requestSentTime = Date.now() @@ -71,12 +69,12 @@ async function streamGenerateLlamaCpp( }) }) } catch (e) { - callbacks.onError(`无法连接 llama.cpp server(${baseUrl}):${String(e)}`) + callbacks.onError(`无法连接生成服务(${baseUrl},er_backend 代理):${String(e)}`) return } if (!response.ok) { - callbacks.onError(`llama.cpp server 请求失败:${response.status}`) + callbacks.onError(`生成服务请求失败:${response.status}`) return }