diff --git a/.env b/.env
index 2c9db12..91c18ed 100644
--- a/.env
+++ b/.env
@@ -1 +1,2 @@
+
OPENROUTER_API_KEY=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
\ No newline at end of file
diff --git a/bot.db b/bot.db
index 301db5e..e2b21a9 100644
Binary files a/bot.db and b/bot.db differ
diff --git a/db/db.go b/db/db.go
index 0fd9579..3e285b0 100644
--- a/db/db.go
+++ b/db/db.go
@@ -31,3 +31,11 @@ func Init() {
);`
Conn.Exec(schema)
}
+
+func SaveAppointment(phone string, date string) error {
+ _, err := Conn.Exec(
+ "INSERT INTO appointments (customer_phone, appointment_date, status) VALUES (?, ?, ?)",
+ phone, date, "confirmed",
+ )
+ return err
+}
diff --git a/go.mod b/go.mod
index 538f846..d20bad1 100644
--- a/go.mod
+++ b/go.mod
@@ -21,6 +21,7 @@ require (
github.com/goccy/go-json v0.10.5 // indirect
github.com/goccy/go-yaml v1.19.2 // indirect
github.com/google/uuid v1.6.0 // indirect
+ github.com/joho/godotenv v1.5.1 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/cpuid/v2 v2.3.0 // indirect
github.com/leodido/go-urn v1.4.0 // indirect
diff --git a/go.sum b/go.sum
index 1f727bc..39f5994 100644
--- a/go.sum
+++ b/go.sum
@@ -38,6 +38,8 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
+github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
+github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y=
diff --git a/handlers/dashboard.go b/handlers/dashboard.go
index 62df81c..d6a7b3f 100644
--- a/handlers/dashboard.go
+++ b/handlers/dashboard.go
@@ -49,6 +49,26 @@ func TestAIHandler(c *gin.Context) {
c.JSON(200, gin.H{"response": response})
}
+// Add this to handlers/dashboard.go
+func CreateAppointmentHandler(c *gin.Context) {
+ var body struct {
+ Phone string `json:"phone"`
+ Date string `json:"date"`
+ }
+ if err := c.BindJSON(&body); err != nil {
+ c.Status(400)
+ return
+ }
+
+ // Use the helper function instead of raw SQL here
+ if err := db.SaveAppointment(body.Phone, body.Date); err != nil {
+ c.JSON(500, gin.H{"error": err.Error()})
+ return
+ }
+
+ c.Status(200)
+}
+
// Manage/Delete Appointment
func DeleteAppointmentHandler(c *gin.Context) {
id := c.Param("id")
diff --git a/main.go b/main.go
index 1b7299a..fdb5051 100644
--- a/main.go
+++ b/main.go
@@ -1,13 +1,22 @@
package main
import (
+ "log"
"whatsapp-bot/db"
"whatsapp-bot/handlers"
"github.com/gin-gonic/gin"
+ "github.com/joho/godotenv"
)
func main() {
+
+ // 1. Load the .env file
+ err := godotenv.Load()
+ if err != nil {
+ log.Println("Warning: No .env file found. Hope you set your vars manually, seki.")
+ }
+
db.Init()
r := gin.Default()
@@ -21,6 +30,7 @@ func main() {
r.GET("/dashboard", handlers.ShowDashboard)
r.POST("/admin/test-ai", handlers.TestAIHandler)
r.DELETE("/admin/appointment/:id", handlers.DeleteAppointmentHandler)
+ r.POST("/admin/appointment", handlers.CreateAppointmentHandler)
// A little something for the root so you don't get a 404 again, seki
r.GET("/", func(c *gin.Context) {
diff --git a/services/openrouter.go b/services/openrouter.go
index 11dafe9..32b1651 100644
--- a/services/openrouter.go
+++ b/services/openrouter.go
@@ -3,18 +3,45 @@ package services
import (
"bytes"
"encoding/json"
+ "io"
"net/http"
"os"
)
+// The structs to map OpenRouter's response
+type OpenRouterResponse struct {
+ Choices []struct {
+ Message struct {
+ Content string `json:"content"`
+ } `json:"message"`
+ } `json:"choices"`
+}
+
func GetAIResponse(input string) (string, error) {
apiKey := os.Getenv("OPENROUTER_API_KEY")
payload := map[string]interface{}{
- "model": "stepfun/step-3.5-flash:free",
+ "model": "google/gemini-2.0-flash-001",
"messages": []map[string]string{
- {"role": "system", "content": "You are a business assistant in Chile. Book appointments or answer FAQs."},
+ {"role": "system", "content": "You are a Chilean business assistant. Be brief."},
{"role": "user", "content": input},
},
+ "tools": []map[string]interface{}{
+ {
+ "type": "function",
+ "function": map[string]interface{}{
+ "name": "create_appointment",
+ "description": "Schedules a new appointment in the database",
+ "parameters": map[string]interface{}{
+ "type": "object",
+ "properties": map[string]interface{}{
+ "customer_phone": map[string]string{"type": "string"},
+ "date": map[string]string{"type": "string", "description": "ISO format date and time"},
+ },
+ "required": []string{"customer_phone", "date"},
+ },
+ },
+ },
+ },
}
data, _ := json.Marshal(payload)
@@ -28,7 +55,21 @@ func GetAIResponse(input string) (string, error) {
}
defer resp.Body.Close()
- // Simplification: You need to parse the JSON response here, seki.
- // I assume you know how to decode a nested map. Big assumption, I know.
- return "AI Response Placeholder", nil
+ bodyBytes, _ := io.ReadAll(resp.Body)
+
+ // If it's not a 200, return the error body so you can see why it failed
+ if resp.StatusCode != http.StatusOK {
+ return "API Error: " + string(bodyBytes), nil
+ }
+
+ var result OpenRouterResponse
+ if err := json.Unmarshal(bodyBytes, &result); err != nil {
+ return "", err
+ }
+
+ if len(result.Choices) > 0 {
+ return result.Choices[0].Message.Content, nil
+ }
+
+ return "No response from AI.", nil
}
diff --git a/templates/dashboard.html b/templates/dashboard.html
index 9182468..14abb2e 100644
--- a/templates/dashboard.html
+++ b/templates/dashboard.html
@@ -1,69 +1,210 @@
{{ define "dashboard.html" }}
-
+
- SekiBot Admin
+
+
+ SekiBot Admin | Discord Edition
- SekiBot Business Analytics
-
-
-
Test OpenRouter AI
-
-
-
+
-
-
-
Manage Appointments
-
- | ID | Customer | Date | Status | Actions |
- {{range .Appointments}}
-
- | {{.ID}} |
- {{.CustomerPhone}} |
- {{.Date}} |
- {{.Status}} |
-
-
- |
-
- {{end}}
-
+
+
Welcome back, seki
+
+
+
+
Test OpenRouter AI
+
+
+
+
+
+
+
+
+
+
+
+
+
Scheduled Appointments
+
+
+
+ | ID |
+ Customer |
+ Date & Time |
+ Status |
+ Actions |
+
+
+
+ {{range .Appointments}}
+
+ | #{{.ID}} |
+ {{.CustomerPhone}} |
+ {{.Date}} |
+ {{.Status}} |
+
+
+ |
+
+ {{end}}
+
+
+