improve parsing
This commit is contained in:
+23
-3
@@ -23,21 +23,41 @@ For each receipt:
|
||||
| `store` | Best-effort store from the header + `known_stores` |
|
||||
| `receiptTotal` | First grand-total amount after the items |
|
||||
| `totalDiscount` | Receipt-level `Totaal korting` (and similar) |
|
||||
| `validationPassed` | Item sum matches `receiptTotal` within €0.01 |
|
||||
| `validationPassed` | Item sum matches `receiptTotal` within €0.01, item count matches when printed, and no line needs manual review |
|
||||
| `items[].sourceBounds` | Normalized rect on the receipt photo for tap-to-highlight in Review |
|
||||
| `items[].needsManualReview` | Parser could not resolve price/qty confidently |
|
||||
| `expectedItemCount` | From `Aantal Artikel`-style lines when found |
|
||||
| `ocrImageWidth` / `ocrImageHeight` | Image size used to normalize bounds |
|
||||
|
||||
If validation fails, Review shows: *Parsed totals do not match the receipt.*
|
||||
If validation fails, Review shows a banner asking you to check items before saving.
|
||||
|
||||
---
|
||||
|
||||
## Pipeline
|
||||
|
||||
### Primary: spatial (ML Kit bounding boxes)
|
||||
|
||||
Used automatically after scanning a receipt photo.
|
||||
|
||||
1. **Extract elements** from ML Kit `RecognizedText` (blocks → lines → elements), keeping each element's pixel bounding box.
|
||||
2. **Cluster rows** by Y-center (threshold ≈ 1.2× median element height — see `spatial_parsing` in the JSON config).
|
||||
3. **Classify rows** with column logic: right ~25% of content width is the price column; pure `N X price` rows are quantity modifiers (checked first).
|
||||
4. **Build items** with a one-row lookahead buffer (Jumbo split layout + Kruidvat inline layout).
|
||||
5. **Validate** totals, printed item count, and manual-review flags.
|
||||
|
||||
Implementation: `ReceiptOcr`, `ReceiptRowBuilder`, `ReceiptSpatialParser` in `lib/services/`.
|
||||
|
||||
### Fallback: flat text
|
||||
|
||||
`ReceiptParser.parseReceipt(String)` for tests and when only flattened OCR text exists.
|
||||
|
||||
1. **Preprocess** each OCR line: trim, collapse spaces, drop empty lines.
|
||||
2. **Choose a layout**
|
||||
- **Sequential** (default): name, price, quantity and discount appear in
|
||||
reading order. Jumbo (printed), Lidl, Kruidvat, World Toko.
|
||||
- **Column OCR fallback:** ML Kit sometimes dumps every name, then every
|
||||
amount. Detected when there is a run of 4+ price-only lines *and* enough
|
||||
name-like lines. Used for the Jumbo sample dump in tests.
|
||||
name-like lines.
|
||||
3. **Classify** each line (first match wins) using the keyword JSON.
|
||||
4. **Build items** (pending name, then quantity/discount/price).
|
||||
5. **Validate** against the receipt total when one was found.
|
||||
|
||||
Reference in New Issue
Block a user