Careeroza
Real World Example
Invoice and Receipt Extraction
Expense apps (Zoho Expense, Razorpay Payroll, Fyle) and GST tools read photos of bills and invoices: vision plus structured output. A ShopEase seller-onboarding version that reads a supplier invoice image:
import base64
from pydantic import BaseModel, Field
import anthropic
class LineItem(BaseModel):
description: str
quantity: int
amount: float
class Invoice(BaseModel):
seller_name: str
gstin: str | None = Field(description="15-character GSTIN if printed, else null")
invoice_number: str
invoice_date: str = Field(description="YYYY-MM-DD")
items: list[LineItem]
total_amount: float
client = anthropic.Anthropic()
with open("invoice_photo.jpg", "rb") as f:
img = base64.standard_b64encode(f.read()).decode("utf-8")
response = client.messages.parse(
model="claude-sonnet-5-5",
max_tokens=2000,
messages=[{"role": "user", "content": [
{"type": "image", "source": {"type": "base64", "media_type": "image/jpeg", "data": img}},
{"type": "text", "text": "Extract the invoice fields. Use null for anything not visible."},
]}],
output_format=Invoice,
)
inv = response.parsed_output
assert abs(sum(i.amount for i in inv.items) - inv.total_amount) < 1, "totals do not match - send to review"
print(inv.model_dump_json(indent=2))Run it
python invoice.pyExample output
{
"seller_name": "Shree Ganesh Textiles",
"gstin": "27AABCS1429B1Z5",
"invoice_number": "SGT/2026/1187",
"invoice_date": "2026-10-14",
"items": [
{"description": "Cotton kurta, indigo, M", "quantity": 20, "amount": 9800.0},
{"description": "Cotton kurta, indigo, L", "quantity": 15, "amount": 7350.0}
],
"total_amount": 17150.0
}Checks Before Trusting It
Example
Model output from a photo can misread a digit. Cheap code checks catch many mistakes. Here the GSTIN format is checked with a regular expression and the line items are added up:
import re
GSTIN = re.compile(r"^\d{2}[A-Z]{5}\d{4}[A-Z][1-9A-Z]Z[0-9A-Z]$")
extracted = [
{"gstin": "27AABCS1429B1Z5", "items": [9800.0, 7350.0], "total": 17150.0},
{"gstin": "27AABCS1429B1Z5", "items": [9800.0, 7350.0], "total": 17750.0}, # misread 1 as 7
{"gstin": "27AABCS142gB1Z5", "items": [5000.0], "total": 5000.0}, # misread 9 as g
]
for inv in extracted:
problems = []
if inv["gstin"] and not GSTIN.match(inv["gstin"]):
problems.append("GSTIN format invalid")
if abs(sum(inv["items"]) - inv["total"]) >= 1:
problems.append(f"items add up to {sum(inv['items']):,.0f}, total says {inv['total']:,.0f}")
print("OK" if not problems else "REVIEW: " + "; ".join(problems))Output
OK REVIEW: items add up to 17,150, total says 17,750 REVIEW: GSTIN format invalid