Use case

Data extraction

Pull fields out of invoices, receipts, emails and screenshots into JSON your code can trust. The model does the reading; a schema check in your code decides whether the result is accepted.

The problem

Documents arrive in every layout imaginable, and rule-based parsers break on the first new template. Models read them well but occasionally return a malformed date, a missing field or a total that doesn't add up. Extraction is only useful if bad output is caught before it reaches your database.

How it works with NeuronGate

  1. 01

    Document

    Text, or an image of the page

  2. 02

    Extraction prompt

    Field list and an example JSON

  3. 03

    Model reads

    Vision models take images directly

  4. 04

    Schema check

    Pydantic or Zod in your code

  5. 05

    Accept or retry

    Retry with the error, then flag for review

Extract, validate, retry once with the error, then accept or flag

Vision-capable models accept images as image_url content parts, including base64 data URLs, so a scanned invoice can go straight to the model. Use the catalog's vision filter to see which models take images.

Choosing models

Model roles in an extraction pipeline
RoleGood fitWhyTrade-off
Scans and screenshots~google/gemini-flash-latestReads images well at a low price per pageVerify small print and handwritten fields
Plain-text documentsdeepseek/deepseek-v4-flashCheap for emails and text-layer PDFsText only: no images
Retries and hard cases~anthropic/claude-sonnet-latestMore reliable on messy layouts and tablesUse it for the failures, not every page

A common pattern: run everything through the cheap model, and send only documents that fail validation twice to the stronger one. Current prices are in the model catalog.

Example: an invoice from an image

The schema is the contract. The model is told the fields; your code checks them and retries once with the validation error so the model can correct itself.

import os
from openai import OpenAI

client = OpenAI(
    base_url="https://neurongate.net/v1",
    api_key=os.environ["NEURONGATE_API_KEY"],
)
import base64, json
from datetime import date
from pydantic import BaseModel, ValidationError

class Invoice(BaseModel):
    vendor: str
    invoice_number: str
    issue_date: date
    currency: str
    total: float

PROMPT = (
    "Extract the invoice as JSON with keys vendor, invoice_number, "
    "issue_date (YYYY-MM-DD), currency (ISO code) and total (number). "
    "Reply with the JSON object only."
)

def extract(image_path: str) -> Invoice:
    b64 = base64.b64encode(open(image_path, "rb").read()).decode()
    messages = [{"role": "user", "content": [
        {"type": "text", "text": PROMPT},
        {"type": "image_url", "image_url": {"url": f"data:image/png;base64,{b64}"}},
    ]}]
    for attempt in range(2):
        reply = client.chat.completions.create(
            model="~google/gemini-flash-latest", messages=messages, temperature=0,
        )
        raw = reply.choices[0].message.content or ""
        try:
            text = raw.strip().removeprefix("```json").removesuffix("```")
            return Invoice.model_validate(json.loads(text))
        except (json.JSONDecodeError, ValidationError) as err:
            messages += [
                {"role": "assistant", "content": raw},
                {"role": "user", "content": f"That was invalid: {err}. Reply with corrected JSON only."},
            ]
    raise ValueError(f"Could not extract {image_path}; flag for review")

Validate meaning, not just shape

A schema catches a missing field; it won't catch a total that doesn't match the line items. Add business checks (sums, date ranges, known vendors) and send failures to a review queue.

Images cost tokens too

Each image is billed as input tokens, and large scans cost more. Downscale pages to the smallest size where the text is still legible before sending them.

Cost control

  1. 1

    Give the workload its own key

    Create a key just for the extraction pipeline under API keys. Its usage then shows up separately in the logs, and revoking it touches nothing else.
  2. 2

    Set a monthly spend cap

    Once the key has spent its cap for the month, its requests are refused until the next month or until you raise the cap. Size it from a week of real traffic, not a guess.
  3. 3

    Allowlist the models it may call

    Restrict the key to the models this workload actually uses, for example ~google/gemini-flash-latest and ~anthropic/claude-sonnet-latest. A typo or a prompt-injected model switch then fails instead of quietly running on a pricier model.
  4. 4

    Watch the logs

    Filter the request log by this key to see tokens, cost and latency per call. Export CSV for a monthly cost-per-workload report.

FAQ

Are the documents I send stored?

No. Request and response content passes through and isn't stored; NeuronGate keeps usage metadata only (model, tokens, cost, latency, status).

How do I send a PDF?

Either extract the text layer and send it as text, or render each page to an image and send it to a vision-capable model as an image_url content part.

Why validate in my code instead of trusting the model?

Even good models occasionally return a wrong type or a missing field. A schema check plus one retry with the error message fixes most of these, and anything still invalid is flagged instead of loaded.