feat: 初始提交 v1.2.0 - 钢琴练习方案生成系统
This commit is contained in:
@@ -0,0 +1,348 @@
|
||||
# 钢琴练习方案系统 - 部署 SOP
|
||||
|
||||
> 版本:v1.1
|
||||
> 日期:2026-04-21
|
||||
> 核心原则:**不删除,只备份后新增/替换**
|
||||
|
||||
---
|
||||
|
||||
## 一、部署原则(铁律)
|
||||
|
||||
| 操作 | 允许? | 说明 |
|
||||
|------|--------|------|
|
||||
| 删除容器 | ❌ 禁止 | 停止即可,容器配置是资产 |
|
||||
| 删除 volume | ❌ 禁止 | 数据资产,不可恢复 |
|
||||
| 删除 host 文件 | ❌ 禁止 | 先备份到 `/tmp/backup_YYYYMMDD/` |
|
||||
| 覆盖文件 | ⚠️ 先备份 | 任何覆盖操作前必须先备份 |
|
||||
| 停止容器 | ✅ 允许 | stop 是安全的 |
|
||||
| 启动新容器 | ✅ 允许 | 配合正确的挂载配置 |
|
||||
|
||||
### 脚本优先原则(铁律)
|
||||
|
||||
> **当脚本执行失败时:修复脚本,而非绕过脚本。**
|
||||
|
||||
| 错误行为 | 正确行为 |
|
||||
|---------|---------|
|
||||
| 脚本报错 → `docker rm` 手动清理 | 脚本报错 → 查看日志 → 修复脚本问题 → 重跑脚本 |
|
||||
| 挂载丢失 → 手动指定新挂载 | 挂载丢失 → 更新脚本的挂载配置 → 重跑脚本 |
|
||||
| 镜像加载失败 → `docker rmi` 清理 | 镜像加载失败 → 检查错误 → 重跑脚本 |
|
||||
| 容器启动失败 → `docker rm` 重来 | 容器启动失败 → 查看 `docker logs` → 修复配置 → 重跑脚本 |
|
||||
|
||||
**一旦开始用脚本部署,就要坚持用到底,中途放弃脚本去做手动操作,等于打开了破坏系统的潘多拉魔盒。**
|
||||
|
||||
---
|
||||
|
||||
## 二、部署前检查清单
|
||||
|
||||
```
|
||||
[ ] 确认本地代码已验证通过
|
||||
[ ] 确认无未提交的代码
|
||||
[ ] 确认获得用户的明确同意(用户说"部署吧"或"可以部署")
|
||||
[ ] 确认需要保留的挂载点列表(见下方)
|
||||
[ ] 确认 Docker Desktop 已启动(Windows)
|
||||
```
|
||||
|
||||
### 必须保留的挂载点
|
||||
|
||||
| 类型 | 源 | 容器内 | 说明 |
|
||||
|------|-----|--------|------|
|
||||
| Bind Mount | `/opt/piano-plan/个性化方案` | `/app/个性化方案` | 问题文件(15个md) |
|
||||
| Volume | `piano-plan-data` | `/app/data` | SQLite 数据库 |
|
||||
| Volume | `piano-plan-output` | `/app/output` | PDF 输出 |
|
||||
| Bind Mount | `/opt/piano-plan/config` | `/app/config` | API 配置 |
|
||||
|
||||
---
|
||||
|
||||
## 三、部署步骤
|
||||
|
||||
### 3.1 本地构建
|
||||
|
||||
```powershell
|
||||
# 1. 启动 Docker Desktop(Windows)
|
||||
Start-Process "C:\Program Files\Docker\Docker\Docker Desktop.exe"
|
||||
|
||||
# 2. 等待 Docker 就绪
|
||||
docker version # 看到 Server: Docker Desktop 即为就绪
|
||||
|
||||
# 3. 进入项目目录
|
||||
cd "D:\F\NewI\opencode\daily-workspace\projects\青年钢琴集体课\练习方案系统"
|
||||
|
||||
# 4. 构建 Docker 镜像
|
||||
docker build -t piano-plan:latest .
|
||||
|
||||
# 5. 保存镜像为 tar 文件
|
||||
docker save piano-plan:latest -o piano-plan.tar
|
||||
```
|
||||
|
||||
### 3.2 上传到服务器
|
||||
|
||||
```powershell
|
||||
# 6. 上传到服务器临时目录
|
||||
scp -i ~/.ssh/id_rsa piano-plan.tar root@47.106.65.108:/opt/piano-plan/
|
||||
```
|
||||
|
||||
### 3.3 服务器部署(使用脚本!)
|
||||
|
||||
```bash
|
||||
# 7. SSH 到服务器
|
||||
ssh -i ~/.ssh/id_rsa root@47.106.65.108
|
||||
|
||||
# 8. 使用自动化部署脚本(会自动完成所有步骤并验证)
|
||||
bash /path/to/deploy.sh /opt/piano-plan/piano-plan.tar
|
||||
|
||||
# 或者手动部署(不推荐):
|
||||
# 8a. 确认当前容器挂载配置
|
||||
docker inspect piano-plan --format '{{json .Mounts}}'
|
||||
|
||||
# 9. 创建备份
|
||||
mkdir -p /opt/piano-plan/backups
|
||||
docker cp piano-plan:/app/data/piano_plans.db /opt/piano-plan/backups/piano_plans.db.bak
|
||||
|
||||
# 10. 停止旧容器
|
||||
docker stop piano-plan
|
||||
docker rm piano-plan
|
||||
|
||||
# 11. 加载新镜像
|
||||
docker load -i /opt/piano-plan/piano-plan.tar
|
||||
|
||||
# 12. 启动新容器(挂载配置必须完全正确!)
|
||||
docker run -d \
|
||||
--name piano-plan \
|
||||
-p 5001:5001 \
|
||||
--restart unless-stopped \
|
||||
-e FLASK_ENV=production \
|
||||
-v /opt/piano-plan/个性化方案:/app/个性化方案 \
|
||||
-v piano-plan-data:/app/data \
|
||||
-v piano-plan-output:/app/output \
|
||||
-v /opt/piano-plan/config:/app/config \
|
||||
piano-plan:latest
|
||||
```
|
||||
|
||||
### 3.4 验证
|
||||
|
||||
```bash
|
||||
# 13. 检查容器状态
|
||||
docker ps --filter name=piano-plan
|
||||
|
||||
# 14. 检查日志
|
||||
docker logs piano-plan --tail 20
|
||||
|
||||
# 15. 验证服务
|
||||
curl -I http://localhost:5001/
|
||||
|
||||
# 16. 验证问题文件(应该看到15个md文件)
|
||||
docker exec piano-plan ls /app/个性化方案/
|
||||
|
||||
# 17. 验证数据库(应该看到 templates 表)
|
||||
docker exec piano-plan python -c "import sqlite3; conn=sqlite3.connect('/app/data/piano_plans.db'); print([r[0] for r in conn.execute('SELECT name FROM sqlite_master WHERE type=\"table\"')])"
|
||||
|
||||
# 18. 验证 API 配置
|
||||
docker exec piano-plan cat /app/config/api_config.json
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 四、数据保护规范
|
||||
|
||||
### 4.1 必须保护的数据(绝对不删除)
|
||||
|
||||
| 数据类型 | 存储位置 | 说明 |
|
||||
|----------|----------|------|
|
||||
| 用户数据 | piano-plan-data:/app/data | users 表 |
|
||||
| 学员数据 | piano-plan-data:/app/data | students, student_problems 表 |
|
||||
| 班级数据 | piano-plan-data:/app/data | classes 表 |
|
||||
| 练习方案 | piano-plan-data:/app/data | practice_plans 表 |
|
||||
| 问题文件 | /opt/piano-plan/个性化方案 | 15个md文件 |
|
||||
|
||||
### 4.2 新增/更新的数据
|
||||
|
||||
| 数据类型 | 说明 |
|
||||
|----------|------|
|
||||
| templates 表 | AI提示词模板、报告导出模板 |
|
||||
| api_config.json | API 配置(provider, model, api_key) |
|
||||
|
||||
### 4.3 备份操作
|
||||
|
||||
```bash
|
||||
# 备份数据库(volume)
|
||||
docker cp piano-plan:/app/data/piano_plans.db /opt/piano-plan/backups/piano_plans.db.$(date +%Y%m%d)
|
||||
|
||||
# 备份 API 配置
|
||||
cp /opt/piano-plan/config/api_config.json /opt/piano-plan/backups/
|
||||
|
||||
# 列出所有备份
|
||||
ls -la /opt/piano-plan/backups/
|
||||
```
|
||||
|
||||
### 4.4 更新模板数据(部署后必做)
|
||||
|
||||
当代码中的模板内容更新时,需要手动更新生产数据库:
|
||||
|
||||
```python
|
||||
# update_templates.py - 在服务器容器内执行
|
||||
import sqlite3
|
||||
|
||||
NEW_AI_PROMPT = '''你是一位资深的钢琴教师。请根据学员的具体问题详情,生成一份个性化练习方案报告。
|
||||
|
||||
## 学员基本信息
|
||||
- **姓名**: {student_name}
|
||||
- **微信昵称**: {wechat_nickname}
|
||||
- **每日可练习时间**: {practice_time}
|
||||
|
||||
## 学员被诊断的问题
|
||||
{student_problems}
|
||||
|
||||
## 每个问题的详细信息和练习方法(请务必基于这些内容生成方案)
|
||||
|
||||
{problems}
|
||||
|
||||
## 任务要求
|
||||
请根据上述学员的问题诊断和详细信息,生成一份针对性的练习方案报告:
|
||||
1. 先简述该学员当前存在的主要问题
|
||||
2. 给出一个每日练习安排建议
|
||||
3. 针对每个问题给出具体的日常练习方法
|
||||
4. 给出3-5条重点注意事项
|
||||
|
||||
请使用Markdown格式,语言专业、简洁、有鼓励性。'''
|
||||
|
||||
conn = sqlite3.connect('/app/data/piano_plans.db')
|
||||
conn.execute("UPDATE templates SET content = ? WHERE type = 'ai_prompt'", (NEW_AI_PROMPT,))
|
||||
conn.commit()
|
||||
conn.close()
|
||||
```
|
||||
|
||||
上传脚本到服务器执行:
|
||||
```bash
|
||||
scp update_templates.py root@47.106.65.108:/tmp/
|
||||
ssh -i ~/.ssh/id_rsa root@47.106.65.108 "docker cp /tmp/update_templates.py piano-plan:/tmp/ && docker exec piano-plan python /tmp/update_templates.py"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 五、回滚流程
|
||||
|
||||
### 5.1 快速回滚(推荐)
|
||||
|
||||
```bash
|
||||
# 停止当前容器
|
||||
docker stop piano-plan
|
||||
docker rm piano-plan
|
||||
|
||||
# 使用旧镜像重新启动(如果镜像还在)
|
||||
docker run -d \
|
||||
--name piano-plan \
|
||||
-p 5001:5001 \
|
||||
--restart unless-stopped \
|
||||
-e FLASK_ENV=production \
|
||||
-v /opt/piano-plan/个性化方案:/app/个性化方案 \
|
||||
-v piano-plan-data:/app/data \
|
||||
-v piano-plan-output:/app/output \
|
||||
-v /opt/piano-plan/config:/app/config \
|
||||
piano-plan:latest
|
||||
```
|
||||
|
||||
### 5.2 从备份恢复
|
||||
|
||||
```bash
|
||||
# 恢复数据库
|
||||
docker stop piano-plan
|
||||
cp /opt/piano-plan/backups/piano_plans.db.bak /var/lib/docker/volumes/piano-plan-data/_data/piano_plans.db
|
||||
docker start piano-plan
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 六、服务信息
|
||||
|
||||
| 项目 | 值 |
|
||||
|------|-----|
|
||||
| 生产地址 | https://piano.yoin.fun |
|
||||
| SSH | `ssh -i ~/.ssh/id_rsa root@47.106.65.108` |
|
||||
| 容器名 | piano-plan |
|
||||
| 端口 | 5001 |
|
||||
| 数据库位置 | piano-plan-data volume |
|
||||
| 问题文件位置 | /opt/piano-plan/个性化方案 |
|
||||
| API配置位置 | /opt/piano-plan/config |
|
||||
|
||||
### Volume 列表
|
||||
|
||||
| Volume | 容器内路径 | 说明 |
|
||||
|--------|------------|------|
|
||||
| piano-plan-data | /app/data | SQLite 数据库 |
|
||||
| piano-plan-output | /app/output | PDF 导出 |
|
||||
|
||||
### Bind Mount 列表
|
||||
|
||||
| 源 | 容器内路径 | 说明 |
|
||||
|-----|------------|------|
|
||||
| /opt/piano-plan/个性化方案 | /app/个性化方案 | 问题文件 |
|
||||
| /opt/piano-plan/config | /app/config | API 配置 |
|
||||
|
||||
---
|
||||
|
||||
## 七、API 配置说明
|
||||
|
||||
### 7.1 支持的 Provider
|
||||
|
||||
| Provider | Endpoint | 模型 |
|
||||
|----------|----------|------|
|
||||
| minimax | https://api.minimaxi.com/anthropic/v1 | MiniMax-M2.7-highspeed |
|
||||
| volcengine | https://ark.cn-beijing.volces.com/api/coding/v3 | doubao-seed-2.0-pro |
|
||||
| deepseek | https://api.deepseek.com | deepseek-chat |
|
||||
|
||||
### 7.2 API 配置存储
|
||||
|
||||
- 配置存储在 `/opt/piano-plan/config/api_config.json`
|
||||
- 每个 provider 的 key 存储在 `api_keys` 映射中
|
||||
- 切换 provider 时自动使用对应的 key
|
||||
|
||||
---
|
||||
|
||||
## 八、常见问题
|
||||
|
||||
### Q: 部署后问题文件看不到?
|
||||
A: 检查挂载 `/opt/piano-plan/个性化方案:/app/个性化方案` 是否正确
|
||||
|
||||
### Q: 数据库是空的?
|
||||
A: 检查 volume `piano-plan-data` 是否被错误覆盖,尝试从备份恢复
|
||||
|
||||
### Q: 容器无法启动?
|
||||
A: 检查日志 `docker logs piano-plan`,常见原因:端口被占用、volume 权限问题
|
||||
|
||||
### Q: API 配置没生效?
|
||||
A: 检查 `/opt/piano-plan/config/api_config.json` 是否存在且正确
|
||||
|
||||
### Q: SSE 不完整,提示词显示不出来或卡在95%?
|
||||
A: nginx 需要为 SSE (Server-Sent Events) 配置特定的代理设置:
|
||||
```nginx
|
||||
location /api/generate-plan {
|
||||
proxy_buffering off;
|
||||
proxy_cache off;
|
||||
tcp_nodelay on;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Connection '';
|
||||
proxy_buffers 8 32k;
|
||||
proxy_buffer_size 32k;
|
||||
proxy_max_temp_file_size 1024m;
|
||||
}
|
||||
```
|
||||
配置文件位置:`/srv/nginx/conf/conf.d/piano.yoin.fun.conf`
|
||||
|
||||
---
|
||||
|
||||
## 九、检查清单(部署完成后必填)
|
||||
|
||||
```
|
||||
[ ] 容器状态:running
|
||||
[ ] 服务响应:HTTP 200/302
|
||||
[ ] 问题文件数量:15个 md 文件
|
||||
[ ] 数据库记录:users, students, classes, student_problems, practice_plans 完整
|
||||
[ ] templates 表存在且包含 AI提示词模板、报告导出模板
|
||||
[ ] API 配置:provider, model, api_key 正确
|
||||
[ ] 功能验证:能生成练习方案
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
> **最后更新**:2026-04-21
|
||||
> **更新原因**:更新部署流程,添加数据保护规范,明确挂载点配置;添加 SSE 问题排查
|
||||
Reference in New Issue
Block a user