Document AI (Python)를 사용한 양식 파싱

1. 소개

이 Codelab에서는 Document AI 양식 파서를 사용하여 Python으로 필기 양식을 파싱하는 방법을 알아봅니다.

여기서는 간단한 의료 접수 양식을 예로 사용하지만, 이 절차는 DocAI에서 지원하는 일반화된 모든 양식에서 작동합니다.

기본 요건

이 Codelab은 다른 Document AI Codelabs에서 다룬 콘텐츠를 기반으로 합니다.

다음 Codelab을 먼저 완료한 후에 진행하는 것이 좋습니다.

학습할 내용

  • Document AI 양식 파서를 사용하여 스캔한 양식에서 데이터를 파싱하고 추출하는 방법

필요한 항목

  • Google Cloud 프로젝트
  • 브라우저(Chrome, Firefox 등)
  • 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. 양식 파서 프로세서 만들기

먼저 이 튜토리얼의 Document AI Platform에서 사용할 양식 파서 프로세서 인스턴스를 만들어야 합니다.

  1. 콘솔에서 Document AI Platform 개요로 이동합니다.
  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 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. 파싱 테이블

양식 파서는 문서 내의 테이블에서 데이터를 추출할 수도 있습니다. 이 단계에서는 새 샘플 문서를 다운로드하고 표에서 데이터를 추출합니다. 데이터를 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를 입력한 후 종료를 클릭하여 프로젝트를 삭제합니다.

자세히 알아보기

다음과 같은 후속 Codelab에서 Document AI 학습을 계속하세요.

리소스

라이선스

이 작업물은 Creative Commons Attribution 2.0 일반 라이선스에 따라 사용이 허가되었습니다.