Refresh AI model setup (#13171)
Instead of initializing model at start time we do it at run time to be able to swap model provider more easily. Also introduce a third driver for openai-compatible providers, which among other allows for local models with Ollama
This commit is contained in:
+7
-7
@@ -3,19 +3,13 @@ import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { NodeEnvironment } from 'src/engine/core-modules/twenty-config/interfaces/node-environment.interface';
|
||||
import { SupportDriver } from 'src/engine/core-modules/twenty-config/interfaces/support.interface';
|
||||
|
||||
import { AiModelRegistryService } from 'src/engine/core-modules/ai/services/ai-model-registry.service';
|
||||
import { CaptchaDriverType } from 'src/engine/core-modules/captcha/interfaces';
|
||||
import { ClientConfigService } from 'src/engine/core-modules/client-config/services/client-config.service';
|
||||
import { DomainManagerService } from 'src/engine/core-modules/domain-manager/services/domain-manager.service';
|
||||
import { PUBLIC_FEATURE_FLAGS } from 'src/engine/core-modules/feature-flag/constants/public-feature-flag.const';
|
||||
import { TwentyConfigService } from 'src/engine/core-modules/twenty-config/twenty-config.service';
|
||||
|
||||
jest.mock(
|
||||
'src/engine/core-modules/ai/utils/get-ai-models-with-auto.util',
|
||||
() => ({
|
||||
getAIModelsWithAuto: jest.fn(() => []),
|
||||
}),
|
||||
);
|
||||
|
||||
describe('ClientConfigService', () => {
|
||||
let service: ClientConfigService;
|
||||
let twentyConfigService: TwentyConfigService;
|
||||
@@ -37,6 +31,12 @@ describe('ClientConfigService', () => {
|
||||
getFrontUrl: jest.fn(),
|
||||
},
|
||||
},
|
||||
{
|
||||
provide: AiModelRegistryService,
|
||||
useValue: {
|
||||
getAvailableModels: jest.fn().mockReturnValue([]),
|
||||
},
|
||||
},
|
||||
],
|
||||
}).compile();
|
||||
|
||||
|
||||
+37
-26
@@ -3,9 +3,12 @@ import { Injectable } from '@nestjs/common';
|
||||
import { NodeEnvironment } from 'src/engine/core-modules/twenty-config/interfaces/node-environment.interface';
|
||||
import { SupportDriver } from 'src/engine/core-modules/twenty-config/interfaces/support.interface';
|
||||
|
||||
import { ModelProvider } from 'src/engine/core-modules/ai/constants/ai-models.const';
|
||||
import {
|
||||
AI_MODELS,
|
||||
ModelProvider,
|
||||
} from 'src/engine/core-modules/ai/constants/ai-models.const';
|
||||
import { AiModelRegistryService } from 'src/engine/core-modules/ai/services/ai-model-registry.service';
|
||||
import { convertCentsToBillingCredits } from 'src/engine/core-modules/ai/utils/convert-cents-to-billing-credits.util';
|
||||
import { getAIModelsWithAuto } from 'src/engine/core-modules/ai/utils/get-ai-models-with-auto.util';
|
||||
import {
|
||||
ClientAIModelConfig,
|
||||
ClientConfig,
|
||||
@@ -19,41 +22,49 @@ export class ClientConfigService {
|
||||
constructor(
|
||||
private twentyConfigService: TwentyConfigService,
|
||||
private domainManagerService: DomainManagerService,
|
||||
private aiModelRegistryService: AiModelRegistryService,
|
||||
) {}
|
||||
|
||||
async getClientConfig(): Promise<ClientConfig> {
|
||||
const captchaProvider = this.twentyConfigService.get('CAPTCHA_DRIVER');
|
||||
const supportDriver = this.twentyConfigService.get('SUPPORT_DRIVER');
|
||||
const openaiApiKey = this.twentyConfigService.get('OPENAI_API_KEY');
|
||||
const anthropicApiKey = this.twentyConfigService.get('ANTHROPIC_API_KEY');
|
||||
|
||||
const aiModels = getAIModelsWithAuto().reduce<ClientAIModelConfig[]>(
|
||||
(acc, model) => {
|
||||
const isAvailable =
|
||||
(model.provider === ModelProvider.OPENAI && openaiApiKey) ||
|
||||
(model.provider === ModelProvider.ANTHROPIC && anthropicApiKey);
|
||||
const availableModels = this.aiModelRegistryService.getAvailableModels();
|
||||
|
||||
if (!isAvailable) {
|
||||
return acc;
|
||||
}
|
||||
const aiModels: ClientAIModelConfig[] = availableModels.map(
|
||||
(registeredModel) => {
|
||||
const builtInModel = AI_MODELS.find(
|
||||
(m) => m.modelId === registeredModel.modelId,
|
||||
);
|
||||
|
||||
acc.push({
|
||||
modelId: model.modelId,
|
||||
label: model.label,
|
||||
provider: model.provider,
|
||||
inputCostPer1kTokensInCredits: convertCentsToBillingCredits(
|
||||
model.inputCostPer1kTokensInCents,
|
||||
),
|
||||
outputCostPer1kTokensInCredits: convertCentsToBillingCredits(
|
||||
model.outputCostPer1kTokensInCents,
|
||||
),
|
||||
});
|
||||
|
||||
return acc;
|
||||
return {
|
||||
modelId: registeredModel.modelId,
|
||||
label: builtInModel?.label || registeredModel.modelId,
|
||||
provider: registeredModel.provider,
|
||||
inputCostPer1kTokensInCredits: builtInModel
|
||||
? convertCentsToBillingCredits(
|
||||
builtInModel.inputCostPer1kTokensInCents,
|
||||
)
|
||||
: 0,
|
||||
outputCostPer1kTokensInCredits: builtInModel
|
||||
? convertCentsToBillingCredits(
|
||||
builtInModel.outputCostPer1kTokensInCents,
|
||||
)
|
||||
: 0,
|
||||
};
|
||||
},
|
||||
[],
|
||||
);
|
||||
|
||||
if (aiModels.length > 0) {
|
||||
aiModels.unshift({
|
||||
modelId: 'auto',
|
||||
label: 'Auto',
|
||||
provider: ModelProvider.NONE,
|
||||
inputCostPer1kTokensInCredits: 0,
|
||||
outputCostPer1kTokensInCredits: 0,
|
||||
});
|
||||
}
|
||||
|
||||
const clientConfig: ClientConfig = {
|
||||
billing: {
|
||||
isBillingEnabled: this.twentyConfigService.get('IS_BILLING_ENABLED'),
|
||||
|
||||
Reference in New Issue
Block a user