1. はじめに
この Codelab では、Document AI の Form パーサーを使用して、Python で手書きのフォームを解析する方法を学びます。
ここでは、例として簡単な医療用登録フォームを使用しますが、この手順は DocAI でサポートされているすべての一般化フォームでも機能します。
前提条件
この Codelab は、Document AI の他の Codelab の内容に基づいて作成されています。
このラボを始める前に、次の Codelab を完了しておくことをおすすめします。
学習内容
- Document AI Form パーサーを使用して、スキャンしたフォームのデータを解析して抽出する方法。
必要なもの
アンケート
このチュートリアルをどのように使用されますか?
Python のご利用経験はどの程度ありますか?
Google Cloud サービスの使用経験はどの程度ありますか?
<ph type="x-smartling-placeholder">2. 設定と要件
この Codelab は、Document AI OCR Codelab に記載されている Document AI の設定手順を完了していることを前提としています。
先に進む前に、次のステップを完了してください。
また、Python 用のオープンソース データ分析ライブラリである Pandas もインストールする必要があります。
pip3 install --upgrade pandas
3. Form パーサー プロセッサを作成する
まず、このチュートリアルの Document AI Platform で使用する Form パーサー プロセッサ インスタンスを作成する必要があります。
- コンソールで [Document AI Platform Overview] に移動します。
- [プロセッサを作成] をクリックして、[Form パーサー] を選択します。
- プロセッサ名を指定し、リストからリージョンを選択します。
- [作成] をクリックして、プロセッサを作成します。
- プロセッサ 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 汎用ライセンスにより使用許諾されています。