Skip to main content

bobine

Crates.io docs.rs PyPI Python Rust onnxruntime CI License

Standalone PDF / Office / text → Markdown ingestion engine — a pure-Rust core with Python bindings. Runs on a single onnxruntime shared library with no CUDA-version coupling: pdf_oxide for fast native PDF text extraction, ONNX models (TexTeller formula OCR, DocLayout-YOLO layout analysis, PaddleOCR) for the heavy passes. No torch, no optimum, no opencv — not even on the Python side.

Dual-licensed under the terms of either the MIT License or the Apache License, Version 2.0 — you may choose either (see LICENSE).

Docs

Why bobine?

The ingestion pipeline was originally entangled with the knowledge-graph project it served (OKFgraph). This crate moves conversion into its own package so any consumer — a graph, a CLI, an MCP server, a batch tool — can reuse it without importing a database stack. The v0.3.0 rewrite ports the whole pipeline to Rust: same routing heuristics and output contract as the proven Python implementation (preserved under legacy/), with native speed and no Python ML dependencies.

Installation

# Python package (wheels: linux + windows x86_64, macOS arm64)
pip install bobine

# Rust library (crates.io, no Python involved)
cargo add bobine

# ...or build from source (repo root)
pip install maturin && maturin develop --release

Runtime requirement: an ONNX Runtime library for the heavy passes — or nothing at all (Office/text/fast-path PDF work needs no models):

pip install bobine[cpu]   # adds onnxruntime >= 1.28 (CPU)
# or: pip install bobine[gpu]   # onnxruntime-gpu (self-contained CUDA)

import bobine points ORT_DYLIB_PATH at the pip-installed library automatically; an already-set ORT_DYLIB_PATH always wins (e.g. a custom CUDA build):

export ORT_DYLIB_PATH=/path/to/onnxruntime.dll   # e.g. <venv>/Lib/site-packages/onnxruntime/capi/onnxruntime.dll

ort loads the library dynamically (load-dynamic, no CUDA-version coupling) and refuses runtimes older than 1.28 (BadVersion) — hence the >=1.28 pins. Never install both onnxruntime and onnxruntime-gpu (same module name, they clobber each other).

Quick start (Python)

import bobine

conv = bobine.HybridConverter(
    bobine.ConverterConfig(routing_mode=bobine.RoutingMode.Surgical),
    cache_dir="~/.cache/bobine",       # TexTeller models auto-download here
)

md = conv.convert_pdf("paper.pdf", work_dir="/tmp/out")
latex = conv.recognize_formula("crop.png")          # r"\frac{1}{2}"

# one-shot helper
md = bobine.convert_to_markdown(
    "paper.pdf", bobine.ConverterConfig(), work_dir="/tmp/out",
    cache_dir="~/.cache/bobine",
)

# Text documents need no models at all
md = conv.convert("notes.txt", work_dir="/tmp/out")

PDF conversion with ONNX heavy passes

HybridConverter routes pages through four modes:

Mode Behaviour Models loaded
Never Fast path only (pdf_oxide). No ONNX models loaded. none
Auto (default) Heuristics per page → full ONNX layout + OCR on flagged pages. TexTeller + layout + OCR (table lazy)
Surgical Formula crops via TexTeller only; full pipeline just for scans. TexTeller only
Always Every page through the full ONNX layout + OCR pipeline; on born-digital pages, formula regions are refined against text-layer math boxes (v0.4.8) and output matches Surgical. TexTeller + layout + OCR (table lazy)

RapidLayout and RapidOCR weights also auto-download from HuggingFace on first use (DocStructBench YOLO ~72 MB, PP-OCRv4 ~16 MB); explicit local paths can override them. Missing/broken heavy models degrade gracefully to the fast path per page — a conversion never fails because of them.

Quick start (Rust)

use bobine::{ConverterConfig, HybridConverter, RoutingMode};

let mut conv = HybridConverter::new(
    ConverterConfig { routing_mode: RoutingMode::Surgical, ..Default::default() },
    std::path::Path::new("~/.cache/bobine"),
);
let md = conv.convert_pdf(std::path::Path::new("paper.pdf"),
                          std::path::Path::new("/tmp/out"))?;

Module layout

