124 lines
3.6 KiB
Go
124 lines
3.6 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
"html/template"
|
|
"net/http"
|
|
"os"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
_ "github.com/jackc/pgx/v5/stdlib"
|
|
"github.com/pressly/goose/v3"
|
|
"github.com/sirupsen/logrus"
|
|
)
|
|
|
|
// TemplateWrapper adapts html/template.Template to TemplateExecutor
|
|
// (implements Execute(http.ResponseWriter, interface{}) error)
|
|
type TemplateWrapper struct {
|
|
Tmpl *template.Template
|
|
}
|
|
|
|
func (tw *TemplateWrapper) Execute(wr http.ResponseWriter, data interface{}) error {
|
|
return tw.Tmpl.Execute(wr, data)
|
|
}
|
|
|
|
func main() {
|
|
logrus.SetFormatter(&logrus.TextFormatter{FullTimestamp: true})
|
|
logrus.SetLevel(logrus.InfoLevel)
|
|
|
|
if err := loadConfig("config/config.yaml"); err != nil {
|
|
logrus.Fatalf("Failed to load config/config.yaml: %v", err)
|
|
}
|
|
logrus.Infof("Loaded config: %+v", appConfig)
|
|
visitDB := NewVisitDB()
|
|
|
|
if err := loadUITemplate("web_templates/ui.html"); err != nil {
|
|
logrus.Fatalf("Failed to load web_templates/ui.html: %v", err)
|
|
}
|
|
if err := loadDBEditTemplate("web_templates/ui_dbedit.html"); err != nil {
|
|
logrus.Fatalf("Failed to load web_templates/ui_dbedit.html: %v", err)
|
|
}
|
|
if err := loadAdminChatsTemplate("web_templates/ui_admin_chats.html"); err != nil {
|
|
logrus.Fatalf("Failed to load web_templates/ui_admin_chats.html: %v", err)
|
|
}
|
|
uiAdminLoginTmpl := &TemplateWrapper{Tmpl: template.Must(template.ParseFiles("web_templates/ui_admin_login.html"))}
|
|
|
|
// Initialize PostgreSQL repository first
|
|
dsn := buildDefaultDSN()
|
|
logrus.Info("Connecting to PostgreSQL with DSN: ", dsn)
|
|
|
|
// Run goose migrations using database/sql with pgx driver before initializing repository
|
|
if dsn != "" {
|
|
sqlDB, err := sql.Open("pgx", dsn)
|
|
if err != nil {
|
|
logrus.Fatalf("Failed to open database for migration: %v", err)
|
|
}
|
|
defer sqlDB.Close()
|
|
goose.SetDialect("postgres")
|
|
if err := goose.Up(sqlDB, "migrations"); err != nil {
|
|
logrus.Fatalf("Goose migration failed: %v", err)
|
|
}
|
|
logrus.Info("Database migrations applied successfully (goose)")
|
|
}
|
|
|
|
repo, err := NewPGChatRepository(context.Background(), dsn)
|
|
if err != nil {
|
|
logrus.WithError(err).Warn("PostgreSQL repository disabled (connection failed)")
|
|
} else if repo == nil {
|
|
logrus.Info("PostgreSQL repository not configured (no DSN)")
|
|
}
|
|
// defer repo.Close() // optionally enable
|
|
|
|
// Initialize LLM client
|
|
llmClient := NewLLMClient(
|
|
os.Getenv("OPENAI_API_KEY"),
|
|
os.Getenv("OPENAI_BASE_URL"),
|
|
os.Getenv("OPENAI_MODEL"),
|
|
repo,
|
|
)
|
|
var llm LLMClientAPI = llmClient
|
|
|
|
// Wrap templates for controller
|
|
uiTmpl := &TemplateWrapper{Tmpl: uiTemplate}
|
|
uiDBEditTmpl := &TemplateWrapper{Tmpl: uiDBEditTemplate}
|
|
uiAdminChatsTmpl := &TemplateWrapper{Tmpl: uiAdminChatsTemplate}
|
|
|
|
// Create controller
|
|
ctrl := NewController(
|
|
repo,
|
|
llm,
|
|
&visitDB,
|
|
uiTmpl,
|
|
uiDBEditTmpl,
|
|
uiAdminChatsTmpl,
|
|
uiAdminLoginTmpl,
|
|
)
|
|
|
|
r := gin.Default()
|
|
|
|
// Admin login/logout routes (no auth)
|
|
r.GET("/admin/login", ctrl.AdminLoginPage)
|
|
r.POST("/admin/login", ctrl.AdminLogin)
|
|
r.GET("/admin/logout", ctrl.AdminLogout)
|
|
|
|
// All /admin* routes require authentication except login/logout
|
|
admin := r.Group("/admin", AdminAuthMiddleware())
|
|
admin.GET("/", ctrl.AdminUI)
|
|
admin.GET("/chats", ctrl.ListChatInteractions)
|
|
admin.GET("/chats/events", ctrl.ListLLMEvents)
|
|
admin.GET("/chats/ui", ctrl.AdminChatsUI)
|
|
admin.POST("/chats/snapshot", ctrl.SaveKnowledgeModel)
|
|
admin.GET("/chats/snapshots", ctrl.ListKnowledgeModels)
|
|
admin.GET("/chats/snapshot/:id", ctrl.GetKnowledgeModel)
|
|
|
|
r.GET("/", ctrl.RootUI)
|
|
r.GET("/health", ctrl.Health)
|
|
r.POST("/chat", ctrl.HandleChat)
|
|
r.GET("/db.yaml", ctrl.DownloadDB)
|
|
|
|
r.POST("/admin/create-initial-admin", ctrl.CreateInitialAdmin)
|
|
|
|
r.Run(":8080")
|
|
}
|