![]() |
| https://www.pexels.com/photo/person-using-a-computer-and-holding-a-credit-card-and-receipts-4968390/ |
Introduction
The Azure Document Intelligence prebuilt receipt model extracts structured data from receipts without any model training. It identifies key information such as merchant name, transaction date, total amount, tax, and individual line items, which makes it straightforward to process and analyze receipt data. This is a common need for businesses that automate expense tracking, accounting, and financial reporting. The prebuilt model saves time and reduces the errors that come with manual data entry.
Under the hood, the service combines computer vision and machine learning to read the content of a receipt and return labeled fields. It handles a range of receipt formats, including printed and handwritten receipts, and adapts to different layouts and designs.
This post walks through using the prebuilt receipt model from Python: how to authenticate, send a file, and turn the raw response into a clean, typed data model. The full source code is available on GitHub: receipt-scanning.
Prerequisites
To follow along, you need:
- An Azure subscription with a Document Intelligence (or Azure AI Services) resource.
- The resource endpoint, exposed through the
AZURE_DOCUMENTINTELLIGENCE_ENDPOINTenvironment variable. - Python 3.13 or later.
- The
azure-ai-documentintelligenceandazure-identitypackages.
Python SDK
The Azure Document Intelligence Python SDK provides a convenient way to interact with the prebuilt receipt model. The SDK handles authentication, request formatting, and response parsing, so you can focus on the extracted data rather than the transport details.
Authentication uses DefaultAzureCredential, which works with your Azure CLI login during development and with managed identity in production. There are no API keys to manage
import os
from azure.ai.documentintelligence import DocumentIntelligenceClient
from azure.identity import DefaultAzureCredential
def _get_client() -> DocumentIntelligenceClient:
endpoint = os.getenv("AZURE_DOCUMENTINTELLIGENCE_ENDPOINT")
if not endpoint:
raise ValueError(
"AZURE_DOCUMENTINTELLIGENCE_ENDPOINT environment variable is not set."
)
return DocumentIntelligenceClient(
endpoint=endpoint, credential=DefaultAzureCredential()
)Receipt Formats
- Printed receipts: the most common type, typically generated by point-of-sale systems. They may include text, logos, and barcodes.
- Handwritten receipts: common in small businesses or informal transactions. The model recognizes and extracts information from handwritten text.
- Digital receipts: generated electronically and delivered by email or mobile apps. The model processes them as PDF or image files.
Scanning a Receipt
prebuilt-receipt model, and wait for the long-running operation to finish. The service can return more than one document per file, so the result is a list:def scan_receipt(file_path) -> list[Receipt]:
client = _get_client()
with open(file_path, "rb") as f:
poller = client.begin_analyze_document(
"prebuilt-receipt",
f,
content_type="application/octet-stream",
)
result = poller.result()
if not result.documents:
return []
return [
receipt
for document in result.documents
if (receipt := _parse_field_value(document)) is not None
]Working with the Extracted Fields
fields dictionary. The values are typed: a currency field carries valueCurrency.amount, a number carries valueNumber, a date carries valueDate, and so on. One subtlety is that the SDK value objects behave like mappings but are not dict subclasses, so an isinstance(val, dict) check fails. Use hasattr(val, "get") instead when you need to reach into a nested value:def _get_field_value(
fields, field_name, prop_name="valueString", sub_prop_name=None
) -> float | None:
field = fields.get(field_name)
val = field.get(prop_name) if field else None
if sub_prop_name and val is not None:
val = val.get(sub_prop_name) if hasattr(val, "get") else None
return round(val, 2) if isinstance(val, (int, float)) else NoneTaxDetails array, so the total tax is the sum of each entry's amount.Modeling the Result
from pydantic import BaseModel
class ReceiptLineItem(BaseModel):
description: str | None
quantity: float | None
unit_price: float | None
price: float | None
class Receipt(BaseModel):
receipt_type: str | None
merchant: str | None
merchant_address: str | None
country: str | None
transaction_date: str | None
transaction_time: str | None
subtotal: float | None
total_tax: float | None
total_amount: float | None
line_items: list[ReceiptLineItem]Running the Sample
--file_name, and it prints the parsed result as JSON:uv run python main.py --file_name groceries.jpg uv run python main.py --file_name restaurant.pdf
.jpg, .png, and .pdf inputs because the content type is sent as application/octet-stream.Demo
Conclusion
DefaultAzureCredential, submit a file, and map the typed fields onto your own models. Whether the input is a printed, handwritten, or digital receipt, the model helps you extract the information you need quickly and accurately.
Comments
Post a Comment