src/
├── lib.rs            crate root & re-exports
├── config.rs         ConverterConfig · RoutingMode · ModelPrecision
├── engine.rs         OnnxEngine (lazy model manager: TexTeller/Layout/OCR)
├── converter.rs      HybridConverter (core PDF/Office pipeline)
├── tex_teller.rs     TexTeller ONNX — ViT encoder → RoBERTa decoder
├── rapid_layout.rs   DocLayout-YOLO page layout analysis
├── rapid_ocr.rs      PaddleOCR det + rec (DBNet / CRNN, CTC decode)
├── rapid_table.rs    SLANet-plus table-structure recognition (scans)
├── pdf_source.rs     PdfSource trait — page text without a real PDF file
├── tables.rs         HTML table → GFM pipe-table converter
├── excel.rs          Excel workbooks → per-sheet csv/json/md
├── office_images.rs  Office picture staging (IR walk + package fallback)
├── assets.rs         okf-asset://\ staging store
├── documents.rs      ConvertedDocument + frontmatter
├── pipeline.rs       ingest_document / convert_directory / ProgressHooks
├── error.rs          BobineError
└── py_bindings.rs    PyO3 surface (behind the extension-module feature)
python/bobine/        Python shim + type stubs        (import bobine)
legacy/               frozen pure-Python bobine v0.2.0 (reference implementation)

Formula OCR (SURGICAL mode)

Formulas are recognized by TexTeller (80M training pairs), decoded with KV-cache over a ViT encoder → RoBERTa decoder ONNX graph — roughly 5× faster per crop than the RapidLaTeXOCR backend used by the legacy Python package, with markedly better accuracy.

By default bobine downloads the quantized export (~319 MB total, HF Ji-Ha/TexTeller3-ONNX-dynamic) into the converter's cache dir on first use; set model_quantization=ModelQuantization::Fp32 to use full-precision weights (~1.25 GB, HF OleehyO/TexTeller) instead. Preprocessing matches upstream TexTeller exactly, including its normalize-before-pad order (v0.4.4 fixed black pad fill, which measurably degraded recognition). Measured on a 10-formula corpus: Int8+CPU scores 10/10, Fp32+CUDA 9/10 — occasional single-token decode noise flips between examples on either variant, so pick by hardware, not quality.

On NVIDIA GPUs, point ORT_DYLIB_PATH at a GPU onnxruntime build — v0.4.9+ auto-enables CUDA for the layout and OCR slots when the loaded library registers the CUDA execution provider (measured 12.3x / 3.6x speedups), and keeps table recognition pinned to CPU (SLANet measures 2-9x slower on CUDA: its graph fragments across devices). Zero config needed; explicit per-slot overrides: layout_ort_providers, ocr_ort_providers, table_ort_providers, encoder_ort_providers, decoder_ort_providers. To also run Fp32 formula decode on the GPU, set ort_providers=["CUDAExecutionProvider", "CPUExecutionProvider"] (Int8 + CUDA is discouraged and warned against).

Formula regions come from the PDF text layer (TeX math fonts such as cmmi/cmsy/cmex, plus unicode math codepoints), merged line-aware so multi-line display equations become one crop while separate equations, columns and prose stay apart. For text-layer-hostile PDFs (Word/InDesign/OCR output without math fonts), set formula_layout_fallback=True to ask the layout model for equation regions instead (off by default).

OCR recognition runs line crops in chunks of 32 on accelerators (6.3x faster on CUDA, measured) while CPU-only sessions keep the exact single-line path — provider-gated batching, byte-identical tensors on CPU (v0.4.28, see benchmarks).

Office documents

.docx / .xlsx / .pptx plus legacy .doc / .xls / .ppt convert to markdown via office_oxide (HybridConverter::convert_office(path) or the convert() dispatcher — no models needed). Excel workbooks additionally export per-sheet csv/json (convert_excel, <stem>.<sheet>.csv + <stem>.json siblings). Embedded pictures stage into <work_dir>/assets/office/ and rewrite to staged files, promoted to okf-asset:// by ingest_document — details in the Office export plan.

Output contract

convert_pdf returns one markdown string: inline $…$ / display $$…$$ LaTeX spliced in place, GFM pipe tables, fenced code blocks from monospaced font runs, embedded images written to work_dir, plus an okf-asset:// staging store for unreferenced figures. Office docs additionally stage pictures into <work_dir>/assets/office/; workbooks yield <stem>.<sheet>.csv + <stem>.json siblings. For document-level workflows use ingest_document / convert_directory, which return versioned ConvertedDocuments with frontmatter and lint hooks.

Testing

cargo test                # 128 lib tests (ORT_DYLIB_PATH required — no dylib = abort)
cargo test --test test_office --test test_excel --test test_golden   # no models needed
ORT_DYLIB_PATH=... cargo test --test test_converter                 # incl. full-paper AUTO run
maturin develop && python -c "import bobine"   # bindings smoke test

