feat(config): 重构配置层为 Viper + YAML + .env 三级加载
- config 改用 Viper 读取 YAML + 绑定环境变量 + godotenv 加载 .env - 新增 LLM / ImageGen / JWT / Database / Server 分组配置结构 - 新增 backend/.env.example 环境变量模板 - .gitignore 添加 backend/.env 和 backend/main
This commit is contained in:
@@ -1,55 +1,138 @@
|
||||
// Package config 负责从环境变量加载应用配置。
|
||||
package config
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strconv"
|
||||
"log"
|
||||
|
||||
"github.com/joho/godotenv"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
// Config 应用全局配置,优先读取环境变量,未设置时使用默认值。
|
||||
// Config 应用全局配置。
|
||||
type Config struct {
|
||||
Port int // HTTP 监听端口,默认 8080,环境变量 GEN2D_PORT
|
||||
Mode string // Gin 运行模式 (debug/release),环境变量 GEN2D_MODE
|
||||
MaxFileSize int64 // 上传文件大小上限(字节),默认 10MB
|
||||
DSN string // SQLite 数据库路径,默认 data/gen2d.db,环境变量 GEN2D_DSN
|
||||
JWTSecret string // JWT 签名密钥,环境变量 GEN2D_JWT_SECRET
|
||||
JWTExpire int64 // JWT 过期时间(秒),默认 7200
|
||||
Server ServerConfig `mapstructure:"server"`
|
||||
Database DatabaseConfig `mapstructure:"database"`
|
||||
JWT JWTConfig `mapstructure:"jwt"`
|
||||
LLM LLMConfig `mapstructure:"llm"`
|
||||
ImageGen ImageGenConfig `mapstructure:"image_gen"`
|
||||
}
|
||||
|
||||
// Load 从环境变量加载配置并返回。
|
||||
// ServerConfig HTTP 服务配置。
|
||||
type ServerConfig struct {
|
||||
Port int `mapstructure:"port"`
|
||||
Mode string `mapstructure:"mode"`
|
||||
MaxFileSize int64 `mapstructure:"max_file_size"`
|
||||
}
|
||||
|
||||
// DatabaseConfig 数据库配置。
|
||||
type DatabaseConfig struct {
|
||||
DSN string `mapstructure:"dsn"`
|
||||
}
|
||||
|
||||
// JWTConfig JWT 签名配置。
|
||||
type JWTConfig struct {
|
||||
Secret string `mapstructure:"secret"`
|
||||
Expire int64 `mapstructure:"expire"`
|
||||
}
|
||||
|
||||
// LLMConfig 大语言模型配置。
|
||||
type LLMConfig struct {
|
||||
BaseURL string `mapstructure:"base_url"`
|
||||
APIKey string `mapstructure:"api_key"`
|
||||
Model string `mapstructure:"model"`
|
||||
Temperature float64 `mapstructure:"temperature"`
|
||||
MaxTokens int `mapstructure:"max_tokens"`
|
||||
}
|
||||
|
||||
// ImageGenConfig 文生图模型配置。
|
||||
type ImageGenConfig struct {
|
||||
BaseURL string `mapstructure:"base_url"`
|
||||
APIKey string `mapstructure:"api_key"`
|
||||
Model string `mapstructure:"model"`
|
||||
Width int `mapstructure:"width"`
|
||||
Height int `mapstructure:"height"`
|
||||
NumImages int `mapstructure:"num_images"`
|
||||
Steps int `mapstructure:"steps"`
|
||||
CFGScale float64 `mapstructure:"cfg_scale"`
|
||||
}
|
||||
|
||||
// Load 从 YAML 配置文件和环境变量加载配置。
|
||||
// 优先级:环境变量 > YAML 文件 > 默认值。
|
||||
func Load() *Config {
|
||||
cfg := &Config{
|
||||
Port: 8080,
|
||||
Mode: "debug",
|
||||
MaxFileSize: 10 << 20, // 10MB
|
||||
DSN: "data/gen2d.db",
|
||||
JWTSecret: "gen2d-dev-secret",
|
||||
JWTExpire: 7200,
|
||||
if err := godotenv.Load(); err != nil {
|
||||
log.Println("config: no .env file found, using system env or defaults")
|
||||
}
|
||||
|
||||
if port := os.Getenv("GEN2D_PORT"); port != "" {
|
||||
if p, err := strconv.Atoi(port); err == nil {
|
||||
cfg.Port = p
|
||||
}
|
||||
v := viper.New()
|
||||
v.SetConfigName("config")
|
||||
v.SetConfigType("yaml")
|
||||
v.AddConfigPath("internal/config")
|
||||
|
||||
setDefaults(v)
|
||||
|
||||
if err := v.ReadInConfig(); err != nil {
|
||||
log.Printf("config: could not read config file: %v, using env + defaults", err)
|
||||
} else {
|
||||
log.Printf("config: using config file: %s", v.ConfigFileUsed())
|
||||
}
|
||||
|
||||
if mode := os.Getenv("GEN2D_MODE"); mode != "" {
|
||||
cfg.Mode = mode
|
||||
bindEnvVars(v)
|
||||
|
||||
v.AllowEmptyEnv(true)
|
||||
|
||||
var cfg Config
|
||||
if err := v.Unmarshal(&cfg); err != nil {
|
||||
log.Fatalf("config: unmarshal failed: %v", err)
|
||||
}
|
||||
|
||||
if dsn := os.Getenv("GEN2D_DSN"); dsn != "" {
|
||||
cfg.DSN = dsn
|
||||
}
|
||||
|
||||
if secret := os.Getenv("GEN2D_JWT_SECRET"); secret != "" {
|
||||
cfg.JWTSecret = secret
|
||||
}
|
||||
|
||||
if expire := os.Getenv("GEN2D_JWT_EXPIRE"); expire != "" {
|
||||
if e, err := strconv.ParseInt(expire, 10, 64); err == nil {
|
||||
cfg.JWTExpire = e
|
||||
}
|
||||
}
|
||||
|
||||
return cfg
|
||||
return &cfg
|
||||
}
|
||||
|
||||
func setDefaults(v *viper.Viper) {
|
||||
v.SetDefault("server.port", 8080)
|
||||
v.SetDefault("server.mode", "debug")
|
||||
v.SetDefault("server.max_file_size", int64(10<<20))
|
||||
|
||||
v.SetDefault("database.dsn", "data/gen2d.db")
|
||||
|
||||
v.SetDefault("jwt.secret", "gen2d-dev-secret")
|
||||
v.SetDefault("jwt.expire", int64(7200))
|
||||
|
||||
v.SetDefault("llm.base_url", "https://api.openai.com/v1")
|
||||
v.SetDefault("llm.api_key", "")
|
||||
v.SetDefault("llm.model", "gpt-4o")
|
||||
v.SetDefault("llm.temperature", 0.7)
|
||||
v.SetDefault("llm.max_tokens", 2048)
|
||||
|
||||
v.SetDefault("image_gen.base_url", "https://api.stability.ai/v1")
|
||||
v.SetDefault("image_gen.api_key", "")
|
||||
v.SetDefault("image_gen.model", "stable-diffusion-xl")
|
||||
v.SetDefault("image_gen.width", 1024)
|
||||
v.SetDefault("image_gen.height", 1024)
|
||||
v.SetDefault("image_gen.num_images", 1)
|
||||
v.SetDefault("image_gen.steps", 30)
|
||||
v.SetDefault("image_gen.cfg_scale", 7.0)
|
||||
}
|
||||
|
||||
func bindEnvVars(v *viper.Viper) {
|
||||
v.BindEnv("server.port", "GEN2D_PORT")
|
||||
v.BindEnv("server.mode", "GEN2D_MODE")
|
||||
v.BindEnv("server.max_file_size", "GEN2D_MAX_FILE_SIZE")
|
||||
v.BindEnv("database.dsn", "GEN2D_DSN")
|
||||
v.BindEnv("jwt.secret", "GEN2D_JWT_SECRET")
|
||||
v.BindEnv("jwt.expire", "GEN2D_JWT_EXPIRE")
|
||||
|
||||
v.BindEnv("llm.base_url", "GEN2D_LLM_BASE_URL")
|
||||
v.BindEnv("llm.api_key", "GEN2D_LLM_API_KEY")
|
||||
v.BindEnv("llm.model", "GEN2D_LLM_MODEL")
|
||||
v.BindEnv("llm.temperature", "GEN2D_LLM_TEMPERATURE")
|
||||
v.BindEnv("llm.max_tokens", "GEN2D_LLM_MAX_TOKENS")
|
||||
|
||||
v.BindEnv("image_gen.base_url", "GEN2D_IMAGE_BASE_URL")
|
||||
v.BindEnv("image_gen.api_key", "GEN2D_IMAGE_API_KEY")
|
||||
v.BindEnv("image_gen.model", "GEN2D_IMAGE_MODEL")
|
||||
v.BindEnv("image_gen.width", "GEN2D_IMAGE_WIDTH")
|
||||
v.BindEnv("image_gen.height", "GEN2D_IMAGE_HEIGHT")
|
||||
v.BindEnv("image_gen.num_images", "GEN2D_IMAGE_NUM_IMAGES")
|
||||
v.BindEnv("image_gen.steps", "GEN2D_IMAGE_STEPS")
|
||||
v.BindEnv("image_gen.cfg_scale", "GEN2D_IMAGE_CFG_SCALE")
|
||||
}
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
# gen2d backend configuration
|
||||
# 敏感信息(api_key)请通过环境变量设置,不要直接写在文件中提交。
|
||||
|
||||
server:
|
||||
port: 8080
|
||||
mode: debug
|
||||
max_file_size: 10485760 # 10MB
|
||||
|
||||
database:
|
||||
dsn: "data/gen2d.db"
|
||||
|
||||
jwt:
|
||||
secret: "gen2d-dev-secret"
|
||||
expire: 7200
|
||||
|
||||
llm:
|
||||
base_url: "https://api.deepseek.com/v1"
|
||||
api_key: ""
|
||||
model: "deepseek-v4-pro"
|
||||
temperature: 0.7
|
||||
max_tokens: 2048
|
||||
|
||||
image_gen:
|
||||
base_url: "https://api.stability.ai/v1"
|
||||
api_key: ""
|
||||
model: "stable-diffusion-xl"
|
||||
width: 1024
|
||||
height: 1024
|
||||
num_images: 1
|
||||
steps: 30
|
||||
cfg_scale: 7.0
|
||||
Reference in New Issue
Block a user