package config import ( "os" "strconv" "strings" "time" ) // Config 定义服务运行配置。 // AI 调用统一走 OpenAI 兼容协议,上游地址和鉴权由环境变量提供。 type Config struct { Port string ProviderName string AIBaseURL string AIChatPath string AIAPIKey string AIModel string AITimeout time.Duration AllowedOrigins []string } // Load 从环境变量装载运行配置。 // 未提供的字段使用保守默认值,确保本地开发可以直接启动服务。 func Load() Config { return Config{ Port: getenv("SERVER_PORT", "8080"), ProviderName: getenv("AI_PROVIDER_NAME", "OpenAI Compatible"), AIBaseURL: strings.TrimRight(getenv("AI_BASE_URL", "https://api.openai.com"), "/"), AIChatPath: normalizePath(getenv("AI_CHAT_PATH", "/v1/chat/completions")), AIAPIKey: strings.TrimSpace(os.Getenv("AI_API_KEY")), AIModel: strings.TrimSpace(os.Getenv("AI_MODEL")), AITimeout: time.Duration(getenvInt("AI_TIMEOUT_SECONDS", 60)) * time.Second, AllowedOrigins: splitOrigins(getenv("WEB_ALLOWED_ORIGINS", "http://127.0.0.1:5173,http://localhost:5173")), } } // AIEnabled 判断 AI 服务是否已具备调用条件。 func (c Config) AIEnabled() bool { return c.AIAPIKey != "" && c.AIModel != "" && c.AIBaseURL != "" } func getenv(key string, fallback string) string { value := strings.TrimSpace(os.Getenv(key)) if value == "" { return fallback } return value } func getenvInt(key string, fallback int) int { value := strings.TrimSpace(os.Getenv(key)) if value == "" { return fallback } parsed, err := strconv.Atoi(value) if err != nil || parsed <= 0 { return fallback } return parsed } func normalizePath(path string) string { if path == "" { return "/v1/chat/completions" } if strings.HasPrefix(path, "/") { return path } return "/" + path } func splitOrigins(raw string) []string { parts := strings.Split(raw, ",") origins := make([]string, 0, len(parts)) for _, part := range parts { origin := strings.TrimSpace(part) if origin != "" { origins = append(origins, origin) } } if len(origins) == 0 { return []string{"http://127.0.0.1:5173", "http://localhost:5173"} } return origins }