Production-grade document-to-Markdown conversion library with hexagonal architecture.
Project description
CyberDocExtractor
Production-grade Python library for converting PDF, DOCX, DOC, XLSX, XLS and CSV documents to Markdown. Multiple precision levels, automatic fallback, LLM-assisted image descriptions, and a strict hexagonal core.
⚠️ Status: early development (Phase 1 / Foundation). The public API is not yet stable. The project skeleton, tooling, CI, and architectural guardrails are in place; domain/application/infra layers are under construction. See the project roadmap.
Why another document extractor?
Extraction tooling is a fragmented landscape — each upstream library (Docling, PyMuPDF, pdfplumber, python-docx, openpyxl, …) has its own model, error semantics, and failure modes. CyberDocExtractor wraps them behind a single typed domain model and applies:
- Hexagonal architecture — the domain doesn't know what PyMuPDF is.
- Pluggable extractors — swap, reorder, or add adapters without touching the core.
- Automatic fallback — if the preferred extractor fails, the next one in the policy chain is tried.
- Deterministic quality scoring — every conversion comes with a 0.0-1.0 score so downstream consumers can gate on confidence.
- Typed, immutable value objects everywhere.
- Strict CI: mypy strict, ruff with pydocstyle,
import-linterarchitectural contracts, coverage floor of 90%, matrix tests on Linux + macOS × Python 3.11/3.12/3.13.
Installation
pip install cyberdocextractor # core only
pip install cyberdocextractor[pdf] # + PDF adapters
pip install cyberdocextractor[docx] # + DOCX adapter
pip install cyberdocextractor[xlsx] # + XLSX adapter
pip install cyberdocextractor[llm] # + LLM image description
pip install cyberdocextractor[cli] # + Typer CLI
pip install cyberdocextractor[all] # everything
Quick start
from pathlib import Path
from cyberdocextractor import Document, PrecisionLevel, build_pipeline
pipeline = build_pipeline()
source = Path("report.pdf")
doc = Document.from_path(source, precision=PrecisionLevel.BALANCED)
result = pipeline.convert(doc)
print(result.markdown.text)
print(f"quality={result.markdown.quality_score:.2f}, extractor={result.extractor}")
CLI:
cyberdoc convert report.pdf --level 2 --output report.md
cyberdoc batch ./inputs ./outputs --pattern '*.pdf'
cyberdoc status
cyberdoc version
Architecture
┌──────────────────────────────────────┐
│ CLI │ cyberdoc convert …
├──────────────────────────────────────┤
│ Application │ ConversionPipeline + stages
│ (extraction → metadata → profile │
│ → image enrichment → render) │
├──────────────────────────────────────┤
│ Infrastructure │ PyMuPDF, pdfplumber, Docling,
│ │ openpyxl, Jinja2, OpenAI-compat
├──────────────────────────────────────┤
│ Domain │ Document, Block, NormalizedDoc,
│ (pure, zero-dependency core) │ Extractor / Policy / Renderer
└──────────────────────────────────────┘
▲ depends on (↑ only)
import-linter enforces the arrows in CI. See
docs/architecture/overview.md (coming in
Phase 7) for the full write-up.
Precision levels
| Level | Name | Typical extractor | Trade-off |
|---|---|---|---|
| 1 | FASTEST |
chunked PyMuPDF | speed > fidelity, no table stats |
| 2 | BALANCED |
pymupdf4llm |
default; good text + table output |
| 3 | TABLE_OPTIMIZED |
pdfplumber |
best for structured tables |
| 4 | HIGHEST_QUALITY |
Docling | OCR, images, layout — slowest |
The SelectionPolicy picks the chain automatically from file size, MIME
type, and hinted table presence, but callers can override with
doc.precision = PrecisionLevel.HIGHEST_QUALITY.
Roadmap
| Phase | Scope | Status |
|---|---|---|
| 1 | Tooling, CI, architectural scaffolding | ✅ in progress |
| 2 | Domain layer (models, ports, rules) | ⏳ next |
| 3 | Application layer + DI container | ⏳ |
| 4 | Infra adapters (extractors, LLM, Jinja) | ⏳ |
| 5 | CLI + public API | ⏳ |
| 6 | BDD scenarios | ⏳ |
| 7 | mkdocs-material site + ADRs | ⏳ |
| 8 | v0.1.0 release + PyPI publish | ⏳ |
Development
just bootstrap # install dev env
just check # format + lint + types + arch + tests
just test # tests with coverage gate
just docs-serve # preview docs
See CONTRIBUTING.md for details.
Security
See SECURITY.md for the responsible disclosure policy.
License
MIT — see LICENSE.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file cyberdocextractor-0.1.1.tar.gz.
File metadata
- Download URL: cyberdocextractor-0.1.1.tar.gz
- Upload date:
- Size: 44.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
24cf2674fac912309a935da8cabad404c23398f6219fc7551b86c18cad8ef9ae
|
|
| MD5 |
87d8ca089e0cd0bac0e778ffd51e93eb
|
|
| BLAKE2b-256 |
ac7e067d3764248dc374e65ef31f49fbeb15efe32dddd3f83c9b615901481c7d
|
File details
Details for the file cyberdocextractor-0.1.1-py3-none-any.whl.
File metadata
- Download URL: cyberdocextractor-0.1.1-py3-none-any.whl
- Upload date:
- Size: 67.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ea769653bf44c12a2eec15fb27df52348ece9f530fcd125bf6f907fe6b00f9f2
|
|
| MD5 |
c51f512bf5b1900e32b783a671ff6ed5
|
|
| BLAKE2b-256 |
9d5cb6670fbf0991a6b7ff849cf10744536e3ef29e1da090a00bcbb43c777d2c
|