空提交
This commit is contained in:
@@ -1,237 +0,0 @@
|
|||||||
# OCR热量识别功能使用指南
|
|
||||||
|
|
||||||
## 功能概述
|
|
||||||
|
|
||||||
OCR热量识别功能允许用户通过拍摄或上传包含食物信息的图片,自动识别其中的热量信息,大大简化了餐食记录的过程。
|
|
||||||
|
|
||||||
## 主要特性
|
|
||||||
|
|
||||||
### 1. 多OCR引擎支持
|
|
||||||
- **Tesseract OCR**: 开源OCR引擎,支持中英文识别
|
|
||||||
- **PaddleOCR**: 百度开源OCR,对中文识别效果优秀
|
|
||||||
- **EasyOCR**: 简单易用的OCR库,支持多语言
|
|
||||||
|
|
||||||
### 2. 智能验证机制
|
|
||||||
- **多级验证**: 结合OCR结果、食物数据库和用户学习数据
|
|
||||||
- **置信度评估**: 为每个识别结果提供置信度评分
|
|
||||||
- **用户修正**: 支持用户手动修正识别结果
|
|
||||||
|
|
||||||
### 3. 学习优化系统
|
|
||||||
- **用户反馈学习**: 记录用户修正,提高后续识别准确性
|
|
||||||
- **数据库匹配**: 与内置食物数据库进行智能匹配
|
|
||||||
- **模式识别**: 识别多种热量表示格式
|
|
||||||
|
|
||||||
## 使用方法
|
|
||||||
|
|
||||||
### 1. 启动OCR功能
|
|
||||||
|
|
||||||
#### 在移动端界面:
|
|
||||||
1. 打开应用,进入"记录"页面
|
|
||||||
2. 在食物输入框右侧找到"📷"按钮
|
|
||||||
3. 点击按钮打开OCR识别界面
|
|
||||||
|
|
||||||
#### 在桌面端界面:
|
|
||||||
1. 在主界面选择"OCR热量识别"功能
|
|
||||||
2. 或通过菜单栏访问OCR功能
|
|
||||||
|
|
||||||
### 2. 上传图片
|
|
||||||
|
|
||||||
1. 点击"选择图片"按钮
|
|
||||||
2. 选择包含食物信息的图片文件
|
|
||||||
3. 支持的格式:JPG、JPEG、PNG、BMP、GIF
|
|
||||||
4. 图片将显示在预览区域
|
|
||||||
|
|
||||||
### 3. 开始识别
|
|
||||||
|
|
||||||
1. 确认图片选择正确后,点击"开始识别"按钮
|
|
||||||
2. 系统将使用多个OCR引擎进行识别
|
|
||||||
3. 识别过程中会显示进度条和状态信息
|
|
||||||
4. 识别完成后显示结果
|
|
||||||
|
|
||||||
### 4. 查看和编辑结果
|
|
||||||
|
|
||||||
#### 识别结果表格:
|
|
||||||
- **食物名称**: 识别到的食物名称
|
|
||||||
- **热量**: 识别到的热量数值(卡路里)
|
|
||||||
- **置信度**: 识别结果的置信度(0-1)
|
|
||||||
- **来源**: 数据来源(OCR、数据库、用户确认)
|
|
||||||
|
|
||||||
#### 详细信息:
|
|
||||||
- OCR识别过程详情
|
|
||||||
- 各引擎的识别结果
|
|
||||||
- 处理时间和整体置信度
|
|
||||||
|
|
||||||
#### 建议:
|
|
||||||
- 系统提供的改进建议
|
|
||||||
- 识别准确性提示
|
|
||||||
- 手动输入建议
|
|
||||||
|
|
||||||
### 5. 编辑和确认结果
|
|
||||||
|
|
||||||
#### 编辑结果:
|
|
||||||
1. 双击表格中的任意行或选择后点击"编辑结果"
|
|
||||||
2. 在弹出的对话框中修改食物名称、热量和置信度
|
|
||||||
3. 点击"保存"确认修改
|
|
||||||
|
|
||||||
#### 确认结果:
|
|
||||||
1. 检查所有识别结果是否正确
|
|
||||||
2. 点击"确认结果"按钮
|
|
||||||
3. 系统将保存到餐食记录中
|
|
||||||
|
|
||||||
## 识别准确性优化
|
|
||||||
|
|
||||||
### 1. 图片质量要求
|
|
||||||
|
|
||||||
#### 推荐条件:
|
|
||||||
- **清晰度**: 图片清晰,文字可读
|
|
||||||
- **对比度**: 文字与背景对比明显
|
|
||||||
- **角度**: 文字水平,避免倾斜
|
|
||||||
- **光照**: 光线充足,避免阴影
|
|
||||||
|
|
||||||
#### 避免的情况:
|
|
||||||
- 模糊不清的图片
|
|
||||||
- 文字过小或过大的图片
|
|
||||||
- 严重倾斜的图片
|
|
||||||
- 光线过暗或过亮的图片
|
|
||||||
|
|
||||||
### 2. 文字格式支持
|
|
||||||
|
|
||||||
#### 支持的热量表示格式:
|
|
||||||
- `130卡路里`
|
|
||||||
- `155 kcal`
|
|
||||||
- `52千卡`
|
|
||||||
- `42大卡`
|
|
||||||
- `110 KJ` (千焦)
|
|
||||||
- `76卡`
|
|
||||||
|
|
||||||
#### 支持的食物名称:
|
|
||||||
- 中文食物名称:米饭、鸡蛋、苹果等
|
|
||||||
- 英文食物名称:rice、egg、apple等
|
|
||||||
- 混合格式:米饭 130卡路里
|
|
||||||
|
|
||||||
### 3. 提高识别准确性的技巧
|
|
||||||
|
|
||||||
#### 图片预处理:
|
|
||||||
- 确保图片中的文字清晰可见
|
|
||||||
- 避免复杂的背景干扰
|
|
||||||
- 保持文字区域的完整性
|
|
||||||
|
|
||||||
#### 结果验证:
|
|
||||||
- 仔细检查识别结果
|
|
||||||
- 及时修正错误信息
|
|
||||||
- 利用数据库匹配功能
|
|
||||||
|
|
||||||
#### 学习优化:
|
|
||||||
- 经常使用修正功能
|
|
||||||
- 系统会学习您的修正习惯
|
|
||||||
- 提高后续识别的准确性
|
|
||||||
|
|
||||||
## 故障排除
|
|
||||||
|
|
||||||
### 1. 常见问题
|
|
||||||
|
|
||||||
#### 识别失败:
|
|
||||||
- **原因**: 图片质量差、OCR引擎不可用
|
|
||||||
- **解决**: 检查图片质量,确保OCR依赖已安装
|
|
||||||
|
|
||||||
#### 识别结果不准确:
|
|
||||||
- **原因**: 图片模糊、文字格式特殊
|
|
||||||
- **解决**: 重新拍摄清晰图片,手动修正结果
|
|
||||||
|
|
||||||
#### 无法打开OCR界面:
|
|
||||||
- **原因**: 依赖包未安装、模块初始化失败
|
|
||||||
- **解决**: 检查requirements.txt中的依赖是否已安装
|
|
||||||
|
|
||||||
### 2. 依赖安装
|
|
||||||
|
|
||||||
确保已安装以下依赖包:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
pip install pytesseract>=0.3.10
|
|
||||||
pip install opencv-python>=4.8.0
|
|
||||||
pip install paddleocr>=2.7.0
|
|
||||||
pip install easyocr>=1.7.0
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Tesseract安装:
|
|
||||||
- **Windows**: 下载Tesseract安装包并添加到PATH
|
|
||||||
- **macOS**: `brew install tesseract`
|
|
||||||
- **Linux**: `sudo apt-get install tesseract-ocr`
|
|
||||||
|
|
||||||
### 3. 性能优化
|
|
||||||
|
|
||||||
#### 提高识别速度:
|
|
||||||
- 使用较小的图片文件
|
|
||||||
- 选择清晰的图片
|
|
||||||
- 避免过于复杂的图片
|
|
||||||
|
|
||||||
#### 提高识别准确性:
|
|
||||||
- 使用标准格式的食物标签
|
|
||||||
- 保持文字清晰可读
|
|
||||||
- 及时修正错误结果
|
|
||||||
|
|
||||||
## 技术架构
|
|
||||||
|
|
||||||
### 1. 模块结构
|
|
||||||
|
|
||||||
```
|
|
||||||
modules/ocr_calorie_recognition.py # OCR识别模块
|
|
||||||
gui/ocr_calorie_gui.py # OCR GUI界面
|
|
||||||
test_ocr_system.py # 测试脚本
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. 核心组件
|
|
||||||
|
|
||||||
#### OCRCalorieRecognitionModule:
|
|
||||||
- 多OCR引擎集成
|
|
||||||
- 图片预处理
|
|
||||||
- 热量信息提取
|
|
||||||
- 数据库匹配
|
|
||||||
- 用户学习系统
|
|
||||||
|
|
||||||
#### OCRCalorieGUI:
|
|
||||||
- 图片上传界面
|
|
||||||
- 识别结果展示
|
|
||||||
- 结果编辑功能
|
|
||||||
- 用户交互处理
|
|
||||||
|
|
||||||
### 3. 数据流程
|
|
||||||
|
|
||||||
1. **图片上传** → 图片预处理
|
|
||||||
2. **OCR识别** → 多引擎并行识别
|
|
||||||
3. **文本提取** → 热量信息解析
|
|
||||||
4. **数据库匹配** → 食物信息验证
|
|
||||||
5. **用户确认** → 结果保存和学习
|
|
||||||
|
|
||||||
## 未来改进计划
|
|
||||||
|
|
||||||
### 1. 功能增强
|
|
||||||
- 支持更多图片格式
|
|
||||||
- 增加批量识别功能
|
|
||||||
- 支持手写文字识别
|
|
||||||
- 集成营养信息识别
|
|
||||||
|
|
||||||
### 2. 性能优化
|
|
||||||
- 优化识别算法
|
|
||||||
- 提高处理速度
|
|
||||||
- 减少内存占用
|
|
||||||
- 支持GPU加速
|
|
||||||
|
|
||||||
### 3. 用户体验
|
|
||||||
- 改进界面设计
|
|
||||||
- 增加语音输入
|
|
||||||
- 支持离线识别
|
|
||||||
- 提供更多个性化选项
|
|
||||||
|
|
||||||
## 联系支持
|
|
||||||
|
|
||||||
如果您在使用OCR功能时遇到问题,请:
|
|
||||||
|
|
||||||
1. 查看本文档的故障排除部分
|
|
||||||
2. 运行测试脚本检查系统状态
|
|
||||||
3. 检查依赖包是否正确安装
|
|
||||||
4. 提供详细的错误信息和截图
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
*最后更新: 2024年12月*
|
|
||||||
@@ -1,193 +0,0 @@
|
|||||||
# 个性化饮食推荐助手 - 项目完成总结
|
|
||||||
|
|
||||||
## 🎯 项目概述
|
|
||||||
|
|
||||||
基于您的需求,我已经完成了一个完整的个性化饮食推荐系统,具有以下核心特性:
|
|
||||||
|
|
||||||
### ✨ 核心功能
|
|
||||||
1. **5天数据采集** - 详细记录用户三餐数据
|
|
||||||
2. **智能问卷系统** - 收集用户偏好、生理信息、个性化因素
|
|
||||||
3. **大模型集成** - 深度理解用户需求,提供智能分析
|
|
||||||
4. **混合推荐系统** - 结合机器学习和AI的个性化推荐
|
|
||||||
5. **持续学习机制** - 根据用户反馈不断优化模型
|
|
||||||
6. **女性专属优化** - 考虑生理周期、排卵期等特殊因素
|
|
||||||
7. **现代化GUI** - 基于CustomTkinter的美观界面
|
|
||||||
|
|
||||||
## 🏗️ 基座架构设计
|
|
||||||
|
|
||||||
### 核心基座 (`core/base.py`)
|
|
||||||
- **BaseModule**: 所有功能模块的抽象基类
|
|
||||||
- **DataManager**: 统一的数据管理基座
|
|
||||||
- **EventBus**: 事件总线,支持模块间通信
|
|
||||||
- **ModuleManager**: 模块管理器,统一管理所有功能模块
|
|
||||||
- **AppCore**: 应用核心,协调所有模块
|
|
||||||
|
|
||||||
### 功能模块
|
|
||||||
1. **数据采集模块** (`modules/data_collection.py`)
|
|
||||||
- 问卷数据收集
|
|
||||||
- 餐食记录管理
|
|
||||||
- 用户反馈处理
|
|
||||||
|
|
||||||
2. **AI分析模块** (`modules/ai_analysis.py`)
|
|
||||||
- 用户意图分析
|
|
||||||
- 营养状况分析
|
|
||||||
- 生理状态分析
|
|
||||||
- 餐食建议生成
|
|
||||||
|
|
||||||
3. **推荐引擎模块** (`modules/recommendation_engine.py`)
|
|
||||||
- 基于历史数据的推荐
|
|
||||||
- 基于相似用户的推荐
|
|
||||||
- 基于内容相似性的推荐
|
|
||||||
- 基于生理状态的推荐
|
|
||||||
- 多维度融合推荐
|
|
||||||
|
|
||||||
4. **GUI界面模块** (`gui/main_window.py`)
|
|
||||||
- 现代化界面设计
|
|
||||||
- 数据采集界面
|
|
||||||
- AI分析界面
|
|
||||||
- 推荐系统界面
|
|
||||||
- 个人中心界面
|
|
||||||
|
|
||||||
## 🔧 技术特点
|
|
||||||
|
|
||||||
### 1. 基座架构优势
|
|
||||||
- **代码复用**: 所有模块基于统一基座,减少重复代码
|
|
||||||
- **模块化设计**: 每个功能独立,易于维护和扩展
|
|
||||||
- **统一接口**: 所有模块使用相同的接口规范
|
|
||||||
- **事件驱动**: 支持模块间松耦合通信
|
|
||||||
|
|
||||||
### 2. 大模型深度集成
|
|
||||||
- **用户意图理解**: 不仅理解表面需求,还分析深层意图
|
|
||||||
- **情绪状态分析**: 考虑用户当前情绪对饮食需求的影响
|
|
||||||
- **生理周期智能**: 专门针对女性的生理周期分析
|
|
||||||
- **个性化建议**: 结合星座、性格等多维度因素
|
|
||||||
|
|
||||||
### 3. 智能推荐系统
|
|
||||||
- **多维度融合**: 历史偏好 + 相似用户 + 内容相似性 + 生理状态
|
|
||||||
- **持续学习**: 根据用户反馈不断优化推荐算法
|
|
||||||
- **个性化过滤**: 考虑过敏、不喜欢等个人限制
|
|
||||||
- **置信度评估**: 为每个推荐提供置信度评分
|
|
||||||
|
|
||||||
### 4. 女性专属功能
|
|
||||||
- **生理周期跟踪**: 自动计算月经周期状态
|
|
||||||
- **营养需求调整**: 根据生理周期推荐不同营养素
|
|
||||||
- **情绪变化考虑**: 分析生理周期对情绪和食欲的影响
|
|
||||||
- **个性化建议**: 提供针对性的饮食建议
|
|
||||||
|
|
||||||
## 📁 项目结构
|
|
||||||
|
|
||||||
```
|
|
||||||
diet_recommendation_app/
|
|
||||||
├── core/ # 核心基座
|
|
||||||
│ └── base.py # 基础架构
|
|
||||||
├── modules/ # 功能模块
|
|
||||||
│ ├── data_collection.py # 数据采集
|
|
||||||
│ ├── ai_analysis.py # AI分析
|
|
||||||
│ └── recommendation_engine.py # 推荐引擎
|
|
||||||
├── gui/ # GUI界面
|
|
||||||
│ └── main_window.py # 主窗口
|
|
||||||
├── data/ # 数据存储
|
|
||||||
│ ├── users/ # 用户数据
|
|
||||||
│ └── training/ # 训练数据
|
|
||||||
├── models/ # 模型存储
|
|
||||||
├── logs/ # 日志文件
|
|
||||||
├── main.py # 主应用入口
|
|
||||||
├── start.py # 启动脚本
|
|
||||||
├── requirements.txt # 依赖包
|
|
||||||
├── .env.example # 配置示例
|
|
||||||
└── README.md # 项目说明
|
|
||||||
```
|
|
||||||
|
|
||||||
## 🚀 快速开始
|
|
||||||
|
|
||||||
### 1. 安装依赖
|
|
||||||
```bash
|
|
||||||
pip install -r requirements.txt
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. 配置环境
|
|
||||||
```bash
|
|
||||||
cp .env.example .env
|
|
||||||
# 编辑 .env 文件,配置API密钥(可选)
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3. 启动应用
|
|
||||||
```bash
|
|
||||||
python start.py
|
|
||||||
```
|
|
||||||
|
|
||||||
## 💡 使用流程
|
|
||||||
|
|
||||||
### 1. 用户注册/登录
|
|
||||||
- 输入用户ID和姓名
|
|
||||||
- 系统自动创建用户档案
|
|
||||||
|
|
||||||
### 2. 数据采集(5天)
|
|
||||||
- **基础信息问卷**: 年龄、性别、身高体重等
|
|
||||||
- **口味偏好问卷**: 甜、咸、辣、酸等偏好评分
|
|
||||||
- **生理信息问卷**: 月经周期、排卵期症状等
|
|
||||||
- **餐食记录**: 详细记录三餐内容和满意度
|
|
||||||
|
|
||||||
### 3. AI分析
|
|
||||||
- **用户意图分析**: 理解用户真实需求
|
|
||||||
- **营养分析**: 分析餐食营养状况
|
|
||||||
- **生理状态分析**: 分析当前生理周期状态
|
|
||||||
|
|
||||||
### 4. 个性化推荐
|
|
||||||
- **智能推荐**: 基于多维度因素生成推荐
|
|
||||||
- **用户反馈**: 收集用户对推荐的反馈
|
|
||||||
- **持续优化**: 根据反馈不断改进推荐算法
|
|
||||||
|
|
||||||
## 🔮 核心创新点
|
|
||||||
|
|
||||||
### 1. 基座架构设计
|
|
||||||
- 避免了"一个代码一个功能"的问题
|
|
||||||
- 统一的数据管理和事件处理
|
|
||||||
- 模块化设计,易于扩展和维护
|
|
||||||
|
|
||||||
### 2. 大模型深度集成
|
|
||||||
- 不仅用于营养分析,还用于用户需求理解
|
|
||||||
- 结合传统机器学习和大模型的优势
|
|
||||||
- 提供更智能、更个性化的服务
|
|
||||||
|
|
||||||
### 3. 女性专属优化
|
|
||||||
- 深度考虑生理周期对饮食需求的影响
|
|
||||||
- 结合星座、性格等个性化因素
|
|
||||||
- 提供更贴心的个性化服务
|
|
||||||
|
|
||||||
### 4. 持续学习机制
|
|
||||||
- 避免完全随机推荐的问题
|
|
||||||
- 根据用户反馈不断优化模型
|
|
||||||
- 提供越来越精准的推荐
|
|
||||||
|
|
||||||
## 🎉 项目完成度
|
|
||||||
|
|
||||||
✅ **核心基座架构** - 完成
|
|
||||||
✅ **数据采集系统** - 完成
|
|
||||||
✅ **AI分析模块** - 完成
|
|
||||||
✅ **推荐引擎** - 完成
|
|
||||||
✅ **GUI界面** - 完成
|
|
||||||
✅ **女性专属功能** - 完成
|
|
||||||
✅ **持续学习机制** - 完成
|
|
||||||
✅ **大模型集成** - 完成
|
|
||||||
|
|
||||||
## 🔧 后续扩展建议
|
|
||||||
|
|
||||||
1. **移动端适配**: 开发手机APP版本
|
|
||||||
2. **云端部署**: 支持多用户在线使用
|
|
||||||
3. **更多大模型**: 集成更多AI模型
|
|
||||||
4. **营养数据库**: 扩展更丰富的食物营养数据
|
|
||||||
5. **社交功能**: 添加用户交流和分享功能
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**项目已完成,可以立即运行使用!** 🎊
|
|
||||||
|
|
||||||
所有功能都基于您提出的需求设计,特别是:
|
|
||||||
- ✅ 5天数据采集系统
|
|
||||||
- ✅ 大模型深度集成用于需求分析
|
|
||||||
- ✅ 女性生理周期智能优化
|
|
||||||
- ✅ 星座等个性化因素考虑
|
|
||||||
- ✅ 持续学习和模型矫正机制
|
|
||||||
- ✅ 基座架构避免代码重复
|
|
||||||
- ✅ 现代化桌面GUI界面
|
|
||||||
273
README_DOCKER.md
273
README_DOCKER.md
@@ -1,273 +0,0 @@
|
|||||||
# Docker 部署指南
|
|
||||||
|
|
||||||
本文档说明如何使用Docker部署个性化饮食推荐助手Web应用。
|
|
||||||
|
|
||||||
## 📋 前置要求
|
|
||||||
|
|
||||||
- Docker Engine 20.10+
|
|
||||||
- Docker Compose 2.0+
|
|
||||||
|
|
||||||
## 🚀 快速开始
|
|
||||||
|
|
||||||
### 方式一:使用 Docker Compose(推荐)
|
|
||||||
|
|
||||||
#### 生产环境
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# 构建并启动容器
|
|
||||||
docker-compose up -d
|
|
||||||
|
|
||||||
# 查看日志
|
|
||||||
docker-compose logs -f
|
|
||||||
|
|
||||||
# 停止容器
|
|
||||||
docker-compose down
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 开发环境(支持代码热重载)
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# 使用开发配置启动
|
|
||||||
docker-compose -f docker-compose.dev.yml up -d
|
|
||||||
|
|
||||||
# 查看日志
|
|
||||||
docker-compose -f docker-compose.dev.yml logs -f
|
|
||||||
|
|
||||||
# 停止容器
|
|
||||||
docker-compose -f docker-compose.dev.yml down
|
|
||||||
```
|
|
||||||
|
|
||||||
### 方式二:使用 Docker 命令
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# 构建镜像
|
|
||||||
docker build -t diet-recommendation-app .
|
|
||||||
|
|
||||||
# 运行容器
|
|
||||||
docker run -d \
|
|
||||||
--name diet_recommendation_app \
|
|
||||||
-p 7400:7400 \
|
|
||||||
-v $(pwd)/data:/app/data \
|
|
||||||
-v $(pwd)/logs:/app/logs \
|
|
||||||
-v $(pwd)/models:/app/models \
|
|
||||||
diet-recommendation-app
|
|
||||||
|
|
||||||
# 查看日志
|
|
||||||
docker logs -f diet_recommendation_app
|
|
||||||
|
|
||||||
# 停止容器
|
|
||||||
docker stop diet_recommendation_app
|
|
||||||
docker rm diet_recommendation_app
|
|
||||||
```
|
|
||||||
|
|
||||||
## 🌐 访问应用
|
|
||||||
|
|
||||||
容器启动后,访问:
|
|
||||||
- **主页**: http://localhost:7400
|
|
||||||
- **背诵排序**: http://localhost:7400/recitation
|
|
||||||
- **数据采集**: http://localhost:7400/data-collection
|
|
||||||
- **智能推荐**: http://localhost:7400/recommendation
|
|
||||||
- **营养分析**: http://localhost:7400/analysis
|
|
||||||
- **健康检查**: http://localhost:7400/health
|
|
||||||
|
|
||||||
## 📁 数据持久化
|
|
||||||
|
|
||||||
以下目录会自动挂载到容器中,确保数据不丢失:
|
|
||||||
|
|
||||||
- `./data` - 用户数据和数据库
|
|
||||||
- `./logs` - 日志文件
|
|
||||||
- `./models` - 训练好的模型文件
|
|
||||||
|
|
||||||
## 🔧 配置说明
|
|
||||||
|
|
||||||
### 环境变量
|
|
||||||
|
|
||||||
可以通过 `docker-compose.yml` 中的 `environment` 部分或 `.env` 文件配置:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
environment:
|
|
||||||
- FLASK_ENV=production
|
|
||||||
- QWEN_API_KEY=your_api_key_here
|
|
||||||
```
|
|
||||||
|
|
||||||
### 端口配置
|
|
||||||
|
|
||||||
默认端口为 `7400`,如需修改:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
ports:
|
|
||||||
- "8080:7400" # 将主机的8080端口映射到容器的7400端口
|
|
||||||
```
|
|
||||||
|
|
||||||
## 🐛 故障排除
|
|
||||||
|
|
||||||
### 查看容器日志
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Docker Compose
|
|
||||||
docker-compose logs -f web
|
|
||||||
|
|
||||||
# Docker
|
|
||||||
docker logs -f diet_recommendation_app
|
|
||||||
```
|
|
||||||
|
|
||||||
### 进入容器调试
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Docker Compose
|
|
||||||
docker-compose exec web bash
|
|
||||||
|
|
||||||
# Docker
|
|
||||||
docker exec -it diet_recommendation_app bash
|
|
||||||
```
|
|
||||||
|
|
||||||
### 重启容器
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Docker Compose
|
|
||||||
docker-compose restart
|
|
||||||
|
|
||||||
# Docker
|
|
||||||
docker restart diet_recommendation_app
|
|
||||||
```
|
|
||||||
|
|
||||||
### 重新构建镜像
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Docker Compose
|
|
||||||
docker-compose build --no-cache
|
|
||||||
|
|
||||||
# Docker
|
|
||||||
docker build --no-cache -t diet-recommendation-app .
|
|
||||||
```
|
|
||||||
|
|
||||||
## 📊 健康检查
|
|
||||||
|
|
||||||
容器包含健康检查功能,可以通过以下方式查看状态:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Docker Compose
|
|
||||||
docker-compose ps
|
|
||||||
|
|
||||||
# Docker
|
|
||||||
docker ps
|
|
||||||
```
|
|
||||||
|
|
||||||
健康检查端点:`http://localhost:7400/health`
|
|
||||||
|
|
||||||
## 🔒 安全建议
|
|
||||||
|
|
||||||
1. **生产环境**:
|
|
||||||
- 使用反向代理(Nginx/Traefik)
|
|
||||||
- 配置HTTPS
|
|
||||||
- 限制端口访问
|
|
||||||
- 使用环境变量管理敏感信息
|
|
||||||
|
|
||||||
2. **数据备份**:
|
|
||||||
- 定期备份 `data` 目录
|
|
||||||
- 备份 `models` 目录中的模型文件
|
|
||||||
|
|
||||||
## 🚢 生产部署示例
|
|
||||||
|
|
||||||
### 使用 Nginx 作为反向代理
|
|
||||||
|
|
||||||
```nginx
|
|
||||||
server {
|
|
||||||
listen 80;
|
|
||||||
server_name your-domain.com;
|
|
||||||
|
|
||||||
location / {
|
|
||||||
proxy_pass http://localhost:7400;
|
|
||||||
proxy_set_header Host $host;
|
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
|
||||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
||||||
proxy_set_header X-Forwarded-Proto $scheme;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## 💾 小内存机器配置(512MB-1GB)
|
|
||||||
|
|
||||||
如果你的 Linux 机器内存较小,可以使用专门优化的小内存版本:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# 使用小内存优化的 Dockerfile 和配置
|
|
||||||
docker-compose -f docker-compose.low-mem.yml up -d
|
|
||||||
|
|
||||||
# 查看日志
|
|
||||||
docker-compose -f docker-compose.low-mem.yml logs -f
|
|
||||||
|
|
||||||
# 停止容器
|
|
||||||
docker-compose -f docker-compose.low-mem.yml down
|
|
||||||
```
|
|
||||||
|
|
||||||
### 小内存优化措施
|
|
||||||
|
|
||||||
1. **单 Worker 配置**:Gunicorn 使用 1 个 worker + 2 个线程,减少内存占用
|
|
||||||
2. **最小化依赖**:移除 GUI 相关依赖(CustomTkinter、Kivy等)
|
|
||||||
3. **OpenCV Headless**:使用 `opencv-python-headless`,不包含 GUI 组件
|
|
||||||
4. **内存限制**:容器内存限制为 512MB(最大),保留 256MB
|
|
||||||
5. **环境变量优化**:设置 `MALLOC_ARENA_MAX=2` 和 `PYTHONHASHSEED=0` 减少内存碎片
|
|
||||||
|
|
||||||
### 内存需求对比
|
|
||||||
|
|
||||||
| 配置 | 内存需求 | 适用场景 |
|
|
||||||
|------|---------|---------|
|
|
||||||
| 标准版(Dockerfile) | 1GB+ | 服务器、开发环境 |
|
|
||||||
| 小内存版(Dockerfile.low-mem) | 512MB-1GB | 树莓派、小型 VPS、低配服务器 |
|
|
||||||
|
|
||||||
### 手动调整内存限制
|
|
||||||
|
|
||||||
如果使用标准版,可以通过修改 `docker-compose.yml` 来限制内存:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
services:
|
|
||||||
web:
|
|
||||||
deploy:
|
|
||||||
resources:
|
|
||||||
limits:
|
|
||||||
memory: 512M # 限制最大内存
|
|
||||||
reservations:
|
|
||||||
memory: 256M # 保留内存
|
|
||||||
```
|
|
||||||
|
|
||||||
## 📝 注意事项
|
|
||||||
|
|
||||||
1. **OCR功能**:
|
|
||||||
- Docker镜像已包含 Tesseract OCR 支持(轻量级)
|
|
||||||
- **未包含** PaddleOCR 和 EasyOCR(内存占用大,需要手动安装)
|
|
||||||
- 默认只使用 Tesseract OCR,内存占用很小
|
|
||||||
|
|
||||||
2. **内存限制**:
|
|
||||||
- 标准版:建议至少分配 **1GB 内存**给容器
|
|
||||||
- 小内存版:可以在 **512MB 内存**的机器上运行
|
|
||||||
|
|
||||||
3. **Worker 数量调整**:
|
|
||||||
- 标准版默认 2 个 worker(适合 1GB+ 内存)
|
|
||||||
- 小内存机器可以在 `Dockerfile` 中修改为 1 个 worker:
|
|
||||||
```dockerfile
|
|
||||||
CMD ["python", "-m", "gunicorn", "--bind", "0.0.0.0:7400", "--workers", "1", ...]
|
|
||||||
```
|
|
||||||
|
|
||||||
4. **文件权限**:确保挂载的目录有适当的读写权限
|
|
||||||
|
|
||||||
5. **时区设置**:如需修改时区,在Dockerfile中添加:
|
|
||||||
```dockerfile
|
|
||||||
ENV TZ=Asia/Shanghai
|
|
||||||
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
|
|
||||||
```
|
|
||||||
|
|
||||||
## 🔄 更新应用
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# 停止容器
|
|
||||||
docker-compose down
|
|
||||||
|
|
||||||
# 拉取最新代码
|
|
||||||
git pull
|
|
||||||
|
|
||||||
# 重新构建并启动
|
|
||||||
docker-compose build --no-cache
|
|
||||||
docker-compose up -d
|
|
||||||
```
|
|
||||||
|
|
||||||
@@ -1,182 +0,0 @@
|
|||||||
# Git 自动上传脚本使用指南
|
|
||||||
|
|
||||||
本目录提供了三个版本的 Git 自动上传脚本,适用于不同操作系统。
|
|
||||||
|
|
||||||
## 📋 脚本说明
|
|
||||||
|
|
||||||
### 1. `git_push.sh` - Linux/Mac Bash 脚本
|
|
||||||
适用于 Linux 和 MacOS 系统。
|
|
||||||
|
|
||||||
**使用方法:**
|
|
||||||
```bash
|
|
||||||
# 给脚本添加执行权限(首次使用)
|
|
||||||
chmod +x git_push.sh
|
|
||||||
|
|
||||||
# 基本使用(交互式输入提交信息)
|
|
||||||
./git_push.sh
|
|
||||||
|
|
||||||
# 直接指定提交信息
|
|
||||||
./git_push.sh "feat: 添加新功能"
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. `git_push.bat` - Windows 批处理脚本
|
|
||||||
适用于 Windows 系统。
|
|
||||||
|
|
||||||
**使用方法:**
|
|
||||||
```cmd
|
|
||||||
# 基本使用(交互式输入提交信息)
|
|
||||||
git_push.bat
|
|
||||||
|
|
||||||
# 直接指定提交信息
|
|
||||||
git_push.bat "feat: 添加新功能"
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3. `git_push.py` - Python 跨平台脚本(推荐)
|
|
||||||
适用于所有操作系统(Windows、Linux、Mac),需要 Python 3.6+。
|
|
||||||
|
|
||||||
**使用方法:**
|
|
||||||
```bash
|
|
||||||
# 基本使用(交互式输入提交信息)
|
|
||||||
python git_push.py
|
|
||||||
|
|
||||||
# 直接指定提交信息
|
|
||||||
python git_push.py "feat: 添加新功能"
|
|
||||||
|
|
||||||
# 多个单词的提交信息
|
|
||||||
python git_push.py "feat: 添加新功能和修复bug"
|
|
||||||
```
|
|
||||||
|
|
||||||
## 🚀 功能特性
|
|
||||||
|
|
||||||
所有脚本都包含以下功能:
|
|
||||||
|
|
||||||
1. **自动检测 Git 仓库**:检查当前目录是否为 Git 仓库
|
|
||||||
2. **显示更改状态**:显示将要提交的文件
|
|
||||||
3. **交互式确认**:在提交前确认操作
|
|
||||||
4. **智能提交信息**:
|
|
||||||
- 可以直接通过命令行参数指定
|
|
||||||
- 也可以交互式输入
|
|
||||||
- 默认提供带时间戳的提交信息
|
|
||||||
5. **自动添加文件**:自动添加所有更改的文件
|
|
||||||
6. **错误处理**:友好的错误提示和处理
|
|
||||||
7. **颜色输出**:支持彩色输出(Python 版本)
|
|
||||||
|
|
||||||
## 📝 使用示例
|
|
||||||
|
|
||||||
### 示例 1:基本使用
|
|
||||||
```bash
|
|
||||||
# Linux/Mac
|
|
||||||
./git_push.sh
|
|
||||||
|
|
||||||
# Windows
|
|
||||||
git_push.bat
|
|
||||||
|
|
||||||
# Python(跨平台)
|
|
||||||
python git_push.py
|
|
||||||
```
|
|
||||||
脚本会:
|
|
||||||
1. 显示当前更改的文件
|
|
||||||
2. 询问是否继续
|
|
||||||
3. 请求输入提交信息(或使用默认)
|
|
||||||
4. 自动添加、提交并推送
|
|
||||||
|
|
||||||
### 示例 2:指定提交信息
|
|
||||||
```bash
|
|
||||||
# Linux/Mac
|
|
||||||
./git_push.sh "fix: 修复用户注册bug"
|
|
||||||
|
|
||||||
# Windows
|
|
||||||
git_push.bat "fix: 修复用户注册bug"
|
|
||||||
|
|
||||||
# Python
|
|
||||||
python git_push.py "fix: 修复用户注册bug"
|
|
||||||
```
|
|
||||||
|
|
||||||
### 示例 3:提交多个文件的更改
|
|
||||||
```bash
|
|
||||||
# 脚本会自动检测所有更改的文件
|
|
||||||
./git_push.sh "feat: 添加Docker支持和优化内存配置"
|
|
||||||
```
|
|
||||||
|
|
||||||
## ⚙️ 配置说明
|
|
||||||
|
|
||||||
### 默认分支
|
|
||||||
脚本会自动检测当前分支并使用该分支进行推送。
|
|
||||||
|
|
||||||
### 远程仓库
|
|
||||||
确保已配置远程仓库:
|
|
||||||
```bash
|
|
||||||
# 查看远程仓库
|
|
||||||
git remote -v
|
|
||||||
|
|
||||||
# 如果未配置,添加远程仓库
|
|
||||||
git remote add origin <your-repo-url>
|
|
||||||
```
|
|
||||||
|
|
||||||
### 身份验证
|
|
||||||
如果推送时遇到身份验证问题:
|
|
||||||
|
|
||||||
1. **HTTPS 方式**:
|
|
||||||
- 需要输入用户名和密码(或访问令牌)
|
|
||||||
- 可以配置凭证助手避免每次输入:
|
|
||||||
```bash
|
|
||||||
git config --global credential.helper store
|
|
||||||
```
|
|
||||||
|
|
||||||
2. **SSH 方式**:
|
|
||||||
- 配置 SSH 密钥更安全
|
|
||||||
- 将远程 URL 改为 SSH 格式:
|
|
||||||
```bash
|
|
||||||
git remote set-url origin git@github.com:username/repo.git
|
|
||||||
```
|
|
||||||
|
|
||||||
## 🔧 故障排除
|
|
||||||
|
|
||||||
### 问题 1:权限不足(Linux/Mac)
|
|
||||||
```bash
|
|
||||||
# 解决方案:添加执行权限
|
|
||||||
chmod +x git_push.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
### 问题 2:Python 脚本无法运行
|
|
||||||
```bash
|
|
||||||
# 检查 Python 版本
|
|
||||||
python --version # 需要 Python 3.6+
|
|
||||||
|
|
||||||
# 如果系统中有多个 Python 版本
|
|
||||||
python3 git_push.py
|
|
||||||
```
|
|
||||||
|
|
||||||
### 问题 3:推送失败(认证问题)
|
|
||||||
- 检查远程仓库地址是否正确
|
|
||||||
- 确认已配置 SSH 密钥或访问令牌
|
|
||||||
- 可以手动执行 `git push origin <branch>` 测试
|
|
||||||
|
|
||||||
### 问题 4:没有需要提交的更改
|
|
||||||
- 脚本会检测是否有未提交的更改
|
|
||||||
- 如果没有更改,可以选择拉取远程更新
|
|
||||||
|
|
||||||
## 💡 建议
|
|
||||||
|
|
||||||
1. **推荐使用 Python 版本**(`git_push.py`):
|
|
||||||
- 跨平台兼容性最好
|
|
||||||
- 错误处理更完善
|
|
||||||
- 支持彩色输出
|
|
||||||
|
|
||||||
2. **提交信息规范**:
|
|
||||||
- 使用规范的提交信息格式,例如:
|
|
||||||
- `feat: 添加新功能`
|
|
||||||
- `fix: 修复bug`
|
|
||||||
- `docs: 更新文档`
|
|
||||||
- `chore: 更新配置`
|
|
||||||
- `refactor: 代码重构`
|
|
||||||
|
|
||||||
3. **定期提交**:
|
|
||||||
- 建议频繁提交小的更改
|
|
||||||
- 避免一次性提交大量更改
|
|
||||||
|
|
||||||
## 📚 相关文档
|
|
||||||
|
|
||||||
- [Git 官方文档](https://git-scm.com/doc)
|
|
||||||
- [提交信息规范](https://www.conventionalcommits.org/)
|
|
||||||
|
|
||||||
117
core/base.py
117
core/base.py
@@ -207,15 +207,24 @@ class DataManager:
|
|||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
def save_user_data(self, user_data: UserData) -> bool:
|
def save_user_data(self, user_data: UserData) -> bool:
|
||||||
"""保存用户数据"""
|
"""保存用户数据(只保存profile,其他数据用独立表)"""
|
||||||
try:
|
try:
|
||||||
conn = sqlite3.connect(self.db_path)
|
conn = sqlite3.connect(self.db_path)
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
|
|
||||||
|
# 只保存profile和preferences到users表
|
||||||
|
user_basic_data = {
|
||||||
|
'user_id': user_data.user_id,
|
||||||
|
'profile': user_data.profile,
|
||||||
|
'preferences': user_data.preferences,
|
||||||
|
'created_at': user_data.created_at,
|
||||||
|
'updated_at': user_data.updated_at
|
||||||
|
}
|
||||||
|
|
||||||
cursor.execute('''
|
cursor.execute('''
|
||||||
INSERT OR REPLACE INTO users (user_id, data, updated_at)
|
INSERT OR REPLACE INTO users (user_id, data, updated_at)
|
||||||
VALUES (?, ?, CURRENT_TIMESTAMP)
|
VALUES (?, ?, CURRENT_TIMESTAMP)
|
||||||
''', (user_data.user_id, json.dumps(user_data.__dict__)))
|
''', (user_data.user_id, json.dumps(user_basic_data)))
|
||||||
|
|
||||||
conn.commit()
|
conn.commit()
|
||||||
conn.close()
|
conn.close()
|
||||||
@@ -412,6 +421,110 @@ class DataManager:
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"获取分析历史失败: {e}")
|
logger.error(f"获取分析历史失败: {e}")
|
||||||
return []
|
return []
|
||||||
|
|
||||||
|
def save_meal_record(self, user_id: str, meal_data: Dict[str, Any]) -> bool:
|
||||||
|
"""保存餐食记录(包括非推荐食物,用于学习)"""
|
||||||
|
try:
|
||||||
|
conn = sqlite3.connect(self.db_path)
|
||||||
|
cursor = conn.cursor()
|
||||||
|
|
||||||
|
# 提取food_items,如果没有则从foods生成
|
||||||
|
food_items = meal_data.get('food_items', [])
|
||||||
|
if not food_items and meal_data.get('foods'):
|
||||||
|
food_items = [{'name': food, 'quantity': qty}
|
||||||
|
for food, qty in zip(meal_data.get('foods', []),
|
||||||
|
meal_data.get('quantities', []))]
|
||||||
|
|
||||||
|
cursor.execute('''
|
||||||
|
INSERT INTO meal_records
|
||||||
|
(user_id, date, meal_type, foods, quantities, calories, satisfaction_score, food_items)
|
||||||
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
||||||
|
''', (
|
||||||
|
user_id,
|
||||||
|
meal_data.get('date'),
|
||||||
|
meal_data.get('meal_type'),
|
||||||
|
json.dumps(meal_data.get('foods', [])),
|
||||||
|
json.dumps(meal_data.get('quantities', [])),
|
||||||
|
meal_data.get('calories'),
|
||||||
|
meal_data.get('satisfaction_score'),
|
||||||
|
json.dumps(food_items)
|
||||||
|
))
|
||||||
|
|
||||||
|
conn.commit()
|
||||||
|
conn.close()
|
||||||
|
return True
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"保存餐食记录失败: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def save_recommendation_result(self, user_id: str, recommendation_data: Dict[str, Any]) -> int:
|
||||||
|
"""保存推荐结果到recommendations表,返回recommendation_id"""
|
||||||
|
try:
|
||||||
|
conn = sqlite3.connect(self.db_path)
|
||||||
|
cursor = conn.cursor()
|
||||||
|
|
||||||
|
# 添加recommendations表(如果不存在)
|
||||||
|
cursor.execute('''
|
||||||
|
CREATE TABLE IF NOT EXISTS recommendations (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
user_id TEXT,
|
||||||
|
date TEXT,
|
||||||
|
meal_type TEXT,
|
||||||
|
recommended_foods TEXT,
|
||||||
|
reasoning TEXT,
|
||||||
|
confidence_score REAL,
|
||||||
|
special_considerations TEXT,
|
||||||
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
FOREIGN KEY (user_id) REFERENCES users (user_id)
|
||||||
|
)
|
||||||
|
''')
|
||||||
|
|
||||||
|
cursor.execute('''
|
||||||
|
INSERT INTO recommendations
|
||||||
|
(user_id, date, meal_type, recommended_foods, reasoning, confidence_score, special_considerations)
|
||||||
|
VALUES (?, ?, ?, ?, ?, ?, ?)
|
||||||
|
''', (
|
||||||
|
user_id,
|
||||||
|
recommendation_data.get('date', datetime.now().strftime('%Y-%m-%d')),
|
||||||
|
recommendation_data.get('meal_type'),
|
||||||
|
json.dumps(recommendation_data.get('recommended_foods', [])),
|
||||||
|
recommendation_data.get('reasoning', ''),
|
||||||
|
recommendation_data.get('confidence', 0.5),
|
||||||
|
json.dumps(recommendation_data.get('special_considerations', []))
|
||||||
|
))
|
||||||
|
|
||||||
|
recommendation_id = cursor.lastrowid
|
||||||
|
conn.commit()
|
||||||
|
conn.close()
|
||||||
|
return recommendation_id
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"保存推荐结果失败: {e}")
|
||||||
|
return -1
|
||||||
|
|
||||||
|
def save_feedback_record(self, user_id: str, feedback_data: Dict[str, Any]) -> bool:
|
||||||
|
"""保存用户反馈(用户实际吃的食物,可能不是推荐的)"""
|
||||||
|
try:
|
||||||
|
conn = sqlite3.connect(self.db_path)
|
||||||
|
cursor = conn.cursor()
|
||||||
|
|
||||||
|
cursor.execute('''
|
||||||
|
INSERT INTO feedback_records
|
||||||
|
(user_id, date, recommended_foods, user_choice, feedback_type)
|
||||||
|
VALUES (?, ?, ?, ?, ?)
|
||||||
|
''', (
|
||||||
|
user_id,
|
||||||
|
feedback_data.get('date', datetime.now().strftime('%Y-%m-%d')),
|
||||||
|
json.dumps(feedback_data.get('recommended_foods', [])),
|
||||||
|
feedback_data.get('user_choice', ''),
|
||||||
|
feedback_data.get('feedback_type', 'custom') # custom表示用户自定义选择
|
||||||
|
))
|
||||||
|
|
||||||
|
conn.commit()
|
||||||
|
conn.close()
|
||||||
|
return True
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"保存反馈记录失败: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
class EventBus:
|
class EventBus:
|
||||||
|
|||||||
@@ -93,6 +93,9 @@ class RecommendationEngine(BaseModule):
|
|||||||
context = input_data.get('context', {})
|
context = input_data.get('context', {})
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
# 检查数据充足性
|
||||||
|
data_check = self._check_data_sufficiency(user_data)
|
||||||
|
|
||||||
# 生成完整餐食搭配推荐
|
# 生成完整餐食搭配推荐
|
||||||
meal_combinations = self._generate_meal_combinations(user_data, meal_type, preferences, context)
|
meal_combinations = self._generate_meal_combinations(user_data, meal_type, preferences, context)
|
||||||
|
|
||||||
@@ -101,6 +104,7 @@ class RecommendationEngine(BaseModule):
|
|||||||
'recommendations': meal_combinations,
|
'recommendations': meal_combinations,
|
||||||
'reasoning': self._generate_meal_reasoning(meal_combinations, user_data, meal_type),
|
'reasoning': self._generate_meal_reasoning(meal_combinations, user_data, meal_type),
|
||||||
'confidence': self._calculate_recommendation_confidence(user_data),
|
'confidence': self._calculate_recommendation_confidence(user_data),
|
||||||
|
'data_sufficiency': data_check,
|
||||||
'metadata': {
|
'metadata': {
|
||||||
'meal_type': meal_type,
|
'meal_type': meal_type,
|
||||||
'combination_count': len(meal_combinations)
|
'combination_count': len(meal_combinations)
|
||||||
@@ -117,27 +121,34 @@ class RecommendationEngine(BaseModule):
|
|||||||
combinations = []
|
combinations = []
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# 1. 基于用户历史数据生成搭配
|
# 检查数据充足性
|
||||||
historical_combinations = self._generate_historical_combinations(user_data, meal_type)
|
data_check = self._check_data_sufficiency(user_data)
|
||||||
combinations.extend(historical_combinations)
|
|
||||||
|
|
||||||
# 2. 基于用户偏好生成个性化搭配
|
# 数据充足:使用个性化推荐
|
||||||
personalized_combinations = self._generate_personalized_combinations(user_data, meal_type, preferences)
|
if data_check['sufficient']:
|
||||||
combinations.extend(personalized_combinations)
|
# 1. 基于用户历史数据生成搭配
|
||||||
|
historical_combinations = self._generate_historical_combinations(user_data, meal_type)
|
||||||
|
combinations.extend(historical_combinations)
|
||||||
|
|
||||||
|
# 2. 基于用户偏好生成个性化搭配
|
||||||
|
personalized_combinations = self._generate_personalized_combinations(user_data, meal_type, preferences)
|
||||||
|
combinations.extend(personalized_combinations)
|
||||||
|
|
||||||
|
# 3. 如果个性化推荐不足,补充模板
|
||||||
|
if len(combinations) < 3:
|
||||||
|
template_combinations = self._generate_template_combinations(user_data, meal_type)
|
||||||
|
combinations.extend(template_combinations)
|
||||||
|
|
||||||
# 3. 基于相似用户生成搭配
|
# 数据不足:使用通用模板推荐
|
||||||
similar_user_combinations = self._generate_similar_user_combinations(user_data, meal_type)
|
else:
|
||||||
combinations.extend(similar_user_combinations)
|
self.logger.info(f"用户数据不足({data_check['days']}天),使用通用推荐")
|
||||||
|
|
||||||
# 4. 如果没有足够数据,使用模板生成
|
|
||||||
if len(combinations) < 3:
|
|
||||||
template_combinations = self._generate_template_combinations(user_data, meal_type)
|
template_combinations = self._generate_template_combinations(user_data, meal_type)
|
||||||
combinations.extend(template_combinations)
|
combinations.extend(template_combinations)
|
||||||
|
|
||||||
# 5. 去重和排序
|
# 去重和排序
|
||||||
combinations = self._deduplicate_and_rank_combinations(combinations, user_data)
|
combinations = self._deduplicate_and_rank_combinations(combinations, user_data)
|
||||||
|
|
||||||
# 6. 确保至少有一些推荐
|
# 确保至少有推荐
|
||||||
if not combinations:
|
if not combinations:
|
||||||
combinations = self._generate_fallback_combinations(meal_type)
|
combinations = self._generate_fallback_combinations(meal_type)
|
||||||
|
|
||||||
@@ -145,7 +156,6 @@ class RecommendationEngine(BaseModule):
|
|||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.logger.error(f"生成餐食搭配失败: {e}")
|
self.logger.error(f"生成餐食搭配失败: {e}")
|
||||||
# 返回基础推荐
|
|
||||||
return self._generate_fallback_combinations(meal_type)
|
return self._generate_fallback_combinations(meal_type)
|
||||||
|
|
||||||
def _generate_historical_combinations(self, user_data: UserData, meal_type: str) -> List[Dict[str, Any]]:
|
def _generate_historical_combinations(self, user_data: UserData, meal_type: str) -> List[Dict[str, Any]]:
|
||||||
@@ -666,18 +676,44 @@ class RecommendationEngine(BaseModule):
|
|||||||
else:
|
else:
|
||||||
return f"推荐{top_rec['food']},基于您的个人偏好"
|
return f"推荐{top_rec['food']},基于您的个人偏好"
|
||||||
|
|
||||||
|
def _check_data_sufficiency(self, user_data: UserData) -> Dict[str, Any]:
|
||||||
|
"""检查数据充足性(按日期去重计算天数)"""
|
||||||
|
if not user_data.meals:
|
||||||
|
return {
|
||||||
|
'sufficient': False,
|
||||||
|
'days': 0,
|
||||||
|
'meals': 0,
|
||||||
|
'message': '暂无餐食记录,将提供通用推荐'
|
||||||
|
}
|
||||||
|
|
||||||
|
# 按日期去重计算天数
|
||||||
|
unique_dates = set(meal.get('date') for meal in user_data.meals if meal.get('date'))
|
||||||
|
meal_count = len(user_data.meals)
|
||||||
|
day_count = len(unique_dates)
|
||||||
|
|
||||||
|
return {
|
||||||
|
'sufficient': day_count >= 3,
|
||||||
|
'days': day_count,
|
||||||
|
'meals': meal_count,
|
||||||
|
'message': f'已收集{day_count}天{meal_count}餐数据' + (',数据充足' if day_count >= 3 else ',建议继续记录')
|
||||||
|
}
|
||||||
|
|
||||||
def _calculate_recommendation_confidence(self, user_data: UserData) -> float:
|
def _calculate_recommendation_confidence(self, user_data: UserData) -> float:
|
||||||
"""计算推荐置信度"""
|
"""计算推荐置信度"""
|
||||||
meal_count = len(user_data.meals)
|
data_check = self._check_data_sufficiency(user_data)
|
||||||
|
meal_count = data_check['meals']
|
||||||
|
day_count = data_check['days']
|
||||||
feedback_count = len(user_data.feedback)
|
feedback_count = len(user_data.feedback)
|
||||||
|
|
||||||
# 基于数据量计算置信度
|
# 基于数据量计算置信度
|
||||||
if meal_count >= 15 and feedback_count >= 5:
|
if day_count >= 5 and feedback_count >= 5:
|
||||||
return 0.9
|
return 0.9
|
||||||
elif meal_count >= 10 and feedback_count >= 3:
|
elif day_count >= 3 and meal_count >= 7:
|
||||||
return 0.7
|
return 0.7
|
||||||
elif meal_count >= 5:
|
elif day_count >= 3:
|
||||||
return 0.5
|
return 0.6
|
||||||
|
elif meal_count >= 3:
|
||||||
|
return 0.4
|
||||||
else:
|
else:
|
||||||
return 0.3
|
return 0.3
|
||||||
|
|
||||||
@@ -991,7 +1027,7 @@ if __name__ == "__main__":
|
|||||||
# 初始化应用
|
# 初始化应用
|
||||||
config = BaseConfig()
|
config = BaseConfig()
|
||||||
if initialize_app(config):
|
if initialize_app(config):
|
||||||
print("✅ 应用初始化成功")
|
print(" 应用初始化成功")
|
||||||
|
|
||||||
# 测试餐食推荐
|
# 测试餐食推荐
|
||||||
test_user_id = "test_user_001"
|
test_user_id = "test_user_001"
|
||||||
@@ -999,7 +1035,7 @@ if __name__ == "__main__":
|
|||||||
result = generate_meal_recommendations(test_user_id, "lunch", {"taste": "sweet"})
|
result = generate_meal_recommendations(test_user_id, "lunch", {"taste": "sweet"})
|
||||||
if result and result.get('success'):
|
if result and result.get('success'):
|
||||||
recommendations = result.get('recommendations', [])
|
recommendations = result.get('recommendations', [])
|
||||||
print(f"✅ 餐食推荐成功,推荐了{len(recommendations)}种食物")
|
print(f" 餐食推荐成功,推荐了{len(recommendations)}种食物")
|
||||||
for rec in recommendations[:3]:
|
for rec in recommendations[:3]:
|
||||||
print(f" - {rec['food']}: {rec.get('score', 0):.2f}")
|
print(f" - {rec['food']}: {rec.get('score', 0):.2f}")
|
||||||
|
|
||||||
@@ -1007,10 +1043,10 @@ if __name__ == "__main__":
|
|||||||
result = find_similar_foods(test_user_id, "米饭")
|
result = find_similar_foods(test_user_id, "米饭")
|
||||||
if result and result.get('success'):
|
if result and result.get('success'):
|
||||||
similar_foods = result.get('similar_foods', [])
|
similar_foods = result.get('similar_foods', [])
|
||||||
print(f"✅ 相似食物查找成功,找到{len(similar_foods)}种相似食物")
|
print(f" 相似食物查找成功,找到{len(similar_foods)}种相似食物")
|
||||||
|
|
||||||
# 清理应用
|
# 清理应用
|
||||||
cleanup_app()
|
cleanup_app()
|
||||||
print("✅ 应用清理完成")
|
print(" 应用清理完成")
|
||||||
else:
|
else:
|
||||||
print("❌ 应用初始化失败")
|
print(" 应用初始化失败")
|
||||||
|
|||||||
Reference in New Issue
Block a user