你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn

适用于 .NET 的 Azure 表单识别器 客户端库 - 版本 4.1.0

注意:2023 年 7 月,Azure 认知服务表单识别器服务已重命名为 Azure AI 文档智能。 文档中对 表单识别器 或文档智能的任何提及都指同一 Azure 服务。

Azure AI 文档智能是一项云服务,它使用机器学习来分析文档中的文本和结构化数据。 它包括以下main功能:

  • 布局 - 从文档中提取文本、选择标记、表格结构、样式和段落及其边界区域坐标。
  • 常规文档 - 除了分析文档中的常规布局外,还分析键值对。
  • 读取 - 除了文本语言信息外,还读取有关文本元素的信息,例如页面字词和行。
  • 预生成 - 使用预生成模型分析某些类型的常见文档中的数据。 支持的文档包括收据、发票、名片、身份证、美国 W2 税单等。
  • 自定义分析 - 生成自定义文档模型以分析文档中的文本、字段值、选择标记、表结构、样式和段落。 自定义模型是使用你自己的数据构建的,因此它们是针对你的文档定制的。
  • 自定义分类 - 生成自定义分类器模型,这些模型结合了布局和语言功能,以准确检测和识别在应用程序中处理的文档。

源代码 | 包 (NuGet) | API 参考文档 | 产品文档 | 样品

入门

安装包

使用 NuGet 安装适用于 .NET 的 Azure 表单识别器 客户端库:

dotnet add package Azure.AI.FormRecognizer

注意:此版本的客户端库默认为 2023-07-31 服务版本。

此表显示了 SDK 版本与服务支持的 API 版本之间的关系:

SDK 版本 服务支持的 API 版本
4.1.0 2.0, 2.1, 2022-08-31, 2023-07-31
4.0.0 2.0, 2.1, 2022-08-31
3.1.X 2.0, 2.1
3.0.X 2.0

注意:从版本 4.0.0开始,引入了一组新的客户端,以利用文档智能服务的最新功能。 有关如何将应用程序代码从客户端库版本或更低版本3.1.X更新到最新版本的详细说明,请参阅迁移指南。 此外,请参阅 Changelog 了解更多详细信息。 下表描述了每个客户端及其支持的 API 版本 () 之间的关系:

API 版本 支持的客户端
2023-07-31 DocumentAnalysisClient 和 DocumentModelAdministrationClient
2022-08-31 DocumentAnalysisClient 和 DocumentModelAdministrationClient
2.1 FormRecognizerClient 和 FormTrainingClient
2.0 FormRecognizerClient 和 FormTrainingClient

先决条件

创建认知服务或表单识别器资源

文档智能支持 多服务和单服务访问。 如果计划通过一个终结点/密钥访问多个认知服务,请创建认知服务资源。 仅对于文档智能访问,请创建表单识别器资源。 请注意,如果打算使用 Azure Active Directory 身份验证,则需要单服务资源。

可以使用以下方法创建任一资源:

下面是如何使用 CLI 创建表单识别器资源的示例:

# Create a new resource group to hold the Form Recognizer resource
# If using an existing resource group, skip this step
az group create --name <your-resource-name> --location <location>
# Create the Form Recognizer resource
az cognitiveservices account create \
    --name <resource-name> \
    --resource-group <resource-group-name> \
    --kind FormRecognizer \
    --sku <sku> \
    --location <location> \
    --yes

有关创建资源以及如何获取位置和 SKU 信息的详细信息,请参阅 此处

验证客户端

若要与文档智能服务交互,需要创建 类的 DocumentAnalysisClient 实例。 实例化客户端对象需要 终结点凭据

获取终结点

可以使用 Azure 门户Azure CLI 查找表单识别器资源的终结点:

# Get the endpoint for the Form Recognizer resource
az cognitiveservices account show --name "<resource-name>" --resource-group "<resource-group-name>" --query "properties.endpoint"

可以使用区域终结点或自定义子域进行身份验证。 它们的格式如下:

Regional endpoint: https://<region>.api.cognitive.microsoft.com/
Custom subdomain: https://<resource-name>.cognitiveservices.azure.com/

区域终结点对于某个区域中的每个资源都是相同的。 可 在此处查阅受支持的区域终结点的完整列表。 请注意,区域终结点不支持 AAD 身份验证。

