
anydoc란 무엇인가요?
anydoc는 문서를 깔끔한 GitHub Flavored Markdown으로 빠르게 변환하는 Rust 라이브러리입니다. Word, PowerPoint, Excel, OpenDocument, RTF, EPUB, CSV 및 텍스트 기반 PDF 파일을 지원합니다. 또한 이 프로젝트는 명령줄 인터페이스와 Node.js, Python, 브라우저 기반 WebAssembly용 바인딩을 제공합니다.
이 라이브러리는 여러 문서 형식을 입력받지만 일관된 하나의 Markdown 표현이 필요한 파이프라인을 위해 설계되었습니다. 지원되는 각 오피스 형식은 공통 문서 모델로 파싱된 후 동일한 Markdown 직렬 변환기를 거칩니다. 따라서 형식에 관계없이 표, 이스케이프, 제목, 각주, 링크, 목록 및 기타 구조를 일관되게 유지할 수 있습니다.
변환은 머신러닝 모델이나 외부 서비스 없이 로컬에서 실행됩니다. README의 벤치마크에 따르면 문서당 변환 시간 중앙값은 5밀리초 미만입니다. 텍스트 기반 PDF는 pdf-inspector를 통해 로컬에서 처리됩니다.
anydoc는 OCR을 수행하지 않습니다. 읽을 수 있는 텍스트가 없는 이미지만 포함된 PDF 또는 스캔된 PDF는 지원되지 않는 형식으로 보고될 수 있습니다. OCR도 필요한 워크플로의 경우 프로젝트에서 언급하는 호스팅 대안은 Firecrawl Parse입니다.
주요 기능
- 일관된 Markdown: 모든 오피스 형식이 공통 문서 모델과 직렬 변환기를 사용합니다.
- 구조화된 출력: 지원되는 구조에는 제목과 앵커, 링크, 내부 참조, 목록, 표, 인용 블록, 각주, 미주, 발표자 노트, 인라인 코드 및 코드 블록이 포함됩니다.
- 서식 보존: 굵게, 기울임꼴, 취소선, 작업 목록, 중첩 목록, 원본 번호 매기기, 병합된 표 셀 및 머리글 행을 표현할 수 있습니다.
- 포함된 자산: 포함된 이미지와 개체는 Markdown에서 대체 텍스트로 표시되며, 원시 바이트와 미디어 유형은 문서 모델을 통해 계속 사용할 수 있습니다.
- 콘텐츠 기반 감지: PDF, RTF, OLE 및 ZIP 기반 문서 형식은 파일 확장자에만 의존하지 않고 바이트에서 식별됩니다.
- 비블로킹 바인딩: Node.js 변환은 libuv 스레드 풀을 사용하고, Python은 변환 중 전역 인터프리터 잠금을 해제합니다.
- 타입이 포함된 패키지: TypeScript 타입과 Python 스텁이 포함됩니다.
- 에이전트 통합: 이 프로젝트에는 호환되는 코딩 에이전트가 anydoc CLI를 사용하도록 가르치는 Agent Skill이 포함되어 있습니다.
지원되는 파일 형식
- Word:
.doc,.docx및.docm - PowerPoint:
.ppt,.pps,.pot,.pptx,.pptm,.ppsx및.ppsm - Excel:
.xls,.xlsx,.xlsm및.xlsb - OpenDocument:
.odt,.ods및.odp - 기타 형식:
.rtf,.epub,.csv및.pdf
설치 방법 선택
셸 스크립트와 일회성 변환에는 CLI를 사용하세요. 문서 변환이 애플리케이션의 일부라면 Node.js 또는 Python을, 네이티브 통합에는 Rust를, 브라우저에서 직접 파일을 변환해야 한다면 WebAssembly를 선택하세요.
CLI 설치
npx를 사용하면 영구적으로 설치하지 않고 사전 빌드된 CLI를 실행할 수 있습니다.
npx @firecrawl/anydoc report.docx플랫폼에 맞는 사전 빌드 바이너리는 처음 실행할 때 다운로드됩니다. anydoc를 영구 명령으로 사용하려면 전역으로 설치하세요.
npm install -g @firecrawl/anydoc
anydoc --helpNode.js용 설치
npm install @firecrawl/anydocPython용 설치
pip install firecrawl-anydoc브라우저 WebAssembly용 설치
npm install @firecrawl/anydoc-wasm브라우저 데모를 사용해 볼 수도 있습니다. 데모는 WebAssembly 라이브러리를 로컬에서 실행하므로 선택한 파일이 컴퓨터 밖으로 전송되지 않습니다.
Rust용 설치
cargo add anydocAgent Skill 설치
호환되는 에이전트가 anydoc CLI로 문서를 변환하는 방법을 익히게 하려면 포함된 스킬을 설치하세요.
npx skills add firecrawl/anydocREADME에는 호환 클라이언트로 Claude Code, Codex, Cursor 및 OpenCode가 소개되어 있습니다.
CLI로 파일 변환
표준 출력으로 Markdown 작성
소스 문서를 첫 번째 인수로 전달하세요. 생성된 Markdown이 표준 출력에 표시됩니다.
npx @firecrawl/anydoc report.docx결과를 확인하거나 다른 명령으로 파이프하려는 경우 편리합니다.
Markdown을 파일에 저장
-o를 사용해 출력 파일을 지정하세요.
npx @firecrawl/anydoc slides.pptx -o slides.md표준 입력에서 데이터 변환
입력 경로로 -를 사용하면 표준 입력에서 바이트를 읽습니다. CSV는 콘텐츠에 신뢰할 수 있는 시그니처가 없으므로 형식을 명시적으로 지정하세요.
npx @firecrawl/anydoc - --format csv < data.csvNode.js에서 anydoc 사용
Node.js 패키지는 파일 경로, 바이트 배열 및 공용 문서 모델을 위한 별도의 함수를 제공합니다.
파일 경로 변환
import { toMarkdown } from '@firecrawl/anydoc';
const markdown = await toMarkdown('report.docx');
console.log(markdown);바이트 변환
파일이 이미 업로드되었거나 다운로드되었거나 메모리로 읽힌 경우 toMarkdownBytes를 사용하세요.
import { toMarkdownBytes } from '@firecrawl/anydoc';
const markdown = await toMarkdownBytes(bytes);식별 가능한 시그니처가 있는 형식의 경우 anydoc는 콘텐츠에서 형식을 감지합니다. CSV에는 이러한 시그니처가 없으므로 형식 이름을 전달해야 합니다:
const markdown = await toMarkdownBytes(bytes, 'csv');문서 모델과 에셋 유지
최종 Markdown 문자열 이상의 정보가 필요하다면 toDocument를 사용해 공유 문서 모델에서 처리를 중단하세요:
import { toDocument } from '@firecrawl/anydoc';
const document = await toDocument(bytes);문서 모델에는 파싱된 구조와 포함된 에셋이 담깁니다. Markdown 표현에서는 대체 텍스트를 사용하지만, 포함된 에셋의 바이트는 미디어 유형과 함께 계속 사용할 수 있습니다.
Python에서 anydoc 사용
파일 경로 변환
import anydoc
markdown = anydoc.to_markdown("report.docx")
print(markdown)메모리 내 바이트 변환
import anydoc
markdown = anydoc.to_markdown_bytes(data)CSV처럼 시그니처가 없는 입력은 명시적으로 지정하세요:
markdown = anydoc.to_markdown_bytes(data, "csv")문서 모델에 액세스
document = anydoc.to_document(data)이 방식은 직렬화된 Markdown만 필요한 것이 아니라 파싱된 문서와 포함된 에셋이 필요한 애플리케이션에 유용합니다.
브라우저에서 문서 변환
WebAssembly 패키지는 브라우저에서 바이트 배열을 로컬로 변환합니다. 변환 함수를 호출하기 전에 모듈을 초기화하세요:
import init, { toMarkdownBytes, toDocument } from '@firecrawl/anydoc-wasm';
await init();
const markdown = toMarkdownBytes(bytes);다른 바인딩과 마찬가지로 CSV의 형식을 지정하세요:
const markdown = toMarkdownBytes(bytes, 'csv');문서 모델과 포함된 에셋을 유지하려면 toDocument를 사용하세요:
const document = toDocument(bytes);앞서 설명한 Node.js API와 달리 README의 WebAssembly 변환 호출은 초기화 후 동기적으로 실행됩니다.
Rust에서 anydoc 사용
파일 경로 변환
let markdown = anydoc::to_markdown("report.docx")?;자동 감지로 바이트 변환
let markdown = anydoc::to_markdown_bytes(&bytes, None)?;CSV 명시적 지정
let markdown = anydoc::to_markdown_bytes(
&bytes,
anydoc::Format::Csv,
)?;문서 모델 반환
let document = anydoc::to_document(&bytes, None)?;형식 감지 이해
anydoc는 PDF 헤더, RTF 시작 그룹, OLE 스트림 이름, ZIP 패키지 메타데이터와 같은 콘텐츠 마커를 검사합니다. 따라서 실제 형식을 바이트에서 식별할 수 있다면 파일 이름의 확장자가 잘못 지정된 파일도 변환할 수 있습니다.
Rust는 바이트, 확장자, 경로를 확인하는 헬퍼를 제공합니다:
Format::from_bytes(&bytes);
Format::from_extension("pptm");
Format::from_path(Path::new("report.odt"));첫 번째 호출은 Some(Format::Docx)와 같은 감지된 형식을 반환하며, 알려진 콘텐츠 마커와 일치하지 않으면 None을 반환합니다. Node.js에서는 formatFromBytes와 같은 이름으로, Python에서는 anydoc.format_from_bytes와 같은 이름으로 이에 상응하는 헬퍼를 사용할 수 있습니다.
CSV에 특별한 처리가 필요한 이유
CSV는 일반 텍스트이며 고유하게 식별할 수 있는 표준 바이트 시그니처가 없습니다. 이름이 지정되지 않은 CSV 바이트나 표준 입력을 변환할 때는 csv를 명시적으로 제공하세요. 파일 경로에 .csv 확장자가 포함되어 있다면 확장자로 식별할 수 있습니다.
변환 오류 처리
의미 있는 Markdown을 생성할 수 없으면 변환에서 오류가 반환됩니다. Rust는 이러한 경우를 ConvertError를 통해 노출합니다:
- Unsupported: 형식을 알 수 없거나 변환할 수 없습니다. 이미지로만 구성된 PDF도 포함됩니다.
- Malformed: 파일 구조를 사용할 수 없어 의미 있는 콘텐츠를 추출할 수 없습니다.
- Encrypted: 문서가 암호화되었거나 비밀번호로 보호되어 있습니다.
- ResourceLimit: 압축 해제, 중첩 또는 노드 수와 관련된 고정된 안전 한도를 초과했습니다.
- MissingPart: 필수 문서 구성 요소가 없습니다.
- Io:
to_markdown에 전달된 파일을 읽을 수 없습니다.
일괄 처리 파이프라인은 암호화되었거나 지원되지 않는 파일을 기록하고 나머지 입력을 계속 처리할 수 있습니다:
match anydoc::to_markdown(path) {
Ok(markdown) => Some(markdown),
Err(error @ (ConvertError::Encrypted | ConvertError::Unsupported(_))) => {
unconverted.push((path, error));
None
}
Err(error) => return Err(error),
}Node.js와 WebAssembly에서는 error.code를 통해 오류 변형 이름을 확인할 수 있습니다. Python은 각 변환 변형에 대해 전용 anydoc.ConvertError 하위 클래스를 발생시키며, 파일을 읽을 수 없을 때는 OSError를 발생시킵니다.
고급 통합 팁
업로드 파이프라인에서는 바이트 변환 우선
애플리케이션이 업로드, 객체 저장소 또는 HTTP 응답에서 이미 문서 바이트를 받고 있다면 toMarkdownBytes 또는 to_markdown_bytes를 사용하세요. 이렇게 하면 파일 경로가 필요하지 않고, 사용자가 제공한 파일 이름을 신뢰하는 대신 anydoc가 실제 콘텐츠를 검사할 수 있습니다.
에셋이 중요할 때 문서 모델 사용
Markdown만으로는 포함된 객체의 원시 바이트를 담을 수 없습니다. 포함된 에셋과 해당 미디어 유형을 저장하거나 검사하거나 별도로 처리해야 한다면 toDocument 또는 to_document를 사용하세요.
스캔된 PDF는 별도로 처리
anydoc의 내장 PDF 지원은 텍스트 기반 PDF를 대상으로 하며 OCR은 포함하지 않습니다. 이미지로만 구성된 PDF는 로컬 변환을 반복해서 시도하지 말고 OCR을 지원하는 워크플로로 전달하세요.
CSV 형식 선택을 명시적으로 지정하기
메모리에서 처리하는 입력이 섞여 있을 때는 CSV 바이트에 명시적인 형식 메타데이터를 연결하세요. 지원되는 다른 형식은 콘텐츠에서 자동으로 감지되는 경우가 많지만, CSV에는 이름, 확장자 또는 명시적인 형식 인수가 필요합니다.
런타임 동작 활용하기
Node.js 변환은 이벤트 루프를 차단하지 않고 libuv 스레드 풀에서 실행됩니다. Python은 변환 중 GIL을 해제하므로 다른 Python 스레드가 계속 실행될 수 있습니다. 이러한 특성은 변환을 동시성 애플리케이션에 통합할 때 유용합니다.
다운스트림에서 일관된 출력 사용하기
오피스 형식은 하나의 직렬 변환기를 공유하므로, 다운스트림 시스템은 Word, PowerPoint, Excel, RTF, OpenDocument 입력마다 별도의 정리 규칙을 유지하는 대신 하나의 Markdown 구조를 사용할 수 있습니다. 따라서 anydoc는 검색 인덱싱, 추출 파이프라인, 언어 모델용 구조화 텍스트 준비에 특히 적합합니다.
변환 파이프라인의 작동 방식
- anydoc는 문서 바이트 또는 사용 가능한 파일 이름 정보를 검사하여 형식을 확인합니다.
- 형식별 파서는 Word, PowerPoint, Excel, OpenDocument, RTF, EPUB 또는 CSV 콘텐츠를 읽습니다.
- 파서는 블록, 인라인 요소, 표, 각주 및 자산을 포함하는 공유 문서 모델을 생성합니다.
- 공통 직렬 변환기가 해당 모델을 GitHub Flavored Markdown으로 변환합니다.
- PDF는 pdf-inspector를 통해 처리되며 Markdown으로 직접 변환됩니다.
이 아키텍처에서는 직렬 변환기 개선 사항이 여러 형식에 동시에 적용될 수 있습니다. 예를 들어 표 이스케이프 수정은 단일 입력 파서에만 국한되지 않습니다.
성능 및 적합한 사용 사례
저장소에는 14개 형식에 걸친 실제 문서 100개를 대상으로 한 벤치마크 결과가 보고되어 있습니다. anydoc는 14개 형식을 모두 지원했으며, 변환 시간 중앙값 4.4밀리초와 해당 비교에서 종합 품질 점수 81점을 기록했습니다. 품질은 완성도, 구조, 서식 및 깔끔함을 기준으로 평가되었습니다.
벤치마크 결과는 코퍼스, 하드웨어 및 방법론에 따라 달라지므로, 포함된 벤치마크를 모든 워크로드에 대한 보장이 아닌 프로젝트별 근거로 활용하세요. 프로젝트에서 설명하는 가장 적합한 사용 사례는 여러 오피스 문서를 혼합해 입력받고 빠르고 구조화되며 일관된 Markdown이 필요한 파이프라인입니다.
결론
anydoc는 Rust, Node.js, Python, 브라우저 및 명령줄에서 하나의 변환 워크플로를 제공합니다. 빠르게 테스트하려면 CLI로 시작한 다음 애플리케이션에 맞는 바인딩을 선택하세요. 업로드된 파일에는 바이트 기반 변환을 사용하고, CSV 형식은 명시적으로 지정하며, 포함된 자산이 중요할 때는 문서 모델을 유지하세요. 암호화되었거나 손상되었거나 지원되지 않거나 스캔된 문서는 별도의 사례로 처리해야 합니다.
