package handler import ( "net/http" "accounting-app/internal/service" "github.com/gin-gonic/gin" ) // AIHandler handles AI bookkeeping API requests type AIHandler struct { aiService *service.AIBookkeepingService } // NewAIHandler creates a new AIHandler func NewAIHandler(aiService *service.AIBookkeepingService) *AIHandler { return &AIHandler{ aiService: aiService, } } // ChatRequest represents a chat request type ChatRequest struct { SessionID string `json:"session_id"` Message string `json:"message" binding:"required"` } // TranscribeRequest represents a transcription request type TranscribeRequest struct { // Audio file is sent as multipart form data } // ConfirmRequest represents a transaction confirmation request type ConfirmRequest struct { SessionID string `json:"session_id" binding:"required"` } // RegisterRoutes registers AI routes func (h *AIHandler) RegisterRoutes(rg *gin.RouterGroup) { ai := rg.Group("/ai") { ai.POST("/chat", h.Chat) ai.POST("/transcribe", h.Transcribe) ai.POST("/confirm", h.Confirm) } } // Chat handles chat messages for AI bookkeeping // POST /api/v1/ai/chat // Requirements: 12.1, 12.5 func (h *AIHandler) Chat(c *gin.Context) { var req ChatRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{ "success": false, "error": "Invalid request: " + err.Error(), }) return } // Get user ID from context (default to 1 for now) userID := uint(1) if id, exists := c.Get("user_id"); exists { userID = id.(uint) } response, err := h.aiService.ProcessChat(c.Request.Context(), userID, req.SessionID, req.Message) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{ "success": false, "error": "Failed to process chat: " + err.Error(), }) return } c.JSON(http.StatusOK, gin.H{ "success": true, "data": response, }) } // Transcribe handles audio transcription // POST /api/v1/ai/transcribe // Requirements: 12.2, 12.6 func (h *AIHandler) Transcribe(c *gin.Context) { // Get audio file from form file, header, err := c.Request.FormFile("audio") if err != nil { c.JSON(http.StatusBadRequest, gin.H{ "success": false, "error": "No audio file provided: " + err.Error(), }) return } defer file.Close() // Transcribe audio result, err := h.aiService.TranscribeAudio(c.Request.Context(), file, header.Filename) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{ "success": false, "error": "Failed to transcribe audio: " + err.Error(), }) return } c.JSON(http.StatusOK, gin.H{ "success": true, "data": result, }) } // Confirm handles transaction confirmation // POST /api/v1/ai/confirm // Requirements: 12.3, 12.7, 12.8 func (h *AIHandler) Confirm(c *gin.Context) { var req ConfirmRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{ "success": false, "error": "Invalid request: " + err.Error(), }) return } // Get user ID from context (default to 1 for now) userID := uint(1) if id, exists := c.Get("user_id"); exists { userID = id.(uint) } transaction, err := h.aiService.ConfirmTransaction(c.Request.Context(), req.SessionID, userID) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{ "success": false, "error": "Failed to confirm transaction: " + err.Error(), }) return } c.JSON(http.StatusOK, gin.H{ "success": true, "data": transaction, "message": "Transaction created successfully", }) }