erp-core-backend-v2/src/modules/ai/controllers/ai.controller.ts
rckrdmrd ca07b4268d feat: Add complete module structure for ERP backend
- Add modules: ai, audit, billing-usage, biometrics, branches, dashboard,
  feature-flags, invoices, mcp, mobile, notifications, partners,
  payment-terminals, products, profiles, purchases, reports, sales,
  storage, warehouses, webhooks, whatsapp
- Add controllers, DTOs, entities, and services for each module
- Add shared services and utilities

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-16 00:40:54 -06:00

382 lines
12 KiB
TypeScript

import { Request, Response, NextFunction, Router } from 'express';
import { AIService, ConversationFilters } from '../services/ai.service';
export class AIController {
public router: Router;
constructor(private readonly aiService: AIService) {
this.router = Router();
this.initializeRoutes();
}
private initializeRoutes(): void {
// Models
this.router.get('/models', this.findAllModels.bind(this));
this.router.get('/models/:id', this.findModel.bind(this));
this.router.get('/models/code/:code', this.findModelByCode.bind(this));
this.router.get('/models/provider/:provider', this.findModelsByProvider.bind(this));
this.router.get('/models/type/:type', this.findModelsByType.bind(this));
// Prompts
this.router.get('/prompts', this.findAllPrompts.bind(this));
this.router.get('/prompts/:id', this.findPrompt.bind(this));
this.router.get('/prompts/code/:code', this.findPromptByCode.bind(this));
this.router.post('/prompts', this.createPrompt.bind(this));
this.router.patch('/prompts/:id', this.updatePrompt.bind(this));
// Conversations
this.router.get('/conversations', this.findConversations.bind(this));
this.router.get('/conversations/user/:userId', this.findUserConversations.bind(this));
this.router.get('/conversations/:id', this.findConversation.bind(this));
this.router.post('/conversations', this.createConversation.bind(this));
this.router.patch('/conversations/:id', this.updateConversation.bind(this));
this.router.post('/conversations/:id/archive', this.archiveConversation.bind(this));
// Messages
this.router.get('/conversations/:conversationId/messages', this.findMessages.bind(this));
this.router.post('/conversations/:conversationId/messages', this.addMessage.bind(this));
this.router.get('/conversations/:conversationId/tokens', this.getConversationTokenCount.bind(this));
// Usage & Quotas
this.router.post('/usage', this.logUsage.bind(this));
this.router.get('/usage/stats', this.getUsageStats.bind(this));
this.router.get('/quotas', this.getTenantQuota.bind(this));
this.router.patch('/quotas', this.updateTenantQuota.bind(this));
this.router.get('/quotas/check', this.checkQuotaAvailable.bind(this));
}
// ============================================
// MODELS
// ============================================
private async findAllModels(req: Request, res: Response, next: NextFunction): Promise<void> {
try {
const models = await this.aiService.findAllModels();
res.json({ data: models, total: models.length });
} catch (error) {
next(error);
}
}
private async findModel(req: Request, res: Response, next: NextFunction): Promise<void> {
try {
const { id } = req.params;
const model = await this.aiService.findModel(id);
if (!model) {
res.status(404).json({ error: 'Model not found' });
return;
}
res.json({ data: model });
} catch (error) {
next(error);
}
}
private async findModelByCode(req: Request, res: Response, next: NextFunction): Promise<void> {
try {
const { code } = req.params;
const model = await this.aiService.findModelByCode(code);
if (!model) {
res.status(404).json({ error: 'Model not found' });
return;
}
res.json({ data: model });
} catch (error) {
next(error);
}
}
private async findModelsByProvider(req: Request, res: Response, next: NextFunction): Promise<void> {
try {
const { provider } = req.params;
const models = await this.aiService.findModelsByProvider(provider);
res.json({ data: models, total: models.length });
} catch (error) {
next(error);
}
}
private async findModelsByType(req: Request, res: Response, next: NextFunction): Promise<void> {
try {
const { type } = req.params;
const models = await this.aiService.findModelsByType(type);
res.json({ data: models, total: models.length });
} catch (error) {
next(error);
}
}
// ============================================
// PROMPTS
// ============================================
private async findAllPrompts(req: Request, res: Response, next: NextFunction): Promise<void> {
try {
const tenantId = req.headers['x-tenant-id'] as string;
const prompts = await this.aiService.findAllPrompts(tenantId);
res.json({ data: prompts, total: prompts.length });
} catch (error) {
next(error);
}
}
private async findPrompt(req: Request, res: Response, next: NextFunction): Promise<void> {
try {
const { id } = req.params;
const prompt = await this.aiService.findPrompt(id);
if (!prompt) {
res.status(404).json({ error: 'Prompt not found' });
return;
}
res.json({ data: prompt });
} catch (error) {
next(error);
}
}
private async findPromptByCode(req: Request, res: Response, next: NextFunction): Promise<void> {
try {
const { code } = req.params;
const tenantId = req.headers['x-tenant-id'] as string;
const prompt = await this.aiService.findPromptByCode(code, tenantId);
if (!prompt) {
res.status(404).json({ error: 'Prompt not found' });
return;
}
// Increment usage count
await this.aiService.incrementPromptUsage(prompt.id);
res.json({ data: prompt });
} catch (error) {
next(error);
}
}
private async createPrompt(req: Request, res: Response, next: NextFunction): Promise<void> {
try {
const tenantId = req.headers['x-tenant-id'] as string;
const userId = req.headers['x-user-id'] as string;
const prompt = await this.aiService.createPrompt(tenantId, req.body, userId);
res.status(201).json({ data: prompt });
} catch (error) {
next(error);
}
}
private async updatePrompt(req: Request, res: Response, next: NextFunction): Promise<void> {
try {
const { id } = req.params;
const userId = req.headers['x-user-id'] as string;
const prompt = await this.aiService.updatePrompt(id, req.body, userId);
if (!prompt) {
res.status(404).json({ error: 'Prompt not found' });
return;
}
res.json({ data: prompt });
} catch (error) {
next(error);
}
}
// ============================================
// CONVERSATIONS
// ============================================
private async findConversations(req: Request, res: Response, next: NextFunction): Promise<void> {
try {
const tenantId = req.headers['x-tenant-id'] as string;
const filters: ConversationFilters = {
userId: req.query.userId as string,
modelId: req.query.modelId as string,
status: req.query.status as string,
};
if (req.query.startDate) filters.startDate = new Date(req.query.startDate as string);
if (req.query.endDate) filters.endDate = new Date(req.query.endDate as string);
const limit = parseInt(req.query.limit as string) || 50;
const conversations = await this.aiService.findConversations(tenantId, filters, limit);
res.json({ data: conversations, total: conversations.length });
} catch (error) {
next(error);
}
}
private async findUserConversations(req: Request, res: Response, next: NextFunction): Promise<void> {
try {
const tenantId = req.headers['x-tenant-id'] as string;
const { userId } = req.params;
const limit = parseInt(req.query.limit as string) || 20;
const conversations = await this.aiService.findUserConversations(tenantId, userId, limit);
res.json({ data: conversations, total: conversations.length });
} catch (error) {
next(error);
}
}
private async findConversation(req: Request, res: Response, next: NextFunction): Promise<void> {
try {
const { id } = req.params;
const conversation = await this.aiService.findConversation(id);
if (!conversation) {
res.status(404).json({ error: 'Conversation not found' });
return;
}
res.json({ data: conversation });
} catch (error) {
next(error);
}
}
private async createConversation(req: Request, res: Response, next: NextFunction): Promise<void> {
try {
const tenantId = req.headers['x-tenant-id'] as string;
const userId = req.headers['x-user-id'] as string;
const conversation = await this.aiService.createConversation(tenantId, userId, req.body);
res.status(201).json({ data: conversation });
} catch (error) {
next(error);
}
}
private async updateConversation(req: Request, res: Response, next: NextFunction): Promise<void> {
try {
const { id } = req.params;
const conversation = await this.aiService.updateConversation(id, req.body);
if (!conversation) {
res.status(404).json({ error: 'Conversation not found' });
return;
}
res.json({ data: conversation });
} catch (error) {
next(error);
}
}
private async archiveConversation(req: Request, res: Response, next: NextFunction): Promise<void> {
try {
const { id } = req.params;
const archived = await this.aiService.archiveConversation(id);
if (!archived) {
res.status(404).json({ error: 'Conversation not found' });
return;
}
res.json({ data: { success: true } });
} catch (error) {
next(error);
}
}
// ============================================
// MESSAGES
// ============================================
private async findMessages(req: Request, res: Response, next: NextFunction): Promise<void> {
try {
const { conversationId } = req.params;
const messages = await this.aiService.findMessages(conversationId);
res.json({ data: messages, total: messages.length });
} catch (error) {
next(error);
}
}
private async addMessage(req: Request, res: Response, next: NextFunction): Promise<void> {
try {
const { conversationId } = req.params;
const message = await this.aiService.addMessage(conversationId, req.body);
res.status(201).json({ data: message });
} catch (error) {
next(error);
}
}
private async getConversationTokenCount(req: Request, res: Response, next: NextFunction): Promise<void> {
try {
const { conversationId } = req.params;
const tokenCount = await this.aiService.getConversationTokenCount(conversationId);
res.json({ data: { tokenCount } });
} catch (error) {
next(error);
}
}
// ============================================
// USAGE & QUOTAS
// ============================================
private async logUsage(req: Request, res: Response, next: NextFunction): Promise<void> {
try {
const tenantId = req.headers['x-tenant-id'] as string;
const log = await this.aiService.logUsage(tenantId, req.body);
res.status(201).json({ data: log });
} catch (error) {
next(error);
}
}
private async getUsageStats(req: Request, res: Response, next: NextFunction): Promise<void> {
try {
const tenantId = req.headers['x-tenant-id'] as string;
const startDate = new Date(req.query.startDate as string || Date.now() - 30 * 24 * 60 * 60 * 1000);
const endDate = new Date(req.query.endDate as string || Date.now());
const stats = await this.aiService.getUsageStats(tenantId, startDate, endDate);
res.json({ data: stats });
} catch (error) {
next(error);
}
}
private async getTenantQuota(req: Request, res: Response, next: NextFunction): Promise<void> {
try {
const tenantId = req.headers['x-tenant-id'] as string;
const quota = await this.aiService.getTenantQuota(tenantId);
res.json({ data: quota });
} catch (error) {
next(error);
}
}
private async updateTenantQuota(req: Request, res: Response, next: NextFunction): Promise<void> {
try {
const tenantId = req.headers['x-tenant-id'] as string;
const quota = await this.aiService.updateTenantQuota(tenantId, req.body);
res.json({ data: quota });
} catch (error) {
next(error);
}
}
private async checkQuotaAvailable(req: Request, res: Response, next: NextFunction): Promise<void> {
try {
const tenantId = req.headers['x-tenant-id'] as string;
const result = await this.aiService.checkQuotaAvailable(tenantId);
res.json({ data: result });
} catch (error) {
next(error);
}
}
}