另一方面,自定义子域是表单识别器资源唯一的名称。 它们只能由 单服务资源使用。

获取 API 密钥

可以在 Azure 门户中 或通过运行以下 Azure CLI 命令找到 API 密钥:

az cognitiveservices account keys list --name "<resource-name>" --resource-group "<resource-group-name>"

使用 AzureKeyCredential 创建 DocumentAnalysisClient

获得 API 密钥的值后,请 AzureKeyCredential创建 。 使用终结点和密钥凭据,可以创建 DocumentAnalysisClient

string endpoint = "<endpoint>";
string apiKey = "<apiKey>";
var credential = new AzureKeyCredential(apiKey);
var client = new DocumentAnalysisClient(new Uri(endpoint), credential);

使用 Azure Active Directory 凭据创建 DocumentAnalysisClient

AzureKeyCredential 本入门指南的示例中使用了身份验证,但也可以使用 Azure 标识库通过 Azure Active Directory 进行身份验证。 请注意,区域终结点不支持 AAD 身份验证。 为资源创建自定义子域,以使用此类身份验证。

若要使用如下所示的 DefaultAzureCredential 提供程序或 Azure SDK 随附的其他凭据提供程序,请安装 Azure.Identity 包:

dotnet add package Azure.Identity

还需要注册新的 AAD 应用程序,并通过将角色分配给服务主体来"Cognitive Services User"授予对文档智能的访问权限

将 AAD 应用程序的客户端 ID、租户 ID 和客户端密码的值设置为环境变量:AZURE_CLIENT_ID、AZURE_TENANT_ID、AZURE_CLIENT_SECRET。

string endpoint = "<endpoint>";
var client = new DocumentAnalysisClient(new Uri(endpoint), new DefaultAzureCredential());

关键概念

DocumentAnalysisClient

DocumentAnalysisClient 提供操作以实现以下目的:

  • 通过 AnalyzeDocumentAnalyzeDocumentFromUri API 使用预生成模型和自定义模型分析输入文档。
  • 使用 ClassifyDocumentClassifyDocumentFromUri 和 API 检测和标识自定义输入文档。

此处提供了示例代码片段来说明如何使用 DocumentAnalysisClient。 有关分析文档的详细信息,包括支持的功能、区域设置和文档类型,请参阅 服务文档

DocumentModelAdministrationClient

DocumentModelAdministrationClient 提供操作以实现以下目的:

  • 生成自定义模型以分析通过标记自定义文档指定的特定字段。 返回一个 DocumentModelDetails 实例,指示模型可以分析的文档类型 (s) 、它可以针对每种文档类型分析的字段,以及每个字段的估计置信度。 有关更详细的说明,请参阅 服务文档
  • 从现有模型集合中撰写模型。
  • 管理在帐户中创建的模型。
  • 将自定义模型从一个表单识别器资源复制到另一个资源。
  • 列出在过去 24 小时内创建的生成操作或获取特定操作。
  • 生成和管理文档分类模型,以准确检测和识别在应用程序中处理的文档。

请参阅 生成自定义模型管理模型生成文档分类器的示例。

请注意,也可以使用图形用户界面(如 Document Intelligence Studio)生成模型和分类器。

Long-Running 操作

由于分析文档和生成模型需要一些时间,因此这些操作是作为 长时间运行的操作实现的。 长时间运行的操作包括发送到服务以启动操作的初始请求,然后每隔一段时间轮询服务以确定操作是否已完成或失败,如果操作成功,则获取结果。

对于 Azure SDK 中长时间运行的操作,客户端会公开返回 Operation<T> 对象的方法。 可以将其 参数 waitUntil 设置为 WaitUntil.Completed 以等待操作完成并获取其结果;如果只想启动操作并稍后使用结果,则可以将其 WaitUntil.Started 设置为 。 下面提供了一个示例代码片段,用于说明如何使用长时间运行的操作。

线程安全

我们保证所有客户端实例方法都是线程安全的,并且彼此独立 (准则) 。 这可确保重用客户端实例的建议始终是安全的,即使在线程之间也是如此。

其他概念

客户端选项 | 访问响应 | 处理失败 | 诊断 | 嘲笑 | 客户端生存期

示例

