ניתוח טפסים באמצעות Document AI (Python)

1. מבוא

ב-Codelab הזה תלמדו איך להשתמש ב-Document AI Form Parser כדי לנתח טופס בכתב יד באמצעות Python.

נשתמש בטופס פשוט של קבלת מטופל כדוגמה, אבל התהליך הזה יעבוד עם כל טופס כללי שנתמך על ידי DocAI.

דרישות מוקדמות

ה-Codelab הזה מבוסס על תוכן שמוצג ב-Codelabs אחרים של Document AI.

מומלץ להשלים את ה-Codelabs הבאים לפני שממשיכים.

מה תלמדו

  • איך מנתחים ומחלצים נתונים מטופס סרוק באמצעות הכלי Document AI Form Parser.

מה תצטרכו

  • פרויקט ב-Google Cloud
  • דפדפן, כמו Chrome או Firefox
  • ידע ב-Python 3

סקר

איך תשתמשו במדריך הזה?

רק לקרוא לקרוא ולבצע את התרגילים

איך היית מדרג את חוויית השימוש שלך ב-Python?

מתחילים ביניים מומחים

איזה דירוג מתאים לדעתך לחוויית השימוש שלך בשירותי Google Cloud?

מתחילים ביניים מומחים

2. הגדרה ודרישות

ב-codelab הזה מניחים שהשלמתם את שלבי ההגדרה של Document AI שמפורטים ב-Document AI OCR Codelab.

לפני שממשיכים, צריך לבצע את הפעולות הבאות:

תצטרכו גם להתקין את Pandas, ספרייה בקוד פתוח לניתוח נתונים ב-Python.

pip3 install --upgrade pandas

3. יצירת מעבד לניתוח טפסים

כדי להשתמש ב-Document AI Platform במדריך הזה, צריך קודם ליצור מופע של מעבד Form Parser.

  1. במסוף, עוברים אל Document AI Platform Overview.
  2. לוחצים על יצירת מעבד ובוחרים באפשרות ניתוח טופסמעבדים.
  3. מציינים את שם המעבד ובוחרים את האזור מהרשימה.
  4. לוחצים על יצירה כדי ליצור את המעבד.
  5. מעתיקים את מזהה המעבד. תצטרכו להשתמש בערך הזה בקוד בהמשך.

בדיקת המעבד ב-Cloud Console

כדי לבדוק את המעבד במסוף, אפשר להעלות מסמך. לוחצים על העלאת מסמך ובוחרים טופס לניתוח. אם אין לכם טופס זמין, אתם יכולים להוריד את הטופס לדוגמה הזה ולהשתמש בו.

טופס בריאות

הפלט שלכם אמור להיראות כך: טופס שנותח

4. הורדת טופס לדוגמה

יש לנו מסמך לדוגמה שמכיל טופס פשוט לקבלת מידע רפואי.

אפשר להוריד את קובץ ה-PDF באמצעות הקישור הבא. לאחר מכן מעלים אותו למופע Cloud Shell.

לחלופין, ניתן להוריד אותו מקטגוריה ציבורית של Cloud Storage באמצעות gsutil.

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

כדי לוודא שהקובץ הורד ל-Cloud Shell, מריצים את הפקודה הבאה:

ls -ltr intake-form.pdf

5. חילוץ צמדי מפתח/ערך מטופס

בשלב הזה תשתמשו ב-API לעיבוד אונליין כדי להפעיל את מעבד ניתוח הטפסים שיצרתם קודם. לאחר מכן, תחלצו את צמדי המפתח/ערך שנמצאים במסמך.

עיבוד אונליין מיועד לשליחת מסמך יחיד ולהמתנה לתגובה. אפשר גם להשתמש בעיבוד באצווה אם רוצים לשלוח כמה קבצים או אם גודל הקובץ חורג מהמספר המקסימלי של הדפים בעיבוד אונליין. ב-OCR Codelab מוסבר איך עושים את זה.

הקוד ליצירת בקשת עיבוד זהה לכל סוגי המעבדים, מלבד מזהה המעבד.

אובייקט התגובה 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. ניתוח טבלאות

כלי הניתוח של טפסים יכול גם לחלץ נתונים מטבלאות במסמכים. בשלב הזה נוריד מסמך לדוגמה חדש ונחלץ נתונים מהטבלה. מכיוון שאנחנו טוענים את הנתונים ל-Pandas, אפשר להוציא את הנתונים האלה לקובץ CSV ולפורמטים רבים אחרים באמצעות הפעלת method יחידה.

הורדת טופס לדוגמה עם טבלאות

יש לנו מסמך לדוגמה שמכיל טופס לדוגמה וטבלה.

אפשר להוריד את קובץ ה-PDF באמצעות הקישור הבא. לאחר מכן מעלים אותו למופע Cloud Shell.

לחלופין, ניתן להוריד אותו מקטגוריה ציבורית של Cloud Storage באמצעות gsutil.

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, נכנסים לדף Manage resources.
  • ברשימת הפרויקטים, בוחרים את הפרויקט ולוחצים על Delete (מחיקה).
  • כדי למחוק את הפרויקט, כותבים את מזהה הפרויקט בתיבת הדו-שיח ולוחצים על Shut down.

מידע נוסף

כדי להמשיך ללמוד על Document AI, אפשר לעבור לשיעורי ה-Codelab הבאים.

מקורות מידע

רישיון

עבודה זו מורשית תחת רישיון Creative Commons שמותנה בייחוס 2.0 כללי.