Tutorial Marker: Mengubah PDF dan Dokumen Menjadi Markdown untuk Pipeline RAG

# Tutorial Marker: Mengubah PDF dan Dokumen Menjadi Markdown untuk Pipeline RAG Dalam dunia AI dan data engineering, kemampuan mengekstrak teks dari dokumen PDF, EPUB, dan gambar menjadi format terst...

By Ruby Abdullah · · tutorial
MarkerPDFOCRRAGDocument Processing

Tutorial Marker: Mengubah PDF dan Dokumen Menjadi Markdown untuk Pipeline RAG

Dalam dunia AI dan data engineering, kemampuan mengekstrak teks dari dokumen PDF, EPUB, dan gambar menjadi format terstruktur adalah kebutuhan fundamental. Marker adalah library open-source buatan VikParuchuri yang mampu mengkonversi dokumen menjadi Markdown berkualitas tinggi dengan akurasi luar biasa, termasuk mengenali tabel, rumus matematika, dan layout dokumen yang kompleks.

Tutorial ini akan membahas cara menggunakan Marker secara lengkap, mulai dari instalasi hingga integrasi ke pipeline RAG (Retrieval-Augmented Generation) produksi.

Mengapa Marker?

Sebelum Marker, developer biasanya mengandalkan PyPDF2, pdfminer, atau Tesseract OCR untuk ekstraksi teks dari PDF. Namun tools tersebut sering menghasilkan output yang berantakan, kehilangan format tabel, dan gagal mengenali layout multi-kolom.

Marker menyelesaikan masalah ini dengan pendekatan berbeda. Library ini menggunakan kombinasi model deep learning untuk:

  • Mendeteksi layout halaman (header, footer, kolom, tabel)
  • Mengenali teks dengan OCR berbasis Surya
  • Mengkonversi tabel menjadi format Markdown yang rapi
  • Memproses rumus matematika menjadi LaTeX
  • Menangani dokumen multi-bahasa

Marker mendukung format input PDF, EPUB, MOBI, dan berbagai format gambar. Output yang dihasilkan berupa Markdown bersih yang siap digunakan untuk indexing, RAG pipeline, atau analisis lebih lanjut.

Instalasi

Prasyarat Sistem

Marker membutuhkan Python 3.9 atau lebih baru. Untuk performa optimal, GPU dengan CUDA sangat direkomendasikan meskipun CPU juga didukung.

python --version

Pastikan versi Python Anda minimal 3.9.

Instalasi via pip

Cara paling mudah menginstall Marker adalah menggunakan pip:

pip install marker-pdf

Ini akan menginstall Marker beserta semua dependensi yang diperlukan, termasuk model Surya untuk OCR dan deteksi layout.

Instalasi dari Source

Jika Anda ingin versi terbaru atau berkontribusi ke development:

git clone https://github.com/VikParuchuri/marker.git

cd marker

pip install -e .

Instalasi dengan GPU Support

Untuk mengaktifkan akselerasi GPU dengan CUDA:

pip install marker-pdf[gpu]

Pastikan CUDA toolkit sudah terinstall di sistem Anda. Verifikasi dengan:

python -c "import torch; print(torch.cuda.isavailable())"

Download Model

Saat pertama kali dijalankan, Marker akan otomatis mendownload model yang diperlukan dari Hugging Face. Model-model ini termasuk:

  • Model deteksi layout
  • Model OCR (Surya)
  • Model pengenalan tabel
  • Model konversi rumus matematika

Total ukuran model sekitar 2-3 GB. Pastikan koneksi internet stabil saat pertama kali menjalankan.

Basic Usage

Konversi File Tunggal via CLI

Marker menyediakan command-line interface yang mudah digunakan:

markersingle /path/to/document.pdf /path/to/output/folder

Perintah ini akan menghasilkan file Markdown di folder output beserta gambar yang diekstrak dari dokumen.

Konversi Batch

Untuk mengkonversi banyak dokumen sekaligus:

marker /path/to/input/folder /path/to/output/folder

Marker akan memproses semua file PDF, EPUB, dan MOBI di folder input secara paralel.

Penggunaan via Python API

Untuk integrasi ke aplikasi Python, gunakan API langsung:

from marker.converters.pdf import PdfConverter

from marker.models import createmodeldict

from marker.output import textfromrendered

Inisialisasi converter dengan model

converter = PdfConverter(

artifactdict=createmodeldict(),

)

Konversi dokumen

