Files
s01e03/cmd/app/main.go
2026-03-12 19:17:00 +01:00

136 lines
4.1 KiB
Go

package main
import (
"context"
"flag"
"fmt"
"io"
"log"
"os"
"path/filepath"
"time"
"github.com/gin-gonic/gin"
"github.com/paramah/ai_devs4/s01e03/internal/api"
"github.com/paramah/ai_devs4/s01e03/internal/config"
"github.com/paramah/ai_devs4/s01e03/internal/domain"
"github.com/paramah/ai_devs4/s01e03/internal/infrastructure/llm"
"github.com/paramah/ai_devs4/s01e03/internal/infrastructure/packages"
"github.com/paramah/ai_devs4/s01e03/internal/infrastructure/session"
"github.com/paramah/ai_devs4/s01e03/internal/infrastructure/verify"
"github.com/paramah/ai_devs4/s01e03/internal/infrastructure/weather"
"github.com/paramah/ai_devs4/s01e03/internal/usecase"
)
func main() {
configPath := flag.String("config", "config.json", "Path to configuration file")
flag.Parse()
// Setup logging to file
if err := setupLogging(); err != nil {
log.Fatalf("Failed to setup logging: %v", err)
}
// Load configuration
cfg, err := config.Load(*configPath)
if err != nil {
log.Fatalf("Failed to load configuration: %v", err)
}
if err := cfg.Validate(); err != nil {
log.Fatalf("Invalid configuration: %v", err)
}
// Log configuration
log.Printf("Log level: %s", cfg.LogLevel)
verbose := cfg.IsVerbose()
// Generate session ID
sessionID, err := verify.GenerateSessionID(16)
if err != nil {
log.Fatalf("Failed to generate session ID: %v", err)
}
log.Printf("Generated session ID: %s", sessionID)
// Register with the hub
verifyClient := verify.NewClient(cfg.Verify.URL, cfg.Verify.APIKey, verbose)
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
log.Printf("Registering with hub at %s", cfg.Verify.URL)
log.Printf("Tunnel URL: %s/shadow", cfg.Verify.TunnelURL)
if err := verifyClient.Register(ctx, cfg.Verify.TunnelURL+"/shadow", sessionID); err != nil {
log.Fatalf("Failed to register with hub: %v", err)
}
log.Printf("Successfully registered with hub")
// Initialize infrastructure
var llmProvider domain.LLMProvider
switch cfg.LLM.Provider {
case "openrouter":
llmProvider = llm.NewOpenRouterProvider(cfg.LLM.APIKey, cfg.LLM.Model, verbose)
log.Printf("Using OpenRouter with model: %s", cfg.LLM.Model)
case "lmstudio":
llmProvider = llm.NewLMStudioProvider(cfg.LLM.BaseURL, cfg.LLM.Model, verbose)
log.Printf("Using LM Studio at %s with model: %s", cfg.LLM.BaseURL, cfg.LLM.Model)
default:
log.Fatalf("Unknown LLM provider: %s", cfg.LLM.Provider)
}
sessionStorage := session.NewFileStorage(cfg.CacheDir)
packageClient := packages.NewAPIClient(cfg.PackageAPI.BaseURL, cfg.PackageAPI.APIKey, verbose)
weatherClient := weather.NewAPIClient(cfg.WeatherAPI.BaseURL, cfg.WeatherAPI.APIKey)
// Initialize use case
conversationUC := usecase.NewConversationUseCase(llmProvider, sessionStorage, packageClient, weatherClient)
// Initialize API handler
handler := api.NewHandler(conversationUC)
// Setup Gin router
router := gin.Default()
// Add verbose logging middleware
router.Use(api.VerboseLoggingMiddleware(verbose))
// Register routes
router.POST("/shadow", handler.Shadow)
// Start server
log.Printf("Starting server on port %s", cfg.Server.Port)
log.Printf("Using LLM model: %s", cfg.LLM.Model)
log.Printf("Cache directory: %s", cfg.CacheDir)
if err := router.Run(":" + cfg.Server.Port); err != nil {
log.Fatalf("Failed to start server: %v", err)
}
}
// setupLogging configures logging to both console and file
func setupLogging() error {
// Create logs directory if it doesn't exist
logsDir := "logs"
if err := os.MkdirAll(logsDir, 0755); err != nil {
return fmt.Errorf("creating logs directory: %w", err)
}
// Create log file with timestamp
timestamp := time.Now().Format("2006-01-02_15-04-05")
logFile := filepath.Join(logsDir, fmt.Sprintf("app_%s.log", timestamp))
file, err := os.OpenFile(logFile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
if err != nil {
return fmt.Errorf("opening log file: %w", err)
}
// Setup multi-writer to log to both console and file
multiWriter := io.MultiWriter(os.Stdout, file)
log.SetOutput(multiWriter)
log.SetFlags(log.Ldate | log.Ltime | log.Lmicroseconds | log.Lshortfile)
log.Printf("Logging to file: %s", logFile)
return nil
}