From a55318a5fce6c6ae2154bfcb56de136e2d64675c Mon Sep 17 00:00:00 2001 From: Nigel Jones Date: Wed, 20 May 2026 14:28:03 +0100 Subject: [PATCH 1/7] =?UTF-8?q?docs:=20draft=20blog=20=E2=80=94=20structur?= =?UTF-8?q?ed=20image=20extraction=20with=20Granite=20Vision=204.1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Blog post covering m.instruct() + format= + ImageBlock for typed receipt extraction, building up through requirements= and IVR validation_fn. Includes a synthetic receipt image generated with PIL. Assisted-by: Claude Code Signed-off-by: Nigel Jones --- .../granite-vision-structured-extraction.md | 219 ++++++++++++++++++ public/images/blogs/receipt-sample.jpg | Bin 0 -> 40046 bytes 2 files changed, 219 insertions(+) create mode 100644 content/blogs/granite-vision-structured-extraction.md create mode 100644 public/images/blogs/receipt-sample.jpg diff --git a/content/blogs/granite-vision-structured-extraction.md b/content/blogs/granite-vision-structured-extraction.md new file mode 100644 index 0000000..1c6020f --- /dev/null +++ b/content/blogs/granite-vision-structured-extraction.md @@ -0,0 +1,219 @@ +--- +title: "Getting Structured Data Out of Images with Granite Vision 4.1" +date: "2026-06-03" +author: "Nigel Jones" +excerpt: "Vision models return prose. This post shows how to get a typed Python object back instead, using Mellea's format= parameter and ImageBlock." +tags: ["vision", "structured-output", "granite", "IVR", "image-extraction"] +--- + +Vision models narrate. Hand one a receipt and you get three paragraphs describing it — and now +you're writing a parser for natural language, which is exactly what you were trying to avoid. + +The usual workaround is to append "respond with JSON matching this schema" to your prompt, hope +the model complies, catch the `json.JSONDecodeError` when it doesn't, and wonder why extracting +a number from a picture turned into a reliability project. + +There's a cleaner path. + +--- + +> **EDITORIAL NOTE — remove before publishing** +> +> Granite Vision 4.1 is not yet in the Ollama library. The blog is written for Ollama +> (that's the final published form — don't change the code examples). For testing and review, +> run the code against mlx-vlm instead: +> +> ```bash +> pip install mlx-vlm mellea pillow +> python -m mlx_vlm.server --model ibm-granite/granite-vision-4.1-4b +> # Serves at http://localhost:8080/v1 — model downloads (~3 GB) on first run +> ``` +> +> Then change the session setup in each code block from: +> `m = start_session(model_id="granite-vision-4.1")` +> to: +> `m = MelleaSession(OpenAIBackend("ibm-granite/granite-vision-4.1-4b", base_url="http://localhost:8080/v1", api_key="mlx"))` +> +> Watch the [Ollama library](https://ollama.com/library) for `granite-vision-4.1`. When it +> lands: delete this note, verify `ollama pull granite-vision-4.1` works, publish. + +--- + +## Running locally + +[Granite Vision 4.1](https://huggingface.co/ibm-granite/granite-vision-4.1-4b) runs locally +on Ollama. No API key, no cloud bill: + +```bash +ollama pull granite-vision-4.1 +pip install mellea pillow +``` + +## The problem + +Here's the receipt we'll work with — a small deli order with a loyalty discount: + +![Sample deli receipt](/images/blogs/receipt-sample.jpg) + +Start with the naïve approach: ask the model to describe it. + +```python +from mellea import start_session +from mellea.core import ImageBlock +from PIL import Image + +m = start_session(model_id="granite-vision-4.1") +img = ImageBlock.from_pil_image(Image.open("receipt.jpg")) + +result = m.instruct("What's on this receipt?", images=[img]) +print(result) +``` + +Output: + +``` +"This receipt is from Grove Street Deli in Portland, dated March 15th 2026. + It shows two drip coffees at $3.50 each, an avocado toast for $10.50, and + a blueberry muffin for $3.95, with a $1.00 loyalty discount applied. The + subtotal comes to $20.45 with 8.5% tax of $1.74, for a total of $22.19." +``` + +Readable. Useless as data. You can't do `result.total` or `result.items[0].unit_price`. + +## The return type is the extraction schema + +Define what you want as a Pydantic model and pass it to `format=`. Mellea uses constrained +decoding to guarantee the output matches — no prompt-engineering the JSON shape, no parse +errors to catch. + +```python +from pydantic import BaseModel +from mellea import start_session +from mellea.core import ImageBlock +from PIL import Image + + +class LineItem(BaseModel): + description: str + quantity: int + unit_price: float + + +class Receipt(BaseModel): + vendor: str + date: str + items: list[LineItem] + subtotal: float + tax: float + total: float + + +m = start_session(model_id="granite-vision-4.1") +img = ImageBlock.from_pil_image(Image.open("receipt.jpg")) + +result = m.instruct("Extract the receipt data.", images=[img], format=Receipt) +receipt = Receipt.model_validate_json(str(result)) + +print(receipt.vendor) # "Grove Street Deli" +print(receipt.total) # 22.19 +print(receipt.items[0].quantity) # 2 +``` + +`ImageBlock.from_pil_image()` converts any PIL image to the base64 PNG the backends expect. +`format=Receipt` switches the model into constrained decoding. `model_validate_json` gives you +a fully typed Python object with IDE autocomplete on every field. + +Notice the discount line on the receipt (`unit_price: -1.00`). The model needs to handle +negative values correctly — structured output forces it to produce a proper float, which we +can verify programmatically. + +## When the type isn't enough + +Pydantic catches structural failures: wrong shape, missing fields, values that can't be coerced. +It won't catch semantic ones. If the model reads the total as `-22.19`, that's valid JSON. +If it parses the date as `"March 15"` instead of `"2026-03-15"`, the field is populated — +it's just wrong. + +`requirements=` handles this. Pass plain-English constraints; if the first attempt fails one, +Mellea repairs and retries with the failure reason fed back into the prompt: + +```python +from mellea.stdlib.sampling import RejectionSamplingStrategy + +result = m.instruct( + "Extract the receipt data.", + images=[img], + format=Receipt, + requirements=[ + "total must be a positive number", + "date must be in ISO 8601 format (YYYY-MM-DD)", + "each item's unit_price must be positive except for discounts", + ], + strategy=RejectionSamplingStrategy(loop_budget=3), +) +receipt = Receipt.model_validate_json(str(result)) +``` + +Worth being clear about the limit: requirements validate the *extracted values*, not whether +they match what's physically in the image. A requirement catches the model hallucinating a +negative total; it can't verify the number on screen was $22.19 rather than $21.19. For that +you need an external check. + +## When to reach for IVR + +If you have a concrete verifiable property — something independent of the image — wire it as a +`validation_fn`. Mellea runs it on each attempt and feeds the failure reason back into the +repair prompt if it fails. + +Line-item arithmetic is the natural case here: the items should sum to the subtotal. The +discount makes this a real test — the model has to correctly treat `-$1.00` as negative: + +```python +from mellea.stdlib.requirements import req +from mellea.stdlib.sampling import RejectionSamplingStrategy + + +def check_line_totals(json_str: str) -> tuple[bool, str]: + r = Receipt.model_validate_json(json_str) + computed = round(sum(i.quantity * i.unit_price for i in r.items), 2) + if abs(computed - r.subtotal) > 0.01: + return False, f"line items sum to ${computed:.2f}, subtotal shows ${r.subtotal:.2f}" + return True, "" + + +result = m.instruct( + "Extract the receipt data.", + images=[img], + format=Receipt, + requirements=[ + "total must be a positive number", + req("line items match subtotal", validation_fn=check_line_totals), + ], + strategy=RejectionSamplingStrategy(loop_budget=3), +) +receipt = Receipt.model_validate_json(str(result)) +``` + +The general progression: `format=` alone → `requirements=` for semantic constraints → +`validation_fn` when you have something concrete to verify programmatically. Most image +extraction stops at step two. Reach for `validation_fn` when you'd be writing the same check +in post-processing anyway — it belongs in the prompt loop, not after it. + +## Swapping backends + +`ImageBlock` is backend-agnostic. The only thing that changes is the session setup: + +```python +# Ollama (this post) +from mellea import start_session +m = start_session(model_id="granite-vision-4.1") + +# Any OpenAI-compatible endpoint (vLLM, mlx-vlm, cloud) +from mellea import MelleaSession +from mellea.backends.openai import OpenAIBackend +m = MelleaSession(OpenAIBackend("ibm-granite/granite-vision-4.1-4b", + base_url="http://localhost:8080/v1", api_key="mlx")) +``` + +The `instruct` call — `images=`, `format=`, `requirements=`, `strategy=` — is identical +across all backends. diff --git a/public/images/blogs/receipt-sample.jpg b/public/images/blogs/receipt-sample.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b27151b3d32a816754c99774fa712cac1abf1261 GIT binary patch literal 40046 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 literal 0 HcmV?d00001 From f6b6d271e1ea8531629dda9c98a51039f9f96576 Mon Sep 17 00:00:00 2001 From: Nigel Jones Date: Wed, 20 May 2026 14:30:03 +0100 Subject: [PATCH 2/7] chore: rename receipt image to match blog post slug Assists-by: Claude Code Signed-off-by: Nigel Jones --- .../blogs/granite-vision-structured-extraction.md | 2 +- ...ranite-vision-structured-extraction-receipt.jpg} | Bin 2 files changed, 1 insertion(+), 1 deletion(-) rename public/images/blogs/{receipt-sample.jpg => granite-vision-structured-extraction-receipt.jpg} (100%) diff --git a/content/blogs/granite-vision-structured-extraction.md b/content/blogs/granite-vision-structured-extraction.md index 1c6020f..1b21b1c 100644 --- a/content/blogs/granite-vision-structured-extraction.md +++ b/content/blogs/granite-vision-structured-extraction.md @@ -53,7 +53,7 @@ pip install mellea pillow Here's the receipt we'll work with — a small deli order with a loyalty discount: -![Sample deli receipt](/images/blogs/receipt-sample.jpg) +![Sample deli receipt](/images/blogs/granite-vision-structured-extraction-receipt.jpg) Start with the naïve approach: ask the model to describe it. diff --git a/public/images/blogs/receipt-sample.jpg b/public/images/blogs/granite-vision-structured-extraction-receipt.jpg similarity index 100% rename from public/images/blogs/receipt-sample.jpg rename to public/images/blogs/granite-vision-structured-extraction-receipt.jpg From ca353933763853965760932c0c068d54186400bf Mon Sep 17 00:00:00 2001 From: Nigel Jones Date: Wed, 20 May 2026 14:45:29 +0100 Subject: [PATCH 3/7] fix: resolve CI lint error, bug in validation_fn, and add conclusion MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add `text` language tag to output fence (fixes MD040 lint failure) - Wrap check_line_totals with simple_validate() — validation_fn expects Callable[[Context], ValidationResult], not str directly - pip install → uv add (consistent with other Mellea blogs) - Add conclusion section with recap and cross-references to docs.mellea.ai Assisted-by: Claude Code Signed-off-by: Nigel Jones --- .../granite-vision-structured-extraction.md | 32 ++++++++++++++++--- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/content/blogs/granite-vision-structured-extraction.md b/content/blogs/granite-vision-structured-extraction.md index 1b21b1c..415c207 100644 --- a/content/blogs/granite-vision-structured-extraction.md +++ b/content/blogs/granite-vision-structured-extraction.md @@ -46,7 +46,7 @@ on Ollama. No API key, no cloud bill: ```bash ollama pull granite-vision-4.1 -pip install mellea pillow +uv add mellea pillow ``` ## The problem @@ -71,7 +71,7 @@ print(result) Output: -``` +```text "This receipt is from Grove Street Deli in Portland, dated March 15th 2026. It shows two drip coffees at $3.50 each, an avocado toast for $10.50, and a blueberry muffin for $3.95, with a $1.00 loyalty discount applied. The @@ -169,7 +169,7 @@ Line-item arithmetic is the natural case here: the items should sum to the subto discount makes this a real test — the model has to correctly treat `-$1.00` as negative: ```python -from mellea.stdlib.requirements import req +from mellea.stdlib.requirements import req, simple_validate from mellea.stdlib.sampling import RejectionSamplingStrategy @@ -187,7 +187,7 @@ result = m.instruct( format=Receipt, requirements=[ "total must be a positive number", - req("line items match subtotal", validation_fn=check_line_totals), + req("line items match subtotal", validation_fn=simple_validate(check_line_totals)), ], strategy=RejectionSamplingStrategy(loop_budget=3), ) @@ -217,3 +217,27 @@ m = MelleaSession(OpenAIBackend("ibm-granite/granite-vision-4.1-4b", The `instruct` call — `images=`, `format=`, `requirements=`, `strategy=` — is identical across all backends. + +## What we covered + +- `ImageBlock.from_pil_image()` loads any PIL image for use with vision-capable backends +- `format=` on `m.instruct()` uses constrained decoding to guarantee a valid Pydantic object + back — no JSON parsing errors to handle +- `requirements=` adds plain-English semantic constraints with automatic repair on failure +- `simple_validate(fn)` wraps a `str → (bool, str)` function into the form `validation_fn=` + expects, enabling programmatic checks like arithmetic verification +- The whole pipeline — structured output, requirements, IVR — composes with any backend; + only the session setup changes + +**Going further:** + +- [Use Images and Vision Models](https://docs.mellea.ai/how-to/use-images-and-vision) — + image loading, backend configuration, multi-image prompts +- [Enforce Structured Output](https://docs.mellea.ai/how-to/enforce-structured-output) — + `format=`, `@generative`, and constrained decoding in detail +- [The Requirements System](https://docs.mellea.ai/concepts/requirements-system) — + how `Requirement`, `ValidationResult`, and `simple_validate` work together +- [Instruct-Validate-Repair](https://docs.mellea.ai/concepts/instruct-validate-repair) — + the IVR loop, sampling strategies, and repair prompts explained +- [Write Custom Verifiers](https://docs.mellea.ai/how-to/write-custom-verifiers) — + validation functions beyond simple string checks From abdc88f4d1e3a5d8b2b0e45e145d498fd277d2c6 Mon Sep 17 00:00:00 2001 From: Nigel Jones Date: Wed, 20 May 2026 14:53:43 +0100 Subject: [PATCH 4/7] fix: IVR check and narrative conclusion in vision structured extraction blog - Replace line-item arithmetic check with subtotal+tax=total verification; the old check failed because granite3.2-vision reads discounts as positive - Rewrite 'What we covered' as narrative 'From narration to data' section Assisted-by: Claude Code Signed-off-by: Nigel Jones --- .../granite-vision-structured-extraction.md | 38 +++++++++++-------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/content/blogs/granite-vision-structured-extraction.md b/content/blogs/granite-vision-structured-extraction.md index 415c207..2fbd7ad 100644 --- a/content/blogs/granite-vision-structured-extraction.md +++ b/content/blogs/granite-vision-structured-extraction.md @@ -165,19 +165,20 @@ If you have a concrete verifiable property — something independent of the imag `validation_fn`. Mellea runs it on each attempt and feeds the failure reason back into the repair prompt if it fails. -Line-item arithmetic is the natural case here: the items should sum to the subtotal. The -discount makes this a real test — the model has to correctly treat `-$1.00` as negative: +Receipt arithmetic is the natural case here: subtotal plus tax should equal the total. +The model extracts all three values independently, so it's possible for them to be +internally inconsistent even when each looks plausible in isolation: ```python from mellea.stdlib.requirements import req, simple_validate from mellea.stdlib.sampling import RejectionSamplingStrategy -def check_line_totals(json_str: str) -> tuple[bool, str]: +def check_totals_add_up(json_str: str) -> tuple[bool, str]: r = Receipt.model_validate_json(json_str) - computed = round(sum(i.quantity * i.unit_price for i in r.items), 2) - if abs(computed - r.subtotal) > 0.01: - return False, f"line items sum to ${computed:.2f}, subtotal shows ${r.subtotal:.2f}" + computed = round(r.subtotal + r.tax, 2) + if abs(computed - r.total) > 0.01: + return False, f"subtotal {r.subtotal} + tax {r.tax} = {computed}, total shows {r.total}" return True, "" @@ -187,7 +188,7 @@ result = m.instruct( format=Receipt, requirements=[ "total must be a positive number", - req("line items match subtotal", validation_fn=simple_validate(check_line_totals)), + req("subtotal + tax = total", validation_fn=simple_validate(check_totals_add_up)), ], strategy=RejectionSamplingStrategy(loop_budget=3), ) @@ -218,16 +219,21 @@ m = MelleaSession(OpenAIBackend("ibm-granite/granite-vision-4.1-4b", The `instruct` call — `images=`, `format=`, `requirements=`, `strategy=` — is identical across all backends. -## What we covered +## From narration to data -- `ImageBlock.from_pil_image()` loads any PIL image for use with vision-capable backends -- `format=` on `m.instruct()` uses constrained decoding to guarantee a valid Pydantic object - back — no JSON parsing errors to handle -- `requirements=` adds plain-English semantic constraints with automatic repair on failure -- `simple_validate(fn)` wraps a `str → (bool, str)` function into the form `validation_fn=` - expects, enabling programmatic checks like arithmetic verification -- The whole pipeline — structured output, requirements, IVR — composes with any backend; - only the session setup changes +The gap this closes is a real one. Vision models are already good at reading documents — +they just default to telling you about them rather than handing you the data. Mellea's +`format=` parameter shifts that: the return type becomes a contract, constrained decoding +enforces it, and you get a typed Python object the rest of your code can actually use. + +`requirements=` and `validation_fn` extend that contract beyond structure. Plain-English +requirements catch semantic problems the type system can't — negative totals, badly +formatted dates, values that are plausible individually but wrong together. A `validation_fn` +pushes further still, running the kind of check you'd write in post-processing anyway and +folding it directly into the generation loop rather than bolting it on after. + +All of this composes with any backend. Swap from a local model to a cloud endpoint, or to a +different local runtime, and the extraction logic doesn't change — only the session setup does. **Going further:** From 40338783de762aa568a9f9f210aa640f5ebfac39 Mon Sep 17 00:00:00 2001 From: Nigel Jones Date: Wed, 20 May 2026 15:26:44 +0100 Subject: [PATCH 5/7] wip: update receipt image and sync blog to 6-item receipt - New receipt image: 6 line items with smudged subtotal digit - Expanded editorial note: marks as draft, notes scenario still being iterated, clarifies Ollama not yet available but expected soon - Sync blog body to new receipt values ($79.86 total, no discounts) - IVR section references smudged subtotal as the failure trigger Assisted-by: Claude Code Signed-off-by: Nigel Jones --- .../granite-vision-structured-extraction.md | 65 +++++++++++------- ...e-vision-structured-extraction-receipt.jpg | Bin 40046 -> 53433 bytes 2 files changed, 39 insertions(+), 26 deletions(-) diff --git a/content/blogs/granite-vision-structured-extraction.md b/content/blogs/granite-vision-structured-extraction.md index 2fbd7ad..958598b 100644 --- a/content/blogs/granite-vision-structured-extraction.md +++ b/content/blogs/granite-vision-structured-extraction.md @@ -19,14 +19,23 @@ There's a cleaner path. > **EDITORIAL NOTE — remove before publishing** > -> Granite Vision 4.1 is not yet in the Ollama library. The blog is written for Ollama -> (that's the final published form — don't change the code examples). For testing and review, +> **Status:** Draft — scenario is still being iterated to produce a compelling IVR repair +> demonstration. Code structure and Mellea API usage are stable; receipt values and the exact +> IVR check may change before publication. +> +> **Model availability:** This blog is written for Ollama (final published form — don't change +> the code examples). Granite Vision 4.1 is not yet in the Ollama library, but is expected +> there soon; it is also available in safetensors form on Hugging Face. For testing and review, > run the code against mlx-vlm instead: > > ```bash -> pip install mlx-vlm mellea pillow -> python -m mlx_vlm.server --model ibm-granite/granite-vision-4.1-4b -> # Serves at http://localhost:8080/v1 — model downloads (~3 GB) on first run +> mkdir granite-vision-test && cd granite-vision-test +> uv init --bare --python 3.12 +> uv add mlx-vlm mellea pillow +> uv run python -m mlx_vlm.server --model ibm-granite/granite-vision-4.1-4b +> # Serves at http://localhost:8080/v1 — model downloads (~8 GB) on first run. +> # This is the full bfloat16 safetensors weights, not a quantized GGUF — +> # expect roughly double the size you'd see from an Ollama pull. > ``` > > Then change the session setup in each code block from: @@ -51,7 +60,8 @@ uv add mellea pillow ## The problem -Here's the receipt we'll work with — a small deli order with a loyalty discount: +Here's the receipt we'll work with — a deli order with non-trivial quantities and a +partially smudged subtotal (thermal printer wear): ![Sample deli receipt](/images/blogs/granite-vision-structured-extraction-receipt.jpg) @@ -72,10 +82,11 @@ print(result) Output: ```text -"This receipt is from Grove Street Deli in Portland, dated March 15th 2026. - It shows two drip coffees at $3.50 each, an avocado toast for $10.50, and - a blueberry muffin for $3.95, with a $1.00 loyalty discount applied. The - subtotal comes to $20.45 with 8.5% tax of $1.74, for a total of $22.19." +"This receipt is from Grove Street Deli in Portland, dated March 22nd 2026, + order #2231. It lists three cold brew coffees at $4.75 each, two grain bowls + at $12.95 each, four granola bars at $2.95 each, three oat milk add-ons at + $0.75 each, one avocado toast at $11.50, and two blueberry muffins at $3.95 + each. The subtotal is $73.60, tax at 8.5% is $6.26, for a total of $79.86." ``` Readable. Useless as data. You can't do `result.total` or `result.items[0].unit_price`. @@ -115,18 +126,14 @@ result = m.instruct("Extract the receipt data.", images=[img], format=Receipt) receipt = Receipt.model_validate_json(str(result)) print(receipt.vendor) # "Grove Street Deli" -print(receipt.total) # 22.19 -print(receipt.items[0].quantity) # 2 +print(receipt.total) # 79.86 +print(receipt.items[0].quantity) # 3 ``` `ImageBlock.from_pil_image()` converts any PIL image to the base64 PNG the backends expect. `format=Receipt` switches the model into constrained decoding. `model_validate_json` gives you a fully typed Python object with IDE autocomplete on every field. -Notice the discount line on the receipt (`unit_price: -1.00`). The model needs to handle -negative values correctly — structured output forces it to produce a proper float, which we -can verify programmatically. - ## When the type isn't enough Pydantic catches structural failures: wrong shape, missing fields, values that can't be coerced. @@ -147,7 +154,7 @@ result = m.instruct( requirements=[ "total must be a positive number", "date must be in ISO 8601 format (YYYY-MM-DD)", - "each item's unit_price must be positive except for discounts", + "each item's unit_price must be a positive number", ], strategy=RejectionSamplingStrategy(loop_budget=3), ) @@ -156,7 +163,7 @@ receipt = Receipt.model_validate_json(str(result)) Worth being clear about the limit: requirements validate the *extracted values*, not whether they match what's physically in the image. A requirement catches the model hallucinating a -negative total; it can't verify the number on screen was $22.19 rather than $21.19. For that +negative total; it can't verify the number on screen was $79.86 rather than $78.86. For that you need an external check. ## When to reach for IVR @@ -165,20 +172,22 @@ If you have a concrete verifiable property — something independent of the imag `validation_fn`. Mellea runs it on each attempt and feeds the failure reason back into the repair prompt if it fails. -Receipt arithmetic is the natural case here: subtotal plus tax should equal the total. -The model extracts all three values independently, so it's possible for them to be -internally inconsistent even when each looks plausible in isolation: +Receipt arithmetic is the natural case here: the sum of every line item (quantity × unit price) +must equal the subtotal. The model reads each line independently, so with non-round quantities +like `3 × $4.75` and `4 × $2.95`, it's easy for the accumulated total to drift — especially +when the printed subtotal is partially obscured. The validation function catches it and tells +the model exactly what went wrong: ```python from mellea.stdlib.requirements import req, simple_validate from mellea.stdlib.sampling import RejectionSamplingStrategy -def check_totals_add_up(json_str: str) -> tuple[bool, str]: +def check_line_items(json_str: str) -> tuple[bool, str]: r = Receipt.model_validate_json(json_str) - computed = round(r.subtotal + r.tax, 2) - if abs(computed - r.total) > 0.01: - return False, f"subtotal {r.subtotal} + tax {r.tax} = {computed}, total shows {r.total}" + computed = round(sum(i.quantity * i.unit_price for i in r.items), 2) + if abs(computed - r.subtotal) > 0.01: + return False, f"line items sum to {computed}, subtotal shows {r.subtotal}" return True, "" @@ -188,13 +197,17 @@ result = m.instruct( format=Receipt, requirements=[ "total must be a positive number", - req("subtotal + tax = total", validation_fn=simple_validate(check_totals_add_up)), + req("line items sum to subtotal", validation_fn=simple_validate(check_line_items)), ], strategy=RejectionSamplingStrategy(loop_budget=3), ) receipt = Receipt.model_validate_json(str(result)) ``` +When the check fails, Mellea feeds the error string back into the next attempt — +`"line items sum to 73.60, subtotal shows 70.60"` — so the model knows which numbers +to revisit rather than starting from scratch. + The general progression: `format=` alone → `requirements=` for semantic constraints → `validation_fn` when you have something concrete to verify programmatically. Most image extraction stops at step two. Reach for `validation_fn` when you'd be writing the same check diff --git a/public/images/blogs/granite-vision-structured-extraction-receipt.jpg b/public/images/blogs/granite-vision-structured-extraction-receipt.jpg index b27151b3d32a816754c99774fa712cac1abf1261..1a7ad5f09be3be4c812e093f1a19dd28f55fdd40 100644 GIT binary patch literal 53433 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 WpTDm?^7q>R9gF`jVgUZf#Qy*-n-#?X literal 40046 zcmeFZcT`hdw=Wz7MVd%&LX@h~6e*8@L_`Ecj95Sj5S31Vh=2r%2}L@Hpn}2!QK?Fa zln@albW~KNOCqG8qDV+jYXkgZ3LxEz6qh(I7B;16V-262FF5c&Q3{l4M%OHB0l`$jP_QL#-MH*NaI5SQ4z zNnApF)27W*n>219WBDY!OhR739 z5pBo@IT2Agk@Y?Z6r^+GKga`#{kNCM22rt%o5Vpfq`(VETS4+gMM0uBf)s;SUj;vh zh{E)XNx7DqmY$KBRdDmx?ZTov zcZ(mCS5#J2*F1dG)Z9X9B|m9<+SA+DKQQ?G#mmvL@rlW)chgiRYwp9xPxGI@EO5Sk z|FOzl1AhMcy)F@m=)WxseE;LRzt<(QAr2g(a$*~I?A;`9?=F5mNc+H{Jt5Q&tJ(@SGOBKQ5|i;b@1tR2zM1&;q3m-4F_Iu zOyjyGw{?S;MyXOeV6B?+yxO&hx|h;Ubxe$sizg;aXW1i6clxejTu zO0u)~+NsXIMJN4(68ZU_vMo&$Bq=v}nXuj?Q<00z1dXa^ZDp$@XO@FZ_d4XrHAl6e z9i4@Oj1DJQ)_sn01wPa?&(AJPzcs^=Lt!jn4!Z29WA4!IWRlyGBC1G!qSutReM_)b%EopF0F(`{NXpRFDy%fQjJJB(Lvjkl2 zJ2-K9I0^4Bvj$^7XiKQ$P0x~hoo@De5JL4OD)%&wEo*+f@kmXw4)vALoST=0GslPy zs2il>BlD<132ns#hG;pg6JS^gAWw{_1%#@#03@iy+3pzqGkcE)CVz2{YJPEf%R#%l z4?6b?61NMg!F4(CQ7Nq9B|68T|CebGJo_8q>BOETGFK#M)UZN0^Y!kZe&1X*m9(I8sffadF`>68(DvyV*m8aO>mqsHqLk4o?@Dvdwu$_Ov` z40L)+>(6zFuBaP|4|q>jS7P^0U>(m#f1E{x?0esB*>4kg)+^;)j@H4ybd*4K!9Jds zC4>Ph>kzSZ2(W|G&T6FyYFT&{z8;%PVj0618|}I6U+XO;s*8qFPyV&$yhw9DbL1jK zRZ(Pd+}#nP_+K!TKCDAX^NWqayi*v{gH2-{R}+{}CBUG+wQMIFn*D=!`pHe_iHOm& z6SESV5gEG43EA=YFLVZ+dLo@mnwm6B7F5_70pA&ey;1}<>^@+}BkaM+Yn^AxlByOi zPww0@c)9G;CuTB@_TawBLX*pL3B{alXYp(dg1ZU$QY)Mo;`s{S;z`%CKtCHL7+5TW1(!Ial96p`EMFSfn zI45=Lgm12-r#8gosgTn*ExE+h?)8sVOZEzQl=M{_UvUJGed zxh>zs7v){VdINcEUf)H)lk0uefdx(NGeYKAt_mTcG=IDZWC3 ztA)B%7dHpV>b^)kXxPnD5WWR9ScmJ}S&#-gb;^YeOSQ$bP;|MlGA)j2FM8=qON7U2 z#}F-7pAn{98?JxnS$EbajVF_#0f8s#PSyiNp~MJd2>tGqqaYh6i4m^#s%XhS8;iw@ zW9Cjbt5<$3YY%)l_(;DtN(*p&)ikT~!a6PIsEI!EHd5)G@HwbWxwSlJ3}V0vw--o= zU|#j_!r4&R4U{dV#C1qmXpxF#qrKs9;FWWU@9kTe?sxBJ7KBu1-ZDSZkqiZPf%Xw_ z_aL+i))pxd;){X=bF00W=K!M=cVLUxr0VL_h_FW+p%#1Zh%mPU6BTinU#&w>ZRFsh zh@P#%mozNCQpB(pJde*-S5kzdP<1;kph3bvC)6F#Vdk!-&rWxv_q?3)o_wG$7SVMk zJ5oZg3G$jlSR(Swu`pmLg00Yx-x^Hj=nYg?e`(0aB%CN482z;l5!%)*6In_1#wI3q z$lYomU39L!DMt}MXu3(?abu|DX-!%uM)RKmV?V>1O2R}gkGF1P|dqA0}z>n6ya`f;Ct^c zeKPY1p|5e)8%YwB-g^3>s7|jrjZx#yb^N?Y*E*v0FR zAbigQPNk3{C>4~<<55?u9mZpbIh^l%)5ksZ}SYv?GXIk zqG`j@BGzG#w~|S~se8Tkz_*W!%eK#K+=^eUTxj?B#)($2-9Y^8iBepn>H8KgTY0ElzEXcp9ou>%thIp> z+&o@raoYqE)avnV0x^UP;sh^^@Jun#L1p?DzB@;9dFte?P)ax&a9lMYjcS|-M5wMB zR*?6EUON8j!Cx!7sqda9+MO?1hqU6CR6t)Xou`L&5hPVFP5MgD*ktZ^L7{Lj z>IM+k?Poh)u(0M(;x#hm$G%)&QAMggv~?)1+T|)rGVH{o7aD5D#~vvk4rh+vkRmh_ zeoLaH=pbFyHfkLrLFAJ8#`sJEyXa~W&+55wXdRMicehGV6n966=cjbg_elubBk4Dz zFWOlPZooomvecCU0tvpzJSkwGKUbavHIM23n@se zbAr;hzVGiI-8!F;_GI|BSbn^Glbdc->tGUv@sQB$IJo$g-9A@6PBrF)gQ7R*%9=4DzJ*Jeyc0`BDJnffm+?((c%4V@$rn$Cz zKl(|;G>5=f9O4=R__;hK{sE3>e*$327q3Tr@w0xC-hHKyYq#x5nN&P8;t<#HNNZE- z+|!KuzENG>pIOkDlVaV14m_iV4uPGgq(SAdZV#pC3K#-&?Ha-B8GEv{a$(ctes7h6 zH>12$ zL1rBiAxK}OP@xx^vuI0N$A8+^3;mW#=#h(&;Q=Fphm_Eabx1I53+95RLKj(UHwT?( z>xE_#MKRv9KO>IZuNe|sGYWhXcpi}B)R!eXW{*<5w#=M1t@wc+)(?R0{8D`BGxU-RY22*v#Z#3Q+eaQOQU`~@T zt}^o(7?HVN@aULBih^+zVH=)Nab>ONYA}nOWea0#jd=mFY@IVrkAX&3`>@*8EaAk* z#^!MoDEu)`H~UKAWZdNF^S~#qMy?fyjvPN|SM#7VQb5FqtwX3&+~5!kxTNqEa!ZF- zHLA>b3~R$^-;dive;4*^VrlWAy2133By;z0tr$?K%qo<>y*#^dyA$s$ZU(Oe3qs+w zunr`_?PUvOIzg&#u>tGPDn;}agcezSv92h{l^>rT(t7lEPrRE~JPxTSfHyy|EkA#!_EBQOlA`;;jsMvZ43J&graE>#{Ol2#ZLv%+mou+O zmFCPw@}dpgqZ_~XHCVT-k? z8$Vt)+TbYNfN?meB^t`J#m#^gox-?7m%s<0r&IcHB4i+w35Njap0eE>%UYI3I|5~s zaKKsvMJqM4ubNSL5|mLV6BQ|E+if_&vn`@9h`&Sf`+yg39}vgHcT=u`TD8NhMIxO+G%KprmgQ4&`-A&9NqzM_yJ9Xf&l!pEOzaw;l>=i}c2)igv`VV=A zSSSbCyCVOkOk=bTduHyclkXT`lrdd-^AJ0?^wl0m!OiNH#zV(6?iVmK(l&mN{4_0Z zvJvw|kVHZ8R^GiC7D`0d0x8Vz{2ipxdcLt$-gHJ*8ae~ZF^BKPH+m3kV>o8L& zhR`p|fjN$^8s7C7KK_KWg;*Q%{quK=Rv;kPLe}I{e=FjJ?zdM3;yI+jx5$l@2xJnp z#e{?|=j$Ui7UX<0sl$kNz@25Nsm(lZ)G)H(=^;1$^rPx7FXu~kZqtfbWdR8%hI{*T zqBDb0hJr-#00or1pJI#(IEgS3_ zmvncRSRk4ToZW4QYwVvLrwxr20c#gbe!}jN*^Nt|1iiPEx^BE15Wys0eN`0<*&WSk&9d zUg@VO~H8MA-OKfo+?@E%{4-63|f!_qoN;r)wk&MyP<{dcLxzCZHu zxwsNXLn!fuxA*Hhq-m`WL?^QuYdvrYzF8Ac$*6bgrOs9|;1bhcMmIifDSUT)C^A2@ zc(38shKuo<5)G=tS1=NNfSw7J!TR!?`q?!5R=~9?Y^8!Aii(@cV`+Ma4^xH3g7&B{iCMG5@(BmXT{3T%nj6onkagv1Thns2{LmvQto(Uam0Hic~Jk5@H z#SS@U`ePmP!-3nP@Oimvf9I>C$93O)+)I!KNT5c~6Hq#}h5hQV#bRtUV^_ft*Jl)` zhCt+H*=-+dd98Eyan`3hYWM$iK)YsgdCg+kU$4lzX0I_Ud`Z z%2E+{H&4)Lr-u;*ZNomE%>rE}7=#Ey5dj?~-keSnJ|Z5}(jk|<55L`PyjYEBkJlcn zpVl?&n_M!#=JeN@BfLjh5DtMR#f{+%57fdS*nGO>u2Rjl*R@KhdZPF z)up#AWt{g%#K%Q03<4m^?HIBRQBO6MMc!s@5@u1I5s`jL=W zVj6Obt;K!Jb)Ng^kG}DW>j~|&nL`Mv_=?aVQsaqys)!_Fo0>PgXzABZ(Rq3b{_#`_ zK8Q&DwKgZdNN0cT_7i7AGjZD*Zn9RS0ncM@=DsLPat}gd1cjFD`ha+kJp8TDYts%N z>+jGTxM@7wb$FX_5~?KJ5lU?+VvI0|Sq{!A$SD@bqp>>7#19@Ax-1kAJdE2yWHt**{42vkgF`jz@{xk7;p6E;p(e&1cLQ$Z z?@skzgM$9+RSuzlIBy*S5$*=ir$!lLoyu7I2@CpGhpXn<7X75*G}6^w^6z!SiQ5S$ zQZp_e)bZMUq1*jgS{7vIga7<6oHwPdIE{y6@jM%B(39K>Fvdz0+R%J4_nlwbZz_Kf z_Dk>C*e|2FrJBqu%7(KjS0-C)ptdK(tUnBTqpF&O1BEwJdPmuiQtI$nCm4EsYSlBG>_*MM*%2 z)8)qiH1<%p-6lYdqta_#l)MfJagBiY!?rYF#qdnY$(YZvp$2%x7xj9#++8p2pw%Gy z$f?4qj}?j!l@1#Y>>|PNED^#xUo7)zF2iwlR}n zCrG+Wq2tRZ2A>ypihdvBZe^?V5!1A6044T30|~+)AqSMldU4S4n3e0lOb2$63`UI^ z>BljPbEIOH?pSb}dKN9b#L0eJp)ld~kO};qLl;uMQx&tq@a!cd;eIm^0ha;r?qi)c zpDC(U;{<1NvgZD|=IfKFjGJy{AHobHnj$pCE+KxdSQ)hmWF92KY+x6_C{2{jfzkpLbV*uF&`s?!?w}IP{rokmAIOKG+c`3r3QpQcl{z|KLeQx|I z%{BW)q`~%nb%MF-)X*-!=KmUy{=Wj~|6h4V^g2YbQ-N;;%rRV7QYq>}bqsz$OLfAQ zxCF-P)kjiJJZ}H?(WU%*#JtmWw}QcK*=@%s9nU9=5Vx;G(vO2+y%FV$I=&giTh*R{ zs7^kL{>vxCobBUDaIl*Q|( z^{mqNepykqS25Nu=n_4s24#Pt1A0XQ9XJ;c1~pdq*CF4G|2XN&z|+V*t;$IG7$P;H z_ab&bN4Dow_0XK*U$IUTb%8D8O1Y^ssXg|J6wq)u(N69(w>Ul)TTg zng-UGMM+qL3Si9lCd;btfKzv~1~Q#G?y03UUiYIdR!y7IQt;dd(U!Zz&L<=H!!Y;n zcsbYIi71e=>fg@tk6aiS{DENOZ2CInc?RRT42jNB_He7=bg{BBMO!4vP+Rv@( z>8a)i#N7&QUVEW)w5RsI%;J8=0<)gC#q(A3Kb+7xe{h=>-#Shx5x5R<9upA2WYp`= zcz(9ipC*0q8F)rznI7O-$v?%W53Edon;aWN$}HRNiU?-X#WBM?k3nP`$C!5Zi}Ksq z;ouPV%c(H`y8&daqh?2?vsmO7Sz0+OKpCcFD+78-m%hQlT(Z=ZV3`?I&76O1!7kC@Y94GI!Yl!uqo2xof0}G_ z^A}2b;n^ief#wR~2z_IC3|xtCq@^l;lwF;ZR$Kk`B#_2jGB3fPBO}6d_8p+cpR9Xa zlj^rW&iXHl&(KElQs5)u_@tI@i94HotsE{(x8F#~=+wkIWcS-aCkoFFHPPsm&zj@e zO-*jnH+JOQd2Z4K3M2BL7RF0>EefO3dIgLo6#4K;Fe$l7Gl4nWHRE)w2_Vl&V12o+ zLu!%r_2^(rW$n?!od{PO8Y1&mk@BFt*??|X-`R%f&GbVe`Mve1Qs#Zf}T#1 zCBalN{>;|KIhmtxlq|K>-)ha6tV-OSkT*}bdm(kxS><@mGm85Z`mrm_VPF?D!@?9W z2wYpDu#ibtE@wBK1=`)&uR1rkbDp3Mk4JQzu}W98t1`AbTZWlDwViCE^t^X23bH_9 zj#1dIroWC57Jr|UG_=Dy9M4CQ)9mTl(+3YMtd7uh{| zu_*Zr#@$)hJ6*o_Xa0I-C6x4J4>8{q&DBC_R!-?me1_dN)Gy_`tOQpCE%#E-naK*d zP^-&vd%OpYCZ`nQZ>$u|DqnZjm*4$J{G1H(pWfTHJQ`T3GQqPFzMyQthH_3CMnw0i z&tJoC?$o{6Lu5u=cz!U599maLvZ;EUZ*G(Q_eN*p;gid;TJE~LR-sTKbsf?S?*UpG-{TY}mt(G8=5$!qcq8m<5HoO8RM^e;-P=yNZfhMCcfR|w z_VB!f`7vQE8`J{sY@4~krMPy)HX%ZqatlWqE`AI1 zumpadX4(O1LeYm1Lm__6#zkQ~fQ@ zh<|e2c9+~37DhxOz7(U=f4Gk987ZGAm_f@UGUms7!}ijgbltGhCsHJvFXF}UjAA4S z-IJF|wHh$E*#(cQ#*I%AL4{DYIR8}l4H+18k_gy@HUUI+U7KbWc9we6Fzevr)N zaR+~h^Y>Dgl-40G7XyM2Y4H^3WpfkPAwAK|`E`idEfLl%XjGFC z*rRNxfzMTCyyFvC%|H(M43HaG7lv2Cp8fWdeC76Jz2*(}hf7trw>A3tEb-8HcyoEt zH1no?o?}o28g~dkeTD@%1hW}@R7r1P3J@}KQw*z`QY zz*F(-KUOky2G=_E+Bi;GF|Uu)PO4mKe^C)Sph|U>LR`FIl&RT%hjm>ySvRu84Uphn z!CYFIi(7JJN)n_HwF!W&PVUMD|FvQ&jA(B6rH)52%N$ z*Y-w=#*p6qfi(9&ZoZ>9Ux7F$ejTjgAt+!Wz-!(QLB%Ltxq;afb~$$!hnOYQ=br&+JlAKGGz(~E zb?;kB8g480$YkAIlbg0i&0O16kBJysNp_}ia%lUva`n#cUVAOateElzv| zIyZyEr)zdfV)t>xQ#_e@OFECftj(HFSUmIlcEG>)&RBR%y_>P|NvbnRwq-i>?P6$T zM2^`D9l70!q-x$JTtB{L9kLWNs||QQMDR_=J1p?^-eJfscDiBTeY}BcX3UV%Q@BZq zwDNJXr8wWHZhPIR#M#t8aMS5ei-262x`tB(kll7BQyu8?urj^kwZ3TG zr`N10IjaW_y-{|1r`%fPDUWzZe08aHq^~~pxs4~(76ao#foDwkJLp+KaUg-YT+fQP z+x4~6WNfL!wX(JP-fVx=9EvFCP4(4%n||`GtD@WPBd^g`D;K^?J0n3KF3n2tfbzu% z*&;4fAjrag-YOTW(z#in%h-r}3k8m2ZPy{6P9_=%Zi9(xO17UAu*89L%Ydo#Og9A| z;O?f>5TOFwqduzU-Lzw6Z?w9vOMDb6WXkvoG zzjD~4xkUm3&J;z^vV-C#3C*SS^dL@pQcG^I{WJDTHhR8kY;{TH6lzy+Qo|DCNx^8y zviaBj<+tqj>49r>Y?iv?;IP?rl2>HNLB z+-8o*mmgyp^da-`3Rs77FiDP+1G-tcP%nXuRj91?0cuY=N!vC zGH464y5l6**!P@)*$cGULwN(rhtJi$6ea8zBvTlrD$u65ey9rn949zuwcgc(qZqNV z&WwMYv#Ali%`8l1?c2}Bg?+aQ?Dg2W0fE6ZiJKP-SeFFIe}SuwV8*$<-`aGko`dG5 zb2f5|U}>G(!NS_S^cbFM@U58&s_(!vy|H6ed$KheY9WUjULAFPqOV9!=Zk>WA^|s6 zrVLLaNOT%vKvTl?lNOZ37{iaVRkCdL9u8Z!HMr>K+oe~}_;|mcHf|;8wGyKD2YQ(* zd%bLx6LI+ZXU6?O>Q9Il3x^48SEPpU6@@h13(LZ759 z=)e3Q#TKv#Zlj$#W{inUjkG;5N2IC@K;;`gjcc(E#0|81o2#5Sa?(Qi`O_l=f04|i z`;te@ODeH#C$dUY|7Xdz(hL4!V2({@!ZJGy7%LfeyM1lkIRmw^Re;~7mSX$(Xms^V z*uEW@kwW9vLQk{h8;=NvA$oUDuipMf;VT9+I@>wKIoZXp5A4~Uc*PJ8p&iEzc%(A& zdM5W->2MO(DX8lE?vX+1o9`Vq1@`QFmHFc0X7N#|tlf6ZKGtxeIV=mm#nusB3ncVC zJ^@2}d(;k!abhYh zmv9hWvqpmARf>GCY;J1VZFyfh=F&@7o04iXhdMFJE^}=cKD}i4dd!CoI8PKCI@t*k zzSS}Y(%Gg1vj#vCb7k6~=OH`JdmO8IvADj9ym2L~p`I~TxPL{{!tgKJu{=2+x9F{y z-p-&MiLk((#M^lPyy?+lZiJv6X9Xacc|F+#DZcf1rxr%?y9-ahNU!rQzCIIczopU^ z-Qr}yOf$AxGLguqTpX46a{2WrQF7;le;X{jzi=Z2aZqu)86KOkGs2W5xL7=MT2$Y1 zyYlnem9p|jGvT4qmW7t?ZeS>D9v7HpwL9b0#e2m|Uq8X9W6qr5UO4R(V}2aX7S2`dQQM+?h;N3AGQk;t_~dD&)s$lo|>IaB7pQ@j#z z<-Qf%?FePu|Yv_k{PkMq4O|2nmR(+A)+_Pk4e_->mYrcyqRU~dhqPX;=7ZK2Ru zv%dBAg)Hjz(qzb?UxKvkeLY=~ZWnO(y$*_hj=1C}3w&V{2gzlYkJ*GQ+>~i={nZw@ zn!&r^Jf58(+&ETri!Y=|pvhac(&UAbo?mu%xgKrJY0lxnuFtFk(5z%t{q%RZ~;uI>DAV}E_AiH&N^P)JPsUUc}4?PM|{dTZ96^03A2id|i_q#XYZ z)%Rqz1%IzYB2A~)xWu*s)1+?zRk*pLGjr7q$%JRLWXoE=`BHCkPvuJLwXJFoo?Le> z-YPs7QlWu6GI$Sr9JtFcO@VG%rDVetJKRwZFd*v#sMp(SXB)RpQ~Ods+WdPc0w z#IB6lA*NN}A*LmklIMw6caI+jIjsNcA$aqQ)`_SyB+T&x)(?*4C4W&m)kG$=S9_4PRUvu+gNcAFi)m9oopG@gG0=229@RGAi?} z<3%y9mAm!8s}b|F7u$<2ijT(pFE;x8&fk$tv#vNLnUZ9a%VfZeeuga^dRuU}0#n^L z_L-}qc3Z40;)AkhlS8YHjtMQ^%IuM5Qa14hz6UhN$yMu+k&=HP<^@y`PuP2V<;Mx} z#6N#_>(A5wUAL^}JpwH&{=P5$EDC2mvN%7wnEI(&X0lol9U6XIY&7khf6k2~+^)HL z2xgFPga&q_1!|Ok2 zCtHu-`i)vPf|cf!A3-2A4yHMETiZZ1Ch*U*|BlZ6>4r-qIbH-8B5SR3u^u ze`4*Q`3;7=5HRNbr}yVyy?&ZS0aws<*^*j)9qU^aGC5UTT2&GnRf`;q*tS-5s`44B z$vj8Y)o9d7F)Huw%*1K=E|1dxtt9=cOZdOng9)hrk0bm42mbtyG%SdDPuEf-O<^I! zX=SqPhSsMkl??<2ahorS+vL5NQ%8)7tqNT(C^CDPapV`T`pN3_P5-Cp z6I-Uv|E+KkN+8ICaD$7WxFdo?U^*>oa5mAqJ7vhgFgv|hUE=ZR(#j8_49a@4S*egx z?Tt8AFTFQ=f6KJrta0+L$PWSEDlU!lC{$B!344A?o6y{v$2;?a`Obn!+shZJ!;H@L zSZ@G(21}tmJQ+u^YiIS^>2BDXll~HYxrzw&8D%QvU<@%4xgiF+Arvna1556dZ(yZz*F|TZ!8J(UG&^nR|ByDxQTHZr=!d z=Q<|~R=H%%$^rFEC=}?n4NPE9u?Fgya9N-y!6w0zBhvzcm=d~Q!}4jF4~iEMyS!EB z9Q1D9$hcJg2|tZy<}LcqApwK*UKmXl1a7w#JM}LGdyG_a(EZP>$E|WA_)#X6ik{Zi z#~NLuNa$CE;>W3P>!0jZy>@Qyhf3G%2DT}frj?k+NHMFEe-O5O_73p#D0%SNJI151 zFtgzDp!Cs)sxJ&AAulXm(}Y9xX20vjLP%HJv|x;8ft`ntZ+PRP_w79p~je zKfYQ1JLaBjj&KKVicXR#TAbsgb3ctzLaN7Np=n4Z5@pL5sHlqlC};|@-6oHhMpVtX z=(UH*)P%VkMfb4Z4-dI~Rvy;bym*tAr>&t!se{>e7Ux9xxd8#K&IpyLa;Ff%D6Tencw0r=~;#kw2tp( zlFLHDxA@{ly$5?AcI*f1A$iCxCbxs}@fXzf6Gj?dJo@P|R1@*;LX1hKNKR!p4-Hmr zH_vy$H26-VoqI9EjPz?3c$JW&5%cm44+_su)dxd8)2Felif#dADwjek{LI9UYGBxYBMqIb>^1*W>sQ7j8R4q z!>PWn~XcPWFg>~>W4#9+s~5Zp zC_Qzey%du3k_cP;zPssmpqO0p=C6L9Yz?l4AdeEbqK+wHnJ%vKtN^DT_4ynN9qiL)m}3l5nhHfIX6cxJmW>DZ&^Tr4Fnqv)=tC3I;41UzdJ1DVZj0eho@|0 zpRs9Q+%NoqrV7#ujN((GO|qlnw1JER9n#?^(4_&U7f&u5I`i8PZm^qLs%8)O5VU?* z+R0->Mpy7b!)jmbwhBsqyiRZ##hC(L9S8Hm)_#$CXAuOmoyPSh@)|M1w=O1@@w(<> zX39K+E=se(B8}ZX;7#d6r{SCDllV3)=vE0BnY1L;bNO=7)55h`u+p_`=ftP?^u4pk z;ReM-(9BF*aXo>QY5?uRSy>zb;|(7YJEG;XaBJ(Nt(t$dR=RXpR{nHdzFhbtot%w% zAtH)fk`wJ@Iik2>N-MMvE(i32Z4&;~AzE9SCKZT7{^hzo8W+*ey` zQ3)a2N6+&P+v_Hs++MW@47+K_$9b7JUCc0;1hSZu&1v$XWUr!A?KC?$h}mTQh@-xi zGt0;B&g1_c{(J3p3`GeRj0el|=IW?!g99r`xGkJp#WLMb-qQR1R9nW6m+snq?1n}L z{e^!cE};9T)4hhl>Z1@os8Lf=up2A+aNs^$7CuHA7RNMuzO{|J=Mu$s7$`dFfM#hR zz$Q`55V+tuz1%`gu_ke>3-I-R*bztTkf8;+;q@+LuZGe0!%&TO{2KI zqvjD(Tmm4+q-fAE30|!eF{h_mR&P;#dTpa09$|L0V*KU%;6-Ml+iG>gpI>=rr^Mew z!fzQuvFGe_JGNghQwaHi5g9pi&vMat59M=L&uclkrI&mC(iKI%ix0xmyzzX6DdA?` z9ATQmg-;a>_4{oEL|CpA@v5?s?wT22+O&(_n_6i(#?Pwd561^AsLek2Adx3<7lE~M zj6WBClXZZ=S2#3Eb8H@morB2(kG=}GzTeqCQU8JDE9D)f^6Tr*`$cC0+ro$TCq@Rp z+xsganhBSh#T3xNe^H?ExX82RaoNDsnS$5qpESH?4T{BXc+Opqy&DkSW!k`;=*WQo>2?bm@AgGmlQG^mbVi;UXOk9 zn$&5d52^B!pMY(xl;)`}(?s`$6MP9klL7iz`puV2Vz04_(jsC;uI_oGdj~O4hRPlM z6kZ0ezpMyxcl^%{&vbmZ6W9@`VTf6PT-*S}B>D#HBkb4mXJvt!(Y|h}i9TcDsSXWiynLa=na%;%1Gc6A=?wLS`A#libk;lT~%Y> znNLl8yi3v}2k{`IV@t_V;ek6pmmR#_DoNLXG4A7)g&VLoW3lioXme4jtuYH#it=cD zO5zX)G$Kq7-!(etHHnb=9<&Dj7lKePMF-WUBOCR#A#p7q5;@s0j4~>$+C;YOnYrdF`JhG(EY9OAz`C9a ztM3CnaH=b-&(3JHK9=X^G=OS2>x!?N{t6HIm0CA+Ae%-Vpr31z;HpM=i)@xNkB{iu z)`w)Dq-bEn*tpv@!sqzr1x(>L9>X%51+wQME`0H8u z=0h58c3)#(zv31x?{L;hGf&qWyR>U5h6w24drT!T`+9IP0Ez>ak*12L3AcVBNR!-L z4^70ZKIK@YE$YOO$ep3#0cQ&L8h0Z~99v6eUbSmFKuiIDp+qfvg-J-`OH^TH!0fz6 z*A+^VopLBrR)+&mZ}`!Mj(sM6JTKyJE6(gYAMY2s;bYFtPGTo@e2&T84lq2ZIn_nU zwS=|iE%t_TU`$~>3n~h4sN@oCZ}bQ1SKbTrh`V`qw#OD|Fs>+&stskmA9{$51P z^EF+pb1&Z;aF6D>@#6(mlt^TzpEet|_;GIO&_v6Az7;cM?8L}Yhe1WyH?UgAf8<`7 zOCNbn!}jidnI@&}e43C9$gyF}d9ZP+$PqAP6Wz+D9NscwT22ca7m&Cxk!DpPgn*d>iQVund9QY+-w_;c>JtK~-;M?R4< zj%2(L^?v7g*O+l&TxkA9xCyGn>_Ce7ex9|qewB|z zcpcyu5K@SgP?^5Ot~Gash~0O^pCgAll)#gn-oi1>?ucM~!EHRdKrKqQQvk9D zi>=Z-HTm{rjy^GNQ(oN07HZ(fXDw1nh2=Ukh{fbx%SHN*ChE3UjoAOu-g`$iwXglY zC?G0e1f-WJMMZ=tRcXNr$bwku5EYSThzLlKkO)W@5l~QA5Tpo5iPEAF2oQ>j7&&&sdGCAfJ!_A#_q)d(_Z|1_KNw*INWx6!Z$7{8^ZkAvQ(*#GZtg9f0_1jjCB1rye0A7AcNs>FUQmb7e6t8BxMQ|l3hSw zEn;>i#Zq}0!iFZ>YIBm>NW z%)_DU4%zz6mT%;>p^t6Cc?Cc!x3p)bX#%YACg+%YdNu8tKS`-%ITl(ODCo)8dI)x9 zcgq^1b`MJ%T&iSvGj?X9+#PjHjTnaURYyN3pQsUa%!vO)Peyg)pYKp!7v?2kFEE8j zr}0Pw)KT*>J(P>bTs!%Dc?O$*yx{}wpr5MUH;tX%d+EYria#8Jjpo7=ZFT1V5L3Xq z%_3C*ee@H~>Rqg=VIJdRQ`or)<12}2ZDf~3j}66;eSjhVf*=Y= z1`X~tT>EA9u!=$?n9LSfu)QR-G>7hHR4-b}eyMm`HqJ|fhI>0#)TD1rl6WU~L`Cs) z5XiJb2=j0f*bCg`UYHg(aNJf0V=}v`g1syaCKXi3X3P)+&C3RdPVyP9gNBzM%7uDv zE{|V0U!?oWd9dmtbsiy$>q2g_2KU*0Jj~Ef!j6h~6jr8&MH=eBvNW#w+QKa9k3)lK!sqJP!QxprDO!Ad1T4iZ|&at5+ zho)G#%GD8q0`It-HQE2o;Df`Z%!rDM#oG|Gkb9IM_#H|!E}6d%dqY@kB+{b;eY52= zcXKX`{?Ih<_1SZNqM}r=b#;Elk;?ZyJ3%SO0-#!hRy7k#z_8SJ1 zj$X)oS0*>QJy86+f@t#_zL#j6B8Ly6Xkkr+&%vFitnWl$17>9frhruipEg;t#nakX zb#U$h=GK=(-IuLm-WVP8tod$0ca)vV&@G&MxgN#y02x!~=i$wyJ_5)!qxBYA^|YW9 zMNo`YH+@?kxDISRR^b^~Tj`C-FfuH*Dq_v5{9t&ub-(u*d#tomss5uzBI?z_=p z(>WP;@lOPBuUH|hHcOwGI>$!zWM(+CY@ocVVPc&bOu{y?qSK$L?>`udJ#x`>zIK`2 zawTng*vSJoVc41V$?cqyc~Jw82K4crfdF3FsP*C5e#*V|DC&$Xc5mavPpj30b_i#H z{wB)s=eoCP!y>P~hA7!q=FD?CIw51Ec*kWknER1{&lV7*L=pgvs--j7u8Wy*9mYXD zf?WyHSZM8n68b5|NS#^l|Kc0U?`6)l!|^6jW}Qh&f$Y6CM_#bulM1J}o|A}j(I`bZ zLY>Q5r*#(X8*3zPcYhPk8Ze)9`rO9%nfgs>>G6vDv}bxqd?-|2Z2L~BETDlG4=nPX zur3nbgP zLI@NMs{1|lJu11bXoed2R`%~ z=`jv`^qrq2Y{DR!eF>(S$wg8_mqsFdq?|}2jj@(9wm!8ray4g;ztUYkf8k6~*KMwrT=9KzUn6bud9Kay8jk@6`zT z{KR_XopoeV=+CwGdcsnc?GtIe7KUPA?eyW_-clnZp;P3;;E7Db8FJRTG8Hj+mK1%z ztp!zsB0VR1+lp8&%W)*Q9cwC)MHQ$=KNSL*>gLejpFtnCtAO!HLy@7tJcqeb&MZJ~ z2vob7z(2CsZqWur7KbPYl>*4)V^~;p@tcakZw0%)n4%*lSSIKY>3-|4*7uK{CrIEg zW-_9v%J_Ob6`ATuq3$I^_{R2;;I%4WDkV}i628MTbL)bdY$2WT#!us>!roV@pOR^X zh{rnnsc+9e5FfF%0bhhW{wg7HW}~eRSi*)>IkRP*I@%>Ctewi|72J{YuC{yAosd7u zMw$*U%Qh|OCdxaaoI5fxx|iGbfG*-z{y~8kc>=UKZxuMic#y4%pSC`OrJ5QntKhGg z3tP$zE01h$d133tT9M~yQt(;GtqU_8FyxhKF;gEqu|z@G+-~^=<&w?@x#>=RJ(GSDZ)p{{x?#VBwxS)RRp21JZ41Xum|$3IyeAW6b>`tF z;?#@}fGELtwT&9BjywE}id*>^BpN}XJ~3;SvDJFtkBT3#kVmVC{iyy!4A^I}WL1jU z&1XSVLA|otUvL(OdUQjpgI}GLwCEDBP8V*@24-`4!ZdhoH)t@8zuK z>1%VxVjeYTit~C!dP%zf%b&O9f%%pmEQO;Zl9sN(27=YBF9fTt0}8J0+0g>nFj!u)52ydCz??-F-H+n zm;fg74jV`>_4xSFD%jVY16~~KBD}o%W5*YC8zPE^U8BuUK~L0c!yk9uj)n1e;XWd_ zf)`X!tnt<2_K*aQSbIDtp=)M4*_nx$`2dOolOfGHA3TZlyK;Tu1Ldr%2h`Wp^G&C3 z3zoSgk#rmrBIU@1^&zEj8VkM#91ALKieV2F`qe--hrGr*n5Dq>j6AvL|Kh+TZP!87%9@i=9mea?I0r*z;CA2%wG z#4)P4to`Etg853Mer6VIO5@jNY|r%3aFHf>yd7{u>-I~2++)1RS6pJex)+zUbZHiG z=hlVcV7H`kL-dJ}pVcANsqXY-FN@fd;_A;#?^f;pdOuNS!zz!!Ig5{@$dX}|!N|td zZbK95ISl>?r+hAD4lT3Tj0iHP;A8wQ)=y2lmo*QO#}mb^OzL!lhCeE5Ahwm-*$K%887; z^CY>4H+9Pj9v&#aZIhI?w|Lt>9bCN*B1@Jnh@uHf!^6zpRZt$y?94A~*W+$Wt-^$A zMg#{1g_SKv(a$G_9zT$JtSRe0ZaIvC9?0mM2a(?1Z`68h()s@ zeekJU(jhTs+!J5oss%=41dkWvmxh}@9&@(DhG>@&(2O9}%pgo1_1Ei5A5g4ydtN*U zE}|(3c7QU9NE}mrVhHOORrb0_bCm2@UhvV@>UV$FFWZk`kdjc1#2a?HVmR%p&R%Xr6O#ZFxaz!_=658V=2% zPbHC==w>ltY**9DLhT#lXfdgFYJ!3@{p~>DGBVF>_B^2wWj>BYk*y z>d_I&oW5$B@)VZglv-Ci{jux4N504i%7)+eZYskn(S#_9cgNeDL9*BKT6iyU!*l|sQYl`Vv@&7E&W@p z`NFPH*T5CjWtH>07iNar4~syJrU`jZv?Ykr;Fih;ytuS3dBK6<2*dM&E7>sy)o?iv z>i)Bsd*&oC9{(y}M&qdxMoSg7W`F&u>%I-(?s_`~MS%c1yn`Itax987;Z;Zu3See2 z2~x-h4ehb^zONdZp4Yz$cuRl&vORJ4%@5iek0mi0Ikupl9e*Fw$FzvIHJHMB0jf-) z2}`-FkJFD}E<#gKVWq*Y>%zIo#{R_7Pa~{c35zXZ8YNCPLj^bNvOL@u1t2WX7LIA< zS-uqBkAx`$@E%@1k~*_>{+4SSyCCLO9rnbt`R}2l{-e$EsBxxYt&E%b(!_S>{Ub7s zXF|UdH-Tp&PWvlP0;C0443Q;@tbv>=j7y-vg7p!7mizSXc)M1svTO6i`aR-ia(ix& zZp$BHrvi`BQw_TvzKl8Dj+N!_2A$a2!cuEZJR5bA&Ac#8kX@UqF@xNhQ6%)_hFji! zoBcjw(JbkN9?nkp^|frW_(Bud;Hal8t#Ly-@tW=WqLCT3C2ReX5Q4(a!CGh+ZtGZ` znY#Mk#+RXfPE{}?LzLE+1$2|*O}_P|%gv-rSVP#_e+@}w@Q6$Kn{{&=Hehx&dD?^v zo&1>zU361J+(Fs)nG(?C_^!FrxrW@*{a&bRD_1`5I$`TO=ww_qzxbI5?7hINngu;8 zVCcVB-&&k48)C;n_tg4+?_SfA;hd}>(ki?Vv%*_%^~;(^4Ce^_Aq9`LKWx7}T<4%M zC^g#X);-fCl|okJpTZ&m1UG~Q=|F%^Y+y?X1CvYbwS|n^$}Ebm;Iy+M#)q4v+cvKB zpv|O@$3^Zvd%ih$Z^f&V3+1eD>8rAs2A&H5QC|KP&0%-9NF~@pu(6{*LC1~pA7U=K zHcl=;&@(!i8BHv1z)#b=NC@*<#R3V;Q|Iw128`dxRMzPTJKHe=3x*O%jv`7P` zj`?*_nn=U>)Z3Nu2=^J^_Lt9xx1T!KpS2QN8<2WI^|8lE&XYk>CsdPiH8a*9y8 zGm$;esn(K}!Y0TD}W(msBP!Ie#X_ z$p1xSE?vDK$=T@rY>%2_)V0Ji`j*Fb1K0!>`p)_tC`oTlpg=jwY3fF9Yu6Fj4T%o9 zR9zmTGlE?A)>h6>?v#KLCj%R-_iy?%zGp%4!L7MvD62{Y!FM8TRRm#NIF+asY`cR5 zK-f0h7Tq~f)Qo^`eN?6QqOID?_~{EELs@Niwt-XbS>}=Lq{FP+ws8Q8yU2w1!nOpq zTLE6IQeu#r5G2A`totW+S1ERHL|YpCZeOq`qd0euSLXh*x4W*LdYk;5_?{vmkOG$A zflx5^s718hf+74iBDe&W?frdD#pxSKwwgn8Kup!VYyFJkyPL*7-W@rphj~}%*(X2y z>q-5N16|M?;DLkh)5p627=UrMp1hd`*J^(zEwxA&h^+!lyfeGmpX;BGdj`1_ zvJBnd=w^dH7y1?bB)j+hmJPRYwL{1PTT?)Pc1B(x#Wf@?De_eW9vr=Xj2Bf7d+G%e z;tO~pAo_#lW#yYvj8XKO}sqFi*MY8j*ck8M08|}8Z{DJll?yJ=0(kbBC z0RnX?JqU)q2M|{)P!Q(Y!rnY3E*Wx_k2b#?7byj=Un6<`6oOlUPw5V6($x{UUWK{u z-pYCSQ-3+{dAPeD&pC?*ktB5)-~biCjcp|N! zmF>_n{iT|=lg0X5UgYjAYutC}06FkAX5Z$Xh(&o`tw!KG` z6E@&yiwO-COL{1#9`G@??!$tu1y`>qllf7+s~t)>KN{*8!*H^Ar8Fq6b3`VudHT|6 z@5g@kbaR6)rwUsrrj%I<-Mj#PS0n{ABPFoE4K~F>S~|%zu5X8Vyrd6ju_r9u8C2@UvPhOM@Mxd>JZN+962aB_ymk@cjvb?B^6Y7 zI!5C0F~&WzjdE2{x%QVgYFF-ezb__{57yjk@%SLfT_ooyJhf#{HzlrH;5sJS4m9`D zsMD&PtoU`o`?aG}!(EVrvn}LARH$Cl(Vl?E_wPQHY6it4GL)T}NvKEnAg08bnTbCi zTZ1XW*}OE=4^1CK^PsGc!dxr&nmVIYX_=8W*3z-H(j;cRg#AuU<<1!f5!7E7(KX(H zG|PMNX#x{y655O8@!J;ER7HIc9Q?+#)gF>Jv3l;Dy}V+`(M+DJ{u73^T)?-)jnK=# zB!UjJyfru8tqXO}u9*>~7d)-k)FR)6q48*~CungWPY1v2c?Xgc(`FBwaq-L2Aj(`y zu)`9a;z{TL>k(g5j&}ghfa^y6l+dTOgUtCw=)U!?`7C2TOL~%J(ihq+U;3e2>qG4G zYY)Fo@?cYQ=eQQjvV1Higm;&-)(KI^z`8`+ganv1thOQps~Pj8HAF3`>Zy<3orBXS z)O`%gZe3$m+_7m7ePD0!`T2&QLhSr(Ca^DWDTEDTZ$`S|FX|H6g~u@kRMO3x@*uic zW4>g1A*a9cXvAw6@0VeeMm`vU4?P#t%kA>dmcElbMaGv4E{>vqc-Sfdi&Rgu8nrY^ z%99C!epr=bY|z7xiVakJu%W-sb@`U}#rLrd@sLlnrOptr{FvdmK~vSDmOgXr`$X!Z zNpLg^5w}yI$6ZZuDJ`XYe!%4PgfHA`Yp)qhSt`Bz#;EG@;0I%G=U8h4jU;og(~uG3 zRuLTu76kY3L9qxPoP+FPXnL`BrjC2_24f&Zw(HG}7X=ad7Hv(C&@0~` zxZFLhKM;hyDXhTB;0Cx~`?=?kqkd$r;%M{wrgTtZmswC7uc#!SQN4P=eSQ!TzRz9- zrc>kZ=dEOrMK}OncnI>KEvVBCsW$=}*y%R*Aj1BGJGIg$WLl-@(3Qt- z{T^T3jr=$F#iaOO+%~S04a~4@VvY&xMRFo~KA{tlLh{`@NZ!L0@1T!?R$wck)45^T z(=pT1kjf0p-otfeO|N{EKKm6Nnv9Mzf6qAUT`5Hb2!9fwu`teD=Zqqx`&Con9+u2W zq(mPR3VuvK^P1GUu4XMSH7-W4l)1Ad%P%Qu&+n%8M1lVnZVyJBZBP9OWl_2)ic^b4 znq0{{Q7yK$mv(=xyBPNH(g&>`2br?%c01Dqd||<#6h~opBzkIG@JEN%Wi8mLPb~kw4F6Vq+}sbv=H5$`4e&2ojU>lb+_~{ z?)#stvVZ^b-;U6~kH-J{dHH|$XdD8okNkqhy1Kn=88KaRbb5Tgdzb&#l<7-G7p%7KE#3%16x_gV=|PxTdb9N+4UOLrY6-o+oL7!$%Jpk^J5$<2g)Q09`ozi%u>(H#PIu;UoCf+H=hPaIq%%)Lh4emINs>1TTqT8dwZ#`-f{kY&aOb z?^rffnyT@$<`v~KVUj-ARoX#<*1J*lO;3z^o%T@`NLHwyxjC+bu+Tb_9FTwQAgy3B=vY`P}?Il(p#Gz}jNS7_9d5E8LIvyaFZO5Eqo!5&ubq!$Kydi1Q* z>z*9D?>+hi=e#!#C5AF9FZwKdbZy|Et%%QiQZM`+cR=)k?zX&RJ+ze5&uS(yKkCe0 z{%Ywpzs3z}c{5Vm$f(jKp^h}kp3=LA@l}5`XeMl)EVIMX8m|fq-~mpVk^r6wa)ZRk zJ3vBSZpF4zrq2d&kk+-vkk?M87UuU=1g+7hTOVd0s40IGZyeO}&%`^#fE+4ZQM3m~ zTMt++=WavLk-ZkmR9@aN)?}7%P^;iHdap3DYTi~ciEgE$W_3luIzNqZg7>)RS#+4Q z@eBTM4LAM}lLEyG*j>0fJ_M3bBo9o~Ezs{h0lD2nT;!c4nDxmPyD_yfoKmoICv4lj z>dPa2hJqo5jg<_wP3qK~^(`#OR5kAg*MBap395+Qz;USvV}m2?km|HbjO+UVuFQ6$ zN$vK4y9JGR#pL`yY?l$+M*zJ#S2Cv%UAJQIAh-yZ5W>dC;b&&$fGn zNqD~*H89r^wH(QsnQHA)%j_;RaEUR1Do+Ovy@|+b=wQA-Iq_Jw@#x`6)k{9}>LvZ! z&!yf`IH!?QBTV}~%3bj)~9Lt!jLu zZiE-cMl5aNTc0)6vgf0|POD5rP#6j9)w?LeGT;rTy2n>5VfH4`7W~M3r95v8DbzH5 z1EGbI^4ofT+}NC=yluFf-?apd!L0Hi!epF2hH(bS<67`cfpaXl+`_8*!t~CGcFp;` zyos8un!pjnep%f_zvFi9zwf(!NX*TNMf=k_&Ry-!fU=?Y+BadWJh}Mf_zdwLPf`-f zDAMqNfzlcD-!eAuK$B3s{5+z#VNQ3Knxu#(MOo4FK$Gs_GdcF7`2VD_Bh z8eq06k(>$&kA7h|lU`;S$Ai`anT^0?^?f2F$-x zbMwsz%Q0*la~mu6#2vGsYfUL7V*;>S;y&x9RrO?`g$p*%_Cjk?Zebh!rgx0 zrGWtIM1F2*G3I7(FWaMCxuu(TGgV>6JLU3igvs7b9@dX8Wybh7A5)v#S{$BFTjFxW zyYaFs?Xp1fEE)u;?uw1ISzb*F-))S$##0ITlk^sYVOG!P6u_x zUsGoDeRYS7Y}G-c_|*(f6gWl-w1f2cAiCCQoCfNf@<7iI90uKGg2#L2_4+c&K;p$? zJ$;*+H(zXrkoK7V5sA}a1P?-mNd{?Y3^q=ZYpqUzH#N(K=X96vsXRQh$??$X zO^&s<{xyRAZBW}*WmA-}wy#<_Qhi`c4^AGgtuq=}P23+5J-vGEH&=bP^Uuk4kHrLO z8Ch#DdZK>1c@3kQmX*FAB}ciVQCH$!Q*L+qoXR%d{2ub87?MT_fYb5pzG`Bs)=m(#PT4%|+ru^K*3#fqB>yn@XpeBJ`oj0g&D-(fsL$K|F)+QW-_9uH z-74x6N$0)>8NijZI{EdY~gJrFe@MzllYmOBv1S~g}Qz)on4rZ#Gq?&Hv! zFAard4KE9!k7)jF|qveUNFga-r$7cl+juKG%rgJ#Yv6|71%FBrKnTGRt zMY7_ojn;RTQZe=zXR*fG&kj~K1cN@=T zX$|fW^T$m?x5I-5)Y%rG4>TFN;WF?-E2lQ7NSnevG0}yDU~mh|MT0@}A!t2X%B~pc z6XB882{FCjgoO{K<(kRiyli191tp8;AvpHS`g|Ed$haAF(|pkmuHwX9fg9Tk0&!nZ zqW3)fAlGX)8ESYb&Cr(ddh7`~(_v&Kg>Yj){MSRD@FZ^iBy!EFXi zc#$K-$gkvGOvsL7#1HeRs{IsB*0g=3A=k3tjk-dz?Rqh$|B=e9G9$T9ii4{{sH?f#HqI)xGs6oihA{xzUcSY z)1qOyM|(CP8mm8Rf(o%RN4blKlyA)3gc<2R;|}&3%9CEO8JfNhb)~sovcYSfd5%q! zSt=KcR?oD{JL(r9_pLZk#a^hi*ZpU4_#Z_gcnj%=PBD0|gv4da>5>v^2vs^U+Wjzci;OEL<;LZuKazTGf$E`6>!g~IxbSYXCFh`Q+T07 za8y_=_%oW~JuKRWJpoLWFTf#W4{+oeZs!nIu?*v?eq}^=q$v|Zrw8a z>iYrik?)o6H;Vki@iLUz47dyk*c)k?>lHfj61b}=*7~uPK+J_9oO+0b(l@2ZmbHJKw02mNOYuwiy6nY^vxJAH*VIgeLV5mT^-XHi~V z&E{bPD)lioC%?P27TF(D4d3_Xsn?y0%%kMn)$-+bhX@Rk=O|7^pf)CgJMvuw$2hwS zn1;JO{D-Y2p9U(Mgpgboa>pxM>hf+4gqaR#lJ!;XXqNF?c4nG#1A3A4IUZJ+X)VrC z@1Bv{2~J5p%+7>(Hw3TcqaKllHIL4Wlwze=B}j!)V5`@bLF4>9ct%7hNL z)D!sm1e}7n%8LR};F-MWTnWxJ6Pa?`#^XXX>-r4$d4u-G1ae&WDeVK#9!8-L?ASW1 z<@0wQa_H~eKk-PQ1HOV1fzK%ADojB%1#Ltu^)SIAL;c8DQ>?g40~kPEq-+mq=}Xx! zu%pXZV$H+9jvq*DA!m%MI={ccS3~Eu@(&i?@5*MhjrxY4yt|<5x>Jqt4@0AGARA%JS^RM9 zc5nwoT2$+r}vgI5U`P}%)|Ot}Eva({JqNHrI-d{CIc4+hThY(a0D0jMC} z0qqd2tX05)(%38n`vPFkzL5``5;RcWfxY%G(dneuz2h?vf1VQKK>lG$d7CKh|D0bh z9$jS(H!?C@FrOlt<32|uN?S=v+%Jx_zHT)rmGDpT(!Wm#X8G9>HQ0pZ@t=Kxm|a3Aa%-+%s?M6f6r*&=+R@!*wPTq#}t+)_Jec8ZV3 zo|v$;###Y*E`;aV0*;ix!4}rPJO&*AZoYc3XZ^MXsPHJtnc<>g`12ECr~vE1`VTIX z-^R};mWhc){3Z1KFYgQ&{mV}mitls)$FqWA4^bz)p}B!O(Mf68-O4rmVFNimZe|st z=__kab*ZmUaWW-EWhWn0l2O{rN(<7(GB;MYh&le973J@(G~;NHtx&*1$Kwu!%t+z` zW~ScK`fd^9Z8hi^MjxUYU`9ABoARsBI?c@u@GCF*K44H_?V3EIp{vAn#xhSVCZLm$ zCV~LpIruJu22Sgvqiq};E<3r{qA_Cs;!{H_$tlGnZ;wQucDC{LK=C*DzZ@m;*8?X0 zr-uKJPo((wAN(V8JO2N2lrljqj16|9FkfI0HjA91&4Mc6h7z9z2tKkDV?Z@;xll9l zTUPG`M6o6?L*Jp~=%-KvH5ul~|C{QW1{Mk!i*EdO>n*WNFoW*Sm5OVUrWh=V^f^t< zg=WIsH)j}colgy~jILfdNO~;JymGnK+W!v|FNYg$o} zazAJp>#Lb$RiziP8aza}RA!yvM7eZwQ_x0gxICkp9o|in(r?@9=Ee=DQktTcr&zEg z=r(IKUw09{MF0cE%+!2n1{O^Oh&{K=ezoV=zw%o2k~Ok1UST;NCuMo%6@5nCq-s3M zDC{DFJ&OMglmC}QWii;YKj$0^-A$t>@U8->vzanN(n%neYvndZMn>}{{rHlJY2XvOe)HIpB|y#4H*bw4Xlpm2GD#{?MM);?rYK4#*`u-U*qMh9*~J%`p^ zEi^Y+l|A7%hlq?sKlRmh+lV?U0yZ0sW#*x@K5gK{n*0^eI}`B3(+xz~J$ySn^DyW8 zA7YQeD{Uq?i;gsN8)qS+A)BOn;FA+Q)7BFLE579-I1u!q|14z(5a``WL{tXeFdUCG zbRE{;Ss2lu8h6kB%6C7v(~K9q%r3YlrkVwhTL$-ihy*Pi&ZZ}(_50gZxjxg6ZI)lU z?W
g&VUKD$Z%>g5gU@xRA?qWmSp|1aNn%8>7dfB3M+2o*t29q66>-{u4ScYo}w zzyQ{F8Zzd_{LvC|>(@wtnnr&2S(}pSXw;|2e+S~k+Q-8GIY`pZ$~zU-_Y07#TXjk%bibHU_;$uS~|LQ<={vuJ7@`{)E_ z=#9)DVqd>)0oF4?Kh3THz6tIfVH+ht7Jk8kgAwm&K_u^L*Khn#oAJAA*V)6JXoH(J zi!?Yh1C;KG>rTqc;HhwDj!F~x@BIsqe=!7KLKgprKOAf8;3&&~KlFdDhW}?Ake6WD zPLQ<@;t;z?T3XzRWob4f)h#?25~kJ4_A*qHuGG<2OTXfygLrYfyIi$1FyDE&-MjLH zOV@w$rT+ob$$!PD^7sFSXeq2{7Z+>;Rym|IBesXIs^GZ0+QwGt>RR)e9-L~C`8lm1AQN@rGB^14ODbawf45x2t0xTQegTDT&1X(a+RdE-K(#inIQ zYJRcOH-K5xq&LuA!+G%P)xkFre%Va_3%RJJY}vQdQ?TVQzI~u4ES(ZyXwN35nPn=^ z6PgYHVN9r8pq9d*SGOk*R5doYRiw}l80F45kX|`}!=+wj%PHqvJK8bg@K}t`OB0L> zL76xN#z69D;LZb*tivOWl65W-0cF<1xr`>10u>}{mse7f$^HQ)L2Ghv^lE#4caz<5 z`|ah7<=>qSI`m$`kSn@pNHfclVA+y}-vTZQ2zf?N9i|QhwfE2@7u&63r7ds91yo>9 z4E~7Xo&*U8O&N{mJcDrS>-(y*xcn3+r|nXULdEak7(kFkv9>hFhXQyuF&-S~j>!fS zvPH=?f@2dajUR1hxY4)sgmulQMs3L9x+DJ$(9WkRp zu-@q)tr_U#BWSZQNucKI_}NTpOblX#csb^g%#dlg_kv|zPM9W{WMFC+Y|c2-e&Rah z)mI{IHI34|XW4)Q?QRE`XK-HPIzqu6YXhh$mh5a(bgkeHV*`j-1#C6^4$bh9H}^?Yd-=nCV)x7 z%6?+o^e;K=c+k$~5yq9fM-wHFu3qlYS}X@jsh(e+#Fl+6(tbg18UErPX%*ttnC;}a zb!E%Gs@>)~_tm8|#ufyf!utXQH(*wI>ESG17GuTkEx#1aZQylsX-U?OTy^gu)9BrU z+L_(9`Z@2@{U3xmM#Y#H%C?x%5o!qBM(yIX4>zG&_+TPKiWxi8jh|{|t}PqxCO*S> zv8B3VrH=#U&oF*Y`QJ7Roa>GR;mdtHCCRQgXcFrFA2klVOg@va(vs>f{=+iu*CIGV zyMnui=bSe?(d~m~Esw3;zDB+vl_)Y?u>AQj-Z4t)2{`%DEc$cOv~K+IG0FTxahLAY z3d)M*daJ){i^kziBwk${*Te@XWNM1LbMuyn++!@|L?hdsf#c?`wknX?uMj2x3msQ1 zQjdu-c&+r=^EXHBhPSFEnf+qIoh1|tGYA;eNvh|7@-h{XGNXV!V{tbEmI;+wHbX$L zP8>wi)6s}RxF^@JkeuBUU9J;E;;n5oNNz4Vw5z2#@X-sfWAg}FPwYl!5M*$w0*S^p zV6hg{jF1y)be1dY2rSn)%jU`s=aG>k-`TC6Isq*@?t5W++HV#)Nn%5KiFD6D#QL&vLq$*q8!m%j`e?s@Pq*hp^4iehmr;h7i>%^# z`WhvUWr+jbKs1+`6UFQ#!1xB)(^%3xk)}%+;jbZQs$utkpv`j;42c zHWxQ58S6cpE}8n+gGL|D5Au&LIntsRqu!azW+ILOpj5i74o}9wMQMKF(je~Z1B)NX| z{S(qM2fBA(_trgAdFX;TspR%ym;`nspul;*-hU22bKJUop|3_z#O21t342Ttja*hT){Tl_P8){GNe21Ve~&KdY|i;yIe0nQ;_B~6@bN@DdH?z7H;?spV&Mk}k?df*|Mu>;)mAbR2&*)`=GcY!)eTw&g_^Hz)gT z#28z(SvilC9g}(9d1=QuSO1&G_yNZZm8!r`r~N{Twh15Oq%c;z2(azszkxG%YK$yi z3!^(!~L1x23mEZ*;8uALX2*5*nhGR>8}IxCizC zC$9q`Ige8tX)1_CA~-9B%n*nDsL0KGoKj#qB!})G>+n8}s(qD_*=E;|?bT^4xqYyG zr@#{2riOIpCsQ-i+9ij;81b?vWY2{`?6LBm82=cpBUAeo40O})Z&Q)Gzt83zGm2`1 z_DJu(H9@W2`u%jm(N{w|DJ{dhvIBqg=cd-}zcA$_9qqYUx@%kCfnImb^bGo5ahgD# zzx&VV$2P1HR*tjA3jpxNUn{&D$M0p8VvKvoM;Bb{`^=hFAMQ9s2uyM>$vzy`re*5C zvr>CJk8g&1e@m-jPs$JEZQCskqr17X;}kO?G4UGv@z0QgXv5IRjf*ONk%r`9s_v&> znHqI>d)yNkXY4el3&CuVQf38k&SBVA5eOY0=?JWv4e>&4`>4ZNs4bn^`{II~p;%L{ z({*h|N?D+2aXZcrkOB*b!au!JYu>FWs#B~*x7z2=pUVeQ zTDhBQNb=?lrmlH;XADwM{f*1I1vB~ljcH=#Oo}WJ)!DB3oRfUVRNc_Pak!?WVfaUz s`PfcU11WW*z08?nX^p_NXO+d0Vq#*7H`DftmHhkbzuPeo|6}TZ0KkXB?*IS* From 20df5a9635d4f6cd55ba70ba1ddf3af222601132 Mon Sep 17 00:00:00 2001 From: Nigel Jones Date: Wed, 20 May 2026 16:12:21 +0100 Subject: [PATCH 6/7] blog: fix strategy class and strengthen IVR section MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Switch from RejectionSamplingStrategy to RepairTemplateStrategy in both the requirements= and IVR sections. RejectionSamplingStrategy just retries with the same prompt; RepairTemplateStrategy injects the validation failure reason into the repair prompt — which is what the surrounding prose already describes. Also promote "Going further" from bold text to a ## heading, and add a paragraph to the conclusion making detection vs. repair guarantees explicit. Assisted-by: Claude Code Signed-off-by: Nigel Jones --- .../granite-vision-structured-extraction.md | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/content/blogs/granite-vision-structured-extraction.md b/content/blogs/granite-vision-structured-extraction.md index 958598b..54ad716 100644 --- a/content/blogs/granite-vision-structured-extraction.md +++ b/content/blogs/granite-vision-structured-extraction.md @@ -145,7 +145,7 @@ it's just wrong. Mellea repairs and retries with the failure reason fed back into the prompt: ```python -from mellea.stdlib.sampling import RejectionSamplingStrategy +from mellea.stdlib.sampling import RepairTemplateStrategy result = m.instruct( "Extract the receipt data.", @@ -156,7 +156,7 @@ result = m.instruct( "date must be in ISO 8601 format (YYYY-MM-DD)", "each item's unit_price must be a positive number", ], - strategy=RejectionSamplingStrategy(loop_budget=3), + strategy=RepairTemplateStrategy(loop_budget=3), ) receipt = Receipt.model_validate_json(str(result)) ``` @@ -180,7 +180,7 @@ the model exactly what went wrong: ```python from mellea.stdlib.requirements import req, simple_validate -from mellea.stdlib.sampling import RejectionSamplingStrategy +from mellea.stdlib.sampling import RepairTemplateStrategy def check_line_items(json_str: str) -> tuple[bool, str]: @@ -199,7 +199,7 @@ result = m.instruct( "total must be a positive number", req("line items sum to subtotal", validation_fn=simple_validate(check_line_items)), ], - strategy=RejectionSamplingStrategy(loop_budget=3), + strategy=RepairTemplateStrategy(loop_budget=3), ) receipt = Receipt.model_validate_json(str(result)) ``` @@ -245,10 +245,17 @@ formatted dates, values that are plausible individually but wrong together. A `v pushes further still, running the kind of check you'd write in post-processing anyway and folding it directly into the generation loop rather than bolting it on after. +One thing worth being clear about: detection and repair are separate guarantees. The +validation layer will always surface a mismatch — if the arithmetic is wrong, you'll know. +Repair success depends on the model's capacity. A 4b model working from a partially obscured +image will not always correct itself in three tries; a larger model usually will. The value of +wiring the check programmatically isn't that repair always succeeds — it's that a silent wrong +answer is no longer possible. + All of this composes with any backend. Swap from a local model to a cloud endpoint, or to a different local runtime, and the extraction logic doesn't change — only the session setup does. -**Going further:** +## Going further - [Use Images and Vision Models](https://docs.mellea.ai/how-to/use-images-and-vision) — image loading, backend configuration, multi-image prompts From f0be9bbe08ecd1ea7172b0f697bcb4a8c496fe13 Mon Sep 17 00:00:00 2001 From: Nigel Jones Date: Thu, 21 May 2026 08:42:42 +0100 Subject: [PATCH 7/7] blog: address ajbozarth review comments - Add representative-output note after prose output block (line 89) - Apply suggested rewrite: "The point of wiring the check programmatically is that a silent wrong answer is no longer possible. Repair success is a separate question." - Tighten conclusion: drop recap paragraphs covering format=, requirements=, and backend portability (all covered inline); lead with the detection-vs-repair framing which is the only new content Assisted-by: Claude Code Signed-off-by: Nigel Jones --- .../granite-vision-structured-extraction.md | 31 +++++++------------ 1 file changed, 11 insertions(+), 20 deletions(-) diff --git a/content/blogs/granite-vision-structured-extraction.md b/content/blogs/granite-vision-structured-extraction.md index 54ad716..18174b0 100644 --- a/content/blogs/granite-vision-structured-extraction.md +++ b/content/blogs/granite-vision-structured-extraction.md @@ -89,6 +89,8 @@ Output: each. The subtotal is $73.60, tax at 8.5% is $6.26, for a total of $79.86." ``` +Output will vary — models describe the same receipt differently. The structure of the problem is the same. + Readable. Useless as data. You can't do `result.total` or `result.items[0].unit_price`. ## The return type is the extraction schema @@ -234,26 +236,15 @@ across all backends. ## From narration to data -The gap this closes is a real one. Vision models are already good at reading documents — -they just default to telling you about them rather than handing you the data. Mellea's -`format=` parameter shifts that: the return type becomes a contract, constrained decoding -enforces it, and you get a typed Python object the rest of your code can actually use. - -`requirements=` and `validation_fn` extend that contract beyond structure. Plain-English -requirements catch semantic problems the type system can't — negative totals, badly -formatted dates, values that are plausible individually but wrong together. A `validation_fn` -pushes further still, running the kind of check you'd write in post-processing anyway and -folding it directly into the generation loop rather than bolting it on after. - -One thing worth being clear about: detection and repair are separate guarantees. The -validation layer will always surface a mismatch — if the arithmetic is wrong, you'll know. -Repair success depends on the model's capacity. A 4b model working from a partially obscured -image will not always correct itself in three tries; a larger model usually will. The value of -wiring the check programmatically isn't that repair always succeeds — it's that a silent wrong -answer is no longer possible. - -All of this composes with any backend. Swap from a local model to a cloud endpoint, or to a -different local runtime, and the extraction logic doesn't change — only the session setup does. +Vision models are already good at reading documents — they just default to telling you about +them rather than handing you the data. `format=` shifts that. + +The more important thing to understand about `requirements=` and `validation_fn` is what they +guarantee. Detection is reliable: the validation layer always surfaces a mismatch — if the +arithmetic is wrong, you'll know. Repair depends on model capacity. A 4b model working from a +partially obscured image will not always correct itself in three tries; a larger model usually +will. The point of wiring the check programmatically is that a silent wrong answer is no longer +possible. Repair success is a separate question. ## Going further