概要
本記事では、Azure Cognitive Servicesで提供されているForm Recognizerを用いて、請求書の画像ファイルから、請求金額などの読み取りをおこなうWebアプリを構築する手順を説明します。WebアプリケーションフレームワークとしてASP.NET Core 5.0を使用します。
目次
-
Form Recognizerの概要
-
Webアプリの構成
-
準備
-
Webアプリの開発
-
まとめ
1. Form Recognizerの概要
1.1 Form Recognizerとは?
Form Recognizerは、Azure Cognitive Servicesが提供するサービスの1つで、ドキュメントからレイアウト(テキストと構造)を抽出することができるサービスです。また構築済みの機械学習モデルを使って、名刺や請求書、レシートなどの画像データから値を読み取ることも可能です。
Form Recognizerの概要
https://docs.microsoft.com/ja-jp/azure/cognitive-services/form-recognizer/overview?tabs=v2-1
対応言語
https://docs.microsoft.com/ja-jp/azure/cognitive-services/form-recognizer/language-support?tabs=v2-1
価格
https://azure.microsoft.com/ja-jp/pricing/details/form-recognizer/
1.2 Form Recognizerの利用方法
Azureサブスクリプション内でForm Recognizerリソースを作成し、SDKおよびREST APIを通じてサービスを利用します。SDKはC#、Java、Python、JavaScriptなどの言語で利用することができます。
2. Webアプリの構成
Form Recognizerを用いて請求書の画像ファイルから請求金額などを読み取り、データベースに格納するWebアプリを構築します。前編ではファイルのアップロードおよび請求書の読み取りをおこなう部分を構築し、後編で読み取り結果のデータベースへの格納と表示をおこなう部分を構築します。
3. 準備
Webアプリ構築の準備として.NETのインストールとForm Recognizerリソースの作成をおこないます。
3.1 .NETをインストールする
開発環境に.NETをインストールします。本記事では .NET 5.0を使用します。
https://docs.microsoft.com/ja-jp/dotnet/core/install/
3.2 Form Recognizerリソースを作成する
(1) Azure Portal(https://portal.azure.com)にアクセスし、[リソースの作成]を選択します。
(2) 検索窓に Form Recognizer と入力してEnterキーを押し、[作成]をクリックします。
(3) サブスクリプション、リソースグループ、リージョン、名前、価格レベルの各項目を入力して、[確認および作成]をクリックします。本記事ではリージョンを東日本、価格レベルをFree F0としています。
確認および作成の画面で[作成]をクリックします。
(4) 作成したForm Recognizerにアクセスし、リソース管理の[キーとエンドポイント]を表示します。後ほどアプリで利用するため、キー1およびエンドポイントについてメモしておきます。
(5) サンプルツール(https://fott-2-1.azurewebsites.net/prebuilts-analyze)を使って請求書や名刺の読み取りを試行することができます。(4)のキー1およびエンドポイントを利用します。
※執筆時点(2021年6月、1)では、請求書読み取りの事前構築済みモデルは日本語に対応しておらず、日本語の請求書に対する読み取り精度はよくありません。
4. Webアプリの開発
Form Recognizerを用いて請求書の画像ファイルから請求金額などを読み取り、データベースに格納するWebアプリを構築します。前編ではファイルのアップロードおよび請求書の読み取りをおこなう部分を構築します。
※ 本記事ではLinux上で開発をおこなっていますので、Windowsなど別OSで開発される場合は、NuGetパッケージのインストール方法などを適宜読み替えてください。
4.1 Webアプリを作成する
(1) 最初にベースとなるWebアプリを作成して起動します。
$ dotnet new webapp -o FormRecognizer $ cd FormRecognizer $ dotnet run |
(2) ブラウザを起動してアプリに接続します。接続先URLは https://localhost:5001 です。
(3) 端末でCtrl+Cを押してアプリを終了します。
4.2 Form Recognizerへのインターフェースを準備する
(1) 必要なパッケージを追加します。端末で以下のコマンドを実行します。
$ dotnet add package Azure.AI.FormRecognizer |
(2) appsettings.jsonにキー情報を記載します。3.2 (4) でメモしたキー1およびエンドポイントをそれぞれ記載します。赤字が追記部分。
appsettings.json
{ "Logging": { "LogLevel": { "Default": "Information", "Microsoft": "Warning", "Microsoft.Hosting.Lifetime": "Information" } }, "AzureFormRecognizer": { "EndPoint": "Your Endpoint", "Key": "Your Key" }, "AllowedHosts": "*" } |
(3) Form Recognizerを扱うためのRecognizerクラスを作成します。
$ mkdir Services $ touch Services/Recognizer.cs |
Services/Recognizer.cs
using System.Threading.Tasks; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Configuration; using Azure; using Azure.AI.FormRecognizer; using Azure.AI.FormRecognizer.Models; using Microsoft.AspNetCore.Http; using System; using System.IO; using System.Linq; using System.Text.RegularExpressions;
namespace FormRecognizer.Services { public interface IRecognizer { Task RecognizeFromFile(IFormFile formFile); }
public class Recognizer : IRecognizer { private readonly ILogger<Recognizer> _logger; private readonly FormRecognizerClient _formRecognizerClient;
public Recognizer(ILogger<Recognizer> logger, IConfiguration configuration) { _logger = logger;
// appsettings.jsonからFormRecognizerの資格情報を取得する var configs = configuration.GetSection("AzureFormRecognizer"); var credential = new AzureKeyCredential(configs["Key"]);
// クライアントを認証する _formRecognizerClient = new FormRecognizerClient(new Uri(configs["EndPoint"]), credential); }
public async Task RecognizeFromFile(IFormFile formFile) { // アップロードされたファイルをMemoryStreamにコピーする using var stream = new MemoryStream(); await formFile.CopyToAsync(stream); stream.Position = 0;
// 請求書読み取りを実行する var options = new RecognizeInvoicesOptions() { Locale = "en-US" }; RecognizeInvoicesOperation operation = await _formRecognizerClient.StartRecognizeInvoicesAsync(stream, options); Response<RecognizedFormCollection> operationResponse = await operation.WaitForCompletionAsync(); RecognizedFormCollection invoices = operationResponse.Value;
// 読み取り結果を処理する RecognizedForm invoice = invoices.Single();
_logger.LogInformation($"Invoice File : '{formFile.FileName}'");
// 請求金額 if (invoice.Fields.TryGetValue("InvoiceTotal", out FormField invoiceTotalField)) { if (invoiceTotalField.Value.ValueType == FieldValueType.Float) { float invoiceTotal = invoiceTotalField.Value.AsFloat(); _logger.LogInformation($"Invoice Total: '{invoiceTotal}', with confidence {invoiceTotalField.Confidence}"); } }
// 発行日 if (invoice.Fields.TryGetValue("InvoiceDate", out FormField invoiceDateField)) { if (invoiceDateField.Value.ValueType == FieldValueType.Date) { DateTime invoiceDate = new DateTime(); try { invoiceDate = invoiceDateField.Value.AsDate(); } catch { string tmpDate = invoiceDateField.ValueData.Text; tmpDate = tmpDate.Replace(" ", ""); tmpDate = Regex.Replace(tmpDate, "[年月⽉]", "/"); tmpDate = Regex.Replace(tmpDate, "[⽇日]", ""); _logger.LogDebug($"{tmpDate}"); invoiceDate = DateTime.Parse(tmpDate); } _logger.LogInformation($"Invoice Date: '{invoiceDate}', with confidence {invoiceDateField.Confidence}"); } }
} } } |
(4) Startup.csのConfigureServicesにおいて依存性の注入をおこないます。赤字が追記部分。
Startup.cs
~省略~ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using FormRecognizer.Services;
namespace FormRecognizer { ~省略~ public void ConfigureServices(IServiceCollection services) { services.AddRazorPages(); services.AddScoped<IRecognizer, Recognizer>(); } ~省略~ |
4.3 ページの設定をおこなう
(1) Index.cshtml.csを修正します。赤字が追記部分。
Pages/Index.cshtml.cs
using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.RazorPages; using Microsoft.Extensions.Logging; using FormRecognizer.Services; using System.ComponentModel.DataAnnotations; using Microsoft.AspNetCore.Http;
namespace FormRecognizer.Pages { public class IndexModel : PageModel { private readonly ILogger<IndexModel> _logger; private readonly IRecognizer _recoginzer;
[BindProperty(SupportsGet = true)] public string Notice { get; set; } [BindProperty] public SingleFileUpload FileUpload { get; set; }
public IndexModel(ILogger<IndexModel> logger, IRecognizer recognizer) { _logger = logger; _recoginzer = recognizer; }
public void OnGet() {
}
public async Task<IActionResult> OnPostUploadAsync() { if (!ModelState.IsValid) return Page();
Notice = $"{FileUpload.FormFile.FileName} を読み込みました"; await _recoginzer.RecognizeFromFile(FileUpload.FormFile);
return RedirectToPage("./Index", new { Notice }); }
public class SingleFileUpload { [Required] [Display(Name = "請求書ファイル")] public IFormFile FormFile { get; set; } } } } |
(2) Index.cshtmlを以下のように変更します。
Pages/Index.cshtml
@page @model IndexModel @{ ViewData["Title"] = "Form Recognizer"; }
<div class="row"> <div class="col-1"></div> <div class="col-3"> <form enctype="multipart/form-data" method="post"> <label>請求書ファイル</label> <input asp-for="FileUpload.FormFile" type="file"> <span asp-validation-for="FileUpload.FormFile"></span> <button type="submit" asp-page-handler="upload" class="btn btn-primary btn-block mt-1">Upload</button> </form> </div> <div class="col-7"> <p class="text-danger">@Model.Notice</p> </div> <div class="col-1"></div> </div>
@section Scripts{ @{await Html.RenderPartialAsync("_ValidationScriptsPartial");} } |
4.4 Webアプリを起動してテストする
(1) アプリを起動してブラウザから接続します。接続先URLは https://localhost:5001 です。
$ dotnet run |
(2) ファイル選択ボタンを押して請求書のファイルを選んだ後、Uploadボタンを押すとForm Recognizerによる読み取りがおこなわれます。JPEG、PNG、PDF、TIFFファイルに対応しています。
(3) 端末のログに請求金額などの読み取り結果が表示されます。
(4) 端末でCtrl+Cを押してアプリを終了します。
4.5 解説
(1) Form RecognizerへのインターフェースとしてRecognizerクラスを定義し、csにおいて依存性の注入をおこなこうことで、IndexModelからRecognizerインスタンスにアクセスできるようにしています。IndexModelでは画像ファイルがPOSTされるとRecognizerのRecognizeFromFileメソッドを呼び出して読み取りを実行しています。
依存性の注入について
https://docs.microsoft.com/ja-jp/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-5.0
(2) RecognizerのRecognizeFromFileメソッドではFormRecognizerClientを用いて読み取りを実行し、結果を端末に表示しています。本記事では、読み取り結果から請求金額と発行日を取り出していますが、Form Recognizerはこれらの他にも支払期日や請求元などの情報も抽出します。
請求書読み取りで抽出されるフィールドについて
5. まとめ
前編ではファイルのアップロードおよびForm Recognizerを用いた請求書の読み取りをおこなう部分を構築しました。後編では読み取り結果のデータベースへの格納と表示をおこなう部分を構築します。
~~連載記事一覧~~