A FastAPI service that converts documents to Markdown. Designed for RAG pipelines that need clean, structured text — including tables embedded as images inside PowerPoint presentations.
- Converts PPTX, DOCX, PDF, XLSX and other formats to Markdown
- PPTX image intelligence: extracts images slide-by-slide via
python-pptx, sends each image to Azure Content Understanding (prebuilt-layout) to extract table data as structured Markdown - Vector image support: EMF/WMF images are automatically converted to PDF via LibreOffice before analysis — no resolution loss
- Automatic retry (up to 3 attempts per image)
- Isolated temp directories per request — no file collisions under concurrent load
- Configurable log level via
LOG_LEVELenv var
Converts an uploaded file to Markdown.
Request: multipart/form-data with a file field.
Response:
{
"markdown": "# Slide title\n\n| Col A | Col B |\n|-------|-------|\n| 1 | 2 |\n"
}Example with curl:
curl -X POST http://localhost:8000/convert \
-F "file=@presentation.pptx"Returns {"status": "healthy"}. Use for container health checks and load balancer probes.
Accepts an EMF, WMF, or SVG file and returns the PDF generated by LibreOffice. Useful for inspecting the intermediate conversion before it is sent to Azure Content Understanding.
curl -X POST http://localhost:8000/debug-to-pdf \
-F "file=@image.wmf" \
--output result.pdfStandard MarkItDown produces empty ![]() placeholders for images it cannot process as text. This API replaces that behaviour for PPTX files:
- MarkItDown (without LLM) extracts all text and slide structure, producing base Markdown with image placeholders.
python-pptxextracts image bytes directly from each slide by shape position — avoiding name collisions where PowerPoint reuses names likeImagem1across slides pointing to different images.- For each image placeholder:
- If the image is a vector format (EMF, WMF, SVG) → LibreOffice converts it to PDF first (preserving vector fidelity).
- The image (or PDF) is sent to Azure Content Understanding (
prebuilt-layoutanalyzer). - The detected tables are converted to Markdown and replace the placeholder.
- If no table is detected in an image, the placeholder is removed cleanly.
All other file formats (DOCX, PDF, XLSX, etc.) are handled directly by MarkItDown.
| Variable | Required | Description |
|---|---|---|
AZURE_CONTENT_UNDERSTANDING_ENDPOINT |
Yes | Azure AI Foundry endpoint (e.g. https://your-resource.services.ai.azure.com) |
AZURE_FOUNDRY_API_KEY |
Yes | API key for the Azure AI Foundry resource |
LIBREOFFICE_BIN |
No | Full path to the LibreOffice binary. In Docker (Linux) it is found automatically via PATH. Required on Windows if soffice.exe is not in PATH. |
LOG_LEVEL |
No | Logging level: DEBUG, INFO, WARNING, ERROR. Defaults to INFO. |
Create a .env file at the project root (see .env.example if available). The application loads it automatically at startup.
Windows local development: if LibreOffice is not in your PATH, uncomment and set
LIBREOFFICE_BINin your.env:LIBREOFFICE_BIN=C:/Program Files/LibreOffice/program/soffice.exe
docker build -t markitdown-api .
docker run -p 8000:8000 \
-e AZURE_CONTENT_UNDERSTANDING_ENDPOINT=https://your-resource.services.ai.azure.com \
-e AZURE_FOUNDRY_API_KEY=your-key \
markitdown-apiDo not pass
LIBREOFFICE_BINwhen running on Linux/Docker — LibreOffice is installed in the image and found automatically via PATH.
pip install -r requirements.txt
# Make sure .env is populated, then:
uvicorn app:app --host 0.0.0.0 --port 8000 --reload.
├── app.py # FastAPI application
├── requirements.txt # Python dependencies
├── Dockerfile # Container definition
└── README.md
| Package | Purpose |
|---|---|
fastapi + uvicorn |
HTTP server |
markitdown |
Text and structure extraction from documents |
python-pptx |
Slide-level image extraction for PPTX |
azure-ai-contentunderstanding |
Table extraction from images via Azure Content Understanding |
azure-identity |
Azure credential helpers |
python-multipart |
File upload support |
python-dotenv |
.env file loading |
System dependencies installed in the Docker image: libreoffice-draw, fonts-liberation, libmagic1.