SAP Leonardo Machine Learning Foundation es un conjunto de servicios y tecnologías que SAP Cloud Platform brinda permitiendo la introducción de Inteligencia Artificial a sus procesos de negocio.
GeneXus permite consumir los servicios de Inteligencia Artificial de SAP Leonardo agregando valor a las aplicaciones desarrolladas.
La solución GeneXus for SAP Leonardo, dentro de lo que conocemos como GeneXus for SAP Systems, engloba los siguientes pilares:

GeneXus cuenta con un SDK para SAP Leonardo que contiene todos los objetos necesarios para consumir servicios de Machine Learning de SAP Leonardo.
El SDK de GeneXus for SAP Leonardo es actualizado constantemente para mantener la última versión de los servicios ofrecidos por SAP.
Para descargar el SDK haga click aquí.
Obtendrá un archivo con extensión xpz (una de las metodología utilizada por GeneXus para compartir conocimiento entre developers)


Explore el directorio donde descargó el xpz y selecciónelo.
Cargue el archivo xpz descargado seleccionando la opción ‘Load’
Seleccione ‘Import’ para realizar la importación del SDK para SAP Leonardo .
Para el caso del ejemplo que venimos desarrollando, necesitamos que una foto tomada desde el dispositivo móvil se pueda comparar con las imágenes que están registradas en nuestra base de datos (el atributo ProductImage de la transacción Product).
En el procesamiento de imágenes, se obtiene de las imágenes un vector de características (un vector numérico que representa al objeto) que permite efectuar comparaciones con otros vectores de características obtenidos de otras imágenes.
Cuando se definió la transacción Product se tomó en cuenta definir un atributo para poder guardar en cada registro de un producto, el vector de características asociado a la imagen que tiene como atributo.
Además de trabajar con el vector de características de una imagen, también debemos comparar imágenes y establecer qué tan similares son para saber a qué repuesto del sistema corresponde la foto enviada por el taller mecánico.
SAP Leonardo Machine Learning Foundation cuenta con dos servicios que nos sirven para los fines buscados, uno de ellos dada una imagen obtiene su vector de características y otro que compara imágenes (en base a este vector de características) y nos devuelve la similitud entre las mismas, retornando un porcentaje de similitud en un rango de 0% a 100%.
Una vez terminada la importación de SDK para SAP Leonardo puede observar en el explorador de la Knowledge Base que se han importado módulos de diferentes servicios de inteligencia artificial.

Observe que para cada uno de los servicios, se han generado los procedimientos y estructuras de forma automática para realizar la llamada al servicio. En este caso se observan los objetos generados para los servicios a ser utilizado en este desarrollo.
- ImageFeatureExtraction
- Similarity Scoring
Los objetos incluyen los procedimientos de invocación del servicio dentro de la carpeta Api, la carpeta Client que contiene el procedimiento donde se define la dirección del servicio a consumir y la carpeta Model que contiene las estructuras necesarias para trabajar con el servicio.

Antes de implementar el procedimiento que compara la similitud de las imágenes deberá importar una herramienta que permite comprimir archivos en formato .zip
El archivo .xpz a importar contiene los archivos necesarios para el funcionamiento de la herramienta e imágenes a utilizar en la solución (descargarlo aquí).
En la barra de menú de su Knowledge Base diríjase a Knowledge Manager y seleccione Import

Seleccione el archivo descargado de GeneXus Marketplace y seleccione la opción Import.

Una vez que vea el mensaje de ‘Import Succes’ en el panel de Output, podrá ver en KB Explorer que se ha creado la siguiente carpeta:

Utilizaremos esta herramienta a continuación para efectuar la comparación de las imágenes y poder obtener el porcentaje de similitud.
Una vez terminada la importación del SDK puede comenzar a implementar la utilización de los servicios para cumplir con la funcionalidad requerida.
Para implementar de manera ordenada, cree una nueva carpeta en Root Module haciendo click derecho y seleccionando New->Folder
Llame a esta carpeta ‘LeonardoProductPrompt’
Primero comience por implementar un procedimiento que haga uso del servicio de Image Feature Extraction para guardar el vector de características de una imagen asociada a un producto.
Haga click derecho en la carpeta ‘LeonardoProductPrompt’ y seleccione New->Object o presione Ctrl+N.
Nombre al procedimiento ‘ProductFeatureExtraction’ y haga click en Create.

