Document AI(Python)を使用したフォーム解析

1. はじめに

この Codelab では、Document AI の Form パーサーを使用して Python で手書きフォームを解析する方法を学びます。

ここでは簡単な医療用登録フォームを例として使用しますが、DocAI でサポートされている一般的なフォームであれば、すべてにこの手順を使用できます。

前提条件

この Codelab は、Document AI の他の Codelab の内容に基づいて作成されています。

このラボを始める前に、次の Codelab を完了しておくことをおすすめします。

学習内容

  • Document AI の Form パーサーを使用して、スキャンしたフォームからデータを解析して抽出する方法。

必要なもの

  • Google Cloud プロジェクト
  • ブラウザ(ChromeFirefox など)
  • Python 3 の知識

アンケート

このチュートリアルをどのように使用されますか?

通読のみ 通読して演習を行う

Python のご利用経験はどの程度ありますか?

初心者 中級者 上級者

Google Cloud サービスの使用経験はどの程度ありますか?

初心者 中級者 上級者

2. 設定と要件

この Codelab は、Document AI OCR Codelab に記載されている Document AI の設定手順を完了していることを前提としています。

先に進む前に、次のステップを完了してください。

Python 用のオープンソース データ分析ライブラリである Pandas もインストールする必要があります。

pip3 install --upgrade pandas

3. Form パーサー プロセッサを作成する

このチュートリアルでは最初に、Document AI Platform で使用する Form パーサー プロセッサのインスタンスを作成する必要があります。

  1. コンソールで [Document AI Platform Overview] に移動します。
  2. [プロセッサを作成] をクリックして、[Form パーサー] を選択します。プロセッサ
  3. プロセッサ名を指定し、リストからリージョンを選択します。
  4. [作成] をクリックして、プロセッサを作成します。
  5. プロセッサ ID をコピーします。これは、後でコード内で使用します。

Cloud コンソールでプロセッサをテストする

ドキュメントをアップロードして、プロセッサをテストしてみましょう。[ドキュメントをアップロード] をクリックして、解析するフォームを選択します。使用できるフォームがない場合は、このサンプル フォームをダウンロードして使用できます。

医療用フォーム

出力は次のようになります。解析されたフォーム

4. サンプル フォームをダウンロードする

簡単な医療用登録フォームを含むサンプル ドキュメントが用意されています。

この PDF ファイルは次のリンク先からダウンロードできます。ダウンロードしたファイルを Cloud Shell インスタンスにアップロードします。

このファイルは、gsutil を使用して、Google の Google Cloud Storage 公開バケットからダウンロードすることもできます。

gsutil cp gs://cloud-samples-data/documentai/codelabs/form-parser/intake-form.pdf .

次のコマンドを使用して、ファイルが Cloud Shell にダウンロードされたことを確認します。

ls -ltr intake-form.pdf

5. フォームの Key-Value ペアを抽出する

このステップでは、オンライン処理 API を使用して、先ほど作成したフォーム パーサー プロセッサを呼び出します。次に、ドキュメントで見つかった Key-Value ペアを抽出します。

オンライン処理は、単一のドキュメントを送信してレスポンスを待つ場合に使用します。複数のファイルを送信する場合や、ファイルサイズがオンライン処理の最大ページ数を超える場合は、バッチ処理を使用することもできます。その方法については、OCR Codelab をご覧ください。

プロセス リクエストを行うコードは、プロセッサ ID を除き、すべてのプロセッサ タイプで同じです。

Document レスポンス オブジェクトには、入力ドキュメントのページのリストが含まれます。

page オブジェクトには、フォーム フィールドのリストとテキスト内の位置が含まれます。

次のコードは、各ページを反復処理し、それぞれのキー、値、信頼スコアを抽出します。これは、データベースに簡単に保存したり、他のアプリケーションで使用したりできる構造化データです。

form_parser.py というファイルを作成して、以下のコードを使用します。

form_parser.py

import pandas as pd
from google.cloud import documentai_v1 as documentai


def online_process(
    project_id: str,
    location: str,
    processor_id: str,
    file_path: str,
    mime_type: str,
) -> documentai.Document:
    """
    Processes a document using the Document AI Online Processing API.
    """

    opts = {"api_endpoint": f"{location}-documentai.googleapis.com"}

    # Instantiates a client
    documentai_client = documentai.DocumentProcessorServiceClient(client_options=opts)

    # The full resource name of the processor, e.g.:
    # projects/project-id/locations/location/processor/processor-id
    # You must create new processors in the Cloud Console first
    resource_name = documentai_client.processor_path(project_id, location, processor_id)

    # Read the file into memory
    with open(file_path, "rb") as image:
        image_content = image.read()

        # Load Binary Data into Document AI RawDocument Object
        raw_document = documentai.RawDocument(
            content=image_content, mime_type=mime_type
        )

        # Configure the process request
        request = documentai.ProcessRequest(
            name=resource_name, raw_document=raw_document
        )

        # Use the Document AI client to process the sample form
        result = documentai_client.process_document(request=request)

        return result.document


