优化注册功能
This commit is contained in:
@@ -44,4 +44,6 @@ HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
|
||||
CMD python -c "import requests; requests.get('http://localhost:5000/health')" || exit 1
|
||||
|
||||
# 使用gunicorn启动应用(生产环境)
|
||||
# 注意:默认配置使用2个worker,适合1GB+内存的机器
|
||||
# 如果机器内存较小(512MB-1GB),建议修改为 "--workers", "1"
|
||||
CMD ["gunicorn", "--bind", "0.0.0.0:5000", "--workers", "2", "--timeout", "120", "--access-logfile", "-", "--error-logfile", "-", "web_app:app"]
|
||||
|
||||
63
Dockerfile.low-mem
Normal file
63
Dockerfile.low-mem
Normal file
@@ -0,0 +1,63 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# 小内存优化版 Dockerfile(适用于 512MB-1GB 内存的 Linux 机器)
|
||||
FROM python:3-slim
|
||||
|
||||
# 设置工作目录
|
||||
WORKDIR /app
|
||||
|
||||
# 设置环境变量(优化内存使用)
|
||||
ENV PYTHONUNBUFFERED=1 \
|
||||
PYTHONDONTWRITEBYTECODE=1 \
|
||||
FLASK_APP=web_app.py \
|
||||
FLASK_ENV=production \
|
||||
PYTHONHASHSEED=0 \
|
||||
MALLOC_ARENA_MAX=2
|
||||
|
||||
# 安装系统依赖(最小化安装)
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
tesseract-ocr \
|
||||
tesseract-ocr-chi-sim \
|
||||
tesseract-ocr-eng \
|
||||
&& rm -rf /var/lib/apt/lists/* \
|
||||
&& apt-get clean
|
||||
|
||||
# 复制requirements文件
|
||||
COPY requirements.txt .
|
||||
|
||||
# 创建最小化的 requirements.txt(移除GUI相关依赖)
|
||||
RUN echo "scikit-learn>=1.3.0" > requirements-minimal.txt && \
|
||||
echo "pandas>=2.0.0" >> requirements-minimal.txt && \
|
||||
echo "numpy>=1.24.0" >> requirements-minimal.txt && \
|
||||
echo "joblib>=1.3.0" >> requirements-minimal.txt && \
|
||||
echo "requests>=2.31.0" >> requirements-minimal.txt && \
|
||||
echo "python-dotenv>=1.0.0" >> requirements-minimal.txt && \
|
||||
echo "python-dateutil>=2.8.0" >> requirements-minimal.txt && \
|
||||
echo "Pillow>=10.0.0" >> requirements-minimal.txt && \
|
||||
echo "pytesseract>=0.3.10" >> requirements-minimal.txt && \
|
||||
echo "opencv-python-headless>=4.8.0" >> requirements-minimal.txt && \
|
||||
echo "Flask>=3.0.0" >> requirements-minimal.txt && \
|
||||
echo "Werkzeug>=3.0.0" >> requirements-minimal.txt && \
|
||||
echo "gunicorn" >> requirements-minimal.txt
|
||||
|
||||
# 安装Python依赖(使用最小化依赖,opencv使用headless版本)
|
||||
RUN pip install --no-cache-dir -r requirements-minimal.txt
|
||||
|
||||
# 复制应用代码
|
||||
COPY . .
|
||||
|
||||
# 创建必要的目录
|
||||
RUN mkdir -p templates static/css static/js logs data models
|
||||
|
||||
# 设置权限
|
||||
RUN chmod +x start_web.py
|
||||
|
||||
# 暴露端口
|
||||
EXPOSE 5000
|
||||
|
||||
# 健康检查(不使用 requests,直接用 Python)
|
||||
HEALTHCHECK --interval=30s --timeout=10s --start-period=10s --retries=3 \
|
||||
CMD python -c "import urllib.request; urllib.request.urlopen('http://localhost:5000/health').read()" || exit 1
|
||||
|
||||
# 使用gunicorn启动应用(小内存配置:单worker,减少内存占用)
|
||||
CMD ["gunicorn", "--bind", "0.0.0.0:5000", "--workers", "1", "--threads", "2", "--timeout", "120", "--worker-class", "sync", "--max-requests", "1000", "--max-requests-jitter", "100", "--preload", "--access-logfile", "-", "--error-logfile", "-", "web_app:app"]
|
||||
|
||||
@@ -186,12 +186,72 @@ server {
|
||||
}
|
||||
```
|
||||
|
||||
## 💾 小内存机器配置(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支持
|
||||
2. **内存限制**:建议至少分配1GB内存给容器
|
||||
3. **文件权限**:确保挂载的目录有适当的读写权限
|
||||
4. **时区设置**:如需修改时区,在Dockerfile中添加:
|
||||
1. **OCR功能**:
|
||||
- Docker镜像已包含 Tesseract OCR 支持(轻量级)
|
||||
- **未包含** PaddleOCR 和 EasyOCR(内存占用大,需要手动安装)
|
||||
- 默认只使用 Tesseract OCR,内存占用很小
|
||||
|
||||
2. **内存限制**:
|
||||
- 标准版:建议至少分配 **1GB 内存**给容器
|
||||
- 小内存版:可以在 **512MB 内存**的机器上运行
|
||||
|
||||
3. **Worker 数量调整**:
|
||||
- 标准版默认 2 个 worker(适合 1GB+ 内存)
|
||||
- 小内存机器可以在 `Dockerfile` 中修改为 1 个 worker:
|
||||
```dockerfile
|
||||
CMD ["gunicorn", "--bind", "0.0.0.0:5000", "--workers", "1", ...]
|
||||
```
|
||||
|
||||
4. **文件权限**:确保挂载的目录有适当的读写权限
|
||||
|
||||
5. **时区设置**:如需修改时区,在Dockerfile中添加:
|
||||
```dockerfile
|
||||
ENV TZ=Asia/Shanghai
|
||||
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
|
||||
|
||||
182
README_GIT_PUSH.md
Normal file
182
README_GIT_PUSH.md
Normal file
@@ -0,0 +1,182 @@
|
||||
# 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/)
|
||||
|
||||
169
core/base.py
169
core/base.py
@@ -135,6 +135,50 @@ class DataManager:
|
||||
)
|
||||
''')
|
||||
|
||||
# 餐食记录表
|
||||
cursor.execute('''
|
||||
CREATE TABLE IF NOT EXISTS meal_records (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
user_id TEXT,
|
||||
date TEXT,
|
||||
meal_type TEXT,
|
||||
foods TEXT,
|
||||
quantities TEXT,
|
||||
calories REAL,
|
||||
satisfaction_score INTEGER,
|
||||
food_items TEXT,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (user_id) REFERENCES users (user_id)
|
||||
)
|
||||
''')
|
||||
|
||||
# 反馈记录表
|
||||
cursor.execute('''
|
||||
CREATE TABLE IF NOT EXISTS feedback_records (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
user_id TEXT,
|
||||
date TEXT,
|
||||
recommended_foods TEXT,
|
||||
user_choice TEXT,
|
||||
feedback_type TEXT,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (user_id) REFERENCES users (user_id)
|
||||
)
|
||||
''')
|
||||
|
||||
# 问卷记录表
|
||||
cursor.execute('''
|
||||
CREATE TABLE IF NOT EXISTS questionnaire_records (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
user_id TEXT,
|
||||
questionnaire_type TEXT,
|
||||
answers TEXT,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (user_id) REFERENCES users (user_id),
|
||||
UNIQUE(user_id, questionnaire_type)
|
||||
)
|
||||
''')
|
||||
|
||||
# 分析结果表
|
||||
cursor.execute('''
|
||||
CREATE TABLE IF NOT EXISTS analysis_results (
|
||||
@@ -195,66 +239,95 @@ class DataManager:
|
||||
return None
|
||||
|
||||
# 解析用户基本信息
|
||||
data_dict = json.loads(result[0])
|
||||
try:
|
||||
data_dict = json.loads(result[0])
|
||||
except json.JSONDecodeError as e:
|
||||
logger.error(f"解析用户数据JSON失败: user_id={user_id}, error={e}")
|
||||
conn.close()
|
||||
return None
|
||||
|
||||
# 获取餐食记录
|
||||
cursor.execute('''
|
||||
SELECT date, meal_type, foods, quantities, calories, satisfaction_score, food_items
|
||||
FROM meal_records
|
||||
WHERE user_id = ?
|
||||
ORDER BY date DESC
|
||||
''', (user_id,))
|
||||
|
||||
meal_rows = cursor.fetchall()
|
||||
# 获取餐食记录(如果表存在)
|
||||
meals = []
|
||||
for row in meal_rows:
|
||||
meal = {
|
||||
'date': row[0],
|
||||
'meal_type': row[1],
|
||||
'foods': json.loads(row[2]) if row[2] else [],
|
||||
'quantities': json.loads(row[3]) if row[3] else [],
|
||||
'calories': row[4],
|
||||
'satisfaction_score': row[5],
|
||||
'food_items': json.loads(row[6]) if row[6] else []
|
||||
}
|
||||
meals.append(meal)
|
||||
try:
|
||||
cursor.execute('''
|
||||
SELECT date, meal_type, foods, quantities, calories, satisfaction_score, food_items
|
||||
FROM meal_records
|
||||
WHERE user_id = ?
|
||||
ORDER BY date DESC
|
||||
''', (user_id,))
|
||||
|
||||
# 获取反馈记录
|
||||
cursor.execute('''
|
||||
SELECT date, recommended_foods, user_choice, feedback_type
|
||||
FROM feedback_records
|
||||
WHERE user_id = ?
|
||||
ORDER BY date DESC
|
||||
''', (user_id,))
|
||||
meal_rows = cursor.fetchall()
|
||||
for row in meal_rows:
|
||||
try:
|
||||
meal = {
|
||||
'date': row[0],
|
||||
'meal_type': row[1],
|
||||
'foods': json.loads(row[2]) if row[2] else [],
|
||||
'quantities': json.loads(row[3]) if row[3] else [],
|
||||
'calories': row[4],
|
||||
'satisfaction_score': row[5],
|
||||
'food_items': json.loads(row[6]) if row[6] else []
|
||||
}
|
||||
meals.append(meal)
|
||||
except (json.JSONDecodeError, IndexError) as e:
|
||||
logger.warning(f"解析餐食记录失败: {e}")
|
||||
continue
|
||||
except sqlite3.OperationalError as e:
|
||||
# 表不存在,跳过
|
||||
logger.warning(f"meal_records表不存在,跳过: {e}")
|
||||
|
||||
feedback_rows = cursor.fetchall()
|
||||
# 获取反馈记录(如果表存在)
|
||||
feedback = []
|
||||
for row in feedback_rows:
|
||||
fb = {
|
||||
'date': row[0],
|
||||
'recommended_foods': json.loads(row[1]) if row[1] else [],
|
||||
'user_choice': row[2],
|
||||
'feedback_type': row[3]
|
||||
}
|
||||
feedback.append(fb)
|
||||
try:
|
||||
cursor.execute('''
|
||||
SELECT date, recommended_foods, user_choice, feedback_type
|
||||
FROM feedback_records
|
||||
WHERE user_id = ?
|
||||
ORDER BY date DESC
|
||||
''', (user_id,))
|
||||
|
||||
# 获取问卷数据
|
||||
cursor.execute('''
|
||||
SELECT questionnaire_type, answers
|
||||
FROM questionnaire_records
|
||||
WHERE user_id = ?
|
||||
''', (user_id,))
|
||||
feedback_rows = cursor.fetchall()
|
||||
for row in feedback_rows:
|
||||
try:
|
||||
fb = {
|
||||
'date': row[0],
|
||||
'recommended_foods': json.loads(row[1]) if row[1] else [],
|
||||
'user_choice': row[2],
|
||||
'feedback_type': row[3]
|
||||
}
|
||||
feedback.append(fb)
|
||||
except (json.JSONDecodeError, IndexError) as e:
|
||||
logger.warning(f"解析反馈记录失败: {e}")
|
||||
continue
|
||||
except sqlite3.OperationalError as e:
|
||||
# 表不存在,跳过
|
||||
logger.warning(f"feedback_records表不存在,跳过: {e}")
|
||||
|
||||
questionnaire_rows = cursor.fetchall()
|
||||
# 获取问卷数据(如果表存在)
|
||||
preferences = {}
|
||||
for row in questionnaire_rows:
|
||||
preferences[row[0]] = json.loads(row[1]) if row[1] else {}
|
||||
try:
|
||||
cursor.execute('''
|
||||
SELECT questionnaire_type, answers
|
||||
FROM questionnaire_records
|
||||
WHERE user_id = ?
|
||||
''', (user_id,))
|
||||
|
||||
questionnaire_rows = cursor.fetchall()
|
||||
for row in questionnaire_rows:
|
||||
try:
|
||||
preferences[row[0]] = json.loads(row[1]) if row[1] else {}
|
||||
except (json.JSONDecodeError, IndexError) as e:
|
||||
logger.warning(f"解析问卷记录失败: {e}")
|
||||
continue
|
||||
except sqlite3.OperationalError as e:
|
||||
# 表不存在,跳过
|
||||
logger.warning(f"questionnaire_records表不存在,跳过: {e}")
|
||||
|
||||
conn.close()
|
||||
|
||||
# 构建完整的用户数据
|
||||
user_data = UserData(
|
||||
user_id=data_dict['user_id'],
|
||||
user_id=data_dict.get('user_id', user_id),
|
||||
profile=data_dict.get('profile', {}),
|
||||
meals=meals,
|
||||
feedback=feedback,
|
||||
@@ -266,7 +339,7 @@ class DataManager:
|
||||
return user_data
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"获取用户数据失败: {e}")
|
||||
logger.error(f"获取用户数据失败: user_id={user_id}, error={e}", exc_info=True)
|
||||
return None
|
||||
|
||||
def save_analysis_result(self, result: AnalysisResult) -> bool:
|
||||
|
||||
41
docker-compose.low-mem.yml
Normal file
41
docker-compose.low-mem.yml
Normal file
@@ -0,0 +1,41 @@
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
web:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile.low-mem
|
||||
container_name: diet_recommendation_app_low_mem
|
||||
ports:
|
||||
- "5000:5000"
|
||||
environment:
|
||||
- FLASK_ENV=production
|
||||
- PYTHONUNBUFFERED=1
|
||||
- PYTHONHASHSEED=0
|
||||
- MALLOC_ARENA_MAX=2
|
||||
volumes:
|
||||
# 持久化数据目录
|
||||
- ./data:/app/data
|
||||
- ./logs:/app/logs
|
||||
- ./models:/app/models
|
||||
restart: unless-stopped
|
||||
# 内存限制(小内存机器配置)
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
memory: 512M
|
||||
reservations:
|
||||
memory: 256M
|
||||
networks:
|
||||
- app-network
|
||||
healthcheck:
|
||||
test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:5000/health').read()"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 15s
|
||||
|
||||
networks:
|
||||
app-network:
|
||||
driver: bridge
|
||||
|
||||
86
git_push.bat
Normal file
86
git_push.bat
Normal file
@@ -0,0 +1,86 @@
|
||||
@echo off
|
||||
REM -*- coding: utf-8 -*-
|
||||
REM Git 自动上传脚本(Windows)
|
||||
|
||||
chcp 65001 >nul
|
||||
setlocal enabledelayedexpansion
|
||||
|
||||
echo === Git 自动上传脚本 ===
|
||||
|
||||
REM 检查是否在 git 仓库中
|
||||
if not exist .git (
|
||||
echo 错误: 当前目录不是 git 仓库
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
REM 获取当前分支
|
||||
for /f "tokens=2" %%i in ('git branch --show-current 2^>nul') do set CURRENT_BRANCH=%%i
|
||||
if "!CURRENT_BRANCH!"=="" (
|
||||
for /f "delims=" %%i in ('git rev-parse --abbrev-ref HEAD 2^>nul') do set CURRENT_BRANCH=%%i
|
||||
)
|
||||
echo 当前分支: !CURRENT_BRANCH!
|
||||
|
||||
REM 检查是否有未提交的更改
|
||||
git status --porcelain >nul 2>&1
|
||||
if errorlevel 1 (
|
||||
echo 没有需要提交的更改
|
||||
set /p CONTINUE="是否继续检查远程更新? (y/n) "
|
||||
if /i "!CONTINUE!"=="y" (
|
||||
echo 拉取远程更新...
|
||||
git pull origin !CURRENT_BRANCH! 2>nul || echo 拉取失败,可能没有远程分支
|
||||
)
|
||||
exit /b 0
|
||||
)
|
||||
|
||||
REM 显示当前状态
|
||||
echo 当前更改状态:
|
||||
git status --short
|
||||
|
||||
REM 询问是否继续
|
||||
set /p CONTINUE="是否继续提交并推送? (y/n) "
|
||||
if /i not "!CONTINUE!"=="y" (
|
||||
echo 操作已取消
|
||||
exit /b 0
|
||||
)
|
||||
|
||||
REM 获取提交信息
|
||||
if "%1"=="" (
|
||||
set /p COMMIT_MSG="请输入提交信息(或直接按回车使用默认信息): "
|
||||
if "!COMMIT_MSG!"=="" (
|
||||
for /f "tokens=1-3 delims=/- " %%a in ('date /t') do set DATE_STR=%%a-%%b-%%c
|
||||
for /f "tokens=1-2 delims=: " %%a in ('time /t') do set TIME_STR=%%a:%%b
|
||||
set COMMIT_MSG=chore: update code !DATE_STR! !TIME_STR!
|
||||
)
|
||||
) else (
|
||||
set COMMIT_MSG=%1
|
||||
)
|
||||
|
||||
REM 添加所有更改
|
||||
echo 添加文件到暂存区...
|
||||
git add -A
|
||||
if errorlevel 1 (
|
||||
echo 添加文件失败
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
REM 提交更改
|
||||
echo 提交更改...
|
||||
git commit -m "!COMMIT_MSG!"
|
||||
if errorlevel 1 (
|
||||
echo 提交失败
|
||||
exit /b 1
|
||||
)
|
||||
echo 提交成功!
|
||||
|
||||
REM 推送到远程
|
||||
echo 推送到远程仓库...
|
||||
git push origin !CURRENT_BRANCH!
|
||||
if errorlevel 1 (
|
||||
echo 推送失败,可能需要设置远程仓库或认证
|
||||
echo 提示: 可以手动执行 'git push origin !CURRENT_BRANCH!'
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
echo ✓ 推送成功!
|
||||
echo === 完成 ===
|
||||
|
||||
138
git_push.py
Normal file
138
git_push.py
Normal file
@@ -0,0 +1,138 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Git 自动上传脚本(跨平台)
|
||||
支持 Windows、Linux、Mac
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import subprocess
|
||||
import platform
|
||||
from datetime import datetime
|
||||
|
||||
# 颜色输出(Windows 10+ 支持 ANSI)
|
||||
def print_color(text, color="white"):
|
||||
colors = {
|
||||
"red": "\033[0;31m",
|
||||
"green": "\033[0;32m",
|
||||
"yellow": "\033[1;33m",
|
||||
"blue": "\033[0;34m",
|
||||
"reset": "\033[0m"
|
||||
}
|
||||
if platform.system() == "Windows":
|
||||
# Windows 10+ 支持 ANSI,需要启用
|
||||
try:
|
||||
import ctypes
|
||||
kernel32 = ctypes.windll.kernel32
|
||||
kernel32.SetConsoleMode(kernel32.GetStdHandle(-11), 7)
|
||||
except:
|
||||
pass
|
||||
|
||||
color_code = colors.get(color.lower(), colors["reset"])
|
||||
reset = colors["reset"]
|
||||
print(f"{color_code}{text}{reset}")
|
||||
|
||||
def run_command(cmd, check=True):
|
||||
"""执行命令并返回结果"""
|
||||
try:
|
||||
result = subprocess.run(
|
||||
cmd,
|
||||
shell=True,
|
||||
check=check,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
encoding='utf-8'
|
||||
)
|
||||
return result.returncode == 0, result.stdout.strip(), result.stderr.strip()
|
||||
except subprocess.CalledProcessError as e:
|
||||
return False, e.stdout.strip() if hasattr(e, 'stdout') else "", e.stderr.strip() if hasattr(e, 'stderr') else ""
|
||||
|
||||
def main():
|
||||
print_color("=== Git 自动上传脚本 ===", "green")
|
||||
|
||||
# 检查是否在 git 仓库中
|
||||
if not os.path.exists(".git"):
|
||||
print_color("错误: 当前目录不是 git 仓库", "red")
|
||||
sys.exit(1)
|
||||
|
||||
# 获取当前分支
|
||||
success, branch, _ = run_command("git branch --show-current", check=False)
|
||||
if not success:
|
||||
success, branch, _ = run_command("git rev-parse --abbrev-ref HEAD", check=False)
|
||||
|
||||
if not branch:
|
||||
print_color("错误: 无法获取当前分支", "red")
|
||||
sys.exit(1)
|
||||
|
||||
print_color(f"当前分支: {branch}", "yellow")
|
||||
|
||||
# 检查是否有未提交的更改
|
||||
success, status, _ = run_command("git status --porcelain", check=False)
|
||||
if not status:
|
||||
print_color("没有需要提交的更改", "yellow")
|
||||
response = input("是否继续检查远程更新? (y/n) ").strip().lower()
|
||||
if response == 'y':
|
||||
print_color("拉取远程更新...", "green")
|
||||
run_command(f"git pull origin {branch}", check=False)
|
||||
sys.exit(0)
|
||||
|
||||
# 显示当前状态
|
||||
print_color("当前更改状态:", "yellow")
|
||||
success, status_output, _ = run_command("git status --short", check=False)
|
||||
print(status_output)
|
||||
|
||||
# 询问是否继续
|
||||
response = input("是否继续提交并推送? (y/n) ").strip().lower()
|
||||
if response != 'y':
|
||||
print_color("操作已取消", "yellow")
|
||||
sys.exit(0)
|
||||
|
||||
# 获取提交信息
|
||||
if len(sys.argv) > 1:
|
||||
commit_msg = " ".join(sys.argv[1:])
|
||||
else:
|
||||
default_msg = f"chore: update code {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}"
|
||||
user_msg = input(f"请输入提交信息(或直接按回车使用默认信息): ").strip()
|
||||
commit_msg = user_msg if user_msg else default_msg
|
||||
|
||||
# 添加所有更改
|
||||
print_color("添加文件到暂存区...", "green")
|
||||
success, _, error = run_command("git add -A")
|
||||
if not success:
|
||||
print_color(f"添加文件失败: {error}", "red")
|
||||
sys.exit(1)
|
||||
|
||||
# 提交更改
|
||||
print_color("提交更改...", "green")
|
||||
success, _, error = run_command(f'git commit -m "{commit_msg}"')
|
||||
if not success:
|
||||
if "nothing to commit" in error.lower():
|
||||
print_color("没有需要提交的更改", "yellow")
|
||||
sys.exit(0)
|
||||
print_color(f"提交失败: {error}", "red")
|
||||
sys.exit(1)
|
||||
print_color("提交成功!", "green")
|
||||
|
||||
# 推送到远程
|
||||
print_color("推送到远程仓库...", "green")
|
||||
success, _, error = run_command(f"git push origin {branch}")
|
||||
if not success:
|
||||
print_color(f"推送失败: {error}", "red")
|
||||
print_color(f"提示: 可以手动执行 'git push origin {branch}'", "yellow")
|
||||
print_color("可能需要设置远程仓库地址或进行身份验证", "yellow")
|
||||
sys.exit(1)
|
||||
|
||||
print_color("✓ 推送成功!", "green")
|
||||
print_color("=== 完成 ===", "green")
|
||||
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
main()
|
||||
except KeyboardInterrupt:
|
||||
print_color("\n操作已取消", "yellow")
|
||||
sys.exit(0)
|
||||
except Exception as e:
|
||||
print_color(f"发生错误: {e}", "red")
|
||||
sys.exit(1)
|
||||
|
||||
84
git_push.sh
Normal file
84
git_push.sh
Normal file
@@ -0,0 +1,84 @@
|
||||
#!/bin/bash
|
||||
# -*- coding: utf-8 -*-
|
||||
# Git 自动上传脚本(Linux/Mac)
|
||||
|
||||
set -e # 遇到错误立即退出
|
||||
|
||||
# 颜色输出
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
echo -e "${GREEN}=== Git 自动上传脚本 ===${NC}"
|
||||
|
||||
# 检查是否在 git 仓库中
|
||||
if [ ! -d .git ]; then
|
||||
echo -e "${RED}错误: 当前目录不是 git 仓库${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 获取当前分支
|
||||
CURRENT_BRANCH=$(git branch --show-current)
|
||||
echo -e "${YELLOW}当前分支: ${CURRENT_BRANCH}${NC}"
|
||||
|
||||
# 检查是否有未提交的更改
|
||||
if [ -z "$(git status --porcelain)" ]; then
|
||||
echo -e "${YELLOW}没有需要提交的更改${NC}"
|
||||
read -p "是否继续检查远程更新? (y/n) " -n 1 -r
|
||||
echo
|
||||
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
||||
echo -e "${GREEN}拉取远程更新...${NC}"
|
||||
git pull origin "$CURRENT_BRANCH" || echo -e "${YELLOW}拉取失败,可能没有远程分支${NC}"
|
||||
fi
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# 显示当前状态
|
||||
echo -e "${YELLOW}当前更改状态:${NC}"
|
||||
git status --short
|
||||
|
||||
# 询问是否继续
|
||||
read -p "是否继续提交并推送? (y/n) " -n 1 -r
|
||||
echo
|
||||
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
||||
echo -e "${YELLOW}操作已取消${NC}"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# 获取提交信息
|
||||
if [ -z "$1" ]; then
|
||||
echo -e "${YELLOW}请输入提交信息(或直接按回车使用默认信息):${NC}"
|
||||
read -r COMMIT_MSG
|
||||
if [ -z "$COMMIT_MSG" ]; then
|
||||
COMMIT_MSG="chore: update code $(date '+%Y-%m-%d %H:%M:%S')"
|
||||
fi
|
||||
else
|
||||
COMMIT_MSG="$1"
|
||||
fi
|
||||
|
||||
# 添加所有更改
|
||||
echo -e "${GREEN}添加文件到暂存区...${NC}"
|
||||
git add -A
|
||||
|
||||
# 提交更改
|
||||
echo -e "${GREEN}提交更改...${NC}"
|
||||
if git commit -m "$COMMIT_MSG"; then
|
||||
echo -e "${GREEN}提交成功!${NC}"
|
||||
else
|
||||
echo -e "${RED}提交失败${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 推送到远程
|
||||
echo -e "${GREEN}推送到远程仓库...${NC}"
|
||||
if git push origin "$CURRENT_BRANCH"; then
|
||||
echo -e "${GREEN}✓ 推送成功!${NC}"
|
||||
else
|
||||
echo -e "${RED}推送失败,可能需要设置远程仓库或认证${NC}"
|
||||
echo -e "${YELLOW}提示: 可以手动执行 'git push origin $CURRENT_BRANCH'${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo -e "${GREEN}=== 完成 ===${NC}"
|
||||
|
||||
73
web_app.py
73
web_app.py
@@ -411,40 +411,57 @@ def user_register():
|
||||
|
||||
# 如果用户不存在,创建新用户
|
||||
if not user_data:
|
||||
initial_data = {
|
||||
'profile': {
|
||||
'name': name,
|
||||
'age': 25,
|
||||
'gender': '未知',
|
||||
'height': 170,
|
||||
'weight': 60,
|
||||
'activity_level': 'moderate'
|
||||
},
|
||||
'preferences': {}
|
||||
from core.base import UserData
|
||||
# 直接创建UserData对象并保存
|
||||
initial_profile = {
|
||||
'name': name,
|
||||
'age': 25,
|
||||
'gender': '未知',
|
||||
'height': 170,
|
||||
'weight': 60,
|
||||
'activity_level': 'moderate'
|
||||
}
|
||||
if core.create_user(user_id, initial_data):
|
||||
user_data = core.get_user_data(user_id)
|
||||
else:
|
||||
user_data = UserData(
|
||||
user_id=user_id,
|
||||
profile=initial_profile,
|
||||
preferences={}
|
||||
)
|
||||
|
||||
# 保存用户数据
|
||||
if not core.data_manager.save_user_data(user_data):
|
||||
logger.error(f"保存用户数据失败: user_id={user_id}")
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'message': '创建用户失败'
|
||||
'message': '创建用户失败:数据保存失败'
|
||||
}), 500
|
||||
|
||||
# 更新用户基本信息
|
||||
if user_data:
|
||||
user_data.profile['name'] = name
|
||||
core.data_manager.save_user_data(user_data)
|
||||
session['user_id'] = user_id
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'user_id': user_id,
|
||||
'name': name
|
||||
})
|
||||
# 验证保存是否成功(重新获取一次)
|
||||
saved_user_data = core.get_user_data(user_id)
|
||||
if not saved_user_data:
|
||||
logger.error(f"用户数据保存后无法获取: user_id={user_id}")
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'message': '创建用户失败:数据验证失败'
|
||||
}), 500
|
||||
user_data = saved_user_data
|
||||
else:
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'message': '用户数据获取失败'
|
||||
}), 500
|
||||
# 用户已存在,更新姓名
|
||||
user_data.profile['name'] = name
|
||||
if not core.data_manager.save_user_data(user_data):
|
||||
logger.error(f"更新用户数据失败: user_id={user_id}")
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'message': '更新用户信息失败'
|
||||
}), 500
|
||||
|
||||
# 设置会话
|
||||
session['user_id'] = user_id
|
||||
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'user_id': user_id,
|
||||
'name': user_data.profile.get('name', name)
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"用户注册失败: {e}", exc_info=True)
|
||||
|
||||
Reference in New Issue
Block a user