以下部分提供了几个代码片段,说明了 表单识别器 .NET API 中使用的常见模式。 下面的大多数代码片段都使用异步服务调用,但请记住,Azure.AI.FormRecognizer 包支持同步 API 和异步 API。

异步示例

同步示例

请注意,这些示例使用 SDK 版本 4.1.0。 有关版本 3.1.1 或更低版本,请参阅 V3.1.X 表单识别器示例

提取布局

从文档中提取文本、选择标记、表格结构、样式和段落及其边界区域坐标。

Uri fileUri = new Uri("<fileUri>");

AnalyzeDocumentOperation operation = await client.AnalyzeDocumentFromUriAsync(WaitUntil.Completed, "prebuilt-layout", fileUri);
AnalyzeResult result = operation.Value;

foreach (DocumentPage page in result.Pages)
{
    Console.WriteLine($"Document Page {page.PageNumber} has {page.Lines.Count} line(s), {page.Words.Count} word(s),");
    Console.WriteLine($"and {page.SelectionMarks.Count} selection mark(s).");

    for (int i = 0; i < page.Lines.Count; i++)
    {
        DocumentLine line = page.Lines[i];
        Console.WriteLine($"  Line {i} has content: '{line.Content}'.");

        Console.WriteLine($"    Its bounding polygon (points ordered clockwise):");

        for (int j = 0; j < line.BoundingPolygon.Count; j++)
        {
            Console.WriteLine($"      Point {j} => X: {line.BoundingPolygon[j].X}, Y: {line.BoundingPolygon[j].Y}");
        }
    }

    for (int i = 0; i < page.SelectionMarks.Count; i++)
    {
        DocumentSelectionMark selectionMark = page.SelectionMarks[i];

        Console.WriteLine($"  Selection Mark {i} is {selectionMark.State}.");
        Console.WriteLine($"    Its bounding polygon (points ordered clockwise):");

        for (int j = 0; j < selectionMark.BoundingPolygon.Count; j++)
        {
            Console.WriteLine($"      Point {j} => X: {selectionMark.BoundingPolygon[j].X}, Y: {selectionMark.BoundingPolygon[j].Y}");
        }
    }
}

Console.WriteLine("Paragraphs:");

foreach (DocumentParagraph paragraph in result.Paragraphs)
{
    Console.WriteLine($"  Paragraph content: {paragraph.Content}");

    if (paragraph.Role != null)
    {
        Console.WriteLine($"    Role: {paragraph.Role}");
    }
}

foreach (DocumentStyle style in result.Styles)
{
    // Check the style and style confidence to see if text is handwritten.
    // Note that value '0.8' is used as an example.

    bool isHandwritten = style.IsHandwritten.HasValue && style.IsHandwritten == true;

    if (isHandwritten && style.Confidence > 0.8)
    {
        Console.WriteLine($"Handwritten content found:");

        foreach (DocumentSpan span in style.Spans)
        {
            Console.WriteLine($"  Content: {result.Content.Substring(span.Index, span.Length)}");
        }
    }
}

Console.WriteLine("The following tables were extracted:");

for (int i = 0; i < result.Tables.Count; i++)
{
    DocumentTable table = result.Tables[i];
    Console.WriteLine($"  Table {i} has {table.RowCount} rows and {table.ColumnCount} columns.");

    foreach (DocumentTableCell cell in table.Cells)
    {
        Console.WriteLine($"    Cell ({cell.RowIndex}, {cell.ColumnIndex}) has kind '{cell.Kind}' and content: '{cell.Content}'.");
    }
}

有关详细信息和示例,请参阅 此处

使用预生成的常规文档模型

使用预生成的常规文档模型分析文档中的文本、选择标记、表格结构、样式、段落和键值对。

Uri fileUri = new Uri("<fileUri>");

AnalyzeDocumentOperation operation = await client.AnalyzeDocumentFromUriAsync(WaitUntil.Completed, "prebuilt-document", fileUri);
AnalyzeResult result = operation.Value;

Console.WriteLine("Detected key-value pairs:");

foreach (DocumentKeyValuePair kvp in result.KeyValuePairs)
{
    if (kvp.Value == null)
    {
        Console.WriteLine($"  Found key with no value: '{kvp.Key.Content}'");
    }
    else
    {
        Console.WriteLine($"  Found key-value pair: '{kvp.Key.Content}' and '{kvp.Value.Content}'");
    }
}

