はじめに
こんにちは、フジマロです![]()
最近、生成AI技術の発展とともに、AIというワードを聞く頻度が多くなりました。
ひとことで表すとAIと呼ばれていますが、その中には機械学習、ディープラーニング、生成AIといった幅広い用語が登場します。
前回に引き続き今回は、ディープラーニング技術の代表的な例であるAIを使用したOCRサービスをAPIで試してみたいと思います。
前回のおさらい
Azure AI Document Itelligenceの事前構築済みモデルというサービスを使用してPDFの画像を文字に起こし、ファイルに書き込んでいく処理をAPIで作成します。

前回は、 ➀画像ファイルをAIサービスにPOSTし画像IDを得る まで実施しました
今回は、 「➁画像IDを使いGETしたデータをExcelファイルに書込む」 をご紹介します
今回やること
➁画像IDを使いGETしたデータをExcelファイルに書込む
11.画像IDからデータ取得
12.ファイル書込み
13.スキーマ
14.mapper
15.非同期処理
16.実行と結果確認
AzureやHULFT Squareの設定について詳しくはこちらの前回の記事もご確認ください
➁画像IDを使いGETしたデータをExcelファイルに書込む
ここでは、アップロードした画像のIDから必要な文字データを取得する処理を作成します。

11.画像IDからデータ取得
HULFT Squareデザイナー画面の右側のツールパレットから下記の順番で設定します
[ネットワーク] - [REST] - [POST実行]

