From a28c7ba963bd4072a3802ddaf9f83f7cdb477ce3 Mon Sep 17 00:00:00 2001 From: dindang Date: Thu, 16 Jul 2026 10:39:55 +0800 Subject: [PATCH] Update README with current project structure and features - Add api/ package, model/response.go, logger, queue docs - Document environment variables (WORKER_COUNT, LOG_DIR, LOG_LEVEL) - Add cache strategy and async queue sections - Update project structure tree - Add GORM + raw SQL hybrid approach doc Co-Authored-By: Claude --- README.md | 131 ++++++++++++++++++++++++++++++++---------------------- 1 file changed, 78 insertions(+), 53 deletions(-) diff --git a/README.md b/README.md index 87f0e8e..cba7e37 100644 --- a/README.md +++ b/README.md @@ -1,31 +1,33 @@ # FloorVisualizer -AI 换地板可视化后端服务 —— 上传房间照片,AI 自动识别地面区域并生成换地板效果图。 +AI 换地板可视化后端服务 — 上传房间照片,AI 自动识别地面区域并生成换地板效果图。 ## 技术栈 - **语言**: Go 1.23+ -- **数据库**: PostgreSQL 15 +- **数据库**: PostgreSQL 15(GORM + 原生 SQL) - **缓存/队列**: Redis 7 - **AI**: OpenRouter API (Gemini 3 Pro / Flash) - **部署**: Docker Compose ## 快速开始 -### 本地开发 +### 首次部署 ```bash -# 1. 起依赖(仅 DB + Redis) -docker compose -f docker-compose.dev.yml up -d +# 1. 初始化数据库(仅一次) +psql -U postgres < schema.sql # 2. 导入产品数据 -go run cmd/import/main.go +go run cmd/import/main.go # 3539 条产品 +go run cmd/import_articles/main.go # 30 篇科普文章 -# 3. 启动服务 +# 3. 启动开发服务(本地 DB + Redis) +docker compose -f docker-compose.dev.yml up -d go run main.go ``` -服务默认运行在 `http://localhost:8099`。 +服务运行在 `http://localhost:8099`。 ### 生产部署 @@ -36,43 +38,54 @@ docker compose up -d --build ## 项目结构 ``` -├── main.go # 入口 +├── main.go +├── schema.sql # 建表脚本(导入一次) ├── cmd/ │ ├── import/main.go # 产品数据导入 │ ├── import_articles/main.go # 科普文章导入 │ └── scrape_logos/main.py # 品牌 Logo 刮取 ├── internal/ -│ ├── handler/ # HTTP 处理器 -│ │ ├── router.go # 路由注册 -│ │ ├── product_handler.go # 产品列表/详情 -│ │ ├── floor_handler.go # AI 换地板 -│ │ ├── auth_handler.go # 注册/登录 -│ │ ├── user_handler.go # 用户/收藏/项目/头像 -│ │ ├── recommend_handler.go # 智能推荐 -│ │ ├── calc_handler.go # 面积计算 -│ │ ├── article_handler.go # 科普文章 -│ │ ├── upload_handler.go # 图片上传 -│ │ └── health_handler.go # 健康检查 -│ ├── model/ # 数据模型 -│ ├── repository/ # 数据库操作 +│ ├── api/ +│ │ └── router.go # 路由注册 + 依赖注入 + 响应 helper +│ ├── handler/ # HTTP 处理器(函数导出) +│ │ ├── router.go # writeJSON/writeErr +│ │ ├── auth_handler.go # Register / Login +│ │ ├── user_handler.go # Me / UploadAvatar / Favorites / Projects / FrequentBrands +│ │ ├── product_handler.go # Products / ProductOptions / FilterOptions +│ │ ├── recommend_handler.go # Recommend +│ │ ├── calc_handler.go # Calc +│ │ ├── floor_handler.go # FloorGenerate / FloorStatus / FloorOptions +│ │ ├── article_handler.go # Articles / ArticleRecommend +│ │ ├── health_handler.go # Healthz +│ │ └── upload_handler.go # Upload +│ ├── model/ # 数据模型 + 返回结构体 +│ │ ├── response.go # ApiResponse / ApiError +│ │ ├── calc.go # CalcInput / CalcResult / CalcDeduction +│ │ ├── product.go # Product / ProductSpec +│ │ ├── brand.go # BrandInfo +│ │ └── ... +│ ├── repository/ # 数据访问(GORM + 原生 SQL) +│ │ ├── gorm.go # GORM 初始化 +│ │ ├── db.go # PostgreSQL 连接 +│ │ ├── product_repo.go # 产品查询(简单 GORM,复杂 SQL) +│ │ ├── brand_view_repo.go # 品牌浏览统计 +│ │ └── ... │ ├── service/ # 业务逻辑(推荐算法) -│ ├── middleware/ # 中间件(JWT、日志、访问记录) -│ ├── queue/ # Redis 队列(异步任务) +│ ├── middleware/ # JWT 认证 + 访问日志 +│ ├── queue/ # Redis 异步任务队列 +│ │ ├── redis.go # 入队/出队/状态管理 +│ │ └── worker.go # Worker 池(并发消费) │ ├── openrouter/ # OpenRouter API 客户端 -│ └── logger/ # 分级日志 -├── data/products/ # 产品 JSON 数据(3539 条) -├── data/articles.json # 科普文章(30 篇) -├── knowledge_images/ # 文章图片 +│ └── logger/ # 分级日志(日切 + 30 天清理) +├── data/products/ # 产品 JSON(3539 条,不入 git) ├── Dockerfile -├── docker-compose.yml # 生产部署 -├── docker-compose.dev.yml # 本地开发 +├── docker-compose.yml +├── docker-compose.dev.yml └── apifox-import.json # API 文档 ``` ## 环境变量 -### 服务配置 - | 变量 | 默认值 | 说明 | |------|--------|------| | `PORT` | `8099` | HTTP 端口 | @@ -82,19 +95,9 @@ docker compose up -d --build | `OPENROUTER_API_KEY` | 内置默认值 | OpenRouter API Key | | `PROXY_URL` | `127.0.0.1:7897` | HTTP 代理(留空禁用) | | `DISABLE_PROXY` | — | 设为 `true` 强制禁用代理 | - -### 队列 - -| 变量 | 默认值 | 说明 | -|------|--------|------| | `WORKER_COUNT` | `5` | AI 生成并发 worker 数(1-20) | - -### 日志 - -| 变量 | 默认值 | 说明 | -|------|--------|------| | `LOG_DIR` | `logs` | 日志目录 | -| `LOG_LEVEL` | `INFO` | 日志级别:DEBUG / INFO / WARN / ERROR | +| `LOG_LEVEL` | `INFO` | DEBUG / INFO / WARN / ERROR | ## API 总览 @@ -106,23 +109,23 @@ docker compose up -d --build ### 产品(公开) - `GET /products` — 列表(多维度筛选+搜索+分页) -- `GET /products/{sku}` — 详情(含规格 specs、收藏状态) +- `GET /products/{sku}` — 详情(含 specs 规格、收藏状态、热点缓存) - `GET /product-options` — 筛选选项(含品牌 logo、款式数、合集数) ### 推荐(公开) -- `GET /recommend/api?sku=xxx` — 跨品牌相似推荐 +- `GET /recommend/api?sku=xxx` — 跨品牌相似推荐(specs 感知) -### 地板更换 +### 地板更换(需 Redis) - `GET /floor/options` — 地板样式+铺设方式+房间类型 - `POST /floor/generate` — 提交 AI 生成任务 → 返回 `job_id` -- `GET /floor/status?job_id=xxx` — 查询任务进度 +- `GET /floor/status?job_id=xxx` — 查询异步任务进度 ### 用户(需 JWT) - `GET /user/me` / `PUT /user/me` — 个人信息 - `POST /user/avatar` — 上传头像 - `GET /user/favorites` / `POST` / `DELETE` — 收藏管理 - `GET /user/projects` / `POST` / `PUT` / `DELETE` — 项目(生成记录) -- `GET /user/frequent-brands` — 常用品牌(浏览≥3 或 收藏≥2) +- `GET /user/frequent-brands` — 常用品牌(自动统计,浏览≥3 或 收藏≥2) ### 计算器 - `POST /calculator/calc` — 多房间面积+损耗+费用计算 @@ -133,7 +136,7 @@ docker compose up -d --build - `GET /articles/recommend` — 随机推荐 ### 其他 -- `POST /upload` — 通用图片上传 +- `POST /upload` — 通用图片上传(20MB) - `GET /healthz` — 健康检查 ## 数字编码 @@ -165,12 +168,34 @@ docker compose up -d --build ## 产品数据 -10 个品牌,3539 条产品,涵盖 Hardwood / Engineered Wood / Laminate / SPC/LVP / Wood-Look Tile 五大品类。 +10 个品牌,3539 条产品,覆盖 Hardwood / Engineered Wood / Laminate / SPC/LVP / Wood-Look Tile 五大品类。 -数据存储在 `data/products/*.json`,首次使用需运行 `go run cmd/import/main.go` 导入 PostgreSQL。 +数据存储在 `data/products/*.json`(不入 git),首次使用需运行 `go run cmd/import/main.go` 导入 PostgreSQL。 + +## 数据库 + +表结构统一管理在 `schema.sql`,服务启动时不再自动建表。修改表结构后更新此文件即可。 + +查询层使用 GORM + 原生 SQL 混合: +- 简单 CRUD(`GetProductBySKU`)→ GORM +- 复杂查询(动态筛选 `DISTINCT ON`、批量统计)→ 原生 SQL ## 日志 -- **格式**: `2026-07-10 16:30:01 [INFO] main.go:96 Server started` -- **存储**: `logs/app-YYYY-MM-DD.log`,每天一个文件 +- **格式**: `2026-07-10 16:30:01.234 [INFO] main.go:96 Server started` +- **存储**: `logs/app-YYYY-MM-DD.log`,每天自动切文件 - **清理**: 自动删除 30 天前的日志 +- **输出**: 同时写 stdout + 文件 + +## 缓存 + +- **热点产品缓存**: Redis sorted set 统计浏览量,Top 200 自动缓存,TTL 1h ± 10min 随机抖动防雪崩 +- **品牌浏览统计**: 自动记录(查询产品详情时触发) + +## 异步队列 + +AI 图片生成使用 Redis List 做消息队列,Worker 池消费: +- 提交任务 → RPUSH 入队 → 立即返回 `job_id` +- Worker 从 BRPOP 出队 → 调用 OpenRouter → 写入结果 +- 并发数通过 `WORKER_COUNT` 控制,默认 5 +- 进度查询: `GET /floor/status?job_id=xxx`