Skip to content

Commit 60ae7cf

Browse files
[formrecognizer] Sample + Migration guide improvements (Azure#26068)
* update receipt samples * update samples README * migration guide updates * update sample wording
1 parent 34bf60f commit 60ae7cf

12 files changed

+106
-112
lines changed

sdk/formrecognizer/azure-ai-formrecognizer/MIGRATION_GUIDE.md

+72-76
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,8 @@ Please refer to the [README][readme] for more information on these new clients.
5252

5353
Some terminology has changed to reflect the enhanced capabilities of the newest Form Recognizer service APIs. While the service is still called `Form Recognizer`, it is capable of much more than simple recognition and is not limited to documents that are `forms`. As a result, we've made the following broad changes to the terminology used throughout the SDK:
5454

55-
- The word `Document` has broadly replaced the word `Form.` The service supports a wide variety of documents and data-extraction scenarios, not merely limited to `forms.`
56-
- The word `Analyze` has broadly replaced the word `Recognize.` The document analysis operation executes a data extraction pipeline that supports more than just recognition.
55+
- The word `Document` has broadly replaced the word `Form.` The service supports a wide variety of documents and data-extraction scenarios, not merely limited to `forms`.
56+
- The word `Analyze` has broadly replaced the word `Recognize`. The document analysis operation executes a data extraction pipeline that supports more than just recognition.
5757
- Distinctions between `custom` and `prebuilt` models have broadly been eliminated. Prebuilt models are simply models that were created by the Form Recognizer service team and that exist within every Form Recognizer resource.
5858
- The concept of `model training` has broadly been replaced with `model creation`, `building a model`, or `model administration` (whatever is most appropriate in context), as not all model creation operations involve `training` a model from a data set. When referring to a model schema trained from a data set, we will use the term `document type` instead.
5959

@@ -106,7 +106,7 @@ document_model_admin_client = DocumentModelAdministrationClient(
106106
Differences between the versions:
107107
- `begin_analyze_document` and `begin_analyze_document_from_url` accept a string with the desired model ID for analysis. The model ID can be any of the prebuilt model IDs or a custom model ID.
108108
- Along with more consolidated analysis methods in the `DocumentAnalysisClient`, the return types have also been improved and remove the hierarchical dependencies between elements. An instance of the `AnalyzeResult` model is now returned which showcases important document elements, such as key-value pairs, tables, and document fields and values, among others, at the top level of the returned model. This can be contrasted with `RecognizedForm` which included more hierarchical relationships, for instance tables were an element of a `FormPage` and not a top-level element.
109-
- In the new version of the library, the functionality of `begin_recognize_content` has been added as a prebuilt model and can be called in library version `azure-ai-formrecognizer (3.2.x)` with `begin_analyze_document` by passing in the `prebuilt-layout` model ID. Similarly, to get general document information, such as key-value pairs and text layout, the `prebuilt-document` model ID can be used with `begin_analyze_document`. Additionally, passing in the `prebuilt-read` model was added to read information about pages and detected languages.
109+
- In the new version of the library, the functionality of `begin_recognize_content` has been added as a prebuilt model and can be called in library version `azure-ai-formrecognizer (3.2.x)` with `begin_analyze_document` by passing in the `prebuilt-layout` model ID. Similarly, to get general document information, such as key-value pairs and text layout, the `prebuilt-document` model ID can be used with `begin_analyze_document`. Additionally, the `prebuilt-read` model was added to read information about pages and detected languages.
110110
- When calling `begin_analyze_document` and `begin_analyze_document_from_url` the returned type is an `AnalyzeResult` object, while the various methods used with `FormRecognizerClient` return a list of `RecognizedForm`.
111111
- The `pages` keyword argument is a string with library version `azure-ai-formrecognizer (3.2.x)`. In `azure-ai-formrecognizer (3.1.x)`, `pages` was a list of strings.
112112
- The `include_field_elements` keyword argument is not supported with the `DocumentAnalysisClient`, text details are automatically included with API version `2022-08-31` and later.
@@ -169,14 +169,8 @@ with open(path_to_sample_documents, "rb") as f:
169169
receipts = poller.result()
170170

171171
for idx, receipt in enumerate(receipts.documents):
172-
print("--------Recognizing receipt #{}--------".format(idx + 1))
173-
receipt_type = receipt.fields.get("ReceiptType")
174-
if receipt_type:
175-
print(
176-
"Receipt Type: {} has confidence: {}".format(
177-
receipt_type.value, receipt_type.confidence
178-
)
179-
)
172+
print("--------Analysis of receipt #{}--------".format(idx + 1))
173+
print("Receipt type: {}".format(receipt.doc_type or "N/A"))
180174
merchant_name = receipt.fields.get("MerchantName")
181175
if merchant_name:
182176
print(
@@ -195,11 +189,11 @@ for idx, receipt in enumerate(receipts.documents):
195189
print("Receipt items:")
196190
for idx, item in enumerate(receipt.fields.get("Items").value):
197191
print("...Item #{}".format(idx + 1))
198-
item_name = item.value.get("Name")
199-
if item_name:
192+
item_description = item.value.get("Description")
193+
if item_description:
200194
print(
201-
"......Item Name: {} has confidence: {}".format(
202-
item_name.value, item_name.confidence
195+
"......Item Description: {} has confidence: {}".format(
196+
item_description.value, item_description.confidence
203197
)
204198
)
205199
item_quantity = item.value.get("Quantity")
@@ -230,9 +224,9 @@ for idx, receipt in enumerate(receipts.documents):
230224
subtotal.value, subtotal.confidence
231225
)
232226
)
233-
tax = receipt.fields.get("Tax")
227+
tax = receipt.fields.get("TotalTax")
234228
if tax:
235-
print("Tax: {} has confidence: {}".format(tax.value, tax.confidence))
229+
print("Total tax: {} has confidence: {}".format(tax.value, tax.confidence))
236230
tip = receipt.fields.get("Tip")
237231
if tip:
238232
print("Tip: {} has confidence: {}".format(tip.value, tip.confidence))
@@ -307,35 +301,37 @@ for idx, style in enumerate(result.styles):
307301
)
308302
)
309303

