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
Original file line number Diff line number Diff line change
Expand Up @@ -267,14 +267,14 @@

<!-- Use the logger in a Utility static method. -->
<suppress checks="com.azure.tools.checkstyle.checks.GoodLoggingCheck" files="com.azure.ai.formrecognizer.Transforms.java" />
<suppress checks="com.azure.tools.checkstyle.checks.GoodLoggingCheck" files="com.azure.ai.formrecognizer.CustomModelTransforms.java" />
<suppress checks="com.azure.tools.checkstyle.checks.GoodLoggingCheck" files="com.azure.ai.formrecognizer.training.CustomModelTransforms.java" />
<suppress checks="com.azure.tools.checkstyle.checks.GoodLoggingCheck" files="com.azure.ai.formrecognizer.implementation.Utility.java" />

<!-- Common vocabulary error for LRO methods starting with begin* https://github.com/Azure/azure-sdk-for-java/issues/10147 -->
<suppress checks="com.azure.tools.checkstyle.checks.ServiceClientCheck" files="com.azure.ai.formrecognizer.FormRecognizerAsyncClient.java" />
<suppress checks="com.azure.tools.checkstyle.checks.ServiceClientCheck" files="com.azure.ai.formrecognizer.FormRecognizerClient.java" />
<suppress checks="com.azure.tools.checkstyle.checks.ServiceClientCheck" files="com.azure.ai.formrecognizer.FormTrainingClient.java" />
<suppress checks="com.azure.tools.checkstyle.checks.ServiceClientCheck" files="com.azure.ai.formrecognizer.FormTrainingAsyncClient.java" />
<suppress checks="com.azure.tools.checkstyle.checks.ServiceClientCheck" files="com.azure.ai.formrecognizer.training.FormTrainingClient.java" />
<suppress checks="com.azure.tools.checkstyle.checks.ServiceClientCheck" files="com.azure.ai.formrecognizer.training.FormTrainingAsyncClient.java" />

<!-- Throws a non-runtime exception -->
<suppress checks="com.azure.tools.checkstyle.checks.ThrowFromClientLogger"
Expand Down
6 changes: 6 additions & 0 deletions sdk/formrecognizer/azure-ai-formrecognizer/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@

## 1.0.0-beta.3 (Unreleased)

FormTraining Client updates:
- Adopt the `training` namespace for Form Recognizer Training Clients
- Rename parameter `fileSourceUrl` to `trainingFilesUrl` on `beginTraining` method in FormTrainingClients
- Rename parameter `useLabelFile` to `useTrainingLabels` on `beginTraining` method in FormTrainingClients
- Replace parameters `filePrefix` and `includeSubFolders` with `TrainModelOptions` model
- Rename AccountProperties `count` and `limit` to `customModelCount` and `customModelLimit`

