Skip to content

Commit 4197d67

Browse files
[FR] add document classifier to operation details (#29732)
1 parent fa77a41 commit 4197d67

File tree

7 files changed

+82
-18
lines changed

7 files changed

+82
-18
lines changed

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
`list_document_classifiers`, `get_document_classifier`, and `delete_document_classifier`.
1414
- Added support for classifying documents on `DocumentAnalysisClient`: `begin_classify_document` and `begin_classify_document_from_url`.
1515
- Added model `QuotaDetails` and property `custom_neural_document_model_builds` on `ResourceDetails`.
16-
- Added kind `documentClassifierBuild` to `OperationSummary`.
16+
- Added kind `documentClassifierBuild` to `OperationSummary` and `OperationDetails`.
1717
- Added property `expires_on` to `DocumentModelDetails` and `DocumentModelSummary`.
1818
- Added kind `formulaBlock` to `DocumentParagraph`.
1919
- Added property `common_name` to `DocumentKeyValuePair`.

sdk/formrecognizer/azure-ai-formrecognizer/assets.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,5 @@
22
"AssetsRepo": "Azure/azure-sdk-assets",
33
"AssetsRepoPrefixPath": "python",
44
"TagPrefix": "python/formrecognizer/azure-ai-formrecognizer",
5-
"Tag": "python/formrecognizer/azure-ai-formrecognizer_390e54ecb9"
5+
"Tag": "python/formrecognizer/azure-ai-formrecognizer_311c87465f"
66
}

sdk/formrecognizer/azure-ai-formrecognizer/azure/ai/formrecognizer/_models.py

