infoxtractor/README.md
Dirk Riemann 703da9035e
All checks were successful
tests / test (push) Successful in 2m1s
tests / test (pull_request) Successful in 1m18s
feat(use-cases): add inline use-case definitions
Adds RequestIX.use_case_inline so callers can define ad-hoc extraction
schemas in the request itself, bypassing the backend registry. The
pipeline builds a fresh (Request, Response) Pydantic class pair per
call via ix.use_cases.inline.build_use_case_classes; structural errors
(dup field, bad identifier, choices-on-non-str, empty fields) raise
IX_001_001 to match the registry-miss path. Inline wins when both
use_case and use_case_inline are set. Existing REST callers see no
behavioural change.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 21:01:27 +02:00

3.4 KiB

InfoXtractor (ix)

Async, on-prem, LLM-powered structured information extraction microservice.

Given a document (PDF, image, text) and a named use case, ix returns a structured JSON result whose shape matches the use-case schema — together with per-field provenance (OCR segment IDs, bounding boxes, cross-OCR agreement flags) that let the caller decide how much to trust each extracted value.

Status: MVP deployed. Live on the home LAN at http://192.168.68.42:8994.

Principles

  • On-prem always. LLM = Ollama, OCR = local engines (Surya first). No OpenAI / Anthropic / Azure / AWS / cloud.
  • Grounded extraction, not DB truth. ix returns best-effort fields + provenance; the caller decides what to trust.
  • Transport-agnostic pipeline core. REST + Postgres-queue adapters in parallel on one job store.

Submitting a job

curl -X POST http://192.168.68.42:8994/jobs \
  -H "Content-Type: application/json" \
  -d '{
    "use_case": "bank_statement_header",
    "ix_client_id": "mammon",
    "request_id": "some-correlation-id",
    "context": {
      "files": [{
        "url": "http://paperless.local/api/documents/42/download/",
        "headers": {"Authorization": "Token …"}
      }],
      "texts": ["<Paperless Tesseract OCR content>"]
    }
  }'
# → {"job_id":"…","ix_id":"…","status":"pending"}

Poll GET /jobs/{job_id} until status is done or error. Optionally pass callback_url to receive a webhook on completion (one-shot, no retry; polling stays authoritative).

Ad-hoc use cases

For one-offs where a registered use case doesn't exist yet, ship the schema inline:

{
  "use_case": "adhoc-invoice",        // free-form label (logs/metrics only)
  "use_case_inline": {
    "use_case_name": "Invoice totals",
    "system_prompt": "Extract vendor and total amount.",
    "fields": [
      {"name": "vendor", "type": "str", "required": true},
      {"name": "total",  "type": "decimal"},
      {"name": "currency", "type": "str", "choices": ["USD", "EUR", "CHF"]}
    ]
  },
  // ...ix_client_id, request_id, context...
}

When use_case_inline is set, the pipeline builds the response schema on the fly and skips the registry. Supported types: str, int, float, decimal, date, datetime, bool. choices is only allowed on str fields. Precedence: inline wins over use_case when both are present.

Full REST surface + provenance response shape documented in the MVP design spec.

Running locally

uv sync --extra dev
uv run pytest tests/unit -v                    # hermetic unit + integration suite
IX_TEST_OLLAMA=1 uv run pytest tests/live -v    # needs LAN access to Ollama + GPU

Deploying

git push server main      # rebuilds Docker image, restarts container, /healthz deploy gate
python scripts/e2e_smoke.py   # E2E acceptance against the live service

See docs/deployment.md for full runbook + rollback.