Spaces:
Running
Running
| # Data & Extraction Specification | |
| ## 1. Datasets | |
| All free, all on Hugging Face and/or Kaggle. data.gov.sg is **not** a source β | |
| it publishes statistical open data, not document images. The set below is | |
| chosen to cover every required input modality *and* to provide ground-truth | |
| labels, which the evaluation harness needs. | |
| | Dataset | What it is | Modality covered | Labels | Where | | |
| |---|---|---|---|---| | |
| | **SROIE (ICDAR 2019)** | ~1,000 real scanned receipts from shops/restaurants; variable print & scan quality | Scans | company, address, date, total | HF: `Voxel51/scanned_receipts`; also `priyank-m/SROIE_2019_text_recognition` | | |
| | **CORD** | ~11,000 Indonesian receipts captured in the wild; noisy, low quality; multi-level labels (store/menu/subtotal/total + subclasses) | Scans / in-the-wild | rich key-value + line items | HF: search `CORD` (naver-clova-ix) | | |
| | **MC-OCR** | 2,436 receipts captured on mobile devices | Phone photos | quality + key fields | Search "MC-OCR RIVF 2021" (HF mirrors / challenge page) | | |
| | **High Quality Invoice Images for OCR** | ~6,700 synthetic but realistic invoices | Native-style invoices | invoice fields | Kaggle: `osamahosamabdellatif/high-quality-invoice-images-for-ocr`; HF: `Voxel51/high-quality-invoice-images-for-ocr` | | |
| | **invoices-and-receipts_ocr_v1** | Mixed invoices + receipts with OCR/structure | Mixed | structured | HF: `mychen76/invoices-and-receipts_ocr_v1` | | |
| | **invoice-ocr-json** | Invoices with structured JSON ground truth | Native invoices | JSON key-values | HF: `GokulRajaR/invoice-ocr-json` | | |
| | **FUNSD** | 199 noisy scanned forms | Messy scans/forms | entities + relations | HF: search `funsd` | | |
| | **DocILE** (optional, large) | Large invoice benchmark for key-info localization & extraction | Native invoices | KILE/LIR | DocILE project (HF/registration) | | |
| ### Recommended working split | |
| - **Messy real receipts:** SROIE (baseline real) + CORD (noisy in-the-wild). | |
| - **Phone photos:** MC-OCR. | |
| - **Native invoices:** High Quality Invoice Images + `invoice-ocr-json` (has | |
| clean JSON labels, convenient for the eval harness). | |
| - **Messy forms (stretch):** FUNSD. | |
| Hold out a fixed evaluation slice per source and never tune against it. | |
| ### Licensing note | |
| These are research/benchmark datasets with their own terms; several invoice | |
| sets are synthetic. Use them for development, evaluation, and demo only, and | |
| keep real/sensitive documents off the public demo and off free hosted | |
| backends (see NFR-2). Confirm each dataset's license before any redistribution. | |
| ## 2. Output schema | |
| A single unified schema spans receipts and invoices; fields not present in a | |
| given document are `null`. Define with Pydantic so the same model enforces | |
| structured output, validates types, and serializes to storage. | |
| ```python | |
| class LineItem(BaseModel): | |
| description: str | None | |
| quantity: float | None | |
| unit_price: float | None | |
| amount: float | None | |
| class Document(BaseModel): | |
| doc_type: Literal["receipt", "invoice", "other"] | |
| vendor_name: str | None | |
| vendor_address: str | None | |
| invoice_number: str | None # critical | |
| document_date: date | None # ISO 8601 | |
| due_date: date | None | |
| currency: str | None # ISO 4217 where detectable | |
| line_items: list[LineItem] | |
| subtotal: float | None | |
| tax: float | None # critical | |
| total: float | None # critical | |
| # populated by the pipeline, not the model: | |
| field_confidence: dict[str, float] = {} | |
| validation: dict = {} | |
| decision: Literal["accept", "review"] | None = None | |
| ``` | |
| **Field requirements** | |
| - Always attempt: `doc_type`, `vendor_name`, `document_date`, `total`. | |
| - Critical (precision-prioritised): `total`, `tax`, `invoice_number`. | |
| - Monetary fields are numbers (no currency symbols/thousands separators); | |
| normalize during extraction. | |
| - Dates are ISO 8601 (`YYYY-MM-DD`); store raw string alongside if parsing is | |
| ambiguous. | |
| ## 3. Validation rules | |
| Validation is pure functions over the parsed `Document` β a report. Two | |
| classes of rule: | |
| **Hard rules (a failure forces `review`):** | |
| - `H1` All critical fields parse to the correct type when present. | |
| - `H2` Arithmetic reconciliation, when the inputs exist: | |
| `subtotal + tax β total` within a small epsilon (rounding tolerance). | |
| - `H3` Line-item reconciliation, when line items exist: | |
| `sum(line_items.amount) β subtotal` (or `total` if no subtotal). | |
| - `H4` `total` is present and non-negative. | |
| **Soft rules (reduce confidence, do not force review):** | |
| - `S1` `document_date` present and plausible (not in the far future). | |
| - `S2` `currency` resolves to a known code. | |
| - `S3` `vendor_name` non-empty. | |
| - `S4` Per-line arithmetic: `quantity * unit_price β amount`. | |
| Epsilon for monetary comparisons accommodates rounding (e.g. Β±0.02 absolute or | |
| a small relative tolerance, whichever is larger). | |
| ## 4. Confidence scoring | |
| Document confidence β [0, 1] blends: | |
| - **Model signal** (weighted) β backend field/token confidence where exposed; | |
| neutral (0.5) when unavailable. | |
| - **Validation** β start from model signal; subtract penalties for each soft | |
| failure; any hard failure short-circuits to `review`. | |
| - **Completeness** β penalty proportional to missing required fields. | |
| Exact weights live in config and are set empirically via the eval harness. Keep | |
| the function pure and unit-tested with hand-built cases. | |
| ## 5. Routing | |
| ``` | |
| decision = review if any hard rule fails | |
| = accept if confidence >= THRESHOLD | |
| = review otherwise | |
| ``` | |
| `THRESHOLD` is one constant, tuned in evaluation. | |
| ## 6. Evaluation methodology | |
| This is what turns "seems to work" into evidence, and it is how the | |
| precision/recall question is answered concretely. | |
| **Definitions (field level, against ground truth):** | |
| - *Precision* = correct extracted values / all values the system produced | |
| (and auto-accepted). | |
| - *Recall* = correct extracted values / all values present in ground truth. | |
| - *F1* = harmonic mean. | |
| **Procedure:** | |
| 1. Run the core over each held-out dataset slice. | |
| 2. Normalize predicted and gold values (numbers, dates, casing/whitespace) | |
| before comparison. | |
| 3. Compute precision, recall, F1 **per field** and **per critical field**. | |
| 4. Compute document-level routing stats: % auto-accepted, % to review, and β | |
| crucially β **precision on the auto-accepted subset** for critical fields. | |
| 5. Sweep `THRESHOLD` and report the precision/recall trade-off curve. | |
| **Target / operating point:** | |
| - Optimize so **auto-accept precision on `total`, `tax`, `invoice_number` β₯ | |
| 0.98**, then report recall at that point. Recall "lost" to the threshold is | |
| simply review-queue volume β acceptable, because the asymmetric cost favours | |
| not writing wrong numbers. Arithmetic cross-checks (H2/H3) are the lever that | |
| raises precision without collapsing recall, since they let confident, | |
| internally-consistent values through while catching the inconsistent ones. | |
| Report a small table per dataset (precision/recall/F1 per field, plus routing | |
| stats) in the project README β this is the portfolio's evidence of rigor. | |
| ## 7. Modality handling summary | |
| - **Native PDF:** Docling β text/layout β backend (text or vision). | |
| - **Scan:** vision-direct (Gemini reads the image) **or** OCR β text β backend. | |
| - **Phone photo:** same as scan; vision-direct is more robust to skew/lighting, | |
| which is why the Gemini path is preferred for the demo. | |