Files
CamTalk/backend/internal/config/config.go

161 lines
4.2 KiB
Go
Raw Normal View History

package config
import (
"fmt"
"os"
"strings"
2026-06-13 19:57:35 +08:00
"github.com/joho/godotenv"
"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"`
2026-06-13 19:57:35 +08:00
Model string `mapstructure:"model"`
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"`
2026-06-13 19:57:35 +08:00
Model string `mapstructure:"model"`
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")
2026-06-13 19:57:35 +08:00
v.SetDefault("ai.stt.model", "nova-2")
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")
2026-06-13 19:57:35 +08:00
v.SetDefault("ai.tts.model", "tts-1")
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()
}
2026-06-13 19:57:35 +08:00
// 加载 .env 文件(不覆盖已有环境变量)
// 按优先级尝试:当前目录、上级目录(兼容从 backend/ 或项目根目录启动)
_ = godotenv.Load()
_ = godotenv.Load("../.env")
// 环境变量覆盖
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
}