Markdrop
A Python package for converting PDFs to structured Markdown and interactive HTML, with AI-powered image and table descriptions across six major LLM providers. Available on PyPI.
Features
- PDF → Markdown conversion with formatting preservation (via Docling)
- Automatic image extraction using XRef IDs
- Table detection using Microsoft's Table Transformer
- PDF URL support
- AI-powered image and table descriptions — 6 providers: Gemini, OpenAI, Anthropic Claude, Groq, OpenRouter, LiteLLM
- Interactive HTML output with downloadable Excel tables
- Customisable image resolution and UI elements
- Structured logging (never pollutes your app's root logger)
Installation
Core install (PDF conversion + Gemini/OpenAI):
pip install markdrop
With Anthropic Claude:
pip install "markdrop[anthropic]"
With Groq:
pip install "markdrop[groq]"
With LiteLLM (routes to 100+ providers):
pip install "markdrop[litellm]"
Everything (including local HuggingFace models):
pip install "markdrop[all]"
Faster CPU / lightweight Markdown (--fast mode):
pip install "markdrop[lite]"
markdrop convert report.pdf --output_dir out --fast
See docs/cpu-guide.md for CPU-only and Colab guidance.
OpenRouter is accessed through the
openaipackage (already included in core), so no extra install is needed.
Supported AI Providers
| Provider | --ai_provider |
Default vision model | Default text model (tables) | Vision |
|---|---|---|---|---|
| Google Gemini | gemini |
gemini-3.1-flash-lite |
gemini-3.1-flash-lite |
✅ |
| OpenAI | openai |
gpt-5.6-terra |
gpt-5.6-luna |
✅ |
| Anthropic Claude | anthropic |
claude-opus-5 |
claude-sonnet-5 |
✅ |
| Groq | groq |
meta-llama/llama-4-maverick-17b-128e-instruct |
meta-llama/llama-4-scout-17b-16e-instruct |
✅ |
| OpenRouter | openrouter |
google/gemini-3.1-flash-lite |
anthropic/claude-sonnet-5 |
✅ |
| LiteLLM | litellm |
openai/gpt-5.6-terra |
openai/gpt-5.6-luna |
✅ |
All models are configurable — use
--modelto override for any provider, or setmodel_name_overrideinProcessorConfig.
Quick Start
See examples/quickstart.md for copy-paste commands.
CLI Usage
Check the installed version:
markdrop --version
1. Convert PDF → Markdown + HTML
markdrop convert <input_path> --output_dir <dir> [--add_tables] [--fast]
# Example
markdrop convert report.pdf --output_dir out --add_tables
# Outputs: out/report-markdroped.md and out/report-markdroped.html
# Also works with URLs (SSRF-protected download):
markdrop convert https://arxiv.org/pdf/1706.03762 --output_dir out
2. Generate AI Descriptions for Images & Tables
markdrop describe <markdown_file> --ai_provider <provider> [--output_dir <dir>] [--remove_images] [--remove_tables]
| Provider | --ai_provider |
|---|---|
| Google Gemini | gemini |
| OpenAI | openai |
| Anthropic Claude | anthropic |
| Groq | groq |
| OpenRouter | openrouter |
| LiteLLM | litellm |
# Gemini (default)
markdrop describe doc.md --ai_provider gemini
# Anthropic Claude
markdrop describe doc.md --ai_provider anthropic --remove_images
# Groq (fastest inference)
markdrop describe doc.md --ai_provider groq
# OpenRouter (any model)
markdrop describe doc.md --ai_provider openrouter
# LiteLLM (unified gateway)
markdrop describe doc.md --ai_provider litellm
3. Set Up API Keys
markdrop setup <provider>
Keys are stored in your user config directory (via platformdirs, with a fallback to ~/.config/markdrop/):
- Linux/macOS:
~/.config/markdrop/.env(or$XDG_CONFIG_HOME/markdrop/.env) - Windows:
%LOCALAPPDATA%\markdrop\.env
On POSIX systems, the .env file is written with 0o600 permissions.
markdrop setup gemini # → GEMINI_API_KEY (GOOGLE_API_KEY also accepted)
markdrop setup openai # → OPENAI_API_KEY
markdrop setup anthropic # → ANTHROPIC_API_KEY
markdrop setup groq # → GROQ_API_KEY
markdrop setup openrouter # → OPENROUTER_API_KEY
markdrop setup litellm # → LITELLM_API_KEY
4. Analyze Images in a PDF
markdrop analyze report.pdf --output_dir pdf_analysis --save_images
5. Batch Image Description Generation
markdrop generate images/ --output_dir descriptions/ --prompt "Describe in detail." \
--llm_client gemini openai
Available --llm_client values: qwen, gemini, openai, llama-vision, molmo, pixtral
Python API
PDF Conversion
from markdrop import markdrop, MarkDropConfig, add_downloadable_tables
from pathlib import Path
import logging
config = MarkDropConfig(
image_resolution_scale=2.0,
download_button_color="#444444",
log_level=logging.INFO,
log_dir="logs",
excel_dir="markdrop-excel-tables",
)
html_path = markdrop("path/to/input.pdf", "output", config)
downloadable_html = add_downloadable_tables(html_path, config)
AI Descriptions
import asyncio
from markdrop import process_markdown, ProcessorConfig, AIProvider, setup_keys
# One-time key setup (writes to user config ~/.config/markdrop/.env)
setup_keys("anthropic")
config = ProcessorConfig(
input_path="out/report-markdroped.md",
output_dir="output",
ai_provider=AIProvider.ANTHROPIC, # GEMINI | OPENAI | ANTHROPIC | GROQ | OPENROUTER | LITELLM
remove_images=False,
remove_tables=False,
table_descriptions=True,
image_descriptions=True,
max_retries=3,
retry_delay=2,
# Override default models (all providers have matching config fields):
anthropic_model_name="claude-opus-5",
anthropic_text_model_name="claude-sonnet-5",
)
output_path = asyncio.run(process_markdown(config))
Using OpenRouter to access any model
config = ProcessorConfig(
input_path="doc.md",
output_dir="output",
ai_provider=AIProvider.OPENROUTER,
openrouter_model_name="meta-llama/llama-4-scout", # any model on openrouter.ai/models
openrouter_text_model_name="anthropic/claude-sonnet-5",
openrouter_site_url="https://yoursite.com",
openrouter_site_name="My App",
)
Using LiteLLM for any 100+ provider
import os
os.environ["ANTHROPIC_API_KEY"] = "..." # set any provider's key
config = ProcessorConfig(
input_path="doc.md",
output_dir="output",
ai_provider=AIProvider.LITELLM,
litellm_model_name="anthropic/claude-opus-5",
litellm_text_model_name="openai/gpt-5.6-luna",
)
Batch Image Description Generation
from markdrop import generate_descriptions
generate_descriptions(
input_path="images/",
output_dir="output/",
prompt="Give a highly detailed description of this image.",
llm_client=["gemini", "llama-vision"],
)
API Reference
ProcessorConfig – AI Provider Fields
| Field | Default | Notes |
|---|---|---|
gemini_model_name |
gemini-3.1-flash-lite |
Vision model |
gemini_text_model_name |
gemini-3.1-flash-lite |
Text model |
openai_model_name |
gpt-5.6-terra |
Vision |
openai_text_model_name |
gpt-5.6-luna |
Tables / text |
anthropic_model_name |
claude-opus-5 |
Vision |
anthropic_text_model_name |
claude-sonnet-5 |
Text (cheaper) |
groq_model_name |
meta-llama/llama-4-maverick-17b-128e-instruct |
Vision |
groq_text_model_name |
meta-llama/llama-4-scout-17b-16e-instruct |
Text |
openrouter_model_name |
google/gemini-3.1-flash-lite |
Any model string from openrouter.ai/models |
openrouter_text_model_name |
anthropic/claude-sonnet-5 |
|
litellm_model_name |
openai/gpt-5.6-terra |
provider/model format |
litellm_text_model_name |
openai/gpt-5.6-luna |
MarkDropConfig
| Field | Default | Notes |
|---|---|---|
image_resolution_scale |
2.0 |
Scale factor for extracted images |
download_button_color |
'#444444' |
HTML button colour |
log_level |
logging.INFO |
|
log_dir |
'logs' |
|
excel_dir |
'markdrop_excel_tables' |
Contributing
We welcome contributions! See CONTRIBUTING.md. Please read our Code of Conduct.
git clone https://github.com/shoryasethia/markdrop.git
cd markdrop
python -m venv venv && source venv/bin/activate # Windows: venv\Scripts\activate
pip install -e .
Project Structure
markdrop/
├── setup.py
├── requirements.txt
├── README.md
└── markdrop/
├── __init__.py
├── main.py ← CLI entry-point
├── process.py ← PDF conversion
├── parse.py ← AI description engine (all 6 providers)
├── helper.py ← PDF image analysis
├── utils.py ← PDF download helpers
├── setup_keys.py ← Interactive API key manager
├── ignore_warnings.py
├── src/
│ └── markdrop-logo.png
└── models/
├── img_descriptions.py
├── model_loader.py ← Local HF model loader
├── responder.py
└── logger.py
License
GPL-3.0 — see LICENSE.
Changelog
See CHANGELOG.md.
Support
Metadata
Release files for markdrop 4.1.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| markdrop-4.1.2.tar.gz | 49.7 kB | Without provenance | Details for markdrop-4.1.2.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| markdrop-4.1.2-py3-none-any.whl | Python 3 | none | any | Details for markdrop-4.1.2-py3-none-any.whl |
Total release size: 102.3 kB
Release files / markdrop-4.1.2.tar.gz
| Download URL | markdrop-4.1.2.tar.gz |
|---|---|
| Size | 49.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
2bb6ba3b72257c47d6767aedb5ec25278f920feb1a96f274857286b524fe5b40
|
|
BLAKE2b-256 checksum How to use checksums |
60238a77d772c44932983a3e0afc9074bbc9ec7e5ff50911c25e9d45ef681264
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.11
|
Release files / markdrop-4.1.2-py3-none-any.whl
| Download URL | markdrop-4.1.2-py3-none-any.whl |
|---|---|
| Size | 52.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
ed90cedb8f4a3e2f1fd55b8fe47d5f14ae617d8760190dd34f7857742dce4230
|
|
BLAKE2b-256 checksum How to use checksums |
0e4a617aeb6a1f1a5b2a18cb6b8d706e5b1f353d1e4b16ff2038554eb496db9b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.11
|
Security for markdrop 4.1.2
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.