π Document Parsing for RAG β The Art of Extracting Clean Text
Dari PDF, HTML, Word ke Teks Bersih: Fondasi Pipeline Ingestion
Dokumen adalah lumbung pengetahuan. Tapi sebelum LLM bisa membacanya, Anda harus mengubahnya menjadi teks bersih. Parsing bukan sekadar βmembuka file.β Ia adalah seni mengekstrak struktur semantik dari representasi visual yang kacau. PDF dengan tabel, gambar, dan multi-kolom. HTML dengan JavaScript dan iklan. Word dengan track changes. Dokumen ini membedah arsitektur parsing modern, dari Unstructured.io hingga LlamaParse, dengan implementasi kode production-ready untuk setiap format.
Hubungan ke Vault
Nota ini adalah pintu masuk data eksternal ke vault. Output parser (teks markdown terstruktur) adalah input untuk advanced-chunking-strategies-deepdive (parent-child chunking). Terkait dengan ai-engineering-stack-roadmap (Fase 2: Data Pipeline), encoding-serialization-compression-deepdive (encoding charset), dan linux-fundamentals-deepdive (filesystem path, encoding locales).
Daftar Isi
- 1. First Principles
- 2. Arsitektur Pipeline Parsing
- 3. Implementasi per Format
- 4. Cleaning & Normalization
- 5. Perbandingan Tools
- 6. Rekomendasi untuk Vault Ini
- Roadmap Ingestion
- Koneksi ke Vault
- References
1. First Principles: Mengapa Parsing Sulit?
1.1 The Visual-Textual Gap
Dokumen digital, terutama PDF, dirancang untuk tampilan visual yang konsisten, bukan untuk ekstraksi teks. Teks bisa tersimpan sebagai karakter individual dengan koordinat absolut, bukan sebagai paragraf yang mengalir. Sebuah tabel mungkin bukan βtabelβ dalam kode, melainkan serangkaian kotak teks yang diposisikan secara visual agar terlihat seperti tabel bagi mata manusia.
Masalah fundamental:
- Urutan Membaca: Teks multi-kolom bisa terbaca sebagai satu baris yang melompat dari kolom kiri ke kanan
- Header/Footer: Nomor halaman, judul bab berulang, dan catatan kaki ikut terekstrak sebagai teks yang tidak relevan
- Tabel: Data tabular kehilangan strukturnya dan menjadi teks yang tidak koheren
- Gambar & Grafik: Informasi di dalam gambar (diagram, flowchart) hilang sama sekali
1.2 Spektrum Format Dokumen
| Format | Kompleksitas | Tools Utama | Skenario Vault |
|---|---|---|---|
| Markdown | π’ Sangat Rendah | MarkdownHeaderTextSplitter | Dokumen vault sendiri (sudah optimal) |
| HTML | π‘ Rendah-Sedang | BeautifulSoup, Unstructured | Web scraping, arsip blog |
| Word (DOCX) | π‘ Sedang | python-docx, Unstructured | Laporan internal, whitepaper |
| PDF (Digital) | π΄ Tinggi | PyMuPDF, pdfplumber | Paper akademik, laporan resmi |
| PDF (Scanned/OCR) | π΄ Sangat Tinggi | Tesseract, Azure Document Intelligence | Dokumen historis, faks |
| Gambar (Screenshot) | π΄ Sangat Tinggi | LlamaParse, GPT-4V | Infografis, slide presentasi |
2. Arsitektur Pipeline Parsing
Pipeline parsing yang tangguh tidak bergantung pada satu alat. Ia adalah rantai pemrosesan bertingkat yang menangani berbagai format dan kualitas dokumen.
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β DOCUMENT PARSING PIPELINE β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β [Input File] β
β β β
β βΌ β
β ββββββββββββββββββββββ β
β β DETECTOR β Identifikasi tipe file β
β β (MIME/Magic bytes) β (PDF, DOCX, HTML, MD, Gambar) β
β βββββββββββ¬βββββββββββ β
β β β
β βββββββΌβββββββ¬βββββββββββ¬ββββββββββββ β
β βΌ βΌ βΌ βΌ βΌ β
β [PDF] [DOCX] [HTML] [Markdown] [Image] β
β β β β β β β
β βΌ βΌ βΌ βΌ βΌ β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β EXTRACTION LAYER (Format-Specific Parsers) β β
β β β’ PyMuPDF (fitz) β PDF digital β β
β β β’ pdfplumber β tabel dalam PDF β β
β β β’ Tesseract β OCR untuk PDF scan β β
β β β’ python-docx β DOCX β β
β β β’ BeautifulSoup / Trafilatura β HTML β β
β β β’ LlamaParse / GPT-4V β gambar kompleks β β
β βββββββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββ β
β β β
β βΌ β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β CLEANING & NORMALIZATION β β
β β β’ Hapus header/footer berulang β β
β β β’ Normalisasi whitespace & encoding β β
β β β’ Deteksi dan perbaiki urutan baca (multi-kolom) β β
β β β’ Ekstrak metadata (judul, penulis, tanggal) β β
β βββββββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββ β
β β β
β βΌ β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β STRUCTURE PRESERVATION β β
β β β’ Tandai heading (H1, H2, H3) β β
β β β’ Tandai paragraf, list, tabel, kode β β
β β β’ Output: Markdown terstruktur β β
β βββββββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββ β
β β β
β βΌ β
β [Clean Structured Text] β Siap untuk Chunking β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
3. Implementasi per Format
3.1 PDF Digital β PyMuPDF (fitz)
import fitz # PyMuPDF
def parse_pdf_digital(file_path: str) -> str:
doc = fitz.open(file_path)
full_text = []
for page_num, page in enumerate(doc):
text = page.get_text("text", sort=True)
tables = page.find_tables()
if tables:
for table in tables:
text += f"\n\n{table.to_markdown()}"
full_text.append(f"[Page {page_num + 1}]\n{text}")
doc.close()
return "\n\n".join(full_text)3.2 PDF Scanned (OCR) β Tesseract
import pytesseract
from pdf2image import convert_from_path
def parse_pdf_scanned(file_path: str) -> str:
images = convert_from_path(file_path, dpi=300)
full_text = []
for i, image in enumerate(images):
text = pytesseract.image_to_string(image, lang="eng+ind")
full_text.append(f"[Page {i + 1}]\n{text}")
return "\n\n".join(full_text)3.3 DOCX β python-docx
from docx import Document
def parse_docx(file_path: str) -> str:
doc = Document(file_path)
full_text = []
for para in doc.paragraphs:
if para.style.name.startswith("Heading"):
level = para.style.name.split()[-1]
full_text.append(f"{'#' * int(level)} {para.text}")
else:
full_text.append(para.text)
for table in doc.tables:
for row in table.rows:
full_text.append(" | ".join(cell.text for cell in row.cells))
return "\n\n".join(full_text)3.4 HTML β Trafilatura
import trafilatura
def parse_html(url: str) -> str:
downloaded = trafilatura.fetch_url(url)
return trafilatura.extract(downloaded, output_format="markdown")3.5 Universal Parser β Unstructured.io
from unstructured.partition.auto import partition
def parse_universal(file_path: str) -> list[dict]:
elements = partition(filename=file_path)
return [{
"type": el.category,
"text": el.text,
"metadata": el.metadata.to_dict() if el.metadata else {},
} for el in elements]3.6 AI-Powered β LlamaParse
import nest_asyncio
from llama_parse import LlamaParse
nest_asyncio.apply()
def parse_with_ai(file_path: str, api_key: str) -> str:
parser = LlamaParse(api_key=api_key, result_type="markdown", num_workers=4)
documents = parser.load_data(file_path)
return "\n\n".join([doc.text for doc in documents])4. Cleaning & Normalization
import re
def clean_extracted_text(text: str) -> str:
lines = text.split("\n")
# Hapus header/footer berulang (>30% halaman)
line_counts = {}
for line in lines:
line_counts[line] = line_counts.get(line, 0) + 1
cleaned = [l for l in lines if line_counts[l] < len(lines) * 0.3]
text = "\n".join(cleaned)
text = re.sub(r'\n{3,}', '\n\n', text) # max 2 consecutive newlines
text = re.sub(r'[ \t]+', ' ', text) # normalize spaces
text = text.encode("utf-8", errors="ignore").decode("utf-8")
text = re.sub(r'[^\x20-\x7E\n]', '', text) # non-printable
return text.strip()5. Perbandingan Tools
| Tool | Format Terbaik | Keunggulan | Kelemahan | Biaya |
|---|---|---|---|---|
| PyMuPDF (fitz) | PDF digital | π’ Cepat, akurat, open-source | π΄ Tidak bisa OCR | π’ Gratis |
| pdfplumber | PDF + tabel | π’ Ekstraksi tabel sangat baik | π‘ Lebih lambat | π’ Gratis |
| Tesseract | PDF scan, gambar | π’ OCR gratis, banyak bahasa | π‘ Akurasi bervariasi | π’ Gratis |
| Unstructured.io | Semua format | π’ Universal, output terstruktur | π‘ Setup kompleks | π’ Gratis (OSS) |
| LlamaParse | Semua kompleks | π’ AI-powered, paham konteks visual | π΄ Biaya API, latency | π΄ Berbayar |
| Azure Document Intel | Form, invoice | π’ Akurasi tinggi, cloud-native | π΄ Vendor lock-in | π΄ Berbayar |
6. Rekomendasi untuk Vault Ini
Karena vault mayoritas file Markdown (sudah bersih), fokus parsing adalah data eksternal:
- Unstructured.io sebagai default parser β 20+ format, output terstruktur
- PyMuPDF + pdfplumber untuk paper akademik (PDF digital)
- LlamaParse untuk dokumen scan/historis β biaya sepadan akurasi
- Simpan hasil sebagai Markdown β langsung diproses Structure-Aware chunking vault
Roadmap Ingestion
| Phase | Kemampuan | Tools |
|---|---|---|
| 1 (sekarang) | Vault markdown β Chunking β Vector DB | index_vault.py |
| 2 | + PDF ingestion | PyMuPDF β Markdown β pipeline existing |
| 3 | + Web scraping | Trafilatura β Markdown β pipeline existing |
| 4 | + DOCX/XLSX | Unstructured β Markdown β pipeline existing |
| 5 | + OCR pipeline | Tesseract/LlamaParse β Markdown β pipeline existing |
Koneksi ke Vault
- advanced-chunking-strategies-deepdive β Output parser jadi input chunking. Kualitas chunking tergantung kualitas parsing
- ai-engineering-stack-roadmap β Fase 2: Data Pipeline & Vector Infrastructure dimulai dari parsing
- encoding-serialization-compression-deepdive β Encoding charset, base64, charset detection
- linux-fundamentals-deepdive β Filesystem path, file permissions buat pipeline ingestion
- index_vault.py β Implementasi chunking yang nerima output parser
References
- PyMuPDF. https://pymupdf.readthedocs.io/
- pdfplumber. https://github.com/jsvine/pdfplumber
- Tesseract OCR. https://github.com/tesseract-ocr/tesseract
- Unstructured.io. https://docs.unstructured.io/
- LlamaParse. https://docs.llamaindex.ai/en/stable/llama_cloud/llama_parse/
- Trafilatura. https://trafilatura.readthedocs.io/
- python-docx. https://python-docx.readthedocs.io/
- Azure Document Intelligence. https://learn.microsoft.com/en-us/azure/ai-services/document-intelligence/
Bottom Line
Parsing adalah βfirst mileβ RAG β kualitas output menentukan kualitas semua langkah berikutnya. PDF digital dan Markdown relatif mudah; PDF scan dan HTML kompleks butuh tool khusus. Strategi vault: Unstructured.io untuk universal, PyMuPDF untuk PDF digital, LlamaParse untuk yang kompleks. Simpan hasil sebagai Markdown supaya langsung bisa diproses Structure-Aware chunking vault.