diff --git a/backend/config.yaml b/backend/config.yaml new file mode 100644 index 0000000..ab4607f --- /dev/null +++ b/backend/config.yaml @@ -0,0 +1,37 @@ +# config.yaml — 默认配置 +app: + env: dev + +server: + host: "0.0.0.0" + port: 8080 + read_timeout: 30 + write_timeout: 30 + +redis: + addr: "localhost:6379" + password: "" + db: 0 + +ai: + stt: + provider: deepgram + endpoint: "wss://api.deepgram.com/v1/listen" + llm: + provider: openai + model: gpt-4o + endpoint: "https://api.openai.com/v1" + timeout: 10 + tts: + provider: openai + voice: alloy + speed: 1.0 + endpoint: "https://api.openai.com/v1" + timeout: 5 + +storage: + driver: memory + +log: + level: info + format: console diff --git a/backend/internal/config/config.go b/backend/internal/config/config.go new file mode 100644 index 0000000..d8c252c --- /dev/null +++ b/backend/internal/config/config.go @@ -0,0 +1,150 @@ +package config + +import ( + "fmt" + "os" + "strings" + + "github.com/spf13/viper" +) + +// Config 应用配置。 +type Config struct { + App AppConfig `mapstructure:"app"` + Server ServerConfig `mapstructure:"server"` + Redis RedisConfig `mapstructure:"redis"` + AI AIConfig `mapstructure:"ai"` + Storage StorageConfig `mapstructure:"storage"` + Log LogConfig `mapstructure:"log"` +} + +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"` +} + +// 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"` + Endpoint string `mapstructure:"endpoint"` +} + +type LLMConfig struct { + Provider string `mapstructure:"provider"` + APIKey string `mapstructure:"api_key"` + Model string `mapstructure:"model"` + Endpoint string `mapstructure:"endpoint"` + Timeout int `mapstructure:"timeout"` +} + +type TTSConfig struct { + Provider string `mapstructure:"provider"` + APIKey string `mapstructure:"api_key"` + Voice string `mapstructure:"voice"` + Speed float64 `mapstructure:"speed"` + Endpoint string `mapstructure:"endpoint"` + Timeout int `mapstructure:"timeout"` +} + +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.SetDefault("app.env", "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("redis.addr", "localhost:6379") + v.SetDefault("redis.db", 0) + v.SetDefault("ai.stt.provider", "deepgram") + v.SetDefault("ai.stt.endpoint", "wss://api.deepgram.com/v1/listen") + 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.tts.provider", "openai") + v.SetDefault("ai.tts.voice", "alloy") + 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("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 +}