From 1451496829e09e913fa83f4aa49b146216c47744 Mon Sep 17 00:00:00 2001 From: Parker Smith Date: Sat, 2 Mar 2024 17:13:48 -0700 Subject: [PATCH 1/5] [MLC-37] app: First step towards production build --- app/main/main.ts | 4 +- app/notarize.js | 18 +++++ app/package-lock.json | 124 +++++++++++++++++++++++------ app/package.json | 19 ++++- app/src/components/ui/textarea.tsx | 4 +- 5 files changed, 137 insertions(+), 32 deletions(-) create mode 100644 app/notarize.js diff --git a/app/main/main.ts b/app/main/main.ts index cb603e2..e0e0567 100644 --- a/app/main/main.ts +++ b/app/main/main.ts @@ -50,7 +50,7 @@ class ServerManager { const modifiedArgs = args.flatMap(arg => arg.split(/\s+/)); const pythonProcess = spawn('python', ['-m', 'server.server', ...modifiedArgs], { - cwd: '../', + cwd: isProd ? process.resourcesPath : '../', }); pythonProcess.stdout.on( 'data', @@ -280,7 +280,7 @@ const createWindow = () => { }); if (isProd) { - settingsModal.loadURL('app://./home.html'); + settingsModal.loadURL('app://./settings.html'); } else { // const port = process.argv[2]; settingsModal.loadURL('http://localhost:3000/settings'); diff --git a/app/notarize.js b/app/notarize.js new file mode 100644 index 0000000..34f4a47 --- /dev/null +++ b/app/notarize.js @@ -0,0 +1,18 @@ +require('dotenv').config(); +const { notarize } = require('electron-notarize'); + +exports.default = async function notarizing(context) { + const { electronPlatformName, appOutDir } = context; + if (electronPlatformName !== 'darwin') { + return; + } + + const appName = context.packager.appInfo.productFilename; + + return await notarize({ + appBundleId: 'com.parkersmith.mlx-chat', + appPath: `${appOutDir}/${appName}.app`, + appleId: process.env.APPLEID, + appleIdPassword: process.env.APPLEIDPASS, + }); +}; diff --git a/app/package-lock.json b/app/package-lock.json index 4595c02..72552e3 100644 --- a/app/package-lock.json +++ b/app/package-lock.json @@ -8,6 +8,7 @@ "name": "electron-app", "version": "0.1.0", "dependencies": { + "@electron/osx-sign": "^1.0.5", "@fortawesome/fontawesome-free": "^6.5.1", "@fortawesome/fontawesome-svg-core": "^6.5.1", "@fortawesome/free-regular-svg-icons": "^6.5.1", @@ -52,6 +53,7 @@ "dprint": "^0.45.0", "electron": "^26.2.0", "electron-builder": "^24.6.4", + "electron-notarize": "^1.2.2", "eslint": "^8.56.0", "eslint-config-airbnb-base": "^15.0.0", "eslint-plugin-compat": "^4.2.0", @@ -315,7 +317,6 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/@electron/osx-sign/-/osx-sign-1.0.5.tgz", "integrity": "sha512-k9ZzUQtamSoweGQDV2jILiRIHUu7lYlJ3c6IEmjv1hC17rclE+eb9U+f6UFlOOETo0JzY1HNlXy4YOlCvl+Lww==", - "dev": true, "dependencies": { "compare-version": "^0.1.2", "debug": "^4.3.4", @@ -336,7 +337,6 @@ "version": "10.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", - "dev": true, "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", @@ -350,7 +350,6 @@ "version": "4.0.10", "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.10.tgz", "integrity": "sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw==", - "dev": true, "engines": { "node": ">= 8.0.0" }, @@ -362,7 +361,6 @@ "version": "6.1.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "dev": true, "dependencies": { "universalify": "^2.0.0" }, @@ -374,7 +372,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", - "dev": true, "engines": { "node": ">= 10.0.0" } @@ -2087,7 +2084,6 @@ "version": "0.8.10", "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.10.tgz", "integrity": "sha512-2WALfTl4xo2SkGCYRt6rDTFfk9R1czmBvUQy12gK2KuRKIpWEhcbbzy8EZXtz/jkRqHX8bFEc6FC1HjX4TUWYw==", - "dev": true, "engines": { "node": ">=10.0.0" } @@ -2638,7 +2634,6 @@ "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "dev": true, "funding": [ { "type": "github", @@ -3208,7 +3203,6 @@ "version": "0.1.2", "resolved": "https://registry.npmjs.org/compare-version/-/compare-version-0.1.2.tgz", "integrity": "sha512-pJDh5/4wrEnXX/VWRZvruAGHkzKdr46z11OlTPN+VrATlWWhSKewNCJ1futCO5C7eJB3nPMFZA1LeYtcFboZ2A==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -3874,6 +3868,56 @@ "node": ">= 10.0.0" } }, + "node_modules/electron-notarize": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/electron-notarize/-/electron-notarize-1.2.2.tgz", + "integrity": "sha512-ZStVWYcWI7g87/PgjPJSIIhwQXOaw4/XeXU+pWqMMktSLHaGMLHdyPPN7Cmao7+Cr7fYufA16npdtMndYciHNw==", + "deprecated": "Please use @electron/notarize moving forward. There is no API change, just a package name change", + "dev": true, + "dependencies": { + "debug": "^4.1.1", + "fs-extra": "^9.0.1" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/electron-notarize/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/electron-notarize/node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/electron-notarize/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "engines": { + "node": ">= 10.0.0" + } + }, "node_modules/electron-publish": { "version": "24.5.0", "resolved": "https://registry.npmjs.org/electron-publish/-/electron-publish-24.5.0.tgz", @@ -7129,7 +7173,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/plist/-/plist-3.1.0.tgz", "integrity": "sha512-uysumyrvkUX0rX/dEVqt8gC3sTBzd4zoWfLeS29nb53imdaXVvLINYXTI2GNqzaMuvacNx4uJQ8+b3zXR0pkgQ==", - "dev": true, "dependencies": { "@xmldom/xmldom": "^0.8.8", "base64-js": "^1.5.1", @@ -9001,7 +9044,6 @@ "version": "15.1.1", "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-15.1.1.tgz", "integrity": "sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==", - "dev": true, "engines": { "node": ">=8.0" } @@ -9247,7 +9289,6 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/@electron/osx-sign/-/osx-sign-1.0.5.tgz", "integrity": "sha512-k9ZzUQtamSoweGQDV2jILiRIHUu7lYlJ3c6IEmjv1hC17rclE+eb9U+f6UFlOOETo0JzY1HNlXy4YOlCvl+Lww==", - "dev": true, "requires": { "compare-version": "^0.1.2", "debug": "^4.3.4", @@ -9261,7 +9302,6 @@ "version": "10.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", - "dev": true, "requires": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", @@ -9271,14 +9311,12 @@ "isbinaryfile": { "version": "4.0.10", "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.10.tgz", - "integrity": "sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw==", - "dev": true + "integrity": "sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw==" }, "jsonfile": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "dev": true, "requires": { "graceful-fs": "^4.1.6", "universalify": "^2.0.0" @@ -9287,8 +9325,7 @@ "universalify": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", - "dev": true + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==" } } }, @@ -10383,8 +10420,7 @@ "@xmldom/xmldom": { "version": "0.8.10", "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.10.tgz", - "integrity": "sha512-2WALfTl4xo2SkGCYRt6rDTFfk9R1czmBvUQy12gK2KuRKIpWEhcbbzy8EZXtz/jkRqHX8bFEc6FC1HjX4TUWYw==", - "dev": true + "integrity": "sha512-2WALfTl4xo2SkGCYRt6rDTFfk9R1czmBvUQy12gK2KuRKIpWEhcbbzy8EZXtz/jkRqHX8bFEc6FC1HjX4TUWYw==" }, "7zip-bin": { "version": "5.1.1", @@ -10794,8 +10830,7 @@ "base64-js": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "dev": true + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" }, "big-integer": { "version": "1.6.51", @@ -11174,8 +11209,7 @@ "compare-version": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/compare-version/-/compare-version-0.1.2.tgz", - "integrity": "sha512-pJDh5/4wrEnXX/VWRZvruAGHkzKdr46z11OlTPN+VrATlWWhSKewNCJ1futCO5C7eJB3nPMFZA1LeYtcFboZ2A==", - "dev": true + "integrity": "sha512-pJDh5/4wrEnXX/VWRZvruAGHkzKdr46z11OlTPN+VrATlWWhSKewNCJ1futCO5C7eJB3nPMFZA1LeYtcFboZ2A==" }, "concat-map": { "version": "0.0.1", @@ -11658,6 +11692,46 @@ } } }, + "electron-notarize": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/electron-notarize/-/electron-notarize-1.2.2.tgz", + "integrity": "sha512-ZStVWYcWI7g87/PgjPJSIIhwQXOaw4/XeXU+pWqMMktSLHaGMLHdyPPN7Cmao7+Cr7fYufA16npdtMndYciHNw==", + "dev": true, + "requires": { + "debug": "^4.1.1", + "fs-extra": "^9.0.1" + }, + "dependencies": { + "fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "requires": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + }, + "jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6", + "universalify": "^2.0.0" + } + }, + "universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true + } + } + }, "electron-publish": { "version": "24.5.0", "resolved": "https://registry.npmjs.org/electron-publish/-/electron-publish-24.5.0.tgz", @@ -13918,7 +13992,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/plist/-/plist-3.1.0.tgz", "integrity": "sha512-uysumyrvkUX0rX/dEVqt8gC3sTBzd4zoWfLeS29nb53imdaXVvLINYXTI2GNqzaMuvacNx4uJQ8+b3zXR0pkgQ==", - "dev": true, "requires": { "@xmldom/xmldom": "^0.8.8", "base64-js": "^1.5.1", @@ -15187,8 +15260,7 @@ "xmlbuilder": { "version": "15.1.1", "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-15.1.1.tgz", - "integrity": "sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==", - "dev": true + "integrity": "sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==" }, "y18n": { "version": "5.0.8", diff --git a/app/package.json b/app/package.json index da7decb..e221aba 100644 --- a/app/package.json +++ b/app/package.json @@ -23,6 +23,7 @@ "lint": "npx eslint --max-warnings 0 --ext=.ts ." }, "dependencies": { + "@electron/osx-sign": "^1.0.5", "@fortawesome/fontawesome-free": "^6.5.1", "@fortawesome/fontawesome-svg-core": "^6.5.1", "@fortawesome/free-regular-svg-icons": "^6.5.1", @@ -67,6 +68,7 @@ "dprint": "^0.45.0", "electron": "^26.2.0", "electron-builder": "^24.6.4", + "electron-notarize": "^1.2.2", "eslint": "^8.56.0", "eslint-config-airbnb-base": "^15.0.0", "eslint-plugin-compat": "^4.2.0", @@ -85,6 +87,7 @@ "build": { "appId": "mlx-chat", "productName": "MLX Chat", + "afterSign": "notarize.js", "win": { "target": [ "nsis" @@ -101,10 +104,15 @@ "target": [ "dmg" ], - "icon": "assets/icon.icns" + "gatekeeperAssess": false, + "hardenedRuntime": true, + "icon": "assets/icon.icns", + "entitlements": "/Users/parker/Desktop/SideProjects/mlx-chat-app/app/build/entitlements.mac.inherit.plist", + "entitlementsInherit": "/Users/parker/Desktop/SideProjects/mlx-chat-app/app/build/entitlements.mac.inherit.plist" }, "dmg": { - "title": "MLX Chat Installer" + "title": "MLX Chat Installer", + "sign": false }, "extraFiles": [ { @@ -113,6 +121,13 @@ "filter": [ "**/*" ] + }, + { + "from": "../server", + "to": "resources/server", + "filter": [ + "**/*" + ] } ] } diff --git a/app/src/components/ui/textarea.tsx b/app/src/components/ui/textarea.tsx index df34af0..b5aabf9 100644 --- a/app/src/components/ui/textarea.tsx +++ b/app/src/components/ui/textarea.tsx @@ -1,7 +1,7 @@ +import * as React from 'react'; import { cn, -} from '@/lib/utils'; -import * as React from 'react'; +} from '../../lib/utils'; export interface TextareaProps extends React.TextareaHTMLAttributes {} From 1ebaefa0b8726f0c43404867657d557f80513c85 Mon Sep 17 00:00:00 2001 From: Parker Smith Date: Sat, 2 Mar 2024 17:54:25 -0700 Subject: [PATCH 2/5] [MLC-37] app: Enable app to use executable and wait for init of model --- app/main/main.ts | 40 ++++++++++++++++++++++++++++++---------- app/package.json | 2 +- 2 files changed, 31 insertions(+), 11 deletions(-) diff --git a/app/main/main.ts b/app/main/main.ts index e0e0567..7255fba 100644 --- a/app/main/main.ts +++ b/app/main/main.ts @@ -1,5 +1,8 @@ // Main File for Electron +import { + execFile, +} from 'child_process'; import { app, BrowserWindow, @@ -45,13 +48,17 @@ class ServerManager { }); } - private runPythonServer(model: string, port: number): any { - const args = [`--model ${model}`, '--host 127.0.0.1', `--port ${port}`]; + private runPythonServer(port: number): any { + const args = ['--host 127.0.0.1', `--port ${port}`]; const modifiedArgs = args.flatMap(arg => arg.split(/\s+/)); - const pythonProcess = spawn('python', ['-m', 'server.server', ...modifiedArgs], { - cwd: isProd ? process.resourcesPath : '../', - }); + const pythonProcess = !isProd + ? execFile(path.join('dist', 'runner'), modifiedArgs, { + cwd: '../', + }) + : spawn('python', ['-m', 'server.server', ...modifiedArgs], { + cwd: '../', + }); pythonProcess.stdout.on( 'data', (data: Buffer) => console.log('Server output:', data.toString('utf8')), @@ -69,16 +76,29 @@ class ServerManager { this.stop(); this.findOpenPort(8080).then((port) => { - console.log(`Starting server for model: ${model} on port: ${port}`); - this.serverProcess = this.runPythonServer(model, port); + console.log(`APP: Starting server for model: ${model} on port: ${port}`); + this.serverProcess = this.runPythonServer(port); - this.serverProcess.stdout.on('data', (data: Buffer) => { + this.serverProcess.stdout.on('data', async (data: Buffer) => { const output = data.toString('utf8'); console.log('Server output:', output); + await new Promise((resolve) => setTimeout(resolve, 1000)); + // Check if the server is ready - if (output.includes('starting server on')) { - resolve(); // Resolve the promise when the server is ready + if (output.includes('Starting httpd')) { + fetch(`http://127.0.0.1:${port}/api/init`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ model }), + }).then(() => { + resolve(); // Resolve the promise when the server is ready + }).catch((err) => { + console.error('Error initializing the server:', err); + reject(err); + }); } }); diff --git a/app/package.json b/app/package.json index e221aba..4045ffe 100644 --- a/app/package.json +++ b/app/package.json @@ -123,7 +123,7 @@ ] }, { - "from": "../server", + "from": "../dist", "to": "resources/server", "filter": [ "**/*" From 3e870660305adb9eeede2e4204c0531f42ded1a2 Mon Sep 17 00:00:00 2001 From: Parker Smith Date: Sat, 2 Mar 2024 17:54:45 -0700 Subject: [PATCH 3/5] [MLC-37] server: Remove model loading from starting of script, move to endpoint --- server/__init__.py | 2 +- server/server.py | 70 ++++++++++++++++++++++++++-------------------- 2 files changed, 41 insertions(+), 31 deletions(-) diff --git a/server/__init__.py b/server/__init__.py index 92fe283..afdb63b 100644 --- a/server/__init__.py +++ b/server/__init__.py @@ -1,3 +1,3 @@ from .utils import generate, load, convert -__version__ = "0.0.14" +__version__ = "0.1.0" diff --git a/server/server.py b/server/server.py index f04befc..f34b60c 100644 --- a/server/server.py +++ b/server/server.py @@ -1,7 +1,8 @@ import json +import os import time import uuid -import argparse +import sys import mlx.core as mx import mlx.nn as nn @@ -119,6 +120,13 @@ def do_POST(self): directory: str } + Endpoint: /api/init + Desc: initializes the model + Body: + { + model: str + } + Endpoint: /api/query Desc: handles messages requests (with directory index) Body: @@ -137,6 +145,7 @@ def do_POST(self): method = { '/api/index': self.index, '/api/query': self.query, + '/api/init': self.init, } handle = method.get(self.path, None) if handle is None: @@ -158,6 +167,11 @@ def index(self, body): index_directory(directory) return {'directory': directory} + def init(self, body): + model = body.get('model', None) + load_model(model) + return {'model': model} + def query(self, body): chat_id = f'chatcmpl-{uuid.uuid4()}' @@ -211,40 +225,36 @@ def query(self, body): def run(host: str, port: int, server_class=HTTPServer, handler_class=APIHandler): server_address = (host, port) httpd = server_class(server_address, handler_class) - print(f'Starting httpd at {host} on port {port}...') + print(f'Starting httpd at {host} on port {port}...', flush=True) httpd.serve_forever() def main(): - parser = argparse.ArgumentParser(description='MLX Http Server.') - parser.add_argument( - '--model', - type=str, - required=True, - help='The path to the MLX model weights, tokenizer, and config', - ) - parser.add_argument( - '--adapter-file', - type=str, - help='Optional path for the trained adapter weights.', - ) - parser.add_argument( - '--host', - type=str, - default='127.0.0.1', - help='Host for the HTTP server (default: 127.0.0.1)', - ) - parser.add_argument( - '--port', - type=int, - default=8080, - help='Port for the HTTP server (default: 8080)', - ) - args = parser.parse_args() + if len(sys.argv) < 2: + print( + "Usage: python script.py [--host ] [--port ]") + sys.exit(1) + + args = { + '--host': '127.0.0.1', + '--port': 8080 + } - load_model(args.model, adapter_file=args.adapter_file) - print(f'>> starting server on {args.host}:{args.port}', flush=True) - run(args.host, args.port) + i = 1 + while i < len(sys.argv): + if sys.argv[i] in args: + args[sys.argv[i]] = sys.argv[i + 1] + i += 2 + else: + print(f"Unknown argument: {sys.argv[i]}") + sys.exit(1) + + # Now you can access the parsed arguments using args dictionary + host = args['--host'] + port = int(args['--port']) + + print(f'>> starting server on {host}:{port}', flush=True) + run(host, port) if __name__ == '__main__': From 045858360aea44b011f537f7d92b0c4318936c1b Mon Sep 17 00:00:00 2001 From: Parker Smith Date: Sun, 3 Mar 2024 10:10:51 -0700 Subject: [PATCH 4/5] [MLC-37] app: Update main to use new runner --- app/main/main.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/app/main/main.ts b/app/main/main.ts index 7255fba..38546fd 100644 --- a/app/main/main.ts +++ b/app/main/main.ts @@ -52,10 +52,8 @@ class ServerManager { const args = ['--host 127.0.0.1', `--port ${port}`]; const modifiedArgs = args.flatMap(arg => arg.split(/\s+/)); - const pythonProcess = !isProd - ? execFile(path.join('dist', 'runner'), modifiedArgs, { - cwd: '../', - }) + const pythonProcess = isProd + ? execFile(path.join(process.resourcesPath, 'server', 'runner'), modifiedArgs) : spawn('python', ['-m', 'server.server', ...modifiedArgs], { cwd: '../', }); From a9fff2b87517ea7d2e969bd53d3004f40d4a11db Mon Sep 17 00:00:00 2001 From: Parker Smith Date: Sun, 3 Mar 2024 14:00:41 -0700 Subject: [PATCH 5/5] [MLC-37] app: Final productionization --- app/mac/entitlements.mac.inherit.plist | 12 ++++++++++ app/package-lock.json | 33 ++++++++++++++++++++------ app/package.json | 5 ++-- 3 files changed, 41 insertions(+), 9 deletions(-) create mode 100644 app/mac/entitlements.mac.inherit.plist diff --git a/app/mac/entitlements.mac.inherit.plist b/app/mac/entitlements.mac.inherit.plist new file mode 100644 index 0000000..9a279dc --- /dev/null +++ b/app/mac/entitlements.mac.inherit.plist @@ -0,0 +1,12 @@ + + + + + com.apple.security.cs.allow-jit + + com.apple.security.cs.allow-unsigned-executable-memory + + com.apple.security.cs.disable-library-validation + + + diff --git a/app/package-lock.json b/app/package-lock.json index 72552e3..2390ae4 100644 --- a/app/package-lock.json +++ b/app/package-lock.json @@ -50,6 +50,7 @@ "devDependencies": { "@typescript-eslint/eslint-plugin": "^6.21.0", "@typescript-eslint/parser": "^6.21.0", + "dotenv": "^16.4.5", "dprint": "^0.45.0", "electron": "^26.2.0", "electron-builder": "^24.6.4", @@ -3742,12 +3743,15 @@ } }, "node_modules/dotenv": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-9.0.2.tgz", - "integrity": "sha512-I9OvvrHp4pIARv4+x9iuewrWycX6CcZtoAu1XrzPxc5UygMJXJZYmBsynku8IkrJwgypE5DGNjDPmPRhDCptUg==", + "version": "16.4.5", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz", + "integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==", "dev": true, "engines": { - "node": ">=10" + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" } }, "node_modules/dotenv-expand": { @@ -7555,6 +7559,15 @@ "node": ">=12.0.0" } }, + "node_modules/read-config-file/node_modules/dotenv": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-9.0.2.tgz", + "integrity": "sha512-I9OvvrHp4pIARv4+x9iuewrWycX6CcZtoAu1XrzPxc5UygMJXJZYmBsynku8IkrJwgypE5DGNjDPmPRhDCptUg==", + "dev": true, + "engines": { + "node": ">=10" + } + }, "node_modules/read-config-file/node_modules/json5": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", @@ -11592,9 +11605,9 @@ } }, "dotenv": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-9.0.2.tgz", - "integrity": "sha512-I9OvvrHp4pIARv4+x9iuewrWycX6CcZtoAu1XrzPxc5UygMJXJZYmBsynku8IkrJwgypE5DGNjDPmPRhDCptUg==", + "version": "16.4.5", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz", + "integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==", "dev": true }, "dotenv-expand": { @@ -14206,6 +14219,12 @@ "lazy-val": "^1.0.4" }, "dependencies": { + "dotenv": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-9.0.2.tgz", + "integrity": "sha512-I9OvvrHp4pIARv4+x9iuewrWycX6CcZtoAu1XrzPxc5UygMJXJZYmBsynku8IkrJwgypE5DGNjDPmPRhDCptUg==", + "dev": true + }, "json5": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", diff --git a/app/package.json b/app/package.json index 4045ffe..c8d0caf 100644 --- a/app/package.json +++ b/app/package.json @@ -65,6 +65,7 @@ "devDependencies": { "@typescript-eslint/eslint-plugin": "^6.21.0", "@typescript-eslint/parser": "^6.21.0", + "dotenv": "^16.4.5", "dprint": "^0.45.0", "electron": "^26.2.0", "electron-builder": "^24.6.4", @@ -107,8 +108,8 @@ "gatekeeperAssess": false, "hardenedRuntime": true, "icon": "assets/icon.icns", - "entitlements": "/Users/parker/Desktop/SideProjects/mlx-chat-app/app/build/entitlements.mac.inherit.plist", - "entitlementsInherit": "/Users/parker/Desktop/SideProjects/mlx-chat-app/app/build/entitlements.mac.inherit.plist" + "entitlements": "./mac/entitlements.mac.inherit.plist", + "entitlementsInherit": "./mac/entitlements.mac.inherit.plist" }, "dmg": { "title": "MLX Chat Installer",