feat: 完善项目架构并增强分析页面功能
- 新增项目文档和 Docker 配置 - 添加 README.md 和 TODO.md 项目文档 - 为各服务添加 Dockerfile 和 docker-compose 配置 - 重构后端架构 - 新增 adapter 层(HTTP/Python 适配器) - 新增 repository 层(数据访问抽象) - 新增 router 模块统一管理路由 - 新增账单处理 handler - 扩展前端 UI 组件库 - 新增 Calendar、DateRangePicker、Drawer、Popover 等组件 - 集成 shadcn-svelte 组件库 - 增强分析页面功能 - 添加时间范围筛选器(支持本月默认值) - 修复 DateRangePicker 默认值显示问题 - 优化数据获取和展示逻辑 - 完善分析器服务 - 新增 FastAPI 服务接口 - 改进账单清理器实现
This commit is contained in:
105
server/main.go
105
server/main.go
@@ -2,16 +2,20 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"billai-server/adapter"
|
||||
adapterHttp "billai-server/adapter/http"
|
||||
"billai-server/adapter/python"
|
||||
"billai-server/config"
|
||||
"billai-server/database"
|
||||
"billai-server/handler"
|
||||
"billai-server/repository"
|
||||
repoMongo "billai-server/repository/mongo"
|
||||
"billai-server/router"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@@ -36,7 +40,17 @@ func main() {
|
||||
fmt.Println(" 请在配置文件中指定正确的 Python 路径")
|
||||
}
|
||||
|
||||
// 连接 MongoDB
|
||||
// 初始化适配器(外部服务交互层)
|
||||
initAdapters()
|
||||
|
||||
// 初始化数据层
|
||||
if err := initRepository(); err != nil {
|
||||
fmt.Printf("⚠️ 警告: 数据层初始化失败: %v\n", err)
|
||||
fmt.Println(" 账单数据将不会存储到数据库")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// 连接 MongoDB(保持兼容旧代码,后续可移除)
|
||||
if err := database.Connect(); err != nil {
|
||||
fmt.Printf("⚠️ 警告: MongoDB 连接失败: %v\n", err)
|
||||
fmt.Println(" 账单数据将不会存储到数据库")
|
||||
@@ -50,7 +64,10 @@ func main() {
|
||||
r := gin.Default()
|
||||
|
||||
// 注册路由
|
||||
setupRoutes(r, outputDirAbs, pythonPathAbs)
|
||||
router.Setup(r, router.Config{
|
||||
OutputDir: outputDirAbs,
|
||||
PythonPath: pythonPathAbs,
|
||||
})
|
||||
|
||||
// 监听系统信号
|
||||
go func() {
|
||||
@@ -67,34 +84,18 @@ func main() {
|
||||
r.Run(":" + config.Global.Port)
|
||||
}
|
||||
|
||||
// setupRoutes 设置路由
|
||||
func setupRoutes(r *gin.Engine, outputDirAbs, pythonPathAbs string) {
|
||||
// 健康检查
|
||||
r.GET("/health", func(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"status": "ok",
|
||||
"python_path": pythonPathAbs,
|
||||
})
|
||||
})
|
||||
|
||||
// API 路由
|
||||
api := r.Group("/api")
|
||||
{
|
||||
api.POST("/upload", handler.Upload)
|
||||
api.GET("/review", handler.Review)
|
||||
}
|
||||
|
||||
// 静态文件下载
|
||||
r.Static("/download", outputDirAbs)
|
||||
}
|
||||
|
||||
// printBanner 打印启动横幅
|
||||
func printBanner(pythonPath, uploadDir, outputDir string) {
|
||||
fmt.Println("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━")
|
||||
fmt.Println("📦 BillAI 账单分析服务")
|
||||
fmt.Println("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━")
|
||||
fmt.Printf("📁 项目根目录: %s\n", config.Global.ProjectRoot)
|
||||
fmt.Printf("🐍 Python路径: %s\n", pythonPath)
|
||||
fmt.Printf("<EFBFBD> 适配器模式: %s\n", config.Global.AnalyzerMode)
|
||||
if config.Global.AnalyzerMode == "http" {
|
||||
fmt.Printf("🌐 分析服务: %s\n", config.Global.AnalyzerURL)
|
||||
} else {
|
||||
fmt.Printf("🐍 Python路径: %s\n", pythonPath)
|
||||
}
|
||||
fmt.Printf("📂 上传目录: %s\n", uploadDir)
|
||||
fmt.Printf("📂 输出目录: %s\n", outputDir)
|
||||
fmt.Printf("🍃 MongoDB: %s/%s\n", config.Global.MongoURI, config.Global.MongoDatabase)
|
||||
@@ -106,8 +107,60 @@ func printAPIInfo() {
|
||||
fmt.Printf("\n🚀 服务已启动: http://localhost:%s\n", config.Global.Port)
|
||||
fmt.Println("📝 API 接口:")
|
||||
fmt.Println(" POST /api/upload - 上传并分析账单")
|
||||
fmt.Println(" GET /api/bills - 获取账单列表(支持分页和时间筛选)")
|
||||
fmt.Println(" GET /api/review - 获取需要复核的记录")
|
||||
fmt.Println(" GET /download/* - 下载结果文件")
|
||||
fmt.Println(" GET /health - 健康检查")
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// initAdapters 初始化适配器(外部服务交互层)
|
||||
// 在这里配置与外部系统的交互方式
|
||||
// 支持两种模式: http (推荐) 和 subprocess
|
||||
func initAdapters() {
|
||||
var cleaner adapter.Cleaner
|
||||
|
||||
switch config.Global.AnalyzerMode {
|
||||
case "http":
|
||||
// 使用 HTTP API 调用 Python 服务(推荐)
|
||||
httpCleaner := adapterHttp.NewCleaner(config.Global.AnalyzerURL)
|
||||
|
||||
// 检查服务健康状态
|
||||
if err := httpCleaner.HealthCheck(); err != nil {
|
||||
fmt.Printf("⚠️ 警告: Python 分析服务不可用 (%s): %v\n", config.Global.AnalyzerURL, err)
|
||||
fmt.Println(" 请确保分析服务已启动: cd analyzer && python server.py")
|
||||
} else {
|
||||
fmt.Printf("🌐 已连接到分析服务: %s\n", config.Global.AnalyzerURL)
|
||||
}
|
||||
cleaner = httpCleaner
|
||||
|
||||
case "subprocess":
|
||||
// 使用子进程调用 Python 脚本(传统模式)
|
||||
pythonCleaner := python.NewCleaner()
|
||||
fmt.Println("🐍 使用子进程模式调用 Python")
|
||||
cleaner = pythonCleaner
|
||||
|
||||
default:
|
||||
// 默认使用 HTTP 模式
|
||||
cleaner = adapterHttp.NewCleaner(config.Global.AnalyzerURL)
|
||||
fmt.Printf("🌐 使用 HTTP 模式 (默认): %s\n", config.Global.AnalyzerURL)
|
||||
}
|
||||
|
||||
adapter.SetCleaner(cleaner)
|
||||
fmt.Println("🔌 适配器初始化完成")
|
||||
}
|
||||
|
||||
// initRepository 初始化数据存储层
|
||||
// 在这里配置数据持久化方式
|
||||
// 后续可以通过修改这里来切换不同的存储实现(如 PostgreSQL、MySQL 等)
|
||||
func initRepository() error {
|
||||
// 初始化 MongoDB 存储
|
||||
mongoRepo := repoMongo.NewRepository()
|
||||
if err := mongoRepo.Connect(); err != nil {
|
||||
return err
|
||||
}
|
||||
repository.SetRepository(mongoRepo)
|
||||
|
||||
fmt.Println("💾 数据层初始化完成")
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user