97e91a83f3
Ruff / Ruff (push) Has been cancelled
Test / Core Tests (push) Has been cancelled
Test / Offline Coverage Tests (Python 3.10) (push) Has been cancelled
Test / Offline Coverage Tests (Python 3.11) (push) Has been cancelled
Test / Offline Coverage Tests (Python 3.12) (push) Has been cancelled
Test / Offline Coverage Tests (Python 3.13) (push) Has been cancelled
Test / Offline Coverage Tests (Python 3.9) (push) Has been cancelled
Test / Full Coverage (Python 3.11) (push) Has been cancelled
Test / Core Provider Tests (OpenAI) (push) Has been cancelled
Test / Core Provider Tests (Anthropic) (push) Has been cancelled
Test / Core Provider Tests (Google) (push) Has been cancelled
Test / Core Provider Tests (Other) (push) Has been cancelled
Test / Anthropic Tests (push) Has been cancelled
Test / Gemini Tests (push) Has been cancelled
Test / Google GenAI Tests (push) Has been cancelled
Test / Vertex AI Tests (push) Has been cancelled
Test / OpenAI Tests (push) Has been cancelled
Test / Writer Tests (push) Has been cancelled
Test / Auto Client Tests (push) Has been cancelled
ty / type-check (push) Has been cancelled
179 lines
5.5 KiB
Markdown
179 lines
5.5 KiB
Markdown
---
|
|
title: Receipt Data Extraction with GPT-4 Vision - Expense Tracking
|
|
description: Extract and validate receipt data from images using GPT-4 Vision and Instructor. Automate expense tracking with structured receipt parsing.
|
|
---
|
|
|
|
# Extracting Receipt Data using GPT-4 and Python
|
|
|
|
This post demonstrates how to use Python's Pydantic library and OpenAI's GPT-4 model to extract receipt data from images and validate the total amount. This method is particularly useful for automating expense tracking and financial analysis tasks.
|
|
|
|
## Defining the Item and Receipt Classes
|
|
|
|
First, we define two Pydantic models, `Item` and `Receipt`, to structure the extracted data. The `Item` class represents individual items on the receipt, with fields for name, price, and quantity. The `Receipt` class contains a list of `Item` objects and the total amount.
|
|
|
|
```python
|
|
from pydantic import BaseModel
|
|
|
|
|
|
class Item(BaseModel):
|
|
name: str
|
|
price: float
|
|
quantity: int
|
|
|
|
|
|
class Receipt(BaseModel):
|
|
items: list[Item]
|
|
total: float
|
|
```
|
|
|
|
## Validating the Total Amount
|
|
|
|
To ensure the accuracy of the extracted data, we use Pydantic's `model_validator` decorator to define a custom validation function, `check_total`. This function calculates the sum of item prices and compares it to the extracted total amount. If there's a discrepancy, it raises a `ValueError`.
|
|
|
|
```python
|
|
from pydantic import model_validator
|
|
|
|
|
|
@model_validator(mode="after")
|
|
def check_total(self):
|
|
items = self.items
|
|
total = self.total
|
|
calculated_total = sum(item.price * item.quantity for item in items)
|
|
if calculated_total != total:
|
|
raise ValueError(
|
|
f"Total {total} does not match the sum of item prices {calculated_total}"
|
|
)
|
|
return self
|
|
```
|
|
|
|
## Extracting Receipt Data from Images
|
|
|
|
The `extract_receipt` function uses OpenAI's GPT-4 model to process an image URL and extract receipt data. We utilize the `instructor` library to configure the OpenAI client for this purpose.
|
|
|
|
```python
|
|
import instructor
|
|
|
|
# <%hide%>
|
|
from pydantic import BaseModel, model_validator
|
|
|
|
|
|
class Item(BaseModel):
|
|
name: str
|
|
price: float
|
|
quantity: int
|
|
|
|
|
|
class Receipt(BaseModel):
|
|
items: list[Item]
|
|
total: float
|
|
|
|
@model_validator(mode="after")
|
|
def check_total(cls, values: "Receipt"):
|
|
items = values.items
|
|
total = values.total
|
|
calculated_total = sum(item.price * item.quantity for item in items)
|
|
if calculated_total != total:
|
|
raise ValueError(
|
|
f"Total {total} does not match the sum of item prices {calculated_total}"
|
|
)
|
|
return values
|
|
|
|
|
|
# <%hide%>
|
|
|
|
client = instructor.from_provider("openai/gpt-5-nano")
|
|
|
|
|
|
def extract(url: str) -> Receipt:
|
|
return client.create(
|
|
model="gpt-5.4-mini",
|
|
max_tokens=4000,
|
|
response_model=Receipt,
|
|
messages=[
|
|
{
|
|
"role": "user",
|
|
"content": [
|
|
{
|
|
"type": "image_url",
|
|
"image_url": {"url": url},
|
|
},
|
|
{
|
|
"type": "text",
|
|
"text": "Analyze the image and return the items in the receipt and the total amount.",
|
|
},
|
|
],
|
|
}
|
|
],
|
|
)
|
|
```
|
|
|
|
## Practical Examples
|
|
|
|
In these examples, we apply the method to extract receipt data from two different images. The custom validation function ensures that the extracted total amount matches the sum of item prices.
|
|
|
|
```python
|
|
# <%hide%>
|
|
from pydantic import BaseModel, model_validator
|
|
import instructor
|
|
|
|
|
|
class Item(BaseModel):
|
|
name: str
|
|
price: float
|
|
quantity: int
|
|
|
|
|
|
class Receipt(BaseModel):
|
|
items: list[Item]
|
|
total: float
|
|
|
|
@model_validator(mode="after")
|
|
def check_total(cls, values: "Receipt"):
|
|
items = values.items
|
|
total = values.total
|
|
calculated_total = round(sum(item.price * item.quantity for item in items), 2)
|
|
if calculated_total != total:
|
|
raise ValueError(
|
|
f"Total {total} does not match the sum of item prices {calculated_total}"
|
|
)
|
|
return values
|
|
|
|
|
|
client = instructor.from_provider("openai/gpt-5-nano")
|
|
|
|
|
|
def extract(url: str) -> Receipt:
|
|
return client.create(
|
|
model="gpt-4o",
|
|
max_tokens=4000,
|
|
response_model=Receipt,
|
|
messages=[
|
|
{
|
|
"role": "user",
|
|
"content": [
|
|
{
|
|
"type": "image_url",
|
|
"image_url": {"url": url},
|
|
},
|
|
{
|
|
"type": "text",
|
|
"text": "Analyze the image and return the items in the receipt and the total amount.",
|
|
},
|
|
],
|
|
}
|
|
],
|
|
)
|
|
|
|
|
|
# <%hide%>
|
|
url = "https://templates.mediamodifier.com/645124ff36ed2f5227cbf871/supermarket-receipt-template.jpg"
|
|
|
|
|
|
receipt = extract(url)
|
|
print(receipt)
|
|
"""
|
|
items=[Item(name='Lorem ipsum', price=9.2, quantity=1), Item(name='Lorem ipsum dolor sit', price=19.2, quantity=1), Item(name='Lorem ipsum dolor sit amet', price=15.0, quantity=1), Item(name='Lorem ipsum', price=15.0, quantity=1), Item(name='Lorem ipsum', price=15.0, quantity=1), Item(name='Lorem ipsum dolor sit', price=15.0, quantity=1), Item(name='Lorem ipsum', price=19.2, quantity=1)] total=107.6
|
|
"""
|
|
```
|
|
|
|
By combining the power of GPT-4 and Python's Pydantic library, we can accurately extract and validate receipt data from images, streamlining expense tracking and financial analysis tasks. |