package config import ( "flag" "fmt" "os" "path/filepath" "gopkg.in/yaml.v3" ) // Config 服务配置 type Config struct { Port string // 服务端口 ProjectRoot string // 项目根目录 PythonPath string // Python 解释器路径 CleanScript string // 清理脚本路径 UploadDir string // 上传文件目录 OutputDir string // 输出文件目录 } // configFile YAML 配置文件结构 type configFile struct { Server struct { Port int `yaml:"port"` } `yaml:"server"` Python struct { Path string `yaml:"path"` Script string `yaml:"script"` } `yaml:"python"` Directories struct { Upload string `yaml:"upload"` Output string `yaml:"output"` } `yaml:"directories"` } // Global 全局配置实例 var Global Config // getEnvOrDefault 获取环境变量,如果不存在则返回默认值 func getEnvOrDefault(key, defaultValue string) string { if value := os.Getenv(key); value != "" { return value } return defaultValue } // getDefaultProjectRoot 获取默认项目根目录 func getDefaultProjectRoot() string { if root := os.Getenv("BILLAI_ROOT"); root != "" { return root } exe, err := os.Executable() if err == nil { exeDir := filepath.Dir(exe) if filepath.Base(exeDir) == "server" { return filepath.Dir(exeDir) } } cwd, _ := os.Getwd() if filepath.Base(cwd) == "server" { return filepath.Dir(cwd) } return cwd } // getDefaultPythonPath 获取默认 Python 路径 func getDefaultPythonPath() string { if python := os.Getenv("BILLAI_PYTHON"); python != "" { return python } return "analyzer/venv/bin/python" } // loadConfigFile 加载 YAML 配置文件 func loadConfigFile(configPath string) *configFile { data, err := os.ReadFile(configPath) if err != nil { return nil } var cfg configFile if err := yaml.Unmarshal(data, &cfg); err != nil { fmt.Printf("⚠️ 配置文件解析失败: %v\n", err) return nil } return &cfg } // Load 加载配置 func Load() { var configFilePath string flag.StringVar(&configFilePath, "config", "config.yaml", "配置文件路径") flag.Parse() // 设置默认值 Global.Port = getEnvOrDefault("PORT", "8080") Global.ProjectRoot = getDefaultProjectRoot() Global.PythonPath = getDefaultPythonPath() Global.CleanScript = "analyzer/clean_bill.py" Global.UploadDir = "server/uploads" Global.OutputDir = "server/outputs" // 查找配置文件 configPath := configFilePath if !filepath.IsAbs(configPath) { if _, err := os.Stat(configPath); os.IsNotExist(err) { configPath = filepath.Join("server", configFilePath) } } // 加载配置文件 if cfg := loadConfigFile(configPath); cfg != nil { fmt.Printf("📄 加载配置文件: %s\n", configPath) if cfg.Server.Port > 0 { Global.Port = fmt.Sprintf("%d", cfg.Server.Port) } if cfg.Python.Path != "" { Global.PythonPath = cfg.Python.Path } if cfg.Python.Script != "" { Global.CleanScript = cfg.Python.Script } if cfg.Directories.Upload != "" { Global.UploadDir = cfg.Directories.Upload } if cfg.Directories.Output != "" { Global.OutputDir = cfg.Directories.Output } } // 环境变量覆盖 if port := os.Getenv("PORT"); port != "" { Global.Port = port } if python := os.Getenv("BILLAI_PYTHON"); python != "" { Global.PythonPath = python } if root := os.Getenv("BILLAI_ROOT"); root != "" { Global.ProjectRoot = root } } // ResolvePath 解析路径(相对路径转为绝对路径) func ResolvePath(path string) string { if filepath.IsAbs(path) { return path } return filepath.Join(Global.ProjectRoot, path) }