From 8034171cb97620cfa7ef942d539bf6e4de7c2d20 Mon Sep 17 00:00:00 2001 From: Louis Date: Fri, 31 May 2024 14:55:54 +0700 Subject: [PATCH] chore: Update the run command to allow model selection and add the Cortex version. (#640) --- .../commanders/cortex-command.commander.ts | 20 ++++++- .../commanders/models/model-start.command.ts | 2 +- .../commanders/shortcuts/run.command.ts | 50 ++++++++++++----- .../src/usecases/models/models.usecases.ts | 55 ++++++++----------- 4 files changed, 79 insertions(+), 48 deletions(-) diff --git a/cortex-js/src/infrastructure/commanders/cortex-command.commander.ts b/cortex-js/src/infrastructure/commanders/cortex-command.commander.ts index c55d17d2e..b5616865b 100644 --- a/cortex-js/src/infrastructure/commanders/cortex-command.commander.ts +++ b/cortex-js/src/infrastructure/commanders/cortex-command.commander.ts @@ -1,4 +1,4 @@ -import { RootCommand, CommandRunner } from 'nest-commander'; +import { RootCommand, CommandRunner, Option } from 'nest-commander'; import { ServeCommand } from './serve.command'; import { ChatCommand } from './chat.command'; import { ModelsCommand } from './models.command'; @@ -7,7 +7,11 @@ import { RunCommand } from './shortcuts/run.command'; import { ModelPullCommand } from './models/model-pull.command'; import { PSCommand } from './ps.command'; import { KillCommand } from './kill.command'; +import pkg from '@/../package.json'; +interface CortexCommandOptions { + version: boolean; +} @RootCommand({ subCommands: [ ModelsCommand, @@ -22,5 +26,17 @@ import { KillCommand } from './kill.command'; description: 'Cortex CLI', }) export class CortexCommand extends CommandRunner { - async run(): Promise {} + async run(input: string[], option: CortexCommandOptions): Promise { + if (option.version) console.log(pkg.version); + } + + @Option({ + flags: '-v, --version', + description: 'Cortex version', + defaultValue: false, + name: 'version', + }) + parseVersion() { + return true; + } } diff --git a/cortex-js/src/infrastructure/commanders/models/model-start.command.ts b/cortex-js/src/infrastructure/commanders/models/model-start.command.ts index d479b4ddf..bfed61aed 100644 --- a/cortex-js/src/infrastructure/commanders/models/model-start.command.ts +++ b/cortex-js/src/infrastructure/commanders/models/model-start.command.ts @@ -34,7 +34,7 @@ export class ModelStartCommand extends CommandRunner { await this.cortexUsecases .startCortex(options.attach) - .then(() => this.modelsCliUsecases.startModel(input[0])) + .then(() => this.modelsCliUsecases.startModel(modelId)) .then(console.log) .then(() => !options.attach && process.exit(0)); } diff --git a/cortex-js/src/infrastructure/commanders/shortcuts/run.command.ts b/cortex-js/src/infrastructure/commanders/shortcuts/run.command.ts index 522ca75bc..169b28b64 100644 --- a/cortex-js/src/infrastructure/commanders/shortcuts/run.command.ts +++ b/cortex-js/src/infrastructure/commanders/shortcuts/run.command.ts @@ -1,9 +1,14 @@ import { CortexUsecases } from '@/usecases/cortex/cortex.usecases'; -import { ModelsUsecases } from '@/usecases/models/models.usecases'; -import { CommandRunner, SubCommand, Option } from 'nest-commander'; +import { + CommandRunner, + SubCommand, + Option, + InquirerService, +} from 'nest-commander'; import { exit } from 'node:process'; import { ChatCliUsecases } from '../usecases/chat.cli.usecases'; import { defaultCortexCppHost, defaultCortexCppPort } from 'constant'; +import { ModelsCliUsecases } from '../usecases/models.cli.usecases'; type RunOptions = { threadId?: string; @@ -15,27 +20,29 @@ type RunOptions = { }) export class RunCommand extends CommandRunner { constructor( - private readonly modelsUsecases: ModelsUsecases, + private readonly modelsCliUsecases: ModelsCliUsecases, private readonly cortexUsecases: CortexUsecases, private readonly chatCliUsecases: ChatCliUsecases, + private readonly inquirerService: InquirerService, ) { super(); } async run(input: string[], option?: RunOptions): Promise { - if (input.length === 0) { - console.error('Model Id is required'); - exit(1); + let modelId = input[0]; + if (!modelId) { + try { + modelId = await this.modelInquiry(); + } catch { + console.error('Model ID is required'); + exit(1); + } } - const modelId = input[0]; - await this.cortexUsecases.startCortex( - false, - defaultCortexCppHost, - defaultCortexCppPort, - ); - await this.modelsUsecases.startModel(modelId); - await this.chatCliUsecases.chat(modelId, option?.threadId); + return this.cortexUsecases + .startCortex(false, defaultCortexCppHost, defaultCortexCppPort) + .then(() => this.modelsCliUsecases.startModel(modelId)) + .then(() => this.chatCliUsecases.chat(modelId, option?.threadId)); } @Option({ @@ -45,4 +52,19 @@ export class RunCommand extends CommandRunner { parseThreadId(value: string) { return value; } + + modelInquiry = async () => { + const models = await this.modelsCliUsecases.listAllModels(); + if (!models.length) throw 'No models found'; + const { model } = await this.inquirerService.inquirer.prompt({ + type: 'list', + name: 'model', + message: 'Select a model to start:', + choices: models.map((e) => ({ + name: e.name, + value: e.id, + })), + }); + return model; + }; } diff --git a/cortex-js/src/usecases/models/models.usecases.ts b/cortex-js/src/usecases/models/models.usecases.ts index d1fe1a7c6..980b0569e 100644 --- a/cortex-js/src/usecases/models/models.usecases.ts +++ b/cortex-js/src/usecases/models/models.usecases.ts @@ -141,30 +141,27 @@ export class ModelsUsecases { if (!engine) { return { message: 'No extension handler found for model', - modelId: modelId, + modelId, }; } return engine .loadModel(model, settings) - .then(() => { - return { - message: 'Model loaded successfully', - modelId: modelId, - }; - }) - .catch((e) => { - if (e.code === AxiosError.ERR_BAD_REQUEST) { - return { - message: 'Model already loaded', - modelId: modelId, - }; - } - return { - message: 'Model failed to load', - modelId: modelId, - }; - }); + .then(() => ({ + message: 'Model loaded successfully', + modelId, + })) + .catch((e) => + e.code === AxiosError.ERR_BAD_REQUEST + ? { + message: 'Model already loaded', + modelId, + } + : { + message: 'Model failed to load', + modelId, + }, + ); } async stopModel(modelId: string): Promise { @@ -183,18 +180,14 @@ export class ModelsUsecases { return engine .unloadModel(modelId) - .then(() => { - return { - message: 'Model is stopped', - modelId, - }; - }) - .catch(() => { - return { - message: 'Failed to stop model', - modelId, - }; - }); + .then(() => ({ + message: 'Model is stopped', + modelId, + })) + .catch(() => ({ + message: 'Failed to stop model', + modelId, + })); } async downloadModel(modelId: string, callback?: (progress: number) => void) {