// Cyrene v2 — LLM-powered AI companion platform. // Single binary entry point for all services. package main import ( "context" "fmt" "log" "net/http" "os" "os/signal" "syscall" "git.yeij.top/AskaEth/Cyrene_v2/internal/config" "git.yeij.top/AskaEth/Cyrene_v2/internal/db" "git.yeij.top/AskaEth/Cyrene_v2/internal/nats" "git.yeij.top/AskaEth/Cyrene_v2/internal/platform" "git.yeij.top/AskaEth/Cyrene_v2/services/gateway/api" "git.yeij.top/AskaEth/Cyrene_v2/services/gateway/ws" "git.yeij.top/AskaEth/Cyrene_v2/services/memory" "git.yeij.top/AskaEth/Cyrene_v2/services/voice" ) func main() { log.SetFlags(log.LstdFlags | log.Lshortfile) log.Println("🧠 Cyrene v2 启动中...") // 1. Platform detection plat := platform.Detect() log.Printf("[platform] %s", plat.Summary()) // 2. Load config cfg, err := config.Load() if err != nil { log.Printf("[config] .env load failed (using defaults): %v", err) } cfg.ValidateOrFatal() cfg.LogSanitized() // 3. Ensure directories if err := plat.EnsureDirs(); err != nil { log.Printf("[platform] directory creation warning: %v", err) } // 4. Connect database database, err := db.Connect(db.Config{ Host: cfg.PostgresHost, Port: cfg.PostgresPort, User: cfg.PostgresUser, Password: cfg.PostgresPassword, DBName: cfg.PostgresDB, SSLMode: cfg.PostgresSSLMode, MaxOpenConns: 25, MaxIdleConns: 5, }) if err != nil { log.Printf("[db] warning: database connection failed (running without persistence): %v", err) } else { defer database.Close() // Run migrations if err := db.RunMigration(context.Background(), database, "memories", db.SplitSQL(memory.CreateTableSQL())); err != nil { log.Printf("[db] migration warning: %v", err) } } // 5. Initialize NATS (in-process for dev) natsConn := nats.NewInProcess() log.Printf("[nats] in-process connection ready") // 6. Initialize services voiceSvc := voice.New(voice.Config{ STTProvider: cfg.ASRProvider, TTSProviders: []string{cfg.TTSProvider}, DashScopeKey: cfg.DashScopeAPIKey, }) log.Printf("[voice] service ready") // 7. Set up Gateway authMgr := api.NewStubAuthManager() apiRouter := api.New(authMgr) // 8. WebSocket Hub wsHub := ws.NewHub() wsMux := http.NewServeMux() wsMux.HandleFunc("/ws/chat", wsHub.UpgradeHandler()) // 9. Combined HTTP server (API + WS on same port) mainMux := http.NewServeMux() mainMux.Handle("/api/", apiRouter) mainMux.Handle("/ws/", wsMux) addr := fmt.Sprintf("%s:%d", cfg.Host, cfg.Port) srv := &http.Server{ Addr: addr, Handler: mainMux, } // 10. Start server go func() { log.Printf("[gateway] listening on %s", addr) if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed { log.Fatalf("[gateway] failed: %v", err) } }() // 11. Wait for shutdown signal quit := make(chan os.Signal, 1) signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM) <-quit log.Println("[gateway] shutting down...") srv.Close() log.Println("Cyrene v2 已安全退出") _ = natsConn _ = voiceSvc }