DEV Community

camilo cabrales
camilo cabrales

Posted on

Definición de arquitectura con Application Composer para análisis de documentos con Textract

Este mes (Diciembre de 2022) AWS lanzo un nuevo servicio llamado Application Composer, que nos sirve para la definición de arquitecturas Serverless de manera gráfica e intuitiva, donde podemos arrastrar los diferentes servicios en el espacio de trabajo con el objetivo de definir nuestra arquitectura.

En este post vamos a definir una arquitectura que nos va a permitir extraer el texto de varias facturas para llevar el control de nuestros gastos.

Iniciemos buscando el Servicio Application Composer

Init Page

Y en la pagina principal le damos click en Canvas, que nos va a mostrar las opciones de creación de nuestra arquitectura.

Create Project

Vemos dos opciones para la creación de nuestra arquitectura conectada y no conectada. La opción conectada va a sincronizar los cambios que realicemos en una carpeta de nuestro equipo y no conectada nosotros somos los encargados de guardar nuestra arquitectura.
Seleccionamos la opción no conectada y damos click en crear.

Canvas

Como podemos ver la pantalla es muy intuitiva y podemos encontrar los servicios que podemos incluir, la vista de diseño, la vista de la plantilla de SAM que se va generando de acuerdo vamos incluyendo servicios en nuestra arquitectura y el ménu.

Vamos a crear la siguiente arquitectura arrastrando los servicios al Canvas.

Canvas

Ahora vamos a configurar algunas de las propiedades que están disponibles desde el diseñador.

Para el Bucket configuramos el nombre:

Bucket

Para la función Lambda configuramos el nombre, el runtime, la memoria y el tiempo de ejecución:

Lambda

Para la tabla de DynamoDB le definimos un nombre y el nombre de la primarykey:

DynamoDB

Ahora podemos visualizar la plantilla generada y guardamos el archivo desde el menú.

Template

Antes de validar y modificar nuestra plantilla, vamos a ver el servicio Textract que nos sirve para extraer texto de diferentes tipos de documentos.

Para esto buscamos el servicio Textract, en la pantalla principal del servicio damos click en Analyze Document.

Textract

En la pagina podemos ver los resultados de la extracción de texto de un documento de ejemplo que nos brinda AWS y las formas con las cuales podemos obtener la información, que son: texto plano, formularios, tablas, consultas o firmas. Para nuestro caso vamos utilizar consultas (queries).

Ahora utilicemos una de las imágenes de nuestro ejemplo.

Primero seleccionamos la imagen de la cual queremos extraer el texto:

Select File

Ahora seleccionamos como queremos ver los resultados (Forms,Tables,Queries) y agregamos las consultas que vamos hacer sobre el documento. Es importante que todas las consultas empiecen por what o where, en este caso utilice una mezcla de ingles y español para que Textract encontrara los resultados de manera mas acertada, ya que si hacia los queries solo en ingles no encontraba de manera correcta los valores.

Select Queries

Al final Textract nos muestra los resultados en los formatos que hallamos seleccionado.

Result Queries

Ya que hemos visto el funcionamiento de Textract vamos a ver como podemos realizar esto de manera asíncrona con la arquitectura que definimos al inicio del post.

Vamos hacer algunas modificaciones a la plantilla que descargamos de Application Composer.

Empecemos modificando la sección de la funcion Lambda agregando las políticas TextractDetectAnalyzePolicy,CloudWatchPutMetricPolicy,S3FullAccessPolicy Lambda y después agregamos el código fuente de la función.

import boto3
import urllib

textract = boto3.client('textract')
dynamodb = boto3.client('dynamodb')

class Factura:

    def __init__(self, idFactura="", fechaFactura="", valorAPagar="",nombreArchivo=""):
        self.idFactura = idFactura
        self.fechaFactura = fechaFactura
        self.valorAPagar = valorAPagar
        self.nombreArchivo = nombreArchivo

    def getNombreArchivo(self):
        return self.nombreArchivo

    def getIdFactura(self):
        return self.idFactura

    def getFechaFactura(self):
        return self.fechaFactura

    def getValorAPagar(self):
        return self.valorAPagar

    def setIdFactura(self, idFactura):
        self.idFactura = idFactura

    def setFechaFactura(self, fechaFactura):
        self.fechaFactura = fechaFactura

    def setValorAPagar(self, valorAPagar):
        self.valorAPagar = valorAPagar

    def setNombreArchivo(self, nombreArchivo):
        self.nombreArchivo = nombreArchivo

