Análisis de formularios con Document AI (Python)

1. Introducción

En este codelab, aprenderás a usar el analizador de formularios de Document AI para analizar un formulario escrito a mano con Python.

Usaremos un formulario de admisión médica simple como ejemplo, pero este procedimiento funcionará con cualquier formulario generalizado admitido por DocAI.

Requisitos previos

Este codelab se basa en contenido presentado en otros codelabs de Document AI.

Recomendamos que completes los siguientes codelabs antes de continuar.

Qué aprenderás

  • Cómo analizar y extraer datos de un formulario escaneado con el analizador de formularios de Document AI.

Requisitos

  • Un proyecto de Google Cloud
  • Un navegador, como Chrome o Firefox
  • Conocimiento de Python 3

Encuesta

¿Cómo usarás este instructivo?

Leer Leer y completar los ejercicios

¿Cómo calificarías tu experiencia en Python?

Principiante Intermedio Avanzado

¿Cómo calificarías tu experiencia en el uso de los servicios de Google Cloud?

Principiante Intermedio Avanzado .
.

2. Configuración y requisitos

En este codelab, se supone que completaste los pasos de configuración de Document AI que se indican en el Codelab de OCR de Document AI.

Completa estos pasos antes de continuar:

También tendrás que instalar Pandas, una biblioteca de análisis de datos de código abierto para Python.

pip3 install --upgrade pandas

3. Crea un procesador de analizador de formularios

Primero, debes crear una instancia del procesador del Analizador de formularios para usarla en Document AI Platform para este instructivo.

  1. En Console, navega a Descripción general de la plataforma de Document AI
  2. Haz clic en Create Processor y selecciona Form Parser.Procesadores
  3. Especifica el nombre del procesador y selecciona tu región en la lista.
  4. Haz clic en Crear para crear tu procesador.
  5. Copia el ID del procesador. Debes usar esto en el código más adelante.

Prueba un procesador en la consola de Cloud

Para probar tu procesador en la consola, puedes subir un documento. Haz clic en Subir documento y selecciona un formulario para analizar. Puedes descargar y usar este formulario de muestra si no tienes uno disponible para usar.

Formulario de salud

Tu resultado debería tener la siguiente apariencia: Formulario analizado

4. Descargar el formulario de muestra

Tenemos un documento de muestra que contiene un formulario simple de admisión médica.

Puedes descargar el PDF mediante el siguiente vínculo. Luego, súbelo a la instancia de Cloud Shell.

También puedes descargarlo de nuestro bucket público de Google Cloud Storage con gsutil.

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

Confirma que el archivo se haya descargado en Cloud Shell con el siguiente comando:

ls -ltr intake-form.pdf

5. Extrae pares clave-valor de formularios

En este paso, usarás la API de procesamiento en línea para llamar al procesador del analizador de formularios que creaste anteriormente. Luego, extraerás los pares clave-valor que se encuentran en el documento.

El procesamiento en línea consiste en enviar un solo documento y esperar la respuesta. También puedes utilizar el procesamiento por lotes si deseas enviar varios archivos o si el tamaño del archivo supera el máximo de páginas de procesamiento en línea. Puedes revisar cómo hacerlo en el Codelab de OCR.

El código que se usa a fin de realizar una solicitud de proceso es idéntico para todos los tipos de procesadores, excepto el ID.

El objeto de respuesta Document contiene una lista de páginas del documento de entrada.

Cada objeto page contiene una lista de campos de formulario y sus ubicaciones en el texto.

El siguiente código se itera en cada página y extrae cada clave, valor y puntuación de confianza. Se trata de datos estructurados que pueden almacenarse más fácilmente en bases de datos o usarse en otras aplicaciones.

Crea un archivo llamado form_parser.py y usa el código que se proporciona a continuación.

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)

Ejecuta el código ahora y deberías ver el texto extraído e impreso en tu consola.

Deberías ver el siguiente resultado si usas nuestro documento de muestra:

$ 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. Analizar tablas

El analizador de formularios también puede extraer datos de tablas de documentos. En este paso, descargaremos un nuevo documento de muestra y extraeremos datos de la tabla. Dado que estamos cargando los datos en Pandas, estos se pueden enviar a un archivo CSV y a muchos otros formatos con una sola llamada al método.

Descargar el formulario de muestra con tablas

Tenemos un documento de muestra que contiene un formulario de muestra y una tabla.

Puedes descargar el PDF mediante el siguiente vínculo. Luego, súbelo a la instancia de Cloud Shell.

También puedes descargarlo de nuestro bucket público de Google Cloud Storage con gsutil.

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

Confirma que el archivo se haya descargado en Cloud Shell con el siguiente comando:

ls -ltr form_with_tables.pdf

Extraer datos de tablas

La solicitud de procesamiento de los datos de la tabla es exactamente la misma que la de la extracción de pares clave-valor. La diferencia está en los campos de los que extraemos los datos en la respuesta. Los datos de la tabla se almacenan en el campo pages[].tables[].

En este ejemplo, se extrae información de las filas de encabezado y de cuerpo de la tabla para cada tabla y página. Luego, imprime la tabla y la guarda como un archivo CSV.

Crea un archivo llamado table_parsing.py y usa el código que se proporciona a continuación.

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)

Ejecuta el código ahora y deberías ver el texto extraído e impreso en tu consola.

Deberías ver el siguiente resultado si usas nuestro documento de muestra:

$ 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

También deberías tener dos archivos CSV nuevos en el directorio desde el que ejecutas el código.

$ ls
form_with_tables_pg1_tb0.csv form_with_tables_pg1_tb1.csv table_parsing.py

7. Felicitaciones

Felicitaciones, usaste correctamente la API de Document AI para extraer datos de un formulario escrito a mano. Te recomendamos experimentar con otros documentos del formulario.

Realiza una limpieza

Para evitar que se generen cargos en tu cuenta de Google Cloud por los recursos que usaste en este instructivo, sigue estos pasos:

  • En la consola de Cloud, ve a la página Administrar recursos.
  • En la lista de proyectos, selecciona tu proyecto y haz clic en Borrar.
  • En el diálogo, escribe el ID del proyecto y, luego, haz clic en Cerrar para borrarlo.

Más información

Sigue aprendiendo sobre Document AI con estos codelabs de seguimiento.

Recursos

Licencia

Este trabajo cuenta con una licencia Atribución 2.0 Genérica de Creative Commons.