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 サービスの使用経験はどの程度ありますか?

<ph type="x-smartling-placeholder"></ph> 初心者 中級 上達 をご覧ください。

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 コンソールでプロセッサをテストする

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

健康管理フォーム

出力は次のようになります。解析された形式

4. サンプル・フォームのダウンロード

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

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

また、gsutil を使用して、一般公開されている 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 を使用して、前に作成した Form パーサー プロセッサを呼び出します。次に、ドキュメントから見つかった Key-Value ペアを抽出します。

オンライン処理では、1 つのドキュメントを送信して応答を待ちます。また、複数のファイルを送信する場合や、ファイルサイズがオンライン処理の最大数を超える場合にも、バッチ処理を使用できます。その方法については、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 に読み込むため、1 回のメソッド呼び出しで、このデータは CSV ファイルやその他の多くの形式で出力できます。

表のサンプル フォームをダウンロードする

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

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

また、gsutil を使用して、一般公開されている 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 汎用ライセンスにより使用許諾されています。