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.
This commit is contained in:
2026-08-21 14:04:42 +02:00
commit 7e706793fa
49 changed files with 2512 additions and 0 deletions
+46
View File
@@ -0,0 +1,46 @@
"""Tests for the structured extraction stage."""
import pytest
from PIL import Image
from odoo_ocr.config import Settings
from odoo_ocr.pipeline.extractor import extract_invoice
from odoo_ocr.schemas import ExtractedInvoice
from tests.conftest import FakeVLMClient
@pytest.mark.asyncio
async def test_extract_invoice() -> None:
client = FakeVLMClient(
responses={
"invoice data extraction": {
"vendor_name": "Acme",
"vendor_address": None,
"vendor_vat": None,
"invoice_number": "INV-1",
"invoice_date": "2024-01-01",
"due_date": None,
"currency": "EUR",
"payment_terms": None,
"line_items": [
{
"description": "Widget",
"quantity": 2.0,
"unit_price": 50.0,
"total_price": 100.0,
"tax_rate": 0.0,
}
],
"subtotal": 100.0,
"tax_total": 0.0,
"total": 100.0,
"iban": None,
"raw_ocr_text": "",
}
}
)
result = await extract_invoice("raw text", [Image.new("RGB", (10, 10))], client, Settings())
assert isinstance(result, ExtractedInvoice)
assert result.vendor_name == "Acme"
assert result.line_items_sum() == 100