foreach (DocumentPage page in result.Pages)
{
    Console.WriteLine($"Document Page {page.PageNumber} has {page.Lines.Count} line(s), {page.Words.Count} word(s),");
    Console.WriteLine($"and {page.SelectionMarks.Count} selection mark(s).");

    for (int i = 0; i < page.Lines.Count; i++)
    {
        DocumentLine line = page.Lines[i];
        Console.WriteLine($"  Line {i} has content: '{line.Content}'.");

        Console.WriteLine($"    Its bounding polygon (points ordered clockwise):");

        for (int j = 0; j < line.BoundingPolygon.Count; j++)
        {
            Console.WriteLine($"      Point {j} => X: {line.BoundingPolygon[j].X}, Y: {line.BoundingPolygon[j].Y}");
        }
    }

    for (int i = 0; i < page.SelectionMarks.Count; i++)
    {
        DocumentSelectionMark selectionMark = page.SelectionMarks[i];

        Console.WriteLine($"  Selection Mark {i} is {selectionMark.State}.");
        Console.WriteLine($"    Its bounding polygon (points ordered clockwise):");

        for (int j = 0; j < selectionMark.BoundingPolygon.Count; j++)
        {
            Console.WriteLine($"      Point {j} => X: {selectionMark.BoundingPolygon[j].X}, Y: {selectionMark.BoundingPolygon[j].Y}");
        }
    }
}

foreach (DocumentStyle style in result.Styles)
{
    // Check the style and style confidence to see if text is handwritten.
    // Note that value '0.8' is used as an example.

    bool isHandwritten = style.IsHandwritten.HasValue && style.IsHandwritten == true;

    if (isHandwritten && style.Confidence > 0.8)
    {
        Console.WriteLine($"Handwritten content found:");

        foreach (DocumentSpan span in style.Spans)
        {
            Console.WriteLine($"  Content: {result.Content.Substring(span.Index, span.Length)}");
        }
    }
}

Console.WriteLine("The following tables were extracted:");

for (int i = 0; i < result.Tables.Count; i++)
{
    DocumentTable table = result.Tables[i];
    Console.WriteLine($"  Table {i} has {table.RowCount} rows and {table.ColumnCount} columns.");

    foreach (DocumentTableCell cell in table.Cells)
    {
        Console.WriteLine($"    Cell ({cell.RowIndex}, {cell.ColumnIndex}) has kind '{cell.Kind}' and content: '{cell.Content}'.");
    }
}

有关详细信息和示例,请参阅 此处

使用预生成的读取模型

使用预生成的阅读模型分析文档中的文本元素,例如页面字词和线条、样式、段落和文本语言信息。

Uri fileUri = new Uri("<fileUri>");

AnalyzeDocumentOperation operation = await client.AnalyzeDocumentFromUriAsync(WaitUntil.Completed, "prebuilt-read", fileUri);
AnalyzeResult result = operation.Value;

Console.WriteLine("Detected languages:");

foreach (DocumentLanguage language in result.Languages)
{
    Console.WriteLine($"  Found language with locale '{language.Locale}' and confidence {language.Confidence}.");
}

foreach (DocumentPage page in result.Pages)
{
    Console.WriteLine($"Document Page {page.PageNumber} has {page.Lines.Count} line(s), {page.Words.Count} word(s),");
    Console.WriteLine($"and {page.SelectionMarks.Count} selection mark(s).");

    for (int i = 0; i < page.Lines.Count; i++)
    {
        DocumentLine line = page.Lines[i];
        Console.WriteLine($"  Line {i} has content: '{line.Content}'.");

        Console.WriteLine($"    Its bounding polygon (points ordered clockwise):");

        for (int j = 0; j < line.BoundingPolygon.Count; j++)
        {
            Console.WriteLine($"      Point {j} => X: {line.BoundingPolygon[j].X}, Y: {line.BoundingPolygon[j].Y}");
        }
    }
}

