Halo Sobat Kampus dan pencinta tech! Buat kalian yang sering banget dapet tugas bikin laporan numpuk, makalah tebal, atau bahan skripsi dari dokumen PDF scan yang susah banget di-copy teksnya, pasti paham betapa melelahkannya proses transkripsi manual. Tenang, sekarang ada solusi canggih dari Baidu yang bakal bikin hidup kalian jauh lebih gampang, yaitu Baidu Unlimited-OCR.

Model AI vision-language berparameter 3B ini dirancang khusus buat ngebaca seluruh halaman dokumen—mulai dari judul, paragraf, sampai tabel rumit—dalam satu kali proses decoding saja. Kerennya lagi, kita nggak butuh tahap analisis layout terpisah seperti pipeline OCR klasik yang ribet. Artikel ini bakal ngajak kalian tuntas ngebangun workflow OCR end-to-end langsung di Google Colab menggunakan Python.

Persiapan Lingkungan dan Instalasi Dependensi

Sebelum mulai ngoprek kodenya, pastikan Google Colab kalian udah dapet jatah GPU aktif. Kita butuh GPU buat nanganin model berukuran besar ini dengan lancar. Pertama-tama, kita instal dulu library yang dibutuhkan seperti transformers, Pillow, pymupdf, dan accelerate.

import subprocess, sys
def pip_install(*pkgs):
   subprocess.check_call([sys.executable, "-m", "pip", "install", "-q", *pkgs])
print(">> Installing dependencies (1-2 min)...")
pip_install(
   "transformers==4.57.1",
   "Pillow",
   "matplotlib",
   "einops",
   "addict",
   "easydict",
   "pymupdf",
   "psutil",
   "accelerate",
)
print(">> Done.")

Setelah dependensi terpasang, kita cek ketersediaan CUDA GPU dan otomatis ngeset tipe data presisi ke bfloat16 atau float16 tergantung hardware kalian. Tokenizer dan model baidu/Unlimited-OCR dari Hugging Face bakal di-load dan dipindahin langsung ke GPU.

import os
import torch
from transformers import AutoModel, AutoTokenizer
assert torch.cuda.is_available(), (
   "No GPU detected! In Colab: Runtime -> Change runtime type -> GPU."
)
gpu_name = torch.cuda.get_device_name(0)
print(f">> GPU: {gpu_name}")
use_bf16 = torch.cuda.is_bf16_supported()
DTYPE = torch.bfloat16 if use_bf16 else torch.float16
print(f">> Using dtype: {DTYPE}")
MODEL_NAME = "baidu/Unlimited-OCR"
print(">> Downloading model (~6 GB for 3B params in BF16). First run takes a while...")
tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME, trust_remote_code=True)
model = AutoModel.from_pretrained(
   MODEL_NAME,
   trust_remote_code=True,
   use_safetensors=True,
   torch_dtype=DTYPE,
)
model = model.eval().cuda()
print(">> Model loaded and moved to GPU.")

Membuat Sampel Dokumen Uji Coba

Biar pengujian makin seru, kita bikin beberapa halaman dokumen sampel pakai library PIL. Dokumen ini bakal punya elemen lengkap kayak judul, paragraf teks panjang, tabel data regional, dan catatan kaki untuk ngetes kemampuan parsing layout-nya.

from PIL import Image, ImageDraw, ImageFont
import textwrap
os.makedirs("inputs", exist_ok=True)
os.makedirs("outputs/single_gundam", exist_ok=True)
os.makedirs("outputs/single_base", exist_ok=True)
os.makedirs("outputs/multi_page", exist_ok=True)
def load_font(size):
   for path in [
       "/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf",
       "/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf",
   ]:
       if os.path.exists(path):
           return ImageFont.truetype(path, size)
   return ImageFont.load_default()
def make_sample_page(path, page_no):
   W, H = 1240, 1754
   img = Image.new("RGB", (W, H), "white")
   d = ImageDraw.Draw(img)
   title_f, head_f, body_f = load_font(48), load_font(34), load_font(26)
   d.text((80, 70), f"Quarterly Operations Report — Page {page_no}",
          fill="black", font=title_f)
   d.line([(80, 145), (W - 80, 145)], fill="black", width=3)
   body = (
       "This document demonstrates Unlimited-OCR's one-shot long-horizon "
       "parsing. The model reads an entire page — headings, paragraphs, "
       "and tables — and emits structured text in a single decoding pass. "
       "Unlike classic OCR pipelines, no separate layout-analysis stage "
       "is required."
   )
   y = 190
   for line in textwrap.wrap(body, width=72):
       d.text((80, y), line, fill="black", font=body_f)
       y += 40
   y += 30
   d.text((80, y), f"Table {page_no}: Regional Revenue (USD, millions)",
          fill="black", font=head_f)
   y += 60
   rows = [
       ["Region",  "Q1",   "Q2",   "Q3"],
       ["North",   "12.4", "13.1", "15.0"],
       ["South",   "9.8",  "10.2", "11.7"],
       ["East",    "14.3", "13.9", "16.2"],
       ["West",    "11.1", "12.5", "12.9"],
   ]
   col_w, row_h, x0 = 260, 56, 80
   for r, row in enumerate(rows):
       for c, cell in enumerate(row):
           x = x0 + c * col_w
           d.rectangle([x, y, x + col_w, y + row_h], outline="black", width=2)
           d.text((x + 14, y + 12), cell, fill="black", font=body_f)
       y += row_h
   y += 50
   footer = (
       f"Note {page_no}: Figures are illustrative. Multi-page mode stitches "
       "context across pages, so cross-page references remain coherent."
   )
   for line in textwrap.wrap(footer, width=72):
       d.text((80, y), line, fill="black", font=body_f)
       y += 40
   img.save(path)
   return path
