手机连拍实体书页、或 PC 批量上传图片,本机服务器自动 OCR 提取文本,并可一次性合成整书完整文本。本地 RapidOCR 离线识别为主(免费、无次数限制),页面可选 DeepSeek VL 云端增强/修正(复杂版面、低质量照片效果更好,按 API 用量计费)。照片与原页文本自动按书名存档。
当前运行中(单一 HTTP 入口,无需证书):
- 手机端:http://192.168.31.76:8901/(📷 拍照 / 📖 相册连拍)
- PC 端:http://192.168.31.76:8901/pc(🗂 图片批量上传 / 拖拽 + ✨ VL 修正 + 手动编辑)
- 本项目目录(下载中心可浏览/下载存档):http://192.168.31.76:8899/23-拍照OCR取字/
两页数据互通(同一存档目录):手机补拍的页,PC 端「含历史页」合成即可并入;PC 修正好文本,手机端重新合成同样生效。
打开 http://192.168.31.76:8901/pc(无需摄像头,两个页签:🖥 上传识别 / 🗂 项目管理)。
页签一:上传识别
页签二:项目管理(管理手机端产生的项目)
data/books/ 下全部项目(含手机端拍摄产生):页数 / 字数 / 最近更新时间,点「打开」提示:手机页与 PC 页数据同目录互通;PC 上「含历史页/合成整书」都只读服务器存档,不依赖浏览器会话。
data/books/<书名>/,也能在下载中心 http://192.168.31.76:8899/23-拍照OCR取字/data/books/ 直接浏览下载拍摄技巧:书页放平、正对光源避免反光、别让手指/影子进画面、尽量拍全整页(竖拍优先)。
⚠️ 局域网是 HTTP(非 HTTPS),浏览器不允许网页直接调起"取景框预览", 所以手机「拍照识别」走系统相机(
capture属性),安卓/iOS 均可正常弹起相机。 若某浏览器没弹相机,用「相册选图」先拍好再选即可;PC 页本就是上传图片,不受影响。
cd /home/zyw/Downloads/dl-hub/23-拍照OCR取字
bash start.sh # 启动(后台,日志 server.log,PID 存 server.pid)
bash stop.sh # 停止
OCR_PORT 可改;改端口记得改 start.sh 提示文案)http://<本机局域网IP>:8901/(手机)与 http://<本机局域网IP>:8901/pc(PC)首次部署(重建环境,一般无需):
python3 -m venv .venv
.venv/bin/pip install -r requirements.txt # flask / pillow / requests / rapidocr-onnxruntime
| 引擎 | 速度/成本 | 特点 | 适用 |
|---|---|---|---|
| 🔤 本地 RapidOCR(默认) | ~3–8 秒/页,免费离线 | 印刷体中英文识别准、无网络依赖、无次数限制 | 绝大多数清晰的印刷书页 |
| ✨ DeepSeek VL 增强 | ~10–20 秒/页,按 token 计费 | 视觉大模型整页阅读,还原空格/标点/版面更好,抗模糊反光更强 | 本地效果不满意、复杂版式、拍照质量差的页 |
api.deepseek.com(模型 deepseek-v4-flash-vision-exp),key 存于同目录 deepseek_key.txt(权限 600)。该文件含密钥,勿外传、勿上传到公开位置。deepseek_key.txt 即关闭 VL(页面开关自动变灰并回退本地)。23-拍照OCR取字/
├── server.py # 后端:Flask + RapidOCR + DeepSeek VL(单文件)
├── static/index.html # 移动端页面(单文件,内联 CSS/JS)
├── static/index_pc.html # PC 端页面(图片上传 + VL 修正,单文件)
├── requirements.txt # Python 依赖
├── start.sh / stop.sh # 启停脚本
├── deepseek_key.txt # DeepSeek API key(敏感,勿外传)
├── server.log # 运行日志
├── data/books/<书名>/ # 每页存档:第xxx页_时间.jpg + 同名 .txt + 全书文本_*.txt
└── test/ # 自测脚本与样例图(gen_sample.py / sample_book_page.png)
| 接口 | 说明 |
|---|---|
GET / | 移动端页面 |
GET /pc | PC 端页面(上传 + 项目管理 + VL 修正) |
GET /api/health | 服务状态:{ok, local_engine, vl_enabled, vl_model} |
POST /api/ocr | 【旧流程,保留兼容】multipart:image、engine、book_name、seq → 上传+识别一次完成 |
POST /api/photo | 【推荐】multipart:files[](多张)+book_name+engine → 照片即时存档并自动入识别队列,返回 {book, items:[{seq,stem}], failed} |
| 上传限制 | 单次 ≤100 张、每张 ≤10MB(请求体上限 ≈1.02GB);超限返回 413 + JSON 错误说明。手机页会自动分批(每批 ≤100 张且 ≤900MB)依次上传,无需手动拆批 |
POST /api/batch/process | JSON:{book_name?, retry_errors?} → 把待识别/失败页排入服务器识别队列(逐条处理) |
POST /api/batch/vlall | JSON:{book_name, scope:"all"|"todo", retry_errors?} → 整书 VL 批量:标记为结构化 VL 并排队(scope=all 重跑全部页 / todo 只补待识别失败页) |
POST /api/page/reocr | JSON:{book_name, stem, engine, save?} → 对已存档页用指定引擎重跑(VL 修正/本地重跑);save:true 时覆盖该页存档 txt |
POST /api/page/text | JSON:{book_name, stem, text} → 手动修正,覆盖存档 txt(合成即采用) |
POST /api/page/delete | JSON:{book_name, stem} → 删除一页(jpg+txt,不可恢复) |
POST /api/batch/export | JSON:{book_name, scope:"session"|"folder", stems?, include_side?:0|1} → 服务器按印刷页码自动排序合成整书文本(VL 页按页码、其余按拍摄顺序),可选含页眉页脚;返回 {ok, pages, chars, file, url, missing, skipped, ordered_by, vl_pages, preview} |
POST /api/batch/exportall | JSON:{book_name} → 一键生成全套成品 4 份(正文标注版/纯净全文/含页眉页脚 txt/含页眉页脚 md)到存档目录,返回 {files:[{tag,name,url,chars}], dropped, skipped, ordered_by} |
GET /api/books | 项目管理:列出全部项目 {books:[{name, pages, chars, size, updated_at, first}]}(含手机端产生的) |
GET /api/books/<书>/pages[?text=1] | 项目管理:某项目全部页(页码/时间/缩略图/txt 链接;text=1 附每页全文供修正) |
POST /api/books/delete | JSON:{book_name} → 整个项目移入回收站(data/trash,可恢复),非永久删除 |
POST /api/books/rename | JSON:{book_name, new_name} → 重命名项目目录 |
GET /api/trash | 回收站列表:{entries:[{entry, kind, book, stem, files, size, time}]} |
POST /api/trash/restore | JSON:{entry} → 从回收站恢复整书或单页 |
POST /api/trash/purge | JSON:{entry} → 永久删除回收站条目(不可恢复) |
GET /f/<书名>/<页>.jpg[?w=480] | 原图 / 实时缩略图 |
GET /txt/<书名>/<页或全书>.txt | 下载单页 / 整书文本 |
data/books/<书名>/。data/books/<书>/<页>.vl.json; 正文 = 剔除页眉页脚页码后的阅读顺序文本(.txt)。POST /api/batch/vlall {book_name, scope:all|todo}:一键把整本(或待处理)页标为 VL 并排队逐条处理,进度实时可见。ordered_by/vl_pages。include_side=1 生成「含页眉页脚版」(【页眉】…正文…【页脚】…);默认正文版已剔除。reocr engine=vl 亦结构化并返回页码/页眉/页脚。POST /api/batch/exportall {book_name},服务器一次生成 4 份到存档目录并返回链接: 正文标注版.txt(带页码标注分隔)/ 纯净全文.txt(无任何装饰行)/ 含页眉页脚.txt / 含页眉页脚.md(每页一个小节 + 页眉页脚引用样式); 页面(PC 项目管理、手机整书卡片)均加「📦 一键导出全套成品」按钮;页文件名识别收紧为"第NNN页_…"避免把成品文件误当页。POST /api/photo(多图即时上传存档,自动入识别队列)、POST /api/batch/process (把待识别/失败页重新排入队列)。页状态由磁盘推导:jpg 在=照片已上服务器;+txt=完成;+err.json=失败。/api/books、/api/books/<书>/pages 返回新增 done/todo/errors/status/err 等字段; /api/batch/export(folder)会报告 skipped(未识别/失败未并入的页)。GET /api/trash、POST /api/trash/restore、POST /api/trash/purge。 (历史教训:早期联调 rm 清理过测试目录,可能误删同名用户目录——现已改为回收站制。)GET /api/books、GET /api/books/<书>/pages?text=1、POST /api/books/delete、 POST /api/books/rename、POST /api/page/delete。GET /pc(static/index_pc.html):纯图片上传(多选 + 整窗拖拽),不依赖摄像头/HTTPS; 批量队列与识别节奏同手机版;每页支持 ✨ VL 修正 / 🔤 本地重跑 / 手动编辑 → 💾 保存修正, 修正写回服务器存档,整书合成自动采用。POST /api/page/reocr(对存档页重跑指定引擎,可选落盘)、POST /api/page/text(手动覆盖存档文本)。POST /api/batch/export:服务器端一次合成整书文本(session=本次拍摄按页序, folder=含历史页),落盘 全书文本_<时间>.txt 并返回下载链接;同秒多次合成自动加序号不覆盖。/api/ocr 响应新增 stem 字段供合成引用。deepseek-v4-flash-vision-exp, prompt 544 + completion 1348 tokens),存档/缩略图/文本下载路由均 200。_2.txt 不覆盖。reocr VL 重跑正常(save:false 不落盘 / save:true 覆盖存档,输出含 VL 空格特征); page/text 手动覆盖后 session 合成输出人工文本;合成文件为「修正后文本」。MAX_CONTENT_LENGTH 由 40MB(旧的"单图上限"注释其实是整请求上限)提升为 100×10MB+16MB ≈ 1.02GB;failed[] 说明原因,不拖垮整批);OCR_MAX_FILES(默认 100)、OCR_MAX_FILE_MB(默认 10)、OCR_MAX_UPLOAD_MB(默认 100×10+16);| --- | 分隔 + 数据行),不再拍平成用“/”或空格分隔的纯文本;并规定单元格内不用 <br>、同格多条用“;”、不去重重复行、照抄真实表头。_save_page_text():VL/本地识别结果为空、或比现有正文骤减到 <30% 时拒绝覆盖,改为写 err.json 并提示重试(force=true 可强制覆盖)。
POST /api/page/reocr 在触发闸门时返回 422 + 说明,不再静默写坏数据。