foreach (DocumentStyle style in result.Styles)
{
    // Check the style and style confidence to see if text is handwritten.
    // Note that value '0.8' is used as an example.

    bool isHandwritten = style.IsHandwritten.HasValue && style.IsHandwritten == true;

    if (isHandwritten && style.Confidence > 0.8)
    {
        Console.WriteLine($"Handwritten content found:");

        foreach (DocumentSpan span in style.Spans)
        {
            Console.WriteLine($"  Content: {result.Content.Substring(span.Index, span.Length)}");
        }
    }
}

有关详细信息和示例,请参阅 此处

使用预生成模型

使用文档智能服务提供的预生成模型分析某些类型的常见文档中的数据。

例如,若要分析发票中的字段,请使用通过将模型 ID 传递到 prebuilt-invoiceAnalyzeDocumentAsync 方法提供的预生成发票模型:

string filePath = "<filePath>";

using var stream = new FileStream(filePath, FileMode.Open);

AnalyzeDocumentOperation operation = await client.AnalyzeDocumentAsync(WaitUntil.Completed, "prebuilt-invoice", stream);
AnalyzeResult result = operation.Value;

// To see the list of all the supported fields returned by service and its corresponding types for the
// prebuilt-invoice model, consult:
// https://aka.ms/azsdk/formrecognizer/invoicefieldschema

for (int i = 0; i < result.Documents.Count; i++)
{
    Console.WriteLine($"Document {i}:");

    AnalyzedDocument document = result.Documents[i];

    if (document.Fields.TryGetValue("VendorName", out DocumentField vendorNameField))
    {
        if (vendorNameField.FieldType == DocumentFieldType.String)
        {
            string vendorName = vendorNameField.Value.AsString();
            Console.WriteLine($"Vendor Name: '{vendorName}', with confidence {vendorNameField.Confidence}");
        }
    }

    if (document.Fields.TryGetValue("CustomerName", out DocumentField customerNameField))
    {
        if (customerNameField.FieldType == DocumentFieldType.String)
        {
            string customerName = customerNameField.Value.AsString();
            Console.WriteLine($"Customer Name: '{customerName}', with confidence {customerNameField.Confidence}");
        }
    }

    if (document.Fields.TryGetValue("Items", out DocumentField itemsField))
    {
        if (itemsField.FieldType == DocumentFieldType.List)
        {
            foreach (DocumentField itemField in itemsField.Value.AsList())
            {
                Console.WriteLine("Item:");

                if (itemField.FieldType == DocumentFieldType.Dictionary)
                {
                    IReadOnlyDictionary<string, DocumentField> itemFields = itemField.Value.AsDictionary();

                    if (itemFields.TryGetValue("Description", out DocumentField itemDescriptionField))
                    {
                        if (itemDescriptionField.FieldType == DocumentFieldType.String)
                        {
                            string itemDescription = itemDescriptionField.Value.AsString();

                            Console.WriteLine($"  Description: '{itemDescription}', with confidence {itemDescriptionField.Confidence}");
                        }
                    }

                    if (itemFields.TryGetValue("Amount", out DocumentField itemAmountField))
                    {
                        if (itemAmountField.FieldType == DocumentFieldType.Currency)
                        {
                            CurrencyValue itemAmount = itemAmountField.Value.AsCurrency();

                            Console.WriteLine($"  Amount: '{itemAmount.Symbol}{itemAmount.Amount}', with confidence {itemAmountField.Confidence}");
                        }
                    }
                }
            }
        }
    }

    if (document.Fields.TryGetValue("SubTotal", out DocumentField subTotalField))
    {
        if (subTotalField.FieldType == DocumentFieldType.Currency)
        {
            CurrencyValue subTotal = subTotalField.Value.AsCurrency();
            Console.WriteLine($"Sub Total: '{subTotal.Symbol}{subTotal.Amount}', with confidence {subTotalField.Confidence}");
        }
    }

    if (document.Fields.TryGetValue("TotalTax", out DocumentField totalTaxField))
    {
        if (totalTaxField.FieldType == DocumentFieldType.Currency)
        {
            CurrencyValue totalTax = totalTaxField.Value.AsCurrency();
            Console.WriteLine($"Total Tax: '{totalTax.Symbol}{totalTax.Amount}', with confidence {totalTaxField.Confidence}");
        }
    }

    if (document.Fields.TryGetValue("InvoiceTotal", out DocumentField invoiceTotalField))
    {
        if (invoiceTotalField.FieldType == DocumentFieldType.Currency)
        {
            CurrencyValue invoiceTotal = invoiceTotalField.Value.AsCurrency();
            Console.WriteLine($"Invoice Total: '{invoiceTotal.Symbol}{invoiceTotal.Amount}', with confidence {invoiceTotalField.Confidence}");
        }
    }
}

