Skip to content

Commit

Permalink
Consistency related changes in form recognizer (#11467)
Browse files Browse the repository at this point in the history
* page range + form field page number

* us receipt

* RecognizedReceipt

* Update sdk/formrecognizer/azure-ai-formrecognizer/CHANGELOG.md

* async

* comments
  • Loading branch information
rakshith91 authored May 18, 2020
1 parent 88fae6e commit 83915fa
Show file tree
Hide file tree
Showing 13 changed files with 88 additions and 76 deletions.
5 changes: 4 additions & 1 deletion sdk/formrecognizer/azure-ai-formrecognizer/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,16 @@
- Removed `get_form_training_client` from `FormRecognizerClient`
- Added `get_form_recognizer_client` to `FormTrainingClient`
- A `HttpResponseError` is now raised if a model with `status=="invalid"` is returned from the `begin_train_model()` or `train_model()` methods
- `PageRange` is renamed to `FormPageRange`
- `FormField` does not have a page_number.
- `begin_recognize_receipts` APIs now return `RecognizedReceipt` instead of `USReceipt`
- `USReceiptType` is renamed to `ReceiptType`

**New features**

- Authentication using `azure-identity` credentials now supported
- see the [Azure Identity documentation](https://github.com/Azure/azure-sdk-for-python/blob/master/sdk/identity/azure-identity/README.md) for more information


## 1.0.0b2 (2020-05-06)

**Fixes and improvements**
Expand Down
2 changes: 1 addition & 1 deletion sdk/formrecognizer/azure-ai-formrecognizer/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ See the full details regarding [authentication][cognitive_authentication] of cog

- Recognizing form fields and content using custom models trained to recognize your custom forms. These values are returned in a collection of `RecognizedForm` objects.
- Recognizing form content, including tables, lines and words, without the need to train a model. Form content is returned in a collection of `FormPage` objects.
- Recognizing common fields from US receipts, using a pre-trained receipt model on the Form Recognizer service. These fields and meta-data are returned in a collection of `USReceipt` objects.
- Recognizing common fields from US receipts, using a pre-trained receipt model on the Form Recognizer service. These fields and meta-data are returned in a collection of `RecognizedReceipt` objects.

### FormTrainingClient
`FormTrainingClient` provides operations for:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
CustomFormModelStatus,
FormContentType,
USReceipt,
USReceiptType,
ReceiptType,
USReceiptItem,
FormTable,
FormTableCell,
Expand All @@ -24,7 +24,7 @@
CustomFormModelInfo,
AccountProperties,
Point,
PageRange,
FormPageRange,
RecognizedForm,
FormField,
FieldText,
Expand All @@ -46,7 +46,7 @@
'FormContentType',
'FormContent',
'USReceipt',
'USReceiptType',
'ReceiptType',
'USReceiptItem',
'FormTable',
'FormTableCell',
Expand All @@ -55,7 +55,7 @@
'CustomFormModelInfo',
'AccountProperties',
'Point',
'PageRange',
'FormPageRange',
'RecognizedForm',
'FormField',
'FieldText',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,8 @@ def begin_recognize_receipts(self, stream, **kwargs):
:keyword int polling_interval: Waiting time between two polls for LRO operations
if no Retry-After header is present. Defaults to 5 seconds.
:return: An instance of an LROPoller. Call `result()` on the poller
object to return a list[:class:`~azure.ai.formrecognizer.USReceipt`].
:rtype: ~azure.core.polling.LROPoller[list[~azure.ai.formrecognizer.USReceipt]]
object to return a list[:class:`~azure.ai.formrecognizer.RecognizedReceipt`].
:rtype: ~azure.core.polling.LROPoller[list[~azure.ai.formrecognizer.RecognizedReceipt]]
:raises ~azure.core.exceptions.HttpResponseError:
.. admonition:: Example:
Expand Down Expand Up @@ -142,8 +142,8 @@ def begin_recognize_receipts_from_url(self, url, **kwargs):
:keyword int polling_interval: Waiting time between two polls for LRO operations
if no Retry-After header is present. Defaults to 5 seconds.
:return: An instance of an LROPoller. Call `result()` on the poller
object to return a list[:class:`~azure.ai.formrecognizer.USReceipt`].
:rtype: ~azure.core.polling.LROPoller[list[~azure.ai.formrecognizer.USReceipt]]
object to return a list[:class:`~azure.ai.formrecognizer.RecognizedReceipt`].
:rtype: ~azure.core.polling.LROPoller[list[~azure.ai.formrecognizer.RecognizedReceipt]]
:raises ~azure.core.exceptions.HttpResponseError:
.. admonition:: Example:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,17 +120,17 @@ def __new__(cls, x, y):
return super(Point, cls).__new__(cls, x, y)


class PageRange(namedtuple("PageRange", "first_page last_page")):
"""The 1-based page range of the document.
class FormPageRange(namedtuple("FormPageRange", "first_page last_page")):
"""The 1-based page range of the form.
:ivar int first_page: The first page number of the document.
:ivar int last_page: The last page number of the document.
:ivar int first_page: The first page number of the form.
:ivar int last_page: The last page number of the form.
"""

__slots__ = ()

def __new__(cls, first_page, last_page):
return super(PageRange, cls).__new__(cls, first_page, last_page)
return super(FormPageRange, cls).__new__(cls, first_page, last_page)


class FormContent(object):
Expand Down Expand Up @@ -162,7 +162,7 @@ class RecognizedForm(object):
this is the training-time label of the field. For models trained
without labels, a unique name is generated for each field.
:vartype fields: dict[str, ~azure.ai.formrecognizer.FormField]
:ivar ~azure.ai.formrecognizer.PageRange page_range:
:ivar ~azure.ai.formrecognizer.FormPageRange page_range:
The first and last page of the input form.
:ivar list[~azure.ai.formrecognizer.FormPage] pages:
A list of pages recognized from the input document. Contains lines,
Expand All @@ -179,8 +179,39 @@ def __repr__(self):
self.form_type, repr(self.fields), repr(self.page_range), repr(self.pages)
)[:1024]

class RecognizedReceipt(RecognizedForm):
"""Represents a receipt that has been recognized by a trained model.
class USReceipt(object): # pylint: disable=too-many-instance-attributes
:ivar str form_type:
The type of form the model identified the submitted form to be.
:ivar fields:
A dictionary of the fields found on the form. The fields dictionary
keys are the `name` of the field. For models trained with labels,
this is the training-time label of the field. For models trained
without labels, a unique name is generated for each field.
:vartype fields: dict[str, ~azure.ai.formrecognizer.FormField]
:ivar ~azure.ai.formrecognizer.FormPageRange page_range:
The first and last page of the input form.
:ivar list[~azure.ai.formrecognizer.FormPage] pages:
A list of pages recognized from the input document. Contains lines,
words, tables and page metadata.
:ivar ~azure.ai.formrecognizer.ReceiptType receipt_type:
The reciept type and confidence.
:ivar str receipt_locale: Defaults to "en-US".
"""
def __init__(self, **kwargs):
super(RecognizedReceipt, self).__init__(**kwargs)
self.receipt_type = kwargs.get("receipt_type", None)
self.receipt_locale = kwargs.get("receipt_locale", "en-US")

def __repr__(self):
return "RecognizedReceipt(form_type={}, fields={}, page_range={}, pages={}, " \
"receipt_type={}, receipt_locale={})".format(
self.form_type, repr(self.fields), repr(self.page_range), repr(self.pages),
repr(self.receipt_type), self.receipt_locale
)[:1024]

class USReceipt(RecognizedReceipt): # pylint: disable=too-many-instance-attributes
"""Extracted fields found on the US sales receipt. Provides
attributes for accessing common fields present in US sales receipts.
Expand All @@ -190,8 +221,6 @@ class USReceipt(object): # pylint: disable=too-many-instance-attributes
The name of the merchant.
:ivar ~azure.ai.formrecognizer.FormField merchant_phone_number:
The phone number associated with the merchant.
:ivar ~azure.ai.formrecognizer.USReceiptType receipt_type:
The reciept type and confidence.
:ivar list[~azure.ai.formrecognizer.USReceiptItem] receipt_items:
The purchased items found on the receipt.
:ivar ~azure.ai.formrecognizer.FormField subtotal:
Expand All @@ -209,33 +238,27 @@ class USReceipt(object): # pylint: disable=too-many-instance-attributes
:ivar fields:
A dictionary of the fields found on the receipt.
:vartype fields: dict[str, ~azure.ai.formrecognizer.FormField]
:ivar ~azure.ai.formrecognizer.PageRange page_range:
:ivar ~azure.ai.formrecognizer.FormPageRange page_range:
The first and last page of the input receipt.
:ivar list[~azure.ai.formrecognizer.FormPage] pages:
Contains page metadata such as page width, length, text angle, unit.
If `include_text_content=True` is passed, contains a list
of extracted text lines for each page in the input document.
:ivar str form_type: The type of form.
:ivar str receipt_locale: Defaults to "en-US".
"""

def __init__(self, **kwargs):
super(USReceipt, self).__init__(**kwargs)
self.merchant_address = kwargs.get("merchant_address", None)
self.merchant_name = kwargs.get("merchant_name", None)
self.merchant_phone_number = kwargs.get("merchant_phone_number", None)
self.receipt_type = kwargs.get("receipt_type", None)
self.receipt_items = kwargs.get("receipt_items", None)
self.subtotal = kwargs.get("subtotal", None)
self.tax = kwargs.get("tax", None)
self.tip = kwargs.get("tip", None)
self.total = kwargs.get("total", None)
self.transaction_date = kwargs.get("transaction_date", None)
self.transaction_time = kwargs.get("transaction_time", None)
self.fields = kwargs.get("fields", None)
self.page_range = kwargs.get("page_range", None)
self.pages = kwargs.get("pages", None)
self.form_type = kwargs.get("form_type", None)
self.receipt_locale = kwargs.get("receipt_locale", "en-US")

def __repr__(self):
return "USReceipt(merchant_address={}, merchant_name={}, merchant_phone_number={}, " \
Expand Down Expand Up @@ -264,8 +287,6 @@ class FormField(object):
:class:`~azure.ai.formrecognizer.FormField`, or list[:class:`~azure.ai.formrecognizer.FormField`]
:ivar float confidence:
Measures the degree of certainty of the recognition result. Value is between [0.0, 1.0].
:ivar int page_number:
The 1-based number of the page in which this content is present.
"""

def __init__(self, **kwargs):
Expand All @@ -274,7 +295,6 @@ def __init__(self, **kwargs):
self.name = kwargs.get("name", None)
self.value = kwargs.get("value", None)
self.confidence = kwargs.get("confidence", None)
self.page_number = kwargs.get("page_number", None)

@classmethod
def _from_generated(cls, field, value, read_result):
Expand All @@ -284,7 +304,6 @@ def _from_generated(cls, field, value, read_result):
value=get_field_value(field, value, read_result),
name=field,
confidence=adjust_confidence(value.confidence) if value else None,
page_number=value.page if value else None,
)


Expand All @@ -296,12 +315,11 @@ def _from_generated_unlabeled(cls, field, idx, page, read_result):
value=field.value.text,
name="field-" + str(idx),
confidence=adjust_confidence(field.confidence),
page_number=page,
)

