@GitHub_Daily: 给大模型喂文档,Word、PPT、Excel 格式都不一样,转出来的 Markdown 质量也参差不齐。 Firecrawl 团队用 Rust 写了 anydoc,支持 14 种办公格式转 Markdown,转换速度中位数不到 5 毫秒,…

X AI KOLs Timeline 工具

摘要

Firecrawl 团队用 Rust 开发了 anydoc,一个可将 Word、PPT、Excel 等 14 种办公格式快速转换为统一 Markdown 的开源库,中位转换速度不到 5 毫秒,支持 Node.js、Python 和浏览器(WASM)使用。

给大模型喂文档,Word、PPT、Excel 格式都不一样,转出来的 Markdown 质量也参差不齐。 Firecrawl 团队用 Rust 写了 anydoc,支持 14 种办公格式转 Markdown,转换速度中位数不到 5 毫秒,已斩获了 12000+ Star! 所有格式转出来的 Markdown 结构一致,表格、脚注、嵌套列表都保留,不会因为换个格式结果就变样。 GitHub:http://github.com/firecrawl/anydoc… 有 Node.js、Python 和浏览器三种用法,浏览器版文件在本地转换,不传服务器。 平时要把各种格式文档转给大模型处理的朋友,这个库拿来用挺省事的。
查看原文
查看缓存全文

缓存时间: 2026/08/10 15:32

给大模型喂文档,Word、PPT、Excel 格式都不一样,转出来的 Markdown 质量也参差不齐。

Firecrawl 团队用 Rust 写了 anydoc,支持 14 种办公格式转 Markdown,转换速度中位数不到 5 毫秒,已斩获了 12000+ Star!

所有格式转出来的 Markdown 结构一致,表格、脚注、嵌套列表都保留,不会因为换个格式结果就变样。

GitHub:http://github.com/firecrawl/anydoc…

有 Node.js、Python 和浏览器三种用法,浏览器版文件在本地转换,不传服务器。

平时要把各种格式文档转给大模型处理的朋友,这个库拿来用挺省事的。


firecrawl/anydoc

Source: https://github.com/firecrawl/anydoc

anydoc

Crates.io npm PyPI License: MIT skills.sh

Fast Rust library that converts documents (Word, PowerPoint, Excel, OpenDocument, RTF, EPUB, CSV, and PDF) into clean GitHub-Flavored Markdown. Includes bindings for Node.js, Python, and the browser (WebAssembly).

Built by Firecrawl to turn any office document into LLM-ready Markdown in single-digit milliseconds, with one consistent output no matter which format goes in. It powers Firecrawl Parse, so if you’d rather not run it yourself, the hosted API gives you the same conversion plus our OCR models for the scanned pages anydoc can’t read on its own.

Try it in your browser: the demo page runs the library as WebAssembly, so files are converted locally and never leave your machine.

Quick start

Agent skill

anydoc ships as an Agent Skill, so your agent can read any document it runs into:

npx skills add firecrawl/anydoc

The skill teaches the agent to convert documents with the anydoc CLI. Works with Claude Code, Codex, Cursor, OpenCode, and any other compatible agent.

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 downloads the prebuilt binary for your platform on first run. For a permanent anydoc command, install globally with npm install -g @firecrawl/anydoc. Run anydoc --help for all options.

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);

Full API reference: node/README.md

Python

pip install firecrawl-anydoc
import anydoc

# From a file path:
markdown = anydoc.to_markdown("report.docx")

# From bytes, with the format detected from the content:
markdown = anydoc.to_markdown_bytes(data)

# Or name it, which signature-less formats (CSV) need:
markdown = anydoc.to_markdown_bytes(data, "csv")

# Or stop at the document model, which also carries embedded assets:
document = anydoc.to_document(data)

Full API reference: python/README.md

Browser (WebAssembly)

npm install @firecrawl/anydoc-wasm
import init, { toMarkdownBytes, toDocument } from '@firecrawl/anydoc-wasm';

await init();

// From bytes, with the format detected from the content:
const markdown = toMarkdownBytes(bytes);

// Or name it, which signature-less formats (CSV) need:
const fromCsv = toMarkdownBytes(bytes, 'csv');

// Or stop at the document model, which also carries embedded assets:
const document = toDocument(bytes);

Full API reference: wasm/README.md

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)?;

Features

  • One output for every format. Each format parses into a shared document model and renders through a single Markdown serializer, so escaping, tables, heading anchors, and footnotes behave identically whether the input was a .doc from 2003 or a .pptx from yesterday.
  • Full document structure. Headings with anchors, bold/italic/strikethrough, inline code and code blocks, links and internal cross-references, bulleted/numbered/nested/task lists with the source’s own numbering, tables with merged cells and header rows, block quotes, footnotes and endnotes, and speaker notes.
  • Embedded assets. Images and embedded objects render as their alt text in the Markdown, and the raw bytes stay available on the document model, tagged with their media type. Images with an external URL become ordinary Markdown images.
  • Content-based format detection. The format is read from the bytes themselves (PDF header, RTF open group, OLE stream names, ZIP package mimetype), so mislabeled files still convert correctly.
  • Fast. Pure Rust, no ML models, no external services. Median conversion time is under 5ms per document.
  • Bindings that stay out of the way. Node.js conversion runs on the libuv thread pool and never blocks the event loop; Python releases the GIL so other threads keep running. TypeScript types and Python stubs ship with the packages.
  • PDF support built in. Text-based PDFs convert locally through pdf-inspector, no OCR service required.
  • Agent ready. Ships as an Agent Skill: one npx skills add firecrawl/anydoc and any agent can read office documents.

Supported formats

FormatExtensions
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

Benchmark

anydoc is measured against six other converters on 100 real-world documents spanning fourteen formats. Scores run from 0 to 100, higher is better; speed is the median time to convert one document.