不限于发票! 有几个预生成模型可供选择,每个模型都有自己的一组受支持字段。 有关支持的文档类型的详细信息,请参阅 服务文档

有关详细信息和示例,请参阅 此处

生成自定义模型

根据自己的文档类型生成自定义模型。 生成的模型可用于分析生成模型所基于的文档类型的值。

// For this sample, you can use the training documents found in the `trainingFiles` folder.
// Upload the documents to your storage container and then generate a container SAS URL. Note
// that a container URI without SAS is accepted only when the container is public or has a
// managed identity configured.
//
// For instructions to set up documents for training in an Azure Blob Storage Container, please see:
// https://aka.ms/azsdk/formrecognizer/buildcustommodel

Uri blobContainerUri = new Uri("<blobContainerUri>");
var client = new DocumentModelAdministrationClient(new Uri(endpoint), new AzureKeyCredential(apiKey));

// We are selecting the Template build mode in this sample. For more information about the available
// build modes and their differences, please see:
// https://aka.ms/azsdk/formrecognizer/buildmode

BuildDocumentModelOperation operation = await client.BuildDocumentModelAsync(WaitUntil.Completed, blobContainerUri, DocumentBuildMode.Template);
DocumentModelDetails model = operation.Value;

Console.WriteLine($"  Model Id: {model.ModelId}");
Console.WriteLine($"  Created on: {model.CreatedOn}");

Console.WriteLine("  Document types the model can recognize:");
foreach (KeyValuePair<string, DocumentTypeDetails> documentType in model.DocumentTypes)
{
    Console.WriteLine($"    Document type: {documentType.Key} which has the following fields:");
    foreach (KeyValuePair<string, DocumentFieldSchema> schema in documentType.Value.FieldSchema)
    {
        Console.WriteLine($"    Field: {schema.Key} with confidence {documentType.Value.FieldConfidence[schema.Key]}");
    }
}

有关详细信息和示例,请参阅 此处

分析自定义文档

使用使用自己的文档类型生成的模型,分析自定义文档中的文本、字段值、选择标记以及表格结构、样式和段落。

string modelId = "<modelId>";
Uri fileUri = new Uri("<fileUri>");

AnalyzeDocumentOperation operation = await client.AnalyzeDocumentFromUriAsync(WaitUntil.Completed, modelId, fileUri);
AnalyzeResult result = operation.Value;

Console.WriteLine($"Document was analyzed with model with ID: {result.ModelId}");

foreach (AnalyzedDocument document in result.Documents)
{
    Console.WriteLine($"Document of type: {document.DocumentType}");

    foreach (KeyValuePair<string, DocumentField> fieldKvp in document.Fields)
    {
        string fieldName = fieldKvp.Key;
        DocumentField field = fieldKvp.Value;

        Console.WriteLine($"Field '{fieldName}': ");

        Console.WriteLine($"  Content: '{field.Content}'");
        Console.WriteLine($"  Confidence: '{field.Confidence}'");
    }
}

有关详细信息和示例,请参阅 此处

管理模型

管理帐户中存储的模型。

var client = new DocumentModelAdministrationClient(new Uri(endpoint), new AzureKeyCredential(apiKey));

// Check number of custom models in the Form Recognizer resource, and the maximum number of custom models that can be stored.
ResourceDetails resourceDetails = await client.GetResourceDetailsAsync();
Console.WriteLine($"Resource has {resourceDetails.CustomDocumentModelCount} custom models.");
Console.WriteLine($"It can have at most {resourceDetails.CustomDocumentModelLimit} custom models.");

// List the first ten or fewer models currently stored in the resource.
AsyncPageable<DocumentModelSummary> models = client.GetDocumentModelsAsync();

int count = 0;
await foreach (DocumentModelSummary modelSummary in models)
{
    Console.WriteLine($"Custom Model Summary:");
    Console.WriteLine($"  Model Id: {modelSummary.ModelId}");
    if (string.IsNullOrEmpty(modelSummary.Description))
        Console.WriteLine($"  Model description: {modelSummary.Description}");
    Console.WriteLine($"  Created on: {modelSummary.CreatedOn}");
    if (++count == 10)
        break;
}