def trim_text(text: str):
    """
    Remove extra space characters from text (blank, newline, tab, etc.)
    """
    return text.strip().replace("\n", " ")


PROJECT_ID = "YOUR_PROJECT_ID"
LOCATION = "YOUR_PROJECT_LOCATION"  # Format is 'us' or 'eu'
PROCESSOR_ID = "FORM_PARSER_ID"  # Create processor in Cloud Console

# The local file in your current working directory
FILE_PATH = "intake-form.pdf"
# Refer to https://cloud.google.com/document-ai/docs/processors-list
# for supported file types
MIME_TYPE = "application/pdf"

document = online_process(
    project_id=PROJECT_ID,
    location=LOCATION,
    processor_id=PROCESSOR_ID,
    file_path=FILE_PATH,
    mime_type=MIME_TYPE,
)

names = []
name_confidence = []
values = []
value_confidence = []

for page in document.pages:
    for field in page.form_fields:
        # Get the extracted field names
        names.append(trim_text(field.field_name.text_anchor.content))
        # Confidence - How "sure" the Model is that the text is correct
        name_confidence.append(field.field_name.confidence)

        values.append(trim_text(field.field_value.text_anchor.content))
        value_confidence.append(field.field_value.confidence)

# Create a Pandas Dataframe to print the values in tabular format.
df = pd.DataFrame(
    {
        "Field Name": names,
        "Field Name Confidence": name_confidence,
        "Field Value": values,
        "Field Value Confidence": value_confidence,
    }
)

print(df)

コードを実行します。テキストが抽出され、コンソールに出力されます。

サンプル ドキュメントの出力結果は次のようになります。

$ python3 form_parser.py
                                           Field Name  Field Name Confidence                                        Field Value  Field Value Confidence
0                                            Phone #:               0.999982                                     (906) 917-3486                0.999982
1                                  Emergency Contact:               0.999972                                         Eva Walker                0.999972
2                                     Marital Status:               0.999951                                             Single                0.999951
3                                             Gender:               0.999933                                                  F                0.999933
4                                         Occupation:               0.999914                                  Software Engineer                0.999914
5                                        Referred By:               0.999862                                               None                0.999862
6                                               Date:               0.999858                                            9/14/19                0.999858
7                                                DOB:               0.999716                                         09/04/1986                0.999716
8                                            Address:               0.999147                                     24 Barney Lane                0.999147
9                                               City:               0.997718                                             Towaco                0.997718
10                                              Name:               0.997345                                       Sally Walker                0.997345
11                                             State:               0.996944                                                 NJ                0.996944
...

6. テーブルを解析する

Form パーサーは、ドキュメント内のテーブルからデータを抽出することもできます。このステップでは、新しいサンプル ドキュメントをダウンロードして、テーブルからデータを抽出します。Pandas にデータが読み込まれているため、このデータは単一のメソッド呼び出しで CSV ファイルや他の多くの形式に出力できます。

テーブルを含むサンプル フォームをダウンロードする

サンプル フォームとテーブルを含むサンプル ドキュメントが用意されています。

この PDF ファイルは次のリンク先からダウンロードできます。ダウンロードしたファイルを Cloud Shell インスタンスにアップロードします。

このファイルは、gsutil を使用して、Google の Google Cloud Storage 公開バケットからダウンロードすることもできます。

gsutil cp gs://cloud-samples-data/documentai/codelabs/form-parser/form_with_tables.pdf .

次のコマンドを使用して、ファイルが Cloud Shell にダウンロードされたことを確認します。

ls -ltr form_with_tables.pdf

テーブルデータを抽出する

テーブルデータの処理リクエストは、Key-Value ペアの抽出リクエストと同じです。レスポンスからどのフィールドのデータを抽出するかが異なります。テーブルデータは pages[].tables[] フィールドに保存されます。

この例では、それぞれのテーブルとページについて、テーブル ヘッダー行と本文行から情報を抽出し、テーブルを出力して CSV ファイルとして保存します。

table_parsing.py というファイルを作成して、以下のコードを使用します。

table_parsing.py

# type: ignore[1]
"""
Uses Document AI online processing to call a form parser processor
Extracts the tables and data in the document.
"""
from os.path import splitext
from typing import List, Sequence

import pandas as pd
from google.cloud import documentai


