-
Notifications
You must be signed in to change notification settings - Fork 0
azure di
Code reference:
backend/app/adapters/ocr/azure_di.pyConfig model:backend/app/config/settings.py→AzureDIConfig
Azure Document Intelligence (formerly Form Recognizer) is the default OCR engine in azure_di pipeline mode. It handles the full extraction pipeline — PDF to text with per-word metadata. Key capabilities:
| Capability | Detail |
|---|---|
| Per-word handwriting detection | Every word carries an is_handwritten boolean |
| Per-word confidence scores | Float 0.0–1.0 indicating OCR certainty |
| Barcode / QR-code reading | 17+ symbologies decoded per page |
| Selection mark detection | Checkbox and radio-button state with confidence |
The same AzureDIOCRAdapter class is used in all environments. Only the endpoint URL changes:
| Mode | Environment | Endpoint example |
|---|---|---|
| Cloud API (Azure AI Foundry) | Dev / staging | https://<resource>.cognitiveservices.azure.com |
| Disconnected container | Production on-prem | http://localhost:5000 |
class AzureDIConfig(BaseModel):
endpoint: str = "https://<resource>.cognitiveservices.azure.com"
api_key: str = ""
features: list[str] = Field(
default_factory=lambda: ["barcodes", "keyValuePairs"]
)The features list controls which add-on capabilities are requested. barcodes enables barcode extraction and keyValuePairs enables key-value pair detection (useful for forms).
Like Marker, the Azure DI client is lazily initialised on first use:
def _get_client(self):
if self._client is not None:
return self._client
from azure.ai.documentintelligence import DocumentIntelligenceClient
from azure.core.credentials import AzureKeyCredential
self._client = DocumentIntelligenceClient(
endpoint=self._config.endpoint,
credential=AzureKeyCredential(self._config.api_key),
)
return self._clientThe SDK import is deferred into the method body so the module can be loaded even if the azure-ai-documentintelligence package is not installed (useful for local dev with Marker-only runs).
The adapter calls the prebuilt-layout model with the configured feature flags:
poller = client.begin_analyze_document(
"prebuilt-layout",
analyze_request=AnalyzeDocumentRequest(bytes_source=pdf_bytes),
features=self._config.features,
)
result = poller.result()The call is wrapped in run_in_executor because the SDK's begin_analyze_document / poller.result() cycle is synchronous and involves network I/O:
result = await loop.run_in_executor(None, _analyze)For every page, each word is mapped to an OCRWord:
OCRWord(
text=word.content,
confidence=word.confidence, # 0.0–1.0
is_handwritten=word.is_handwritten, # bool
bounding_region=BoundingRegion(
page_num=page_num,
x=min(x_coords),
y=min(y_coords),
width=max(x_coords) - min(x_coords),
height=max(y_coords) - min(y_coords),
),
)The BoundingRegion is computed from the Azure polygon (list of x,y coordinate pairs) by taking the min/max extents.
Each detected barcode is mapped to a BarcodeResult:
BarcodeResult(
barcode_type=bc.kind, # e.g. "Code128", "QRCode", "EAN13"
value=bc.value, # decoded string
page_num=page_num,
)Azure DI supports 17+ barcode symbologies including Code 39, Code 93, Code 128, UPC-A, UPC-E, EAN-8, EAN-13, ITF, Codabar, Data Matrix, QR Code, PDF417, and more.
Checkboxes and radio buttons are extracted as SelectionMark:
SelectionMark(
state=sm.state, # "selected" or "unselected"
confidence=sm.confidence, # 0.0–1.0
page_num=page_num,
)Azure DI's bounding_regions can reference multiple pages, enabling native cross-page table and field detection. The adapter currently extracts the first bounding region per word:
def _to_bounding_region(regions, page_num):
if not regions:
return None
r = regions[0]
# ... compute from polygon ...For tables, Azure DI natively tracks cell spans across pages via bounding_regions on each cell.
In azure_di pipeline mode, confidence comes directly from DI's per-word scores:
Page confidence = 0.50 × avg_word_confidence + 0.20 × min_word_confidence + 0.30 × validation_pass_rate
Pages below the HITL threshold are routed for human review.
supports_handwriting() → True
supports_barcodes() → True
supports_selection_marks() → TrueThe adapter uses these port models from backend/app/core/ports/ocr.py:
| Model | Purpose |
|---|---|
OCRWord |
Per-word text, confidence, handwriting flag, bounding box |
BarcodeResult |
Decoded barcode type + value per page |
SelectionMark |
Checkbox/radio state + confidence per page |
BoundingRegion |
Rectangular bounding box (page, x, y, width, height) |
OCRPageResult |
Aggregation of words, barcodes, selection marks per page |
OCRResult |
Collection of page results + full Markdown content |
Auto-synced from wiki/ on the main repo. Edit there, not here — direct wiki edits will be overwritten.