From cb184206224c912879eb610e0607f7a20369bf1b Mon Sep 17 00:00:00 2001 From: Zhao Date: Fri, 24 Apr 2026 23:19:34 +0900 Subject: [PATCH] docs: complete handoff guide with credentials, scraper, and API monitoring Co-Authored-By: Claude Opus 4.6 (1M context) --- backend/BATCH_IMPORT_GUIDE.md | 250 +++++++++++++++++++++------------- 1 file changed, 152 insertions(+), 98 deletions(-) diff --git a/backend/BATCH_IMPORT_GUIDE.md b/backend/BATCH_IMPORT_GUIDE.md index 3992cb7..82c06a4 100644 --- a/backend/BATCH_IMPORT_GUIDE.md +++ b/backend/BATCH_IMPORT_GUIDE.md @@ -1,4 +1,4 @@ -# 批量导入试卷指南 +# 批量导入试卷 — 交接文档 ## 概述 @@ -8,9 +8,53 @@ 3. Gemini Vision 提取题目结构 4. DeepSeek 生成 AI 解题三件套(knowledge reminder + hint + solution) -## 环境准备 +--- -### 1. 服务器信息 +## 凭据 & 账号 + +### .env 文件(项目根目录) + +```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 + +## 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。 + +--- + +## 服务器信息 | 项目 | 值 | |------|-----| @@ -19,103 +63,137 @@ | 后端容器 | `pastpaper-backend-1` | | 项目路径 | `/opt/pastpaper/` | | 前端静态文件 | `/opt/1panel/www/pastpaper/` | +| Gitea 服务器 | `43.134.230.28`(1Panel 面板管理) | -### 2. 在本地运行(推荐) +--- + +## 第一步:获取试卷 PDF(PeterGao Scraper) + +### 概述 + +HKUST 历年试卷来源: https://petergao.cc/ustpastpaper/ + +该网站有 quota 限制(每账号每学期 50 次下载),需要多个 HKUST 学生账号协作下载。 + +### Scraper 位置 ```bash -cd /path/to/PastPaper\ Master/backend - -# 确保 .env 在项目根目录(../. env) -# 需要的 key: SUPABASE_URL, SUPABASE_SERVICE_ROLE_KEY, GOOGLE_GEMINI_API_KEY, DEEPSEEK_API_KEY - -# 激活虚拟环境 -source .venv/bin/activate - -# 或用 venv 的 python -.venv/bin/python batch_import.py ... +cd /path/to/PastPaper\ Master/pastpaper-scraper/ ``` -### 3. 在服务器 Docker 容器里运行 +GitHub repo: https://github.com/ZhaoYiping789/PeterGao-raper.git + +### 环境 ```bash -# 先把脚本和试卷文件传到服务器 -scp -i ~/.ssh/id_ed25519 batch_import.py root@129.226.210.66:/opt/pastpaper/backend/ -scp -i ~/.ssh/id_ed25519 -r /path/to/papers root@129.226.210.66:/opt/pastpaper/papers_to_import/ +# 安装 uv +curl -LsSf https://astral.sh/uv/install.sh | sh -# 进容器运行 -ssh -i ~/.ssh/id_ed25519 root@129.226.210.66 -docker exec -it pastpaper-backend-1 bash -cd /app -python batch_import.py /path/to/papers --batch +# 安装依赖 +uv sync ``` -## 使用方法 - -### 单份导入 +### 运行 ```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 +# 批量下载(按 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_spring_midterm_answer.pdf <- 答案,自动匹配 │ ├── 2024_fall_final.pdf │ └── 2023_spring_midterm.pdf ├── COMP2011/ -│ ├── 2024_spring_midterm.pdf -│ └── 2024_fall_final.pdf +│ └── ... ├── MATH1014/ -│ └── 2024_spring_midterm.pdf +│ └── ... └── FINA2303/ - └── 2023_fall_midterm.pdf + └── ... ``` +规则: - 一级目录名 = 课程代码(自动转大写) -- 文件名格式: `{year}_{term}_{examtype}.pdf` -- 答案文件: `{year}_{term}_{examtype}_answer.pdf`(可选,放同一目录,自动匹配) +- 文件名: `{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 -# 先试运行看看会导入什么 -python batch_import.py papers_to_import/ --batch --dry-run +cd /path/to/PastPaper\ Master/backend +source .venv/bin/activate # 或 .venv/bin/python -# 正式导入(串行,最安全) -python batch_import.py papers_to_import/ --batch +# 试运行(不实际导入,只打印) +python batch_import.py /path/to/papers_to_import/ --batch --dry-run -# 并发导入(2个同时处理,更快但 API 可能限流) -python batch_import.py papers_to_import/ --batch --concurrency 2 +# 正式导入(串行) +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 且 status 为 ready 或 processing)。 +脚本会跳过已存在的试卷(相同 course_code + year + term + exam_type)。 + +--- ## 处理时间估计 -单份试卷处理时间取决于页数和题目数: - | 阶段 | 耗时 | |------|------| | PDF 渲染 | 2-5s | @@ -125,26 +203,16 @@ python batch_import.py papers_to_import/ --batch --concurrency 2 | **总计(30 题试卷)** | **~3-5 min** | | **总计(40+ 题试卷)** | **~5-8 min** | -建议: 并发不要超过 2,否则 Gemini API 可能限流(429 错误,脚本会自动重试但会更慢)。 +并发不要超过 2,Gemini 会限流(429 错误,脚本自动重试但更慢)。 -## API 费用 - -| 模型 | 用途 | 费用 | -|------|------|------| -| Gemini 2.5 Flash | Vision 提取 + 答案匹配 | 免费额度内通常够 | -| DeepSeek V3 | AI trio 生成 | ~$0.5-1.5/份试卷 | - -监控费用: -- Gemini: https://aistudio.google.com (API keys 页面看用量) -- DeepSeek: https://platform.deepseek.com (Usage 页面) +--- ## 常见问题 -### Q: 处理失败怎么办? +### Q: 处理失败(status=error)怎么办? -试卷会标记为 `status=error`。可以删掉重来: -```python -# 在 backend/ 目录下 +```bash +cd backend/ .venv/bin/python -c " import sys; sys.path.insert(0, '.') from dotenv import load_dotenv; load_dotenv('../.env') @@ -158,63 +226,49 @@ for p in errors: " ``` -### Q: JSON 解析错误? +然后重新导入即可。 -已内置多层 JSON 修复 + 自动重试(最多 6 次)。如果还是失败,通常是因为试卷内容太复杂(大量 LaTeX + 代码),可以尝试: -1. 删掉 error 记录重新导入 -2. 如果反复失败,可能需要拆分试卷 PDF +### Q: 只重新生成 AI trio(题目已提取成功)? -### Q: 如何只重新生成 AI trio(题目已提取)? - -```python -# 清空 solution 字段,重启后端会自动续传 +```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-...' # 替换 +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, restart backend to regenerate') +print(f'Reset {len(qs)} questions') " -# 然后重启后端 +# 重启后端触发自动续传 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 +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 余额不够了? -`pastpaper-scraper/papers/` 目录下有从 HKUST 爬取的历年试卷 PDF,按课程分目录。可以从中挑选热门课程导入: +去 https://platform.deepseek.com 充值。用的是 DeepSeek V3(deepseek-chat),很便宜但批量跑几百份也会花几十美元。 -优先导入的课程(用户量大): -- COMP2011, COMP2211, COMP2711H -- MATH1013, MATH1014, MATH2023 -- PHYS1112 -- ELEC2100 -- FINA2303 +### Q: Gemini 限流(429)? -将文件按上述目录结构组织后运行 `--batch` 即可。 +免费额度有每分钟请求限制。脚本内置自动重试(指数退避),等几秒就好。如果频繁 429,降低并发到 1。