Menginstal dan menggunakan MarkItDown Image: AI generated

Cukup dengan pip install markitdown, PDF, dokumen Word, spreadsheet Excel, dan presentasi PowerPoint berubah menjadi markdown. Tapi berikan PDF yang isinya hanya gambar hasil pindaian — misalnya kontrak yang dipindai — dan hasilnya adalah dokumen kosong. Artikel ini berjalan pada dua jalur: mengapa dan bagaimana menggunakan MarkItDown, dan cara menambahkan OCR tepat di titik di mana kepercayaan itu runtuh — PDF yang hanya berisi gambar.


Mengapa Anda Harus Menggunakan MarkItDown — Kondisi Agent-Operable

MarkItDown adalah pustaka CLI/Python open source dari Microsoft yang mengonversi file PDF, Word, Excel, PowerPoint, HTML, gambar, dan audio menjadi markdown.

Mulai dari konsep agent-operable (keadaan yang bisa dikerjakan oleh agen). Agar sebuah agen dapat menangani dokumen secara otonom, dokumen itu harus berada dalam keadaan yang dapat diurai secara struktural oleh mesin — bukan sekadar keadaan yang dianggap manusia mudah dibaca. Ini bukan kondisi yang hanya berlaku pada kode. Aturan bisnis yang terkubur di dalam PDF atau spreadsheet Excel bisa jadi sama saja dengan tidak ada bagi sebuah agen, karena manusia harus membukanya untuk tahu isinya. Ini adalah kondisi pertama dari tiga kondisi — dapat dibaca, dapat diverifikasi, persisten — yang diuraikan dalam Membangun Sistem Agent-Operable: “dapat dibaca tanpa gangguan (noise)”.

Lalu mengapa harus MarkItDown secara spesifik? Anda bisa membangun konversi yang sama sendiri dengan merangkai parser pihak ketiga (PyPDF2, python-docx). Bedanya ada pada siapa yang membuatnya. docx, xlsx, dan pptx semuanya adalah OOXML — spesifikasi yang dimiliki Microsoft sendiri. Ketika perusahaan pemilik spesifikasi itu membangun konverter untuk formatnya sendiri, kasus-kasus tepi (sel gabungan, tabel bersarang, catatan kaki) secara struktural lebih mungkin bertahan dibandingkan dengan parser pihak ketiga. Jika konversi itu sendiri tidak dapat dipercaya, semua yang dibangun di atasnya menuju keadaan agent-operable jadi tidak berarti. Itulah alasan menggunakan MarkItDown — untuk format milik Microsoft sendiri, kepercayaan itu sudah tersedia secara default.

Masalahnya, kepercayaan ini tidak berlanjut ke PDF, terutama PDF yang hanya berisi gambar. Paruh kedua artikel ini berfokus pada menutup celah tersebut dengan OCR.


Instalasi

Instalasi dasar

pip install markitdown

Instalasi dasar saja hanya menangani format ringan seperti teks biasa dan HTML. Untuk mengonversi dokumen PDF dan Office, diperlukan ekstra khusus format.

Ekstra khusus format

pip install 'markitdown[pdf]'    # PDF (pdfminer.six + pdfplumber)
pip install 'markitdown[docx]'   # Word
pip install 'markitdown[pptx]'   # PowerPoint
pip install 'markitdown[xlsx]'   # Excel
pip install 'markitdown[all]'    # everything above, plus audio transcription, YouTube captions, Azure Document Intelligence, etc.

Jika artikel ini hanya memerlukan PDF, markitdown[pdf] sudah cukup.


Penggunaan Dasar

CLI

markitdown example.pdf                  # print markdown to stdout
markitdown example.pdf -o example.md    # save to a file
cat example.pdf | markitdown            # read from stdin (pipe)

Python API

from markitdown import MarkItDown

md = MarkItDown()
result = md.convert("example.pdf")
print(result.markdown)

Kedua cara ini secara otomatis memilih konverter berdasarkan ekstensi file atau tipe MIME. Ketika tidak ada informasi ekstensi — misalnya saat membaca dari stdin — beri petunjuk dengan -x (--extension) atau -m (--mime-type).


Apa yang Sebenarnya Dilakukan Konversi PDF — Hanya Membaca Lapisan Teks

Konverter PDF milik MarkItDown (packages/markitdown/src/markitdown/converters/_pdf_converter.py) pertama-tama menggunakan pdfplumber untuk mendeteksi struktur tabel/formulir di setiap halaman, dan beralih ke page.extract_text() ketika sebuah halaman bukan tabel. Jika pdfplumber gagal, ia beralih ke pdfminer.six.

Kedua pustaka ini adalah alat yang membaca lapisan teks yang sudah ada di dalam PDF. Jika sebuah halaman hanya terdiri dari gambar hasil pindaian tanpa lapisan teks, extract_text() mengembalikan string kosong, dan keluaran MarkItDown pun pada akhirnya kosong. Tidak ada jalur kode di paket dasar yang me-render gambar atau mengenali karakter di dalamnya.

Dengan kata lain, ini adalah dua masalah yang berbeda:

  • PDF dengan lapisan teks (diekspor dari Word, sebagian besar kontrak elektronik) → instalasi dasar bekerja dengan baik. Kepercayaan yang sama yang menopang format milik Microsoft sendiri berlanjut ke sini juga.
  • PDF tanpa lapisan teks (dokumen yang melewati pemindai, foto yang disematkan sebagai gambar) → instalasi dasar mengembalikan hasil kosong. Di sinilah kondisi “dapat dibaca” pada agent-operable terputus.

Menyiapkan OCR — Tempat Kepercayaan yang Rusak Ditambal

Di sinilah paruh kedua artikel ini dimulai. Kepercayaan yang diamankan MarkItDown untuk format milik Microsoft sendiri harus dibangun ulang secara terpisah untuk PDF yang hanya berisi gambar.

1. Instal plugin

Dukungan OCR berada dalam paket terpisah, markitdown-ocr. Paket ini ada di repositori yang sama (microsoft/markitdown), tetapi tidak termasuk dalam pip install markitdown.

pip install markitdown-ocr
pip install openai   # an OpenAI-compatible client — this plugin has no OCR model of its own

Setelah instalasi, periksa apakah plugin terdeteksi.

markitdown --list-plugins
#   * ocr             (package: markitdown_ocr)

2. Yang Tidak Bisa Ditawar — Klien LLM Vision

markitdown-ocr tidak menyertakan mesin OCR tradisional seperti Tesseract atau PaddleOCR. Yang sebenarnya dilakukannya hanyalah meng-encode gambar ke base64 dan meminta API chat.completions yang kompatibel dengan OpenAI (misalnya gpt-4o) untuk “mengekstrak teks dari gambar ini” (LLMVisionOCRService di _ocr_service.py). Karena itu, kunci API yang dapat memanggil model visi adalah keharusan mutlak agar OCR bisa berfungsi sama sekali.

from markitdown import MarkItDown
from openai import OpenAI

md = MarkItDown(
    enable_plugins=True,
    llm_client=OpenAI(),      # reads OPENAI_API_KEY from the environment
    llm_model="gpt-4o",
)

result = md.convert("scanned_contract.pdf")
print(result.markdown)

Klien kompatibel OpenAI apa pun — termasuk Azure OpenAI — dapat diberikan dengan cara yang sama.

from openai import AzureOpenAI

md = MarkItDown(
    enable_plugins=True,
    llm_client=AzureOpenAI(
        api_key="...",
        azure_endpoint="https://<resource>.openai.azure.com/",
        api_version="2024-02-01",
    ),
    llm_model="gpt-4o",
)

3. Tidak Bekerja dari CLI — Diverifikasi Terhadap Kode Sebenarnya

