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

Commit 9f48d1d

Browse files
feat: support martian nvidia engine (#956)
1 parent f1f8055 commit 9f48d1d

File tree

10 files changed

+146
-23
lines changed

10 files changed

+146
-23
lines changed

cortex-js/src/domain/abstracts/oai.abstract.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { HttpService } from '@nestjs/axios';
22
import { EngineExtension } from './engine.abstract';
33
import stream, { Transform } from 'stream';
44
import { firstValueFrom } from 'rxjs';
5-
import _ from 'lodash';
5+
import { omit } from 'lodash';
66

77
export abstract class OAIEngineExtension extends EngineExtension {
88
abstract apiUrl: string;
@@ -22,7 +22,7 @@ export abstract class OAIEngineExtension extends EngineExtension {
2222
? this.transformPayload(createChatDto)
2323
: createChatDto;
2424
const { stream: isStream } = payload;
25-
const additionalHeaders = _.omit(headers, [
25+
const additionalHeaders = omit(headers, [
2626
'content-type',
2727
'authorization',
2828
'content-length',
@@ -54,7 +54,7 @@ export abstract class OAIEngineExtension extends EngineExtension {
5454
const transformedLines = [];
5555
for (const line of lines) {
5656
if (line.trim().length > 0) {
57-
const transformedLine = transformResponse(line);
57+
const transformedLine = transformResponse(line, true);
5858
if (transformedLine) {
5959
transformedLines.push(`data: ${transformedLine}\n\n`);
6060
}
@@ -65,6 +65,6 @@ export abstract class OAIEngineExtension extends EngineExtension {
6565
});
6666
return response.data.pipe(lineStream);
6767
}
68-
return this.transformResponse(response.data);
68+
return this.transformResponse(response.data, false);
6969
}
7070
}

cortex-js/src/extensions/anthropic.engine.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { HttpService } from '@nestjs/axios';
33
import { OAIEngineExtension } from '../domain/abstracts/oai.abstract';
44
import { ConfigsUsecases } from '@/usecases/configs/configs.usecase';
55
import { EventEmitter2 } from '@nestjs/event-emitter';
6-
import _ from 'lodash';
6+
import { pick } from 'lodash';
77
import { EngineStatus } from '@/domain/abstracts/engine.abstract';
88

99
/**
@@ -59,7 +59,13 @@ export default class AnthropicEngineExtension extends OAIEngineExtension {
5959
}
6060

6161
transformPayload = (data: any): any => {
62-
return _.pick(data, ['messages', 'model', 'stream', 'max_tokens']);
62+
const system = data.messages.find((m: any) => m.role === 'system');
63+
const messages = data.messages.filter((m: any) => m.role !== 'system');
64+
return {
65+
system: system.content,
66+
messages,
67+
...pick(data, ['model', 'stream', 'max_tokens']),
68+
};
6369
};
6470

6571
transformResponse = (data: any) => {

cortex-js/src/extensions/cohere.engine.ts

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
1-
import stream from 'stream';
21
import { HttpService } from '@nestjs/axios';
32
import { OAIEngineExtension } from '../domain/abstracts/oai.abstract';
43
import { ConfigsUsecases } from '@/usecases/configs/configs.usecase';
54
import { EventEmitter2 } from '@nestjs/event-emitter';
6-
import _ from 'lodash';
75
import { EngineStatus } from '@/domain/abstracts/engine.abstract';
86
import { ChatCompletionMessage } from '@/infrastructure/dtos/chat/chat-completion-message.dto';
97

@@ -98,17 +96,27 @@ export default class CoHereEngineExtension extends OAIEngineExtension {
9896
return convertedData;
9997
};
10098

101-
transformResponse = (data: any) => {
99+
transformResponse = (data: any, stream: boolean) => {
102100
const text =
103101
typeof data === 'object' ? data.text : (JSON.parse(data).text ?? '');
104-
return JSON.stringify({
105-
choices: [
106-
{
107-
delta: {
108-
content: text,
109-
},
110-
},
111-
],
112-
});
102+
return stream
103+
? JSON.stringify({
104+
choices: [
105+
{
106+
delta: {
107+
content: text,
108+
},
109+
},
110+
],
111+
})
112+
: {
113+
choices: [
114+
{
115+
message: {
116+
content: text,
117+
},
118+
},
119+
],
120+
};
113121
};
114122
}

cortex-js/src/extensions/extensions.module.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ import { EventEmitter2 } from '@nestjs/event-emitter';
99
import AnthropicEngineExtension from './anthropic.engine';
1010
import OpenRouterEngineExtension from './openrouter.engine';
1111
import CoHereEngineExtension from './cohere.engine';
12+
import MartianEngineExtension from './martian.engine';
13+
import NvidiaEngineExtension from './nvidia.engine';
1214

1315
const provider = {
1416
provide: 'EXTENSIONS_PROVIDER',
@@ -24,6 +26,8 @@ const provider = {
2426
new AnthropicEngineExtension(httpService, configUsecases, eventEmitter),
2527
new OpenRouterEngineExtension(httpService, configUsecases, eventEmitter),
2628
new CoHereEngineExtension(httpService, configUsecases, eventEmitter),
29+
new MartianEngineExtension(httpService, configUsecases, eventEmitter),
30+
new NvidiaEngineExtension(httpService, configUsecases, eventEmitter),
2731
],
2832
};
2933

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import { HttpService } from '@nestjs/axios';
2+
import { OAIEngineExtension } from '../domain/abstracts/oai.abstract';
3+
import { ConfigsUsecases } from '@/usecases/configs/configs.usecase';
4+
import { EventEmitter2 } from '@nestjs/event-emitter';
5+
import { EngineStatus } from '@/domain/abstracts/engine.abstract';
6+
7+
/**
8+
* A class that implements the InferenceExtension interface from the @janhq/core package.
9+
* The class provides methods for initializing and stopping a model, and for making inference requests.
10+
* It also subscribes to events emitted by the @janhq/core package and handles new message requests.
11+
*/
12+
export default class MartianEngineExtension extends OAIEngineExtension {
13+
apiUrl = 'https://withmartian.com/api/openai/v1/chat/completions';
14+
name = 'martian';
15+
productName = 'Martian Inference Engine';
16+
description = 'This extension enables Martian chat completion API calls';
17+
version = '0.0.1';
18+
apiKey?: string;
19+
20+
constructor(
21+
protected readonly httpService: HttpService,
22+
protected readonly configsUsecases: ConfigsUsecases,
23+
protected readonly eventEmmitter: EventEmitter2,
24+
) {
25+
super(httpService);
26+
27+
eventEmmitter.on('config.updated', async (data) => {
28+
if (data.engine === this.name) {
29+
this.apiKey = data.value;
30+
this.status =
31+
(this.apiKey?.length ?? 0) > 0
32+
? EngineStatus.READY
33+
: EngineStatus.MISSING_CONFIGURATION;
34+
}
35+
});
36+
}
37+
38+
async onLoad() {
39+
const configs = (await this.configsUsecases.getGroupConfigs(
40+
this.name,
41+
)) as unknown as { apiKey: string };
42+
43+
this.apiKey = configs?.apiKey;
44+
this.status =
45+
(this.apiKey?.length ?? 0) > 0
46+
? EngineStatus.READY
47+
: EngineStatus.MISSING_CONFIGURATION;
48+
}
49+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import { HttpService } from '@nestjs/axios';
2+
import { OAIEngineExtension } from '../domain/abstracts/oai.abstract';
3+
import { ConfigsUsecases } from '@/usecases/configs/configs.usecase';
4+
import { EventEmitter2 } from '@nestjs/event-emitter';
5+
import { EngineStatus } from '@/domain/abstracts/engine.abstract';
6+
7+
/**
8+
* A class that implements the InferenceExtension interface from the @janhq/core package.
9+
* The class provides methods for initializing and stopping a model, and for making inference requests.
10+
* It also subscribes to events emitted by the @janhq/core package and handles new message requests.
11+
*/
12+
export default class NvidiaEngineExtension extends OAIEngineExtension {
13+
apiUrl = 'https://integrate.api.nvidia.com/v1/chat/completions';
14+
name = 'nvidia';
15+
productName = 'Nvidia Inference Engine';
16+
description = 'This extension enables Nvidia chat completion API calls';
17+
version = '0.0.1';
18+
apiKey?: string;
19+
20+
constructor(
21+
protected readonly httpService: HttpService,
22+
protected readonly configsUsecases: ConfigsUsecases,
23+
protected readonly eventEmmitter: EventEmitter2,
24+
) {
25+
super(httpService);
26+
27+
eventEmmitter.on('config.updated', async (data) => {
28+
if (data.engine === this.name) {
29+
this.apiKey = data.value;
30+
this.status =
31+
(this.apiKey?.length ?? 0) > 0
32+
? EngineStatus.READY
33+
: EngineStatus.MISSING_CONFIGURATION;
34+
}
35+
});
36+
}
37+
38+
async onLoad() {
39+
const configs = (await this.configsUsecases.getGroupConfigs(
40+
this.name,
41+
)) as unknown as { apiKey: string };
42+
43+
this.apiKey = configs?.apiKey;
44+
this.status =
45+
(this.apiKey?.length ?? 0) > 0
46+
? EngineStatus.READY
47+
: EngineStatus.MISSING_CONFIGURATION;
48+
}
49+
}

cortex-js/src/extensions/openrouter.engine.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
1-
import stream from 'stream';
21
import { HttpService } from '@nestjs/axios';
32
import { OAIEngineExtension } from '../domain/abstracts/oai.abstract';
43
import { ConfigsUsecases } from '@/usecases/configs/configs.usecase';
54
import { EventEmitter2 } from '@nestjs/event-emitter';
6-
import _ from 'lodash';
75
import { EngineStatus } from '@/domain/abstracts/engine.abstract';
86

97
/**

cortex-js/src/infrastructure/commanders/types/engine.interface.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ export enum Engines {
1010
anthropic = 'anthropic',
1111
openrouter = 'openrouter',
1212
cohere = 'cohere',
13+
martian = 'martian',
14+
nvidia = 'nvidia',
1315
}
1416

1517
export const EngineNamesMap: {
@@ -27,4 +29,6 @@ export const RemoteEngines: Engines[] = [
2729
Engines.anthropic,
2830
Engines.openrouter,
2931
Engines.cohere,
32+
Engines.martian,
33+
Engines.nvidia,
3034
];

cortex-js/src/infrastructure/controllers/chat.controller.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ export class ChatController {
3333
@Body() createChatDto: CreateChatCompletionDto,
3434
@Res() res: Response,
3535
) {
36-
let { stream } = createChatDto;
36+
const { stream } = createChatDto;
3737
this.chatService
3838
.inference(createChatDto, extractCommonHeaders(headers))
3939
.then((response) => {
@@ -50,6 +50,9 @@ export class ChatController {
5050
let errorMessage;
5151
if (!stream) {
5252
const data = error.response?.data;
53+
if (!data) {
54+
return res.status(500).send(error.message || 'An error occurred');
55+
}
5356
return res
5457
.status(statusCode)
5558
.send(
@@ -60,8 +63,10 @@ export class ChatController {
6063
);
6164
}
6265
const streamResponse = error.response?.data;
66+
if (!streamResponse) {
67+
return res.status(500).send(error.message || 'An error occurred');
68+
}
6369
let data = '';
64-
6570
streamResponse.on('data', (chunk: any) => {
6671
data += chunk;
6772
});

cortex-js/src/infrastructure/services/resources-manager/resources-manager.service.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ export class ResourcesManagerService {
2121
return {
2222
mem: memInfo,
2323
cpu: {
24-
usage: cpuUsage.avgLoad,
24+
usage: Number(cpuUsage.currentLoad.toFixed(2)),
2525
},
2626
};
2727
}

0 commit comments

Comments
 (0)