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
  • More than 6GB VRAM for Marker 1 on GPU — its model set fills a 6GB card before inference starts and dies with a CUDA OOM. On a smaller card run TORCH_DEVICE=cpu sahaf
  • 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

Download files

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

Source Distribution

sahaf-0.2.2.tar.gz (43.4 kB view details)

Uploaded Source

Built Distribution

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

sahaf-0.2.2-py3-none-any.whl (41.1 kB view details)

Uploaded Python 3

File details

Details for the file sahaf-0.2.2.tar.gz.

File metadata

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

File hashes

Hashes for sahaf-0.2.2.tar.gz
Algorithm Hash digest
SHA256 94b306256adbc8548c4bf434fe97d4d5221f73f893dcfdc4f0ef4ac4fac1f09e
MD5 b680e84e3191236b7b67183751b0a1aa
BLAKE2b-256 e94865f9cfccfc1a9dcb8311dfaaaae6d49690225ecf02526711a7f41fb08d83

See more details on using hashes here.

Provenance

The following attestation bundles were made for sahaf-0.2.2.tar.gz:

Publisher: publish.yml on arikusi/sahaf

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

File details

Details for the file sahaf-0.2.2-py3-none-any.whl.

File metadata

  • Download URL: sahaf-0.2.2-py3-none-any.whl
  • Upload date:
  • Size: 41.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for sahaf-0.2.2-py3-none-any.whl
Algorithm Hash digest
SHA256 49d57f9dd09971d92f85ad1d31434201ff51bfeb2aa821cc23f24aaa333170ad
MD5 e3307b2c8a5b1241369a36dcad9f0871
BLAKE2b-256 ca4df7dd92e464ad0a4a52c3c073fdd3d9766ab1fec37ecaf4521c48f2105bd2

See more details on using hashes here.

Provenance

The following attestation bundles were made for sahaf-0.2.2-py3-none-any.whl:

Publisher: publish.yml on arikusi/sahaf

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.2.3

2 files

This release

0.2.2 This release

2 files

0.2.1

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