Como parámetro el procedimiento deberá recibir el identificador del producto (ProductId), el cual tiene una imagen asociada. Para dicha imagen se utilizara el servicio de extracción del vector de características.
En la pestaña ‘Rules’ defina:

La variable ProductId se habrá definido de manera automática en la pestaña ‘Variables’.
En la pestaña ‘Source’ especifique el siguiente código.
for each
where ProductId = &ProductId
&ProductBlob = ProductImage
endfor
// SAP Leonardo Image Feature Extraction for comparing images
&SendFile.Source = &ProductBlob
&isOK = GeneXusSAPLeonardo.ImageFeatureExtraction.POSTInferenceSync(&SendFile, '', '', &ResponseOK, &ResponseError, &Messages)
if &isOK
&FeatureVector = &ResponseOK.predictions.Item(1)
for each
where ProductId = &ProductId
ProductFeatureVector = &FeatureVector.featureVectors.ToJson()
endfor
endif
|
Analicemos el código definido.
for each
where ProductId = &ProductId
&ProductBlob = ProductImage
endfor
|
Se busca en la base de datos el producto que coincida con identificador recibido como parámetro de entrada y se copia la imagen asociada del producto a una variable de tipo Blob.
// SAP Leonardo Image Feature Extraction for comparing images
&SendFile.Source = &ProductBlob
&isOK = GeneXusSAPLeonardo.ImageFeatureExtraction.POSTInferenceSync(&SendFile, '', '', &ResponseOK, &ResponseError, &Messages)
|
Se asocia la imagen contenida en la variable Blob como fuente de una variable de tipo File.
Se realiza la llamada al servicio de ImageFeatureExtraction pasando como parámetro, el archivo de la imagen y variables que retornan información sobre la ejecución de la llamada.
También se retorna una variable booleana &isOK indicando si la llamada se realizó con éxito.
if &isOK
&FeatureVector = &ResponseOK.predictions.Item(1)
for each
where ProductId = &ProductId
ProductFeatureVector = &FeatureVector.featureVectors.ToJson()
endfor
endif
|
Si la llamada al servicio de SAP Leonardo fue exitosa, se extrae el vector de características de la estructura retornada por el servicio y se guarda en la base de datos, para el producto tratado.
Defina las variables de la siguiente manera
Nombre Variable
|
Tipo Variable
|
FeatureVector
|
FeatureVector, GeneXusSAPLeonardo.ImageFeatureExtraction
|
ProductBlob
|
Blob
|
ProductId
|
Attribute: ProductId
|
isOK
|
Boolean
|
Messages
|
Messages.Message, GeneXus.Common
|
ResponseError
|
ResponseError, GeneXusSAPLeonardo.ImageFeatureExtraction
|
ResponseOK
|
ResponseOk, GeneXusSAPLeonardo.ImageFeatureExtraction
|
SendFile
|
File
|
TIP: a las variables FeatureVector, ProductBlob, isOK y SendFile, para definirlas, podrá simplemente clickear botón derecho sobre ellas en el Source y seleccionar Add Variable. GeneXus definira automaticamente las mismas del tipo correcto, debido a que puede inferirlo del nombre de cada una de ellas.
|
Haga click en el Icono del Diskette o presione Ctrl+S para salvar el progreso realizado.
El método implementado anteriormente realiza una llamada al servicio de ImageFeatureExtraction que se encuentra en SAP Cloud Platform.
SimilarityScoring
A continuación definiremos un procedimiento que permita compara la imagen de un producto (el producto a pedir por parte del tallerista), con las del catálogo de productos de la compañía, utilizando el servicio de similitud de imágenes.
Para esto, primero crearemos un tipo de datos estructurado (Structured Data Type) que permita almacenar la información necesaria para la comparación.
Haga click derecho en la carpeta ‘LeonardoProductPrompt’ y seleccione New->Object o presione Ctrl+N.
Nombre al Structured Data Type ‘SDTProductSimilar’

