Azure.AI.FormRecognizer 4.1.0

前缀保留
dotnet add package Azure.AI.FormRecognizer --version 4.1.0                
NuGet\Install-Package Azure.AI.FormRecognizer -Version 4.1.0                
此命令旨在在 Visual Studio 的包管理器控制台中使用,因为它使用了 NuGet 模块的 Install-Package 版本。
<PackageReference Include="Azure.AI.FormRecognizer" Version="4.1.0" />                
对于支持 PackageReference 的项目,将此 XML 节点复制到项目文件中以引用此包。
paket add Azure.AI.FormRecognizer --version 4.1.0                
#r "nuget: Azure.AI.FormRecognizer, 4.1.0"                
#r 指令可以在 F# Interactive 和 Polyglot Notebooks 中使用。将此内容复制到交互式工具或脚本的源代码中以引用此包。
// Install Azure.AI.FormRecognizer as a Cake Addin
#addin nuget:?package=Azure.AI.FormRecognizer&version=4.1.0

// Install Azure.AI.FormRecognizer as a Cake Tool
#tool nuget:?package=Azure.AI.FormRecognizer&version=4.1.0                

Azure 表单识别 .NET 客户端库

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

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

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

源代码 | 软件包(NuGet) | API参考文档 | 产品文档 | 示例

入门教程

安装包

使用 NuGet 安装 Azure Form Recognizer 客户端库

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 或更低版本更新应用程序代码的详细说明。此外,请参阅 变更日志 获取更多信息。下表描述了每个客户端及其支持的 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 Portal 或 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 密钥

API 密钥可在 Azure Portal 中找到或通过运行以下 Azure CLI 命令来获取

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 Identity 库 使用 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实例,指示模型可以分析哪些文档类型,以及它可以分析每种文档类型的字段,还包括对每个字段的估计置信度。有关更详细的信息,请参阅服务文档
  • 从一个现有模型集合中组合一个模型。
  • 管理您账户中创建的模型。
  • 将自定义模型从一个表单识别器资源复制到另一个。
  • 列出构建操作或获取最近24小时内创建的特定操作。
  • 构建和管理用于在应用程序中对文档进行准确检测和识别的文档分类模型。

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

请注意,模型和分类器还可以使用如图形用户界面文档智能工作室之类的工具来构建。

长时间运行的操作

由于分析文档和构建模型需要时间,这些操作以长时间运行的操作的形式实现。长时间运行的操作包括向服务发送初始请求以启动操作,然后定期轮询服务以确定操作是否已完成或失败,如果已成功,则获取结果。

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

线程安全

我们保证所有客户端实例方法都是线程安全的,并且彼此独立(《a href="https://azure.github.io/azure-sdk/dotnet_introduction.html#dotnet-service-methods-thread-safety" rel="noopener noreferrer nofollow">指南)。这确保了重用客户端实例的建议始终是安全的,即使在多个线程之间也是如此。

其他概念

客户端选项 | 访问响应 | 处理失败 | 诊断 | 模拟 | 客户端生命周期

示例

以下部分提供了几个代码片段,说明在表单识别器.NET API中使用的常用模式。下面的绝大多数片段都使用了异步服务调用,但是请注意,Azure.AI.FormRecognizer包同时支持同步和异步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)}");
        }
    }
}

有关更多信息及示例,请参阅此处

使用预构建模型

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

例如,为了分析发票的字段,请使用通过将prebuilt-invoice模型ID传递到AnalyzeDocumentAsync方法的预先构建的发票模型进行分析。

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与表单识别客户端库交互时,服务返回的错误将导致返回具有与REST API请求相同的HTTP状态码的RequestFailedException

例如,如果提交一个包含无效Uri的收据图像,将返回400错误,表示“无效请求”。

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 仓库中提供了如何使用 Form Recognizer 库的示例。每个主要功能区域均提供了示例。

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

贡献

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

当您提交拉取请求时,CLA-bot 将自动确定您是否需要提供 CLA,并相应地装饰 PR(例如,标签,注释)。只需遵循机器人提供的说明即可。您只需在一个使用我们的 CLA 的所有存储库中做一次。

本项目采用了 Microsoft 开源行为准则。有关更多信息,请参阅 行为准则常见问题解答,或通过 [email protected] 发送任何额外的问题或评论。

