From 1b4f9028355177668aad143b4578e0388898995b Mon Sep 17 00:00:00 2001 From: marknguyen1302 Date: Tue, 6 Aug 2024 19:09:08 +0700 Subject: [PATCH 01/20] fix: correct swagger port (#980) --- cortex-js/src/app.ts | 2 +- cortex-js/src/index.ts | 3 +-- cortex-js/src/main.ts | 3 +-- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/cortex-js/src/app.ts b/cortex-js/src/app.ts index c02edd428..53104b886 100644 --- a/cortex-js/src/app.ts +++ b/cortex-js/src/app.ts @@ -26,7 +26,7 @@ export const getApp = async (host?: string, port?: number) => { enableDebugMessages: true, }), ); - + cleanLogs(); const config = new DocumentBuilder() .setTitle('Cortex API') diff --git a/cortex-js/src/index.ts b/cortex-js/src/index.ts index 601955bf4..4d31b2eeb 100644 --- a/cortex-js/src/index.ts +++ b/cortex-js/src/index.ts @@ -12,11 +12,10 @@ import { CortexUsecases } from './usecases/cortex/cortex.usecases'; * Start the API server */ export async function start(host?: string, port?: number) { - const app = await getApp(host, port); // getting port from env const sHost = host || process.env.CORTEX_JS_HOST || defaultCortexJsHost; const sPort = port || process.env.CORTEX_JS_PORT || defaultCortexJsPort; - + const app = await getApp(sHost, Number(sPort)); try { await app.listen(sPort, sHost); const cortexUsecases = await app.resolve(CortexUsecases); diff --git a/cortex-js/src/main.ts b/cortex-js/src/main.ts index 1a43ca318..988e55426 100644 --- a/cortex-js/src/main.ts +++ b/cortex-js/src/main.ts @@ -6,11 +6,10 @@ import { getApp } from './app'; import chalk from 'chalk'; async function bootstrap() { - const app = await getApp(); // getting port from env const host = process.env.CORTEX_JS_HOST || defaultCortexJsHost; const port = process.env.CORTEX_JS_PORT || defaultCortexJsPort; - + const app = await getApp(host, Number(port)); try { await app.listen(port, host); console.log(chalk.blue(`Started server at http://${host}:${port}`)); From 4c53713e48995d365a9ed1f90239dad9637b2c9f Mon Sep 17 00:00:00 2001 From: Louis Date: Tue, 6 Aug 2024 19:31:56 +0700 Subject: [PATCH 02/20] chore: name cortex processes (#983) --- cortex-js/src/command.ts | 1 + cortex-js/src/index.ts | 7 ++----- .../commanders/cortex-command.commander.ts | 6 ++---- .../infrastructure/commanders/serve-stop.command.ts | 1 - cortex-js/src/main.ts | 13 ++++++------- cortex-js/src/usecases/cortex/cortex.usecases.ts | 1 - cortex-js/src/utils/cortex-cpp.ts | 1 + 7 files changed, 12 insertions(+), 18 deletions(-) diff --git a/cortex-js/src/command.ts b/cortex-js/src/command.ts index 72de34dcb..37aa2a77a 100644 --- a/cortex-js/src/command.ts +++ b/cortex-js/src/command.ts @@ -13,6 +13,7 @@ dependenciesSpinner.succeed( ); process.removeAllListeners('warning'); +process.title = 'Cortex CLI Command Process'; async function bootstrap() { let telemetryUseCase: TelemetryUsecases | null = null; diff --git a/cortex-js/src/index.ts b/cortex-js/src/index.ts index 4d31b2eeb..c383a5417 100644 --- a/cortex-js/src/index.ts +++ b/cortex-js/src/index.ts @@ -5,7 +5,6 @@ import { defaultCortexJsPort, } from '@/infrastructure/constants/cortex'; import { getApp } from './app'; -import chalk from 'chalk'; import { CortexUsecases } from './usecases/cortex/cortex.usecases'; /** @@ -20,10 +19,8 @@ export async function start(host?: string, port?: number) { await app.listen(sPort, sHost); const cortexUsecases = await app.resolve(CortexUsecases); await cortexUsecases.startCortex(); - console.log(chalk.blue(`Started server at http://${sHost}:${sPort}`)); - console.log( - chalk.blue(`API Playground available at http://${sHost}:${sPort}/api`), - ); + console.log(`Started server at http://${sHost}:${sPort}`); + console.log(`API Playground available at http://${sHost}:${sPort}/api`); } catch { console.error(`Failed to start server. Is port ${port} in use?`); } diff --git a/cortex-js/src/infrastructure/commanders/cortex-command.commander.ts b/cortex-js/src/infrastructure/commanders/cortex-command.commander.ts index ddc24d2d2..98746894c 100644 --- a/cortex-js/src/infrastructure/commanders/cortex-command.commander.ts +++ b/cortex-js/src/infrastructure/commanders/cortex-command.commander.ts @@ -91,7 +91,7 @@ export class CortexCommand extends CommandRunner { this.host = options?.address || configApiServerHost || defaultCortexJsHost; this.port = options?.port || configApiServerPort || defaultCortexJsPort; - if(this.host === 'localhost') { + if (this.host === 'localhost') { this.host = '127.0.0.1'; } this.enginePort = @@ -122,9 +122,7 @@ export class CortexCommand extends CommandRunner { const isServerOnline = await this.cortexUseCases.isAPIServerOnline(); if (isServerOnline) { console.log( - chalk.blue( - `Server is already running at http://${this.configHost}:${this.configPort}. Please use 'cortex stop' to stop the server.`, - ), + `Server is already running at http://${this.configHost}:${this.configPort}. Please use 'cortex stop' to stop the server.`, ); process.exit(0); } diff --git a/cortex-js/src/infrastructure/commanders/serve-stop.command.ts b/cortex-js/src/infrastructure/commanders/serve-stop.command.ts index 3fa96be9e..ea9039a4d 100644 --- a/cortex-js/src/infrastructure/commanders/serve-stop.command.ts +++ b/cortex-js/src/infrastructure/commanders/serve-stop.command.ts @@ -1,7 +1,6 @@ import { SubCommand } from 'nest-commander'; import { BaseCommand } from './base.command'; import { CortexUsecases } from '@/usecases/cortex/cortex.usecases'; -import { FileManagerService } from '../services/file-manager/file-manager.service'; @SubCommand({ name: 'stop', diff --git a/cortex-js/src/main.ts b/cortex-js/src/main.ts index 988e55426..19c3e4d74 100644 --- a/cortex-js/src/main.ts +++ b/cortex-js/src/main.ts @@ -3,7 +3,8 @@ import { defaultCortexJsPort, } from '@/infrastructure/constants/cortex'; import { getApp } from './app'; -import chalk from 'chalk'; + +process.title = 'Cortex API Server'; async function bootstrap() { // getting port from env @@ -12,12 +13,10 @@ async function bootstrap() { const app = await getApp(host, Number(port)); try { await app.listen(port, host); - console.log(chalk.blue(`Started server at http://${host}:${port}`)); - console.log( - chalk.blue(`API Playground available at http://${host}:${port}/api`), - ); - } catch { - console.error(`Failed to start server. Is port ${port} in use?`); + console.log(`Started server at http://${host}:${port}`); + console.log(`API Playground available at http://${host}:${port}/api`); + } catch (error) { + console.error(`Failed to start server. Is port ${port} in use? ${error}`); } } diff --git a/cortex-js/src/usecases/cortex/cortex.usecases.ts b/cortex-js/src/usecases/cortex/cortex.usecases.ts index 400c76163..01bf1ed09 100644 --- a/cortex-js/src/usecases/cortex/cortex.usecases.ts +++ b/cortex-js/src/usecases/cortex/cortex.usecases.ts @@ -206,7 +206,6 @@ export class CortexUsecases implements BeforeApplicationShutdown { // for backward compatibility, we didn't have the apiServerHost and apiServerPort in the config file in the past const apiServerHost = configApiServerHost || defaultCortexJsHost; const apiServerPort = configApiServerPort || defaultCortexJsPort; - await this.stopCortex(); return fetch(CORTEX_JS_SYSTEM_URL(apiServerHost, apiServerPort), { method: 'DELETE', }).catch(() => {}); diff --git a/cortex-js/src/utils/cortex-cpp.ts b/cortex-js/src/utils/cortex-cpp.ts index 3efd755dd..efa28adbd 100644 --- a/cortex-js/src/utils/cortex-cpp.ts +++ b/cortex-js/src/utils/cortex-cpp.ts @@ -1,5 +1,6 @@ import * as cortexCPP from 'cortex-cpp'; +process.title = 'Cortex Engine Process (cortex.cpp)'; const port = process.env.CORTEX_CPP_PORT ? parseInt(process.env.CORTEX_CPP_PORT) : 3929; From 4ac07e244b703654ff2da2bb00e2fa18fb61b83e Mon Sep 17 00:00:00 2001 From: hiento09 <136591877+hiento09@users.noreply.github.com> Date: Wed, 7 Aug 2024 01:10:39 +0700 Subject: [PATCH 03/20] Windows uninstaller should stop cortex and remove cortex home folder for all users (#984) Co-authored-by: Hien To --- cortex-js/installer.iss | 47 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/cortex-js/installer.iss b/cortex-js/installer.iss index 3a0332b07..874e4d79a 100644 --- a/cortex-js/installer.iss +++ b/cortex-js/installer.iss @@ -37,3 +37,50 @@ Name: "quicklaunchicon"; Description: "Create a &Quick Launch icon"; GroupDescri [Icons] Name: "{commondesktop}\Cortexso"; Filename: "{app}\cortex.exe"; Tasks: desktopicon Name: "{userappdata}\Microsoft\Internet Explorer\Quick Launch\Cortexso"; Filename: "{app}\cortex.exe"; Tasks: quicklaunchicon + +; Define the uninstall run section to execute commands before uninstallation +[UninstallRun] +Filename: "{app}\cortex.exe"; Parameters: "stop"; StatusMsg: "Stopping Cortexso service..."; Flags: runhidden + +; Use Pascal scripting to delete the directory for all users +[Code] +function GetUsersFolder: String; +var + WinDir: String; +begin + WinDir := ExpandConstant('{win}'); + Result := Copy(WinDir, 1, Pos('\Windows', WinDir) - 1) + '\Users'; +end; + +procedure DeleteUserCortexFolder; +var + UsersFolder: String; + FindRec: TFindRec; +begin + UsersFolder := GetUsersFolder; + if FindFirst(UsersFolder + '\*', FindRec) then + begin + try + repeat + if (FindRec.Attributes and FILE_ATTRIBUTE_DIRECTORY <> 0) and + (FindRec.Name <> '.') and (FindRec.Name <> '..') then + begin + if DirExists(UsersFolder + '\' + FindRec.Name + '\cortex') then + begin + DelTree(UsersFolder + '\' + FindRec.Name + '\cortex', True, True, True); + end; + end; + until not FindNext(FindRec); + finally + FindClose(FindRec); + end; + end; +end; + +procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep); +begin + if CurUninstallStep = usPostUninstall then + begin + DeleteUserCortexFolder; + end; +end; From ca5fb29d46c5136d937c3635af723f3782931e57 Mon Sep 17 00:00:00 2001 From: marknguyen1302 Date: Wed, 7 Aug 2024 13:14:54 +0700 Subject: [PATCH 04/20] feat: download model checksum (#986) --- cortex-js/package.json | 2 +- .../domain/models/huggingface.interface.ts | 1 + .../infrastructure/commanders/base.command.ts | 3 ++ .../infrastructure/commanders/chat.command.ts | 16 ++++++- .../commanders/engines.command.ts | 1 + .../commanders/models.command.ts | 1 + .../infrastructure/commanders/run.command.ts | 7 ++- .../download-manager.service.ts | 46 ++++++++++++++++--- .../file-manager/file-manager.service.ts | 42 +++++++++++------ .../src/usecases/engines/engines.usecase.ts | 4 +- .../src/usecases/models/models.usecases.ts | 34 +++++++++++--- cortex-js/src/utils/huggingface.ts | 5 +- cortex-js/src/utils/model-check.ts | 16 +++++++ 13 files changed, 144 insertions(+), 34 deletions(-) diff --git a/cortex-js/package.json b/cortex-js/package.json index d8ceb5063..aaf92f5d5 100644 --- a/cortex-js/package.json +++ b/cortex-js/package.json @@ -38,7 +38,7 @@ "preuninstall": "node ./uninstall.js" }, "dependencies": { - "@cortexso/cortex.js": "^0.1.5", + "@cortexso/cortex.js": "^0.1.7", "@nestjs/axios": "^3.0.2", "@nestjs/common": "^10.0.0", "@nestjs/config": "^3.2.2", diff --git a/cortex-js/src/domain/models/huggingface.interface.ts b/cortex-js/src/domain/models/huggingface.interface.ts index 2ab46dc79..2c2274b3e 100644 --- a/cortex-js/src/domain/models/huggingface.interface.ts +++ b/cortex-js/src/domain/models/huggingface.interface.ts @@ -10,6 +10,7 @@ export interface HuggingFaceRepoSibling { downloadUrl?: string; fileSize?: number; quantization?: Quantization; + lfs?: { oid?: string }; } export interface HuggingFaceRepoData { id: string; diff --git a/cortex-js/src/infrastructure/commanders/base.command.ts b/cortex-js/src/infrastructure/commanders/base.command.ts index e0839fcb2..5d3be2b98 100644 --- a/cortex-js/src/infrastructure/commanders/base.command.ts +++ b/cortex-js/src/infrastructure/commanders/base.command.ts @@ -34,4 +34,7 @@ export abstract class BaseCommand extends CommandRunner { } await this.runCommand(passedParam, options); } + protected setCortex(cortex: CortexClient) { + this.cortex = cortex; + } } diff --git a/cortex-js/src/infrastructure/commanders/chat.command.ts b/cortex-js/src/infrastructure/commanders/chat.command.ts index b23a9b956..35b2ef5ba 100644 --- a/cortex-js/src/infrastructure/commanders/chat.command.ts +++ b/cortex-js/src/infrastructure/commanders/chat.command.ts @@ -18,7 +18,7 @@ import { Cortex } from '@cortexso/cortex.js'; import { ChatClient } from './services/chat-client'; import { downloadProgress } from '@/utils/download-progress'; import { DownloadType } from '@/domain/models/download.interface'; -import { CortexClient } from './services/cortex.client'; +import { checkRequiredVersion } from '@/utils/model-check'; type ChatOptions = { threadId?: string; @@ -96,8 +96,20 @@ export class ChatCommand extends BaseCommand { await downloadProgress(this.cortex, undefined, DownloadType.Engine); } + const { version: engineVersion } = + await this.cortex.engines.retrieve(engine); + if ( + existingModel.engine_version && + !checkRequiredVersion(existingModel.engine_version, engineVersion) + ) { + console.log( + `Model engine version ${existingModel.engine_version} is not compatible with engine version ${engineVersion}`, + ); + process.exit(1); + } + if (!message) options.attach = true; - this.telemetryUsecases.sendEvent( + void this.telemetryUsecases.sendEvent( [ { name: EventName.CHAT, diff --git a/cortex-js/src/infrastructure/commanders/engines.command.ts b/cortex-js/src/infrastructure/commanders/engines.command.ts index 9f3e84b82..c4861f325 100644 --- a/cortex-js/src/infrastructure/commanders/engines.command.ts +++ b/cortex-js/src/infrastructure/commanders/engines.command.ts @@ -61,6 +61,7 @@ export class EnginesCommand extends BaseCommand { ) { const commandInstance = this.moduleRef.get(commandClass, { strict: false }); if (commandInstance) { + commandInstance.setCortex(this.cortex); await commandInstance.runCommand(params, options); } else { console.error('Command not found.'); diff --git a/cortex-js/src/infrastructure/commanders/models.command.ts b/cortex-js/src/infrastructure/commanders/models.command.ts index ab3f562b4..d66dd0989 100644 --- a/cortex-js/src/infrastructure/commanders/models.command.ts +++ b/cortex-js/src/infrastructure/commanders/models.command.ts @@ -67,6 +67,7 @@ export class ModelsCommand extends BaseCommand { ) { const commandInstance = this.moduleRef.get(commandClass, { strict: false }); if (commandInstance) { + commandInstance.setCortex(this.cortex); await commandInstance.runCommand(params, options); } else { console.error('Command not found.'); diff --git a/cortex-js/src/infrastructure/commanders/run.command.ts b/cortex-js/src/infrastructure/commanders/run.command.ts index 1ae5fc9a4..a0dcdcb84 100644 --- a/cortex-js/src/infrastructure/commanders/run.command.ts +++ b/cortex-js/src/infrastructure/commanders/run.command.ts @@ -5,7 +5,7 @@ import ora from 'ora'; import { existsSync } from 'fs'; import { join } from 'path'; import { Engines } from './types/engine.interface'; -import { checkModelCompatibility } from '@/utils/model-check'; +import { checkModelCompatibility, checkRequiredVersion } from '@/utils/model-check'; import { BaseCommand } from './base.command'; import { isRemoteEngine } from '@/utils/normalize-model-id'; import { ChatClient } from './services/chat-client'; @@ -98,6 +98,11 @@ export class RunCommand extends BaseCommand { await this.cortex.engines.init(engine); await downloadProgress(this.cortex, undefined, DownloadType.Engine); } + const { version: engineVersion } = await this.cortex.engines.retrieve(engine); + if(existingModel.engine_version && !checkRequiredVersion(existingModel.engine_version, engineVersion)) { + console.log(`Model engine version ${existingModel.engine_version} is not compatible with engine version ${engineVersion}`); + process.exit(1); + } const startingSpinner = ora('Loading model...').start(); diff --git a/cortex-js/src/infrastructure/services/download-manager/download-manager.service.ts b/cortex-js/src/infrastructure/services/download-manager/download-manager.service.ts index 8da2810bb..6ae6550fb 100644 --- a/cortex-js/src/infrastructure/services/download-manager/download-manager.service.ts +++ b/cortex-js/src/infrastructure/services/download-manager/download-manager.service.ts @@ -11,6 +11,7 @@ import { Presets, SingleBar } from 'cli-progress'; import { createWriteStream, unlinkSync } from 'node:fs'; import { basename } from 'node:path'; import { firstValueFrom } from 'rxjs'; +import crypto from 'crypto'; @Injectable() export class DownloadManagerService { @@ -51,7 +52,13 @@ export class DownloadManagerService { downloadId: string, title: string, downloadType: DownloadType, - urlToDestination: Record, + urlToDestination: Record< + string, + { + destination: string; + checksum?: string; + } + >, finishedCallback?: () => Promise, inSequence: boolean = true, ) { @@ -65,7 +72,7 @@ export class DownloadManagerService { const downloadItems: DownloadItem[] = Object.keys(urlToDestination).map( (url) => { - const destination = urlToDestination[url]; + const { destination, checksum } = urlToDestination[url]; const downloadItem: DownloadItem = { id: destination, time: { @@ -78,6 +85,7 @@ export class DownloadManagerService { }, progress: 0, status: DownloadStatus.Downloading, + checksum, }; return downloadItem; @@ -119,15 +127,15 @@ export class DownloadManagerService { if (!inSequence) { Promise.all( Object.keys(urlToDestination).map((url) => { - const destination = urlToDestination[url]; - return this.downloadFile(downloadId, url, destination); + const { destination, checksum } = urlToDestination[url]; + return this.downloadFile(downloadId, url, destination, checksum); }), ).then(callBack); } else { // Download model file in sequence for (const url of Object.keys(urlToDestination)) { - const destination = urlToDestination[url]; - await this.downloadFile(downloadId, url, destination); + const { destination, checksum } = urlToDestination[url]; + await this.downloadFile(downloadId, url, destination, checksum); } return callBack(); } @@ -137,7 +145,14 @@ export class DownloadManagerService { downloadId: string, url: string, destination: string, + checksum?: string, ) { + console.log('Downloading', { + downloadId, + url, + destination, + checksum, + }); const controller = new AbortController(); // adding to abort controllers this.abortControllers[downloadId][destination] = controller; @@ -155,6 +170,7 @@ export class DownloadManagerService { } const writer = createWriteStream(destination); + const hash = crypto.createHash('sha256'); const totalBytes = Number(response.headers['content-length']); // update download state @@ -214,8 +230,23 @@ export class DownloadManagerService { const downloadItem = currentDownloadState?.children.find( (downloadItem) => downloadItem.id === destination, ); + const isFileBroken = checksum && checksum === hash.digest('hex'); if (downloadItem) { - downloadItem.status = DownloadStatus.Downloaded; + downloadItem.status = isFileBroken + ? DownloadStatus.Error + : DownloadStatus.Downloaded; + if (isFileBroken) { + downloadItem.error = 'Checksum is not matched'; + this.handleError( + new Error('Checksum is not matched'), + downloadId, + destination, + ); + } + } + if (isFileBroken) { + currentDownloadState.status = DownloadStatus.Error; + currentDownloadState.error = 'Checksum is not matched'; } this.eventEmitter.emit('download.event', this.allDownloadStates); } finally { @@ -234,6 +265,7 @@ export class DownloadManagerService { }); response.data.on('data', (chunk: any) => { + hash.update(chunk); resetTimeout(); transferredBytes += chunk.length; diff --git a/cortex-js/src/infrastructure/services/file-manager/file-manager.service.ts b/cortex-js/src/infrastructure/services/file-manager/file-manager.service.ts index 071f95b12..5043028cd 100644 --- a/cortex-js/src/infrastructure/services/file-manager/file-manager.service.ts +++ b/cortex-js/src/infrastructure/services/file-manager/file-manager.service.ts @@ -28,7 +28,6 @@ const writeAsync = promisify(write); @Injectable() export class FileManagerService { - private configFile = '.cortexrc'; private cortexDirectoryName = 'cortex'; private modelFolderName = 'models'; private presetFolderName = 'presets'; @@ -44,7 +43,10 @@ export class FileManagerService { */ async getConfig(dataFolderPath?: string): Promise { const homeDir = os.homedir(); - const configPath = join(homeDir, this.configFile); + const configPath = join( + homeDir, + this.getConfigFileName(this.configProfile), + ); const config = this.defaultConfig(); const dataFolderPathUsed = dataFolderPath || config.dataFolderPath; if (!existsSync(configPath) || !existsSync(dataFolderPathUsed)) { @@ -55,8 +57,7 @@ export class FileManagerService { try { const content = await promises.readFile(configPath, 'utf8'); - const configs = yaml.load(content) as Record; - const config = configs?.[this.configProfile] ?? {}; + const config = yaml.load(content) as Config & object; return { ...this.defaultConfig(), ...config, @@ -72,17 +73,20 @@ export class FileManagerService { async writeConfigFile(config: Config & object): Promise { const homeDir = os.homedir(); - const configPath = join(homeDir, this.configFile); + const configPath = join( + homeDir, + this.getConfigFileName(this.configProfile), + ); // write config to file as yaml if (!existsSync(configPath)) { await promises.writeFile(configPath, '', 'utf8'); } const content = await promises.readFile(configPath, 'utf8'); - const currentConfig = yaml.load(content) as Record; + const currentConfig = yaml.load(content) as Config & object; const configString = yaml.dump({ ...currentConfig, - [this.configProfile]: config, + ...config, }); await promises.writeFile(configPath, configString, 'utf8'); } @@ -345,12 +349,17 @@ export class FileManagerService { */ getServerConfig(): { host: string; port: number } { const homeDir = os.homedir(); - const configPath = join(homeDir, this.configFile); + const configPath = join( + homeDir, + this.getConfigFileName(this.configProfile), + ); let config = this.defaultConfig(); try { const content = readFileSync(configPath, 'utf8'); - const configs = (yaml.load(content) as Record) ?? {}; - config = configs?.[this.configProfile] ?? config; + const currentConfig = (yaml.load(content) as Config & object) ?? {}; + if (currentConfig) { + config = currentConfig; + } } catch {} return { host: config.apiServerHost ?? '127.0.0.1', @@ -366,15 +375,22 @@ export class FileManagerService { } public profileConfigExists(profile: string): boolean { const homeDir = os.homedir(); - const configPath = join(homeDir, this.configFile); + const configPath = join(homeDir, this.getConfigFileName(profile)); try { const content = readFileSync(configPath, 'utf8'); - const configs = (yaml.load(content) as Record) ?? {}; - return !!configs[profile]; + const config = yaml.load(content) as Config & object; + return !!config; } catch { return false; } } + + private getConfigFileName(configProfile: string): string { + if (configProfile === 'default') { + return '.cortexrc'; + } + return `.${configProfile}rc`; + } } export const fileManagerService = new FileManagerService(); diff --git a/cortex-js/src/usecases/engines/engines.usecase.ts b/cortex-js/src/usecases/engines/engines.usecase.ts index 7df0a23e3..ae8d50f55 100644 --- a/cortex-js/src/usecases/engines/engines.usecase.ts +++ b/cortex-js/src/usecases/engines/engines.usecase.ts @@ -199,7 +199,7 @@ export class EnginesUsecases { url, 'Cuda Toolkit Dependencies', DownloadType.Engine, - { [url]: destination }, + { [url]: { destination } }, async () => { try { await decompress( @@ -274,7 +274,7 @@ export class EnginesUsecases { toDownloadAsset.browser_download_url, engine, DownloadType.Engine, - { [toDownloadAsset.browser_download_url]: destination }, + { [toDownloadAsset.browser_download_url]: { destination } }, // On completed - post processing async () => { try { diff --git a/cortex-js/src/usecases/models/models.usecases.ts b/cortex-js/src/usecases/models/models.usecases.ts index 3f45ec254..7c631e6f9 100644 --- a/cortex-js/src/usecases/models/models.usecases.ts +++ b/cortex-js/src/usecases/models/models.usecases.ts @@ -399,14 +399,34 @@ export class ModelsUsecases { } // Start downloading the model - const toDownloads: Record = files + const toDownloads: Record< + string, + { + destination: string; + checksum?: string; + } + > = files .filter((e) => this.validFileDownload(e)) - .reduce((acc: Record, file) => { - if (file.downloadUrl) - acc[file.downloadUrl] = join(modelFolder, file.rfilename); - return acc; - }, {}); - + .reduce( + ( + acc: Record< + string, + { + destination: string; + checksum?: string; + } + >, + file, + ) => { + if (file.downloadUrl) + acc[file.downloadUrl] = { + destination: join(modelFolder, file.rfilename), + checksum: file.lfs.oid, + }; + return acc; + }, + {}, + ); return this.downloadManagerService.submitDownloadRequest( modelId, modelId, diff --git a/cortex-js/src/utils/huggingface.ts b/cortex-js/src/utils/huggingface.ts index 9df80eeeb..38b642ad0 100644 --- a/cortex-js/src/utils/huggingface.ts +++ b/cortex-js/src/utils/huggingface.ts @@ -144,6 +144,7 @@ export async function fetchJanRepoData( | { path: string; size: number; + oid?: string; }[] | { error: string } = jsonData; @@ -159,6 +160,9 @@ export async function fetchJanRepoData( rfilename: e.path, downloadUrl: HUGGING_FACE_TREE_REF_URL(repo, tree, e.path), fileSize: e.size ?? 0, + lfs: { + oid: e.oid, + }, }; }) : [], @@ -186,7 +190,6 @@ export async function fetchJanRepoData( }); data.modelUrl = url; - return data; } diff --git a/cortex-js/src/utils/model-check.ts b/cortex-js/src/utils/model-check.ts index 78ca84b60..05cd8827f 100644 --- a/cortex-js/src/utils/model-check.ts +++ b/cortex-js/src/utils/model-check.ts @@ -45,3 +45,19 @@ export const checkModelCompatibility = async ( } } }; + +export const parseVersion = (version: string) => { + return version.split('.').map(Number); +}; + +export const checkRequiredVersion = (version: string, minVersion: string) => { + const [currentMajor, currentMinor, currentPatch] = parseVersion(version); + const [requiredMajor, requiredMinor, requiredPatch] = + parseVersion(minVersion); + return ( + currentMajor > requiredMajor || + (currentMajor === requiredMajor && + (currentMinor > requiredMinor || + (currentMinor === requiredMinor && currentPatch >= requiredPatch))) + ); +}; From 0ef01d93b2fce629806bf205d150337109ae3a5e Mon Sep 17 00:00:00 2001 From: Louis Date: Wed, 7 Aug 2024 13:20:03 +0700 Subject: [PATCH 05/20] fix: env does not work after bundled in an electron app (#987) --- cortex-js/src/usecases/cortex/cortex.usecases.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/cortex-js/src/usecases/cortex/cortex.usecases.ts b/cortex-js/src/usecases/cortex/cortex.usecases.ts index 01bf1ed09..573a9db00 100644 --- a/cortex-js/src/usecases/cortex/cortex.usecases.ts +++ b/cortex-js/src/usecases/cortex/cortex.usecases.ts @@ -152,6 +152,7 @@ export class CortexUsecases implements BeforeApplicationShutdown { CORTEX_JS_HOST: host, CORTEX_JS_PORT: port.toString(), CORTEX_PROFILE: fileManagerService.getConfigProfile(), + ...process.env, }, }); server.disconnect(); // closes the IPC channel From e21aaf49581e2939176c3c1ef491fd5b4815c8cb Mon Sep 17 00:00:00 2001 From: hiento09 <136591877+hiento09@users.noreply.github.com> Date: Wed, 7 Aug 2024 16:31:13 +0700 Subject: [PATCH 06/20] add build-deps for cortex-cpp binding (#988) Co-authored-by: Hien To --- .github/workflows/cortex-build.yml | 9 +- .../engines/cortex.llamacpp/engine.cmake | 92 ------------------- cortex-cpp/package.json | 12 +-- 3 files changed, 14 insertions(+), 99 deletions(-) delete mode 100644 cortex-cpp/engines/cortex.llamacpp/engine.cmake diff --git a/.github/workflows/cortex-build.yml b/.github/workflows/cortex-build.yml index c3efe7bbe..8681f8b1a 100644 --- a/.github/workflows/cortex-build.yml +++ b/.github/workflows/cortex-build.yml @@ -187,6 +187,13 @@ jobs: rm package.json mv package-tmp.json package.json + - name: Remove build build-deps and build folder for windows + if: runner.os == 'Windows' + run: | + cd cortex-cpp + Remove-Item -Recurse -Force build + Remove-Item -Recurse -Force build-deps + # build prebuilds - name: Build Prebuilds working-directory: cortex-cpp @@ -207,7 +214,7 @@ jobs: asset_content_type: application/gzip # Setup .npmrc file to publish to npm - upload only once - - run: npm publish --access public + - run: rm -rf build-deps && rm -rf build && rm -rf prebuilds && npm publish --access public continue-on-error: true if: runner.os == 'linux' env: diff --git a/cortex-cpp/engines/cortex.llamacpp/engine.cmake b/cortex-cpp/engines/cortex.llamacpp/engine.cmake deleted file mode 100644 index f724a1963..000000000 --- a/cortex-cpp/engines/cortex.llamacpp/engine.cmake +++ /dev/null @@ -1,92 +0,0 @@ -# cortex.llamacpp release version -set(VERSION 0.1.23-29.07.24) -# vulka is unstable, we need to use a customized version -set(VULKA_VERSION 0.1.23-29.07.24) - -set(ENGINE_VERSION v${VERSION}) -add_compile_definitions(CORTEX_LLAMACPP_VERSION="${VERSION}") - -# MESSAGE("ENGINE_VERSION=" ${ENGINE_VERSION}) - -# Download library based on instructions -if(UNIX AND NOT APPLE) - if(CUDA_12_0) - if(LLAMA_AVX512) - set(LIBRARY_NAME cortex.llamacpp-${VERSION}-linux-amd64-avx512-cuda-12-0.tar.gz) - elseif(NOT LLAMA_AVX2) - set(LIBRARY_NAME cortex.llamacpp-${VERSION}-linux-amd64-avx-cuda-12-0.tar.gz) - else() - set(LIBRARY_NAME cortex.llamacpp-${VERSION}-linux-amd64-avx2-cuda-12-0.tar.gz) - endif() - elseif(CUDA_11_7) - if(LLAMA_AVX512) - set(LIBRARY_NAME cortex.llamacpp-${VERSION}-linux-amd64-avx512-cuda-11-7.tar.gz) - elseif(NOT LLAMA_AVX2) - set(LIBRARY_NAME cortex.llamacpp-${VERSION}-linux-amd64-avx-cuda-11-7.tar.gz) - else() - set(LIBRARY_NAME cortex.llamacpp-${VERSION}-linux-amd64-avx2-cuda-11-7.tar.gz) - endif() - elseif(LLAMA_VULKAN) - set(LIBRARY_NAME cortex.llamacpp-${VULKA_VERSION}-linux-amd64-vulkan.tar.gz) - set(ENGINE_VERSION v${VULKA_VERSION}) - elseif(LLAMA_AVX512) - set(LIBRARY_NAME cortex.llamacpp-${VERSION}-linux-amd64-avx512.tar.gz) - elseif(NOT LLAMA_AVX2) - set(LIBRARY_NAME cortex.llamacpp-${VERSION}-linux-amd64-avx.tar.gz) - else() - set(LIBRARY_NAME cortex.llamacpp-${VERSION}-linux-amd64-avx2.tar.gz) - endif() -elseif(UNIX) - if(MAC_ARM64) - set(LIBRARY_NAME cortex.llamacpp-${VERSION}-mac-arm64.tar.gz) - else() - set(LIBRARY_NAME cortex.llamacpp-${VERSION}-mac-amd64.tar.gz) - endif() -else() - if(CUDA_12_0) - if(LLAMA_AVX512) - set(LIBRARY_NAME cortex.llamacpp-${VERSION}-windows-amd64-avx512-cuda-12-0.tar.gz) - elseif(NOT LLAMA_AVX2) - set(LIBRARY_NAME cortex.llamacpp-${VERSION}-windows-amd64-avx-cuda-12-0.tar.gz) - else() - set(LIBRARY_NAME cortex.llamacpp-${VERSION}-windows-amd64-avx2-cuda-12-0.tar.gz) - endif() - elseif(CUDA_11_7) - if(LLAMA_AVX512) - set(LIBRARY_NAME cortex.llamacpp-${VERSION}-windows-amd64-avx512-cuda-11-7.tar.gz) - elseif(NOT LLAMA_AVX2) - set(LIBRARY_NAME cortex.llamacpp-${VERSION}-windows-amd64-avx-cuda-11-7.tar.gz) - else() - set(LIBRARY_NAME cortex.llamacpp-${VERSION}-windows-amd64-avx2-cuda-11-7.tar.gz) - endif() - elseif(LLAMA_VULKAN) - set(LIBRARY_NAME cortex.llamacpp-${VULKA_VERSION}-windows-amd64-vulkan.tar.gz) - set(ENGINE_VERSION v${VULKA_VERSION}) - elseif(LLAMA_AVX512) - set(LIBRARY_NAME cortex.llamacpp-${VERSION}-windows-amd64-avx512.tar.gz) - elseif(NOT LLAMA_AVX2) - set(LIBRARY_NAME cortex.llamacpp-${VERSION}-windows-amd64-avx.tar.gz) - else() - set(LIBRARY_NAME cortex.llamacpp-${VERSION}-windows-amd64-avx2.tar.gz) - endif() -endif() - - -set(LIBLLAMA_ENGINE_URL https://github.com/janhq/cortex.llamacpp/releases/download/${ENGINE_VERSION}/${LIBRARY_NAME}) -# MESSAGE("LIBLLAMA_ENGINE_URL="${LIBLLAMA_ENGINE_URL}) -# MESSAGE("LIBARRY_NAME=" ${LIBRARY_NAME}) - -set(LIBLLAMA_ENGINE_PATH ${CMAKE_BINARY_DIR}/engines/${LIBRARY_NAME}) - -# MESSAGE("CMAKE_BINARY_DIR = " ${CMAKE_BINARY_DIR}) - -file(DOWNLOAD ${LIBLLAMA_ENGINE_URL} ${LIBLLAMA_ENGINE_PATH} STATUS LIBLLAMA_ENGINE_DOWNLOAD_STATUS) -list(GET LIBLLAMA_ENGINE_DOWNLOAD_STATUS 0 LIBLLAMA_ENGINE_DOWNLOAD_STATUS_NO) -# MESSAGE("file = " ${CMAKE_BINARY_DIR}/engines/${LIBRARY_NAME}) - -if(LIBLLAMA_ENGINE_DOWNLOAD_STATUS_NO) - message(STATUS "Pre-built library not downloaded. (${LIBLLAMA_ENGINE_DOWNLOAD_STATUS})") -else() - message(STATUS "Linking downloaded pre-built library.") - file(ARCHIVE_EXTRACT INPUT ${CMAKE_BINARY_DIR}/engines/${LIBRARY_NAME} DESTINATION ${CMAKE_BINARY_DIR}/engines/) -endif() diff --git a/cortex-cpp/package.json b/cortex-cpp/package.json index 6271d7702..e104f616c 100644 --- a/cortex-cpp/package.json +++ b/cortex-cpp/package.json @@ -9,10 +9,11 @@ "url": "git+https://github.com/janhq/cortex.git" }, "scripts": { - "install": "prebuild-install --runtime napi --backend cmake-js --config Release || cmake-js rebuild --config Release", - "build": "cmake-js configure --config Release && cmake-js build --config Release", - "rebuild": "cmake-js rebuild --config Release", - "prebuild": "prebuild --runtime napi --backend cmake-js --all --strip --verbose --config Release --include-regex \"\\.(node|exp|lib|so)$\"", + "install": "prebuild-install --runtime napi --backend cmake-js --config Release || yarn build-deps && cmake-js rebuild --config Release", + "build-deps": "cmake-js configure --directory ./cortex-cpp-deps --out ./build-deps/cortex-cpp-deps && cmake-js build --directory ./cortex-cpp-deps --out ./build-deps/cortex-cpp-deps --config Release", + "build": "yarn build-deps && cmake-js configure --config Release && cmake-js build --config Release", + "rebuild": "yarn build-deps && cmake-js rebuild --config Release", + "prebuild": "yarn build-deps && prebuild --runtime napi --backend cmake-js --all --strip --verbose --config Release --include-regex \"\\.(node|exp|lib|so)$\"", "upload": "prebuild --runtime napi --backend cmake-js --upload ${GITHUB_TOKEN}" }, "author": "Jan ", @@ -35,7 +36,6 @@ ] }, "files": [ - "binding/*.js", - "binding/*.d.ts" + "**" ] } From 82fb67ecc10ab28bebc79202620a642a828a64fc Mon Sep 17 00:00:00 2001 From: hiento09 <136591877+hiento09@users.noreply.github.com> Date: Wed, 7 Aug 2024 17:23:11 +0700 Subject: [PATCH 07/20] cortex js allow tag x.y.z-t (#990) Co-authored-by: Hien To --- .github/workflows/cortex-build.yml | 2 +- .github/workflows/cortex-js.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/cortex-build.yml b/.github/workflows/cortex-build.yml index 8681f8b1a..4ee9b6f86 100644 --- a/.github/workflows/cortex-build.yml +++ b/.github/workflows/cortex-build.yml @@ -2,7 +2,7 @@ name: CI Cortex Release on: push: - tags: ["v[0-9]+.[0-9]+.[0-9]+", "v[0-9]+.[0-9]+.[0-9]+-*", "!v[0-9]+.[0-9]+.[0-9]+-cortex-js"] + tags: ["v[0-9]+.[0-9]+.[0-9]+", "v[0-9]+.[0-9]+.[0-9]+-*", "!v[0-9]+.[0-9]+.[0-9]+-cortex-js", "!v[0-9]+.[0-9]+.[0-9]+-[0-9]+-cortex-js"] paths: ["cortex-cpp/**", "cortex-js/**"] workflow_dispatch: diff --git a/.github/workflows/cortex-js.yml b/.github/workflows/cortex-js.yml index 31175b1be..99f07bb64 100644 --- a/.github/workflows/cortex-js.yml +++ b/.github/workflows/cortex-js.yml @@ -1,7 +1,7 @@ name: Publish cortex js Package to npmjs on: push: - tags: ["v[0-9]+.[0-9]+.[0-9]+-cortex-js"] + tags: ["v[0-9]+.[0-9]+.[0-9]+-cortex-js", "v[0-9]+.[0-9]+.[0-9]+-[0-9]+-cortex-js"] paths: [ "cortex-js/**", From ff2a10240fd55a7b33f8708d06c695b68efee073 Mon Sep 17 00:00:00 2001 From: vansangpfiev Date: Wed, 7 Aug 2024 17:23:24 +0700 Subject: [PATCH 08/20] feat: support unload engine (#989) Co-authored-by: vansangpfiev --- cortex-cpp/controllers/server.cc | 40 ++++++++++++++++++++++++++++---- cortex-cpp/controllers/server.h | 4 ++++ 2 files changed, 39 insertions(+), 5 deletions(-) diff --git a/cortex-cpp/controllers/server.cc b/cortex-cpp/controllers/server.cc index 485695b66..3de3bc2ba 100644 --- a/cortex-cpp/controllers/server.cc +++ b/cortex-cpp/controllers/server.cc @@ -19,12 +19,12 @@ constexpr static auto kOnnxEngine = "cortex.onnx"; constexpr static auto kTensorrtLlmEngine = "cortex.tensorrt-llm"; } // namespace -server::server(){ +server::server() { - // Some default values for now below - // log_disable(); // Disable the log to file feature, reduce bloat for - // target - // system () + // Some default values for now below + // log_disable(); // Disable the log to file feature, reduce bloat for + // target + // system () }; server::~server() {} @@ -326,6 +326,36 @@ void server::LoadModel(const HttpRequestPtr& req, LOG_TRACE << "Done load model"; } +void server::UnloadEngine( + const HttpRequestPtr& req, + std::function&& callback) { + if (!HasFieldInReq(req, callback, "engine")) { + return; + } + + auto engine_type = + (*(req->getJsonObject())).get("engine", cur_engine_type_).asString(); + if (!IsEngineLoaded(engine_type)) { + Json::Value res; + res["message"] = "Engine is not loaded yet"; + auto resp = cortex_utils::CreateCortexHttpJsonResponse(res); + resp->setStatusCode(k409Conflict); + callback(resp); + LOG_WARN << "Engine is not loaded yet"; + return; + } + + EngineI* e = std::get(engines_[engine_type].engine); + delete e; + engines_.erase(engine_type); + LOG_INFO << "Unloaded engine " + engine_type; + Json::Value res; + res["message"] = "Unloaded engine " + engine_type; + auto resp = cortex_utils::CreateCortexHttpJsonResponse(res); + resp->setStatusCode(k200OK); + callback(resp); +} + void server::ProcessStreamRes(std::function cb, std::shared_ptr q) { auto err_or_done = std::make_shared(false); diff --git a/cortex-cpp/controllers/server.h b/cortex-cpp/controllers/server.h index a25288612..1b1360baf 100644 --- a/cortex-cpp/controllers/server.h +++ b/cortex-cpp/controllers/server.h @@ -66,6 +66,8 @@ class server : public drogon::HttpController, // ADD_METHOD_TO(server::handlePrelight, "/v1/embeddings", Options); // PATH_ADD("/llama/chat_completion", Post); + METHOD_ADD(server::UnloadEngine, "unloadengine", Post); + METHOD_LIST_END void ChatCompletion( const HttpRequestPtr& req, @@ -91,6 +93,8 @@ class server : public drogon::HttpController, void FineTuning( const HttpRequestPtr& req, std::function&& callback) override; + void UnloadEngine(const HttpRequestPtr& req, + std::function&& callback); private: void ProcessStreamRes(std::function cb, From ab8d1bfee85b94f468e4b4ffd8e3f4c78cc18d9a Mon Sep 17 00:00:00 2001 From: marknguyen1302 Date: Wed, 7 Aug 2024 21:29:52 +0700 Subject: [PATCH 09/20] fix: fix checksum undefined (#991) --- cortex-js/src/usecases/models/models.usecases.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cortex-js/src/usecases/models/models.usecases.ts b/cortex-js/src/usecases/models/models.usecases.ts index 7c631e6f9..f2ad2b1fb 100644 --- a/cortex-js/src/usecases/models/models.usecases.ts +++ b/cortex-js/src/usecases/models/models.usecases.ts @@ -421,7 +421,7 @@ export class ModelsUsecases { if (file.downloadUrl) acc[file.downloadUrl] = { destination: join(modelFolder, file.rfilename), - checksum: file.lfs.oid, + checksum: file?.lfs?.oid, }; return acc; }, From 463fa3badc627f6861f277dc7c97782892e218a6 Mon Sep 17 00:00:00 2001 From: hiento09 <136591877+hiento09@users.noreply.github.com> Date: Wed, 7 Aug 2024 22:47:42 +0700 Subject: [PATCH 10/20] Fix cortex-cpp rebuild (#994) Co-authored-by: Service Account --- cortex-cpp/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cortex-cpp/package.json b/cortex-cpp/package.json index e104f616c..737c40e3c 100644 --- a/cortex-cpp/package.json +++ b/cortex-cpp/package.json @@ -9,7 +9,7 @@ "url": "git+https://github.com/janhq/cortex.git" }, "scripts": { - "install": "prebuild-install --runtime napi --backend cmake-js --config Release || yarn build-deps && cmake-js rebuild --config Release", + "install": "prebuild-install --runtime napi --backend cmake-js --config Release || yarn rebuild", "build-deps": "cmake-js configure --directory ./cortex-cpp-deps --out ./build-deps/cortex-cpp-deps && cmake-js build --directory ./cortex-cpp-deps --out ./build-deps/cortex-cpp-deps --config Release", "build": "yarn build-deps && cmake-js configure --config Release && cmake-js build --config Release", "rebuild": "yarn build-deps && cmake-js rebuild --config Release", From 18c99db995f67d92c1d12c6cf60448b371a7a0b3 Mon Sep 17 00:00:00 2001 From: hiento09 <136591877+hiento09@users.noreply.github.com> Date: Wed, 7 Aug 2024 23:00:21 +0700 Subject: [PATCH 11/20] Chore bump cortex-cpp to 0.5.0-34 (#992) Co-authored-by: Service Account --- cortex-js/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cortex-js/package.json b/cortex-js/package.json index aaf92f5d5..0f4cbffe5 100644 --- a/cortex-js/package.json +++ b/cortex-js/package.json @@ -54,7 +54,7 @@ "class-transformer": "^0.5.1", "class-validator": "^0.14.1", "cli-progress": "^3.12.0", - "cortex-cpp": "0.5.0-27", + "cortex-cpp": "0.5.0-35", "cpu-instructions": "^0.0.11", "decompress": "^4.2.1", "hyllama": "^0.2.2", From 6d0c507bd59068c0aad66709661b0183bfbdb9ba Mon Sep 17 00:00:00 2001 From: Louis Date: Wed, 7 Aug 2024 23:47:07 +0700 Subject: [PATCH 12/20] fix: hide gpu check windows (#993) --- .../src/usecases/models/models.usecases.ts | 12 ----- cortex-js/src/utils/cuda.ts | 3 ++ cortex-js/src/utils/huggingface.ts | 46 ------------------- 3 files changed, 3 insertions(+), 58 deletions(-) diff --git a/cortex-js/src/usecases/models/models.usecases.ts b/cortex-js/src/usecases/models/models.usecases.ts index f2ad2b1fb..7182436cf 100644 --- a/cortex-js/src/usecases/models/models.usecases.ts +++ b/cortex-js/src/usecases/models/models.usecases.ts @@ -17,11 +17,9 @@ import { TelemetrySource } from '@/domain/telemetry/telemetry.interface'; import { ModelRepository } from '@/domain/repositories/model.interface'; import { ModelParameterParser } from '@/utils/model-parameter.parser'; import { - HuggingFaceRepoData, HuggingFaceRepoSibling, } from '@/domain/models/huggingface.interface'; import { - fetchHuggingFaceRepoData, fetchJanRepoData, getHFModelMetadata, } from '@/utils/huggingface'; @@ -530,16 +528,6 @@ export class ModelsUsecases { else throw 'Model already exists.'; } - /** - * Fetches the model data from HuggingFace - * @param modelId Model repo id. e.g. llama3, llama3:8b, janhq/llama3 - * @returns Model metadata - */ - fetchModelMetadata(modelId: string): Promise { - if (modelId.includes('/')) return fetchHuggingFaceRepoData(modelId); - else return fetchJanRepoData(modelId); - } - /** * Get the current status of the models * @returns Model statuses diff --git a/cortex-js/src/utils/cuda.ts b/cortex-js/src/utils/cuda.ts index 679f61842..ecddbaf4f 100644 --- a/cortex-js/src/utils/cuda.ts +++ b/cortex-js/src/utils/cuda.ts @@ -109,6 +109,9 @@ export const getGpuInfo = async (): Promise => new Promise((resolve) => { exec( 'nvidia-smi --query-gpu=index,memory.total,name --format=csv,noheader,nounits', + { + windowsHide: true, + }, async (error, stdout) => { if (!error) { // Get GPU info and gpu has higher memory first diff --git a/cortex-js/src/utils/huggingface.ts b/cortex-js/src/utils/huggingface.ts index 38b642ad0..a69572992 100644 --- a/cortex-js/src/utils/huggingface.ts +++ b/cortex-js/src/utils/huggingface.ts @@ -60,52 +60,6 @@ export function guessPromptTemplateFromHuggingFace(jinjaCode?: string): string { } } -/** - * Fetches the model data from HuggingFace API - * @param repoId HuggingFace model id. e.g. "janhq/llama-3" - * @returns - */ -export async function fetchHuggingFaceRepoData( - repoId: string, -): Promise { - const sanitizedUrl = getRepoModelsUrl(repoId); - - const { data: response } = await axios.get(sanitizedUrl); - if (response['error'] != null) { - throw new Error(response['error']); - } - - const data = response as HuggingFaceRepoData; - - if (data.tags.indexOf('gguf') === -1) { - throw `${repoId} is not supported. Only GGUF models are supported.`; - } - - // fetching file sizes - const url = new URL(sanitizedUrl); - const paths = url.pathname.split('/').filter((e) => e.trim().length > 0); - - for (let i = 0; i < data.siblings.length; i++) { - const downloadUrl = HUGGING_FACE_DOWNLOAD_FILE_MAIN_URL( - [paths[2], paths[3]].join('/'), - data.siblings[i].rfilename, - ); - data.siblings[i].downloadUrl = downloadUrl; - } - - //TODO: Very hacky? Let's say they don't name it properly - AllQuantizations.forEach((quantization) => { - data.siblings.forEach((sibling: any) => { - if (!sibling.quantization && sibling.rfilename.includes(quantization)) { - sibling.quantization = quantization; - } - }); - }); - - data.modelUrl = HUGGING_FACE_REPO_URL(paths[2], paths[3]); - return data; -} - /** * Fetch the model data from Jan's repo * @param modelId HuggingFace model id. e.g. "llama-3:7b" From 1d822dacb69e3497e589554e247a4f40d720fe3f Mon Sep 17 00:00:00 2001 From: hiento09 <136591877+hiento09@users.noreply.github.com> Date: Thu, 8 Aug 2024 01:45:44 +0700 Subject: [PATCH 13/20] Fix brew build from source error (#995) Co-authored-by: Service Account --- cortex-cpp/package.json | 2 +- cortex-js/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cortex-cpp/package.json b/cortex-cpp/package.json index 737c40e3c..84cc49d9d 100644 --- a/cortex-cpp/package.json +++ b/cortex-cpp/package.json @@ -10,7 +10,7 @@ }, "scripts": { "install": "prebuild-install --runtime napi --backend cmake-js --config Release || yarn rebuild", - "build-deps": "cmake-js configure --directory ./cortex-cpp-deps --out ./build-deps/cortex-cpp-deps && cmake-js build --directory ./cortex-cpp-deps --out ./build-deps/cortex-cpp-deps --config Release", + "build-deps": "cmake-js configure --directory ./cortex-cpp-deps --out ./build-deps/cortex-cpp-deps --config Release && cmake-js build --directory ./cortex-cpp-deps --out ./build-deps/cortex-cpp-deps --config Release", "build": "yarn build-deps && cmake-js configure --config Release && cmake-js build --config Release", "rebuild": "yarn build-deps && cmake-js rebuild --config Release", "prebuild": "yarn build-deps && prebuild --runtime napi --backend cmake-js --all --strip --verbose --config Release --include-regex \"\\.(node|exp|lib|so)$\"", diff --git a/cortex-js/package.json b/cortex-js/package.json index 0f4cbffe5..ad405c5a5 100644 --- a/cortex-js/package.json +++ b/cortex-js/package.json @@ -54,7 +54,7 @@ "class-transformer": "^0.5.1", "class-validator": "^0.14.1", "cli-progress": "^3.12.0", - "cortex-cpp": "0.5.0-35", + "cortex-cpp": "0.5.0-36", "cpu-instructions": "^0.0.11", "decompress": "^4.2.1", "hyllama": "^0.2.2", From 14ab0f565ee2287ac9c515d9d8d7df1addb3891d Mon Sep 17 00:00:00 2001 From: Louis Date: Thu, 8 Aug 2024 12:25:56 +0700 Subject: [PATCH 14/20] chore: support more configurations via direct js import (#997) --- cortex-js/src/index.ts | 97 +++++++++++++++++++++++++++++-------- cortex-js/src/utils/logs.ts | 2 +- 2 files changed, 78 insertions(+), 21 deletions(-) diff --git a/cortex-js/src/index.ts b/cortex-js/src/index.ts index c383a5417..34a1cef2a 100644 --- a/cortex-js/src/index.ts +++ b/cortex-js/src/index.ts @@ -1,31 +1,95 @@ import { - CORTEX_CPP_PROCESS_DESTROY_URL, CORTEX_JS_SYSTEM_URL, + defaultCortexCppPort, defaultCortexJsHost, defaultCortexJsPort, } from '@/infrastructure/constants/cortex'; import { getApp } from './app'; +import { fileManagerService } from './infrastructure/services/file-manager/file-manager.service'; import { CortexUsecases } from './usecases/cortex/cortex.usecases'; +let host: string; +let port: number; +let enginePort: number; + /** * Start the API server */ -export async function start(host?: string, port?: number) { - // getting port from env - const sHost = host || process.env.CORTEX_JS_HOST || defaultCortexJsHost; - const sPort = port || process.env.CORTEX_JS_PORT || defaultCortexJsPort; - const app = await getApp(sHost, Number(sPort)); +export async function start( + name?: string, + address?: string, + portNumber?: number, + enginePortNumber?: number, + dataFolder?: string, +) { + if (name) { + const isProfileConfigExists = fileManagerService.profileConfigExists(name); + if (!isProfileConfigExists) { + await fileManagerService.writeConfigFile({ + ...fileManagerService.defaultConfig(), + apiServerHost: address || defaultCortexJsHost, + apiServerPort: port || defaultCortexJsPort, + cortexCppPort: Number(enginePort) || defaultCortexCppPort, + }); + } + } + const { + apiServerHost: configApiServerHost, + apiServerPort: configApiServerPort, + cortexCppPort: configCortexCppPort, + } = await fileManagerService.getConfig(); + + host = address || configApiServerHost || defaultCortexJsHost; + port = portNumber || configApiServerPort || defaultCortexJsPort; + if (host === 'localhost') { + host = '127.0.0.1'; + } + enginePort = + Number(enginePortNumber) || configCortexCppPort || defaultCortexCppPort; + const dataFolderPath = dataFolder; + + return startServer(dataFolderPath); +} + +async function startServer(dataFolderPath?: string) { + const config = await fileManagerService.getConfig(); try { - await app.listen(sPort, sHost); + if (dataFolderPath) { + await fileManagerService.writeConfigFile({ + ...config, + dataFolderPath, + }); + // load config again to create the data folder + await fileManagerService.getConfig(dataFolderPath); + } + const app = await getApp(host, port); const cortexUsecases = await app.resolve(CortexUsecases); - await cortexUsecases.startCortex(); - console.log(`Started server at http://${sHost}:${sPort}`); - console.log(`API Playground available at http://${sHost}:${sPort}/api`); - } catch { + await cortexUsecases.startCortex().catch((e) => { + throw e; + }); + const isServerOnline = await cortexUsecases.isAPIServerOnline(); + if (isServerOnline) { + console.log( + `Server is already running at http://${host}:${port}. Please use 'cortex stop' to stop the server.`, + ); + } + await app.listen(port, host); + await fileManagerService.writeConfigFile({ + ...config, + apiServerHost: host, + apiServerPort: port, + dataFolderPath: dataFolderPath || config.dataFolderPath, + cortexCppPort: enginePort, + }); + } catch (e) { + console.error(e); + // revert the data folder path if it was set + await fileManagerService.writeConfigFile({ + ...config, + }); console.error(`Failed to start server. Is port ${port} in use?`); } } - /** * Stop the API server * @returns @@ -33,12 +97,5 @@ export async function start(host?: string, port?: number) { export async function stop(host?: string, port?: number) { return fetch(CORTEX_JS_SYSTEM_URL(host, port), { method: 'DELETE', - }) - .catch(() => {}) - .then(() => - fetch(CORTEX_CPP_PROCESS_DESTROY_URL(host, port), { - method: 'DELETE', - }), - ) - .catch(() => {}); + }); } diff --git a/cortex-js/src/utils/logs.ts b/cortex-js/src/utils/logs.ts index 3ee06be92..1802d6d2b 100644 --- a/cortex-js/src/utils/logs.ts +++ b/cortex-js/src/utils/logs.ts @@ -74,7 +74,7 @@ export async function cleanLogs( // Schedule the next execution with doubled delays timeout = setTimeout( - () => this.cleanLogs(maxFileSizeBytes, daysToKeep), + () => cleanLogs(maxFileSizeBytes, daysToKeep), logCleaningInterval, ); } From b725a6c00cfcbdeebefaaf062372e2d56f8c246f Mon Sep 17 00:00:00 2001 From: Louis Date: Thu, 8 Aug 2024 15:22:35 +0700 Subject: [PATCH 15/20] fix: increase CI timeout (#998) --- .github/workflows/cortex-build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/cortex-build.yml b/.github/workflows/cortex-build.yml index 4ee9b6f86..44a25b6c5 100644 --- a/.github/workflows/cortex-build.yml +++ b/.github/workflows/cortex-build.yml @@ -226,7 +226,7 @@ jobs: build-cortex-single-binary: runs-on: ${{ matrix.runs-on }} needs: [create-draft-release, build-and-test] - timeout-minutes: 20 + timeout-minutes: 40 strategy: fail-fast: false matrix: From fcbf84269d2b44db11769a037c89b48aff143148 Mon Sep 17 00:00:00 2001 From: Louis Date: Thu, 8 Aug 2024 16:22:37 +0700 Subject: [PATCH 16/20] fix: set namespace for js module (#999) --- cortex-js/package.json | 5 ++++- cortex-js/src/index.ts | 1 + cortex-js/src/infrastructure/commanders/base.command.ts | 1 - 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/cortex-js/package.json b/cortex-js/package.json index ad405c5a5..7aea006a7 100644 --- a/cortex-js/package.json +++ b/cortex-js/package.json @@ -14,7 +14,10 @@ "dev": "nest dev", "compile": "npx ncc build ./dist/src/command.js -o command", "build": "nest build", - "build:binary": "yarn build && yarn compile && npx -q patch-package && npx @yao-pkg/pkg .", + "build:binary": "yarn build && yarn compile && npx -q patch-package && run-script-os", + "build:binary:windows": "npx @yao-pkg/pkg . --targets node20-win", + "build:binary:linux": "npx @yao-pkg/pkg . --targets node20-linux", + "build:binary:macos": "npx @yao-pkg/pkg . --targets node20-macos", "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"", "build:extensions": "run-script-os", "build:extensions:windows": "powershell -command \"$jobs = Get-ChildItem -Path './src/extensions' -Directory | ForEach-Object { Start-Job -Name ($_.Name) -ScriptBlock { param($_dir); try { Set-Location $_dir; yarn; yarn build; Write-Output 'Build successful in ' + $_dir } catch { Write-Error 'Error in ' + $_dir; throw } } -ArgumentList $_.FullName }; $jobs | Wait-Job; $jobs | ForEach-Object { Receive-Job -Job $_ -Keep } | ForEach-Object { Write-Host $_ }; $failed = $jobs | Where-Object { $_.State -ne 'Completed' -or $_.ChildJobs[0].JobStateInfo.State -ne 'Completed' }; if ($failed) { Exit 1 }\"", diff --git a/cortex-js/src/index.ts b/cortex-js/src/index.ts index 34a1cef2a..24dfa6d73 100644 --- a/cortex-js/src/index.ts +++ b/cortex-js/src/index.ts @@ -23,6 +23,7 @@ export async function start( dataFolder?: string, ) { if (name) { + fileManagerService.setConfigProfile(name); const isProfileConfigExists = fileManagerService.profileConfigExists(name); if (!isProfileConfigExists) { await fileManagerService.writeConfigFile({ diff --git a/cortex-js/src/infrastructure/commanders/base.command.ts b/cortex-js/src/infrastructure/commanders/base.command.ts index 5d3be2b98..e6b23463f 100644 --- a/cortex-js/src/infrastructure/commanders/base.command.ts +++ b/cortex-js/src/infrastructure/commanders/base.command.ts @@ -3,7 +3,6 @@ import { Injectable } from '@nestjs/common'; import { CortexUsecases } from '@/usecases/cortex/cortex.usecases'; import ora from 'ora'; import { CortexClient } from './services/cortex.client'; -import { fileManagerService } from '../services/file-manager/file-manager.service'; @Injectable() export abstract class BaseCommand extends CommandRunner { From 5fee4a296e63bfd538d164a327da86708a4a03c1 Mon Sep 17 00:00:00 2001 From: marknguyen1302 Date: Thu, 8 Aug 2024 16:23:55 +0700 Subject: [PATCH 17/20] feat: add pagination for thread list api (#1000) --- .../controllers/threads.controller.ts | 9 ++- .../src/usecases/threads/threads.usecases.ts | 66 +++++++++++++++++-- 2 files changed, 69 insertions(+), 6 deletions(-) diff --git a/cortex-js/src/infrastructure/controllers/threads.controller.ts b/cortex-js/src/infrastructure/controllers/threads.controller.ts index 78a013864..dfa47a37d 100644 --- a/cortex-js/src/infrastructure/controllers/threads.controller.ts +++ b/cortex-js/src/infrastructure/controllers/threads.controller.ts @@ -44,8 +44,13 @@ export class ThreadsController { 'Lists all the available threads along with its configurations.', }) @Get() - findAll() { - return this.threadsUsecases.findAll(); + findAll( + @Query('limit', new DefaultValuePipe(20)) limit: number, + @Query('order', new DefaultValuePipe('desc')) order: 'asc' | 'desc', + @Query('after') after?: string, + @Query('before') before?: string, + ) { + return this.threadsUsecases.findAll(limit, order, after, before); } @ApiOperation({ diff --git a/cortex-js/src/usecases/threads/threads.usecases.ts b/cortex-js/src/usecases/threads/threads.usecases.ts index 7791b955e..46c38bea2 100644 --- a/cortex-js/src/usecases/threads/threads.usecases.ts +++ b/cortex-js/src/usecases/threads/threads.usecases.ts @@ -51,11 +51,69 @@ export class ThreadsUsecases { return this.threadRepository.create(thread); } - async findAll(): Promise { - return this.threadRepository.findAll({ - include: [{ all: true }], - order: [['created_at', 'DESC']], + async findAll( + limit: number, + order: 'asc' | 'desc', + after?: string, + before?: string, + ): Promise> { + const normalizedOrder = order === 'asc' ? 'ASC' : 'DESC'; + let afterQuery = {}; + let beforeQuery = {}; + if (after) { + const [afterDate, afterId] = after.split('_'); + const operator = order === 'asc' ? Op.gt : Op.lt; + afterQuery = { + [Op.or]: [ + { + created_at: { [operator]: Number(afterDate) }, + }, + { + created_at: Number(afterDate), + id: { [operator]: afterId }, + }, + ], + }; + } + if (before) { + const [beforeDate, beforeId] = before.split('_'); + const operator = order === 'asc' ? Op.lt : Op.gt; + beforeQuery = { + [Op.or]: [ + { + created_at: { [operator]: Number(beforeDate) }, + }, + { + created_at: Number(beforeDate), + id: { [operator]: beforeId }, + }, + ], + }; + } + const threads = await this.threadRepository.findAll({ + order: [ + ['created_at', normalizedOrder], + ['id', normalizedOrder], + ], + limit: limit + 1, + where: { + [Op.and]: [afterQuery, beforeQuery], + }, }); + let hasMore = false; + if (threads.length > limit) { + hasMore = true; + threads.pop(); + } + const firstItem = threads[0]; + const lastItem = threads[threads.length - 1]; + const firstId = firstItem + ? `${firstItem.created_at}_${firstItem.id}` + : undefined; + const lastId = lastItem + ? `${lastItem?.created_at}_${lastItem?.id}` + : undefined; + return new PageDto(threads, hasMore, firstId, lastId); } async getMessagesOfThread( From 59090bb732221d5e4825229d3cdef227a46c1cd6 Mon Sep 17 00:00:00 2001 From: Louis Date: Thu, 8 Aug 2024 17:29:33 +0700 Subject: [PATCH 18/20] fix: binary file lookup (#1001) Co-authored-by: Hien To --- .github/workflows/cortex-build.yml | 8 ++++---- cortex-js/Makefile | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/cortex-build.yml b/.github/workflows/cortex-build.yml index 44a25b6c5..182e445d9 100644 --- a/.github/workflows/cortex-build.yml +++ b/.github/workflows/cortex-build.yml @@ -233,7 +233,7 @@ jobs: include: - os: "linux" name: "amd64" - runs-on: "ubuntu-latest" + runs-on: "ubuntu-20-04" - os: "windows" name: "amd64" @@ -322,14 +322,14 @@ jobs: which cp which mv npm install -g cpx - npx cpx ./dist/cortexso-macos ./ - mv cortexso-macos cortex + npx cpx ./dist/cortexso ./ + mv cortexso cortex - name: Code Signing macOS if: runner.os == 'macOS' run: | cd cortex-js - ./dist/cortexso-macos --help + ./dist/cortexso --help echo "--------" ./cortex --help make codesign-binary CODE_SIGN=true DEVELOPER_ID="${{ secrets.DEVELOPER_ID }}" diff --git a/cortex-js/Makefile b/cortex-js/Makefile index 798d55a1a..2d9d7bcec 100644 --- a/cortex-js/Makefile +++ b/cortex-js/Makefile @@ -5,7 +5,7 @@ AZURE_TENANT_ID ?= xxxx AZURE_CLIENT_SECRET ?= xxxx AZURE_CERT_NAME ?= xxxx DEVELOPER_ID ?= xxxx -CORTEX_EXE_IN ?= "dist/cortexso-win.exe" +CORTEX_EXE_IN ?= "dist/cortexso.exe" CORTEX_EXE_OUT ?= "cortex.exe" CORTEX_VERSION ?= "0.0.0.1" @@ -13,7 +13,7 @@ update-app-info: ifeq ($(OS),Windows_NT) @powershell -Command 'npx resedit --in $(CORTEX_EXE_IN) --out $(CORTEX_EXE_OUT) --icon "1,cortex.ico" --no-grow --company-name "Homebrew Computer Pte Ltd" --file-description "cortex cli" --file-version "$(CORTEX_VERSION)" --internal-name "cortex" --product-name "cortex" --product-version "$(CORTEX_VERSION)"' else ifeq ($(shell uname -s),Linux) - @cp ./dist/cortexso-linux ./cortex + @cp ./dist/cortexso ./cortex endif codesign-binary: From bdf8ecbc9683cad2b14887be0503fed5968ce05c Mon Sep 17 00:00:00 2001 From: marknguyen1302 Date: Fri, 9 Aug 2024 00:38:38 +0700 Subject: [PATCH 19/20] feat: unload engine when init engine (#1003) --- cortex-js/package.json | 6 +++-- .../engines/engines-init.command.ts | 9 ++++--- .../infrastructure/commanders/ps.command.ts | 5 ++-- .../src/infrastructure/constants/cortex.ts | 5 ++++ .../resources-manager.service.ts | 6 +++-- .../src/usecases/cortex/cortex.usecases.ts | 25 +++++++++++++++++++ cortex-js/src/utils/system-resource.ts | 16 ++++++++++++ 7 files changed, 62 insertions(+), 10 deletions(-) create mode 100644 cortex-js/src/utils/system-resource.ts diff --git a/cortex-js/package.json b/cortex-js/package.json index 7aea006a7..f22c50b8e 100644 --- a/cortex-js/package.json +++ b/cortex-js/package.json @@ -53,16 +53,18 @@ "@nestjs/sequelize": "^10.0.1", "@nestjs/swagger": "^7.3.1", "@terascope/fetch-github-release": "^0.8.8", + "@types/node-os-utils": "^1.3.4", "axios": "^1.6.8", "class-transformer": "^0.5.1", "class-validator": "^0.14.1", "cli-progress": "^3.12.0", - "cortex-cpp": "0.5.0-36", + "cortex-cpp": "0.5.0-40", "cpu-instructions": "^0.0.11", "decompress": "^4.2.1", "hyllama": "^0.2.2", "js-yaml": "^4.1.0", "nest-commander": "^3.13.0", + "node-os-utils": "^1.3.7", "ora": "5.4.1", "readline": "^1.3.0", "reflect-metadata": "^0.2.0", @@ -70,7 +72,7 @@ "sequelize": "^6.37.3", "sequelize-typescript": "^2.1.6", "sqlite3": "^5.1.7", - "systeminformation": "^5.22.11", + "systeminformation": "^5.23.4", "ulid": "^2.3.0", "uuid": "^9.0.1", "whatwg-url": "^14.0.0", diff --git a/cortex-js/src/infrastructure/commanders/engines/engines-init.command.ts b/cortex-js/src/infrastructure/commanders/engines/engines-init.command.ts index c65075e5d..28d15a7f1 100644 --- a/cortex-js/src/infrastructure/commanders/engines/engines-init.command.ts +++ b/cortex-js/src/infrastructure/commanders/engines/engines-init.command.ts @@ -41,12 +41,13 @@ export class EnginesInitCommand extends BaseCommand { const configs = await fileManagerService.getConfig(); const host = configs.cortexCppHost; const port = configs.cortexCppPort; - // Should stop cortex before installing engine - const stopCortexSpinner = ora('Stopping cortex...').start(); + // Should unload engine before installing engine + const unloadCortexEngineSpinner = ora('Unloading cortex...').start(); if (await this.cortexUsecases.healthCheck(host, port)) { - await this.cortexUsecases.stopCortex(); + await this.cortexUsecases.unloadCortexEngine(engine as Engines); } - stopCortexSpinner.succeed('Cortex stopped'); + + unloadCortexEngineSpinner.succeed('Cortex unloaded'); console.log(`Installing engine ${engine}...`); await this.cortex.engines.init(engine, params); diff --git a/cortex-js/src/infrastructure/commanders/ps.command.ts b/cortex-js/src/infrastructure/commanders/ps.command.ts index b4c2d30b0..f2268cdd6 100644 --- a/cortex-js/src/infrastructure/commanders/ps.command.ts +++ b/cortex-js/src/infrastructure/commanders/ps.command.ts @@ -12,6 +12,7 @@ import { firstValueFrom } from 'rxjs'; import { HttpService } from '@nestjs/axios'; import { CORTEX_CPP_MODELS_URL } from '../constants/cortex'; import { fileManagerService } from '../services/file-manager/file-manager.service'; +import { getMemoryInformation } from '@/utils/system-resource'; @SubCommand({ name: 'ps', @@ -45,9 +46,9 @@ export class PSCommand extends BaseCommand { totalVram, }); } - const memoryData = await systeminformation.mem(); + const { total, used } = await getMemoryInformation() const memoryUsage = ( - (memoryData.active / memoryData.total) * + (used / total) * 100 ).toFixed(2); const consumedTable = { diff --git a/cortex-js/src/infrastructure/constants/cortex.ts b/cortex-js/src/infrastructure/constants/cortex.ts index 04d80634c..9e07868f8 100644 --- a/cortex-js/src/infrastructure/constants/cortex.ts +++ b/cortex-js/src/infrastructure/constants/cortex.ts @@ -26,6 +26,11 @@ export const CORTEX_CPP_PROCESS_DESTROY_URL = ( port: number = defaultCortexCppPort, ) => `http://${host}:${port}/processmanager/destroy`; +export const CORTEX_CPP_UNLOAD_ENGINE_URL = ( + host: string = defaultCortexCppHost, + port: number = defaultCortexCppPort, +) => `http://${host}:${port}/inferences/server/unloadengine`; + export const CORTEX_CPP_HEALTH_Z_URL = ( host: string = defaultCortexCppHost, port: number = defaultCortexCppPort, diff --git a/cortex-js/src/infrastructure/services/resources-manager/resources-manager.service.ts b/cortex-js/src/infrastructure/services/resources-manager/resources-manager.service.ts index da7a0c402..8b8752af6 100644 --- a/cortex-js/src/infrastructure/services/resources-manager/resources-manager.service.ts +++ b/cortex-js/src/infrastructure/services/resources-manager/resources-manager.service.ts @@ -1,18 +1,20 @@ +import osUtils from 'node-os-utils' import { ResourceStatus, UsedMemInfo, } from '@/domain/models/resource.interface'; +import { getMemoryInformation, MemoryInformation } from '@/utils/system-resource'; import { Injectable } from '@nestjs/common'; import systemInformation, { Systeminformation } from 'systeminformation'; @Injectable() export class ResourcesManagerService { async getResourceStatuses(): Promise { - const promises = [systemInformation.currentLoad(), systemInformation.mem()]; + const promises = [systemInformation.currentLoad(), getMemoryInformation()]; const results = await Promise.all(promises); const cpuUsage = results[0] as Systeminformation.CurrentLoadData; - const memory = results[1] as Systeminformation.MemData; + const memory = results[1] as MemoryInformation const memInfo: UsedMemInfo = { total: memory.total, used: memory.used, diff --git a/cortex-js/src/usecases/cortex/cortex.usecases.ts b/cortex-js/src/usecases/cortex/cortex.usecases.ts index 573a9db00..74fbe942e 100644 --- a/cortex-js/src/usecases/cortex/cortex.usecases.ts +++ b/cortex-js/src/usecases/cortex/cortex.usecases.ts @@ -13,11 +13,13 @@ import { fileManagerService } from '@/infrastructure/services/file-manager/file- import { CORTEX_CPP_HEALTH_Z_URL, CORTEX_CPP_PROCESS_DESTROY_URL, + CORTEX_CPP_UNLOAD_ENGINE_URL, CORTEX_JS_SYSTEM_URL, defaultCortexJsHost, defaultCortexJsPort, } from '@/infrastructure/constants/cortex'; import { openSync } from 'fs'; +import { Engines } from '@/infrastructure/commanders/types/engine.interface'; @Injectable() export class CortexUsecases implements BeforeApplicationShutdown { @@ -123,6 +125,29 @@ export class CortexUsecases implements BeforeApplicationShutdown { } } + /** + * Unload the engine + */ + async unloadCortexEngine(engine: Engines): Promise { + const configs = await fileManagerService.getConfig(); + try { + await firstValueFrom( + this.httpService.post( + CORTEX_CPP_UNLOAD_ENGINE_URL( + configs.cortexCppHost, + configs.cortexCppPort, + ), + ), + ); + } finally { + return { + message: `${engine} unloaded successfully`, + status: 'success', + }; + } + } + + /** * Check whether the Cortex CPP is healthy * @param host diff --git a/cortex-js/src/utils/system-resource.ts b/cortex-js/src/utils/system-resource.ts new file mode 100644 index 000000000..527884a9c --- /dev/null +++ b/cortex-js/src/utils/system-resource.ts @@ -0,0 +1,16 @@ +import osUtils from 'node-os-utils' + +export type MemoryInformation = { + total: osUtils.MemUsedInfo['totalMemMb']; + used: osUtils.MemUsedInfo['usedMemMb']; + free: osUtils.MemFreeInfo['freeMemMb'] +} + +export const getMemoryInformation = async (): Promise => { + const [usedMemoryInfo, freeMemoryInfo] = await Promise.all([osUtils.mem.used(), osUtils.mem.free()]) + return { + total: usedMemoryInfo.totalMemMb, + used: usedMemoryInfo.usedMemMb, + free: freeMemoryInfo.freeMemMb + } +} \ No newline at end of file From 93916504107cad6de9facfc2fa270fd959000b92 Mon Sep 17 00:00:00 2001 From: vansangpfiev Date: Fri, 9 Aug 2024 08:48:49 +0700 Subject: [PATCH 20/20] fix: remove uploads_folder_path (#996) --- cortex-cpp/addon.cc | 5 ----- cortex-cpp/main.cc | 10 ---------- 2 files changed, 15 deletions(-) diff --git a/cortex-cpp/addon.cc b/cortex-cpp/addon.cc index 3669d71e0..503358160 100644 --- a/cortex-cpp/addon.cc +++ b/cortex-cpp/addon.cc @@ -27,7 +27,6 @@ static Napi::Env* s_env = nullptr; void start(const int port = 3929) { int thread_num = 1; std::string host = "127.0.0.1"; - std::string uploads_folder_path; int logical_cores = std::thread::hardware_concurrency(); int drogon_thread_num = std::max(thread_num, logical_cores); #ifdef CORTEX_CPP_VERSION @@ -40,10 +39,6 @@ void start(const int port = 3929) { LOG_INFO << "Please load your model"; drogon::app().addListener(host, port); drogon::app().setThreadNum(drogon_thread_num); - if (!uploads_folder_path.empty()) { - LOG_INFO << "Drogon uploads folder is at: " << uploads_folder_path; - drogon::app().setUploadPath(uploads_folder_path); - } LOG_INFO << "Number of thread is:" << drogon::app().getThreadNum(); drogon::app().run(); diff --git a/cortex-cpp/main.cc b/cortex-cpp/main.cc index 5e61dd9a8..6ec7ea205 100644 --- a/cortex-cpp/main.cc +++ b/cortex-cpp/main.cc @@ -44,7 +44,6 @@ int main(int argc, char* argv[]) { int thread_num = 1; std::string host = "127.0.0.1"; int port = 3928; - std::string uploads_folder_path; // Number of cortex-cpp threads if (argc > 1) { @@ -61,11 +60,6 @@ int main(int argc, char* argv[]) { port = std::atoi(argv[3]); // Convert string argument to int } - // Uploads folder path - if (argc > 4) { - uploads_folder_path = argv[4]; - } - int logical_cores = std::thread::hardware_concurrency(); int drogon_thread_num = std::max(thread_num, logical_cores); // cortex_utils::nitro_logo(); @@ -79,10 +73,6 @@ int main(int argc, char* argv[]) { LOG_INFO << "Please load your model"; drogon::app().addListener(host, port); drogon::app().setThreadNum(drogon_thread_num); - if (!uploads_folder_path.empty()) { - LOG_INFO << "Drogon uploads folder is at: " << uploads_folder_path; - drogon::app().setUploadPath(uploads_folder_path); - } LOG_INFO << "Number of thread is:" << drogon::app().getThreadNum(); drogon::app().run();