Análise de formulário com a Document AI (Python)

1. Introdução

Neste codelab, você vai aprender a usar o analisador de formulários da Document AI para analisar um formulário escrito à mão com Python.

Usaremos um formulário de admissão médica simples como exemplo, mas esse procedimento funcionará com qualquer forma generalizada compatível com o DocAI.

Pré-requisitos

Este codelab se baseia no conteúdo apresentado em outros codelabs da Document AI.

Recomendamos que você conclua os codelabs a seguir antes de continuar.

O que você vai aprender

  • Como analisar e extrair dados de um formulário digitalizado usando o analisador de formulários da Document AI.

O que é necessário

  • Um projeto do Google Cloud
  • Um navegador, como o Chrome ou o Firefox
  • Conhecimento sobre o Python 3

Pesquisa

Como você vai usar este tutorial?

Apenas leitura Ler e fazer os exercícios

Como você classificaria sua experiência com Python?

Iniciante Intermediário Proficiente

Como você classificaria sua experiência de uso dos serviços do Google Cloud?

Iniciante Intermediário Proficiente

2. Configuração e requisitos

Este codelab presume que você concluiu as etapas de configuração da Document AI listadas no Codelab da OCR da Document AI.

Conclua as etapas a seguir antes de continuar:

Também é necessário instalar o Pandas, uma biblioteca de análise de dados de código aberto para Python.

pip3 install --upgrade pandas

3. Criar um processador do analisador de formulários

Primeiro, é necessário criar uma instância do processador do analisador de formulários para usar na Document AI Platform neste tutorial.

  1. No console, navegue até a Visão geral do Document AI Platform.
  2. Clique em Criar processador e selecione Form ParserProcessadores
  3. Especifique um nome de processador e selecione sua região na lista.
  4. Clique em Criar para criar seu processador.
  5. Copie o ID do processador. Você precisará usá-la em seu código mais tarde.

Testar o processador no console do Cloud

É possível fazer upload de um documento para testar o processador no console. Clique em Fazer upload do documento e selecione um formulário para analisar. É possível fazer o download e usar este formulário de exemplo se você não tiver um disponível.

Formulário de integridade

A resposta será parecida com esta: Formulário analisado

4. Faça o download do formulário de amostra

Temos um documento de amostra que contém um formulário de admissão médica simples.

Faça o download do PDF usando o link abaixo. Em seguida, faça o upload dele na instância do Cloud Shell.

Como alternativa, é possível fazer o download dele pelo bucket público do Google Cloud Storage usando gsutil.

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

Confirme se o download do arquivo foi feito no Cloud Shell usando o comando abaixo:

ls -ltr intake-form.pdf

5. Extrair pares de chave-valor de formulários

Nesta etapa, você vai usar a API de processamento on-line para chamar o processador analisador de formulários criado anteriormente. Depois, você vai extrair os pares de chave-valor encontrados no documento.

O processamento on-line serve para enviar um único documento e aguardar a resposta. Também é possível usar o processamento em lote se quiser enviar vários arquivos ou se o tamanho do arquivo exceder o máximo de páginas do processamento on-line. Veja como fazer isso no Codelab de OCR.

O código para fazer uma solicitação de processo é idêntico para todos os tipos de processador, exceto o ID do processador.

O objeto de resposta Document contém uma lista de páginas do documento de entrada.

Cada objeto page contém uma lista de campos de formulário e os respectivos locais no texto.

O código a seguir itera em cada página e extrai cada chave, valor e pontuação de confiança. São dados estruturados que podem ser armazenados em bancos de dados ou usados em outros aplicativos com mais facilidade.

Crie um arquivo chamado form_parser.py e use o código abaixo.

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)

Execute o código agora para ver o texto extraído e impresso no console.

Você vai ver a resposta a seguir se estiver usando o documento de amostra:

$ 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. Analisar tabelas

O Analisador de formulários também é capaz de extrair dados de tabelas dentro de documentos. Nesta etapa, vamos fazer o download de um novo documento de amostra e extrair dados da tabela. Como estamos carregando os dados no Pandas, eles podem ser enviados para um arquivo CSV e muitos outros formatos com uma única chamada de método.

Faça o download do formulário de amostra com tabelas

Temos um documento de amostra que contém um formulário de amostra e uma tabela.

Faça o download do PDF usando o link abaixo. Em seguida, faça o upload dele na instância do Cloud Shell.

Como alternativa, é possível fazer o download dele pelo bucket público do Google Cloud Storage usando gsutil.

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

Confirme se o download do arquivo foi feito no Cloud Shell usando o comando abaixo:

ls -ltr form_with_tables.pdf

Extrair dados da tabela

A solicitação de processamento de dados de tabela é exatamente igual à extração de pares de chave-valor. A diferença é de quais campos extraímos os dados na resposta. Os dados da tabela são armazenados no campo pages[].tables[].

Este exemplo extrai informações sobre as linhas do cabeçalho e do corpo da tabela para cada tabela e página, depois imprime a tabela e salva como um arquivo CSV.

Crie um arquivo chamado table_parsing.py e use o código abaixo.

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)

Execute o código agora para ver o texto extraído e impresso no console.

Você vai ver a resposta a seguir se estiver usando o documento de amostra:

$ 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

Você também precisa ter dois novos arquivos CSV no diretório do qual está executando o código.

$ ls
form_with_tables_pg1_tb0.csv form_with_tables_pg1_tb1.csv table_parsing.py

7. Parabéns

Parabéns! Você usou a API Document AI para extrair dados de um formulário escrito à mão. Incentivamos você a testar outros documentos de formulário.

Limpeza

Para evitar cobranças dos recursos usados neste tutorial na conta do Google Cloud, siga estas etapas:

  • No console do Cloud, acesse a página Gerenciar recursos.
  • Na lista de projetos, selecione o projeto e clique em "Excluir".
  • Na caixa de diálogo, digite o ID do projeto e clique em "Encerrar" para excluí-lo.

Saiba mais

Saiba mais sobre a Document AI com estes codelabs de acompanhamento.

Recursos

Licença

Este conteúdo está sob a licença Atribuição 2.0 Genérica da Creative Commons.