Skip to content

Commit

Permalink
[ai-form-recognizer] Rework samples for 3.1.0-beta.3 (#14689)
Browse files Browse the repository at this point in the history
* [ai-form-recognizer] Migrate to samples v2

* Move test-assets to assets

* Remove dirname based path computation

* Backport fix for stronglyTypedRecognizedForm to samples/v3

* Fix aka.ms links for FR data types

* Remove old typescript samples

* Use newer invoice sample document

* Rework samples and tag with metadata

* Added package.json metadata

* Fixed a tense inconsistency

* Disable generation of docs.ms metadata until GA.

* Fixed links in sample READMEs

* [min/max] Changed asset path from test-assets to assets

* addressed feedback
  • Loading branch information
witemple-msft authored Apr 5, 2021
1 parent 85c2873 commit fadd5b9
Show file tree
Hide file tree
Showing 137 changed files with 2,925 additions and 869 deletions.
2 changes: 1 addition & 1 deletion eng/tools/dependency-testing/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ async function insertTsConfigJson(targetPackagePath, testFolder) {
async function readAndReplaceSourceReferences(filePath, packageName) {
var fileContent = await packageUtils.readFile(filePath);
console.log("Reading filePath = " + filePath);
testAssetsContent = fileContent.replace('path.resolve(path.join(process.cwd(), "test-assets"','path.resolve(path.join(process.cwd(),"..","..", "test-assets"');
testAssetsContent = fileContent.replace('path.resolve(path.join(process.cwd(), "assets"','path.resolve(path.join(process.cwd(),"..","..", "assets"');
// Regex for internal references = /* ["']+[../]*src[/][a-z]+["'] */
var internalrefs = testAssetsContent.match(/[\"\']+[..//]*src[//][a-zA-Z]+[\"\']+/g);
var writeContent = "";
Expand Down
10 changes: 5 additions & 5 deletions sdk/formrecognizer/ai-form-recognizer/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -326,10 +326,10 @@ main().catch((err) => {

You are not limited to receipts! There are a few prebuilt models to choose from, each of which has its own set of supported fields.:

- Receipts, through the `beginRecognizeReceipts` method (see [the supported fields of the receipt model](https://aka.ms/azsdk/formrecognizer/receiptfields)).
- Business cards, through `beginRecognizeBusinessCards` (see [the supported fields of the business card model](https://aka.ms/azsdk/formrecognizer/businesscardfields)).
- Invoices, through `beginRecognizeInvoices` (see [the supported fields of the invoice model](https://aka.ms/azsdk/formrecognizer/invoicefields)).
- Identity Documents (such as driver licenses and passports), through `beginRecognizeIdDocuments` (see [the supported fields of the identity document model](https://aka.ms/azsdk/formrecognizer/iddocumentfields)).
- Receipts, through the `beginRecognizeReceipts` method (see [the supported fields of the receipt model](https://aka.ms/formrecognizer/receiptfields)).
- Business cards, through `beginRecognizeBusinessCards` (see [the supported fields of the business card model](https://aka.ms/formrecognizer/businesscardfields)).
- Invoices, through `beginRecognizeInvoices` (see [the supported fields of the invoice model](https://aka.ms/formrecognizer/invoicefields)).
- Identity Documents (such as driver licenses and passports), through `beginRecognizeIdDocuments` (see [the supported fields of the identity document model](https://aka.ms/formrecognizer/iddocumentfields)).

### Train a Model

Expand Down Expand Up @@ -467,7 +467,7 @@ If you'd like to contribute to this library, please read the [contributing guide
[defaultazurecredential]: https://github.com/Azure/azure-sdk-for-js/tree/master/sdk/identity/identity#defaultazurecredential
[quickstart_training]: https://docs.microsoft.com/azure/cognitive-services/form-recognizer/quickstarts/curl-train-extract#train-a-form-recognizer-model
[quickstart_labeling]: https://docs.microsoft.com/azure/cognitive-services/form-recognizer/quickstarts/label-tool
[labeled_sample]: https://github.com/Azure/azure-sdk-for-js/blob/master/sdk/formrecognizer/ai-form-recognizer/samples/typescript/src/trainLabeledModel.ts
[labeled_sample]: https://github.com/Azure/azure-sdk-for-js/blob/master/sdk/formrecognizer/ai-form-recognizer/samples/v3/typescript/src/trainLabeledModel.ts
[multi_and_single_service]: https://docs.microsoft.com/azure/cognitive-services/cognitive-services-apis-create-account?tabs=multiservice%2Cwindows
[azure_portal_create_fr_resource]: https://ms.portal.azure.com/#create/Microsoft.CognitiveServicesFormRecognizer
[azure_cli_create_fr_resource]: https://docs.microsoft.com/azure/cognitive-services/cognitive-services-apis-create-account-cli?tabs=windows
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
48 changes: 42 additions & 6 deletions sdk/formrecognizer/ai-form-recognizer/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,14 +51,14 @@
"audit": "node ../../../common/scripts/rush-audit.js && rimraf node_modules package-lock.json && npm i --package-lock-only 2>&1 && npm audit",
"build:browser": "tsc -p . && cross-env ONLY_BROWSER=true rollup -c 2>&1",
"build:node": "tsc -p . && cross-env ONLY_NODE=true rollup -c 2>&1",
"build:samples": "dev-tool samples prep && cd dist-samples && tsc -p .",
"build:samples": "echo Obsolete.",
"build:test": "tsc -p . && rollup -c 2>&1",
"build": "tsc -p . && rollup -c 2>&1 && api-extractor run --local",
"check-format": "prettier --list-different --config ../../../.prettierrc.json --ignore-path ../../../.prettierignore \"src/**/*.ts\" \"test/**/*.ts\" \"*.{js,json}\"",
"clean": "rimraf dist dist-esm dist-browser dist-test test-browser temp types *.tgz *.log",
"execute:samples": "npm run build:samples && dev-tool samples run dist-samples/javascript",
"check-format": "prettier --list-different --config ../../../.prettierrc.json --ignore-path ../../../.prettierignore \"src/**/*.ts\" \"test/**/*.ts\" \"samples-dev/**/*.ts\" \"*.{js,json}\"",
"clean": "rimraf dist* test-browser temp types *.tgz *.log test-results.*xml",
"execute:samples": "dev-tool samples run samples-dev/",
"extract-api": "tsc -p . && api-extractor run --local",
"format": "prettier --write --config ../../../.prettierrc.json --ignore-path ../../../.prettierignore \"src/**/*.ts\" \"test/**/*.ts\" \"*.{js,json}\"",
"format": "prettier --write --config ../../../.prettierrc.json --ignore-path ../../../.prettierignore \"src/**/*.ts\" \"test/**/*.ts\" \"samples-dev/**/*.ts\" \"*.{js,json}\"",
"integration-test:browser": "karma start --single-run",
"integration-test:node": "nyc mocha -r esm --require source-map-support/register --reporter ../../../common/tools/mocha-multi-reporter.js --full-trace -t 300000 \"dist-esm/test/*/{,!(browser)/**/}*.spec.js\"",
"integration-test": "npm run integration-test:node && npm run integration-test:browser",
Expand Down Expand Up @@ -136,6 +136,42 @@
"trainUnlabeledModel.js",
"copyModel.js",
"deleteAllModels.js"
]
],
"disableDocsMs": true,
"productName": "Azure Form Recognizer",
"productSlugs": [
"azure",
"azure-cognitive-services",
"azure-form-recognizer"
],
"requiredResources": {
"Azure Cognitive Services account": "https://docs.microsoft.com/azure/cognitive-services/cognitive-services-apis-create-account"
},
"extraFiles": {
"./assets/businessCard/business-card-english.jpg": [
"typescript/assets/businessCard/business-card-english.jpg",
"javascript/assets/businessCard/business-card-english.jpg"
],
"./assets/forms/Form_1.jpg": [
"typescript/assets/forms/Form_1.jpg",
"javascript/assets/forms/Form_1.jpg"
],
"./assets/forms/selection_mark_form.pdf": [
"typescript/assets/forms/selection_mark_form.pdf",
"javascript/assets/forms/selection_mark_form.pdf"
],
"./assets/idDocument/license.jpg": [
"typescript/assets/idDocument/license.jpg",
"javascript/assets/idDocument/license.jpg"
],
"./assets/invoice/sample_invoice.jpg": [
"typescript/assets/invoice/sample_invoice.jpg",
"javascript/assets/invoice/sample_invoice.jpg"
],
"./assets/receipt/contoso-allinone.jpg": [
"typescript/assets/receipt/contoso-allinone.jpg",
"javascript/assets/receipt/contoso-allinone.jpg"
]
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

/**
* This sample demonstrates how to use either an Azure Active Directory (RBAC)
* or an API Key to authenticate a FormRecognizerClient.
*
* @summary authenticate a service client using both Azure Active Directory
* and an API key
* @azsdk-weight 50
*/

// To use an API Key, import `AzureKeyCredential` from the Form Recognizer package
import { FormRecognizerClient, AzureKeyCredential } from "@azure/ai-form-recognizer";

// To use Azure AD, import `DefaultAzureCredential` from the `@azure/identity` package
import { DefaultAzureCredential } from "@azure/identity";

import * as fs from "fs";

// Load the .env file if it exists
import * as dotenv from "dotenv";
dotenv.config();

// You will need to set this environment variables or edit the following values
const endpoint = process.env["FORM_RECOGNIZER_ENDPOINT"] ?? "<cognitive services endpoint>";

/**
* Create a client using Azure Active Directory to authenticate
*/
async function useAad() {
console.log("-- Azure Active Directory --");

// DefaultAzureCredential expects the following three environment variables:
// - AZURE_TENANT_ID: The tenant ID in Azure Active Directory
// - AZURE_CLIENT_ID: The application (client) ID registered in the AAD tenant
// - AZURE_CLIENT_SECRET: The client secret for the registered application
const credential = new DefaultAzureCredential();

const client = new FormRecognizerClient(endpoint, credential);

await recognizeContentWithClient(client);
}

/**
* Create a client using an API Key (Cognitive Services Subscription Key) to authenticate.
*/
async function useApiKey() {
console.log("-- API Key --");

// If using an API Key, you will need to set this environment variable
const apiKey = process.env["FORM_RECOGNIZER_API_KEY"] ?? "<api key>";

const credential = new AzureKeyCredential(apiKey);

const client = new FormRecognizerClient(endpoint, credential);

await recognizeContentWithClient(client);
}

/**
* This function will use the client generated by `useApiKey` and `useAad`
* for content recognition and print its output.
*/
async function recognizeContentWithClient(client: FormRecognizerClient) {
const fileName = "./assets/forms/Form_1.jpg";

if (!fs.existsSync(fileName)) {
throw new Error(`Expecting file ${fileName} exists`);
}

const readStream = fs.createReadStream(fileName);

const poller = await client.beginRecognizeContent(readStream);
const pages = await poller.pollUntilDone();

if (!pages || pages.length === 0) {
throw new Error("Expected to receive a non-empty list of pages!");
}

for (const page of pages!) {
console.log(
`Page ${page.pageNumber}: width="${page.width}", and height="${page.height}" (unit: ${page.unit})`
);
for (const table of page.tables!) {
for (const cell of table.cells) {
console.log(`cell [${cell.rowIndex},${cell.columnIndex}] has text "${cell.text}"`);
}
}
}
}

export async function main() {
console.log("== Client Authentication Methods Sample ==");

await useAad();

await useApiKey();
}

main().catch((err) => {
console.error("The sample encountered an error:", err);
});
59 changes: 59 additions & 0 deletions sdk/formrecognizer/ai-form-recognizer/samples-dev/copyModel.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

/**
* This sample demonstrates how to copy a model from a source Form Recognizer resource
* to a target Form Recognizer resource.
*
* @summary copy a custom model from one Form Recognizer resource to another
* @azsdk-weight 60
*/

import { FormTrainingClient, AzureKeyCredential } from "@azure/ai-form-recognizer";

// Load the .env file if it exists
import * as dotenv from "dotenv";
dotenv.config();

export async function main() {
// You will need to set these environment variables or edit the following values
// information about the source Form Recognizer resource
const endpoint =
process.env["FORM_RECOGNIZER_SOURCE_ENDPOINT"] ?? "<source cognitive services endpoint>";
const apiKey = process.env["FORM_RECOGNIZER_SOURCE_API_KEY"] ?? "<source resource api key>";
const sourceModelId =
process.env["FORM_RECOGNIZER_SOURCE_MODEL_ID"] ?? "<source custom model id>";
// information about the target Form Recognizer resource
const targetEndpoint =
process.env["FORM_RECOGNIZER_TARGET_ENDPOINT"] ?? "<target cognitive services endpoint>";
const targetApiKey = process.env["FORM_RECOGNIZER_TARGET_API_KEY"] ?? "<target resource api key>";
const targetResourceRegion =
process.env["FORM_RECOGNIZER_TARGET_REGION"] ?? "<target resource region>";
const targetResourceId =
process.env["FORM_RECOGNIZER_TARGET_RESOURCE_ID"] ?? "<target resource resource id>";

const targetClient = new FormTrainingClient(targetEndpoint, new AzureKeyCredential(targetApiKey));
const authorization = await targetClient.getCopyAuthorization(
targetResourceId,
targetResourceRegion
);

const sourceClient = new FormTrainingClient(endpoint, new AzureKeyCredential(apiKey));
const poller = await sourceClient.beginCopyModel(sourceModelId, authorization, {
onProgress: (state) => {
console.log(`Copy model status: ${state.status}`);
}
});
const result = await poller.pollUntilDone();

// now verify that the copy in the target Form Recognizer resource
console.log(`Model ID: ${result.modelId}`);
console.log(`Status : ${result.status}`);

const model = await targetClient.getCustomModel(result.modelId);
console.log(model);
}

main().catch((err) => {
console.error("The sample encountered an error:", err);
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

/**
* This sample demonstrates how to create a composed model from several
* individual labeled models.
*
* We train all of the models used in the compose and then finally create
* the composed model.
*
* NOTE: Only models trained using labels can be composed. Attempting to
* compose an unlabeled model will result in an error.
*
* @summary create a composed model from several individual labeled models
* @azsdk-weight 60
*/

import { FormTrainingClient, AzureKeyCredential } from "@azure/ai-form-recognizer";

// Load the .env file if it exists
import * as dotenv from "dotenv";
dotenv.config();

export async function main() {
// You will need to set these environment variables or edit the following values
const endpoint = process.env["FORM_RECOGNIZER_ENDPOINT"] ?? "<cognitive services endpoint>";
const apiKey = process.env["FORM_RECOGNIZER_API_KEY"] ?? "<api key>";

// This object will hold the SAS-encoded URLs to containers that hold
// different types of purchase order documents and their labels.
const purchaseOrderSasUrls = {
supplies:
process.env["PURCHASE_ORDER_OFFICE_SUPPLIES_SAS_URL"] ??
"<sas url to container with purchase orders for supplies>",
equipment:
process.env["PURCHASE_ORDER_OFFICE_SUPPLIES_SAS_URL"] ??
"<sas url to container with purchase orders for equipment>",
furniture:
process.env["PURCHASE_ORDER_OFFICE_SUPPLIES_SAS_URL"] ??
"<sas url to container with purchase orders for furniture>",
cleaningSupplies:
process.env["PURCHASE_ORDER_OFFICE_SUPPLIES_SAS_URL"] ??
"<sas url to container with purchase orders for cleaning supplies>"
};

// Train all of the individual models and extract their model IDs
const trainingClient = new FormTrainingClient(endpoint, new AzureKeyCredential(apiKey));

const modelIds = await Promise.all(
Object.entries(purchaseOrderSasUrls)
.map(async ([kind, sasUrl]) => {
const poller = await trainingClient.beginTraining(sasUrl, true, {
onProgress(state) {
console.log(`training model "${kind}": ${state.status}`);
},
modelName: kind
});

return poller.pollUntilDone();
})
.map(async (model) => (await model).modelId)
);

// Finally, create the composed model.

const poller = await trainingClient.beginCreateComposedModel(modelIds, {
onProgress(state) {
console.log(`composing model "purchase_order": ${state.status}`);
},
modelName: "purchase_order"
});

const composedModel = await poller.pollUntilDone();

// Print the model info to console
console.log(`Composed model: ${composedModel.modelName} (${composedModel.modelId}`);

console.log("Properties:", composedModel.properties);

// Errors
if (composedModel.errors && composedModel.errors.length > 0) {
console.log("Model Errors:");
for (const error of composedModel.errors) {
console.log(`- [${error.code}] ${error.message}`);
}
}

// Submodels
console.log("Submodels:");
for (const model of composedModel.submodels ?? []) {
console.log(`- ${model.formType} (${model.modelId}) - ${model.accuracy} accuracy`);
console.log(" Fields:");
for (const [name, field] of Object.entries(model.fields)) {
console.log(` - ${name} (${field.accuracy} accuracy)`);
}
}

// Training Documents
console.log("Training Documents:");
for (const info of composedModel.trainingDocuments ?? []) {
console.log(`- ${info.name} (in ${info.modelId})`);
}
}

main().catch((err) => {
console.error("The sample encountered an error:", err);
});
Loading

0 comments on commit fadd5b9

Please sign in to comment.