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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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); } } }