fix: complete HoloLake Agent and Forgejo desktop runtime
This commit is contained in:
parent
28f68fa9ac
commit
46bdd0ca73
15 changed files with 1217 additions and 638 deletions
|
|
@ -13,9 +13,10 @@
|
|||
* └── 数据存储:~/Library/Application Support/HoloLake Era/data/
|
||||
*/
|
||||
|
||||
import { app, BrowserWindow, shell, dialog } from 'electron';
|
||||
import { app, BrowserWindow, shell, dialog, ipcMain, safeStorage } from 'electron';
|
||||
import path from 'path';
|
||||
import { spawn, ChildProcess } from 'child_process';
|
||||
import fs from 'fs';
|
||||
|
||||
// ─── 配置 ───
|
||||
|
||||
|
|
@ -26,6 +27,31 @@ const CLIENT_PORT = 5180;
|
|||
// 数据目录:macOS 标准位置
|
||||
const DATA_DIR = path.join(app.getPath('userData'), 'data');
|
||||
const KB_REPO_PATH = path.join(DATA_DIR, 'knowledge-base');
|
||||
const MODEL_CONFIG_PATH = path.join(app.getPath('userData'), 'model-config.json');
|
||||
|
||||
interface ModelConfigFile {
|
||||
baseUrl: string;
|
||||
model: string;
|
||||
encryptedKey?: string;
|
||||
}
|
||||
|
||||
function readModelConfig(): ModelConfigFile {
|
||||
try {
|
||||
return JSON.parse(fs.readFileSync(MODEL_CONFIG_PATH, 'utf8')) as ModelConfigFile;
|
||||
} catch {
|
||||
return { baseUrl: 'https://api.openai.com/v1', model: 'gpt-4o' };
|
||||
}
|
||||
}
|
||||
|
||||
function applyModelConfig(): ModelConfigFile {
|
||||
const config = readModelConfig();
|
||||
process.env.HOLOLAKE_LLM_BASE = config.baseUrl;
|
||||
process.env.HOLOLAKE_LLM_MODEL = config.model;
|
||||
if (config.encryptedKey && safeStorage.isEncryptionAvailable()) {
|
||||
process.env.HOLOLAKE_LLM_KEY = safeStorage.decryptString(Buffer.from(config.encryptedKey, 'base64'));
|
||||
}
|
||||
return config;
|
||||
}
|
||||
|
||||
// ─── 后端服务器 ───
|
||||
|
||||
|
|
@ -73,7 +99,7 @@ function startServer(): Promise<void> {
|
|||
try {
|
||||
process.env.KB_PORT = String(SERVER_PORT);
|
||||
process.env.KB_REPO_PATH = KB_REPO_PATH;
|
||||
const serverBundle = path.join(__dirname, 'server-bundle.js');
|
||||
const serverBundle = path.join(__dirname, 'server-bundle.cjs');
|
||||
require(serverBundle);
|
||||
console.log(`[KB Server] 内嵌启动,端口 ${SERVER_PORT}`);
|
||||
resolve();
|
||||
|
|
@ -106,7 +132,7 @@ function createWindow(): void {
|
|||
trafficLightPosition: { x: 16, y: 16 },
|
||||
backgroundColor: '#0d1117',
|
||||
webPreferences: {
|
||||
preload: path.join(__dirname, 'preload.js'),
|
||||
preload: path.join(__dirname, 'preload.cjs'),
|
||||
contextIsolation: true,
|
||||
nodeIntegration: false,
|
||||
},
|
||||
|
|
@ -130,10 +156,37 @@ function createWindow(): void {
|
|||
});
|
||||
}
|
||||
|
||||
ipcMain.handle('get-data-path', () => DATA_DIR);
|
||||
ipcMain.handle('agent:get-config', () => {
|
||||
const config = readModelConfig();
|
||||
return {
|
||||
baseUrl: config.baseUrl,
|
||||
model: config.model,
|
||||
configured: Boolean(config.encryptedKey && safeStorage.isEncryptionAvailable()),
|
||||
};
|
||||
});
|
||||
ipcMain.handle('agent:save-config', (_event, input: { baseUrl: string; model: string; apiKey?: string }) => {
|
||||
const baseUrl = String(input.baseUrl || '').trim().replace(/\/$/, '');
|
||||
const model = String(input.model || '').trim();
|
||||
if (!/^https:\/\//i.test(baseUrl)) throw new Error('模型服务地址必须使用 HTTPS');
|
||||
if (!model) throw new Error('模型名称不能为空');
|
||||
if (!safeStorage.isEncryptionAvailable()) throw new Error('macOS 加密存储当前不可用');
|
||||
const previous = readModelConfig();
|
||||
const encryptedKey = input.apiKey
|
||||
? safeStorage.encryptString(String(input.apiKey)).toString('base64')
|
||||
: previous.encryptedKey;
|
||||
if (!encryptedKey) throw new Error('请填写模型密钥');
|
||||
fs.mkdirSync(path.dirname(MODEL_CONFIG_PATH), { recursive: true });
|
||||
fs.writeFileSync(MODEL_CONFIG_PATH, JSON.stringify({ baseUrl, model, encryptedKey }), { mode: 0o600 });
|
||||
applyModelConfig();
|
||||
return { baseUrl, model, configured: true };
|
||||
});
|
||||
|
||||
// ─── 应用生命周期 ───
|
||||
|
||||
app.whenReady().then(async () => {
|
||||
try {
|
||||
applyModelConfig();
|
||||
await startServer();
|
||||
createWindow();
|
||||
} catch (err) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue