diff --git a/app/background.js b/app/background.js index f585e42..a6cc075 100644 --- a/app/background.js +++ b/app/background.js @@ -1,2 +1,435 @@ -(()=>{"use strict";var e={n:n=>{var o=n&&n.__esModule?()=>n.default:()=>n;return e.d(o,{a:o}),o},d:(n,o)=>{for(var t in o)e.o(o,t)&&!e.o(n,t)&&Object.defineProperty(n,t,{enumerable:!0,get:o[t]})},o:(e,n)=>Object.prototype.hasOwnProperty.call(e,n)};const n=require("child_process"),o=require("path");var t=e.n(o);const s=require("os");var l=e.n(s);const r=require("process");var i=e.n(r);const a=require("fs");var c=e.n(a);const p=require("url");var u=e.n(p);const d=require("express");var m=e.n(d);const w=require("electron");let h=null,b=null,g=null;const f=async()=>{h=new w.BrowserWindow({minWidth:480,minHeight:695,maximizable:!0,useContentSize:!0,autoHideMenuBar:!0,webPreferences:{nodeIntegration:!1,contextIsolation:!0,sandbox:!0,preload:t().join(__dirname,"preload.js")},icon:__dirname+"/img/taskbar.png"});const e=m()();let o;o=t().join(i().resourcesPath,"astroDist"),e.use(m().static(o)),e.listen(8080,(()=>{console.log("Express server listening on port 8080")})),function(e){const n=[{label:"View",submenu:[{label:"Send to tray",click(){e.minimize()}},{label:"Reload",role:"reload"},{label:"Dev tools",role:"toggleDevTools"}]}],o=w.Menu.buildFromTemplate(n);w.Menu.setApplicationMenu(o)}(h),h.loadURL("http://localhost:8080/index.html"),h.webContents.setWindowOpenHandler((()=>({action:"deny"}))),b=new w.Tray(t().join(__dirname,"img","tray.png"));const s=w.Menu.buildFromTemplate([{label:"Show App",click:function(){h?.show()}},{label:"Quit",click:function(){b=null,w.app.quit()}}]);b.setToolTip("Electron BitNet"),b.on("right-click",((e,n)=>{b?.popUpContextMenu(s)}));const l=["https://github.com","https://react.dev/","https://astro.build/","https://www.electronjs.org/"];w.ipcMain.on("openURL",((e,n)=>{try{const e=new(u().URL)(n).hostname;l.some((n=>new(u().URL)(n).hostname===e))?w.shell.openExternal(n):console.error(`Rejected opening URL with unsafe domain: ${e}`)}catch(e){console.error(`Failed to open URL: ${e.message}`)}})),w.ipcMain.on("runInference",((e,o)=>{!function(e){let o=t().join("bin","Release","llama-cli.exe");c().existsSync(o)||(o=t().join("bin","llama-cli"));const s=[`"${o}"`,"-m",t().join("models",e.model),"-n",e.n_predict,"-t",e.threads,"-p",`"${e.prompt}"`,"-ngl","0","-c",e.ctx_size,"--temp",e.temperature,"-b","1"];g=(0,n.spawn)(s[0],s.slice(1),{shell:!0}),g.stdout.on("data",(e=>{const n=e.toString();h.webContents.send("aiResponse",n)})),g.on("close",(e=>{h.webContents.send("aiComplete"),g=null}))}(o)})),w.ipcMain.on("stopInference",(e=>{!function(){if(g){console.log("Terminating inference process...");try{g.kill("SIGKILL"),g.stdout.removeAllListeners("data"),g.stderr.removeAllListeners("data"),g=null,console.log("Inference process terminated.")}catch(e){console.error("Failed to terminate inference process:",e)}}else console.log("No inference process to terminate.");h.webContents.send("aiComplete"),g=null}()})),b.on("click",(()=>{h?.setAlwaysOnTop(!0),h?.show(),h?.focus(),h?.setAlwaysOnTop(!1)})),b.on("balloon-click",(()=>{h?.setAlwaysOnTop(!0),h?.show(),h?.focus(),h?.setAlwaysOnTop(!1)}))},y=l().platform();"win32"===y||"linux"===y?(w.app.requestSingleInstanceLock()||w.app.quit(),w.app.whenReady().then((()=>{f()}))):(w.app.whenReady().then((()=>{f()})),w.app.on("window-all-closed",(()=>{"darwin"!==i().platform&&w.app.quit()})),w.app.on("activate",(()=>{null===h&&f()})))})(); +/******/ (() => { // webpackBootstrap +/******/ "use strict"; +/******/ var __webpack_modules__ = ({ + +/***/ "./src/lib/applicationMenu.js": +/*!************************************!*\ + !*** ./src/lib/applicationMenu.js ***! + \************************************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ initApplicationMenu: () => (/* binding */ initApplicationMenu) +/* harmony export */ }); +/* harmony import */ var electron__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! electron */ "electron"); +/* harmony import */ var electron__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(electron__WEBPACK_IMPORTED_MODULE_0__); + + +/** + * For configuring the electron window menu + */ +function initApplicationMenu(mainWindow) { + const template = [ + { + label: 'View', + submenu: [ + { + label: 'Send to tray', + click() { + mainWindow.minimize(); + } + }, + { label: 'Reload', role: 'reload' }, + { label: 'Dev tools', role: 'toggleDevTools' } + ] + } + ]; + const menu = electron__WEBPACK_IMPORTED_MODULE_0__.Menu.buildFromTemplate(template); + electron__WEBPACK_IMPORTED_MODULE_0__.Menu.setApplicationMenu(menu); +} + + +/***/ }), + +/***/ "electron": +/*!***************************!*\ + !*** external "electron" ***! + \***************************/ +/***/ ((module) => { + +module.exports = require("electron"); + +/***/ }), + +/***/ "express": +/*!**************************!*\ + !*** external "express" ***! + \**************************/ +/***/ ((module) => { + +module.exports = require("express"); + +/***/ }), + +/***/ "child_process": +/*!********************************!*\ + !*** external "child_process" ***! + \********************************/ +/***/ ((module) => { + +module.exports = require("child_process"); + +/***/ }), + +/***/ "fs": +/*!*********************!*\ + !*** external "fs" ***! + \*********************/ +/***/ ((module) => { + +module.exports = require("fs"); + +/***/ }), + +/***/ "os": +/*!*********************!*\ + !*** external "os" ***! + \*********************/ +/***/ ((module) => { + +module.exports = require("os"); + +/***/ }), + +/***/ "path": +/*!***********************!*\ + !*** external "path" ***! + \***********************/ +/***/ ((module) => { + +module.exports = require("path"); + +/***/ }), + +/***/ "process": +/*!**************************!*\ + !*** external "process" ***! + \**************************/ +/***/ ((module) => { + +module.exports = require("process"); + +/***/ }), + +/***/ "url": +/*!**********************!*\ + !*** external "url" ***! + \**********************/ +/***/ ((module) => { + +module.exports = require("url"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The module cache +/******/ var __webpack_module_cache__ = {}; +/******/ +/******/ // The require function +/******/ function __webpack_require__(moduleId) { +/******/ // Check if module is in cache +/******/ var cachedModule = __webpack_module_cache__[moduleId]; +/******/ if (cachedModule !== undefined) { +/******/ return cachedModule.exports; +/******/ } +/******/ // Create a new module (and put it into the cache) +/******/ var module = __webpack_module_cache__[moduleId] = { +/******/ // no module.id needed +/******/ // no module.loaded needed +/******/ exports: {} +/******/ }; +/******/ +/******/ // Execute the module function +/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__); +/******/ +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/compat get default export */ +/******/ (() => { +/******/ // getDefaultExport function for compatibility with non-harmony modules +/******/ __webpack_require__.n = (module) => { +/******/ var getter = module && module.__esModule ? +/******/ () => (module['default']) : +/******/ () => (module); +/******/ __webpack_require__.d(getter, { a: getter }); +/******/ return getter; +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/define property getters */ +/******/ (() => { +/******/ // define getter functions for harmony exports +/******/ __webpack_require__.d = (exports, definition) => { +/******/ for(var key in definition) { +/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) { +/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] }); +/******/ } +/******/ } +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/hasOwnProperty shorthand */ +/******/ (() => { +/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) +/******/ })(); +/******/ +/******/ /* webpack/runtime/make namespace object */ +/******/ (() => { +/******/ // define __esModule on exports +/******/ __webpack_require__.r = (exports) => { +/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { +/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); +/******/ } +/******/ Object.defineProperty(exports, '__esModule', { value: true }); +/******/ }; +/******/ })(); +/******/ +/************************************************************************/ +var __webpack_exports__ = {}; +// This entry need to be wrapped in an IIFE because it need to be isolated against other modules in the chunk. +(() => { +/*!***************************!*\ + !*** ./src/background.js ***! + \***************************/ +__webpack_require__.r(__webpack_exports__); +/* harmony import */ var child_process__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! child_process */ "child_process"); +/* harmony import */ var child_process__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(child_process__WEBPACK_IMPORTED_MODULE_0__); +/* harmony import */ var path__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! path */ "path"); +/* harmony import */ var path__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(path__WEBPACK_IMPORTED_MODULE_1__); +/* harmony import */ var os__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! os */ "os"); +/* harmony import */ var os__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(os__WEBPACK_IMPORTED_MODULE_2__); +/* harmony import */ var process__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! process */ "process"); +/* harmony import */ var process__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(process__WEBPACK_IMPORTED_MODULE_3__); +/* harmony import */ var fs__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! fs */ "fs"); +/* harmony import */ var fs__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(fs__WEBPACK_IMPORTED_MODULE_4__); +/* harmony import */ var url__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! url */ "url"); +/* harmony import */ var url__WEBPACK_IMPORTED_MODULE_5___default = /*#__PURE__*/__webpack_require__.n(url__WEBPACK_IMPORTED_MODULE_5__); +/* harmony import */ var express__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! express */ "express"); +/* harmony import */ var express__WEBPACK_IMPORTED_MODULE_6___default = /*#__PURE__*/__webpack_require__.n(express__WEBPACK_IMPORTED_MODULE_6__); +/* harmony import */ var electron__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! electron */ "electron"); +/* harmony import */ var electron__WEBPACK_IMPORTED_MODULE_7___default = /*#__PURE__*/__webpack_require__.n(electron__WEBPACK_IMPORTED_MODULE_7__); +/* harmony import */ var _lib_applicationMenu_js__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./lib/applicationMenu.js */ "./src/lib/applicationMenu.js"); + + + + + + + + + + + + +let mainWindow = null; +let tray = null; +let inferenceProcess = null; + +function runInference(args) { + let mainPath = path__WEBPACK_IMPORTED_MODULE_1___default().join(electron__WEBPACK_IMPORTED_MODULE_7__.app.getAppPath(), 'bin', 'Release', 'llama-cli.exe'); + + if (!fs__WEBPACK_IMPORTED_MODULE_4___default().existsSync(mainPath)) { + mainPath = path__WEBPACK_IMPORTED_MODULE_1___default().join(electron__WEBPACK_IMPORTED_MODULE_7__.app.getAppPath(), 'bin', 'llama-cli'); + } + + const command = [ + `"${mainPath}"`, + '-m', args.model, + '-n', args.n_predict, + '-t', args.threads, + '-p', `"${args.prompt}"`, + '-ngl', '0', + '-c', args.ctx_size, + '--temp', args.temperature, + '-b', '1' + ]; + + inferenceProcess = (0,child_process__WEBPACK_IMPORTED_MODULE_0__.spawn)(command[0], command.slice(1), { shell: true }); + + inferenceProcess.stdout.on('data', (data) => { + const chars = data.toString(); + mainWindow.webContents.send('aiResponse', chars); + }); + + inferenceProcess.on('close', (code) => { + mainWindow.webContents.send('aiComplete'); + inferenceProcess = null; + }); +} + +function signalHandler() { + if (inferenceProcess) { + console.log('Terminating inference process...'); + try { + inferenceProcess.kill('SIGKILL'); // Use SIGKILL to forcefully terminate the process + inferenceProcess.stdout.removeAllListeners('data'); + inferenceProcess.stderr.removeAllListeners('data'); + inferenceProcess = null; + console.log('Inference process terminated.'); + } catch (error) { + console.error('Failed to terminate inference process:', error); + } + } else { + console.log('No inference process to terminate.'); + } + + mainWindow.webContents.send('aiComplete'); + inferenceProcess = null; +} + +const createWindow = async () => { + mainWindow = new electron__WEBPACK_IMPORTED_MODULE_7__.BrowserWindow({ + minWidth: 480, + minHeight: 695, + maximizable: true, + useContentSize: true, + autoHideMenuBar: true, + webPreferences: { + nodeIntegration: false, + contextIsolation: true, + sandbox: true, + preload: path__WEBPACK_IMPORTED_MODULE_1___default().join(__dirname, "preload.js"), + }, + icon: __dirname + "/img/taskbar.png", + }); + + const expressApp = express__WEBPACK_IMPORTED_MODULE_6___default()(); + + let astroDistPath; + if (true) { + astroDistPath = "astroDist"; + } else {} + + expressApp.use(express__WEBPACK_IMPORTED_MODULE_6___default()["static"](astroDistPath)); + expressApp.listen(8080, () => { + console.log("Express server listening on port 8080"); + }); + + (0,_lib_applicationMenu_js__WEBPACK_IMPORTED_MODULE_8__.initApplicationMenu)(mainWindow); + + mainWindow.loadURL("http://localhost:8080/index.html"); + + mainWindow.webContents.setWindowOpenHandler(() => { + return { action: "deny" }; + }); + + tray = new electron__WEBPACK_IMPORTED_MODULE_7__.Tray(path__WEBPACK_IMPORTED_MODULE_1___default().join(__dirname, "img", "tray.png")); + const contextMenu = electron__WEBPACK_IMPORTED_MODULE_7__.Menu.buildFromTemplate([ + { + label: "Show App", + click: function () { + mainWindow?.show(); + }, + }, + { + label: "Quit", + click: function () { + tray = null; + electron__WEBPACK_IMPORTED_MODULE_7__.app.quit(); + }, + }, + ]); + + tray.setToolTip("Electron BitNet"); + + tray.on("right-click", (event, bounds) => { + tray?.popUpContextMenu(contextMenu); + }); + + const safeDomains = [ + "https://github.com", + "https://react.dev/", + "https://astro.build/", + "https://www.electronjs.org/" + ]; + + electron__WEBPACK_IMPORTED_MODULE_7__.ipcMain.on("openURL", (event, arg) => { + try { + const parsedUrl = new (url__WEBPACK_IMPORTED_MODULE_5___default().URL)(arg); + const domain = parsedUrl.hostname; + + const isSafeDomain = safeDomains.some((safeDomain) => { + const safeDomainHostname = new (url__WEBPACK_IMPORTED_MODULE_5___default().URL)(safeDomain).hostname; + return safeDomainHostname === domain; + }); + + if (isSafeDomain) { + electron__WEBPACK_IMPORTED_MODULE_7__.shell.openExternal(arg); + } else { + console.error(`Rejected opening URL with unsafe domain: ${domain}`); + } + } catch (err) { + console.error(`Failed to open URL: ${err.message}`); + } + }); + + electron__WEBPACK_IMPORTED_MODULE_7__.ipcMain.on("runInference", (event, arg) => { + runInference(arg); + }); + + electron__WEBPACK_IMPORTED_MODULE_7__.ipcMain.on("stopInference", (event) => { + signalHandler(); + }); + + electron__WEBPACK_IMPORTED_MODULE_7__.ipcMain.handle('openFileDialog', async () => { + const result = await electron__WEBPACK_IMPORTED_MODULE_7__.dialog.showOpenDialog({ + properties: ['openFile'], + filters: [{ name: 'GGUF Files', extensions: ['gguf'] }] + }); + return result.filePaths; + }); + + tray.on("click", () => { + mainWindow?.setAlwaysOnTop(true); + mainWindow?.show(); + mainWindow?.focus(); + mainWindow?.setAlwaysOnTop(false); + }); + + tray.on("balloon-click", () => { + mainWindow?.setAlwaysOnTop(true); + mainWindow?.show(); + mainWindow?.focus(); + mainWindow?.setAlwaysOnTop(false); + }); +}; + +const currentOS = os__WEBPACK_IMPORTED_MODULE_2___default().platform(); +if (currentOS === "win32" || currentOS === "linux") { + // windows + linux setup phase + const gotTheLock = electron__WEBPACK_IMPORTED_MODULE_7__.app.requestSingleInstanceLock(); + + if (!gotTheLock) { + electron__WEBPACK_IMPORTED_MODULE_7__.app.quit(); + } + + electron__WEBPACK_IMPORTED_MODULE_7__.app.whenReady().then(() => { + createWindow(); + }); +} else { + electron__WEBPACK_IMPORTED_MODULE_7__.app.whenReady().then(() => { + createWindow(); + }); + + electron__WEBPACK_IMPORTED_MODULE_7__.app.on("window-all-closed", () => { + if ((process__WEBPACK_IMPORTED_MODULE_3___default().platform) !== "darwin") { + electron__WEBPACK_IMPORTED_MODULE_7__.app.quit(); + } + }); + + electron__WEBPACK_IMPORTED_MODULE_7__.app.on("activate", () => { + if (mainWindow === null) { + createWindow(); + } + }); +} +})(); + +/******/ })() +; //# sourceMappingURL=background.js.map \ No newline at end of file diff --git a/app/background.js.map b/app/background.js.map index 0758e96..53b57a3 100644 --- a/app/background.js.map +++ b/app/background.js.map @@ -1 +1 @@ -{"version":3,"file":"background.js","mappings":"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","sources":["webpack://electron-bitnet/webpack/bootstrap","webpack://electron-bitnet/webpack/runtime/compat get default export","webpack://electron-bitnet/webpack/runtime/define property getters","webpack://electron-bitnet/webpack/runtime/hasOwnProperty shorthand","webpack://electron-bitnet/external node-commonjs \"child_process\"","webpack://electron-bitnet/external node-commonjs \"path\"","webpack://electron-bitnet/external node-commonjs \"os\"","webpack://electron-bitnet/external node-commonjs \"process\"","webpack://electron-bitnet/external node-commonjs \"fs\"","webpack://electron-bitnet/external node-commonjs \"url\"","webpack://electron-bitnet/external commonjs \"express\"","webpack://electron-bitnet/external commonjs \"electron\"","webpack://electron-bitnet/./src/background.js","webpack://electron-bitnet/./src/lib/applicationMenu.js"],"sourcesContent":["// The require scope\nvar __webpack_require__ = {};\n\n","// getDefaultExport function for compatibility with non-harmony modules\n__webpack_require__.n = (module) => {\n\tvar getter = module && module.__esModule ?\n\t\t() => (module['default']) :\n\t\t() => (module);\n\t__webpack_require__.d(getter, { a: getter });\n\treturn getter;\n};","// define getter functions for harmony exports\n__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n\t\t}\n\t}\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","const __WEBPACK_NAMESPACE_OBJECT__ = require(\"child_process\");","const __WEBPACK_NAMESPACE_OBJECT__ = require(\"path\");","const __WEBPACK_NAMESPACE_OBJECT__ = require(\"os\");","const __WEBPACK_NAMESPACE_OBJECT__ = require(\"process\");","const __WEBPACK_NAMESPACE_OBJECT__ = require(\"fs\");","const __WEBPACK_NAMESPACE_OBJECT__ = require(\"url\");","const __WEBPACK_NAMESPACE_OBJECT__ = require(\"express\");","const __WEBPACK_NAMESPACE_OBJECT__ = require(\"electron\");","import { spawn } from 'child_process';\r\nimport path from 'path';\r\nimport os from 'os';\r\nimport process from 'process';\r\nimport fs from 'fs';\r\nimport url from \"url\";\r\nimport express from \"express\";\r\n\r\nimport { app, BrowserWindow, Menu, Tray, ipcMain, screen, shell } from \"electron\";\r\n\r\nimport { initApplicationMenu } from \"./lib/applicationMenu.js\";\r\n\r\nlet mainWindow = null;\r\nlet tray = null;\r\nlet inferenceProcess = null;\r\n\r\nfunction runInference(args) {\r\n let mainPath = path.join('bin', 'Release', 'llama-cli.exe');\r\n\r\n if (!fs.existsSync(mainPath)) {\r\n mainPath = path.join('bin', 'llama-cli');\r\n }\r\n\r\n const command = [\r\n `\"${mainPath}\"`,\r\n '-m', path.join('models', args.model),\r\n '-n', args.n_predict,\r\n '-t', args.threads,\r\n '-p', `\"${args.prompt}\"`,\r\n '-ngl', '0',\r\n '-c', args.ctx_size,\r\n '--temp', args.temperature,\r\n '-b', '1'\r\n ];\r\n\r\n inferenceProcess = spawn(command[0], command.slice(1), { shell: true });\r\n\r\n inferenceProcess.stdout.on('data', (data) => {\r\n const chars = data.toString();\r\n mainWindow.webContents.send('aiResponse', chars);\r\n });\r\n\r\n inferenceProcess.on('close', (code) => {\r\n mainWindow.webContents.send('aiComplete');\r\n inferenceProcess = null;\r\n });\r\n}\r\n\r\nfunction signalHandler() {\r\n if (inferenceProcess) {\r\n console.log('Terminating inference process...');\r\n try {\r\n inferenceProcess.kill('SIGKILL'); // Use SIGKILL to forcefully terminate the process\r\n inferenceProcess.stdout.removeAllListeners('data');\r\n inferenceProcess.stderr.removeAllListeners('data');\r\n inferenceProcess = null;\r\n console.log('Inference process terminated.');\r\n } catch (error) {\r\n console.error('Failed to terminate inference process:', error);\r\n }\r\n } else {\r\n console.log('No inference process to terminate.');\r\n }\r\n\r\n mainWindow.webContents.send('aiComplete');\r\n inferenceProcess = null;\r\n}\r\n\r\nconst createWindow = async () => {\r\n mainWindow = new BrowserWindow({\r\n minWidth: 480,\r\n minHeight: 695,\r\n maximizable: true,\r\n useContentSize: true,\r\n autoHideMenuBar: true,\r\n webPreferences: {\r\n nodeIntegration: false,\r\n contextIsolation: true,\r\n sandbox: true,\r\n preload: path.join(__dirname, \"preload.js\"),\r\n },\r\n icon: __dirname + \"/img/taskbar.png\",\r\n });\r\n\r\n const expressApp = express();\r\n\r\n let astroDistPath;\r\n if (process.env.NODE_ENV === \"development\") {\r\n astroDistPath = \"astroDist\";\r\n } else {\r\n astroDistPath = path.join(process.resourcesPath, \"astroDist\");\r\n }\r\n\r\n expressApp.use(express.static(astroDistPath));\r\n expressApp.listen(8080, () => {\r\n console.log(\"Express server listening on port 8080\");\r\n });\r\n\r\n initApplicationMenu(mainWindow);\r\n\r\n mainWindow.loadURL(\"http://localhost:8080/index.html\");\r\n\r\n mainWindow.webContents.setWindowOpenHandler(() => {\r\n return { action: \"deny\" };\r\n });\r\n\r\n tray = new Tray(path.join(__dirname, \"img\", \"tray.png\"));\r\n const contextMenu = Menu.buildFromTemplate([\r\n {\r\n label: \"Show App\",\r\n click: function () {\r\n mainWindow?.show();\r\n },\r\n },\r\n {\r\n label: \"Quit\",\r\n click: function () {\r\n tray = null;\r\n app.quit();\r\n },\r\n },\r\n ]);\r\n\r\n tray.setToolTip(\"Electron BitNet\");\r\n\r\n tray.on(\"right-click\", (event, bounds) => {\r\n tray?.popUpContextMenu(contextMenu);\r\n });\r\n\r\n const safeDomains = [\r\n \"https://github.com\",\r\n \"https://react.dev/\",\r\n \"https://astro.build/\",\r\n \"https://www.electronjs.org/\"\r\n ];\r\n\r\n ipcMain.on(\"openURL\", (event, arg) => {\r\n try {\r\n const parsedUrl = new url.URL(arg);\r\n const domain = parsedUrl.hostname;\r\n\r\n const isSafeDomain = safeDomains.some((safeDomain) => {\r\n const safeDomainHostname = new url.URL(safeDomain).hostname;\r\n return safeDomainHostname === domain;\r\n });\r\n\r\n if (isSafeDomain) {\r\n shell.openExternal(arg);\r\n } else {\r\n console.error(`Rejected opening URL with unsafe domain: ${domain}`);\r\n }\r\n } catch (err) {\r\n console.error(`Failed to open URL: ${err.message}`);\r\n }\r\n });\r\n\r\n ipcMain.on(\"runInference\", (event, arg) => {\r\n runInference(arg);\r\n });\r\n\r\n ipcMain.on(\"stopInference\", (event) => {\r\n signalHandler();\r\n });\r\n\r\n tray.on(\"click\", () => {\r\n mainWindow?.setAlwaysOnTop(true);\r\n mainWindow?.show();\r\n mainWindow?.focus();\r\n mainWindow?.setAlwaysOnTop(false);\r\n });\r\n\r\n tray.on(\"balloon-click\", () => {\r\n mainWindow?.setAlwaysOnTop(true);\r\n mainWindow?.show();\r\n mainWindow?.focus();\r\n mainWindow?.setAlwaysOnTop(false);\r\n });\r\n};\r\n\r\nconst currentOS = os.platform();\r\nif (currentOS === \"win32\" || currentOS === \"linux\") {\r\n // windows + linux setup phase\r\n const gotTheLock = app.requestSingleInstanceLock();\r\n\r\n if (!gotTheLock) {\r\n app.quit();\r\n }\r\n\r\n app.whenReady().then(() => {\r\n createWindow();\r\n });\r\n} else {\r\n app.whenReady().then(() => {\r\n createWindow();\r\n });\r\n\r\n app.on(\"window-all-closed\", () => {\r\n if (process.platform !== \"darwin\") {\r\n app.quit();\r\n }\r\n });\r\n\r\n app.on(\"activate\", () => {\r\n if (mainWindow === null) {\r\n createWindow();\r\n }\r\n });\r\n}","import {app, Menu} from 'electron';\r\n\r\n/**\r\n * For configuring the electron window menu\r\n */\r\nexport function initApplicationMenu(mainWindow) {\r\n const template = [\r\n {\r\n label: 'View',\r\n submenu: [\r\n {\r\n label: 'Send to tray',\r\n click() {\r\n mainWindow.minimize();\r\n }\r\n },\r\n { label: 'Reload', role: 'reload' },\r\n { label: 'Dev tools', role: 'toggleDevTools' }\r\n ]\r\n }\r\n ];\r\n const menu = Menu.buildFromTemplate(template);\r\n Menu.setApplicationMenu(menu);\r\n}\r\n"],"names":["__webpack_require__","module","getter","__esModule","d","a","exports","definition","key","o","Object","defineProperty","enumerable","get","obj","prop","prototype","hasOwnProperty","call","require","mainWindow","tray","inferenceProcess","createWindow","async","BrowserWindow","minWidth","minHeight","maximizable","useContentSize","autoHideMenuBar","webPreferences","nodeIntegration","contextIsolation","sandbox","preload","__dirname","icon","expressApp","astroDistPath","use","listen","console","log","template","label","submenu","click","minimize","role","menu","Menu","buildFromTemplate","setApplicationMenu","initApplicationMenu","loadURL","webContents","setWindowOpenHandler","action","Tray","contextMenu","show","app","quit","setToolTip","on","event","bounds","popUpContextMenu","safeDomains","ipcMain","arg","domain","hostname","some","safeDomain","shell","openExternal","error","err","message","args","mainPath","command","model","n_predict","threads","prompt","ctx_size","temperature","spawn","slice","stdout","data","chars","toString","send","code","runInference","kill","removeAllListeners","stderr","signalHandler","setAlwaysOnTop","focus","currentOS","requestSingleInstanceLock","whenReady","then"],"sourceRoot":""} \ No newline at end of file +{"version":3,"file":"background.js","mappings":";;;;;;;;;;;;;;;;AAAmC;AACnC;AACA;AACA;AACA;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW;AACX,YAAY,iCAAiC;AAC7C,YAAY;AACZ;AACA;AACA;AACA,iBAAiB,0CAAI;AACrB,IAAI,0CAAI;AACR;;;;;;;;;;;ACvBA;;;;;;;;;;ACAA;;;;;;;;;;ACAA;;;;;;;;;;ACAA;;;;;;;;;;ACAA;;;;;;;;;;ACAA;;;;;;;;;;ACAA;;;;;;;;;;ACAA;;;;;;UCAA;UACA;;UAEA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;;UAEA;UACA;;UAEA;UACA;UACA;;;;;WCtBA;WACA;WACA;WACA;WACA;WACA,iCAAiC,WAAW;WAC5C;WACA;;;;;WCPA;WACA;WACA;WACA;WACA,yCAAyC,wCAAwC;WACjF;WACA;WACA;;;;;WCPA;;;;;WCAA;WACA;WACA;WACA,uDAAuD,iBAAiB;WACxE;WACA,gDAAgD,aAAa;WAC7D;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACNsC;AACd;AACJ;AACU;AACV;AACE;AACQ;AAC9B;AACkF;AAClF;AAC+D;AAC/D;AACA;AACA;AACA;AACA;AACA;AACA,iBAAiB,gDAAS,CAAC,yCAAG;AAC9B;AACA,OAAO,oDAAa;AACpB,eAAe,gDAAS,CAAC,yCAAG;AAC5B;AACA;AACA;AACA,QAAQ,SAAS;AACjB;AACA;AACA;AACA,cAAc,YAAY;AAC1B;AACA;AACA;AACA;AACA;AACA;AACA,qBAAqB,oDAAK,iCAAiC,aAAa;AACxE;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;AACA;AACA,wCAAwC;AACxC;AACA;AACA;AACA;AACA,MAAM;AACN;AACA;AACA,IAAI;AACJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mBAAmB,mDAAa;AAChC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,eAAe,gDAAS;AACxB,KAAK;AACL;AACA,GAAG;AACH;AACA,qBAAqB,8CAAO;AAC5B;AACA;AACA,MAAM,IAAsC;AAC5C;AACA,IAAI,KAAK,EAEN;AACH;AACA,iBAAiB,wDAAc;AAC/B;AACA;AACA,GAAG;AACH;AACA,EAAE,4EAAmB;AACrB;AACA;AACA;AACA;AACA,aAAa;AACb,GAAG;AACH;AACA,aAAa,0CAAI,CAAC,gDAAS;AAC3B,sBAAsB,0CAAI;AAC1B;AACA;AACA;AACA;AACA,OAAO;AACP,KAAK;AACL;AACA;AACA;AACA;AACA,QAAQ,yCAAG;AACX,OAAO;AACP,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,EAAE,6CAAO;AACT;AACA,4BAA4B,gDAAO;AACnC;AACA;AACA;AACA,uCAAuC,gDAAO;AAC9C;AACA,OAAO;AACP;AACA;AACA,QAAQ,2CAAK;AACb,QAAQ;AACR,kEAAkE,OAAO;AACzE;AACA,MAAM;AACN,2CAA2C,YAAY;AACvD;AACA,GAAG;AACH;AACA,EAAE,6CAAO;AACT;AACA,GAAG;AACH;AACA,EAAE,6CAAO;AACT;AACA,GAAG;AACH;AACA,EAAE,6CAAO;AACT,yBAAyB,4CAAM;AAC/B;AACA,oBAAoB,0CAA0C;AAC9D,KAAK;AACL;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA,kBAAkB,kDAAW;AAC7B;AACA;AACA,qBAAqB,yCAAG;AACxB;AACA;AACA,IAAI,yCAAG;AACP;AACA;AACA,EAAE,yCAAG;AACL;AACA,GAAG;AACH,EAAE;AACF,EAAE,yCAAG;AACL;AACA,GAAG;AACH;AACA,EAAE,yCAAG;AACL,QAAQ,yDAAgB;AACxB,MAAM,yCAAG;AACT;AACA,GAAG;AACH;AACA,EAAE,yCAAG;AACL;AACA;AACA;AACA,GAAG;AACH,C","sources":["webpack://electron-bitnet/./src/lib/applicationMenu.js","webpack://electron-bitnet/external commonjs \"electron\"","webpack://electron-bitnet/external commonjs \"express\"","webpack://electron-bitnet/external node-commonjs \"child_process\"","webpack://electron-bitnet/external node-commonjs \"fs\"","webpack://electron-bitnet/external node-commonjs \"os\"","webpack://electron-bitnet/external node-commonjs \"path\"","webpack://electron-bitnet/external node-commonjs \"process\"","webpack://electron-bitnet/external node-commonjs \"url\"","webpack://electron-bitnet/webpack/bootstrap","webpack://electron-bitnet/webpack/runtime/compat get default export","webpack://electron-bitnet/webpack/runtime/define property getters","webpack://electron-bitnet/webpack/runtime/hasOwnProperty shorthand","webpack://electron-bitnet/webpack/runtime/make namespace object","webpack://electron-bitnet/./src/background.js"],"sourcesContent":["import {app, Menu} from 'electron';\r\n\r\n/**\r\n * For configuring the electron window menu\r\n */\r\nexport function initApplicationMenu(mainWindow) {\r\n const template = [\r\n {\r\n label: 'View',\r\n submenu: [\r\n {\r\n label: 'Send to tray',\r\n click() {\r\n mainWindow.minimize();\r\n }\r\n },\r\n { label: 'Reload', role: 'reload' },\r\n { label: 'Dev tools', role: 'toggleDevTools' }\r\n ]\r\n }\r\n ];\r\n const menu = Menu.buildFromTemplate(template);\r\n Menu.setApplicationMenu(menu);\r\n}\r\n","module.exports = require(\"electron\");","module.exports = require(\"express\");","module.exports = require(\"child_process\");","module.exports = require(\"fs\");","module.exports = require(\"os\");","module.exports = require(\"path\");","module.exports = require(\"process\");","module.exports = require(\"url\");","// The module cache\nvar __webpack_module_cache__ = {};\n\n// The require function\nfunction __webpack_require__(moduleId) {\n\t// Check if module is in cache\n\tvar cachedModule = __webpack_module_cache__[moduleId];\n\tif (cachedModule !== undefined) {\n\t\treturn cachedModule.exports;\n\t}\n\t// Create a new module (and put it into the cache)\n\tvar module = __webpack_module_cache__[moduleId] = {\n\t\t// no module.id needed\n\t\t// no module.loaded needed\n\t\texports: {}\n\t};\n\n\t// Execute the module function\n\t__webpack_modules__[moduleId](module, module.exports, __webpack_require__);\n\n\t// Return the exports of the module\n\treturn module.exports;\n}\n\n","// getDefaultExport function for compatibility with non-harmony modules\n__webpack_require__.n = (module) => {\n\tvar getter = module && module.__esModule ?\n\t\t() => (module['default']) :\n\t\t() => (module);\n\t__webpack_require__.d(getter, { a: getter });\n\treturn getter;\n};","// define getter functions for harmony exports\n__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n\t\t}\n\t}\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","import { spawn } from 'child_process';\r\nimport path from 'path';\r\nimport os from 'os';\r\nimport process from 'process';\r\nimport fs from 'fs';\r\nimport url from \"url\";\r\nimport express from \"express\";\r\n\r\nimport { app, BrowserWindow, Menu, Tray, ipcMain, shell, dialog } from \"electron\";\r\n\r\nimport { initApplicationMenu } from \"./lib/applicationMenu.js\";\r\n\r\nlet mainWindow = null;\r\nlet tray = null;\r\nlet inferenceProcess = null;\r\n\r\nfunction runInference(args) {\r\n let mainPath = path.join(app.getAppPath(), 'bin', 'Release', 'llama-cli.exe');\r\n\r\n if (!fs.existsSync(mainPath)) {\r\n mainPath = path.join(app.getAppPath(), 'bin', 'llama-cli');\r\n }\r\n\r\n const command = [\r\n `\"${mainPath}\"`,\r\n '-m', args.model,\r\n '-n', args.n_predict,\r\n '-t', args.threads,\r\n '-p', `\"${args.prompt}\"`,\r\n '-ngl', '0',\r\n '-c', args.ctx_size,\r\n '--temp', args.temperature,\r\n '-b', '1'\r\n ];\r\n\r\n inferenceProcess = spawn(command[0], command.slice(1), { shell: true });\r\n\r\n inferenceProcess.stdout.on('data', (data) => {\r\n const chars = data.toString();\r\n mainWindow.webContents.send('aiResponse', chars);\r\n });\r\n\r\n inferenceProcess.on('close', (code) => {\r\n mainWindow.webContents.send('aiComplete');\r\n inferenceProcess = null;\r\n });\r\n}\r\n\r\nfunction signalHandler() {\r\n if (inferenceProcess) {\r\n console.log('Terminating inference process...');\r\n try {\r\n inferenceProcess.kill('SIGKILL'); // Use SIGKILL to forcefully terminate the process\r\n inferenceProcess.stdout.removeAllListeners('data');\r\n inferenceProcess.stderr.removeAllListeners('data');\r\n inferenceProcess = null;\r\n console.log('Inference process terminated.');\r\n } catch (error) {\r\n console.error('Failed to terminate inference process:', error);\r\n }\r\n } else {\r\n console.log('No inference process to terminate.');\r\n }\r\n\r\n mainWindow.webContents.send('aiComplete');\r\n inferenceProcess = null;\r\n}\r\n\r\nconst createWindow = async () => {\r\n mainWindow = new BrowserWindow({\r\n minWidth: 480,\r\n minHeight: 695,\r\n maximizable: true,\r\n useContentSize: true,\r\n autoHideMenuBar: true,\r\n webPreferences: {\r\n nodeIntegration: false,\r\n contextIsolation: true,\r\n sandbox: true,\r\n preload: path.join(__dirname, \"preload.js\"),\r\n },\r\n icon: __dirname + \"/img/taskbar.png\",\r\n });\r\n\r\n const expressApp = express();\r\n\r\n let astroDistPath;\r\n if (process.env.NODE_ENV === \"development\") {\r\n astroDistPath = \"astroDist\";\r\n } else {\r\n astroDistPath = path.join(process.resourcesPath, \"astroDist\");\r\n }\r\n\r\n expressApp.use(express.static(astroDistPath));\r\n expressApp.listen(8080, () => {\r\n console.log(\"Express server listening on port 8080\");\r\n });\r\n\r\n initApplicationMenu(mainWindow);\r\n\r\n mainWindow.loadURL(\"http://localhost:8080/index.html\");\r\n\r\n mainWindow.webContents.setWindowOpenHandler(() => {\r\n return { action: \"deny\" };\r\n });\r\n\r\n tray = new Tray(path.join(__dirname, \"img\", \"tray.png\"));\r\n const contextMenu = Menu.buildFromTemplate([\r\n {\r\n label: \"Show App\",\r\n click: function () {\r\n mainWindow?.show();\r\n },\r\n },\r\n {\r\n label: \"Quit\",\r\n click: function () {\r\n tray = null;\r\n app.quit();\r\n },\r\n },\r\n ]);\r\n\r\n tray.setToolTip(\"Electron BitNet\");\r\n\r\n tray.on(\"right-click\", (event, bounds) => {\r\n tray?.popUpContextMenu(contextMenu);\r\n });\r\n\r\n const safeDomains = [\r\n \"https://github.com\",\r\n \"https://react.dev/\",\r\n \"https://astro.build/\",\r\n \"https://www.electronjs.org/\"\r\n ];\r\n\r\n ipcMain.on(\"openURL\", (event, arg) => {\r\n try {\r\n const parsedUrl = new url.URL(arg);\r\n const domain = parsedUrl.hostname;\r\n\r\n const isSafeDomain = safeDomains.some((safeDomain) => {\r\n const safeDomainHostname = new url.URL(safeDomain).hostname;\r\n return safeDomainHostname === domain;\r\n });\r\n\r\n if (isSafeDomain) {\r\n shell.openExternal(arg);\r\n } else {\r\n console.error(`Rejected opening URL with unsafe domain: ${domain}`);\r\n }\r\n } catch (err) {\r\n console.error(`Failed to open URL: ${err.message}`);\r\n }\r\n });\r\n\r\n ipcMain.on(\"runInference\", (event, arg) => {\r\n runInference(arg);\r\n });\r\n\r\n ipcMain.on(\"stopInference\", (event) => {\r\n signalHandler();\r\n });\r\n\r\n ipcMain.handle('openFileDialog', async () => {\r\n const result = await dialog.showOpenDialog({\r\n properties: ['openFile'],\r\n filters: [{ name: 'GGUF Files', extensions: ['gguf'] }]\r\n });\r\n return result.filePaths;\r\n });\r\n\r\n tray.on(\"click\", () => {\r\n mainWindow?.setAlwaysOnTop(true);\r\n mainWindow?.show();\r\n mainWindow?.focus();\r\n mainWindow?.setAlwaysOnTop(false);\r\n });\r\n\r\n tray.on(\"balloon-click\", () => {\r\n mainWindow?.setAlwaysOnTop(true);\r\n mainWindow?.show();\r\n mainWindow?.focus();\r\n mainWindow?.setAlwaysOnTop(false);\r\n });\r\n};\r\n\r\nconst currentOS = os.platform();\r\nif (currentOS === \"win32\" || currentOS === \"linux\") {\r\n // windows + linux setup phase\r\n const gotTheLock = app.requestSingleInstanceLock();\r\n\r\n if (!gotTheLock) {\r\n app.quit();\r\n }\r\n\r\n app.whenReady().then(() => {\r\n createWindow();\r\n });\r\n} else {\r\n app.whenReady().then(() => {\r\n createWindow();\r\n });\r\n\r\n app.on(\"window-all-closed\", () => {\r\n if (process.platform !== \"darwin\") {\r\n app.quit();\r\n }\r\n });\r\n\r\n app.on(\"activate\", () => {\r\n if (mainWindow === null) {\r\n createWindow();\r\n }\r\n });\r\n}"],"names":[],"sourceRoot":""} \ No newline at end of file diff --git a/app/preload.js b/app/preload.js index 9ad7a65..2bf5517 100644 --- a/app/preload.js +++ b/app/preload.js @@ -1,2 +1,120 @@ -(()=>{"use strict";const e=require("electron");e.contextBridge.exposeInMainWorld("electron",{openURL:async n=>e.ipcRenderer.send("openURL",n),onAiResponse:n=>{e.ipcRenderer.on("aiResponse",((e,r)=>{n(r)}))},onAiError:n=>{e.ipcRenderer.on("aiError",(e=>{n()}))},onAiComplete:n=>{e.ipcRenderer.on("aiComplete",(e=>{n()}))},runInference:async n=>e.ipcRenderer.send("runInference",n),stopInference:async n=>e.ipcRenderer.send("stopInference",n)})})(); +/******/ (() => { // webpackBootstrap +/******/ "use strict"; +/******/ var __webpack_modules__ = ({ + +/***/ "electron": +/*!***************************!*\ + !*** external "electron" ***! + \***************************/ +/***/ ((module) => { + +module.exports = require("electron"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The module cache +/******/ var __webpack_module_cache__ = {}; +/******/ +/******/ // The require function +/******/ function __webpack_require__(moduleId) { +/******/ // Check if module is in cache +/******/ var cachedModule = __webpack_module_cache__[moduleId]; +/******/ if (cachedModule !== undefined) { +/******/ return cachedModule.exports; +/******/ } +/******/ // Create a new module (and put it into the cache) +/******/ var module = __webpack_module_cache__[moduleId] = { +/******/ // no module.id needed +/******/ // no module.loaded needed +/******/ exports: {} +/******/ }; +/******/ +/******/ // Execute the module function +/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__); +/******/ +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/compat get default export */ +/******/ (() => { +/******/ // getDefaultExport function for compatibility with non-harmony modules +/******/ __webpack_require__.n = (module) => { +/******/ var getter = module && module.__esModule ? +/******/ () => (module['default']) : +/******/ () => (module); +/******/ __webpack_require__.d(getter, { a: getter }); +/******/ return getter; +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/define property getters */ +/******/ (() => { +/******/ // define getter functions for harmony exports +/******/ __webpack_require__.d = (exports, definition) => { +/******/ for(var key in definition) { +/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) { +/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] }); +/******/ } +/******/ } +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/hasOwnProperty shorthand */ +/******/ (() => { +/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) +/******/ })(); +/******/ +/******/ /* webpack/runtime/make namespace object */ +/******/ (() => { +/******/ // define __esModule on exports +/******/ __webpack_require__.r = (exports) => { +/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { +/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); +/******/ } +/******/ Object.defineProperty(exports, '__esModule', { value: true }); +/******/ }; +/******/ })(); +/******/ +/************************************************************************/ +var __webpack_exports__ = {}; +// This entry need to be wrapped in an IIFE because it need to be isolated against other modules in the chunk. +(() => { +/*!************************!*\ + !*** ./src/preload.js ***! + \************************/ +__webpack_require__.r(__webpack_exports__); +/* harmony import */ var electron__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! electron */ "electron"); +/* harmony import */ var electron__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(electron__WEBPACK_IMPORTED_MODULE_0__); + + +electron__WEBPACK_IMPORTED_MODULE_0__.contextBridge.exposeInMainWorld("electron", { + openURL: async (target) => electron__WEBPACK_IMPORTED_MODULE_0__.ipcRenderer.send("openURL", target), + onAiResponse: (func) => { + electron__WEBPACK_IMPORTED_MODULE_0__.ipcRenderer.on("aiResponse", (event, data) => { + func(data); + }); + }, + onAiError: (func) => { + electron__WEBPACK_IMPORTED_MODULE_0__.ipcRenderer.on("aiError", (event) => { + func(); + }); + }, + onAiComplete: (func) => { + electron__WEBPACK_IMPORTED_MODULE_0__.ipcRenderer.on("aiComplete", (event) => { + func(); + }); + }, + runInference: async (args) => electron__WEBPACK_IMPORTED_MODULE_0__.ipcRenderer.send("runInference", args), + stopInference: async (args) => electron__WEBPACK_IMPORTED_MODULE_0__.ipcRenderer.send("stopInference", args), + openFileDialog: async () => electron__WEBPACK_IMPORTED_MODULE_0__.ipcRenderer.invoke("openFileDialog"), +}); + +})(); + +/******/ })() +; //# sourceMappingURL=preload.js.map \ No newline at end of file diff --git a/app/preload.js.map b/app/preload.js.map index b326a34..fdb0711 100644 --- a/app/preload.js.map +++ b/app/preload.js.map @@ -1 +1 @@ -{"version":3,"file":"preload.js","mappings":"mBAAA,MAAM,EAA+BA,QAAQ,YCE7C,EAAAC,cAAcC,kBAAkB,WAAY,CAC1CC,QAASC,MAAOC,GAAW,EAAAC,YAAYC,KAAK,UAAWF,GAEvDG,aAAeC,IACb,EAAAH,YAAYI,GAAG,cAAc,CAACC,EAAOC,KACnCH,EAAKG,EAAK,GACV,EAEJC,UAAYJ,IACV,EAAAH,YAAYI,GAAG,WAAYC,IACzBF,GAAM,GACN,EAEJK,aAAeL,IACb,EAAAH,YAAYI,GAAG,cAAeC,IAC5BF,GAAM,GACN,EAEJM,aAAcX,MAAOY,GAAS,EAAAV,YAAYC,KAAK,eAAgBS,GAC/DC,cAAeb,MAAOY,GAAS,EAAAV,YAAYC,KAAK,gBAAiBS,I","sources":["webpack://electron-bitnet/external node-commonjs \"electron\"","webpack://electron-bitnet/./src/preload.js"],"sourcesContent":["const __WEBPACK_NAMESPACE_OBJECT__ = require(\"electron\");","import { ipcRenderer, contextBridge } from \"electron\";\r\n\r\ncontextBridge.exposeInMainWorld(\"electron\", {\r\n openURL: async (target) => ipcRenderer.send(\"openURL\", target),\r\n // on aiResponse\r\n onAiResponse: (func) => {\r\n ipcRenderer.on(\"aiResponse\", (event, data) => {\r\n func(data);\r\n });\r\n },\r\n onAiError: (func) => {\r\n ipcRenderer.on(\"aiError\", (event) => {\r\n func();\r\n });\r\n },\r\n onAiComplete: (func) => {\r\n ipcRenderer.on(\"aiComplete\", (event) => {\r\n func();\r\n });\r\n },\r\n runInference: async (args) => ipcRenderer.send(\"runInference\", args),\r\n stopInference: async (args) => ipcRenderer.send(\"stopInference\", args)\r\n});\r\n"],"names":["require","contextBridge","exposeInMainWorld","openURL","async","target","ipcRenderer","send","onAiResponse","func","on","event","data","onAiError","onAiComplete","runInference","args","stopInference"],"sourceRoot":""} \ No newline at end of file +{"version":3,"file":"preload.js","mappings":";;;;;;;;;;AAAA;;;;;;UCAA;UACA;;UAEA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;;UAEA;UACA;;UAEA;UACA;UACA;;;;;WCtBA;WACA;WACA;WACA;WACA;WACA,iCAAiC,WAAW;WAC5C;WACA;;;;;WCPA;WACA;WACA;WACA;WACA,yCAAyC,wCAAwC;WACjF;WACA;WACA;;;;;WCPA;;;;;WCAA;WACA;WACA;WACA,uDAAuD,iBAAiB;WACxE;WACA,gDAAgD,aAAa;WAC7D;;;;;;;;;;;;;ACNsD;AACtD;AACA,mDAAa;AACb,6BAA6B,iDAAW;AACxC;AACA,IAAI,iDAAW;AACf;AACA,KAAK;AACL,GAAG;AACH;AACA,IAAI,iDAAW;AACf;AACA,KAAK;AACL,GAAG;AACH;AACA,IAAI,iDAAW;AACf;AACA,KAAK;AACL,GAAG;AACH,gCAAgC,iDAAW;AAC3C,iCAAiC,iDAAW;AAC5C,8BAA8B,iDAAW;AACzC,CAAC","sources":["webpack://electron-bitnet/external node-commonjs \"electron\"","webpack://electron-bitnet/webpack/bootstrap","webpack://electron-bitnet/webpack/runtime/compat get default export","webpack://electron-bitnet/webpack/runtime/define property getters","webpack://electron-bitnet/webpack/runtime/hasOwnProperty shorthand","webpack://electron-bitnet/webpack/runtime/make namespace object","webpack://electron-bitnet/./src/preload.js"],"sourcesContent":["module.exports = require(\"electron\");","// The module cache\nvar __webpack_module_cache__ = {};\n\n// The require function\nfunction __webpack_require__(moduleId) {\n\t// Check if module is in cache\n\tvar cachedModule = __webpack_module_cache__[moduleId];\n\tif (cachedModule !== undefined) {\n\t\treturn cachedModule.exports;\n\t}\n\t// Create a new module (and put it into the cache)\n\tvar module = __webpack_module_cache__[moduleId] = {\n\t\t// no module.id needed\n\t\t// no module.loaded needed\n\t\texports: {}\n\t};\n\n\t// Execute the module function\n\t__webpack_modules__[moduleId](module, module.exports, __webpack_require__);\n\n\t// Return the exports of the module\n\treturn module.exports;\n}\n\n","// getDefaultExport function for compatibility with non-harmony modules\n__webpack_require__.n = (module) => {\n\tvar getter = module && module.__esModule ?\n\t\t() => (module['default']) :\n\t\t() => (module);\n\t__webpack_require__.d(getter, { a: getter });\n\treturn getter;\n};","// define getter functions for harmony exports\n__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n\t\t}\n\t}\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","import { ipcRenderer, contextBridge } from \"electron\";\r\n\r\ncontextBridge.exposeInMainWorld(\"electron\", {\r\n openURL: async (target) => ipcRenderer.send(\"openURL\", target),\r\n onAiResponse: (func) => {\r\n ipcRenderer.on(\"aiResponse\", (event, data) => {\r\n func(data);\r\n });\r\n },\r\n onAiError: (func) => {\r\n ipcRenderer.on(\"aiError\", (event) => {\r\n func();\r\n });\r\n },\r\n onAiComplete: (func) => {\r\n ipcRenderer.on(\"aiComplete\", (event) => {\r\n func();\r\n });\r\n },\r\n runInference: async (args) => ipcRenderer.send(\"runInference\", args),\r\n stopInference: async (args) => ipcRenderer.send(\"stopInference\", args),\r\n openFileDialog: async () => ipcRenderer.invoke(\"openFileDialog\"),\r\n});\r\n"],"names":[],"sourceRoot":""} \ No newline at end of file diff --git a/package.json b/package.json index a6292da..e9b3491 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,10 @@ "appId": "ElectronBitnet", "productName": "ElectronBitnet", "artifactName": "ElectronBitnet.${ext}", + "asar": false, + "npmRebuild": false, + "buildDependenciesFromSource": false, + "includeSubNodeModules": true, "files": [ "app/**/*", "bin/**/*", @@ -24,6 +28,10 @@ { "from": "./astroDist", "to": "astroDist" + }, + { + "from": "./bin", + "to": "bin" } ], "directories": { diff --git a/src/background.js b/src/background.js index 71374db..c5e385d 100644 --- a/src/background.js +++ b/src/background.js @@ -15,10 +15,10 @@ let tray = null; let inferenceProcess = null; function runInference(args) { - let mainPath = path.join('bin', 'Release', 'llama-cli.exe'); + let mainPath = path.join(app.getAppPath(), 'bin', 'Release', 'llama-cli.exe'); if (!fs.existsSync(mainPath)) { - mainPath = path.join('bin', 'llama-cli'); + mainPath = path.join(app.getAppPath(), 'bin', 'llama-cli'); } const command = [