// Package python 实现通过子进程调用 Python 脚本的清洗器 package python import ( "fmt" "os/exec" "strings" "billai-server/adapter" "billai-server/config" ) // Cleaner 通过子进程调用 Python 脚本的清洗器实现 type Cleaner struct { pythonPath string // Python 解释器路径 scriptPath string // 清洗脚本路径 workDir string // 工作目录 } // NewCleaner 创建 Python 清洗器 func NewCleaner() *Cleaner { return &Cleaner{ pythonPath: config.ResolvePath(config.Global.PythonPath), scriptPath: config.ResolvePath(config.Global.CleanScript), workDir: config.Global.ProjectRoot, } } // NewCleanerWithConfig 使用自定义配置创建 Python 清洗器 func NewCleanerWithConfig(pythonPath, scriptPath, workDir string) *Cleaner { return &Cleaner{ pythonPath: pythonPath, scriptPath: scriptPath, workDir: workDir, } } // Clean 执行 Python 清洗脚本 func (c *Cleaner) Clean(inputPath, outputPath string, opts *adapter.CleanOptions) (*adapter.CleanResult, error) { // 构建命令参数 args := []string{c.scriptPath, inputPath, outputPath} if opts != nil { if opts.Year != "" { args = append(args, "--year", opts.Year) } if opts.Month != "" { args = append(args, "--month", opts.Month) } if opts.Start != "" { args = append(args, "--start", opts.Start) } if opts.End != "" { args = append(args, "--end", opts.End) } if opts.Format != "" { args = append(args, "--format", opts.Format) } } // 执行 Python 脚本 fmt.Printf("🐍 执行清洗脚本...\n") cmd := exec.Command(c.pythonPath, args...) cmd.Dir = c.workDir output, err := cmd.CombinedOutput() outputStr := string(output) if err != nil { return nil, fmt.Errorf("清洗脚本执行失败: %w\n输出: %s", err, outputStr) } // 从输出中检测账单类型 billType := detectBillTypeFromOutput(outputStr) return &adapter.CleanResult{ BillType: billType, Output: outputStr, }, nil } // detectBillTypeFromOutput 从 Python 脚本输出中检测账单类型 func detectBillTypeFromOutput(output string) string { if strings.Contains(output, "支付宝") { return "alipay" } if strings.Contains(output, "微信") { return "wechat" } if strings.Contains(output, "京东") { return "jd" } return "" } // Convert 转换账单文件格式(xlsx -> csv,处理 GBK 编码等) // 子进程模式不支持此功能,请使用 HTTP 模式 func (c *Cleaner) Convert(inputPath string) (outputPath string, billType string, err error) { return "", "", fmt.Errorf("子进程模式不支持文件格式转换,请使用 HTTP 模式 (analyzer_mode: http)") } // 确保 Cleaner 实现了 adapter.Cleaner 接口 var _ adapter.Cleaner = (*Cleaner)(nil)