README markitdown-ocr memberikan perintah berikut sebagai contoh penggunaan:

markitdown document.pdf --use-plugins --llm-client openai --llm-model gpt-4o

Tapi memeriksa langsung definisi argumen CLI inti MarkItDown (packages/markitdown/src/markitdown/__main__.py) menunjukkan bahwa flag semacam itu tidak ada — tidak ada --llm-client atau --llm-model. CLI mendukung -o (file keluaran), -x (petunjuk ekstensi), -m (petunjuk MIME), -c (charset), -d/--use-docintel, --use-cu, -p/--use-plugins, --list-plugins, dan --keep-data-uris, dan itu saja — konstruktor MarkItDown hanya menerima enable_plugins=args.use_plugins. Dengan kata lain, contoh CLI di README adalah bug dokumentasi; itu sebenarnya tidak berjalan.

OCR hanya bekerja lewat Python APIllm_client/llm_model harus diberikan secara langsung. Tidak ada cara untuk memberikan kunci API ke CLI.

4. Cara Kerjanya Sebenarnya — OCR Gambar Tersemat dan Fallback OCR Halaman Penuh

PdfConverterWithOCR (_pdf_converter_with_ocr.py) berjalan dalam dua tahap.

  1. Gambar tersemat lebih dulu: ketika sebuah halaman mencampur teks dengan gambar (misalnya tanda tangan hasil pindaian yang diletakkan di tengah teks utama), hanya gambar itu yang dipotong, dikirim ke LLM Vision, dan hasilnya disisipkan kembali dengan teks di sekitarnya berdasarkan posisi Y aslinya, menjaga urutan pembacaan.
  2. Fallback OCR halaman penuh: jika hasil ekstraksi teks kembali kosong sepenuhnya (PDF hasil pindaian penuh), seluruh halaman di-render sebagai PNG 300dpi dan dikirim ke LLM Vision satu halaman pada satu waktu (_ocr_full_pages).

Teks yang diekstrak selalu dibungkus dalam format ini:

*[Image OCR]
<extracted text>
[End OCR]*

5. Menyempurnakan Akurasi dengan Prompt Kustom

Prompt bawaan adalah “ekstrak semua teks dari gambar ini, pertahankan tata letak dan urutan aslinya”. Untuk dokumen yang banyak mengandung tabel, teks vertikal, atau stempel dan tanda tangan, menimpanya dengan llm_prompt dapat meningkatkan akurasi.

md = MarkItDown(
    enable_plugins=True,
    llm_client=OpenAI(),
    llm_model="gpt-4o",
    llm_prompt="Extract all text from this image, but preserve table structure as markdown tables.",
)

6. Memproses Banyak File Sekaligus

Saat menjalankan seluruh folder PDF hasil pindaian sekaligus, setiap file memicu panggilan API-nya sendiri — setiap konversi perlu dibungkus agar satu kegagalan tidak menjatuhkan seluruh batch.

from pathlib import Path
from markitdown import MarkItDown
from openai import OpenAI

md = MarkItDown(enable_plugins=True, llm_client=OpenAI(), llm_model="gpt-4o")

for pdf_path in Path("scans/").glob("*.pdf"):
    try:
        result = md.convert(str(pdf_path))
        pdf_path.with_suffix(".md").write_text(result.markdown, encoding="utf-8")
    except Exception as e:
        print(f"failed: {pdf_path.name}{e}")

7. Bagaimana Jika Anda Menginstal Plugin Tanpa llm_client?

Plugin tetap termuat, tetapi OCR mati secara diam-diam. register_converters() di _plugin.py hanya membangun LLMVisionOCRService ketika llm_client dan llm_model sama-sama ada; jika tidak, ia mendaftarkan konverter dengan ocr_service=None. Dalam keadaan itu, sistem secara otomatis dan diam-diam kembali ke ekstraksi lapisan teks saja — tanpa error, tanpa peringatan. Sebagian besar masalah “saya sudah instal plugin tapi OCR tidak jalan” berakar tepat di titik ini.