rendered = converter("document.pdf")

Dapatkan teks Markdown dan metadata

text, metadata, images = textfromrendered(rendered)

print(text) # Output Markdown

print(metadata) # Metadata dokumen

Contoh Output

Misalnya Anda memiliki PDF laporan keuangan dengan tabel. Marker akan menghasilkan output seperti:

# Laporan Keuangan Q1 2026

Ringkasan Pendapatan

| Kategori | Q1 2025 | Q1 2026 | Pertumbuhan |

|----------|---------|---------|-------------|

| Produk A | Rp 500M | Rp 750M | 50% |

| Produk B | Rp 300M | Rp 420M | 40% |

| Total | Rp 800M | Rp 1.17T | 46% |

Pendapatan perusahaan meningkat sebesar 46% year-over-year...

Perhatikan bagaimana tabel dikonversi dengan rapi ke format Markdown, lengkap dengan alignment.

Konfigurasi Lanjutan

Mengatur Parameter Konversi

Marker menyediakan berbagai parameter untuk mengontrol proses konversi:

from marker.converters.pdf import PdfConverter

from marker.models import createmodeldict

converter = PdfConverter(

artifactdict=createmodeldict(),

)

Konfigurasi melalui config

import marker.settings as settings

Aktifkan debug mode untuk melihat proses detail

settings.DEBUG = True

Atur jumlah worker untuk batch processing

settings.WORKERNUM = 4

Atur device (cuda atau cpu)

settings.TORCHDEVICE = "cuda"

Memproses Halaman Tertentu

Jika Anda hanya membutuhkan halaman tertentu dari dokumen:

from marker.converters.pdf import PdfConverter

from marker.models import createmodeldict

from marker.output import textfromrendered

converter = PdfConverter(

artifactdict=createmodeldict(),

)

Konversi hanya halaman 1-5

rendered = converter("document.pdf", pagerange=[0, 5])

text, metadata, images = textfromrendered(rendered)

Menangani OCR untuk Dokumen Scan

Untuk dokumen hasil scan yang tidak memiliki text layer:

from marker.converters.pdf import PdfConverter

from marker.models import createmodeldict

from marker.output import textfromrendered

import marker.settings as settings

Force OCR pada semua halaman

settings.OCRALLPAGES = True

converter = PdfConverter(

artifactdict=createmodeldict(),

)

rendered = converter("scanneddocument.pdf")

text, metadata, images = textfromrendered(rendered)

Konfigurasi Bahasa OCR

Marker mendukung OCR multi-bahasa melalui Surya:

import marker.settings as settings

Daftar bahasa yang didukung untuk OCR

settings.OCRLANGUAGES = ["id", "en"] # Indonesia dan English

Advanced Usage

Integrasi dengan Pipeline RAG

Salah satu use case utama Marker adalah menyiapkan dokumen untuk pipeline RAG. Berikut contoh integrasi dengan LangChain:

import os

from marker.converters.pdf import PdfConverter

from marker.models import createmodeldict

from marker.output import textfromrendered

from langchain.textsplitter import RecursiveCharacterTextSplitter

from langchaincommunity.vectorstores import Chroma

from langchaincommunity.embeddings import HuggingFaceEmbeddings

def processdocuments(pdffolder: str) -> list:

"""Konversi semua PDF ke Markdown menggunakan Marker."""

converter = PdfConverter(

artifactdict=createmodeldict(),

)

documents = []

for filename in os.listdir(pdffolder):

if filename.endswith(".pdf"):

filepath = os.path.join(pdffolder, filename)

rendered = converter(filepath)

text, metadata, images = textfromrendered(rendered)

documents.append({

"content": text,

"metadata": {

"source": filename,

*metadata

}

})

return documents

def buildragindex(documents: list):

"""Bangun index RAG dari dokumen yang sudah dikonversi."""

textsplitter = RecursiveCharacterTextSplitter(

chunksize=1000,

chunkoverlap=200,

separators=["\n## ", "\n### ", "\n\n", "\n", " "]

)

chunks = []

for doc in documents:

splits = textsplitter.splittext(doc["content"])

for split in splits:

chunks.append({

"text": split,

"metadata": doc["metadata"]

})

embeddings = HuggingFaceEmbeddings(

modelname="sentence-transformers/all-MiniLM-L6-v2"

)

texts = [c["text"] for c in chunks]

metadatas = [c["metadata"] for c in chunks]

