使用 Document AI 剖析表單 (Python)

1. 簡介

在本程式碼研究室中,您將瞭解如何使用 Document AI 表單剖析器,以 Python 剖析手寫表單。

我們將以簡單的醫療登記表單為例,但此程序將適用於 DocAI 支援的任何一般形式。

必要條件

本程式碼研究室是以其他 Document AI 程式碼研究室呈現的內容為基礎。

建議您先完成下列程式碼研究室,再繼續操作。

課程內容

  • 如何使用 Document AI 表單剖析器剖析及擷取掃描表單中的資料。

軟硬體需求

  • Google Cloud 專案
  • 瀏覽器,例如 ChromeFirefox
  • 對 Python 3 的瞭解

問卷調查

您會如何使用這個教學課程?

僅供閱讀 閱讀並完成練習

您對 Python 的使用體驗有何評價?

新手 中級 還算容易

針對使用 Google Cloud 服務的經驗,您會給予什麼評價?

新手 中級 還算容易

2. 設定和需求

本程式碼研究室假設您已完成 Document AI OCR 程式碼研究室中列出的 Document AI 設定步驟。

請先完成下列步驟再繼續:

您還需要安裝 Pandas,這是 Python 專用的開放原始碼資料分析程式庫。

pip3 install --upgrade pandas

3. 建立表單剖析器處理器

您必須先建立表單剖析器處理器執行個體,才能在 Document AI 平台中使用本教學課程。

  1. 在控制台中,前往 Document AI Platform Overview (Document AI 平台總覽)
  2. 按一下「建立處理器」,然後選取「表單剖析器」處理器
  3. 指定處理器名稱,然後從清單中選取您的區域。
  4. 點選「建立」來建立處理器
  5. 複製處理器 ID。您稍後必須在程式碼中使用此 ID。

Cloud 控制台中的測試處理器

您可以在控制台中上傳文件,測試處理器。按一下「上傳文件」,然後選取要剖析的表單。如果沒有可用的範例表單,可以下載並使用此範例表單。

健康表

輸出內容應如下所示:剖析後的格式

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. 擷取表單鍵/值組合

在這個步驟中,您將使用線上處理 API 呼叫先前建立的表單剖析器處理器。然後擷取文件中的鍵/值組合。

線上處理是用來傳送單一文件並等待回覆。如果您要傳送多個檔案,或是檔案大小超過線上處理數量上限頁面,也可以使用批次處理。操作方法請參閱 OCR 程式碼研究室

除了處理器 ID 以外,每一種處理器類型用來提出程序要求的程式碼都是相同的。

文件回應物件包含輸入文件中的網頁清單。

每個 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. 剖析資料表

表單剖析器也能擷取文件內表格的資料。在這個步驟中,我們會下載新的範例文件,並從資料表中擷取資料。由於我們正在將資料載入 Pandas,因此透過單一方法呼叫,這項資料可以輸出為 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

擷取資料表資料

資料表資料的處理要求與擷取鍵/值組合的要求完全相同。差別在於我們在回應中從哪些欄位擷取資料。資料表資料會儲存在 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

執行程式碼的目錄中也應該有兩個新的 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,然後按一下「關閉」,即可刪除專案。

瞭解詳情

參加這些後續的程式碼研究室,繼續學習 Document AI。

資源

授權

這項內容採用的是創用 CC 姓名標示 2.0 通用授權。