docs: price-tag fields, compliance semantics, and the measured limits
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
parent
8f750c15c5
commit
6182f678eb
1 changed files with 56 additions and 0 deletions
|
|
@ -30,6 +30,8 @@ uv pip install --python .venv/bin/python -r requirements-dev.txt # first time
|
|||
| `--classify-workers` | `5` | Classification thread pool size (measured default). |
|
||||
| `--live-method` | `hybrid` | Default method for live sessions. |
|
||||
| `--live-conf` | `0.1` | Detection threshold in live mode (the tracker gates). |
|
||||
| `--no-tags` | off | Disable price-tag OCR entirely (`DORAYAKI_LIVE_TAGS=0`). |
|
||||
| `DORAYAKI_OCR` | `auto` | OCR backend: `auto` (Vision on macOS), `vision`, `fake`, `none`. |
|
||||
| `DORAYAKI_TORCH_THREADS` | `4` | torch CPU threads; 0 leaves torch's default. |
|
||||
| `--max-sessions` | `4` | Concurrent live sessions. |
|
||||
| `--ssl-certfile` / `--ssl-keyfile` | – | HTTPS (needed for a phone camera). |
|
||||
|
|
@ -153,6 +155,45 @@ with a `file` field.
|
|||
before identities arrive. The `image_id` stays valid for 15 minutes for
|
||||
`classify`/`inspect`.
|
||||
|
||||
### Price tags (OCR)
|
||||
|
||||
When an OCR backend is available (macOS Vision; see the design doc), a still can
|
||||
carry tag evidence. `?tags=true` runs the tag pass synchronously (measured ~0.9 s
|
||||
for a six-band shelf) and adds, per detection:
|
||||
|
||||
```json
|
||||
"price_tag": {"id": "tag_3f2a", "box": [91, 657, 250, 744], "state": "readable",
|
||||
"price": 357, "regular_price": null, "discount": 0.24, "unit_price": 290.52,
|
||||
"name": "ゼロノンコレステロール", "flags": ["sale", "discounted"],
|
||||
"confidence": 0.82, "observations": 2, "settled": false},
|
||||
"reconciliation": {"state": "confirmed | mismatch | unverified | no_tag | tag_only",
|
||||
"signals": [{"kind": "price", "agrees": false, "item": 168, "tag": 269}],
|
||||
"message": "tag says 269, catalog says 168"}
|
||||
```
|
||||
|
||||
`price_tag.state` is `readable` (text parsed), `unreadable` (a tag was found but
|
||||
its text was not read) or `absent` (no tag under this facing). The summary gains
|
||||
`price_tags` counts and `compliance`:
|
||||
|
||||
```json
|
||||
"price_tags": {"readable": 8, "unreadable": 18, "absent": 85},
|
||||
"compliance": {"violations": 7, "by_rule": {"price_mismatch": 7},
|
||||
"rows": [{"row_index": 2, "rule": "price_mismatch", "box": [...], "missing": 1}],
|
||||
"hints": [{"rule": "unreadable_tags", "detail": "tags detected for 5 of 16 facings in this row"}]}
|
||||
```
|
||||
|
||||
**Compliance fails closed on evidence quality.** A row is only judged when at
|
||||
least 70% of its facings carry tag evidence (readable or unreadable); otherwise it
|
||||
produces a hint such as `move closer: the price tags in this row could not be
|
||||
read`, never a violation. Findings must also persist for 3 of the last 5 frames
|
||||
before they publish. This is deliberate: the first implementation reported 106
|
||||
missing-tag violations on a shelf where only 8 tags were readable, which was our
|
||||
detection being incomplete, not the shelf.
|
||||
|
||||
`POST /v1/images/{image_id}/classify` re-reconciles against the cached tag bundle
|
||||
and returns `reconciliation` (and `price_tag`) on each identity row, because in
|
||||
photo mode the tags are read before the identities exist.
|
||||
|
||||
### `POST /v1/images/{image_id}/classify`
|
||||
|
||||
```json
|
||||
|
|
@ -283,6 +324,21 @@ The slide's "約28~30ms per image" matches the measured **detection** time (28.7
|
|||
the full detect-and-classify of a whole 170-product shelf is ~2 s because each product
|
||||
is matched against the catalog separately.
|
||||
|
||||
## Price-tag OCR: what it can and cannot do (measured)
|
||||
|
||||
- **Capture distance decides everything.** At `add/image6.jpg`'s ~1 m (tags ~300x80 px,
|
||||
digits ~22 px) macOS Vision reads a tag's printed fields reliably and the tag pass
|
||||
finds 8 readable tags with names and prices in ~0.9 s. At `image.jpg`'s ~2 m (digits
|
||||
~14 px) it reads none of them - the pass correctly reports nothing readable.
|
||||
- **Tag detection is the weak link, not the OCR.** On a shelf with ~100 facings the
|
||||
pass currently finds tags for a minority of them at this distance; the compliance
|
||||
hints say so instead of inventing violations.
|
||||
- **A single read can misread a digit.** The vote needs independent reads (live mode
|
||||
accumulates them across frames; stills read each band twice at different upscales),
|
||||
and a dead heat stays unread rather than guessing.
|
||||
- **The demo catalog is fictional**, so tag prices legitimately disagree with it. That
|
||||
is shown as `mismatch` with both values; it is not an error.
|
||||
|
||||
## Known limitations
|
||||
|
||||
- **No session totals.** Facings are counted only for products currently in view. A
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue