From 4e1d96d6c45f4f454b03c23bb72573bde3622390 Mon Sep 17 00:00:00 2001 From: Krista Pratico Date: Fri, 7 Apr 2023 17:37:00 -0700 Subject: [PATCH] [FR] add document annotations, images, formulas, barcodes to DocumentPage (#29710) * add document annotations, images, formulas, barcodes to DocumentPage * expose new page properties like we do with others * fix lint and tests * fix polygon access --- .vscode/cspell.json | 4 +- .../azure-ai-formrecognizer/CHANGELOG.md | 2 + .../azure/ai/formrecognizer/__init__.py | 8 + .../azure/ai/formrecognizer/_models.py | 359 +++++++++++++++++- .../tests/test_repr.py | 85 ++++- .../tests/test_to_dict_v3.py | 234 ++++++++++++ 6 files changed, 686 insertions(+), 6 deletions(-) diff --git a/.vscode/cspell.json b/.vscode/cspell.json index f98b805a58a9..bd025731a5b1 100644 --- a/.vscode/cspell.json +++ b/.vscode/cspell.json @@ -652,7 +652,9 @@ "mymodel", "heif", "racwd", - "rrggbb" + "rrggbb", + "UPCA", + "UPCE" ] }, { diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/CHANGELOG.md b/sdk/formrecognizer/azure-ai-formrecognizer/CHANGELOG.md index 4e134c5c35af..beaad9822ada 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/CHANGELOG.md +++ b/sdk/formrecognizer/azure-ai-formrecognizer/CHANGELOG.md @@ -20,6 +20,8 @@ - Added property `code` to `CurrencyValue`. - Added properties `unit`, `city_district`, `state_district`, `suburb`, `house`, and `level` to `AddressValue`. - Added "boolean" `value_type` and `bool` `value` to `DocumentField`. +- Added properties `annotations`, `images`, `formulas`, and `barcodes` to `DocumentPage`. +- Added models `DocumentAnnotation`, `DocumentImage`, `DocumentFormula`, and `DocumentBarcode`. ### Breaking Changes diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/__init__.py b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/__init__.py index 928f86a54032..3da270964475 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/__init__.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/__init__.py @@ -68,6 +68,10 @@ DocumentAnalysisInnerError, TargetAuthorization, QuotaDetails, + DocumentFormula, + DocumentImage, + DocumentBarcode, + DocumentAnnotation, ) from ._generated.models import ( # patched models ClassifierDocumentTypeDetails, @@ -146,6 +150,10 @@ "AzureBlobFileListSource", "AzureBlobContentSource", "QuotaDetails", + "DocumentFormula", + "DocumentImage", + "DocumentBarcode", + "DocumentAnnotation", ] __VERSION__ = VERSION diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_models.py b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_models.py index 6da760e0621f..484a15f4b895 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_models.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_models.py @@ -2867,8 +2867,287 @@ def from_dict(cls, data: Dict) -> "DocumentParagraph": ) -class DocumentPage: - """Content and layout elements extracted from a page of the input.""" +class DocumentAnnotation: + """An annotation object that represents a visual annotation in the document, + such as checks ✓ and crosses X. + """ + + kind: str + """Annotation kind. Known values are: "check", "cross".""" + polygon: Sequence[Point] + """Bounding polygon of the annotation.""" + confidence: float + """Confidence of correctly extracting the annotation.""" + + def __init__( + self, + **kwargs: Any + ) -> None: + self.kind = kwargs.get("kind", None) + self.polygon = kwargs.get("polygon", None) + self.confidence = kwargs.get("confidence", None) + + @classmethod + def _from_generated(cls, annotation): + return cls( + kind=annotation.kind, + polygon=get_polygon(annotation), + confidence=annotation.confidence + ) + + def __repr__(self) -> str: + return ( + f"DocumentAnnotation(kind={self.kind}, polygon={self.polygon}, confidence={self.confidence})" + ) + + def to_dict(self) -> Dict[str, Any]: + """Returns a dict representation of DocumentAnnotation.""" + return { + "kind": self.kind, + "polygon": [f.to_dict() for f in self.polygon] + if self.polygon + else [], + "confidence": self.confidence, + } + + @classmethod + def from_dict(cls, data: Dict[str, Any]) -> "DocumentAnnotation": + """Converts a dict in the shape of a DocumentAnnotation to the model itself. + + :param Dict data: A dictionary in the shape of DocumentAnnotation. + :return: DocumentAnnotation + :rtype: DocumentAnnotation + """ + return cls( + kind=data.get("kind", None), + polygon=[Point.from_dict(v) for v in data.get("polygon")] # type: ignore + if len(data.get("polygon", [])) > 0 + else [], + confidence=data.get("confidence", None), + ) + + +class DocumentBarcode: + """A barcode object.""" + + kind: str + """Barcode kind. Known values are "QRCode", "PDF417", "UPCA", "UPCE", + "Code39", "Code128", "EAN8", "EAN13", "DataBar", "Code93", "Codabar", "DataBarExpanded", "ITF", + "MicroQRCode", "Aztec", "DataMatrix", "MaxiCode".""" + value: str + """Barcode value.""" + polygon: Sequence[Point] + """Bounding polygon of the barcode.""" + span: DocumentSpan + """Location of the barcode in the reading order concatenated content.""" + confidence: float + """Confidence of correctly extracting the barcode.""" + + def __init__( + self, + **kwargs: Any + ) -> None: + self.kind = kwargs.get("kind", None) + self.value = kwargs.get("value", None) + self.polygon = kwargs.get("polygon", None) + self.span = kwargs.get("span", None) + self.confidence = kwargs.get("confidence", None) + + @classmethod + def _from_generated(cls, barcode): + return cls( + kind=barcode.kind, + value=barcode.value, + span=DocumentSpan._from_generated(barcode.span) + if barcode.span + else None, + polygon=get_polygon(barcode) if barcode.polygon else [], + confidence=barcode.confidence + ) + + def __repr__(self) -> str: + return ( + f"DocumentBarcode(kind={self.kind}, polygon={self.polygon}, confidence={self.confidence}, " + f"value={self.value}, span={repr(self.span)})" + ) + + def to_dict(self) -> Dict[str, Any]: + """Returns a dict representation of DocumentBarcode.""" + return { + "kind": self.kind, + "polygon": [f.to_dict() for f in self.polygon] + if self.polygon + else [], + "confidence": self.confidence, + "span": self.span.to_dict() if self.span else None, + "value": self.value, + } + + @classmethod + def from_dict(cls, data: Dict[str, Any]) -> "DocumentBarcode": + """Converts a dict in the shape of a DocumentBarcode to the model itself. + + :param Dict data: A dictionary in the shape of DocumentBarcode. + :return: DocumentBarcode + :rtype: DocumentBarcode + """ + return cls( + kind=data.get("kind", None), + polygon=[Point.from_dict(v) for v in data.get("polygon")] # type: ignore + if len(data.get("polygon", [])) > 0 + else [], + confidence=data.get("confidence", None), + span=DocumentSpan.from_dict(data.get("span")) if data.get("span") else None, # type: ignore + value=data.get("value", None), + ) + + +class DocumentFormula: + """A formula object.""" + + kind: str + """Formula kind. Known values are "inline", "display".""" + value: str + """LaTex expression describing the formula.""" + polygon: Sequence[Point] + """Bounding polygon of the formula.""" + span: DocumentSpan + """Location of the formula in the reading order concatenated content.""" + confidence: float + """Confidence of correctly extracting the formula.""" + + def __init__( + self, + **kwargs: Any + ) -> None: + self.kind = kwargs.get("kind", None) + self.value = kwargs.get("value", None) + self.polygon = kwargs.get("polygon", None) + self.span = kwargs.get("span", None) + self.confidence = kwargs.get("confidence", None) + + @classmethod + def _from_generated(cls, formula): + return cls( + kind=formula.kind, + value=formula.value, + span=DocumentSpan._from_generated(formula.span) + if formula.span + else None, + polygon=get_polygon(formula) if formula.polygon else [], + confidence=formula.confidence + ) + + def __repr__(self) -> str: + return ( + f"DocumentFormula(kind={self.kind}, polygon={self.polygon}, confidence={self.confidence}, " + f"value={self.value}, span={repr(self.span)})" + ) + + def to_dict(self) -> Dict[str, Any]: + """Returns a dict representation of DocumentFormula.""" + return { + "kind": self.kind, + "polygon": [f.to_dict() for f in self.polygon] + if self.polygon + else [], + "confidence": self.confidence, + "span": self.span.to_dict() if self.span else None, + "value": self.value, + } + + @classmethod + def from_dict(cls, data: Dict[str, Any]) -> "DocumentFormula": + """Converts a dict in the shape of a DocumentFormula to the model itself. + + :param Dict data: A dictionary in the shape of DocumentFormula. + :return: DocumentFormula + :rtype: DocumentFormula + """ + return cls( + kind=data.get("kind", None), + polygon=[Point.from_dict(v) for v in data.get("polygon")] # type: ignore + if len(data.get("polygon", [])) > 0 + else [], + confidence=data.get("confidence", None), + span=DocumentSpan.from_dict(data.get("span")) if data.get("span") else None, # type: ignore + value=data.get("value", None), + ) + + +class DocumentImage: + """An image object detected in the page.""" + + page_number: int + """1-based page number of the page that contains the image.""" + polygon: Sequence[Point] + """Bounding polygon of the image.""" + span: DocumentSpan + """Location of the image in the reading order concatenated content.""" + confidence: float + """Confidence of correctly identifying the image.""" + + def __init__( + self, + **kwargs: Any + ) -> None: + self.page_number = kwargs.get("page_number", None) + self.polygon = kwargs.get("polygon", None) + self.span = kwargs.get("span", None) + self.confidence = kwargs.get("confidence", None) + + @classmethod + def _from_generated(cls, image): + return cls( + page_number=image.page_number, + span=DocumentSpan._from_generated(image.span) + if image.span + else None, + polygon=get_polygon(image) if image.polygon else [], + confidence=image.confidence + ) + + def __repr__(self) -> str: + return ( + f"DocumentImage(page_number={self.page_number}, polygon={self.polygon}, confidence={self.confidence}, " + f"span={repr(self.span)})" + ) + + def to_dict(self) -> Dict[str, Any]: + """Returns a dict representation of DocumentImage.""" + return { + "page_number": self.page_number, + "polygon": [f.to_dict() for f in self.polygon] + if self.polygon + else [], + "confidence": self.confidence, + "span": self.span.to_dict() if self.span else None, + } + + @classmethod + def from_dict(cls, data: Dict[str, Any]) -> "DocumentImage": + """Converts a dict in the shape of a DocumentImage to the model itself. + + :param Dict data: A dictionary in the shape of DocumentImage. + :return: DocumentImage + :rtype: DocumentImage + """ + return cls( + page_number=data.get("page_number", None), + polygon=[Point.from_dict(v) for v in data.get("polygon")] # type: ignore + if len(data.get("polygon", [])) > 0 + else [], + confidence=data.get("confidence", None), + span=DocumentSpan.from_dict(data.get("span")) if data.get("span") else None, # type: ignore + ) + + +class DocumentPage: # pylint: disable=too-many-instance-attributes + """Content and layout elements extracted from a page of the input. + + .. versionadded:: 2023-02-28-preview + The *kind*, *annotations*, *barcodes*, *formulas*, and *images* properties. + """ page_number: int """1-based page number in the input document.""" @@ -2892,6 +3171,17 @@ class DocumentPage: lines: Optional[List[DocumentLine]] """Extracted lines from the page, potentially containing both textual and visual elements.""" + kind: str + """Kind of document page. Known values are: "document", "sheet", "slide", + "image".""" + annotations: List[DocumentAnnotation] + """Extracted annotations from the page.""" + barcodes: List[DocumentBarcode] + """Extracted barcodes from the page.""" + formulas: List[DocumentFormula] + """Extracted formulas from the page""" + images: List[DocumentImage] + """Extracted images from the page.""" def __init__(self, **kwargs: Any) -> None: self.page_number = kwargs.get("page_number", None) @@ -2903,9 +3193,20 @@ def __init__(self, **kwargs: Any) -> None: self.words = kwargs.get("words", None) self.selection_marks = kwargs.get("selection_marks", None) self.lines = kwargs.get("lines", None) + self.kind = kwargs.get("kind", None) + self.annotations = kwargs.get("annotations", None) + self.barcodes = kwargs.get("barcodes", None) + self.formulas = kwargs.get("formulas", None) + self.images = kwargs.get("images", None) @classmethod def _from_generated(cls, page): + kind = page.kind if hasattr(page, "kind") else None + annotations = page.annotations if hasattr(page, "annotations") else None + barcodes = page.barcodes if hasattr(page, "barcodes") else None + formulas = page.formulas if hasattr(page, "formulas") else None + images = page.images if hasattr(page, "images") else None + return cls( page_number=page.page_number, angle=adjust_text_angle(page.angle) @@ -2926,6 +3227,31 @@ def _from_generated(cls, page): if page.selection_marks else [], spans=prepare_document_spans(page.spans), + kind=kind, + annotations=[ + DocumentAnnotation._from_generated(annotation) + for annotation in annotations + ] + if annotations + else [], + barcodes=[ + DocumentBarcode._from_generated(barcode) + for barcode in barcodes + ] + if barcodes + else [], + formulas=[ + DocumentBarcode._from_generated(formula) + for formula in formulas + ] + if formulas + else [], + images=[ + DocumentImage._from_generated(image) + for image in images + ] + if images + else [], ) def __repr__(self) -> str: @@ -2933,7 +3259,8 @@ def __repr__(self) -> str: f"DocumentPage(page_number={self.page_number}, angle={self.angle}, " f"width={self.width}, height={self.height}, unit={self.unit}, lines={repr(self.lines)}, " f"words={repr(self.words)}, selection_marks={repr(self.selection_marks)}, " - f"spans={repr(self.spans)})" + f"spans={repr(self.spans)}, kind={self.kind}, annotations={repr(self.annotations)}, " + f"barcodes={repr(self.barcodes)}, formulas={repr(self.formulas)}, images={repr(self.images)})" ) def to_dict(self) -> Dict: @@ -2956,6 +3283,19 @@ def to_dict(self) -> Dict: "spans": [f.to_dict() for f in self.spans] if self.spans else [], + "kind": self.kind, + "annotations": [f.to_dict() for f in self.annotations] + if self.annotations + else [], + "barcodes": [f.to_dict() for f in self.barcodes] + if self.barcodes + else [], + "formulas": [f.to_dict() for f in self.formulas] + if self.formulas + else [], + "images": [f.to_dict() for f in self.images] + if self.images + else [], } @classmethod @@ -2984,6 +3324,19 @@ def from_dict(cls, data: Dict) -> "DocumentPage": spans=[DocumentSpan.from_dict(v) for v in data.get("spans")] # type: ignore if len(data.get("spans", [])) > 0 else [], + kind=data.get("kind", None), + annotations=[DocumentAnnotation.from_dict(v) for v in data.get("annotations")] # type: ignore + if len(data.get("annotations", [])) > 0 + else [], + barcodes=[DocumentBarcode.from_dict(v) for v in data.get("barcodes")] # type: ignore + if len(data.get("barcodes", [])) > 0 + else [], + formulas=[DocumentFormula.from_dict(v) for v in data.get("formulas")] # type: ignore + if len(data.get("formulas", [])) > 0 + else [], + images=[DocumentImage.from_dict(v) for v in data.get("images")] # type: ignore + if len(data.get("images", [])) > 0 + else [], ) diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_repr.py b/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_repr.py index 30d0b8038997..45f6ed7edea2 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_repr.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_repr.py @@ -298,7 +298,77 @@ def document_selection_mark(bounding_box, document_span): return model, model_repr @pytest.fixture -def document_page(document_span, document_word, document_selection_mark, document_line): +def document_annotation(bounding_box, document_span): + model = _models.DocumentAnnotation( + kind="check", + polygon=bounding_box[0], + confidence=0.8 + ) + model_repr = "DocumentAnnotation(kind={}, polygon={}, confidence={})".format( + "check", + bounding_box[1], + 0.8, + ) + assert repr(model) == model_repr + return model, model_repr + +@pytest.fixture +def document_barcode(bounding_box, document_span): + model = _models.DocumentBarcode( + kind="QRCode", + value="15", + polygon=bounding_box[0], + span=document_span[0], + confidence=0.8 + ) + model_repr = "DocumentBarcode(kind={}, polygon={}, confidence={}, value={}, span={})".format( + "QRCode", + bounding_box[1], + 0.8, + "15", + document_span[1], + ) + assert repr(model) == model_repr + return model, model_repr + +@pytest.fixture +def document_formula(bounding_box, document_span): + model = _models.DocumentFormula( + kind="inline", + value="2+2=4", + polygon=bounding_box[0], + span=document_span[0], + confidence=0.8 + ) + model_repr = "DocumentFormula(kind={}, polygon={}, confidence={}, value={}, span={})".format( + "inline", + bounding_box[1], + 0.8, + "2+2=4", + document_span[1], + ) + assert repr(model) == model_repr + return model, model_repr + +@pytest.fixture +def document_image(bounding_box, document_span): + model = _models.DocumentImage( + page_number=1, + polygon=bounding_box[0], + span=document_span[0], + confidence=0.8 + ) + model_repr = "DocumentImage(page_number={}, polygon={}, confidence={}, span={})".format( + 1, + bounding_box[1], + 0.8, + document_span[1], + ) + assert repr(model) == model_repr + return model, model_repr + +@pytest.fixture +def document_page(document_span, document_word, document_selection_mark, document_line, document_annotation, document_formula, document_image, document_barcode): model = _models.DocumentPage( page_number=1, angle=120.0, @@ -309,8 +379,14 @@ def document_page(document_span, document_word, document_selection_mark, documen words=[document_word[0]], selection_marks=[document_selection_mark[0]], lines=[document_line[0]], + kind="document", + annotations=[document_annotation[0]], + formulas=[document_formula[0]], + images=[document_image[0]], + barcodes=[document_barcode[0]], ) - model_repr = "DocumentPage(page_number={}, angle={}, width={}, height={}, unit={}, lines=[{}], words=[{}], selection_marks=[{}], spans=[{}])".format( + model_repr = "DocumentPage(page_number={}, angle={}, width={}, height={}, unit={}, lines=[{}], words=[{}], selection_marks=[{}], spans=[{}], " \ + "kind={}, annotations=[{}], barcodes=[{}], formulas=[{}], images=[{}])".format( 1, 120.0, 8.0, @@ -320,6 +396,11 @@ def document_page(document_span, document_word, document_selection_mark, documen document_word[1], document_selection_mark[1], document_span[1], + "document", + document_annotation[1], + document_barcode[1], + document_formula[1], + document_image[1], ) assert repr(model) == model_repr return model, model_repr diff --git a/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_to_dict_v3.py b/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_to_dict_v3.py index 2dc00bc15687..68350e62393f 100644 --- a/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_to_dict_v3.py +++ b/sdk/formrecognizer/azure-ai-formrecognizer/tests/test_to_dict_v3.py @@ -697,6 +697,60 @@ def test_document_page_to_dict(self): ], ), ], + kind="document", + annotations=[ + _models.DocumentAnnotation( + kind="check", + polygon=[ + _models.Point(1427.0, 1669.0), + _models.Point(1527.0, 1669.0), + _models.Point(1527.0, 1698.0), + _models.Point(1427.0, 1698.0), + ], + confidence=0.8 + ) + ], + barcodes=[ + _models.DocumentBarcode( + kind="QRCode", + value="15", + polygon=[ + _models.Point(1427.0, 1669.0), + _models.Point(1527.0, 1669.0), + _models.Point(1527.0, 1698.0), + _models.Point(1427.0, 1698.0), + ], + span=_models.DocumentSpan(offset=5, length=2), + confidence=0.8 + ) + ], + formulas=[ + _models.DocumentFormula( + kind="inline", + value="2+2=4", + polygon=[ + _models.Point(1427.0, 1669.0), + _models.Point(1527.0, 1669.0), + _models.Point(1527.0, 1698.0), + _models.Point(1427.0, 1698.0), + ], + span=_models.DocumentSpan(offset=5, length=2), + confidence=0.8 + ) + ], + images=[ + _models.DocumentImage( + page_number=1, + polygon=[ + _models.Point(1427.0, 1669.0), + _models.Point(1527.0, 1669.0), + _models.Point(1527.0, 1698.0), + _models.Point(1427.0, 1698.0), + ], + span=_models.DocumentSpan(offset=5, length=2), + confidence=0.8 + ) + ] ) d = model.to_dict() @@ -762,6 +816,69 @@ def test_document_page_to_dict(self): ], }, ], + "kind": "document", + "annotations": [ + { + "kind": "check", + "polygon": [ + {"x": 1427.0, "y": 1669.0}, + {"x": 1527.0, "y": 1669.0}, + {"x": 1527.0, "y": 1698.0}, + {"x": 1427.0, "y": 1698.0} + ], + "confidence": 0.8 + } + ], + "barcodes": [ + { + "kind": "QRCode", + "polygon": [ + {"x": 1427.0, "y": 1669.0}, + {"x": 1527.0, "y": 1669.0}, + {"x": 1527.0, "y": 1698.0}, + {"x": 1427.0, "y": 1698.0} + ], + "confidence": 0.8, + "span": { + "offset": 5, + "length": 2 + }, + "value": "15" + } + ], + "formulas": [ + { + "kind": "inline", + "polygon": [ + {"x": 1427.0, "y": 1669.0}, + {"x": 1527.0, "y": 1669.0}, + {"x": 1527.0, "y": 1698.0}, + {"x": 1427.0, "y": 1698.0} + ], + "confidence": 0.8, + "span": { + "offset": 5, + "length": 2 + }, + "value": "2+2=4" + } + ], + "images": [ + { + "page_number": 1, + "polygon": [ + {"x": 1427.0, "y": 1669.0}, + {"x": 1527.0, "y": 1669.0}, + {"x": 1527.0, "y": 1698.0}, + {"x": 1427.0, "y": 1698.0} + ], + "confidence": 0.8, + "span": { + "offset": 5, + "length": 2 + } + } + ] } assert d == final @@ -1181,6 +1298,60 @@ def test_analyze_result_to_dict(self): spans=[_models.DocumentSpan(offset=5, length=2)], ), ], + kind="document", + annotations=[ + _models.DocumentAnnotation( + kind="check", + polygon=[ + _models.Point(1427.0, 1669.0), + _models.Point(1527.0, 1669.0), + _models.Point(1527.0, 1698.0), + _models.Point(1427.0, 1698.0), + ], + confidence=0.8 + ) + ], + barcodes=[ + _models.DocumentBarcode( + kind="QRCode", + value="15", + polygon=[ + _models.Point(1427.0, 1669.0), + _models.Point(1527.0, 1669.0), + _models.Point(1527.0, 1698.0), + _models.Point(1427.0, 1698.0), + ], + span=_models.DocumentSpan(offset=5, length=2), + confidence=0.8 + ) + ], + formulas=[ + _models.DocumentFormula( + kind="inline", + value="2+2=4", + polygon=[ + _models.Point(1427.0, 1669.0), + _models.Point(1527.0, 1669.0), + _models.Point(1527.0, 1698.0), + _models.Point(1427.0, 1698.0), + ], + span=_models.DocumentSpan(offset=5, length=2), + confidence=0.8 + ) + ], + images=[ + _models.DocumentImage( + page_number=1, + polygon=[ + _models.Point(1427.0, 1669.0), + _models.Point(1527.0, 1669.0), + _models.Point(1527.0, 1698.0), + _models.Point(1427.0, 1698.0), + ], + span=_models.DocumentSpan(offset=5, length=2), + confidence=0.8 + ) + ] ), ], tables=[ @@ -1411,6 +1582,69 @@ def test_analyze_result_to_dict(self): ], }, ], + "kind": "document", + "annotations": [ + { + "kind": "check", + "polygon": [ + {"x": 1427.0, "y": 1669.0}, + {"x": 1527.0, "y": 1669.0}, + {"x": 1527.0, "y": 1698.0}, + {"x": 1427.0, "y": 1698.0} + ], + "confidence": 0.8 + } + ], + "barcodes": [ + { + "kind": "QRCode", + "polygon": [ + {"x": 1427.0, "y": 1669.0}, + {"x": 1527.0, "y": 1669.0}, + {"x": 1527.0, "y": 1698.0}, + {"x": 1427.0, "y": 1698.0} + ], + "confidence": 0.8, + "span": { + "offset": 5, + "length": 2 + }, + "value": "15" + } + ], + "formulas": [ + { + "kind": "inline", + "polygon": [ + {"x": 1427.0, "y": 1669.0}, + {"x": 1527.0, "y": 1669.0}, + {"x": 1527.0, "y": 1698.0}, + {"x": 1427.0, "y": 1698.0} + ], + "confidence": 0.8, + "span": { + "offset": 5, + "length": 2 + }, + "value": "2+2=4" + } + ], + "images": [ + { + "page_number": 1, + "polygon": [ + {"x": 1427.0, "y": 1669.0}, + {"x": 1527.0, "y": 1669.0}, + {"x": 1527.0, "y": 1698.0}, + {"x": 1427.0, "y": 1698.0} + ], + "confidence": 0.8, + "span": { + "offset": 5, + "length": 2 + } + } + ] }, ], "paragraphs": [