template-saas/apps/backend/dist/modules/ai/clients/openrouter.client.js
rckrdmrd 50a821a415
Some checks failed
CI / Backend CI (push) Has been cancelled
CI / Frontend CI (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / CI Summary (push) Has been cancelled
[SIMCO-V38] feat: Actualizar a SIMCO v3.8.0
- HERENCIA-SIMCO.md actualizado con directivas v3.7 y v3.8
- Actualizaciones de configuracion

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-10 08:53:08 -06:00

181 lines
7.6 KiB
JavaScript

"use strict";
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 OpenRouterClient_1;
Object.defineProperty(exports, "__esModule", { value: true });
exports.OpenRouterClient = void 0;
const common_1 = require("@nestjs/common");
const config_1 = require("@nestjs/config");
let OpenRouterClient = OpenRouterClient_1 = class OpenRouterClient {
constructor(configService) {
this.configService = configService;
this.logger = new common_1.Logger(OpenRouterClient_1.name);
this.baseUrl = 'https://openrouter.ai/api/v1';
this.isConfigured = false;
this.timeout = this.configService.get('AI_TIMEOUT_MS', 30000);
}
onModuleInit() {
this.apiKey = this.configService.get('OPENROUTER_API_KEY', '');
if (!this.apiKey) {
this.logger.warn('OpenRouter API key not configured. AI features will be disabled.');
return;
}
this.isConfigured = true;
this.logger.log('OpenRouter client initialized');
}
isReady() {
return this.isConfigured;
}
ensureConfigured() {
if (!this.isConfigured) {
throw new common_1.BadRequestException('AI service is not configured. Please set OPENROUTER_API_KEY.');
}
}
async chatCompletion(dto, defaultModel, defaultTemperature, defaultMaxTokens) {
this.ensureConfigured();
const requestBody = {
model: dto.model || defaultModel,
messages: dto.messages,
temperature: dto.temperature ?? defaultTemperature,
max_tokens: dto.max_tokens ?? defaultMaxTokens,
top_p: dto.top_p ?? 1.0,
stream: false,
};
const startTime = Date.now();
try {
const response = await fetch(`${this.baseUrl}/chat/completions`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${this.apiKey}`,
'HTTP-Referer': this.configService.get('APP_URL', 'http://localhost:3001'),
'X-Title': 'Template SaaS',
},
body: JSON.stringify(requestBody),
signal: AbortSignal.timeout(this.timeout),
});
if (!response.ok) {
const errorBody = await response.text();
this.logger.error(`OpenRouter API error: ${response.status} - ${errorBody}`);
throw new common_1.BadRequestException(`AI request failed: ${response.statusText}`);
}
const data = await response.json();
const latencyMs = Date.now() - startTime;
this.logger.debug(`Chat completion completed in ${latencyMs}ms, tokens: ${data.usage?.total_tokens}`);
return {
id: data.id,
model: data.model,
choices: data.choices.map((c) => ({
index: c.index,
message: {
role: c.message.role,
content: c.message.content,
},
finish_reason: c.finish_reason,
})),
usage: {
prompt_tokens: data.usage?.prompt_tokens || 0,
completion_tokens: data.usage?.completion_tokens || 0,
total_tokens: data.usage?.total_tokens || 0,
},
created: data.created,
};
}
catch (error) {
if (error.name === 'AbortError') {
throw new common_1.BadRequestException('AI request timed out');
}
throw error;
}
}
async getModels() {
this.ensureConfigured();
try {
const response = await fetch(`${this.baseUrl}/models`, {
headers: {
Authorization: `Bearer ${this.apiKey}`,
},
signal: AbortSignal.timeout(10000),
});
if (!response.ok) {
throw new common_1.BadRequestException('Failed to fetch models');
}
const data = await response.json();
const models = data.data || [];
const popularModels = [
'anthropic/claude-3-haiku',
'anthropic/claude-3-sonnet',
'anthropic/claude-3-opus',
'openai/gpt-4-turbo',
'openai/gpt-4',
'openai/gpt-3.5-turbo',
'google/gemini-pro',
'meta-llama/llama-3-70b-instruct',
];
return models
.filter((m) => popularModels.some((p) => m.id.includes(p.split('/')[1])))
.slice(0, 20)
.map((m) => ({
id: m.id,
name: m.name,
provider: m.id.split('/')[0],
context_length: m.context_length,
pricing: {
prompt: parseFloat(m.pricing.prompt) * 1000000,
completion: parseFloat(m.pricing.completion) * 1000000,
},
}));
}
catch (error) {
this.logger.error('Failed to fetch models:', error);
return [
{
id: 'anthropic/claude-3-haiku',
name: 'Claude 3 Haiku',
provider: 'anthropic',
context_length: 200000,
pricing: { prompt: 0.25, completion: 1.25 },
},
{
id: 'openai/gpt-3.5-turbo',
name: 'GPT-3.5 Turbo',
provider: 'openai',
context_length: 16385,
pricing: { prompt: 0.5, completion: 1.5 },
},
];
}
}
calculateCost(model, inputTokens, outputTokens) {
const pricing = {
'anthropic/claude-3-haiku': { input: 0.25, output: 1.25 },
'anthropic/claude-3-sonnet': { input: 3.0, output: 15.0 },
'anthropic/claude-3-opus': { input: 15.0, output: 75.0 },
'openai/gpt-4-turbo': { input: 10.0, output: 30.0 },
'openai/gpt-4': { input: 30.0, output: 60.0 },
'openai/gpt-3.5-turbo': { input: 0.5, output: 1.5 },
default: { input: 1.0, output: 2.0 },
};
const modelPricing = pricing[model] || pricing.default;
const inputCost = (inputTokens / 1_000_000) * modelPricing.input;
const outputCost = (outputTokens / 1_000_000) * modelPricing.output;
return {
input: inputCost,
output: outputCost,
total: inputCost + outputCost,
};
}
};
exports.OpenRouterClient = OpenRouterClient;
exports.OpenRouterClient = OpenRouterClient = OpenRouterClient_1 = __decorate([
(0, common_1.Injectable)(),
__metadata("design:paramtypes", [config_1.ConfigService])
], OpenRouterClient);
//# sourceMappingURL=openrouter.client.js.map