15 KiB
Dokumentasi Detail Alur Kerja PFM OCR (Prima Fresh Mart)
Dokumen ini memuat penjelasan lengkap mengenai alur kerja (workflow) pengolahan gambar dokumen Delivery Order (DO) hingga data tersimpan di database dan divisualisasikan pada dashboard web.
Ringkasan Alur Kerja
Berikut adalah flowchart lengkap yang menggambarkan aliran data dan pemrosesan dari aplikasi mobile, gateway API, pipeline OCR, hingga penyimpanan database:
graph TD
%% Sisi Client (Flutter)
subgraph Client [1. Client-Side: Flutter App]
Start([Mulai: Supir Scan DO]) --> Capture[Ambil Foto via Camera API]
Capture --> GPS[Dapatkan Koordinat via Geolocator]
GPS --> BlurCheck{Cek Kualitas via BlurDetector}
BlurCheck -- Blur/Jelek --> Capture
BlurCheck -- Tajam/Baik --> Upload[Kirim Form Data via Dio HTTP Client]
end
%% Web Gateway (Nginx & Next.js)
subgraph Gateway [2. Gateway & API: Next.js & Nginx]
Upload --> Proxy[Nginx Proxy: Terima Request di Port 8000]
Proxy --> UploadAPI[Next.js Upload API: Simpan Gambar ke /uploads]
UploadAPI --> SQLInit[pg Driver: Simpan Dokumen ke DB - parsed=false]
SQLInit --> TriggerParse[Panggil API /api/parse & Kirim Base64]
end
%% Pipeline OCR (FastAPI)
subgraph OCR [3. Layout Parsing & OCR Pipeline: FastAPI]
TriggerParse --> OriCheck[Deteksi Orientasi via PP-LCNet]
OriCheck --> TiltCalc[Hitung Sudut Kemiringan via block_polygon_points]
TiltCalc --> TiltCheck{Kemiringan > 1.0 deg?}
TiltCheck -- Ya --> Unwarp[Lakukan Unwarping via UVDoc]
Unwarp --> ReRun[Proses Ulang Gambar Lurus]
TiltCheck -- Tidak/Sudah Lurus --> LayoutDet[Segmentasi Tata Letak via PP-DocLayoutV3]
ReRun --> LayoutDet
LayoutDet --> TextRec[Deteksi & Pengenalan Teks via PP-OCRv6_medium]
TextRec --> MarkdownGen[Susun Output Menjadi Teks Markdown]
end
%% VLM Server
subgraph VLM [4. Vision-Language Server: vLLM]
MarkdownGen --> QueryVLM[Query VLM Lokal via Port 8118]
QueryVLM --> ModelVLM[Proses Model PaddleOCR-VL-1.6-0.9B]
ModelVLM --> ResVLM[Kembalikan Hasil Teks Terstruktur]
end
%% Next.js Data Processing
subgraph Processing [5. Pengolahan Data & Validasi: Next.js]
ResVLM --> RegEx[Ekstraksi Regex PO/SO/DO via parseDOMetadata]
RegEx --> StoreMatch[Pencocokan Toko via resolveStoreFromText ke DB]
StoreMatch --> Sanitize[Sanitasi & Standardisasi Data via sanitizeParsedMetadata]
Sanitize --> SQLSave[Update Dokumen & ocr_items ke DB - parsed=true]
end
%% Polling & Selesai
subgraph Polling [6. Sinkronisasi Akhir: Flutter App]
SQLSave --> PollRequest[Dio Polling GET /documents tiap 2s]
PollRequest --> PollCheck{Status parsed = true?}
PollCheck -- Belum --> PollRequest
PollCheck -- Ya --> StateUpdate[Riverpod: Perbarui State UI & Tampilkan Data]
StateUpdate --> PrintPDF[Cetak Label PDF via pdf & printing lib]
PrintPDF --> End([Selesai])
end
Tech Stack (Teknologi yang Digunakan)
Sistem ini dibangun menggunakan arsitektur modern yang membagi tugas antara aplikasi mobile client, API gateway, database, dan engine AI/OCR khusus:
1. Client-Side (Aplikasi Mobile)
- Framework: Flutter (Dart SDK
>=3.2.0) - State Management & DI: Riverpod (
flutter_riverpod) - Routing: GoRouter (
go_router) - HTTP Client: Dio (
dio) - Local Storage / Cache: Hive (
hive,hive_flutter) & SharedPreferences - Sensors & Utilities: Camera API (
camera), Exif Data (exif), Location Service (geolocator), dan Blur Detection (sensors_plus) - PDF & Printing: PDF Generator & Printing (
pdf,printing)
2. Backend Gateway & Dashboard Web Admin
- Framework: Next.js 16 (React 19 & TypeScript)
- Styling (CSS): TailwindCSS v4
- Database Driver: Node-postgres (
pg) - Deployment/Runtime: Node.js & Docker
3. Database
- Engine: PostgreSQL 15 (di-deploy via Docker)
4. Mesin AI & Pipeline OCR (Python & Docker)
- Framework OCR: PaddleX / PaddleOCR (menggunakan GPU CUDA 12.6 devel base image)
- Model Deteksi Tata Letak:
PP-DocLayoutV3(untuk segmentasi blok teks/tabel) - Model Koreksi Kemiringan:
PP-LCNet_x1_0_doc_ori&UVDoc(untuk auto-deskew & unwarping) - Vision-Language Model (VLM):
PaddleOCR-VL-1.6-0.9B(VLM 0.9B lokal) - VLM Inference Engine:
vllmserver (berfungsi sebagai back-end inference manager untuk akselerasi GPU) - Python Web Framework: FastAPI & Uvicorn (untuk expose
/layout-parsingAPI endpoint)
5. Web Proxy / Server Gateway
- Engine: Nginx (Alpine) sebagai reverse proxy untuk routing port internal kontainer Next.js, FastAPI (Pipeline-API), dan vLLM.
Interaksi Alur Kerja & Tech Stack
Di bawah ini adalah pemetaan langkah per langkah bagaimana komponen-komponen tech stack di atas berinteraksi secara real-time:
sequenceDiagram
autonumber
actor User as Pengguna
participant Mobile as Flutter App (Dio & Riverpod)
participant Nginx as Nginx Reverse Proxy
participant Gateway as Next.js Gateway (TypeScript & pg)
participant DB as PostgreSQL 15
participant Pipeline as FastAPI OCR (PaddleX & Python)
participant VLM as vLLM Server (PaddleOCR-VL-1.6)
User->>Mobile: Ambil foto DO
Note over Mobile: Kamera & GPS diakses via camera & geolocator.<br/>Pemeriksaan blur via BlurDetector.
Mobile->>Nginx: POST /api/v1/documents/upload (Base64/Form Data via Dio)
Nginx->>Gateway: Forward ke Next.js (port 3000)
Gateway->>DB: Simpan data awal dokumen (pg driver)
Gateway->>Pipeline: POST /layout-parsing (Base64)
Note over Pipeline: 1. Koreksi kemiringan (PP-LCNet & UVDoc)<br/>2. Deteksi layout tabel & teks (PP-DocLayoutV3)<br/>3. Ekstraksi teks (PP-OCRv6)<br/>4. Hasil akhir diubah ke Markdown.
Pipeline->>VLM: Query VLM lokal (port 8118 via vLLM)
VLM-->>Pipeline: Respons teks terstruktur dari model VL-1.6-0.9B
Pipeline-->>Gateway: Kembalikan Markdown lengkap & koordinat polygon
Note over Gateway: 1. parseDOMetadata() mengurai PO, SO, DO via Regex.<br/>2. resolveStoreFromText() mencocokkan toko ke DB.<br/>3. sanitizeParsedMetadata() menstandardisasi tanggal & plat.
Gateway->>DB: INSERT/UPDATE metadata & ocr_items (parsed = true)
loop Polling (tiap 2 detik)
Mobile->>Gateway: GET /documents (Status check via Dio)
Gateway-->>Mobile: Kirim data final (di-render via Riverpod)
end
User->>Mobile: Cetak Label
Note over Mobile: Generate & cetak dokumen PDF via pdf & printing lib.
Penjelasan Alur Data & Teknologi:
- Pengambilan Gambar (Flutter Client): Pengguna mengambil foto Delivery Order (DO). Aplikasi Flutter mengakses kamera via Camera API dan mengambil GPS via Geolocator. Setelah lolos uji kualitas blur via
BlurDetector, data dikirim menggunakan Dio HTTP Client via requestPOSTMultipart Form ke Nginx pada port8000(eksternal) ke endpoint/api/v1/documents/upload(untuk supir/mobile) atau/api/upload(untuk dashboard web admin). - Reverse Proxy (Nginx): Kontainer
paddleocr-nginxmendengarkan di port80(internal) /8000(eksternal). Nginx merutekan request dari client eksternal secara internal di dalam Docker network:- Request ke
/api/*diteruskan ke kontainerpaddleocr-pfm-web-apppada port3000. - Request langsung ke
/layout-parsingditeruskan ke kontainerpaddleocr-pipeline-api-v10pada port8090. - Request langsung ke
/v1diteruskan ke kontainerpaddleocr-vllm-serverpada port8118.
- Request ke
- Penyimpanan Dokumen Awal (Next.js Gateway): Kontainer
paddleocr-pfm-web-appmenerima request upload di port3000, menulis gambar fisik ke folder/uploads, dan menyimpannya ke databasepaddleocr-dbpada port5432dengan queryINSERT(statusparsed = false) menggunakan driver pg (node-postgres). Setelah itu, Next.js mengirimkan data Base64 via requestPOSTsecara internal ke kontainerpaddleocr-pipeline-api-v10pada port8090ke endpoint/layout-parsing. - Layout-Parsing (FastAPI OCR Pipeline): Kontainer
paddleocr-pipeline-api-v10menerima request di port8090pada endpoint/layout-parsing. Menjalankan kode Python dengan model-model:- Klasifikasi orientasi & unwarping kemiringan via PP-LCNet_x1_0_doc_ori & UVDoc.
- Deteksi tata letak via PP-DocLayoutV3.
- Pengenalan teks via PP-OCRv6_medium dengan akselerasi GPU CUDA 12.6.
- Hasil parsing ditransformasi menjadi teks Markdown mentah.
- Pemahaman Konten Dokumen (vLLM Server): FastAPI (
pipeline-api) meneruskan request secara internal ke kontainerpaddleocr-vllm-serverdi port8118pada endpoint/v1/chat/completionsdengan menggunakan Vision-Language ModelPaddleOCR-VL-1.6-0.9Buntuk menganalisis teks secara kontekstual. - Ekstraksi Metadata & Fuzzy Matching (Next.js): Next.js menerima respons balik, mengekstrak data PO, SO, DO via Regex (
parseDOMetadata), mencocokkan toko penerima ke database PostgreSQL port5432(resolveStoreFromText), menstandardisasi format data (sanitizeParsedMetadata), lalu memperbarui status dokumen di PostgreSQL menjadiparsed = truedan menyimpan item barang ke tabelocr_items. - Sinkronisasi (Flutter Polling): Aplikasi Flutter mengirim request
GETsecara berkala setiap 2 detik menggunakan Dio ke port8000(eksternal) ke endpoint/api/documents(atau/api/documents/[id]) untuk memantau status parsing. Begitu status berubah menjaditrue, Riverpod memperbarui UI secara real-time pada perangkat supir. Pengguna juga dapat mengekspor data ke format PDF menggunakan pustaka pdf & printing Flutter.
Detail Langkah Per Langkah
Langkah 1: Client-Side (Flutter App)
- Layar Konfirmasi: Setelah memotret dokumen, pengguna diarahkan ke image_preview_screen.dart. Di layar ini, sistem mendeteksi apakah gambar blur menggunakan kelas
BlurDetector. - Unggah Dokumen: Pengguna menekan tombol "Unggah Dokumen". Ini memicu aksi pada
PendingDocumentsNotifierdi pending_documents_provider.dart:- Status dokumen diatur ke
PendingDocumentStatus.uploading. - Koordinat GPS (latitude & longitude) diambil menggunakan
LocationService. - Gambar dikirim menggunakan form data ke backend (endpoint
/documents/upload). - Halaman otomatis beralih ke daftar dokumen (
/documents) untuk memulai background polling setiap 2 detik.
- Status dokumen diatur ke
Langkah 2: Gateway Penerimaan (Next.js Upload)
Ada dua gerbang masuk upload:
- API Web (route.ts (api/upload)): Digunakan oleh dashboard website admin.
- API Mobile v1 (route.ts (api/v1/documents/upload)): Digunakan oleh aplikasi Flutter.
Mekanisme Penyimpanan:
- Berkas disimpan ke folder
/uploadsdengan nama unik (Date.now()-filename). - Koordinat GPS disimpan.
- Memicu pemanggilan API parse sinkron
/api/parsedengan menyertakan nama file.
Langkah 3: Mesin Ekstraksi & OCR Pipeline (/api/parse)
Di dalam file route.ts (api/parse):
1. Layout-Parsing (OCR Pipeline)
- Berkas dikonversi menjadi format Base64 dan diposkan ke API Pipeline (
http://localhost:7871/layout-parsing). - Pipeline membedah tata letak halaman (tabel, teks, paragraf) dan menghasilkan format terstruktur (Markdown) beserta informasi polygon koordinat tiap blok teks.
- Konfigurasi
markdown_ignore_labelsdisetel kosong ([]) pada berkaspipeline_config_vllm.yamlagar elemen tata letak sepertiheader,footer,footnote,number, danaside_texttidak di-filter oleh detektor layout. Hal ini memastikan informasi administratif penting (seperti nomor PO/SO/Tanggal) yang terletak di bagian atas atau bawah halaman tetap terekstrak secara akurat.
2. Auto-Deskew & Unwarping (Rotasi Gambar Otomatis)
- Sudut kemiringan dihitung secara trigonometris melalui
calculateAverageTilt(data)dengan melihat titik polygonblock_polygon_points:\text{Angle} = \arctan\left(\frac{dy}{dx}\right) \times \frac{180}{\pi} - Jika kemiringan rata-rata melampaui 1.0 derajat, backend otomatis memicu pemrosesan ulang dengan menyalakan flag:
useDocUnwarping: trueuseDocOrientationClassify: true
- Hal ini menjamin pembacaan teks lurus dan akurat walaupun dokumen difoto miring.
3. Ekstraksi Metadata Lapis 1 (Regex & Alinyemen Layout)
Fungsi parseDOMetadata(markdownText) mengurai konten Markdown hasil OCR:
- Vendor & Customer: Mencari baris teks berawalan
PT.(Vendor dibedakan dengan Customer/Primafood). - Nomor Dokumen:
- No PO: Pola
PO/YY/XXXX(dipaksa tahun berjalan). - No SO & DO: Pola numerik 10 digit (misal: dimulai dengan
16).
- No PO: Pola
- Koreksi Layout Tergeser (Shifted Layout): Jika hasil OCR tidak menyejajarkan teks label dengan nilainya (misal, nilai nomor SO tergeser di bawah label DO), parser memindai baris terdekat untuk melakukan pemetaan ulang berdasarkan kedekatan indeks baris.
4. Sanitasi Lapis 2 (Validator Sanity Check)
Fungsi sanitizeParsedMetadata() menjamin kepatuhan data sebelum disimpan ke database:
- Tanggal: Wajib berformat
"dd Month yyyy"(Januari s.d. Desember Inggris). Jika tidak valid atau di luar rentang (2010 s.d. tahun depan), nilainya diganti"Not Found". - SO & DO: Wajib berupa digit angka murni sepanjang 7 s.d. 12 karakter.
- Plat Nomor: Wajib memiliki format plat nomor Indonesia yang valid (misalnya:
B 1234 ABC).
5. Pencocokan Toko (Fuzzy Database Match)
Fungsi resolveStoreFromText() mencocokkan teks penerima dengan data toko aktif di database (store_master):
- Kata umum seperti "dan", "dki", "jalan", "raya", "kelurahan" dihapus dari token OCR.
- Dilakukan penghitungan rasio irisan token (token intersection score) dengan seluruh kombinasi
nama_tokodanalamatdi database. - Toko dengan kecocokan minimal 2 token dan skor tertinggi dipilih untuk mengisi kolom
orderUntukdanalamat.
6. Parsing Tabel Item SKU
- Backend memindai tag
<table>di Markdown. - Kolom kode barang dibersihkan dan difilter ketat untuk hanya menerima format 8 digit angka murni (sesuai standar SKU item internal).
- Jika kolom kuantitas (
banyak) tidak terbaca satuannya (misal hanya angka"10"), backend melengkapinya berdasarkan pola SKU (contoh: SKU11310024dilengkapi menjadi"10 KRG").
Langkah 4: Penyimpanan Database (PostgreSQL)
- Metadata dokumen disimpan atau diperbarui pada tabel
documents:- Kolom status parsing diubah menjadi
parsed = true. - Kolom JSONB
metadatamenyimpan struktur PO, SO, DO, Plat Truk, Tanggal, dll. - Kolom JSONB
layout_parsing_resultmenyimpan mentahan respons Pipeline OCR (termasuk data tilt). - Kolom JSONB
processing_logsmenyimpan log terperinci tiap tahapan ekstraksi.
- Kolom status parsing diubah menjadi
- Item lama yang terkait dengan dokumen di tabel
ocr_itemsdihapus untuk menghindari data usang, kemudian data item hasil ekstraksi baru dimasukkan kembali via bulk-insert.