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

186 lines
6.0 KiB
Go
Raw Normal View History

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")
2026-06-14 12:29:46 +08:00
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")
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.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")
2026-06-13 19:57:35 +08:00
v.SetDefault("ai.tts.model", "tts-1")
2026-06-14 11:12:49 +08:00
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
}