Skip to content

Commit

Permalink
Merge branch 'dev' into fix/openai_coverage_misc
Browse files Browse the repository at this point in the history
  • Loading branch information
hiro-v committed Jun 12, 2024
2 parents 8bd1983 + 38a4c81 commit 37cf2a4
Show file tree
Hide file tree
Showing 25 changed files with 624 additions and 100 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ Cortex currently supports two inference engines:

Before installation, ensure that you have installed the following:

- **Node.js**: Required for running the installation.
- **Node.js**: version 18 and above is required to run the installation.
- **NPM**: Needed to manage packages.
- **CPU Instruction Sets**: Available for download from the [Cortex GitHub Releases](https://github.com/janhq/cortex/releases) page.

Expand Down
6 changes: 6 additions & 0 deletions cortex-js/.eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,11 @@ module.exports = {
'@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off',
'@typescript-eslint/no-explicit-any': 'off',
"prettier/prettier": [
"error",
{
"endOfLine": "auto"
},
],
},
};
3 changes: 1 addition & 2 deletions cortex-js/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,7 @@ Cortex
### **Dependencies**

Before installation, ensure that you have installed the following:

- **Node.js**: Required for running the installation.
- **Node.js**: version 18 and above is required to run the installation.
- **NPM**: Needed to manage packages.
- **CPU Instruction Sets**: Available for download from the [Cortex GitHub Releases](https://github.com/janhq/cortex/releases) page.

Expand Down
2 changes: 2 additions & 0 deletions cortex-js/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,13 @@
"decompress": "^4.2.1",
"js-yaml": "^4.1.0",
"nest-commander": "^3.13.0",
"openai": "^4.50.0",
"readline": "^1.3.0",
"reflect-metadata": "^0.2.0",
"rxjs": "^7.8.1",
"sqlite": "^5.1.1",
"sqlite3": "^5.1.7",
"systeminformation": "^5.22.10",
"typeorm": "^0.3.20",
"ulid": "^2.3.0",
"update-notifier": "^5.0.0",
Expand Down
2 changes: 2 additions & 0 deletions cortex-js/src/command.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import { PSCommand } from './infrastructure/commanders/ps.command';
import { KillCommand } from './infrastructure/commanders/kill.command';
import { PresetCommand } from './infrastructure/commanders/presets.command';
import { EmbeddingCommand } from './infrastructure/commanders/embeddings.command';
import { BenchmarkCommand } from './infrastructure/commanders/benchmark.command';

@Module({
imports: [
Expand Down Expand Up @@ -56,6 +57,7 @@ import { EmbeddingCommand } from './infrastructure/commanders/embeddings.command
KillCommand,
PresetCommand,
EmbeddingCommand,
BenchmarkCommand,

// Questions
InitRunModeQuestions,
Expand Down
11 changes: 11 additions & 0 deletions cortex-js/src/file-manager/file-manager.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export class FileManagerService {
private modelFolderName = 'models';
private presetFolderName = 'presets';
private extensionFoldername = 'extensions';
private benchmarkFoldername = 'benchmark';
private cortexCppFolderName = 'cortex-cpp';

/**
Expand Down Expand Up @@ -116,4 +117,14 @@ export class FileManagerService {
const dataFolderPath = await this.getDataFolderPath();
return join(dataFolderPath, this.extensionFoldername);
}

/**
* Get the benchmark folder path
* Usually it is located at the home directory > cortex > extensions
* @returns the path to the extensions folder
*/
async getBenchmarkPath(): Promise<string> {
const dataFolderPath = await this.getDataFolderPath();
return join(dataFolderPath, this.benchmarkFoldername);
}
}
18 changes: 18 additions & 0 deletions cortex-js/src/infrastructure/commanders/benchmark.command.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { CommandRunner, SubCommand } from 'nest-commander';
import { BenchmarkCliUsecases } from './usecases/benchmark.cli.usecases';

@SubCommand({
name: 'benchmark',
subCommands: [],
description:
'Benchmark and analyze the performance of a specific AI model using a variety of system resources',
})
export class BenchmarkCommand extends CommandRunner {
constructor(private readonly benchmarkUsecases: BenchmarkCliUsecases) {
super();
}

async run(): Promise<void> {
return this.benchmarkUsecases.benchmark();
}
}
3 changes: 2 additions & 1 deletion cortex-js/src/infrastructure/commanders/chat.command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ import {
} from 'nest-commander';
import { ChatCliUsecases } from './usecases/chat.cli.usecases';
import { exit } from 'node:process';
import { ModelStat, PSCliUsecases } from './usecases/ps.cli.usecases';
import { PSCliUsecases } from './usecases/ps.cli.usecases';
import { ModelsUsecases } from '@/usecases/models/models.usecases';
import { ModelStat } from './types/model-stat.interface';

type ChatOptions = {
threadId?: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { KillCommand } from './kill.command';
import pkg from '@/../package.json';
import { PresetCommand } from './presets.command';
import { EmbeddingCommand } from './embeddings.command';
import { BenchmarkCommand } from './benchmark.command';

interface CortexCommandOptions {
version: boolean;
Expand All @@ -26,6 +27,7 @@ interface CortexCommandOptions {
KillCommand,
PresetCommand,
EmbeddingCommand,
BenchmarkCommand,
],
description: 'Cortex CLI',
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@ import {
SubCommand,
} from 'nest-commander';
import { ModelsUsecases } from '@/usecases/models/models.usecases';
import { ModelStat, PSCliUsecases } from './usecases/ps.cli.usecases';
import { PSCliUsecases } from './usecases/ps.cli.usecases';
import { ChatCliUsecases } from './usecases/chat.cli.usecases';
import { inspect } from 'util';
import { ModelStat } from './types/model-stat.interface';

interface EmbeddingCommandOptions {
encoding_format?: string;
Expand Down
24 changes: 15 additions & 9 deletions cortex-js/src/infrastructure/commanders/serve.command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,22 @@ export class ServeCommand extends CommandRunner {
const host = options?.host || defaultCortexJsHost;
const port = options?.port || defaultCortexJsPort;

spawn('node', [join(__dirname, '../../main.js')], {
env: {
...process.env,
CORTEX_JS_HOST: host,
CORTEX_JS_PORT: port.toString(),
NODE_ENV: 'production',
spawn(
'node',
process.env.TEST
? [join(__dirname, '../../../dist/src/main.js')]
: [join(__dirname, '../../main.js')],
{
env: {
...process.env,
CORTEX_JS_HOST: host,
CORTEX_JS_PORT: port.toString(),
NODE_ENV: 'production',
},
stdio: 'inherit',
detached: false,
},
stdio: 'inherit',
detached: false,
});
);
}

@Option({
Expand Down
107 changes: 107 additions & 0 deletions cortex-js/src/infrastructure/commanders/test/helpers.command.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import { TestingModule } from '@nestjs/testing';
import { spy, Stub, stubMethod } from 'hanbi';
import { CommandTestFactory } from 'nest-commander-testing';
import { CommandModule } from '@/command.module';
import { LogService } from '@/infrastructure/commanders/test/log.service';
import axios from 'axios';

let commandInstance: TestingModule,
exitSpy: Stub<typeof process.exit>,
stdoutSpy: Stub<typeof process.stdout.write>,
stderrSpy: Stub<typeof process.stderr.write>;
export const timeout = 500000;

beforeEach(
() =>
new Promise<void>(async (res) => {
stubMethod(process.stderr, 'write');
exitSpy = stubMethod(process, 'exit');
stdoutSpy = stubMethod(process.stdout, 'write');
stderrSpy = stubMethod(process.stderr, 'write');
commandInstance = await CommandTestFactory.createTestingCommand({
imports: [CommandModule],
})
.overrideProvider(LogService)
.useValue({ log: spy().handler })
.compile();
res();
stdoutSpy.reset();
stderrSpy.reset();
}),
);

describe('Helper commands', () => {
test(
'Init with hardware auto detection',
async () => {
await CommandTestFactory.run(commandInstance, ['init', '-s']);

// Wait for a brief period to allow the command to execute
await new Promise((resolve) => setTimeout(resolve, 1000));

expect(stdoutSpy.firstCall?.args.length).toBeGreaterThan(0);
},
timeout,
);

test('Chat with option -m', async () => {
const logMock = stubMethod(console, 'log');

await CommandTestFactory.run(commandInstance, [
'chat',
// '-m',
// 'hello',
// '>output.txt',
]);
expect(logMock.firstCall?.args[0]).toBe("Inorder to exit, type 'exit()'.");
// expect(exitSpy.callCount).toBe(1);
// expect(exitSpy.firstCall?.args[0]).toBe(1);
});

test('Show / kill running models', async () => {
const tableMock = stubMethod(console, 'table');

const logMock = stubMethod(console, 'log');
await CommandTestFactory.run(commandInstance, ['kill']);
await CommandTestFactory.run(commandInstance, ['ps']);

expect(logMock.firstCall?.args[0]).toEqual({
message: 'Cortex stopped successfully',
status: 'success',
});
expect(tableMock.firstCall?.args[0]).toBeInstanceOf(Array);
expect(tableMock.firstCall?.args[0].length).toEqual(0);
});

test('Help command return guideline to users', async () => {
await CommandTestFactory.run(commandInstance, ['-h']);
expect(stdoutSpy.firstCall?.args).toBeInstanceOf(Array);
expect(stdoutSpy.firstCall?.args.length).toBe(1);
expect(stdoutSpy.firstCall?.args[0]).toContain('display help for command');

expect(exitSpy.callCount).toBeGreaterThan(1);
expect(exitSpy.firstCall?.args[0]).toBe(0);
});

test('Should handle missing command', async () => {
await CommandTestFactory.run(commandInstance, ['--unknown']);
expect(stderrSpy.firstCall?.args[0]).toContain('error: unknown option');
expect(stderrSpy.firstCall?.args[0]).toContain('--unknown');
expect(exitSpy.callCount).toBe(1);
expect(exitSpy.firstCall?.args[0]).toBe(1);
});

test('Local API server via localhost:1337/api', async () => {
await CommandTestFactory.run(commandInstance, ['serve']);

// Add a delay of 1000 milliseconds (1 second)
return new Promise<void>(async (resolve) => {
setTimeout(async () => {
// Send a request to the API server to check if it's running
const response = await axios.get('http://localhost:1337/api');
expect(response.status).toBe(200);
resolve();
}, 1000);
});
});
});
8 changes: 8 additions & 0 deletions cortex-js/src/infrastructure/commanders/test/log.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { Injectable } from '@nestjs/common';

@Injectable()
export class LogService {
log(...args: any[]): void {
console.log(...args);
}
}

This file was deleted.

Loading

0 comments on commit 37cf2a4

Please sign in to comment.