def lambda_handler(event, context):
    # TODO implement
    bucket = event['Records'][0]['s3']['bucket']['name']
    nombreObjeto = urllib.parse.unquote_plus(event['Records'][0]['s3']['object']['key'], encoding='utf-8')

    response = textract.analyze_document(
        Document={
            'S3Object': {
                'Bucket': bucket,
                'Name': nombreObjeto
            }
        },
        FeatureTypes=["QUERIES"],
        QueriesConfig={
            "Queries": [{
                "Text": "What is the Fecha vencimiento y pago",
                "Alias": "Fecha de pago"
            },
                {
                "Text": "What is the Total a pagar",
                "Alias": "Valor a pagar"
            },
                {
                "Text": "What is the BEC",
                "Alias": "Numero de Factura"
            }]
        })
    blocks = response['Blocks']
    i = 0
    factura = Factura()
    factura.setNombreArchivo(nombreObjeto)
    for block in blocks:
        if block['BlockType'] == "QUERY_RESULT":
            if float(block['Confidence']) >= 60:
                if i == 0:
                    factura.setFechaFactura(block["Text"])
                elif i == 1:
                    factura.setValorAPagar(block["Text"])
                elif i == 2:
                    factura.setIdFactura(block["Text"])
            i += 1
            print(block)
    result = dynamodb.put_item(
        TableName='datosfacturas',
        Item={
            'PK': {'S': factura.getIdFactura()},
            'FechaPago': {'S': factura.getFechaFactura()},
            'ValorPago': {'S': factura.getValorAPagar()},
            'NombreArchivo': {'S': factura.getNombreArchivo()}
        },
        ConditionExpression="attribute_not_exists(PK)"
    )
Enter fullscreen mode Exit fullscreen mode

Cuando ejecutamos el código vamos a obtener un error.
De acuerdo a la que encontré me di cuenta que al parecer se debe a la versión de boto3 que tiene Lambda configurada, para solucionar este error debemos crear una Layer con una versión mas actualizada de Boto3.

Para saber la versión de Boto3 que maneja Lambda se puede ejecutar dentro de la función:

print(boto3.__version__)
Enter fullscreen mode Exit fullscreen mode

Que en mi caso el resultado es: 1.26.23 y la version actual en este momento de Boto3 es: 1.26.26.

Para dar solución vamos a crear el Layer.

LIB_DIR=boto3-mylayer/python
mkdir -p $LIB_DIR

pip3 install boto3 -t $LIB_DIR

cd boto3-mylayer
zip -r /tmp/boto3-mylayer.zip .

aws lambda publish-layer-version --layer-name boto3updated --zip-file fileb:///tmp/boto3-mylayer.zip --compatible-runtimes "python3.7" "python3.8"
Enter fullscreen mode Exit fullscreen mode

Una vez creado el Layer debemos copiar el ARN y agregarlo al template.

Layer

Una vez creada la Layer y realizados los cambios en la plantilla vamos a validar y desplegar los servicios.

Para validar la plantilla debemos ejecutar el siguiente comando desde la terminal (textract.yml es el nombre que le dimos a nuestra plantilla).

sam validate --template textract.yml
Enter fullscreen mode Exit fullscreen mode

Al ejecutar este comando debemos ver en la terminal algo como esto:

SAM Validate

Ahora que la validación de nuestra plantilla es correcta debemos eejecutar el siguiente comando para desplegar los servicios de nuestra arquitectura.

sam deploy --template textract.yml --stack-name textractinvoices --capabilities CAPABILITY_IAM
Enter fullscreen mode Exit fullscreen mode

El resultado del comando es el siguiente:

Deploy

Hemos finalizado con el despliegue satisfactoriamente, ahora podemos ingresar a S3 y subir los archivos de prueba al bucket y validar en DynamoDB que los datos se hayan ingresado correctamente.

Application Composer es un nuevo servicio que como tal hacen algunas cosas por afinar como: agregar mas opciones de edición a cada servicio, mejorar como se generan las plantillas, sin embargo es una muy opción para definir arquitecturas Serverless y tener una plantilla SAM base que nos ayude a mejorar nuestros tiempos de desarrollo.

Archivos del post:

plantilla

archivos de prueba

Me pueden encontrar en

Camilo Cabrales

Referencias

Textract Boto3
Crear Layer Boto3

Top comments (0)