Files
odoo_ocr/.agents/skills/odoo-ocr-pipeline/SKILL.md
T
fegger 7e706793fa Initial scaffold: local invoice OCR pipeline with Ollama, classifier branches, structured extraction, review, and Odoo XML export
- Add AGENTS.md and project-specific Zed skills (odoo-ocr-pipeline, odoo-xml-import, local-vlm-client).
- Implement Pydantic schemas for documents, invoices, review results, and VLM responses.
- Add unified BaseVLMClient with Ollama implementation and llama.cpp stub.
- Build pipeline stages: loader, classifier, digital_pdf/scanned_print/handwritten/mixed_unknown branches, extractor, reviewer, xml_builder.
- Add CLI entry point  with sidecar JSON and confidence-gated XML output.
- Include prompts for classifier, OCR, extraction, and review models.
- Add tests with FakeVLMClient; pytest, ruff, and mypy all pass.
2026-08-21 14:04:42 +02:00

4.5 KiB
Raw Blame History

name, description
name description
odoo-ocr-pipeline Use this skill when implementing the document classifier, OCR branches, structured extraction, or review stages of the odoo_ocr invoice processing pipeline.

Odoo OCR Pipeline Implementation Skill

Use this skill whenever you are asked to write or modify code for the invoice OCR pipeline in odoo_ocr.

Pipeline Stages

The pipeline has these stages, each as a separate module under src/odoo_ocr/pipeline/:

  1. Loader (pipeline/loader.py): converts PDFs and images to normalized PIL.Image.Image or numpy arrays. Handle multi-page PDFs by yielding one page at a time.
  2. Classifier (pipeline/classifier.py): determines the invoice type. Return a DocumentClass enum with values:
    • digital_pdf — native PDF with embedded text.
    • scanned_print — clean printed scan/photo.
    • handwritten — handwritten invoice.
    • mixed_unknown — ambiguous or low-quality input. Implementation should first try fast heuristics (file extension, text layer presence, image features), then fall back to a small VLM classifier if confidence is low.
  3. Branch routers:
    • pipeline/digital_pdf.py: extract text and layout with pymupdf / pdfplumber. Preserve bounding boxes for table reconstruction.
    • pipeline/scanned_print.py: preprocess image and call the OCR VLM.
    • pipeline/handwritten.py: preprocess image (binarization, slant correction, line segmentation if needed) and call GLM-OCR / handwriting OCR model.
    • pipeline/mixed_unknown.py: run multiple OCR backends and merge/confidence-rank outputs.
  4. Extractor (pipeline/extractor.py): take raw OCR output (text + image) and call a structured-extraction VLM to produce an ExtractedInvoice Pydantic object. Force JSON output only.
  5. Reviewer (pipeline/reviewer.py): call a review VLM with the original image and the extracted JSON. Return a ReviewResult with valid, confidence, and issues.

Branch Routing Logic

# src/odoo_ocr/schemas/document.py
from enum import Enum

class DocumentClass(str, Enum):
    digital_pdf = "digital_pdf"
    scanned_print = "scanned_print"
    handwritten = "handwritten"
    mixed_unknown = "mixed_unknown"

Routing decision tree:

  • If file is PDF and pdfplumber extracts meaningful text → digital_pdf.
  • Else if image and classifier confidence > 0.85:
    • handwriting features dominate → handwritten
    • otherwise → scanned_print
  • Else → mixed_unknown.

Preprocessing Rules

For scanned/photo inputs:

  1. Convert to grayscale.
  2. Resize to a standard DPI (300 DPI preferred; 200 DPI minimum).
  3. Deskew if skew angle > 0.5°.
  4. Apply adaptive contrast/clarity; avoid over-blurring.
  5. For handwriting branch, also:
    • Binarize with Otsu or Sauvola.
    • Detect and correct slant.
    • Optionally segment lines.

Structured Extraction Output

The final extraction must always fit the ExtractedInvoice Pydantic schema defined in src/odoo_ocr/schemas/invoice.py. Required fields include:

  • vendor_name
  • vendor_address (optional)
  • invoice_number
  • invoice_date
  • due_date (optional)
  • currency (default to settings)
  • payment_terms (optional)
  • line_items: list of InvoiceLineItem with description, quantity, unit_price, total_price, tax_rate.
  • subtotal
  • tax_total
  • total
  • bank_details / iban (optional)
  • raw_ocr_text (for debugging)

Review Output

The review stage must return:

class ReviewIssue(BaseModel):
    field: str
    severity: Literal["error", "warning"]
    message: str
    suggested_value: Any | None

class ReviewResult(BaseModel):
    valid: bool
    confidence: float  # 0.01.0
    issues: list[ReviewIssue]
    corrected_invoice: ExtractedInvoice | None

Confidence thresholds (from config):

  • confidence >= 0.90: accept and generate XML.
  • 0.75 <= confidence < 0.90: generate XML with human_review_required=true flag.
  • confidence < 0.75: do not generate final XML; emit draft sidecar only and flag for human review.

Implementation Guidelines

  • Keep each stage stateless; pass a ProcessingContext Pydantic object that holds settings, original path, classified type, and intermediate results.
  • Every model call goes through the unified model client from src/odoo_ocr/models/base_vlm.py.
  • Log each stage with timing and input/output file hashes.
  • Add unit tests for each branch with small fixture images/PDFs; mock model calls by default.
  • Do not commit large model weights or binary fixtures.