toolformatsmedian msdocs judgedscorecompletenessstructureformattingcleanliness
anydoc14/144.4948187797881
libreoffice12/141129.5874059424024
unstructured8/14572.9586376595163
markitdown6/14134.8336578666052
pandoc5/14102.1345674575638
docling4/14513.6215760605751
mammoth1/1452.587084717551

Per format, like for like:

formatanydoclibreofficeunstructuredmarkitdownpandocdoclingmammoth
doc875767----
docm8448-----
docx88565371687170
epub77-727252--
odp8623-----
ods8238-----
odt805168-60--
ppt8026-----
pptx7424-66-52-
rtf885346-45--
xls80386662---
xlsm7632-----
xlsx72306655-47-

How quality was scored: an LLM judge (Claude Sonnet 5) compares two tools’ outputs blind against ground truth: the document’s first six pages, rendered to images by LibreOffice. Each output is scored on completeness, structure, formatting, and cleanliness. Every pair is judged twice with the outputs swapped to cancel position bias, for 482 verdicts in total. Each tool’s score averages its per-format scores over the formats it supports, so a corpus heavy in one format can’t skew it. It also means each row averages a different set of formats (mammoth’s 69 is docx alone, while anydoc’s 81 spans all fourteen), so the per-format table is the fair comparison.

Speed is one warm conversion per document on a Ryzen 9 9950X3D (Windows 11, 64 GB DDR5-6400). anydoc and the Python libraries are timed with process spawn excluded; the CLI tools include it, since that is how they are used. The harness lives in bench/; the corpus is not redistributable and is not in the repo.

Best fit: pipelines that receive a mixed bag of office documents and need one consistent, structured Markdown output. In this comparison, anydoc was the only tool to cover all fourteen formats, scored highest on every judged format, and converted documents an order of magnitude faster than the next-fastest tool.

Format detection

The format is read from the file content, using the marker its specification designates: the PDF header, the RTF open group, OLE stream names, the ZIP package mimetype and content types. CSV has no such marker, so the extension or an explicit format names it instead.

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)

The same three functions exist in Node (formatFromBytes, …) and Python (anydoc.format_from_bytes, …).

Errors

A conversion returns Err only when no meaningful Markdown could come out of the file. ConvertError names what went wrong:

match anydoc::to_markdown(path) {
    Ok(markdown) => Some(markdown),
    // No document comes out of these, so record the file and take the next one.
    Err(error @ (ConvertError::Encrypted | ConvertError::Unsupported(_))) => {
        unconverted.push((path, error));
        None
    }
    Err(error) => return Err(error),
}
VariantMeaning
UnsupportedUnknown format, or one that cannot be converted (an image-only PDF)
MalformedStructurally unusable: no meaningful content could be extracted
EncryptedEncrypted or password-protected
ResourceLimitCrossed a fixed safety limit (decompression, nesting, node count)
MissingPartA part required for any meaningful output is absent
IoThe file could not be read, from to_markdown only

Node and wasm publish the variant name on error.code; Python raises one anydoc.ConvertError subclass per variant, or OSError when the file cannot be read.

How it works

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

Because every format funnels through the same document model and serializer, output quirks get fixed once. A table-escaping fix for docx is automatically a table-escaping fix for rtf, odt, and everything else.

Development

cargo test
cd node && npm install && npm run build && npm test
cd python && pip install maturin && maturin develop && python -m unittest discover -s tests
wasm-pack build wasm --release --target web --scope firecrawl && node --test wasm/test.mjs  # see wasm/README.md

A committed fixture corpus under tests/fixtures/ is snapshot-tested, tests/robustness.rs mutation-tests every fixture, and fuzz/ carries cargo-fuzz targets per format. The speed and quality benchmark lives in bench/.

Releases are tagged v<version>, which publishes the crate, the npm package, and the PyPI wheels from .github/workflows/release.yml. The version lives in three places, bumped together for a release:

License

MIT

相似文章

@GitHub_Daily: 给大模型喂 PDF 文档,常见做法是先跑 OCR 再提文字,但实际上有一半多的 PDF 本来就是文字版,根本不需要 OCR。 Firecrawl 团队最近开源的 pdf-inspector,能自动判断 PDF 是文字版还是扫描版,文字版的…

X AI KOLs Timeline

Firecrawl 团队开源了 pdf-inspector,一个快速 Rust 库,可自动判断 PDF 是文字版还是扫描版,并直接提取文字转成 Markdown,免去不必要的 OCR,支持表格、多栏排版识别,提供 Python/Node.js/Rust/WASM 接口。

@Chenzeze777: 微软开源了一个 14 万星的文档神器,我整理了它最实用的 5 个场景。 MarkItDown,Python 工具,把 PDF/Word/PPT/Excel/HTML/图片,一键转成干净的 Markdown 文本。 你能用它做什么: · P…

X AI KOLs Timeline

微软开源了 MarkItDown,一个轻量级 Python 工具,可将 PDF、Word、PPT、Excel、HTML 和图片等文件一键转换为干净的结构化 Markdown 文本,方便用于 AI 摘要、数据分析、知识库构建等场景。

@AIExplorerTim: 有人刚刚开发了一个工具,可以将 PDF 转换为 干净、结构化的 Markdown 速度达到 100 页/秒 不需要 GPU。 不需要 API 成本。 没有混乱的解析。 只有原始的、可用的数据。 它可以轻松处理的内容: • 表格 → 完美提…

X AI KOLs Timeline

OpenDataLoader 是一个开源工具,可将 PDF 转换为结构化的 Markdown 和 JSON,支持 100 页/秒的本地处理速度,无需 GPU 或 API 成本,专为 RAG 管道和 PDF 无障碍自动化设计。