Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[text analytics] Updates to Healthcare design #16247

Merged
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
c00140c
Renamed healthcare methods
Jan 14, 2021
e69151c
Exposing job metadata on the healthcare polling operation
Jan 14, 2021
d005b70
Aligning with other similar work for Analyze
Feb 2, 2021
ac9faf0
Fixed merge conflicts
Feb 2, 2021
078e875
Regenerated with custom pollers; updated tests and a few other files
Feb 2, 2021
c2a09ff
Renamed HealthcareEntityLink -> HealthcareEntityDataSource and also r…
Feb 3, 2021
fb37651
Fixed missed renames in __init__.py
Feb 3, 2021
f827c6b
Updated links and other things in the readme
Feb 3, 2021
864b1b2
Updated samples readme
Feb 3, 2021
2649001
Merge branch 'master' of https://github.com/Azure/azure-sdk-for-pytho…
Feb 3, 2021
eed2d38
Reverted an unintentional change in analyze_sentiment
Feb 3, 2021
429c4ea
Moved cancellation to the poller; fixed some linting issues
Feb 4, 2021
ef6c210
Removed an unused model
Feb 4, 2021
91ba6a1
PR comments and updated changelog
Feb 4, 2021
a78decd
Added related_entities; Fixed merge conflicts
Feb 5, 2021
7da7797
Fixed a few issues caused by merge conflicts; made HealthcareEntity h…
Feb 5, 2021
0a14704
Fixed a problem with cancellation; updated samples
Feb 5, 2021
d952ded
Merge conflicts
Feb 5, 2021
82bc4e4
PR comments
Feb 5, 2021
03d68a7
PR comments
Feb 5, 2021
00c00a5
Fixed bidirectional check; updated/added tests
Feb 5, 2021
f2dedef
added a test for async
Feb 5, 2021
bae8200
PR comments and fixing test issues
Feb 5, 2021
4563059
Fixed a linting issue
Feb 5, 2021
f9e5776
PR comments and fixed a test issue
Feb 5, 2021
3745666
Fixed cancellation issue
Feb 5, 2021
0971671
Another cancellation test fix
Feb 5, 2021
7771a70
PR comments
Feb 5, 2021
acc58ed
Async syntax issue
Feb 5, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 14 additions & 14 deletions sdk/textanalytics/azure-ai-textanalytics/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Text Analytics is a cloud-based service that provides advanced natural language
* Personally Identifiable Information (PII) Entity Recognition
* Language Detection
* Key Phrase Extraction
* Healthcare Analysis (Gated Preview)
* Healthcare Entities Analysis (Gated Preview)

[Source code][source_code] | [Package (PyPI)][TA_pypi] | [API reference documentation][TA_ref_docs]| [Product documentation][TA_product_documentation] | [Samples][TA_samples]

