Microsoft Foundryには様々なサービスが用意されていて、その中には、ドキュメント内のテキストデータを抽出するサービスもある。

今回は、Microsoft Foundry上でドキュメントを読み込みテキストデータを抽出してみたので、その手順を共有する。

前提条件

下記記事の「Microsoft Foundryへのログインとプロジェクト作成」が完了していること。

Microsoft Foundry上で用意されているAIモデルをデプロイしてみたMicrosoft Foundryとは、企業や開発者が生成AIアプリケーションやAIエージェントを迅速に構築、デプロイ、管理するための統...

情報抽出の手順

Microsoft Foundry上の情報抽出(Content Understanding – ドキュメント レイアウト アナライザー)サービスは、デプロイしなくても画面から実行できる。また、APIキーを指定してAPIで呼び出すことができる。その手順は、以下の通り。

1) Microsoft Foundryにログインし、「ビルド」メニューを押下する。
情報抽出の手順_1

2)「サービス」メニューを押下後、「Content Understanding – ドキュメント レイアウト アナライザー」メニューを押下する。
情報抽出の手順_2

3) 以下の画面が表示されるのが確認できる。
情報抽出の手順_3

4) 請求書PDFファイルを取り込むため、「ファイルの参照」リンクを押下する。
情報抽出の手順_4_1

なお、取り込むPDFファイルは以下とする。
情報抽出の手順_4_2

ちなみに、上記PDFファイルは、下記サイトのテンプレートファイル(請求書シート)をPDF出力したものである。
https://www.robotpayment.co.jp/service/mikata/template/invoice/01.html

5) 読み込むPDFファイルを選択し「開く」ボタンを押下する。
情報抽出の手順_5

6) 以下のように、PDFファイルの内容が読み取られたことが確認できる。
情報抽出の手順_6

7) 読み込んだPDFファイルの内容を分析するため、「分析の実行」ボタンを押下する。
情報抽出の手順_7

8) 以下のように、PDFファイルの請求書が読み取られたことが確認できる。
情報抽出の手順_8_1

また、「テーブル」タブの内容は以下の通りで、表データの各値が読み込まれているのが確認できる。
情報抽出の手順_8_2

情報抽出の手順_8_3 情報抽出の手順_8_4

さらに、「結果」タブの抜粋は以下の通りで、読み取った請求書がJSON形式で出力されるのが確認できる。
情報抽出の手順_8_5

情報抽出の手順_8_6

また、「結果」タブの「テーブル1(請求金額(税込))」の部分を抜粋した内容は、以下の通り。

tables: [
    {
        "rowCount": 1,
        "columnCount": 2,
        "cells": [
            {
                 "kind": "content",
                 "rowIndex": 0,
                 "columnIndex": 0,
                 "rowSpan": 1,
                 "columnSpan": 1,
                 "content": "請求金額(税込)",
                 "source": "D(1,0.9502,2.1888,2.3704,2.1887,2.3699,2.5074,0.9501,2.5076)",
                 "span": {
                     "offset": 122,
                      "length": 8
                 },
                 "elements": [
                     "/paragraphs/5"
                 ]
              },
              {
                  "kind": "content",
                  "rowIndex": 0,
                  "columnIndex": 1,
                  "rowSpan": 1,
                  "columnSpan": 1,
                  "content": "¥407,957,393-",
                  "source": "D(1,2.3704,2.1887,4.0597,2.1891,4.0598,2.5077,2.3699,2.5074)",
                  "span": {
                      "offset": 140,
                      "length": 13
                  },
                  "elements": [
                      "/paragraphs/6"
                  ]
             }
         ],
         "source": "D(1,0.9356,2.1031,4.0432,2.1003,4.0512,2.4981,0.9437,2.4995)",
         "span": {
             "offset": 105,
             "length": 68
         }
    },
エンジニアファーストバナー

9)「コード」ボタンを押下すると、サンプルコードが表示されるため、表示されたソースコードをコピーする。
情報抽出の手順_9

10) 9)でコピーしたソースコードのうち、上部のコメントを省略したものは、以下の通り。

import json
from urllib.parse import urlparse
from azure.ai.contentunderstanding import ContentUnderstandingClient
from azure.ai.contentunderstanding.models import AnalysisInput, AnalysisResult
from azure.core.credentials import AzureKeyCredential
from azure.core.exceptions import AzureError
from azure.identity import DefaultAzureCredential


def is_absolute_url(value: str) -> bool:
    parsed_url = urlparse(value)
    return bool(parsed_url.scheme and parsed_url.netloc)


