一眼看全局
公网服务
docscan.evowit.com
iOS 默认请求入口
后端框架
FastAPI
单文件 app/main.py,Docker 或 uvicorn 运行
数据目录
/data
JSON + 图片文件,无数据库
请求链路
iOS SwiftUI AppAVFoundation 相机、Vision 文档检测、自动快门、手势识别、语音输入和答案播报。
公网 HTTPS
https://docscan.evowit.com,手机直接访问,不需要加入 Tailscale。广州 VPS NginxHTTPS 终结后反向代理到 Tailscale 内网。
100.64.0.2:30182DocScan FastAPI 后端。当前项目支持 Docker Compose 8080 映射或 native uvicorn 直接监听。
Dell AI 服务OCR、LLM、TTS、STT 多个 OpenAI-compatible 或专用 HTTP 服务。
能完成的事情
自动扫描归档iOS 自动/手动拍摄后上传 JPEG、四边形、画质、置信度、页面变化分数等 metadata。
学习回合管理一次相机打开到关闭是一轮学习,后端记录开始、结束、时长和扫描遥测。
OCR 与去重保存原图和缩略图,生成图像指纹,重复页跳过 OCR/报告,但仍保留图片供复查。
学习报告把可用 OCR 文本、时长、专注度、重复页、题目停留估算交给 LLM 生成中文 Markdown 报告。
单页分析对某一页 OCR 文本做学科、主题、题型、可疑 OCR、下一步建议分析。
手势问答食指指向截图,可附带前几页上下文和语音问题,后端调用视觉模型回答。
语音能力后端代理 VoxCPM2 TTS 返回 WAV;后端 Whisper STT 作为 Apple 语音识别兜底。
后台运维Dashboard 查看学习回合、报告、手势日志;提示词后台可改 report/page/gesture prompts。
当前运行配置快照
| 公网入口 | https://docscan.evowit.com | iOS 默认 Base URL |
|---|---|---|
| 反向代理 | 广州 VPS Nginx -> Tailscale 100.64.0.2:30182 | 手机无需加入 Tailscale |
| 当前数据目录 | /data | 容器内通常是 /data,挂载到 backend/data |
| 上传总数 | 17 | unique=15, duplicate=2 |
| 学习回合 | 25 | reports=0 |
| OCR 顺序 | qianfan | auto 模式按可用配置选择 |
| QianfanOCR | http://100.64.0.5:30080/api/ocr | Dell GPU OCR 服务 |
| PaddleOCR AI Studio | configured=False | PaddleOCR-VL-1.5 |
| LLM 主链路 | https://ollama.evowit.com/v1 | evowit-agent27b |
| LLM fallback | https://sapi.evowit.com/v1 | gpt-5.5 |
| TTS | http://100.64.0.5:39040 | voxcpm2 / voice=default |
| STT | http://100.64.0.5:39050 | whisper-1 |
后端 API
| GET /health | 运行状态、自检与当前 OCR/LLM/TTS/STT 配置快照 | 不返回任何 API key |
|---|---|---|
| GET / | 学习监控 Dashboard | 按 camera open -> close 的学习回合展示 |
| GET /architecture | 系统架构与技术细节页 | 当前页面 |
| GET /admin/prompts | 提示词配置后台 | 覆盖项保存到 data/prompt_config.json |
| POST /api/study-sessions/start | 开始学习回合 | iOS 打开扫描页时调用 |
| POST /api/study-sessions/{id}/finish | 结束学习回合并回传扫描遥测 | iOS 关闭扫描页/完成时调用 |
| POST /api/uploads | 上传单页 JPEG + metadata | 保存原图/缩略图,后台触发去重与 OCR |
| GET /api/uploads | 上传列表 | 支持 session_id 和 limit |
| GET /api/uploads/{id} | 单页 JSON 详情 | 含 OCR、去重、页级分析状态 |
| POST /api/uploads/{id}/analyze | 对单页 OCR 文本做大模型分析 | 可 force 重跑 |
| POST /api/uploads/{id}/ocr/retry | 重试单页 OCR | 后台任务执行 |
| POST /api/ocr/retry-failed | 批量重试失败 OCR | 可指定 limit |
| POST /api/dedup/rebuild | 重建页面去重指纹 | 支持 dry_run |
| GET /api/sessions | 学习回合列表 | Dashboard 数据源 |
| GET /api/sessions/{id} | 学习回合详情 JSON | 含统计、图片、报告、手势数据 |
| POST /api/sessions/{id}/report | 生成学习报告 | 等待 OCR 后调用 LLM,失败时本地兜底摘要 |
| GET /api/sessions/{id}/report | 读取已生成报告 | 用于复查/前端展示 |
| DELETE /api/sessions/{id} | 删除单个学习回合 | 同时删除图片、报告和相关手势图 |
| DELETE /api/sessions | 清空所有学习数据 | 同时清空手势事件 |
| POST /api/gesture-query | 手势触发视觉问答 | 当前帧 + 可选上下文页 + 语音文本 |
| GET /api/gesture-events | 最近手势问答日志 | 支持 session_id 过滤 |
| DELETE /api/gesture-events | 清空手势日志 | 清 gesture_thumbs |
| POST /api/tts | 文本转语音代理 | 转发到 VoxCPM2 OpenAI-compatible speech |
| POST /api/stt | 语音转文字代理 | 转发到 Whisper OpenAI-compatible transcription |
| GET /privacy | TestFlight 隐私说明页 | App Store Connect 使用 |
关键环境变量
| DocScanBackendBaseURL | https://docscan.evowit.com | iOS Info.plist 默认值 |
|---|---|---|
| DOCSCAN_STORAGE_DIR | 后端数据根目录 | uploads/previews/ocr_inputs/gesture_thumbs/json indexes |
| DOCSCAN_OCR_PROVIDER | auto / qianfan / paddleocr | 当前 auto |
| DOCSCAN_PADDLEOCR_API_TOKEN | PaddleOCR 云 OCR token | 只显示 configured,不显示 token |
| QIANFAN_OCR_URL | QianfanOCR 服务地址 | http://100.64.0.5:30080/api/ocr |
| DOCSCAN_OPENAI_BASE_URL / API_KEY | 主 OpenAI-compatible LLM | key 只在 .env |
| DOCSCAN_REPORT_MODEL | 学习报告模型 | evowit-agent27b |
| DOCSCAN_PAGE_ANALYSIS_MODEL | 单页分析模型 | evowit-agent27b |
| DOCSCAN_FINAL_OPENAI_BASE_URL / API_KEY | 最终兜底 OpenAI-compatible LLM | key 只在 .env |
| DOCSCAN_GESTURE_MODEL | 视觉问答模型 | gpt-5.5 |
| DOCSCAN_TTS_BASE_URL | TTS 网关 | http://100.64.0.5:39040 |
| DOCSCAN_STT_BASE_URL | STT 网关 | http://100.64.0.5:39050 |
| DOCSCAN_DEDUP_* | 图像指纹和 OCR 文本相似度去重阈值 | {"image_distance": 0.145, "blank_image_distance": 0.105, "ocr_text_similarity": 0.92} |
持久化与文件结构
| data/uploads.json | 所有上传页记录 | OCR、去重、页级分析 metadata 都写在记录里 |
|---|---|---|
| data/study_sessions.json | 学习回合索引 | started_at、ended_at、scanner_telemetry |
| data/reports.json | 学习报告缓存 | 按 session_id 保存 |
| data/prompt_config.json | 后台提示词覆盖 | 仅保存 prompt 文本,不保存密钥 |
| data/uploads/{session_id}/ | 原始 JPEG | iOS 上传的扫描页 |
| data/previews/{session_id}/ | 缩略图 JPEG | Dashboard 和详情页展示 |
| data/ocr_inputs/ | OCR 压缩输入图 | 按最大边和质量压缩后交给 OCR |
| data/gesture_thumbs/ | 手势问答缩略图 | 用于日志追踪 |
运维注意
生产部署历史上在 Docker Desktop 和 native uvicorn 之间切换过。判断当前真身时以 /health、端口监听和目标机进程/容器状态为准;不要只看旧文档。
所有 API key、PaddleOCR token、App Store Connect key、p12/p8 和证书密码都只能放在本地私有环境或目标机器,不写入仓库、知识库、日志或页面。