package handlers import ( "fmt" "net/http" "whatsapp-bot/db" "whatsapp-bot/services" "github.com/gin-gonic/gin" ) // Structs to parse incoming WhatsApp Webhook JSON type WebhookPayload struct { Entry []struct { Changes []struct { Value struct { Messages []struct { From string `json:"from"` Text struct { Body string `json:"body"` } `json:"text"` Type string `json:"type"` } `json:"messages"` } `json:"value"` } `json:"changes"` } `json:"entry"` } // VerifyWebhook (Keep this as is) func VerifyWebhook(c *gin.Context) { mode := c.Query("hub.mode") token := c.Query("hub.verify_token") challenge := c.Query("hub.challenge") if mode == "subscribe" && token == "YOUR_SECRET_TOKEN" { // CHANGE THIS to match your Meta setup c.String(http.StatusOK, challenge) } else { c.Status(http.StatusForbidden) } } func HandleMessage(c *gin.Context) { var payload WebhookPayload if err := c.BindJSON(&payload); err != nil { // WhatsApp sends other events (statuses) that might not match. Ignore errors. c.Status(200) return } // 1. Loop through messages (usually just one) for _, entry := range payload.Entry { for _, change := range entry.Changes { for _, msg := range change.Value.Messages { // We only handle text for now if msg.Type != "text" { continue } userPhone := msg.From userText := msg.Text.Body fmt.Printf("📩 Received from %s: %s\n", userPhone, userText) // 2. Identify the Chat Logic chatID := db.GetOrCreateChatByPhone(userPhone) // 3. Save User Message db.Conn.Exec("INSERT INTO messages (chat_id, role, content) VALUES (?, 'user', ?)", chatID, userText) // 4. Get AI Response // Fetch history rows, _ := db.Conn.Query("SELECT role, content FROM messages WHERE chat_id = ? ORDER BY created_at ASC", chatID) var history []services.Message for rows.Next() { var m services.Message rows.Scan(&m.Role, &m.Content) history = append(history, m) } rows.Close() // Call AI (We don't need the stream callback here, just the final string) aiResponse, _ := services.StreamAIResponse(history, func(chunk string) { // We can't stream to WhatsApp, so we do nothing here. }) // 5. Save & Send Response if aiResponse != "" { db.Conn.Exec("INSERT INTO messages (chat_id, role, content) VALUES (?, 'assistant', ?)", chatID, aiResponse) err := services.SendWhatsAppMessage(userPhone, aiResponse) if err != nil { fmt.Println("❌ Error sending to WhatsApp:", err) } } } } } c.Status(200) }