## 1.0.0-beta.2 (2020-05-06)
- Fixed Receipt type bug to select the valueString field via fieldValue.
Expand Down
22 changes: 11 additions & 11 deletions sdk/formrecognizer/azure-ai-formrecognizer/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ To use AzureKeyCredential authentication, provide the [key][key] as a string to
az cognitiveservices account keys list --resource-group <your-resource-group-name> --name <your-resource-name>
```
Use the API key as the credential parameter to authenticate the client:
<!-- embedme ./src/samples/java/com/azure/ai/formrecognizer/ReadmeSamples.java#L37-L40 -->
<!-- embedme ./src/samples/java/com/azure/ai/formrecognizer/ReadmeSamples.java#L38-L41 -->
```java
FormRecognizerClient formRecognizerClient = new FormRecognizerClientBuilder()
.credential(new AzureKeyCredential("{key}"))
Expand All @@ -83,7 +83,7 @@ FormRecognizerClient formRecognizerClient = new FormRecognizerClientBuilder()
```
The Azure Form Recognizer client library provides a way to **rotate the existing API key**.

<!-- embedme ./src/samples/java/com/azure/ai/formrecognizer/ReadmeSamples.java#L47-L53 -->
<!-- embedme ./src/samples/java/com/azure/ai/formrecognizer/ReadmeSamples.java#L48-L54 -->
```java
AzureKeyCredential credential = new AzureKeyCredential("{key}");
FormRecognizerClient formRecognizerClient = new FormRecognizerClientBuilder()
Expand Down Expand Up @@ -143,7 +143,7 @@ The following section provides several code snippets covering some of the most c
### Recognize Forms Using a Custom Model
Recognize name/value pairs and table data from forms. These models are trained with your own data,
so they're tailored to your forms. You should only recognize forms of the same form type that the custom model was trained on.
<!-- embedme ./src/samples/java/com/azure/ai/formrecognizer/ReadmeSamples.java#L57-L73 -->
<!-- embedme ./src/samples/java/com/azure/ai/formrecognizer/ReadmeSamples.java#L58-L74 -->
```java
String analyzeFilePath = "{file_source_url}";
String modelId = "{custom_trained_model_id}";
Expand All @@ -166,7 +166,7 @@ recognizedForms.forEach(form -> {

### Recognize Content
Recognize text and table structures, along with their bounding box coordinates, from documents.
<!-- embedme ./src/samples/java/com/azure/ai/formrecognizer/ReadmeSamples.java#L77-L97 -->
<!-- embedme ./src/samples/java/com/azure/ai/formrecognizer/ReadmeSamples.java#L78-L98 -->
```java
String analyzeFilePath = "{file_source_url}";
SyncPoller<OperationResult, IterableStream<FormPage>> recognizeLayoutPoller =
Expand All @@ -193,7 +193,7 @@ layoutPageResults.forEach(formPage -> {

### Recognize receipts
Recognize data from a USA sales receipts using a prebuilt model.
<!-- embedme ./src/samples/java/com/azure/ai/formrecognizer/ReadmeSamples.java#L101-L118 -->
<!-- embedme ./src/samples/java/com/azure/ai/formrecognizer/ReadmeSamples.java#L102-L119 -->
```java
String receiptSourceUrl = "https://docs.microsoft.com/en-us/azure/cognitive-services/form-recognizer/media"
+ "/contoso-allinone.jpg";
Expand All @@ -219,11 +219,11 @@ receiptPageResults.forEach(recognizedReceipt -> {
Train a machine-learned model on your own form type. The resulting model will be able to recognize values from the types of forms it was trained on.
Provide a container SAS url to your Azure Storage Blob container where you're storing the training documents. See details on setting this up
in the [service quickstart documentation][quickstart_training].
<!-- embedme ./src/samples/java/com/azure/ai/formrecognizer/ReadmeSamples.java#L122-L142 -->
<!-- embedme ./src/samples/java/com/azure/ai/formrecognizer/ReadmeSamples.java#L123-L143 -->
```java
String trainingSetSource = "{unlabeled_training_set_SAS_URL}";
String trainingFilesUrl = "{training_set_SAS_URL}";
SyncPoller<OperationResult, CustomFormModel> trainingPoller =
formTrainingClient.beginTraining(trainingSetSource, false);
formTrainingClient.beginTraining(trainingFilesUrl, false);

CustomFormModel customFormModel = trainingPoller.getFinalResult();

Expand All @@ -246,13 +246,13 @@ customFormModel.getSubModels().forEach(customFormSubModel -> {

### Manage your models
Manage the custom models attached to your account.
<!-- embedme ./src/samples/java/com/azure/ai/formrecognizer/ReadmeSamples.java#L146-L175 -->
<!-- embedme ./src/samples/java/com/azure/ai/formrecognizer/ReadmeSamples.java#L147-L176 -->
```java
AtomicReference<String> modelId = new AtomicReference<>();
// First, we see how many custom models we have, and what our limit is
AccountProperties accountProperties = formTrainingClient.getAccountProperties();
System.out.printf("The account has %s custom models, and we can have at most %s custom models",
accountProperties.getCount(), accountProperties.getLimit());
accountProperties.getCustomModelCount(), accountProperties.getCustomModelLimit());

// Next, we get a paged list of all of our custom models
PagedIterable<CustomFormModelInfo> customModels = formTrainingClient.getModelInfos();
Expand Down Expand Up @@ -288,7 +288,7 @@ to provide an invalid file source URL an `ErrorResponseException` would be raise
In the following code snippet, the error is handled
gracefully by catching the exception and display the additional information about the error.

<!-- embedme ./src/samples/java/com/azure/ai/formrecognizer/ReadmeSamples.java#L182-L186 -->
<!-- embedme ./src/samples/java/com/azure/ai/formrecognizer/ReadmeSamples.java#L183-L187 -->
```java
try {
formRecognizerClient.beginRecognizeContentFromUrl("invalidSourceUrl");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import com.azure.ai.formrecognizer.models.OperationResult;
import com.azure.ai.formrecognizer.models.RecognizedForm;
import com.azure.ai.formrecognizer.models.RecognizedReceipt;
import com.azure.ai.formrecognizer.training.FormTrainingAsyncClient;
import com.azure.core.annotation.ReturnType;
import com.azure.core.annotation.ServiceClient;
import com.azure.core.annotation.ServiceMethod;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import com.azure.ai.formrecognizer.models.OperationResult;
import com.azure.ai.formrecognizer.models.RecognizedForm;
import com.azure.ai.formrecognizer.models.RecognizedReceipt;
import com.azure.ai.formrecognizer.training.FormTrainingClient;
import com.azure.core.annotation.ReturnType;
import com.azure.core.annotation.ServiceClient;
import com.azure.core.annotation.ServiceMethod;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,11 @@
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.function.BiConsumer;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import static com.azure.ai.formrecognizer.implementation.Utility.forEachWithIndex;

/**
* Helper class to convert service level models to SDK exposed models.
*/
Expand Down Expand Up @@ -159,18 +160,6 @@ static List<FormPage> toRecognizedLayout(AnalyzeResult analyzeResult, boolean in
return formPages;
}

/**
* Given an iterable will apply the indexing function to it and return the index and each item of the iterable.
*
* @param iterable the list to apply the mapping function to.
* @param biConsumer the function which accepts the index and the each value of the iterable.
* @param <T> the type of items being returned.
*/
static <T> void forEachWithIndex(Iterable<T> iterable, BiConsumer<Integer, T> biConsumer) {
int[] index = new int[]{0};
iterable.forEach(element -> biConsumer.accept(index[0]++, element));
}

/**
* Helper method to get per-page table information.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.util.function.BiConsumer;

/**
* Utility method class.
Expand All @@ -26,7 +27,7 @@ private Utility() {

/**
* Automatically detect byte buffer's content type.
*
* <p>
* Given the source: <a href="https://en.wikipedia.org/wiki/Magic_number_(programming)#Magic_numbers_in_files"></a>.
*
* @param buffer The byte buffer input.
Expand All @@ -35,8 +36,8 @@ private Utility() {
*/
public static Mono<ContentType> detectContentType(Flux<ByteBuffer> buffer) {
byte[] header = new byte[4];
int[] written = new int[] {0};
ContentType[] contentType = { ContentType.fromString("none")};
int[] written = new int[]{0};
ContentType[] contentType = {ContentType.fromString("none")};
return buffer.map(chunk -> {
final int len = chunk.remaining();
for (int i = 0; i < len; i++) {
Expand All @@ -61,15 +62,15 @@ public static Mono<ContentType> detectContentType(Flux<ByteBuffer> buffer) {
// current chunk don't have enough bytes so return true to get next Chunk if there is one.
return true;
})
.takeWhile(doContinue -> doContinue)
.then(Mono.defer(() -> {
if (contentType[0] != null) {
return Mono.just(contentType[0]);
} else {
return Mono.error(new RuntimeException("Content type could not be detected. "
+ "Should use other overload API that takes content type."));
}
}));
.takeWhile(doContinue -> doContinue)
.then(Mono.defer(() -> {
if (contentType[0] != null) {
return Mono.just(contentType[0]);
} else {
return Mono.error(new RuntimeException("Content type could not be detected. "
+ "Should use other overload API that takes content type."));
}
}));
}

private static boolean isJpeg(byte[] header) {
Expand All @@ -85,7 +86,7 @@ private static boolean isPdf(byte[] header) {

private static boolean isPng(byte[] header) {
return header[0] == (byte) 0x89
&& header[1] == (byte) 0x50
&& header[1] == (byte) 0x50
&& header[2] == (byte) 0x4e
&& header[3] == (byte) 0x47;
}
Expand All @@ -107,6 +108,7 @@ private static boolean isTiff(byte[] header) {
* InputStream.
*
* @param inputStream InputStream to back the Flux
*
* @return Flux of ByteBuffer backed by the InputStream
*/
public static Flux<ByteBuffer> toFluxByteBuffer(InputStream inputStream) {
Expand All @@ -132,6 +134,37 @@ public static Flux<ByteBuffer> toFluxByteBuffer(InputStream inputStream) {
.cache();
}

/**
* Extracts the result ID from the URL.
*
* @param operationLocation The URL specified in the 'Operation-Location' response header containing the
* resultId used to track the progress and obtain the result of the analyze operation.
*
* @return The resultId used to track the progress.
*/
public static String parseModelId(String operationLocation) {
if (!CoreUtils.isNullOrEmpty(operationLocation)) {
int lastIndex = operationLocation.lastIndexOf('/');
if (lastIndex != -1) {
return operationLocation.substring(lastIndex + 1);
}
}
throw LOGGER.logExceptionAsError(
new RuntimeException("Failed to parse operation header for result Id from: " + operationLocation));
}

/**
* Given an iterable will apply the indexing function to it and return the index and each item of the iterable.
*
* @param iterable the list to apply the mapping function to.
* @param biConsumer the function which accepts the index and the each value of the iterable.
* @param <T> the type of items being returned.
*/
public static <T> void forEachWithIndex(Iterable<T> iterable, BiConsumer<Integer, T> biConsumer) {
int[] index = new int[]{0};
iterable.forEach(element -> biConsumer.accept(index[0]++, element));
}

private static class Pair {
private ByteBuffer byteBuffer;
private int readBytes;
Expand All @@ -154,23 +187,4 @@ Pair readBytes(int cnt) {
return this;
}
}

/**
* Extracts the result ID from the URL.
*
* @param operationLocation The URL specified in the 'Operation-Location' response header containing the
* resultId used to track the progress and obtain the result of the analyze operation.
*
* @return The resultId used to track the progress.
*/
public static String parseModelId(String operationLocation) {
if (!CoreUtils.isNullOrEmpty(operationLocation)) {
int lastIndex = operationLocation.lastIndexOf('/');
if (lastIndex != -1) {
return operationLocation.substring(lastIndex + 1);
}
}
throw LOGGER.logExceptionAsError(
new RuntimeException("Failed to parse operation header for result Id from: " + operationLocation));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,31 +14,31 @@ public final class AccountProperties {
/*
* The current count of trained custom models.
*/
private final int count;
private final int customModelCount;

/*
* Max number of models that can be trained for this account.
*/
private final int limit;
private final int customModelLimit;

/**
* Constructs an AccountProperties object.
*
* @param count The current count of trained custom models.
* @param limit Max number of models that can be trained for this account.
* @param customModelCount The current count of trained custom models.
* @param customModelLimit Max number of models that can be trained for this account.
*/
public AccountProperties(final int count, final int limit) {
this.count = count;
this.limit = limit;
public AccountProperties(final int customModelCount, final int customModelLimit) {
this.customModelCount = customModelCount;
this.customModelLimit = customModelLimit;
}

/**
* Get the current count of trained custom models.
*
* @return the count value.
*/
public int getCount() {
return this.count;
public int getCustomModelCount() {
return this.customModelCount;
}

/**
Expand All @@ -47,7 +47,7 @@ public int getCount() {
*
* @return the limit value.
*/
public int getLimit() {
return this.limit;
public int getCustomModelLimit() {
return this.customModelLimit;
}
}
Loading