diff --git a/backend/BATCH_IMPORT_GUIDE.md b/backend/BATCH_IMPORT_GUIDE.md index 82c06a4..a01a457 100644 --- a/backend/BATCH_IMPORT_GUIDE.md +++ b/backend/BATCH_IMPORT_GUIDE.md @@ -1,274 +1,53 @@ # 批量导入试卷 — 交接文档 -## 概述 +## 凭据 -`batch_import.py` 用于批量向 PastPaper Master 数据库填充试卷。它会自动完成: -1. 创建 DB 记录 -2. 上传 PDF 到 Supabase Storage -3. Gemini Vision 提取题目结构 -4. DeepSeek 生成 AI 解题三件套(knowledge reminder + hint + solution) +所有 API key 在项目根目录 `.env` 文件中。 ---- +费用监控: +- **DeepSeek**(会花钱): https://platform.deepseek.com → Usage +- **Gemini**(免费额度): https://aistudio.google.com → API keys +- **Supabase**: 找 soda 要登录 +- **Gitea**: https://git.deepknow.site — 用户名 `soda`,密码 `Jermaine0805` -## 凭据 & 账号 +## 试卷来源 -### .env 文件(项目根目录) +PeterGao 爬虫: `pastpaper-scraper/` 目录,详见 `pastpaper-scraper/README.md` -```env -## Supabase -SUPABASE_URL=https://pvcxipwovpwrurebouwg.supabase.co -SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InB2Y3hpcHdvdnB3cnVyZWJvdXdnIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NzM0MDAzMzIsImV4cCI6MjA4ODk3NjMzMn0.pq9JhSSdok4eHOul7rmLLN7AjXNCw0Mz8fxXEu-eQLY -SUPABASE_SERVICE_ROLE_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InB2Y3hpcHdvdnB3cnVyZWJvdXdnIiwicm9sZSI6InNlcnZpY2Vfcm9sZSIsImlhdCI6MTc3MzQwMDMzMiwiZXhwIjoyMDg4OTc2MzMyfQ.JUlHLKYhf7MaLU_YfmqUXmCBgQOv3vEbsSUke6tS41w -SUPABASE_DB_PASSWORD=nyddiq-5mefde-senSih +需要 HKUST 学生 ITSC 账号配合下载,找 soda 协调。 -## LLM -DEEPSEEK_BASE_URL=https://api.deepseek.com/v1 -DEEPSEEK_API_KEY=sk-f7768364050d4a38bb0f42030ea138da +## 批量导入 -GOOGLE_GEMINI_API_KEY=AIzaSyBm_SMw5iwxn5KxWmVoyAJMMpjfu86m-yU - -# 以下备用,批量导入不需要 -LAOZHANG_BASE_URL=https://api.laozhang.ai/v1 -LAOZHANG_API_KEY=sk-oqKIhugRggjtjzPg0e07Bb2aB9Fb44B2A904BfA1E9C67947 -DASHSCOPE_BASE_URL=https://dashscope.aliyuncs.com/compatible-mode/v1 -DASHSCOPE_API_KEY=sk-20164094f29e416aad0437d9e678b04f -``` - -### 管理后台 - -| 服务 | 地址 | 账号 | 用途 | -|------|------|------|------| -| **Supabase** | https://supabase.com/dashboard | 找 soda 要登录 | 数据库管理、Storage、Auth | -| **Google AI Studio** | https://aistudio.google.com | 用自己的 Google 账号,API key 在 .env 里 | 监控 Gemini 用量,免费额度 | -| **DeepSeek** | https://platform.deepseek.com | 用 .env 里的 key 登录 | 监控用量和余额,**这个会花钱** | -| **Gitea** | https://git.deepknow.site | 用户名 `soda`,密码 `Jermaine0805` | 代码仓库 | - -### API 费用监控(重要!) - -| 模型 | 用途 | 单价 | 单份试卷约费用 | -|------|------|------|------| -| Gemini 2.5 Flash | Vision 提取 + 答案匹配 | 免费额度(每分钟有限) | $0 | -| DeepSeek V3 | AI trio 生成 | $0.28/M input, $1.10/M output | ~$0.5-1.5 | - -**批量导入前先去 DeepSeek 平台看余额!** 50 份试卷大约消耗 $25-75。 - ---- - -## 服务器信息 - -| 项目 | 值 | -|------|-----| -| 生产服务器 | `129.226.210.66` | -| SSH | `ssh -i ~/.ssh/id_ed25519 root@129.226.210.66` | -| 后端容器 | `pastpaper-backend-1` | -| 项目路径 | `/opt/pastpaper/` | -| 前端静态文件 | `/opt/1panel/www/pastpaper/` | -| Gitea 服务器 | `43.134.230.28`(1Panel 面板管理) | - ---- - -## 第一步:获取试卷 PDF(PeterGao Scraper) - -### 概述 - -HKUST 历年试卷来源: https://petergao.cc/ustpastpaper/ - -该网站有 quota 限制(每账号每学期 50 次下载),需要多个 HKUST 学生账号协作下载。 - -### Scraper 位置 - -```bash -cd /path/to/PastPaper\ Master/pastpaper-scraper/ -``` - -GitHub repo: https://github.com/ZhaoYiping789/PeterGao-raper.git - -### 环境 - -```bash -# 安装 uv -curl -LsSf https://astral.sh/uv/install.sh | sh - -# 安装依赖 -uv sync -``` - -### 运行 - -```bash -# 批量下载(按 group 分配) -uv run python batch_download.py --group B -``` - -流程: -1. 脚本显示本轮要下载的课程(每轮不超过 45 quota) -2. 输入一个 ITSC 用户名(如 `chanxm`) -3. 网站向该用户发验证邮件 -4. **让该用户把邮件链接发给你** -5. 粘贴链接到脚本 -6. 自动下载,完成后换下一个账号 - -### 获取账号 - -需要找 HKUST 学生要 ITSC 账号配合。每个账号每学期可用 50 quota,全站约 3400 份试卷需要约 52 个账号。联系 soda 协调。 - -### 下载结果 - -PDF 保存在 `pastpaper-scraper/papers/{课程名}/` 目录下。 - ---- - -## 第二步:整理文件结构 - -将 scraper 下载的 PDF 整理成以下结构: - -``` -papers_to_import/ -├── COMP2211/ -│ ├── 2024_spring_midterm.pdf -│ ├── 2024_spring_midterm_answer.pdf <- 答案,自动匹配 -│ ├── 2024_fall_final.pdf -│ └── 2023_spring_midterm.pdf -├── COMP2011/ -│ └── ... -├── MATH1014/ -│ └── ... -└── FINA2303/ - └── ... -``` - -规则: -- 一级目录名 = 课程代码(自动转大写) -- 文件名: `{year}_{term}_{examtype}.pdf` -- 答案: `{year}_{term}_{examtype}_answer.pdf`(可选) -- term: `spring` / `fall` / `summer` -- examtype: `midterm` / `final` / `quiz` - -scraper 下载的文件名格式比较杂(如 `(COMP2211)[2024](s)midterm~xxx.pdf`),需要手动或写脚本重命名。 - -### 优先导入的课程 - -用户量大,优先补充: -- COMP2011, COMP2211, COMP2711H -- MATH1013, MATH1014, MATH2023 -- PHYS1112 -- ELEC2100 -- FINA2303 - ---- - -## 第三步:批量导入 - -### 在本地运行(推荐) - -```bash -cd /path/to/PastPaper\ Master/backend -source .venv/bin/activate # 或 .venv/bin/python - -# 试运行(不实际导入,只打印) -python batch_import.py /path/to/papers_to_import/ --batch --dry-run - -# 正式导入(串行) -python batch_import.py /path/to/papers_to_import/ --batch - -# 并发导入(最多 2 个同时,别超过 2) -python batch_import.py /path/to/papers_to_import/ --batch --concurrency 2 -``` - -### 单份导入 - -```bash -python batch_import.py paper.pdf \ - --course COMP2211 --year 2024 --term spring --exam midterm - -# 带答案 -python batch_import.py paper.pdf --answer answer.pdf \ - --course COMP2211 --year 2024 --term spring --exam midterm -``` - -### 自动查重 - -脚本会跳过已存在的试卷(相同 course_code + year + term + exam_type)。 - ---- - -## 处理时间估计 - -| 阶段 | 耗时 | -|------|------| -| PDF 渲染 | 2-5s | -| Vision 提取(每 8 页一批) | 30-60s/批 | -| 答案匹配 | 20-40s | -| AI trio 生成(每 3 题一批) | 15-25s/批 | -| **总计(30 题试卷)** | **~3-5 min** | -| **总计(40+ 题试卷)** | **~5-8 min** | - -并发不要超过 2,Gemini 会限流(429 错误,脚本自动重试但更慢)。 - ---- - -## 常见问题 - -### Q: 处理失败(status=error)怎么办? +脚本: `backend/batch_import.py` ```bash cd backend/ -.venv/bin/python -c " -import sys; sys.path.insert(0, '.') -from dotenv import load_dotenv; load_dotenv('../.env') -from app.services.supabase_client import get_supabase -sb = get_supabase() -errors = sb.table('papers').select('id, course_code').eq('status', 'error').execute().data -for p in errors: - sb.table('paper_questions').delete().eq('paper_id', p['id']).execute() - sb.table('papers').delete().eq('id', p['id']).execute() - print('Deleted', p['course_code']) -" +source .venv/bin/activate + +# 试运行 +python batch_import.py /path/to/papers/ --batch --dry-run + +# 正式导入 +python batch_import.py /path/to/papers/ --batch ``` -然后重新导入即可。 +目录结构: `课程代码/year_term_examtype.pdf`,答案文件加 `_answer` 后缀自动匹配。 -### Q: 只重新生成 AI trio(题目已提取成功)? +## 服务器 -```bash -.venv/bin/python -c " -import sys; sys.path.insert(0, '.') -from dotenv import load_dotenv; load_dotenv('../.env') -from app.services.supabase_client import get_supabase -sb = get_supabase() -PAPER_ID = 'xxxxxxxx-xxxx-...' # 替换为实际 ID -qs = sb.table('paper_questions').select('id').eq('paper_id', PAPER_ID).execute().data -for q in qs: - sb.table('paper_questions').update({'solution': None, 'ai_hint': None, 'knowledge_reminder': None}).eq('id', q['id']).execute() -sb.table('papers').update({'status': 'processing'}).eq('id', PAPER_ID).execute() -print(f'Reset {len(qs)} questions') -" +- SSH: `ssh -i ~/.ssh/id_ed25519 root@129.226.210.66` +- 后端: `/opt/pastpaper/`,容器 `pastpaper-backend-1` +- 前端: `/opt/1panel/www/pastpaper/` -# 重启后端触发自动续传 -ssh -i ~/.ssh/id_ed25519 root@129.226.210.66 "sudo docker restart pastpaper-backend-1" -``` +## 相关文件 -### Q: 如何部署后端代码改动? - -```bash -scp -i ~/.ssh/id_ed25519 app/services/paper_processor.py root@129.226.210.66:/opt/pastpaper/backend/app/services/ -ssh -i ~/.ssh/id_ed25519 root@129.226.210.66 "cd /opt/pastpaper && sudo docker compose up -d --build backend" -``` - -### Q: 如何部署前端改动? - -```bash -cd frontend && npm run build -cp public/favicon.jpg dist/ -ssh -i ~/.ssh/id_ed25519 root@129.226.210.66 "rm -rf /opt/1panel/www/pastpaper/assets" -scp -i ~/.ssh/id_ed25519 dist/index.html dist/favicon.jpg root@129.226.210.66:/opt/1panel/www/pastpaper/ -scp -i ~/.ssh/id_ed25519 -r dist/assets root@129.226.210.66:/opt/1panel/www/pastpaper/ -``` - -### Q: DeepSeek 余额不够了? - -去 https://platform.deepseek.com 充值。用的是 DeepSeek V3(deepseek-chat),很便宜但批量跑几百份也会花几十美元。 - -### Q: Gemini 限流(429)? - -免费额度有每分钟请求限制。脚本内置自动重试(指数退避),等几秒就好。如果频繁 429,降低并发到 1。 +| 文件 | 说明 | +|------|------| +| `.env` | 所有 API 凭据 | +| `backend/batch_import.py` | 批量导入脚本 | +| `backend/app/services/paper_processor.py` | 处理管线核心(Vision 提取 + AI trio) | +| `backend/app/services/grader.py` | 判卷 + variant 生成 | +| `backend/app/routers/papers.py` | 上传 API | +| `pastpaper-scraper/README.md` | 爬虫使用说明 | +| `pastpaper-scraper/batch_download.py` | 爬虫主脚本 | +| `docker-compose.yml` | 后端部署配置 |