package config import ( "fmt" "os" "strconv" "github.com/joho/godotenv" ) type Config struct { BotToken string AppID string GuildID string DBHost string LavalinkHost string LavalinkPass string TwitchClientID string OllamaHost string TLDRModel string TLDRThreads int } func LoadConfig() (*Config, error) { // Load .env if present (e.g. local dev). Ignore if missing (e.g. Docker injects env vars). _ = godotenv.Load() token := os.Getenv("BOT_TOKEN") if token == "" { return nil, fmt.Errorf("BOT_TOKEN is not set") } appID := os.Getenv("APP_ID") if appID == "" { return nil, fmt.Errorf("APP_ID is not set") } guildID := os.Getenv("GUILD_ID") dbHost := os.Getenv("DB_HOST") if dbHost == "" { return nil, fmt.Errorf("DB_HOST is not set") } lavalinkHost := os.Getenv("LAVALINK_HOST") lavalinkPass := os.Getenv("LAVALINK_PASSWORD") twitchClientID := os.Getenv("TWITCH_CLIENT_ID") if twitchClientID == "" { return nil, fmt.Errorf("TWITCH_CLIENT_ID is not set") } ollamaHost := os.Getenv("OLLAMA_HOST") if ollamaHost == "" { ollamaHost = "http://ollama:11434" } tldrModel := os.Getenv("TLDR_MODEL") if tldrModel == "" { tldrModel = "qwen3:4b-instruct-2507-q4_K_M" } // CPU threads the summarizer may use. Keep it well under the machine's // core count so music playback never has to compete with inference. tldrThreads := 6 if v := os.Getenv("TLDR_THREADS"); v != "" { n, err := strconv.Atoi(v) if err != nil || n < 1 { return nil, fmt.Errorf("TLDR_THREADS must be a positive integer, got %q", v) } tldrThreads = n } return &Config{ BotToken: token, AppID: appID, GuildID: guildID, DBHost: dbHost, LavalinkHost: lavalinkHost, LavalinkPass: lavalinkPass, TwitchClientID: twitchClientID, OllamaHost: ollamaHost, TLDRModel: tldrModel, TLDRThreads: tldrThreads, }, nil }