From ef03c5208e1d43b0c313d884ef2d42aeef222f90 Mon Sep 17 00:00:00 2001 From: Graham Thomas Date: Mon, 22 Jul 2024 10:51:16 -0700 Subject: [PATCH] Initial Creation of Azure.Health.Deidentification Dataplane SDK (#43913) Adds Azure.Health.Deidentification to the .NET SDK repo --------- Co-authored-by: Graham Thomas --- .github/CODEOWNERS | 8 +- .vscode/cspell.json | 10 + .../Azure.Health.Deidentification.sln | 56 + .../CHANGELOG.md | 6 + .../Directory.Build.props | 6 + .../Azure.Health.Deidentification/README.md | 125 ++ ....Health.Deidentification.netstandard2.0.cs | 333 +++++ .../Azure.Health.Deidentification/assets.json | 6 + .../docs/HowTo-RedactionFormatting.md | 46 + .../docs/images/ServiceUrl_Location.png | Bin 0 -> 162387 bytes .../samples/README.md | 17 + .../samples/Sample1_HelloWorld.md | 25 + .../samples/Sample1_HelloWorldAsync.md | 25 + .../samples/Sample2_CreateJob.md | 18 + .../samples/Sample2_CreateJobAsync.md | 19 + .../samples/Sample3_ListJobs.md | 16 + .../samples/Sample3_ListJobsAsync.md | 16 + .../samples/Sample4_ListCompletedFiles.md | 17 + .../Sample4_ListCompletedFilesAsync.md | 17 + .../src/Azure.Health.Deidentification.csproj | 19 + .../src/Generated/DeidentificationClient.cs | 974 +++++++++++++++ .../DeidentificationClientOptions.cs | 37 + .../DeidentificationContent.Serialization.cs | 176 +++ .../src/Generated/DeidentificationContent.cs | 87 ++ .../DeidentificationJob.Serialization.cs | 286 +++++ .../src/Generated/DeidentificationJob.cs | 134 ++ .../DeidentificationResult.Serialization.cs | 153 +++ .../src/Generated/DeidentificationResult.cs | 69 ++ .../Generated/Docs/DeidentificationClient.xml | 1003 +++++++++++++++ .../src/Generated/DocumentDataType.cs | 48 + .../DocumentDetails.Serialization.cs | 190 +++ .../src/Generated/DocumentDetails.cs | 93 ++ .../DocumentLocation.Serialization.cs | 146 +++ .../src/Generated/DocumentLocation.cs | 79 ++ ...DeidentificationClientBuilderExtensions.cs | 35 + .../HealthDeidentificationModelFactory.cs | 168 +++ .../src/Generated/Internal/Argument.cs | 129 ++ .../Internal/ChangeTrackingDictionary.cs | 167 +++ .../Generated/Internal/ChangeTrackingList.cs | 153 +++ .../Internal/ModelSerializationExtensions.cs | 398 ++++++ .../src/Generated/Internal/Optional.cs | 51 + .../Internal/Utf8JsonRequestContent.cs | 55 + .../src/Generated/JobStatus.cs | 63 + .../src/Generated/JobSummary.Serialization.cs | 173 +++ .../src/Generated/JobSummary.cs | 96 ++ .../src/Generated/OperationState.cs | 60 + .../src/Generated/OperationType.cs | 54 + .../src/Generated/PhiCategory.cs | 132 ++ .../src/Generated/PhiEntity.Serialization.cs | 183 +++ .../src/Generated/PhiEntity.cs | 96 ++ .../PhiTaggerResult.Serialization.cs | 171 +++ .../src/Generated/PhiTaggerResult.cs | 84 ++ .../SourceStorageLocation.Serialization.cs | 168 +++ .../src/Generated/SourceStorageLocation.cs | 87 ++ .../Generated/StringIndex.Serialization.cs | 151 +++ .../src/Generated/StringIndex.cs | 108 ++ .../TargetStorageLocation.Serialization.cs | 143 +++ .../src/Generated/TargetStorageLocation.cs | 82 ++ .../src/Properties/AssemblyInfo.cs | 11 + ...Azure.Health.Deidentification.Tests.csproj | 20 + .../example_patient_1/doctor_dictation.txt | 1 + .../Data/example_patient_1/visit_summary.txt | 8 + .../Samples/Samples_DeidentificationClient.cs | 1095 +++++++++++++++++ .../Tests/Helpers/DeidentificationTestBase.cs | 32 + .../DeidentificationTestEnvironment.cs | 21 + .../tests/Tests/JobOperationsTest.cs | 229 ++++ .../tests/Tests/RealtimeOperationsTest.cs | 65 + .../tests/samples/Sample1_HelloWorld.cs | 42 + .../tests/samples/Sample1_HelloWorldAsync.cs | 42 + .../tests/samples/Sample2_CreateAndRunJob.cs | 47 + .../samples/Sample2_CreateAndRunJobAsync.cs | 47 + .../tests/samples/Sample3_ListJobs.cs | 42 + .../tests/samples/Sample3_ListJobsAsync.cs | 42 + .../samples/Sample4_ListCompletedFiles.cs | 40 + .../Sample4_ListCompletedFilesAsync.cs | 40 + .../tsp-location.yaml | 5 + sdk/healthdataaiservices/ci.yml | 40 + .../test-resources-post.ps1 | 63 + sdk/healthdataaiservices/test-resources.bicep | 205 +++ sdk/healthdataaiservices/tests.yml | 6 + 80 files changed, 9409 insertions(+), 1 deletion(-) create mode 100644 sdk/healthdataaiservices/Azure.Health.Deidentification/Azure.Health.Deidentification.sln create mode 100644 sdk/healthdataaiservices/Azure.Health.Deidentification/CHANGELOG.md create mode 100644 sdk/healthdataaiservices/Azure.Health.Deidentification/Directory.Build.props create mode 100644 sdk/healthdataaiservices/Azure.Health.Deidentification/README.md create mode 100644 sdk/healthdataaiservices/Azure.Health.Deidentification/api/Azure.Health.Deidentification.netstandard2.0.cs create mode 100644 sdk/healthdataaiservices/Azure.Health.Deidentification/assets.json create mode 100644 sdk/healthdataaiservices/Azure.Health.Deidentification/docs/HowTo-RedactionFormatting.md create mode 100644 sdk/healthdataaiservices/Azure.Health.Deidentification/docs/images/ServiceUrl_Location.png create mode 100644 sdk/healthdataaiservices/Azure.Health.Deidentification/samples/README.md create mode 100644 sdk/healthdataaiservices/Azure.Health.Deidentification/samples/Sample1_HelloWorld.md create mode 100644 sdk/healthdataaiservices/Azure.Health.Deidentification/samples/Sample1_HelloWorldAsync.md create mode 100644 sdk/healthdataaiservices/Azure.Health.Deidentification/samples/Sample2_CreateJob.md create mode 100644 sdk/healthdataaiservices/Azure.Health.Deidentification/samples/Sample2_CreateJobAsync.md create mode 100644 sdk/healthdataaiservices/Azure.Health.Deidentification/samples/Sample3_ListJobs.md create mode 100644 sdk/healthdataaiservices/Azure.Health.Deidentification/samples/Sample3_ListJobsAsync.md create mode 100644 sdk/healthdataaiservices/Azure.Health.Deidentification/samples/Sample4_ListCompletedFiles.md create mode 100644 sdk/healthdataaiservices/Azure.Health.Deidentification/samples/Sample4_ListCompletedFilesAsync.md create mode 100644 sdk/healthdataaiservices/Azure.Health.Deidentification/src/Azure.Health.Deidentification.csproj create mode 100644 sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/DeidentificationClient.cs create mode 100644 sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/DeidentificationClientOptions.cs create mode 100644 sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/DeidentificationContent.Serialization.cs create mode 100644 sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/DeidentificationContent.cs create mode 100644 sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/DeidentificationJob.Serialization.cs create mode 100644 sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/DeidentificationJob.cs create mode 100644 sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/DeidentificationResult.Serialization.cs create mode 100644 sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/DeidentificationResult.cs create mode 100644 sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/Docs/DeidentificationClient.xml create mode 100644 sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/DocumentDataType.cs create mode 100644 sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/DocumentDetails.Serialization.cs create mode 100644 sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/DocumentDetails.cs create mode 100644 sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/DocumentLocation.Serialization.cs create mode 100644 sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/DocumentLocation.cs create mode 100644 sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/HealthDeidentificationClientBuilderExtensions.cs create mode 100644 sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/HealthDeidentificationModelFactory.cs create mode 100644 sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/Internal/Argument.cs create mode 100644 sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/Internal/ChangeTrackingDictionary.cs create mode 100644 sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/Internal/ChangeTrackingList.cs create mode 100644 sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/Internal/ModelSerializationExtensions.cs create mode 100644 sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/Internal/Optional.cs create mode 100644 sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/Internal/Utf8JsonRequestContent.cs create mode 100644 sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/JobStatus.cs create mode 100644 sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/JobSummary.Serialization.cs create mode 100644 sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/JobSummary.cs create mode 100644 sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/OperationState.cs create mode 100644 sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/OperationType.cs create mode 100644 sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/PhiCategory.cs create mode 100644 sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/PhiEntity.Serialization.cs create mode 100644 sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/PhiEntity.cs create mode 100644 sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/PhiTaggerResult.Serialization.cs create mode 100644 sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/PhiTaggerResult.cs create mode 100644 sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/SourceStorageLocation.Serialization.cs create mode 100644 sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/SourceStorageLocation.cs create mode 100644 sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/StringIndex.Serialization.cs create mode 100644 sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/StringIndex.cs create mode 100644 sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/TargetStorageLocation.Serialization.cs create mode 100644 sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/TargetStorageLocation.cs create mode 100644 sdk/healthdataaiservices/Azure.Health.Deidentification/src/Properties/AssemblyInfo.cs create mode 100644 sdk/healthdataaiservices/Azure.Health.Deidentification/tests/Azure.Health.Deidentification.Tests.csproj create mode 100644 sdk/healthdataaiservices/Azure.Health.Deidentification/tests/Data/example_patient_1/doctor_dictation.txt create mode 100644 sdk/healthdataaiservices/Azure.Health.Deidentification/tests/Data/example_patient_1/visit_summary.txt create mode 100644 sdk/healthdataaiservices/Azure.Health.Deidentification/tests/Generated/Samples/Samples_DeidentificationClient.cs create mode 100644 sdk/healthdataaiservices/Azure.Health.Deidentification/tests/Tests/Helpers/DeidentificationTestBase.cs create mode 100644 sdk/healthdataaiservices/Azure.Health.Deidentification/tests/Tests/Helpers/DeidentificationTestEnvironment.cs create mode 100644 sdk/healthdataaiservices/Azure.Health.Deidentification/tests/Tests/JobOperationsTest.cs create mode 100644 sdk/healthdataaiservices/Azure.Health.Deidentification/tests/Tests/RealtimeOperationsTest.cs create mode 100644 sdk/healthdataaiservices/Azure.Health.Deidentification/tests/samples/Sample1_HelloWorld.cs create mode 100644 sdk/healthdataaiservices/Azure.Health.Deidentification/tests/samples/Sample1_HelloWorldAsync.cs create mode 100644 sdk/healthdataaiservices/Azure.Health.Deidentification/tests/samples/Sample2_CreateAndRunJob.cs create mode 100644 sdk/healthdataaiservices/Azure.Health.Deidentification/tests/samples/Sample2_CreateAndRunJobAsync.cs create mode 100644 sdk/healthdataaiservices/Azure.Health.Deidentification/tests/samples/Sample3_ListJobs.cs create mode 100644 sdk/healthdataaiservices/Azure.Health.Deidentification/tests/samples/Sample3_ListJobsAsync.cs create mode 100644 sdk/healthdataaiservices/Azure.Health.Deidentification/tests/samples/Sample4_ListCompletedFiles.cs create mode 100644 sdk/healthdataaiservices/Azure.Health.Deidentification/tests/samples/Sample4_ListCompletedFilesAsync.cs create mode 100644 sdk/healthdataaiservices/Azure.Health.Deidentification/tsp-location.yaml create mode 100644 sdk/healthdataaiservices/ci.yml create mode 100644 sdk/healthdataaiservices/test-resources-post.ps1 create mode 100644 sdk/healthdataaiservices/test-resources.bicep create mode 100644 sdk/healthdataaiservices/tests.yml diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index eba52c7f90fb..483352ca44f6 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -120,7 +120,7 @@ # ServiceOwners: @miaojiang # PRLabel: %App Configuration -/sdk/appconfiguration/ @jorgerangel-msft @jsquire +/sdk/appconfiguration/ @jorgerangel-msft @jsquire # ServiceLabel: %App Configuration # AzureSdkOwners: @jsquire @@ -531,6 +531,12 @@ # ServiceLabel: %HDInsight # ServiceOwners: @aim-for-better @idear1203 @deshriva +# PRLabel: %Health Deidentification +/sdk/healthdataaiservices/ @GrahamMThomas @danielszaniszlo + +# ServiceLabel: %Health Deidentification +# ServiceOwners: @GrahamMThomas @danielszaniszlo + # ServiceLabel: %HPC Cache # ServiceOwners: @romahamu @omzevall diff --git a/.vscode/cspell.json b/.vscode/cspell.json index 9d7ea2e8e118..c9d9a43f1512 100644 --- a/.vscode/cspell.json +++ b/.vscode/cspell.json @@ -1435,6 +1435,16 @@ "nfvis" ] }, + { + "filename": "**/sdk/healthdataaiservices/**/*", + "words": [ + "Deidentification", + "Deidentify", + "Deidentified", + "Deid", + "HEALTHDATAAISERVICES" + ] + }, { "filename": "**/sdk/confluent/**/*.cs", "words": [ diff --git a/sdk/healthdataaiservices/Azure.Health.Deidentification/Azure.Health.Deidentification.sln b/sdk/healthdataaiservices/Azure.Health.Deidentification/Azure.Health.Deidentification.sln new file mode 100644 index 000000000000..9459cccff3d3 --- /dev/null +++ b/sdk/healthdataaiservices/Azure.Health.Deidentification/Azure.Health.Deidentification.sln @@ -0,0 +1,56 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.29709.97 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Azure.Core.TestFramework", "..\..\core\Azure.Core.TestFramework\src\Azure.Core.TestFramework.csproj", "{ECC730C1-4AEA-420C-916A-66B19B79E4DC}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Azure.Health.Deidentification", "src\Azure.Health.Deidentification.csproj", "{28FF4005-4467-4E36-92E7-DEA27DEB1519}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Azure.Health.Deidentification.Tests", "tests\Azure.Health.Deidentification.Tests.csproj", "{1F1CD1D4-9932-4B73-99D8-C252A67D4B46}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {B0C276D1-2930-4887-B29A-D1A33E7009A2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B0C276D1-2930-4887-B29A-D1A33E7009A2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B0C276D1-2930-4887-B29A-D1A33E7009A2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B0C276D1-2930-4887-B29A-D1A33E7009A2}.Release|Any CPU.Build.0 = Release|Any CPU + {8E9A77AC-792A-4432-8320-ACFD46730401}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8E9A77AC-792A-4432-8320-ACFD46730401}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8E9A77AC-792A-4432-8320-ACFD46730401}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8E9A77AC-792A-4432-8320-ACFD46730401}.Release|Any CPU.Build.0 = Release|Any CPU + {ECC730C1-4AEA-420C-916A-66B19B79E4DC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {ECC730C1-4AEA-420C-916A-66B19B79E4DC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {ECC730C1-4AEA-420C-916A-66B19B79E4DC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {ECC730C1-4AEA-420C-916A-66B19B79E4DC}.Release|Any CPU.Build.0 = Release|Any CPU + {A4241C1F-A53D-474C-9E4E-075054407E74}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A4241C1F-A53D-474C-9E4E-075054407E74}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A4241C1F-A53D-474C-9E4E-075054407E74}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A4241C1F-A53D-474C-9E4E-075054407E74}.Release|Any CPU.Build.0 = Release|Any CPU + {FA8BD3F1-8616-47B6-974C-7576CDF4717E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FA8BD3F1-8616-47B6-974C-7576CDF4717E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FA8BD3F1-8616-47B6-974C-7576CDF4717E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FA8BD3F1-8616-47B6-974C-7576CDF4717E}.Release|Any CPU.Build.0 = Release|Any CPU + {85677AD3-C214-42FA-AE6E-49B956CAC8DC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {85677AD3-C214-42FA-AE6E-49B956CAC8DC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {85677AD3-C214-42FA-AE6E-49B956CAC8DC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {85677AD3-C214-42FA-AE6E-49B956CAC8DC}.Release|Any CPU.Build.0 = Release|Any CPU + {28FF4005-4467-4E36-92E7-DEA27DEB1519}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {28FF4005-4467-4E36-92E7-DEA27DEB1519}.Debug|Any CPU.Build.0 = Debug|Any CPU + {28FF4005-4467-4E36-92E7-DEA27DEB1519}.Release|Any CPU.ActiveCfg = Release|Any CPU + {28FF4005-4467-4E36-92E7-DEA27DEB1519}.Release|Any CPU.Build.0 = Release|Any CPU + {1F1CD1D4-9932-4B73-99D8-C252A67D4B46}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1F1CD1D4-9932-4B73-99D8-C252A67D4B46}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1F1CD1D4-9932-4B73-99D8-C252A67D4B46}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1F1CD1D4-9932-4B73-99D8-C252A67D4B46}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {A97F4B90-2591-4689-B1F8-5F21FE6D6CAE} + EndGlobalSection +EndGlobal diff --git a/sdk/healthdataaiservices/Azure.Health.Deidentification/CHANGELOG.md b/sdk/healthdataaiservices/Azure.Health.Deidentification/CHANGELOG.md new file mode 100644 index 000000000000..e7dd20f9e0ab --- /dev/null +++ b/sdk/healthdataaiservices/Azure.Health.Deidentification/CHANGELOG.md @@ -0,0 +1,6 @@ +# Release History + +## 1.0.0-beta.1 (2024-08-15) + +### Features Added +- Initial Creation diff --git a/sdk/healthdataaiservices/Azure.Health.Deidentification/Directory.Build.props b/sdk/healthdataaiservices/Azure.Health.Deidentification/Directory.Build.props new file mode 100644 index 000000000000..63bd836ad44b --- /dev/null +++ b/sdk/healthdataaiservices/Azure.Health.Deidentification/Directory.Build.props @@ -0,0 +1,6 @@ + + + + diff --git a/sdk/healthdataaiservices/Azure.Health.Deidentification/README.md b/sdk/healthdataaiservices/Azure.Health.Deidentification/README.md new file mode 100644 index 000000000000..56c7a56a43af --- /dev/null +++ b/sdk/healthdataaiservices/Azure.Health.Deidentification/README.md @@ -0,0 +1,125 @@ +# Azure Health.Deidentification client library for .NET + +Azure.Health.Deidentification is a managed service that enables users to tag, redact, or surrogate health data. + + + + +[Source code][source_root] | [Package (NuGet)][package] | [API reference documentation][reference_docs] | [Product documentation][azconfig_docs] | [Samples][source_samples] + + [Source code](https://github.com/Azure/azure-sdk-for-net/blob/main/sdk/healthdataaiservices/Azure.Health.Deidentification/src) | [Package (NuGet)](https://www.nuget.org/packages) | [API reference documentation](https://azure.github.io/azure-sdk-for-net) | [Product documentation](https://docs.microsoft.com/azure) + +## Getting started + + +### Install the package + +Install the client library for .NET with [NuGet](https://www.nuget.org/ ): + +```dotnetcli +dotnet add package Azure.Health.Deidentification --prerelease +``` + +### Prerequisites + +> You must have an `Azure subscription` and `Deid Service`. + +### Authenticate the client + +Pull `ServiceUrl` from your created Deidentification Service. + +![Service Url Location](docs/images/ServiceUrl_Location.png) + +Basic code snippet to create your Deidentification Client and Deidentify a string. + +```cs + const string serviceEndpoint = "https://example.api.cac001.deid.azure.com"; + TokenCredential credential = new DefaultAzureCredential(); + + DeidentificationClient client = new( + new Uri(serviceEndpoint), + credential, + new DeidentificationClientOptions() + ); + + DeidentificationContent content = new("Hello, John!", OperationType.Surrogate, DocumentDataType.Plaintext); + + Response result = client.Deidentify(content); + string outputString = result.Value.OutputText; + Console.WriteLine(outputString); // Hello, Tom! +``` + +## Key concepts + +**Operation Modes** +- Tag: Will return a structure of offset and length with the PHI category of the related text spans. +- Redact: Will return output text with placeholder stubbed text. ex. `[name]` +- Surrogate: Will return output text with synthetic replacements. + - `My name is John Smith` + - `My name is Tom Jones` + +**Job Integration with Azure Storage** +Instead of sending text, you can send an Azure Storage Location to the service. We will asynchronously +process the list of files and output the deidentified files to a location of your choice. + +Limitations: +- Maximum file count per job: 1000 documents +- Maximum file size per file: 2 MB + +**Redaction Formatting** + +[Redaction formatting guide](https://github.com/Azure/azure-sdk-for-net/blob/main/sdk/healthdataaiservices/Azure.Health.Deidentification/docs/HowTo-RedactionFormatting.md) + +### Thread safety + +We guarantee that all client instance methods are thread-safe and independent of each other ([guideline](https://azure.github.io/azure-sdk/dotnet_introduction.html#dotnet-service-methods-thread-safety)). This ensures that the recommendation of reusing client instances is always safe, even across threads. + +### Additional concepts + +[Client options](https://github.com/Azure/azure-sdk-for-net/blob/main/sdk/core/Azure.Core/README.md#configuring-service-clients-using-clientoptions) | +[Accessing the response](https://github.com/Azure/azure-sdk-for-net/blob/main/sdk/core/Azure.Core/README.md#accessing-http-response-details-using-responset) | +[Long-running operations](https://github.com/Azure/azure-sdk-for-net/blob/main/sdk/core/Azure.Core/README.md#consuming-long-running-operations-using-operationt) | +[Handling failures](https://github.com/Azure/azure-sdk-for-net/blob/main/sdk/core/Azure.Core/README.md#reporting-errors-requestfailedexception) | +[Diagnostics](https://github.com/Azure/azure-sdk-for-net/blob/main/sdk/core/Azure.Core/samples/Diagnostics.md) | +[Mocking](https://github.com/Azure/azure-sdk-for-net/blob/main/sdk/core/Azure.Core/README.md#mocking) | +[Client lifetime](https://devblogs.microsoft.com/azure-sdk/lifetime-management-and-thread-safety-guarantees-of-azure-sdk-net-clients/) + + +## Examples + +You can familiarize yourself with different APIs using [Samples](https://github.com/Azure/azure-sdk-for-net/tree/main/sdk/healthdataaiservices/Azure.Health.Deidentification/samples). + +## Next steps + +- Find a bug, or have feedback? Raise an issue with "Health Deidentification" Label. + + +## Troubleshooting + +- **Unabled to Access Source or Target Storage** + - Ensure you create your deid service with a system assigned managed identity + - Ensure your storage account has given permissions to that managed identity + +## Contributing + +This project welcomes contributions and suggestions. Most contributions require +you to agree to a Contributor License Agreement (CLA) declaring that you have +the right to, and actually do, grant us the rights to use your contribution. +For details, visit https://cla.microsoft.com. + +When you submit a pull request, a CLA-bot will automatically determine whether +you need to provide a CLA and decorate the PR appropriately (e.g., label, +comment). Simply follow the instructions provided by the bot. You will only +need to do this once across all repos using our CLA. + +This project has adopted the +[Microsoft Open Source Code of Conduct][code_of_conduct]. For more information, +see the Code of Conduct FAQ or contact opencode@microsoft.com with any +additional questions or comments. + + +[code_of_conduct]: https://opensource.microsoft.com/codeofconduct/ +[style-guide-msft]: https://docs.microsoft.com/style-guide/capitalization +[style-guide-cloud]: https://aka.ms/azsdk/cloud-style-guide + +![Impressions](https://azure-sdk-impressions.azurewebsites.net/api/impressions/azure-sdk-for-net/sdk/healthdataaiservices/Azure.Health.Deidentification/README.png) diff --git a/sdk/healthdataaiservices/Azure.Health.Deidentification/api/Azure.Health.Deidentification.netstandard2.0.cs b/sdk/healthdataaiservices/Azure.Health.Deidentification/api/Azure.Health.Deidentification.netstandard2.0.cs new file mode 100644 index 000000000000..12205c6a9049 --- /dev/null +++ b/sdk/healthdataaiservices/Azure.Health.Deidentification/api/Azure.Health.Deidentification.netstandard2.0.cs @@ -0,0 +1,333 @@ +namespace Azure.Health.Deidentification +{ + public partial class DeidentificationClient + { + protected DeidentificationClient() { } + public DeidentificationClient(System.Uri endpoint, Azure.Core.TokenCredential credential) { } + public DeidentificationClient(System.Uri endpoint, Azure.Core.TokenCredential credential, Azure.Health.Deidentification.DeidentificationClientOptions options) { } + public virtual Azure.Core.Pipeline.HttpPipeline Pipeline { get { throw null; } } + public virtual Azure.Response CancelJob(string name, Azure.RequestContext context) { throw null; } + public virtual Azure.Response CancelJob(string name, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public virtual System.Threading.Tasks.Task CancelJobAsync(string name, Azure.RequestContext context) { throw null; } + public virtual System.Threading.Tasks.Task> CancelJobAsync(string name, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public virtual Azure.Operation CreateJob(Azure.WaitUntil waitUntil, string name, Azure.Core.RequestContent content, Azure.RequestContext context = null) { throw null; } + public virtual Azure.Operation CreateJob(Azure.WaitUntil waitUntil, string name, Azure.Health.Deidentification.DeidentificationJob resource, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public virtual System.Threading.Tasks.Task> CreateJobAsync(Azure.WaitUntil waitUntil, string name, Azure.Core.RequestContent content, Azure.RequestContext context = null) { throw null; } + public virtual System.Threading.Tasks.Task> CreateJobAsync(Azure.WaitUntil waitUntil, string name, Azure.Health.Deidentification.DeidentificationJob resource, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public virtual Azure.Response Deidentify(Azure.Core.RequestContent content, Azure.RequestContext context = null) { throw null; } + public virtual Azure.Response Deidentify(Azure.Health.Deidentification.DeidentificationContent body, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public virtual System.Threading.Tasks.Task DeidentifyAsync(Azure.Core.RequestContent content, Azure.RequestContext context = null) { throw null; } + public virtual System.Threading.Tasks.Task> DeidentifyAsync(Azure.Health.Deidentification.DeidentificationContent body, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public virtual Azure.Response DeleteJob(string name, Azure.RequestContext context = null) { throw null; } + public virtual System.Threading.Tasks.Task DeleteJobAsync(string name, Azure.RequestContext context = null) { throw null; } + public virtual Azure.Response GetJob(string name, Azure.RequestContext context) { throw null; } + public virtual Azure.Response GetJob(string name, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public virtual System.Threading.Tasks.Task GetJobAsync(string name, Azure.RequestContext context) { throw null; } + public virtual System.Threading.Tasks.Task> GetJobAsync(string name, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public virtual Azure.Pageable GetJobDocuments(string name, int? maxpagesize, string continuationToken, Azure.RequestContext context) { throw null; } + public virtual Azure.Pageable GetJobDocuments(string name, int? maxpagesize = default(int?), string continuationToken = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public virtual Azure.AsyncPageable GetJobDocumentsAsync(string name, int? maxpagesize, string continuationToken, Azure.RequestContext context) { throw null; } + public virtual Azure.AsyncPageable GetJobDocumentsAsync(string name, int? maxpagesize = default(int?), string continuationToken = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public virtual Azure.Pageable GetJobs(int? maxpagesize, string continuationToken, Azure.RequestContext context) { throw null; } + public virtual Azure.Pageable GetJobs(int? maxpagesize = default(int?), string continuationToken = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public virtual Azure.AsyncPageable GetJobsAsync(int? maxpagesize, string continuationToken, Azure.RequestContext context) { throw null; } + public virtual Azure.AsyncPageable GetJobsAsync(int? maxpagesize = default(int?), string continuationToken = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + } + public partial class DeidentificationClientOptions : Azure.Core.ClientOptions + { + public DeidentificationClientOptions(Azure.Health.Deidentification.DeidentificationClientOptions.ServiceVersion version = Azure.Health.Deidentification.DeidentificationClientOptions.ServiceVersion.V2024_07_12_Preview) { } + public enum ServiceVersion + { + V2024_07_12_Preview = 1, + } + } + public partial class DeidentificationContent : System.ClientModel.Primitives.IJsonModel, System.ClientModel.Primitives.IPersistableModel + { + public DeidentificationContent(string inputText) { } + public Azure.Health.Deidentification.DocumentDataType? DataType { get { throw null; } set { } } + public string InputText { get { throw null; } } + public Azure.Health.Deidentification.OperationType? Operation { get { throw null; } set { } } + public string RedactionFormat { get { throw null; } set { } } + Azure.Health.Deidentification.DeidentificationContent System.ClientModel.Primitives.IJsonModel.Create(ref System.Text.Json.Utf8JsonReader reader, System.ClientModel.Primitives.ModelReaderWriterOptions options) { throw null; } + void System.ClientModel.Primitives.IJsonModel.Write(System.Text.Json.Utf8JsonWriter writer, System.ClientModel.Primitives.ModelReaderWriterOptions options) { } + Azure.Health.Deidentification.DeidentificationContent System.ClientModel.Primitives.IPersistableModel.Create(System.BinaryData data, System.ClientModel.Primitives.ModelReaderWriterOptions options) { throw null; } + string System.ClientModel.Primitives.IPersistableModel.GetFormatFromOptions(System.ClientModel.Primitives.ModelReaderWriterOptions options) { throw null; } + System.BinaryData System.ClientModel.Primitives.IPersistableModel.Write(System.ClientModel.Primitives.ModelReaderWriterOptions options) { throw null; } + } + public partial class DeidentificationJob : System.ClientModel.Primitives.IJsonModel, System.ClientModel.Primitives.IPersistableModel + { + public DeidentificationJob(Azure.Health.Deidentification.SourceStorageLocation sourceLocation, Azure.Health.Deidentification.TargetStorageLocation targetLocation) { } + public System.DateTimeOffset CreatedAt { get { throw null; } } + public Azure.Health.Deidentification.DocumentDataType? DataType { get { throw null; } set { } } + public Azure.ResponseError Error { get { throw null; } } + public System.DateTimeOffset LastUpdatedAt { get { throw null; } } + public string Name { get { throw null; } } + public Azure.Health.Deidentification.OperationType? Operation { get { throw null; } set { } } + public string RedactionFormat { get { throw null; } set { } } + public Azure.Health.Deidentification.SourceStorageLocation SourceLocation { get { throw null; } set { } } + public System.DateTimeOffset? StartedAt { get { throw null; } } + public Azure.Health.Deidentification.JobStatus Status { get { throw null; } } + public Azure.Health.Deidentification.JobSummary Summary { get { throw null; } } + public Azure.Health.Deidentification.TargetStorageLocation TargetLocation { get { throw null; } set { } } + Azure.Health.Deidentification.DeidentificationJob System.ClientModel.Primitives.IJsonModel.Create(ref System.Text.Json.Utf8JsonReader reader, System.ClientModel.Primitives.ModelReaderWriterOptions options) { throw null; } + void System.ClientModel.Primitives.IJsonModel.Write(System.Text.Json.Utf8JsonWriter writer, System.ClientModel.Primitives.ModelReaderWriterOptions options) { } + Azure.Health.Deidentification.DeidentificationJob System.ClientModel.Primitives.IPersistableModel.Create(System.BinaryData data, System.ClientModel.Primitives.ModelReaderWriterOptions options) { throw null; } + string System.ClientModel.Primitives.IPersistableModel.GetFormatFromOptions(System.ClientModel.Primitives.ModelReaderWriterOptions options) { throw null; } + System.BinaryData System.ClientModel.Primitives.IPersistableModel.Write(System.ClientModel.Primitives.ModelReaderWriterOptions options) { throw null; } + } + public partial class DeidentificationResult : System.ClientModel.Primitives.IJsonModel, System.ClientModel.Primitives.IPersistableModel + { + internal DeidentificationResult() { } + public string OutputText { get { throw null; } } + public Azure.Health.Deidentification.PhiTaggerResult TaggerResult { get { throw null; } } + Azure.Health.Deidentification.DeidentificationResult System.ClientModel.Primitives.IJsonModel.Create(ref System.Text.Json.Utf8JsonReader reader, System.ClientModel.Primitives.ModelReaderWriterOptions options) { throw null; } + void System.ClientModel.Primitives.IJsonModel.Write(System.Text.Json.Utf8JsonWriter writer, System.ClientModel.Primitives.ModelReaderWriterOptions options) { } + Azure.Health.Deidentification.DeidentificationResult System.ClientModel.Primitives.IPersistableModel.Create(System.BinaryData data, System.ClientModel.Primitives.ModelReaderWriterOptions options) { throw null; } + string System.ClientModel.Primitives.IPersistableModel.GetFormatFromOptions(System.ClientModel.Primitives.ModelReaderWriterOptions options) { throw null; } + System.BinaryData System.ClientModel.Primitives.IPersistableModel.Write(System.ClientModel.Primitives.ModelReaderWriterOptions options) { throw null; } + } + [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)] + public readonly partial struct DocumentDataType : System.IEquatable + { + private readonly object _dummy; + private readonly int _dummyPrimitive; + public DocumentDataType(string value) { throw null; } + public static Azure.Health.Deidentification.DocumentDataType Plaintext { get { throw null; } } + public bool Equals(Azure.Health.Deidentification.DocumentDataType other) { throw null; } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + public override bool Equals(object obj) { throw null; } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + public override int GetHashCode() { throw null; } + public static bool operator ==(Azure.Health.Deidentification.DocumentDataType left, Azure.Health.Deidentification.DocumentDataType right) { throw null; } + public static implicit operator Azure.Health.Deidentification.DocumentDataType (string value) { throw null; } + public static bool operator !=(Azure.Health.Deidentification.DocumentDataType left, Azure.Health.Deidentification.DocumentDataType right) { throw null; } + public override string ToString() { throw null; } + } + public partial class DocumentDetails : System.ClientModel.Primitives.IJsonModel, System.ClientModel.Primitives.IPersistableModel + { + internal DocumentDetails() { } + public Azure.ResponseError Error { get { throw null; } } + public string Id { get { throw null; } } + public Azure.Health.Deidentification.DocumentLocation Input { get { throw null; } } + public Azure.Health.Deidentification.DocumentLocation Output { get { throw null; } } + public Azure.Health.Deidentification.OperationState Status { get { throw null; } } + Azure.Health.Deidentification.DocumentDetails System.ClientModel.Primitives.IJsonModel.Create(ref System.Text.Json.Utf8JsonReader reader, System.ClientModel.Primitives.ModelReaderWriterOptions options) { throw null; } + void System.ClientModel.Primitives.IJsonModel.Write(System.Text.Json.Utf8JsonWriter writer, System.ClientModel.Primitives.ModelReaderWriterOptions options) { } + Azure.Health.Deidentification.DocumentDetails System.ClientModel.Primitives.IPersistableModel.Create(System.BinaryData data, System.ClientModel.Primitives.ModelReaderWriterOptions options) { throw null; } + string System.ClientModel.Primitives.IPersistableModel.GetFormatFromOptions(System.ClientModel.Primitives.ModelReaderWriterOptions options) { throw null; } + System.BinaryData System.ClientModel.Primitives.IPersistableModel.Write(System.ClientModel.Primitives.ModelReaderWriterOptions options) { throw null; } + } + public partial class DocumentLocation : System.ClientModel.Primitives.IJsonModel, System.ClientModel.Primitives.IPersistableModel + { + internal DocumentLocation() { } + public Azure.ETag Etag { get { throw null; } } + public string Path { get { throw null; } } + Azure.Health.Deidentification.DocumentLocation System.ClientModel.Primitives.IJsonModel.Create(ref System.Text.Json.Utf8JsonReader reader, System.ClientModel.Primitives.ModelReaderWriterOptions options) { throw null; } + void System.ClientModel.Primitives.IJsonModel.Write(System.Text.Json.Utf8JsonWriter writer, System.ClientModel.Primitives.ModelReaderWriterOptions options) { } + Azure.Health.Deidentification.DocumentLocation System.ClientModel.Primitives.IPersistableModel.Create(System.BinaryData data, System.ClientModel.Primitives.ModelReaderWriterOptions options) { throw null; } + string System.ClientModel.Primitives.IPersistableModel.GetFormatFromOptions(System.ClientModel.Primitives.ModelReaderWriterOptions options) { throw null; } + System.BinaryData System.ClientModel.Primitives.IPersistableModel.Write(System.ClientModel.Primitives.ModelReaderWriterOptions options) { throw null; } + } + public static partial class HealthDeidentificationModelFactory + { + public static Azure.Health.Deidentification.DeidentificationContent DeidentificationContent(string inputText = null, Azure.Health.Deidentification.OperationType? operation = default(Azure.Health.Deidentification.OperationType?), Azure.Health.Deidentification.DocumentDataType? dataType = default(Azure.Health.Deidentification.DocumentDataType?), string redactionFormat = null) { throw null; } + public static Azure.Health.Deidentification.DeidentificationJob DeidentificationJob(string name = null, Azure.Health.Deidentification.SourceStorageLocation sourceLocation = null, Azure.Health.Deidentification.TargetStorageLocation targetLocation = null, Azure.Health.Deidentification.OperationType? operation = default(Azure.Health.Deidentification.OperationType?), Azure.Health.Deidentification.DocumentDataType? dataType = default(Azure.Health.Deidentification.DocumentDataType?), string redactionFormat = null, Azure.Health.Deidentification.JobStatus status = default(Azure.Health.Deidentification.JobStatus), Azure.ResponseError error = null, System.DateTimeOffset lastUpdatedAt = default(System.DateTimeOffset), System.DateTimeOffset createdAt = default(System.DateTimeOffset), System.DateTimeOffset? startedAt = default(System.DateTimeOffset?), Azure.Health.Deidentification.JobSummary summary = null) { throw null; } + public static Azure.Health.Deidentification.DeidentificationResult DeidentificationResult(string outputText = null, Azure.Health.Deidentification.PhiTaggerResult taggerResult = null) { throw null; } + public static Azure.Health.Deidentification.DocumentDetails DocumentDetails(string id = null, Azure.Health.Deidentification.DocumentLocation input = null, Azure.Health.Deidentification.DocumentLocation output = null, Azure.Health.Deidentification.OperationState status = default(Azure.Health.Deidentification.OperationState), Azure.ResponseError error = null) { throw null; } + public static Azure.Health.Deidentification.DocumentLocation DocumentLocation(string path = null, Azure.ETag etag = default(Azure.ETag)) { throw null; } + public static Azure.Health.Deidentification.JobSummary JobSummary(int successful = 0, int failed = 0, int canceled = 0, int total = 0, long bytesProcessed = (long)0) { throw null; } + public static Azure.Health.Deidentification.PhiEntity PhiEntity(Azure.Health.Deidentification.PhiCategory category = default(Azure.Health.Deidentification.PhiCategory), Azure.Health.Deidentification.StringIndex offset = null, Azure.Health.Deidentification.StringIndex length = null, string text = null, double? confidenceScore = default(double?)) { throw null; } + public static Azure.Health.Deidentification.PhiTaggerResult PhiTaggerResult(System.Collections.Generic.IEnumerable entities = null, string path = null, Azure.ETag? etag = default(Azure.ETag?)) { throw null; } + public static Azure.Health.Deidentification.StringIndex StringIndex(int utf8 = 0, int utf16 = 0, int codePoint = 0) { throw null; } + } + [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)] + public readonly partial struct JobStatus : System.IEquatable + { + private readonly object _dummy; + private readonly int _dummyPrimitive; + public JobStatus(string value) { throw null; } + public static Azure.Health.Deidentification.JobStatus Canceled { get { throw null; } } + public static Azure.Health.Deidentification.JobStatus Failed { get { throw null; } } + public static Azure.Health.Deidentification.JobStatus NotStarted { get { throw null; } } + public static Azure.Health.Deidentification.JobStatus PartialFailed { get { throw null; } } + public static Azure.Health.Deidentification.JobStatus Running { get { throw null; } } + public static Azure.Health.Deidentification.JobStatus Succeeded { get { throw null; } } + public bool Equals(Azure.Health.Deidentification.JobStatus other) { throw null; } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + public override bool Equals(object obj) { throw null; } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + public override int GetHashCode() { throw null; } + public static bool operator ==(Azure.Health.Deidentification.JobStatus left, Azure.Health.Deidentification.JobStatus right) { throw null; } + public static implicit operator Azure.Health.Deidentification.JobStatus (string value) { throw null; } + public static bool operator !=(Azure.Health.Deidentification.JobStatus left, Azure.Health.Deidentification.JobStatus right) { throw null; } + public override string ToString() { throw null; } + } + public partial class JobSummary : System.ClientModel.Primitives.IJsonModel, System.ClientModel.Primitives.IPersistableModel + { + internal JobSummary() { } + public long BytesProcessed { get { throw null; } } + public int Canceled { get { throw null; } } + public int Failed { get { throw null; } } + public int Successful { get { throw null; } } + public int Total { get { throw null; } } + Azure.Health.Deidentification.JobSummary System.ClientModel.Primitives.IJsonModel.Create(ref System.Text.Json.Utf8JsonReader reader, System.ClientModel.Primitives.ModelReaderWriterOptions options) { throw null; } + void System.ClientModel.Primitives.IJsonModel.Write(System.Text.Json.Utf8JsonWriter writer, System.ClientModel.Primitives.ModelReaderWriterOptions options) { } + Azure.Health.Deidentification.JobSummary System.ClientModel.Primitives.IPersistableModel.Create(System.BinaryData data, System.ClientModel.Primitives.ModelReaderWriterOptions options) { throw null; } + string System.ClientModel.Primitives.IPersistableModel.GetFormatFromOptions(System.ClientModel.Primitives.ModelReaderWriterOptions options) { throw null; } + System.BinaryData System.ClientModel.Primitives.IPersistableModel.Write(System.ClientModel.Primitives.ModelReaderWriterOptions options) { throw null; } + } + [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)] + public readonly partial struct OperationState : System.IEquatable + { + private readonly object _dummy; + private readonly int _dummyPrimitive; + public OperationState(string value) { throw null; } + public static Azure.Health.Deidentification.OperationState Canceled { get { throw null; } } + public static Azure.Health.Deidentification.OperationState Failed { get { throw null; } } + public static Azure.Health.Deidentification.OperationState NotStarted { get { throw null; } } + public static Azure.Health.Deidentification.OperationState Running { get { throw null; } } + public static Azure.Health.Deidentification.OperationState Succeeded { get { throw null; } } + public bool Equals(Azure.Health.Deidentification.OperationState other) { throw null; } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + public override bool Equals(object obj) { throw null; } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + public override int GetHashCode() { throw null; } + public static bool operator ==(Azure.Health.Deidentification.OperationState left, Azure.Health.Deidentification.OperationState right) { throw null; } + public static implicit operator Azure.Health.Deidentification.OperationState (string value) { throw null; } + public static bool operator !=(Azure.Health.Deidentification.OperationState left, Azure.Health.Deidentification.OperationState right) { throw null; } + public override string ToString() { throw null; } + } + [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)] + public readonly partial struct OperationType : System.IEquatable + { + private readonly object _dummy; + private readonly int _dummyPrimitive; + public OperationType(string value) { throw null; } + public static Azure.Health.Deidentification.OperationType Redact { get { throw null; } } + public static Azure.Health.Deidentification.OperationType Surrogate { get { throw null; } } + public static Azure.Health.Deidentification.OperationType Tag { get { throw null; } } + public bool Equals(Azure.Health.Deidentification.OperationType other) { throw null; } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + public override bool Equals(object obj) { throw null; } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + public override int GetHashCode() { throw null; } + public static bool operator ==(Azure.Health.Deidentification.OperationType left, Azure.Health.Deidentification.OperationType right) { throw null; } + public static implicit operator Azure.Health.Deidentification.OperationType (string value) { throw null; } + public static bool operator !=(Azure.Health.Deidentification.OperationType left, Azure.Health.Deidentification.OperationType right) { throw null; } + public override string ToString() { throw null; } + } + [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)] + public readonly partial struct PhiCategory : System.IEquatable + { + private readonly object _dummy; + private readonly int _dummyPrimitive; + public PhiCategory(string value) { throw null; } + public static Azure.Health.Deidentification.PhiCategory Account { get { throw null; } } + public static Azure.Health.Deidentification.PhiCategory Age { get { throw null; } } + public static Azure.Health.Deidentification.PhiCategory BioID { get { throw null; } } + public static Azure.Health.Deidentification.PhiCategory City { get { throw null; } } + public static Azure.Health.Deidentification.PhiCategory CountryOrRegion { get { throw null; } } + public static Azure.Health.Deidentification.PhiCategory Date { get { throw null; } } + public static Azure.Health.Deidentification.PhiCategory Device { get { throw null; } } + public static Azure.Health.Deidentification.PhiCategory Doctor { get { throw null; } } + public static Azure.Health.Deidentification.PhiCategory Email { get { throw null; } } + public static Azure.Health.Deidentification.PhiCategory Fax { get { throw null; } } + public static Azure.Health.Deidentification.PhiCategory HealthPlan { get { throw null; } } + public static Azure.Health.Deidentification.PhiCategory Hospital { get { throw null; } } + public static Azure.Health.Deidentification.PhiCategory IDNum { get { throw null; } } + public static Azure.Health.Deidentification.PhiCategory IPAddress { get { throw null; } } + public static Azure.Health.Deidentification.PhiCategory License { get { throw null; } } + public static Azure.Health.Deidentification.PhiCategory LocationOther { get { throw null; } } + public static Azure.Health.Deidentification.PhiCategory MedicalRecord { get { throw null; } } + public static Azure.Health.Deidentification.PhiCategory Organization { get { throw null; } } + public static Azure.Health.Deidentification.PhiCategory Patient { get { throw null; } } + public static Azure.Health.Deidentification.PhiCategory Phone { get { throw null; } } + public static Azure.Health.Deidentification.PhiCategory Profession { get { throw null; } } + public static Azure.Health.Deidentification.PhiCategory SocialSecurity { get { throw null; } } + public static Azure.Health.Deidentification.PhiCategory State { get { throw null; } } + public static Azure.Health.Deidentification.PhiCategory Street { get { throw null; } } + public static Azure.Health.Deidentification.PhiCategory Unknown { get { throw null; } } + public static Azure.Health.Deidentification.PhiCategory Url { get { throw null; } } + public static Azure.Health.Deidentification.PhiCategory Username { get { throw null; } } + public static Azure.Health.Deidentification.PhiCategory Vehicle { get { throw null; } } + public static Azure.Health.Deidentification.PhiCategory Zip { get { throw null; } } + public bool Equals(Azure.Health.Deidentification.PhiCategory other) { throw null; } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + public override bool Equals(object obj) { throw null; } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + public override int GetHashCode() { throw null; } + public static bool operator ==(Azure.Health.Deidentification.PhiCategory left, Azure.Health.Deidentification.PhiCategory right) { throw null; } + public static implicit operator Azure.Health.Deidentification.PhiCategory (string value) { throw null; } + public static bool operator !=(Azure.Health.Deidentification.PhiCategory left, Azure.Health.Deidentification.PhiCategory right) { throw null; } + public override string ToString() { throw null; } + } + public partial class PhiEntity : System.ClientModel.Primitives.IJsonModel, System.ClientModel.Primitives.IPersistableModel + { + internal PhiEntity() { } + public Azure.Health.Deidentification.PhiCategory Category { get { throw null; } } + public double? ConfidenceScore { get { throw null; } } + public Azure.Health.Deidentification.StringIndex Length { get { throw null; } } + public Azure.Health.Deidentification.StringIndex Offset { get { throw null; } } + public string Text { get { throw null; } } + Azure.Health.Deidentification.PhiEntity System.ClientModel.Primitives.IJsonModel.Create(ref System.Text.Json.Utf8JsonReader reader, System.ClientModel.Primitives.ModelReaderWriterOptions options) { throw null; } + void System.ClientModel.Primitives.IJsonModel.Write(System.Text.Json.Utf8JsonWriter writer, System.ClientModel.Primitives.ModelReaderWriterOptions options) { } + Azure.Health.Deidentification.PhiEntity System.ClientModel.Primitives.IPersistableModel.Create(System.BinaryData data, System.ClientModel.Primitives.ModelReaderWriterOptions options) { throw null; } + string System.ClientModel.Primitives.IPersistableModel.GetFormatFromOptions(System.ClientModel.Primitives.ModelReaderWriterOptions options) { throw null; } + System.BinaryData System.ClientModel.Primitives.IPersistableModel.Write(System.ClientModel.Primitives.ModelReaderWriterOptions options) { throw null; } + } + public partial class PhiTaggerResult : System.ClientModel.Primitives.IJsonModel, System.ClientModel.Primitives.IPersistableModel + { + internal PhiTaggerResult() { } + public System.Collections.Generic.IReadOnlyList Entities { get { throw null; } } + public Azure.ETag? Etag { get { throw null; } } + public string Path { get { throw null; } } + Azure.Health.Deidentification.PhiTaggerResult System.ClientModel.Primitives.IJsonModel.Create(ref System.Text.Json.Utf8JsonReader reader, System.ClientModel.Primitives.ModelReaderWriterOptions options) { throw null; } + void System.ClientModel.Primitives.IJsonModel.Write(System.Text.Json.Utf8JsonWriter writer, System.ClientModel.Primitives.ModelReaderWriterOptions options) { } + Azure.Health.Deidentification.PhiTaggerResult System.ClientModel.Primitives.IPersistableModel.Create(System.BinaryData data, System.ClientModel.Primitives.ModelReaderWriterOptions options) { throw null; } + string System.ClientModel.Primitives.IPersistableModel.GetFormatFromOptions(System.ClientModel.Primitives.ModelReaderWriterOptions options) { throw null; } + System.BinaryData System.ClientModel.Primitives.IPersistableModel.Write(System.ClientModel.Primitives.ModelReaderWriterOptions options) { throw null; } + } + public partial class SourceStorageLocation : System.ClientModel.Primitives.IJsonModel, System.ClientModel.Primitives.IPersistableModel + { + public SourceStorageLocation(System.Uri location, string prefix) { } + public System.Collections.Generic.IList Extensions { get { throw null; } } + public System.Uri Location { get { throw null; } set { } } + public string Prefix { get { throw null; } set { } } + Azure.Health.Deidentification.SourceStorageLocation System.ClientModel.Primitives.IJsonModel.Create(ref System.Text.Json.Utf8JsonReader reader, System.ClientModel.Primitives.ModelReaderWriterOptions options) { throw null; } + void System.ClientModel.Primitives.IJsonModel.Write(System.Text.Json.Utf8JsonWriter writer, System.ClientModel.Primitives.ModelReaderWriterOptions options) { } + Azure.Health.Deidentification.SourceStorageLocation System.ClientModel.Primitives.IPersistableModel.Create(System.BinaryData data, System.ClientModel.Primitives.ModelReaderWriterOptions options) { throw null; } + string System.ClientModel.Primitives.IPersistableModel.GetFormatFromOptions(System.ClientModel.Primitives.ModelReaderWriterOptions options) { throw null; } + System.BinaryData System.ClientModel.Primitives.IPersistableModel.Write(System.ClientModel.Primitives.ModelReaderWriterOptions options) { throw null; } + } + public partial class StringIndex : System.ClientModel.Primitives.IJsonModel, System.ClientModel.Primitives.IPersistableModel + { + internal StringIndex() { } + public int CodePoint { get { throw null; } } + public int Utf16 { get { throw null; } } + public int Utf8 { get { throw null; } } + Azure.Health.Deidentification.StringIndex System.ClientModel.Primitives.IJsonModel.Create(ref System.Text.Json.Utf8JsonReader reader, System.ClientModel.Primitives.ModelReaderWriterOptions options) { throw null; } + void System.ClientModel.Primitives.IJsonModel.Write(System.Text.Json.Utf8JsonWriter writer, System.ClientModel.Primitives.ModelReaderWriterOptions options) { } + Azure.Health.Deidentification.StringIndex System.ClientModel.Primitives.IPersistableModel.Create(System.BinaryData data, System.ClientModel.Primitives.ModelReaderWriterOptions options) { throw null; } + string System.ClientModel.Primitives.IPersistableModel.GetFormatFromOptions(System.ClientModel.Primitives.ModelReaderWriterOptions options) { throw null; } + System.BinaryData System.ClientModel.Primitives.IPersistableModel.Write(System.ClientModel.Primitives.ModelReaderWriterOptions options) { throw null; } + } + public partial class TargetStorageLocation : System.ClientModel.Primitives.IJsonModel, System.ClientModel.Primitives.IPersistableModel + { + public TargetStorageLocation(System.Uri location, string prefix) { } + public System.Uri Location { get { throw null; } set { } } + public string Prefix { get { throw null; } set { } } + Azure.Health.Deidentification.TargetStorageLocation System.ClientModel.Primitives.IJsonModel.Create(ref System.Text.Json.Utf8JsonReader reader, System.ClientModel.Primitives.ModelReaderWriterOptions options) { throw null; } + void System.ClientModel.Primitives.IJsonModel.Write(System.Text.Json.Utf8JsonWriter writer, System.ClientModel.Primitives.ModelReaderWriterOptions options) { } + Azure.Health.Deidentification.TargetStorageLocation System.ClientModel.Primitives.IPersistableModel.Create(System.BinaryData data, System.ClientModel.Primitives.ModelReaderWriterOptions options) { throw null; } + string System.ClientModel.Primitives.IPersistableModel.GetFormatFromOptions(System.ClientModel.Primitives.ModelReaderWriterOptions options) { throw null; } + System.BinaryData System.ClientModel.Primitives.IPersistableModel.Write(System.ClientModel.Primitives.ModelReaderWriterOptions options) { throw null; } + } +} +namespace Microsoft.Extensions.Azure +{ + public static partial class HealthDeidentificationClientBuilderExtensions + { + public static Azure.Core.Extensions.IAzureClientBuilder AddDeidentificationClient(this TBuilder builder, System.Uri endpoint) where TBuilder : Azure.Core.Extensions.IAzureClientFactoryBuilderWithCredential { throw null; } + public static Azure.Core.Extensions.IAzureClientBuilder AddDeidentificationClient(this TBuilder builder, TConfiguration configuration) where TBuilder : Azure.Core.Extensions.IAzureClientFactoryBuilderWithConfiguration { throw null; } + } +} diff --git a/sdk/healthdataaiservices/Azure.Health.Deidentification/assets.json b/sdk/healthdataaiservices/Azure.Health.Deidentification/assets.json new file mode 100644 index 000000000000..6b99266787b7 --- /dev/null +++ b/sdk/healthdataaiservices/Azure.Health.Deidentification/assets.json @@ -0,0 +1,6 @@ +{ + "AssetsRepo": "Azure/azure-sdk-assets", + "AssetsRepoPrefixPath": "net", + "TagPrefix": "net/healthdataaiservices/Azure.Health.Deidentification", + "Tag": "net/healthdataaiservices/Azure.Health.Deidentification_d8c55b7fa6" +} diff --git a/sdk/healthdataaiservices/Azure.Health.Deidentification/docs/HowTo-RedactionFormatting.md b/sdk/healthdataaiservices/Azure.Health.Deidentification/docs/HowTo-RedactionFormatting.md new file mode 100644 index 000000000000..9748cc767426 --- /dev/null +++ b/sdk/healthdataaiservices/Azure.Health.Deidentification/docs/HowTo-RedactionFormatting.md @@ -0,0 +1,46 @@ +# Redaction Format Guide + +## Prerequisites + +1. Pass `RedactionFormat` to the API or Job parameters. +2. Must select `Redact` as `Operation` as well. +3. RedactionFormat supports up to 16 characters. + +## Variables + +Only supports a single instance of each variable type + +### Type + +`{type} => patient` + +```text + "inputText": "Hi my name is John Smith" + "operation": "Redact", + "redactionFormat": "<{type}>", + + # Output: + Hi my name is +``` + +Also supports Upper and Title cases + +```text + {Type} => {Patient} + {TYPE} => {PATIENT} +``` + +### Length + +`*{len} => ******(length of entity)` + +This will allow you to create a string matching the length of the PHI + +```text + "inputText": "Hi my name is John Smith" + "operation": "Redact", + "redactionFormat": "*{len}", + + # Output: + Hi my name is ********** +``` diff --git a/sdk/healthdataaiservices/Azure.Health.Deidentification/docs/images/ServiceUrl_Location.png b/sdk/healthdataaiservices/Azure.Health.Deidentification/docs/images/ServiceUrl_Location.png new file mode 100644 index 0000000000000000000000000000000000000000..923747280e9323b98caa7c4f58f5967e68cd3fe6 GIT binary patch literal 162387 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

8*3Jw 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%0D$;TYbSU&db=`R65 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≪;*XDj# zHUU1Jjs)|1=k1~H>s00uBhlN(aOel!?z@j$8J1FN8`c)&#$#5Piod`I!8K((=B?OZ z(hs}4^5y533(CEbkn)*GFI=dsH$U*)Jx&Ldf#E0avdwc67zKu83Bq*ATBGh= z&LRM46$NWp_(k`{okL`tXo+DFv2z^cj7Gl=KxiJvkCGFg^*jl?yJ#{mCnjw=Czs_} zDA5`{Kz0dCCosPY4mD=M`|wjr6cepgT*;%eGT>jQM}@ejJ~MD{FVI?-NXr|vVw{pc zD!%z42}_T&sra!Rgn0ITaszRY7VOukD*^Mjc(&NO`n5~iKPz+89!hz@H-FMg?;&wm z2kalzlf5p|6TU{+qNX_9HVy^B7hR5!v}7>54~_Eb^@YmWQhTNsFwUrHw~o47MR^Pz zR>?iV0Ix>S4nLzu~*rv!K|A=Vwb5B z-w9or-Ba}5#69A4A^A*&IQ4a)2Jyz4rh4&iJz(iTgQTgLBU5bKHH7e+l{w zch9&Wyrf~$M0y9el6bxRUJ8#=3die5V#8! zbrPSmzK(n7jtUJ#R3;Z;N;ckRmi{o5Ohj$H2UTke)zXf8Q9N?2=S~z`9hfz6+s18w z+23`VdStfi0AHx67d7OX`4*(gJzG-V)DAgN$?~|w}UZpi-px*5Sf4W`(1R-dB zE8LcBuChwK_g7_8>m^4~eQMx&75nuL6Zqtp`R{Ghr(<_EubBOx9<~T2=(Ju=o>sx0 z*friE`+{4+UQ4SSM;2{)2N_iT^90$A8*S)0V&BJxK(iRdmGZWM_N@u3MxKp1o^17* zJnKYBCg^^UwPkIQkf0j#qO+__jC+^#H&JMLB+1l7OKw1;`w^Myrh$+wvlb;pYw@K= zye@^J=Vla_vd2+!b?Ld{%sy|^PVhe5E>cm9PX+~&G$X8PA}!8Zs7i|RxQYTqH7J?S zvLi|Vyr8umlo2<#E*8^026I8;BL)f)ndPkOtN7>&_d>B>7e)-K3~t7as+pXlX_Ng* z4dv};2O9;(t+q*0UdM=?Z;FYHsUNAFefBA~jl_4=M1eO(lVG}+dY~8E<>11b_SU

|_&U|M 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 BunhnJ literal 0 HcmV?d00001 diff --git a/sdk/healthdataaiservices/Azure.Health.Deidentification/samples/README.md b/sdk/healthdataaiservices/Azure.Health.Deidentification/samples/README.md new file mode 100644 index 000000000000..99609b4f4440 --- /dev/null +++ b/sdk/healthdataaiservices/Azure.Health.Deidentification/samples/README.md @@ -0,0 +1,17 @@ +--- +page_type: sample +languages: +- csharp +products: +- azure +- azure-health-data-services +name: Azure.Health.Deidentification samples for .NET +description: Samples for the Azure.Health.Deidentification client library +--- + +# Azure Health Deidentification client SDK samples + + - [Deidentify a string of test](https://github.com/Azure/azure-sdk-for-net/blob/main/sdk/healthdataaiservices/Azure.Health.Deidentification/samples/Sample1_HelloWorld.md) + - [Create a job to deidentify files in Azure storage](https://github.com/Azure/azure-sdk-for-net/blob/main/sdk/healthdataaiservices/Azure.Health.Deidentification/samples/Sample2_CreateJob.md) + - [List all created jobs](https://github.com/Azure/azure-sdk-for-net/blob/main/sdk/healthdataaiservices/Azure.Health.Deidentification/samples/Sample3_ListJobs.md) + - [List all files processed by a job](https://github.com/Azure/azure-sdk-for-net/blob/main/sdk/healthdataaiservices/Azure.Health.Deidentification/samples/Sample4_ListCompletedFiles.md) diff --git a/sdk/healthdataaiservices/Azure.Health.Deidentification/samples/Sample1_HelloWorld.md b/sdk/healthdataaiservices/Azure.Health.Deidentification/samples/Sample1_HelloWorld.md new file mode 100644 index 000000000000..52fd1a443025 --- /dev/null +++ b/sdk/healthdataaiservices/Azure.Health.Deidentification/samples/Sample1_HelloWorld.md @@ -0,0 +1,25 @@ +# Realtime Deidentification + +This sample demonstrates how to create a `DeidentificationClient` and then deidentify a `string`. + +## Create a DeidentificationClient + +The service endpoint url can be pulled from the azure portal `Service Url`. + +```C# Snippet:AzHealthDeidSample1_HelloWorld +DeidentificationClient client = new( + new Uri(serviceEndpoint), + credential, + new DeidentificationClientOptions() +); +``` + +## Build Request and Call Function + +```C# Snippet:AzHealthDeidSample1_CreateRequest +DeidentificationContent content = new("Hello, John!", OperationType.Surrogate, DocumentDataType.Plaintext, null, null); + +Response result = client.Deidentify(content); +string outputString = result.Value.OutputText; +Console.WriteLine(outputString); // Hello, Tom! +``` diff --git a/sdk/healthdataaiservices/Azure.Health.Deidentification/samples/Sample1_HelloWorldAsync.md b/sdk/healthdataaiservices/Azure.Health.Deidentification/samples/Sample1_HelloWorldAsync.md new file mode 100644 index 000000000000..644c7cbabe72 --- /dev/null +++ b/sdk/healthdataaiservices/Azure.Health.Deidentification/samples/Sample1_HelloWorldAsync.md @@ -0,0 +1,25 @@ +# Realtime Deidentification Async + +This sample demonstrates how to create a `DeidentificationClient` and then deidentify a `string`. + +## Create a DeidentificationClient + +The service endpoint url can be pulled from the azure portal `Service Url`. + +```C# Snippet:AzHealthDeidSample1Async_HelloWorld +DeidentificationClient client = new( + new Uri(serviceEndpoint), + credential, + new DeidentificationClientOptions() +); +``` + +## Build Request and Call Function + +```C# Snippet:AzHealthDeidSample1Async_CreateRequest +DeidentificationContent content = new("Hello, John!", OperationType.Surrogate, DocumentDataType.Plaintext, null, null); + +Response result = await client.DeidentifyAsync(content); +string outputString = result.Value.OutputText; +Console.WriteLine(outputString); // Hello, Tom! +``` diff --git a/sdk/healthdataaiservices/Azure.Health.Deidentification/samples/Sample2_CreateJob.md b/sdk/healthdataaiservices/Azure.Health.Deidentification/samples/Sample2_CreateJob.md new file mode 100644 index 000000000000..97d4c98f9698 --- /dev/null +++ b/sdk/healthdataaiservices/Azure.Health.Deidentification/samples/Sample2_CreateJob.md @@ -0,0 +1,18 @@ +# Realtime Deidentification + +This sample demonstrates how to create a job which will deidentify all files within a blob storage container filtering via a prefix. + +## Create Job and Check Status + +```C# Snippet:AzHealthDeidSample2_CreateJob +DeidentificationJob job = new() +{ + SourceLocation = new SourceStorageLocation(new Uri(storageAccountUrl), "folder1/"), + TargetLocation = new TargetStorageLocation(new Uri(storageAccountUrl), "output_path"), + DataType = DocumentDataType.Plaintext, + Operation = OperationType.Surrogate +}; + +job = client.CreateJob(WaitUntil.Started, "my-job-1", job).Value; +Console.WriteLine($"Job status: {job.Status}"); // Job status: NotStarted +``` diff --git a/sdk/healthdataaiservices/Azure.Health.Deidentification/samples/Sample2_CreateJobAsync.md b/sdk/healthdataaiservices/Azure.Health.Deidentification/samples/Sample2_CreateJobAsync.md new file mode 100644 index 000000000000..0a64e294e38a --- /dev/null +++ b/sdk/healthdataaiservices/Azure.Health.Deidentification/samples/Sample2_CreateJobAsync.md @@ -0,0 +1,19 @@ +# Create and Run Job Async + +This sample demonstrates how to create a job which will deidentify all files within a blob storage container filtering via a prefix. + + +## Create Job and Check Status + +```C# Snippet:AzHealthDeidSample2Async_CreateJob +DeidentificationJob job = new() +{ + SourceLocation = new SourceStorageLocation(new Uri(storageAccountUrl), "folder1/"), + TargetLocation = new TargetStorageLocation(new Uri(storageAccountUrl), "output_path"), + DataType = DocumentDataType.Plaintext, + Operation = OperationType.Surrogate +}; + +job = (await client.CreateJobAsync(WaitUntil.Completed, "my-job-1", job)).Value; +Console.WriteLine($"Job Status: {job.Status}"); // Job Status: Completed +``` diff --git a/sdk/healthdataaiservices/Azure.Health.Deidentification/samples/Sample3_ListJobs.md b/sdk/healthdataaiservices/Azure.Health.Deidentification/samples/Sample3_ListJobs.md new file mode 100644 index 000000000000..a0d55c25598a --- /dev/null +++ b/sdk/healthdataaiservices/Azure.Health.Deidentification/samples/Sample3_ListJobs.md @@ -0,0 +1,16 @@ +# List Jobs + +This sample demonstrates how to list jobs an iterate over in a for loop. + + +## List Jobs and iterate over in a for loop + +```C# Snippet:AzHealthDeidSample3_ListJobs +Pageable jobs = client.GetJobs(); + +foreach (DeidentificationJob job in jobs) +{ + Console.WriteLine($"Job Name: {job.Name}"); + Console.WriteLine($"Job Status: {job.Status}"); +} +``` diff --git a/sdk/healthdataaiservices/Azure.Health.Deidentification/samples/Sample3_ListJobsAsync.md b/sdk/healthdataaiservices/Azure.Health.Deidentification/samples/Sample3_ListJobsAsync.md new file mode 100644 index 000000000000..e583db0c1afb --- /dev/null +++ b/sdk/healthdataaiservices/Azure.Health.Deidentification/samples/Sample3_ListJobsAsync.md @@ -0,0 +1,16 @@ +# List Jobs Async + +This sample demonstrates how to list jobs an iterate over in a for loop. + + +## List Jobs and iterate over in a for loop + +```C# Snippet:AzHealthDeidSample3Async_ListJobs +AsyncPageable jobs = client.GetJobsAsync(); + +await foreach (DeidentificationJob job in jobs) +{ + Console.WriteLine($"Job Name: {job.Name}"); + Console.WriteLine($"Job Status: {job.Status}"); +} +``` diff --git a/sdk/healthdataaiservices/Azure.Health.Deidentification/samples/Sample4_ListCompletedFiles.md b/sdk/healthdataaiservices/Azure.Health.Deidentification/samples/Sample4_ListCompletedFiles.md new file mode 100644 index 000000000000..438f6ce8f43c --- /dev/null +++ b/sdk/healthdataaiservices/Azure.Health.Deidentification/samples/Sample4_ListCompletedFiles.md @@ -0,0 +1,17 @@ +# List Completed Files + +This sample demonstrates how to list files that were completed by a job. + + +## List Completed Files and iterate over in a for loop + +```C# Snippet:AzHealthDeidSample4_ListCompletedFiles +Pageable files = client.GetJobDocuments("job-name-1"); + +foreach (DocumentDetails file in files) +{ + Console.WriteLine($"File Name: {file.Input.Path}"); + Console.WriteLine($"File Status: {file.Status}"); + Console.WriteLine($"File Output Path: {file.Output.Path}"); +} +``` diff --git a/sdk/healthdataaiservices/Azure.Health.Deidentification/samples/Sample4_ListCompletedFilesAsync.md b/sdk/healthdataaiservices/Azure.Health.Deidentification/samples/Sample4_ListCompletedFilesAsync.md new file mode 100644 index 000000000000..43447cd0f513 --- /dev/null +++ b/sdk/healthdataaiservices/Azure.Health.Deidentification/samples/Sample4_ListCompletedFilesAsync.md @@ -0,0 +1,17 @@ +# List Completed Files Async + +This sample demonstrates how to list files that were completed by a job. + + +## List Completed Files and iterate over in a for loop + +```C# Snippet:AzHealthDeidSample4Async_ListCompletedFiles +AsyncPageable files = client.GetJobDocumentsAsync("job-name-1"); + +await foreach (DocumentDetails file in files) +{ + Console.WriteLine($"File Name: {file.Input.Path}"); + Console.WriteLine($"File Status: {file.Status}"); + Console.WriteLine($"File Output Path: {file.Output.Path}"); +} +``` diff --git a/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Azure.Health.Deidentification.csproj b/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Azure.Health.Deidentification.csproj new file mode 100644 index 000000000000..95277fd817b6 --- /dev/null +++ b/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Azure.Health.Deidentification.csproj @@ -0,0 +1,19 @@ + + + This is the Azure.Health.Deidentification client library for developing .NET applications with rich experience. + Azure SDK Code Generation Azure.Health.Deidentification for Azure Data Plane + 1.0.0-beta.1 + Azure.Health.Deidentification + $(RequiredTargetFrameworks) + true + + + + + + + + + + + diff --git a/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/DeidentificationClient.cs b/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/DeidentificationClient.cs new file mode 100644 index 000000000000..cf93beb8499e --- /dev/null +++ b/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/DeidentificationClient.cs @@ -0,0 +1,974 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System; +using System.Threading; +using System.Threading.Tasks; +using Autorest.CSharp.Core; +using Azure.Core; +using Azure.Core.Pipeline; + +namespace Azure.Health.Deidentification +{ + // Data plane generated client. + ///

The Deidentification service client. + public partial class DeidentificationClient + { + private static readonly string[] AuthorizationScopes = new string[] { "https://deid.azure.com/.default" }; + private readonly TokenCredential _tokenCredential; + private readonly HttpPipeline _pipeline; + private readonly Uri _endpoint; + private readonly string _apiVersion; + + /// The ClientDiagnostics is used to provide tracing support for the client library. + internal ClientDiagnostics ClientDiagnostics { get; } + + /// The HTTP pipeline for sending and receiving REST requests and responses. + public virtual HttpPipeline Pipeline => _pipeline; + + /// Initializes a new instance of DeidentificationClient for mocking. + protected DeidentificationClient() + { + } + + /// Initializes a new instance of DeidentificationClient. + /// Url of your De-identification Service. + /// A credential used to authenticate to an Azure Service. + /// or is null. + public DeidentificationClient(Uri endpoint, TokenCredential credential) : this(endpoint, credential, new DeidentificationClientOptions()) + { + } + + /// Initializes a new instance of DeidentificationClient. + /// Url of your De-identification Service. + /// A credential used to authenticate to an Azure Service. + /// The options for configuring the client. + /// or is null. + public DeidentificationClient(Uri endpoint, TokenCredential credential, DeidentificationClientOptions options) + { + Argument.AssertNotNull(endpoint, nameof(endpoint)); + Argument.AssertNotNull(credential, nameof(credential)); + options ??= new DeidentificationClientOptions(); + + ClientDiagnostics = new ClientDiagnostics(options, true); + _tokenCredential = credential; + _pipeline = HttpPipelineBuilder.Build(options, Array.Empty(), new HttpPipelinePolicy[] { new BearerTokenAuthenticationPolicy(_tokenCredential, AuthorizationScopes) }, new ResponseClassifier()); + _endpoint = endpoint; + _apiVersion = options.Version; + } + + /// Get a de-identification job. + /// The name of a job. + /// The cancellation token to use. + /// is null. + /// is an empty string, and was expected to be non-empty. + /// Resource read operation template. + /// + public virtual async Task> GetJobAsync(string name, CancellationToken cancellationToken = default) + { + Argument.AssertNotNullOrEmpty(name, nameof(name)); + + RequestContext context = FromCancellationToken(cancellationToken); + Response response = await GetJobAsync(name, context).ConfigureAwait(false); + return Response.FromValue(DeidentificationJob.FromResponse(response), response); + } + + /// Get a de-identification job. + /// The name of a job. + /// The cancellation token to use. + /// is null. + /// is an empty string, and was expected to be non-empty. + /// Resource read operation template. + /// + public virtual Response GetJob(string name, CancellationToken cancellationToken = default) + { + Argument.AssertNotNullOrEmpty(name, nameof(name)); + + RequestContext context = FromCancellationToken(cancellationToken); + Response response = GetJob(name, context); + return Response.FromValue(DeidentificationJob.FromResponse(response), response); + } + + /// + /// [Protocol Method] Get a de-identification job. + /// + /// + /// + /// This protocol method allows explicit creation of the request and processing of the response for advanced scenarios. + /// + /// + /// + /// + /// Please try the simpler convenience overload with strongly typed models first. + /// + /// + /// + /// + /// The name of a job. + /// The request context, which can override default behaviors of the client pipeline on a per-call basis. + /// is null. + /// is an empty string, and was expected to be non-empty. + /// Service returned a non-success status code. + /// The response returned from the service. + /// + public virtual async Task GetJobAsync(string name, RequestContext context) + { + Argument.AssertNotNullOrEmpty(name, nameof(name)); + + using var scope = ClientDiagnostics.CreateScope("DeidentificationClient.GetJob"); + scope.Start(); + try + { + using HttpMessage message = CreateGetJobRequest(name, context); + return await _pipeline.ProcessMessageAsync(message, context).ConfigureAwait(false); + } + catch (Exception e) + { + scope.Failed(e); + throw; + } + } + + /// + /// [Protocol Method] Get a de-identification job. + /// + /// + /// + /// This protocol method allows explicit creation of the request and processing of the response for advanced scenarios. + /// + /// + /// + /// + /// Please try the simpler convenience overload with strongly typed models first. + /// + /// + /// + /// + /// The name of a job. + /// The request context, which can override default behaviors of the client pipeline on a per-call basis. + /// is null. + /// is an empty string, and was expected to be non-empty. + /// Service returned a non-success status code. + /// The response returned from the service. + /// + public virtual Response GetJob(string name, RequestContext context) + { + Argument.AssertNotNullOrEmpty(name, nameof(name)); + + using var scope = ClientDiagnostics.CreateScope("DeidentificationClient.GetJob"); + scope.Start(); + try + { + using HttpMessage message = CreateGetJobRequest(name, context); + return _pipeline.ProcessMessage(message, context); + } + catch (Exception e) + { + scope.Failed(e); + throw; + } + } + + /// Cancel a de-identification job. + /// The name of a job. + /// The cancellation token to use. + /// is null. + /// is an empty string, and was expected to be non-empty. + /// + /// Cancels a job that is in progress. + /// + /// The job will be marked as canceled and the service will stop processing the job. The service will not delete any documents that have already been processed. + /// + /// If the job is already complete, this will have no effect. + /// + /// + public virtual async Task> CancelJobAsync(string name, CancellationToken cancellationToken = default) + { + Argument.AssertNotNullOrEmpty(name, nameof(name)); + + RequestContext context = FromCancellationToken(cancellationToken); + Response response = await CancelJobAsync(name, context).ConfigureAwait(false); + return Response.FromValue(DeidentificationJob.FromResponse(response), response); + } + + /// Cancel a de-identification job. + /// The name of a job. + /// The cancellation token to use. + /// is null. + /// is an empty string, and was expected to be non-empty. + /// + /// Cancels a job that is in progress. + /// + /// The job will be marked as canceled and the service will stop processing the job. The service will not delete any documents that have already been processed. + /// + /// If the job is already complete, this will have no effect. + /// + /// + public virtual Response CancelJob(string name, CancellationToken cancellationToken = default) + { + Argument.AssertNotNullOrEmpty(name, nameof(name)); + + RequestContext context = FromCancellationToken(cancellationToken); + Response response = CancelJob(name, context); + return Response.FromValue(DeidentificationJob.FromResponse(response), response); + } + + /// + /// [Protocol Method] Cancel a de-identification job. + /// + /// + /// + /// This protocol method allows explicit creation of the request and processing of the response for advanced scenarios. + /// + /// + /// + /// + /// Please try the simpler convenience overload with strongly typed models first. + /// + /// + /// + /// + /// The name of a job. + /// The request context, which can override default behaviors of the client pipeline on a per-call basis. + /// is null. + /// is an empty string, and was expected to be non-empty. + /// Service returned a non-success status code. + /// The response returned from the service. + /// + public virtual async Task CancelJobAsync(string name, RequestContext context) + { + Argument.AssertNotNullOrEmpty(name, nameof(name)); + + using var scope = ClientDiagnostics.CreateScope("DeidentificationClient.CancelJob"); + scope.Start(); + try + { + using HttpMessage message = CreateCancelJobRequest(name, context); + return await _pipeline.ProcessMessageAsync(message, context).ConfigureAwait(false); + } + catch (Exception e) + { + scope.Failed(e); + throw; + } + } + + /// + /// [Protocol Method] Cancel a de-identification job. + /// + /// + /// + /// This protocol method allows explicit creation of the request and processing of the response for advanced scenarios. + /// + /// + /// + /// + /// Please try the simpler convenience overload with strongly typed models first. + /// + /// + /// + /// + /// The name of a job. + /// The request context, which can override default behaviors of the client pipeline on a per-call basis. + /// is null. + /// is an empty string, and was expected to be non-empty. + /// Service returned a non-success status code. + /// The response returned from the service. + /// + public virtual Response CancelJob(string name, RequestContext context) + { + Argument.AssertNotNullOrEmpty(name, nameof(name)); + + using var scope = ClientDiagnostics.CreateScope("DeidentificationClient.CancelJob"); + scope.Start(); + try + { + using HttpMessage message = CreateCancelJobRequest(name, context); + return _pipeline.ProcessMessage(message, context); + } + catch (Exception e) + { + scope.Failed(e); + throw; + } + } + + // The convenience method is omitted here because it has exactly the same parameter list as the corresponding protocol method + /// + /// [Protocol Method] Delete a de-identification job. + /// + /// + /// + /// This protocol method allows explicit creation of the request and processing of the response for advanced scenarios. + /// + /// + /// + /// + /// The name of a job. + /// The request context, which can override default behaviors of the client pipeline on a per-call basis. + /// is null. + /// is an empty string, and was expected to be non-empty. + /// Service returned a non-success status code. + /// The response returned from the service. + /// + public virtual async Task DeleteJobAsync(string name, RequestContext context = null) + { + Argument.AssertNotNullOrEmpty(name, nameof(name)); + + using var scope = ClientDiagnostics.CreateScope("DeidentificationClient.DeleteJob"); + scope.Start(); + try + { + using HttpMessage message = CreateDeleteJobRequest(name, context); + return await _pipeline.ProcessMessageAsync(message, context).ConfigureAwait(false); + } + catch (Exception e) + { + scope.Failed(e); + throw; + } + } + + // The convenience method is omitted here because it has exactly the same parameter list as the corresponding protocol method + /// + /// [Protocol Method] Delete a de-identification job. + /// + /// + /// + /// This protocol method allows explicit creation of the request and processing of the response for advanced scenarios. + /// + /// + /// + /// + /// The name of a job. + /// The request context, which can override default behaviors of the client pipeline on a per-call basis. + /// is null. + /// is an empty string, and was expected to be non-empty. + /// Service returned a non-success status code. + /// The response returned from the service. + /// + public virtual Response DeleteJob(string name, RequestContext context = null) + { + Argument.AssertNotNullOrEmpty(name, nameof(name)); + + using var scope = ClientDiagnostics.CreateScope("DeidentificationClient.DeleteJob"); + scope.Start(); + try + { + using HttpMessage message = CreateDeleteJobRequest(name, context); + return _pipeline.ProcessMessage(message, context); + } + catch (Exception e) + { + scope.Failed(e); + throw; + } + } + + /// De-identify text. + /// Request body for de-identification operation. + /// The cancellation token to use. + /// is null. + /// A remote procedure call (RPC) operation. + /// + public virtual async Task> DeidentifyAsync(DeidentificationContent body, CancellationToken cancellationToken = default) + { + Argument.AssertNotNull(body, nameof(body)); + + using RequestContent content = body.ToRequestContent(); + RequestContext context = FromCancellationToken(cancellationToken); + Response response = await DeidentifyAsync(content, context).ConfigureAwait(false); + return Response.FromValue(DeidentificationResult.FromResponse(response), response); + } + + /// De-identify text. + /// Request body for de-identification operation. + /// The cancellation token to use. + /// is null. + /// A remote procedure call (RPC) operation. + /// + public virtual Response Deidentify(DeidentificationContent body, CancellationToken cancellationToken = default) + { + Argument.AssertNotNull(body, nameof(body)); + + using RequestContent content = body.ToRequestContent(); + RequestContext context = FromCancellationToken(cancellationToken); + Response response = Deidentify(content, context); + return Response.FromValue(DeidentificationResult.FromResponse(response), response); + } + + /// + /// [Protocol Method] De-identify text. + /// + /// + /// + /// This protocol method allows explicit creation of the request and processing of the response for advanced scenarios. + /// + /// + /// + /// + /// Please try the simpler convenience overload with strongly typed models first. + /// + /// + /// + /// + /// The content to send as the body of the request. + /// The request context, which can override default behaviors of the client pipeline on a per-call basis. + /// is null. + /// Service returned a non-success status code. + /// The response returned from the service. + /// + public virtual async Task DeidentifyAsync(RequestContent content, RequestContext context = null) + { + Argument.AssertNotNull(content, nameof(content)); + + using var scope = ClientDiagnostics.CreateScope("DeidentificationClient.Deidentify"); + scope.Start(); + try + { + using HttpMessage message = CreateDeidentifyRequest(content, context); + return await _pipeline.ProcessMessageAsync(message, context).ConfigureAwait(false); + } + catch (Exception e) + { + scope.Failed(e); + throw; + } + } + + /// + /// [Protocol Method] De-identify text. + /// + /// + /// + /// This protocol method allows explicit creation of the request and processing of the response for advanced scenarios. + /// + /// + /// + /// + /// Please try the simpler convenience overload with strongly typed models first. + /// + /// + /// + /// + /// The content to send as the body of the request. + /// The request context, which can override default behaviors of the client pipeline on a per-call basis. + /// is null. + /// Service returned a non-success status code. + /// The response returned from the service. + /// + public virtual Response Deidentify(RequestContent content, RequestContext context = null) + { + Argument.AssertNotNull(content, nameof(content)); + + using var scope = ClientDiagnostics.CreateScope("DeidentificationClient.Deidentify"); + scope.Start(); + try + { + using HttpMessage message = CreateDeidentifyRequest(content, context); + return _pipeline.ProcessMessage(message, context); + } + catch (Exception e) + { + scope.Failed(e); + throw; + } + } + + /// List de-identification jobs. + /// The maximum number of result items per page. + /// Token to continue a previous query. + /// The cancellation token to use. + /// Resource list operation template. + /// + public virtual AsyncPageable GetJobsAsync(int? maxpagesize = null, string continuationToken = null, CancellationToken cancellationToken = default) + { + RequestContext context = cancellationToken.CanBeCanceled ? new RequestContext { CancellationToken = cancellationToken } : null; + HttpMessage FirstPageRequest(int? pageSizeHint) => CreateGetJobsRequest(maxpagesize, continuationToken, context); + HttpMessage NextPageRequest(int? pageSizeHint, string nextLink) => CreateGetJobsNextPageRequest(nextLink, maxpagesize, continuationToken, context); + return GeneratorPageableHelpers.CreateAsyncPageable(FirstPageRequest, NextPageRequest, e => DeidentificationJob.DeserializeDeidentificationJob(e), ClientDiagnostics, _pipeline, "DeidentificationClient.GetJobs", "value", "nextLink", context); + } + + /// List de-identification jobs. + /// The maximum number of result items per page. + /// Token to continue a previous query. + /// The cancellation token to use. + /// Resource list operation template. + /// + public virtual Pageable GetJobs(int? maxpagesize = null, string continuationToken = null, CancellationToken cancellationToken = default) + { + RequestContext context = cancellationToken.CanBeCanceled ? new RequestContext { CancellationToken = cancellationToken } : null; + HttpMessage FirstPageRequest(int? pageSizeHint) => CreateGetJobsRequest(maxpagesize, continuationToken, context); + HttpMessage NextPageRequest(int? pageSizeHint, string nextLink) => CreateGetJobsNextPageRequest(nextLink, maxpagesize, continuationToken, context); + return GeneratorPageableHelpers.CreatePageable(FirstPageRequest, NextPageRequest, e => DeidentificationJob.DeserializeDeidentificationJob(e), ClientDiagnostics, _pipeline, "DeidentificationClient.GetJobs", "value", "nextLink", context); + } + + /// + /// [Protocol Method] List de-identification jobs. + /// + /// + /// + /// This protocol method allows explicit creation of the request and processing of the response for advanced scenarios. + /// + /// + /// + /// + /// Please try the simpler convenience overload with strongly typed models first. + /// + /// + /// + /// + /// The maximum number of result items per page. + /// Token to continue a previous query. + /// The request context, which can override default behaviors of the client pipeline on a per-call basis. + /// Service returned a non-success status code. + /// The from the service containing a list of objects. Details of the body schema for each item in the collection are in the Remarks section below. + /// + public virtual AsyncPageable GetJobsAsync(int? maxpagesize, string continuationToken, RequestContext context) + { + HttpMessage FirstPageRequest(int? pageSizeHint) => CreateGetJobsRequest(maxpagesize, continuationToken, context); + HttpMessage NextPageRequest(int? pageSizeHint, string nextLink) => CreateGetJobsNextPageRequest(nextLink, maxpagesize, continuationToken, context); + return GeneratorPageableHelpers.CreateAsyncPageable(FirstPageRequest, NextPageRequest, e => BinaryData.FromString(e.GetRawText()), ClientDiagnostics, _pipeline, "DeidentificationClient.GetJobs", "value", "nextLink", context); + } + + /// + /// [Protocol Method] List de-identification jobs. + /// + /// + /// + /// This protocol method allows explicit creation of the request and processing of the response for advanced scenarios. + /// + /// + /// + /// + /// Please try the simpler convenience overload with strongly typed models first. + /// + /// + /// + /// + /// The maximum number of result items per page. + /// Token to continue a previous query. + /// The request context, which can override default behaviors of the client pipeline on a per-call basis. + /// Service returned a non-success status code. + /// The from the service containing a list of objects. Details of the body schema for each item in the collection are in the Remarks section below. + /// + public virtual Pageable GetJobs(int? maxpagesize, string continuationToken, RequestContext context) + { + HttpMessage FirstPageRequest(int? pageSizeHint) => CreateGetJobsRequest(maxpagesize, continuationToken, context); + HttpMessage NextPageRequest(int? pageSizeHint, string nextLink) => CreateGetJobsNextPageRequest(nextLink, maxpagesize, continuationToken, context); + return GeneratorPageableHelpers.CreatePageable(FirstPageRequest, NextPageRequest, e => BinaryData.FromString(e.GetRawText()), ClientDiagnostics, _pipeline, "DeidentificationClient.GetJobs", "value", "nextLink", context); + } + + /// List processed documents within a job. + /// The name of a job. + /// The maximum number of result items per page. + /// Token to continue a previous query. + /// The cancellation token to use. + /// is null. + /// is an empty string, and was expected to be non-empty. + /// Resource list operation template. + /// + public virtual AsyncPageable GetJobDocumentsAsync(string name, int? maxpagesize = null, string continuationToken = null, CancellationToken cancellationToken = default) + { + Argument.AssertNotNullOrEmpty(name, nameof(name)); + + RequestContext context = cancellationToken.CanBeCanceled ? new RequestContext { CancellationToken = cancellationToken } : null; + HttpMessage FirstPageRequest(int? pageSizeHint) => CreateGetJobDocumentsRequest(name, maxpagesize, continuationToken, context); + HttpMessage NextPageRequest(int? pageSizeHint, string nextLink) => CreateGetJobDocumentsNextPageRequest(nextLink, name, maxpagesize, continuationToken, context); + return GeneratorPageableHelpers.CreateAsyncPageable(FirstPageRequest, NextPageRequest, e => DocumentDetails.DeserializeDocumentDetails(e), ClientDiagnostics, _pipeline, "DeidentificationClient.GetJobDocuments", "value", "nextLink", context); + } + + /// List processed documents within a job. + /// The name of a job. + /// The maximum number of result items per page. + /// Token to continue a previous query. + /// The cancellation token to use. + /// is null. + /// is an empty string, and was expected to be non-empty. + /// Resource list operation template. + /// + public virtual Pageable GetJobDocuments(string name, int? maxpagesize = null, string continuationToken = null, CancellationToken cancellationToken = default) + { + Argument.AssertNotNullOrEmpty(name, nameof(name)); + + RequestContext context = cancellationToken.CanBeCanceled ? new RequestContext { CancellationToken = cancellationToken } : null; + HttpMessage FirstPageRequest(int? pageSizeHint) => CreateGetJobDocumentsRequest(name, maxpagesize, continuationToken, context); + HttpMessage NextPageRequest(int? pageSizeHint, string nextLink) => CreateGetJobDocumentsNextPageRequest(nextLink, name, maxpagesize, continuationToken, context); + return GeneratorPageableHelpers.CreatePageable(FirstPageRequest, NextPageRequest, e => DocumentDetails.DeserializeDocumentDetails(e), ClientDiagnostics, _pipeline, "DeidentificationClient.GetJobDocuments", "value", "nextLink", context); + } + + /// + /// [Protocol Method] List processed documents within a job. + /// + /// + /// + /// This protocol method allows explicit creation of the request and processing of the response for advanced scenarios. + /// + /// + /// + /// + /// Please try the simpler convenience overload with strongly typed models first. + /// + /// + /// + /// + /// The name of a job. + /// The maximum number of result items per page. + /// Token to continue a previous query. + /// The request context, which can override default behaviors of the client pipeline on a per-call basis. + /// is null. + /// is an empty string, and was expected to be non-empty. + /// Service returned a non-success status code. + /// The from the service containing a list of objects. Details of the body schema for each item in the collection are in the Remarks section below. + /// + public virtual AsyncPageable GetJobDocumentsAsync(string name, int? maxpagesize, string continuationToken, RequestContext context) + { + Argument.AssertNotNullOrEmpty(name, nameof(name)); + + HttpMessage FirstPageRequest(int? pageSizeHint) => CreateGetJobDocumentsRequest(name, maxpagesize, continuationToken, context); + HttpMessage NextPageRequest(int? pageSizeHint, string nextLink) => CreateGetJobDocumentsNextPageRequest(nextLink, name, maxpagesize, continuationToken, context); + return GeneratorPageableHelpers.CreateAsyncPageable(FirstPageRequest, NextPageRequest, e => BinaryData.FromString(e.GetRawText()), ClientDiagnostics, _pipeline, "DeidentificationClient.GetJobDocuments", "value", "nextLink", context); + } + + /// + /// [Protocol Method] List processed documents within a job. + /// + /// + /// + /// This protocol method allows explicit creation of the request and processing of the response for advanced scenarios. + /// + /// + /// + /// + /// Please try the simpler convenience overload with strongly typed models first. + /// + /// + /// + /// + /// The name of a job. + /// The maximum number of result items per page. + /// Token to continue a previous query. + /// The request context, which can override default behaviors of the client pipeline on a per-call basis. + /// is null. + /// is an empty string, and was expected to be non-empty. + /// Service returned a non-success status code. + /// The from the service containing a list of objects. Details of the body schema for each item in the collection are in the Remarks section below. + /// + public virtual Pageable GetJobDocuments(string name, int? maxpagesize, string continuationToken, RequestContext context) + { + Argument.AssertNotNullOrEmpty(name, nameof(name)); + + HttpMessage FirstPageRequest(int? pageSizeHint) => CreateGetJobDocumentsRequest(name, maxpagesize, continuationToken, context); + HttpMessage NextPageRequest(int? pageSizeHint, string nextLink) => CreateGetJobDocumentsNextPageRequest(nextLink, name, maxpagesize, continuationToken, context); + return GeneratorPageableHelpers.CreatePageable(FirstPageRequest, NextPageRequest, e => BinaryData.FromString(e.GetRawText()), ClientDiagnostics, _pipeline, "DeidentificationClient.GetJobDocuments", "value", "nextLink", context); + } + + /// Create a de-identification job. + /// if the method should wait to return until the long-running operation has completed on the service; if it should return after starting the operation. For more information on long-running operations, please see Azure.Core Long-Running Operation samples. + /// The name of a job. + /// The resource instance. + /// The cancellation token to use. + /// or is null. + /// is an empty string, and was expected to be non-empty. + /// Long-running resource create or replace operation template. + /// + public virtual async Task> CreateJobAsync(WaitUntil waitUntil, string name, DeidentificationJob resource, CancellationToken cancellationToken = default) + { + Argument.AssertNotNullOrEmpty(name, nameof(name)); + Argument.AssertNotNull(resource, nameof(resource)); + + using RequestContent content = resource.ToRequestContent(); + RequestContext context = FromCancellationToken(cancellationToken); + Operation response = await CreateJobAsync(waitUntil, name, content, context).ConfigureAwait(false); + return ProtocolOperationHelpers.Convert(response, DeidentificationJob.FromResponse, ClientDiagnostics, "DeidentificationClient.CreateJob"); + } + + /// Create a de-identification job. + /// if the method should wait to return until the long-running operation has completed on the service; if it should return after starting the operation. For more information on long-running operations, please see Azure.Core Long-Running Operation samples. + /// The name of a job. + /// The resource instance. + /// The cancellation token to use. + /// or is null. + /// is an empty string, and was expected to be non-empty. + /// Long-running resource create or replace operation template. + /// + public virtual Operation CreateJob(WaitUntil waitUntil, string name, DeidentificationJob resource, CancellationToken cancellationToken = default) + { + Argument.AssertNotNullOrEmpty(name, nameof(name)); + Argument.AssertNotNull(resource, nameof(resource)); + + using RequestContent content = resource.ToRequestContent(); + RequestContext context = FromCancellationToken(cancellationToken); + Operation response = CreateJob(waitUntil, name, content, context); + return ProtocolOperationHelpers.Convert(response, DeidentificationJob.FromResponse, ClientDiagnostics, "DeidentificationClient.CreateJob"); + } + + /// + /// [Protocol Method] Create a de-identification job. + /// + /// + /// + /// This protocol method allows explicit creation of the request and processing of the response for advanced scenarios. + /// + /// + /// + /// + /// Please try the simpler convenience overload with strongly typed models first. + /// + /// + /// + /// + /// if the method should wait to return until the long-running operation has completed on the service; if it should return after starting the operation. For more information on long-running operations, please see Azure.Core Long-Running Operation samples. + /// The name of a job. + /// The content to send as the body of the request. + /// The request context, which can override default behaviors of the client pipeline on a per-call basis. + /// or is null. + /// is an empty string, and was expected to be non-empty. + /// Service returned a non-success status code. + /// The representing an asynchronous operation on the service. + /// + public virtual async Task> CreateJobAsync(WaitUntil waitUntil, string name, RequestContent content, RequestContext context = null) + { + Argument.AssertNotNullOrEmpty(name, nameof(name)); + Argument.AssertNotNull(content, nameof(content)); + + using var scope = ClientDiagnostics.CreateScope("DeidentificationClient.CreateJob"); + scope.Start(); + try + { + using HttpMessage message = CreateCreateJobRequest(name, content, context); + return await ProtocolOperationHelpers.ProcessMessageAsync(_pipeline, message, ClientDiagnostics, "DeidentificationClient.CreateJob", OperationFinalStateVia.OriginalUri, context, waitUntil).ConfigureAwait(false); + } + catch (Exception e) + { + scope.Failed(e); + throw; + } + } + + /// + /// [Protocol Method] Create a de-identification job. + /// + /// + /// + /// This protocol method allows explicit creation of the request and processing of the response for advanced scenarios. + /// + /// + /// + /// + /// Please try the simpler convenience overload with strongly typed models first. + /// + /// + /// + /// + /// if the method should wait to return until the long-running operation has completed on the service; if it should return after starting the operation. For more information on long-running operations, please see Azure.Core Long-Running Operation samples. + /// The name of a job. + /// The content to send as the body of the request. + /// The request context, which can override default behaviors of the client pipeline on a per-call basis. + /// or is null. + /// is an empty string, and was expected to be non-empty. + /// Service returned a non-success status code. + /// The representing an asynchronous operation on the service. + /// + public virtual Operation CreateJob(WaitUntil waitUntil, string name, RequestContent content, RequestContext context = null) + { + Argument.AssertNotNullOrEmpty(name, nameof(name)); + Argument.AssertNotNull(content, nameof(content)); + + using var scope = ClientDiagnostics.CreateScope("DeidentificationClient.CreateJob"); + scope.Start(); + try + { + using HttpMessage message = CreateCreateJobRequest(name, content, context); + return ProtocolOperationHelpers.ProcessMessage(_pipeline, message, ClientDiagnostics, "DeidentificationClient.CreateJob", OperationFinalStateVia.OriginalUri, context, waitUntil); + } + catch (Exception e) + { + scope.Failed(e); + throw; + } + } + + internal HttpMessage CreateGetJobRequest(string name, RequestContext context) + { + var message = _pipeline.CreateMessage(context, ResponseClassifier200); + var request = message.Request; + request.Method = RequestMethod.Get; + var uri = new RawRequestUriBuilder(); + uri.AppendRaw("https://", false); + uri.Reset(_endpoint); + uri.AppendPath("/jobs/", false); + uri.AppendPath(name, true); + uri.AppendQuery("api-version", _apiVersion, true); + request.Uri = uri; + request.Headers.Add("Accept", "application/json"); + return message; + } + + internal HttpMessage CreateCreateJobRequest(string name, RequestContent content, RequestContext context) + { + var message = _pipeline.CreateMessage(context, ResponseClassifier200201); + var request = message.Request; + request.Method = RequestMethod.Put; + var uri = new RawRequestUriBuilder(); + uri.AppendRaw("https://", false); + uri.Reset(_endpoint); + uri.AppendPath("/jobs/", false); + uri.AppendPath(name, true); + uri.AppendQuery("api-version", _apiVersion, true); + request.Uri = uri; + request.Headers.Add("Accept", "application/json"); + request.Headers.Add("Content-Type", "application/json"); + request.Content = content; + return message; + } + + internal HttpMessage CreateGetJobsRequest(int? maxpagesize, string continuationToken, RequestContext context) + { + var message = _pipeline.CreateMessage(context, ResponseClassifier200); + var request = message.Request; + request.Method = RequestMethod.Get; + var uri = new RawRequestUriBuilder(); + uri.AppendRaw("https://", false); + uri.Reset(_endpoint); + uri.AppendPath("/jobs", false); + uri.AppendQuery("api-version", _apiVersion, true); + if (maxpagesize != null) + { + uri.AppendQuery("maxpagesize", maxpagesize.Value, true); + } + if (continuationToken != null) + { + uri.AppendQuery("continuationToken", continuationToken, true); + } + request.Uri = uri; + request.Headers.Add("Accept", "application/json"); + return message; + } + + internal HttpMessage CreateGetJobDocumentsRequest(string name, int? maxpagesize, string continuationToken, RequestContext context) + { + var message = _pipeline.CreateMessage(context, ResponseClassifier200); + var request = message.Request; + request.Method = RequestMethod.Get; + var uri = new RawRequestUriBuilder(); + uri.AppendRaw("https://", false); + uri.Reset(_endpoint); + uri.AppendPath("/jobs/", false); + uri.AppendPath(name, true); + uri.AppendPath("/documents", false); + uri.AppendQuery("api-version", _apiVersion, true); + if (maxpagesize != null) + { + uri.AppendQuery("maxpagesize", maxpagesize.Value, true); + } + if (continuationToken != null) + { + uri.AppendQuery("continuationToken", continuationToken, true); + } + request.Uri = uri; + request.Headers.Add("Accept", "application/json"); + return message; + } + + internal HttpMessage CreateCancelJobRequest(string name, RequestContext context) + { + var message = _pipeline.CreateMessage(context, ResponseClassifier200); + var request = message.Request; + request.Method = RequestMethod.Post; + var uri = new RawRequestUriBuilder(); + uri.AppendRaw("https://", false); + uri.Reset(_endpoint); + uri.AppendPath("/jobs/", false); + uri.AppendPath(name, true); + uri.AppendPath(":cancel", false); + uri.AppendQuery("api-version", _apiVersion, true); + request.Uri = uri; + request.Headers.Add("Accept", "application/json"); + return message; + } + + internal HttpMessage CreateDeleteJobRequest(string name, RequestContext context) + { + var message = _pipeline.CreateMessage(context, ResponseClassifier204); + var request = message.Request; + request.Method = RequestMethod.Delete; + var uri = new RawRequestUriBuilder(); + uri.AppendRaw("https://", false); + uri.Reset(_endpoint); + uri.AppendPath("/jobs/", false); + uri.AppendPath(name, true); + uri.AppendQuery("api-version", _apiVersion, true); + request.Uri = uri; + request.Headers.Add("Accept", "application/json"); + return message; + } + + internal HttpMessage CreateDeidentifyRequest(RequestContent content, RequestContext context) + { + var message = _pipeline.CreateMessage(context, ResponseClassifier200); + var request = message.Request; + request.Method = RequestMethod.Post; + var uri = new RawRequestUriBuilder(); + uri.AppendRaw("https://", false); + uri.Reset(_endpoint); + uri.AppendPath("/deid", false); + uri.AppendQuery("api-version", _apiVersion, true); + request.Uri = uri; + request.Headers.Add("Accept", "application/json"); + request.Headers.Add("Content-Type", "application/json"); + request.Content = content; + return message; + } + + internal HttpMessage CreateGetJobsNextPageRequest(string nextLink, int? maxpagesize, string continuationToken, RequestContext context) + { + var message = _pipeline.CreateMessage(context, ResponseClassifier200); + var request = message.Request; + request.Method = RequestMethod.Get; + var uri = new RawRequestUriBuilder(); + uri.AppendRaw("https://", false); + uri.Reset(_endpoint); + uri.AppendRawNextLink(nextLink, false); + request.Uri = uri; + request.Headers.Add("Accept", "application/json"); + return message; + } + + internal HttpMessage CreateGetJobDocumentsNextPageRequest(string nextLink, string name, int? maxpagesize, string continuationToken, RequestContext context) + { + var message = _pipeline.CreateMessage(context, ResponseClassifier200); + var request = message.Request; + request.Method = RequestMethod.Get; + var uri = new RawRequestUriBuilder(); + uri.AppendRaw("https://", false); + uri.Reset(_endpoint); + uri.AppendRawNextLink(nextLink, false); + request.Uri = uri; + request.Headers.Add("Accept", "application/json"); + return message; + } + + private static RequestContext DefaultRequestContext = new RequestContext(); + internal static RequestContext FromCancellationToken(CancellationToken cancellationToken = default) + { + if (!cancellationToken.CanBeCanceled) + { + return DefaultRequestContext; + } + + return new RequestContext() { CancellationToken = cancellationToken }; + } + + private static ResponseClassifier _responseClassifier200; + private static ResponseClassifier ResponseClassifier200 => _responseClassifier200 ??= new StatusCodeClassifier(stackalloc ushort[] { 200 }); + private static ResponseClassifier _responseClassifier200201; + private static ResponseClassifier ResponseClassifier200201 => _responseClassifier200201 ??= new StatusCodeClassifier(stackalloc ushort[] { 200, 201 }); + private static ResponseClassifier _responseClassifier204; + private static ResponseClassifier ResponseClassifier204 => _responseClassifier204 ??= new StatusCodeClassifier(stackalloc ushort[] { 204 }); + } +} diff --git a/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/DeidentificationClientOptions.cs b/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/DeidentificationClientOptions.cs new file mode 100644 index 000000000000..175092a43a01 --- /dev/null +++ b/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/DeidentificationClientOptions.cs @@ -0,0 +1,37 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System; +using Azure.Core; + +namespace Azure.Health.Deidentification +{ + /// Client options for DeidentificationClient. + public partial class DeidentificationClientOptions : ClientOptions + { + private const ServiceVersion LatestVersion = ServiceVersion.V2024_07_12_Preview; + + /// The version of the service to use. + public enum ServiceVersion + { + /// Service version "2024-07-12-preview". + V2024_07_12_Preview = 1, + } + + internal string Version { get; } + + /// Initializes new instance of DeidentificationClientOptions. + public DeidentificationClientOptions(ServiceVersion version = LatestVersion) + { + Version = version switch + { + ServiceVersion.V2024_07_12_Preview => "2024-07-12-preview", + _ => throw new NotSupportedException() + }; + } + } +} diff --git a/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/DeidentificationContent.Serialization.cs b/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/DeidentificationContent.Serialization.cs new file mode 100644 index 000000000000..d618584adf6f --- /dev/null +++ b/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/DeidentificationContent.Serialization.cs @@ -0,0 +1,176 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System; +using System.ClientModel.Primitives; +using System.Collections.Generic; +using System.Text.Json; +using Azure.Core; + +namespace Azure.Health.Deidentification +{ + public partial class DeidentificationContent : IUtf8JsonSerializable, IJsonModel + { + void IUtf8JsonSerializable.Write(Utf8JsonWriter writer) => ((IJsonModel)this).Write(writer, ModelSerializationExtensions.WireOptions); + + void IJsonModel.Write(Utf8JsonWriter writer, ModelReaderWriterOptions options) + { + var format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + if (format != "J") + { + throw new FormatException($"The model {nameof(DeidentificationContent)} does not support writing '{format}' format."); + } + + writer.WriteStartObject(); + writer.WritePropertyName("inputText"u8); + writer.WriteStringValue(InputText); + if (Optional.IsDefined(Operation)) + { + writer.WritePropertyName("operation"u8); + writer.WriteStringValue(Operation.Value.ToString()); + } + if (Optional.IsDefined(DataType)) + { + writer.WritePropertyName("dataType"u8); + writer.WriteStringValue(DataType.Value.ToString()); + } + if (Optional.IsDefined(RedactionFormat)) + { + writer.WritePropertyName("redactionFormat"u8); + writer.WriteStringValue(RedactionFormat); + } + if (options.Format != "W" && _serializedAdditionalRawData != null) + { + foreach (var item in _serializedAdditionalRawData) + { + writer.WritePropertyName(item.Key); +#if NET6_0_OR_GREATER + writer.WriteRawValue(item.Value); +#else + using (JsonDocument document = JsonDocument.Parse(item.Value)) + { + JsonSerializer.Serialize(writer, document.RootElement); + } +#endif + } + } + writer.WriteEndObject(); + } + + DeidentificationContent IJsonModel.Create(ref Utf8JsonReader reader, ModelReaderWriterOptions options) + { + var format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + if (format != "J") + { + throw new FormatException($"The model {nameof(DeidentificationContent)} does not support reading '{format}' format."); + } + + using JsonDocument document = JsonDocument.ParseValue(ref reader); + return DeserializeDeidentificationContent(document.RootElement, options); + } + + internal static DeidentificationContent DeserializeDeidentificationContent(JsonElement element, ModelReaderWriterOptions options = null) + { + options ??= ModelSerializationExtensions.WireOptions; + + if (element.ValueKind == JsonValueKind.Null) + { + return null; + } + string inputText = default; + OperationType? operation = default; + DocumentDataType? dataType = default; + string redactionFormat = default; + IDictionary serializedAdditionalRawData = default; + Dictionary rawDataDictionary = new Dictionary(); + foreach (var property in element.EnumerateObject()) + { + if (property.NameEquals("inputText"u8)) + { + inputText = property.Value.GetString(); + continue; + } + if (property.NameEquals("operation"u8)) + { + if (property.Value.ValueKind == JsonValueKind.Null) + { + continue; + } + operation = new OperationType(property.Value.GetString()); + continue; + } + if (property.NameEquals("dataType"u8)) + { + if (property.Value.ValueKind == JsonValueKind.Null) + { + continue; + } + dataType = new DocumentDataType(property.Value.GetString()); + continue; + } + if (property.NameEquals("redactionFormat"u8)) + { + redactionFormat = property.Value.GetString(); + continue; + } + if (options.Format != "W") + { + rawDataDictionary.Add(property.Name, BinaryData.FromString(property.Value.GetRawText())); + } + } + serializedAdditionalRawData = rawDataDictionary; + return new DeidentificationContent(inputText, operation, dataType, redactionFormat, serializedAdditionalRawData); + } + + BinaryData IPersistableModel.Write(ModelReaderWriterOptions options) + { + var format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + + switch (format) + { + case "J": + return ModelReaderWriter.Write(this, options); + default: + throw new FormatException($"The model {nameof(DeidentificationContent)} does not support writing '{options.Format}' format."); + } + } + + DeidentificationContent IPersistableModel.Create(BinaryData data, ModelReaderWriterOptions options) + { + var format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + + switch (format) + { + case "J": + { + using JsonDocument document = JsonDocument.Parse(data); + return DeserializeDeidentificationContent(document.RootElement, options); + } + default: + throw new FormatException($"The model {nameof(DeidentificationContent)} does not support reading '{options.Format}' format."); + } + } + + string IPersistableModel.GetFormatFromOptions(ModelReaderWriterOptions options) => "J"; + + /// Deserializes the model from a raw response. + /// The response to deserialize the model from. + internal static DeidentificationContent FromResponse(Response response) + { + using var document = JsonDocument.Parse(response.Content); + return DeserializeDeidentificationContent(document.RootElement); + } + + /// Convert into a . + internal virtual RequestContent ToRequestContent() + { + var content = new Utf8JsonRequestContent(); + content.JsonWriter.WriteObjectValue(this, ModelSerializationExtensions.WireOptions); + return content; + } + } +} diff --git a/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/DeidentificationContent.cs b/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/DeidentificationContent.cs new file mode 100644 index 000000000000..64d542e67a4c --- /dev/null +++ b/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/DeidentificationContent.cs @@ -0,0 +1,87 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System; +using System.Collections.Generic; + +namespace Azure.Health.Deidentification +{ + /// Request body for de-identification operation. + public partial class DeidentificationContent + { + /// + /// Keeps track of any properties unknown to the library. + /// + /// To assign an object to the value of this property use . + /// + /// + /// To assign an already formatted json string to this property use . + /// + /// + /// Examples: + /// + /// + /// BinaryData.FromObjectAsJson("foo") + /// Creates a payload of "foo". + /// + /// + /// BinaryData.FromString("\"foo\"") + /// Creates a payload of "foo". + /// + /// + /// BinaryData.FromObjectAsJson(new { key = "value" }) + /// Creates a payload of { "key": "value" }. + /// + /// + /// BinaryData.FromString("{\"key\": \"value\"}") + /// Creates a payload of { "key": "value" }. + /// + /// + /// + /// + private IDictionary _serializedAdditionalRawData; + + /// Initializes a new instance of . + /// Input text to de-identify. + /// is null. + public DeidentificationContent(string inputText) + { + Argument.AssertNotNull(inputText, nameof(inputText)); + + InputText = inputText; + } + + /// Initializes a new instance of . + /// Input text to de-identify. + /// Operation to perform on the input. + /// Data type of the input. + /// Format of the redacted output. Only valid when OperationType is "Redact". + /// Keeps track of any properties unknown to the library. + internal DeidentificationContent(string inputText, OperationType? operation, DocumentDataType? dataType, string redactionFormat, IDictionary serializedAdditionalRawData) + { + InputText = inputText; + Operation = operation; + DataType = dataType; + RedactionFormat = redactionFormat; + _serializedAdditionalRawData = serializedAdditionalRawData; + } + + /// Initializes a new instance of for deserialization. + internal DeidentificationContent() + { + } + + /// Input text to de-identify. + public string InputText { get; } + /// Operation to perform on the input. + public OperationType? Operation { get; set; } + /// Data type of the input. + public DocumentDataType? DataType { get; set; } + /// Format of the redacted output. Only valid when OperationType is "Redact". + public string RedactionFormat { get; set; } + } +} diff --git a/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/DeidentificationJob.Serialization.cs b/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/DeidentificationJob.Serialization.cs new file mode 100644 index 000000000000..0d65ae3d9116 --- /dev/null +++ b/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/DeidentificationJob.Serialization.cs @@ -0,0 +1,286 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System; +using System.ClientModel.Primitives; +using System.Collections.Generic; +using System.Text.Json; +using Azure.Core; + +namespace Azure.Health.Deidentification +{ + public partial class DeidentificationJob : IUtf8JsonSerializable, IJsonModel + { + void IUtf8JsonSerializable.Write(Utf8JsonWriter writer) => ((IJsonModel)this).Write(writer, ModelSerializationExtensions.WireOptions); + + void IJsonModel.Write(Utf8JsonWriter writer, ModelReaderWriterOptions options) + { + var format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + if (format != "J") + { + throw new FormatException($"The model {nameof(DeidentificationJob)} does not support writing '{format}' format."); + } + + writer.WriteStartObject(); + if (options.Format != "W") + { + writer.WritePropertyName("name"u8); + writer.WriteStringValue(Name); + } + writer.WritePropertyName("sourceLocation"u8); + writer.WriteObjectValue(SourceLocation, options); + writer.WritePropertyName("targetLocation"u8); + writer.WriteObjectValue(TargetLocation, options); + if (Optional.IsDefined(Operation)) + { + writer.WritePropertyName("operation"u8); + writer.WriteStringValue(Operation.Value.ToString()); + } + if (Optional.IsDefined(DataType)) + { + writer.WritePropertyName("dataType"u8); + writer.WriteStringValue(DataType.Value.ToString()); + } + if (Optional.IsDefined(RedactionFormat)) + { + writer.WritePropertyName("redactionFormat"u8); + writer.WriteStringValue(RedactionFormat); + } + if (options.Format != "W") + { + writer.WritePropertyName("status"u8); + writer.WriteStringValue(Status.ToString()); + } + if (options.Format != "W" && Optional.IsDefined(Error)) + { + writer.WritePropertyName("error"u8); + JsonSerializer.Serialize(writer, Error); + } + if (options.Format != "W") + { + writer.WritePropertyName("lastUpdatedAt"u8); + writer.WriteStringValue(LastUpdatedAt, "O"); + } + if (options.Format != "W") + { + writer.WritePropertyName("createdAt"u8); + writer.WriteStringValue(CreatedAt, "O"); + } + if (options.Format != "W" && Optional.IsDefined(StartedAt)) + { + writer.WritePropertyName("startedAt"u8); + writer.WriteStringValue(StartedAt.Value, "O"); + } + if (options.Format != "W" && Optional.IsDefined(Summary)) + { + writer.WritePropertyName("summary"u8); + writer.WriteObjectValue(Summary, options); + } + if (options.Format != "W" && _serializedAdditionalRawData != null) + { + foreach (var item in _serializedAdditionalRawData) + { + writer.WritePropertyName(item.Key); +#if NET6_0_OR_GREATER + writer.WriteRawValue(item.Value); +#else + using (JsonDocument document = JsonDocument.Parse(item.Value)) + { + JsonSerializer.Serialize(writer, document.RootElement); + } +#endif + } + } + writer.WriteEndObject(); + } + + DeidentificationJob IJsonModel.Create(ref Utf8JsonReader reader, ModelReaderWriterOptions options) + { + var format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + if (format != "J") + { + throw new FormatException($"The model {nameof(DeidentificationJob)} does not support reading '{format}' format."); + } + + using JsonDocument document = JsonDocument.ParseValue(ref reader); + return DeserializeDeidentificationJob(document.RootElement, options); + } + + internal static DeidentificationJob DeserializeDeidentificationJob(JsonElement element, ModelReaderWriterOptions options = null) + { + options ??= ModelSerializationExtensions.WireOptions; + + if (element.ValueKind == JsonValueKind.Null) + { + return null; + } + string name = default; + SourceStorageLocation sourceLocation = default; + TargetStorageLocation targetLocation = default; + OperationType? operation = default; + DocumentDataType? dataType = default; + string redactionFormat = default; + JobStatus status = default; + ResponseError error = default; + DateTimeOffset lastUpdatedAt = default; + DateTimeOffset createdAt = default; + DateTimeOffset? startedAt = default; + JobSummary summary = default; + IDictionary serializedAdditionalRawData = default; + Dictionary rawDataDictionary = new Dictionary(); + foreach (var property in element.EnumerateObject()) + { + if (property.NameEquals("name"u8)) + { + name = property.Value.GetString(); + continue; + } + if (property.NameEquals("sourceLocation"u8)) + { + sourceLocation = SourceStorageLocation.DeserializeSourceStorageLocation(property.Value, options); + continue; + } + if (property.NameEquals("targetLocation"u8)) + { + targetLocation = TargetStorageLocation.DeserializeTargetStorageLocation(property.Value, options); + continue; + } + if (property.NameEquals("operation"u8)) + { + if (property.Value.ValueKind == JsonValueKind.Null) + { + continue; + } + operation = new OperationType(property.Value.GetString()); + continue; + } + if (property.NameEquals("dataType"u8)) + { + if (property.Value.ValueKind == JsonValueKind.Null) + { + continue; + } + dataType = new DocumentDataType(property.Value.GetString()); + continue; + } + if (property.NameEquals("redactionFormat"u8)) + { + redactionFormat = property.Value.GetString(); + continue; + } + if (property.NameEquals("status"u8)) + { + status = new JobStatus(property.Value.GetString()); + continue; + } + if (property.NameEquals("error"u8)) + { + if (property.Value.ValueKind == JsonValueKind.Null) + { + continue; + } + error = JsonSerializer.Deserialize(property.Value.GetRawText()); + continue; + } + if (property.NameEquals("lastUpdatedAt"u8)) + { + lastUpdatedAt = property.Value.GetDateTimeOffset("O"); + continue; + } + if (property.NameEquals("createdAt"u8)) + { + createdAt = property.Value.GetDateTimeOffset("O"); + continue; + } + if (property.NameEquals("startedAt"u8)) + { + if (property.Value.ValueKind == JsonValueKind.Null) + { + continue; + } + startedAt = property.Value.GetDateTimeOffset("O"); + continue; + } + if (property.NameEquals("summary"u8)) + { + if (property.Value.ValueKind == JsonValueKind.Null) + { + continue; + } + summary = JobSummary.DeserializeJobSummary(property.Value, options); + continue; + } + if (options.Format != "W") + { + rawDataDictionary.Add(property.Name, BinaryData.FromString(property.Value.GetRawText())); + } + } + serializedAdditionalRawData = rawDataDictionary; + return new DeidentificationJob( + name, + sourceLocation, + targetLocation, + operation, + dataType, + redactionFormat, + status, + error, + lastUpdatedAt, + createdAt, + startedAt, + summary, + serializedAdditionalRawData); + } + + BinaryData IPersistableModel.Write(ModelReaderWriterOptions options) + { + var format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + + switch (format) + { + case "J": + return ModelReaderWriter.Write(this, options); + default: + throw new FormatException($"The model {nameof(DeidentificationJob)} does not support writing '{options.Format}' format."); + } + } + + DeidentificationJob IPersistableModel.Create(BinaryData data, ModelReaderWriterOptions options) + { + var format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + + switch (format) + { + case "J": + { + using JsonDocument document = JsonDocument.Parse(data); + return DeserializeDeidentificationJob(document.RootElement, options); + } + default: + throw new FormatException($"The model {nameof(DeidentificationJob)} does not support reading '{options.Format}' format."); + } + } + + string IPersistableModel.GetFormatFromOptions(ModelReaderWriterOptions options) => "J"; + + /// Deserializes the model from a raw response. + /// The response to deserialize the model from. + internal static DeidentificationJob FromResponse(Response response) + { + using var document = JsonDocument.Parse(response.Content); + return DeserializeDeidentificationJob(document.RootElement); + } + + /// Convert into a . + internal virtual RequestContent ToRequestContent() + { + var content = new Utf8JsonRequestContent(); + content.JsonWriter.WriteObjectValue(this, ModelSerializationExtensions.WireOptions); + return content; + } + } +} diff --git a/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/DeidentificationJob.cs b/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/DeidentificationJob.cs new file mode 100644 index 000000000000..14a040d4411e --- /dev/null +++ b/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/DeidentificationJob.cs @@ -0,0 +1,134 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System; +using System.Collections.Generic; + +namespace Azure.Health.Deidentification +{ + /// A job containing a batch of documents to de-identify. + public partial class DeidentificationJob + { + /// + /// Keeps track of any properties unknown to the library. + /// + /// To assign an object to the value of this property use . + /// + /// + /// To assign an already formatted json string to this property use . + /// + /// + /// Examples: + /// + /// + /// BinaryData.FromObjectAsJson("foo") + /// Creates a payload of "foo". + /// + /// + /// BinaryData.FromString("\"foo\"") + /// Creates a payload of "foo". + /// + /// + /// BinaryData.FromObjectAsJson(new { key = "value" }) + /// Creates a payload of { "key": "value" }. + /// + /// + /// BinaryData.FromString("{\"key\": \"value\"}") + /// Creates a payload of { "key": "value" }. + /// + /// + /// + /// + private IDictionary _serializedAdditionalRawData; + + /// Initializes a new instance of . + /// Storage location to perform the operation on. + /// Target location to store output of operation. + /// or is null. + public DeidentificationJob(SourceStorageLocation sourceLocation, TargetStorageLocation targetLocation) + { + Argument.AssertNotNull(sourceLocation, nameof(sourceLocation)); + Argument.AssertNotNull(targetLocation, nameof(targetLocation)); + + SourceLocation = sourceLocation; + TargetLocation = targetLocation; + } + + /// Initializes a new instance of . + /// The name of a job. + /// Storage location to perform the operation on. + /// Target location to store output of operation. + /// Operation to perform on the input documents. + /// Data type of the input documents. + /// Format of the redacted output. Only valid when Operation is Redact. + /// Current status of a job. + /// Error when job fails in it's entirety. + /// + /// Date and time when the job was completed. + /// + /// If the job is canceled, this is the time when the job was canceled. + /// + /// If the job failed, this is the time when the job failed. + /// + /// Date and time when the job was created. + /// Date and time when the job was started. + /// Summary of a job. Exists only when the job is completed. + /// Keeps track of any properties unknown to the library. + internal DeidentificationJob(string name, SourceStorageLocation sourceLocation, TargetStorageLocation targetLocation, OperationType? operation, DocumentDataType? dataType, string redactionFormat, JobStatus status, ResponseError error, DateTimeOffset lastUpdatedAt, DateTimeOffset createdAt, DateTimeOffset? startedAt, JobSummary summary, IDictionary serializedAdditionalRawData) + { + Name = name; + SourceLocation = sourceLocation; + TargetLocation = targetLocation; + Operation = operation; + DataType = dataType; + RedactionFormat = redactionFormat; + Status = status; + Error = error; + LastUpdatedAt = lastUpdatedAt; + CreatedAt = createdAt; + StartedAt = startedAt; + Summary = summary; + _serializedAdditionalRawData = serializedAdditionalRawData; + } + + /// Initializes a new instance of for deserialization. + internal DeidentificationJob() + { + } + + /// The name of a job. + public string Name { get; } + /// Storage location to perform the operation on. + public SourceStorageLocation SourceLocation { get; set; } + /// Target location to store output of operation. + public TargetStorageLocation TargetLocation { get; set; } + /// Operation to perform on the input documents. + public OperationType? Operation { get; set; } + /// Data type of the input documents. + public DocumentDataType? DataType { get; set; } + /// Format of the redacted output. Only valid when Operation is Redact. + public string RedactionFormat { get; set; } + /// Current status of a job. + public JobStatus Status { get; } + /// Error when job fails in it's entirety. + public ResponseError Error { get; } + /// + /// Date and time when the job was completed. + /// + /// If the job is canceled, this is the time when the job was canceled. + /// + /// If the job failed, this is the time when the job failed. + /// + public DateTimeOffset LastUpdatedAt { get; } + /// Date and time when the job was created. + public DateTimeOffset CreatedAt { get; } + /// Date and time when the job was started. + public DateTimeOffset? StartedAt { get; } + /// Summary of a job. Exists only when the job is completed. + public JobSummary Summary { get; } + } +} diff --git a/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/DeidentificationResult.Serialization.cs b/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/DeidentificationResult.Serialization.cs new file mode 100644 index 000000000000..baf75cf44aac --- /dev/null +++ b/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/DeidentificationResult.Serialization.cs @@ -0,0 +1,153 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System; +using System.ClientModel.Primitives; +using System.Collections.Generic; +using System.Text.Json; +using Azure.Core; + +namespace Azure.Health.Deidentification +{ + public partial class DeidentificationResult : IUtf8JsonSerializable, IJsonModel + { + void IUtf8JsonSerializable.Write(Utf8JsonWriter writer) => ((IJsonModel)this).Write(writer, ModelSerializationExtensions.WireOptions); + + void IJsonModel.Write(Utf8JsonWriter writer, ModelReaderWriterOptions options) + { + var format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + if (format != "J") + { + throw new FormatException($"The model {nameof(DeidentificationResult)} does not support writing '{format}' format."); + } + + writer.WriteStartObject(); + if (Optional.IsDefined(OutputText)) + { + writer.WritePropertyName("outputText"u8); + writer.WriteStringValue(OutputText); + } + if (Optional.IsDefined(TaggerResult)) + { + writer.WritePropertyName("taggerResult"u8); + writer.WriteObjectValue(TaggerResult, options); + } + if (options.Format != "W" && _serializedAdditionalRawData != null) + { + foreach (var item in _serializedAdditionalRawData) + { + writer.WritePropertyName(item.Key); +#if NET6_0_OR_GREATER + writer.WriteRawValue(item.Value); +#else + using (JsonDocument document = JsonDocument.Parse(item.Value)) + { + JsonSerializer.Serialize(writer, document.RootElement); + } +#endif + } + } + writer.WriteEndObject(); + } + + DeidentificationResult IJsonModel.Create(ref Utf8JsonReader reader, ModelReaderWriterOptions options) + { + var format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + if (format != "J") + { + throw new FormatException($"The model {nameof(DeidentificationResult)} does not support reading '{format}' format."); + } + + using JsonDocument document = JsonDocument.ParseValue(ref reader); + return DeserializeDeidentificationResult(document.RootElement, options); + } + + internal static DeidentificationResult DeserializeDeidentificationResult(JsonElement element, ModelReaderWriterOptions options = null) + { + options ??= ModelSerializationExtensions.WireOptions; + + if (element.ValueKind == JsonValueKind.Null) + { + return null; + } + string outputText = default; + PhiTaggerResult taggerResult = default; + IDictionary serializedAdditionalRawData = default; + Dictionary rawDataDictionary = new Dictionary(); + foreach (var property in element.EnumerateObject()) + { + if (property.NameEquals("outputText"u8)) + { + outputText = property.Value.GetString(); + continue; + } + if (property.NameEquals("taggerResult"u8)) + { + if (property.Value.ValueKind == JsonValueKind.Null) + { + continue; + } + taggerResult = PhiTaggerResult.DeserializePhiTaggerResult(property.Value, options); + continue; + } + if (options.Format != "W") + { + rawDataDictionary.Add(property.Name, BinaryData.FromString(property.Value.GetRawText())); + } + } + serializedAdditionalRawData = rawDataDictionary; + return new DeidentificationResult(outputText, taggerResult, serializedAdditionalRawData); + } + + BinaryData IPersistableModel.Write(ModelReaderWriterOptions options) + { + var format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + + switch (format) + { + case "J": + return ModelReaderWriter.Write(this, options); + default: + throw new FormatException($"The model {nameof(DeidentificationResult)} does not support writing '{options.Format}' format."); + } + } + + DeidentificationResult IPersistableModel.Create(BinaryData data, ModelReaderWriterOptions options) + { + var format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + + switch (format) + { + case "J": + { + using JsonDocument document = JsonDocument.Parse(data); + return DeserializeDeidentificationResult(document.RootElement, options); + } + default: + throw new FormatException($"The model {nameof(DeidentificationResult)} does not support reading '{options.Format}' format."); + } + } + + string IPersistableModel.GetFormatFromOptions(ModelReaderWriterOptions options) => "J"; + + /// Deserializes the model from a raw response. + /// The response to deserialize the model from. + internal static DeidentificationResult FromResponse(Response response) + { + using var document = JsonDocument.Parse(response.Content); + return DeserializeDeidentificationResult(document.RootElement); + } + + /// Convert into a . + internal virtual RequestContent ToRequestContent() + { + var content = new Utf8JsonRequestContent(); + content.JsonWriter.WriteObjectValue(this, ModelSerializationExtensions.WireOptions); + return content; + } + } +} diff --git a/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/DeidentificationResult.cs b/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/DeidentificationResult.cs new file mode 100644 index 000000000000..d3c32df97a0e --- /dev/null +++ b/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/DeidentificationResult.cs @@ -0,0 +1,69 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System; +using System.Collections.Generic; + +namespace Azure.Health.Deidentification +{ + /// Response body for de-identification operation. + public partial class DeidentificationResult + { + /// + /// Keeps track of any properties unknown to the library. + /// + /// To assign an object to the value of this property use . + /// + /// + /// To assign an already formatted json string to this property use . + /// + /// + /// Examples: + /// + /// + /// BinaryData.FromObjectAsJson("foo") + /// Creates a payload of "foo". + /// + /// + /// BinaryData.FromString("\"foo\"") + /// Creates a payload of "foo". + /// + /// + /// BinaryData.FromObjectAsJson(new { key = "value" }) + /// Creates a payload of { "key": "value" }. + /// + /// + /// BinaryData.FromString("{\"key\": \"value\"}") + /// Creates a payload of { "key": "value" }. + /// + /// + /// + /// + private IDictionary _serializedAdditionalRawData; + + /// Initializes a new instance of . + internal DeidentificationResult() + { + } + + /// Initializes a new instance of . + /// Output text after de-identification. Not available for "Tag" operation. + /// Result of the "Tag" operation. Only available for "Tag" Operation. + /// Keeps track of any properties unknown to the library. + internal DeidentificationResult(string outputText, PhiTaggerResult taggerResult, IDictionary serializedAdditionalRawData) + { + OutputText = outputText; + TaggerResult = taggerResult; + _serializedAdditionalRawData = serializedAdditionalRawData; + } + + /// Output text after de-identification. Not available for "Tag" operation. + public string OutputText { get; } + /// Result of the "Tag" operation. Only available for "Tag" Operation. + public PhiTaggerResult TaggerResult { get; } + } +} diff --git a/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/Docs/DeidentificationClient.xml b/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/Docs/DeidentificationClient.xml new file mode 100644 index 000000000000..5ee3cc2323bd --- /dev/null +++ b/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/Docs/DeidentificationClient.xml @@ -0,0 +1,1003 @@ + + + + + +This sample shows how to call GetJobAsync. +"); +TokenCredential credential = new DefaultAzureCredential(); +DeidentificationClient client = new DeidentificationClient(endpoint, credential); + +Response response = await client.GetJobAsync(""); +]]> +This sample shows how to call GetJobAsync with all parameters. +"); +TokenCredential credential = new DefaultAzureCredential(); +DeidentificationClient client = new DeidentificationClient(endpoint, credential); + +Response response = await client.GetJobAsync(""); +]]> + + + +This sample shows how to call GetJob. +"); +TokenCredential credential = new DefaultAzureCredential(); +DeidentificationClient client = new DeidentificationClient(endpoint, credential); + +Response response = client.GetJob(""); +]]> +This sample shows how to call GetJob with all parameters. +"); +TokenCredential credential = new DefaultAzureCredential(); +DeidentificationClient client = new DeidentificationClient(endpoint, credential); + +Response response = client.GetJob(""); +]]> + + + +This sample shows how to call GetJobAsync and parse the result. +"); +TokenCredential credential = new DefaultAzureCredential(); +DeidentificationClient client = new DeidentificationClient(endpoint, credential); + +Response response = await client.GetJobAsync("", null); + +JsonElement result = JsonDocument.Parse(response.ContentStream).RootElement; +Console.WriteLine(result.GetProperty("name").ToString()); +Console.WriteLine(result.GetProperty("sourceLocation").GetProperty("location").ToString()); +Console.WriteLine(result.GetProperty("sourceLocation").GetProperty("prefix").ToString()); +Console.WriteLine(result.GetProperty("targetLocation").GetProperty("location").ToString()); +Console.WriteLine(result.GetProperty("targetLocation").GetProperty("prefix").ToString()); +Console.WriteLine(result.GetProperty("status").ToString()); +Console.WriteLine(result.GetProperty("lastUpdatedAt").ToString()); +Console.WriteLine(result.GetProperty("createdAt").ToString()); +]]> +This sample shows how to call GetJobAsync with all parameters and parse the result. +"); +TokenCredential credential = new DefaultAzureCredential(); +DeidentificationClient client = new DeidentificationClient(endpoint, credential); + +Response response = await client.GetJobAsync("", null); + +JsonElement result = JsonDocument.Parse(response.ContentStream).RootElement; +Console.WriteLine(result.GetProperty("name").ToString()); +Console.WriteLine(result.GetProperty("sourceLocation").GetProperty("location").ToString()); +Console.WriteLine(result.GetProperty("sourceLocation").GetProperty("prefix").ToString()); +Console.WriteLine(result.GetProperty("sourceLocation").GetProperty("extensions")[0].ToString()); +Console.WriteLine(result.GetProperty("targetLocation").GetProperty("location").ToString()); +Console.WriteLine(result.GetProperty("targetLocation").GetProperty("prefix").ToString()); +Console.WriteLine(result.GetProperty("operation").ToString()); +Console.WriteLine(result.GetProperty("dataType").ToString()); +Console.WriteLine(result.GetProperty("redactionFormat").ToString()); +Console.WriteLine(result.GetProperty("status").ToString()); +Console.WriteLine(result.GetProperty("error").GetProperty("code").ToString()); +Console.WriteLine(result.GetProperty("error").GetProperty("message").ToString()); +Console.WriteLine(result.GetProperty("error").GetProperty("target").ToString()); +Console.WriteLine(result.GetProperty("error").GetProperty("innererror").GetProperty("code").ToString()); +Console.WriteLine(result.GetProperty("lastUpdatedAt").ToString()); +Console.WriteLine(result.GetProperty("createdAt").ToString()); +Console.WriteLine(result.GetProperty("startedAt").ToString()); +Console.WriteLine(result.GetProperty("summary").GetProperty("successful").ToString()); +Console.WriteLine(result.GetProperty("summary").GetProperty("failed").ToString()); +Console.WriteLine(result.GetProperty("summary").GetProperty("canceled").ToString()); +Console.WriteLine(result.GetProperty("summary").GetProperty("total").ToString()); +Console.WriteLine(result.GetProperty("summary").GetProperty("bytesProcessed").ToString()); +]]> + + + +This sample shows how to call GetJob and parse the result. +"); +TokenCredential credential = new DefaultAzureCredential(); +DeidentificationClient client = new DeidentificationClient(endpoint, credential); + +Response response = client.GetJob("", null); + +JsonElement result = JsonDocument.Parse(response.ContentStream).RootElement; +Console.WriteLine(result.GetProperty("name").ToString()); +Console.WriteLine(result.GetProperty("sourceLocation").GetProperty("location").ToString()); +Console.WriteLine(result.GetProperty("sourceLocation").GetProperty("prefix").ToString()); +Console.WriteLine(result.GetProperty("targetLocation").GetProperty("location").ToString()); +Console.WriteLine(result.GetProperty("targetLocation").GetProperty("prefix").ToString()); +Console.WriteLine(result.GetProperty("status").ToString()); +Console.WriteLine(result.GetProperty("lastUpdatedAt").ToString()); +Console.WriteLine(result.GetProperty("createdAt").ToString()); +]]> +This sample shows how to call GetJob with all parameters and parse the result. +"); +TokenCredential credential = new DefaultAzureCredential(); +DeidentificationClient client = new DeidentificationClient(endpoint, credential); + +Response response = client.GetJob("", null); + +JsonElement result = JsonDocument.Parse(response.ContentStream).RootElement; +Console.WriteLine(result.GetProperty("name").ToString()); +Console.WriteLine(result.GetProperty("sourceLocation").GetProperty("location").ToString()); +Console.WriteLine(result.GetProperty("sourceLocation").GetProperty("prefix").ToString()); +Console.WriteLine(result.GetProperty("sourceLocation").GetProperty("extensions")[0].ToString()); +Console.WriteLine(result.GetProperty("targetLocation").GetProperty("location").ToString()); +Console.WriteLine(result.GetProperty("targetLocation").GetProperty("prefix").ToString()); +Console.WriteLine(result.GetProperty("operation").ToString()); +Console.WriteLine(result.GetProperty("dataType").ToString()); +Console.WriteLine(result.GetProperty("redactionFormat").ToString()); +Console.WriteLine(result.GetProperty("status").ToString()); +Console.WriteLine(result.GetProperty("error").GetProperty("code").ToString()); +Console.WriteLine(result.GetProperty("error").GetProperty("message").ToString()); +Console.WriteLine(result.GetProperty("error").GetProperty("target").ToString()); +Console.WriteLine(result.GetProperty("error").GetProperty("innererror").GetProperty("code").ToString()); +Console.WriteLine(result.GetProperty("lastUpdatedAt").ToString()); +Console.WriteLine(result.GetProperty("createdAt").ToString()); +Console.WriteLine(result.GetProperty("startedAt").ToString()); +Console.WriteLine(result.GetProperty("summary").GetProperty("successful").ToString()); +Console.WriteLine(result.GetProperty("summary").GetProperty("failed").ToString()); +Console.WriteLine(result.GetProperty("summary").GetProperty("canceled").ToString()); +Console.WriteLine(result.GetProperty("summary").GetProperty("total").ToString()); +Console.WriteLine(result.GetProperty("summary").GetProperty("bytesProcessed").ToString()); +]]> + + + +This sample shows how to call CancelJobAsync. +"); +TokenCredential credential = new DefaultAzureCredential(); +DeidentificationClient client = new DeidentificationClient(endpoint, credential); + +Response response = await client.CancelJobAsync(""); +]]> +This sample shows how to call CancelJobAsync with all parameters. +"); +TokenCredential credential = new DefaultAzureCredential(); +DeidentificationClient client = new DeidentificationClient(endpoint, credential); + +Response response = await client.CancelJobAsync(""); +]]> + + + +This sample shows how to call CancelJob. +"); +TokenCredential credential = new DefaultAzureCredential(); +DeidentificationClient client = new DeidentificationClient(endpoint, credential); + +Response response = client.CancelJob(""); +]]> +This sample shows how to call CancelJob with all parameters. +"); +TokenCredential credential = new DefaultAzureCredential(); +DeidentificationClient client = new DeidentificationClient(endpoint, credential); + +Response response = client.CancelJob(""); +]]> + + + +This sample shows how to call CancelJobAsync and parse the result. +"); +TokenCredential credential = new DefaultAzureCredential(); +DeidentificationClient client = new DeidentificationClient(endpoint, credential); + +Response response = await client.CancelJobAsync("", null); + +JsonElement result = JsonDocument.Parse(response.ContentStream).RootElement; +Console.WriteLine(result.GetProperty("name").ToString()); +Console.WriteLine(result.GetProperty("sourceLocation").GetProperty("location").ToString()); +Console.WriteLine(result.GetProperty("sourceLocation").GetProperty("prefix").ToString()); +Console.WriteLine(result.GetProperty("targetLocation").GetProperty("location").ToString()); +Console.WriteLine(result.GetProperty("targetLocation").GetProperty("prefix").ToString()); +Console.WriteLine(result.GetProperty("status").ToString()); +Console.WriteLine(result.GetProperty("lastUpdatedAt").ToString()); +Console.WriteLine(result.GetProperty("createdAt").ToString()); +]]> +This sample shows how to call CancelJobAsync with all parameters and parse the result. +"); +TokenCredential credential = new DefaultAzureCredential(); +DeidentificationClient client = new DeidentificationClient(endpoint, credential); + +Response response = await client.CancelJobAsync("", null); + +JsonElement result = JsonDocument.Parse(response.ContentStream).RootElement; +Console.WriteLine(result.GetProperty("name").ToString()); +Console.WriteLine(result.GetProperty("sourceLocation").GetProperty("location").ToString()); +Console.WriteLine(result.GetProperty("sourceLocation").GetProperty("prefix").ToString()); +Console.WriteLine(result.GetProperty("sourceLocation").GetProperty("extensions")[0].ToString()); +Console.WriteLine(result.GetProperty("targetLocation").GetProperty("location").ToString()); +Console.WriteLine(result.GetProperty("targetLocation").GetProperty("prefix").ToString()); +Console.WriteLine(result.GetProperty("operation").ToString()); +Console.WriteLine(result.GetProperty("dataType").ToString()); +Console.WriteLine(result.GetProperty("redactionFormat").ToString()); +Console.WriteLine(result.GetProperty("status").ToString()); +Console.WriteLine(result.GetProperty("error").GetProperty("code").ToString()); +Console.WriteLine(result.GetProperty("error").GetProperty("message").ToString()); +Console.WriteLine(result.GetProperty("error").GetProperty("target").ToString()); +Console.WriteLine(result.GetProperty("error").GetProperty("innererror").GetProperty("code").ToString()); +Console.WriteLine(result.GetProperty("lastUpdatedAt").ToString()); +Console.WriteLine(result.GetProperty("createdAt").ToString()); +Console.WriteLine(result.GetProperty("startedAt").ToString()); +Console.WriteLine(result.GetProperty("summary").GetProperty("successful").ToString()); +Console.WriteLine(result.GetProperty("summary").GetProperty("failed").ToString()); +Console.WriteLine(result.GetProperty("summary").GetProperty("canceled").ToString()); +Console.WriteLine(result.GetProperty("summary").GetProperty("total").ToString()); +Console.WriteLine(result.GetProperty("summary").GetProperty("bytesProcessed").ToString()); +]]> + + + +This sample shows how to call CancelJob and parse the result. +"); +TokenCredential credential = new DefaultAzureCredential(); +DeidentificationClient client = new DeidentificationClient(endpoint, credential); + +Response response = client.CancelJob("", null); + +JsonElement result = JsonDocument.Parse(response.ContentStream).RootElement; +Console.WriteLine(result.GetProperty("name").ToString()); +Console.WriteLine(result.GetProperty("sourceLocation").GetProperty("location").ToString()); +Console.WriteLine(result.GetProperty("sourceLocation").GetProperty("prefix").ToString()); +Console.WriteLine(result.GetProperty("targetLocation").GetProperty("location").ToString()); +Console.WriteLine(result.GetProperty("targetLocation").GetProperty("prefix").ToString()); +Console.WriteLine(result.GetProperty("status").ToString()); +Console.WriteLine(result.GetProperty("lastUpdatedAt").ToString()); +Console.WriteLine(result.GetProperty("createdAt").ToString()); +]]> +This sample shows how to call CancelJob with all parameters and parse the result. +"); +TokenCredential credential = new DefaultAzureCredential(); +DeidentificationClient client = new DeidentificationClient(endpoint, credential); + +Response response = client.CancelJob("", null); + +JsonElement result = JsonDocument.Parse(response.ContentStream).RootElement; +Console.WriteLine(result.GetProperty("name").ToString()); +Console.WriteLine(result.GetProperty("sourceLocation").GetProperty("location").ToString()); +Console.WriteLine(result.GetProperty("sourceLocation").GetProperty("prefix").ToString()); +Console.WriteLine(result.GetProperty("sourceLocation").GetProperty("extensions")[0].ToString()); +Console.WriteLine(result.GetProperty("targetLocation").GetProperty("location").ToString()); +Console.WriteLine(result.GetProperty("targetLocation").GetProperty("prefix").ToString()); +Console.WriteLine(result.GetProperty("operation").ToString()); +Console.WriteLine(result.GetProperty("dataType").ToString()); +Console.WriteLine(result.GetProperty("redactionFormat").ToString()); +Console.WriteLine(result.GetProperty("status").ToString()); +Console.WriteLine(result.GetProperty("error").GetProperty("code").ToString()); +Console.WriteLine(result.GetProperty("error").GetProperty("message").ToString()); +Console.WriteLine(result.GetProperty("error").GetProperty("target").ToString()); +Console.WriteLine(result.GetProperty("error").GetProperty("innererror").GetProperty("code").ToString()); +Console.WriteLine(result.GetProperty("lastUpdatedAt").ToString()); +Console.WriteLine(result.GetProperty("createdAt").ToString()); +Console.WriteLine(result.GetProperty("startedAt").ToString()); +Console.WriteLine(result.GetProperty("summary").GetProperty("successful").ToString()); +Console.WriteLine(result.GetProperty("summary").GetProperty("failed").ToString()); +Console.WriteLine(result.GetProperty("summary").GetProperty("canceled").ToString()); +Console.WriteLine(result.GetProperty("summary").GetProperty("total").ToString()); +Console.WriteLine(result.GetProperty("summary").GetProperty("bytesProcessed").ToString()); +]]> + + + +This sample shows how to call DeleteJobAsync. +"); +TokenCredential credential = new DefaultAzureCredential(); +DeidentificationClient client = new DeidentificationClient(endpoint, credential); + +Response response = await client.DeleteJobAsync(""); + +Console.WriteLine(response.Status); +]]> +This sample shows how to call DeleteJobAsync with all parameters. +"); +TokenCredential credential = new DefaultAzureCredential(); +DeidentificationClient client = new DeidentificationClient(endpoint, credential); + +Response response = await client.DeleteJobAsync(""); + +Console.WriteLine(response.Status); +]]> + + + +This sample shows how to call DeleteJob. +"); +TokenCredential credential = new DefaultAzureCredential(); +DeidentificationClient client = new DeidentificationClient(endpoint, credential); + +Response response = client.DeleteJob(""); + +Console.WriteLine(response.Status); +]]> +This sample shows how to call DeleteJob with all parameters. +"); +TokenCredential credential = new DefaultAzureCredential(); +DeidentificationClient client = new DeidentificationClient(endpoint, credential); + +Response response = client.DeleteJob(""); + +Console.WriteLine(response.Status); +]]> + + + +This sample shows how to call DeidentifyAsync. +"); +TokenCredential credential = new DefaultAzureCredential(); +DeidentificationClient client = new DeidentificationClient(endpoint, credential); + +DeidentificationContent body = new DeidentificationContent(""); +Response response = await client.DeidentifyAsync(body); +]]> +This sample shows how to call DeidentifyAsync with all parameters. +"); +TokenCredential credential = new DefaultAzureCredential(); +DeidentificationClient client = new DeidentificationClient(endpoint, credential); + +DeidentificationContent body = new DeidentificationContent("") +{ + Operation = OperationType.Redact, + DataType = DocumentDataType.Plaintext, + RedactionFormat = "", +}; +Response response = await client.DeidentifyAsync(body); +]]> + + + +This sample shows how to call Deidentify. +"); +TokenCredential credential = new DefaultAzureCredential(); +DeidentificationClient client = new DeidentificationClient(endpoint, credential); + +DeidentificationContent body = new DeidentificationContent(""); +Response response = client.Deidentify(body); +]]> +This sample shows how to call Deidentify with all parameters. +"); +TokenCredential credential = new DefaultAzureCredential(); +DeidentificationClient client = new DeidentificationClient(endpoint, credential); + +DeidentificationContent body = new DeidentificationContent("") +{ + Operation = OperationType.Redact, + DataType = DocumentDataType.Plaintext, + RedactionFormat = "", +}; +Response response = client.Deidentify(body); +]]> + + + +This sample shows how to call DeidentifyAsync and parse the result. +"); +TokenCredential credential = new DefaultAzureCredential(); +DeidentificationClient client = new DeidentificationClient(endpoint, credential); + +using RequestContent content = RequestContent.Create(new +{ + inputText = "", +}); +Response response = await client.DeidentifyAsync(content); + +JsonElement result = JsonDocument.Parse(response.ContentStream).RootElement; +Console.WriteLine(result.ToString()); +]]> +This sample shows how to call DeidentifyAsync with all request content and parse the result. +"); +TokenCredential credential = new DefaultAzureCredential(); +DeidentificationClient client = new DeidentificationClient(endpoint, credential); + +using RequestContent content = RequestContent.Create(new +{ + inputText = "", + operation = "Redact", + dataType = "Plaintext", + redactionFormat = "", +}); +Response response = await client.DeidentifyAsync(content); + +JsonElement result = JsonDocument.Parse(response.ContentStream).RootElement; +Console.WriteLine(result.GetProperty("outputText").ToString()); +Console.WriteLine(result.GetProperty("taggerResult").GetProperty("entities")[0].GetProperty("category").ToString()); +Console.WriteLine(result.GetProperty("taggerResult").GetProperty("entities")[0].GetProperty("offset").GetProperty("utf8").ToString()); +Console.WriteLine(result.GetProperty("taggerResult").GetProperty("entities")[0].GetProperty("offset").GetProperty("utf16").ToString()); +Console.WriteLine(result.GetProperty("taggerResult").GetProperty("entities")[0].GetProperty("offset").GetProperty("codePoint").ToString()); +Console.WriteLine(result.GetProperty("taggerResult").GetProperty("entities")[0].GetProperty("length").GetProperty("utf8").ToString()); +Console.WriteLine(result.GetProperty("taggerResult").GetProperty("entities")[0].GetProperty("length").GetProperty("utf16").ToString()); +Console.WriteLine(result.GetProperty("taggerResult").GetProperty("entities")[0].GetProperty("length").GetProperty("codePoint").ToString()); +Console.WriteLine(result.GetProperty("taggerResult").GetProperty("entities")[0].GetProperty("text").ToString()); +Console.WriteLine(result.GetProperty("taggerResult").GetProperty("entities")[0].GetProperty("confidenceScore").ToString()); +Console.WriteLine(result.GetProperty("taggerResult").GetProperty("path").ToString()); +Console.WriteLine(result.GetProperty("taggerResult").GetProperty("etag").ToString()); +]]> + + + +This sample shows how to call Deidentify and parse the result. +"); +TokenCredential credential = new DefaultAzureCredential(); +DeidentificationClient client = new DeidentificationClient(endpoint, credential); + +using RequestContent content = RequestContent.Create(new +{ + inputText = "", +}); +Response response = client.Deidentify(content); + +JsonElement result = JsonDocument.Parse(response.ContentStream).RootElement; +Console.WriteLine(result.ToString()); +]]> +This sample shows how to call Deidentify with all request content and parse the result. +"); +TokenCredential credential = new DefaultAzureCredential(); +DeidentificationClient client = new DeidentificationClient(endpoint, credential); + +using RequestContent content = RequestContent.Create(new +{ + inputText = "", + operation = "Redact", + dataType = "Plaintext", + redactionFormat = "", +}); +Response response = client.Deidentify(content); + +JsonElement result = JsonDocument.Parse(response.ContentStream).RootElement; +Console.WriteLine(result.GetProperty("outputText").ToString()); +Console.WriteLine(result.GetProperty("taggerResult").GetProperty("entities")[0].GetProperty("category").ToString()); +Console.WriteLine(result.GetProperty("taggerResult").GetProperty("entities")[0].GetProperty("offset").GetProperty("utf8").ToString()); +Console.WriteLine(result.GetProperty("taggerResult").GetProperty("entities")[0].GetProperty("offset").GetProperty("utf16").ToString()); +Console.WriteLine(result.GetProperty("taggerResult").GetProperty("entities")[0].GetProperty("offset").GetProperty("codePoint").ToString()); +Console.WriteLine(result.GetProperty("taggerResult").GetProperty("entities")[0].GetProperty("length").GetProperty("utf8").ToString()); +Console.WriteLine(result.GetProperty("taggerResult").GetProperty("entities")[0].GetProperty("length").GetProperty("utf16").ToString()); +Console.WriteLine(result.GetProperty("taggerResult").GetProperty("entities")[0].GetProperty("length").GetProperty("codePoint").ToString()); +Console.WriteLine(result.GetProperty("taggerResult").GetProperty("entities")[0].GetProperty("text").ToString()); +Console.WriteLine(result.GetProperty("taggerResult").GetProperty("entities")[0].GetProperty("confidenceScore").ToString()); +Console.WriteLine(result.GetProperty("taggerResult").GetProperty("path").ToString()); +Console.WriteLine(result.GetProperty("taggerResult").GetProperty("etag").ToString()); +]]> + + + +This sample shows how to call GetJobsAsync. +"); +TokenCredential credential = new DefaultAzureCredential(); +DeidentificationClient client = new DeidentificationClient(endpoint, credential); + +await foreach (DeidentificationJob item in client.GetJobsAsync()) +{ +} +]]> +This sample shows how to call GetJobsAsync with all parameters. +"); +TokenCredential credential = new DefaultAzureCredential(); +DeidentificationClient client = new DeidentificationClient(endpoint, credential); + +await foreach (DeidentificationJob item in client.GetJobsAsync(maxpagesize: 1234, continuationToken: "")) +{ +} +]]> + + + +This sample shows how to call GetJobs. +"); +TokenCredential credential = new DefaultAzureCredential(); +DeidentificationClient client = new DeidentificationClient(endpoint, credential); + +foreach (DeidentificationJob item in client.GetJobs()) +{ +} +]]> +This sample shows how to call GetJobs with all parameters. +"); +TokenCredential credential = new DefaultAzureCredential(); +DeidentificationClient client = new DeidentificationClient(endpoint, credential); + +foreach (DeidentificationJob item in client.GetJobs(maxpagesize: 1234, continuationToken: "")) +{ +} +]]> + + + +This sample shows how to call GetJobsAsync and parse the result. +"); +TokenCredential credential = new DefaultAzureCredential(); +DeidentificationClient client = new DeidentificationClient(endpoint, credential); + +await foreach (BinaryData item in client.GetJobsAsync(null, null, null)) +{ + JsonElement result = JsonDocument.Parse(item.ToStream()).RootElement; + Console.WriteLine(result.GetProperty("name").ToString()); + Console.WriteLine(result.GetProperty("sourceLocation").GetProperty("location").ToString()); + Console.WriteLine(result.GetProperty("sourceLocation").GetProperty("prefix").ToString()); + Console.WriteLine(result.GetProperty("targetLocation").GetProperty("location").ToString()); + Console.WriteLine(result.GetProperty("targetLocation").GetProperty("prefix").ToString()); + Console.WriteLine(result.GetProperty("status").ToString()); + Console.WriteLine(result.GetProperty("lastUpdatedAt").ToString()); + Console.WriteLine(result.GetProperty("createdAt").ToString()); +} +]]> +This sample shows how to call GetJobsAsync with all parameters and parse the result. +"); +TokenCredential credential = new DefaultAzureCredential(); +DeidentificationClient client = new DeidentificationClient(endpoint, credential); + +await foreach (BinaryData item in client.GetJobsAsync(1234, "", null)) +{ + JsonElement result = JsonDocument.Parse(item.ToStream()).RootElement; + Console.WriteLine(result.GetProperty("name").ToString()); + Console.WriteLine(result.GetProperty("sourceLocation").GetProperty("location").ToString()); + Console.WriteLine(result.GetProperty("sourceLocation").GetProperty("prefix").ToString()); + Console.WriteLine(result.GetProperty("sourceLocation").GetProperty("extensions")[0].ToString()); + Console.WriteLine(result.GetProperty("targetLocation").GetProperty("location").ToString()); + Console.WriteLine(result.GetProperty("targetLocation").GetProperty("prefix").ToString()); + Console.WriteLine(result.GetProperty("operation").ToString()); + Console.WriteLine(result.GetProperty("dataType").ToString()); + Console.WriteLine(result.GetProperty("redactionFormat").ToString()); + Console.WriteLine(result.GetProperty("status").ToString()); + Console.WriteLine(result.GetProperty("error").GetProperty("code").ToString()); + Console.WriteLine(result.GetProperty("error").GetProperty("message").ToString()); + Console.WriteLine(result.GetProperty("error").GetProperty("target").ToString()); + Console.WriteLine(result.GetProperty("error").GetProperty("innererror").GetProperty("code").ToString()); + Console.WriteLine(result.GetProperty("lastUpdatedAt").ToString()); + Console.WriteLine(result.GetProperty("createdAt").ToString()); + Console.WriteLine(result.GetProperty("startedAt").ToString()); + Console.WriteLine(result.GetProperty("summary").GetProperty("successful").ToString()); + Console.WriteLine(result.GetProperty("summary").GetProperty("failed").ToString()); + Console.WriteLine(result.GetProperty("summary").GetProperty("canceled").ToString()); + Console.WriteLine(result.GetProperty("summary").GetProperty("total").ToString()); + Console.WriteLine(result.GetProperty("summary").GetProperty("bytesProcessed").ToString()); +} +]]> + + + +This sample shows how to call GetJobs and parse the result. +"); +TokenCredential credential = new DefaultAzureCredential(); +DeidentificationClient client = new DeidentificationClient(endpoint, credential); + +foreach (BinaryData item in client.GetJobs(null, null, null)) +{ + JsonElement result = JsonDocument.Parse(item.ToStream()).RootElement; + Console.WriteLine(result.GetProperty("name").ToString()); + Console.WriteLine(result.GetProperty("sourceLocation").GetProperty("location").ToString()); + Console.WriteLine(result.GetProperty("sourceLocation").GetProperty("prefix").ToString()); + Console.WriteLine(result.GetProperty("targetLocation").GetProperty("location").ToString()); + Console.WriteLine(result.GetProperty("targetLocation").GetProperty("prefix").ToString()); + Console.WriteLine(result.GetProperty("status").ToString()); + Console.WriteLine(result.GetProperty("lastUpdatedAt").ToString()); + Console.WriteLine(result.GetProperty("createdAt").ToString()); +} +]]> +This sample shows how to call GetJobs with all parameters and parse the result. +"); +TokenCredential credential = new DefaultAzureCredential(); +DeidentificationClient client = new DeidentificationClient(endpoint, credential); + +foreach (BinaryData item in client.GetJobs(1234, "", null)) +{ + JsonElement result = JsonDocument.Parse(item.ToStream()).RootElement; + Console.WriteLine(result.GetProperty("name").ToString()); + Console.WriteLine(result.GetProperty("sourceLocation").GetProperty("location").ToString()); + Console.WriteLine(result.GetProperty("sourceLocation").GetProperty("prefix").ToString()); + Console.WriteLine(result.GetProperty("sourceLocation").GetProperty("extensions")[0].ToString()); + Console.WriteLine(result.GetProperty("targetLocation").GetProperty("location").ToString()); + Console.WriteLine(result.GetProperty("targetLocation").GetProperty("prefix").ToString()); + Console.WriteLine(result.GetProperty("operation").ToString()); + Console.WriteLine(result.GetProperty("dataType").ToString()); + Console.WriteLine(result.GetProperty("redactionFormat").ToString()); + Console.WriteLine(result.GetProperty("status").ToString()); + Console.WriteLine(result.GetProperty("error").GetProperty("code").ToString()); + Console.WriteLine(result.GetProperty("error").GetProperty("message").ToString()); + Console.WriteLine(result.GetProperty("error").GetProperty("target").ToString()); + Console.WriteLine(result.GetProperty("error").GetProperty("innererror").GetProperty("code").ToString()); + Console.WriteLine(result.GetProperty("lastUpdatedAt").ToString()); + Console.WriteLine(result.GetProperty("createdAt").ToString()); + Console.WriteLine(result.GetProperty("startedAt").ToString()); + Console.WriteLine(result.GetProperty("summary").GetProperty("successful").ToString()); + Console.WriteLine(result.GetProperty("summary").GetProperty("failed").ToString()); + Console.WriteLine(result.GetProperty("summary").GetProperty("canceled").ToString()); + Console.WriteLine(result.GetProperty("summary").GetProperty("total").ToString()); + Console.WriteLine(result.GetProperty("summary").GetProperty("bytesProcessed").ToString()); +} +]]> + + + +This sample shows how to call GetJobDocumentsAsync. +"); +TokenCredential credential = new DefaultAzureCredential(); +DeidentificationClient client = new DeidentificationClient(endpoint, credential); + +await foreach (DocumentDetails item in client.GetJobDocumentsAsync("")) +{ +} +]]> +This sample shows how to call GetJobDocumentsAsync with all parameters. +"); +TokenCredential credential = new DefaultAzureCredential(); +DeidentificationClient client = new DeidentificationClient(endpoint, credential); + +await foreach (DocumentDetails item in client.GetJobDocumentsAsync("", maxpagesize: 1234, continuationToken: "")) +{ +} +]]> + + + +This sample shows how to call GetJobDocuments. +"); +TokenCredential credential = new DefaultAzureCredential(); +DeidentificationClient client = new DeidentificationClient(endpoint, credential); + +foreach (DocumentDetails item in client.GetJobDocuments("")) +{ +} +]]> +This sample shows how to call GetJobDocuments with all parameters. +"); +TokenCredential credential = new DefaultAzureCredential(); +DeidentificationClient client = new DeidentificationClient(endpoint, credential); + +foreach (DocumentDetails item in client.GetJobDocuments("", maxpagesize: 1234, continuationToken: "")) +{ +} +]]> + + + +This sample shows how to call GetJobDocumentsAsync and parse the result. +"); +TokenCredential credential = new DefaultAzureCredential(); +DeidentificationClient client = new DeidentificationClient(endpoint, credential); + +await foreach (BinaryData item in client.GetJobDocumentsAsync("", null, null, null)) +{ + JsonElement result = JsonDocument.Parse(item.ToStream()).RootElement; + Console.WriteLine(result.GetProperty("id").ToString()); + Console.WriteLine(result.GetProperty("input").GetProperty("path").ToString()); + Console.WriteLine(result.GetProperty("input").GetProperty("etag").ToString()); + Console.WriteLine(result.GetProperty("status").ToString()); +} +]]> +This sample shows how to call GetJobDocumentsAsync with all parameters and parse the result. +"); +TokenCredential credential = new DefaultAzureCredential(); +DeidentificationClient client = new DeidentificationClient(endpoint, credential); + +await foreach (BinaryData item in client.GetJobDocumentsAsync("", 1234, "", null)) +{ + JsonElement result = JsonDocument.Parse(item.ToStream()).RootElement; + Console.WriteLine(result.GetProperty("id").ToString()); + Console.WriteLine(result.GetProperty("input").GetProperty("path").ToString()); + Console.WriteLine(result.GetProperty("input").GetProperty("etag").ToString()); + Console.WriteLine(result.GetProperty("output").GetProperty("path").ToString()); + Console.WriteLine(result.GetProperty("output").GetProperty("etag").ToString()); + Console.WriteLine(result.GetProperty("status").ToString()); + Console.WriteLine(result.GetProperty("error").GetProperty("code").ToString()); + Console.WriteLine(result.GetProperty("error").GetProperty("message").ToString()); + Console.WriteLine(result.GetProperty("error").GetProperty("target").ToString()); + Console.WriteLine(result.GetProperty("error").GetProperty("innererror").GetProperty("code").ToString()); +} +]]> + + + +This sample shows how to call GetJobDocuments and parse the result. +"); +TokenCredential credential = new DefaultAzureCredential(); +DeidentificationClient client = new DeidentificationClient(endpoint, credential); + +foreach (BinaryData item in client.GetJobDocuments("", null, null, null)) +{ + JsonElement result = JsonDocument.Parse(item.ToStream()).RootElement; + Console.WriteLine(result.GetProperty("id").ToString()); + Console.WriteLine(result.GetProperty("input").GetProperty("path").ToString()); + Console.WriteLine(result.GetProperty("input").GetProperty("etag").ToString()); + Console.WriteLine(result.GetProperty("status").ToString()); +} +]]> +This sample shows how to call GetJobDocuments with all parameters and parse the result. +"); +TokenCredential credential = new DefaultAzureCredential(); +DeidentificationClient client = new DeidentificationClient(endpoint, credential); + +foreach (BinaryData item in client.GetJobDocuments("", 1234, "", null)) +{ + JsonElement result = JsonDocument.Parse(item.ToStream()).RootElement; + Console.WriteLine(result.GetProperty("id").ToString()); + Console.WriteLine(result.GetProperty("input").GetProperty("path").ToString()); + Console.WriteLine(result.GetProperty("input").GetProperty("etag").ToString()); + Console.WriteLine(result.GetProperty("output").GetProperty("path").ToString()); + Console.WriteLine(result.GetProperty("output").GetProperty("etag").ToString()); + Console.WriteLine(result.GetProperty("status").ToString()); + Console.WriteLine(result.GetProperty("error").GetProperty("code").ToString()); + Console.WriteLine(result.GetProperty("error").GetProperty("message").ToString()); + Console.WriteLine(result.GetProperty("error").GetProperty("target").ToString()); + Console.WriteLine(result.GetProperty("error").GetProperty("innererror").GetProperty("code").ToString()); +} +]]> + + + +This sample shows how to call CreateJobAsync. +"); +TokenCredential credential = new DefaultAzureCredential(); +DeidentificationClient client = new DeidentificationClient(endpoint, credential); + +DeidentificationJob resource = new DeidentificationJob(new SourceStorageLocation(new Uri("http://localhost:3000"), ""), new TargetStorageLocation(new Uri("http://localhost:3000"), "")); +Operation operation = await client.CreateJobAsync(WaitUntil.Completed, "", resource); +DeidentificationJob responseData = operation.Value; +]]> +This sample shows how to call CreateJobAsync with all parameters. +"); +TokenCredential credential = new DefaultAzureCredential(); +DeidentificationClient client = new DeidentificationClient(endpoint, credential); + +DeidentificationJob resource = new DeidentificationJob(new SourceStorageLocation(new Uri("http://localhost:3000"), "") +{ + Extensions = { "" }, +}, new TargetStorageLocation(new Uri("http://localhost:3000"), "")) +{ + Operation = OperationType.Redact, + DataType = DocumentDataType.Plaintext, + RedactionFormat = "", +}; +Operation operation = await client.CreateJobAsync(WaitUntil.Completed, "", resource); +DeidentificationJob responseData = operation.Value; +]]> + + + +This sample shows how to call CreateJob. +"); +TokenCredential credential = new DefaultAzureCredential(); +DeidentificationClient client = new DeidentificationClient(endpoint, credential); + +DeidentificationJob resource = new DeidentificationJob(new SourceStorageLocation(new Uri("http://localhost:3000"), ""), new TargetStorageLocation(new Uri("http://localhost:3000"), "")); +Operation operation = client.CreateJob(WaitUntil.Completed, "", resource); +DeidentificationJob responseData = operation.Value; +]]> +This sample shows how to call CreateJob with all parameters. +"); +TokenCredential credential = new DefaultAzureCredential(); +DeidentificationClient client = new DeidentificationClient(endpoint, credential); + +DeidentificationJob resource = new DeidentificationJob(new SourceStorageLocation(new Uri("http://localhost:3000"), "") +{ + Extensions = { "" }, +}, new TargetStorageLocation(new Uri("http://localhost:3000"), "")) +{ + Operation = OperationType.Redact, + DataType = DocumentDataType.Plaintext, + RedactionFormat = "", +}; +Operation operation = client.CreateJob(WaitUntil.Completed, "", resource); +DeidentificationJob responseData = operation.Value; +]]> + + + +This sample shows how to call CreateJobAsync and parse the result. +"); +TokenCredential credential = new DefaultAzureCredential(); +DeidentificationClient client = new DeidentificationClient(endpoint, credential); + +using RequestContent content = RequestContent.Create(new +{ + sourceLocation = new + { + location = "http://localhost:3000", + prefix = "", + }, + targetLocation = new + { + location = "http://localhost:3000", + prefix = "", + }, +}); +Operation operation = await client.CreateJobAsync(WaitUntil.Completed, "", content); +BinaryData responseData = operation.Value; + +JsonElement result = JsonDocument.Parse(responseData.ToStream()).RootElement; +Console.WriteLine(result.GetProperty("name").ToString()); +Console.WriteLine(result.GetProperty("sourceLocation").GetProperty("location").ToString()); +Console.WriteLine(result.GetProperty("sourceLocation").GetProperty("prefix").ToString()); +Console.WriteLine(result.GetProperty("targetLocation").GetProperty("location").ToString()); +Console.WriteLine(result.GetProperty("targetLocation").GetProperty("prefix").ToString()); +Console.WriteLine(result.GetProperty("status").ToString()); +Console.WriteLine(result.GetProperty("lastUpdatedAt").ToString()); +Console.WriteLine(result.GetProperty("createdAt").ToString()); +]]> +This sample shows how to call CreateJobAsync with all parameters and request content and parse the result. +"); +TokenCredential credential = new DefaultAzureCredential(); +DeidentificationClient client = new DeidentificationClient(endpoint, credential); + +using RequestContent content = RequestContent.Create(new +{ + sourceLocation = new + { + location = "http://localhost:3000", + prefix = "", + extensions = new object[] + { + "" + }, + }, + targetLocation = new + { + location = "http://localhost:3000", + prefix = "", + }, + operation = "Redact", + dataType = "Plaintext", + redactionFormat = "", +}); +Operation operation = await client.CreateJobAsync(WaitUntil.Completed, "", content); +BinaryData responseData = operation.Value; + +JsonElement result = JsonDocument.Parse(responseData.ToStream()).RootElement; +Console.WriteLine(result.GetProperty("name").ToString()); +Console.WriteLine(result.GetProperty("sourceLocation").GetProperty("location").ToString()); +Console.WriteLine(result.GetProperty("sourceLocation").GetProperty("prefix").ToString()); +Console.WriteLine(result.GetProperty("sourceLocation").GetProperty("extensions")[0].ToString()); +Console.WriteLine(result.GetProperty("targetLocation").GetProperty("location").ToString()); +Console.WriteLine(result.GetProperty("targetLocation").GetProperty("prefix").ToString()); +Console.WriteLine(result.GetProperty("operation").ToString()); +Console.WriteLine(result.GetProperty("dataType").ToString()); +Console.WriteLine(result.GetProperty("redactionFormat").ToString()); +Console.WriteLine(result.GetProperty("status").ToString()); +Console.WriteLine(result.GetProperty("error").GetProperty("code").ToString()); +Console.WriteLine(result.GetProperty("error").GetProperty("message").ToString()); +Console.WriteLine(result.GetProperty("error").GetProperty("target").ToString()); +Console.WriteLine(result.GetProperty("error").GetProperty("innererror").GetProperty("code").ToString()); +Console.WriteLine(result.GetProperty("lastUpdatedAt").ToString()); +Console.WriteLine(result.GetProperty("createdAt").ToString()); +Console.WriteLine(result.GetProperty("startedAt").ToString()); +Console.WriteLine(result.GetProperty("summary").GetProperty("successful").ToString()); +Console.WriteLine(result.GetProperty("summary").GetProperty("failed").ToString()); +Console.WriteLine(result.GetProperty("summary").GetProperty("canceled").ToString()); +Console.WriteLine(result.GetProperty("summary").GetProperty("total").ToString()); +Console.WriteLine(result.GetProperty("summary").GetProperty("bytesProcessed").ToString()); +]]> + + + +This sample shows how to call CreateJob and parse the result. +"); +TokenCredential credential = new DefaultAzureCredential(); +DeidentificationClient client = new DeidentificationClient(endpoint, credential); + +using RequestContent content = RequestContent.Create(new +{ + sourceLocation = new + { + location = "http://localhost:3000", + prefix = "", + }, + targetLocation = new + { + location = "http://localhost:3000", + prefix = "", + }, +}); +Operation operation = client.CreateJob(WaitUntil.Completed, "", content); +BinaryData responseData = operation.Value; + +JsonElement result = JsonDocument.Parse(responseData.ToStream()).RootElement; +Console.WriteLine(result.GetProperty("name").ToString()); +Console.WriteLine(result.GetProperty("sourceLocation").GetProperty("location").ToString()); +Console.WriteLine(result.GetProperty("sourceLocation").GetProperty("prefix").ToString()); +Console.WriteLine(result.GetProperty("targetLocation").GetProperty("location").ToString()); +Console.WriteLine(result.GetProperty("targetLocation").GetProperty("prefix").ToString()); +Console.WriteLine(result.GetProperty("status").ToString()); +Console.WriteLine(result.GetProperty("lastUpdatedAt").ToString()); +Console.WriteLine(result.GetProperty("createdAt").ToString()); +]]> +This sample shows how to call CreateJob with all parameters and request content and parse the result. +"); +TokenCredential credential = new DefaultAzureCredential(); +DeidentificationClient client = new DeidentificationClient(endpoint, credential); + +using RequestContent content = RequestContent.Create(new +{ + sourceLocation = new + { + location = "http://localhost:3000", + prefix = "", + extensions = new object[] + { + "" + }, + }, + targetLocation = new + { + location = "http://localhost:3000", + prefix = "", + }, + operation = "Redact", + dataType = "Plaintext", + redactionFormat = "", +}); +Operation operation = client.CreateJob(WaitUntil.Completed, "", content); +BinaryData responseData = operation.Value; + +JsonElement result = JsonDocument.Parse(responseData.ToStream()).RootElement; +Console.WriteLine(result.GetProperty("name").ToString()); +Console.WriteLine(result.GetProperty("sourceLocation").GetProperty("location").ToString()); +Console.WriteLine(result.GetProperty("sourceLocation").GetProperty("prefix").ToString()); +Console.WriteLine(result.GetProperty("sourceLocation").GetProperty("extensions")[0].ToString()); +Console.WriteLine(result.GetProperty("targetLocation").GetProperty("location").ToString()); +Console.WriteLine(result.GetProperty("targetLocation").GetProperty("prefix").ToString()); +Console.WriteLine(result.GetProperty("operation").ToString()); +Console.WriteLine(result.GetProperty("dataType").ToString()); +Console.WriteLine(result.GetProperty("redactionFormat").ToString()); +Console.WriteLine(result.GetProperty("status").ToString()); +Console.WriteLine(result.GetProperty("error").GetProperty("code").ToString()); +Console.WriteLine(result.GetProperty("error").GetProperty("message").ToString()); +Console.WriteLine(result.GetProperty("error").GetProperty("target").ToString()); +Console.WriteLine(result.GetProperty("error").GetProperty("innererror").GetProperty("code").ToString()); +Console.WriteLine(result.GetProperty("lastUpdatedAt").ToString()); +Console.WriteLine(result.GetProperty("createdAt").ToString()); +Console.WriteLine(result.GetProperty("startedAt").ToString()); +Console.WriteLine(result.GetProperty("summary").GetProperty("successful").ToString()); +Console.WriteLine(result.GetProperty("summary").GetProperty("failed").ToString()); +Console.WriteLine(result.GetProperty("summary").GetProperty("canceled").ToString()); +Console.WriteLine(result.GetProperty("summary").GetProperty("total").ToString()); +Console.WriteLine(result.GetProperty("summary").GetProperty("bytesProcessed").ToString()); +]]> + + + \ No newline at end of file diff --git a/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/DocumentDataType.cs b/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/DocumentDataType.cs new file mode 100644 index 000000000000..a783dc0231ca --- /dev/null +++ b/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/DocumentDataType.cs @@ -0,0 +1,48 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System; +using System.ComponentModel; + +namespace Azure.Health.Deidentification +{ + /// Enum of supported Data Types. + public readonly partial struct DocumentDataType : IEquatable + { + private readonly string _value; + + /// Initializes a new instance of . + /// is null. + public DocumentDataType(string value) + { + _value = value ?? throw new ArgumentNullException(nameof(value)); + } + + private const string PlaintextValue = "Plaintext"; + + /// Plain text data type. + public static DocumentDataType Plaintext { get; } = new DocumentDataType(PlaintextValue); + /// Determines if two values are the same. + public static bool operator ==(DocumentDataType left, DocumentDataType right) => left.Equals(right); + /// Determines if two values are not the same. + public static bool operator !=(DocumentDataType left, DocumentDataType right) => !left.Equals(right); + /// Converts a string to a . + public static implicit operator DocumentDataType(string value) => new DocumentDataType(value); + + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public override bool Equals(object obj) => obj is DocumentDataType other && Equals(other); + /// + public bool Equals(DocumentDataType other) => string.Equals(_value, other._value, StringComparison.InvariantCultureIgnoreCase); + + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public override int GetHashCode() => _value != null ? StringComparer.InvariantCultureIgnoreCase.GetHashCode(_value) : 0; + /// + public override string ToString() => _value; + } +} diff --git a/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/DocumentDetails.Serialization.cs b/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/DocumentDetails.Serialization.cs new file mode 100644 index 000000000000..020655f3c876 --- /dev/null +++ b/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/DocumentDetails.Serialization.cs @@ -0,0 +1,190 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System; +using System.ClientModel.Primitives; +using System.Collections.Generic; +using System.Text.Json; +using Azure.Core; + +namespace Azure.Health.Deidentification +{ + public partial class DocumentDetails : IUtf8JsonSerializable, IJsonModel + { + void IUtf8JsonSerializable.Write(Utf8JsonWriter writer) => ((IJsonModel)this).Write(writer, ModelSerializationExtensions.WireOptions); + + void IJsonModel.Write(Utf8JsonWriter writer, ModelReaderWriterOptions options) + { + var format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + if (format != "J") + { + throw new FormatException($"The model {nameof(DocumentDetails)} does not support writing '{format}' format."); + } + + writer.WriteStartObject(); + if (options.Format != "W") + { + writer.WritePropertyName("id"u8); + writer.WriteStringValue(Id); + } + writer.WritePropertyName("input"u8); + writer.WriteObjectValue(Input, options); + if (Optional.IsDefined(Output)) + { + writer.WritePropertyName("output"u8); + writer.WriteObjectValue(Output, options); + } + writer.WritePropertyName("status"u8); + writer.WriteStringValue(Status.ToString()); + if (Optional.IsDefined(Error)) + { + writer.WritePropertyName("error"u8); + JsonSerializer.Serialize(writer, Error); + } + if (options.Format != "W" && _serializedAdditionalRawData != null) + { + foreach (var item in _serializedAdditionalRawData) + { + writer.WritePropertyName(item.Key); +#if NET6_0_OR_GREATER + writer.WriteRawValue(item.Value); +#else + using (JsonDocument document = JsonDocument.Parse(item.Value)) + { + JsonSerializer.Serialize(writer, document.RootElement); + } +#endif + } + } + writer.WriteEndObject(); + } + + DocumentDetails IJsonModel.Create(ref Utf8JsonReader reader, ModelReaderWriterOptions options) + { + var format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + if (format != "J") + { + throw new FormatException($"The model {nameof(DocumentDetails)} does not support reading '{format}' format."); + } + + using JsonDocument document = JsonDocument.ParseValue(ref reader); + return DeserializeDocumentDetails(document.RootElement, options); + } + + internal static DocumentDetails DeserializeDocumentDetails(JsonElement element, ModelReaderWriterOptions options = null) + { + options ??= ModelSerializationExtensions.WireOptions; + + if (element.ValueKind == JsonValueKind.Null) + { + return null; + } + string id = default; + DocumentLocation input = default; + DocumentLocation output = default; + OperationState status = default; + ResponseError error = default; + IDictionary serializedAdditionalRawData = default; + Dictionary rawDataDictionary = new Dictionary(); + foreach (var property in element.EnumerateObject()) + { + if (property.NameEquals("id"u8)) + { + id = property.Value.GetString(); + continue; + } + if (property.NameEquals("input"u8)) + { + input = DocumentLocation.DeserializeDocumentLocation(property.Value, options); + continue; + } + if (property.NameEquals("output"u8)) + { + if (property.Value.ValueKind == JsonValueKind.Null) + { + continue; + } + output = DocumentLocation.DeserializeDocumentLocation(property.Value, options); + continue; + } + if (property.NameEquals("status"u8)) + { + status = new OperationState(property.Value.GetString()); + continue; + } + if (property.NameEquals("error"u8)) + { + if (property.Value.ValueKind == JsonValueKind.Null) + { + continue; + } + error = JsonSerializer.Deserialize(property.Value.GetRawText()); + continue; + } + if (options.Format != "W") + { + rawDataDictionary.Add(property.Name, BinaryData.FromString(property.Value.GetRawText())); + } + } + serializedAdditionalRawData = rawDataDictionary; + return new DocumentDetails( + id, + input, + output, + status, + error, + serializedAdditionalRawData); + } + + BinaryData IPersistableModel.Write(ModelReaderWriterOptions options) + { + var format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + + switch (format) + { + case "J": + return ModelReaderWriter.Write(this, options); + default: + throw new FormatException($"The model {nameof(DocumentDetails)} does not support writing '{options.Format}' format."); + } + } + + DocumentDetails IPersistableModel.Create(BinaryData data, ModelReaderWriterOptions options) + { + var format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + + switch (format) + { + case "J": + { + using JsonDocument document = JsonDocument.Parse(data); + return DeserializeDocumentDetails(document.RootElement, options); + } + default: + throw new FormatException($"The model {nameof(DocumentDetails)} does not support reading '{options.Format}' format."); + } + } + + string IPersistableModel.GetFormatFromOptions(ModelReaderWriterOptions options) => "J"; + + /// Deserializes the model from a raw response. + /// The response to deserialize the model from. + internal static DocumentDetails FromResponse(Response response) + { + using var document = JsonDocument.Parse(response.Content); + return DeserializeDocumentDetails(document.RootElement); + } + + /// Convert into a . + internal virtual RequestContent ToRequestContent() + { + var content = new Utf8JsonRequestContent(); + content.JsonWriter.WriteObjectValue(this, ModelSerializationExtensions.WireOptions); + return content; + } + } +} diff --git a/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/DocumentDetails.cs b/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/DocumentDetails.cs new file mode 100644 index 000000000000..59685c4d8e57 --- /dev/null +++ b/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/DocumentDetails.cs @@ -0,0 +1,93 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System; +using System.Collections.Generic; + +namespace Azure.Health.Deidentification +{ + /// Details of a single document in a job. + public partial class DocumentDetails + { + /// + /// Keeps track of any properties unknown to the library. + /// + /// To assign an object to the value of this property use . + /// + /// + /// To assign an already formatted json string to this property use . + /// + /// + /// Examples: + /// + /// + /// BinaryData.FromObjectAsJson("foo") + /// Creates a payload of "foo". + /// + /// + /// BinaryData.FromString("\"foo\"") + /// Creates a payload of "foo". + /// + /// + /// BinaryData.FromObjectAsJson(new { key = "value" }) + /// Creates a payload of { "key": "value" }. + /// + /// + /// BinaryData.FromString("{\"key\": \"value\"}") + /// Creates a payload of { "key": "value" }. + /// + /// + /// + /// + private IDictionary _serializedAdditionalRawData; + + /// Initializes a new instance of . + /// Location for the input. + /// Status of the document. + /// is null. + internal DocumentDetails(DocumentLocation input, OperationState status) + { + Argument.AssertNotNull(input, nameof(input)); + + Input = input; + Status = status; + } + + /// Initializes a new instance of . + /// Id of the document details. + /// Location for the input. + /// Location for the output. + /// Status of the document. + /// Error when document fails. + /// Keeps track of any properties unknown to the library. + internal DocumentDetails(string id, DocumentLocation input, DocumentLocation output, OperationState status, ResponseError error, IDictionary serializedAdditionalRawData) + { + Id = id; + Input = input; + Output = output; + Status = status; + Error = error; + _serializedAdditionalRawData = serializedAdditionalRawData; + } + + /// Initializes a new instance of for deserialization. + internal DocumentDetails() + { + } + + /// Id of the document details. + public string Id { get; } + /// Location for the input. + public DocumentLocation Input { get; } + /// Location for the output. + public DocumentLocation Output { get; } + /// Status of the document. + public OperationState Status { get; } + /// Error when document fails. + public ResponseError Error { get; } + } +} diff --git a/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/DocumentLocation.Serialization.cs b/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/DocumentLocation.Serialization.cs new file mode 100644 index 000000000000..cc32765123c0 --- /dev/null +++ b/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/DocumentLocation.Serialization.cs @@ -0,0 +1,146 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System; +using System.ClientModel.Primitives; +using System.Collections.Generic; +using System.Text.Json; +using Azure.Core; + +namespace Azure.Health.Deidentification +{ + public partial class DocumentLocation : IUtf8JsonSerializable, IJsonModel + { + void IUtf8JsonSerializable.Write(Utf8JsonWriter writer) => ((IJsonModel)this).Write(writer, ModelSerializationExtensions.WireOptions); + + void IJsonModel.Write(Utf8JsonWriter writer, ModelReaderWriterOptions options) + { + var format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + if (format != "J") + { + throw new FormatException($"The model {nameof(DocumentLocation)} does not support writing '{format}' format."); + } + + writer.WriteStartObject(); + writer.WritePropertyName("path"u8); + writer.WriteStringValue(Path); + if (options.Format != "W") + { + writer.WritePropertyName("etag"u8); + writer.WriteStringValue(Etag.ToString()); + } + if (options.Format != "W" && _serializedAdditionalRawData != null) + { + foreach (var item in _serializedAdditionalRawData) + { + writer.WritePropertyName(item.Key); +#if NET6_0_OR_GREATER + writer.WriteRawValue(item.Value); +#else + using (JsonDocument document = JsonDocument.Parse(item.Value)) + { + JsonSerializer.Serialize(writer, document.RootElement); + } +#endif + } + } + writer.WriteEndObject(); + } + + DocumentLocation IJsonModel.Create(ref Utf8JsonReader reader, ModelReaderWriterOptions options) + { + var format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + if (format != "J") + { + throw new FormatException($"The model {nameof(DocumentLocation)} does not support reading '{format}' format."); + } + + using JsonDocument document = JsonDocument.ParseValue(ref reader); + return DeserializeDocumentLocation(document.RootElement, options); + } + + internal static DocumentLocation DeserializeDocumentLocation(JsonElement element, ModelReaderWriterOptions options = null) + { + options ??= ModelSerializationExtensions.WireOptions; + + if (element.ValueKind == JsonValueKind.Null) + { + return null; + } + string path = default; + ETag etag = default; + IDictionary serializedAdditionalRawData = default; + Dictionary rawDataDictionary = new Dictionary(); + foreach (var property in element.EnumerateObject()) + { + if (property.NameEquals("path"u8)) + { + path = property.Value.GetString(); + continue; + } + if (property.NameEquals("etag"u8)) + { + etag = new ETag(property.Value.GetString()); + continue; + } + if (options.Format != "W") + { + rawDataDictionary.Add(property.Name, BinaryData.FromString(property.Value.GetRawText())); + } + } + serializedAdditionalRawData = rawDataDictionary; + return new DocumentLocation(path, etag, serializedAdditionalRawData); + } + + BinaryData IPersistableModel.Write(ModelReaderWriterOptions options) + { + var format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + + switch (format) + { + case "J": + return ModelReaderWriter.Write(this, options); + default: + throw new FormatException($"The model {nameof(DocumentLocation)} does not support writing '{options.Format}' format."); + } + } + + DocumentLocation IPersistableModel.Create(BinaryData data, ModelReaderWriterOptions options) + { + var format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + + switch (format) + { + case "J": + { + using JsonDocument document = JsonDocument.Parse(data); + return DeserializeDocumentLocation(document.RootElement, options); + } + default: + throw new FormatException($"The model {nameof(DocumentLocation)} does not support reading '{options.Format}' format."); + } + } + + string IPersistableModel.GetFormatFromOptions(ModelReaderWriterOptions options) => "J"; + + /// Deserializes the model from a raw response. + /// The response to deserialize the model from. + internal static DocumentLocation FromResponse(Response response) + { + using var document = JsonDocument.Parse(response.Content); + return DeserializeDocumentLocation(document.RootElement); + } + + /// Convert into a . + internal virtual RequestContent ToRequestContent() + { + var content = new Utf8JsonRequestContent(); + content.JsonWriter.WriteObjectValue(this, ModelSerializationExtensions.WireOptions); + return content; + } + } +} diff --git a/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/DocumentLocation.cs b/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/DocumentLocation.cs new file mode 100644 index 000000000000..6ba76ad5f26b --- /dev/null +++ b/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/DocumentLocation.cs @@ -0,0 +1,79 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System; +using System.Collections.Generic; + +namespace Azure.Health.Deidentification +{ + /// Location of a document. + public partial class DocumentLocation + { + /// + /// Keeps track of any properties unknown to the library. + /// + /// To assign an object to the value of this property use . + /// + /// + /// To assign an already formatted json string to this property use . + /// + /// + /// Examples: + /// + /// + /// BinaryData.FromObjectAsJson("foo") + /// Creates a payload of "foo". + /// + /// + /// BinaryData.FromString("\"foo\"") + /// Creates a payload of "foo". + /// + /// + /// BinaryData.FromObjectAsJson(new { key = "value" }) + /// Creates a payload of { "key": "value" }. + /// + /// + /// BinaryData.FromString("{\"key\": \"value\"}") + /// Creates a payload of { "key": "value" }. + /// + /// + /// + /// + private IDictionary _serializedAdditionalRawData; + + /// Initializes a new instance of . + /// Path of document in storage. + /// is null. + internal DocumentLocation(string path) + { + Argument.AssertNotNull(path, nameof(path)); + + Path = path; + } + + /// Initializes a new instance of . + /// Path of document in storage. + /// The entity tag for this resource. + /// Keeps track of any properties unknown to the library. + internal DocumentLocation(string path, ETag etag, IDictionary serializedAdditionalRawData) + { + Path = path; + Etag = etag; + _serializedAdditionalRawData = serializedAdditionalRawData; + } + + /// Initializes a new instance of for deserialization. + internal DocumentLocation() + { + } + + /// Path of document in storage. + public string Path { get; } + /// The entity tag for this resource. + public ETag Etag { get; } + } +} diff --git a/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/HealthDeidentificationClientBuilderExtensions.cs b/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/HealthDeidentificationClientBuilderExtensions.cs new file mode 100644 index 000000000000..782692f64495 --- /dev/null +++ b/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/HealthDeidentificationClientBuilderExtensions.cs @@ -0,0 +1,35 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System; +using Azure.Core.Extensions; +using Azure.Health.Deidentification; + +namespace Microsoft.Extensions.Azure +{ + /// Extension methods to add to client builder. + public static partial class HealthDeidentificationClientBuilderExtensions + { + /// Registers a instance. + /// The builder to register with. + /// Url of your De-identification Service. + public static IAzureClientBuilder AddDeidentificationClient(this TBuilder builder, Uri endpoint) + where TBuilder : IAzureClientFactoryBuilderWithCredential + { + return builder.RegisterClientFactory((options, cred) => new DeidentificationClient(endpoint, cred, options)); + } + + /// Registers a instance. + /// The builder to register with. + /// The configuration values. + public static IAzureClientBuilder AddDeidentificationClient(this TBuilder builder, TConfiguration configuration) + where TBuilder : IAzureClientFactoryBuilderWithConfiguration + { + return builder.RegisterClientFactory(configuration); + } + } +} diff --git a/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/HealthDeidentificationModelFactory.cs b/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/HealthDeidentificationModelFactory.cs new file mode 100644 index 000000000000..decf093fc8f0 --- /dev/null +++ b/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/HealthDeidentificationModelFactory.cs @@ -0,0 +1,168 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Azure.Health.Deidentification +{ + /// Model factory for models. + public static partial class HealthDeidentificationModelFactory + { + /// Initializes a new instance of . + /// The name of a job. + /// Storage location to perform the operation on. + /// Target location to store output of operation. + /// Operation to perform on the input documents. + /// Data type of the input documents. + /// Format of the redacted output. Only valid when Operation is Redact. + /// Current status of a job. + /// Error when job fails in it's entirety. + /// + /// Date and time when the job was completed. + /// + /// If the job is canceled, this is the time when the job was canceled. + /// + /// If the job failed, this is the time when the job failed. + /// + /// Date and time when the job was created. + /// Date and time when the job was started. + /// Summary of a job. Exists only when the job is completed. + /// A new instance for mocking. + public static DeidentificationJob DeidentificationJob(string name = null, SourceStorageLocation sourceLocation = null, TargetStorageLocation targetLocation = null, OperationType? operation = null, DocumentDataType? dataType = null, string redactionFormat = null, JobStatus status = default, ResponseError error = null, DateTimeOffset lastUpdatedAt = default, DateTimeOffset createdAt = default, DateTimeOffset? startedAt = null, JobSummary summary = null) + { + return new DeidentificationJob( + name, + sourceLocation, + targetLocation, + operation, + dataType, + redactionFormat, + status, + error, + lastUpdatedAt, + createdAt, + startedAt, + summary, + serializedAdditionalRawData: null); + } + + /// Initializes a new instance of . + /// Number of documents that have completed. + /// Number of documents that have failed. + /// Number of documents that have been canceled. + /// Number of documents total. + /// Number of bytes processed. + /// A new instance for mocking. + public static JobSummary JobSummary(int successful = default, int failed = default, int canceled = default, int total = default, long bytesProcessed = default) + { + return new JobSummary( + successful, + failed, + canceled, + total, + bytesProcessed, + serializedAdditionalRawData: null); + } + + /// Initializes a new instance of . + /// Id of the document details. + /// Location for the input. + /// Location for the output. + /// Status of the document. + /// Error when document fails. + /// A new instance for mocking. + public static DocumentDetails DocumentDetails(string id = null, DocumentLocation input = null, DocumentLocation output = null, OperationState status = default, ResponseError error = null) + { + return new DocumentDetails( + id, + input, + output, + status, + error, + serializedAdditionalRawData: null); + } + + /// Initializes a new instance of . + /// Path of document in storage. + /// The entity tag for this resource. + /// A new instance for mocking. + public static DocumentLocation DocumentLocation(string path = null, ETag etag = default) + { + return new DocumentLocation(path, etag, serializedAdditionalRawData: null); + } + + /// Initializes a new instance of . + /// Input text to de-identify. + /// Operation to perform on the input. + /// Data type of the input. + /// Format of the redacted output. Only valid when OperationType is "Redact". + /// A new instance for mocking. + public static DeidentificationContent DeidentificationContent(string inputText = null, OperationType? operation = null, DocumentDataType? dataType = null, string redactionFormat = null) + { + return new DeidentificationContent(inputText, operation, dataType, redactionFormat, serializedAdditionalRawData: null); + } + + /// Initializes a new instance of . + /// Output text after de-identification. Not available for "Tag" operation. + /// Result of the "Tag" operation. Only available for "Tag" Operation. + /// A new instance for mocking. + public static DeidentificationResult DeidentificationResult(string outputText = null, PhiTaggerResult taggerResult = null) + { + return new DeidentificationResult(outputText, taggerResult, serializedAdditionalRawData: null); + } + + /// Initializes a new instance of . + /// List of entities detected in the input. + /// Path to the document in storage. + /// The entity tag for this resource. + /// A new instance for mocking. + public static PhiTaggerResult PhiTaggerResult(IEnumerable entities = null, string path = null, ETag? etag = null) + { + entities ??= new List(); + + return new PhiTaggerResult(entities?.ToList(), path, etag, serializedAdditionalRawData: null); + } + + /// Initializes a new instance of . + /// PHI Category of the entity. + /// Starting index of the location from within the input text. + /// Length of the input text. + /// Text of the entity. + /// Confidence score of the category match. + /// A new instance for mocking. + public static PhiEntity PhiEntity(PhiCategory category = default, StringIndex offset = null, StringIndex length = null, string text = null, double? confidenceScore = null) + { + return new PhiEntity( + category, + offset, + length, + text, + confidenceScore, + serializedAdditionalRawData: null); + } + + /// Initializes a new instance of . + /// The offset or length of the substring in UTF-8 encoding. + /// + /// The offset or length of the substring in UTF-16 encoding. + /// + /// Primary encoding used by .NET, Java, and JavaScript. + /// + /// + /// The offset or length of the substring in CodePoint encoding. + /// + /// Primary encoding used by Python. + /// + /// A new instance for mocking. + public static StringIndex StringIndex(int utf8 = default, int utf16 = default, int codePoint = default) + { + return new StringIndex(utf8, utf16, codePoint, serializedAdditionalRawData: null); + } + } +} diff --git a/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/Internal/Argument.cs b/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/Internal/Argument.cs new file mode 100644 index 000000000000..533e647d400f --- /dev/null +++ b/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/Internal/Argument.cs @@ -0,0 +1,129 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System; +using System.Collections; +using System.Collections.Generic; + +namespace Azure.Health.Deidentification +{ + internal static class Argument + { + public static void AssertNotNull(T value, string name) + { + if (value is null) + { + throw new ArgumentNullException(name); + } + } + + public static void AssertNotNull(T? value, string name) + where T : struct + { + if (!value.HasValue) + { + throw new ArgumentNullException(name); + } + } + + public static void AssertNotNullOrEmpty(IEnumerable value, string name) + { + if (value is null) + { + throw new ArgumentNullException(name); + } + if (value is ICollection collectionOfT && collectionOfT.Count == 0) + { + throw new ArgumentException("Value cannot be an empty collection.", name); + } + if (value is ICollection collection && collection.Count == 0) + { + throw new ArgumentException("Value cannot be an empty collection.", name); + } + using IEnumerator e = value.GetEnumerator(); + if (!e.MoveNext()) + { + throw new ArgumentException("Value cannot be an empty collection.", name); + } + } + + public static void AssertNotNullOrEmpty(string value, string name) + { + if (value is null) + { + throw new ArgumentNullException(name); + } + if (value.Length == 0) + { + throw new ArgumentException("Value cannot be an empty string.", name); + } + } + + public static void AssertNotNullOrWhiteSpace(string value, string name) + { + if (value is null) + { + throw new ArgumentNullException(name); + } + if (string.IsNullOrWhiteSpace(value)) + { + throw new ArgumentException("Value cannot be empty or contain only white-space characters.", name); + } + } + + public static void AssertNotDefault(ref T value, string name) + where T : struct, IEquatable + { + if (value.Equals(default)) + { + throw new ArgumentException("Value cannot be empty.", name); + } + } + + public static void AssertInRange(T value, T minimum, T maximum, string name) + where T : notnull, IComparable + { + if (minimum.CompareTo(value) > 0) + { + throw new ArgumentOutOfRangeException(name, "Value is less than the minimum allowed."); + } + if (maximum.CompareTo(value) < 0) + { + throw new ArgumentOutOfRangeException(name, "Value is greater than the maximum allowed."); + } + } + + public static void AssertEnumDefined(Type enumType, object value, string name) + { + if (!Enum.IsDefined(enumType, value)) + { + throw new ArgumentException($"Value not defined for {enumType.FullName}.", name); + } + } + + public static T CheckNotNull(T value, string name) + where T : class + { + AssertNotNull(value, name); + return value; + } + + public static string CheckNotNullOrEmpty(string value, string name) + { + AssertNotNullOrEmpty(value, name); + return value; + } + + public static void AssertNull(T value, string name, string message = null) + { + if (value != null) + { + throw new ArgumentException(message ?? "Value must be null.", name); + } + } + } +} diff --git a/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/Internal/ChangeTrackingDictionary.cs b/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/Internal/ChangeTrackingDictionary.cs new file mode 100644 index 000000000000..b5b2099cc090 --- /dev/null +++ b/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/Internal/ChangeTrackingDictionary.cs @@ -0,0 +1,167 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System; +using System.Collections; +using System.Collections.Generic; + +namespace Azure.Health.Deidentification +{ + internal class ChangeTrackingDictionary : IDictionary, IReadOnlyDictionary where TKey : notnull + { + private IDictionary _innerDictionary; + + public ChangeTrackingDictionary() + { + } + + public ChangeTrackingDictionary(IDictionary dictionary) + { + if (dictionary == null) + { + return; + } + _innerDictionary = new Dictionary(dictionary); + } + + public ChangeTrackingDictionary(IReadOnlyDictionary dictionary) + { + if (dictionary == null) + { + return; + } + _innerDictionary = new Dictionary(); + foreach (var pair in dictionary) + { + _innerDictionary.Add(pair); + } + } + + public bool IsUndefined => _innerDictionary == null; + + public int Count => IsUndefined ? 0 : EnsureDictionary().Count; + + public bool IsReadOnly => IsUndefined ? false : EnsureDictionary().IsReadOnly; + + public ICollection Keys => IsUndefined ? Array.Empty() : EnsureDictionary().Keys; + + public ICollection Values => IsUndefined ? Array.Empty() : EnsureDictionary().Values; + + public TValue this[TKey key] + { + get + { + if (IsUndefined) + { + throw new KeyNotFoundException(nameof(key)); + } + return EnsureDictionary()[key]; + } + set + { + EnsureDictionary()[key] = value; + } + } + + IEnumerable IReadOnlyDictionary.Keys => Keys; + + IEnumerable IReadOnlyDictionary.Values => Values; + + public IEnumerator> GetEnumerator() + { + if (IsUndefined) + { + IEnumerator> enumerateEmpty() + { + yield break; + } + return enumerateEmpty(); + } + return EnsureDictionary().GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + public void Add(KeyValuePair item) + { + EnsureDictionary().Add(item); + } + + public void Clear() + { + EnsureDictionary().Clear(); + } + + public bool Contains(KeyValuePair item) + { + if (IsUndefined) + { + return false; + } + return EnsureDictionary().Contains(item); + } + + public void CopyTo(KeyValuePair[] array, int index) + { + if (IsUndefined) + { + return; + } + EnsureDictionary().CopyTo(array, index); + } + + public bool Remove(KeyValuePair item) + { + if (IsUndefined) + { + return false; + } + return EnsureDictionary().Remove(item); + } + + public void Add(TKey key, TValue value) + { + EnsureDictionary().Add(key, value); + } + + public bool ContainsKey(TKey key) + { + if (IsUndefined) + { + return false; + } + return EnsureDictionary().ContainsKey(key); + } + + public bool Remove(TKey key) + { + if (IsUndefined) + { + return false; + } + return EnsureDictionary().Remove(key); + } + + public bool TryGetValue(TKey key, out TValue value) + { + if (IsUndefined) + { + value = default; + return false; + } + return EnsureDictionary().TryGetValue(key, out value); + } + + public IDictionary EnsureDictionary() + { + return _innerDictionary ??= new Dictionary(); + } + } +} diff --git a/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/Internal/ChangeTrackingList.cs b/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/Internal/ChangeTrackingList.cs new file mode 100644 index 000000000000..4966a1309b66 --- /dev/null +++ b/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/Internal/ChangeTrackingList.cs @@ -0,0 +1,153 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; + +namespace Azure.Health.Deidentification +{ + internal class ChangeTrackingList : IList, IReadOnlyList + { + private IList _innerList; + + public ChangeTrackingList() + { + } + + public ChangeTrackingList(IList innerList) + { + if (innerList != null) + { + _innerList = innerList; + } + } + + public ChangeTrackingList(IReadOnlyList innerList) + { + if (innerList != null) + { + _innerList = innerList.ToList(); + } + } + + public bool IsUndefined => _innerList == null; + + public int Count => IsUndefined ? 0 : EnsureList().Count; + + public bool IsReadOnly => IsUndefined ? false : EnsureList().IsReadOnly; + + public T this[int index] + { + get + { + if (IsUndefined) + { + throw new ArgumentOutOfRangeException(nameof(index)); + } + return EnsureList()[index]; + } + set + { + if (IsUndefined) + { + throw new ArgumentOutOfRangeException(nameof(index)); + } + EnsureList()[index] = value; + } + } + + public void Reset() + { + _innerList = null; + } + + public IEnumerator GetEnumerator() + { + if (IsUndefined) + { + IEnumerator enumerateEmpty() + { + yield break; + } + return enumerateEmpty(); + } + return EnsureList().GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + public void Add(T item) + { + EnsureList().Add(item); + } + + public void Clear() + { + EnsureList().Clear(); + } + + public bool Contains(T item) + { + if (IsUndefined) + { + return false; + } + return EnsureList().Contains(item); + } + + public void CopyTo(T[] array, int arrayIndex) + { + if (IsUndefined) + { + return; + } + EnsureList().CopyTo(array, arrayIndex); + } + + public bool Remove(T item) + { + if (IsUndefined) + { + return false; + } + return EnsureList().Remove(item); + } + + public int IndexOf(T item) + { + if (IsUndefined) + { + return -1; + } + return EnsureList().IndexOf(item); + } + + public void Insert(int index, T item) + { + EnsureList().Insert(index, item); + } + + public void RemoveAt(int index) + { + if (IsUndefined) + { + throw new ArgumentOutOfRangeException(nameof(index)); + } + EnsureList().RemoveAt(index); + } + + public IList EnsureList() + { + return _innerList ??= new List(); + } + } +} diff --git a/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/Internal/ModelSerializationExtensions.cs b/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/Internal/ModelSerializationExtensions.cs new file mode 100644 index 000000000000..320f662b05c8 --- /dev/null +++ b/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/Internal/ModelSerializationExtensions.cs @@ -0,0 +1,398 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System; +using System.ClientModel.Primitives; +using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; +using System.Text.Json; +using System.Xml; +using Azure.Core; + +namespace Azure.Health.Deidentification +{ + internal static class ModelSerializationExtensions + { + internal static readonly ModelReaderWriterOptions WireOptions = new ModelReaderWriterOptions("W"); + + public static object GetObject(this JsonElement element) + { + switch (element.ValueKind) + { + case JsonValueKind.String: + return element.GetString(); + case JsonValueKind.Number: + if (element.TryGetInt32(out int intValue)) + { + return intValue; + } + if (element.TryGetInt64(out long longValue)) + { + return longValue; + } + return element.GetDouble(); + case JsonValueKind.True: + return true; + case JsonValueKind.False: + return false; + case JsonValueKind.Undefined: + case JsonValueKind.Null: + return null; + case JsonValueKind.Object: + var dictionary = new Dictionary(); + foreach (var jsonProperty in element.EnumerateObject()) + { + dictionary.Add(jsonProperty.Name, jsonProperty.Value.GetObject()); + } + return dictionary; + case JsonValueKind.Array: + var list = new List(); + foreach (var item in element.EnumerateArray()) + { + list.Add(item.GetObject()); + } + return list.ToArray(); + default: + throw new NotSupportedException($"Not supported value kind {element.ValueKind}"); + } + } + + public static byte[] GetBytesFromBase64(this JsonElement element, string format) + { + if (element.ValueKind == JsonValueKind.Null) + { + return null; + } + + return format switch + { + "U" => TypeFormatters.FromBase64UrlString(element.GetRequiredString()), + "D" => element.GetBytesFromBase64(), + _ => throw new ArgumentException($"Format is not supported: '{format}'", nameof(format)) + }; + } + + public static DateTimeOffset GetDateTimeOffset(this JsonElement element, string format) => format switch + { + "U" when element.ValueKind == JsonValueKind.Number => DateTimeOffset.FromUnixTimeSeconds(element.GetInt64()), + _ => TypeFormatters.ParseDateTimeOffset(element.GetString(), format) + }; + + public static TimeSpan GetTimeSpan(this JsonElement element, string format) => TypeFormatters.ParseTimeSpan(element.GetString(), format); + + public static char GetChar(this JsonElement element) + { + if (element.ValueKind == JsonValueKind.String) + { + var text = element.GetString(); + if (text == null || text.Length != 1) + { + throw new NotSupportedException($"Cannot convert \"{text}\" to a char"); + } + return text[0]; + } + else + { + throw new NotSupportedException($"Cannot convert {element.ValueKind} to a char"); + } + } + + [Conditional("DEBUG")] + public static void ThrowNonNullablePropertyIsNull(this JsonProperty property) + { + throw new JsonException($"A property '{property.Name}' defined as non-nullable but received as null from the service. This exception only happens in DEBUG builds of the library and would be ignored in the release build"); + } + + public static string GetRequiredString(this JsonElement element) + { + var value = element.GetString(); + if (value == null) + { + throw new InvalidOperationException($"The requested operation requires an element of type 'String', but the target element has type '{element.ValueKind}'."); + } + return value; + } + + public static void WriteStringValue(this Utf8JsonWriter writer, DateTimeOffset value, string format) + { + writer.WriteStringValue(TypeFormatters.ToString(value, format)); + } + + public static void WriteStringValue(this Utf8JsonWriter writer, DateTime value, string format) + { + writer.WriteStringValue(TypeFormatters.ToString(value, format)); + } + + public static void WriteStringValue(this Utf8JsonWriter writer, TimeSpan value, string format) + { + writer.WriteStringValue(TypeFormatters.ToString(value, format)); + } + + public static void WriteStringValue(this Utf8JsonWriter writer, char value) + { + writer.WriteStringValue(value.ToString(CultureInfo.InvariantCulture)); + } + + public static void WriteBase64StringValue(this Utf8JsonWriter writer, byte[] value, string format) + { + if (value == null) + { + writer.WriteNullValue(); + return; + } + switch (format) + { + case "U": + writer.WriteStringValue(TypeFormatters.ToBase64UrlString(value)); + break; + case "D": + writer.WriteBase64StringValue(value); + break; + default: + throw new ArgumentException($"Format is not supported: '{format}'", nameof(format)); + } + } + + public static void WriteNumberValue(this Utf8JsonWriter writer, DateTimeOffset value, string format) + { + if (format != "U") + { + throw new ArgumentOutOfRangeException(nameof(format), "Only 'U' format is supported when writing a DateTimeOffset as a Number."); + } + writer.WriteNumberValue(value.ToUnixTimeSeconds()); + } + + public static void WriteObjectValue(this Utf8JsonWriter writer, T value, ModelReaderWriterOptions options = null) + { + switch (value) + { + case null: + writer.WriteNullValue(); + break; + case IJsonModel jsonModel: + jsonModel.Write(writer, options ?? WireOptions); + break; + case IUtf8JsonSerializable serializable: + serializable.Write(writer); + break; + case byte[] bytes: + writer.WriteBase64StringValue(bytes); + break; + case BinaryData bytes0: + writer.WriteBase64StringValue(bytes0); + break; + case JsonElement json: + json.WriteTo(writer); + break; + case int i: + writer.WriteNumberValue(i); + break; + case decimal d: + writer.WriteNumberValue(d); + break; + case double d0: + if (double.IsNaN(d0)) + { + writer.WriteStringValue("NaN"); + } + else + { + writer.WriteNumberValue(d0); + } + break; + case float f: + writer.WriteNumberValue(f); + break; + case long l: + writer.WriteNumberValue(l); + break; + case string s: + writer.WriteStringValue(s); + break; + case bool b: + writer.WriteBooleanValue(b); + break; + case Guid g: + writer.WriteStringValue(g); + break; + case DateTimeOffset dateTimeOffset: + writer.WriteStringValue(dateTimeOffset, "O"); + break; + case DateTime dateTime: + writer.WriteStringValue(dateTime, "O"); + break; + case IEnumerable> enumerable: + writer.WriteStartObject(); + foreach (var pair in enumerable) + { + writer.WritePropertyName(pair.Key); + writer.WriteObjectValue(pair.Value, options); + } + writer.WriteEndObject(); + break; + case IEnumerable objectEnumerable: + writer.WriteStartArray(); + foreach (var item in objectEnumerable) + { + writer.WriteObjectValue(item, options); + } + writer.WriteEndArray(); + break; + case TimeSpan timeSpan: + writer.WriteStringValue(timeSpan, "P"); + break; + default: + throw new NotSupportedException($"Not supported type {value.GetType()}"); + } + } + + public static void WriteObjectValue(this Utf8JsonWriter writer, object value, ModelReaderWriterOptions options = null) + { + writer.WriteObjectValue(value, options); + } + + internal static class TypeFormatters + { + private const string RoundtripZFormat = "yyyy-MM-ddTHH:mm:ss.fffffffZ"; + public const string DefaultNumberFormat = "G"; + + public static string ToString(bool value) => value ? "true" : "false"; + + public static string ToString(DateTime value, string format) => value.Kind switch + { + DateTimeKind.Utc => ToString((DateTimeOffset)value, format), + _ => throw new NotSupportedException($"DateTime {value} has a Kind of {value.Kind}. Azure SDK requires it to be UTC. You can call DateTime.SpecifyKind to change Kind property value to DateTimeKind.Utc.") + }; + + public static string ToString(DateTimeOffset value, string format) => format switch + { + "D" => value.ToString("yyyy-MM-dd", CultureInfo.InvariantCulture), + "U" => value.ToUnixTimeSeconds().ToString(CultureInfo.InvariantCulture), + "O" => value.ToUniversalTime().ToString(RoundtripZFormat, CultureInfo.InvariantCulture), + "o" => value.ToUniversalTime().ToString(RoundtripZFormat, CultureInfo.InvariantCulture), + "R" => value.ToString("r", CultureInfo.InvariantCulture), + _ => value.ToString(format, CultureInfo.InvariantCulture) + }; + + public static string ToString(TimeSpan value, string format) => format switch + { + "P" => XmlConvert.ToString(value), + _ => value.ToString(format, CultureInfo.InvariantCulture) + }; + + public static string ToString(byte[] value, string format) => format switch + { + "U" => ToBase64UrlString(value), + "D" => Convert.ToBase64String(value), + _ => throw new ArgumentException($"Format is not supported: '{format}'", nameof(format)) + }; + + public static string ToBase64UrlString(byte[] value) + { + int numWholeOrPartialInputBlocks = checked(value.Length + 2) / 3; + int size = checked(numWholeOrPartialInputBlocks * 4); + char[] output = new char[size]; + + int numBase64Chars = Convert.ToBase64CharArray(value, 0, value.Length, output, 0); + + int i = 0; + for (; i < numBase64Chars; i++) + { + char ch = output[i]; + if (ch == '+') + { + output[i] = '-'; + } + else + { + if (ch == '/') + { + output[i] = '_'; + } + else + { + if (ch == '=') + { + break; + } + } + } + } + + return new string(output, 0, i); + } + + public static byte[] FromBase64UrlString(string value) + { + int paddingCharsToAdd = (value.Length % 4) switch + { + 0 => 0, + 2 => 2, + 3 => 1, + _ => throw new InvalidOperationException("Malformed input") + }; + char[] output = new char[(value.Length + paddingCharsToAdd)]; + int i = 0; + for (; i < value.Length; i++) + { + char ch = value[i]; + if (ch == '-') + { + output[i] = '+'; + } + else + { + if (ch == '_') + { + output[i] = '/'; + } + else + { + output[i] = ch; + } + } + } + + for (; i < output.Length; i++) + { + output[i] = '='; + } + + return Convert.FromBase64CharArray(output, 0, output.Length); + } + + public static DateTimeOffset ParseDateTimeOffset(string value, string format) => format switch + { + "U" => DateTimeOffset.FromUnixTimeSeconds(long.Parse(value, CultureInfo.InvariantCulture)), + _ => DateTimeOffset.Parse(value, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal) + }; + + public static TimeSpan ParseTimeSpan(string value, string format) => format switch + { + "P" => XmlConvert.ToTimeSpan(value), + _ => TimeSpan.ParseExact(value, format, CultureInfo.InvariantCulture) + }; + + public static string ConvertToString(object value, string format = null) => value switch + { + null => "null", + string s => s, + bool b => ToString(b), + int or float or double or long or decimal => ((IFormattable)value).ToString(DefaultNumberFormat, CultureInfo.InvariantCulture), + byte[] b0 when format != null => ToString(b0, format), + IEnumerable s0 => string.Join(",", s0), + DateTimeOffset dateTime when format != null => ToString(dateTime, format), + TimeSpan timeSpan when format != null => ToString(timeSpan, format), + TimeSpan timeSpan0 => XmlConvert.ToString(timeSpan0), + Guid guid => guid.ToString(), + BinaryData binaryData => ConvertToString(binaryData.ToArray(), format), + _ => value.ToString() + }; + } + } +} diff --git a/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/Internal/Optional.cs b/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/Internal/Optional.cs new file mode 100644 index 000000000000..a7253c7c8159 --- /dev/null +++ b/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/Internal/Optional.cs @@ -0,0 +1,51 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System.Collections.Generic; +using System.Text.Json; + +namespace Azure.Health.Deidentification +{ + internal static class Optional + { + public static bool IsCollectionDefined(IEnumerable collection) + { + return !(collection is ChangeTrackingList changeTrackingList && changeTrackingList.IsUndefined); + } + + public static bool IsCollectionDefined(IDictionary collection) + { + return !(collection is ChangeTrackingDictionary changeTrackingDictionary && changeTrackingDictionary.IsUndefined); + } + + public static bool IsCollectionDefined(IReadOnlyDictionary collection) + { + return !(collection is ChangeTrackingDictionary changeTrackingDictionary && changeTrackingDictionary.IsUndefined); + } + + public static bool IsDefined(T? value) + where T : struct + { + return value.HasValue; + } + + public static bool IsDefined(object value) + { + return value != null; + } + + public static bool IsDefined(JsonElement value) + { + return value.ValueKind != JsonValueKind.Undefined; + } + + public static bool IsDefined(string value) + { + return value != null; + } + } +} diff --git a/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/Internal/Utf8JsonRequestContent.cs b/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/Internal/Utf8JsonRequestContent.cs new file mode 100644 index 000000000000..98119f91c994 --- /dev/null +++ b/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/Internal/Utf8JsonRequestContent.cs @@ -0,0 +1,55 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System.IO; +using System.Text.Json; +using System.Threading; +using System.Threading.Tasks; +using Azure.Core; + +namespace Azure.Health.Deidentification +{ + internal class Utf8JsonRequestContent : RequestContent + { + private readonly MemoryStream _stream; + private readonly RequestContent _content; + + public Utf8JsonRequestContent() + { + _stream = new MemoryStream(); + _content = Create(_stream); + JsonWriter = new Utf8JsonWriter(_stream); + } + + public Utf8JsonWriter JsonWriter { get; } + + public override async Task WriteToAsync(Stream stream, CancellationToken cancellationToken = default) + { + await JsonWriter.FlushAsync().ConfigureAwait(false); + await _content.WriteToAsync(stream, cancellationToken).ConfigureAwait(false); + } + + public override void WriteTo(Stream stream, CancellationToken cancellationToken = default) + { + JsonWriter.Flush(); + _content.WriteTo(stream, cancellationToken); + } + + public override bool TryComputeLength(out long length) + { + length = JsonWriter.BytesCommitted + JsonWriter.BytesPending; + return true; + } + + public override void Dispose() + { + JsonWriter.Dispose(); + _content.Dispose(); + _stream.Dispose(); + } + } +} diff --git a/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/JobStatus.cs b/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/JobStatus.cs new file mode 100644 index 000000000000..8cf68d83bb1a --- /dev/null +++ b/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/JobStatus.cs @@ -0,0 +1,63 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System; +using System.ComponentModel; + +namespace Azure.Health.Deidentification +{ + /// List of statuses a job can have. + public readonly partial struct JobStatus : IEquatable + { + private readonly string _value; + + /// Initializes a new instance of . + /// is null. + public JobStatus(string value) + { + _value = value ?? throw new ArgumentNullException(nameof(value)); + } + + private const string NotStartedValue = "NotStarted"; + private const string RunningValue = "Running"; + private const string SucceededValue = "Succeeded"; + private const string PartialFailedValue = "PartialFailed"; + private const string FailedValue = "Failed"; + private const string CanceledValue = "Canceled"; + + /// Job has been submitted and is waiting to be processed. + public static JobStatus NotStarted { get; } = new JobStatus(NotStartedValue); + /// Job has been started. + public static JobStatus Running { get; } = new JobStatus(RunningValue); + /// Job has completed successfully. All documents have succeeded. + public static JobStatus Succeeded { get; } = new JobStatus(SucceededValue); + /// Job has completed with at least a single document failing. + public static JobStatus PartialFailed { get; } = new JobStatus(PartialFailedValue); + /// Job has completed with all documents failing, or a validation failure. + public static JobStatus Failed { get; } = new JobStatus(FailedValue); + /// Job has been canceled after user request. + public static JobStatus Canceled { get; } = new JobStatus(CanceledValue); + /// Determines if two values are the same. + public static bool operator ==(JobStatus left, JobStatus right) => left.Equals(right); + /// Determines if two values are not the same. + public static bool operator !=(JobStatus left, JobStatus right) => !left.Equals(right); + /// Converts a string to a . + public static implicit operator JobStatus(string value) => new JobStatus(value); + + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public override bool Equals(object obj) => obj is JobStatus other && Equals(other); + /// + public bool Equals(JobStatus other) => string.Equals(_value, other._value, StringComparison.InvariantCultureIgnoreCase); + + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public override int GetHashCode() => _value != null ? StringComparer.InvariantCultureIgnoreCase.GetHashCode(_value) : 0; + /// + public override string ToString() => _value; + } +} diff --git a/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/JobSummary.Serialization.cs b/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/JobSummary.Serialization.cs new file mode 100644 index 000000000000..4016ac264b72 --- /dev/null +++ b/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/JobSummary.Serialization.cs @@ -0,0 +1,173 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System; +using System.ClientModel.Primitives; +using System.Collections.Generic; +using System.Text.Json; +using Azure.Core; + +namespace Azure.Health.Deidentification +{ + public partial class JobSummary : IUtf8JsonSerializable, IJsonModel + { + void IUtf8JsonSerializable.Write(Utf8JsonWriter writer) => ((IJsonModel)this).Write(writer, ModelSerializationExtensions.WireOptions); + + void IJsonModel.Write(Utf8JsonWriter writer, ModelReaderWriterOptions options) + { + var format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + if (format != "J") + { + throw new FormatException($"The model {nameof(JobSummary)} does not support writing '{format}' format."); + } + + writer.WriteStartObject(); + writer.WritePropertyName("successful"u8); + writer.WriteNumberValue(Successful); + writer.WritePropertyName("failed"u8); + writer.WriteNumberValue(Failed); + writer.WritePropertyName("canceled"u8); + writer.WriteNumberValue(Canceled); + writer.WritePropertyName("total"u8); + writer.WriteNumberValue(Total); + writer.WritePropertyName("bytesProcessed"u8); + writer.WriteNumberValue(BytesProcessed); + if (options.Format != "W" && _serializedAdditionalRawData != null) + { + foreach (var item in _serializedAdditionalRawData) + { + writer.WritePropertyName(item.Key); +#if NET6_0_OR_GREATER + writer.WriteRawValue(item.Value); +#else + using (JsonDocument document = JsonDocument.Parse(item.Value)) + { + JsonSerializer.Serialize(writer, document.RootElement); + } +#endif + } + } + writer.WriteEndObject(); + } + + JobSummary IJsonModel.Create(ref Utf8JsonReader reader, ModelReaderWriterOptions options) + { + var format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + if (format != "J") + { + throw new FormatException($"The model {nameof(JobSummary)} does not support reading '{format}' format."); + } + + using JsonDocument document = JsonDocument.ParseValue(ref reader); + return DeserializeJobSummary(document.RootElement, options); + } + + internal static JobSummary DeserializeJobSummary(JsonElement element, ModelReaderWriterOptions options = null) + { + options ??= ModelSerializationExtensions.WireOptions; + + if (element.ValueKind == JsonValueKind.Null) + { + return null; + } + int successful = default; + int failed = default; + int canceled = default; + int total = default; + long bytesProcessed = default; + IDictionary serializedAdditionalRawData = default; + Dictionary rawDataDictionary = new Dictionary(); + foreach (var property in element.EnumerateObject()) + { + if (property.NameEquals("successful"u8)) + { + successful = property.Value.GetInt32(); + continue; + } + if (property.NameEquals("failed"u8)) + { + failed = property.Value.GetInt32(); + continue; + } + if (property.NameEquals("canceled"u8)) + { + canceled = property.Value.GetInt32(); + continue; + } + if (property.NameEquals("total"u8)) + { + total = property.Value.GetInt32(); + continue; + } + if (property.NameEquals("bytesProcessed"u8)) + { + bytesProcessed = property.Value.GetInt64(); + continue; + } + if (options.Format != "W") + { + rawDataDictionary.Add(property.Name, BinaryData.FromString(property.Value.GetRawText())); + } + } + serializedAdditionalRawData = rawDataDictionary; + return new JobSummary( + successful, + failed, + canceled, + total, + bytesProcessed, + serializedAdditionalRawData); + } + + BinaryData IPersistableModel.Write(ModelReaderWriterOptions options) + { + var format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + + switch (format) + { + case "J": + return ModelReaderWriter.Write(this, options); + default: + throw new FormatException($"The model {nameof(JobSummary)} does not support writing '{options.Format}' format."); + } + } + + JobSummary IPersistableModel.Create(BinaryData data, ModelReaderWriterOptions options) + { + var format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + + switch (format) + { + case "J": + { + using JsonDocument document = JsonDocument.Parse(data); + return DeserializeJobSummary(document.RootElement, options); + } + default: + throw new FormatException($"The model {nameof(JobSummary)} does not support reading '{options.Format}' format."); + } + } + + string IPersistableModel.GetFormatFromOptions(ModelReaderWriterOptions options) => "J"; + + /// Deserializes the model from a raw response. + /// The response to deserialize the model from. + internal static JobSummary FromResponse(Response response) + { + using var document = JsonDocument.Parse(response.Content); + return DeserializeJobSummary(document.RootElement); + } + + /// Convert into a . + internal virtual RequestContent ToRequestContent() + { + var content = new Utf8JsonRequestContent(); + content.JsonWriter.WriteObjectValue(this, ModelSerializationExtensions.WireOptions); + return content; + } + } +} diff --git a/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/JobSummary.cs b/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/JobSummary.cs new file mode 100644 index 000000000000..b92ca749c320 --- /dev/null +++ b/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/JobSummary.cs @@ -0,0 +1,96 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System; +using System.Collections.Generic; + +namespace Azure.Health.Deidentification +{ + /// Summary metrics of a job. + public partial class JobSummary + { + /// + /// Keeps track of any properties unknown to the library. + /// + /// To assign an object to the value of this property use . + /// + /// + /// To assign an already formatted json string to this property use . + /// + /// + /// Examples: + /// + /// + /// BinaryData.FromObjectAsJson("foo") + /// Creates a payload of "foo". + /// + /// + /// BinaryData.FromString("\"foo\"") + /// Creates a payload of "foo". + /// + /// + /// BinaryData.FromObjectAsJson(new { key = "value" }) + /// Creates a payload of { "key": "value" }. + /// + /// + /// BinaryData.FromString("{\"key\": \"value\"}") + /// Creates a payload of { "key": "value" }. + /// + /// + /// + /// + private IDictionary _serializedAdditionalRawData; + + /// Initializes a new instance of . + /// Number of documents that have completed. + /// Number of documents that have failed. + /// Number of documents that have been canceled. + /// Number of documents total. + /// Number of bytes processed. + internal JobSummary(int successful, int failed, int canceled, int total, long bytesProcessed) + { + Successful = successful; + Failed = failed; + Canceled = canceled; + Total = total; + BytesProcessed = bytesProcessed; + } + + /// Initializes a new instance of . + /// Number of documents that have completed. + /// Number of documents that have failed. + /// Number of documents that have been canceled. + /// Number of documents total. + /// Number of bytes processed. + /// Keeps track of any properties unknown to the library. + internal JobSummary(int successful, int failed, int canceled, int total, long bytesProcessed, IDictionary serializedAdditionalRawData) + { + Successful = successful; + Failed = failed; + Canceled = canceled; + Total = total; + BytesProcessed = bytesProcessed; + _serializedAdditionalRawData = serializedAdditionalRawData; + } + + /// Initializes a new instance of for deserialization. + internal JobSummary() + { + } + + /// Number of documents that have completed. + public int Successful { get; } + /// Number of documents that have failed. + public int Failed { get; } + /// Number of documents that have been canceled. + public int Canceled { get; } + /// Number of documents total. + public int Total { get; } + /// Number of bytes processed. + public long BytesProcessed { get; } + } +} diff --git a/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/OperationState.cs b/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/OperationState.cs new file mode 100644 index 000000000000..62039d7bbd7b --- /dev/null +++ b/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/OperationState.cs @@ -0,0 +1,60 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System; +using System.ComponentModel; + +namespace Azure.Health.Deidentification +{ + /// Enum describing allowed operation states. + public readonly partial struct OperationState : IEquatable + { + private readonly string _value; + + /// Initializes a new instance of . + /// is null. + public OperationState(string value) + { + _value = value ?? throw new ArgumentNullException(nameof(value)); + } + + private const string NotStartedValue = "NotStarted"; + private const string RunningValue = "Running"; + private const string SucceededValue = "Succeeded"; + private const string FailedValue = "Failed"; + private const string CanceledValue = "Canceled"; + + /// The operation has not started. + public static OperationState NotStarted { get; } = new OperationState(NotStartedValue); + /// The operation is in progress. + public static OperationState Running { get; } = new OperationState(RunningValue); + /// The operation has completed successfully. + public static OperationState Succeeded { get; } = new OperationState(SucceededValue); + /// The operation has failed. + public static OperationState Failed { get; } = new OperationState(FailedValue); + /// The operation has been canceled by the user. + public static OperationState Canceled { get; } = new OperationState(CanceledValue); + /// Determines if two values are the same. + public static bool operator ==(OperationState left, OperationState right) => left.Equals(right); + /// Determines if two values are not the same. + public static bool operator !=(OperationState left, OperationState right) => !left.Equals(right); + /// Converts a string to a . + public static implicit operator OperationState(string value) => new OperationState(value); + + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public override bool Equals(object obj) => obj is OperationState other && Equals(other); + /// + public bool Equals(OperationState other) => string.Equals(_value, other._value, StringComparison.InvariantCultureIgnoreCase); + + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public override int GetHashCode() => _value != null ? StringComparer.InvariantCultureIgnoreCase.GetHashCode(_value) : 0; + /// + public override string ToString() => _value; + } +} diff --git a/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/OperationType.cs b/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/OperationType.cs new file mode 100644 index 000000000000..ee1dbdfae04c --- /dev/null +++ b/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/OperationType.cs @@ -0,0 +1,54 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System; +using System.ComponentModel; + +namespace Azure.Health.Deidentification +{ + /// Enum of supported Operation Types. + public readonly partial struct OperationType : IEquatable + { + private readonly string _value; + + /// Initializes a new instance of . + /// is null. + public OperationType(string value) + { + _value = value ?? throw new ArgumentNullException(nameof(value)); + } + + private const string RedactValue = "Redact"; + private const string SurrogateValue = "Surrogate"; + private const string TagValue = "Tag"; + + /// Redact Operation will remove all entities of PHI and replace them with a placeholder value. + public static OperationType Redact { get; } = new OperationType(RedactValue); + /// Surrogation Operation will replace all entities of PHI with a surrogate value. + public static OperationType Surrogate { get; } = new OperationType(SurrogateValue); + /// Tag Operation will detect all entities of PHI, their type, and return their locations in the document. + public static OperationType Tag { get; } = new OperationType(TagValue); + /// Determines if two values are the same. + public static bool operator ==(OperationType left, OperationType right) => left.Equals(right); + /// Determines if two values are not the same. + public static bool operator !=(OperationType left, OperationType right) => !left.Equals(right); + /// Converts a string to a . + public static implicit operator OperationType(string value) => new OperationType(value); + + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public override bool Equals(object obj) => obj is OperationType other && Equals(other); + /// + public bool Equals(OperationType other) => string.Equals(_value, other._value, StringComparison.InvariantCultureIgnoreCase); + + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public override int GetHashCode() => _value != null ? StringComparer.InvariantCultureIgnoreCase.GetHashCode(_value) : 0; + /// + public override string ToString() => _value; + } +} diff --git a/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/PhiCategory.cs b/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/PhiCategory.cs new file mode 100644 index 000000000000..86cef024116b --- /dev/null +++ b/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/PhiCategory.cs @@ -0,0 +1,132 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System; +using System.ComponentModel; + +namespace Azure.Health.Deidentification +{ + /// List of PHI Entities. + public readonly partial struct PhiCategory : IEquatable + { + private readonly string _value; + + /// Initializes a new instance of . + /// is null. + public PhiCategory(string value) + { + _value = value ?? throw new ArgumentNullException(nameof(value)); + } + + private const string UnknownValue = "Unknown"; + private const string AccountValue = "Account"; + private const string AgeValue = "Age"; + private const string BioIDValue = "BioID"; + private const string CityValue = "City"; + private const string CountryOrRegionValue = "CountryOrRegion"; + private const string DateValue = "Date"; + private const string DeviceValue = "Device"; + private const string DoctorValue = "Doctor"; + private const string EmailValue = "Email"; + private const string FaxValue = "Fax"; + private const string HealthPlanValue = "HealthPlan"; + private const string HospitalValue = "Hospital"; + private const string IDNumValue = "IDNum"; + private const string IPAddressValue = "IPAddress"; + private const string LicenseValue = "License"; + private const string LocationOtherValue = "LocationOther"; + private const string MedicalRecordValue = "MedicalRecord"; + private const string OrganizationValue = "Organization"; + private const string PatientValue = "Patient"; + private const string PhoneValue = "Phone"; + private const string ProfessionValue = "Profession"; + private const string SocialSecurityValue = "SocialSecurity"; + private const string StateValue = "State"; + private const string StreetValue = "Street"; + private const string UrlValue = "Url"; + private const string UsernameValue = "Username"; + private const string VehicleValue = "Vehicle"; + private const string ZipValue = "Zip"; + + /// Unknown PHI Type. + public static PhiCategory Unknown { get; } = new PhiCategory(UnknownValue); + /// Account Number. + public static PhiCategory Account { get; } = new PhiCategory(AccountValue); + /// Age. + public static PhiCategory Age { get; } = new PhiCategory(AgeValue); + /// Biological Identifier, such as a fingerprint or retinal scan. + public static PhiCategory BioID { get; } = new PhiCategory(BioIDValue); + /// City. + public static PhiCategory City { get; } = new PhiCategory(CityValue); + /// Country or Region. + public static PhiCategory CountryOrRegion { get; } = new PhiCategory(CountryOrRegionValue); + /// Date. + public static PhiCategory Date { get; } = new PhiCategory(DateValue); + /// Device ID or serial numbers. + public static PhiCategory Device { get; } = new PhiCategory(DeviceValue); + /// Doctor's Name. + public static PhiCategory Doctor { get; } = new PhiCategory(DoctorValue); + /// Email Addresses. + public static PhiCategory Email { get; } = new PhiCategory(EmailValue); + /// Fax Number. + public static PhiCategory Fax { get; } = new PhiCategory(FaxValue); + /// Health Plan ID Numbers. + public static PhiCategory HealthPlan { get; } = new PhiCategory(HealthPlanValue); + /// Hospital Name. + public static PhiCategory Hospital { get; } = new PhiCategory(HospitalValue); + /// Id Number, eg. passport number. + public static PhiCategory IDNum { get; } = new PhiCategory(IDNumValue); + /// IP Address. + public static PhiCategory IPAddress { get; } = new PhiCategory(IPAddressValue); + /// License, eg. Driver's license or medical license. + public static PhiCategory License { get; } = new PhiCategory(LicenseValue); + /// Location Other, eg. Golden Gate Park. + public static PhiCategory LocationOther { get; } = new PhiCategory(LocationOtherValue); + /// Medical Record Number. + public static PhiCategory MedicalRecord { get; } = new PhiCategory(MedicalRecordValue); + /// Organization, eg. Microsoft. + public static PhiCategory Organization { get; } = new PhiCategory(OrganizationValue); + /// Patient Name. + public static PhiCategory Patient { get; } = new PhiCategory(PatientValue); + /// Phone Number. + public static PhiCategory Phone { get; } = new PhiCategory(PhoneValue); + /// Profession. + public static PhiCategory Profession { get; } = new PhiCategory(ProfessionValue); + /// Social Security Number. + public static PhiCategory SocialSecurity { get; } = new PhiCategory(SocialSecurityValue); + /// State. + public static PhiCategory State { get; } = new PhiCategory(StateValue); + /// Street. + public static PhiCategory Street { get; } = new PhiCategory(StreetValue); + /// Web URL. + public static PhiCategory Url { get; } = new PhiCategory(UrlValue); + /// Usernames, eg. a social media handle. + public static PhiCategory Username { get; } = new PhiCategory(UsernameValue); + /// Vehicle IDs, eg. license plate or VIN number. + public static PhiCategory Vehicle { get; } = new PhiCategory(VehicleValue); + /// Zip Code. + public static PhiCategory Zip { get; } = new PhiCategory(ZipValue); + /// Determines if two values are the same. + public static bool operator ==(PhiCategory left, PhiCategory right) => left.Equals(right); + /// Determines if two values are not the same. + public static bool operator !=(PhiCategory left, PhiCategory right) => !left.Equals(right); + /// Converts a string to a . + public static implicit operator PhiCategory(string value) => new PhiCategory(value); + + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public override bool Equals(object obj) => obj is PhiCategory other && Equals(other); + /// + public bool Equals(PhiCategory other) => string.Equals(_value, other._value, StringComparison.InvariantCultureIgnoreCase); + + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public override int GetHashCode() => _value != null ? StringComparer.InvariantCultureIgnoreCase.GetHashCode(_value) : 0; + /// + public override string ToString() => _value; + } +} diff --git a/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/PhiEntity.Serialization.cs b/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/PhiEntity.Serialization.cs new file mode 100644 index 000000000000..9a58cb17d15c --- /dev/null +++ b/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/PhiEntity.Serialization.cs @@ -0,0 +1,183 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System; +using System.ClientModel.Primitives; +using System.Collections.Generic; +using System.Text.Json; +using Azure.Core; + +namespace Azure.Health.Deidentification +{ + public partial class PhiEntity : IUtf8JsonSerializable, IJsonModel + { + void IUtf8JsonSerializable.Write(Utf8JsonWriter writer) => ((IJsonModel)this).Write(writer, ModelSerializationExtensions.WireOptions); + + void IJsonModel.Write(Utf8JsonWriter writer, ModelReaderWriterOptions options) + { + var format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + if (format != "J") + { + throw new FormatException($"The model {nameof(PhiEntity)} does not support writing '{format}' format."); + } + + writer.WriteStartObject(); + writer.WritePropertyName("category"u8); + writer.WriteStringValue(Category.ToString()); + writer.WritePropertyName("offset"u8); + writer.WriteObjectValue(Offset, options); + writer.WritePropertyName("length"u8); + writer.WriteObjectValue(Length, options); + if (Optional.IsDefined(Text)) + { + writer.WritePropertyName("text"u8); + writer.WriteStringValue(Text); + } + if (Optional.IsDefined(ConfidenceScore)) + { + writer.WritePropertyName("confidenceScore"u8); + writer.WriteNumberValue(ConfidenceScore.Value); + } + if (options.Format != "W" && _serializedAdditionalRawData != null) + { + foreach (var item in _serializedAdditionalRawData) + { + writer.WritePropertyName(item.Key); +#if NET6_0_OR_GREATER + writer.WriteRawValue(item.Value); +#else + using (JsonDocument document = JsonDocument.Parse(item.Value)) + { + JsonSerializer.Serialize(writer, document.RootElement); + } +#endif + } + } + writer.WriteEndObject(); + } + + PhiEntity IJsonModel.Create(ref Utf8JsonReader reader, ModelReaderWriterOptions options) + { + var format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + if (format != "J") + { + throw new FormatException($"The model {nameof(PhiEntity)} does not support reading '{format}' format."); + } + + using JsonDocument document = JsonDocument.ParseValue(ref reader); + return DeserializePhiEntity(document.RootElement, options); + } + + internal static PhiEntity DeserializePhiEntity(JsonElement element, ModelReaderWriterOptions options = null) + { + options ??= ModelSerializationExtensions.WireOptions; + + if (element.ValueKind == JsonValueKind.Null) + { + return null; + } + PhiCategory category = default; + StringIndex offset = default; + StringIndex length = default; + string text = default; + double? confidenceScore = default; + IDictionary serializedAdditionalRawData = default; + Dictionary rawDataDictionary = new Dictionary(); + foreach (var property in element.EnumerateObject()) + { + if (property.NameEquals("category"u8)) + { + category = new PhiCategory(property.Value.GetString()); + continue; + } + if (property.NameEquals("offset"u8)) + { + offset = StringIndex.DeserializeStringIndex(property.Value, options); + continue; + } + if (property.NameEquals("length"u8)) + { + length = StringIndex.DeserializeStringIndex(property.Value, options); + continue; + } + if (property.NameEquals("text"u8)) + { + text = property.Value.GetString(); + continue; + } + if (property.NameEquals("confidenceScore"u8)) + { + if (property.Value.ValueKind == JsonValueKind.Null) + { + continue; + } + confidenceScore = property.Value.GetDouble(); + continue; + } + if (options.Format != "W") + { + rawDataDictionary.Add(property.Name, BinaryData.FromString(property.Value.GetRawText())); + } + } + serializedAdditionalRawData = rawDataDictionary; + return new PhiEntity( + category, + offset, + length, + text, + confidenceScore, + serializedAdditionalRawData); + } + + BinaryData IPersistableModel.Write(ModelReaderWriterOptions options) + { + var format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + + switch (format) + { + case "J": + return ModelReaderWriter.Write(this, options); + default: + throw new FormatException($"The model {nameof(PhiEntity)} does not support writing '{options.Format}' format."); + } + } + + PhiEntity IPersistableModel.Create(BinaryData data, ModelReaderWriterOptions options) + { + var format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + + switch (format) + { + case "J": + { + using JsonDocument document = JsonDocument.Parse(data); + return DeserializePhiEntity(document.RootElement, options); + } + default: + throw new FormatException($"The model {nameof(PhiEntity)} does not support reading '{options.Format}' format."); + } + } + + string IPersistableModel.GetFormatFromOptions(ModelReaderWriterOptions options) => "J"; + + /// Deserializes the model from a raw response. + /// The response to deserialize the model from. + internal static PhiEntity FromResponse(Response response) + { + using var document = JsonDocument.Parse(response.Content); + return DeserializePhiEntity(document.RootElement); + } + + /// Convert into a . + internal virtual RequestContent ToRequestContent() + { + var content = new Utf8JsonRequestContent(); + content.JsonWriter.WriteObjectValue(this, ModelSerializationExtensions.WireOptions); + return content; + } + } +} diff --git a/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/PhiEntity.cs b/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/PhiEntity.cs new file mode 100644 index 000000000000..47156ed1bada --- /dev/null +++ b/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/PhiEntity.cs @@ -0,0 +1,96 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System; +using System.Collections.Generic; + +namespace Azure.Health.Deidentification +{ + /// PHI Entity tag in the input. + public partial class PhiEntity + { + /// + /// Keeps track of any properties unknown to the library. + /// + /// To assign an object to the value of this property use . + /// + /// + /// To assign an already formatted json string to this property use . + /// + /// + /// Examples: + /// + /// + /// BinaryData.FromObjectAsJson("foo") + /// Creates a payload of "foo". + /// + /// + /// BinaryData.FromString("\"foo\"") + /// Creates a payload of "foo". + /// + /// + /// BinaryData.FromObjectAsJson(new { key = "value" }) + /// Creates a payload of { "key": "value" }. + /// + /// + /// BinaryData.FromString("{\"key\": \"value\"}") + /// Creates a payload of { "key": "value" }. + /// + /// + /// + /// + private IDictionary _serializedAdditionalRawData; + + /// Initializes a new instance of . + /// PHI Category of the entity. + /// Starting index of the location from within the input text. + /// Length of the input text. + /// or is null. + internal PhiEntity(PhiCategory category, StringIndex offset, StringIndex length) + { + Argument.AssertNotNull(offset, nameof(offset)); + Argument.AssertNotNull(length, nameof(length)); + + Category = category; + Offset = offset; + Length = length; + } + + /// Initializes a new instance of . + /// PHI Category of the entity. + /// Starting index of the location from within the input text. + /// Length of the input text. + /// Text of the entity. + /// Confidence score of the category match. + /// Keeps track of any properties unknown to the library. + internal PhiEntity(PhiCategory category, StringIndex offset, StringIndex length, string text, double? confidenceScore, IDictionary serializedAdditionalRawData) + { + Category = category; + Offset = offset; + Length = length; + Text = text; + ConfidenceScore = confidenceScore; + _serializedAdditionalRawData = serializedAdditionalRawData; + } + + /// Initializes a new instance of for deserialization. + internal PhiEntity() + { + } + + /// PHI Category of the entity. + public PhiCategory Category { get; } + /// Starting index of the location from within the input text. + public StringIndex Offset { get; } + /// Length of the input text. + public StringIndex Length { get; } + /// Text of the entity. + public string Text { get; } + /// Confidence score of the category match. + public double? ConfidenceScore { get; } + } +} diff --git a/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/PhiTaggerResult.Serialization.cs b/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/PhiTaggerResult.Serialization.cs new file mode 100644 index 000000000000..18cc9d1290a2 --- /dev/null +++ b/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/PhiTaggerResult.Serialization.cs @@ -0,0 +1,171 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System; +using System.ClientModel.Primitives; +using System.Collections.Generic; +using System.Text.Json; +using Azure.Core; + +namespace Azure.Health.Deidentification +{ + public partial class PhiTaggerResult : IUtf8JsonSerializable, IJsonModel + { + void IUtf8JsonSerializable.Write(Utf8JsonWriter writer) => ((IJsonModel)this).Write(writer, ModelSerializationExtensions.WireOptions); + + void IJsonModel.Write(Utf8JsonWriter writer, ModelReaderWriterOptions options) + { + var format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + if (format != "J") + { + throw new FormatException($"The model {nameof(PhiTaggerResult)} does not support writing '{format}' format."); + } + + writer.WriteStartObject(); + writer.WritePropertyName("entities"u8); + writer.WriteStartArray(); + foreach (var item in Entities) + { + writer.WriteObjectValue(item, options); + } + writer.WriteEndArray(); + if (Optional.IsDefined(Path)) + { + writer.WritePropertyName("path"u8); + writer.WriteStringValue(Path); + } + if (Optional.IsDefined(Etag)) + { + writer.WritePropertyName("etag"u8); + writer.WriteStringValue(Etag.Value.ToString()); + } + if (options.Format != "W" && _serializedAdditionalRawData != null) + { + foreach (var item in _serializedAdditionalRawData) + { + writer.WritePropertyName(item.Key); +#if NET6_0_OR_GREATER + writer.WriteRawValue(item.Value); +#else + using (JsonDocument document = JsonDocument.Parse(item.Value)) + { + JsonSerializer.Serialize(writer, document.RootElement); + } +#endif + } + } + writer.WriteEndObject(); + } + + PhiTaggerResult IJsonModel.Create(ref Utf8JsonReader reader, ModelReaderWriterOptions options) + { + var format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + if (format != "J") + { + throw new FormatException($"The model {nameof(PhiTaggerResult)} does not support reading '{format}' format."); + } + + using JsonDocument document = JsonDocument.ParseValue(ref reader); + return DeserializePhiTaggerResult(document.RootElement, options); + } + + internal static PhiTaggerResult DeserializePhiTaggerResult(JsonElement element, ModelReaderWriterOptions options = null) + { + options ??= ModelSerializationExtensions.WireOptions; + + if (element.ValueKind == JsonValueKind.Null) + { + return null; + } + IReadOnlyList entities = default; + string path = default; + ETag? etag = default; + IDictionary serializedAdditionalRawData = default; + Dictionary rawDataDictionary = new Dictionary(); + foreach (var property in element.EnumerateObject()) + { + if (property.NameEquals("entities"u8)) + { + List array = new List(); + foreach (var item in property.Value.EnumerateArray()) + { + array.Add(PhiEntity.DeserializePhiEntity(item, options)); + } + entities = array; + continue; + } + if (property.NameEquals("path"u8)) + { + path = property.Value.GetString(); + continue; + } + if (property.NameEquals("etag"u8)) + { + if (property.Value.ValueKind == JsonValueKind.Null) + { + continue; + } + etag = new ETag(property.Value.GetString()); + continue; + } + if (options.Format != "W") + { + rawDataDictionary.Add(property.Name, BinaryData.FromString(property.Value.GetRawText())); + } + } + serializedAdditionalRawData = rawDataDictionary; + return new PhiTaggerResult(entities, path, etag, serializedAdditionalRawData); + } + + BinaryData IPersistableModel.Write(ModelReaderWriterOptions options) + { + var format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + + switch (format) + { + case "J": + return ModelReaderWriter.Write(this, options); + default: + throw new FormatException($"The model {nameof(PhiTaggerResult)} does not support writing '{options.Format}' format."); + } + } + + PhiTaggerResult IPersistableModel.Create(BinaryData data, ModelReaderWriterOptions options) + { + var format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + + switch (format) + { + case "J": + { + using JsonDocument document = JsonDocument.Parse(data); + return DeserializePhiTaggerResult(document.RootElement, options); + } + default: + throw new FormatException($"The model {nameof(PhiTaggerResult)} does not support reading '{options.Format}' format."); + } + } + + string IPersistableModel.GetFormatFromOptions(ModelReaderWriterOptions options) => "J"; + + /// Deserializes the model from a raw response. + /// The response to deserialize the model from. + internal static PhiTaggerResult FromResponse(Response response) + { + using var document = JsonDocument.Parse(response.Content); + return DeserializePhiTaggerResult(document.RootElement); + } + + /// Convert into a . + internal virtual RequestContent ToRequestContent() + { + var content = new Utf8JsonRequestContent(); + content.JsonWriter.WriteObjectValue(this, ModelSerializationExtensions.WireOptions); + return content; + } + } +} diff --git a/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/PhiTaggerResult.cs b/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/PhiTaggerResult.cs new file mode 100644 index 000000000000..8650addf15ca --- /dev/null +++ b/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/PhiTaggerResult.cs @@ -0,0 +1,84 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Azure.Health.Deidentification +{ + /// Result of the "Tag" operation. + public partial class PhiTaggerResult + { + /// + /// Keeps track of any properties unknown to the library. + /// + /// To assign an object to the value of this property use . + /// + /// + /// To assign an already formatted json string to this property use . + /// + /// + /// Examples: + /// + /// + /// BinaryData.FromObjectAsJson("foo") + /// Creates a payload of "foo". + /// + /// + /// BinaryData.FromString("\"foo\"") + /// Creates a payload of "foo". + /// + /// + /// BinaryData.FromObjectAsJson(new { key = "value" }) + /// Creates a payload of { "key": "value" }. + /// + /// + /// BinaryData.FromString("{\"key\": \"value\"}") + /// Creates a payload of { "key": "value" }. + /// + /// + /// + /// + private IDictionary _serializedAdditionalRawData; + + /// Initializes a new instance of . + /// List of entities detected in the input. + /// is null. + internal PhiTaggerResult(IEnumerable entities) + { + Argument.AssertNotNull(entities, nameof(entities)); + + Entities = entities.ToList(); + } + + /// Initializes a new instance of . + /// List of entities detected in the input. + /// Path to the document in storage. + /// The entity tag for this resource. + /// Keeps track of any properties unknown to the library. + internal PhiTaggerResult(IReadOnlyList entities, string path, ETag? etag, IDictionary serializedAdditionalRawData) + { + Entities = entities; + Path = path; + Etag = etag; + _serializedAdditionalRawData = serializedAdditionalRawData; + } + + /// Initializes a new instance of for deserialization. + internal PhiTaggerResult() + { + } + + /// List of entities detected in the input. + public IReadOnlyList Entities { get; } + /// Path to the document in storage. + public string Path { get; } + /// The entity tag for this resource. + public ETag? Etag { get; } + } +} diff --git a/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/SourceStorageLocation.Serialization.cs b/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/SourceStorageLocation.Serialization.cs new file mode 100644 index 000000000000..7c9825395b51 --- /dev/null +++ b/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/SourceStorageLocation.Serialization.cs @@ -0,0 +1,168 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System; +using System.ClientModel.Primitives; +using System.Collections.Generic; +using System.Text.Json; +using Azure.Core; + +namespace Azure.Health.Deidentification +{ + public partial class SourceStorageLocation : IUtf8JsonSerializable, IJsonModel + { + void IUtf8JsonSerializable.Write(Utf8JsonWriter writer) => ((IJsonModel)this).Write(writer, ModelSerializationExtensions.WireOptions); + + void IJsonModel.Write(Utf8JsonWriter writer, ModelReaderWriterOptions options) + { + var format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + if (format != "J") + { + throw new FormatException($"The model {nameof(SourceStorageLocation)} does not support writing '{format}' format."); + } + + writer.WriteStartObject(); + writer.WritePropertyName("location"u8); + writer.WriteStringValue(Location.AbsoluteUri); + writer.WritePropertyName("prefix"u8); + writer.WriteStringValue(Prefix); + if (Optional.IsCollectionDefined(Extensions)) + { + writer.WritePropertyName("extensions"u8); + writer.WriteStartArray(); + foreach (var item in Extensions) + { + writer.WriteStringValue(item); + } + writer.WriteEndArray(); + } + if (options.Format != "W" && _serializedAdditionalRawData != null) + { + foreach (var item in _serializedAdditionalRawData) + { + writer.WritePropertyName(item.Key); +#if NET6_0_OR_GREATER + writer.WriteRawValue(item.Value); +#else + using (JsonDocument document = JsonDocument.Parse(item.Value)) + { + JsonSerializer.Serialize(writer, document.RootElement); + } +#endif + } + } + writer.WriteEndObject(); + } + + SourceStorageLocation IJsonModel.Create(ref Utf8JsonReader reader, ModelReaderWriterOptions options) + { + var format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + if (format != "J") + { + throw new FormatException($"The model {nameof(SourceStorageLocation)} does not support reading '{format}' format."); + } + + using JsonDocument document = JsonDocument.ParseValue(ref reader); + return DeserializeSourceStorageLocation(document.RootElement, options); + } + + internal static SourceStorageLocation DeserializeSourceStorageLocation(JsonElement element, ModelReaderWriterOptions options = null) + { + options ??= ModelSerializationExtensions.WireOptions; + + if (element.ValueKind == JsonValueKind.Null) + { + return null; + } + Uri location = default; + string prefix = default; + IList extensions = default; + IDictionary serializedAdditionalRawData = default; + Dictionary rawDataDictionary = new Dictionary(); + foreach (var property in element.EnumerateObject()) + { + if (property.NameEquals("location"u8)) + { + location = new Uri(property.Value.GetString()); + continue; + } + if (property.NameEquals("prefix"u8)) + { + prefix = property.Value.GetString(); + continue; + } + if (property.NameEquals("extensions"u8)) + { + if (property.Value.ValueKind == JsonValueKind.Null) + { + continue; + } + List array = new List(); + foreach (var item in property.Value.EnumerateArray()) + { + array.Add(item.GetString()); + } + extensions = array; + continue; + } + if (options.Format != "W") + { + rawDataDictionary.Add(property.Name, BinaryData.FromString(property.Value.GetRawText())); + } + } + serializedAdditionalRawData = rawDataDictionary; + return new SourceStorageLocation(location, prefix, extensions ?? new ChangeTrackingList(), serializedAdditionalRawData); + } + + BinaryData IPersistableModel.Write(ModelReaderWriterOptions options) + { + var format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + + switch (format) + { + case "J": + return ModelReaderWriter.Write(this, options); + default: + throw new FormatException($"The model {nameof(SourceStorageLocation)} does not support writing '{options.Format}' format."); + } + } + + SourceStorageLocation IPersistableModel.Create(BinaryData data, ModelReaderWriterOptions options) + { + var format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + + switch (format) + { + case "J": + { + using JsonDocument document = JsonDocument.Parse(data); + return DeserializeSourceStorageLocation(document.RootElement, options); + } + default: + throw new FormatException($"The model {nameof(SourceStorageLocation)} does not support reading '{options.Format}' format."); + } + } + + string IPersistableModel.GetFormatFromOptions(ModelReaderWriterOptions options) => "J"; + + /// Deserializes the model from a raw response. + /// The response to deserialize the model from. + internal static SourceStorageLocation FromResponse(Response response) + { + using var document = JsonDocument.Parse(response.Content); + return DeserializeSourceStorageLocation(document.RootElement); + } + + /// Convert into a . + internal virtual RequestContent ToRequestContent() + { + var content = new Utf8JsonRequestContent(); + content.JsonWriter.WriteObjectValue(this, ModelSerializationExtensions.WireOptions); + return content; + } + } +} diff --git a/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/SourceStorageLocation.cs b/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/SourceStorageLocation.cs new file mode 100644 index 000000000000..02d06ed883e3 --- /dev/null +++ b/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/SourceStorageLocation.cs @@ -0,0 +1,87 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System; +using System.Collections.Generic; + +namespace Azure.Health.Deidentification +{ + /// Storage location. + public partial class SourceStorageLocation + { + /// + /// Keeps track of any properties unknown to the library. + /// + /// To assign an object to the value of this property use . + /// + /// + /// To assign an already formatted json string to this property use . + /// + /// + /// Examples: + /// + /// + /// BinaryData.FromObjectAsJson("foo") + /// Creates a payload of "foo". + /// + /// + /// BinaryData.FromString("\"foo\"") + /// Creates a payload of "foo". + /// + /// + /// BinaryData.FromObjectAsJson(new { key = "value" }) + /// Creates a payload of { "key": "value" }. + /// + /// + /// BinaryData.FromString("{\"key\": \"value\"}") + /// Creates a payload of { "key": "value" }. + /// + /// + /// + /// + private IDictionary _serializedAdditionalRawData; + + /// Initializes a new instance of . + /// URL to storage location. + /// Prefix to filter path by. + /// or is null. + public SourceStorageLocation(Uri location, string prefix) + { + Argument.AssertNotNull(location, nameof(location)); + Argument.AssertNotNull(prefix, nameof(prefix)); + + Location = location; + Prefix = prefix; + Extensions = new ChangeTrackingList(); + } + + /// Initializes a new instance of . + /// URL to storage location. + /// Prefix to filter path by. + /// List of extensions to filter path by. + /// Keeps track of any properties unknown to the library. + internal SourceStorageLocation(Uri location, string prefix, IList extensions, IDictionary serializedAdditionalRawData) + { + Location = location; + Prefix = prefix; + Extensions = extensions; + _serializedAdditionalRawData = serializedAdditionalRawData; + } + + /// Initializes a new instance of for deserialization. + internal SourceStorageLocation() + { + } + + /// URL to storage location. + public Uri Location { get; set; } + /// Prefix to filter path by. + public string Prefix { get; set; } + /// List of extensions to filter path by. + public IList Extensions { get; } + } +} diff --git a/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/StringIndex.Serialization.cs b/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/StringIndex.Serialization.cs new file mode 100644 index 000000000000..df3564cf7471 --- /dev/null +++ b/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/StringIndex.Serialization.cs @@ -0,0 +1,151 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System; +using System.ClientModel.Primitives; +using System.Collections.Generic; +using System.Text.Json; +using Azure.Core; + +namespace Azure.Health.Deidentification +{ + public partial class StringIndex : IUtf8JsonSerializable, IJsonModel + { + void IUtf8JsonSerializable.Write(Utf8JsonWriter writer) => ((IJsonModel)this).Write(writer, ModelSerializationExtensions.WireOptions); + + void IJsonModel.Write(Utf8JsonWriter writer, ModelReaderWriterOptions options) + { + var format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + if (format != "J") + { + throw new FormatException($"The model {nameof(StringIndex)} does not support writing '{format}' format."); + } + + writer.WriteStartObject(); + writer.WritePropertyName("utf8"u8); + writer.WriteNumberValue(Utf8); + writer.WritePropertyName("utf16"u8); + writer.WriteNumberValue(Utf16); + writer.WritePropertyName("codePoint"u8); + writer.WriteNumberValue(CodePoint); + if (options.Format != "W" && _serializedAdditionalRawData != null) + { + foreach (var item in _serializedAdditionalRawData) + { + writer.WritePropertyName(item.Key); +#if NET6_0_OR_GREATER + writer.WriteRawValue(item.Value); +#else + using (JsonDocument document = JsonDocument.Parse(item.Value)) + { + JsonSerializer.Serialize(writer, document.RootElement); + } +#endif + } + } + writer.WriteEndObject(); + } + + StringIndex IJsonModel.Create(ref Utf8JsonReader reader, ModelReaderWriterOptions options) + { + var format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + if (format != "J") + { + throw new FormatException($"The model {nameof(StringIndex)} does not support reading '{format}' format."); + } + + using JsonDocument document = JsonDocument.ParseValue(ref reader); + return DeserializeStringIndex(document.RootElement, options); + } + + internal static StringIndex DeserializeStringIndex(JsonElement element, ModelReaderWriterOptions options = null) + { + options ??= ModelSerializationExtensions.WireOptions; + + if (element.ValueKind == JsonValueKind.Null) + { + return null; + } + int utf8 = default; + int utf16 = default; + int codePoint = default; + IDictionary serializedAdditionalRawData = default; + Dictionary rawDataDictionary = new Dictionary(); + foreach (var property in element.EnumerateObject()) + { + if (property.NameEquals("utf8"u8)) + { + utf8 = property.Value.GetInt32(); + continue; + } + if (property.NameEquals("utf16"u8)) + { + utf16 = property.Value.GetInt32(); + continue; + } + if (property.NameEquals("codePoint"u8)) + { + codePoint = property.Value.GetInt32(); + continue; + } + if (options.Format != "W") + { + rawDataDictionary.Add(property.Name, BinaryData.FromString(property.Value.GetRawText())); + } + } + serializedAdditionalRawData = rawDataDictionary; + return new StringIndex(utf8, utf16, codePoint, serializedAdditionalRawData); + } + + BinaryData IPersistableModel.Write(ModelReaderWriterOptions options) + { + var format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + + switch (format) + { + case "J": + return ModelReaderWriter.Write(this, options); + default: + throw new FormatException($"The model {nameof(StringIndex)} does not support writing '{options.Format}' format."); + } + } + + StringIndex IPersistableModel.Create(BinaryData data, ModelReaderWriterOptions options) + { + var format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + + switch (format) + { + case "J": + { + using JsonDocument document = JsonDocument.Parse(data); + return DeserializeStringIndex(document.RootElement, options); + } + default: + throw new FormatException($"The model {nameof(StringIndex)} does not support reading '{options.Format}' format."); + } + } + + string IPersistableModel.GetFormatFromOptions(ModelReaderWriterOptions options) => "J"; + + /// Deserializes the model from a raw response. + /// The response to deserialize the model from. + internal static StringIndex FromResponse(Response response) + { + using var document = JsonDocument.Parse(response.Content); + return DeserializeStringIndex(document.RootElement); + } + + /// Convert into a . + internal virtual RequestContent ToRequestContent() + { + var content = new Utf8JsonRequestContent(); + content.JsonWriter.WriteObjectValue(this, ModelSerializationExtensions.WireOptions); + return content; + } + } +} diff --git a/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/StringIndex.cs b/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/StringIndex.cs new file mode 100644 index 000000000000..fbe20b3b5803 --- /dev/null +++ b/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/StringIndex.cs @@ -0,0 +1,108 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System; +using System.Collections.Generic; + +namespace Azure.Health.Deidentification +{ + /// String index encoding model. + public partial class StringIndex + { + /// + /// Keeps track of any properties unknown to the library. + /// + /// To assign an object to the value of this property use . + /// + /// + /// To assign an already formatted json string to this property use . + /// + /// + /// Examples: + /// + /// + /// BinaryData.FromObjectAsJson("foo") + /// Creates a payload of "foo". + /// + /// + /// BinaryData.FromString("\"foo\"") + /// Creates a payload of "foo". + /// + /// + /// BinaryData.FromObjectAsJson(new { key = "value" }) + /// Creates a payload of { "key": "value" }. + /// + /// + /// BinaryData.FromString("{\"key\": \"value\"}") + /// Creates a payload of { "key": "value" }. + /// + /// + /// + /// + private IDictionary _serializedAdditionalRawData; + + /// Initializes a new instance of . + /// The offset or length of the substring in UTF-8 encoding. + /// + /// The offset or length of the substring in UTF-16 encoding. + /// + /// Primary encoding used by .NET, Java, and JavaScript. + /// + /// + /// The offset or length of the substring in CodePoint encoding. + /// + /// Primary encoding used by Python. + /// + internal StringIndex(int utf8, int utf16, int codePoint) + { + Utf8 = utf8; + Utf16 = utf16; + CodePoint = codePoint; + } + + /// Initializes a new instance of . + /// The offset or length of the substring in UTF-8 encoding. + /// + /// The offset or length of the substring in UTF-16 encoding. + /// + /// Primary encoding used by .NET, Java, and JavaScript. + /// + /// + /// The offset or length of the substring in CodePoint encoding. + /// + /// Primary encoding used by Python. + /// + /// Keeps track of any properties unknown to the library. + internal StringIndex(int utf8, int utf16, int codePoint, IDictionary serializedAdditionalRawData) + { + Utf8 = utf8; + Utf16 = utf16; + CodePoint = codePoint; + _serializedAdditionalRawData = serializedAdditionalRawData; + } + + /// Initializes a new instance of for deserialization. + internal StringIndex() + { + } + + /// The offset or length of the substring in UTF-8 encoding. + public int Utf8 { get; } + /// + /// The offset or length of the substring in UTF-16 encoding. + /// + /// Primary encoding used by .NET, Java, and JavaScript. + /// + public int Utf16 { get; } + /// + /// The offset or length of the substring in CodePoint encoding. + /// + /// Primary encoding used by Python. + /// + public int CodePoint { get; } + } +} diff --git a/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/TargetStorageLocation.Serialization.cs b/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/TargetStorageLocation.Serialization.cs new file mode 100644 index 000000000000..156e08b1052f --- /dev/null +++ b/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/TargetStorageLocation.Serialization.cs @@ -0,0 +1,143 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System; +using System.ClientModel.Primitives; +using System.Collections.Generic; +using System.Text.Json; +using Azure.Core; + +namespace Azure.Health.Deidentification +{ + public partial class TargetStorageLocation : IUtf8JsonSerializable, IJsonModel + { + void IUtf8JsonSerializable.Write(Utf8JsonWriter writer) => ((IJsonModel)this).Write(writer, ModelSerializationExtensions.WireOptions); + + void IJsonModel.Write(Utf8JsonWriter writer, ModelReaderWriterOptions options) + { + var format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + if (format != "J") + { + throw new FormatException($"The model {nameof(TargetStorageLocation)} does not support writing '{format}' format."); + } + + writer.WriteStartObject(); + writer.WritePropertyName("location"u8); + writer.WriteStringValue(Location.AbsoluteUri); + writer.WritePropertyName("prefix"u8); + writer.WriteStringValue(Prefix); + if (options.Format != "W" && _serializedAdditionalRawData != null) + { + foreach (var item in _serializedAdditionalRawData) + { + writer.WritePropertyName(item.Key); +#if NET6_0_OR_GREATER + writer.WriteRawValue(item.Value); +#else + using (JsonDocument document = JsonDocument.Parse(item.Value)) + { + JsonSerializer.Serialize(writer, document.RootElement); + } +#endif + } + } + writer.WriteEndObject(); + } + + TargetStorageLocation IJsonModel.Create(ref Utf8JsonReader reader, ModelReaderWriterOptions options) + { + var format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + if (format != "J") + { + throw new FormatException($"The model {nameof(TargetStorageLocation)} does not support reading '{format}' format."); + } + + using JsonDocument document = JsonDocument.ParseValue(ref reader); + return DeserializeTargetStorageLocation(document.RootElement, options); + } + + internal static TargetStorageLocation DeserializeTargetStorageLocation(JsonElement element, ModelReaderWriterOptions options = null) + { + options ??= ModelSerializationExtensions.WireOptions; + + if (element.ValueKind == JsonValueKind.Null) + { + return null; + } + Uri location = default; + string prefix = default; + IDictionary serializedAdditionalRawData = default; + Dictionary rawDataDictionary = new Dictionary(); + foreach (var property in element.EnumerateObject()) + { + if (property.NameEquals("location"u8)) + { + location = new Uri(property.Value.GetString()); + continue; + } + if (property.NameEquals("prefix"u8)) + { + prefix = property.Value.GetString(); + continue; + } + if (options.Format != "W") + { + rawDataDictionary.Add(property.Name, BinaryData.FromString(property.Value.GetRawText())); + } + } + serializedAdditionalRawData = rawDataDictionary; + return new TargetStorageLocation(location, prefix, serializedAdditionalRawData); + } + + BinaryData IPersistableModel.Write(ModelReaderWriterOptions options) + { + var format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + + switch (format) + { + case "J": + return ModelReaderWriter.Write(this, options); + default: + throw new FormatException($"The model {nameof(TargetStorageLocation)} does not support writing '{options.Format}' format."); + } + } + + TargetStorageLocation IPersistableModel.Create(BinaryData data, ModelReaderWriterOptions options) + { + var format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + + switch (format) + { + case "J": + { + using JsonDocument document = JsonDocument.Parse(data); + return DeserializeTargetStorageLocation(document.RootElement, options); + } + default: + throw new FormatException($"The model {nameof(TargetStorageLocation)} does not support reading '{options.Format}' format."); + } + } + + string IPersistableModel.GetFormatFromOptions(ModelReaderWriterOptions options) => "J"; + + /// Deserializes the model from a raw response. + /// The response to deserialize the model from. + internal static TargetStorageLocation FromResponse(Response response) + { + using var document = JsonDocument.Parse(response.Content); + return DeserializeTargetStorageLocation(document.RootElement); + } + + /// Convert into a . + internal virtual RequestContent ToRequestContent() + { + var content = new Utf8JsonRequestContent(); + content.JsonWriter.WriteObjectValue(this, ModelSerializationExtensions.WireOptions); + return content; + } + } +} diff --git a/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/TargetStorageLocation.cs b/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/TargetStorageLocation.cs new file mode 100644 index 000000000000..1d72da87487d --- /dev/null +++ b/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Generated/TargetStorageLocation.cs @@ -0,0 +1,82 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System; +using System.Collections.Generic; + +namespace Azure.Health.Deidentification +{ + /// Storage location. + public partial class TargetStorageLocation + { + /// + /// Keeps track of any properties unknown to the library. + /// + /// To assign an object to the value of this property use . + /// + /// + /// To assign an already formatted json string to this property use . + /// + /// + /// Examples: + /// + /// + /// BinaryData.FromObjectAsJson("foo") + /// Creates a payload of "foo". + /// + /// + /// BinaryData.FromString("\"foo\"") + /// Creates a payload of "foo". + /// + /// + /// BinaryData.FromObjectAsJson(new { key = "value" }) + /// Creates a payload of { "key": "value" }. + /// + /// + /// BinaryData.FromString("{\"key\": \"value\"}") + /// Creates a payload of { "key": "value" }. + /// + /// + /// + /// + private IDictionary _serializedAdditionalRawData; + + /// Initializes a new instance of . + /// URL to storage location. + /// Prefix to filter path by. + /// or is null. + public TargetStorageLocation(Uri location, string prefix) + { + Argument.AssertNotNull(location, nameof(location)); + Argument.AssertNotNull(prefix, nameof(prefix)); + + Location = location; + Prefix = prefix; + } + + /// Initializes a new instance of . + /// URL to storage location. + /// Prefix to filter path by. + /// Keeps track of any properties unknown to the library. + internal TargetStorageLocation(Uri location, string prefix, IDictionary serializedAdditionalRawData) + { + Location = location; + Prefix = prefix; + _serializedAdditionalRawData = serializedAdditionalRawData; + } + + /// Initializes a new instance of for deserialization. + internal TargetStorageLocation() + { + } + + /// URL to storage location. + public Uri Location { get; set; } + /// Prefix to filter path by. + public string Prefix { get; set; } + } +} diff --git a/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Properties/AssemblyInfo.cs b/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Properties/AssemblyInfo.cs new file mode 100644 index 000000000000..052a0b4df40c --- /dev/null +++ b/sdk/healthdataaiservices/Azure.Health.Deidentification/src/Properties/AssemblyInfo.cs @@ -0,0 +1,11 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("Azure.Health.Deidentification.Tests, PublicKey = 0024000004800000940000000602000000240000525341310004000001000100d15ddcb29688295338af4b7686603fe614abd555e09efba8fb88ee09e1f7b1ccaeed2e8f823fa9eef3fdd60217fc012ea67d2479751a0b8c087a4185541b851bd8b16f8d91b840e51b1cb0ba6fe647997e57429265e85ef62d565db50a69ae1647d54d7bd855e4db3d8a91510e5bcbd0edfbbecaa20a7bd9ae74593daa7b11b4")] + +// Replace Microsoft.Test with the correct resource provider namepace for your service and uncomment. +// See https://docs.microsoft.com/en-us/azure/azure-resource-manager/management/azure-services-resource-providers +// for the list of possible values. +[assembly: Azure.Core.AzureResourceProviderNamespace("Microsoft.Template")] diff --git a/sdk/healthdataaiservices/Azure.Health.Deidentification/tests/Azure.Health.Deidentification.Tests.csproj b/sdk/healthdataaiservices/Azure.Health.Deidentification/tests/Azure.Health.Deidentification.Tests.csproj new file mode 100644 index 000000000000..af926850b52e --- /dev/null +++ b/sdk/healthdataaiservices/Azure.Health.Deidentification/tests/Azure.Health.Deidentification.Tests.csproj @@ -0,0 +1,20 @@ + + + $(RequiredTargetFrameworks) + + $(NoWarn);CS1591 + + + + + + + + + + + + + + + diff --git a/sdk/healthdataaiservices/Azure.Health.Deidentification/tests/Data/example_patient_1/doctor_dictation.txt b/sdk/healthdataaiservices/Azure.Health.Deidentification/tests/Data/example_patient_1/doctor_dictation.txt new file mode 100644 index 000000000000..dfb10187f123 --- /dev/null +++ b/sdk/healthdataaiservices/Azure.Health.Deidentification/tests/Data/example_patient_1/doctor_dictation.txt @@ -0,0 +1 @@ +Mr. Doe is a 97-year-old gentleman who presented to the clinic today complaining of persistent lower back pain. He reports the pain as dull and achy, primarily localized to the lumbar region. Onset was approximately three weeks ago, following a period of heavy lifting during a recent move. The pain is exacerbated by prolonged sitting and relieved with rest. No associated symptoms of radiculopathy, such as numbness or weakness, were reported. diff --git a/sdk/healthdataaiservices/Azure.Health.Deidentification/tests/Data/example_patient_1/visit_summary.txt b/sdk/healthdataaiservices/Azure.Health.Deidentification/tests/Data/example_patient_1/visit_summary.txt new file mode 100644 index 000000000000..427472ff8d1d --- /dev/null +++ b/sdk/healthdataaiservices/Azure.Health.Deidentification/tests/Data/example_patient_1/visit_summary.txt @@ -0,0 +1,8 @@ +Patient Name: John Doe +Date of Visit: May 8, 2024 +Physician: Dr. Emily Carter + +Summary: + +Chief Complaint: +John Doe presented today with complaints of persistent lower back pain that has been bothering him for the past three weeks. He reports the pain as dull and achy, localized primarily to the lumbar region, exacerbated by prolonged sitting and relieved with rest. diff --git a/sdk/healthdataaiservices/Azure.Health.Deidentification/tests/Generated/Samples/Samples_DeidentificationClient.cs b/sdk/healthdataaiservices/Azure.Health.Deidentification/tests/Generated/Samples/Samples_DeidentificationClient.cs new file mode 100644 index 000000000000..cd72b75607cb --- /dev/null +++ b/sdk/healthdataaiservices/Azure.Health.Deidentification/tests/Generated/Samples/Samples_DeidentificationClient.cs @@ -0,0 +1,1095 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System; +using System.Text.Json; +using System.Threading.Tasks; +using Azure.Core; +using Azure.Identity; +using NUnit.Framework; + +namespace Azure.Health.Deidentification.Samples +{ + public partial class Samples_DeidentificationClient + { + [Test] + [Ignore("Only validating compilation of examples")] + public void Example_DeidentificationJob_GetJob_ShortVersion() + { + Uri endpoint = new Uri(""); + TokenCredential credential = new DefaultAzureCredential(); + DeidentificationClient client = new DeidentificationClient(endpoint, credential); + + Response response = client.GetJob("", null); + + JsonElement result = JsonDocument.Parse(response.ContentStream).RootElement; + Console.WriteLine(result.GetProperty("name").ToString()); + Console.WriteLine(result.GetProperty("sourceLocation").GetProperty("location").ToString()); + Console.WriteLine(result.GetProperty("sourceLocation").GetProperty("prefix").ToString()); + Console.WriteLine(result.GetProperty("targetLocation").GetProperty("location").ToString()); + Console.WriteLine(result.GetProperty("targetLocation").GetProperty("prefix").ToString()); + Console.WriteLine(result.GetProperty("status").ToString()); + Console.WriteLine(result.GetProperty("lastUpdatedAt").ToString()); + Console.WriteLine(result.GetProperty("createdAt").ToString()); + } + + [Test] + [Ignore("Only validating compilation of examples")] + public async Task Example_DeidentificationJob_GetJob_ShortVersion_Async() + { + Uri endpoint = new Uri(""); + TokenCredential credential = new DefaultAzureCredential(); + DeidentificationClient client = new DeidentificationClient(endpoint, credential); + + Response response = await client.GetJobAsync("", null); + + JsonElement result = JsonDocument.Parse(response.ContentStream).RootElement; + Console.WriteLine(result.GetProperty("name").ToString()); + Console.WriteLine(result.GetProperty("sourceLocation").GetProperty("location").ToString()); + Console.WriteLine(result.GetProperty("sourceLocation").GetProperty("prefix").ToString()); + Console.WriteLine(result.GetProperty("targetLocation").GetProperty("location").ToString()); + Console.WriteLine(result.GetProperty("targetLocation").GetProperty("prefix").ToString()); + Console.WriteLine(result.GetProperty("status").ToString()); + Console.WriteLine(result.GetProperty("lastUpdatedAt").ToString()); + Console.WriteLine(result.GetProperty("createdAt").ToString()); + } + + [Test] + [Ignore("Only validating compilation of examples")] + public void Example_DeidentificationJob_GetJob_ShortVersion_Convenience() + { + Uri endpoint = new Uri(""); + TokenCredential credential = new DefaultAzureCredential(); + DeidentificationClient client = new DeidentificationClient(endpoint, credential); + + Response response = client.GetJob(""); + } + + [Test] + [Ignore("Only validating compilation of examples")] + public async Task Example_DeidentificationJob_GetJob_ShortVersion_Convenience_Async() + { + Uri endpoint = new Uri(""); + TokenCredential credential = new DefaultAzureCredential(); + DeidentificationClient client = new DeidentificationClient(endpoint, credential); + + Response response = await client.GetJobAsync(""); + } + + [Test] + [Ignore("Only validating compilation of examples")] + public void Example_DeidentificationJob_GetJob_AllParameters() + { + Uri endpoint = new Uri(""); + TokenCredential credential = new DefaultAzureCredential(); + DeidentificationClient client = new DeidentificationClient(endpoint, credential); + + Response response = client.GetJob("", null); + + JsonElement result = JsonDocument.Parse(response.ContentStream).RootElement; + Console.WriteLine(result.GetProperty("name").ToString()); + Console.WriteLine(result.GetProperty("sourceLocation").GetProperty("location").ToString()); + Console.WriteLine(result.GetProperty("sourceLocation").GetProperty("prefix").ToString()); + Console.WriteLine(result.GetProperty("sourceLocation").GetProperty("extensions")[0].ToString()); + Console.WriteLine(result.GetProperty("targetLocation").GetProperty("location").ToString()); + Console.WriteLine(result.GetProperty("targetLocation").GetProperty("prefix").ToString()); + Console.WriteLine(result.GetProperty("operation").ToString()); + Console.WriteLine(result.GetProperty("dataType").ToString()); + Console.WriteLine(result.GetProperty("redactionFormat").ToString()); + Console.WriteLine(result.GetProperty("status").ToString()); + Console.WriteLine(result.GetProperty("error").GetProperty("code").ToString()); + Console.WriteLine(result.GetProperty("error").GetProperty("message").ToString()); + Console.WriteLine(result.GetProperty("error").GetProperty("target").ToString()); + Console.WriteLine(result.GetProperty("error").GetProperty("innererror").GetProperty("code").ToString()); + Console.WriteLine(result.GetProperty("lastUpdatedAt").ToString()); + Console.WriteLine(result.GetProperty("createdAt").ToString()); + Console.WriteLine(result.GetProperty("startedAt").ToString()); + Console.WriteLine(result.GetProperty("summary").GetProperty("successful").ToString()); + Console.WriteLine(result.GetProperty("summary").GetProperty("failed").ToString()); + Console.WriteLine(result.GetProperty("summary").GetProperty("canceled").ToString()); + Console.WriteLine(result.GetProperty("summary").GetProperty("total").ToString()); + Console.WriteLine(result.GetProperty("summary").GetProperty("bytesProcessed").ToString()); + } + + [Test] + [Ignore("Only validating compilation of examples")] + public async Task Example_DeidentificationJob_GetJob_AllParameters_Async() + { + Uri endpoint = new Uri(""); + TokenCredential credential = new DefaultAzureCredential(); + DeidentificationClient client = new DeidentificationClient(endpoint, credential); + + Response response = await client.GetJobAsync("", null); + + JsonElement result = JsonDocument.Parse(response.ContentStream).RootElement; + Console.WriteLine(result.GetProperty("name").ToString()); + Console.WriteLine(result.GetProperty("sourceLocation").GetProperty("location").ToString()); + Console.WriteLine(result.GetProperty("sourceLocation").GetProperty("prefix").ToString()); + Console.WriteLine(result.GetProperty("sourceLocation").GetProperty("extensions")[0].ToString()); + Console.WriteLine(result.GetProperty("targetLocation").GetProperty("location").ToString()); + Console.WriteLine(result.GetProperty("targetLocation").GetProperty("prefix").ToString()); + Console.WriteLine(result.GetProperty("operation").ToString()); + Console.WriteLine(result.GetProperty("dataType").ToString()); + Console.WriteLine(result.GetProperty("redactionFormat").ToString()); + Console.WriteLine(result.GetProperty("status").ToString()); + Console.WriteLine(result.GetProperty("error").GetProperty("code").ToString()); + Console.WriteLine(result.GetProperty("error").GetProperty("message").ToString()); + Console.WriteLine(result.GetProperty("error").GetProperty("target").ToString()); + Console.WriteLine(result.GetProperty("error").GetProperty("innererror").GetProperty("code").ToString()); + Console.WriteLine(result.GetProperty("lastUpdatedAt").ToString()); + Console.WriteLine(result.GetProperty("createdAt").ToString()); + Console.WriteLine(result.GetProperty("startedAt").ToString()); + Console.WriteLine(result.GetProperty("summary").GetProperty("successful").ToString()); + Console.WriteLine(result.GetProperty("summary").GetProperty("failed").ToString()); + Console.WriteLine(result.GetProperty("summary").GetProperty("canceled").ToString()); + Console.WriteLine(result.GetProperty("summary").GetProperty("total").ToString()); + Console.WriteLine(result.GetProperty("summary").GetProperty("bytesProcessed").ToString()); + } + + [Test] + [Ignore("Only validating compilation of examples")] + public void Example_DeidentificationJob_GetJob_AllParameters_Convenience() + { + Uri endpoint = new Uri(""); + TokenCredential credential = new DefaultAzureCredential(); + DeidentificationClient client = new DeidentificationClient(endpoint, credential); + + Response response = client.GetJob(""); + } + + [Test] + [Ignore("Only validating compilation of examples")] + public async Task Example_DeidentificationJob_GetJob_AllParameters_Convenience_Async() + { + Uri endpoint = new Uri(""); + TokenCredential credential = new DefaultAzureCredential(); + DeidentificationClient client = new DeidentificationClient(endpoint, credential); + + Response response = await client.GetJobAsync(""); + } + + [Test] + [Ignore("Only validating compilation of examples")] + public void Example_DeidServices_CancelJob_ShortVersion() + { + Uri endpoint = new Uri(""); + TokenCredential credential = new DefaultAzureCredential(); + DeidentificationClient client = new DeidentificationClient(endpoint, credential); + + Response response = client.CancelJob("", null); + + JsonElement result = JsonDocument.Parse(response.ContentStream).RootElement; + Console.WriteLine(result.GetProperty("name").ToString()); + Console.WriteLine(result.GetProperty("sourceLocation").GetProperty("location").ToString()); + Console.WriteLine(result.GetProperty("sourceLocation").GetProperty("prefix").ToString()); + Console.WriteLine(result.GetProperty("targetLocation").GetProperty("location").ToString()); + Console.WriteLine(result.GetProperty("targetLocation").GetProperty("prefix").ToString()); + Console.WriteLine(result.GetProperty("status").ToString()); + Console.WriteLine(result.GetProperty("lastUpdatedAt").ToString()); + Console.WriteLine(result.GetProperty("createdAt").ToString()); + } + + [Test] + [Ignore("Only validating compilation of examples")] + public async Task Example_DeidServices_CancelJob_ShortVersion_Async() + { + Uri endpoint = new Uri(""); + TokenCredential credential = new DefaultAzureCredential(); + DeidentificationClient client = new DeidentificationClient(endpoint, credential); + + Response response = await client.CancelJobAsync("", null); + + JsonElement result = JsonDocument.Parse(response.ContentStream).RootElement; + Console.WriteLine(result.GetProperty("name").ToString()); + Console.WriteLine(result.GetProperty("sourceLocation").GetProperty("location").ToString()); + Console.WriteLine(result.GetProperty("sourceLocation").GetProperty("prefix").ToString()); + Console.WriteLine(result.GetProperty("targetLocation").GetProperty("location").ToString()); + Console.WriteLine(result.GetProperty("targetLocation").GetProperty("prefix").ToString()); + Console.WriteLine(result.GetProperty("status").ToString()); + Console.WriteLine(result.GetProperty("lastUpdatedAt").ToString()); + Console.WriteLine(result.GetProperty("createdAt").ToString()); + } + + [Test] + [Ignore("Only validating compilation of examples")] + public void Example_DeidServices_CancelJob_ShortVersion_Convenience() + { + Uri endpoint = new Uri(""); + TokenCredential credential = new DefaultAzureCredential(); + DeidentificationClient client = new DeidentificationClient(endpoint, credential); + + Response response = client.CancelJob(""); + } + + [Test] + [Ignore("Only validating compilation of examples")] + public async Task Example_DeidServices_CancelJob_ShortVersion_Convenience_Async() + { + Uri endpoint = new Uri(""); + TokenCredential credential = new DefaultAzureCredential(); + DeidentificationClient client = new DeidentificationClient(endpoint, credential); + + Response response = await client.CancelJobAsync(""); + } + + [Test] + [Ignore("Only validating compilation of examples")] + public void Example_DeidServices_CancelJob_AllParameters() + { + Uri endpoint = new Uri(""); + TokenCredential credential = new DefaultAzureCredential(); + DeidentificationClient client = new DeidentificationClient(endpoint, credential); + + Response response = client.CancelJob("", null); + + JsonElement result = JsonDocument.Parse(response.ContentStream).RootElement; + Console.WriteLine(result.GetProperty("name").ToString()); + Console.WriteLine(result.GetProperty("sourceLocation").GetProperty("location").ToString()); + Console.WriteLine(result.GetProperty("sourceLocation").GetProperty("prefix").ToString()); + Console.WriteLine(result.GetProperty("sourceLocation").GetProperty("extensions")[0].ToString()); + Console.WriteLine(result.GetProperty("targetLocation").GetProperty("location").ToString()); + Console.WriteLine(result.GetProperty("targetLocation").GetProperty("prefix").ToString()); + Console.WriteLine(result.GetProperty("operation").ToString()); + Console.WriteLine(result.GetProperty("dataType").ToString()); + Console.WriteLine(result.GetProperty("redactionFormat").ToString()); + Console.WriteLine(result.GetProperty("status").ToString()); + Console.WriteLine(result.GetProperty("error").GetProperty("code").ToString()); + Console.WriteLine(result.GetProperty("error").GetProperty("message").ToString()); + Console.WriteLine(result.GetProperty("error").GetProperty("target").ToString()); + Console.WriteLine(result.GetProperty("error").GetProperty("innererror").GetProperty("code").ToString()); + Console.WriteLine(result.GetProperty("lastUpdatedAt").ToString()); + Console.WriteLine(result.GetProperty("createdAt").ToString()); + Console.WriteLine(result.GetProperty("startedAt").ToString()); + Console.WriteLine(result.GetProperty("summary").GetProperty("successful").ToString()); + Console.WriteLine(result.GetProperty("summary").GetProperty("failed").ToString()); + Console.WriteLine(result.GetProperty("summary").GetProperty("canceled").ToString()); + Console.WriteLine(result.GetProperty("summary").GetProperty("total").ToString()); + Console.WriteLine(result.GetProperty("summary").GetProperty("bytesProcessed").ToString()); + } + + [Test] + [Ignore("Only validating compilation of examples")] + public async Task Example_DeidServices_CancelJob_AllParameters_Async() + { + Uri endpoint = new Uri(""); + TokenCredential credential = new DefaultAzureCredential(); + DeidentificationClient client = new DeidentificationClient(endpoint, credential); + + Response response = await client.CancelJobAsync("", null); + + JsonElement result = JsonDocument.Parse(response.ContentStream).RootElement; + Console.WriteLine(result.GetProperty("name").ToString()); + Console.WriteLine(result.GetProperty("sourceLocation").GetProperty("location").ToString()); + Console.WriteLine(result.GetProperty("sourceLocation").GetProperty("prefix").ToString()); + Console.WriteLine(result.GetProperty("sourceLocation").GetProperty("extensions")[0].ToString()); + Console.WriteLine(result.GetProperty("targetLocation").GetProperty("location").ToString()); + Console.WriteLine(result.GetProperty("targetLocation").GetProperty("prefix").ToString()); + Console.WriteLine(result.GetProperty("operation").ToString()); + Console.WriteLine(result.GetProperty("dataType").ToString()); + Console.WriteLine(result.GetProperty("redactionFormat").ToString()); + Console.WriteLine(result.GetProperty("status").ToString()); + Console.WriteLine(result.GetProperty("error").GetProperty("code").ToString()); + Console.WriteLine(result.GetProperty("error").GetProperty("message").ToString()); + Console.WriteLine(result.GetProperty("error").GetProperty("target").ToString()); + Console.WriteLine(result.GetProperty("error").GetProperty("innererror").GetProperty("code").ToString()); + Console.WriteLine(result.GetProperty("lastUpdatedAt").ToString()); + Console.WriteLine(result.GetProperty("createdAt").ToString()); + Console.WriteLine(result.GetProperty("startedAt").ToString()); + Console.WriteLine(result.GetProperty("summary").GetProperty("successful").ToString()); + Console.WriteLine(result.GetProperty("summary").GetProperty("failed").ToString()); + Console.WriteLine(result.GetProperty("summary").GetProperty("canceled").ToString()); + Console.WriteLine(result.GetProperty("summary").GetProperty("total").ToString()); + Console.WriteLine(result.GetProperty("summary").GetProperty("bytesProcessed").ToString()); + } + + [Test] + [Ignore("Only validating compilation of examples")] + public void Example_DeidServices_CancelJob_AllParameters_Convenience() + { + Uri endpoint = new Uri(""); + TokenCredential credential = new DefaultAzureCredential(); + DeidentificationClient client = new DeidentificationClient(endpoint, credential); + + Response response = client.CancelJob(""); + } + + [Test] + [Ignore("Only validating compilation of examples")] + public async Task Example_DeidServices_CancelJob_AllParameters_Convenience_Async() + { + Uri endpoint = new Uri(""); + TokenCredential credential = new DefaultAzureCredential(); + DeidentificationClient client = new DeidentificationClient(endpoint, credential); + + Response response = await client.CancelJobAsync(""); + } + + [Test] + [Ignore("Only validating compilation of examples")] + public void Example_DeidentificationJob_DeleteJob_ShortVersion() + { + Uri endpoint = new Uri(""); + TokenCredential credential = new DefaultAzureCredential(); + DeidentificationClient client = new DeidentificationClient(endpoint, credential); + + Response response = client.DeleteJob(""); + + Console.WriteLine(response.Status); + } + + [Test] + [Ignore("Only validating compilation of examples")] + public async Task Example_DeidentificationJob_DeleteJob_ShortVersion_Async() + { + Uri endpoint = new Uri(""); + TokenCredential credential = new DefaultAzureCredential(); + DeidentificationClient client = new DeidentificationClient(endpoint, credential); + + Response response = await client.DeleteJobAsync(""); + + Console.WriteLine(response.Status); + } + + [Test] + [Ignore("Only validating compilation of examples")] + public void Example_DeidentificationJob_DeleteJob_AllParameters() + { + Uri endpoint = new Uri(""); + TokenCredential credential = new DefaultAzureCredential(); + DeidentificationClient client = new DeidentificationClient(endpoint, credential); + + Response response = client.DeleteJob(""); + + Console.WriteLine(response.Status); + } + + [Test] + [Ignore("Only validating compilation of examples")] + public async Task Example_DeidentificationJob_DeleteJob_AllParameters_Async() + { + Uri endpoint = new Uri(""); + TokenCredential credential = new DefaultAzureCredential(); + DeidentificationClient client = new DeidentificationClient(endpoint, credential); + + Response response = await client.DeleteJobAsync(""); + + Console.WriteLine(response.Status); + } + + [Test] + [Ignore("Only validating compilation of examples")] + public void Example_DeidServices_Deidentify_ShortVersion() + { + Uri endpoint = new Uri(""); + TokenCredential credential = new DefaultAzureCredential(); + DeidentificationClient client = new DeidentificationClient(endpoint, credential); + + using RequestContent content = RequestContent.Create(new + { + inputText = "", + }); + Response response = client.Deidentify(content); + + JsonElement result = JsonDocument.Parse(response.ContentStream).RootElement; + Console.WriteLine(result.ToString()); + } + + [Test] + [Ignore("Only validating compilation of examples")] + public async Task Example_DeidServices_Deidentify_ShortVersion_Async() + { + Uri endpoint = new Uri(""); + TokenCredential credential = new DefaultAzureCredential(); + DeidentificationClient client = new DeidentificationClient(endpoint, credential); + + using RequestContent content = RequestContent.Create(new + { + inputText = "", + }); + Response response = await client.DeidentifyAsync(content); + + JsonElement result = JsonDocument.Parse(response.ContentStream).RootElement; + Console.WriteLine(result.ToString()); + } + + [Test] + [Ignore("Only validating compilation of examples")] + public void Example_DeidServices_Deidentify_ShortVersion_Convenience() + { + Uri endpoint = new Uri(""); + TokenCredential credential = new DefaultAzureCredential(); + DeidentificationClient client = new DeidentificationClient(endpoint, credential); + + DeidentificationContent body = new DeidentificationContent(""); + Response response = client.Deidentify(body); + } + + [Test] + [Ignore("Only validating compilation of examples")] + public async Task Example_DeidServices_Deidentify_ShortVersion_Convenience_Async() + { + Uri endpoint = new Uri(""); + TokenCredential credential = new DefaultAzureCredential(); + DeidentificationClient client = new DeidentificationClient(endpoint, credential); + + DeidentificationContent body = new DeidentificationContent(""); + Response response = await client.DeidentifyAsync(body); + } + + [Test] + [Ignore("Only validating compilation of examples")] + public void Example_DeidServices_Deidentify_AllParameters() + { + Uri endpoint = new Uri(""); + TokenCredential credential = new DefaultAzureCredential(); + DeidentificationClient client = new DeidentificationClient(endpoint, credential); + + using RequestContent content = RequestContent.Create(new + { + inputText = "", + operation = "Redact", + dataType = "Plaintext", + redactionFormat = "", + }); + Response response = client.Deidentify(content); + + JsonElement result = JsonDocument.Parse(response.ContentStream).RootElement; + Console.WriteLine(result.GetProperty("outputText").ToString()); + Console.WriteLine(result.GetProperty("taggerResult").GetProperty("entities")[0].GetProperty("category").ToString()); + Console.WriteLine(result.GetProperty("taggerResult").GetProperty("entities")[0].GetProperty("offset").GetProperty("utf8").ToString()); + Console.WriteLine(result.GetProperty("taggerResult").GetProperty("entities")[0].GetProperty("offset").GetProperty("utf16").ToString()); + Console.WriteLine(result.GetProperty("taggerResult").GetProperty("entities")[0].GetProperty("offset").GetProperty("codePoint").ToString()); + Console.WriteLine(result.GetProperty("taggerResult").GetProperty("entities")[0].GetProperty("length").GetProperty("utf8").ToString()); + Console.WriteLine(result.GetProperty("taggerResult").GetProperty("entities")[0].GetProperty("length").GetProperty("utf16").ToString()); + Console.WriteLine(result.GetProperty("taggerResult").GetProperty("entities")[0].GetProperty("length").GetProperty("codePoint").ToString()); + Console.WriteLine(result.GetProperty("taggerResult").GetProperty("entities")[0].GetProperty("text").ToString()); + Console.WriteLine(result.GetProperty("taggerResult").GetProperty("entities")[0].GetProperty("confidenceScore").ToString()); + Console.WriteLine(result.GetProperty("taggerResult").GetProperty("path").ToString()); + Console.WriteLine(result.GetProperty("taggerResult").GetProperty("etag").ToString()); + } + + [Test] + [Ignore("Only validating compilation of examples")] + public async Task Example_DeidServices_Deidentify_AllParameters_Async() + { + Uri endpoint = new Uri(""); + TokenCredential credential = new DefaultAzureCredential(); + DeidentificationClient client = new DeidentificationClient(endpoint, credential); + + using RequestContent content = RequestContent.Create(new + { + inputText = "", + operation = "Redact", + dataType = "Plaintext", + redactionFormat = "", + }); + Response response = await client.DeidentifyAsync(content); + + JsonElement result = JsonDocument.Parse(response.ContentStream).RootElement; + Console.WriteLine(result.GetProperty("outputText").ToString()); + Console.WriteLine(result.GetProperty("taggerResult").GetProperty("entities")[0].GetProperty("category").ToString()); + Console.WriteLine(result.GetProperty("taggerResult").GetProperty("entities")[0].GetProperty("offset").GetProperty("utf8").ToString()); + Console.WriteLine(result.GetProperty("taggerResult").GetProperty("entities")[0].GetProperty("offset").GetProperty("utf16").ToString()); + Console.WriteLine(result.GetProperty("taggerResult").GetProperty("entities")[0].GetProperty("offset").GetProperty("codePoint").ToString()); + Console.WriteLine(result.GetProperty("taggerResult").GetProperty("entities")[0].GetProperty("length").GetProperty("utf8").ToString()); + Console.WriteLine(result.GetProperty("taggerResult").GetProperty("entities")[0].GetProperty("length").GetProperty("utf16").ToString()); + Console.WriteLine(result.GetProperty("taggerResult").GetProperty("entities")[0].GetProperty("length").GetProperty("codePoint").ToString()); + Console.WriteLine(result.GetProperty("taggerResult").GetProperty("entities")[0].GetProperty("text").ToString()); + Console.WriteLine(result.GetProperty("taggerResult").GetProperty("entities")[0].GetProperty("confidenceScore").ToString()); + Console.WriteLine(result.GetProperty("taggerResult").GetProperty("path").ToString()); + Console.WriteLine(result.GetProperty("taggerResult").GetProperty("etag").ToString()); + } + + [Test] + [Ignore("Only validating compilation of examples")] + public void Example_DeidServices_Deidentify_AllParameters_Convenience() + { + Uri endpoint = new Uri(""); + TokenCredential credential = new DefaultAzureCredential(); + DeidentificationClient client = new DeidentificationClient(endpoint, credential); + + DeidentificationContent body = new DeidentificationContent("") + { + Operation = OperationType.Redact, + DataType = DocumentDataType.Plaintext, + RedactionFormat = "", + }; + Response response = client.Deidentify(body); + } + + [Test] + [Ignore("Only validating compilation of examples")] + public async Task Example_DeidServices_Deidentify_AllParameters_Convenience_Async() + { + Uri endpoint = new Uri(""); + TokenCredential credential = new DefaultAzureCredential(); + DeidentificationClient client = new DeidentificationClient(endpoint, credential); + + DeidentificationContent body = new DeidentificationContent("") + { + Operation = OperationType.Redact, + DataType = DocumentDataType.Plaintext, + RedactionFormat = "", + }; + Response response = await client.DeidentifyAsync(body); + } + + [Test] + [Ignore("Only validating compilation of examples")] + public void Example_DeidentificationJob_GetJobs_ShortVersion() + { + Uri endpoint = new Uri(""); + TokenCredential credential = new DefaultAzureCredential(); + DeidentificationClient client = new DeidentificationClient(endpoint, credential); + + foreach (BinaryData item in client.GetJobs(null, null, null)) + { + JsonElement result = JsonDocument.Parse(item.ToStream()).RootElement; + Console.WriteLine(result.GetProperty("name").ToString()); + Console.WriteLine(result.GetProperty("sourceLocation").GetProperty("location").ToString()); + Console.WriteLine(result.GetProperty("sourceLocation").GetProperty("prefix").ToString()); + Console.WriteLine(result.GetProperty("targetLocation").GetProperty("location").ToString()); + Console.WriteLine(result.GetProperty("targetLocation").GetProperty("prefix").ToString()); + Console.WriteLine(result.GetProperty("status").ToString()); + Console.WriteLine(result.GetProperty("lastUpdatedAt").ToString()); + Console.WriteLine(result.GetProperty("createdAt").ToString()); + } + } + + [Test] + [Ignore("Only validating compilation of examples")] + public async Task Example_DeidentificationJob_GetJobs_ShortVersion_Async() + { + Uri endpoint = new Uri(""); + TokenCredential credential = new DefaultAzureCredential(); + DeidentificationClient client = new DeidentificationClient(endpoint, credential); + + await foreach (BinaryData item in client.GetJobsAsync(null, null, null)) + { + JsonElement result = JsonDocument.Parse(item.ToStream()).RootElement; + Console.WriteLine(result.GetProperty("name").ToString()); + Console.WriteLine(result.GetProperty("sourceLocation").GetProperty("location").ToString()); + Console.WriteLine(result.GetProperty("sourceLocation").GetProperty("prefix").ToString()); + Console.WriteLine(result.GetProperty("targetLocation").GetProperty("location").ToString()); + Console.WriteLine(result.GetProperty("targetLocation").GetProperty("prefix").ToString()); + Console.WriteLine(result.GetProperty("status").ToString()); + Console.WriteLine(result.GetProperty("lastUpdatedAt").ToString()); + Console.WriteLine(result.GetProperty("createdAt").ToString()); + } + } + + [Test] + [Ignore("Only validating compilation of examples")] + public void Example_DeidentificationJob_GetJobs_ShortVersion_Convenience() + { + Uri endpoint = new Uri(""); + TokenCredential credential = new DefaultAzureCredential(); + DeidentificationClient client = new DeidentificationClient(endpoint, credential); + + foreach (DeidentificationJob item in client.GetJobs()) + { + } + } + + [Test] + [Ignore("Only validating compilation of examples")] + public async Task Example_DeidentificationJob_GetJobs_ShortVersion_Convenience_Async() + { + Uri endpoint = new Uri(""); + TokenCredential credential = new DefaultAzureCredential(); + DeidentificationClient client = new DeidentificationClient(endpoint, credential); + + await foreach (DeidentificationJob item in client.GetJobsAsync()) + { + } + } + + [Test] + [Ignore("Only validating compilation of examples")] + public void Example_DeidentificationJob_GetJobs_AllParameters() + { + Uri endpoint = new Uri(""); + TokenCredential credential = new DefaultAzureCredential(); + DeidentificationClient client = new DeidentificationClient(endpoint, credential); + + foreach (BinaryData item in client.GetJobs(1234, "", null)) + { + JsonElement result = JsonDocument.Parse(item.ToStream()).RootElement; + Console.WriteLine(result.GetProperty("name").ToString()); + Console.WriteLine(result.GetProperty("sourceLocation").GetProperty("location").ToString()); + Console.WriteLine(result.GetProperty("sourceLocation").GetProperty("prefix").ToString()); + Console.WriteLine(result.GetProperty("sourceLocation").GetProperty("extensions")[0].ToString()); + Console.WriteLine(result.GetProperty("targetLocation").GetProperty("location").ToString()); + Console.WriteLine(result.GetProperty("targetLocation").GetProperty("prefix").ToString()); + Console.WriteLine(result.GetProperty("operation").ToString()); + Console.WriteLine(result.GetProperty("dataType").ToString()); + Console.WriteLine(result.GetProperty("redactionFormat").ToString()); + Console.WriteLine(result.GetProperty("status").ToString()); + Console.WriteLine(result.GetProperty("error").GetProperty("code").ToString()); + Console.WriteLine(result.GetProperty("error").GetProperty("message").ToString()); + Console.WriteLine(result.GetProperty("error").GetProperty("target").ToString()); + Console.WriteLine(result.GetProperty("error").GetProperty("innererror").GetProperty("code").ToString()); + Console.WriteLine(result.GetProperty("lastUpdatedAt").ToString()); + Console.WriteLine(result.GetProperty("createdAt").ToString()); + Console.WriteLine(result.GetProperty("startedAt").ToString()); + Console.WriteLine(result.GetProperty("summary").GetProperty("successful").ToString()); + Console.WriteLine(result.GetProperty("summary").GetProperty("failed").ToString()); + Console.WriteLine(result.GetProperty("summary").GetProperty("canceled").ToString()); + Console.WriteLine(result.GetProperty("summary").GetProperty("total").ToString()); + Console.WriteLine(result.GetProperty("summary").GetProperty("bytesProcessed").ToString()); + } + } + + [Test] + [Ignore("Only validating compilation of examples")] + public async Task Example_DeidentificationJob_GetJobs_AllParameters_Async() + { + Uri endpoint = new Uri(""); + TokenCredential credential = new DefaultAzureCredential(); + DeidentificationClient client = new DeidentificationClient(endpoint, credential); + + await foreach (BinaryData item in client.GetJobsAsync(1234, "", null)) + { + JsonElement result = JsonDocument.Parse(item.ToStream()).RootElement; + Console.WriteLine(result.GetProperty("name").ToString()); + Console.WriteLine(result.GetProperty("sourceLocation").GetProperty("location").ToString()); + Console.WriteLine(result.GetProperty("sourceLocation").GetProperty("prefix").ToString()); + Console.WriteLine(result.GetProperty("sourceLocation").GetProperty("extensions")[0].ToString()); + Console.WriteLine(result.GetProperty("targetLocation").GetProperty("location").ToString()); + Console.WriteLine(result.GetProperty("targetLocation").GetProperty("prefix").ToString()); + Console.WriteLine(result.GetProperty("operation").ToString()); + Console.WriteLine(result.GetProperty("dataType").ToString()); + Console.WriteLine(result.GetProperty("redactionFormat").ToString()); + Console.WriteLine(result.GetProperty("status").ToString()); + Console.WriteLine(result.GetProperty("error").GetProperty("code").ToString()); + Console.WriteLine(result.GetProperty("error").GetProperty("message").ToString()); + Console.WriteLine(result.GetProperty("error").GetProperty("target").ToString()); + Console.WriteLine(result.GetProperty("error").GetProperty("innererror").GetProperty("code").ToString()); + Console.WriteLine(result.GetProperty("lastUpdatedAt").ToString()); + Console.WriteLine(result.GetProperty("createdAt").ToString()); + Console.WriteLine(result.GetProperty("startedAt").ToString()); + Console.WriteLine(result.GetProperty("summary").GetProperty("successful").ToString()); + Console.WriteLine(result.GetProperty("summary").GetProperty("failed").ToString()); + Console.WriteLine(result.GetProperty("summary").GetProperty("canceled").ToString()); + Console.WriteLine(result.GetProperty("summary").GetProperty("total").ToString()); + Console.WriteLine(result.GetProperty("summary").GetProperty("bytesProcessed").ToString()); + } + } + + [Test] + [Ignore("Only validating compilation of examples")] + public void Example_DeidentificationJob_GetJobs_AllParameters_Convenience() + { + Uri endpoint = new Uri(""); + TokenCredential credential = new DefaultAzureCredential(); + DeidentificationClient client = new DeidentificationClient(endpoint, credential); + + foreach (DeidentificationJob item in client.GetJobs(maxpagesize: 1234, continuationToken: "")) + { + } + } + + [Test] + [Ignore("Only validating compilation of examples")] + public async Task Example_DeidentificationJob_GetJobs_AllParameters_Convenience_Async() + { + Uri endpoint = new Uri(""); + TokenCredential credential = new DefaultAzureCredential(); + DeidentificationClient client = new DeidentificationClient(endpoint, credential); + + await foreach (DeidentificationJob item in client.GetJobsAsync(maxpagesize: 1234, continuationToken: "")) + { + } + } + + [Test] + [Ignore("Only validating compilation of examples")] + public void Example_DocumentDetails_GetJobDocuments_ShortVersion() + { + Uri endpoint = new Uri(""); + TokenCredential credential = new DefaultAzureCredential(); + DeidentificationClient client = new DeidentificationClient(endpoint, credential); + + foreach (BinaryData item in client.GetJobDocuments("", null, null, null)) + { + JsonElement result = JsonDocument.Parse(item.ToStream()).RootElement; + Console.WriteLine(result.GetProperty("id").ToString()); + Console.WriteLine(result.GetProperty("input").GetProperty("path").ToString()); + Console.WriteLine(result.GetProperty("input").GetProperty("etag").ToString()); + Console.WriteLine(result.GetProperty("status").ToString()); + } + } + + [Test] + [Ignore("Only validating compilation of examples")] + public async Task Example_DocumentDetails_GetJobDocuments_ShortVersion_Async() + { + Uri endpoint = new Uri(""); + TokenCredential credential = new DefaultAzureCredential(); + DeidentificationClient client = new DeidentificationClient(endpoint, credential); + + await foreach (BinaryData item in client.GetJobDocumentsAsync("", null, null, null)) + { + JsonElement result = JsonDocument.Parse(item.ToStream()).RootElement; + Console.WriteLine(result.GetProperty("id").ToString()); + Console.WriteLine(result.GetProperty("input").GetProperty("path").ToString()); + Console.WriteLine(result.GetProperty("input").GetProperty("etag").ToString()); + Console.WriteLine(result.GetProperty("status").ToString()); + } + } + + [Test] + [Ignore("Only validating compilation of examples")] + public void Example_DocumentDetails_GetJobDocuments_ShortVersion_Convenience() + { + Uri endpoint = new Uri(""); + TokenCredential credential = new DefaultAzureCredential(); + DeidentificationClient client = new DeidentificationClient(endpoint, credential); + + foreach (DocumentDetails item in client.GetJobDocuments("")) + { + } + } + + [Test] + [Ignore("Only validating compilation of examples")] + public async Task Example_DocumentDetails_GetJobDocuments_ShortVersion_Convenience_Async() + { + Uri endpoint = new Uri(""); + TokenCredential credential = new DefaultAzureCredential(); + DeidentificationClient client = new DeidentificationClient(endpoint, credential); + + await foreach (DocumentDetails item in client.GetJobDocumentsAsync("")) + { + } + } + + [Test] + [Ignore("Only validating compilation of examples")] + public void Example_DocumentDetails_GetJobDocuments_AllParameters() + { + Uri endpoint = new Uri(""); + TokenCredential credential = new DefaultAzureCredential(); + DeidentificationClient client = new DeidentificationClient(endpoint, credential); + + foreach (BinaryData item in client.GetJobDocuments("", 1234, "", null)) + { + JsonElement result = JsonDocument.Parse(item.ToStream()).RootElement; + Console.WriteLine(result.GetProperty("id").ToString()); + Console.WriteLine(result.GetProperty("input").GetProperty("path").ToString()); + Console.WriteLine(result.GetProperty("input").GetProperty("etag").ToString()); + Console.WriteLine(result.GetProperty("output").GetProperty("path").ToString()); + Console.WriteLine(result.GetProperty("output").GetProperty("etag").ToString()); + Console.WriteLine(result.GetProperty("status").ToString()); + Console.WriteLine(result.GetProperty("error").GetProperty("code").ToString()); + Console.WriteLine(result.GetProperty("error").GetProperty("message").ToString()); + Console.WriteLine(result.GetProperty("error").GetProperty("target").ToString()); + Console.WriteLine(result.GetProperty("error").GetProperty("innererror").GetProperty("code").ToString()); + } + } + + [Test] + [Ignore("Only validating compilation of examples")] + public async Task Example_DocumentDetails_GetJobDocuments_AllParameters_Async() + { + Uri endpoint = new Uri(""); + TokenCredential credential = new DefaultAzureCredential(); + DeidentificationClient client = new DeidentificationClient(endpoint, credential); + + await foreach (BinaryData item in client.GetJobDocumentsAsync("", 1234, "", null)) + { + JsonElement result = JsonDocument.Parse(item.ToStream()).RootElement; + Console.WriteLine(result.GetProperty("id").ToString()); + Console.WriteLine(result.GetProperty("input").GetProperty("path").ToString()); + Console.WriteLine(result.GetProperty("input").GetProperty("etag").ToString()); + Console.WriteLine(result.GetProperty("output").GetProperty("path").ToString()); + Console.WriteLine(result.GetProperty("output").GetProperty("etag").ToString()); + Console.WriteLine(result.GetProperty("status").ToString()); + Console.WriteLine(result.GetProperty("error").GetProperty("code").ToString()); + Console.WriteLine(result.GetProperty("error").GetProperty("message").ToString()); + Console.WriteLine(result.GetProperty("error").GetProperty("target").ToString()); + Console.WriteLine(result.GetProperty("error").GetProperty("innererror").GetProperty("code").ToString()); + } + } + + [Test] + [Ignore("Only validating compilation of examples")] + public void Example_DocumentDetails_GetJobDocuments_AllParameters_Convenience() + { + Uri endpoint = new Uri(""); + TokenCredential credential = new DefaultAzureCredential(); + DeidentificationClient client = new DeidentificationClient(endpoint, credential); + + foreach (DocumentDetails item in client.GetJobDocuments("", maxpagesize: 1234, continuationToken: "")) + { + } + } + + [Test] + [Ignore("Only validating compilation of examples")] + public async Task Example_DocumentDetails_GetJobDocuments_AllParameters_Convenience_Async() + { + Uri endpoint = new Uri(""); + TokenCredential credential = new DefaultAzureCredential(); + DeidentificationClient client = new DeidentificationClient(endpoint, credential); + + await foreach (DocumentDetails item in client.GetJobDocumentsAsync("", maxpagesize: 1234, continuationToken: "")) + { + } + } + + [Test] + [Ignore("Only validating compilation of examples")] + public void Example_DeidentificationJob_CreateJob_ShortVersion() + { + Uri endpoint = new Uri(""); + TokenCredential credential = new DefaultAzureCredential(); + DeidentificationClient client = new DeidentificationClient(endpoint, credential); + + using RequestContent content = RequestContent.Create(new + { + sourceLocation = new + { + location = "http://localhost:3000", + prefix = "", + }, + targetLocation = new + { + location = "http://localhost:3000", + prefix = "", + }, + }); + Operation operation = client.CreateJob(WaitUntil.Completed, "", content); + BinaryData responseData = operation.Value; + + JsonElement result = JsonDocument.Parse(responseData.ToStream()).RootElement; + Console.WriteLine(result.GetProperty("name").ToString()); + Console.WriteLine(result.GetProperty("sourceLocation").GetProperty("location").ToString()); + Console.WriteLine(result.GetProperty("sourceLocation").GetProperty("prefix").ToString()); + Console.WriteLine(result.GetProperty("targetLocation").GetProperty("location").ToString()); + Console.WriteLine(result.GetProperty("targetLocation").GetProperty("prefix").ToString()); + Console.WriteLine(result.GetProperty("status").ToString()); + Console.WriteLine(result.GetProperty("lastUpdatedAt").ToString()); + Console.WriteLine(result.GetProperty("createdAt").ToString()); + } + + [Test] + [Ignore("Only validating compilation of examples")] + public async Task Example_DeidentificationJob_CreateJob_ShortVersion_Async() + { + Uri endpoint = new Uri(""); + TokenCredential credential = new DefaultAzureCredential(); + DeidentificationClient client = new DeidentificationClient(endpoint, credential); + + using RequestContent content = RequestContent.Create(new + { + sourceLocation = new + { + location = "http://localhost:3000", + prefix = "", + }, + targetLocation = new + { + location = "http://localhost:3000", + prefix = "", + }, + }); + Operation operation = await client.CreateJobAsync(WaitUntil.Completed, "", content); + BinaryData responseData = operation.Value; + + JsonElement result = JsonDocument.Parse(responseData.ToStream()).RootElement; + Console.WriteLine(result.GetProperty("name").ToString()); + Console.WriteLine(result.GetProperty("sourceLocation").GetProperty("location").ToString()); + Console.WriteLine(result.GetProperty("sourceLocation").GetProperty("prefix").ToString()); + Console.WriteLine(result.GetProperty("targetLocation").GetProperty("location").ToString()); + Console.WriteLine(result.GetProperty("targetLocation").GetProperty("prefix").ToString()); + Console.WriteLine(result.GetProperty("status").ToString()); + Console.WriteLine(result.GetProperty("lastUpdatedAt").ToString()); + Console.WriteLine(result.GetProperty("createdAt").ToString()); + } + + [Test] + [Ignore("Only validating compilation of examples")] + public void Example_DeidentificationJob_CreateJob_ShortVersion_Convenience() + { + Uri endpoint = new Uri(""); + TokenCredential credential = new DefaultAzureCredential(); + DeidentificationClient client = new DeidentificationClient(endpoint, credential); + + DeidentificationJob resource = new DeidentificationJob(new SourceStorageLocation(new Uri("http://localhost:3000"), ""), new TargetStorageLocation(new Uri("http://localhost:3000"), "")); + Operation operation = client.CreateJob(WaitUntil.Completed, "", resource); + DeidentificationJob responseData = operation.Value; + } + + [Test] + [Ignore("Only validating compilation of examples")] + public async Task Example_DeidentificationJob_CreateJob_ShortVersion_Convenience_Async() + { + Uri endpoint = new Uri(""); + TokenCredential credential = new DefaultAzureCredential(); + DeidentificationClient client = new DeidentificationClient(endpoint, credential); + + DeidentificationJob resource = new DeidentificationJob(new SourceStorageLocation(new Uri("http://localhost:3000"), ""), new TargetStorageLocation(new Uri("http://localhost:3000"), "")); + Operation operation = await client.CreateJobAsync(WaitUntil.Completed, "", resource); + DeidentificationJob responseData = operation.Value; + } + + [Test] + [Ignore("Only validating compilation of examples")] + public void Example_DeidentificationJob_CreateJob_AllParameters() + { + Uri endpoint = new Uri(""); + TokenCredential credential = new DefaultAzureCredential(); + DeidentificationClient client = new DeidentificationClient(endpoint, credential); + + using RequestContent content = RequestContent.Create(new + { + sourceLocation = new + { + location = "http://localhost:3000", + prefix = "", + extensions = new object[] + { +"" + }, + }, + targetLocation = new + { + location = "http://localhost:3000", + prefix = "", + }, + operation = "Redact", + dataType = "Plaintext", + redactionFormat = "", + }); + Operation operation = client.CreateJob(WaitUntil.Completed, "", content); + BinaryData responseData = operation.Value; + + JsonElement result = JsonDocument.Parse(responseData.ToStream()).RootElement; + Console.WriteLine(result.GetProperty("name").ToString()); + Console.WriteLine(result.GetProperty("sourceLocation").GetProperty("location").ToString()); + Console.WriteLine(result.GetProperty("sourceLocation").GetProperty("prefix").ToString()); + Console.WriteLine(result.GetProperty("sourceLocation").GetProperty("extensions")[0].ToString()); + Console.WriteLine(result.GetProperty("targetLocation").GetProperty("location").ToString()); + Console.WriteLine(result.GetProperty("targetLocation").GetProperty("prefix").ToString()); + Console.WriteLine(result.GetProperty("operation").ToString()); + Console.WriteLine(result.GetProperty("dataType").ToString()); + Console.WriteLine(result.GetProperty("redactionFormat").ToString()); + Console.WriteLine(result.GetProperty("status").ToString()); + Console.WriteLine(result.GetProperty("error").GetProperty("code").ToString()); + Console.WriteLine(result.GetProperty("error").GetProperty("message").ToString()); + Console.WriteLine(result.GetProperty("error").GetProperty("target").ToString()); + Console.WriteLine(result.GetProperty("error").GetProperty("innererror").GetProperty("code").ToString()); + Console.WriteLine(result.GetProperty("lastUpdatedAt").ToString()); + Console.WriteLine(result.GetProperty("createdAt").ToString()); + Console.WriteLine(result.GetProperty("startedAt").ToString()); + Console.WriteLine(result.GetProperty("summary").GetProperty("successful").ToString()); + Console.WriteLine(result.GetProperty("summary").GetProperty("failed").ToString()); + Console.WriteLine(result.GetProperty("summary").GetProperty("canceled").ToString()); + Console.WriteLine(result.GetProperty("summary").GetProperty("total").ToString()); + Console.WriteLine(result.GetProperty("summary").GetProperty("bytesProcessed").ToString()); + } + + [Test] + [Ignore("Only validating compilation of examples")] + public async Task Example_DeidentificationJob_CreateJob_AllParameters_Async() + { + Uri endpoint = new Uri(""); + TokenCredential credential = new DefaultAzureCredential(); + DeidentificationClient client = new DeidentificationClient(endpoint, credential); + + using RequestContent content = RequestContent.Create(new + { + sourceLocation = new + { + location = "http://localhost:3000", + prefix = "", + extensions = new object[] + { +"" + }, + }, + targetLocation = new + { + location = "http://localhost:3000", + prefix = "", + }, + operation = "Redact", + dataType = "Plaintext", + redactionFormat = "", + }); + Operation operation = await client.CreateJobAsync(WaitUntil.Completed, "", content); + BinaryData responseData = operation.Value; + + JsonElement result = JsonDocument.Parse(responseData.ToStream()).RootElement; + Console.WriteLine(result.GetProperty("name").ToString()); + Console.WriteLine(result.GetProperty("sourceLocation").GetProperty("location").ToString()); + Console.WriteLine(result.GetProperty("sourceLocation").GetProperty("prefix").ToString()); + Console.WriteLine(result.GetProperty("sourceLocation").GetProperty("extensions")[0].ToString()); + Console.WriteLine(result.GetProperty("targetLocation").GetProperty("location").ToString()); + Console.WriteLine(result.GetProperty("targetLocation").GetProperty("prefix").ToString()); + Console.WriteLine(result.GetProperty("operation").ToString()); + Console.WriteLine(result.GetProperty("dataType").ToString()); + Console.WriteLine(result.GetProperty("redactionFormat").ToString()); + Console.WriteLine(result.GetProperty("status").ToString()); + Console.WriteLine(result.GetProperty("error").GetProperty("code").ToString()); + Console.WriteLine(result.GetProperty("error").GetProperty("message").ToString()); + Console.WriteLine(result.GetProperty("error").GetProperty("target").ToString()); + Console.WriteLine(result.GetProperty("error").GetProperty("innererror").GetProperty("code").ToString()); + Console.WriteLine(result.GetProperty("lastUpdatedAt").ToString()); + Console.WriteLine(result.GetProperty("createdAt").ToString()); + Console.WriteLine(result.GetProperty("startedAt").ToString()); + Console.WriteLine(result.GetProperty("summary").GetProperty("successful").ToString()); + Console.WriteLine(result.GetProperty("summary").GetProperty("failed").ToString()); + Console.WriteLine(result.GetProperty("summary").GetProperty("canceled").ToString()); + Console.WriteLine(result.GetProperty("summary").GetProperty("total").ToString()); + Console.WriteLine(result.GetProperty("summary").GetProperty("bytesProcessed").ToString()); + } + + [Test] + [Ignore("Only validating compilation of examples")] + public void Example_DeidentificationJob_CreateJob_AllParameters_Convenience() + { + Uri endpoint = new Uri(""); + TokenCredential credential = new DefaultAzureCredential(); + DeidentificationClient client = new DeidentificationClient(endpoint, credential); + + DeidentificationJob resource = new DeidentificationJob(new SourceStorageLocation(new Uri("http://localhost:3000"), "") + { + Extensions = { "" }, + }, new TargetStorageLocation(new Uri("http://localhost:3000"), "")) + { + Operation = OperationType.Redact, + DataType = DocumentDataType.Plaintext, + RedactionFormat = "", + }; + Operation operation = client.CreateJob(WaitUntil.Completed, "", resource); + DeidentificationJob responseData = operation.Value; + } + + [Test] + [Ignore("Only validating compilation of examples")] + public async Task Example_DeidentificationJob_CreateJob_AllParameters_Convenience_Async() + { + Uri endpoint = new Uri(""); + TokenCredential credential = new DefaultAzureCredential(); + DeidentificationClient client = new DeidentificationClient(endpoint, credential); + + DeidentificationJob resource = new DeidentificationJob(new SourceStorageLocation(new Uri("http://localhost:3000"), "") + { + Extensions = { "" }, + }, new TargetStorageLocation(new Uri("http://localhost:3000"), "")) + { + Operation = OperationType.Redact, + DataType = DocumentDataType.Plaintext, + RedactionFormat = "", + }; + Operation operation = await client.CreateJobAsync(WaitUntil.Completed, "", resource); + DeidentificationJob responseData = operation.Value; + } + } +} diff --git a/sdk/healthdataaiservices/Azure.Health.Deidentification/tests/Tests/Helpers/DeidentificationTestBase.cs b/sdk/healthdataaiservices/Azure.Health.Deidentification/tests/Tests/Helpers/DeidentificationTestBase.cs new file mode 100644 index 000000000000..9a173d3f4693 --- /dev/null +++ b/sdk/healthdataaiservices/Azure.Health.Deidentification/tests/Tests/Helpers/DeidentificationTestBase.cs @@ -0,0 +1,32 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using Azure.Core.TestFramework; +using Azure.Core.TestFramework.Models; +using Azure.Identity; + +namespace Azure.Health.Deidentification.Tests +{ + public class DeidentificationTestBase : RecordedTestBase + { + public DeidentificationTestBase(bool isAsync) : base(isAsync) + { + BodyKeySanitizers.Add(new BodyKeySanitizer("$..location") { Value = DeidentificationTestEnvironment.FakeStorageLocation }); + BodyKeySanitizers.Add(new BodyKeySanitizer("$..nextLink") { Value = DeidentificationTestEnvironment.FakeNextLink }); + UriRegexSanitizers.Add(new UriRegexSanitizer(@"net-sdk-job-\d+-[0-9_]+") { Value = DeidentificationTestEnvironment.FakeJobName }); + BodyRegexSanitizers.Add(new BodyRegexSanitizer(@"net-sdk-job-\d+-[0-9_]+") { Value = DeidentificationTestEnvironment.FakeJobName }); + } + + protected DeidentificationClient GetDeidClient() + { + return InstrumentClient( + new DeidentificationClient( + new Uri(TestEnvironment.Endpoint), + TestEnvironment.Credential, + InstrumentClientOptions(new DeidentificationClientOptions()) + ) + ); + } + } +} diff --git a/sdk/healthdataaiservices/Azure.Health.Deidentification/tests/Tests/Helpers/DeidentificationTestEnvironment.cs b/sdk/healthdataaiservices/Azure.Health.Deidentification/tests/Tests/Helpers/DeidentificationTestEnvironment.cs new file mode 100644 index 000000000000..d31a1b3b24c7 --- /dev/null +++ b/sdk/healthdataaiservices/Azure.Health.Deidentification/tests/Tests/Helpers/DeidentificationTestEnvironment.cs @@ -0,0 +1,21 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using Azure.Core.TestFramework; + +namespace Azure.Health.Deidentification.Tests +{ + public class DeidentificationTestEnvironment : TestEnvironment + { + public string Endpoint => GetRecordedVariable("DEID_SERVICE_ENDPOINT"); + + public static string FakeNextLink => "https://deidservicetest.api.deid.azure.com/jobs?api-version=2000-01-01-preview&continuationToken=1234"; + public static string FakeStorageLocation => "https://fakeblobstorage.blob.core.windows.net/container"; + public static string FakeJobName => "net-sdk-job-1234"; + + public string GetStorageAccountLocation() + { + return $"https://{GetRecordedVariable("STORAGE_ACCOUNT_NAME")}.blob.core.windows.net/{GetRecordedVariable("STORAGE_CONTAINER_NAME")}"; + } + } +} diff --git a/sdk/healthdataaiservices/Azure.Health.Deidentification/tests/Tests/JobOperationsTest.cs b/sdk/healthdataaiservices/Azure.Health.Deidentification/tests/Tests/JobOperationsTest.cs new file mode 100644 index 000000000000..657363de759a --- /dev/null +++ b/sdk/healthdataaiservices/Azure.Health.Deidentification/tests/Tests/JobOperationsTest.cs @@ -0,0 +1,229 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +using System; +using System.Threading; +using System.Threading.Tasks; +using Azure.Core.TestFramework; +using Azure.Identity; +using NUnit.Framework; + +namespace Azure.Health.Deidentification.Tests +{ + [TestFixture] + public class JobOperationsTest : DeidentificationTestBase + { + private const string OUTPUT_FOLDER = "_output"; + + public JobOperationsTest() : base(true) + { + } + + public JobOperationsTest(bool isAsync) : base(isAsync) + { + } + + [Test] + public async Task CreateJobAsync_SucceedsWithExpectedFields() + { + DeidentificationClient client = GetDeidClient(); + + string jobName = GenerateJobName(); + const string inputPrefix = "example_patient_1"; + + DeidentificationJob job = new() + { + SourceLocation = new SourceStorageLocation(new Uri(TestEnvironment.GetStorageAccountLocation()), inputPrefix), + TargetLocation = new TargetStorageLocation(new Uri(TestEnvironment.GetStorageAccountLocation()), OUTPUT_FOLDER), + DataType = DocumentDataType.Plaintext, + Operation = OperationType.Surrogate + }; + + job = (await client.CreateJobAsync(WaitUntil.Started, jobName, job)).Value; + + Assert.IsNotNull(job); + Assert.AreEqual(jobName, job.Name); + Assert.IsNotNull(job.CreatedAt); + Assert.IsNotNull(job.LastUpdatedAt); + Assert.IsNull(job.StartedAt); + Assert.AreEqual(JobStatus.NotStarted, job.Status); + Assert.IsNull(job.Error); + Assert.IsNull(job.RedactionFormat); + Assert.IsNull(job.Summary); + Assert.AreEqual(inputPrefix, job.SourceLocation.Prefix); + Assert.IsTrue(job.SourceLocation.Location.ToString().Contains("blob.core.windows.net")); + Assert.AreEqual(OUTPUT_FOLDER, job.TargetLocation.Prefix); + Assert.IsTrue(job.TargetLocation.Location.ToString().Contains("blob.core.windows.net")); + } + + [Test] + public async Task CreateThenList_JobExists_ContainsExpectedFields() + { + DeidentificationClient client = GetDeidClient(); + + string jobName = GenerateJobName(); + const string inputPrefix = "example_patient_1"; + + DeidentificationJob job = new() + { + SourceLocation = new SourceStorageLocation(new Uri(TestEnvironment.GetStorageAccountLocation()), inputPrefix), + TargetLocation = new TargetStorageLocation(new Uri(TestEnvironment.GetStorageAccountLocation()), OUTPUT_FOLDER), + DataType = DocumentDataType.Plaintext, + Operation = OperationType.Surrogate + }; + + job = (await client.CreateJobAsync(WaitUntil.Started, jobName, job)).Value; + + // Test list jobs + var jobs = client.GetJobsAsync().GetAsyncEnumerator(); + + bool jobFound = false; + int jobsToLookThrough = 10; + while (await jobs.MoveNextAsync()) + { + if (jobs.Current.Name == jobName) + { + jobFound = true; + Assert.IsNotNull(jobs.Current.CreatedAt); + Assert.IsNotNull(jobs.Current.LastUpdatedAt); + Assert.IsNull(jobs.Current.StartedAt); + Assert.AreEqual(JobStatus.NotStarted, jobs.Current.Status); + Assert.IsNull(jobs.Current.Error); + Assert.IsNull(jobs.Current.RedactionFormat); + Assert.IsNull(jobs.Current.Summary); + Assert.AreEqual(inputPrefix, jobs.Current.SourceLocation.Prefix); + Assert.IsTrue(jobs.Current.SourceLocation.Location.ToString().Contains("blob.core.windows.net")); + Assert.AreEqual(OUTPUT_FOLDER, jobs.Current.TargetLocation.Prefix); + Assert.IsTrue(jobs.Current.SourceLocation.Location.ToString().Contains("blob.core.windows.net")); + } + + if (jobFound || --jobsToLookThrough <= 0) + { + break; + } + } + Assert.IsTrue(jobFound, "Job not found in list of jobs."); + } + + [Test] + public async Task JobE2E_WaitUntil_Success() + { + DeidentificationClient client = GetDeidClient(); + + string jobName = GenerateJobName(); + const string inputPrefix = "example_patient_1"; + + DeidentificationJob job = new() + { + SourceLocation = new SourceStorageLocation(new Uri(TestEnvironment.GetStorageAccountLocation()), inputPrefix), + TargetLocation = new TargetStorageLocation(new Uri(TestEnvironment.GetStorageAccountLocation()), OUTPUT_FOLDER), + DataType = DocumentDataType.Plaintext, + Operation = OperationType.Surrogate + }; + + job = (await client.CreateJobAsync(WaitUntil.Completed, jobName, job)).Value; + job = await client.GetJobAsync(jobName); + + Assert.AreEqual(JobStatus.Succeeded, job.Status); + Assert.IsNotNull(job.StartedAt); + Assert.IsNotNull(job.Summary); + Assert.AreEqual(2, job.Summary.Total); + Assert.AreEqual(2, job.Summary.Successful); + + // Check file reports. + var reports = client.GetJobDocumentsAsync(jobName).GetAsyncEnumerator(); + int reportCount = 0; + while (await reports.MoveNextAsync()) + { + reportCount++; + Assert.IsTrue(reports.Current.Input.Path.StartsWith(inputPrefix)); + Assert.AreEqual(OperationState.Succeeded, reports.Current.Status); + Assert.IsTrue(reports.Current.Output.Path.StartsWith(OUTPUT_FOLDER)); + Assert.IsTrue(reports.Current.Id.Length == 36); // Is Guid. + } + Assert.AreEqual(2, reportCount); + } + + [Test] + public async Task JobE2E_CancelDeleteFlow_DeletesJob() + { + DeidentificationClient client = GetDeidClient(); + + string jobName = GenerateJobName(); + const string inputPrefix = "example_patient_1"; + + DeidentificationJob job = new() + { + SourceLocation = new SourceStorageLocation(new Uri(TestEnvironment.GetStorageAccountLocation()), inputPrefix), + TargetLocation = new TargetStorageLocation(new Uri(TestEnvironment.GetStorageAccountLocation()), OUTPUT_FOLDER), + DataType = DocumentDataType.Plaintext, + Operation = OperationType.Surrogate + }; + + job = (await client.CreateJobAsync(WaitUntil.Started, jobName, job)).Value; + + do + { + job = await client.GetJobAsync(jobName); + if (Mode != RecordedTestMode.Playback) + { + await Task.Delay(2000); + } + } + while (job.Status == JobStatus.NotStarted); + + string errorMessage = job.Error is not null ? job.Error.Message : "No Error Message Available."; + Assert.AreEqual(JobStatus.Running, job.Status, $"Job should be running. Error: {errorMessage}"); + + job = await client.CancelJobAsync(jobName); + Assert.AreEqual(JobStatus.Canceled, job.Status); + + await client.DeleteJobAsync(jobName); + + Assert.ThrowsAsync(async () => await client.GetJobAsync(jobName)); + } + + [Test] + public async Task JobE2E_CannotAccessStorage_ThrowsExpectedException() + { + DeidentificationClient client = GetDeidClient(); + + string jobName = GenerateJobName(); + const string inputPrefix = "example_patient_1"; + + string disfunctionalStorageUri = TestEnvironment.GetStorageAccountLocation().Substring(0, TestEnvironment.GetStorageAccountLocation().Length - 5); + + DeidentificationJob job = new() + { + SourceLocation = new SourceStorageLocation(new Uri(disfunctionalStorageUri), inputPrefix), + TargetLocation = new TargetStorageLocation(new Uri(disfunctionalStorageUri), OUTPUT_FOLDER), + DataType = DocumentDataType.Plaintext, + Operation = OperationType.Surrogate + }; + + Type expectedExceptionType = Mode == RecordedTestMode.Playback ? typeof(InvalidOperationException) : typeof(RequestFailedException); + Assert.ThrowsAsync(expectedExceptionType, async () => await client.CreateJobAsync(WaitUntil.Completed, jobName, job)); + job = await client.GetJobAsync(jobName); + + Assert.AreEqual(JobStatus.Failed, job.Status); + Assert.IsNotNull(job.Error); + Assert.AreEqual("JobValidationError", job.Error.Code); + Assert.IsTrue(job.Error.Message.Length > 10); // Arbitrary length choice. + } + + private string GenerateJobName() + { + if (Mode == RecordedTestMode.Playback) + { + return DeidentificationTestEnvironment.FakeJobName; + } + + string netVersion = Environment.Version.ToString().Replace(".", "_"); + netVersion = netVersion.Length > 7 ? netVersion.Substring(0, 7) : netVersion; + string jobName = "net-sdk-job-" + Recording.GenerateId() + "-" + netVersion; + return jobName; + } + } +} diff --git a/sdk/healthdataaiservices/Azure.Health.Deidentification/tests/Tests/RealtimeOperationsTest.cs b/sdk/healthdataaiservices/Azure.Health.Deidentification/tests/Tests/RealtimeOperationsTest.cs new file mode 100644 index 000000000000..5968b1606ae5 --- /dev/null +++ b/sdk/healthdataaiservices/Azure.Health.Deidentification/tests/Tests/RealtimeOperationsTest.cs @@ -0,0 +1,65 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +using System; +using System.Threading; +using System.Threading.Tasks; +using Azure.Core.TestFramework; +using Azure.Identity; +using NUnit.Framework; + +namespace Azure.Health.Deidentification.Tests +{ + [TestFixture] + public class RealtimeOperationsTest : DeidentificationTestBase + { + public RealtimeOperationsTest() : base(true) + { + } + + public RealtimeOperationsTest(bool isAsync) : base(isAsync) + { + } + + [Test] + public async Task Realtime_Surrogate_ReturnsExcepted() + { + DeidentificationClient client = GetDeidClient(); + + string input = "Hello, my name is John Smith."; + DeidentificationContent content = new(input); + + DeidentificationResult result = await client.DeidentifyAsync(content); + + Assert.IsNull(result.TaggerResult, "On Surrogate Operation, expect TaggerResult to be null."); + Assert.IsNotNull(result.OutputText, "On Surrogate Operation, expect OutputText to be not null."); + Assert.IsTrue(result.OutputText.Length > 21, "Expected output text to be longer than the tag and a single character for each name token."); + Assert.AreNotEqual(input, result.OutputText, "Expected output text to be different from input text."); + } + + + [Test] + public async Task Realtime_Tag_ReturnsExcepted() + { + DeidentificationClient client = GetDeidClient(); + + string input = "Hello, my name is John Smith."; + DeidentificationContent content = new(input, OperationType.Tag, null, null, null); + + DeidentificationResult result = await client.DeidentifyAsync(content); + + Assert.IsNotNull(result.TaggerResult, "On Tag Operation, expect TaggerResult to be not null."); + Assert.IsNull(result.OutputText, "On Tag Operation, expect OutputText to be null."); + Assert.IsNull(result.TaggerResult.Etag, "Expected Etag to be null."); + Assert.IsNull(result.TaggerResult.Path, "Expected Path to be null."); + + Assert.IsTrue(result.TaggerResult.Entities.Count > 0, "Expected TaggerResult to have at least one tag."); + Assert.IsTrue(result.TaggerResult.Entities[0].Category == PhiCategory.Doctor || result.TaggerResult.Entities[0].Category == PhiCategory.Patient, "Expected first tag to be a patient/doctor."); + Assert.IsTrue(result.TaggerResult.Entities[0].Text == "John Smith", "Expected first tag to be 'John Smith'."); + Assert.IsTrue(result.TaggerResult.Entities[0].Offset.Utf16 == 18, "Expected first tag to start at index 18."); + Assert.IsTrue(result.TaggerResult.Entities[0].Length.Utf16 == 10, "Expected first tag to be 10 characters long."); + } + } +} diff --git a/sdk/healthdataaiservices/Azure.Health.Deidentification/tests/samples/Sample1_HelloWorld.cs b/sdk/healthdataaiservices/Azure.Health.Deidentification/tests/samples/Sample1_HelloWorld.cs new file mode 100644 index 000000000000..92713d80bcb2 --- /dev/null +++ b/sdk/healthdataaiservices/Azure.Health.Deidentification/tests/samples/Sample1_HelloWorld.cs @@ -0,0 +1,42 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#nullable disable + +using System; +using System.Text.Json; +using System.Threading.Tasks; +using Azure.Core; +using Azure.Core.TestFramework; +using Azure.Health.Deidentification.Tests; +using Azure.Identity; +using NUnit.Framework; + +namespace Azure.Health.Deidentification.Samples +{ + public partial class Samples_DeidentificationClient : SamplesBase + { + [Test] + public void HelloWorld() + { + const string serviceEndpoint = "https://example.api.cac001.deid.azure.com"; + TokenCredential credential = TestEnvironment.Credential; + + #region Snippet:AzHealthDeidSample1_HelloWorld + DeidentificationClient client = new( + new Uri(serviceEndpoint), + credential, + new DeidentificationClientOptions() + ); + #endregion + + #region Snippet:AzHealthDeidSample1_CreateRequest + DeidentificationContent content = new("Hello, John!", OperationType.Surrogate, DocumentDataType.Plaintext, null, null); + + Response result = client.Deidentify(content); + string outputString = result.Value.OutputText; + Console.WriteLine(outputString); // Hello, Tom! + #endregion + } + } +} diff --git a/sdk/healthdataaiservices/Azure.Health.Deidentification/tests/samples/Sample1_HelloWorldAsync.cs b/sdk/healthdataaiservices/Azure.Health.Deidentification/tests/samples/Sample1_HelloWorldAsync.cs new file mode 100644 index 000000000000..f104ede8ba51 --- /dev/null +++ b/sdk/healthdataaiservices/Azure.Health.Deidentification/tests/samples/Sample1_HelloWorldAsync.cs @@ -0,0 +1,42 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#nullable disable + +using System; +using System.Text.Json; +using System.Threading.Tasks; +using Azure.Core; +using Azure.Core.TestFramework; +using Azure.Health.Deidentification.Tests; +using Azure.Identity; +using NUnit.Framework; + +namespace Azure.Health.Deidentification.Samples +{ + public partial class Samples_DeidentificationClient : SamplesBase + { + [Test] + public async void HelloWorldAsync() + { + const string serviceEndpoint = "https://example.api.cac001.deid.azure.com"; + TokenCredential credential = TestEnvironment.Credential; + + #region Snippet:AzHealthDeidSample1Async_HelloWorld + DeidentificationClient client = new( + new Uri(serviceEndpoint), + credential, + new DeidentificationClientOptions() + ); + #endregion + + #region Snippet:AzHealthDeidSample1Async_CreateRequest + DeidentificationContent content = new("Hello, John!", OperationType.Surrogate, DocumentDataType.Plaintext, null, null); + + Response result = await client.DeidentifyAsync(content); + string outputString = result.Value.OutputText; + Console.WriteLine(outputString); // Hello, Tom! + #endregion + } + } +} diff --git a/sdk/healthdataaiservices/Azure.Health.Deidentification/tests/samples/Sample2_CreateAndRunJob.cs b/sdk/healthdataaiservices/Azure.Health.Deidentification/tests/samples/Sample2_CreateAndRunJob.cs new file mode 100644 index 000000000000..b59716824607 --- /dev/null +++ b/sdk/healthdataaiservices/Azure.Health.Deidentification/tests/samples/Sample2_CreateAndRunJob.cs @@ -0,0 +1,47 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#nullable disable + +using System; +using System.Text.Json; +using System.Threading.Tasks; +using Azure.Core; +using Azure.Core.TestFramework; +using Azure.Health.Deidentification.Tests; +using Azure.Identity; +using NUnit.Framework; + +namespace Azure.Health.Deidentification.Samples +{ + public partial class Samples_DeidentificationClient : SamplesBase + { + [Test] + public void CreateAndRunJob() + { + const string serviceEndpoint = "https://example.api.cac001.deid.azure.com"; + TokenCredential credential = TestEnvironment.Credential; + + DeidentificationClient client = new( + new Uri(serviceEndpoint), + credential, + new DeidentificationClientOptions() + ); + + string storageAccountUrl = TestEnvironment.GetStorageAccountLocation(); + + #region Snippet:AzHealthDeidSample2_CreateJob + DeidentificationJob job = new() + { + SourceLocation = new SourceStorageLocation(new Uri(storageAccountUrl), "folder1/"), + TargetLocation = new TargetStorageLocation(new Uri(storageAccountUrl), "output_path"), + DataType = DocumentDataType.Plaintext, + Operation = OperationType.Surrogate + }; + + job = client.CreateJob(WaitUntil.Started, "my-job-1", job).Value; + Console.WriteLine($"Job status: {job.Status}"); // Job status: NotStarted + #endregion + } + } +} diff --git a/sdk/healthdataaiservices/Azure.Health.Deidentification/tests/samples/Sample2_CreateAndRunJobAsync.cs b/sdk/healthdataaiservices/Azure.Health.Deidentification/tests/samples/Sample2_CreateAndRunJobAsync.cs new file mode 100644 index 000000000000..d18c054a1d45 --- /dev/null +++ b/sdk/healthdataaiservices/Azure.Health.Deidentification/tests/samples/Sample2_CreateAndRunJobAsync.cs @@ -0,0 +1,47 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#nullable disable + +using System; +using System.Text.Json; +using System.Threading.Tasks; +using Azure.Core; +using Azure.Core.TestFramework; +using Azure.Health.Deidentification.Tests; +using Azure.Identity; +using NUnit.Framework; + +namespace Azure.Health.Deidentification.Samples +{ + public partial class Samples_DeidentificationClient : SamplesBase + { + [Test] + public async void CreateAndRunJobAsync() + { + const string serviceEndpoint = "https://example.api.cac001.deid.azure.com"; + TokenCredential credential = TestEnvironment.Credential; + + DeidentificationClient client = new( + new Uri(serviceEndpoint), + credential, + new DeidentificationClientOptions() + ); + + string storageAccountUrl = TestEnvironment.GetStorageAccountLocation(); + + #region Snippet:AzHealthDeidSample2Async_CreateJob + DeidentificationJob job = new() + { + SourceLocation = new SourceStorageLocation(new Uri(storageAccountUrl), "folder1/"), + TargetLocation = new TargetStorageLocation(new Uri(storageAccountUrl), "output_path"), + DataType = DocumentDataType.Plaintext, + Operation = OperationType.Surrogate + }; + + job = (await client.CreateJobAsync(WaitUntil.Completed, "my-job-1", job)).Value; + Console.WriteLine($"Job Status: {job.Status}"); // Job Status: Completed + #endregion + } + } +} diff --git a/sdk/healthdataaiservices/Azure.Health.Deidentification/tests/samples/Sample3_ListJobs.cs b/sdk/healthdataaiservices/Azure.Health.Deidentification/tests/samples/Sample3_ListJobs.cs new file mode 100644 index 000000000000..053af6731e20 --- /dev/null +++ b/sdk/healthdataaiservices/Azure.Health.Deidentification/tests/samples/Sample3_ListJobs.cs @@ -0,0 +1,42 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#nullable disable + +using System; +using System.Text.Json; +using System.Threading.Tasks; +using Azure.Core; +using Azure.Core.TestFramework; +using Azure.Health.Deidentification.Tests; +using Azure.Identity; +using NUnit.Framework; + +namespace Azure.Health.Deidentification.Samples +{ + public partial class Samples_DeidentificationClient : SamplesBase + { + [Test] + public void ListJobs() + { + const string serviceEndpoint = "https://example.api.cac001.deid.azure.com"; + TokenCredential credential = TestEnvironment.Credential; + + DeidentificationClient client = new( + new Uri(serviceEndpoint), + credential, + new DeidentificationClientOptions() + ); + + #region Snippet:AzHealthDeidSample3_ListJobs + Pageable jobs = client.GetJobs(); + + foreach (DeidentificationJob job in jobs) + { + Console.WriteLine($"Job Name: {job.Name}"); + Console.WriteLine($"Job Status: {job.Status}"); + } + #endregion + } + } +} diff --git a/sdk/healthdataaiservices/Azure.Health.Deidentification/tests/samples/Sample3_ListJobsAsync.cs b/sdk/healthdataaiservices/Azure.Health.Deidentification/tests/samples/Sample3_ListJobsAsync.cs new file mode 100644 index 000000000000..1d05dc3e1f2b --- /dev/null +++ b/sdk/healthdataaiservices/Azure.Health.Deidentification/tests/samples/Sample3_ListJobsAsync.cs @@ -0,0 +1,42 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#nullable disable + +using System; +using System.Text.Json; +using System.Threading.Tasks; +using Azure.Core; +using Azure.Core.TestFramework; +using Azure.Health.Deidentification.Tests; +using Azure.Identity; +using NUnit.Framework; + +namespace Azure.Health.Deidentification.Samples +{ + public partial class Samples_DeidentificationClient : SamplesBase + { + [Test] + public async void ListJobsAsync() + { + const string serviceEndpoint = "https://example.api.cac001.deid.azure.com"; + TokenCredential credential = TestEnvironment.Credential; + + DeidentificationClient client = new( + new Uri(serviceEndpoint), + credential, + new DeidentificationClientOptions() + ); + + #region Snippet:AzHealthDeidSample3Async_ListJobs + AsyncPageable jobs = client.GetJobsAsync(); + + await foreach (DeidentificationJob job in jobs) + { + Console.WriteLine($"Job Name: {job.Name}"); + Console.WriteLine($"Job Status: {job.Status}"); + } + #endregion + } + } +} diff --git a/sdk/healthdataaiservices/Azure.Health.Deidentification/tests/samples/Sample4_ListCompletedFiles.cs b/sdk/healthdataaiservices/Azure.Health.Deidentification/tests/samples/Sample4_ListCompletedFiles.cs new file mode 100644 index 000000000000..a2f710f8411e --- /dev/null +++ b/sdk/healthdataaiservices/Azure.Health.Deidentification/tests/samples/Sample4_ListCompletedFiles.cs @@ -0,0 +1,40 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#nullable disable + +using System; +using Azure.Core; +using Azure.Core.TestFramework; +using Azure.Health.Deidentification.Tests; +using NUnit.Framework; + +namespace Azure.Health.Deidentification.Samples +{ + public partial class Samples_DeidentificationClient : SamplesBase + { + [Test] + public void ListCompletedFiles() + { + const string serviceEndpoint = "https://example.api.cac001.deid.azure.com"; + TokenCredential credential = TestEnvironment.Credential; + + DeidentificationClient client = new( + new Uri(serviceEndpoint), + credential, + new DeidentificationClientOptions() + ); + + #region Snippet:AzHealthDeidSample4_ListCompletedFiles + Pageable files = client.GetJobDocuments("job-name-1"); + + foreach (DocumentDetails file in files) + { + Console.WriteLine($"File Name: {file.Input.Path}"); + Console.WriteLine($"File Status: {file.Status}"); + Console.WriteLine($"File Output Path: {file.Output.Path}"); + } + #endregion + } + } +} diff --git a/sdk/healthdataaiservices/Azure.Health.Deidentification/tests/samples/Sample4_ListCompletedFilesAsync.cs b/sdk/healthdataaiservices/Azure.Health.Deidentification/tests/samples/Sample4_ListCompletedFilesAsync.cs new file mode 100644 index 000000000000..7b6d6e67adac --- /dev/null +++ b/sdk/healthdataaiservices/Azure.Health.Deidentification/tests/samples/Sample4_ListCompletedFilesAsync.cs @@ -0,0 +1,40 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#nullable disable + +using System; +using Azure.Core; +using Azure.Core.TestFramework; +using Azure.Health.Deidentification.Tests; +using NUnit.Framework; + +namespace Azure.Health.Deidentification.Samples +{ + public partial class Samples_DeidentificationClient : SamplesBase + { + [Test] + public async void ListCompletedFilesAsync() + { + const string serviceEndpoint = "https://example.api.cac001.deid.azure.com"; + TokenCredential credential = TestEnvironment.Credential; + + DeidentificationClient client = new( + new Uri(serviceEndpoint), + credential, + new DeidentificationClientOptions() + ); + + #region Snippet:AzHealthDeidSample4Async_ListCompletedFiles + AsyncPageable files = client.GetJobDocumentsAsync("job-name-1"); + + await foreach (DocumentDetails file in files) + { + Console.WriteLine($"File Name: {file.Input.Path}"); + Console.WriteLine($"File Status: {file.Status}"); + Console.WriteLine($"File Output Path: {file.Output.Path}"); + } + #endregion + } + } +} diff --git a/sdk/healthdataaiservices/Azure.Health.Deidentification/tsp-location.yaml b/sdk/healthdataaiservices/Azure.Health.Deidentification/tsp-location.yaml new file mode 100644 index 000000000000..909f38668483 --- /dev/null +++ b/sdk/healthdataaiservices/Azure.Health.Deidentification/tsp-location.yaml @@ -0,0 +1,5 @@ +additionalDirectories: [] +repo: Azure/azure-rest-api-specs +commit: 2771da5baeee73dfd70b2a5f2813a55549c2aa73 +directory: specification/healthdataaiservices/HealthDataAIServices.DeidServices + diff --git a/sdk/healthdataaiservices/ci.yml b/sdk/healthdataaiservices/ci.yml new file mode 100644 index 000000000000..3c68e71edc17 --- /dev/null +++ b/sdk/healthdataaiservices/ci.yml @@ -0,0 +1,40 @@ +# NOTE: Please refer to https://aka.ms/azsdk/engsys/ci-yaml before editing this file. + +trigger: + branches: + include: + - master + - feature/* + - hotfix/* + - release/* + paths: + include: + - sdk/healthdataaiservices + - sdk/healthdataaiservices/test-resources.bicep + - sdk/healthdataaiservices/test-resources-post.ps1 + - sdk/healthdataaiservices/ci.yml + - sdk/healthdataaiservices/Azure.Health.Deidentification + +pr: + branches: + include: + - main + - feature/* + - hotfix/* + - release/* + paths: + include: + - sdk/healthdataaiservices + - sdk/healthdataaiservices/test-resources.bicep + - sdk/healthdataaiservices/test-resources-post.ps1 + - sdk/healthdataaiservices/ci.yml + - sdk/healthdataaiservices/Azure.Health.Deidentification + +extends: + template: /eng/pipelines/templates/stages/archetype-sdk-client.yml + parameters: + ServiceDirectory: healthdataaiservices + ArtifactName: packages + Artifacts: + - name: Azure.Health.Deidentification + safeName: AzureHealthDeidentification diff --git a/sdk/healthdataaiservices/test-resources-post.ps1 b/sdk/healthdataaiservices/test-resources-post.ps1 new file mode 100644 index 000000000000..997e08d463d7 --- /dev/null +++ b/sdk/healthdataaiservices/test-resources-post.ps1 @@ -0,0 +1,63 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +# This script is used to set up SIP Configuration domains for Azure Communication Services SIP Routing SDK GA tests + +# It is invoked by the https://github.com/Azure/azure-sdk-for-net/blob/main/eng/New-TestResources.ps1 +# script after the ARM template, defined in https://github.com/Azure/azure-sdk-for-net/blob/main/sdk/storage/test-resources.json, +# is finished being deployed. The ARM template is responsible for creating the Storage accounts needed for live tests. + +param ( + [hashtable] $DeploymentOutputs, + [string] $TenantId, + [string] $TestApplicationId, + [string] $TestApplicationSecret +) + +# Retrieve the connection string from environment variables +$resourceGroup = $DeploymentOutputs['HEALTHDATAAISERVICES_RESOURCE_GROUP'] +$endpoint = $DeploymentOutputs['HEALTHDATAAISERVICES_DEID_SERVICE_ENDPOINT'] +$storageAccountName = $DeploymentOutputs['HEALTHDATAAISERVICES_STORAGE_ACCOUNT_NAME'] +$containerName = $DeploymentOutputs['HEALTHDATAAISERVICES_STORAGE_CONTAINER_NAME'] + +# Set the local folder path to upload +$localFolderPath = "Azure.Health.Deidentification\tests\data\example_patient_1" + +# Check if the connection string is present +if ([string]::IsNullOrWhiteSpace($storageAccountName)) { + Write-Host "Error: Azure Storage Name string not found in environment variables." + exit 1 +} + +# Load the Azure Storage module +Import-Module Az.Storage + +# Connect to the storage account +$storageContext = New-AzStorageContext -StorageAccountName $storageAccountName -UseConnectedAccount + +# FIXME Remove once vpn team fixes the network acl issue +$networkRuleSet = New-Object -TypeName Microsoft.Azure.Commands.Management.Storage.Models.PSNetworkRuleSet +$networkRuleSet.DefaultAction = "Allow" +Set-AzStorageAccount -ResourceGroupName $resourceGroup -Name $storageAccountName -NetworkRuleSet $networkRuleSet + +# Sleep for 15 seconds to allow the network rule to take effect +Write-Host "[Fix] Temporary sleep to allow network rule to take effect." +Start-Sleep -Seconds 30 + +Get-AzStorageContainer -Name $containerName -Context $storageContext + +# Upload the folder and its contents to the container +# Gets last folder name + filename. example_patient_1\doctor_dictation.txt +Get-ChildItem -Path $localFolderPath -Recurse | ForEach-Object { + $relativePath = $_.FullName + $relativePath = $relativePath.Replace("\\", "\") + $folderName = ($relativePath -split "\\")[-2] # Get only the folder name. + $blobName = ($relativePath -split "\\")[-1] # Get only the file name. + $destinationBlob = $blobName -replace ":", "" + + $destinationBlob = "$folderName\$destinationBlob" + Write-Host "Uploading file '$destinationBlob'" + Set-AzStorageBlobContent -File $_.FullName -Container $containerName -Blob $destinationBlob -Context $storageContext -Force +} + +Write-Host "Folder '$localFolderPath' uploaded to container '$containerName' successfully." \ No newline at end of file diff --git a/sdk/healthdataaiservices/test-resources.bicep b/sdk/healthdataaiservices/test-resources.bicep new file mode 100644 index 000000000000..a4cccabd07c3 --- /dev/null +++ b/sdk/healthdataaiservices/test-resources.bicep @@ -0,0 +1,205 @@ +// "id": "/subscriptions/d12535ed-5958-4ce6-8350-b17b3af1d6b1/resourceGroups/oro-billing-exhaust-test/providers/Microsoft.HealthDataAIServices/DeidServices/deid-billing-test", +// "name": "deid-billing-test", +// "type": "microsoft.healthdataaiservices/deidservices", +// "location": "East US 2 EUAP", +// "tags": {}, + +@minLength(10) +param testApplicationOid string + +@minLength(6) +@maxLength(50) +@description('The base resource name.') +param baseName string + +param location string = resourceGroup().location + +@description('The location of the resource. By default, this is the same as the resource group.') +param deidLocation string = 'eastus2euap' +param deidLocationShort string = 'eup' + +param deploymentTime string = utcNow('u') + +var realtimeDataUserRoleId = 'bb6577c4-ea0a-40b2-8962-ea18cb8ecd4e' +var batchDataOwnerRoleId = '8a90fa6b-6997-4a07-8a95-30633a7c97b9' +var storageBlobDataContributor = 'ba92f5b4-2d11-453d-a403-e96b0029c9fe' + +var blobStorageName = take(toLower(replace('blob-${baseName}', '-', '')), 24) +var blobContainerName = 'container-${baseName}' +var deidServiceName = 'deid-${baseName}-${deidLocationShort}' + +resource storageAccount 'Microsoft.Storage/storageAccounts@2022-05-01' = { + name: blobStorageName + location: location + sku: { + name: 'Standard_LRS' + } + kind: 'StorageV2' + properties: { + minimumTlsVersion: 'TLS1_2' + networkAcls: { + bypass: 'AzureServices' + defaultAction: 'Deny' + ipRules: [ + { + action: 'Allow' + value: '4.0.0.0/8' + } + { + action: 'Allow' + value: '13.0.0.0/8' + } + { + action: 'Allow' + value: '20.0.0.0/8' + } + { + action: 'Allow' + value: '40.0.0.0/8' + } + { + action: 'Allow' + value: '51.0.0.0/8' + } + { + action: 'Allow' + value: '52.0.0.0/8' + } + { + action: 'Allow' + value: '65.0.0.0/8' + } + { + action: 'Allow' + value: '70.0.0.0/8' + } + { + action: 'Allow' + value: '74.234.0.0/16' + } + { + action: 'Allow' + value: '74.235.60.120/30' + } + { + action: 'Allow' + value: '94.245.0.0/16' + } + { + action: 'Allow' + value: '98.71.0.0/16' + } + { + action: 'Allow' + value: '102.133.0.0/16' + } + { + action: 'Allow' + value: '104.41.214.32/29' + } + { + action: 'Allow' + value: '104.44.0.0/16' + } + { + action: 'Allow' + value: '104.45.71.156/30' + } + { + action: 'Allow' + value: '104.208.0.0/12' + } + { + action: 'Allow' + value: '108.142.0.0/16' + } + { + action: 'Allow' + value: '131.107.0.0/16' + } + { + action: 'Allow' + value: '157.58.0.0/16' + } + { + action: 'Allow' + value: '167.220.0.0/16' + } + { + action: 'Allow' + value: '172.128.0.0/13' + } + { + action: 'Allow' + value: '191.234.97.0/26' + } + { + action: 'Allow' + value: '194.69.0.0/16' + } + { + action: 'Allow' + value: '207.46.0.0/16' + } + ] + } + } +} + +resource blobService 'Microsoft.Storage/storageAccounts/blobServices@2022-05-01' = { + parent: storageAccount + name: 'default' +} + +resource container 'Microsoft.Storage/storageAccounts/blobServices/containers@2022-05-01' = { + parent: blobService + name: blobContainerName +} + +resource storageRoleAssignment 'Microsoft.Authorization/roleAssignments@2020-04-01-preview' = { + name: guid(resourceGroup().id, storageAccount.id, testApplicationOid, storageBlobDataContributor) + properties: { + roleDefinitionId: resourceId('Microsoft.Authorization/roleDefinitions', storageBlobDataContributor) + principalId: testApplicationOid + } + scope: storageAccount +} + +resource testDeidService 'microsoft.healthdataaiservices/deidservices@2024-02-28-preview' = { + name: deidServiceName + location: deidLocation + identity: { + type: 'SystemAssigned' + } +} + +resource storageMIRoleAssignment 'Microsoft.Authorization/roleAssignments@2020-04-01-preview' = { + name: guid(resourceGroup().id, storageAccount.id, testDeidService.id, storageBlobDataContributor) + properties: { + roleDefinitionId: resourceId('Microsoft.Authorization/roleDefinitions', storageBlobDataContributor) + principalId: testDeidService.identity.principalId + } + scope: storageAccount +} + +resource realtimeRole 'Microsoft.Authorization/roleAssignments@2020-10-01-preview' = { + name: guid(resourceGroup().id, testDeidService.id, testApplicationOid, realtimeDataUserRoleId) + scope: testDeidService + properties: { + roleDefinitionId: resourceId('Microsoft.Authorization/roleDefinitions', realtimeDataUserRoleId) + principalId: testApplicationOid + } +} + +resource batchRole 'Microsoft.Authorization/roleAssignments@2020-10-01-preview' = { + name: guid(resourceGroup().id, testDeidService.id, testApplicationOid, batchDataOwnerRoleId) + scope: testDeidService + properties: { + roleDefinitionId: resourceId('Microsoft.Authorization/roleDefinitions', batchDataOwnerRoleId) + principalId: testApplicationOid + } +} + +output HEALTHDATAAISERVICES_DEID_SERVICE_ENDPOINT string = testDeidService.properties.serviceUrl +output HEALTHDATAAISERVICES_STORAGE_ACCOUNT_NAME string = storageAccount.name +output HEALTHDATAAISERVICES_STORAGE_CONTAINER_NAME string = container.name diff --git a/sdk/healthdataaiservices/tests.yml b/sdk/healthdataaiservices/tests.yml new file mode 100644 index 000000000000..51ec08bbe016 --- /dev/null +++ b/sdk/healthdataaiservices/tests.yml @@ -0,0 +1,6 @@ +trigger: none + +extends: + template: ../../eng/pipelines/templates/stages/archetype-sdk-tests.yml + parameters: + ServiceDirectory: healthdataaiservices