def online_process(
    project_id: str,
    location: str,
    processor_id: str,
    file_path: str,
    mime_type: str,
) -> documentai.Document:
    """
    Processes a document using the Document AI Online Processing API.
    """

    opts = {"api_endpoint": f"{location}-documentai.googleapis.com"}

    # Instantiates a client
    documentai_client = documentai.DocumentProcessorServiceClient(client_options=opts)

    # The full resource name of the processor, e.g.:
    # projects/project-id/locations/location/processor/processor-id
    # You must create new processors in the Cloud Console first
    resource_name = documentai_client.processor_path(project_id, location, processor_id)

    # Read the file into memory
    with open(file_path, "rb") as image:
        image_content = image.read()

        # Load Binary Data into Document AI RawDocument Object
        raw_document = documentai.RawDocument(
            content=image_content, mime_type=mime_type
        )

        # Configure the process request
        request = documentai.ProcessRequest(
            name=resource_name, raw_document=raw_document
        )

        # Use the Document AI client to process the sample form
        result = documentai_client.process_document(request=request)

        return result.document


def get_table_data(
    rows: Sequence[documentai.Document.Page.Table.TableRow], text: str
) -> List[List[str]]:
    """
    Get Text data from table rows
    """
    all_values: List[List[str]] = []
    for row in rows:
        current_row_values: List[str] = []
        for cell in row.cells:
            current_row_values.append(
                text_anchor_to_text(cell.layout.text_anchor, text)
            )
        all_values.append(current_row_values)
    return all_values


def text_anchor_to_text(text_anchor: documentai.Document.TextAnchor, text: str) -> str:
    """
    Document AI identifies table data by their offsets in the entirety of the
    document's text. This function converts offsets to a string.
    """
    response = ""
    # If a text segment spans several lines, it will
    # be stored in different text segments.
    for segment in text_anchor.text_segments:
        start_index = int(segment.start_index)
        end_index = int(segment.end_index)
        response += text[start_index:end_index]
    return response.strip().replace("\n", " ")


PROJECT_ID = "YOUR_PROJECT_ID"
LOCATION = "YOUR_PROJECT_LOCATION"  # Format is 'us' or 'eu'
PROCESSOR_ID = "FORM_PARSER_ID"  # Create processor before running sample

# The local file in your current working directory
FILE_PATH = "form_with_tables.pdf"
# Refer to https://cloud.google.com/document-ai/docs/file-types
# for supported file types
MIME_TYPE = "application/pdf"

document = online_process(
    project_id=PROJECT_ID,
    location=LOCATION,
    processor_id=PROCESSOR_ID,
    file_path=FILE_PATH,
    mime_type=MIME_TYPE,
)

header_row_values: List[List[str]] = []
body_row_values: List[List[str]] = []

# Input Filename without extension
output_file_prefix = splitext(FILE_PATH)[0]

for page in document.pages:
    for index, table in enumerate(page.tables):
        header_row_values = get_table_data(table.header_rows, document.text)
        body_row_values = get_table_data(table.body_rows, document.text)

        # Create a Pandas Dataframe to print the values in tabular format.
        df = pd.DataFrame(
            data=body_row_values,
            columns=pd.MultiIndex.from_arrays(header_row_values),
        )

        print(f"Page {page.page_number} - Table {index}")
        print(df)

        # Save each table as a CSV file
        output_filename = f"{output_file_prefix}_pg{page.page_number}_tb{index}.csv"
        df.to_csv(output_filename, index=False)

コードを実行します。テキストが抽出され、コンソールに出力されます。

サンプル ドキュメントの出力結果は次のようになります。

$ python3 table_parsing.py
Page 1 - Table 0
     Item    Description
0  Item 1  Description 1
1  Item 2  Description 2
2  Item 3  Description 3
Page 1 - Table 1
  Form Number:     12345678
0   Form Date:   2020/10/01
1        Name:   First Last
2     Address:  123 Fake St

コードを実行したディレクトリに 2 つの新しい CSV ファイルも作成されます。

$ ls
form_with_tables_pg1_tb0.csv form_with_tables_pg1_tb1.csv table_parsing.py

7. 完了

このラボでは、Document AI API を使用して手書きのフォームからデータを抽出しました。他のフォーム ドキュメントでもこの機能を試してみてください。

クリーンアップ

このチュートリアルで使用したリソースについて、Google Cloud アカウントに課金されないようにする手順は次のとおりです。

  • Cloud コンソールで、[リソースの管理] ページに移動します。
  • プロジェクト リストでプロジェクトを選択し、[削除] をクリックします。
  • ダイアログでプロジェクト ID を入力し、[シャットダウン] をクリックしてプロジェクトを削除します。

詳細

次の Codelab で Document AI について理解を深めてください。

リソース

ライセンス

この作業はクリエイティブ・コモンズの表示 2.0 汎用ライセンスにより使用許諾されています。