bb-inspired
Version:
Core library for BB-inspired NestJS backend
242 lines • 10.2 kB
JavaScript
;
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var OpenAIService_1;
Object.defineProperty(exports, "__esModule", { value: true });
exports.OpenAIService = void 0;
const common_1 = require("@nestjs/common");
const openai_1 = require("openai");
let OpenAIService = OpenAIService_1 = class OpenAIService {
constructor(config) {
this.logger = new common_1.Logger(OpenAIService_1.name);
if (!config.apiKey) {
throw new Error('OpenAI API key is required');
}
this.client = new openai_1.OpenAI({
apiKey: config.apiKey,
organization: config.organization,
baseURL: config.baseUrl,
timeout: config.timeout || 30000,
maxRetries: config.maxRetries || 3,
});
this.defaultModel = config.defaultModel || 'gpt-4';
this.logger.log(`OpenAI service initialized with default model: ${this.defaultModel}`);
}
async listModels() {
try {
const response = await this.client.models.list();
return response.data.map(model => ({
id: model.id,
created: model.created,
ownedBy: model.owned_by,
maxContextLength: this.getModelContextLength(model.id),
supportsFunctionCalling: this.supportsFunctionCalling(model.id),
}));
}
catch (error) {
this.logger.error(`Error listing models: ${error.message}`, error.stack);
throw new Error(`Failed to list models: ${error.message}`);
}
}
async getModel(modelId) {
try {
const model = await this.client.models.retrieve(modelId);
return {
id: model.id,
created: model.created,
ownedBy: model.owned_by,
maxContextLength: this.getModelContextLength(model.id),
supportsFunctionCalling: this.supportsFunctionCalling(model.id),
};
}
catch (error) {
this.logger.error(`Error retrieving model ${modelId}: ${error.message}`, error.stack);
throw new Error(`Failed to retrieve model ${modelId}: ${error.message}`);
}
}
async createCompletion(prompt, options = {}) {
var _a, _b, _c, _d, _e;
try {
const model = options.model || this.defaultModel;
const messages = [
{
role: 'user',
content: prompt
}
];
const response = await this.client.chat.completions.create({
model,
messages,
max_tokens: options.maxTokens,
temperature: options.temperature,
top_p: options.topP,
presence_penalty: options.presencePenalty,
frequency_penalty: options.frequencyPenalty,
stop: options.stop,
stream: false,
});
const result = {
text: ((_b = (_a = response.choices[0]) === null || _a === void 0 ? void 0 : _a.message) === null || _b === void 0 ? void 0 : _b.content) || '',
usage: {
promptTokens: ((_c = response.usage) === null || _c === void 0 ? void 0 : _c.prompt_tokens) || 0,
completionTokens: ((_d = response.usage) === null || _d === void 0 ? void 0 : _d.completion_tokens) || 0,
totalTokens: ((_e = response.usage) === null || _e === void 0 ? void 0 : _e.total_tokens) || 0,
},
};
return result;
}
catch (error) {
this.logger.error(`Error creating completion: ${error.message}`, error.stack);
throw new Error(`Failed to create completion: ${error.message}`);
}
}
async createChatCompletion(options) {
var _a, _b, _c, _d, _e, _f, _g;
try {
const model = options.model || this.defaultModel;
const messages = options.messages.map(msg => {
if (msg.role === 'function') {
return {
role: msg.role,
content: msg.content,
name: msg.name || 'function'
};
}
return {
role: msg.role,
content: msg.content,
...(msg.name ? { name: msg.name } : {})
};
});
let functions;
if (options.functions && options.functions.length > 0) {
functions = options.functions.map(fn => ({
name: fn.name,
description: fn.description,
parameters: fn.parameters
}));
}
let function_call;
if (options.functionCall) {
if (typeof options.functionCall === 'string') {
function_call = options.functionCall;
}
else {
function_call = { name: options.functionCall.name };
}
}
if (options.stream) {
throw new Error('Streaming is not supported in createChatCompletion');
}
const response = await this.client.chat.completions.create({
model,
messages,
functions,
function_call,
max_tokens: options.maxTokens,
temperature: options.temperature,
top_p: options.topP,
presence_penalty: options.presencePenalty,
frequency_penalty: options.frequencyPenalty,
stop: options.stop,
stream: false,
});
const message = {
role: 'assistant',
content: ((_b = (_a = response.choices[0]) === null || _a === void 0 ? void 0 : _a.message) === null || _b === void 0 ? void 0 : _b.content) || '',
};
if ((_d = (_c = response.choices[0]) === null || _c === void 0 ? void 0 : _c.message) === null || _d === void 0 ? void 0 : _d.function_call) {
message.functionCall = {
name: response.choices[0].message.function_call.name,
arguments: response.choices[0].message.function_call.arguments,
};
}
const result = {
message,
usage: {
promptTokens: ((_e = response.usage) === null || _e === void 0 ? void 0 : _e.prompt_tokens) || 0,
completionTokens: ((_f = response.usage) === null || _f === void 0 ? void 0 : _f.completion_tokens) || 0,
totalTokens: ((_g = response.usage) === null || _g === void 0 ? void 0 : _g.total_tokens) || 0,
},
};
return result;
}
catch (error) {
this.logger.error(`Error creating chat completion: ${error.message}`, error.stack);
throw new Error(`Failed to create chat completion: ${error.message}`);
}
}
async createEmbedding(input, options = {}) {
try {
const inputArray = Array.isArray(input) ? input : [input];
const model = options.model || 'text-embedding-ada-002';
const embeddings = await this.client.embeddings.create({
model,
input: inputArray,
user: options.user,
});
const result = {
embeddings: embeddings.data.map(item => item.embedding),
usage: {
promptTokens: embeddings.usage.prompt_tokens,
totalTokens: embeddings.usage.total_tokens,
},
};
return result;
}
catch (error) {
this.logger.error(`Error creating embeddings: ${error.message}`, error.stack);
throw new Error(`Failed to create embeddings: ${error.message}`);
}
}
estimateTokenCount(text) {
return Math.ceil(text.length / 4);
}
getModelContextLength(modelId) {
const modelContextLengths = {
'gpt-4': 8192,
'gpt-4-32k': 32768,
'gpt-4-turbo': 128000,
'gpt-3.5-turbo': 4096,
'gpt-3.5-turbo-16k': 16384,
'text-embedding-ada-002': 8191,
};
if (modelContextLengths[modelId]) {
return modelContextLengths[modelId];
}
for (const [model, length] of Object.entries(modelContextLengths)) {
if (modelId.startsWith(model)) {
return length;
}
}
return undefined;
}
supportsFunctionCalling(modelId) {
const functionCallingModels = [
'gpt-4',
'gpt-4-32k',
'gpt-4-turbo',
'gpt-3.5-turbo',
'gpt-3.5-turbo-16k',
];
for (const model of functionCallingModels) {
if (modelId.startsWith(model)) {
return true;
}
}
return false;
}
};
exports.OpenAIService = OpenAIService;
exports.OpenAIService = OpenAIService = OpenAIService_1 = __decorate([
(0, common_1.Injectable)(),
__metadata("design:paramtypes", [Object])
], OpenAIService);
//# sourceMappingURL=openai.service.js.map