【必須設定】
名前:REST接続_AzureDocumentIntelligence ※「4.コネクションの設定」で設定したものを選択
パス:/documentintelligence/documentModels/prebuilt-invoice/analyzeResults/${ID}
クエリパラメーター:
| 名前 | 値 |
|---|---|
api-version |
2024-11-30 |
【レスポンス設定】
データ形式: JSON ※選択
【ヘッダ設定】
| リクエストヘッダ | |
|---|---|
| 名前 | 値 |
Ocp-Apim-Subscription-Key |
%{APIキー} |
12.ファイル書込み
ここでは取得したデータを書き込むファイルを設定します。
【必須設定】
ファイル:/Personal/請求書.xlsx ※任意のファイルパス
列一覧:下記を設定
| 列名 |
|---|
請求会社名 |
日付 |
商品 |
金額 |
【書き込み設定】
[ 一行目に列名を挿入 ] にチェックを入れる
[完了]をクリック
13.スキーマ
ここではJson形式のデータをExcel形式に変換するための出力するJsonを定義します。
Web画面の方から下記の順番で作成していきます
[HULFT INTEGRATE] - [スキーマ] - [新規作成]
名前:AzureDocumentIntelligence請求書
タイプ:JSON ※選択
JSON定義: ※下記を設定
請求書モデル(prebuilt-invoice)のレスポンスJson
{
"status": "succeeded",
"createdDateTime": "2025-04-07T09:27:33Z",
"lastUpdatedDateTime": "2025-04-07T09:27:36Z",
"analyzeResult": {
"apiVersion": "2024-02-29-preview",
"modelId": "prebuilt-invoice",
"stringIndexType": "textElements",
"content": "請求書\n発行日 令和元年 8月31日\n〒102-0073",
"pages": [
{
"pageNumber": 1,
"angle": 0,
"width": 792,
"height": 1122,
"unit": "pixel",
"words": [
{
"content": "書",
"polygon": [66],
"confidence": 0.993,
"span": {
"offset": 2,
"length": 1
}
}
],
"lines": [
{
"content": "請求書",
"polygon": [66],
"spans": [
{
"offset": 0,
"length": 3
}
]
}
],
"spans": [
{
"offset": 0,
"length": 483
}
]
}
],
"tables": [
{
"rowCount": 2,
"columnCount": 3,
"cells": [
{
"kind": "columnHeader",
"rowIndex": 0,
"columnIndex": 0,
"content": "今回御買上額",
"boundingRegions": [
{
"pageNumber": 1,
"polygon": [341]
}
],
"spans": [
{
"offset": 145,
"length": 6
}
]
},
{
"rowIndex": 1,
"columnIndex": 0,
"content": "¥32,500",
"boundingRegions": [
{
"pageNumber": 1,
"polygon": [373]
}
],
"spans": [
{
"offset": 181,
"length": 7
}
]
}
],
"boundingRegions": [
{
"pageNumber": 1,
"polygon": [375]
}
],
"spans": [
{
"offset": 145,
"length": 18
},
{
"offset": 181,
"length": 22
}
]
},
{
"rowCount": 29,
"columnCount": 8,
"cells": [
{
"kind": "columnHeader",
"rowIndex": 0,
"columnIndex": 0,
"content": "日付",
"boundingRegions": [
{
"pageNumber": 1,
"polygon": [398]
}
],
"spans": [
{
"offset": 204,
"length": 2
}
]
},
{
"kind": "columnHeader",
"rowIndex": 0,
"columnIndex": 1,
"content": "伝票No",
"boundingRegions": [
{
"pageNumber": 1,
"polygon": [398]
}
],
"spans": [
{
"offset": 207,
"length": 4
}
]
},
{
"rowIndex": 1,
"columnIndex": 0,
"content": "8/10",
"boundingRegions": [
{
"pageNumber": 1,
"polygon": [70, 398, 106, 398, 106, 419, 70, 419]
}
],
"spans": [
{
"offset": 231,
"length": 4
}
]
}
],
"boundingRegions": [
{
"pageNumber": 1,
"polygon": [1044]
}
],
"spans": [
{
"offset": 204,
"length": 81
}
]
}
],
"styles": [
{
"confidence": 0.4,
"spans": [
{
"offset": 73,
"length": 2
}
],
"isHandwritten": true
}
],
"documents": [
{
"docType": "invoice",
"boundingRegions": [
{
"pageNumber": 1,
"polygon": [1122]
}
],
"fields": {
"CustomerAddress": {
"type": "address",
"content": "〒102-0073\n東京都千代田区九段北0-0-0",
"boundingRegions": [
{
"pageNumber": 1,
"polygon": [156]
}
],
"confidence": 0.371,
"spans": [
{
"offset": 19,
"length": 25
}
],
"valueAddress": {
"houseNumber": "4-1-7",
"road": "九段北",
"postalCode": "〒102-0073",
"city": "東京都千代田区",
"streetAddress": "0-0-0 九段北"
}
},
"CustomerAddressRecipient": {
"type": "string",
"valueString": "手作り弁当",
"content": "手作り弁当",
"boundingRegions": [
{
"pageNumber": 1,
"polygon": [200]
}
],
"confidence": 0.659,
"spans": [
{
"offset": 57,
"length": 5
}
]
},
"CustomerName": {
"type": "string",
"valueString": "手作り弁当",
"content": "手作り弁当",
"boundingRegions": [
{
"pageNumber": 1,
"polygon": [200]
}
],
"confidence": 0.659,
"spans": [
{
"offset": 57,
"length": 5
}
]
},
"InvoiceDate": {
"type": "date",
"valueDate": "2019-08-31",
"content": "令和元年 8月31日",
"boundingRegions": [
{
"pageNumber": 1,
"polygon": [122]
}
],
"confidence": 0.886,
"spans": [
{
"offset": 8,
"length": 10
}
]
},
"InvoiceTotal": {
"type": "currency",
"valueCurrency": {
"currencySymbol": "¥",
"amount": 35100,
"currencyCode": "JPY"
},
"content": "¥35,100",
"boundingRegions": [
{
"pageNumber": 1,
"polygon": [368]
}
],
"confidence": 0.954,
"spans": [
{
"offset": 196,
"length": 7
}
]
},
"Items": {
"type": "array",
"valueArray": [
{
"type": "object",
"valueObject": {
"Amount": {
"type": "currency",
"valueCurrency": {
"amount": 4000,
"currencyCode": "JPY"
},
"content": "4,000",
"boundingRegions": [
{
"pageNumber": 1,
"polygon": [418]
}
],
"confidence": 0.944,
"spans": [
{
"offset": 265,
"length": 5
}
]
},
"Date": {
"type": "date",
"content": "8/10",
"boundingRegions": [
{
"pageNumber": 1,
"polygon": [418]
}
],
"confidence": 0.918,
"spans": [
{
"offset": 231,
"length": 4
}
]
},
"Description": {
"type": "string",
"valueString": "業務用しょうゆ 2L",
"content": "業務用しょうゆ 2L",
"boundingRegions": [
{
"pageNumber": 1,
"polygon": [417]
}
],
"confidence": 0.94,
"spans": [
{
"offset": 245,
"length": 10
}
]
},
"Quantity": {
"type": "number",
"valueNumber": 10,
"content": "10",
"boundingRegions": [
{
"pageNumber": 1,
"polygon": [416]
}
],
"confidence": 0.944,
"spans": [
{
"offset": 256,
"length": 2
}
]
},
"Unit": {
"type": "string",
"valueString": "本",
"content": "本",
"boundingRegions": [
{
"pageNumber": 1,
"polygon": [417]
}
],
"confidence": 0.943,
"spans": [
{
"offset": 259,
"length": 1
}
]
},
"UnitPrice": {
"type": "currency",
"valueCurrency": {
"amount": 400,
"currencyCode": "JPY"
},
"content": "400",
"boundingRegions": [
{
"pageNumber": 1,
"polygon": [416]
}
],
"confidence": 0.944,
"spans": [
{
"offset": 261,
"length": 3
}
]
}
},
"content": "8/10 60000100\n業務用しょうゆ 2L\n10\n本\n400\n4,000",
"boundingRegions": [
{
"pageNumber": 1,
"polygon": [418]
}
],
"confidence": 0.923,
"spans": [
{
"offset": 231,
"length": 39
}
]
}
]
},
"SubTotal": {
"type": "currency",
"valueCurrency": {
"currencySymbol": "¥",
"amount": 32500,
"currencyCode": "JPY"
},
"content": "¥32,500",
"boundingRegions": [
{
"pageNumber": 1,
"polygon": [363]
}
],
"confidence": 0.96,
"spans": [
{
"offset": 181,
"length": 7
}
]
},
"TotalTax": {
"type": "currency",
"valueCurrency": {
"currencySymbol": "¥",
"amount": 2600,
"currencyCode": "JPY"
},
"content": "¥2,600",
"boundingRegions": [
{
"pageNumber": 1,
"polygon": [363]
}
],
"confidence": 0.96,
"spans": [
{
"offset": 189,
"length": 6
}
]
},
"VendorAddress": {
"type": "address",
"content": "〒151-8543\n東京都渋谷区本町1",
"boundingRegions": [
{
"pageNumber": 1,
"polygon": [225]
}
],
"confidence": 0.536,
"spans": [
{
"offset": 63,
"length": 9
}
],
"valueAddress": {
"postalCode": "〒151-8543",
"city": "東",
"state": "京都渋谷",
"streetAddress": ""
}
},
"VendorAddressRecipient": {
"type": "string",
"valueString": "食品株式会社",
"content": "食品株式会社",
"boundingRegions": [
{
"pageNumber": 1,
"polygon": [261]
}
],
"confidence": 0.698,
"spans": [
{
"offset": 112,
"length": 8
}
]
},
"VendorName": {
"type": "string",
"valueString": "食\nサラダ\nE",
"content": "食\nサラダ\nE",
"boundingRegions": [
{
"pageNumber": 1,
"polygon": [281]
}
],
"confidence": 0.306,
"spans": [
{
"offset": 73,
"length": 2
}
]
}
},
"confidence": 1,
"spans": [
{
"offset": 0,
"length": 483
}
]
}
],
"contentFormat": "text"
}
}
14.mapper
ここではAIから受け取ったJSONデータをExcel形式に変換するためのmapperを設定していきます
デザイナー画面に戻り下記のように設定します。
➀アイコン [execute_http_get] → [excel_write] をドラッグ&ドロップする
➁下記を選択する
[プロセスフローとデータフローを引く]
[マッピングを追加する]
mappingアイコンが配置されたらダブルクリックで開きます

