
En la nueva versión de Sofia2 se ha añadido un nuevo nodo al motor de flujos capaz de gestionar ejecuciones sobre notebooks de la plataforma.
Con esta nueva característica, se pueden orquestar procesos basados en notebook e incluso paralelizar los mismos distribuyendo la carga de trabajo. Es posible pasar parámetros dinámicos a estos notebooks, pudiendo incluir información fija o generada por un flujo sobre cualquier lenguaje usado en los notebooks y más adelante iniciar una ejecución con los mismos.
Al igual que los parámetros de entrada, se posibilita la salida de los datos generados por uno o varios párrafos de un notebook, incluyendo información generada por un proceso analítico dentro del flujo y tomar decisiones en base al mismo.
Vamos a ver un tutorial de uso del mismo. Tendremos varios elementos de Sofia2 que nos ayudarán a construir y procesar una imagen que el usuario incluirá a través de una web, los cuales son:
- Proyecto Web: Donde alojaremos la web donde el usuario subirá su imagen y verá los resultados.
- Binary Repository: Para almacenar y recuperar las diferentes imágenes generadas
- SSAP: Que nos servirá para comunicarnos entre los diferentes elementos
- Motor de Flujos (Nodered + nodo Notebook Launcher)
- Notebooks Sofia2: Usaremos dentro de los mismos Python junto con la librería PIL para procesar imágenes.
- Gadgets Sofia2: Tendremos un gadget donde se mostrará el histograma de la imagen subida
Lo primero que haremos, será crear un proyecto en Sofia2 que tendrá un domino del motor de flujos y que también tendrá asociada la web.

En la web asociada al proyecto tendremos una interfaz simple que permitirá subir un imagen al binary repository, realizará un POST sobre una URL que iniciará el flujo de procesamiento (al que le pasará los datos de la imagen ya subida) y que mediante el protocolo SSAP se subscribirá a la ontología donde recibirá los resultados de las imágenes ya procesadas.

La url donde se pueden ver los resultados y el código fuente es la siguiente https://sofia2.com/web/imageprocess/imageFlow.html
A continuación, veremos los notebooks necesarios para el procesamiento, así como la configuración necesaria en el motor de flujos. Los notebooks se han construido de manera que cada uno haga una funcionalidad concreta y aislada.
Conversor de RGB a escala de grises: recibe como parámetro una sessionKey válida y el identificador del binary repository (la referencia de la imagen de entrada). Utilizando lenguaje Python y la librería PIL se obtendrá esa imagen del binary repository se convertirá a escala de grises y se volverá a subir al binary repository.
En este notebook podemos comprobar cómo se pueden recibir parámetros en el mismo. Simplemente usando z.input(“nombreParámetro”) crearemos un párrafo que podrá recibir datos dinámicos de forma externa por un formulario, esto no solo es válido para Python, se puede incluir igualmente en otros lenguajes soportados en los notebook como por ejemplo con el interpreter de Spark(scala).


Teniendo ese notebook creado, dentro del motor de flujos podremos añadirlo con el nodo Notebook Launcher:

Al añadir ese nodo, podremos seleccionar cualquiera de los notebooks del usuario en la configuración:

Posteriormente añadiremos el párrafo de entrada (se nos mostrará la lista de los mismos junto con el título y el texto de los mismos):

Al añadir un párrafo con parámetros de entrada, se nos desplegará el formulario correspondiente para configurar cada entrada dinámicamente.

En cuanto a la salida del párrafo (la cual, en este caso, será el nuevo identificador del binary repository de la imagen procesada) la haremos como salida del último párrafo el cuál imprimirá ese identificador. De manera análoga a los parámetros de entrada seleccionaremos un párrafo de salida. Además, se le podrá añadir un tópico para poder distinguir esta salida de otras en nodos posteriores.

Si tuviéramos varios párrafos de salida, podríamos incluir diferentes salidas distinguidas por tópico.

Al enviarlas, podrá ser por array en el mismo puerto (Split Output desactivado) o por diferentes puertos de salida (Split Output activado):

Filtro Blur sobre imagen RGB: similar al notebook anterior salvo que se hará un filtro blur sobre un imagen.


Obtención histograma: en este caso se leerá la imagen y se devolverá en el último párrafo el array del histograma

Agrupación de datos: notebook que unificará los datos de los diferentes notebook de procesamiento para conformar una salida única que se enviará posteriormente a la ontología de salida por SSAP a Sofia2.

En este caso, en la configuración del nodo, al tener varios notebooks de entrada tendremos que tener activado el Workflow Mode. Con esta opción, este nodo, se esperará a todos los notebooks de entrada antes de ejecutarse (cada notebook le enviará un parámetro). A parte, al tener varias entradas y no saber el orden de las mismas, tendremos que diferenciar las entradas del nodo por tópico para direccionarlas correctamente. Este direccionamiento se puede hacer de 3 formas:
- payload: única entrada y se recoge el parámetro el contenido de “payload”
- payload[n]: múltiples entradas, se recoge la que llega en posición n
- payload{“topic”:”t1″}: múltiples entradas, se busca la que “topic” sea igual a “t1”
Para este nodo en concreto tendremos:

Ahora, vamos a ver el flujo de procesamiento completo dentro del motor de flujos:

La primera parte del mismo crea un endpoint REST de tipo POST (este será el disparador de todo el flujo). Dentro de este POST se incluirán por JSON los datos de:
- SessionKey: sessionKey del usuario contra Sofia2. Se usará en todos los acceso al binary repository o al enviar mensajes SSAP
- BinaryID: id en el binary repository de la imagen inicial

A parte también se incluirá la sessionKey (común para todos los procesos) en el contexto del flow mediante el nodo function.

Más adelante esta información llega a 3 nodos de tipo Notebook Launcher:

Cada uno de estos notebooks recibirá como parámetro el ID del Binario junto con la sessionKey (desde el contexto del flow).

La salida en el caso concreto del conversor a escala de grises va tanto al notebook de agrupación de datos, como a otro notebook idéntico al de filtrado blur.

Aquí, se puede el porqué de la distinción por funcionalidad completa y aislada de los notebooks pudiendo verlos como “cajas negras” reutilizables que procesa con una entrada y una salida. A parte, el nodo notebook launcher crea una instancia de ejecución nueva para cada notebook, por lo que se puede usar varios nodos iguales en paralelo.
Finalmente, se crea un mensaje SSAP que se envía por POST a la ontología destino.


El resultado de todo este proceso, al subir una imagen de este tipo:

Obtendremos al terminar el procesamiento las diferentes imágenes:
- Imagen con filtro blur
- Imagen en escala de grises
- Imagen en escala de grises más filtro blur
- Histograma en un gadget

El código de los notebook así como la exportación del flujo de nodered puede descargar en el siguiente enlace del github de Sofia2: https://github.com/Sofia2/Sofia2-ImageProcessing