Skip to content
This repository was archived by the owner on Jul 4, 2025. It is now read-only.

Commit 0954152

Browse files
fix: handle multi download model, uninstall script (#932)
1 parent a8eb3b4 commit 0954152

File tree

11 files changed

+82
-23
lines changed

11 files changed

+82
-23
lines changed

cortex-js/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@
3434
"build:dev": "yarn build && run-script-os && npm link",
3535
"build:dev:windows": "echo 'Windows build complete'",
3636
"build:dev:macos": "chmod +x ./dist/src/command.js",
37-
"build:dev:linux": "chmod +x ./dist/src/command.js"
37+
"build:dev:linux": "chmod +x ./dist/src/command.js",
38+
"preuninstall": "node ./uninstall.js"
3839
},
3940
"dependencies": {
4041
"@cortexso/cortex.js": "^0.1.3",

cortex-js/src/infrastructure/commanders/chat.command.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,9 @@ import { FileManagerService } from '../services/file-manager/file-manager.servic
1616
import { isRemoteEngine } from '@/utils/normalize-model-id';
1717
import { Cortex } from '@cortexso/cortex.js';
1818
import { ChatClient } from './services/chat-client';
19-
import { downloadModelProgress } from '@/utils/pull-model';
19+
import { downloadProgress } from '@/utils/download-progress';
2020
import { CortexClient } from './services/cortex.client';
21+
import { DownloadType } from '@/domain/models/download.interface';
2122

2223
type ChatOptions = {
2324
threadId?: string;
@@ -92,7 +93,7 @@ export class ChatCommand extends BaseCommand {
9293
) {
9394
console.log('Downloading engine...');
9495
await this.cortex.engines.init(engine);
95-
await downloadModelProgress(this.cortex);
96+
await downloadProgress(this.cortex, undefined, DownloadType.Engine)
9697
}
9798

9899
if (!message) options.attach = true;
@@ -107,7 +108,7 @@ export class ChatCommand extends BaseCommand {
107108
);
108109

109110
const preset = await this.fileService.getPreset(options.preset);
110-
111+
111112
return this.cortex.models.start(modelId, preset).then(() =>
112113
this.chatClient.chat(
113114
modelId,

cortex-js/src/infrastructure/commanders/engines/engines-init.command.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { BaseCommand } from '../base.command';
99
import { defaultInstallationOptions } from '@/utils/init';
1010
import { Presets, SingleBar } from 'cli-progress';
1111
import { CortexClient } from '../services/cortex.client';
12+
import ora from 'ora';
1213

1314
@SubCommand({
1415
name: '<name> init',
@@ -44,9 +45,11 @@ export class EnginesInitCommand extends BaseCommand {
4445
const host = configs.cortexCppHost;
4546
const port = configs.cortexCppPort;
4647
// Should stop cortex before installing engine
48+
const stopCortexSpinner = ora('Stopping cortex...').start();
4749
if (await this.cortexUsecases.healthCheck(host, port)) {
4850
await this.cortexUsecases.stopCortex();
4951
}
52+
stopCortexSpinner.succeed('Cortex stopped');
5053
console.log(`Installing engine ${engine}...`);
5154
await this.cortex.engines.init(engine, params);
5255
const response = await this.cortex.events.downloadEvent();
@@ -68,6 +71,9 @@ export class EnginesInitCommand extends BaseCommand {
6871
}
6972
}
7073
progressBar.stop();
74+
const startCortexSpinner = ora('Starting cortex...').start();
75+
await this.cortexUsecases.startCortex();
76+
startCortexSpinner.succeed('Cortex started');
7177
console.log('Engine installed successfully');
7278
process.exit(0);
7379
}

cortex-js/src/infrastructure/commanders/models/model-pull.command.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,9 @@ import { checkModelCompatibility } from '@/utils/model-check';
1515
import { Engines } from '../types/engine.interface';
1616
import { CortexUsecases } from '@/usecases/cortex/cortex.usecases';
1717
import { BaseCommand } from '../base.command';
18-
import { downloadModelProgress } from '@/utils/pull-model';
18+
import { downloadProgress } from '@/utils/download-progress';
1919
import { CortexClient } from '../services/cortex.client';
20+
import { DownloadType } from '@/domain/models/download.interface';
2021

2122
@SubCommand({
2223
name: 'pull',
@@ -58,7 +59,7 @@ export class ModelPullCommand extends BaseCommand {
5859
exit(1);
5960
});
6061

61-
await downloadModelProgress(this.cortex, modelId);
62+
await downloadProgress(this.cortex, modelId);
6263

6364
const existingModel = await this.cortex.models.retrieve(modelId);
6465
const engine = existingModel?.engine || Engines.llamaCPP;
@@ -70,7 +71,7 @@ export class ModelPullCommand extends BaseCommand {
7071
console.log('\n');
7172
console.log('Downloading engine...');
7273
await this.cortex.engines.init(engine);
73-
await downloadModelProgress(this.cortex);
74+
await downloadProgress(this.cortex, undefined, DownloadType.Engine);
7475
}
7576
this.telemetryUsecases.sendEvent(
7677
[

cortex-js/src/infrastructure/commanders/models/model-start.command.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,9 @@ import { Engines } from '../types/engine.interface';
1111
import { checkModelCompatibility } from '@/utils/model-check';
1212
import { BaseCommand } from '../base.command';
1313
import { isRemoteEngine } from '@/utils/normalize-model-id';
14-
import { downloadModelProgress } from '@/utils/pull-model';
14+
import { downloadProgress } from '@/utils/download-progress';
1515
import { CortexClient } from '../services/cortex.client';
16+
import { DownloadType } from '@/domain/models/download.interface';
1617

1718
type ModelStartOptions = {
1819
attach: boolean;
@@ -73,7 +74,7 @@ export class ModelStartCommand extends BaseCommand {
7374
) {
7475
console.log('Downloading engine...');
7576
await this.cortex.engines.init(engine);
76-
await downloadModelProgress(this.cortex);
77+
await downloadProgress(this.cortex, undefined, DownloadType.Engine);
7778
}
7879

7980
// Attached - stdout logs

cortex-js/src/infrastructure/commanders/run.command.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,9 @@ import { checkModelCompatibility } from '@/utils/model-check';
1010
import { BaseCommand } from './base.command';
1111
import { isRemoteEngine } from '@/utils/normalize-model-id';
1212
import { ChatClient } from './services/chat-client';
13-
import { downloadModelProgress } from '@/utils/pull-model';
13+
import { downloadProgress } from '@/utils/download-progress';
1414
import { CortexClient } from './services/cortex.client';
15+
import { DownloadType } from '@/domain/models/download.interface';
1516

1617
type RunOptions = {
1718
threadId?: string;
@@ -65,7 +66,7 @@ export class RunCommand extends BaseCommand {
6566
checkingSpinner.fail(e.message ?? e);
6667
exit(1);
6768
});
68-
await downloadModelProgress(this.cortex, modelId);
69+
await downloadProgress(this.cortex, modelId);
6970
}
7071

7172
// Second check if model is available
@@ -84,7 +85,7 @@ export class RunCommand extends BaseCommand {
8485
) {
8586
console.log('Downloading engine...');
8687
await this.cortex.engines.init(engine);
87-
await downloadModelProgress(this.cortex);
88+
await downloadProgress(this.cortex, undefined, DownloadType.Engine);
8889
}
8990

9091
const startingSpinner = ora('Loading model...').start();

cortex-js/src/infrastructure/controllers/engines.controller.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,10 @@ import {
77
Post,
88
Body,
99
Patch,
10+
Res,
1011
} from '@nestjs/common';
1112
import { ApiOperation, ApiParam, ApiTags, ApiResponse } from '@nestjs/swagger';
13+
import { Response } from 'express';
1214
import { TransformInterceptor } from '../interceptors/transform.interceptor';
1315
import { EnginesUsecases } from '@/usecases/engines/engines.usecase';
1416
import { EngineDto, InitEngineDto } from '../dtos/engines/engines.dto';
@@ -78,11 +80,15 @@ export class EnginesController {
7880
description: 'The unique identifier of the engine.',
7981
})
8082
@Post(':name(*)/init')
81-
initialize(@Param('name') name: string, @Body() body: InitEngineDto | undefined) {
83+
initialize(@Param('name') name: string, @Body() body: InitEngineDto | undefined, @Res() res: Response) {
84+
try{
8285
this.initUsescases.installEngine(body, 'latest', name, true);
83-
return {
84-
message: 'Engine initialization started successfully.',
85-
};
86+
res.json({
87+
message: 'Engine initialization started successfully.',
88+
})
89+
} catch (error) {
90+
res.status(400).send(error.message);
91+
}
8692
}
8793

8894
@HttpCode(200)

cortex-js/src/usecases/engines/engines.usecase.ts

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -79,9 +79,11 @@ export class EnginesUsecases {
7979
force: boolean = false,
8080
): Promise<any> => {
8181
// Use default option if not defined
82+
8283
if (!options && engine === Engines.llamaCPP) {
8384
options = await defaultInstallationOptions();
8485
}
86+
const installPackages = [];
8587
// Ship Llama.cpp engine by default
8688
if (
8789
!existsSync(
@@ -93,7 +95,7 @@ export class EnginesUsecases {
9395
engine === Engines.llamaCPP &&
9496
(options?.vulkan ||
9597
(options?.runMode === 'GPU' && options?.gpuType !== 'Nvidia'));
96-
await this.installAcceleratedEngine(version, engine, [
98+
installPackages.push(this.installAcceleratedEngine(version, engine, [
9799
process.platform === 'win32'
98100
? '-windows'
99101
: process.platform === 'darwin'
@@ -116,7 +118,7 @@ export class EnginesUsecases {
116118
? '-arm64'
117119
: '-amd64'
118120
: '',
119-
]);
121+
]));
120122
}
121123

122124
if (
@@ -126,12 +128,12 @@ export class EnginesUsecases {
126128
options?.gpuType === 'Nvidia' &&
127129
!options?.vulkan)
128130
)
129-
await this.installCudaToolkitDependency(
131+
installPackages.push(this.installCudaToolkitDependency(
130132
engine === Engines.tensorrtLLM
131133
? MIN_CUDA_VERSION
132134
: options?.cudaVersion,
133-
);
134-
135+
));
136+
await Promise.all(installPackages);
135137
// Update states
136138
await this.extensionRepository.findOne(engine).then((e) => {
137139
if (e) e.status = EngineStatus.READY;
@@ -254,7 +256,6 @@ export class EnginesUsecases {
254256
console.log(
255257
`Could not find engine file for platform ${process.platform}`,
256258
);
257-
exit(1);
258259
}
259260

260261
const engineDir = await this.fileManagerService.getCortexCppEnginePath();

cortex-js/src/usecases/models/models.usecases.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,14 @@ export class ModelsUsecases {
119119
}
120120

121121
const modelFolder = join(modelsContainerDir, normalizeModelId(id));
122+
const model = await this.getModelOrThrow(id);
123+
const engine = (await this.extensionRepository.findOne(
124+
model!.engine ?? Engines.llamaCPP,
125+
)) as EngineExtension | undefined;
122126

127+
if (engine) {
128+
await engine.unloadModel(id, model.engine || Engines.llamaCPP).catch(() => {}); // Silent fail
129+
}
123130
return this.modelRepository
124131
.remove(id)
125132
.then(
Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import { Presets, SingleBar } from "cli-progress";
22
import { Cortex } from "@cortexso/cortex.js";
33
import { exit, stdin, stdout } from 'node:process';
4+
import { DownloadType } from "@/domain/models/download.interface";
45

5-
export const downloadModelProgress = async (cortex: Cortex, downloadId?: string) => {
6+
export const downloadProgress = async (cortex: Cortex, downloadId?: string, downloadType?: DownloadType) => {
67
const response = await cortex.events.downloadEvent();
78

89
const rl = require('readline').createInterface({
@@ -27,6 +28,7 @@ export const downloadModelProgress = async (cortex: Cortex, downloadId?: string)
2728
for await (const stream of response) {
2829
if (stream.length) {
2930
const data = stream[0] as any;
31+
if (downloadId && data.id !== downloadId || downloadType && data.type !== downloadType) continue;
3032

3133
if (data.status === 'downloaded') break;
3234

0 commit comments

Comments
 (0)