| const { app, BrowserWindow, ipcMain, shell, powerMonitor } = require('electron'); |
| const path = require('path'); |
| const { spawn, exec } = require('child_process'); |
| const fs = require('fs'); |
| const os = require('os'); |
| const si = require('systeminformation'); |
|
|
| let mainWindow; |
| let apiProcess; |
|
|
| |
| function logToDesktop(message) {} |
|
|
| function createWindow() { |
| mainWindow = new BrowserWindow({ |
| width: 1300, |
| height: 900, |
| backgroundColor: '#ffffff', |
| icon: path.join(__dirname, 'remiai.ico'), |
| webPreferences: { |
| nodeIntegration: true, |
| contextIsolation: false, |
| webviewTag: true |
| }, |
| autoHideMenuBar: true, |
| title: "RemiAI - bujji" |
| }); |
|
|
| mainWindow.loadFile('index.html'); |
| |
| |
| mainWindow.webContents.on('did-finish-load', () => { |
| mainWindow.webContents.send('check-tasks'); |
| }); |
|
|
| powerMonitor.on('resume', () => { |
| if (mainWindow) mainWindow.webContents.send('check-tasks'); |
| }); |
|
|
| powerMonitor.on('unlock-screen', () => { |
| if (mainWindow) mainWindow.webContents.send('check-tasks'); |
| }); |
|
|
| |
| mainWindow.webContents.setWindowOpenHandler(({ url }) => { |
| return { action: 'allow' }; |
| }); |
|
|
| mainWindow.on('closed', function () { mainWindow = null; }); |
| } |
|
|
| |
|
|
| async function selectEngine() { |
| try { |
| const cpuFlags = await si.cpuFlags(); |
| const flagsStr = JSON.stringify(cpuFlags).toLowerCase(); |
| |
| const basePath = app.isPackaged ? process.resourcesPath : __dirname; |
| const engineBaseDir = path.join(basePath, 'engine'); |
| const hasFolder = (f) => fs.existsSync(path.join(engineBaseDir, f)); |
|
|
| |
| if (flagsStr.includes('avx2') && hasFolder('cpu_avx2')) { |
| return 'cpu_avx2'; |
| } |
|
|
| |
| return 'cpu_avx'; |
|
|
| } catch (e) { |
| return 'cpu_avx'; |
| } |
| } |
|
|
| async function startNativeBackend() { |
| killProcess(); |
| await new Promise(resolve => setTimeout(resolve, 500)); |
|
|
| const engineSubfolder = await selectEngine(); |
| const basePath = app.isPackaged ? process.resourcesPath : __dirname; |
| const workingDir = path.join(basePath, 'engine', engineSubfolder); |
| |
| let exeName = fs.existsSync(path.join(workingDir, 'bujji_engine.exe')) |
| ? 'bujji_engine.exe' |
| : 'llama-server.exe'; |
| |
| const exePath = path.join(workingDir, exeName); |
|
|
| |
| |
| |
| const optimizedThreads = 4; |
|
|
| const args = [ |
| '-m', '../model.gguf', |
| '-c', '2048', |
| '--batch-size', '512', |
| '--port', '5000', |
| '-t', optimizedThreads.toString(), |
| '--n-gpu-layers', '0', |
| '--no-mmap' |
| ]; |
|
|
| try { |
| apiProcess = spawn(exePath, args, { |
| cwd: workingDir, |
| windowsHide: true, |
| stdio: ['ignore', 'pipe', 'pipe'] |
| }); |
|
|
| apiProcess.stderr.on('data', (data) => logToDesktop(data.toString())); |
| } catch (e) { |
| logToDesktop(`Catch Error: ${e.message}`); |
| } |
| } |
|
|
| function killProcess() { |
| try { |
| exec('taskkill /IM bujji_engine.exe /F /T'); |
| exec('taskkill /IM llama-server.exe /F /T'); |
| } catch(e) {} |
| } |
|
|
| ipcMain.on('restart-brain', () => { |
| startNativeBackend(); |
| if(mainWindow) mainWindow.webContents.send('brain-restarted'); |
| }); |
|
|
| ipcMain.on('reload-window', () => { |
| if(mainWindow) mainWindow.reload(); |
| }); |
|
|
| |
|
|
| app.whenReady().then(() => { |
| startNativeBackend(); |
| createWindow(); |
| }); |
|
|
| app.on('window-all-closed', () => { |
| killProcess(); |
| if (process.platform !== 'darwin') app.quit(); |
| }); |
|
|
| app.on('will-quit', () => { killProcess(); }); |