Fixtures: trimmed CC BY 4.0 arXiv papers + a generated scanned page + generated OOXML fixtures — see tests/fixtures/SOURCES.md for provenance.

ONNX Runtime versioning

ort requires onnxruntime ≥ 1.19 and fails loudly at session creation on older system libraries (BadVersion). Set ORT_DYLIB_PATH explicitly in CI or dev environments with multiple installations. GPU support = point the same variable at a CUDA-enabled build; layout/OCR then auto-enable CUDA per slot (v0.4.9+) and ConverterConfig exposes per-slot overrides (layout_ort_providers, ocr_ort_providers, table_ort_providers, encoder_ort_providers, decoder_ort_providers), with ort_providers as the base list for TexTeller.

License

Apache-2.0 OR MIT (dual, choose either). Test fixtures are CC BY 4.0 (attribution in tests/fixtures/SOURCES.md). legacy/ keeps the original Python release's licensing.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

bobine-0.5.9.tar.gz (215.2 kB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

bobine-0.5.9-cp314-cp314-macosx_11_0_arm64.whl (16.0 MB view details)

Uploaded CPython 3.14macOS 11.0+ ARM64

bobine-0.5.9-cp312-cp312-win_amd64.whl (17.3 MB view details)

Uploaded CPython 3.12Windows x86-64

bobine-0.5.9-cp312-cp312-manylinux_2_28_x86_64.whl (18.0 MB view details)

Uploaded CPython 3.12manylinux: glibc 2.28+ x86-64

File details

Details for the file bobine-0.5.9.tar.gz.

File metadata

  • Download URL: bobine-0.5.9.tar.gz
  • Upload date:
  • Size: 215.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for bobine-0.5.9.tar.gz
Algorithm Hash digest
SHA256 bc8fe37aaedf77e3a1badf550d91ac52037ddb5f09602b75d07a674dcfcf8b4e
MD5 d0ff74e4696529b396999556b2dbfad2
BLAKE2b-256 9ddcb4a9a3e7a24971f7e631d9d7718162581b0ae431ff369083b0bc5bbca388

See more details on using hashes here.

Provenance

The following attestation bundles were made for bobine-0.5.9.tar.gz:

Publisher: release.yml on opticsWolf/bobine

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file bobine-0.5.9-cp314-cp314-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for bobine-0.5.9-cp314-cp314-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 ca8164c37c0f54b6ef3de9308026530646fd2c040b0cc346c7761791d7d11c97
MD5 c8053f8415bee99347d868b47a252cb6
BLAKE2b-256 51736152dcbda917a317d33dbbb5aeb54bad15c491637f7b4b65eafcf7be275c

See more details on using hashes here.

Provenance

The following attestation bundles were made for bobine-0.5.9-cp314-cp314-macosx_11_0_arm64.whl:

Publisher: release.yml on opticsWolf/bobine

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file bobine-0.5.9-cp312-cp312-win_amd64.whl.

File metadata

  • Download URL: bobine-0.5.9-cp312-cp312-win_amd64.whl
  • Upload date:
  • Size: 17.3 MB
  • Tags: CPython 3.12, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for bobine-0.5.9-cp312-cp312-win_amd64.whl
Algorithm Hash digest
SHA256 599db14784de1102502b9cef8907188cb03a8b1ea0742c0ed3c4386d2dc8a7dd
MD5 6dbb99afc5b8112e8f1c6679676b39ad
BLAKE2b-256 0607d3d860905b6cac3074ebaf0a5f2b4cbfa6772174058bbf9cf70382f43a12

See more details on using hashes here.

Provenance

The following attestation bundles were made for bobine-0.5.9-cp312-cp312-win_amd64.whl:

Publisher: release.yml on opticsWolf/bobine

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file bobine-0.5.9-cp312-cp312-manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for bobine-0.5.9-cp312-cp312-manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 1983076f01e1555a73d55f6fdab9c8f77892a622a00362e0dfee1d2dfd24d816
MD5 de9f58bcafec7cf995a28134634530ac
BLAKE2b-256 a93c189782ca5c0ae69ddf53db64362aa66731b1da8823d45130b1e9e90f8df0

See more details on using hashes here.

Provenance

The following attestation bundles were made for bobine-0.5.9-cp312-cp312-manylinux_2_28_x86_64.whl:

Publisher: release.yml on opticsWolf/bobine

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

0.5.11

4 files

0.5.10

4 files

This release

0.5.9 This release

4 files

0.5.8

4 files

0.5.7

4 files

0.2.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page