Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions sdk/formrecognizer/azure-ai-formrecognizer/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
- Rename parameter `useLabelFile` to `useTrainingLabels` on `beginTraining` method in FormTrainingClients
- Replace parameters `filePrefix` and `includeSubFolders` with `TrainingFileFilter` model
- Rename AccountProperties `count` and `limit` to `customModelCount` and `customModelLimit`
- Added support for AAD Authentication.

### New Features
- Support to copy a custom model from one Form Recognizer resource to another
Expand Down
112 changes: 81 additions & 31 deletions sdk/formrecognizer/azure-ai-formrecognizer/README.md

Large diffs are not rendered by default.

6 changes: 6 additions & 0 deletions sdk/formrecognizer/azure-ai-formrecognizer/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -75,5 +75,11 @@
<version>5.6.2</version> <!-- {x-version-update;org.junit.jupiter:junit-jupiter-params;external_dependency} -->
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.azure</groupId>
<artifactId>azure-identity</artifactId>
<version>1.0.6</version> <!-- {x-version-update;com.azure:azure-identity;dependency} -->
<scope>test</scope>
</dependency>
</dependencies>
</project>
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import com.azure.ai.formrecognizer.implementation.FormRecognizerClientImplBuilder;
import com.azure.core.annotation.ServiceClientBuilder;
import com.azure.core.credential.AzureKeyCredential;
import com.azure.core.credential.TokenCredential;
import com.azure.core.http.ContentType;
import com.azure.core.http.HttpClient;
import com.azure.core.http.HttpHeaders;
Expand All @@ -15,6 +16,7 @@
import com.azure.core.http.policy.AddDatePolicy;
import com.azure.core.http.policy.AddHeadersPolicy;
import com.azure.core.http.policy.AzureKeyCredentialPolicy;
import com.azure.core.http.policy.BearerTokenAuthenticationPolicy;
import com.azure.core.http.policy.HttpLogDetailLevel;
import com.azure.core.http.policy.HttpLogOptions;
import com.azure.core.http.policy.HttpLoggingPolicy;
Expand Down Expand Up @@ -43,7 +45,8 @@
*
* <p>
* The client needs the service endpoint of the Azure Form Recognizer to access the resource service.
* {@link #credential(AzureKeyCredential)} gives the builder access credential.
* {@link #credential(AzureKeyCredential)} or {@link #credential(TokenCredential) credential(TokenCredential)} gives
* the builder access credential.
* </p>
*
* <p><strong>Instantiating an asynchronous Form Recognizer Client</strong></p>
Expand Down Expand Up @@ -77,6 +80,7 @@ public final class FormRecognizerClientBuilder {
private static final String NAME = "name";
private static final String VERSION = "version";
private static final RetryPolicy DEFAULT_RETRY_POLICY = new RetryPolicy("retry-after-ms", ChronoUnit.MILLIS);
private static final String DEFAULT_SCOPE = "https://cognitiveservices.azure.com/.default";

private final ClientLogger logger = new ClientLogger(FormRecognizerClientBuilder.class);
private final List<HttpPipelinePolicy> policies;
Expand All @@ -91,6 +95,7 @@ public final class FormRecognizerClientBuilder {
private HttpPipeline httpPipeline;
private Configuration configuration;
private RetryPolicy retryPolicy;
private TokenCredential tokenCredential;
private FormRecognizerServiceVersion version;

static final String OCP_APIM_SUBSCRIPTION_KEY = "Ocp-Apim-Subscription-Key";
Expand Down Expand Up @@ -182,7 +187,9 @@ private HttpPipeline getDefaultHttpPipeline(Configuration buildConfiguration) {
policies.add(retryPolicy == null ? DEFAULT_RETRY_POLICY : retryPolicy);
policies.add(new AddDatePolicy());
// Authentications
if (credential != null) {
if (tokenCredential != null) {
policies.add(new BearerTokenAuthenticationPolicy(tokenCredential, DEFAULT_SCOPE));
} else if (credential != null) {
policies.add(new AzureKeyCredentialPolicy(OCP_APIM_SUBSCRIPTION_KEY, credential));
} else {
// Throw exception that credential and tokenCredential cannot be null
Expand Down Expand Up @@ -241,6 +248,18 @@ public FormRecognizerClientBuilder credential(AzureKeyCredential apiKeyCredentia
return this;
}

/**
* Sets the {@link TokenCredential} used to authenticate HTTP requests.
*
* @param tokenCredential {@link TokenCredential} used to authenticate HTTP requests.
* @return The updated {@link FormRecognizerClientBuilder} object.
* @throws NullPointerException If {@code tokenCredential} is null.
*/
public FormRecognizerClientBuilder credential(TokenCredential tokenCredential) {
this.tokenCredential = Objects.requireNonNull(tokenCredential, "'tokenCredential' cannot be null.");
return this;
}

/**
* Sets the logging configuration for HTTP requests and responses.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import com.azure.ai.formrecognizer.implementation.FormRecognizerClientImplBuilder;
import com.azure.core.annotation.ServiceClientBuilder;
import com.azure.core.credential.AzureKeyCredential;
import com.azure.core.credential.TokenCredential;
import com.azure.core.http.ContentType;
import com.azure.core.http.HttpClient;
import com.azure.core.http.HttpHeaders;
Expand All @@ -16,6 +17,7 @@
import com.azure.core.http.policy.AddDatePolicy;
import com.azure.core.http.policy.AddHeadersPolicy;
import com.azure.core.http.policy.AzureKeyCredentialPolicy;
import com.azure.core.http.policy.BearerTokenAuthenticationPolicy;
import com.azure.core.http.policy.HttpLogDetailLevel;
import com.azure.core.http.policy.HttpLogOptions;
import com.azure.core.http.policy.HttpLoggingPolicy;
Expand Down Expand Up @@ -43,7 +45,8 @@
*
* <p>
* The client needs the service endpoint of the Azure Form Recognizer to access the resource service.
* {@link #credential(AzureKeyCredential)} gives the builder access credential.
* {@link #credential(AzureKeyCredential)} or {@link #credential(TokenCredential) credential(TokenCredential)} gives
* the builder access credential.
* </p>
*
* <p><strong>Instantiating an asynchronous Form Training Client</strong></p>
Expand Down Expand Up @@ -91,9 +94,11 @@ public final class FormTrainingClientBuilder {
private HttpPipeline httpPipeline;
private Configuration configuration;
private RetryPolicy retryPolicy;
private TokenCredential tokenCredential;
private FormRecognizerServiceVersion version;

static final String OCP_APIM_SUBSCRIPTION_KEY = "Ocp-Apim-Subscription-Key";
private static final String DEFAULT_SCOPE = "https://cognitiveservices.azure.com/.default";
private static final String OCP_APIM_SUBSCRIPTION_KEY = "Ocp-Apim-Subscription-Key";

/**
* The constructor with defaults.
Expand Down Expand Up @@ -184,7 +189,10 @@ private HttpPipeline getDefaultHttpPipeline() {
policies.add(retryPolicy == null ? DEFAULT_RETRY_POLICY : retryPolicy);
policies.add(new AddDatePolicy());
// Authentications
if (credential != null) {
if (tokenCredential != null) {
// User token based policy
policies.add(new BearerTokenAuthenticationPolicy(tokenCredential, DEFAULT_SCOPE));
} else if (credential != null) {
policies.add(new AzureKeyCredentialPolicy(OCP_APIM_SUBSCRIPTION_KEY, credential));
} else {
// Throw exception that credential and tokenCredential cannot be null
Expand Down Expand Up @@ -243,6 +251,18 @@ public FormTrainingClientBuilder credential(AzureKeyCredential apiKeyCredential)
return this;
}

/**
* Sets the {@link TokenCredential} used to authenticate HTTP requests.
*
* @param tokenCredential {@link TokenCredential} used to authenticate HTTP requests.
* @return The updated {@link FormTrainingClientBuilder} object.
* @throws NullPointerException If {@code tokenCredential} is null.
*/
public FormTrainingClientBuilder credential(TokenCredential tokenCredential) {
this.tokenCredential = Objects.requireNonNull(tokenCredential, "'tokenCredential' cannot be null.");
return this;
}

/**
* Sets the logging configuration for HTTP requests and responses.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ The following sections provide code samples covering common scenario operations
- Manage the custom models in your account
- [ManageCustomModels][manage_custom_models] and [ManageCustomModelsAsync][manage_custom_models_async]
- Copy custom model between Form Recognizer resources
- [CopyModel](copy_model) and [CopyModelAsync](copy_model_async)
- [CopyModel][copy_model] and [CopyModelAsync][copy_model_async]

## Troubleshooting
Troubleshooting steps can be found [here][SDK_README_TROUBLESHOOTING].
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

package com.azure.ai.formrecognizer;

import com.azure.ai.formrecognizer.models.AccountProperties;
import com.azure.ai.formrecognizer.models.OperationResult;
import com.azure.ai.formrecognizer.models.RecognizedReceipt;
import com.azure.ai.formrecognizer.models.USReceipt;
import com.azure.ai.formrecognizer.training.FormTrainingClient;
import com.azure.ai.formrecognizer.training.FormTrainingClientBuilder;
import com.azure.core.credential.AzureKeyCredential;
import com.azure.core.util.polling.SyncPoller;
import com.azure.identity.DefaultAzureCredentialBuilder;

import java.io.IOException;
import java.util.List;

/**
* Samples for two supported methods of authentication in Form Recognizer and Form Training clients:
* 1) Use a Form Recognizer API key with AzureKeyCredential from azure.core.credentials
* 2) Use a token credential from azure-identity to authenticate with Azure Active Directory
*/
public class Authentication {
/**
* Main method to invoke this demo.
*
* @param args Unused arguments to the program.
*
* @throws IOException Exception thrown when there is an error in reading all the bytes from the File.
*/
public static void main(String[] args) {
/*
Set the environment variables with your own values before running the sample:

1) AZURE_FORM_RECOGNIZER_ENDPOINT - the endpoint to your Form Recognizer resource.
2) AZURE_FORM_RECOGNIZER_KEY - your Form Recognizer API key
3) AZURE_CLIENT_ID - the client ID of your active directory application.
4) AZURE_TENANT_ID - the tenant ID of your active directory application.
5) AZURE_CLIENT_SECRET - the secret of your active directory application.
*/
// Form recognizer client: Key credential
authenticationWithKeyCredentialFormRecognizerClient();
// Form recognizer client: Azure Active Directory
authenticationWithAzureActiveDirectoryFormRecognizerClient();
// Form training client: Key credential
authenticationWithKeyCredentialFormTrainingClient();
// Form training client: Azure Active Directory
authenticationWithAzureActiveDirectoryFormTrainingClient();
}

private static void authenticationWithKeyCredentialFormRecognizerClient() {
FormRecognizerClient formRecognizerClient = new FormRecognizerClientBuilder()
.credential(new AzureKeyCredential("{key}"))
.endpoint("{endpoint}")
.buildClient();
beginRecognizeCustomFormsFromUrl(formRecognizerClient);
}

private static void authenticationWithAzureActiveDirectoryFormRecognizerClient() {
FormRecognizerClient formRecognizerClient = new FormRecognizerClientBuilder()
.credential(new DefaultAzureCredentialBuilder().build())
.endpoint("{endpoint}")
.buildClient();
beginRecognizeCustomFormsFromUrl(formRecognizerClient);
}

private static void authenticationWithKeyCredentialFormTrainingClient() {
FormTrainingClient formTrainingClient = new FormTrainingClientBuilder()
.credential(new AzureKeyCredential("{key}"))
.endpoint("{endpoint}")
.buildClient();
getAccountProperties(formTrainingClient);
}

private static void authenticationWithAzureActiveDirectoryFormTrainingClient() {
FormTrainingClient formTrainingClient = new FormTrainingClientBuilder()
.credential(new DefaultAzureCredentialBuilder().build())
.endpoint("{endpoint}")
.buildClient();
getAccountProperties(formTrainingClient);
}

private static void beginRecognizeCustomFormsFromUrl(FormRecognizerClient formRecognizerClient) {
String receiptUrl = "https://raw.githubusercontent.com/Azure/azure-sdk-for-java/master/sdk/formrecognizer/azure-ai-formrecognizer/src/samples/java/sample-forms/receipts/contoso-allinone.jpg";

SyncPoller<OperationResult, List<RecognizedReceipt>> recognizeReceiptPoller =
formRecognizerClient.beginRecognizeReceiptsFromUrl(receiptUrl);

List<RecognizedReceipt> receiptPageResults = recognizeReceiptPoller.getFinalResult();

for (int i = 0; i < receiptPageResults.size(); i++) {
final RecognizedReceipt recognizedReceipt = receiptPageResults.get(i);
System.out.printf("----------- Recognized Receipt page %s -----------", i);
USReceipt usReceipt = ReceiptExtensions.asUSReceipt(recognizedReceipt);
System.out.printf("Merchant Name: %s, confidence: %.2f%n", usReceipt.getMerchantName().getFieldValue(),
usReceipt.getMerchantName().getConfidence());
System.out.printf("Merchant Address: %s, confidence: %.2f%n", usReceipt.getMerchantAddress().getName(),
usReceipt.getMerchantAddress().getConfidence());
System.out.printf("Merchant Phone Number %s, confidence: %.2f%n",
usReceipt.getMerchantPhoneNumber().getFieldValue(), usReceipt.getMerchantPhoneNumber().getConfidence());
System.out.printf("Total: %s confidence: %.2f%n", usReceipt.getTotal().getName(),
usReceipt.getTotal().getConfidence());
System.out.printf("Receipt Items: %n");
usReceipt.getReceiptItems().forEach(receiptItem -> {
if (receiptItem.getName() != null) {
System.out.printf("Name: %s, confidence: %.2f%n", receiptItem.getName().getFieldValue(),
receiptItem.getName().getConfidence());
}
if (receiptItem.getQuantity() != null) {
System.out.printf("Quantity: %s, confidence: %.2f%n", receiptItem.getQuantity().getFieldValue(),
receiptItem.getQuantity().getConfidence());
}
if (receiptItem.getPrice() != null) {
System.out.printf("Price: %s, confidence: %.2f%n", receiptItem.getPrice().getFieldValue(),
receiptItem.getPrice().getConfidence());
}
if (receiptItem.getTotalPrice() != null) {
System.out.printf("Total Price: %s, confidence: %.2f%n",
receiptItem.getTotalPrice().getFieldValue(), receiptItem.getTotalPrice().getConfidence());
}
});
System.out.print("-----------------------------------");
}
}

private static void getAccountProperties(FormTrainingClient formTrainingClient) {
AccountProperties accountProperties = formTrainingClient.getAccountProperties();
System.out.printf("Max number of models that can be trained for this account: %s%n",
accountProperties.getCustomModelLimit());
System.out.printf("Current count of trained custom models: %d%n", accountProperties.getCustomModelCount());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@
import com.azure.ai.formrecognizer.training.FormTrainingClient;
import com.azure.ai.formrecognizer.training.FormTrainingClientBuilder;
import com.azure.core.credential.AzureKeyCredential;
import com.azure.core.credential.TokenCredential;
import com.azure.core.http.rest.PagedIterable;
import com.azure.core.util.polling.SyncPoller;
import com.azure.identity.DefaultAzureCredentialBuilder;

import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
Expand All @@ -42,6 +44,17 @@ public void useAzureKeyCredentialSyncClient() {
.buildClient();
}

/**
* Code snippet for getting async client using AAD authentication.
*/
public void useAadAsyncClient() {
TokenCredential credential = new DefaultAzureCredentialBuilder().build();
FormRecognizerClient formRecognizerClient = new FormRecognizerClientBuilder()
.endpoint("{endpoint}")
.credential(credential)
.buildClient();
}

/**
* Code snippet for rotating AzureKeyCredential of the client
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,8 @@
import com.azure.ai.formrecognizer.models.RecognizedForm;
import com.azure.ai.formrecognizer.models.RecognizedReceipt;
import com.azure.ai.formrecognizer.training.FormTrainingAsyncClient;
import com.azure.ai.formrecognizer.training.FormTrainingClientBuilder;
import com.azure.core.credential.AzureKeyCredential;
import com.azure.core.exception.HttpResponseException;
import com.azure.core.http.HttpClient;
import com.azure.core.http.policy.HttpLogDetailLevel;
import com.azure.core.http.policy.HttpLogOptions;
import com.azure.core.test.TestMode;
import com.azure.core.util.polling.SyncPoller;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
Expand All @@ -32,7 +27,6 @@
import static com.azure.ai.formrecognizer.TestUtils.CUSTOM_FORM_FILE_LENGTH;
import static com.azure.ai.formrecognizer.TestUtils.DISPLAY_NAME_WITH_ARGUMENTS;
import static com.azure.ai.formrecognizer.TestUtils.FORM_LOCAL_URL;
import static com.azure.ai.formrecognizer.TestUtils.INVALID_KEY;
import static com.azure.ai.formrecognizer.TestUtils.INVALID_SOURCE_URL_ERROR;
import static com.azure.ai.formrecognizer.TestUtils.INVALID_URL;
import static com.azure.ai.formrecognizer.TestUtils.LAYOUT_FILE_LENGTH;
Expand Down Expand Up @@ -60,28 +54,12 @@ static void afterAll() {

private FormRecognizerAsyncClient getFormRecognizerAsyncClient(HttpClient httpClient,
FormRecognizerServiceVersion serviceVersion) {
FormRecognizerClientBuilder builder = new FormRecognizerClientBuilder()
.endpoint(getEndpoint()).httpClient(httpClient == null
? interceptorManager.getPlaybackClient() : httpClient)
.httpLogOptions(new HttpLogOptions().setLogLevel(HttpLogDetailLevel.BODY_AND_HEADERS))
.serviceVersion(serviceVersion).addPolicy(interceptorManager.getRecordPolicy());
AzureKeyCredential credential = (getTestMode() == TestMode.PLAYBACK) ? new AzureKeyCredential(INVALID_KEY)
: new AzureKeyCredential(getApiKey());
builder.credential(credential);
return builder.buildAsyncClient();
return getFormRecognizerClientBuilder(httpClient, serviceVersion).buildAsyncClient();
}

private FormTrainingAsyncClient getFormTrainingAsyncClient(HttpClient httpClient,
FormRecognizerServiceVersion serviceVersion) {
FormTrainingClientBuilder builder = new FormTrainingClientBuilder()
.endpoint(getEndpoint()).httpClient(httpClient == null
? interceptorManager.getPlaybackClient() : httpClient)
.httpLogOptions(new HttpLogOptions().setLogLevel(HttpLogDetailLevel.BODY_AND_HEADERS))
.serviceVersion(serviceVersion).addPolicy(interceptorManager.getRecordPolicy());
AzureKeyCredential credential = (getTestMode() == TestMode.PLAYBACK) ? new AzureKeyCredential(INVALID_KEY)
: new AzureKeyCredential(getApiKey());
builder.credential(credential);
return builder.buildAsyncClient();
return getFormTrainingClientBuilder(httpClient, serviceVersion).buildAsyncClient();
}
/**
* Verifies receipt data for a document using source as file url.
Expand Down
Loading