Expand Down Expand Up @@ -205,7 +205,7 @@ The following section provides several code snippets covering some of the most c
* [Recognize PII Entities](#recognize-pii-entities "Recognize pii entities")
* [Extract Key Phrases](#extract-key-phrases "Extract key phrases")
* [Detect Language](#detect-language "Detect language")
* [Healthcare Analysis](#healthcare-analysis "Healthcare analysis")
* [Healthcare Entities Analysis](#healthcare-analysis "Healthcare entities analysis")
* [Batch Analysis](#batch-analysis "Batch analysis")

### Analyze sentiment
Expand Down Expand Up @@ -418,7 +418,7 @@ The returned response is a heterogeneous list of result and error objects: list[
Please refer to the service documentation for a conceptual discussion of [language detection][language_detection]
and [language and regional support][language_and_regional_support].

### Healthcare Analysis
### Healthcare Entities Analysis
The example below extracts entities recognized within the healthcare domain, and identifies relationships between entities within the input document and links to known sources of information in various well known databases, such as UMLS, CHV, MSH, etc. This sample demonstrates the usage for [long-running operations](#long-running-operations).

```python
Expand All @@ -432,24 +432,24 @@ text_analytics_client = TextAnalyticsClient(endpoint, credential)

documents = ["Subject is taking 100mg of ibuprofen twice daily"]

poller = text_analytics_client.begin_analyze_healthcare(documents, show_stats=True)
poller = text_analytics_client.begin_analyze_healthcare_entities(documents, show_stats=True)
result = poller.result()

docs = [doc for doc in result if not doc.is_error]

print("Results of Healthcare Analysis:")
print("Results of Healthcare Entities Analysis:")
for idx, doc in enumerate(docs):
for entity in doc.entities:
print("Entity: {}".format(entity.text))
print("...Category: {}".format(entity.category))
print("...Subcategory: {}".format(entity.subcategory))
print("...Offset: {}".format(entity.offset))
print("...Confidence score: {}".format(entity.confidence_score))
if entity.links is not None:
print("...Links:")
for link in entity.links:
print("......ID: {}".format(link.id))
print("......Data source: {}".format(link.data_source))
if entity.data_sources is not None:
print("...Data Sources:")
for data_source in entity.data_sources:
print("......Entity ID: {}".format(data_source.entity_id))
print("......Name: {}".format(data_source.name))
for relation in doc.relations:
print("Relation:")
print("...Source: {}".format(relation.source.text))
Expand All @@ -459,7 +459,7 @@ for idx, doc in enumerate(docs):
print("------------------------------------------")
```

Note: The Healthcare Analysis service is currently available only in API version v3.1-preview.3 in gated preview. Since this is a gated preview, AAD is not supported. More information [here](https://docs.microsoft.com/azure/cognitive-services/text-analytics/how-tos/text-analytics-for-health?tabs=ner#request-access-to-the-public-preview).
Note: The Healthcare Entities Analysis service is currently available only in API version v3.1-preview.3 in gated preview. Since this is a gated preview, AAD is not supported. More information [here](https://docs.microsoft.com/azure/cognitive-services/text-analytics/how-tos/text-analytics-for-health?tabs=ner#request-access-to-the-public-preview).

### Batch Analysis
The example below demonstrates how to perform multiple analyses over one set of documents in a single request. Currently batching is supported using any combination of the following Text Analytics APIs in a single request:
Expand Down Expand Up @@ -597,7 +597,7 @@ Common scenarios
* Recognize linked entities: [sample_recognize_linked_entities.py][recognize_linked_entities_sample] ([async version][recognize_linked_entities_sample_async])
* Extract key phrases: [sample_extract_key_phrases.py][extract_key_phrases_sample] ([async version][extract_key_phrases_sample_async])
* Detect language: [sample_detect_language.py][detect_language_sample] ([async version][detect_language_sample_async])
* Healthcare Analysis: [sample_analyze_healthcare.py][analyze_healthcare_sample] ([async version][analyze_healthcare_sample_async])
* Healthcare Analysis: [sample_analyze_healthcare_entities.py][analyze_healthcare_entities_sample] ([async version][analyze_healthcare_entities_sample_async])
* Batch Analysis: [sample_anayze.py][analyze_sample] ([async version][analyze_sample_async])

Advanced scenarios
Expand Down Expand Up @@ -688,8 +688,8 @@ This project has adopted the [Microsoft Open Source Code of Conduct][code_of_con
[recognize_linked_entities_sample_async]: https://github.com/Azure/azure-sdk-for-python/blob/master/sdk/textanalytics/azure-ai-textanalytics/samples/async_samples/sample_recognize_linked_entities_async.py
[recognize_pii_entities_sample]: https://github.com/Azure/azure-sdk-for-python/blob/master/sdk/textanalytics/azure-ai-textanalytics/samples/sample_recognize_pii_entities.py
[recognize_pii_entities_sample_async]: https://github.com/Azure/azure-sdk-for-python/blob/master/sdk/textanalytics/azure-ai-textanalytics/samples/async_samples/sample_recognize_pii_entities_async.py
[analyze_healthcare_sample]: https://github.com/Azure/azure-sdk-for-python/blob/master/sdk/textanalytics/azure-ai-textanalytics/samples/sample_analyze_healthcare.py
[analyze_healthcare_sample_async]: https://github.com/Azure/azure-sdk-for-python/blob/master/sdk/textanalytics/azure-ai-textanalytics/samples/async_samples/sample_analyze_healthcare_async.py
[analyze_healthcare_entities_sample]: https://github.com/Azure/azure-sdk-for-python/blob/master/sdk/textanalytics/azure-ai-textanalytics/samples/sample_analyze_healthcare_entities.py
[analyze_healthcare_entities_sample_async]: https://github.com/Azure/azure-sdk-for-python/blob/master/sdk/textanalytics/azure-ai-textanalytics/samples/async_samples/sample_analyze_healthcare_entities_async.py
[analyze_sample]: https://github.com/Azure/azure-sdk-for-python/blob/master/sdk/textanalytics/azure-ai-textanalytics/samples/sample_analyze.py
[analyze_sample_async]: https://github.com/Azure/azure-sdk-for-python/blob/master/sdk/textanalytics/azure-ai-textanalytics/samples/async_samples/sample_analyze_async.py

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,17 +32,17 @@
RecognizePiiEntitiesResult,
PiiEntity,
PiiEntityDomainType,
AnalyzeHealthcareResultItem,
AnalyzeHealthcareEntitiesResultItem,
HealthcareEntity,
HealthcareRelation,
HealthcareEntityLink,
HealthcareEntityDataSource,
EntitiesRecognitionTask,
PiiEntitiesRecognitionTask,
KeyPhraseExtractionTask,
TextAnalysisResult,
RequestStatistics
)
from._paging import AnalyzeHealthcareResult
from ._paging import AnalyzeHealthcareEntitiesResult

__all__ = [
'TextAnalyticsApiVersion',
Expand Down Expand Up @@ -71,11 +71,11 @@
'RecognizePiiEntitiesResult',
'PiiEntity',
'PiiEntityDomainType',
'AnalyzeHealthcareResultItem',
'AnalyzeHealthcareResult',
'AnalyzeHealthcareEntitiesResultItem',
'AnalyzeHealthcareEntitiesResult',
'HealthcareEntity',
'HealthcareRelation',
'HealthcareEntityLink',
'HealthcareEntityDataSource',
'EntitiesRecognitionTask',
'PiiEntitiesRecognitionTask',
'KeyPhraseExtractionTask',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@
# Licensed under the MIT License.
# ------------------------------------

from azure.core.polling import AsyncLROPoller
from azure.core.polling.base_polling import OperationFailed, BadStatus
from azure.core.polling.async_base_polling import AsyncLROBasePolling
from azure.core.polling._async_poller import PollingReturnType


_FINISHED = frozenset(["succeeded", "cancelled", "failed", "partiallysucceeded"])
Expand Down Expand Up @@ -73,3 +75,55 @@ async def _poll(self): # pylint:disable=invalid-overridden-method
TextAnalyticsAsyncLROPollingMethod._raise_if_bad_http_status_and_method(
self._pipeline_response.http_response
)

class AnalyzeHealthcareEntitiesAsyncLROPollingMethod(TextAnalyticsAsyncLROPollingMethod):

@property
def _current_body(self):
from ._generated.v3_1_preview_3.models import JobMetadata
return JobMetadata.deserialize(self._pipeline_response)

@property
def created_on(self):
if not self._current_body:
return None
return self._current_body.created_date_time

@property
def expires_on(self):
if not self._current_body:
return None
return self._current_body.expiration_date_time

@property
def last_modified_on(self):
if not self._current_body:
return None
return self._current_body.last_update_date_time

@property
def id(self):
if not self._current_body:
return None
return self._current_body.job_id


class AnalyzeHealthcareEntitiesAsyncLROPoller(AsyncLROPoller[PollingReturnType]):

@property
def created_on(self):
return self._polling_method.created_on

@property
def expires_on(self):
return self._polling_method.expires_on

@property
def last_modified_on(self):
return self._polling_method.last_modified_on

@property
def id(self):
return self._polling_method.id


Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@
from azure.core.async_paging import AsyncItemPaged


class AnalyzeHealthcareResultAsync(AsyncItemPaged):
class AnalyzeHealthcareEntitiesResultAsync(AsyncItemPaged):
def __init__(self, *args, **kwargs):
self.model_version = kwargs.pop('model_version')
self.statistics = kwargs.pop('statistics')
super(AnalyzeHealthcareResultAsync, self).__init__(*args, **kwargs)
super(AnalyzeHealthcareEntitiesResultAsync, self).__init__(*args, **kwargs)


class AnalyzeResultAsync(AsyncItemPaged):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from typing import TYPE_CHECKING
import warnings

from .._lro import AnalyzeHealthcareEntitiesLROPoller, AnalyzeHealthcareEntitiesLROPollingMethod
from azure.core.exceptions import ClientAuthenticationError, HttpResponseError, ResourceExistsError, ResourceNotFoundError, map_error
from azure.core.pipeline import PipelineResponse
from azure.core.pipeline.transport import HttpRequest, HttpResponse
Expand Down Expand Up @@ -160,12 +161,12 @@ def begin_health(
:type string_index_type: str or ~azure.ai.textanalytics.v3_1_preview_3.models.StringIndexType
:keyword callable cls: A custom type or function that will be passed the direct response
:keyword str continuation_token: A continuation token to restart a poller from a saved state.
:keyword polling: Pass in True if you'd like the LROBasePolling polling method,
:keyword polling: Pass in True if you'd like the AnalyzeHealthcareEntitiesLROPollingMethod polling method,
False for no polling, or your own initialized polling object for a personal polling strategy.
:paramtype polling: bool or ~azure.core.polling.PollingMethod
:keyword int polling_interval: Default waiting time between two polls for LRO operations if no Retry-After header is present.
:return: An instance of LROPoller that returns either None or the result of cls(response)
:rtype: ~azure.core.polling.LROPoller[None]
:return: An instance of AnalyzeHealthcareEntitiesLROPoller that returns either HealthcareJobState or the result of cls(response)
maririos marked this conversation as resolved.
Show resolved Hide resolved
:rtype: ~...._lro.AnalyzeHealthcareEntitiesLROPoller[~azure.ai.textanalytics.v3_1_preview_3.models.HealthcareJobState]
:raises ~azure.core.exceptions.HttpResponseError:
"""
api_version = self._get_api_version('begin_health')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from typing import Any, Callable, Dict, Generic, List, Optional, TypeVar, Union
import warnings

from ..._async_lro import AnalyzeHealthcareEntitiesAsyncLROPoller, AnalyzeHealthcareEntitiesAsyncLROPollingMethod
from azure.core.exceptions import ClientAuthenticationError, HttpResponseError, ResourceExistsError, ResourceNotFoundError, map_error
from azure.core.pipeline import PipelineResponse
from azure.core.pipeline.transport import AsyncHttpResponse, HttpRequest
Expand Down Expand Up @@ -139,7 +140,7 @@ async def begin_health(
model_version: Optional[str] = None,
string_index_type: Optional[Union[str, "_models.StringIndexType"]] = "TextElements_v8",
**kwargs
) -> AsyncLROPoller[None]:
) -> AnalyzeHealthcareEntitiesAsyncLROPoller["_models.HealthcareJobState"]:
"""Submit healthcare analysis job.

Start a healthcare analysis job to recognize healthcare related entities (drugs, conditions,
Expand All @@ -156,12 +157,12 @@ async def begin_health(
:type string_index_type: str or ~azure.ai.textanalytics.v3_1_preview_3.models.StringIndexType
:keyword callable cls: A custom type or function that will be passed the direct response
:keyword str continuation_token: A continuation token to restart a poller from a saved state.
:keyword polling: Pass in True if you'd like the AsyncLROBasePolling polling method,
:keyword polling: Pass in True if you'd like the AnalyzeHealthcareEntitiesAsyncLROPollingMethod polling method,
False for no polling, or your own initialized polling object for a personal polling strategy.
:paramtype polling: bool or ~azure.core.polling.AsyncPollingMethod
:keyword int polling_interval: Default waiting time between two polls for LRO operations if no Retry-After header is present.
:return: An instance of AsyncLROPoller that returns either None or the result of cls(response)
:rtype: ~azure.core.polling.AsyncLROPoller[None]
:return: An instance of AnalyzeHealthcareEntitiesAsyncLROPoller that returns either HealthcareJobState or the result of cls(response)
:rtype: ~....._async_lro.AnalyzeHealthcareEntitiesAsyncLROPoller[~azure.ai.textanalytics.v3_1_preview_3.models.HealthcareJobState]
:raises ~azure.core.exceptions.HttpResponseError:
"""
api_version = self._get_api_version('begin_health')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,37 @@
},
"constant": {
},
"call": "credential, endpoint"
"call": "credential, endpoint",
"service_client_specific": {
"sync": {
"api_version": {
"signature": "api_version=None, # type: Optional[str]",
"description": "API version to use if no profile is provided, or if missing in profile.",
"docstring_type": "str",
"required": false
},
"profile": {
"signature": "profile=KnownProfiles.default, # type: KnownProfiles",
"description": "A profile definition, from KnownProfiles to dict.",
"docstring_type": "azure.profiles.KnownProfiles",
"required": false
}
},
"async": {
"api_version": {
"signature": "api_version: Optional[str] = None,",
"description": "API version to use if no profile is provided, or if missing in profile.",
"docstring_type": "str",
"required": false
},
"profile": {
"signature": "profile: KnownProfiles = KnownProfiles.default,",
"description": "A profile definition, from KnownProfiles to dict.",
"docstring_type": "azure.profiles.KnownProfiles",
"required": false
}
}
}
},
"config": {
"credential": true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ async def entities_recognition_general(

if response.status_code not in [200]:
map_error(status_code=response.status_code, response=response, error_map=error_map)
error = self._deserialize(_models.ErrorResponse, response)
error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response)
raise HttpResponseError(response=response, model=error)

deserialized = self._deserialize('EntitiesResult', pipeline_response)
Expand Down Expand Up @@ -159,7 +159,7 @@ async def entities_linking(

if response.status_code not in [200]:
map_error(status_code=response.status_code, response=response, error_map=error_map)
error = self._deserialize(_models.ErrorResponse, response)
error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response)
raise HttpResponseError(response=response, model=error)

deserialized = self._deserialize('EntityLinkingResult', pipeline_response)
Expand Down Expand Up @@ -234,7 +234,7 @@ async def key_phrases(

if response.status_code not in [200]:
map_error(status_code=response.status_code, response=response, error_map=error_map)
error = self._deserialize(_models.ErrorResponse, response)
error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response)
raise HttpResponseError(response=response, model=error)

deserialized = self._deserialize('KeyPhraseResult', pipeline_response)
Expand Down Expand Up @@ -310,7 +310,7 @@ async def languages(

if response.status_code not in [200]:
map_error(status_code=response.status_code, response=response, error_map=error_map)
error = self._deserialize(_models.ErrorResponse, response)
error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response)
raise HttpResponseError(response=response, model=error)

deserialized = self._deserialize('LanguageResult', pipeline_response)
Expand Down Expand Up @@ -386,7 +386,7 @@ async def sentiment(

if response.status_code not in [200]:
map_error(status_code=response.status_code, response=response, error_map=error_map)
error = self._deserialize(_models.ErrorResponse, response)
error = self._deserialize.failsafe_deserialize(_models.ErrorResponse, response)
raise HttpResponseError(response=response, model=error)

deserialized = self._deserialize('SentimentResponse', pipeline_response)
Expand Down
Loading