Una vez creado, marque el Structured Data Type como colección.

Defina los siguientes atributos:
Nombre Atributo
|
Tipo Atributo
|
SDTProductSimilarItemId
|
Attribute:ProductId
|
SDTProductSimilarItemDesc
|
Attribute:ProductDesc
|
SDTProductSimilarItemImage
|
Attribute:ProductImage
|
SDTProductSimilarItemSimilarity
|
Character(10)
|
SDTProductSimilarItemBar
|
Image
|
La estructura debería haber quedado definida de la siguiente manera:

Haga click en el Icono del Diskette o presione Ctrl+S para salvar el progreso realizado.
Para utilizar el servicio de similitud de imágenes cree un Procedure en la carpeta LeonardoProductPrompt haciendo click derecho, seleccione New->Object

Nombre al procedimiento ‘SimilarImages’ y haga click en Create.
Este procedimiento recibirá una imagen (la imagen del repuesto del que se desea obtener los datos) y retornará una variable del tipo del Structured Data Type definido anteriormente, donde se almacenará la información del resultado de comparar la similitud con el resto de las imágenes, una por una.
En la pestaña ‘Rules’ defina los siguientes parámetros.
parm(in:&NewImage, out:&SDTProductSimilar);
|
El tipo de datos de estas variables será inferido por GeneXus de forma automática.
En la solapa Source agregue el siguiente código:
do 'GetNewImage'
do 'GetFeatureVectorForAllImages'
for each
// Compare New Image with each Product in the Material Master
&ProductFeatureVector = ProductFeatureVector
do 'CreateZipFileToSendToTheService'
//Call SAP Leonardo API for Similarity Scoring
&isOK = GeneXusSAPLeonardo.SimilarityScoring.PostSimilarityScoring(&chara, &sendFile,'','',&ResponseOK, &ResponseError,&Messages)
if &isOK
&SDTProductSimilarItem.SDTProductSimilarItemId = ProductId
&SDTProductSimilarItem.SDTProductSimilarItemDesc = ProductDesc
&SDTProductSimilarItem.SDTProductSimilarItemImage = ProductImage
&ProductSimilarSimilarity = &ResponseOk.predictions.Item(1).similarVectors.Item(1).score * 100
&SDTProductSimilarItem.SDTProductSimilarItemSimilarity = &ProductSimilarSimilarity.ToString().Trim() + ' %'
do 'StoreGraphImage'
&SDTProductSimilar.Add(&SDTProductSimilarItem)
&SDTProductSimilarItem = new()
else
msg('Result - Id : ' + &Messages.Id.Trim() + ' ' + &Messages.Description.Trim())
msg('Leonardo msg - Status: ' + &ResponseOk.status.Trim() + ' ' + &ResponseError.error.code + ' ' + &ResponseError.error.message.Trim())
endif
endfor
&SDTProductSimilar.Sort('SDTProductSimilarItemSimilarity')
|
Este código se puede separar en seis etapas.
- En la primera se obtiene la imagen a comparar por similitud.
- En la segunda etapa, para la nueva imagen recibida se obtiene su vector de características y se guarda en un archivo para ser enviado posteriormente al servicio de comparación por similitud. Adicionalmente, para cada imagen del Maestro de Productos, si no tiene vector de características definido, se llama al procedimiento para obtenerlo.
- Se crea un archivo de tipo zip (el tipo esperado por el servicio de SAP Leonardo) con los vectores de características a ser comparados.
- Se llama al servicio de similitud de imágenes comparando una a una las imágenes almacenadas con la imagen recibida como parámetro.
- Los resultados de comparar las imágenes en la base de datos con la imagen recibida por parámetro son almacenados en la estructura a ser retornada por la función.
Esta estructura contendrá el porcentaje de similitud de cada imagen con la imagen recibida por parámetro.
- Como último paso se ordena la estructura, para devolver el resultado ordenado en base a la similitud de las imágenes, con la imagen recibida por parámetro.
Agregue en la solapa Source del procedimiento, la definición de las cuatro subrutinas utilizadas.
sub 'GetNewImage'
CSHARP !&ImagePathString! = !&NewImage!;
JAVA !&ImagePathString! = !&NewImage!;
&ImageGUIDString = &ImagePathString.Substring(&ImagePathString.IndexOf(!':') +1, 9999)
&Cache = Cache.GetCache("FL")
&ImagePathString = &Cache.Get( &ImageGUIDString )
endsub
sub 'GetFeatureVectorForAllImages'
&SendFile.Source = &ImagePathString
&isOK = GeneXusSAPLeonardo.ImageFeatureExtraction.POSTInferenceSync(&SendFile, '', '', &ResponseOKFExtraction, &ResponseErrorFExtraction, &Messages)
&FeatureVector = &ResponseOKFExtraction.predictions.Item(1)
&FeatureFileA.Source = 'vectora.txt'
&FeatureLines = new()
&FeatureLines.Add(&FeatureVector.featureVectors.ToJson())
&FeatureFileA.WriteAllLines(&FeatureLines)
for each
if ProductFeatureVector.IsEmpty()
ProductFeatureExtraction(ProductId)
endif
endfor
endsub
sub 'CreateZipFileToSendToTheService'
&FeatureFileB.Source = 'vectorb.txt'
&FeatureLines = new()
&FeatureLines.Add(&ProductFeatureVector)
&FeatureFileB.WriteAllLines(&FeatureLines)
&ZipFiles = !'vectora.txt;vectorb.txt'
&ZipFileName = !'data.zip'
&ZipTools.doZipListFiles(&ZipFiles, &ZipFileName)
&CodErr = &ZipTools.getZipErrCode()
&MsgErr = &ZipTools.getZipErrText()
if not &CodErr = 'ZIP000'
Msg("Cód. Error: " + &CodErr + " Msg. Error: " + &MsgErr)
endif
&SendFile.Source = !'data.zip'
&chara = '{"numSimilarVectors":1}'
endsub
sub 'StoreGraphImage'
do case
case &ProductSimilarSimilarity = 0
&SDTProductSimilarItem.SDTProductSimilarItemBar.FromImage(Image:bar_0)
case &ProductSimilarSimilarity > 0 and &ProductSimilarSimilarity <= 10
&SDTProductSimilarItem.SDTProductSimilarItemBar.FromImage(Image:bar_10)
case &ProductSimilarSimilarity > 10 and &ProductSimilarSimilarity <= 20
&SDTProductSimilarItem.SDTProductSimilarItemBar.FromImage(Image:bar_20)
case &ProductSimilarSimilarity > 20 and &ProductSimilarSimilarity <= 30
&SDTProductSimilarItem.SDTProductSimilarItemBar.FromImage(Image:bar_30)
case &ProductSimilarSimilarity > 30 and &ProductSimilarSimilarity <= 40
&SDTProductSimilarItem.SDTProductSimilarItemBar.FromImage(Image:bar_40)
case &ProductSimilarSimilarity > 40 and &ProductSimilarSimilarity <= 50
&SDTProductSimilarItem.SDTProductSimilarItemBar.FromImage(Image:bar_50)
case &ProductSimilarSimilarity > 50 and &ProductSimilarSimilarity <= 60
&SDTProductSimilarItem.SDTProductSimilarItemBar.FromImage(Image:bar_60)
case &ProductSimilarSimilarity > 60 and &ProductSimilarSimilarity <= 70
&SDTProductSimilarItem.SDTProductSimilarItemBar.FromImage(Image:bar_70)
case &ProductSimilarSimilarity > 70 and &ProductSimilarSimilarity <= 80
&SDTProductSimilarItem.SDTProductSimilarItemBar.FromImage(Image:bar_80)
case &ProductSimilarSimilarity > 80 and &ProductSimilarSimilarity <= 90
&SDTProductSimilarItem.SDTProductSimilarItemBar.FromImage(Image:bar_90)
case &ProductSimilarSimilarity > 90
&SDTProductSimilarItem.SDTProductSimilarItemBar.FromImage(Image:bar_100)
endcase
endsub
|
En la pestaña ‘Variables’ verifique que la definición de las variables del procedimiento sea la siguiente.
Nombre Variable
|
Tipo Variable
|
Colección
|
Cache
|
Cache
|
|
FeatureVector
|
FeatureVector, GeneXusSAPLeonardo.ImageFeatureExtraction
|
|
isOK
|
Boolean
|
|
NewImage
|
Image
|
|
SDTProductSimilar
|
SDTProductSimilar
|
|
SendFile
|
File
|
|
chara
|
VarChar(40)
|
|
CodErr
|
VarChar(120)
|
|
FeatureFileA
|
File
|
|
FeatureFileB
|
File
|
|
FeatureLines
|
Character(20)
|
X
|
ImageGUIDString
|
VarChar(40)
|
|
ImagePathString
|
VarChar(40)
|
|
Messages
|
Messages.Message, GeneXus.Common
|
|
MsgErr
|
VarChar(120)
|
|
ProductFeatureVector
|
Attribute: ProductFeatureVector
|
|
ProductSimilarSimilarity
|
Numeric(6.2)
|
|
ResponseError
|
ResponseError, GeneXusSAPLeonardo.SimilarityScoring
|
|
ResponseErrorFExtraction
|
ResponseError, GeneXusSAPLeonardo.ImageFeatureExtraction
|
|
ResponseOK
|
ResponseOk, GeneXusSAPLeonardo.SimilarityScoring
|
|
ResponseOKFExtraction
|
ResponseOk, GeneXusSAPLeonardo.ImageFeatureExtraction
|
|
SDTProductSimilarItem
|
SDTProductSimilar.SDTProductSimilarItem
|
|
ZipFileName
|
VarChar(200)
|
|
ZipFiles
|
LongVarChar(2M)
|
|
ZipTools
|
ZipTools
|
|
Finalmente resta crear un panel para Smart Devices para permitir que el usuario de la aplicación Mobile llame al servicio de Inteligencia Artificial que permita que, a partir de una foto tomada de la pieza, obtenga los datos del producto correspondiente.
Para utilizar el servicio de similitud de imágenes cree un SD Panel en la carpeta LeonardoProductPrompt haciendo click derecho, seleccione New->Object

