multixtract — Vendor-neutral document extraction, OCR, chunking, and embeddings for RAG pipelines
Pull text, tables, and images out of PDFs, Word, PowerPoint, Excel/CSV and more — let any vision model describe the images, chunk everything for retrieval, embed it, and store the result anywhere.
The core is tiny (just Pillow + ImageHash). Every format parser and every cloud SDK is an optional extra — install only what you need.
Highlights
✅ Vendor-neutral — swap OpenAI for Azure, Qwen, Llama, or your own model with one line
✅ Extract text, tables, and images from 15+ file formats
✅ Modular — use only extraction, or run the full extract → vision → chunk → embed → store pipeline
✅ Fully offline — local vision models, no API key, no cloud
✅ Tiny core install — only Pillow + ImageHash; every heavy dependency is optional
✅ Fully typed — mypy and pyright compatible out of the box
Why Multixtract?
Most libraries optimise for one part of the workflow — parse documents, run OCR, generate embeddings, or store vectors. You end up stitching together five packages with incompatible interfaces and rebuilding the same pipeline on every project.
multixtract connects all of them without locking you into a provider. Swap OpenAI for Azure or a local model, swap Azure Blob for S3, add a new file format — none of it touches the rest of the pipeline.
What multixtract is not: It is not a vector database, retrieval framework, or chat system. It focuses on document ingestion and preparation — getting clean, structured, chunked content into whatever AI system you're building.
| Feature | multixtract | Unstructured | Docling |
|---|---|---|---|
| ✅ | ✅ | ✅ | |
| DOCX | ✅ | ✅ | ✅ |
| PPTX | ✅ | ✅ | ✅ |
| XLSX / CSV | ✅ | Partial | ❌ |
| EPUB / RTF / HTML / Email | ✅ | Partial | ❌ |
| Vendor-neutral vision model | ✅ | ❌ | ❌ |
| Bring your own embeddings | ✅ | ❌ | ❌ |
| Bring your own storage backend | ✅ | Partial | Partial |
| Fully modular pipeline | ✅ | Partial | Partial |
| Optional dependencies | ✅ | ❌ | ❌ |
| Offline / no-cloud mode | ✅ | ❌ | Partial |
| Core install size | Pillow + ImageHash | Heavy | Heavy |
Quick Start
pip install "multixtract[pdf,docx,pptx,xlsx]"
One call. Any document. Done.
from multixtract import Pipeline
Pipeline().process("report.pdf") # extract → filter → chunk
Pipeline().process("report.pdf", split_chunks=True) # + write individual chunk files
Or stay close to the data:
from multixtract import extract_document, chunk_document
document, images = extract_document("report.pdf")
chunks = chunk_document(document, base_name="report")
Supported formats: PDF · DOCX · PPTX · XLSX · CSV · EPUB · HTML · RTF · Email · Images · Plain text · Markdown — and legacy .doc / .ppt via LibreOffice.
Vision providers: OpenAI · Azure OpenAI · Qwen2.5-VL · Llama 3.2 Vision · SmolVLM (CPU) · bring your own.
→ Full installation guide · Recipes · Provider setup
Document Schema
Every call to extract_document returns the same structure regardless of input format:
PDF / DOCX / PPTX / XLSX / …
│
▼
{
"_base_name": "report",
"metadata": { "format": "pdf", "page_count": 12, ... },
"pgs": [
{
"pg_num": 1,
"kind": "page",
"title": "Executive Summary",
"txt": "The quarterly results show a 12% increase...",
"tables": [
[["Region", "Q1", "Q2"], ["North", "1.2M", "1.4M"], ...]
],
"imgs": [
{ "image_id": "report-p1-img0", "width": 800, "height": 600 }
],
"hyperlinks": ["https://example.com/data"]
},
...
]
}
→ Full data model and chunk schema
Architecture
┌─────────────────────────────────────────────────────────────────┐
│ Your document │
│ PDF · DOCX · PPTX · XLSX · EPUB · HTML · RTF … │
└────────────────────────────┬────────────────────────────────────┘
│
┌────────▼────────┐
│ Extractors │ (registry — one per format)
└────────┬────────┘
│
┌──────────────┼──────────────┐
│ │ │
┌────▼────┐ ┌─────▼─────┐ ┌─────▼───┐
│ Text │ │ Tables │ │ Images │
└────┬────┘ └─────┬─────┘ └─────┬───┘
│ │ │
│ │ ┌─────────▼───────────┐
│ │ │ ImageFilterPipeline│
│ │ │ · dimension │
│ │ │ · solid-color │
│ │ │ · icon rejection │
│ │ │ · logo dedup (hash)│
│ │ └─────────┬───────────┘
│ │ │
│ │ ┌─────────▼───────────┐
│ │ │ VisionModel │
│ │ │ OpenAI · Azure │
│ │ │ Qwen · Llama · CPU │
│ │ │ (or skip entirely) │
│ │ └─────────┬───────────┘
│ │ │
└──────────────┴──────────────┘
│
┌────────▼────────┐
│ Chunking │ sliding-window · table-MD · image
└────────┬────────┘
│
┌────────▼────────┐
│ Embedder │ OpenAI · Azure · BYO · (skip)
└────────┬────────┘
│
┌────────▼────────┐
│ BlobStore │ LocalDisk · AzureBlob · S3 · BYO
└─────────────────┘
The pipeline talks only to three interfaces — it never imports a vendor directly:
| Interface | Job | Built-in implementations |
|---|---|---|
VisionModel |
image → caption + OCR + description | OpenAIVisionModel, AzureOpenAIVisionModel, Qwen2VLVisionModel, SmolVLMVisionModel, Llama32VisionModel |
Embedder |
text → vector | OpenAIEmbedder, AzureOpenAIEmbedder |
BlobStore |
save bytes/JSON | LocalDiskStore, AzureBlobStore |
Add a new format with register_extractor. Plug in S3, GCS, or any backend by implementing three methods on BlobStore.
Integrations
Multixtract is an extraction and chunking layer, not a RAG framework. It fits underneath the tools you already use:
from multixtract import extract_document, chunk_document
from langchain.schema import Document as LCDocument
document, _ = extract_document("report.pdf")
chunks = chunk_document(document, base_name="report")
# LangChain
lc_docs = [LCDocument(page_content=c["content"], metadata={"pg": c["pg_num"]}) for c in chunks]
# LlamaIndex
from llama_index.core import Document as LIDocument
li_docs = [LIDocument(text=c["content"], metadata={"chunk_id": c["chunk_id"]}) for c in chunks]
Example projects
| Integration | What it shows |
|---|---|
| LangChain + Chroma | Ingest → Chroma vector store → RetrievalQA |
| Azure AI Search | Ingest → hybrid keyword + vector search → GPT-4o answer |
| LlamaIndex | Ingest → LlamaIndex VectorStoreIndex → query engine |
| pgvector | Ingest → PostgreSQL + pgvector → cosine similarity search |
| Semantic Kernel | Ingest → SK memory store → prompt function RAG |
| Offline OCR | Tesseract OCR on images — no API key, no cloud, no GPU |
Each example is a self-contained ingest.py with a --query flag so you can extract, store, and query in one command.
Features
- Multi-format: PDF, Word, PowerPoint, Excel/CSV, EPUB, HTML, RTF, email, images (+ legacy
.doc/.pptvia LibreOffice) - Cross-page image deduplication via xref tracking
- Image filters: solid-color / tiny-icon / dimension / reference-logo (perceptual hash)
- Sliding-window text chunking (~500 tokens, ~50 overlap) at sentence boundaries
- Tables serialized to Markdown; images embedded once and reused
- Parallel vision calls (
vision_workers), batched embeddings - Resume support — skip documents already in the store (
skip_if_exists) - Two-stage chunking:
_chunks.jsonwritten automatically; passsplit_chunks=Trueto also write flat individual chunk documents ready for Azure AI Search or any vector store build_index_document()— transforms a raw chunk into a flat, AI-Search-ready document (renamesembedding→content_vector, flattensmetadata)safe_index_key()— sanitizes any string to a valid Azure AI Search document key- Fully typed —
py.typedmarker, compatible with mypy and pyright
Roadmap
- PDF / DOCX / PPTX / XLSX extraction
- EPUB / HTML / RTF / email extraction
- Azure OpenAI vision + embeddings integration
- Local vision models (Qwen2.5-VL, Llama 3.2, SmolVLM)
- Azure Blob Storage backend
- Sliding-window chunking with sentence-boundary awareness
- Smart image filtering (dimension, solid-color, logo dedup)
- Document-level metadata on every chunk (
file_path,doc_id,last_updated, …) - Individual chunk splitting —
split_chunks=Trueorsplit_chunks_file()writes per-chunk documents for AI Search ingestion -
build_index_document()— flat AI-Search-optimized output withcontent_vector, flattenedmetadata - Figure-caption association (link extracted images to their nearest caption)
- Table-of-contents aware chunking (respect heading hierarchy)
- multisense — companion RAG pipeline library built on multixtract
PRs and feature requests welcome via GitHub Issues.
Performance
Extracts a 50-page PDF in ~4 s and a 100-slide PPTX in ~0.14 s on a standard developer machine (no GPU, no API key). Chunking adds negligible overhead.
→ Full benchmark results and methodology
Documentation
| Installation | Extras, formats, providers |
| Recipes | OpenAI · Azure · extract-only · chunk-only · offline OCR |
| Providers | OpenAI · Azure · Qwen · SmolVLM · Llama |
| Data model | Document schema · chunk schema · metadata fields |
| Performance | Benchmark results and methodology |
| Compatibility | Python · OS · torch / CUDA combinations |
| Troubleshooting | LibreOffice · CUDA · Azure auth · common errors |
| API Reference | Full public API |
Contributing
pip install -e ".[dev,pdf,docx,pptx,xlsx,epub,html,rtf]"
pytest
ruff check src tests
mypy src/multixtract --ignore-missing-imports --no-error-summary
python benchmarks/run_benchmarks.py
See CONTRIBUTING.md for guidelines. Bug reports and PRs are welcome.
Example Applications
- Internal RAG systems on Azure OpenAI
- Enterprise search over mixed document libraries
- Research document processing pipelines
Using multixtract in your project? Open a PR to add it here.
License
MIT — see LICENSE.
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 multixtract-0.1.2.tar.gz.
File metadata
- Download URL: multixtract-0.1.2.tar.gz
- Upload date:
- Size: 66.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
25a9971936a49ba5324ed0be8f73db10e139f935d41643df64cf011e8c60365d
|
|
| MD5 |
091ce5e7513c234137613fab186625b1
|
|
| BLAKE2b-256 |
636aa7d48df84232e30f9a2224c5d3bb01178aa93f362dfc4206a860d94c33f6
|
Provenance
The following attestation bundles were made for multixtract-0.1.2.tar.gz:
Publisher:
publish.yml on srivnamrata/multixtract
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
multixtract-0.1.2.tar.gz -
Subject digest:
25a9971936a49ba5324ed0be8f73db10e139f935d41643df64cf011e8c60365d - Sigstore transparency entry: 2475509754
- Sigstore integration time:
-
Permalink:
srivnamrata/multixtract@b74ac0b9f323df035cc5201ffbe39eccd8f60775 -
Branch / Tag:
refs/tags/v0.1.2 - Owner: https://github.com/srivnamrata
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@b74ac0b9f323df035cc5201ffbe39eccd8f60775 -
Trigger Event:
release
-
Statement type:
File details
Details for the file multixtract-0.1.2-py3-none-any.whl.
File metadata
- Download URL: multixtract-0.1.2-py3-none-any.whl
- Upload date:
- Size: 82.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
61bfcf0c29ad60451618232a3168ca12722bcc361cc57285578af54e099abc9f
|
|
| MD5 |
d3d46949b0bd467c92b7320e6f4eb00b
|
|
| BLAKE2b-256 |
ca5d2d98c192178a04f561305352ba4f5ec72b9eb4cd0d1bce3a09ad3dda918d
|
Provenance
The following attestation bundles were made for multixtract-0.1.2-py3-none-any.whl:
Publisher:
publish.yml on srivnamrata/multixtract
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
multixtract-0.1.2-py3-none-any.whl -
Subject digest:
61bfcf0c29ad60451618232a3168ca12722bcc361cc57285578af54e099abc9f - Sigstore transparency entry: 2475509773
- Sigstore integration time:
-
Permalink:
srivnamrata/multixtract@b74ac0b9f323df035cc5201ffbe39eccd8f60775 -
Branch / Tag:
refs/tags/v0.1.2 - Owner: https://github.com/srivnamrata
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@b74ac0b9f323df035cc5201ffbe39eccd8f60775 -
Trigger Event:
release
-
Statement type: