Adopt agents-settings kit, ship Product/SKU scan models, harden auth, verify OCR accuracy
Backend (app-pfm-ocr-v2/backend): - Product/SKU scan feature complete: trained DINOv2 index (118 reference photos, 16 SKU classes) and YOLO classifier (83.3% top-1 val accuracy), fixed scripts/install-pipeline.sh (was missing ultralytics/torch), fully browser-verified end-to-end on /scan-pfm. Mobile m-scan-pfm page cancelled (Flutter app handles mobile; web UI is desktop-only for pipeline testing). - Fixed a real data-loss bug: Save Ground Truth (scan-pfm and the DO-flow's manual-label) was silently writing into the pfm-web-app container's ephemeral filesystem instead of the host, because /sources wasn't bind-mounted in docker-compose.yml. Added the mount, recovered an orphaned entry. - accounts.password is now bcrypt-hashed (bcryptjs, idempotent migration in db/init.ts) instead of plaintext; login route compares hashes. - /api/v1/documents/* (list, PUT, upload) now enforces real 401 auth, matching what the Flutter client already sends. The "classic" routes deliberately stay open — they're dev-only web UI with no login flow and won't exist in production. - OCR accuracy investigated end-to-end: real baseline is 95.10% overall (target met; accuracy_report.md was stale at 75.04%, now flagged). Fixed one genuine parser.ts bug (SO/DO field duplication in the global fallback regex); remaining gaps are OCR/layout-model limitations, not parser bugs. - Adopted a standalone copy of the fhanyuh/agents-settings e/n workflow scoped to backend/ (AGENTS.md Part A/B split, SKILLS.md, plans/, docs/), independent of the root copy which now covers Flutter only. - next-implementation.md deleted; content folded into backend/plans/next-enhancements.md for traceability. Root: - Adopted fhanyuh/agents-settings kit (AGENTS.md, SKILLS.md, plans/, docs/feature-list.md), scoped to the Flutter app only. - Pending documents queue now persists to Hive (lib/core/storage) instead of memory-only, surviving an app kill mid-upload. Removed backend_backup/ (stale Express/Prisma prototype, superseded by pfm-web-app) and the completed plans/next-enhancement-plan.md checklist. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
3df9f6ec5d
commit
e60ab63154
129 files changed
+8520
-6684
No files matched your search
@@ -1,5 +1,18 @@
|
||||
# AI OCR Accuracy & Performance Report
|
||||
|
||||
> **⚠️ Stale as of 2026-07-08.** The numbers below (75.04% overall) predate several
|
||||
> parser fixes (table column-shift correction, unit normalization, date
|
||||
> standardization — see git log) and are significantly out of date. The real
|
||||
> current baseline, confirmed 2026-07-08 by re-running
|
||||
> `node pfm-web-app/scripts/accuracy-check.mts` at commit `3df9f6e` (matches
|
||||
> `sources/accuracy_history.jsonl`'s latest entry exactly): **95.10% overall
|
||||
> layer3Final** — already at/above the 95% target. Worst fields now: `plat`
|
||||
> (67.6%, almost entirely OCR/layout-model misses — see
|
||||
> `backend/plans/next-enhancements.md` §2 task 2.3 for the full investigation),
|
||||
> `noSO` (86.5%), `tanggal` (89.2%), `noPO`/`noDO` (91.9% each). Don't trust the
|
||||
> prose/table below without re-running the harness first — this file isn't
|
||||
> auto-regenerated on every run.
|
||||
|
||||
This report summarizes the comparison of **AI OCR Extraction (Layer 3 Final)** against the **Manual Ground Truth Labels** across all **37 test images**.
|
||||
|
||||
---
|
||||
@@ -44,3 +57,80 @@ This report summarizes the comparison of **AI OCR Extraction (Layer 3 Final)** a
|
||||
- *Recommendation*: Enhance `sanitizeParsedMetadata` in [parser.ts](file:///d:/Client/Data%20Bisnis%20Solusi/app-pfm-ocr-v2/backend/pfm-web-app/src/utils/parser.ts) to parse multiple date format variations into a unified target format.
|
||||
3. **Plat Nomor (56.76%)**:
|
||||
- *Why it's low*: License plates on delivery orders are often stamped, handwritten, or placed in odd margins, which makes clean extraction difficult.
|
||||
---
|
||||
|
||||
## 🧪 Parser Unit Test Results (`parser.test.ts`)
|
||||
|
||||
**Last run:** 2026-07-06 · **Result: 48 / 48 passed (100%)** ✅
|
||||
|
||||
Unit-level regression tests for `parseDOMetadata()` and `sanitizeParsedMetadata()` in [parser.ts](file:///d:/Client/Data%20Bisnis%20Solusi/app-pfm-ocr-v2/backend/pfm-web-app/src/utils/parser.ts). Run anytime with:
|
||||
```
|
||||
npx tsx src/utils/parser.test.ts
|
||||
```
|
||||
(from `backend/pfm-web-app`). Triggered this run by the **Customer Name post-processing cleanup** — removed the now-dead OCR extraction/regex logic for `customerInfo` (it was always overwritten by a hardcoded `"PT. PRIMAFOOD INTERNATIONAL"` constant anyway) and confirmed nothing else regressed.
|
||||
|
||||
| Status | Count |
|
||||
| :--- | :---: |
|
||||
| ✅ Passed | **48** |
|
||||
| ❌ Failed | **0** |
|
||||
| **Total** | **48** |
|
||||
|
||||
### `parseDOMetadata` — 26 tests
|
||||
|
||||
| # | Test Case | Result |
|
||||
| :---: | :--- | :---: |
|
||||
| 1 | PO standard PO/26/ | ✅ |
|
||||
| 2 | PO misread P0/26/ on label | ✅ |
|
||||
| 3 | PO label raw 10-digit, real PO in body | ✅ |
|
||||
| 4 | PO misread F0/20/ — use current year NOT 20 | ✅ |
|
||||
| 5 | PO body P0/26/ | ✅ |
|
||||
| 6 | PO real doc: label raw, body has P0/26/ | ✅ |
|
||||
| 7 | PO fused F012070000170727 | ✅ |
|
||||
| 8 | PO fused PO12070000190729 | ✅ |
|
||||
| 9 | PO noise digits PO120/0000170727 | ✅ |
|
||||
| 10 | Date trailing noise cut | ✅ |
|
||||
| 11 | Date no space 25May2020 | ✅ |
|
||||
| 12 | Date standard 23 June 2026 | ✅ |
|
||||
| 13 | Date Tanggal blank shifted to No.SO | ✅ |
|
||||
| 14 | Date prefix timestamp noise | ✅ |
|
||||
| 15 | Date (Asli/Copy) prefix noise | ✅ |
|
||||
| 16 | Date junk suffix cut | ✅ |
|
||||
| 17 | Date bad OCR month Hv → Not Found | ✅ |
|
||||
| 18 | Date single digit 7 May 2026 → 07 May 2026 | ✅ |
|
||||
| 19 | Date single digit 4 Apr 2026 → 04 April 2026 | ✅ |
|
||||
| 20 | 00117709 before Tanggal must not pollute date | ✅ |
|
||||
| 21 | Plate B 9427 UXT | ✅ |
|
||||
| 22 | Plate B-9999-XYZ dash | ✅ |
|
||||
| 23 | Plate ignore PO/SO prefix | ✅ |
|
||||
| 24 | Plate B9427UXT adjacent | ✅ |
|
||||
| 25 | Plate real doc B 9723 CXS | ✅ |
|
||||
| 26 | Table column shift alignment correction | ✅ |
|
||||
|
||||
### `sanitizeParsedMetadata` — 22 tests
|
||||
|
||||
| # | Test Case | Result |
|
||||
| :---: | :--- | :---: |
|
||||
| 27 | valid tanggal 30 June 2026 passes | ✅ |
|
||||
| 28 | valid tanggal 25 May 2020 passes | ✅ |
|
||||
| 29 | single digit tanggal 4 April 2026 → 04 April 2026 | ✅ |
|
||||
| 30 | tanggal bad month Hv → Not Found | ✅ |
|
||||
| 31 | tanggal as number 0011770 → Not Found | ✅ |
|
||||
| 32 | tanggal day 0 → Not Found | ✅ |
|
||||
| 33 | tanggal day 32 → Not Found | ✅ |
|
||||
| 34 | tanggal year 2009 (too old) → Not Found | ✅ |
|
||||
| 35 | tanggal Not Found stays Not Found | ✅ |
|
||||
| 36 | tanggal with noise suffix → Not Found | ✅ |
|
||||
| 37 | valid noPO PO/26/0000178435 passes | ✅ |
|
||||
| 38 | noPO wrong year auto-corrected to current | ✅ |
|
||||
| 39 | noPO raw number → Not Found | ✅ |
|
||||
| 40 | noPO Not Found stays Not Found | ✅ |
|
||||
| 41 | valid noSO 1691908676 passes | ✅ |
|
||||
| 42 | noSO 'abc' → Not Found | ✅ |
|
||||
| 43 | noSO too short '123' → Not Found | ✅ |
|
||||
| 44 | valid noDO 1659932080 passes | ✅ |
|
||||
| 45 | noDO 'XYZXYZ' → Not Found | ✅ |
|
||||
| 46 | valid platTruk B 9427 UXT passes | ✅ |
|
||||
| 47 | platTruk XY 1234 ABC invalid prefix → empty | ✅ |
|
||||
| 48 | platTruk empty stays empty | ✅ |
|
||||
|
||||
> Note: no test case directly exercises `customerInfo` (it wasn't covered before this change either) - passing confirms the surrounding logic (PO/date/plate/table parsing) is unaffected by the cleanup.
|
||||
Reference in new issue
Block a user