Llame al SD panel ‘SDProductPrompt’ (no seleccione ningún template del pattern para este panel, presione Skip).
Agregue un control Atributte/Variable del panel de Toolbox, arrastrándolo hasta el SD Panel.

Seleccione ‘New Variable’ para crear una variable a mostrar.

Nombre la nueva variable como ‘NewImage’. Esta será la imagen correspondiente a la foto tomada.
GeneXus infiere el tipo de la variable automáticamente.

Seleccione OK. Luego fije la propiedad Label Position con el valor ‘None’.
Agregue una nueva variable debajo de la variable NewImage, arrastrando desde la Toolbox

Al soltar el control Seleccione New Variable.

Nombre la variable como SDTProductSimilar. GeneXus infiere que es de tipo SDTSimilarImage definido previamente.

Una vez que seleccione Ok debe elegir qué atributos de la estructura desea mostrar.
Esta Grid tendrá la lista de todos los productos del maestro de productos, con su respectivo porcentaje de similitud respecto a la imagen de la variable New Image.

Seleccione para incluir los campos SDTProductSimilarItemDesc, SDTProductSimilarItemImage, SDTProductSimilarItemSimilarity, SDTProductSimilarItemBar y haga click en OK.

Esto agregara al form del panel un Grid (ya que la variable es de tipo Collection) con los campos seleccionados.
Al campo SDTProductSimilarItemImage configurele la propiedad Class con el valor ‘ListCardBanner’.