产品 可兼容及额外的计算目标框架版本。
.NET net5.0 已计算。 net5.0-windows 已计算。 net6.0 已计算。 net6.0-android 已计算。 net6.0-ios 已计算。 net6.0-maccatalyst 已计算。 net6.0-macos 已计算。 net6.0-tvos 已计算。 net6.0-windows 已计算。 net7.0 已计算。 net7.0-android 已计算。 net7.0-ios 已计算。 net7.0-maccatalyst 已计算。 net7.0-macos 已计算。 net7.0-tvos 已计算。 net7.0-windows 已计算。 net8.0 已计算。 net8.0-android 已计算。 net8.0-browser 已计算。 net8.0-ios 已计算。 net8.0-maccatalyst 已计算。 net8.0-macos 已计算。 net8.0-tvos 已计算。 net8.0-windows 已计算。
.NET Core netcoreapp2.0 已计算。 netcoreapp2.1 已计算。 netcoreapp2.2 已计算。 netcoreapp3.0 已计算。 netcoreapp3.1 已计算。
.NET Standard netstandard2.0 兼容。 netstandard2.1 已计算。
.NET Framework net461 已计算。 net462 已计算。 net463 已计算。 net47 已计算。 net471 已计算。 net472 已计算。 net48 已计算。 net481 已计算。
MonoAndroid monoandroid 已计算。
MonoMac monomac 已计算。
MonoTouch monotouch 已计算。
Tizen tizen40 已计算。 tizen60 已计算。
Xamarin.iOS xamarinios 已计算。
Xamarin.Mac xamarinmac 已计算。
Xamarin.TVOS xamarintvos 已计算。
Xamarin.WatchOS xamarinwatchos 已计算。
兼容的目标框架
包含的目标框架(在包中)
有关 目标框架.NET Standard 的更多信息。

NuGet 包 (18)

显示依赖于 Azure.AI.FormRecognizer 的前 5 个 NuGet 包

下载
Microsoft.KernelMemory.DataFormats.AzureAIDocIntel

将 Azure AI 文档智能添加到内核内存,以从图像和文档中提取内容。

DTF.Services.Common.V2

DTF 通用服务。

AuthScape.Services

即将推出

Genocs.Integration.CognitiveServices

将 Azure 认知服务集成到 .NET Core 项目中的 Genocs 库。

PaaS.Framework

Paas.framework 是一个 Nuget 包,旨在使非专家云程序员能够以简单流畅的方式与云的各个组件交互。通过 Paas.framework,开发者可以轻松访问和操作云资源,无需担心底层云的复杂性问题。Paas.framework 还提供了一系列功能和工具,帮助开发者更高效、更有效地在云环境中工作。无论您是刚开始接触云计算的新手,还是经验丰富的开发者希望简化工作流程,Paas.framework 都是充分利用云体验的绝佳资源。如果您有任何建议或推荐,请随时联系我。我总是欢迎反馈和建议,以改进 Paas.framework 并使其对开发者更有用。

GitHub 仓库 (3)

展示依赖 Azure.AI.FormRecognizer 的最受欢迎的 3 个 GitHub 仓库。

仓库 星星
microsoft/kernel-memory
RAG 架构:使用 LLM 和自然语言索引和查询任何数据,跟踪来源,显示引用,异步内存模式。
Azure-Samples/azure-search-openai-demo-csharp
Azure 搜索示例应用程序,使用 Azure 认知搜索进行检索,使用 Azure OpenAI 大型语言模型来驱动 ChatGPT 风格的 Q&A 经验。
jongio/memealyzer
Memealyzer 是一个用于展示一些最新、最先进的 Azure 技术的应用程序,供开发人员进行开发、调试和部署微服务应用程序。
版本 下载 最后更新
4.1.0 1,235,147 8/11/2023
4.1.0-beta.1 31,924 4/13/2023
4.0.0 863,307 9/9/2022
4.0.0-beta.5 22,047 8/9/2022
4.0.0-beta.4 73,310 6/8/2022
4.0.0-beta.3 78,753 2/11/2022
4.0.0-beta.2 38,246 11/9/2021
4.0.0-beta.1 55,607 10/7/2021
3.1.1 489,128 6/9/2021
3.1.0 139,912 5/26/2021
3.1.0-beta.4 13,365 4/6/2021
3.1.0-beta.3 3,325 3/9/2021
3.1.0-beta.2 10,716 2/9/2021
3.1.0-beta.1 36,854 11/23/2020
3.0.1 26,971 4/9/2021
3.0.0 180,221 8/20/2020
3.0.0-preview.2 11,021 8/18/2020
1.0.0-preview.4 12,475 7/7/2020
1.0.0-preview.3 3,133 6/10/2020
1.0.0-preview.2 3,991 5/6/2020
1.0.0-preview.1 1,567 4/23/2020