Metadata-Version: 2.4
Name: read4all
Version: 0.1.0
Summary: 多格式附件提取 MCP Server — MinerU 优先 + 本地降级,PDF/Office/图片/网页文档 → Markdown
Author: int2t
License-Expression: MIT
Project-URL: Homepage, https://gitcode.com/int2t/read4all
Project-URL: Issues, https://gitcode.com/int2t/read4all/issues
Keywords: mcp,markdown,pdf,mineru,document-conversion,ocr,claude
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Operating System :: OS Independent
Classifier: Topic :: Text Processing :: Markup :: Markdown
Classifier: Topic :: Office/Business :: Office Suites
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: mcp>=2.0
Requires-Dist: pymupdf
Requires-Dist: pypdf
Requires-Dist: pdfplumber
Requires-Dist: markitdown[docx,pptx,xlsx]
Requires-Dist: requests
Requires-Dist: pydantic>=2
Provides-Extra: test
Requires-Dist: pytest; extra == "test"
Requires-Dist: pytest-asyncio; extra == "test"
Requires-Dist: python-docx; extra == "test"
Requires-Dist: python-pptx; extra == "test"
Requires-Dist: openpyxl; extra == "test"
Requires-Dist: Pillow; extra == "test"
Dynamic: license-file

# read4all — 多格式附件提取 MCP Server

MinerU 云端优先 + 本地库降级的全格式附件读取器,以 MCP 工具暴露。把 PDF / Office / 图片 / 网页文档转为 Markdown + 图片,并提供 PDF 深度提取 API 与图片理解(供纯文本模型)。

```mermaid
flowchart LR
    A["附件<br/>PDF/DOCX/PPTX/XLSX/图片/HTML/..."] --> R[read4all MCP Server]
    R -->|MinerU 优先| M[MinerU 云端<br/>公式/表格/版面]
    R -->|降级| L[本地库<br/>pymupdf/pypdf/pdfplumber/MarkItDown]
    R --> O["<附件目录>/<stem>/<stem>.md + images/"]
    M -->|内容哈希缓存| R
```

## 快速开始(uvx 一键运行)