// Create a new model to store in the resource.
Uri blobContainerUri = new Uri("<blobContainerUri>");
BuildDocumentModelOperation operation = await client.BuildDocumentModelAsync(WaitUntil.Completed, blobContainerUri, DocumentBuildMode.Template);
DocumentModelDetails model = operation.Value;

// Get the model that was just created.
DocumentModelDetails newCreatedModel = await client.GetDocumentModelAsync(model.ModelId);

Console.WriteLine($"Custom Model with Id {newCreatedModel.ModelId} has the following information:");

Console.WriteLine($"  Model Id: {newCreatedModel.ModelId}");
if (string.IsNullOrEmpty(newCreatedModel.Description))
    Console.WriteLine($"  Model description: {newCreatedModel.Description}");
Console.WriteLine($"  Created on: {newCreatedModel.CreatedOn}");

// Delete the model from the resource.
await client.DeleteDocumentModelAsync(newCreatedModel.ModelId);

有关详细信息和示例,请参阅 此处

同步管理模型

使用同步 API 管理帐户中存储的模型。

var client = new DocumentModelAdministrationClient(new Uri(endpoint), new AzureKeyCredential(apiKey));

// Check number of custom models in the Form Recognizer resource, and the maximum number of custom models that can be stored.
ResourceDetails resourceDetails = client.GetResourceDetails();
Console.WriteLine($"Resource has {resourceDetails.CustomDocumentModelCount} custom models.");
Console.WriteLine($"It can have at most {resourceDetails.CustomDocumentModelLimit} custom models.");

// List the first ten or fewer models currently stored in the resource.
Pageable<DocumentModelSummary> models = client.GetDocumentModels();

foreach (DocumentModelSummary modelSummary in models.Take(10))
{
    Console.WriteLine($"Custom Model Summary:");
    Console.WriteLine($"  Model Id: {modelSummary.ModelId}");
    if (string.IsNullOrEmpty(modelSummary.Description))
        Console.WriteLine($"  Model description: {modelSummary.Description}");
    Console.WriteLine($"  Created on: {modelSummary.CreatedOn}");
}

// Create a new model to store in the resource.

Uri blobContainerUri = new Uri("<blobContainerUri>");
BuildDocumentModelOperation operation = client.BuildDocumentModel(WaitUntil.Completed, blobContainerUri, DocumentBuildMode.Template);
DocumentModelDetails model = operation.Value;

// Get the model that was just created.
DocumentModelDetails newCreatedModel = client.GetDocumentModel(model.ModelId);

Console.WriteLine($"Custom Model with Id {newCreatedModel.ModelId} has the following information:");

Console.WriteLine($"  Model Id: {newCreatedModel.ModelId}");
if (string.IsNullOrEmpty(newCreatedModel.Description))
    Console.WriteLine($"  Model description: {newCreatedModel.Description}");
Console.WriteLine($"  Created on: {newCreatedModel.CreatedOn}");

// Delete the created model from the resource.
client.DeleteDocumentModel(newCreatedModel.ModelId);

生成文档分类器

通过上传自定义训练文档来生成文档分类器。

// For this sample, you can use the training documents found in the `classifierTrainingFiles` folder.
// Upload the documents to your storage container and then generate a container SAS URL. Note
// that a container URI without SAS is accepted only when the container is public or has a
// managed identity configured.
//
// For instructions to set up documents for training in an Azure Blob Storage Container, please see:
// https://aka.ms/azsdk/formrecognizer/buildclassifiermodel

Uri trainingFilesUri = new Uri("<trainingFilesUri>");
var client = new DocumentModelAdministrationClient(new Uri(endpoint), new AzureKeyCredential(apiKey));

var sourceA = new BlobContentSource(trainingFilesUri) { Prefix = "IRS-1040-A/train" };
var sourceB = new BlobContentSource(trainingFilesUri) { Prefix = "IRS-1040-B/train" };

var documentTypes = new Dictionary<string, ClassifierDocumentTypeDetails>()
{
    { "IRS-1040-A", new ClassifierDocumentTypeDetails(sourceA) },
    { "IRS-1040-B", new ClassifierDocumentTypeDetails(sourceB) }
};

