基于 Electron + Vue3 + TypeScript + LanceDB 的本地化 RAG 问答桌面应用。 仅支持 Linux(Kylin V10 / Ubuntu),适配 ER160(揽月 M50 NPU)和 ER25(芯动力 RPP)计算卡。 服务进程管理委托给 er_backend(HTTP 17700),前端专注 RAG 逻辑与用户交互。 包含: - src/elec_rag_ui 前端工程(Electron + Vue3) - models/ 本地嵌入模型(bge-small/base/large,ASR,标点恢复,onnx 文件由 Git LFS 管理) - docs/ 示例文档(用于测试索引与问答)
96 lines
3.6 KiB
TypeScript
96 lines
3.6 KiB
TypeScript
import { contextBridge, ipcRenderer } from 'electron'
|
||
|
||
console.log('[preload] 正在注册 electronAPI...')
|
||
|
||
contextBridge.exposeInMainWorld('electronAPI', {
|
||
// 文件选择
|
||
selectFiles: (): Promise<string[]> =>
|
||
ipcRenderer.invoke('select-files'),
|
||
selectDirectory: (): Promise<string | null> =>
|
||
ipcRenderer.invoke('select-directory'),
|
||
|
||
// 入库
|
||
indexDocuments: (payload: { paths: string[]; mode: 'append' | 'rebuild' }): Promise<void> =>
|
||
ipcRenderer.invoke('index-documents', payload),
|
||
|
||
// 查询
|
||
query: (payload: { question: string; systemPrompt: string; topK: number }): Promise<void> =>
|
||
ipcRenderer.invoke('query', payload),
|
||
|
||
// 状态 & 配置
|
||
getDbStatus: (): Promise<{ count: number; ready: boolean }> =>
|
||
ipcRenderer.invoke('get-db-status'),
|
||
getConfig: () => ipcRenderer.invoke('get-config'),
|
||
saveConfig: (config: unknown) => ipcRenderer.invoke('save-config', config),
|
||
testEmbedConnection: (embedConfig: unknown): Promise<{ ok: boolean; message: string }> =>
|
||
ipcRenderer.invoke('embed-test', embedConfig),
|
||
testChatConnection: (chatConfig: unknown): Promise<{ ok: boolean; message: string }> =>
|
||
ipcRenderer.invoke('chat-test', chatConfig),
|
||
|
||
// 本地嵌入模型
|
||
selectModelDir: (): Promise<string | null> =>
|
||
ipcRenderer.invoke('select-model-dir'),
|
||
checkModelPath: (dirPath: string): Promise<boolean> =>
|
||
ipcRenderer.invoke('check-model-path', dirPath),
|
||
|
||
// 退出程序
|
||
quitApp: (): Promise<void> =>
|
||
ipcRenderer.invoke('quit-app'),
|
||
|
||
// 批量问题导入导出
|
||
importBatchQuestions: (): Promise<string[] | null> =>
|
||
ipcRenderer.invoke('batch:import'),
|
||
exportBatchQuestions: (questions: string[]): Promise<boolean> =>
|
||
ipcRenderer.invoke('batch:export', questions),
|
||
|
||
// 硬件探测
|
||
hardwareGetDetected: (): Promise<'er160' | 'er25' | 'none' | null> =>
|
||
ipcRenderer.invoke('hardware:get-detected'),
|
||
|
||
// 平台信息
|
||
platform: process.platform,
|
||
|
||
// 语音输入(ASR)
|
||
asrSelectModelDir: (): Promise<string | null> =>
|
||
ipcRenderer.invoke('asr:select-model-dir'),
|
||
asrSelectExecutable: (): Promise<string | null> =>
|
||
ipcRenderer.invoke('asr:select-executable'),
|
||
asrCheckModelDir: (dirPath: string): Promise<boolean> =>
|
||
ipcRenderer.invoke('asr:check-model-dir', dirPath),
|
||
asrInitModel: (): Promise<boolean> =>
|
||
ipcRenderer.invoke('asr:init-model'),
|
||
asrStartStream: (): Promise<boolean> =>
|
||
ipcRenderer.invoke('asr:start-stream'),
|
||
asrFeedChunk: (samples: number[]): Promise<boolean> =>
|
||
ipcRenderer.invoke('asr:feed-chunk', samples),
|
||
asrStopStream: (): Promise<string> =>
|
||
ipcRenderer.invoke('asr:stop-stream'),
|
||
asrUnloadModel: (): Promise<boolean> =>
|
||
ipcRenderer.invoke('asr:unload-model'),
|
||
|
||
// 语音输出(系统 TTS 兜底)
|
||
ttsAvailable: (): Promise<boolean> =>
|
||
ipcRenderer.invoke('tts:available'),
|
||
ttsConfigure: (options: unknown): Promise<boolean> =>
|
||
ipcRenderer.invoke('tts:configure', options),
|
||
ttsSpeak: (text: string): Promise<boolean> =>
|
||
ipcRenderer.invoke('tts:speak', text),
|
||
ttsStop: (): Promise<boolean> =>
|
||
ipcRenderer.invoke('tts:stop'),
|
||
|
||
// er-backend 管理服务(Linux NPU)
|
||
erBackendEnsure: (): Promise<{ ok: boolean; message: string }> =>
|
||
ipcRenderer.invoke('er-backend:ensure'),
|
||
erBackendStatus: (): Promise<unknown> =>
|
||
ipcRenderer.invoke('er-backend:status'),
|
||
|
||
// 事件监听(ASR/TTS 推送事件)
|
||
on: (channel: string, callback: (...args: unknown[]) => void) => {
|
||
ipcRenderer.removeAllListeners(channel)
|
||
ipcRenderer.on(channel, (_event, ...args) => callback(...args))
|
||
},
|
||
off: (channel: string) => {
|
||
ipcRenderer.removeAllListeners(channel)
|
||
}
|
||
})
|