execute_http_get を右クリックしてリソースからスキーマを読み込む を押下

先程13.スキーマ で作成した AzureDocumentIntelligence請求書を選択します。
すると [入力データ] にJsonが定義されます。
下記の項目を繋いでいきます
| 親オブジェクト | 入力データ | → | 出力データ |
|---|---|---|---|
CustomerName |
content |
→ | 請求会社名 |
InvoiceDate |
valueDate |
→ | 日付 |
valueObject |
content |
→ | 商品 |
UnitPrice |
content |
→ | 金額 |
次に
Jsonの中で表形式の箇所を繰り返し入力します。
画面右のツールパレットの中から下記のロジックをドラッグ&ドロップで中央に配置します。
[繰り返し] - [基本] - [単純な繰り返し]
ポップアップが開きますが [完了] を押下してください
[単純な繰り返し]アイコンが配置されたら下記のように繋いでいきます
| 親オブジェクト | 入力データ | → | ロジック | → | 出力データ |
|---|---|---|---|---|---|
| Items | element |
→ | [単純な繰り返し] |
→ | row |
ここまでで一通りのデータの紐づけが完了しました。
画像に含まれるAI OCR出力結果のノイズをキレイにしよう
文字におこしたいPDFファイルには画像に予期しない文字が含まれていることはよくあると思います。
このようなノイズを除去する方法もご紹介します
正規表現置換ロジックを配置してノイズを除去する処理を作成します。
画面右のツールパレットの中から下記のロジックをドラッグ&ドロップで中央に配置します。
[文字列] - [変換] - [正規表現置換]
正規表現置換ロジックに下記を入力します
| 置換前文字列(正規表現パターン) | [^\w\sぁ-んァ-ン一-龥]+ |
|---|---|
| 置換後文字列 |
※補足
| 正規表現 | 意味 |
|---|---|
| \w | 英数字、アンダースコア |
| \s | 空白 |
| ぁ-ん | 平仮名 |
| ァ-ン | カタカナ |
| 一-龥 | 漢字 |
| [^...] | それ以外の文字にマッチ(除去対象) |
| + | 連続する対象文字列にマッチ |
配置した 正規表現置換 ロジックを下記のようにノイズを除去したい項目に繋いでいきます
| 親オブジェクト | 入力データ | → | ロジック | → | 出力データ |
|---|---|---|---|---|---|
| UnitPrice | content |
→ | [正規表現置換ロジック] |
→ | 金額 |
これでノイズを除去することが出来ます
15.非同期処理
ここではAIの処理が完了したか、確認するための同期をとる仕組みを作成していきます
Document IntelligencのAPI仕様で行われる一連の処理は下記になります
➀画像をPOSTしてAIに読み込ませる(未完了でも画像IDは出力される)
➁AIが文字に起こす
➂処理が完了
➃データとして出力
上記の➂はGETしたデータのstatusの項目から確認することが出来ます
mapperの入力データのJson項目に status がありますので、変数 status にドラッグ&ドロップで繋ぎます
完了したらmapperを閉じてください

