// Package config 配置加载模块,基于 Viper 读取 YAML 配置并提供默认值 package config import ( "errors" "strings" "github.com/spf13/viper" ) const ( DefaultAdminPath = "/admin" // 默认后台管理路径 DefaultMaxLoginAttempts = 5 // 默认最大登录尝试次数 DefaultLockoutDuration = 15 // 默认锁定时长(分钟) DefaultServerHost = "0.0.0.0" // 默认服务监听地址 DefaultServerPort = 8090 // 默认服务端口 DefaultServerMode = "release" // 默认运行模式 DefaultDatabaseType = "sqlite" // 默认数据库类型 DefaultDatabasePath = "./data/resume.db" // 默认数据库文件路径 DefaultLogLevel = "info" // 默认日志级别 DefaultTemplateDefault = "modern" // 默认简历模板 ) // Config 全局配置结构体 type Config struct { Server ServerConfig `mapstructure:"server"` // 服务配置 Database DatabaseConfig `mapstructure:"database"` // 数据库配置 Auth AuthConfig `mapstructure:"auth"` // 认证配置 Template TemplateConfig `mapstructure:"template"` // 模板配置 Log LogConfig `mapstructure:"log"` // 日志配置 AI AIConfig `mapstructure:"ai"` // AI配置 } // ServerConfig 服务配置 type ServerConfig struct { Host string `mapstructure:"host"` // 监听地址 Port int `mapstructure:"port"` // 监听端口 Mode string `mapstructure:"mode"` // 运行模式(debug/release) Debug bool `mapstructure:"debug"` // 是否开启调试 } // DatabaseConfig 数据库配置 type DatabaseConfig struct { Type string `mapstructure:"type"` // 数据库类型 Path string `mapstructure:"path"` // 数据库文件路径 Password string `mapstructure:"password"` // 数据库加密密码 } // AuthConfig 认证配置 type AuthConfig struct { Enabled bool `mapstructure:"enabled"` // 是否启用认证 Username string `mapstructure:"username"` // 管理员用户名 Password string `mapstructure:"password"` // 管理员密码 AdminPath string `mapstructure:"admin_path"` // 后台路径 MaxLoginAttempts int `mapstructure:"max_login_attempts"` // 最大登录尝试 LockoutDuration int `mapstructure:"lockout_duration"` // 锁定时长(分钟) } // TemplateConfig 模板配置 type TemplateConfig struct { Default string `mapstructure:"default"` // 默认模板名称 } // LogConfig 日志配置 type LogConfig struct { Level string `mapstructure:"level"` // 日志级别 Output string `mapstructure:"output"` // 输出文件路径 } // AIConfig AI 大模型配置 type AIConfig struct { Provider string `mapstructure:"provider"` // 默认供应商 Enabled bool `mapstructure:"enabled"` // 是否启用 Spark SparkConfig `mapstructure:"spark"` // 讯飞星火配置 Tongyi TongyiConfig `mapstructure:"tongyi"` // 通义千问配置 Doubao DoubaoConfig `mapstructure:"doubao"` // 豆包配置 DeepSeek DeepSeekConfig `mapstructure:"deepseek"` // DeepSeek配置 } // SparkConfig 讯飞星火配置 type SparkConfig struct { APPID string `mapstructure:"app_id"` // APP ID APIKey string `mapstructure:"api_key"` // API Key APISecret string `mapstructure:"api_secret"` // API Secret APIPassword string `mapstructure:"api_password"` // API 密码(HTTP接口使用) BaseURL string `mapstructure:"base_url"` // 接口地址 Model string `mapstructure:"model"` // 模型版本 MaxTokens int `mapstructure:"max_tokens"` // 最大token数 Timeout int `mapstructure:"timeout"` // 超时时间(秒) WebSearch bool `mapstructure:"web_search"` // 是否启用联网搜索 ShowRefLabel bool `mapstructure:"show_ref_label"` // 是否显示引用标签 } // TongyiConfig 通义千问配置 type TongyiConfig struct { APIKey string `mapstructure:"api_key"` // API Key BaseURL string `mapstructure:"base_url"` // 接口地址 Model string `mapstructure:"model"` // 模型名称 MaxTokens int `mapstructure:"max_tokens"` // 最大token数 Timeout int `mapstructure:"timeout"` // 超时时间(秒) } // DoubaoConfig 豆包配置 type DoubaoConfig struct { APIKey string `mapstructure:"api_key"` // API Key BaseURL string `mapstructure:"base_url"` // 接口地址 Model string `mapstructure:"model"` // 模型名称 MaxTokens int `mapstructure:"max_tokens"` // 最大token数 Timeout int `mapstructure:"timeout"` // 超时时间(秒) } // DeepSeekConfig DeepSeek 配置 type DeepSeekConfig struct { APIKey string `mapstructure:"api_key"` // API Key BaseURL string `mapstructure:"base_url"` // 接口地址 Model string `mapstructure:"model"` // 模型名称 MaxTokens int `mapstructure:"max_tokens"` // 最大token数 Timeout int `mapstructure:"timeout"` // 超时时间(秒) } // setDefaults 设置 Viper 默认值 // @author sunct func setDefaults() { viper.SetDefault("server.host", DefaultServerHost) viper.SetDefault("server.port", DefaultServerPort) viper.SetDefault("server.mode", DefaultServerMode) viper.SetDefault("server.debug", false) viper.SetDefault("database.type", DefaultDatabaseType) viper.SetDefault("database.path", DefaultDatabasePath) viper.SetDefault("auth.enabled", true) viper.SetDefault("auth.admin_path", DefaultAdminPath) viper.SetDefault("auth.max_login_attempts", DefaultMaxLoginAttempts) viper.SetDefault("auth.lockout_duration", DefaultLockoutDuration) viper.SetDefault("template.default", DefaultTemplateDefault) viper.SetDefault("log.level", DefaultLogLevel) } // LoadConfig 加载并解析配置文件,支持多路径查找 // @return *Config 配置实例 // @return error 加载错误 // @author sunct func LoadConfig() (*Config, error) { setDefaults() viper.SetConfigName("config") viper.SetConfigType("yaml") viper.AddConfigPath("./config") viper.AddConfigPath(".") viper.AddConfigPath("../config") viper.AddConfigPath("../") if err := viper.ReadInConfig(); err != nil { var configFileNotFoundError viper.ConfigFileNotFoundError if !errors.As(err, &configFileNotFoundError) { return nil, err } } var cfg Config if err := viper.Unmarshal(&cfg); err != nil { return nil, err } if err := validateAndNormalize(&cfg); err != nil { return nil, err } return &cfg, nil } // validateAndNormalize 校验并规范化配置,补全默认值 // @param cfg 配置实例 // @return error 校验错误 // @author sunct func validateAndNormalize(cfg *Config) error { if cfg.Server.Port <= 0 || cfg.Server.Port > 65535 { cfg.Server.Port = DefaultServerPort } if cfg.Server.Host == "" { cfg.Server.Host = DefaultServerHost } if cfg.Server.Mode == "" { cfg.Server.Mode = DefaultServerMode } if cfg.Database.Type == "" { cfg.Database.Type = DefaultDatabaseType } if cfg.Database.Path == "" { cfg.Database.Path = DefaultDatabasePath } if !strings.HasPrefix(cfg.Auth.AdminPath, "/") { cfg.Auth.AdminPath = "/" + cfg.Auth.AdminPath } if cfg.Auth.AdminPath == "/" { cfg.Auth.AdminPath = DefaultAdminPath } if cfg.Auth.MaxLoginAttempts <= 0 { cfg.Auth.MaxLoginAttempts = DefaultMaxLoginAttempts } if cfg.Auth.LockoutDuration <= 0 { cfg.Auth.LockoutDuration = DefaultLockoutDuration } if cfg.Template.Default == "" { cfg.Template.Default = DefaultTemplateDefault } if cfg.Log.Level == "" { cfg.Log.Level = DefaultLogLevel } return nil }