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

Commit 4d05273

Browse files
authored
chore: error output logs for cortex run (#818)
1 parent 36c247f commit 4d05273

File tree

9 files changed

+103
-24
lines changed

9 files changed

+103
-24
lines changed

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

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ import { SetCommandContext } from '../decorators/CommandContext';
33
import { ContextService } from '@/infrastructure/services/context/context.service';
44
import { InitCliUsecases } from '../usecases/init.cli.usecases';
55
import { Engines } from '../types/engine.interface';
6+
import { CortexUsecases } from '@/usecases/cortex/cortex.usecases';
7+
import { FileManagerService } from '@/infrastructure/services/file-manager/file-manager.service';
68

79
@SubCommand({
810
name: 'init',
@@ -16,6 +18,8 @@ import { Engines } from '../types/engine.interface';
1618
export class EnginesInitCommand extends CommandRunner {
1719
constructor(
1820
private readonly initUsecases: InitCliUsecases,
21+
private readonly cortexUsecases: CortexUsecases,
22+
private readonly fileManagerService: FileManagerService,
1923
readonly contextService: ContextService,
2024
) {
2125
super();
@@ -26,14 +30,24 @@ export class EnginesInitCommand extends CommandRunner {
2630
const options = passedParams.includes(Engines.llamaCPP)
2731
? await this.initUsecases.defaultInstallationOptions()
2832
: {};
33+
34+
const configs = await this.fileManagerService.getConfig();
35+
const host = configs.cortexCppHost;
36+
const port = configs.cortexCppPort;
37+
// Should stop cortex before installing engine
38+
if (await this.cortexUsecases.healthCheck(host, port)) {
39+
await this.cortexUsecases.stopCortex();
40+
}
2941
return this.initUsecases
3042
.installEngine(
3143
options,
3244
engine.includes('@') ? engine.split('@')[1] : 'latest',
3345
engine,
34-
true
46+
true,
3547
)
3648
.then(() => console.log('Engine installed successfully!'))
37-
.catch(() => console.error('Engine not found or installation failed!'));
49+
.catch((e) =>
50+
console.error('Install engine failed with reason: %s', e.message ?? e),
51+
);
3852
}
3953
}

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { ModelStopCommand } from './models/model-stop.command';
66
import { ModelPullCommand } from './models/model-pull.command';
77
import { ModelRemoveCommand } from './models/model-remove.command';
88
import { ModelUpdateCommand } from './models/model-update.command';
9+
import { RunCommand } from './shortcuts/run.command';
910

1011
@SubCommand({
1112
name: 'models',
@@ -17,6 +18,7 @@ import { ModelUpdateCommand } from './models/model-update.command';
1718
ModelGetCommand,
1819
ModelRemoveCommand,
1920
ModelUpdateCommand,
21+
RunCommand,
2022
],
2123
description: 'Subcommands for managing models',
2224
})

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ export class ModelStartCommand extends CommandRunner {
6060
/^(http|https):\/\/[^/]+\/.*/.test(existingModel.files[0])
6161
) {
6262
console.error(
63-
`${modelId} not found on filesystem. Please try 'cortex pull ${modelId}' first.`,
63+
`${modelId} not found on filesystem.\nPlease try 'cortex pull ${modelId}' first.`,
6464
);
6565
process.exit(1);
6666
}

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

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,13 +52,9 @@ export class RunCommand extends CommandRunner {
5252
exit(1);
5353
}
5454
}
55-
5655
// If not exist
5756
// Try Pull
5857
if (!(await this.modelsCliUsecases.getModel(modelId))) {
59-
console.log(
60-
`${modelId} not found on filesystem. Downloading from remote: https://huggingface.co/cortexso if possible.`,
61-
);
6258
await this.modelsCliUsecases.pullModel(modelId).catch((e: Error) => {
6359
if (e instanceof ModelNotFoundException)
6460
console.error('Model does not exist.');
@@ -78,6 +74,7 @@ export class RunCommand extends CommandRunner {
7874
process.exit(1);
7975
}
8076

77+
// Check model compatibility on this machine
8178
checkModelCompatibility(modelId);
8279

8380
const engine = existingModel.engine || Engines.llamaCPP;

cortex-js/src/infrastructure/commanders/usecases/chat.cli.usecases.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ export class ChatCliUsecases {
3737
attach: boolean = true,
3838
stopModel: boolean = true,
3939
): Promise<void> {
40-
if (attach) console.log(`Inorder to exit, type '${this.exitClause}'.`);
40+
if (attach) console.log(`In order to exit, type '${this.exitClause}'.`);
4141
const thread = await this.getOrCreateNewThread(modelId, threadId);
4242
const messages: ChatCompletionMessage[] = (
4343
await this.messagesUsecases.getLastMessagesByThread(thread.id, 10)

cortex-js/src/infrastructure/commanders/usecases/models.cli.usecases.ts

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,7 @@ import { ModelsUsecases } from '@/usecases/models/models.usecases';
33
import { Model } from '@/domain/models/model.interface';
44
import { InquirerService } from 'nest-commander';
55
import { Inject, Injectable } from '@nestjs/common';
6-
import { Presets, SingleBar } from 'cli-progress';
76

8-
import { HttpService } from '@nestjs/axios';
97
import { StartModelSuccessDto } from '@/infrastructure/dtos/models/start-model-success.dto';
108
import { UpdateModelDto } from '@/infrastructure/dtos/models/update-model.dto';
119
import { FileManagerService } from '@/infrastructure/services/file-manager/file-manager.service';
@@ -14,14 +12,14 @@ import { load } from 'js-yaml';
1412
import { existsSync, readdirSync, readFileSync } from 'fs';
1513
import { isLocalModel } from '@/utils/normalize-model-id';
1614
import { HuggingFaceRepoSibling } from '@/domain/models/huggingface.interface';
15+
import { printLastErrorLines } from '@/utils/logs';
1716

1817
@Injectable()
1918
export class ModelsCliUsecases {
2019
constructor(
2120
private readonly modelsUsecases: ModelsUsecases,
2221
@Inject(InquirerService)
2322
private readonly inquirerService: InquirerService,
24-
private readonly httpService: HttpService,
2523
private readonly fileService: FileManagerService,
2624
) {}
2725

@@ -40,11 +38,16 @@ export class ModelsCliUsecases {
4038
...parsedPreset,
4139
}))
4240
.then((settings) => this.modelsUsecases.startModel(modelId, settings))
43-
.catch(() => {
44-
return {
45-
modelId: modelId,
46-
message: 'Model not found',
47-
};
41+
.catch(async (e) => {
42+
console.error('Model start failed with reason:', e.message);
43+
44+
printLastErrorLines(await this.fileService.getDataFolderPath(), 5);
45+
46+
console.log(
47+
'For more information, please check the logs at: %s',
48+
join(await this.fileService.getDataFolderPath(), 'cortex.log'),
49+
);
50+
process.exit(1);
4851
});
4952
}
5053

@@ -114,6 +117,11 @@ export class ModelsCliUsecases {
114117
console.error('Model already exists');
115118
process.exit(1);
116119
}
120+
// Checking dependencies
121+
122+
console.log(
123+
`${modelId} not found on filesystem.\nDownloading from remote: https://huggingface.co/${modelId.includes('/') ? modelId : 'cortexso'} ...`,
124+
);
117125
await this.modelsUsecases.pullModel(modelId, true, (files) => {
118126
return new Promise<HuggingFaceRepoSibling>(async (resolve) => {
119127
const listChoices = files

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

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
CORTEX_CPP_PROCESS_DESTROY_URL,
1313
CORTEX_JS_STOP_API_SERVER_URL,
1414
} from '@/infrastructure/constants/cortex';
15+
import { createWriteStream, openSync } from 'fs';
1516

1617
@Injectable()
1718
export class CortexUsecases {
@@ -25,8 +26,8 @@ export class CortexUsecases {
2526

2627
/**
2728
* Start the Cortex CPP process
28-
* @param attach
29-
* @returns
29+
* @param attach
30+
* @returns
3031
*/
3132
async startCortex(
3233
attach: boolean = false,
@@ -55,11 +56,16 @@ export class CortexUsecases {
5556
'cortex-cpp',
5657
);
5758

59+
const writer = openSync(
60+
join(await this.fileManagerService.getDataFolderPath(), 'cortex.log'),
61+
'a+',
62+
);
63+
5864
// go up one level to get the binary folder, have to also work on windows
5965
this.cortexProcess = spawn(cortexCppPath, args, {
6066
detached: !attach,
6167
cwd: cortexCppFolderPath,
62-
stdio: attach ? 'inherit' : undefined,
68+
stdio: [0, writer, writer],
6369
env: {
6470
...process.env,
6571
CUDA_VISIBLE_DEVICES: '0',
@@ -135,7 +141,13 @@ export class CortexUsecases {
135141
.catch(() => {});
136142
}
137143

138-
private healthCheck(host: string, port: number): Promise<boolean> {
144+
/**
145+
* Check whether the Cortex CPP is healthy
146+
* @param host
147+
* @param port
148+
* @returns
149+
*/
150+
healthCheck(host: string, port: number): Promise<boolean> {
139151
return fetch(CORTEX_CPP_HEALTH_Z_URL(host, port))
140152
.then((res) => {
141153
if (res.ok) {

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

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ export class ModelsUsecases {
163163
modelId,
164164
};
165165
}
166-
166+
console.log('Loading model...');
167167
// update states and emitting event
168168
this.activeModelStatuses[modelId] = {
169169
model: modelId,
@@ -233,7 +233,7 @@ export class ModelsUsecases {
233233
e,
234234
TelemetrySource.CORTEX_CPP,
235235
);
236-
return {
236+
throw {
237237
message: e.message,
238238
modelId,
239239
};
@@ -365,14 +365,25 @@ export class ModelsUsecases {
365365
const model: CreateModelDto = load(
366366
readFileSync(join(modelFolder, 'model.yml'), 'utf-8'),
367367
) as CreateModelDto;
368-
if (model.engine === Engines.llamaCPP) {
368+
if (model.engine === Engines.llamaCPP && model.files) {
369369
const fileUrl = join(
370370
await this.fileManagerService.getModelsPath(),
371371
normalizeModelId(modelId),
372372
llamaModelFile(model.files),
373373
);
374374
model.files = [fileUrl];
375375
model.name = modelId.replace(':default', '');
376+
} else if (model.engine === Engines.llamaCPP) {
377+
model.files = [
378+
join(
379+
await this.fileManagerService.getModelsPath(),
380+
normalizeModelId(modelId),
381+
basename(
382+
files.find((e) => e.rfilename.endsWith('.gguf'))?.rfilename ??
383+
files[0].rfilename,
384+
),
385+
),
386+
];
376387
} else {
377388
model.files = [modelFolder];
378389
}
@@ -387,7 +398,10 @@ export class ModelsUsecases {
387398
const fileUrl = join(
388399
await this.fileManagerService.getModelsPath(),
389400
normalizeModelId(modelId),
390-
basename(files[0].rfilename),
401+
basename(
402+
files.find((e) => e.rfilename.endsWith('.gguf'))?.rfilename ??
403+
files[0].rfilename,
404+
),
391405
);
392406
await this.update(modelId, {
393407
files: [fileUrl],

cortex-js/src/utils/logs.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { createReadStream } from 'fs';
2+
import { join } from 'path';
3+
import { createInterface } from 'readline';
4+
5+
/**
6+
* Print the last N lines of a file that contain the word 'ERROR'
7+
* @param filename
8+
* @param numLines
9+
*/
10+
export async function printLastErrorLines(
11+
dataFolderPath: string,
12+
numLines: number = 5,
13+
): Promise<void> {
14+
const errorLines: string[] = [];
15+
16+
const fileStream = createReadStream(join(dataFolderPath, 'cortex.log'));
17+
const rl = createInterface({
18+
input: fileStream,
19+
crlfDelay: Infinity,
20+
});
21+
22+
for await (const line of rl) {
23+
errorLines.push(line);
24+
if (errorLines.length > numLines) {
25+
errorLines.shift();
26+
}
27+
}
28+
29+
console.log(`Last errors:`);
30+
errorLines.forEach((line) => console.log(line));
31+
console.log('...');
32+
}

0 commit comments

Comments
 (0)