次に画像IDが出力されてから待機する処理を作成します。
画面右側のツールパレットから下記の順番でアイコンを配置します。
[基本] - [処理] - [待機]
ポップアップが出てきますので 10秒 と入力します

次に画像IDが出力されたあと、10秒待機してからGETを繰り返す処理を作成します。
画面右側のツールパレットから下記の順番でアイコンを配置します。
[基本] - [フロー] - [繰り返し(条件指定)]
繰り返しロジックに下記のように設定しましょう
アイコンが配置できましたらドラッグ&ドロップで下記のように線で繋いでください

こうすることでGETした値が未完了を示していたら繰り返し、完了していたらファイルに書込みます
16.実行と結果確認
ここまで作成できたら実行します。
画面右上の デバック実行 ボタンを押下してください

実行ログを見ると正常にデータが書き込まれたことを確認できます

最後に
いかがでしたでしょうか
ここまで読んで頂きありがとうございます
今回は、事前にトレーニングされているモデルを使用しましたが、現在のAIの精度ではノイズが多く
自分で画像をトレーニングさせてもAIが出力するデータにはノイズが含まれることはよくあります。
そのためノーコードで実装できたうえにロジックでノイズを除去できる方法があるのはかなり嬉しい機能でした
この記事の内容がみなさんの参考になれば「いいね」をおして頂けると嬉しいです。
ここまで読んでいただきありがとうございました。それでは、また!![]()



















