La validación y corrección de Document AI aprovechan el Lenguaje de expresiones comunes (CEL) para permitir la validación y manipulación flexibles de los datos dentro de tus flujos de trabajo de procesamiento de documentos. Document AI ofrece un conjunto de funciones personalizadas, macros y modificaciones de comportamiento diseñadas para los datos de entidades de documentos.
Cómo acceder a entidades en la expresión CEL
Todas las expresiones se evalúan en función de una variable raíz llamada doc, que consta de entidades que son frases o propiedades que pertenecen al documento. Estas entidades siguen de cerca la estructura de las entidades de tu documento extraído.
Si bien una entidad extraída contiene muchas propiedades, solo tres de ellas están disponibles para la evaluación de CEL.
mention_text: Es el texto sin procesar extraído tal como se presenta en una entidad extraída. El valor predeterminado es una cadena vacía.normalized_value: Texto de mención normalizado tal como se presenta en una entidad extraída. El valor predeterminado es nulo. Obtén más información sobre la normalización.bounding_poly: Es un objeto especial que contiene una representación de la ubicación de la entidad extraída en el documento y se usa para las verificaciones de alineación. El valor predeterminado es nulo.
Modelo de datos
La estructura exacta de una entidad extraída dentro del mapa de doc depende de dos factores. El primero es si su estructura es un valor concreto, como un número o texto sin formato, o si es un objeto complejo. El segundo factor es si su tipo de ocurrencia es único o múltiple. Para obtener más información, consulta OccurrenceType.
Una característica clave del modelo de datos de validación es que cualquier entidad definida en el esquema, pero no extraída del documento, se propaga automáticamente con valores predeterminados. Este diseño te permite omitir la mayoría de las verificaciones de nulos explícitas en tus expresiones de CEL, lo que simplifica significativamente tus expresiones de validación. Solo necesitas escribir explícitamente verificaciones de nulos para asegurarte de que se haya extraído una entidad seleccionada.
Ejemplos de casos de entidades hoja
En las siguientes secciones, se describe cómo acceder a las entidades en una entidad hoja, que es aquella que no tiene entidades secundarias anidadas. Las entidades hoja contienen un valor directamente.
Entidad hoja con una sola ocurrencia
Este es el caso más básico, en el que se usa OccurrenceType de OPTIONAL_ONCE o REQUIRED_ONCE. La entidad se representa como un objeto que contiene las tres propiedades estándar.
Un ejemplo de cómo acceder a estos valores es doc.invoice_date.normalized_value.
Tiene la siguiente estructura:
"invoice_date": {
"mention_text": "1",
"normalized_value": 1.0,
"bounding_poly": bounding_poly_object
}
Y el valor predeterminado:
"invoice_date": {
"mention_text": "",
"normalized_value": null,
"bounding_poly": null
}
Entidad de hoja con varias ocurrencias
Este caso se aplica a las entidades hoja que pueden aparecer varias veces y tener un OccurrenceType de OPTIONAL_MULTIPLE o REQUIRED_MULTIPLE. Por ejemplo, en una lista de fechas de vencimiento de pagos, se representa como un objeto en el que cada propiedad contiene una lista de los valores correspondientes de todas las ocurrencias. Por lo tanto, las propiedades como mention_text, normalized_value y bounding_poly pueden tener varias entidades.
Un ejemplo de cómo acceder a estos valores es doc.payment_due_dates.normalized_value[0].
Tiene la siguiente estructura:
"payment_due_dates": {
"mention_text": ["Mar 1, 2024", "Apr 1, 2024"],
"normalized_value": [null, proto.timestamp(2024-04-01)],
// Note: If a value is not normalized, it is stored as a null.
"bounding_poly": [bounding_poly_object,bounding_poly_object]
}
Y el valor predeterminado:
"payment_due_dates": {
"mention_text": [],
"normalized_value": []
"bounding_poly": []
}
Entidades anidadas
Una entidad anidada es un contenedor para otras entidades, que son sus "elementos secundarios".
Entidad anidada con una ocurrencia
Si una entidad anidada aparece solo una vez, por ejemplo, un solo receiver_address, se representa como un objeto en el que las claves son los nombres de sus entidades secundarias.
Un ejemplo de cómo acceder a estos valores es doc.receiver_address.city.mention_text.
Tiene la siguiente estructura:
"receiver_address": {
"street": {
"mention_text": "123 Main St",
"normalized_value": "123 Main St",
"bounding_poly": bounding_poly_object
}
}
Y el valor predeterminado:
"receiver_address": {
"street": {
"mention_text": "",
"normalized_value": null,
"bounding_poly": null
}
}
Entidad anidada con varias ocurrencias
Cuando una entidad anidada puede aparecer varias veces, se representa como una lista de objetos. Cada objeto de la lista representa una instancia completa de la entidad anidada y contiene sus elementos secundarios.
Un ejemplo de cómo acceder a estos valores es doc.line_items[1].description.normalized_value.
Tiene la siguiente estructura:
"line_items": [
{
"description": { "mention_text": "Product A", ... },
"quantity": { "mention_text": "2", ... }
},
{
"description": { "mention_text": "Service B", ... },
"quantity": { "mention_text": "5", ... }
}
]
Y el valor predeterminado:
"line_items": []
Tabla de conversión del valor normalizado
En esta tabla, se muestra cómo se traduce el tipo de datos de la entidad del esquema seleccionado al tipo de datos de CELnormalized_value.
| Tipo de datos del esquema | Tipo de datos de CEL |
|---|---|
| Moneda y dirección | string |
| Número, dinero | double |
| Fecha y hora | proto.Timestamp |
| Casilla de verificación, Firma | bool
|
| Texto sin formato | N/A |
Expresiones de ejemplo
Estas son algunas expresiones en CEL de ejemplo.
// Leaf entity with a single occurrence: Get the invoice ID string
doc.invoice_id.normalized_value == "INV-12345"
// Leaf entity with multiple occurrences: Get the first payment term from the list
doc.payments.mention_text[0].matches('^\d+$')
// Nested entity with one occurrence: Access a child entity of a single nested entity
doc.receiver_address.name.normalized_value.star
tsWith("John")
// Nested entity with multiple occurrences: Access a child of a specific item in a list of nested entities
doc.line_items[1].description.normalized_value == "Premium Gadget"
// Advanced: Sum the total of all line items
doc.line_items.map(item, item.total.normalized_value).sum() == 275.0
// Advanced: Check if any line item has a quantity greater than 1
doc.line_items.exists(item, item.quantity.normalized_value > 1.0)
Estos son otros ejemplos de lógica de CEL que puedes usar.
// Ensure due date is after invoice date
doc.due_date.normalized_value > doc.invoice_date.normalized_value
// Cross list validation: ensure that each employer_contribution
// has a corresponding employee deduction
doc.employer_contribution.size() == doc.employee_deduction.size() && lists.range(doc.employer_contribution.size()).all(i,doc.employee_deduction[i].current_amount.mention_text != "" && doc.employer_contribution[i].current_amount.mention_text != "")
Cambios de comportamiento
El dialecto de CEL de Document AI modifica algunos comportamientos estándar para adaptarse mejor a los casos de uso del procesamiento de documentos.
Igualdad basada en el valor de Epsilon
Para abordar la falta de un tipo decimal en CEL y tener en cuenta las imprecisiones comunes de punto flotante en los datos financieros y numéricos, se modifican los operadores de igualdad (==) y desigualdad (!=) para los tipos numéricos (double, int). En lugar de una igualdad exacta, usan una comparación basada en épsilon con una tolerancia de 1e-2 (0.01).
Por ejemplo, considera un total_amount con un valor normalizado de 100.005.
Con la expresión doc.total_amount.normalized_value == 100.0, el resultado es true. Esto se debe a que abs(100.005 - 100.0) es menor que 0.01. La expresión CEL estándar devolvería false.
Para la expresión doc.total_amount.normalized_value == 100.02, el resultado es false. Esto se debe a que abs(100.005 - 100.02) es mayor que 0.01.
Restricciones de las funciones de cadena
Las funciones estándar de manipulación de cadenas de CEL están restringidas para operar solo en la propiedad mention_text de una entidad. Esta restricción garantiza que las reglas de validación se apliquen de manera coherente a la cadena de texto literal tal como aparece en el documento.
Las funciones afectadas son las siguientes:
contains()endsWith()startsWith()matches()
A continuación, se muestra un ejemplo válido:
// Checks if the extracted currency symbol is a dollar sign.
doc.total_amount.mention_text.startsWith("$")
Este es un ejemplo de un comando no válido:
// This will produce a validation error upon save because contains() is not
// being used on a .mention_text field.
doc.supplier_name.normalized_value.contains("Inc.")
Funciones adicionales
En esta sección, se describen las funciones globales y de miembros no estándar disponibles en el entorno de evaluación de CEL de Document AI.
Función Sum
### sum()
Calcula la suma de una lista de elementos numéricos. Se puede llamar en listas de números enteros o dobles. Ten en cuenta que se ignoran los valores nulos de la lista. Si la lista contiene elementos no numéricos, la función activará un error.
Firma: <list>.sum()
Este es un ejemplo en el que se suma el valor normalizado de varios conceptos.
// Calculates the sum of all line item amounts.
doc.line_item_amounts.normalized_value.sum()
Función OR
### or()
Devuelve el valor original si no es nulo; de lo contrario, devuelve el segundo argumento (predeterminado).
Firma: <value>.or(<;default_value>)
Por ejemplo, puedes usarlo para proporcionar un valor predeterminado cuando podría faltar un campo opcional.
// If the tax amount is not found, use a default of 0.0 for calculation.
doc.tax_amount.normalized_value.or(0.0) > 5.0
Función de alineación vertical de la lista de verificación
### checkVerticalAlignment()
Devuelve true si todos los objetos bounding_poly están alineados verticalmente en un grado especificado por la tolerancia. De lo contrario, devuelve un error que describe qué entidades no están alineadas.
La tolerancia es un argumento opcional que especifica la superposición de un polígono de límite con el polígono de límite mejor alineado seleccionado automáticamente. El valor 0 significa que los polígonos de límite no se intersecan, y el valor 1 significa que los polígonos de límite son idénticos.
Firma: checkVerticalAlignment([<;bounding_poly>,...],tolerance=0.8)
Por ejemplo, puedes usarlo para mantener todas las entidades extraídas en una sola columna.
// Make sure that all extracted quantities are in the same column
checkVerticalAlignment(doc.line_items.map(li,li.quantity.bounding_poly))
Verifica la función de alineación horizontal
### checkHorizontalAlignment()
Devuelve true si todos los objetos bounding_poly están alineados horizontalmente en un grado especificado por la tolerancia. De lo contrario, devuelve un error que describe qué entidades no están alineadas.
La tolerancia es un argumento opcional que especifica la superposición de un polígono de límite con el polígono de límite mejor alineado seleccionado automáticamente. El valor 0 significa que los polígonos de límite no se intersecan, y el valor 1 significa que son idénticos.
Firma: checkHorizontalAlignment([<;bounding_poly>,...],tolerance=0.6)
Por ejemplo, puedes usarlo para mantener todas las entidades extraídas en una sola fila.
// For all line items make sure that each extracted line item's
// children are in the same row. For example, if line item has
// quantity and description properties, it makes sure they are in
// a single row for each respective line item.
doc.line_items.all(li, checkHorizontalAlignment(li.map(col,li[col].bounding_poly)))
Macros adicionales
En esta sección, se describen las macros no estándar disponibles en el entorno de evaluación de CEL de Document AI.
Para obtener más información sobre las macros, consulta Definición del lenguaje: Macros.
Reduce macro
### reduce()
Usa la macro reduce para realizar operaciones acumulativas en una lista.
Firma: <list>.reduce(<;iterator_name>, <;accumulator_name>, <;initial_value>, <;loop_expression>)
iterator_name: Es el nombre de una variable para el elemento que se procesa en cada iteración.accumulator_name: Es el nombre de una variable para el valor que acumula el resultado.initial_value: Es el valor inicial del acumulador.loop_expression: Es una expresión que define cómo se actualiza el acumulador en cada paso.
A continuación, se muestra un ejemplo de uso de una macro:
// Use reduce to sum up the quantities from all line items.
doc.line_items.reduce(item, running_total, 0.0, running_total + item.quantity.normalized_value)
// Result: 3.0
// Tip: this could also be done by concatenating map and sum:
doc.line_items.map(item,item.quantity.normalized_value).sum()
Bibliotecas de extensiones de CEL
Además de las funciones personalizadas, están disponibles las siguientes bibliotecas de extensión de CEL estándar.
- Listas: Proporciona funciones para la manipulación de listas:
range, distinct, flatten, reverse, sort, slice. Para obtener más información, consulta Listas. - Math: Proporciona funciones matemáticas extendidas, como
math.greatest, math.least, math.abs. Para obtener más información, consulta Math.
¿Qué sigue?
Obtén más información sobre los procesadores previamente entrenados.