Skip to main content

Sahaf

CI PyPI Downloads License: GPL v3

Local PDF & EPUB to Markdown converter with automatic digital/scanned detection, OCR support, smart splitting, and page-range selection. Converts books to clean, self-contained Markdown files with embedded images using Marker and Surya OCR (90+ languages). No cloud APIs — runs entirely on your hardware.

Features

  • PDF & EPUB support — handles both formats natively
  • Automatic PDF classification — detects digital, scanned, or mixed PDFs via PyMuPDF
  • High-accuracy conversion — works with both Marker 1.x and Marker 2.x, whichever you install
  • Built-in OCR — Surya OCR supports 90+ languages (Turkish, English, Arabic, etc.)
  • Page/chapter range selection — convert only a specific section of the book (e.g. pages 19-88)
  • Smart splitting — split output into N parts, cutting at heading/paragraph boundaries instead of mid-sentence
  • Self-contained output — images embedded as base64 directly in Markdown, no separate files
  • Split preview — see exactly how parts will be divided before downloading
  • Bilingual UI — Turkish / English interface with one-click toggle
  • Dark/light theme — lavender-toned design, persistent toggle
  • Drag & drop UI — clean single-page web interface

Install

pip install sahaf

Or from source:

git clone https://github.com/arikusi/sahaf.git
cd sahaf
pip install -e .

Models are downloaded automatically on first conversion.

Choosing Marker 1 or Marker 2

Both lines work — Sahaf detects which one is installed and configures it accordingly. The difference only matters for scanned PDFs; digital PDFs and EPUBs convert the same either way.

Marker 1.x — OCR in-process, nothing else to install

pip install sahaf "marker-pdf<2"

OCR runs inside the Python process with torch, on any CUDA GPU including pre-Ampere cards (GTX 16xx, RTX 20xx). The safe choice for scanned books.

Marker 2.x — faster and more accurate, needs an OCR server

pip install sahaf

Marker 2 reads the PDF text layer and only OCRs what needs it (76.0% on olmOCR-bench in balanced mode). But its OCR model is served out of process, so scanned pages need one of:

  • Docker plus the NVIDIA Container Toolkit, on an Ampere or newer GPU — the server runs in bfloat16, which needs compute capability 8.0+. On Arch: sudo pacman -S nvidia-container-toolkit && sudo nvidia-ctk runtime configure --runtime=docker && sudo systemctl restart docker
  • llama.cpp (llama-server on your PATH) — works anywhere, but CPU inference is slow on book-length documents

Sahaf classifies each PDF before converting, so under Marker 2 a digital book runs in fast mode and never starts that server.

Quick Start

sahaf

Open http://localhost:8000 in your browser.

Uploads and converted files land in ~/.local/share/sahaf. To keep them elsewhere:

SAHAF_DATA_DIR=./sahaf-data sahaf

How It Works

  1. Upload — drag & drop a PDF or EPUB file
  2. Classify — PyMuPDF analyzes PDF type; EPUB chapters are counted
  3. Select range (optional) — pick specific pages or chapters to convert
  4. Convert — Marker processes PDF; ebooklib + markdownify handles EPUB
  5. Split (optional) — choose how many parts to split the output into
  6. Download — get a single .md or a ZIP with split parts, all images embedded inline

API

Method Path Description
POST /api/upload Upload PDF/EPUB, returns task_id
GET /api/classify/{task_id} Detect PDF type + page count, or EPUB chapter count
POST /api/convert/{task_id}?page_from=&page_to= Start conversion (optional page range)
GET /api/status/{task_id} Poll conversion progress
GET /api/result/{task_id} Get markdown + image list
GET /api/download/{task_id} Download .md with embedded images
GET /api/download/{task_id}/zip?parts=N Download ZIP with N split .md files
GET /api/split-preview/{task_id}?parts=N Preview split structure before download

Tech Stack

  • Backend: FastAPI + Uvicorn
  • PDF Classification: PyMuPDF
  • PDF Conversion: Marker (marker-pdf 1.x or 2.x) + Surya OCR
  • EPUB Conversion: ebooklib + markdownify
  • Smart Splitting: Custom algorithm — heading/HR/paragraph boundary detection
  • Frontend: Vanilla HTML/CSS/JS + marked.js
  • i18n: TR/EN with client-side toggle

Requirements

  • Python 3.10 – 3.13 (Marker's dependency stack pins pillow<11, which has no 3.14 wheels)
  • 4-6GB RAM (when Marker models are loaded)
  • GPU strongly recommended for scanned PDFs — those go through the OCR model; CPU inference is slow on book-length documents
  • 4GB+ VRAM — below 8GB, Sahaf automatically switches Marker to memory settings that fit, so a 6GB card converts scanned books without any configuration. Set FOUNDATION_CHUNK_SIZE or the *_BATCH_SIZE variables yourself to override
  • Under Marker 2, digital PDFs run without the OCR server at all
  • EPUB conversion is lightweight — no GPU needed, runs instantly

License

GPL-3.0

Metadata

Release files for sahaf 0.2.3

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for sahaf 0.2.3
File Size Uploaded
sahaf-0.2.3.tar.gz 48.5 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for sahaf 0.2.3
File Interpreter ABI Platform
sahaf-0.2.3-py3-none-any.whl Python 3 none any Details

Total release size: 92.7 kB

Release files / sahaf-0.2.3.tar.gz

Download URL sahaf-0.2.3.tar.gz
Size 48.5 kB
Tags Source
SHA-256 checksum
How to use checksums
6e2e044ad74c8d06ce644dd898ba07e9e3d1b2a10bb4b9c0d75079e560099765
BLAKE2b-256 checksum
How to use checksums
ecfbfe2e7e41042f3fc2c7769fdd94a37766c0025243de94dda19eb65af766b7
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 2, 2026.

Transparency log

Release files / sahaf-0.2.3-py3-none-any.whl

Download URL sahaf-0.2.3-py3-none-any.whl
Size 44.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
dcca4633a67d85a0c38612dabe319781ee3744e33575ceb9dee172e55ed2d5c4
BLAKE2b-256 checksum
How to use checksums
f39de4138d7b7712e3152890c7762cbce1c9cf5ae9c99d1823446eeb33aaeede
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 2, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.2.3 This release

2 release files

0.2.2

2 release files

0.2.1

2 release 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