`uvx` 是 Python 版的 `npx`——自动构建隔离环境运行,无需预装 read4all。需先装 [uv](https://docs.astral.sh/uv/):

```bash
# macOS/Linux
curl -LsSf https://astral.sh/uv/install.sh | sh
# Windows PowerShell
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
```

### 形态一:发布到 PyPI 后(全局一键,推荐)

发布后任意目录均可,无需源码:

```bash
uvx read4all        # 类似 npx,一键运行
```

`.mcp.json`:

```json
{
  "mcpServers": {
    "read4all": { "command": "uvx", "args": ["read4all"] }
  }
}
```

发布(维护者):

```bash
uv build && uv publish   # 需 PyPI token
```

### 形态二:本地源码运行(当前未发布)

从项目根目录启动 Claude Code,`.mcp.json`:

```json
{
  "mcpServers": {
    "read4all": { "command": "uvx", "args": ["--from", ".", "read4all"] }
  }
}
```

或命令行:

```bash
uvx --from . read4all
```

### 形态三:开发模式(改代码即生效)

```bash
pip install -e ".[test]"   # 可编辑安装到当前 Python 环境
python -m read4all          # 或 pytest test/ -v
```

## MinerU 配置(可选,优先引擎)

未配置时自动降级本地库(秒级),功能仍可用。配置后启用高精度公式/表格/版面还原。

```bash
# Linux/macOS
export MINERU_API_KEY="your_token"
# Windows PowerShell
$env:MINERU_API_KEY = "your_token"
```

从 https://mineru.net/apiManage 获取 token。**切勿把 key 写入代码/配置文件**,仅用环境变量。

Claude Code 下两种方式把 key 传给 server(任选其一):

- **shell 环境变量**(推荐,不入库):在启动 Claude Code 的 shell 里 `export MINERU_API_KEY="..."`,uvx 子进程继承
- **`.mcp.json` env 字段**(注意:会把 key 写进文件):
  ```json
  {
    "mcpServers": {
      "read4all": {
        "command": "uvx", "args": ["read4all"],
        "env": { "MINERU_API_KEY": "your_token" }
      }
    }
  }
  ```

## 工具

唯一转换入口 + 能力查询,共 2 个工具。深度提取能力不单独暴露,而是**融入 convert 降级链**:

| 工具 | 说明 | 引擎 |
|---|---|---|
| `get_capabilities` | 支持格式/引擎/MinerU 状态 | — |
| `convert_to_markdown` | 全格式 → Markdown + 图片(产物同级目录) | MinerU 优先 + 按格式降级 |

**convert 的降级链(其他能力都做降级处理)**:

| 降级路径 | 融入的深度能力 | 产出 |
|---|---|---|
| PDF(无 MinerU) | 表格(pypdf+pdfplumber 并行择优 → markdown table)+ 图表几何标注(pymupdf get_drawings)+ 嵌入图片(存盘) | 文本 + 表格 + 图表标注 + 图片 |
| Office(无 MinerU) | zipfile 提取嵌入图 | MarkItDown + 图片 |
| 图片 | 直接复制 | images/ |
| 网页(HTML/EPUB/CSV/JSON/XML/TXT) | — | MarkItDown |

`describe_images=True` 时为提取图跑 MinerU 图片理解,文本写入 alt(供纯文本模型)。

## 产物契约

输入 `<dir>/<stem>.<ext>` → 产物落到**附件同级目录**:

```
<dir>/
├── <stem>.<ext>          ← 原附件
└── <stem>/               ← 同级产物目录
    ├── <stem>.md         ← Markdown(图片以 ![图片 img1.png](images/img1.png) 引用)
    └── images/           ← 提取图片,统一 imgN.<ext> 命名
```

`convert_to_markdown` 返回 `{md_path, images_dir, image_count, engine_used, fallback_reason, page_count, char_count, preview}`(preview = Markdown 前 2000 字符预览,供 LLM 即用;完整内容 Read `md_path`)。

## 引擎路由

| 格式                        | 首选           | 降级                                   |
| --------------------------- | -------------- | -------------------------------------- |
| PDF                         | MinerU(vision) | pymupdf(文本+图片存盘)→ pypdf(纯文本) |
| DOCX/PPTX/XLSX              | MinerU(结构化) | MarkItDown + zipfile 提图              |
| 图片(PNG/JPG/BMP/TIFF/WEBP) | —             | 直接复制到 images/                     |
| HTML/EPUB/CSV/JSON/XML/TXT  | —             | MarkItDown                             |

降级触发:`MINERU_API_KEY` 未设 / 401 / 429 / 超时 / >200MB 或 >200 页。结果含 `engine_used` + `fallback_reason`。

## 图片理解(供纯文本模型)

让非多模态模型也能"看图"——为图片生成文本描述,挂为 alt / 返回结构化字段。

| 路径   | 引擎   | 产出                                   | 适用                                                         |
| ------ | ------ | -------------------------------------- | ------------------------------------------------------------ |
| 首选   | MinerU | 图片→转 PDF→结构化 OCR 文本          | 文档型图片(截图/扫描/含文字图表)                             |
| 扩展点 | VLM    | 视觉大模型自然语言描述                 | 通用图片(预留`description` 字段,需配置 `READ4ALL_VLM_*`) |
| 降级   | —     | 空描述 +`fallback_reason`,图片仍落盘 | —                                                           |

- `understand_image(image_path)` 返回 `{text, description, engine_used, fallback_reason}`
- `convert_to_markdown(..., describe_images=True)` 转换时为每张提取图跑理解,文本写入 alt(复用 `update_image_alts`)

VLM 语义描述扩展(可选,启用通用图片语义):

```bash
export READ4ALL_VLM_BASE_URL="https://api.openai.com/v1"   # OpenAI 兼容 vision 端点
export READ4ALL_VLM_API_KEY="..."
export READ4ALL_VLM_MODEL="gpt-4o-mini"                     # 或 claude-3-5-haiku / gemini-2.0-flash / 本地 Qwen-VL
```

未配置时 `description=None`,MinerU `text` 仍可用(文档型图片足够);配置后通用图片(照片/图表)语义描述启用。

## MinerU 内容哈希缓存

MinerU 单次 30s~3min。同文件重复转换命中缓存即秒级返回(内容寻址,文件改动自动失效):

- 缓存键 = `sha1(文件内容)[:16]` + 参数哈希
- 缓存目录:`~/.cache/read4all/mineru/<key>/`(存 `markdown.md` + `content_list.json` + `images/`)

## 测试

```bash
pip install -e ".[test]"
python -m pytest test/ -v
```

真实数据测试(无 mock):夹具在 `test/conftest.py` 运行时生成(pymupdf 造 PDF/PNG,stdlib zipfile 造 DOCX/XLSX)。MinerU 降级路径用真实环境(key 缺失)触发;缓存命中用预填缓存(不触网)。MinerU 成功路径需 key+网络,为手动集成测试。

## 能力边界

- 仅读,不做 PDF 生成/合并/拆分/表单
- 本地库不还原矢量路径公式、不做本地 OCR(均需 MinerU)
- Office/网页无表格择优/图表矢量/字符坐标概念(仅 PDF 深度 API)

架构细节见 [docs/architecture.md](docs/architecture.md)。