def __repr__(self):
return "FormField(label_data={}, value_data={}, name={}, value={}, confidence={}, page_number={})".format(
repr(self.label_data), repr(self.value_data), self.name, repr(self.value), self.confidence, self.page_number
return "FormField(label_data={}, value_data={}, name={}, value={}, confidence={})".format(
repr(self.label_data), repr(self.value_data), self.name, repr(self.value), self.confidence
)[:1024]


Expand Down Expand Up @@ -495,7 +513,7 @@ def __repr__(self):
)[:1024]


class USReceiptType(object):
class ReceiptType(object):
"""The type of the analyzed US receipt and the confidence
value of that type.
Expand All @@ -516,7 +534,7 @@ def _from_generated(cls, item):
confidence=adjust_confidence(item.confidence)) if item else None

def __repr__(self):
return "USReceiptType(type={}, confidence={})".format(self.type, self.confidence)[:1024]
return "ReceiptType(type={}, confidence={})".format(self.type, self.confidence)[:1024]


class USReceiptItem(object):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@

from ._models import (
USReceipt,
USReceiptType,
ReceiptType,
FormField,
USReceiptItem,
FormPage,
FormLine,
FormTable,
FormTableCell,
PageRange,
FormPageRange,
RecognizedForm
)

Expand All @@ -29,7 +29,7 @@ def prepare_us_receipt(response):
for page in document_result:
if page.fields is None:
receipt = USReceipt(
page_range=PageRange(first_page=page.page_range[0], last_page=page.page_range[1]),
page_range=FormPageRange(first_page=page.page_range[0], last_page=page.page_range[1]),
pages=form_page[page.page_range[0]-1:page.page_range[1]],
form_type=page.doc_type,
)
Expand All @@ -47,7 +47,7 @@ def prepare_us_receipt(response):
page.fields.get("MerchantPhoneNumber"),
read_result,
),
receipt_type=USReceiptType._from_generated(page.fields.get("ReceiptType")),
receipt_type=ReceiptType._from_generated(page.fields.get("ReceiptType")),
receipt_items=USReceiptItem._from_generated(
page.fields.get("Items"), read_result
),
Expand All @@ -65,7 +65,7 @@ def prepare_us_receipt(response):
transaction_time=FormField._from_generated(
"TransactionTime", page.fields.get("TransactionTime"), read_result
),
page_range=PageRange(
page_range=FormPageRange(
first_page=page.page_range[0], last_page=page.page_range[1]
),
pages=form_page[page.page_range[0]-1:page.page_range[1]],
Expand Down Expand Up @@ -132,7 +132,7 @@ def prepare_unlabeled_result(response):
if unlabeled_fields:
unlabeled_fields = {field.name: field for field in unlabeled_fields}
form = RecognizedForm(
page_range=PageRange(
page_range=FormPageRange(
first_page=page.page,
last_page=page.page
),
Expand All @@ -152,7 +152,7 @@ def prepare_labeled_result(response, model_id):
result = []
for doc in response.analyze_result.document_results:
form = RecognizedForm(
page_range=PageRange(
page_range=FormPageRange(
first_page=doc.page_range[0],
last_page=doc.page_range[1]
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
from azure.core.credentials import AzureKeyCredential
from azure.core.credentials_async import AsyncTokenCredential
from .._models import (
USReceipt,
RecognizedReceipt,
FormPage,
RecognizedForm
)
Expand Down Expand Up @@ -91,7 +91,7 @@ async def recognize_receipts(
self,
stream: Union[bytes, IO[bytes]],
**kwargs: Any
) -> List["USReceipt"]:
) -> List["RecognizedReceipt"]:
"""Extract field text and semantic values from a given US sales receipt.
The input document must be of one of the supported content types - 'application/pdf',
'image/jpeg', 'image/png' or 'image/tiff'.
Expand All @@ -106,8 +106,8 @@ async def recognize_receipts(
see :class:`~azure.ai.formrecognizer.FormContentType`.
:keyword int polling_interval: Waiting time between two polls for LRO operations
if no Retry-After header is present. Defaults to 5 seconds.
:return: A list of USReceipt.
:rtype: list[~azure.ai.formrecognizer.USReceipt]
:return: A list of RecognizedReceipt.
:rtype: list[~azure.ai.formrecognizer.RecognizedReceipt]
:raises ~azure.core.exceptions.HttpResponseError:
.. admonition:: Example:
Expand Down Expand Up @@ -145,7 +145,7 @@ async def recognize_receipts_from_url(
self,
url: str,
**kwargs: Any
) -> List["USReceipt"]:
) -> List["RecognizedReceipt"]:
"""Extract field text and semantic values from a given US sales receipt.
The input document must be the location (Url) of the receipt to be analyzed.
Expand All @@ -156,8 +156,8 @@ async def recognize_receipts_from_url(
Whether or not to include text elements such as lines and words in addition to form fields.
:keyword int polling_interval: Waiting time between two polls for LRO operations
if no Retry-After header is present. Defaults to 5 seconds.
:return: A list of USReceipt.
:rtype: list[~azure.ai.formrecognizer.USReceipt]
:return: A list of RecognizedReceipt.
:rtype: list[~azure.ai.formrecognizer.RecognizedReceipt]
:raises ~azure.core.exceptions.HttpResponseError:
.. admonition:: Example:
Expand Down
Loading

0 comments on commit 83915fa

Please sign in to comment.