BuildDocumentClassifierOperation operation = await client.BuildDocumentClassifierAsync(WaitUntil.Completed, documentTypes);
DocumentClassifierDetails classifier = operation.Value;

Console.WriteLine($"  Classifier Id: {classifier.ClassifierId}");
Console.WriteLine($"  Created on: {classifier.CreatedOn}");

Console.WriteLine("  Document types the classifier can recognize:");
foreach (KeyValuePair<string, ClassifierDocumentTypeDetails> documentType in classifier.DocumentTypes)
{
    Console.WriteLine($"    {documentType.Key}");
}

有关详细信息和示例,请参阅 此处

对文档进行分类

使用文档分类器准确检测和标识在应用程序中处理的文档。

string classifierId = "<classifierId>";
Uri fileUri = new Uri("<fileUri>");

ClassifyDocumentOperation operation = await client.ClassifyDocumentFromUriAsync(WaitUntil.Completed, classifierId, fileUri);
AnalyzeResult result = operation.Value;

Console.WriteLine($"Document was classified by classifier with ID: {result.ModelId}");

foreach (AnalyzedDocument document in result.Documents)
{
    Console.WriteLine($"Document of type: {document.DocumentType}");
}

有关详细信息和示例,请参阅 此处

疑难解答

常规

使用 .NET SDK 与 表单识别器 客户端库交互时,服务返回的错误将导致具有 RequestFailedExceptionREST API 请求返回的相同 HTTP 状态代码的 。

例如,如果提交的回执图像无效 Uri400 则返回错误,指示“请求错误”。

try
{
    AnalyzeDocumentOperation operation = await client.AnalyzeDocumentFromUriAsync(WaitUntil.Completed, "prebuilt-receipt", new Uri("http://invalid.uri"));
}
catch (RequestFailedException e)
{
    Console.WriteLine(e.ToString());
}

你会注意到记录了其他信息,例如操作的客户端请求 ID。

Message:
    Azure.RequestFailedException: Service request failed.
    Status: 400 (Bad Request)
    ErrorCode: InvalidRequest

Content:
    {"error":{"code":"InvalidRequest","message":"Invalid request.","innererror":{"code":"InvalidContent","message":"The file is corrupted or format is unsupported. Refer to documentation for the list of supported formats."}}}

Headers:
    Transfer-Encoding: chunked
    x-envoy-upstream-service-time: REDACTED
    apim-request-id: REDACTED
    Strict-Transport-Security: REDACTED
    X-Content-Type-Options: REDACTED
    Date: Fri, 01 Oct 2021 02:55:44 GMT
    Content-Type: application/json; charset=utf-8

文档智能服务引发的错误代码和消息可在 服务文档中找到。

有关常见问题的更多详细信息,请参阅 故障排除指南

设置控制台日志记录

查看日志的最简单方法是启用控制台日志记录。 若要创建将消息输出到控制台的 Azure SDK 日志侦听器,请使用 AzureEventSourceListener.CreateConsoleLogger 方法。

// Setup a listener to monitor logged events.
using AzureEventSourceListener listener = AzureEventSourceListener.CreateConsoleLogger();

若要了解有关其他日志记录机制的详细信息,请参阅 诊断示例

后续步骤

此 GitHub 存储库中提供了演示如何使用 表单识别器 库的示例。 每个main功能区域都提供了示例:

请注意,这些示例使用 SDK 版本 4.1.0。 有关版本 3.1.1 或更低版本,请参阅 V3.1.X 表单识别器示例

贡献

本项目欢迎贡献和建议。 大多数贡献要求你同意贡献者许可协议 (CLA),并声明你有权(并且确实有权)授予我们使用你的贡献的权利。 有关详细信息,请访问 cla.microsoft.com

提交拉取请求时,CLA 机器人将自动确定你是否需要提供 CLA,并相应地修饰 PR(例如标签、注释)。 直接按机器人提供的说明操作。 只需使用 CLA 对所有存储库执行一次这样的操作。

此项目采用了 Microsoft 开放源代码行为准则。 有关详细信息,请参阅行为准则常见问题解答,或如果有任何其他问题或意见,请与 联系。

曝光数