IMAGE_PATH = make_sample_page("inputs/sample_page_1.png", 1)
PAGE_2     = make_sample_page("inputs/sample_page_2.png", 2)
PAGE_3     = make_sample_page("inputs/sample_page_3.png", 3)
print(f">> Sample pages written: {IMAGE_PATH}, {PAGE_2}, {PAGE_3}")

Menjalankan Mode Gundam dan Mode Base untuk Gambar Tunggal

Model ini menyediakan dua mode inferensi utama untuk dokumen halaman tunggal:

  • Mode Gundam (Tiled & High Detail): Menggabungkan pandangan dokumen global dengan potongan tile kecil untuk menjaga detail teks kecil dan layout padat.
  • Mode Base (Single View & Faster): Menggunakan satu pandangan gambar utuh beresolusi 1024 piksel untuk dokumen yang bersih dan cepat diproses.

Berikut kode untuk menjalankan Mode Gundam:

print("\n" + "=" * 76)
print("STEP 4: Single image — GUNDAM mode (tiled, high detail)")
print("=" * 76)
model.infer(
   tokenizer,
   prompt="<image>document parsing.",
   image_file=IMAGE_PATH,
   output_path="outputs/single_gundam",
   base_size=1024,
   image_size=640,
   crop_mode=True,
   max_length=32768,
   no_repeat_ngram_size=35,
   ngram_window=128,
   save_results=True,
)

Sedangkan ini kode untuk menjalankan Mode Base:

print("\n" + "=" * 76)
print("STEP 5: Single image — BASE mode (single view, faster)")
print("=" * 76)
model.infer(
   tokenizer,
   prompt="<image>document parsing.",
   image_file=IMAGE_PATH,
   output_path="outputs/single_base",
   base_size=1024,
   image_size=1024,
   crop_mode=False,
   max_length=32768,
   no_repeat_ngram_size=35,
   ngram_window=128,
   save_results=True,
)

Parsing Dokumen Multi-Halaman dan File PDF

Kalau tugas kuliah kalian berupa file PDF berhalaman-halaman, kita bisa manfaatin PyMuPDF untuk merubah halaman PDF menjadi gambar PNG beresolusi tinggi, lalu mengeksekusinya menggunakan fungsi infer_multi().

print("\n" + "=" * 76)
print("STEP 6: Multi-page / PDF parsing")
print("=" * 76)
import tempfile
import fitz
def pdf_to_images(pdf_path, dpi=300):
   doc = fitz.open(pdf_path)
   tmp_dir = tempfile.mkdtemp(prefix="pdf_ocr_")
   mat = fitz.Matrix(dpi / 72, dpi / 72)
   paths = []
   for i, page in enumerate(doc):
       out = os.path.join(tmp_dir, f"page_{i + 1:04d}.png")
       page.get_pixmap(matrix=mat).save(out)
       paths.append(out)
   doc.close()
   return paths
SAMPLE_PDF = "inputs/sample_doc.pdf"
pdf = fitz.open()
for p in [IMAGE_PATH, PAGE_2, PAGE_3]:
   img_doc = fitz.open(p)
   rect = img_doc[0].rect
   pdf_bytes = img_doc.convert_to_pdf()
   img_pdf = fitz.open("pdf", pdf_bytes)
   page = pdf.new_page(width=rect.width, height=rect.height)
   page.show_pdf_page(rect, img_pdf, 0)
pdf.save(SAMPLE_PDF)
pdf.close()
print(f">> Built sample PDF: {SAMPLE_PDF}")
page_images = pdf_to_images(SAMPLE_PDF, dpi=300)
print(f">> Rasterized {len(page_images)} pages")
model.infer_multi(
   tokenizer,
   prompt="<image>Multi page parsing.",
   image_files=page_images,
   output_path="outputs/multi_page",
   image_size=1024,
   max_length=32768,
   no_repeat_ngram_size=35,
   ngram_window=1024,
   save_results=True,
)

Memeriksa Hasil Output

Langkah terakhir adalah mengecek direktori output untuk melihat hasil file teks, Markdown, MMD, dan JSON yang telah digenerate secara otomatis oleh model.

print("\n" + "=" * 76)
print("STEP 7: Saved outputs")
print("=" * 76)
TEXT_EXTS = {".txt", ".md", ".mmd", ".json"}
def show_outputs(root):
   print(f"\n--- {root} ---")
   if not os.path.isdir(root):
       print("  (no output directory found)")
       return
   for dirpath, _, files in os.walk(root):
       for fn in sorted(files):
           fp = os.path.join(dirpath, fn)
           size = os.path.getsize(fp)
           print(f"  {fp}  ({size:,} bytes)")
for out_dir in ["outputs/single_gundam", "outputs/single_base", "outputs/multi_page"]:
   show_outputs(out_dir)

Kesimpulan: Worth It Gak Buat Mahasiswa?

Buat kalian mahasiswa tingkat akhir yang bergulat dengan riset, jurnal, dan dokumen arsip tebal, pipeline Unlimited-OCR ini sangat worth it dicoba gratis lewat Google Colab. Kalian nggak perlu keluar biaya langganan software mahal dan bisa memproses layout rumit beserta tabel secara akurat tanpa pusing.

Yuk, siapkan skrip Colab kalian sekarang, explore berbagai model AI keren lainnya, dan buat urusan nugas jadi jauh lebih sat-set anti ribet!