firecrawl/anydoc

GitHub: firecrawl/anydoc

anydoc 是一款基于 Rust 构建的高性能文档转换库,可将十四种主流 Office 文档及 PDF 快速转换为统一、整洁的 Markdown 文本。

Stars: 1551 | Forks: 67

# anydoc [![Crates.io](https://img.shields.io/crates/v/anydoc.svg)](https://crates.io/crates/anydoc) [![npm](https://img.shields.io/npm/v/@firecrawl/anydoc.svg)](https://www.npmjs.com/package/@firecrawl/anydoc) [![PyPI](https://img.shields.io/pypi/v/firecrawl-anydoc.svg)](https://pypi.org/project/firecrawl-anydoc/) [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE) [![skills.sh](https://skills.sh/b/firecrawl/anydoc)](https://skills.sh/firecrawl/anydoc) 快速的 Rust 库,可将文档(Word、PowerPoint、Excel、OpenDocument、RTF、EPUB、CSV 和 PDF)转换为整洁的 GitHub-Flavored Markdown。包含 [Node.js](node/README.md) 和 [Python](python/README.md) 的绑定。 由 [Firecrawl](https://firecrawl.dev) 构建,旨在将任何 Office 文档在个位数的毫秒级时间内转换为适配 LLM 的 Markdown,无论输入的是哪种格式,都能提供一致的输出。它为 [Firecrawl Parse](https://firecrawl.dev/parse) 提供支持,因此如果您不想自己运行它,托管 API 可为您提供相同的转换,并为 anydoc 无法自行读取的扫描页面提供我们的 OCR 模型。 ## 快速开始 ### Agent 技能 anydoc 以 [Agent Skill](https://agentskills.io) 的形式发布,因此您的 agent 可以读取它遇到的任何文档: ``` npx skills add firecrawl/anydoc ``` 该[技能](skills/convert-documents-to-markdown/SKILL.md)教会 agent 使用 anydoc CLI 转换文档。与 [Claude Code](https://claude.ai/code)、[Codex](https://openai.com/codex/)、[Cursor](https://cursor.com)、[OpenCode](https://opencode.ai) 以及任何其他[兼容的 agent](https://agentskills.io/clients) 兼容。 ### CLI ``` npx @firecrawl/anydoc report.docx # Markdown to stdout npx @firecrawl/anydoc slides.pptx -o slides.md # or to a file npx @firecrawl/anydoc - --format csv < data.csv # read stdin ``` `npx` 在首次运行时会下载适合您平台的预编译二进制文件。如果需要永久使用 `anydoc` 命令,请使用 `npm install -g @firecrawl/anydoc` 进行全局安装。运行 `anydoc --help` 查看所有选项。 ### Node.js ``` npm install @firecrawl/anydoc ``` ``` import { toDocument, toMarkdown, toMarkdownBytes } from '@firecrawl/anydoc'; // From a file path: const markdown = await toMarkdown('report.docx'); // From bytes, with the format detected from the content: const fromBytes = await toMarkdownBytes(bytes); // Or name it, which signature-less formats (CSV) need: const fromCsv = await toMarkdownBytes(bytes, 'csv'); // Or stop at the document model, which also carries embedded assets: const document = await toDocument(bytes); ``` ### Python ``` pip install firecrawl-anydoc ``` ``` import anydoc # 从文件路径: markdown = anydoc.to_markdown("report.docx") # 从字节,从内容中检测格式: markdown = anydoc.to_markdown_bytes(data) # 或者为其命名,无签名格式 (CSV) 需要: markdown = anydoc.to_markdown_bytes(data, "csv") # 或者停在文档模型,它也携带嵌入的资产: document = anydoc.to_document(data) ``` ### Rust ``` cargo add anydoc ``` ``` // From a file path: let markdown = anydoc::to_markdown("report.docx")?; // From bytes, with the format detected from the content: let markdown = anydoc::to_markdown_bytes(&bytes, None)?; // Or name it, which signature-less formats (CSV) need: let markdown = anydoc::to_markdown_bytes(&bytes, anydoc::Format::Csv)?; // Or stop at the document model, which also carries embedded assets: let document = anydoc::to_document(&bytes, None)?; ``` ## 功能特性 - **每种格式提供统一的输出。** 每种格式都会解析为共享的文档模型,并通过单一的 Markdown 序列化器进行渲染,因此无论是 2003 年的 `.doc` 还是昨天的 `.pptx`,其转义、表格、标题锚点和脚注的行为都完全一致。 - **完整的文档结构。** 带有锚点的标题、粗体/斜体/删除线、内联代码和代码块、链接和内部交叉引用、带有源文档自身编号的符号/编号/嵌套/任务列表、带有合并单元格和表头行的表格、块引用、脚注和尾注以及演讲者备注。 - **嵌入资产。** 图像和嵌入对象在 Markdown 中渲染为其替代文本,原始字节保留在文档模型中并标记有其媒体类型。具有外部 URL 的图像将转换为普通的 Markdown 图像。 - **基于内容的格式检测。** 直接从字节本身读取格式(PDF header、RTF open group、OLE stream names、ZIP package mimetype),因此标签错误的文件仍能正确转换。 - **快速。** 纯 Rust 编写,无 ML 模型,无外部服务。每个文档的中位转换时间在 5ms 以下。 - **毫不干扰的绑定。** Node.js 转换在 libuv 线程池上运行,绝不会阻塞事件循环;Python 会释放 GIL,以便其他线程继续运行。包中附带了 TypeScript 类型和 Python stubs。 - **内置 PDF 支持。** 基于文本的 PDF 通过 [pdf-inspector](https://github.com/firecrawl/pdf-inspector) 在本地转换,无需 OCR 服务。 - **Agent 就绪。** 以 [Agent Skill](#agent-skill) 的形式发布:只需一句 `npx skills add firecrawl/anydoc`,任何 agent 都能读取 Office 文档。 ## 支持的格式 | 格式 | 扩展名 | | ---------------- | ---------------------------------------------------------- | | Word | `.doc`, `.docx`, `.docm` | | PowerPoint | `.ppt`, `.pps`, `.pot`, `.pptx`, `.pptm`, `.ppsx`, `.ppsm` | | Excel | `.xls`, `.xlsx`, `.xlsm`, `.xlsb` | | OpenDocument | `.odt`, `.ods`, `.odp` | | Rich Text Format | `.rtf` | | EPUB | `.epub` | | CSV | `.csv` | | PDF | `.pdf` | ## 基准测试 anydoc 在涵盖十四种格式的 100 份真实文档上与其他六款转换器进行了对比测量。分数范围为 0 到 100,越高越好;速度是转换单个文档的中位时间。 | 工具 | 格式 | 中位数 ms | 评定文档数 | 分数 | 完整性 | 结构 | 格式化 | 整洁度 | | ------------ | --------- | --------- | ----------- | ------ | ------------ | --------- | ---------- | ----------- | | anydoc | **14/14** | **4.7** | 94 | **80** | **88** | **78** | **77** | **79** | | libreoffice | 12/14 | 1129.5 | 87 | 40 | 59 | 43 | 43 | 24 | | unstructured | 8/14 | 572.9 | 58 | 65 | 76 | 62 | 52 | 67 | | markitdown | 6/14 | 134.8 | 33 | 65 | 80 | 67 | 61 | 53 | | pandoc | 5/14 | 102.1 | 34 | 57 | 75 | 57 | 58 | 39 | | docling | 4/14 | 513.6 | 21 | 57 | 63 | 59 | 57 | 52 | | mammoth | 1/14 | 52.5 | 8 | 70 | 85 | 68 | 74 | 55 | 按格式逐个对比: | 格式 | anydoc | libreoffice | unstructured | markitdown | pandoc | docling | mammoth | | ------ | ------ | ----------- | ------------ | ---------- | ------ | ------- | ------- | | doc | **88** | 58 | 68 | - | - | - | - | | docm | **82** | 49 | - | - | - | - | - | | docx | **86** | 53 | 56 | 72 | 68 | 68 | 70 | | epub | 74 | - | 74 | **77** | 53 | - | - | | odp | **87** | 22 | - | - | - | - | - | | ods | **82** | 42 | - | - | - | - | - | | odt | **80** | 52 | 70 | - | 61 | - | - | | ppt | **80** | 25 | - | - | - | - | - | | pptx | **76** | 22 | - | 59 | - | 50 | - | | rtf | **89** | 58 | 48 | - | 46 | - | - | | xls | **77** | 40 | 68 | 64 | - | - | - | | xlsm | **70** | 30 | - | - | - | - | - | | xlsx | **70** | 31 | 69 | 55 | - | 51 | - | **质量评分方式:** 由 LLM 评判端(Claude Sonnet 5)将两个工具的输出与基准事实(Ground Truth)进行盲测对比:即由 LibreOffice 渲染为图像的文档前六页。每个输出都会在完整性、结构、格式化和整洁度上进行评分。每对输出都会在交换位置后进行两次评定以消除位置偏差,总共得出 479 次判定结果。每个工具的 `score` 是其支持的格式得分的平均值,因此包含大量单一格式的语料库不会扭曲该分数。这也意味着每一行平均的格式集合各不相同(mammoth 的 70 分仅来自 docx,而 anydoc 的 80 分涵盖了所有十四种格式),因此按格式划分的表格才是公平的比较。 速度测试是在 Ryzen 9 9950X3D(Windows 11,64 GB DDR5-6400)上对每个文档进行一次预热转换。anydoc 和 Python 库的计时排除了进程生成时间;而 CLI 工具则包含该时间,因为这是它们的使用方式。测试套件位于 [`bench/`](bench/README.md);语料库不可再分发,且不在仓库中。 **最佳适用场景:** 需要接收各种混合的 Office 文档并输出统一、结构化的 Markdown 的 pipeline。在此对比中,anydoc 是唯一一个覆盖全部十四种格式的工具,在除 EPUB 外的所有受评格式上得分最高,并且转换文档的速度比第二快的工具快一个数量级。 ## 格式检测 直接从文件内容中读取格式,使用其规范指定的标记:PDF header、RTF open group、OLE stream names、ZIP package mimetype 和 content types。CSV 没有这样的标记,因此需要通过扩展名或显式格式来指定。 ``` Format::from_bytes(&bytes); // Some(Format::Docx), or None when nothing matches Format::from_extension("pptm"); // Some(Format::Pptx) Format::from_path(Path::new("report.odt")); // Some(Format::Odt) ``` 同样的三个函数也存在于 Node(`formatFromBytes`, ...)和 Python(`anydoc.format_from_bytes`, ...)中。 ## 工作原理 ``` document bytes │ ├─► format detection → content markers, not the extension │ ├─► format parser → one per format (doc, docx, ppt, pptx, xls, │ xlsx, odt/ods/odp, rtf, epub, csv) │ │ │ └─► Document → shared model: blocks, inlines, tables, │ footnotes, assets │ │ │ └─► GFM serializer → Markdown │ └─► PDF → pdf-inspector → Markdown directly ``` 因为每种格式都汇聚到同一个文档模型和序列化器中,所以输出的某些怪异行为只需修复一次。针对 docx 的表格转义修复,会自动应用到 rtf、odt 以及其他所有格式的表格转义修复中。 ## 开发 ``` cargo test cd node && npm install && npm run build && npm test cd python && pip install maturin && maturin develop && python -m unittest discover -s tests ``` `tests/fixtures/` 下提交的固定语料库进行了快照测试,`tests/robustness.rs` 对每个 fixture 进行了变异测试,而 `fuzz/` 为每种格式包含了 cargo-fuzz 目标。速度和质量基准测试位于 [`bench/`](bench/README.md)。 发布版本会被标记为 `v`,这将通过 [`.github/workflows/release.yml`](.github/workflows/release.yml) 发布 crate、npm 包和 PyPI wheel。版本号存在于三个位置,发布时会一同更新: - [`Cargo.toml`](Cargo.toml):crate - [`node/package.json`](node/package.json):npm 包 - [`python/Cargo.toml`](python/Cargo.toml):wheel(由 `python/pyproject.toml` 读取) ## 许可证 [MIT](LICENSE)
标签:GNU通用公共许可证, Markdown, MITM代理, Node.js, Python, Rust, 可视化界面, 大语言模型准备, 文档转换, 无后门, 网络流量审计, 逆向工具, 通知系统