vectorstore = Chroma.fromtexts(

texts=texts,

metadatas=metadatas,

embedding=embeddings,

persistdirectory="./chromadb"

)

return vectorstore

Penggunaan

pdffolder = "./documents"

docs = processdocuments(pdffolder)

vectorstore = buildragindex(docs)

Query

results = vectorstore.similaritysearch("pendapatan Q1 2026", k=3)

for r in results:

print(r.pagecontent)

print(r.metadata)

print("---")

Batch Processing dengan Monitoring

Untuk memproses dokumen dalam jumlah besar dengan monitoring progress:

import os

import json

import time

from marker.converters.pdf import PdfConverter

from marker.models import createmodeldict

from marker.output import textfromrendered

def batchconvertwithmonitoring(

inputfolder: str,

outputfolder: str,

logfile: str = "conversionlog.json"

):

"""Batch convert dengan logging dan error handling."""

os.makedirs(outputfolder, existok=True)

converter = PdfConverter(

artifactdict=createmodeldict(),

)

pdffiles = [f for f in os.listdir(inputfolder) if f.endswith(".pdf")]

total = len(pdffiles)

results = []

print(f"Memproses {total} dokumen...")

for i, filename in enumerate(pdffiles, 1):

filepath = os.path.join(inputfolder, filename)

starttime = time.time()

try:

rendered = converter(filepath)

text, metadata, images = textfromrendered(rendered)

# Simpan output Markdown

outputname = filename.replace(".pdf", ".md")

outputpath = os.path.join(outputfolder, outputname)

with open(outputpath, "w", encoding="utf-8") as f:

f.write(text)

# Simpan gambar jika ada

if images:

imgfolder = os.path.join(

outputfolder,

filename.replace(".pdf", "images")

)

os.makedirs(imgfolder, existok=True)

for imgname, imgdata in images.items():

imgpath = os.path.join(imgfolder, imgname)

with open(imgpath, "wb") as f:

f.write(imgdata)

elapsed = time.time() - starttime

result = {

"file": filename,

"status": "success",

"output": outputpath,

"pages": metadata.get("pages", 0),

"timeseconds": round(elapsed, 2),

"imagesextracted": len(images) if images else 0

}

print(f"[{i}/{total}] OK: {filename} ({elapsed:.1f}s)")

except Exception as e:

elapsed = time.time() - starttime

result = {

"file": filename,

"status": "error",

"error": str(e),

"timeseconds": round(elapsed, 2)

}

print(f"[{i}/{total}] ERROR: {filename} - {e}")

results.append(result)

# Simpan log

with open(logfile, "w") as f:

json.dump(results, f, indent=2)

success = sum(1 for r in results if r["status"] == "success")

print(f"\nSelesai: {success}/{total} berhasil dikonversi")

print(f"Log disimpan ke: {logfile}")

return results

Jalankan

results = batchconvertwithmonitoring(

inputfolder="./pdfdocuments",

outputfolder="./markdownoutput"

)

Membuat REST API dengan FastAPI

Untuk menyediakan Marker sebagai service:

import os

import tempfile

from fastapi import FastAPI, UploadFile, File, HTTPException

from fastapi.responses import JSONResponse

from marker.converters.pdf import PdfConverter

from marker.models import createmodeldict

from marker.output import textfromrendered

app = FastAPI(title="Marker PDF Converter API")

converter = None

@app.onevent("startup")

async def loadmodels():

global converter

converter = PdfConverter(

artifactdict=createmodeldict(),

)

@app.post("/convert")

async def convertpdf(file: UploadFile = File(...)):

"""Konversi PDF ke Markdown."""

if not file.filename.endswith((".pdf", ".epub", ".mobi")):

raise HTTPException(

statuscode=400,

detail="Format file tidak didukung. Gunakan PDF, EPUB, atau MOBI."

)

with tempfile.NamedTemporaryFile(

suffix=os.path.splitext(file.filename)[1],

delete=False

) as tmp:

content = await file.read()

tmp.write(content)

tmppath = tmp.name

try:

rendered = converter(tmppath)

text, metadata, images = textfromrendered(rendered)

return JSONResponse({

"filename": file.filename,

"markdown": text,

"metadata": metadata,

"imagescount": len(images) if images else 0

})

except Exception as e:

raise HTTPException(statuscode=500, detail=str(e))

finally:

os.unlink(tmppath)

@app.get("/health")

async def health():

return {"status": "ok", "modelloaded": converter is not None}

Jalankan server:

pip install fastapi uvicorn python-multipart