def main() -> None:
    # Insert the following configurations.
    # 1) AZURE_CONTENT_UNDERSTANDING_ENDPOINT - the endpoint to your Content Understanding resource.
    endpoint = "https://stanahas-8273-resource.services.ai.azure.com/"

    # 2) CONTENT_UNDERSTANDING_KEY - your Content Understanding API key (optional if using DefaultAzureCredential).
    key = "{{CONTENT_UNDERSTANDING_KEY}}"

    # 3) FILE_URL - you can replace this with your own URL.
    file_url = "{{FILE_URL}}"

    # ANALYZER_ID - the ID of the analyzer to use.
    analyzer_id = "prebuilt-layout"

    # API_VERSION - the API version to use.
    api_version = "2026-06-01-preview"

    # Validate Endpoint
    if not is_absolute_url(endpoint):
        print("[Error] Invalid Endpoint. Please provide a valid 'Endpoint'.")
        return

    # Validate File URL
    if not is_absolute_url(file_url):
        print("[Error] Invalid File URL. Please provide a valid URL.")
        return

    # Set up Content Understanding client.
    hasKey = type(key) is str and bool(key.strip()) and "{{CONTENT_UNDERSTANDING_KEY}}" not in key
    credential = AzureKeyCredential(key) if hasKey else DefaultAzureCredential()
    client = ContentUnderstandingClient(endpoint=endpoint, credential=credential, api_version=api_version)

    # [START analyze]
    print(f"Analyzing with {analyzer_id} analyzer...")
    print(f"  File URL: {file_url}\n")

    try:
        poller = client.begin_analyze(
            analyzer_id=analyzer_id,
            inputs=[AnalysisInput(url=file_url)],
        )
        result: AnalysisResult = poller.result()
    except AzureError as err:
        print(f"[Azure Error]: {err.message}")
        return
    except Exception as ex:
        print(f"[Unexpected Error]: {ex}")
        return
    # [END analyze]

    # [START output_result]
    print("=" * 50)
    print("Analysis result:")
    print("=" * 50 + "\n")

    max_display_lines = 50
    result_str = json.dumps(result.as_dict(), indent=2)
    ret_lines = result_str.splitlines()

    if len(ret_lines) > max_display_lines:
        print("\n".join(ret_lines[:max_display_lines]))
        print(f"\n {len(ret_lines) - max_display_lines} more lines to be displayed...\n")
    else:
        print(result_str)
    # [END output_result]


if __name__ == "__main__":
    main()

11) 10)の内容を、ローカル端末上のソースコード「analyze_pdf.py」に貼り付ける。なお、読み込み用PDF「template_01.pdf」も同フォルダに配置するものとする。
情報抽出の手順_11

12) 11)で貼り付けたソースコードを以下のように変更し、文字コードをUTF-8にした状態で貼り付ける。

import json
from urllib.parse import urlparse
from azure.ai.contentunderstanding import ContentUnderstandingClient
from azure.ai.contentunderstanding.models import AnalysisInput, AnalysisResult
from azure.core.credentials import AzureKeyCredential
from azure.core.exceptions import AzureError
from azure.identity import DefaultAzureCredential


def is_absolute_url(value: str) -> bool:
    parsed_url = urlparse(value)
    return bool(parsed_url.scheme and parsed_url.netloc)


def main() -> None:
    # Insert the following configurations.
    # AZURE_CONTENT_UNDERSTANDING_ENDPOINT - the endpoint to your Content Understanding resource.
    endpoint = "https://stanahas-8273-resource.services.ai.azure.com/"

    # FILE_PATH、FILE_TYPE
    local_file_path = "template_01.pdf"
    content_type = "application/pdf"  # ファイルに合わせたMIMEタイプを指定

    # ANALYZER_ID - the ID of the analyzer to use.
    analyzer_id = "prebuilt-layout"

    # API_VERSION - the API version to use.
    api_version = "2026-06-01-preview"

    # Validate Endpoint
    if not is_absolute_url(endpoint):
        print("[Error] Invalid Endpoint. Please provide a valid 'Endpoint'.")
        return

    # ローカルファイルをバイナリ(bytes)として読み込み
    print(f"ローカルファイル '{local_file_path}' を読み込んでいます...")
    with open(local_file_path, "rb") as f:
        file_bytes = f.read()

    # Set up Content Understanding client.
    credential = DefaultAzureCredential()
    client = ContentUnderstandingClient(endpoint=endpoint, credential=credential, api_version=api_version)

    # [START analyze]
    print(f"Analyzing with {analyzer_id} analyzer...")

    try:
        poller = client.begin_analyze_binary(
            analyzer_id=analyzer_id,
            binary_input=file_bytes,
            content_type=content_type
        )
        result: AnalysisResult = poller.result()
    except AzureError as err:
        print(f"[Azure Error]: {err.message}")
        return
    except Exception as ex:
        print(f"[Unexpected Error]: {ex}")
        return
    # [END analyze]

    # [START output_result]
    print("=" * 50)
    print("Analysis result:")
    print("=" * 50 + "\n")

    max_display_lines = 50
    result_str = json.dumps(result.as_dict(), indent=2, ensure_ascii=False)  # 日本語の文字化け防止対応にensure_ascii=Falseを追加
    ret_lines = result_str.splitlines()

    # 結果が長い場合は、先頭の50行のみ抽出結果を表示する
    if len(ret_lines) > max_display_lines:
        print("\n".join(ret_lines[:max_display_lines]))
        print(f"\n {len(ret_lines) - max_display_lines} more lines to be displayed...\n")
    else:
        print(result_str)
    # [END output_result]


if __name__ == "__main__":
    main()

13) 下記サイトの「Azure上でのAzure Functions動作検証」手順に従って、「az login」コマンドでログインする。

Azure Functions上で動作するPythonアプリケーションを作成してみたAzureが提供するサービスに、さまざまなイベントによって駆動し、サーバーの構築や保守をすることなくプログラムを実行できる「Azure ...

14) 12)のプログラムを実行する際、情報抽出用のライブラリが必要なので、「pip install azure.ai.contentunderstanding」コマンドを実行しインストールする。
情報抽出の手順_14

15)「analyze_pdf.py」を実行すると、結果が、8)で「結果」タブに出力されたJSONと同形式で出力されることが確認できる。
情報抽出の手順_15

要点まとめ

  • Microsoft Foundryには様々なサービスが用意されていて、その中には、ドキュメント内のテキストデータを抽出するサービスが含まれている。