package config import ( "os" "strconv" "strings" "time" ) type Config struct { Server ServerConfig Database DatabaseConfig Redis RedisConfig JWT JWTConfig Dify DifyConfig LLM LLMConfig Embedding EmbeddingConfig Gateway GatewayConfig MinIO MinIOConfig PPTWorker PPTWorkerConfig } type PPTWorkerConfig struct { URL string // PPT Worker 微服务地址 } type LLMConfig struct { Provider string // "openai" / "anthropic" / "local" OpenAIKey string OpenAIBaseURL string OpenAIModel string AnthropicKey string AnthropicBaseURL string AnthropicModel string // 本地推理(私有化):OpenAI 兼容端点,如 vLLM(http://host:8000/v1) / Ollama(http://host:11434/v1) LocalBaseURL string LocalModel string LocalKey string // 多数本地服务无需密钥,可留空 } type EmbeddingConfig struct { APIKey string // Embedding API 密钥 BaseURL string // Embedding API 基础 URL(OpenAI 兼容格式) Model string // 向量模型名称 Dimensions int // 向量维度(必须与所用模型及 pgvector 列维度一致) NoAuth bool // 本地无鉴权端点时置 true } type ServerConfig struct { Host string Port string } type DatabaseConfig struct { URL string } type RedisConfig struct { URL string } type JWTConfig struct { Secret string AccessExpiry time.Duration RefreshExpiry time.Duration } type DifyConfig struct { APIURL string APIKey string } type GatewayConfig struct { URL string } type MinIOConfig struct { Endpoint string AccessKey string SecretKey string Bucket string UseSSL bool } func Load() *Config { return &Config{ Server: ServerConfig{ Host: getEnv("SERVER_HOST", "0.0.0.0"), Port: getEnv("SERVER_PORT", "8080"), }, Database: DatabaseConfig{ URL: getEnv("DATABASE_URL", "postgres://localhost:5432/govai_portal?sslmode=disable"), }, Redis: RedisConfig{ URL: getEnv("REDIS_URL", "redis://localhost:6379"), }, JWT: JWTConfig{ Secret: getEnv("JWT_SECRET", "dev-secret-change-in-production"), AccessExpiry: 24 * time.Hour, RefreshExpiry: 7 * 24 * time.Hour, }, Dify: DifyConfig{ APIURL: getEnv("DIFY_API_URL", "http://localhost:5001/v1"), APIKey: getEnv("DIFY_API_KEY", ""), }, LLM: LLMConfig{ Provider: getEnv("LLM_PROVIDER", "openai"), OpenAIKey: getEnv("OPENAI_API_KEY", ""), OpenAIBaseURL: getEnv("OPENAI_BASE_URL", "https://dashscope.aliyuncs.com/compatible-mode/v1"), OpenAIModel: getEnv("OPENAI_MODEL", "qwen-plus"), AnthropicKey: getEnv("ANTHROPIC_API_KEY", ""), AnthropicBaseURL: getEnv("ANTHROPIC_BASE_URL", "https://api.anthropic.com"), AnthropicModel: getEnv("ANTHROPIC_MODEL", "claude-sonnet-4-20250514"), LocalBaseURL: getEnv("LOCAL_LLM_BASE_URL", ""), LocalModel: getEnv("LOCAL_LLM_MODEL", ""), LocalKey: getEnv("LOCAL_LLM_API_KEY", ""), }, Embedding: EmbeddingConfig{ APIKey: getEnv("EMBEDDING_API_KEY", ""), BaseURL: getEnv("EMBEDDING_BASE_URL", "https://dashscope.aliyuncs.com/compatible-mode/v1"), Model: getEnv("EMBEDDING_MODEL", "text-embedding-v3"), Dimensions: getEnvInt("EMBEDDING_DIMENSIONS", 1024), NoAuth: getEnvBool("EMBEDDING_NO_AUTH", false), }, Gateway: GatewayConfig{ URL: getEnv("MODEL_GATEWAY_URL", "http://localhost:8081"), }, MinIO: MinIOConfig{ Endpoint: getEnv("MINIO_ENDPOINT", "localhost:9000"), AccessKey: getEnv("MINIO_ACCESS_KEY", "minioadmin"), SecretKey: getEnv("MINIO_SECRET_KEY", "minioadmin"), Bucket: getEnv("MINIO_BUCKET", "aily-files"), UseSSL: false, }, PPTWorker: PPTWorkerConfig{ URL: getEnv("PPT_WORKER_URL", "http://localhost:8090"), }, } } func getEnv(key, fallback string) string { if v := os.Getenv(key); v != "" { return v } return fallback } func getEnvBool(key string, fallback bool) bool { switch strings.ToLower(strings.TrimSpace(os.Getenv(key))) { case "1", "true", "yes", "on": return true case "0", "false", "no", "off": return false default: return fallback } } func getEnvInt(key string, fallback int) int { if v := os.Getenv(key); v != "" { if n, err := strconv.Atoi(strings.TrimSpace(v)); err == nil { return n } } return fallback }