openextract reads documents, images, audio, and video with the LLM of your choice and hands back a typed Pydantic object. Not a string. Not a dict. The model you asked for, already validated.
Installs every provider SDK. For just one, use its extra, like [anthropic]. Set its API key and call extract.
pip install 'openextract[all]'
0000 25 50 44 46 2d 31 2e 35 %PDF-1.5 0008 0a 25 8f 0a 31 30 30 20 .%..100 0010 30 20 6f 62 6a 0a 3c 3c 0 obj.<< 0018 20 2f 46 69 6c 74 65 72 /Filter 0020 20 2f 46 6c 61 74 65 44 /FlateD 0028 65 63 6f 64 65 20 2f 4c ecode /L
Halvorsen Print Co.1
Kanalgata 14, 5003 Bergen, Norway
| Letterpress run, 500 cards | 860.00 |
| Cotton stock, 600 gsm | 380.00 |
| Total due | 1,240.002 EUR3 |
from pydantic import BaseModel
from openextract import extract
class Invoice(BaseModel):
vendor: str
total: float
currency: str
invoice = extract(
Invoice,
"openai:gpt-5",
"invoice.pdf",
)
extract(schema, model, source, instructions=None, *, media_type=None)
It takes the first answer it finds: the media_type you passed, the file extension, the URL's Content-Type header, then the file's leading bytes.
Every error subclasses ExtractionError and keeps the original exception as its cause.
Any model pydantic-ai supports. Install the matching extra and set its API key.
pip install 'openextract[anthropic]' # openai, google, bedrock, groq, mistral,
# cohere, huggingface, openrouter, xai, all
Yes. It takes the same arguments. Await it.
invoice = await extract_async(Invoice, "openai:gpt-5", "invoice.pdf")