Bundle
@deepseek-ai/dsh-ocr-vision
Model-facing ocr_image tool that runs local RapidOCR (via a Python subprocess) and returns image text as plain text, so text-only DeepSeek models can read images
- Source
- QEDQCD
- License
- MIT
- Updated
- Updated 3 days ago
Readme
# dsh-ocr-vision
一个 **DeepSeek Harness 插件**(bundle),让**纯文本大模型**(如 DeepSeek)也能"看图"——
新增模型侧 `ocr_image` 工具,用本地 **RapidOCR** 把图片文字提取成纯文本返回给主聊,而不是
把图片发给模型。这是 [`claude-ocr-vision`](../claude-ocr-vision)(Claude Code / Codex 版)在
DeepSeek Harness 上的对应实现。
---
## 解决什么问题
运行 DeepSeek Harness 接入**纯文本大模型**(DeepSeek 无多模态)时,模型需要识图时会调用
`read_image` 工具,把图片作为 content block 发给后端。纯文本路由没有图片输入能力,`read_image`
在 `tool-fs` 侧会严格拒绝("does not declare image input"),模型看到一条错误。
本插件从根上避免这件事:提供 `ocr_image` 工具,把图里文字用本地 OCR 提取成纯文本返回,
模型永远只处理文本。同时通过系统提示段引导模型在纯文本路由下优先用 `ocr_image`。
## 工作机制
```
模型需要看图
│ 调用 ocr_image(file_path, region?, scale?)
▼
ocr-vision 插件:通过 ctx.fs 读取图片字节(受沙箱/观察策略约束)
│ 写入临时文件
▼
ocr.py(RapidOCR,2 倍放大、按阅读顺序还原版面)
│
▼
纯文本(阅读顺序/坐标)──► 主聊继续任务(图片从不进模型上下文)
```
- **工具**:`ocr_image`,模型侧 schema,输出纯文本。图片字节永远不发给模型 API。
- **脚本**:`ocr.py`,RapidOCR 封装(2 倍放大、`--region` 区域裁剪、`--coords`/`--json` 坐标、
`<无文字>` 空图容错),与 claude-ocr-vision 共用同一份。
- **技能**:`SKILL.md`,任务导向三步流程(先明确识图目的/关注区域/任务关联,再提取,再围绕任务组织文本)。
- **系统提示段**:`tool:ocr-vision`,引导模型在纯文本路由下用 `ocr_image`。
## 安装
### 系统要求
| 项目 | 说明 |
|---|---|
| **操作系统** | Linux 或 macOS(Windows 未测试) |
| **Python** | 3.7+ |
| **Python 依赖** | `rapidocr-onnxruntime`、`pillow`、`numpy`(缺失时 `ocr_image` 会失败并报错) |
| **DeepSeek Harness** | `dsh` CLI 与一个 profile(如 `headless` / `web`) |
### 一句话让 Agent 帮你装
把下面整段复制给你的 Agent(Claude Code / Cursor / Codex 均可):
> 请先阅读 https://github.com/QEDQCD/dsh-ocr-vision 的 README.md「系统要求」,确认本机满足(Linux/macOS、Python 3.7+、已装 `rapidocr-onnxruntime`/`pillow`/`numpy`、有 `dsh` CLI 与一个 profile 如 `headless`);不满足则先告知我缺什么。满足后:克隆到任意目录,在该目录内运行 `pnpm install && pnpm build`(或对应 npm 命令),再运行 `node scripts/install.mjs --profile headless`(profile 名按我实际用的改),验证 `dsh --profile headless --dump-config | grep ocr-vision` 能输出,且 `python3 ocr.py <某图片路径>` 能正常提取文字。
### 构建并安装到 profile
```bash
cd dsh-ocr-vision
pnpm install # 或 npm install(安装 devDeps 以构建)
pnpm build # tsc 编译 src -> lib
node scripts/install.mjs --profile headless
```
安装脚本(幂等)把 bundle 拷入 `$DSH_HOME/profiles/<name>/node_modules/@deepseek-ai/dsh-ocr-vision`,
把 `SKILL.md` 拷入 profile 的 `skills/`,并把 `@deepseek-ai/dsh-ocr-vision` 注册进 profile 的
`dsh.profile.bundles`。之后 `dsh --profile <name>` 启动即挂载 `ocr_image` 工具。
卸载:
```bash
node scripts/install.mjs --profile headless --uninstall
```
### 验证
```bash
# 1) OCR 脚本可用(本机需有 RapidOCR)
python3 ocr.py <某图片路径> # 输出提取的文本(或 <无文字>)
# 2) 工具已挂载
dsh --profile headless --dump-config | grep ocr-vision
```
新开会话后,让模型"读这张图",应看到它调用 `ocr_image` 返回纯文本,而不是 `read_image` 报错。
### 从 GitHub 分发/安装(免 npm 发布)
本包是 dsh bundle(`package.json` 声明 `dsh.bundle`),`dsh plugin` 支持从 GitHub 直装,
仓库公开即可,无需发布 npm:
```bash
dsh plugin --profile headless add github:QEDQCD/dsh-ocr-vision
# 或指定分支/标签:github:QEDQCD/dsh-ocr-vision#main
```
`dsh plugin add` 会把包名(`@deepseek-ai/dsh-ocr-vision`)注册进 profile 的
`dsh.profile.bundles`,并自动挂载 `ocr_image` 工具。安装后仍需满足本机
RapidOCR/Python 依赖(见「系统要求」)。
> 将来发布到 npm 后,可改用 `dsh plugin --profile <name> add @deepseek-ai/dsh-ocr-vision`。
> `package.json` 已带 `keywords`/`repository`/`publishConfig.access`,便于 registry 检索与公开发布。
## 使用
模型侧直接调用(或经技能引导):
```text
ocr_image(file_path: "截图.png")
ocr_image(file_path: "截图.png", region: "120,80,600,400") # 只识别关注区域
```
预期输出(工具返回的纯文本信封):
```text
<path>/workspace/截图.png</path>
<type>ocr</type>
<content>
报错码:ERR_DB_CONN_TIMEOUT
关键行:Connection refused -> db.internal:5432 / retry 3/3 failed
</content>
```
## 配置
`ocr_image` 插件可通过 cordis 配置调整:
| 字段 | 默认 | 含义 |
|---|---|---|
| `pythonBin` | `python3` | 运行 `ocr.py` 的 Python 解释器 |
| `ocrScript` | 随包 `ocr.py` | RapidOCR CLI 脚本路径 |
| `ocrCommand` | 空 | 完整命令前缀,覆盖 `pythonBin`+`ocrScript`(测试/定制宿主用) |
| `scale` | `2` | 默认放大倍数(小字更准) |
| `maxImageBytes` | `50 MiB` | 经 `ctx.fs` 读取的最大图片字节 |
| `timeoutMs` | `60000` | 单次 OCR 子进程超时 |
## 目录结构
```
dsh-ocr-vision/
├── package.json # @deepseek-ai/dsh-ocr-vision,bundle 声明(dsh.bundle.patch)
├── cordis.patch.yml # bundle 补丁:把 ocr-vision 插件插入 profile
├── src/
│ ├── index.ts # ocr_image 工具 + 系统提示段
│ ├── ocr.ts # OCR 引擎调用(可注入 command)
│ └── invariant.ts # 包级 invariant 伴生
├── ocr.py # RapidOCR 封装(与 claude-ocr-vision 共用)
├── SKILL.md # 任务导向 OCR 技能
├── scripts/install.mjs # 安装/卸载到指定 profile
├── tsconfig.json
├── README.md
└── LICENSE
```
## 隐私与安全
- **图片不进 API**:`ocr_image` 只返回提取的文本,图片字节从不上行到模型。
- **本地 OCR**:`ocr.py` 用本地 RapidOCR 推理,图片不出本机。
- **走 fs 策略**:图片通过 `ctx.fs` 读取,受沙箱与观察策略约束;临时文件用后即删。
- **仓库洁净**:仓库不含任何密钥、token、个人数据或真实图片。
## 开发与测试
插件源码在 monorepo 中作为工作区包 `packages/fs/ocr-vision` 开发,单测用确定性 fixture OCR
命令(不依赖 Python),并跑真实组合测试。分发时把 `src/`、`ocr.py`、`SKILL.md` 同步到本 bundle。
测试确定性的 OCR 引擎注入:
```ts
ctx.plugin(OcrVision, { ocrCommand: ['node', '-e', 'process.stdout.write("fixture-ocr[...]")'] })
```
## 已知限制与后续
- **需要 Python + RapidOCR 宿主**:默认引擎以子进程跑 `ocr.py`,宿主需装
`rapidocr-onnxruntime`、`pillow`、`numpy`;否则 `ocr_image` 会报错。可用 `ocrCommand` 换引擎。
- **不支持 PDF 输入**:仅光栅图片(PNG/JPEG/WebP/GIF/BMP/TIFF 等,见 `ocr.py`)。PDF 光栅化未实现。
- **不拦截 `read_image`**:本插件只新增 `ocr_image` 与引导,不改写/拒绝 `read_image`;
纯文本路由若调用 `read_image` 仍会得到 `tool-fs` 的严格拒稿。Install
dsh plugin --profile web add github:QEDQCD/dsh-ocr-vision#8de7cf84db16a95501018f4506ceed876dec1695
Profile: web
With the hub plugin installed, ask your agent to install it by name — it resolves the same plan shown here.
dsh plugin --profile web add github:stvlynn/dsh.fish#path:packages/dsh-plugin-hub
install deepseek-ai-dsh-ocr-vision from the hub
- This package builds from source on install. pnpm will ask you to allow its build script — that is permission to run the package’s code on your machine, outside the agent sandbox. Only allow sources you trust.