| | 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(); }); |