template-saas/apps/backend/dist/modules/ai/services/ai.service.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

149 lines
6.8 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 __param = (this && this.__param) || function (paramIndex, decorator) {
return function (target, key) { decorator(target, key, paramIndex); }
};
var AIService_1;
Object.defineProperty(exports, "__esModule", { value: true });
exports.AIService = void 0;
const common_1 = require("@nestjs/common");
const typeorm_1 = require("@nestjs/typeorm");
const typeorm_2 = require("typeorm");
const entities_1 = require("../entities");
const clients_1 = require("../clients");
let AIService = AIService_1 = class AIService {
constructor(configRepository, usageRepository, openRouterClient) {
this.configRepository = configRepository;
this.usageRepository = usageRepository;
this.openRouterClient = openRouterClient;
this.logger = new common_1.Logger(AIService_1.name);
}
async getConfig(tenantId) {
let config = await this.configRepository.findOne({
where: { tenant_id: tenantId },
});
if (!config) {
config = this.configRepository.create({
tenant_id: tenantId,
provider: entities_1.AIProvider.OPENROUTER,
default_model: 'anthropic/claude-3-haiku',
temperature: 0.7,
max_tokens: 2048,
is_enabled: true,
});
await this.configRepository.save(config);
}
return config;
}
async updateConfig(tenantId, dto) {
let config = await this.getConfig(tenantId);
Object.assign(config, dto);
config.updated_at = new Date();
return this.configRepository.save(config);
}
async chat(tenantId, userId, dto) {
const config = await this.getConfig(tenantId);
if (!config.is_enabled) {
throw new common_1.BadRequestException('AI features are disabled for this tenant');
}
if (!this.openRouterClient.isReady()) {
throw new common_1.BadRequestException('AI service is not configured');
}
const usage = this.usageRepository.create({
tenant_id: tenantId,
user_id: userId,
provider: config.provider,
model: dto.model || config.default_model,
status: entities_1.UsageStatus.PENDING,
started_at: new Date(),
});
await this.usageRepository.save(usage);
try {
let messages = [...dto.messages];
if (config.system_prompt && !messages.some((m) => m.role === 'system')) {
messages = [{ role: 'system', content: config.system_prompt }, ...messages];
}
const startTime = Date.now();
const response = await this.openRouterClient.chatCompletion({ ...dto, messages }, config.default_model, config.temperature, config.max_tokens);
const latencyMs = Date.now() - startTime;
const costs = this.openRouterClient.calculateCost(response.model, response.usage.prompt_tokens, response.usage.completion_tokens);
usage.status = entities_1.UsageStatus.COMPLETED;
usage.model = response.model;
usage.input_tokens = response.usage.prompt_tokens;
usage.output_tokens = response.usage.completion_tokens;
usage.cost_input = costs.input;
usage.cost_output = costs.output;
usage.latency_ms = latencyMs;
usage.completed_at = new Date();
usage.request_id = response.id;
usage.endpoint = 'chat';
await this.usageRepository.save(usage);
return response;
}
catch (error) {
usage.status = entities_1.UsageStatus.FAILED;
usage.error_message = error.message;
usage.completed_at = new Date();
await this.usageRepository.save(usage);
throw error;
}
}
async getModels() {
return this.openRouterClient.getModels();
}
async getCurrentMonthUsage(tenantId) {
const startOfMonth = new Date();
startOfMonth.setDate(1);
startOfMonth.setHours(0, 0, 0, 0);
const result = await this.usageRepository
.createQueryBuilder('usage')
.select('COUNT(*)', 'request_count')
.addSelect('COALESCE(SUM(usage.input_tokens), 0)', 'total_input_tokens')
.addSelect('COALESCE(SUM(usage.output_tokens), 0)', 'total_output_tokens')
.addSelect('COALESCE(SUM(usage.input_tokens + usage.output_tokens), 0)', 'total_tokens')
.addSelect('COALESCE(SUM(usage.cost_input + usage.cost_output), 0)', 'total_cost')
.addSelect('COALESCE(AVG(usage.latency_ms), 0)', 'avg_latency_ms')
.where('usage.tenant_id = :tenantId', { tenantId })
.andWhere('usage.status = :status', { status: entities_1.UsageStatus.COMPLETED })
.andWhere('usage.created_at >= :startOfMonth', { startOfMonth })
.getRawOne();
return {
request_count: parseInt(result.request_count, 10),
total_input_tokens: parseInt(result.total_input_tokens, 10),
total_output_tokens: parseInt(result.total_output_tokens, 10),
total_tokens: parseInt(result.total_tokens, 10),
total_cost: parseFloat(result.total_cost),
avg_latency_ms: parseFloat(result.avg_latency_ms),
};
}
async getUsageHistory(tenantId, page = 1, limit = 20) {
const [data, total] = await this.usageRepository.findAndCount({
where: { tenant_id: tenantId },
order: { created_at: 'DESC' },
skip: (page - 1) * limit,
take: limit,
});
return { data, total };
}
isServiceReady() {
return this.openRouterClient.isReady();
}
};
exports.AIService = AIService;
exports.AIService = AIService = AIService_1 = __decorate([
(0, common_1.Injectable)(),
__param(0, (0, typeorm_1.InjectRepository)(entities_1.AIConfig)),
__param(1, (0, typeorm_1.InjectRepository)(entities_1.AIUsage)),
__metadata("design:paramtypes", [typeorm_2.Repository,
typeorm_2.Repository,
clients_1.OpenRouterClient])
], AIService);
//# sourceMappingURL=ai.service.js.map