diff --git a/cortex-js/constant.ts b/cortex-js/constant.ts deleted file mode 100644 index 14bda4837..000000000 --- a/cortex-js/constant.ts +++ /dev/null @@ -1,9 +0,0 @@ -export const databaseName = 'cortex'; - -export const databaseFile = `${databaseName}.db`; - -export const defaultCortexJsHost = 'localhost'; -export const defaultCortexJsPort = 1337; - -export const defaultCortexCppHost = '127.0.0.1'; -export const defaultCortexCppPort = 3928; diff --git a/cortex-js/package.json b/cortex-js/package.json index e795f942a..1e4b08149 100644 --- a/cortex-js/package.json +++ b/cortex-js/package.json @@ -55,12 +55,11 @@ "sqlite3": "^5.1.7", "typeorm": "^0.3.20", "ulid": "^2.3.0", - "yaml": "^2.4.2", + "update-notifier": "^5.0.0", "uuid": "^9.0.1", - "update-notifier": "^5.0.0" + "yaml": "^2.4.2" }, "devDependencies": { - "cpx": "^1.5.0", "@nestjs/cli": "^10.0.0", "@nestjs/schematics": "^10.0.0", "@nestjs/testing": "^10.0.0", @@ -76,18 +75,21 @@ "@types/uuid": "^9.0.8", "@typescript-eslint/eslint-plugin": "^6.0.0", "@typescript-eslint/parser": "^6.0.0", + "cpx": "^1.5.0", "eslint": "^8.42.0", "eslint-config-prettier": "^9.0.0", "eslint-plugin-prettier": "^5.0.0", + "hanbi": "^1.0.3", "jest": "^29.5.0", + "nest-commander-testing": "^3.3.0", "prettier": "^3.0.0", + "run-script-os": "^1.1.6", "source-map-support": "^0.5.21", "supertest": "^6.3.3", "ts-jest": "^29.1.0", "ts-loader": "^9.4.3", "tsconfig-paths": "^4.2.0", - "typescript": "^5.1.3", - "run-script-os": "^1.1.6" + "typescript": "^5.1.3" }, "files": [ "dist" diff --git a/cortex-js/src/file-manager/file-manager.service.ts b/cortex-js/src/file-manager/file-manager.service.ts index 4d838db6f..78b29270c 100644 --- a/cortex-js/src/file-manager/file-manager.service.ts +++ b/cortex-js/src/file-manager/file-manager.service.ts @@ -43,7 +43,7 @@ export class FileManagerService { } } - private async writeConfigFile(config: Config): Promise { + async writeConfigFile(config: Config): Promise { const homeDir = os.homedir(); const configPath = join(homeDir, this.configFile); diff --git a/cortex-js/src/infrastructure/commanders/serve.command.ts b/cortex-js/src/infrastructure/commanders/serve.command.ts index 7e49ad590..f839b4a0b 100644 --- a/cortex-js/src/infrastructure/commanders/serve.command.ts +++ b/cortex-js/src/infrastructure/commanders/serve.command.ts @@ -1,5 +1,8 @@ import { spawn } from 'child_process'; -import { defaultCortexJsHost, defaultCortexJsPort } from 'constant'; +import { + defaultCortexJsHost, + defaultCortexJsPort, +} from '@/infrastructure/constants/cortex'; import { CommandRunner, SubCommand, Option } from 'nest-commander'; import { join } from 'path'; diff --git a/cortex-js/src/infrastructure/commanders/shortcuts/run.command.ts b/cortex-js/src/infrastructure/commanders/shortcuts/run.command.ts index 760b16ba3..118212590 100644 --- a/cortex-js/src/infrastructure/commanders/shortcuts/run.command.ts +++ b/cortex-js/src/infrastructure/commanders/shortcuts/run.command.ts @@ -7,7 +7,7 @@ import { } from 'nest-commander'; import { exit } from 'node:process'; import { ChatCliUsecases } from '../usecases/chat.cli.usecases'; -import { defaultCortexCppHost, defaultCortexCppPort } from 'constant'; +import { defaultCortexCppHost, defaultCortexCppPort } from '@/infrastructure/constants/cortex'; import { ModelsCliUsecases } from '../usecases/models.cli.usecases'; import { isLocalModel } from '../utils/normalize-model-id'; import { ModelNotFoundException } from '@/infrastructure/exception/model-not-found.exception'; diff --git a/cortex-js/src/infrastructure/commanders/test/model-list.command.spec.ts b/cortex-js/src/infrastructure/commanders/test/model-list.command.spec.ts new file mode 100644 index 000000000..b90b26006 --- /dev/null +++ b/cortex-js/src/infrastructure/commanders/test/model-list.command.spec.ts @@ -0,0 +1,67 @@ +import { TestingModule } from '@nestjs/testing'; +import { stubMethod } from 'hanbi'; +import { CommandTestFactory } from 'nest-commander-testing'; +import { CommandModule } from '@/command.module'; +import { FileManagerService } from '@/file-manager/file-manager.service'; +import { join } from 'path'; +import { mkdirSync, rmSync, writeFileSync } from 'fs'; + +let commandInstance: TestingModule; + +beforeEach( + () => + new Promise(async (res) => { + commandInstance = await CommandTestFactory.createTestingCommand({ + imports: [CommandModule], + }) + // .overrideProvider(LogService) + // .useValue({}) + .compile(); + const fileService = + await commandInstance.resolve(FileManagerService); + + // Attempt to create test folder + await fileService.writeConfigFile({ + dataFolderPath: join(__dirname, 'test_data'), + }); + res(); + }), +); + +afterEach( + () => + new Promise(async (res) => { + // Attempt to clean test folder + rmSync(join(__dirname, 'test_data'), { + recursive: true, + force: true, + }); + res(); + }), +); + +describe('models list returns array of models', () => { + test('empty model list', async () => { + const logMock = stubMethod(console, 'table'); + + await CommandTestFactory.run(commandInstance, ['models', 'list']); + expect(logMock.firstCall?.args[0]).toBeInstanceOf(Array); + expect(logMock.firstCall?.args[0].length).toBe(0); + }); + + test('many models in the list', async () => { + const logMock = stubMethod(console, 'table'); + + mkdirSync(join(__dirname, 'test_data', 'models'), { recursive: true }); + writeFileSync( + join(__dirname, 'test_data', 'models', 'test.yaml'), + 'model: test', + 'utf8', + ); + + await CommandTestFactory.run(commandInstance, ['models', 'list']); + expect(logMock.firstCall?.args[0]).toBeInstanceOf(Array); + expect(logMock.firstCall?.args[0].length).toBe(1); + expect(logMock.firstCall?.args[0][0].id).toBe('test'); + }); +}); diff --git a/cortex-js/src/infrastructure/commanders/usecases/models.cli.usecases.ts b/cortex-js/src/infrastructure/commanders/usecases/models.cli.usecases.ts index df60ad0c0..da07499a2 100644 --- a/cortex-js/src/infrastructure/commanders/usecases/models.cli.usecases.ts +++ b/cortex-js/src/infrastructure/commanders/usecases/models.cli.usecases.ts @@ -397,12 +397,14 @@ export class ModelsCliUsecases { private async parsePreset(preset?: string): Promise { const presetsFolder = await this.fileService.getPresetsPath(); + if (!existsSync(presetsFolder)) return {}; + const presetFile = readdirSync(presetsFolder).find( (file) => file.toLowerCase() === `${preset?.toLowerCase()}.yaml` || file.toLowerCase() === `${preset?.toLocaleLowerCase()}.yml`, ); - if (!presetFile) throw new Error(`Preset ${preset} not found`); + if (!presetFile) return {}; const presetPath = join(presetsFolder, presetFile); if (!preset || !existsSync(presetPath)) return {}; diff --git a/cortex-js/src/infrastructure/commanders/usecases/ps.cli.usecases.ts b/cortex-js/src/infrastructure/commanders/usecases/ps.cli.usecases.ts index 51e097e3e..70d20a16b 100644 --- a/cortex-js/src/infrastructure/commanders/usecases/ps.cli.usecases.ts +++ b/cortex-js/src/infrastructure/commanders/usecases/ps.cli.usecases.ts @@ -1,5 +1,5 @@ import { Injectable } from '@nestjs/common'; -import { defaultCortexCppHost, defaultCortexCppPort } from 'constant'; +import { defaultCortexCppHost, defaultCortexCppPort } from '@/infrastructure/constants/cortex'; export interface ModelStat { modelId: string; diff --git a/cortex-js/src/infrastructure/constants/cortex.ts b/cortex-js/src/infrastructure/constants/cortex.ts index 5fab81ecc..6e6b4c400 100644 --- a/cortex-js/src/infrastructure/constants/cortex.ts +++ b/cortex-js/src/infrastructure/constants/cortex.ts @@ -1,5 +1,12 @@ -import { defaultCortexCppHost, defaultCortexCppPort } from '@/../constant'; +export const databaseName = 'cortex'; +export const databaseFile = `${databaseName}.db`; + +export const defaultCortexJsHost = 'localhost'; +export const defaultCortexJsPort = 1337; + +export const defaultCortexCppHost = '127.0.0.1'; +export const defaultCortexCppPort = 3928; // CORTEX CPP export const CORTEX_CPP_EMBEDDINGS_URL = ( host: string = defaultCortexCppHost, diff --git a/cortex-js/src/infrastructure/database/mysql-database.providers.ts b/cortex-js/src/infrastructure/database/mysql-database.providers.ts index 006b726a3..347c82ef5 100644 --- a/cortex-js/src/infrastructure/database/mysql-database.providers.ts +++ b/cortex-js/src/infrastructure/database/mysql-database.providers.ts @@ -1,4 +1,4 @@ -import { databaseName } from 'constant'; +import { databaseName } from '@/infrastructure/constants/cortex'; import { DataSource } from 'typeorm'; export const mysqlDatabaseProviders = [ diff --git a/cortex-js/src/infrastructure/database/sqlite-database.providers.ts b/cortex-js/src/infrastructure/database/sqlite-database.providers.ts index bcedf7b0c..cd3bb54f8 100644 --- a/cortex-js/src/infrastructure/database/sqlite-database.providers.ts +++ b/cortex-js/src/infrastructure/database/sqlite-database.providers.ts @@ -1,5 +1,5 @@ import { FileManagerService } from '@/file-manager/file-manager.service'; -import { databaseFile } from '@/../constant'; +import { databaseFile } from '@/infrastructure/constants/cortex'; import { join } from 'path'; import { DataSource } from 'typeorm'; diff --git a/cortex-js/src/infrastructure/dtos/cortex/start-cortex.dto.ts b/cortex-js/src/infrastructure/dtos/cortex/start-cortex.dto.ts index 3cf6e6b11..6a8536bfc 100644 --- a/cortex-js/src/infrastructure/dtos/cortex/start-cortex.dto.ts +++ b/cortex-js/src/infrastructure/dtos/cortex/start-cortex.dto.ts @@ -1,6 +1,6 @@ import { ApiProperty } from '@nestjs/swagger'; import { IsIP, IsNumber, IsString, Max, Min } from 'class-validator'; -import { defaultCortexCppHost, defaultCortexCppPort } from 'constant'; +import { defaultCortexCppHost, defaultCortexCppPort } from '@/infrastructure/constants/cortex'; export class StartCortexDto { @ApiProperty({ diff --git a/cortex-js/src/infrastructure/providers/cortex/cortex.provider.ts b/cortex-js/src/infrastructure/providers/cortex/cortex.provider.ts index 33aee645e..6d0b26e6b 100644 --- a/cortex-js/src/infrastructure/providers/cortex/cortex.provider.ts +++ b/cortex-js/src/infrastructure/providers/cortex/cortex.provider.ts @@ -4,7 +4,7 @@ import { PromptTemplate } from '@/domain/models/prompt-template.interface'; import { join } from 'path'; import { Model, ModelSettingParams } from '@/domain/models/model.interface'; import { HttpService } from '@nestjs/axios'; -import { defaultCortexCppHost, defaultCortexCppPort } from '@/../constant'; +import { defaultCortexCppHost, defaultCortexCppPort } from '@/infrastructure/constants/cortex'; import { readdirSync } from 'node:fs'; import { normalizeModelId } from '@/infrastructure/commanders/utils/normalize-model-id'; import { firstValueFrom } from 'rxjs'; diff --git a/cortex-js/src/main.ts b/cortex-js/src/main.ts index 9ec978be7..fa7564669 100644 --- a/cortex-js/src/main.ts +++ b/cortex-js/src/main.ts @@ -2,7 +2,10 @@ import { NestFactory } from '@nestjs/core'; import { AppModule } from './app.module'; import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger'; import { INestApplication, ValidationPipe } from '@nestjs/common'; -import { defaultCortexJsHost, defaultCortexJsPort } from 'constant'; +import { + defaultCortexJsHost, + defaultCortexJsPort, +} from '@/infrastructure/constants/cortex'; import { SeedService } from './usecases/seed/seed.service'; import { FileManagerService } from './file-manager/file-manager.service'; diff --git a/cortex-js/src/usecases/cortex/cortex.usecases.ts b/cortex-js/src/usecases/cortex/cortex.usecases.ts index 6369be8cd..f867667f8 100644 --- a/cortex-js/src/usecases/cortex/cortex.usecases.ts +++ b/cortex-js/src/usecases/cortex/cortex.usecases.ts @@ -3,7 +3,7 @@ import { ChildProcess, spawn } from 'child_process'; import { join } from 'path'; import { CortexOperationSuccessfullyDto } from '@/infrastructure/dtos/cortex/cortex-operation-successfully.dto'; import { HttpService } from '@nestjs/axios'; -import { defaultCortexCppHost, defaultCortexCppPort } from '@/../constant'; +import { defaultCortexCppHost, defaultCortexCppPort } from '@/infrastructure/constants/cortex'; import { existsSync } from 'node:fs'; import { firstValueFrom } from 'rxjs'; import { FileManagerService } from '@/file-manager/file-manager.service';