A continuación arrastre del panel de Toolbox un control Canvas y suéltelo dentro de la tabla del Grid agregado en el paso anterior.
TIP: Canvas es un control que permite superponer ítems en el diseño de interfaces para SmartDevices.
Para más información sobre Canvas ver aquí.
|

Una vez insertado el control Canvas, moveremos los controles de los campos del SDT a modo de obtener para cada fila del Grid, una visualización como la siguiente:

Arrastre la imagen sobre el control Canvas (campo SDTProductSimilarItemImage ).

Agregue dentro del Canvas una tabla arrastrando el control desde el panel Toolbox

Una vez agregada la tabla fije las siguientes propiedades:

Arrastre los atributos desde el Grid hacia la tabla creada, en el siguiente orden de tal forma que queden como se ve en la imagen:
SDTProductSimilarItemDesc
SDTProductSimilarItemBar
SDTProductSimilarItemSimilarity
Para la variable SDTProductSimilarItemDesc fije las siguientes propiedades:

Para la variable SDTProductSimilarItemBar fije las siguientes propiedades:

Para la variable SDTProductSimilarItemSimilarity fije las siguientes propiedades:

La disposición de los elementos debería quedar de la siguiente manera:

Para finalizar el diseño agregue un botón al Application Bar arrastrando un control Button desde el panel de toolbox.

