package config import ( "fmt" "os" "strings" "github.com/spf13/viper" ) // Config 应用配置。 type Config struct { App AppConfig `mapstructure:"app"` Server ServerConfig `mapstructure:"server"` Session SessionConfig `mapstructure:"session"` Redis RedisConfig `mapstructure:"redis"` AI AIConfig `mapstructure:"ai"` Storage StorageConfig `mapstructure:"storage"` Log LogConfig `mapstructure:"log"` } // SessionConfig 会话管理配置。 type SessionConfig struct { TTL int `mapstructure:"ttl"` // 会话过期时间(分钟) MaxHistory int `mapstructure:"max_history"` // 对话历史上限(条) } type AppConfig struct { Env string `mapstructure:"env"` Version string `mapstructure:"version"` } type ServerConfig struct { Host string `mapstructure:"host"` Port int `mapstructure:"port"` ReadTimeout int `mapstructure:"read_timeout"` WriteTimeout int `mapstructure:"write_timeout"` HeartbeatInterval int `mapstructure:"heartbeat_interval"` // 心跳检查间隔(秒) HeartbeatTimeout int `mapstructure:"heartbeat_timeout"` // 心跳超时(秒) ShutdownTimeout int `mapstructure:"shutdown_timeout"` // 优雅关闭超时(秒) AllowedOrigins []string `mapstructure:"allowed_origins"` // CORS 允许的来源,空表示允许所有 } // Addr 返回 host:port 地址。 func (s ServerConfig) Addr() string { return fmt.Sprintf("%s:%d", s.Host, s.Port) } type RedisConfig struct { Addr string `mapstructure:"addr"` Password string `mapstructure:"password"` DB int `mapstructure:"db"` } type AIConfig struct { STT STTConfig `mapstructure:"stt"` LLM LLMConfig `mapstructure:"llm"` TTS TTSConfig `mapstructure:"tts"` } type STTConfig struct { Provider string `mapstructure:"provider"` APIKey string `mapstructure:"api_key"` Model string `mapstructure:"model"` Endpoint string `mapstructure:"endpoint"` Timeout int `mapstructure:"timeout"` // STT 超时(秒) HTTPClientTimeout int `mapstructure:"http_client_timeout"` // HTTP 客户端超时(秒) } type LLMConfig struct { Provider string `mapstructure:"provider"` APIKey string `mapstructure:"api_key"` Model string `mapstructure:"model"` Endpoint string `mapstructure:"endpoint"` Timeout int `mapstructure:"timeout"` HTTPClientTimeout int `mapstructure:"http_client_timeout"` // HTTP 客户端超时(秒) } type TTSConfig struct { Provider string `mapstructure:"provider"` APIKey string `mapstructure:"api_key"` Model string `mapstructure:"model"` Voice string `mapstructure:"voice"` Speed float64 `mapstructure:"speed"` Endpoint string `mapstructure:"endpoint"` Timeout int `mapstructure:"timeout"` HTTPClientTimeout int `mapstructure:"http_client_timeout"` // HTTP 客户端超时(秒) OutputFormat string `mapstructure:"output_format"` // 输出格式:mp3/wav SampleRate int `mapstructure:"sample_rate"` // 输出采样率 } type StorageConfig struct { Driver string `mapstructure:"driver"` DSN string `mapstructure:"dsn"` } type LogConfig struct { Level string `mapstructure:"level"` Format string `mapstructure:"format"` } // Load 加载配置。优先级:环境变量 > config.{env}.yaml > config.yaml。 func Load() (*Config, error) { v := viper.New() v.SetConfigName("config") v.SetConfigType("yaml") v.AddConfigPath(".") v.AddConfigPath("./config") v.AddConfigPath("./backend") v.AddConfigPath("..") // 兼容从 backend/cmd/ 启动 v.AddConfigPath("../..") // 兼容从 backend/cmd/server/ 启动 // 默认值 v.SetDefault("app.env", "dev") v.SetDefault("app.version", "dev") v.SetDefault("server.host", "0.0.0.0") v.SetDefault("server.port", 8080) v.SetDefault("server.read_timeout", 30) v.SetDefault("server.write_timeout", 30) v.SetDefault("server.heartbeat_interval", 30) v.SetDefault("server.heartbeat_timeout", 60) v.SetDefault("server.shutdown_timeout", 10) v.SetDefault("session.ttl", 30) v.SetDefault("session.max_history", 20) v.SetDefault("redis.addr", "localhost:6379") v.SetDefault("redis.db", 0) v.SetDefault("ai.stt.provider", "deepgram") v.SetDefault("ai.stt.model", "nova-2") v.SetDefault("ai.stt.endpoint", "wss://api.deepgram.com/v1/listen") v.SetDefault("ai.stt.timeout", 5) v.SetDefault("ai.stt.http_client_timeout", 30) v.SetDefault("ai.llm.provider", "openai") v.SetDefault("ai.llm.model", "gpt-4o") v.SetDefault("ai.llm.endpoint", "https://api.openai.com/v1") v.SetDefault("ai.llm.timeout", 10) v.SetDefault("ai.llm.http_client_timeout", 60) v.SetDefault("ai.tts.provider", "openai") v.SetDefault("ai.tts.model", "tts-1") v.SetDefault("ai.tts.voice", "mimo_default") v.SetDefault("ai.tts.speed", 1.0) v.SetDefault("ai.tts.endpoint", "https://api.openai.com/v1") v.SetDefault("ai.tts.timeout", 5) v.SetDefault("ai.tts.http_client_timeout", 30) v.SetDefault("ai.tts.output_format", "mp3") v.SetDefault("ai.tts.sample_rate", 24000) v.SetDefault("storage.driver", "memory") v.SetDefault("log.level", "info") v.SetDefault("log.format", "console") // 读取基础配置文件 _ = v.ReadInConfig() // 文件不存在不报错 // 根据 APP_ENV 覆盖 env := os.Getenv("APP_ENV") if env == "" { env = v.GetString("app.env") } if env != "" { v.SetConfigName("config." + env) _ = v.MergeInConfig() } // 环境变量覆盖 v.SetEnvPrefix("CAMTALK") v.SetEnvKeyReplacer(strings.NewReplacer(".", "_")) v.AutomaticEnv() var cfg Config if err := v.Unmarshal(&cfg); err != nil { return nil, fmt.Errorf("config unmarshal: %w", err) } // 填充默认值 if cfg.Server.Host == "" { cfg.Server.Host = "0.0.0.0" } if cfg.Server.Port == 0 { cfg.Server.Port = 8080 } if cfg.App.Env == "" { cfg.App.Env = "dev" } return &cfg, nil }