Files
OCR-SPRIN-SERVICE/docs/architecture.md
Devin AI ca0c0a0428 Phase 1 MVP: synchronous OCR + regex header extraction
Implements the foundation of the OCR Sprint service:
- FastAPI app with /api/v1/health and /api/v1/documents (sync upload)
- Pydantic v2 schemas for documents, extraction result, personnel
- Pipeline: PDF/image ingest (PyMuPDF), preprocessing (resize, deskew,
  denoise, optional adaptive threshold), PaddleOCR wrapper, regex-based
  header extraction (nomor sprint, tanggal, satuan, perihal, dasar),
  signatory NRP, master-pangkat validation, confidence scoring + routing.
- Tests: 61 unit tests covering regex rules, validators, preprocess,
  ingest, confidence, and API contract (PaddleOCR mocked).
- Tooling: pyproject (setuptools), ruff, mypy strict, pytest, pre-commit,
  Dockerfile, docker-compose, Makefile.
- Docs: README + docs/architecture.md (full hybrid stack rationale and
  6-phase roadmap).

Co-authored-by: adrian kuman firmansah <adriancuman@gmail.com>
2026-04-25 14:58:50 +00:00

16 KiB
Raw Blame History

Plan & Arsitektur — OCR Service Surat Sprint Kepolisian

1. Penilaian Jujur Tech Stack yang Diusulkan

Tech stack Anda (FastAPI + PaddleOCR + OpenCV/Pillow + Regex) sudah bagus dan layak produksi, tapi belum tentu paling optimal akurasinya untuk kasus surat sprint. Ada beberapa gap yang perlu diisi sebelum bisa disebut "terbaik".

Yang sudah tepat

Komponen Alasan
FastAPI Async native, Pydantic validation, OpenAPI docs otomatis, ideal untuk ML serving.
PaddleOCR (PP-OCRv4/v5) Salah satu OCR open-source terbaik untuk dokumen campuran teks + tabel, mendukung Latin (cocok untuk Bahasa Indonesia), bisa jalan on-premise (penting untuk dokumen kepolisian yang sensitif — cloud OCR seperti Google Vision/AWS Textract sebaiknya dihindari karena masalah kerahasiaan).
OpenCV + Pillow Standar industri untuk preprocessing.
Regex/rule-based Cocok untuk dokumen terstruktur seperti sprint yang format-nya relatif baku.

Yang masih kurang / perlu ditambah

  1. Table extraction belum tertangani Daftar personel di surat sprint hampir selalu berbentuk tabel (No, Pangkat, NRP, Nama, Jabatan, Keterangan). Regex pada teks linear dari OCR biasa akan kacau ketika baris tabel pecah atau kolom bergeser. Solusi: gunakan PaddleOCR PP-Structure (modul table recognition bawaan Paddle) atau model khusus seperti TableTransformer (Microsoft).

  2. Document detection & dewarping untuk foto HP belum eksplisit Foto HP bermasalah karena: perspektif miring, lipatan, bayangan, lighting tidak rata, fokus tidak merata. OpenCV crop + perspective transform manual saja sering gagal. Tambahkan:

    • Document corner detection: DocTR / MobileSAM / model edge-based, atau heuristik kontur OpenCV sebagai fallback.
    • Dewarping: DocTr / DewarpNet untuk halaman yang melengkung (lipatan).
    • Shadow removal: algoritma background division atau model spesialis.
  3. Strategi ekstraksi 100% regex itu rapuh Surat sprint dari satuan berbeda (Polda, Polres, Polsek, Mabes) punya variasi format: header berbeda, urutan field berbeda, kadang pangkat disingkat (AKP, IPDA) kadang ditulis penuh. Regex murni akan butuh ratusan rule dan tetap miss kasus baru. Rekomendasi pendekatan hybrid:

    • Layer 1 — Regex/rule untuk field deterministik (Nomor sprint, tanggal, dasar hukum) yang format-nya baku.
    • Layer 2 — Schema-aware extraction menggunakan LLM lokal (Llama 3.1 8B / Qwen2.5 7B via Ollama atau vLLM) dengan structured output (JSON schema / Pydantic) untuk field yang variatif (jabatan, keterangan tugas).
    • Layer 3 — Validation terhadap master data (daftar pangkat valid, format NRP 8 digit, dll).
  4. Tidak ada confidence scoring & human-in-the-loop Untuk dokumen kepolisian, akurasi 100% otomatis itu mitos. Sistem harus:

    • Mengeluarkan confidence score per field.
    • Otomatis flag dokumen low-confidence untuk review manusia.
    • Sediakan UI/endpoint koreksi yang feedback-nya bisa dipakai retraining.
  5. Alternatif end-to-end yang patut dipertimbangkan Jika nanti volume dokumen besar dan format relatif stabil, fine-tuning model Document Understanding end-to-end bisa lebih akurat:

    • Donut (OCR-free, langsung image → JSON).
    • LayoutLMv3 (kombinasi teks + layout + visual).
    • Surya OCR (newer, sangat bagus untuk dokumen). Untuk MVP, tetap pakai PaddleOCR. Donut/LayoutLM adalah opsi V2 setelah ada labeled dataset cukup (~5001000 dokumen).

Verdict

Stack Anda bisa mencapai ~8592% akurasi field-level untuk surat sprint dengan kualitas scan baik, dan ~7080% untuk foto HP, kalau ditambah komponen di atas. Tanpa table extraction + dewarping + hybrid extraction, akurasinya akan jatuh di kondisi nyata.


2. Arsitektur yang Direkomendasikan

2.1 Diagram Logis

┌────────────────────────────────────────────────────────────────────┐
│                         Client (Web/Mobile)                        │
└──────────────────────────────┬─────────────────────────────────────┘
                               │ HTTPS (multipart upload)
                               ▼
┌────────────────────────────────────────────────────────────────────┐
│                    FastAPI Gateway (stateless)                     │
│   - Auth (JWT/API key)   - Rate limit   - Request validation       │
└──────────────────────────────┬─────────────────────────────────────┘
                               │ enqueue job
                               ▼
┌────────────────────────────────────────────────────────────────────┐
│              Job Queue (Redis + Celery / RQ / Dramatiq)            │
└──────────────────────────────┬─────────────────────────────────────┘
                               ▼
┌────────────────────────────────────────────────────────────────────┐
│                    OCR Worker Pipeline (GPU/CPU)                   │
│  ┌────────────┐  ┌──────────────┐  ┌───────────┐  ┌────────────┐   │
│  │ 1. Ingest  │→ │ 2. Preproc   │→ │ 3. OCR +  │→ │ 4. Extract │   │
│  │  & detect  │  │ (deskew,     │  │  Layout   │  │ (regex +   │   │
│  │  PDF/IMG   │  │  dewarp,     │  │  PP-Struct│  │  LLM +     │   │
│  │            │  │  denoise)    │  │  + Table) │  │  validate) │   │
│  └────────────┘  └──────────────┘  └───────────┘  └─────┬──────┘   │
│                                                         │          │
│                          ┌──────────────────────────────┘          │
│                          ▼                                         │
│                   ┌─────────────┐                                  │
│                   │ 5. Confidence│ → low conf? flag for review    │
│                   │   scoring    │                                 │
│                   └──────┬───────┘                                 │
└──────────────────────────┼─────────────────────────────────────────┘
                           ▼
┌────────────────────────────────────────────────────────────────────┐
│           Storage: PostgreSQL (metadata) + MinIO/S3 (file)         │
│           + Vector store opsional (untuk dedup / search)           │
└────────────────────────────────────────────────────────────────────┘
                           │
                           ▼
┌────────────────────────────────────────────────────────────────────┐
│           Review UI (optional) — koreksi manual + audit trail      │
└────────────────────────────────────────────────────────────────────┘

2.2 Pipeline Detail per Tahap

Tahap 1 — Ingest & Document Detection

  • PDF: render setiap halaman jadi image @ 300 DPI (pdf2image / PyMuPDF).
  • Image (foto HP): deteksi sudut dokumen → crop → perspective transform.
    • Library: OpenCV findContours (cepat) sebagai fallback, DocTR document detector (lebih akurat) sebagai utama.

Tahap 2 — Preprocessing

  • Deskew (rotation correction) — Hough transform atau model.
  • Dewarp (untuk foto buku/lipatan) — DewarpNet atau model RNN.
  • Adaptive thresholding (untuk foto dengan lighting tidak rata).
  • Shadow removal (background division).
  • Denoise (Non-Local Means).
  • Resize ke ukuran optimal OCR (~15002500 px sisi panjang).

Tahap 3 — OCR + Layout Analysis

  • PaddleOCR PP-Structure dijalankan sekali → menghasilkan:
    • Bounding boxes + teks + confidence per word/line.
    • Table region detection + table-to-HTML/JSON.
    • Layout type per region (title, paragraph, table, figure).
  • Output ditampung sebagai struktur intermediate (mirip hOCR / ALTO XML).

Tahap 4 — Information Extraction

  • 4a. Header parsing (regex): Nomor sprint, tanggal, satuan penerbit, dasar hukum, perihal. Format relatif baku → regex sangat cocok.
  • 4b. Personnel table extraction: ambil dari hasil PP-Structure table → mapping kolom (Pangkat, NRP, Nama, Jabatan, Keterangan).
  • 4c. LLM fallback: untuk field yang regex/table miss, kirim chunk teks + JSON schema ke LLM lokal (Ollama / vLLM) dengan structured output (Pydantic via outlines / instructor).
  • 4d. Validation layer:
    • NRP: 8 digit numerik.
    • Pangkat: harus ada di daftar master pangkat Polri.
    • Tanggal: parse + sanity check.
    • Cross-check: jumlah personel di body = jumlah baris tabel.

Tahap 5 — Confidence Scoring & Routing

  • Aggregate confidence: weighted average dari OCR confidence + validation pass/fail + LLM logprob (kalau pakai).
  • Threshold (mis. < 0.85) → status NEEDS_REVIEW.
  • Threshold tinggi (≥ 0.95) + semua validasi pass → status AUTO_APPROVED.

2.3 API Endpoint (FastAPI)

POST   /api/v1/documents              # upload, kembalikan job_id
GET    /api/v1/documents/{job_id}     # poll status + hasil
GET    /api/v1/documents/{job_id}/raw # raw OCR output (debug)
PATCH  /api/v1/documents/{job_id}     # koreksi manual (HITL)
GET    /api/v1/health                 # liveness
GET    /api/v1/metrics                # Prometheus

Response shape (contoh):

{
  "job_id": "uuid",
  "status": "completed | processing | needs_review | failed",
  "confidence": 0.92,
  "data": {
    "nomor_sprint": "Sprin/123/IV/2025",
    "tanggal": "2025-04-21",
    "satuan_penerbit": "Polres Bandung",
    "dasar": ["...", "..."],
    "perihal": "...",
    "personel": [
      {"no": 1, "pangkat": "AKP", "nrp": "12345678", "nama": "...", "jabatan": "Kasat Reskrim", "confidence": 0.97},
      ...
    ],
    "ttd": {"pejabat": "...", "pangkat": "...", "nrp": "..."}
  },
  "review_flags": []
}

2.4 Tech Stack Final yang Direkomendasikan

Layer Pilihan Catatan
API FastAPI + Uvicorn/Gunicorn sesuai usulan
Validation Pydantic v2 wajib
Queue Redis + Celery atau Dramatiq OCR berat, jangan blocking request
OCR PaddleOCR PP-OCRv4 + PP-Structure tambah PP-Structure untuk tabel
Preprocessing OpenCV + Pillow + DocTR (detection) DocTR untuk foto HP
Extraction Regex + Ollama (Llama 3.1 8B / Qwen2.5 7B) + instructor/outlines hybrid
Storage PostgreSQL (metadata) + MinIO (file blob) self-hosted, sesuai compliance
Observability Prometheus + Grafana + Loki wajib produksi
Container Docker + docker-compose (dev) → Kubernetes (prod)
GPU NVIDIA T4/A10 (1× cukup untuk MVP) PaddleOCR jauh lebih cepat di GPU

3. Roadmap Pengembangan (Bertahap)

Fase 0 — Persiapan (1 minggu)

  • Kumpulkan dataset sampel: minimal 50 surat sprint (campur PDF scan + foto HP) dari beragam satuan.
  • Buat ground truth labelling untuk 20 dokumen (untuk evaluasi).
  • Definisikan schema output final (JSON) bersama stakeholder.

Fase 1 — MVP Pipeline Sinkron (2 minggu)

  • Setup FastAPI skeleton + Pydantic schemas.
  • Integrasi PaddleOCR PP-OCRv4 (CPU dulu, GPU menyusul).
  • Preprocessing dasar: deskew + denoise + resize.
  • Regex extraction untuk field header.
  • Endpoint sinkron POST /documents (untuk dev/testing saja).
  • Evaluasi akurasi terhadap 20 ground truth.

Fase 2 — Robustness untuk Foto HP (2 minggu)

  • Integrasi document detection (DocTR atau OpenCV contour).
  • Perspective transform + dewarping.
  • Shadow removal.
  • Re-evaluasi akurasi pada subset foto HP.

Fase 3 — Table Extraction (1.5 minggu)

  • Integrasi PP-Structure untuk personnel table.
  • Mapping kolom + validation (NRP, pangkat).
  • Master data tabel pangkat Polri.

Fase 4 — Async + Production Ready (1.5 minggu)

  • Pindahkan ke arsitektur async dengan Celery + Redis.
  • Storage MinIO + PostgreSQL.
  • Auth, rate limit, logging, metrics.
  • Docker compose untuk deployment.

Fase 5 — LLM Hybrid Extraction (2 minggu)

  • Setup Ollama / vLLM dengan model lokal.
  • Structured output via instructor.
  • Confidence scoring + routing ke review.

Fase 6 — HITL Review UI (opsional, 2 minggu)

  • Endpoint koreksi.
  • Simple web UI (Next.js) untuk reviewer.
  • Audit trail & feedback loop.

Fase 7 — Optimasi Lanjutan (ongoing)

  • Fine-tune PaddleOCR detection/recognition pada dataset internal.
  • Eksplorasi Donut/LayoutLMv3 jika dataset sudah cukup.
  • Batch processing & GPU optimization.

Total estimasi MVP fungsional (Fase 14): ~7 minggu dengan 1 backend engineer + 1 ML engineer.


4. Risiko & Mitigasi

Risiko Mitigasi
Data sensitif (kepolisian) bocor Wajib on-prem; tidak ada cloud OCR; enkripsi at-rest (LUKS/pgcrypto) + in-transit (mTLS); audit log lengkap.
Variasi format antar satuan Hybrid extraction (regex + LLM); kumpulkan sample dari banyak satuan sejak awal.
Foto HP kualitas buruk Validasi kualitas image di client (resolusi minimal, blur detection) sebelum upload.
Akurasi tidak sampai target HITL review wajib untuk dokumen low-confidence; jangan deploy fully-automatic.
Tanggung jawab hukum atas hasil OCR Selalu simpan original document + flag bahwa hasil ekstraksi adalah "draft, perlu verifikasi manusia".

5. Pertanyaan Sebelum Implementasi

Sebelum saya lanjut ke implementasi, mohon konfirmasi:

  1. Volume: berapa dokumen/hari yang ditargetkan? (mempengaruhi pilihan async vs sync, GPU vs CPU)
  2. Deployment target: on-prem mutlak, atau private cloud (GovCloud) boleh?
  3. Source dokumen: apakah ada akses ke 2050 sample surat sprint untuk dijadikan dataset awal?
  4. Integrasi: service ini akan dipanggil sistem apa? (mempengaruhi auth & API contract)
  5. HITL: apakah ada SDM untuk review manual dokumen low-confidence?
  6. Hardware: sudah ada server GPU, atau perlu sizing rekomendasi?
  7. Format output final: ada schema yang sudah dipakai sistem downstream?