Skip to content

Commit

Permalink
chore: add API endpoints
Browse files Browse the repository at this point in the history
  • Loading branch information
louis-jan committed Jun 26, 2024
1 parent 34a4888 commit 161d70e
Show file tree
Hide file tree
Showing 18 changed files with 386 additions and 57 deletions.
4 changes: 4 additions & 0 deletions cortex-js/src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ import { ContextModule } from './infrastructure/services/context/context.module'
import { ExtensionsModule } from './extensions/extensions.module';
import { ConfigsModule } from './usecases/configs/configs.module';
import { EnginesModule } from './usecases/engines/engines.module';
import { ConfigsController } from './infrastructure/controllers/configs.controller';
import { EnginesController } from './infrastructure/controllers/engines.controller';

@Module({
imports: [
Expand Down Expand Up @@ -66,6 +68,8 @@ import { EnginesModule } from './usecases/engines/engines.module';
StatusController,
ProcessController,
EventsController,
ConfigsController,
EnginesController,
],
providers: [
{
Expand Down
2 changes: 0 additions & 2 deletions cortex-js/src/domain/abstracts/engine.abstract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ import { Model, ModelSettingParams } from '../../domain/models/model.interface';
import { Extension } from './extension.abstract';

export abstract class EngineExtension extends Extension {
abstract provider: string;

abstract onLoad(): void;

abstract inference(
Expand Down
2 changes: 1 addition & 1 deletion cortex-js/src/domain/abstracts/extension.abstract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
*/
export abstract class Extension {
/** @type {string} Name of the extension. */
name?: string;
name: string;

/** @type {string} Product Name of the extension. */
productName?: string;
Expand Down
9 changes: 5 additions & 4 deletions cortex-js/src/extensions/groq.engine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@ import { ConfigsUsecases } from '@/usecases/configs/configs.usecase';
* It also subscribes to events emitted by the @janhq/core package and handles new message requests.
*/
export default class GroqEngineExtension extends OAIEngineExtension {
provider: string = 'groq';
apiUrl = 'https://api.groq.com/openai/v1/chat/completions';
name = 'Groq Inference Engine';
name = 'groq';
productName = 'Groq Inference Engine';
description = 'This extension enables fast Groq chat completion API calls';
version = '0.0.1';

constructor(
protected readonly httpService: HttpService,
Expand All @@ -22,9 +23,9 @@ export default class GroqEngineExtension extends OAIEngineExtension {

async onLoad() {
const configs = (await this.configsUsecases.getGroupConfigs(
this.provider,
this.name,
)) as unknown as { apiKey: string };
if (!configs?.apiKey)
await this.configsUsecases.saveConfig('apiKey', '', this.provider);
await this.configsUsecases.saveConfig('apiKey', '', this.name);
}
}
9 changes: 5 additions & 4 deletions cortex-js/src/extensions/mistral.engine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@ import { ConfigsUsecases } from '@/usecases/configs/configs.usecase';
* It also subscribes to events emitted by the @janhq/core package and handles new message requests.
*/
export default class MistralEngineExtension extends OAIEngineExtension {
provider: string = 'mistral';
apiUrl = 'https://api.mistral.ai/v1/chat/completions';
name = 'Mistral Inference Engine';
name = 'mistral';
productName = 'Mistral Inference Engine';
description = 'This extension enables Mistral chat completion API calls';
version = '0.0.1';

constructor(
protected readonly httpService: HttpService,
Expand All @@ -22,9 +23,9 @@ export default class MistralEngineExtension extends OAIEngineExtension {

async onLoad() {
const configs = (await this.configsUsecases.getGroupConfigs(
this.provider,
this.name,
)) as unknown as { apiKey: string };
if (!configs?.apiKey)
await this.configsUsecases.saveConfig('apiKey', '', this.provider);
await this.configsUsecases.saveConfig('apiKey', '', this.name);
}
}
11 changes: 6 additions & 5 deletions cortex-js/src/extensions/openai.engine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@ import { ConfigsUsecases } from '@/usecases/configs/configs.usecase';
* It also subscribes to events emitted by the @janhq/core package and handles new message requests.
*/
export default class OpenAIEngineExtension extends OAIEngineExtension {
provider: string = 'openai';
apiUrl = 'https://api.openai.com/v1/chat/completions';
name = 'OpenAI Inference Engine';
description? = 'This extension enables OpenAI chat completion API calls';
name = 'openai';
productName = 'OpenAI Inference Engine';
description = 'This extension enables OpenAI chat completion API calls';
version = '0.0.1';

constructor(
protected readonly httpService: HttpService,
Expand All @@ -22,9 +23,9 @@ export default class OpenAIEngineExtension extends OAIEngineExtension {

async onLoad() {
const configs = (await this.configsUsecases.getGroupConfigs(
this.provider,
this.name,
)) as unknown as { apiKey: string };
if (!configs?.apiKey)
await this.configsUsecases.saveConfig('apiKey', '', this.provider);
await this.configsUsecases.saveConfig('apiKey', '', this.name);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,6 @@ export class EnginesGetCommand extends CommandRunner {
}

async run(passedParams: string[]): Promise<void> {
return this.engineUsecases.getEngine(passedParams[0]).then((e) =>
console.table({
engine: {
name: passedParams[0],
displayName: e.engine?.name,
description: e.engine?.description,
},
configs: e.configs,
}),
);
return this.engineUsecases.getEngine(passedParams[0]).then(console.table);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { Test, TestingModule } from '@nestjs/testing';
import { DatabaseModule } from '../database/database.module';
import { ExtensionModule } from '../repositories/extensions/extension.module';
import { ModelRepositoryModule } from '../repositories/models/model.module';
import { HttpModule } from '@nestjs/axios';
import { DownloadManagerModule } from '@/infrastructure/services/download-manager/download-manager.module';
import { EventEmitterModule } from '@nestjs/event-emitter';
import { TelemetryModule } from '@/usecases/telemetry/telemetry.module';
import { FileManagerModule } from '../services/file-manager/file-manager.module';
import { ConfigsController } from './configs.controller';
import { ConfigsUsecases } from '@/usecases/configs/configs.usecase';
import { ConfigsModule } from '@/usecases/configs/configs.module';

describe('ConfigsController', () => {
let controller: ConfigsController;

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
imports: [
EventEmitterModule.forRoot(),
DatabaseModule,
ExtensionModule,
ModelRepositoryModule,
HttpModule,
DownloadManagerModule,
EventEmitterModule.forRoot(),
TelemetryModule,
FileManagerModule,
ConfigsModule,
],
controllers: [ConfigsController],
providers: [ConfigsUsecases],
}).compile();

controller = module.get<ConfigsController>(ConfigsController);
});

it('should be defined', () => {
expect(controller).toBeDefined();
});
});
81 changes: 81 additions & 0 deletions cortex-js/src/infrastructure/controllers/configs.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import {
Controller,
Get,
Post,
Body,
Param,
HttpCode,
UseInterceptors,
} from '@nestjs/common';
import { ApiOperation, ApiParam, ApiTags, ApiResponse } from '@nestjs/swagger';
import { TransformInterceptor } from '../interceptors/transform.interceptor';
import { ConfigsUsecases } from '@/usecases/configs/configs.usecase';
import { ConfigUpdateDto } from '../dtos/configs/config-update.dto';
import { CommonResponseDto } from '../dtos/common/common-response.dto';

@ApiTags('Configurations')
@Controller('configs')
@UseInterceptors(TransformInterceptor)
export class ConfigsController {
constructor(private readonly configsUsecases: ConfigsUsecases) {}

@HttpCode(200)
@ApiResponse({
status: 200,
description: 'Ok',
type: [Object],
})
@ApiOperation({
summary: 'List configs',
description:
'Lists the currently available configs, including the default and user-defined configurations',
})
@Get()
findAll() {
return this.configsUsecases.getConfigs();
}

@HttpCode(200)
@ApiResponse({
status: 200,
description: 'Ok',
type: Object,
})
@ApiOperation({
summary: 'Get a config',
description:
'Retrieves a config instance, providing basic information about the config',
})
@ApiParam({
name: 'name',
required: true,
description: 'The unique identifier of the config.',
})
@Get(':name(*)')
findOne(@Param('name') name: string) {
return this.configsUsecases.getGroupConfigs(name);
}

@HttpCode(200)
@ApiResponse({
status: 200,
description: 'The config has been successfully updated.',
type: CommonResponseDto,
})
@ApiOperation({
summary: 'Configure a model',
description: "Updates a config by it's group and key",
parameters: [
{
in: 'path',
name: 'model',
required: true,
description: 'The unique identifier of the model.',
},
],
})
@Post(':name(*)')
async update(@Param('name') name: string, @Body() configs: ConfigUpdateDto) {
return this.configsUsecases.saveConfig(configs.key, configs.value, name);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { Test, TestingModule } from '@nestjs/testing';
import { DatabaseModule } from '../database/database.module';
import { ExtensionModule } from '../repositories/extensions/extension.module';
import { ModelRepositoryModule } from '../repositories/models/model.module';
import { HttpModule } from '@nestjs/axios';
import { DownloadManagerModule } from '@/infrastructure/services/download-manager/download-manager.module';
import { EventEmitterModule } from '@nestjs/event-emitter';
import { TelemetryModule } from '@/usecases/telemetry/telemetry.module';
import { FileManagerModule } from '../services/file-manager/file-manager.module';
import { EnginesController } from './engines.controller';
import { EnginesUsecases } from '@/usecases/engines/engines.usecase';
import { EnginesModule } from '@/usecases/engines/engines.module';

describe('ConfigsController', () => {
let controller: EnginesController;

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
imports: [
EventEmitterModule.forRoot(),
DatabaseModule,
ExtensionModule,
ModelRepositoryModule,
HttpModule,
DownloadManagerModule,
EventEmitterModule.forRoot(),
TelemetryModule,
FileManagerModule,
EnginesModule,
],
controllers: [EnginesController],
providers: [EnginesUsecases],
}).compile();

controller = module.get<EnginesController>(EnginesController);
});

it('should be defined', () => {
expect(controller).toBeDefined();
});
});
55 changes: 55 additions & 0 deletions cortex-js/src/infrastructure/controllers/engines.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import {
Controller,
Get,
Param,
HttpCode,
UseInterceptors,
} from '@nestjs/common';
import { ApiOperation, ApiParam, ApiTags, ApiResponse } from '@nestjs/swagger';
import { TransformInterceptor } from '../interceptors/transform.interceptor';
import { EnginesUsecases } from '@/usecases/engines/engines.usecase';
import { EngineDto } from '../dtos/engines/engines.dto';

@ApiTags('Engines')
@Controller('engines')
@UseInterceptors(TransformInterceptor)
export class EnginesController {
constructor(private readonly enginesUsecases: EnginesUsecases) {}

@HttpCode(200)
@ApiResponse({
status: 200,
description: 'Ok',
type: [EngineDto],
})
@ApiOperation({
summary: 'List available engines',
description:
'Lists the currently available engines, including local and remote engines',
})
@Get()
findAll() {
return this.enginesUsecases.getEngines();
}

@HttpCode(200)
@ApiResponse({
status: 200,
description: 'Ok',
type: EngineDto,
})
@ApiOperation({
summary: 'Get an engine',
description:
'Retrieves an engine instance, providing basic information about the engine',
})
@ApiParam({
name: 'name',
required: true,
description: 'The unique identifier of the engine.',
})
@Get(':name(*)')
findOne(@Param('name') name: string) {
return this.enginesUsecases.getEngine(name);
}
}
10 changes: 10 additions & 0 deletions cortex-js/src/infrastructure/dtos/common/common-response.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsString } from 'class-validator';

export class CommonResponseDto {
@ApiProperty({
description: 'The success or error message',
})
@IsString()
message: string;
}
31 changes: 31 additions & 0 deletions cortex-js/src/infrastructure/dtos/configs/config-update.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsOptional, IsString } from 'class-validator';

export class ConfigUpdateDto {
@ApiProperty({
example: 'apiKey',
description: 'The configuration key.',
})
@IsString()
@IsOptional()
key: string;

// Prompt Settings
@ApiProperty({
type: String,
example: 'sk-xxxxxx',
description: 'The value of the configuration.',
})
@IsString()
@IsOptional()
value: string;

@ApiProperty({
type: String,
example: 'openai',
description: 'The configuration name.',
})
@IsString()
@IsOptional()
name?: string;
}
Loading

0 comments on commit 161d70e

Please sign in to comment.