modified: .env

new file:   __debug_bin.exe
	modified:   bot.db
	modified:   db/db.go
	modified:   go.mod
	new file:   handlers/auth.go
	modified:   handlers/dashboard.go
	new file:   handlers/saas.go
	modified:   handlers/webhook.go
	modified:   main.go
	new file:   saas_bot.db
	modified:   services/openrouter.go
	new file:   services/types.go
	modified:   services/whatsapp.go
	new file:   static/style.css
	modified:   templates/dashboard.html
	new file:   templates/landing.html
	new file:   templates/login.html
	new file:   templates/register.html
	deleted:    types/types.go
This commit is contained in:
2026-03-02 00:38:05 -03:00
parent 9ff021879f
commit e256fcb073
20 changed files with 627 additions and 659 deletions

View File

@@ -3,36 +3,21 @@ package handlers
import (
"fmt"
"net/http"
"time"
"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"`
}
// NOTA: Borramos la definición local de WebhookPayload porque ahora la importamos de services
// 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
if mode == "subscribe" && token == "YOUR_SECRET_TOKEN" {
c.String(http.StatusOK, challenge)
} else {
c.Status(http.StatusForbidden)
@@ -40,61 +25,49 @@ func VerifyWebhook(c *gin.Context) {
}
func HandleMessage(c *gin.Context) {
var payload WebhookPayload
// Ahora usamos services.WebhookPayload sin problemas
var payload services.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 {
// 1. IDENTIFICAR AL USUARIO
phoneID := change.Value.Metadata.PhoneNumberID
// We only handle text for now
botConfig, err := db.GetBotByPhoneID(phoneID)
if err != nil {
fmt.Printf("❌ Unknown Phone ID: %s. Make sure this ID is in bot_configs table.\n", phoneID)
continue
}
for _, msg := range change.Value.Messages {
if msg.Type != "text" {
continue
}
userPhone := msg.From
userText := msg.Text.Body
fmt.Printf("📩 Msg for User %d (%s): %s\n", botConfig.UserID, botConfig.PhoneID, msg.Text.Body)
fmt.Printf("📩 Received from %s: %s\n", userPhone, userText)
// 2. CONSTRUIR PROMPT
currentTime := time.Now().Format("Monday, 2006-01-02 15:04")
finalPrompt := fmt.Sprintf(
"%s\n\nCONTEXT:\nCurrent Time: %s\nAvailability Rules: %s\n\nINSTRUCTIONS:\nIf booking, ask for Name, Date, Time. Use 'create_appointment' tool only when confirmed.",
botConfig.SystemPrompt,
currentTime,
botConfig.Availability,
)
// 2. Identify the Chat Logic
chatID := db.GetOrCreateChatByPhone(userPhone)
// 3. LLAMAR A LA IA
aiResp, _ := services.StreamAIResponse(botConfig.UserID, msg.Text.Body, finalPrompt, nil)
// 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)
}
// 4. RESPONDER
if aiResp != "" {
services.SendWhatsAppMessage(botConfig.Token, botConfig.PhoneID, msg.From, aiResp)
}
}
}
}
c.Status(200)
}