- 嵌入/生成服务地址不再由前端按 cardType 推导端口,改为经 er_backend 的 /v1/* 代理转发,服务端口以后端配置为唯一真相来源 - config.ts: 新增 ER_BACKEND_URL 统一常量,删除端口推导逻辑 - generator/statusHandler/queryHandler/erBackendHandler 跟随改造 - fix: package-kylin-arm64-deb.sh 从 .app-version 读版本号时剥离 v 前缀, 修复无 git 环境下 dpkg-deb 报"版本号没有以数字开头"
64 lines
2.2 KiB
TypeScript
64 lines
2.2 KiB
TypeScript
import { ipcMain, BrowserWindow } from 'electron'
|
||
import { getConfig, getDbPath } from '../config'
|
||
import { embedOne } from '../rag/embedder'
|
||
import { search } from '../db/lancedb'
|
||
import { streamGenerate } from '../rag/generator'
|
||
|
||
export function registerQueryHandlers(getWin: () => BrowserWindow | null): void {
|
||
ipcMain.handle('query', async (_event, payload: {
|
||
question: string
|
||
systemPrompt: string
|
||
topK: number
|
||
}) => {
|
||
const config = getConfig()
|
||
const dbPath = getDbPath()
|
||
|
||
console.log(`\n${'='.repeat(60)}`)
|
||
console.log('[query] 问题:', payload.question)
|
||
console.log('[query] topK:', payload.topK)
|
||
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)
|
||
}
|
||
|
||
try {
|
||
// 1. 问题向量化
|
||
send('query:stage', { stage: '正在向量化...' })
|
||
const queryVector = await embedOne(payload.question, config.embed)
|
||
console.log('[query] 问题向量化完成,维度:', queryVector.length)
|
||
|
||
// 2. 向量检索
|
||
send('query:stage', { stage: '正在检索...' })
|
||
const chunks = await search(dbPath, queryVector, payload.topK)
|
||
console.log(`[query] 检索到 ${chunks.length} 个片段:`)
|
||
chunks.forEach((c, i) => {
|
||
console.log(` 片段${i + 1} 相关度=${c.score} 来源=${c.source}`)
|
||
console.log(` 内容前100字:${c.content.slice(0, 100).replace(/\n/g, ' ')}`)
|
||
})
|
||
send('query:context', { chunks })
|
||
send('query:stage', { stage: '正在生成...' })
|
||
|
||
if (chunks.length === 0) {
|
||
send('query:delta', { delta: '我不知道。' })
|
||
send('query:done', {})
|
||
return
|
||
}
|
||
|
||
// 3. 流式生成
|
||
await streamGenerate(
|
||
payload.question,
|
||
chunks,
|
||
payload.systemPrompt,
|
||
{
|
||
onDelta: (delta) => send('query:delta', { delta }),
|
||
onDone: (stats) => send('query:done', { stats: stats ?? null }),
|
||
onError: (message) => send('query:error', { message })
|
||
}
|
||
)
|
||
} catch (e) {
|
||
send('query:error', { message: String(e) })
|
||
}
|
||
})
|
||
}
|