Nombre al botón ‘Process’.
Este botón será el encargado de realizar la llamada al procedimiento SimilarImages que realiza la comparación.
Para finalizar con el diseño, seleccione el control Main Table y configure la propiedad ‘Rows Style’ con el valor 30%;70%.

Resta la programación de los eventos en el panel diseñado.
Haga doble click en el botón ‘Process’ creado en Application Bar.
GeneXus lo llevara el Evento donde debe agregar el código a ejecutar asociado al botón Process (en la solapa Events).
Ingrese el siguiente código.
Event 'Process'
Composite
GeneXus.Common.UI.Progress.Type = ProgressIndicatorType.Indeterminate
GeneXus.Common.UI.Progress.Show()
SimilarImages(&NewImage, &SDTProductSimilar)
GeneXus.Common.UI.Progress.Hide()
Endcomposite
Endevent
|
Esta especificación muestra un indicador de procesamiento (GeneXus.Common.UI.Progress.Show()) mientras se llama al procedimiento que utiliza el servicio de similitud de imágenes (SimilarImages(&NewImage, &SDTProductSimilar)), una vez retornado los parámetros, se oculta el indicador de procesamiento.
La especificación se realiza dentro del bloque composite para asegurar la ejecución de las instrucciones como un bloque atómico.
Una vez que se retorne el resultado de llamar al procedimiento que usa el servicio de similitud de imágenes se mostrará el resultado para todas las imágenes cargadas en la grilla.
Si el usuario selecciona una de estas, se obtendrán los datos automáticamente.
Para lograr esto, seleccione el objeto Grid y diríjase a ‘Default Action’

Haga click en Default Action y seleccione ‘New’
Aparecerá un formulario solicitando el nombre del nuevo evento a definir.
Nombre al evento ‘SelectProduct’

Luego de nombrar el evento seleccione la pestaña ‘Events’ y verá que se encuentra definido el bloque del evento.
Dentro del bloque especifique el siguiente código.
Event 'SelectProduct'
Composite
&ProductId = &SDTProductSimilar.CurrentItem.SDTProductSimilarItemId
Return
endcomposite
Eendevent
|
Por último defina el parámetro de salida que va a retornar como resultado, en la solapa Rules.

Haga click en el Icono del Diskette o presione Ctrl+S para salvar el progreso realizado.
Con esto finaliza la especificación en la el SD Panel ‘SDProductPrompt’
Ahora queda referenciar desde donde se ejecuta este panel.
Este panel debe ejecutarse al momento de crear una Sales Order, cuando el usuario desea ingresar un producto en la orden de ventas.
En el Panel ‘WorkWithDevicesSalesOrder’, en Fiori Mobile/Detail/Section (General)/Edit, inserte un nuevo botón arrastrando el control desde el panel Toolbox y sueltelo en ‘Application Bar’.

Cuando suelte el control, deberá nombrar el evento. Llámelo ‘Search’

En el panel de Eventos defina el siguiente código:
Event 'Search'
SDProductPrompt(ProductId)
Endevent
|
En el código se especifica la llamada al panel que realiza la búsqueda utilizando los servicios de SAP Leonardo. Como resultado la ejecución de este panel se obtiene el Id de producto.
Haga click en el Icono del Diskette o presione Ctrl+S para salvar el progreso realizado.
Ahora su aplicación se encuentra lista para ser ejecutada (rebuild All).
Al momento de ejecutar puede utilizar las siguientes imágenes: Brake Disc Images to test
|