+29-11
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,11 @@
1010
from enum import Enum
1111
from collections import namedtuple
1212
from azure.core import CaseInsensitiveEnumMeta
13-
from ._generated.v2023_02_28_preview.models import DocumentModelDetails as ModelDetails, Error
13+
from ._generated.v2023_02_28_preview.models import (
14+
DocumentModelDetails as ModelDetails,
15+
DocumentClassifierDetails as ClassifierDetails,
16+
Error
17+
)
1418
from ._generated.models import ClassifierDocumentTypeDetails
1519
from ._helpers import (
1620
adjust_value_type,
@@ -3700,7 +3704,8 @@ class OperationSummary:
37003704
created, and more.
37013705
37023706
Note that operation information only persists for 24 hours. If the operation was successful,
3703-
the model can be accessed using the :func:`~get_document_model` or :func:`~list_document_models` APIs.
3707+
the model can be accessed using the :func:`~get_document_model`, :func:`~list_document_models`,
3708+
:func:`~get_document_classifier`, :func:`~list_document_classifiers` APIs.
37043709
To find out why an operation failed, use :func:`~get_operation` and provide the `operation_id`.
37053710
37063711
.. versionadded:: 2023-02-28-preview
@@ -3800,10 +3805,11 @@ class OperationDetails(OperationSummary):
38003805
error of the operation if it has completed.
38013806
38023807
Note that operation information only persists for 24 hours. If the operation was successful,
3803-
the model can also be accessed using the :func:`~get_document_model` or :func:`~list_document_models` APIs.
3808+
the model can also be accessed using the :func:`~get_document_model`, :func:`~list_document_models`,
3809+
:func:`~get_document_classifier`, :func:`~list_document_classifiers` APIs.
38043810
38053811
.. versionadded:: 2023-02-28-preview
3806-
The `documentClassifierBuild` kind.
3812+
The `documentClassifierBuild` kind and `DocumentClassifierDetails` result.
38073813
"""
38083814
operation_id: str
38093815
"""Operation ID."""
@@ -3824,10 +3830,9 @@ class OperationDetails(OperationSummary):
38243830
error: Optional[DocumentAnalysisError]
38253831
"""Encountered error, includes the error code, message, and details for why
38263832
the operation failed."""
3827-
result: Optional[DocumentModelDetails]
3828-
"""Operation result upon success. Returns a DocumentModelDetails which contains
3829-
all information about the model including the doc types
3830-
and fields it can analyze from documents."""
3833+
result: Optional[Union[DocumentModelDetails, DocumentClassifierDetails]]
3834+
"""Operation result upon success. Returns a DocumentModelDetails or DocumentClassifierDetails
3835+
which contains all the information about the model."""
38313836
api_version: Optional[str]
38323837
"""API version used to create this operation."""
38333838
tags: Optional[Dict[str, str]]
@@ -3871,6 +3876,14 @@ def from_dict(cls, data: Dict) -> "OperationDetails":
38713876
:return: OperationDetails
38723877
:rtype: OperationDetails
38733878
"""
3879+
3880+
kind = data.get("kind", None)
3881+
if kind == "documentClassifierBuild":
3882+
result = \
3883+
DocumentClassifierDetails.from_dict(data.get("result")) if data.get("result") else None # type: ignore
3884+
else:
3885+
result = \
3886+
DocumentModelDetails.from_dict(data.get("result")) if data.get("result") else None # type: ignore
38743887
return cls(
38753888
operation_id=data.get("operation_id", None),
38763889
status=data.get("status", None),
@@ -3879,7 +3892,7 @@ def from_dict(cls, data: Dict) -> "OperationDetails":
38793892
last_updated_on=data.get("last_updated_on", None),
38803893
kind=data.get("kind", None),
38813894
resource_location=data.get("resource_location", None),
3882-
result=DocumentModelDetails.from_dict(data.get("result")) if data.get("result") else None, # type: ignore
3895+
result=result,
38833896
error=DocumentAnalysisError.from_dict(data.get("error")) if data.get("error") else None, # type: ignore
38843897
api_version=data.get("api_version", None),
38853898
tags=data.get("tags", {}),
@@ -3888,6 +3901,12 @@ def from_dict(cls, data: Dict) -> "OperationDetails":
38883901
@classmethod
38893902
def _from_generated(cls, op, api_version): # pylint: disable=arguments-differ
38903903
deserialize = _get_deserialize(api_version)
3904+
if op.kind == "documentClassifierBuild":
3905+
result = DocumentClassifierDetails._from_generated(deserialize(ClassifierDetails, op.result)) \
3906+
if op.result else None
3907+
else:
3908+
result = DocumentModelDetails._from_generated(deserialize(ModelDetails, op.result)) \
3909+
if op.result else None
38913910
return cls(
38923911
operation_id=op.operation_id,
38933912
status=op.status,
@@ -3896,8 +3915,7 @@ def _from_generated(cls, op, api_version): # pylint: disable=arguments-differ
38963915
last_updated_on=op.last_updated_date_time,
38973916
kind=op.kind,
38983917
resource_location=op.resource_location,
3899-
result=DocumentModelDetails._from_generated(deserialize(ModelDetails, op.result))
3900-
if op.result else None,
3918+
result=result,
39013919
error=DocumentAnalysisError._from_generated(deserialize(Error, op.error))
39023920
if op.error else None,
39033921
api_version=op.api_version,

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

+4-1
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,10 @@ async def sample_get_operations_async():
6262
print("My {} operation is completed.".format(operation_info.kind))
6363
result = operation_info.result
6464
if result is not None:
65-
print("Model ID: {}".format(result.model_id))
65+
if operation_info.kind == "documentClassifierBuild":
66+
print(f"Classifier ID: {result.classifier_id}")
67+
else:
68+
print("Model ID: {}".format(result.model_id))
6669
elif operation_info.status == "failed":
6770
print("My {} operation failed.".format(operation_info.kind))
6871
error = operation_info.error

sdk/formrecognizer/azure-ai-formrecognizer/samples/v3.2/sample_get_operations.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,10 @@ def sample_get_operations():
5858
print("My {} operation is completed.".format(operation_info.kind))
5959
result = operation_info.result
6060
if result is not None:
61-
print("Model ID: {}".format(result.model_id))
61+
if operation_info.kind == "documentClassifierBuild":
62+
print(f"Classifier ID: {result.classifier_id}")
63+
else:
64+
print("Model ID: {}".format(result.model_id))
6265
elif operation_info.status == "failed":
6366
print("My {} operation failed.".format(operation_info.kind))
6467
error = operation_info.error

sdk/formrecognizer/azure-ai-formrecognizer/tests/test_dmac_mgmt.py

+22-2
Original file line numberDiff line numberDiff line change
@@ -157,11 +157,14 @@ def test_get_list_operations(self, client, **kwargs):
157157
assert op.kind
158158
assert op.resource_location
159159
if op.status == "succeeded":
160-
successful_op = op
160+
if op.kind != "documentClassifierBuild":
161+
successful_op = op
162+
else:
163+
successful_classifier_op = op
161164
if op.status == "failed":
162165
failed_op = op
163166

164-
# check successful op
167+
# check successful document model op
165168
if successful_op:
166169
op = client.get_operation(successful_op.operation_id)
167170
# TODO not seeing this returned at the operation level
@@ -182,8 +185,25 @@ def test_get_list_operations(self, client, **kwargs):
182185
for key, field in doc_type.field_schema.items():
183186
assert key
184187
assert field["type"]
188+
if doc_type.build_mode == "neural":
189+
continue # neural models don't have field confidence
185190
assert doc_type.field_confidence[key] is not None
186191

192+
# check successful classifier model op
193+
if successful_classifier_op:
194+
op = client.get_operation(successful_classifier_op.operation_id)
195+
# test to/from dict
196+
op_dict = op.to_dict()
197+
op = OperationDetails.from_dict(op_dict)
198+
classifier = op.result
199+
assert classifier.api_version
200+
assert classifier.classifier_id
201+
assert classifier.created_on
202+
assert classifier.expires_on
203+
for doc_type, source in classifier.doc_types.items():
204+
assert doc_type
205+
assert source.azure_blob_source or source.azure_blob_file_list_source
206+
187207
# check failed op
188208
if failed_op:
189209
op = client.get_operation(failed_op.operation_id)

sdk/formrecognizer/azure-ai-formrecognizer/tests/test_dmac_mgmt_async.py

+21-1
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,10 @@ async def test_get_list_operations(self, client):
166166
assert op.kind
167167
assert op.resource_location
168168
if op.status == "succeeded":
169-
successful_op = op
169+
if op.kind != "documentClassifierBuild":
170+
successful_op = op
171+
else:
172+
successful_classifier_op = op
170173
if op.status == "failed":
171174
failed_op = op
172175

@@ -188,8 +191,25 @@ async def test_get_list_operations(self, client):
188191
for key, field in doc_type.field_schema.items():
189192
assert key
190193
assert field["type"]
194+
if doc_type.build_mode == "neural":
195+
continue # neural models don't have field confidence
191196
assert doc_type.field_confidence[key] is not None
192197

198+
# check successful classifier model op
199+
if successful_classifier_op:
200+
op = await client.get_operation(successful_classifier_op.operation_id)
201+
# test to/from dict
202+
op_dict = op.to_dict()
203+
op = OperationDetails.from_dict(op_dict)
204+
classifier = op.result
205+
assert classifier.api_version
206+
assert classifier.classifier_id
207+
assert classifier.created_on
208+
assert classifier.expires_on
209+
for doc_type, source in classifier.doc_types.items():
210+
assert doc_type
211+
assert source.azure_blob_source or source.azure_blob_file_list_source
212+
193213
# check failed op
194214
if failed_op:
195215
op = await client.get_operation(failed_op.operation_id)

0 commit comments

Comments
 (0)