glm-ocr-mcp
# glm-ocr-mcp — GLM-OCR 文档识别工具(PDF/图片 → Markdown)
> **无纸化学习大部头教材的首选工具**:可把上百 MB、几百页的扫描版经典教材
> 整体 OCR 成 Markdown,按章节拆分归档,
> 再配合 Obsidian + DSH 等 AI 助手随时检索、提问、做笔记。
基于智谱 [GLM-OCR](https://github.com/zai-org/GLM-OCR)(官方 `glmocr` SDK,MaaS 云端模式)的本地工具包,提供 **CLI / HTTP / MCP 三个入口**,把图片与 PDF(含扫描版大书)识别为 Markdown,供 AI Agent 或其他程序随时调用。
**核心特性**:
- 📄 **PDF → Markdown**:自动按 8 页/片切分、逐片识别后合并,支持页码范围(`3-10`),临时文件用后即删
- 📚 **大部头教材专用**:上百 MB / 几百页扫描书整本识别;配合 `add_bookmarks.py` + `chapter2md.py` 按书签逐章拆分输出,Obsidian 笔记库 + DSH 等 AI 助手无缝接入
- 🖼️ **图片 OCR**:本地路径 / http(s) URL / data URI,多格式(png / jpg / jpeg / webp / bmp / tiff / gif)
- 📏 **长条图片切片**:超长截图(聊天记录、网页长图、试卷长图)自动切片识别,按单元格/行粒度去重重叠区
- ⏱️ **进度反馈**:超大 PDF 切片后即告知片数与预计用时,识别期间持续汇报百分比 / 已用时间 / 预计剩余;支持中途取消
- 🔌 **MCP 服务器**(stdio):供 ZCode / Claude Desktop / Claude Code / Cursor / Obsidian DSH 等 MCP 客户端直接调用
- ⚡ **即用即走**:CLI 无常驻进程,进程做完即退;API Key 支持 `ZHIPU_API_KEY` 环境变量或 config.json
## 典型场景:大部头教材的无纸化学习
软件工程经典教材(计算机网络、计算机组成原理、操作系统等)动辄几百页、上百 MB:
纸质书又厚又重,扫描版 PDF 无法检索、没法做笔记,"把代码印在纸上"的大部头更是
翻到崩溃。本工具专为此设计,一条龙完成数字化:
1. **整书 OCR**:`ocr pdf "计网.pdf"` 一把梭——上百 MB / 几百页自动分片识别,
跑的过程中持续报告进度(片数 / 百分比 / 预计剩余时间),跑完得到整本书的 Markdown
2. **按章节拆分**:扫描书先 `add_bookmarks.py` 注入目录书签,再 `chapter2md.py`
按章节输出独立 `.md`(每章一个文件 + 图片目录),已完成的章节自动跳过、可断点续跑
3. **归档进 Obsidian**:把各章 `.md` 放进笔记库,图片引用自动重命名、跨章不冲突
4. **随时 AI 检索**:通过 MCP 服务器接入 DSH 等 AI 助手——问"第三章讲了什么"、
复述某个算法的伪代码、生成课后习题解答,AI 直接基于 OCR 好的章节内容作答
从此告别抱着几百页纸翻找,一份 Markdown 笔记库随身带。
## 安装
要求 Python ≥ 3.10。
```bash
pip install glmocr mcp fastapi uvicorn pymupdf pillow requests
# 或安装本仓库(推荐,会获得 ocr / ocr-server / ocr-mcp 三个命令):
pip install -e .
```
## 配置
API Key 在 [open.bigmodel.cn](https://open.bigmodel.cn) 控制台「API Keys」创建,二选一填入:
**方式 1(推荐):环境变量**
```bash
# Linux / macOS
export ZHIPU_API_KEY=你的密钥
# Windows CMD
set ZHIPU_API_KEY=你的密钥
# Windows PowerShell
$env:ZHIPU_API_KEY = "你的密钥"
```
**方式 2:config.json(一次配置永久生效;MCP 场景最稳)**
```bash
cp ocr_agent/config.example.json ocr_agent/config.json
# 编辑 ocr_agent/config.json,把 "api_key": "" 填成自己的密钥
```
CLI / HTTP / MCP 三个入口都从 `ocr_agent/config.json` 读取同一个 key(文件不存在时首次运行会自动生成,含自动生成的 http_token,直接编辑 api_key 即可)。
> 优先级:`ZHIPU_API_KEY` / `GLMOCR_API_KEY` 环境变量 **覆盖** config.json。验证方式:`ocr doctor`,看到 `api_key: OK (已配置,52e25a...vrix)` 即生效。
>
> MCP 场景:key 填在 config.json 则开箱即用(按模块位置解析,与启动目录无关);若用环境变量,需保证启动 MCP 客户端的进程环境里有该变量。**config.json 已加入 .gitignore,切勿提交。**
## CLI 用法(主路径,无常驻)
```bash
ocr doctor # 环境自检
ocr image "截图.png" # 图片 OCR → stdout Markdown
ocr image "截图.png" --json # 输出完整 JSON(含区域级 json_result)
ocr pdf "扫描书.pdf" # PDF OCR(自动分片)
ocr pdf "扫描书.pdf" --pages 3-10 # 指定页码(1-indexed 闭区间)
ocr pdf "扫描书.pdf" -o 笔记.md # 另存 Markdown
ocr serve --port 8765 # 可选:启动本地 HTTP 服务(常驻)
```
输出约定(AI 解析用):stdout 为 Markdown 正文(`--json` 时为完整 JSON);stderr 为 JSON 状态行;退出码 0 成功 / 1 失败。
### 进度输出(CLI)
`ocr pdf` 处理大文件时,stderr 会输出进度 JSON 行:
```json
{"status":"processing","kind":"pdf","event":"chunked","chunk_count":25,"pages":[1,446],"total_pages":446,"estimated_seconds":1500}
{"status":"processing","kind":"pdf","event":"chunk_start","chunk":3,"chunk_count":25,"percent":8.0,"elapsed_seconds":220,"eta_seconds":1320}
{"status":"processing","kind":"pdf","event":"heartbeat","chunk":3,"chunk_count":25,"percent":8.0,"elapsed_seconds":300,"eta_seconds":1240}
{"status":"processing","kind":"pdf","event":"chunk_done","chunk":3,"chunk_count":25,"percent":12.0,"elapsed_seconds":330,"eta_seconds":1180,"chunk_seconds":110.2}
```
- `chunked`:切片完成,告知片数与预计用时(首片按 `pdf_eta_seconds_per_chunk` 估算,之后按实测自动修正)
- `chunk_start` / `chunk_done`:每片开始/完成,带 `percent` / `elapsed_seconds` / `eta_seconds`
- `heartbeat`:单片耗时超过 60 秒时每 60s 补一行,避免长时间无输出
## HTTP 服务(可选,常驻)
```bash
ocr-server # 或 python ocr_agent/server.py
```
启动后提供(全部业务端点需 `Authorization: Bearer <http_token>`,token 在 config.json,首次运行自动生成):
| 端点 | 说明 |
|---|---|
| `GET /health` | 健康检查(公开) |
| `POST /v1/chat/completions` | OpenAI 兼容(`image_url` → OCR Markdown) |
| `POST /api/v1/ocr/image` | `{path\|url\|base64}` → `{status, markdown, json_result}` |
| `POST /api/v1/ocr/pdf` | 同步 PDF OCR(40 页上限,超大文件请用异步端点或 CLI) |
| `POST /api/v1/ocr/pdf/async` | **异步任务**:`{path, pages}` → `{task_id}`(无页数上限) |
| `GET /api/v1/ocr/tasks/{id}` | 查询任务进度(percent / eta / elapsed / chunk / status) |
| `DELETE /api/v1/ocr/tasks/{id}` | 取消任务(分片边界生效) |
异步示例:
```bash
TOKEN=$(python -c "import json;print(json.load(open('ocr_agent/config.json'))['http_token'])")
curl -s -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"path":"D:/书.pdf","pages":"all"}' http://127.0.0.1:8765/api/v1/ocr/pdf/async
# -> {"task_id":"ab12cd34ef56", ...}
curl -s -H "Authorization: Bearer $TOKEN" http://127.0.0.1:8765/api/v1/ocr/tasks/ab12cd34ef56
# -> {"status":"running","percent":36.0,"chunk":9,"chunk_count":25,"eta_seconds":960, ...}
```
## MCP 服务器(推荐,供各类 Agent 调用)
```bash
ocr-mcp # 或 python ocr_agent/mcp_server.py(stdio,由 MCP 客户端拉起)
```
工具列表:
| 工具 | 说明 |
|---|---|
| `ocr_image(source)` | 单张图片 OCR → Markdown |
| `ocr_pdf(path, pages)` | PDF OCR(小文件直接调用;客户端传 `progressToken` 时推送标准进度通知) |
| `ocr_long_image(source, slice_height?, overlap?)` | 长条图片切片识别 |
| `start_pdf_ocr(path, pages)` | **异步**启动 PDF OCR,立即返回 `task_id`(超大 PDF 用,不阻塞) |
| `get_ocr_status(task_id)` | 查询任务进度(percent / eta / elapsed / chunk / message,done 时含 markdown) |
| `cancel_ocr_task(task_id)` | 取消任务(分片边界生效) |
| `doctor()` | 环境自检 |
**超大 PDF 的推荐调用方式**:`start_pdf_ocr` 拿到 `task_id` → 每隔 1–5 分钟调 `get_ocr_status` 并向用户汇报百分比与预计剩余时间 → 完成取结果(或中途 `cancel_ocr_task`)。
**注册示例**(把 `<项目路径>` 换成实际路径):
```json
{
"mcpServers": {
"glm-ocr": {
"command": "python",
"args": ["<项目路径>/ocr_agent/mcp_server.py"]
}
}
}
```
- **ZCode**:写入 `<项目路径>/.zcode/config.json` 的 `mcp.servers.glm-ocr`(工作区级,打开自动连接)
- **Claude Code / Cursor**:`.mcp.json`(仓库根,已被 .gitignore 排除,请按各自客户端文档配置)
## 长条图片切片(ocr_long_image)
超长截图直接提交会超过 GLM-OCR 接口的图片尺寸限制。`ocr_long_image` 自动处理:读取多格式图片 → 任一维度超过 `slice_height`(默认 3000px)时沿超限轴切片(相邻重叠 200px)→ 逐片识别 → 按单元格/行粒度去重重叠区(GLM-OCR 会把连续文本渲染成 HTML 表格,已按表格单元格处理)。
返回 `{"status":"ok","markdown","size","chunk_count","chunks":[{index,x,y,markdown}]}`,`chunks[].x/y` 为切片在原图中的像素坐标。参数可在调用时传,也可在 config.json 配置 `slicing_slice_height` / `slicing_overlap`。
## 扫描书工作流工具
针对扫描版教材的辅助脚本(位于仓库根,与本包相对独立):
| 脚本 | 说明 |
|---|---|
| `chapter2md.py` | 按 PDF 书签逐章转换:每章独立目录输出 `.md` + 图片,已存在章节自动跳过(`--force` 重做) |
| `add_bookmarks.py` | 为无书签的扫描 PDF 注入目录书签(供 chapter2md 按章切分) |
| `fix_md_formulas.py` | 对生成的 Markdown 做公式/格式后处理 |
## 配置项(ocr_agent/config.json)
| 字段 | 默认 | 说明 |
|---|---|---|
| `api_key` | 空 | 智谱 API Key,可被 `ZHIPU_API_KEY` 环境变量覆盖 |
| `http_port` / `http_token` | 8765 / 自动生成 | HTTP 服务端口与 Bearer token |
| `timeout` | 600 | 单次 API 调用超时(秒) |
| `pages_per_chunk` | 8 | PDF 每分片页数 |
| `pdf_max_pages_http` | 40 | HTTP 同步端点的页数上限 |
| `retries` | 2 | 失败重试次数(指数退避) |
| `pdf_eta_seconds_per_chunk` | 60 | 大 PDF 预计用时初值(每片秒数,实测后自动修正) |
| `slicing_slice_height` / `slicing_overlap` | 3000 / 200 | 长条图片切片参数(像素) |
## 测试
```bash
python ocr_agent/test_ocr.py # 图片/PDF OCR 冒烟(真实 API)
python ocr_agent/test_slicing.py # 长条图片切片 + 多格式(真实 API)
python ocr_agent/test_mcp.py --api # MCP 服务器 + 异步任务端到端(真实 API)
python ocr_agent/test_progress.py # 进度事件 / 取消 / 任务生命周期 / CLI / HTTP(真实 API)
```
未配置 API Key 时测试自动跳过(`ZHIPU_API_KEY` 或 config.json)。真实 API 用例会消耗少量额度。
## 开源说明
- 本仓库基于 [zai-org/GLM-OCR](https://github.com/zai-org/GLM-OCR) 官方 SDK(`glmocr`,MIT),云端模式调用,无需 GPU
- 模型:GLM-OCR([open.bigmodel.cn](https://open.bigmodel.cn) 获取 API Key)
- 本仓库 License:MIT
## 常见问题
- **提示缺少 API Key**:设置 `ZHIPU_API_KEY` 环境变量,或填写 `ocr_agent/config.json` 的 `api_key`
- **大 PDF 超时**:HTTP 同步端点限 40 页;整本请用 CLI(`ocr pdf`)或异步端点/`start_pdf_ocr`
- **图片过小被拒(错误 1214)**:GLM-OCR 接口对最小尺寸有要求,截图类图片不受影响
- **长截图识别**:用 `ocr_long_image`(自动切片)或 `slicing.slice_and_ocr()`
- **识别太慢没输出**:看 stderr 的进度行;用异步任务(MCP `start_pdf_ocr` / HTTP `/api/v1/ocr/pdf/async`)可随时查询
TDQS
Scored across 7 tools
Each tool has a clear function: image OCR, long-image OCR, PDF OCR, async task management, and health check. The only potential overlap is ocr_pdf vs start_pdf_ocr, but their descriptions differentiate by synchronous vs asynchronous execution.
Most tools follow a recognizable verb_noun pattern: ocr_image, ocr_pdf, get_ocr_status, cancel_ocr_task, start_pdf_ocr. The outlier is 'doctor', which breaks the pattern but is still an understandable command-style name.
Seven tools is well-scoped for an OCR server: it covers the main input types (image, long image, PDF), both sync and async PDF paths, task status, cancellation, and environment self-check. No tool feels redundant or missing.
The tool surface covers the core OCR domain well: images, long images, PDFs with page ranges, async task lifecycle, and configuration readiness. There are no obvious dead ends for common OCR workflows.