310-
for idx, page in enumerate(result.pages):
311-
print("----Analyzing layout from page #{}----".format(idx + 1))
304+
for page in result.pages:
305+
print("----Analyzing layout from page #{}----".format(page.page_number))
312306
print(
313307
"Page has width: {} and height: {}, measured with unit: {}".format(
314308
page.width, page.height, page.unit
315309
)
316310
)
317311

318312
for line_idx, line in enumerate(page.lines):
313+
words = line.get_words()
319314
print(
320-
"Line # {} has text content '{}' within bounding box '{}'".format(
315+
"...Line # {} has word count {} and text '{}' within bounding polygon '{}'".format(
321316
line_idx,
317+
len(words),
322318
line.content,
323-
line.bounding_box,
319+
line.polygon,
324320
)
325321
)
326322

327-
for word in page.words:
328-
print(
329-
"...Word '{}' has a confidence of {}".format(
330-
word.content, word.confidence
323+
for word in words:
324+
print(
325+
"......Word '{}' has a confidence of {}".format(
326+
word.content, word.confidence
327+
)
331328
)
332-
)
333329

334330
for selection_mark in page.selection_marks:
335331
print(
336-
"Selection mark is '{}' within bounding box '{}' and has a confidence of {}".format(
332+
"...Selection mark is '{}' within bounding polygon '{}' and has a confidence of {}".format(
337333
selection_mark.state,
338-
selection_mark.bounding_box,
334+
selection_mark.polygon,
339335
selection_mark.confidence,
340336
)
341337
)
@@ -351,22 +347,22 @@ for table_idx, table in enumerate(result.tables):
351347
"Table # {} location on page: {} is {}".format(
352348
table_idx,
353349
region.page_number,
354-
region.bounding_box,
350+
region.polygon,
355351
)
356352
)
357353
for cell in table.cells:
358354
print(
359-
"...Cell[{}][{}] has text '{}'".format(
355+
"...Cell[{}][{}] has content '{}'".format(
360356
cell.row_index,
361357
cell.column_index,
362358
cell.content,
363359
)
364360
)
365361
for region in cell.bounding_regions:
366362
print(
367-
"...content on page {} is within bounding box '{}'".format(
363+
"...content on page {} is within bounding polygon '{}'".format(
368364
region.page_number,
369-
region.bounding_box,
365+
region.polygon,
370366
)
371367
)
372368

@@ -385,11 +381,26 @@ with open(path_to_sample_documents, "rb") as f:
385381
result = poller.result()
386382

387383
for style in result.styles:
388-
print(
389-
"Document contains {} content".format(
390-
"handwritten" if style.is_handwritten else "no handwritten"
391-
)
392-
)
384+
if style.is_handwritten:
385+
print("Document contains handwritten content: ")
386+
print(",".join([result.content[span.offset:span.offset + span.length] for span in style.spans]))
387+
388+
print("----Key-value pairs found in document----")
389+
for kv_pair in result.key_value_pairs:
390+
if kv_pair.key:
391+
print(
392+
"Key '{}' found within '{}' bounding regions".format(
393+
kv_pair.key.content,
394+
kv_pair.key.bounding_regions,
395+
)
396+
)
397+
if kv_pair.value:
398+
print(
399+
"Value '{}' found within '{}' bounding regions\n".format(
400+
kv_pair.value.content,
401+
kv_pair.value.bounding_regions,
402+
)
403+
)
393404

394405
for page in result.pages:
395406
print("----Analyzing document from page #{}----".format(page.page_number))
@@ -400,26 +411,28 @@ for page in result.pages:
400411
)
401412

402413
for line_idx, line in enumerate(page.lines):
414+
words = line.get_words()
403415
print(
404-
"...Line # {} has text content '{}' within bounding box '{}'".format(
416+
"...Line # {} has {} words and text '{}' within bounding polygon '{}'".format(
405417
line_idx,
418+
len(words),
406419
line.content,
407-
line.bounding_box,
420+
line.polygon,
408421
)
409422
)
410423

411-
for word in page.words:
412-
print(
413-
"...Word '{}' has a confidence of {}".format(
414-
word.content, word.confidence
424+
for word in words:
425+
print(
426+
"......Word '{}' has a confidence of {}".format(
427+
word.content, word.confidence
428+
)
415429
)
416-
)
417430

418431
for selection_mark in page.selection_marks:
419432
print(
420-
"...Selection mark is '{}' within bounding box '{}' and has a confidence of {}".format(
433+
"...Selection mark is '{}' within bounding polygon '{}' and has a confidence of {}".format(
421434
selection_mark.state,
422-
selection_mark.bounding_box,
435+
selection_mark.polygon,
423436
selection_mark.confidence,
424437
)
425438
)
@@ -435,7 +448,7 @@ for table_idx, table in enumerate(result.tables):
435448
"Table # {} location on page: {} is {}".format(
436449
table_idx,
437450
region.page_number,
438-
region.bounding_box,
451+
region.polygon,
439452
)
440453
)
441454
for cell in table.cells:
@@ -448,26 +461,9 @@ for table_idx, table in enumerate(result.tables):
448461
)
449462
for region in cell.bounding_regions:
450463
print(
451-
"...content on page {} is within bounding box '{}'\n".format(
464+
"...content on page {} is within bounding polygon '{}'\n".format(
452465
region.page_number,
453-
region.bounding_box,
454-
)
455-
)
456-
457-
print("----Key-value pairs found in document----")
458-
for kv_pair in result.key_value_pairs:
459-
if kv_pair.key:
460-
print(
461-
"Key '{}' found within '{}' bounding regions".format(
462-
kv_pair.key.content,
463-
kv_pair.key.bounding_regions,
464-
)
465-
)
466-
if kv_pair.value:
467-
print(
468-
"Value '{}' found within '{}' bounding regions\n".format(
469-
kv_pair.value.content,
470-
kv_pair.value.bounding_regions,
466+
region.polygon,
471467
)
472468
)
473469
print("----------------------------------------")
@@ -539,6 +535,7 @@ for idx, form in enumerate(forms):
539535

540536
Analyze custom document with `3.2.x`:
541537
```python
538+
# Make sure your document's type is included in the list of document types the custom model can analyze
542539
with open(path_to_sample_documents, "rb") as f:
543540
poller = document_analysis_client.begin_analyze_document(
544541
model_id=model_id, document=f
@@ -548,8 +545,8 @@ result = poller.result()
548545
for idx, document in enumerate(result.documents):
549546
print("--------Analyzing document #{}--------".format(idx + 1))
550547
print("Document has type {}".format(document.doc_type))
551-
print("Document has document type confidence {}".format(document.confidence))
552-
print("Document was analyzed with model with ID {}".format(result.model_id))
548+
print("Document has confidence {}".format(document.confidence))
549+
print("Document was analyzed by model with ID {}".format(result.model_id))
553550
for name, field in document.fields.items():
554551
field_value = field.value if field.value else field.content
555552
print("......found field of type '{}' with value '{}' and with confidence {}".format(field.value_type, field_value, field.confidence))
@@ -566,22 +563,20 @@ for page in result.pages:
566563
word.content, word.confidence
567564
)
568565
)
569-
if page.selection_marks:
570-
print("\nSelection marks found on page {}".format(page.page_number))
571-
for selection_mark in page.selection_marks:
572-
print(
573-
"...Selection mark is '{}' and has a confidence of {}".format(
574-
selection_mark.state, selection_mark.confidence
575-
)
566+
for selection_mark in page.selection_marks:
567+
print(
568+
"...Selection mark is '{}' and has a confidence of {}".format(
569+
selection_mark.state, selection_mark.confidence
576570
)
571+
)
577572

578573
for i, table in enumerate(result.tables):
579574
print("\nTable {} can be found on page:".format(i + 1))
580575
for region in table.bounding_regions:
581576
print("...{}".format(i + 1, region.page_number))
582577
for cell in table.cells:
583578
print(
584-
"...Cell[{}][{}] has text '{}'".format(
579+
"...Cell[{}][{}] has content '{}'".format(
585580
cell.row_index, cell.column_index, cell.content
586581
)
587582
)
@@ -632,6 +627,7 @@ for doc in model.training_documents:
632627
```
633628

634629
Train a custom model with `3.2.x`:
630+
635631
Use `begin_build_document_model()` to build a custom document model. Please note that this method has a required `build_mode` parameter. See https://aka.ms/azsdk/formrecognizer/buildmode for more information about build modes. Additionally, `blob_container_url` is a required keyword-only parameter.
636632

637633
```python

sdk/formrecognizer/azure-ai-formrecognizer/samples/README.md

-2
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,6 @@ urlFragment: formrecognizer-samples
1717
1818
These code samples show common scenario operations with the Azure Form Recognizer client library.
1919

20-
These sample programs show common scenarios for the Form Recognizer client's offerings.
21-
2220
All of these samples need the endpoint to your Form Recognizer resource ([instructions on how to get endpoint][get-endpoint-instructions]), and your Form Recognizer API key ([instructions on how to get key][get-key-instructions]).
2321

2422
## Samples for client library versions 3.2.0 and later

sdk/formrecognizer/azure-ai-formrecognizer/samples/v3.2/async_samples/sample_analyze_identity_documents_async.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ async def analyze_identity_documents_async():
5555
id_documents = await poller.result()
5656

5757
for idx, id_document in enumerate(id_documents.documents):
58-
print("--------Recognizing ID document #{}--------".format(idx + 1))
58+
print("--------Analyzing ID document #{}--------".format(idx + 1))
5959
first_name = id_document.fields.get("FirstName")
6060
if first_name:
6161
print(

sdk/formrecognizer/azure-ai-formrecognizer/samples/v3.2/async_samples/sample_analyze_invoices_async.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ async def analyze_invoice_async():
5656
invoices = await poller.result()
5757

5858
for idx, invoice in enumerate(invoices.documents):
59-
print("--------Recognizing invoice #{}--------".format(idx + 1))
59+
print("--------Analyzing invoice #{}--------".format(idx + 1))
6060
vendor_name = invoice.fields.get("VendorName")
6161
if vendor_name:
6262
print(

sdk/formrecognizer/azure-ai-formrecognizer/samples/v3.2/async_samples/sample_analyze_receipts_async.py

+7-7
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ async def analyze_receipts_async():
5656
receipts = await poller.result()
5757

5858
for idx, receipt in enumerate(receipts.documents):
59-
print("--------Recognizing receipt #{}--------".format(idx + 1))
59+
print("--------Analysis of receipt #{}--------".format(idx + 1))
6060
print("Receipt type: {}".format(receipt.doc_type or "N/A"))
6161
merchant_name = receipt.fields.get("MerchantName")
6262
if merchant_name:
@@ -76,11 +76,11 @@ async def analyze_receipts_async():
7676
print("Receipt items:")
7777
for idx, item in enumerate(receipt.fields.get("Items").value):
7878
print("...Item #{}".format(idx + 1))
79-
item_name = item.value.get("Name")
80-
if item_name:
79+
item_description = item.value.get("Description")
80+
if item_description:
8181
print(
82-
"......Item Name: {} has confidence: {}".format(
83-
item_name.value, item_name.confidence
82+
"......Item Description: {} has confidence: {}".format(
83+
item_description.value, item_description.confidence
8484
)
8585
)
8686
item_quantity = item.value.get("Quantity")
@@ -111,9 +111,9 @@ async def analyze_receipts_async():
111111
subtotal.value, subtotal.confidence
112112
)
113113
)
114-
tax = receipt.fields.get("Tax")
114+
tax = receipt.fields.get("TotalTax")
115115
if tax:
116-
print("Tax: {} has confidence: {}".format(tax.value, tax.confidence))
116+
print("Total tax: {} has confidence: {}".format(tax.value, tax.confidence))
117117
tip = receipt.fields.get("Tip")
118118
if tip:
119119
print("Tip: {} has confidence: {}".format(tip.value, tip.confidence))

0 commit comments

Comments
 (0)