aeat.application.ledger._evidence_draft_vision module

On-host vision fallback for invoice-field extraction from a scan-only PDF or image.

extract_invoice_fields() reads a PDF’s embedded text layer. A scan-only or image-only invoice has no text layer at all, so that primitive raises. This module supplies the on-host fallback: rasterise the PDF (or use an image directly) into in-memory base64 PNG pages (rasterise_pdf_pages_to_base64_png()) and read them with the same LOCAL Ollama vision model the classification path already uses (LocalVisionLLMClassifier), fully on-host (sensitive-financial-data-secure-storage-only). Nothing is written to disk and nothing leaves the machine; this needs no cloud consent gate.

The vision model’s role here is strictly transcription, never derivation: the prompt instructs it to copy each field’s printed value verbatim (or emit null when a field is not visibly printed) and forbids it from computing, inferring, or estimating any figure. Every field the model returns is re-validated through the exact same grounded heuristics the text-layer path uses – validate_spanish_tax_id(), parse_date(), and Decimal parsing via normalize_decimal_separators() – so a malformed or hallucinated value is rejected (left None) rather than trusted. This mirrors the document-printed-value semantics extract_invoice_fields() already has for text-layer PDFs: both paths recover what is printed on the document, never a registry-derived or model-computed tax figure (evidence-read-never-emits-regulated-numbers in spirit – the persisted Invoice this draft eventually confirms into still goes through the operator review step before anything is minted).

Gated by LLM_VISION: an operator who has opted out of on-host vision reading gets a typed refusal naming the capability toggle, never a silent empty draft.

See also

InvoiceDraft

Typed draft this vision path returns after grounded re-validation.

extract_invoice_fields()

Text-layer extraction primitive this module complements for scan-only or image-only evidence.

extract_invoice_draft_from_evidence()

Orchestration layer that falls back to this on-host reader.

LocalVisionLLMClassifier

Sibling local Ollama vision transport used for classification and split suggestions.

parse_vision_extraction_response(text)[source]

Parse the vision model’s raw completion text into _VisionExtractedFields.

Parameters:

text (str) – Raw completion text from the local vision model.

Returns:

The parsed (but not yet grounded) fields.

Return type:

_VisionExtractedFields

Raises:

PurchaseInvoiceEvidenceInputError – When no JSON object is present or the object fails schema validation.

class LocalVisionInvoiceFieldExtractor(*, model=None, client=None, settings=None)[source]

Bases: object

Read an invoice image on-host with a local Ollama vision model into an InvoiceDraft.

Mirrors LocalVisionLLMClassifier’s transport (a local Ollama vision model fed in-memory base64 images) but for field transcription instead of category classification. Every returned field is re-validated through the grounded heuristics extract_invoice_fields() uses for the text-layer path, so a hallucinated or malformed value never reaches the operator as a fabricated fact.

Parameters:
  • model (str | None) – Local Ollama vision model identifier; defaults to Settings.aeat_llm_ollama_vision_model.

  • client (LLMClient | None) – Injected LLMClient (dependency injection for tests); default-constructed against the resolved settings otherwise.

  • settings (Settings | None) – Injected settings; defaults to load_settings().

property decided_by: str

Provenance stamp for this extractor’s transport (distinct from classification).

extract(*, evidence_images)[source]

Read evidence_images with the local vision model and return a grounded draft.

Parameters:

evidence_images (tuple[str, ...]) – In-memory base64 page/image renders of the evidence (from rasterise_pdf_pages_to_base64_png() for a scan-only PDF, or the raw image bytes base64-encoded for an image attachment).

Returns:

Every field the model transcribed AND that passed grounded re-validation; everything else is None.

Return type:

InvoiceDraft

extract_invoice_fields_from_images(evidence_images, *, model=None, settings=None)[source]

Convenience wrapper: build a LocalVisionInvoiceFieldExtractor and extract.

Parameters:
  • evidence_images (tuple[str, ...]) – In-memory base64 page/image renders of the evidence.

  • model (str | None) – Optional vision model override.

  • settings (Settings | None) – Optional resolved settings override.

Returns:

The grounded, best-effort extracted fields.

Return type:

InvoiceDraft