uvicorn markerapi:app --host 0.0.0.0 --port 8000

Test dengan curl:

curl -X POST http://localhost:8000/convert \

-F "file=@document.pdf" \

| python -m json.tool

Perbandingan Kualitas dengan Tools Lain

Berikut perbandingan Marker dengan tools ekstraksi teks lainnya pada dokumen dengan tabel kompleks:

import time

def compareextraction(pdfpath: str):

"""Bandingkan hasil ekstraksi berbagai tools."""

# Marker

from marker.converters.pdf import PdfConverter

from marker.models import createmodeldict

from marker.output import textfromrendered

start = time.time()

converter = PdfConverter(artifactdict=createmodeldict())

rendered = converter(pdfpath)

markertext, , = textfromrendered(rendered)

markertime = time.time() - start

# PyPDF2

from PyPDF2 import PdfReader

start = time.time()

reader = PdfReader(pdfpath)

pypdftext = ""

for page in reader.pages:

pypdftext += page.extracttext() or ""

pypdftime = time.time() - start

# pdfminer

from pdfminer.highlevel import extracttext

start = time.time()

pdfminertext = extracttext(pdfpath)

pdfminertime = time.time() - start

print("=== Perbandingan Hasil ===")

print(f"Marker : {len(markertext)} chars, {markertime:.2f}s")

print(f"PyPDF2 : {len(pypdftext)} chars, {pypdftime:.2f}s")

print(f"pdfminer : {len(pdfminertext)} chars, {pdfminertime:.2f}s")

print()

print("--- Marker Output (first 500 chars) ---")

print(markertext[:500])

print()

print("--- PyPDF2 Output (first 500 chars) ---")

print(pypdftext[:500])

compareextraction("complexreport.pdf")

Best Practices

1. Optimasi Memori untuk Dokumen Besar

Saat memproses dokumen besar (ratusan halaman), perhatikan penggunaan memori:

import gc

import torch

def processlargedocument(pdfpath: str, batchsize: int = 20):

"""Proses dokumen besar per batch halaman."""

from marker.converters.pdf import PdfConverter

from marker.models import createmodeldict

from marker.output import textfromrendered

import fitz # PyMuPDF

doc = fitz.open(pdfpath)

totalpages = len(doc)

doc.close()

alltext = []

converter = PdfConverter(artifactdict=createmodeldict())

for start in range(0, totalpages, batchsize):

end = min(start + batchsize, totalpages)

rendered = converter(pdfpath, pagerange=[start, end])

text, , = textfromrendered(rendered)

alltext.append(text)

gc.collect()

if torch.cuda.isavailable():

torch.cuda.emptycache()

return "\n\n".join(alltext)

2. Caching Hasil Konversi

Hindari konversi ulang dokumen yang sama:

import hashlib

import json

import os

CACHEDIR = "./markercache"

def getfilehash(filepath: str) -> str:

"""Hitung hash SHA256 dari file."""

sha256 = hashlib.sha256()

with open(filepath, "rb") as f:

for chunk in iter(lambda: f.read(8192), b""):

sha256.update(chunk)

return sha256.hexdigest()

def convertwithcache(pdfpath: str) -> str:

"""Konversi dengan caching berbasis hash file."""

os.makedirs(CACHEDIR, existok=True)

filehash = getfilehash(pdfpath)

cachepath = os.path.join(CACHEDIR, f"{filehash}.json")

if os.path.exists(cachepath):

with open(cachepath, "r") as f:

cached = json.load(f)

print(f"Cache hit: {pdfpath}")

return cached["text"]

from marker.converters.pdf import PdfConverter

from marker.models import createmodeldict

from marker.output import textfromrendered

converter = PdfConverter(artifactdict=createmodeldict())

rendered = converter(pdfpath)

text, metadata, = textfromrendered(rendered)

with open(cachepath, "w") as f:

json.dump({"text": text, "metadata": metadata}, f)

print(f"Converted and cached: {pdfpath}")

return text

3. Validasi Output

Selalu validasi kualitas output sebelum menggunakannya:

def validateconversion(text: str, minlength: int = 100) -> dict:

"""Validasi kualitas hasil konversi."""

issues = []

if len(text) < minlength:

issues.append(f"Teks terlalu pendek ({len(text)} chars)")

lines = text.split("\n")

emptyratio = sum(1 for l in lines if not l.strip()) / max(len(lines), 1)

if emptyratio > 0.7:

issues.append(f"Terlalu banyak baris kosong ({emptyratio:.0%})")

garbled = sum(1 for c in text if ord(c) > 65535) / max(len(text), 1)

if garbled > 0.05:

issues.append(f"Kemungkinan karakter rusak ({garbled:.1%})")

tablecount = text.count("|---|")

headingcount = text.count("\n#")

return {

"valid": len(issues) == 0,

"issues": issues,

"stats": {

"length": len(text),

"lines": len(lines),

"tables": tablecount,

"headings": headingcount,

"emptylineratio": round(emptyratio, 2)

}

}

4. Penanganan Error yang Baik

from pathlib import Path

def safeconvert(pdfpath: str, fallbackocr: bool = True) -> dict:

"""Konversi dengan error handling lengkap."""

path = Path(pdfpath)

if not path.exists():

return {"status": "error", "error": f"File tidak ditemukan: {pdfpath}"}

if not path.suffix.lower() in [".pdf", ".epub", ".mobi"]:

return {"status": "error", "error": f"Format tidak didukung: {path.suffix}"}

filesizemb = path.stat().stsize / (1024 1024)

if filesizemb > 500:

return {"status": "error", "error": f"File terlalu besar: {filesizemb:.0f}MB (max 500MB)"}

try:

from marker.converters.pdf import PdfConverter

from marker.models import createmodeldict

from marker.output import textfromrendered

import marker.settings as settings

if fallbackocr:

settings.OCRALLPAGES = True

converter = PdfConverter(artifactdict=createmodeldict())

rendered = converter(pdfpath)

text, metadata, images = textfromrendered(rendered)

validation = validateconversion(text)

return {

"status": "success",

"text": text,

"metadata": metadata,

"imagescount": len(images) if images else 0,

"validation": validation

}

except Exception as e:

return {"status": "error", "error": str(e)}

5. Tips Performa

Beberapa tips untuk mengoptimalkan performa Marker:

  • Gunakan GPU: Proses konversi 3-5x lebih cepat dengan GPU CUDA
  • Batch processing: Gunakan marker CLI untuk banyak file sekaligus, bukan loop markersingle
  • Page range: Jika hanya butuh halaman tertentu, gunakan parameter pagerange
  • Disk SSD: Model Marker cukup besar, SSD mempercepat loading model
  • Caching: Implementasi caching untuk dokumen yang sering diakses

Kesimpulan

Marker adalah solusi yang sangat powerful untuk mengkonversi dokumen PDF, EPUB, dan MOBI menjadi Markdown berkualitas tinggi. Keunggulan utamanya adalah:

  • Akurasi tinggi dalam mengenali layout, tabel, dan rumus matematika
  • Multi-format mendukung PDF, EPUB, MOBI, dan gambar
  • Multi-bahasa dengan dukungan OCR Surya
  • Open-source dan aktif dikembangkan
  • Mudah diintegrasikan ke pipeline RAG dan aplikasi Python

Dengan Marker, Anda bisa membangun pipeline document processing yang handal untuk berbagai kebutuhan, mulai dari knowledge base perusahaan, sistem pencarian dokumen, hingga chatbot berbasis RAG yang menggunakan dokumen internal sebagai sumber pengetahuan.

Untuk informasi lebih lanjut, kunjungi repository resmi Marker di GitHub dan dokumentasi Surya OCR untuk konfigurasi bahasa tambahan.

Artikel Terkait

Docling: Document Parsing Cerdas untuk Pipeline AI dan RAG

Docling: Document Parsing Cerdas untuk Pipeline AI dan RAG Dalam era AI generatif, kemampuan untuk mengekstrak informasi...

PaddleOCR: Ekstraksi Teks dari Gambar dan Dokumen dengan Akurasi Tinggi

PaddleOCR: Ekstraksi Teks dari Gambar dan Dokumen dengan Akurasi Tinggi Halo temen-temen, kali ini kita bahas salah satu...

DSPy: Berhenti Ngoprek Prompt Manual, Biarkan Compiler yang Optimasi

DSPy: Berhenti Ngoprek Prompt Manual, Biarkan Compiler yang Optimasi Halo temen-temen, kali ini aku mau ngenalin satu li...

FastEmbed: Bikin Embedding Cepat dan Ringan Tanpa Torch dari Qdrant

FastEmbed: Bikin Embedding Cepat dan Ringan Tanpa Torch dari Qdrant Halo temen-temen, balik lagi sama aku Ruby Abdullah....