2026-06-22 08:31:19 +08:00
|
|
|
|
# OpenOCR Markdown Service
|
|
|
|
|
|
|
|
|
|
|
|
一个精简版图片/PDF 转 Markdown 服务,核心依赖 `openocr-python==0.1.5`,保留文档解析能力,去掉训练、评测和实验脚本。
|
|
|
|
|
|
|
2026-06-22 10:11:25 +08:00
|
|
|
|
**工作流**:Windows 本地编写代码 → Git 推送 → Ubuntu 服务器 Docker 运行。
|
|
|
|
|
|
|
2026-06-22 08:31:19 +08:00
|
|
|
|
## 功能
|
|
|
|
|
|
|
2026-06-22 10:11:25 +08:00
|
|
|
|
- `POST /api/recognize`:上传图片或 PDF,生成 Markdown 和 JSON
|
|
|
|
|
|
- `GET /api/history`:查看已解析文件列表
|
|
|
|
|
|
- `GET /output/...`:访问生成的 Markdown、JSON 和原始文件
|
|
|
|
|
|
- `GET /health`:健康检查
|
|
|
|
|
|
- `GET /docs`:Swagger API 文档
|
2026-06-22 11:06:01 +08:00
|
|
|
|
- `GET /v1/models`:OpenAI 兼容模型列表
|
|
|
|
|
|
- `POST /v1/chat/completions`:OpenAI 兼容文档转 Markdown 接口
|
2026-06-22 10:11:25 +08:00
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 服务器首次初始化(Ubuntu)
|
|
|
|
|
|
|
|
|
|
|
|
### 1. 克隆代码与创建目录
|
2026-06-22 08:31:19 +08:00
|
|
|
|
|
2026-06-22 10:11:25 +08:00
|
|
|
|
```bash
|
|
|
|
|
|
cd ~
|
|
|
|
|
|
git clone <你的仓库地址> OpenOCR
|
|
|
|
|
|
cd OpenOCR
|
|
|
|
|
|
mkdir -p data/output data/uploads
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 2. 生成并配置环境变量
|
2026-06-22 08:31:19 +08:00
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
cp .env.example .env
|
|
|
|
|
|
```
|
|
|
|
|
|
|
2026-06-22 10:11:25 +08:00
|
|
|
|
纯 Docker 部署时,重点确认以下配置:
|
2026-06-22 08:31:19 +08:00
|
|
|
|
|
2026-06-22 10:11:25 +08:00
|
|
|
|
```env
|
|
|
|
|
|
OPENOCR_AUTO_DOWNLOAD=true # 首次运行让容器自动下载模型
|
|
|
|
|
|
OPENOCR_USE_GPU=false # 未配置 NVIDIA Docker 插件前保持 false
|
|
|
|
|
|
OPENOCR_CORS_ORIGINS=*
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
完整配置项见 `.env.example`。
|
|
|
|
|
|
|
|
|
|
|
|
### 3. 一键编译并启动容器
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
docker compose up -d --build
|
2026-06-22 08:31:19 +08:00
|
|
|
|
```
|
|
|
|
|
|
|
2026-06-22 10:11:25 +08:00
|
|
|
|
### 4. 跟踪模型下载进度
|
|
|
|
|
|
|
|
|
|
|
|
模型体积较大,容器启动后会在后台自动下载。**此时不要急着调用接口**,先查看日志:
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
docker compose logs -f
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
首次下载可能需要 **5~30 分钟**(取决于网络)。当日志出现 `Application startup complete.` 且无报错时,说明模型加载完成,按 `Ctrl + C` 退出日志跟踪。
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 健康检查与验证
|
|
|
|
|
|
|
|
|
|
|
|
### 服务器本地
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
curl http://127.0.0.1:8000/health
|
|
|
|
|
|
# 期望返回: {"status":"ok"}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### Windows 本地浏览器
|
|
|
|
|
|
|
|
|
|
|
|
将 `服务器IP` 替换为实际地址:
|
|
|
|
|
|
|
|
|
|
|
|
- API 文档:`http://服务器IP:8000/docs`
|
|
|
|
|
|
- 健康检查:`http://服务器IP:8000/health`
|
|
|
|
|
|
|
|
|
|
|
|
若无法访问,请在云服务器安全组中放行 **8000** 端口。
|
2026-06-22 08:31:19 +08:00
|
|
|
|
|
2026-06-22 10:11:25 +08:00
|
|
|
|
### API 调用示例
|
2026-06-22 08:31:19 +08:00
|
|
|
|
|
|
|
|
|
|
```bash
|
2026-06-22 10:11:25 +08:00
|
|
|
|
# 上传图片/PDF 进行解析
|
|
|
|
|
|
curl -F "file=@/path/to/page.png" http://127.0.0.1:8000/api/recognize
|
|
|
|
|
|
|
|
|
|
|
|
# 查看历史记录
|
2026-06-22 08:31:19 +08:00
|
|
|
|
curl http://127.0.0.1:8000/api/history
|
2026-06-22 10:11:25 +08:00
|
|
|
|
|
|
|
|
|
|
# 强制重新识别(同名文件默认复用已有结果)
|
|
|
|
|
|
curl -F "file=@/path/to/page.png" -F "force=true" http://127.0.0.1:8000/api/recognize
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
成功响应示例:
|
|
|
|
|
|
|
|
|
|
|
|
```json
|
|
|
|
|
|
{
|
|
|
|
|
|
"id": "page",
|
|
|
|
|
|
"status": "success",
|
|
|
|
|
|
"message": "Parsed successfully in 12.34s.",
|
|
|
|
|
|
"markdown_url": "/output/page/page.md",
|
|
|
|
|
|
"json_url": "/output/page/page.json"
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
Markdown 访问地址:`http://服务器IP:8000/output/<文档名>/<文档名>.md`
|
|
|
|
|
|
|
2026-06-22 11:06:01 +08:00
|
|
|
|
### OpenAI 兼容接口
|
|
|
|
|
|
|
|
|
|
|
|
适用于已有 OpenAI SDK / LangChain / 各类 Agent 框架的调用方式。
|
|
|
|
|
|
若配置了 `OPENOCR_ROOT_PATH=/openocr`,则路径前缀为 `/openocr/v1/...`。
|
|
|
|
|
|
|
|
|
|
|
|
**列出模型**
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
curl https://jsuse.com/openocr/v1/models
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**文档转 Markdown(chat/completions)**
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
curl https://jsuse.com/openocr/v1/chat/completions \
|
|
|
|
|
|
-H "Content-Type: application/json" \
|
|
|
|
|
|
-d '{
|
|
|
|
|
|
"model": "opendoc-0.1b",
|
|
|
|
|
|
"messages": [
|
|
|
|
|
|
{
|
|
|
|
|
|
"role": "user",
|
|
|
|
|
|
"content": [
|
|
|
|
|
|
{"type": "text", "text": "Convert this document to markdown"},
|
|
|
|
|
|
{
|
|
|
|
|
|
"type": "image_url",
|
|
|
|
|
|
"image_url": {"url": "https://example.com/page.png"}
|
|
|
|
|
|
}
|
|
|
|
|
|
]
|
|
|
|
|
|
}
|
|
|
|
|
|
]
|
|
|
|
|
|
}'
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
也支持 `data:image/png;base64,...` 形式的图片 URL。
|
|
|
|
|
|
|
|
|
|
|
|
响应中的 `choices[0].message.content` 即为 Markdown 文本。
|
|
|
|
|
|
|
|
|
|
|
|
若设置了 `OPENOCR_API_KEY`,需附加请求头:
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
-H "Authorization: Bearer your-api-key"
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
Python 示例(OpenAI SDK):
|
|
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
|
from openai import OpenAI
|
|
|
|
|
|
|
|
|
|
|
|
client = OpenAI(
|
|
|
|
|
|
base_url="https://jsuse.com/openocr/v1",
|
|
|
|
|
|
api_key="your-api-key-or-empty",
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
response = client.chat.completions.create(
|
|
|
|
|
|
model="opendoc-0.1b",
|
|
|
|
|
|
messages=[
|
|
|
|
|
|
{
|
|
|
|
|
|
"role": "user",
|
|
|
|
|
|
"content": [
|
|
|
|
|
|
{"type": "text", "text": "Convert to markdown"},
|
|
|
|
|
|
{
|
|
|
|
|
|
"type": "image_url",
|
|
|
|
|
|
"image_url": {"url": "https://example.com/page.png"},
|
|
|
|
|
|
},
|
|
|
|
|
|
],
|
|
|
|
|
|
}
|
|
|
|
|
|
],
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
print(response.choices[0].message.content)
|
|
|
|
|
|
```
|
|
|
|
|
|
|
2026-06-22 10:11:25 +08:00
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 日常开发与更新
|
|
|
|
|
|
|
|
|
|
|
|
### Windows 本地
|
|
|
|
|
|
|
|
|
|
|
|
改完代码后推送到远程仓库:
|
|
|
|
|
|
|
|
|
|
|
|
```powershell
|
|
|
|
|
|
# 若已配置 git 快捷别名
|
|
|
|
|
|
gpush "feat: 优化 OCR 的 Markdown 布局解析器"
|
|
|
|
|
|
|
|
|
|
|
|
# 或标准命令
|
|
|
|
|
|
git add .
|
|
|
|
|
|
git commit -m "feat: 优化 OCR 的 Markdown 布局解析器"
|
|
|
|
|
|
git push
|
2026-06-22 08:31:19 +08:00
|
|
|
|
```
|
|
|
|
|
|
|
2026-06-22 10:11:25 +08:00
|
|
|
|
### Ubuntu 服务器
|
2026-06-22 08:31:19 +08:00
|
|
|
|
|
2026-06-22 10:38:41 +08:00
|
|
|
|
**只改了 Python 代码**(最常见):
|
|
|
|
|
|
|
2026-06-22 08:31:19 +08:00
|
|
|
|
```bash
|
2026-06-22 10:11:25 +08:00
|
|
|
|
cd ~/OpenOCR
|
|
|
|
|
|
git pull && docker compose up -d --build
|
2026-06-22 08:31:19 +08:00
|
|
|
|
```
|
|
|
|
|
|
|
2026-06-22 10:38:41 +08:00
|
|
|
|
优化后 Dockerfile 会分层缓存:`pyproject.toml` 不变时不会重装 `openocr-python` 等大依赖,通常 **10~30 秒** 即可完成。
|
|
|
|
|
|
|
|
|
|
|
|
**只改了 `.env` 配置**(无需重新 build):
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
docker compose up -d
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**依赖变更**(改了 `pyproject.toml`)才需要完整重建:
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
docker compose build --no-cache
|
|
|
|
|
|
docker compose up -d
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
模型缓存在 Docker 卷 `openocr-model-cache` 中,重建容器后**不会重复下载模型**。解析结果在 `./data/` 中,同样不会丢失。
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 启动速度优化说明
|
|
|
|
|
|
|
|
|
|
|
|
每次 `docker compose up -d --build` 很慢,通常有两类原因:
|
|
|
|
|
|
|
|
|
|
|
|
| 原因 | 现象 | 已做优化 |
|
|
|
|
|
|
|------|------|----------|
|
|
|
|
|
|
| pip 重复下载依赖 | build 阶段耗时数分钟 | Dockerfile 分层 + BuildKit pip 缓存 |
|
|
|
|
|
|
| 模型重复下载 | 启动后日志里又在下载 | 模型目录挂载到 `openocr-model-cache` 卷 |
|
|
|
|
|
|
|
|
|
|
|
|
**首次部署**仍需下载模型(5~30 分钟,一次性)。之后日常更新应明显变快。
|
|
|
|
|
|
|
|
|
|
|
|
若 BuildKit 缓存未生效,可确认 Docker 版本 ≥ 20.10,compose 会自动使用 BuildKit。
|
2026-06-22 10:11:25 +08:00
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 日常排错与手动测试
|
|
|
|
|
|
|
|
|
|
|
|
### 查看日志
|
2026-06-22 08:31:19 +08:00
|
|
|
|
|
|
|
|
|
|
```bash
|
2026-06-22 10:11:25 +08:00
|
|
|
|
docker compose logs -f openocr-markdown
|
2026-06-22 08:31:19 +08:00
|
|
|
|
```
|
|
|
|
|
|
|
2026-06-22 10:11:25 +08:00
|
|
|
|
### 命令行手动解析(不经过 API)
|
2026-06-22 08:31:19 +08:00
|
|
|
|
|
|
|
|
|
|
```bash
|
2026-06-22 10:11:25 +08:00
|
|
|
|
docker compose exec openocr-markdown openocr-md /app/data/uploads/test.pdf --output-dir /app/data/output
|
2026-06-22 08:31:19 +08:00
|
|
|
|
```
|
|
|
|
|
|
|
2026-06-22 10:11:25 +08:00
|
|
|
|
### 常用运维命令
|
2026-06-22 08:31:19 +08:00
|
|
|
|
|
2026-06-22 10:11:25 +08:00
|
|
|
|
```bash
|
|
|
|
|
|
docker compose ps # 查看容器状态
|
|
|
|
|
|
docker compose down # 停止服务
|
|
|
|
|
|
docker compose up -d --build # 重新构建并启动
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
---
|
2026-06-22 08:31:19 +08:00
|
|
|
|
|
|
|
|
|
|
## 关键配置
|
|
|
|
|
|
|
2026-06-22 10:11:25 +08:00
|
|
|
|
通过 `.env` 或环境变量配置:
|
2026-06-22 08:31:19 +08:00
|
|
|
|
|
2026-06-22 10:11:25 +08:00
|
|
|
|
| 变量 | 默认值 | 说明 |
|
|
|
|
|
|
|------|--------|------|
|
2026-06-22 10:21:13 +08:00
|
|
|
|
| `OPENOCR_ROOT_PATH` | *(空)* | 反向代理子路径,如 `/openocr` |
|
2026-06-22 10:11:25 +08:00
|
|
|
|
| `OPENOCR_OUTPUT_DIR` | `data/output` | 解析结果输出目录 |
|
|
|
|
|
|
| `OPENOCR_UPLOAD_DIR` | `data/uploads` | 上传文件临时目录 |
|
|
|
|
|
|
| `OPENOCR_USE_GPU` | `false` | 是否使用 GPU |
|
|
|
|
|
|
| `OPENOCR_AUTO_DOWNLOAD` | `true` | 首次运行自动下载模型 |
|
|
|
|
|
|
| `OPENOCR_LAYOUT_THRESHOLD` | `0.4` | 版面分析阈值 |
|
|
|
|
|
|
| `OPENOCR_MAX_LENGTH` | `2048` | 识别最大长度 |
|
|
|
|
|
|
| `OPENOCR_CORS_ORIGINS` | `*` | 跨域来源,多个用逗号分隔 |
|
2026-06-22 11:06:01 +08:00
|
|
|
|
| `OPENOCR_API_KEY` | *(空)* | OpenAI 兼容接口 Bearer Token,留空则不校验 |
|
|
|
|
|
|
| `OPENOCR_OPENAI_MODEL` | `opendoc-0.1b` | OpenAI 兼容接口使用的模型 ID |
|
2026-06-22 10:11:25 +08:00
|
|
|
|
| `OPENOCR_LOG_LEVEL` | `info` | 日志级别 |
|
2026-06-22 08:31:19 +08:00
|
|
|
|
|
2026-06-22 10:11:25 +08:00
|
|
|
|
---
|
2026-06-22 08:31:19 +08:00
|
|
|
|
|
|
|
|
|
|
## 项目结构
|
|
|
|
|
|
|
|
|
|
|
|
```text
|
|
|
|
|
|
.
|
|
|
|
|
|
├── src/openocr_markdown/
|
|
|
|
|
|
│ ├── api.py # FastAPI 服务
|
|
|
|
|
|
│ ├── cli.py # 命令行入口
|
|
|
|
|
|
│ ├── config.py # 环境变量配置
|
|
|
|
|
|
│ ├── engine.py # OpenOCR 模型加载和解析封装
|
|
|
|
|
|
│ └── schemas.py # API 响应模型
|
|
|
|
|
|
├── tests/
|
|
|
|
|
|
├── Dockerfile
|
|
|
|
|
|
├── docker-compose.yml
|
|
|
|
|
|
├── pyproject.toml
|
|
|
|
|
|
└── .env.example
|
|
|
|
|
|
```
|
2026-06-22 10:11:25 +08:00
|
|
|
|
|
2026-06-22 10:21:13 +08:00
|
|
|
|
## 反向代理(Nginx 子路径)
|
|
|
|
|
|
|
|
|
|
|
|
若通过 `https://jsuse.com/openocr/` 这类**子路径**访问(而非直接 `:8000`),必须在 `.env` 中设置:
|
|
|
|
|
|
|
|
|
|
|
|
```env
|
|
|
|
|
|
OPENOCR_ROOT_PATH=/openocr
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
否则 `/health` 可能正常,但 `/docs` 会报 **Failed to load API definition**——因为 Swagger 会去根路径请求 `/openapi.json`,而不是 `/openocr/openapi.json`。
|
|
|
|
|
|
|
|
|
|
|
|
Nginx 参考配置:
|
|
|
|
|
|
|
|
|
|
|
|
```nginx
|
|
|
|
|
|
location /openocr/ {
|
|
|
|
|
|
proxy_pass http://127.0.0.1:8000/;
|
|
|
|
|
|
proxy_set_header Host $host;
|
|
|
|
|
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
|
|
|
|
proxy_set_header X-Forwarded-Proto $scheme;
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
修改后重启容器:
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
docker compose up -d --build
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
2026-06-22 10:11:25 +08:00
|
|
|
|
## 注意事项
|
|
|
|
|
|
|
|
|
|
|
|
- `.env`、`data/`、模型缓存目录已在 `.gitignore` 中排除,不会进入 Git
|
|
|
|
|
|
- 首次启动耗时较长属于正常现象,等待模型下载完成后再调用接口
|
|
|
|
|
|
- 生产环境建议在 Docker 前加 Nginx 反向代理并配置 HTTPS
|