8. Bahkan Mencoba Memulihkan PDF yang Rusak

Ketika pdfplumber dan pdfminer sama sekali tidak bisa membuka sebuah PDF — misalnya EOF yang terpotong — markitdown-ocr beralih ke me-render halaman langsung dengan PyMuPDF (fitz) dan mencoba lagi. Jika jalur ini juga gagal, ia meninggalkan *[Error: Could not process scanned PDF]* pada hasilnya.

9. Biaya dan Kecepatan

Karena mengirim seluruh halaman ke model visi, biaya dan latensi menumpuk sebanding dengan jumlah halaman dokumen hasil pindaian. Render 300dpi tidak murah dari segi token per gambar, jadi lebih aman untuk mencuplik beberapa halaman terlebih dahulu guna mengukur kualitas dan biaya sebelum menjalankan seluruh dokumen beratus-ratus halaman.


Memverifikasi Hasil OCR — Menyusul Secara Terpisah

Semua yang di atas adalah tentang cara “menyalakan” OCR. Menyalakannya bukan berarti hasilnya dapat dipercaya — dalam desain saat ini, di mana segala sesuatu lolos secara diam-diam baik llm_client diatur atau tidak, dan baik halamannya kosong atau tidak, tidak ada prosedur deterministik untuk menilai apakah keluaran OCR benar-benar dapat dipercaya.

Prosedur itu tidak dibahas di sini. Cara menerapkan prinsip Symbolic Feedback Loop — LLM menghasilkan → alat deterministik menilai → umpan balik → ulangi — pada keluaran OCR adalah artikel/alat yang terpisah.


Daftar Periksa Praktis

  • Jika Anda hanya berurusan dengan PDF biasa yang memiliki lapisan teks, instalasi dasar markitdown[pdf] sudah cukup. Plugin OCR tidak diperlukan.
  • Jika Anda harus menangani PDF hasil pindaian atau foto, markitdown-ocr ditambah kunci API OpenAI (atau yang kompatibel) wajib ada. Tidak ada integrasi dengan mesin OCR tradisional, lokal, dan gratis seperti Tesseract.
  • Jika hasil OCR kembali kosong, hal pertama yang perlu diperiksa adalah apakah llm_client/llm_model benar-benar diberikan. Ia gagal secara diam-diam, jadi tidak ada yang muncul di log.
  • OCR tidak bisa diaktifkan hanya dari CLI. Diperlukan skrip Python yang memanggil MarkItDown(enable_plugins=True, llm_client=..., llm_model=...).
  • Belum ada cara mekanis untuk menilai seberapa dapat dipercaya hasilnya — untuk saat ini, manusia harus memeriksa sampel secara manual.

Tabel Ringkasan

SituasiYang DiperlukanCatatan
PDF dengan lapisan tekspip install markitdown[pdf]pdfplumber/pdfminer mengekstrak teks
Beberapa gambar tersemat perlu OCRmarkitdown-ocr + klien LLM Visionmemotong gambar saja, disisipkan dengan teks
Hasil pindaian penuh (seluruh halaman adalah gambar)markitdown-ocr + klien LLM Visionme-render seluruh halaman pada 300dpi, lalu OCR
PDF rusaksama seperti di atas (fallback otomatis)mencoba lagi dengan me-render lewat PyMuPDF
llm_client tidak diaturOCR dilewati secara diam-diam, tanpa error
Memberikan --llm-client di CLItidak mungkin (flag tersebut tidak ada)hanya lewat Python API
Menilai keandalan hasil OCR(direncanakan)akan dibahas oleh verifier terpisah

Artikel Terkait


Referensi

Changelog

  • 2026-07-09: Rilis awal — menambahkan kerangka agent-operable, memperluas penyiapan OCR sebagai paruh kedua, menambahkan bagian placeholder untuk verifier