Metadata-Version: 2.5
Name: openextract
Version: 1.0.0
Summary: Extract structured data from documents, images, audio, and video using LLMs
Project-URL: Homepage, https://github.com/Mellow-Artificial-Intelligence/openextract
Project-URL: Documentation, https://mellow-artificial-intelligence.github.io/openextract/
Project-URL: Repository, https://github.com/Mellow-Artificial-Intelligence/openextract
Project-URL: Issues, https://github.com/Mellow-Artificial-Intelligence/openextract/issues
Project-URL: Changelog, https://github.com/Mellow-Artificial-Intelligence/openextract/blob/main/CHANGELOG.md
Author: Cole McIntosh
License-Expression: MIT
License-File: LICENSE
Keywords: ai,document,extraction,llm,pydantic,structured-data
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Requires-Python: >=3.12
Requires-Dist: httpx>=0.28.1
Requires-Dist: pydantic-ai-slim>=1.37.0
Requires-Dist: pydantic>=2.12.5
Provides-Extra: all
Requires-Dist: pydantic-ai-slim[anthropic,bedrock,cohere,google,groq,huggingface,logfire,mistral,openai,openrouter,xai]>=1.37.0; extra == 'all'
Provides-Extra: anthropic
Requires-Dist: pydantic-ai-slim[anthropic]>=1.37.0; extra == 'anthropic'
Provides-Extra: bedrock
Requires-Dist: pydantic-ai-slim[bedrock]>=1.37.0; extra == 'bedrock'
Provides-Extra: cohere
Requires-Dist: pydantic-ai-slim[cohere]>=1.37.0; extra == 'cohere'
Provides-Extra: google
Requires-Dist: pydantic-ai-slim[google]>=1.37.0; extra == 'google'
Provides-Extra: groq
Requires-Dist: pydantic-ai-slim[groq]>=1.37.0; extra == 'groq'
Provides-Extra: huggingface
Requires-Dist: pydantic-ai-slim[huggingface]>=1.37.0; extra == 'huggingface'
Provides-Extra: logfire
Requires-Dist: pydantic-ai-slim[logfire]>=1.37.0; extra == 'logfire'
Provides-Extra: mistral
Requires-Dist: pydantic-ai-slim[mistral]>=1.37.0; extra == 'mistral'
Provides-Extra: openai
Requires-Dist: pydantic-ai-slim[openai]>=1.37.0; extra == 'openai'
Provides-Extra: openrouter
Requires-Dist: pydantic-ai-slim[openrouter]>=1.37.0; extra == 'openrouter'
Provides-Extra: xai
Requires-Dist: pydantic-ai-slim[xai]>=1.37.0; extra == 'xai'
Description-Content-Type: text/markdown

<div align="center">

# openextract

**Extract structured data from documents, images, audio, and video using LLMs.**

[![PyPI version](https://img.shields.io/pypi/v/openextract.svg?logo=pypi&logoColor=white&color=4B8BBE)](https://pypi.org/project/openextract/)
[![Python versions](https://img.shields.io/pypi/pyversions/openextract.svg?logo=python&logoColor=white)](https://pypi.org/project/openextract/)
[![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)
[![CI](https://github.com/Mellow-Artificial-Intelligence/openextract/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/Mellow-Artificial-Intelligence/openextract/actions/workflows/ci.yml)

[Website](https://mellow-artificial-intelligence.github.io/openextract/) &middot; [PyPI](https://pypi.org/project/openextract/) &middot; [Changelog](CHANGELOG.md)

</div>

One function: give it a Pydantic schema, a model, and a file. You get back a validated instance.

```python
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")
print(invoice.total)
```

## Install

```bash
pip install 'openextract[all]'   # or just your provider: [openai], [anthropic], [google], ...
```

Requires Python 3.12+. Set the API key your provider expects, such as `OPENAI_API_KEY`.

## Usage

```python
extract(schema, model, source, instructions=None, *, media_type=None)
await extract_async(schema, model, source, instructions=None, *, media_type=None)
```

- **`source`** is a file path, a `pathlib.Path`, an `http(s)://` URL, or raw `bytes`.
- **`model`** is any [pydantic-ai](https://ai.pydantic.dev/models/) model string (`"anthropic:claude-sonnet-5"`, `"google-gla:gemini-2.5-pro"`, `"ollama:llama3"`, ...) or a configured pydantic-ai `Model`.
- **`instructions`** are optional extra guidance for the model.
- **`media_type`** is inferred for you. openextract checks the file extension, then the URL's `Content-Type`, then the file's leading bytes (PDF, PNG, JPEG, GIF, WebP, MP3, WAV, FLAC, OGG, MP4, UTF-8 text). Pass it only to override the result.

```python
extract(Invoice, "anthropic:claude-sonnet-5", "https://example.com/invoice.pdf")
extract(Invoice, "openai:gpt-5", scanned_page_bytes, "Amounts are in EUR.")
```

## Errors

Every error subclasses `ExtractionError` and keeps the original exception as `__cause__`.

| Exception | Raised when |
| --- | --- |
| `ModelError` | The provider returns an error. |
| `SchemaValidationError` | The model's output doesn't match the schema. |
| `ProviderNotInstalledError` | The provider's SDK isn't installed. |
| `ExtractionError` | A URL can't be fetched. |

If openextract can't infer the media type, it raises a `ValueError` and asks you to pass `media_type`.

## License

MIT
