header-ia-sentiment

Clasificación de texto con JavaScript y TensorFlow.js: Crea una aplicación web de análisis de sentimiento

Clasificación de texto con JavaScript y TensorFlow.js: Crea una aplicación web de análisis de sentimiento

La clasificación de texto es una tarea común en inteligencia artificial y aprendizaje automático. Con JavaScript y TensorFlow.js, podemos realizar este tipo de tareas directamente en una aplicación web, sin depender de servidores externos. En esta guía, aprenderás cómo crear una aplicación interactiva que analiza el sentimiento de un texto usando TensorFlow.js y el modelo pre-entrenado Universal Sentence Encoder.

Paso 1: Configuración del entorno

  1. Crea un nuevo proyecto de Node.js ejecutando el siguiente comando:
npm init -y

Esto generará el archivo package.json.

2. Instala las dependencias necesarias para este proyecto:

npm install @tensorflow/tfjs @tensorflow-models/universal-sentence-encoder --force

Usaremos la librería @tensorflow/tfjs para trabajar con TensorFlow en JavaScript y @tensorflow-models/universal-sentence-encoder como modelo pre-entrenado para procesar texto y generar embeddings.

Paso 2: Cargar el modelo Universal Sentence Encoder

El modelo Universal Sentence Encoder genera representaciones numéricas (embeddings) para oraciones. Vamos a cargar este modelo en nuestro proyecto.

Crea un archivo index.js y agrega el siguiente código:

import * as use from '@tensorflow-models/universal-sentence-encoder';

(async () => {
  const sentences = [
    'Me encanta el clima hoy.',
    'No me gusta nada este lugar.',
    'El café está delicioso.',
    'La película fue aburrida.',
  ];

  // Cargar el modelo pre-entrenado
  const model = await use.load();
  console.log('Modelo Universal Sentence Encoder cargado.');

  // Generar embeddings para las oraciones
  const embeddings = await model.embed(sentences);
  console.log('Embeddings generados:', embeddings.arraySync());
})();
  • Este código carga el modelo y genera embeddings (vectores numéricos) para una lista de oraciones.
  • Estos embeddings serán la base para analizar el sentimiento o clasificar el texto.

Paso 3: Clasificación de texto (simulada)

Como el modelo Universal Sentence Encoder no clasifica directamente el texto, crearemos una regla sencilla para simular el análisis de sentimiento utilizando los embeddings.

Actualiza tu index.js con el siguiente código:

async function classifyText(model, text) {
  const embeddings = await model.embed();
  const score = embeddings.arraySync()[0].reduce((sum, value) => sum + value, 0);

  // Simulación: Sentimiento positivo si el puntaje es mayor que 0
  return score > 0 ? 'positivo' : 'negativo';
}

(async () => {
  const sentences = [
    'Me encanta el clima hoy.',
    'No me gusta nada este lugar.',
    'El café está delicioso.',
    'La película fue aburrida.',
  ];

  const model = await use.load();
  console.log('Modelo cargado exitosamente.');

  for (const sentence of sentences) {
    const sentiment = await classifyText(model, sentence);
    console.log(`"${sentence}" es ${sentiment}.`);
  }
})();
"Me encanta el clima hoy." es positivo.
"No me gusta nada este lugar." es negativo.
"El café está delicioso." es positivo.
"La película fue aburrida." es negativo.

Paso 4: Integración en una aplicación web

Ahora integraremos el modelo en una aplicación web para que los usuarios puedan ingresar su propio texto y obtener una clasificación.

Creamos un archivo index.html con la siguiente estructura:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>Clasificación de Sentimiento con TensorFlow.js</title>
  </head>
  <body>
    <h1>Análisis de Sentimiento</h1>
    <div>
      <textarea id="input-text" rows="4" cols="50" placeholder="Escribe aquí..."></textarea>
      <br />
      <button id="classify-button">Clasificar</button>
      <p>Resultado: <span id="result"></span></p>
    </div>

    <!-- Importar TensorFlow.js y Universal Sentence Encoder -->
    <script src="https://cdn.jsdelivr.net/npm/@tensorflow/[email protected]/dist/tf.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/@tensorflow-models/[email protected]/dist/universal-sentence-encoder.min.js"></script>
    <script src="index.js"></script>
  </body>
</html>

Archivo JS: index.js

Este script conecta el HTML con el modelo de TensorFlow.js:

let model;

async function loadModel() {
  model = await use.load();
  console.log('Modelo cargado exitosamente.');
}

async function classifyText(text) {
  const embeddings = await model.embed();
  const score = embeddings.arraySync()[0].reduce((sum, value) => sum + value, 0);
  return score > 0 ? 'positivo' : 'negativo';
}

async function handleClassifyClick() {
  const inputText = document.getElementById('input-text').value;
  const resultElement = document.getElementById('result');

  if (!inputText) {
    resultElement.textContent = 'Por favor, ingresa un texto.';
    return;
  }

  const sentiment = await classifyText(inputText);
  resultElement.textContent = `Sentimiento: ${sentiment}`;
}

// Inicializar
loadModel();
document.getElementById('classify-button').addEventListener('click', handleClassifyClick);

Conclusión

En este artículo, aprendimos cómo usar TensorFlow.js y el modelo Universal Sentence Encoder para analizar y clasificar texto en una aplicación web.

Hemos visto:

  1. Cómo configurar el entorno y cargar el modelo.
  2. Cómo generar embeddings para el texto.
  3. Cómo integrar la funcionalidad en una aplicación interactiva que puede analizar el sentimiento de cualquier texto ingresado por el usuario.

Con esta base, puedes expandir el proyecto utilizando modelos más complejos o entrenando tus propios clasificadores. ¡El límite es tu imaginación!

pscode cover

Desarrollando una Aplicación de Generación de Código con Inteligencia Artificial

Desarrollando una Aplicación de Generación de Código con Inteligencia Artificial

La inteligencia artificial (IA) es un campo que ha avanzado a pasos agigantados en los últimos años, y su impacto se puede sentir en una variedad de aplicaciones y servicios.

En este artículo, quiero compartir una emocionante noticia con todos ustedes: he desarrollado una aplicación basada en Vue3 y Vuesax que utiliza la inteligencia artificial para generar código en múltiples lenguajes.

Lo mejor de todo es que es completamente gratuita y no almacena ningún dato personal.

Vue3 y Vuesax: Las Herramientas Clave

Para llevar a cabo este proyecto, he utilizado la última versión de VueJS (Vue3) y Vuesax como librería de componentes.

Estas herramientas me permitieron construir una interfaz de usuario elegante y funcional para nuestra aplicación de generación de código.

Vue3 es conocido por su facilidad de uso y flexibilidad, lo que lo convierte en una elección perfecta para proyectos de este tipo.

Por su parte, Vuesax proporciona una amplia gama de componentes predefinidos que facilitan la creación de una interfaz de usuario atractiva y receptiva.

Nuestra Fuente de Poder: Modelo «Phind/Phind-CodeLlama-34B-v2»

El corazón de la aplicación es el modelo de inteligencia artificial «Phind/Phind-CodeLlama-34B-v2«.

Este modelo ha sido puesto a disposición por la comunidad de desarrolladores en Hugging Face, un recurso valioso para la comunidad de IA.

Además, me gustaría reconocer a Meta la creación de este modelo, cuyo trabajo ha hecho posible que nuestra aplicación sea una realidad.

Generación de Texto y Código con Inteligencia Artificial

La generación de texto y código con modelos de inteligencia artificial es un campo en constante crecimiento.

Estos modelos son entrenados en enormes conjuntos de datos y pueden generar contenido de manera coherente y relevante en una variedad de lenguajes de programación.

La aplicación se basa en la capacidad de este modelo para comprender solicitudes de generación de código y proporcionar resultados precisos y útiles.

¡Pruébalo por Ti Mismo!

Si deseas experimentar con la aplicación de generación de código basada en IA, te invitamos a visitar https://ps-code.tecnops.es.

PS CODE

Espero que encuentres la herramienta útil y que te ayude a agilizar tus tareas de desarrollo de software.

Agradecimientos a la Comunidad

Quiero expresar mi más sincero agradecimiento a la comunidad de desarrolladores y entusiastas de la inteligencia artificial.

Los avances en este campo no serían posibles sin la colaboración y el espíritu de compartir conocimiento que caracterizan a esta comunidad.

También quiero agradecer a Hugging Face y Meta por proporcionar el modelo que ha hecho posible nuestra aplicación.

En resumen, la aplicación de generación de código es un emocionante ejemplo de cómo la inteligencia artificial puede ser aplicada para facilitar el trabajo de los desarrolladores.

Esperamos que la encuentres útil y que contribuya a tu productividad en el mundo del desarrollo de software.

¡Explora, experimenta y únete a nosotros en la emocionante era de la IA aplicada!

upscale cover

Upscaler.js: Redimensionando imágenes usando Inteligencia Artificial

Que es Upscaler.js

Upscaler.js es una librería de JavaScript que permite escalar imágenes desde el navegador usando Javascript y/o en un servidor usando Node.

Esta librería esta creada usando redes neuronales que permiten un escalado de hasta 4 veces el tamaño original, es de código abierto, es de uso gratuito y ofrece múltiples modelos listos para usar.

Empezando a codificar

A continuación vamos a detallar los pasos a seguir para hacer uso de esta librería en Javascript desde el navegador, no obstante si necesitamos aprender mas sobre esta librería desde aquí podemos acceder a la documentación oficial.

  1. Para utilizar Upscaler.js, primero debemos incluir la librería en nuestro proyecto, y para ello puedes descargar Upscaler.js desde GitHub y añadirlo a tu proyecto, o instalarlo a través de NPM usando el siguiente comando:
    npm install upscaler
  2. El siguiente paso es añadir la librería en nuestro HTML usando por ejemplo el tag script:
    <script src="node_modules/upscaler.js/dist/upscaler.min.js"></script>
  3. Ahora ya tenemos listo nuestro proyecto para hacer uso de la librería, y para ello necesitamos primero crear una instancia de Upscaler.js y pasarle la imagen que deseamos escalar como argumento. Luego, podemos llamar a la función scale para escalar la imagen:
    <!DOCTYPE html>
    <html lang="es">
      <head>
        <title>Upscaler.js</title>
        <meta charset="utf-8">
        <meta name="description" content="description">
        <meta name="format-detection" content="telephone=no">
        <meta name="msapplication-tap-highlight" content="no">
        <script src="./node_modules/upscaler/dist/browser/umd/upscaler.min.js"></script>
      </head>
      <body>
        <img id="myImage" src="myImage.jpg" width="100" height="100">
        <script>
           const upscaler = new Upscaler();
           const myImage = document.getElementById('myImage');
           upscaler.scale(myImage, function(scaledImage) {
              myImage.src = scaledImage.toDataURL();
           });
        </script>
      </body>
    </html>

Para finalizar, Upscaler.js ofrece varias opciones de configuración que puede especificar al crear una instancia de la biblioteca, por ejemplo podríamos especificar la calidad de la imagen escalada, el tamaño máximo de la imagen escalada, etc…

<!DOCTYPE html>
<html lang="es">
   <head>
      <title>Upscaler.js</title>
      <meta charset="utf-8">
      <meta name="description" content="description">
      <meta name="format-detection" content="telephone=no">
      <meta name="msapplication-tap-highlight" content="no">
      <script src="./node_modules/upscaler/dist/browser/umd/upscaler.min.js"></script>
   </head>
   <body>
      <img id="myImage" src="myImage.jpg" width="100" height="100">
      <script>
         const upscaler = new Upscaler({ quality: 0.8, maxWidth: 500, maxHeight: 500 });
         const myImage = document.getElementById('myImage');
         upscaler.scale(myImage, function(scaledImage) {
            myImage.src = scaledImage.toDataURL();
         });
      </script>
   </body>
</html>

Con esto ya tendríamos nuestra aplicación para escalar imágenes usando Inteligencia Artificial, además si quieres probar como funciona y los resultado que ofrece la librería, desde aquí puedes acceder a la aplicación de ejemplo que he creado.

ml5js

Clasificación de imágenes usando Javascript y ML5.js (Tensorflow)

Clasificación de imágenes usando Javascript y ML5.JS (Tensorflow)

Esta es la primera entrada del año y me gustaría comenzar con un pequeño tutorial sobre inteligencia artificial mostrando algunas cosas que podemos hacer con ella.

Con este y otros pequeños tutoriales que iré creando, me gustaría acercar de una manera sencilla la inteligencia artificial a todos, tanto para nuestros proyectos personales como profesionales.

Pequeña introducción y algunos conceptos

A continuación voy añadir algunos conceptos que entiendo que al menos debemos conocer.

  • TensorFlow: Es una biblioteca de aprendizaje automático desarrollada por Google para crear y entrenar redes neuronales.
  • ml5.js: Es una librería que nos proporciona acceso a los algoritmos y modelos de aprendizaje automático usando Javascript y como única dependencia tensorflow.js.
  • Red neuronal: Es un modelo inspirado en el funcionamiento de un cerebro humano y esta formada por neuronas artificiales (nodos) que están conectadas y transmiten señales entre sí.

Empezando a programar

En este ejemplo vamos a intentar reconocer el contenido de una imagen y así poder realizar una clasificación del mismo.

Para ello la librería ml5.js nos ofrece multitud de métodos que nos facilitan el trabajo, ya que esta librería es una capa superior que envuelve a la librería tensorflow.js.

La clasificación la vamos a realizar usando un modelo que esta previamente entrenado usando una base de datos de unos 15 millones de imágenes (ImageNet) y que ml5.js accede a este modelo desde la nube.

A continuación usaremos el código de ejemplo que tiene la propia página para comprobar lo sencillo que es realizar la clasificación.

<img src="imagen.jpg" id="image />

const classifier = ml5.imageClassifier('MobileNet', modelLoaded);

function modelLoaded() {
  console.log('Model Loaded!');
}

classifier.classify(document.getElementById('image'), (err, results) => {
  console.log(results);
});

Desde este enlace podemos acceder a toda la documentación de la librería.

Entendiendo el código

Lo primero que necesitamos es cargar la imagen que vamos a clasificar, y para ello usaremos el tag <img>.

<img src="imagen.jpg" id="image />

Ahora vamos a inicializar el clasificador y añadiremos un callback, el cual nos indicara cuando se ha cargado el modelo.

También debemos indicar que modelo queremos usar para realizar la clasificación: MobileNet, Darknet, Darknet-tiny, DoodleNet o nuestro propio modelo.

const classifier = ml5.imageClassifier('MobileNet', modelLoaded); 
function modelLoaded() { 
    console.log('Model Loaded!');
}

Para finalizar vamos a realizar la clasificación usando uno de los métodos que nos ofrece ml5.js.

classifier.classify(document.getElementById('image'), (err, results) => { 
   console.log(results);
});

Creando una aplicación mas elaborada

Para finalizar la entrada os dejo el enlace al repositorio en Github y una pequeña aplicación que he creado usando ml5.js, Javascript y Bulma. que podéis usar desde aquí.

App ejemplo

Tensorflow.js y otros servicios API de inteligencia artificial

Tensorflow y los servicios API de Inteligencia Artificial

En esta nueva entrada vamos a crear algún ejemplo usando Tensorflow.js y algunos de los servicios de Inteligencia Artificial que nos ofrecen algunas de las empresas mas punteras y potentes actualmente.

Para realizar las pruebas usaremos los siguientes servicios y librerías:

  • Tensorflow.js: Librería para Javascript que se ejecuta en nuestro navegador.
  • IBM Watson: Usando una parte de sus servicios enfocados a la Inteligencia Artificial.

En principio solo estoy añadiendo las librerías y/o servicios que he usado para realizar alguna POC.

El resto de los servicios que me gustaría probar como son Microsoft Azure, Google Cloud y Amazon, de momento no los vamos a usar, ya que o bien no tienen versiones de prueba o requieren pasar por caja previamente, cosa que de momento no vamos hacer.

Bien, como existen mas servicios y librerías vamos a continuar nuestras pruebas con otros servicios y/o librerías.

Tensorflow.js

Vamos a comenzar por Tensorflow.js, ya que no requiere de ningún registro previo para utilizar la librería permitiendo realizar todas las pruebas que queramos sin ningún límite.

Como en el tutorial anterior sentamos las bases para usar Tensorflow.js, ahora iremos al grano mostrando el código con el resultado para realizar las comparativas.

En cada sección mostrare solo el código correspondiente usado para cada librería y/o servicio, y al final del articulo mostrare el código completo de la aplicación y su enlace al repositorio en Github.

const tensorflowObjectDetection = msn => {
  ...
  const img = document.getElementById('imgPreview');
  mobilenet.load().then(model => {
    ...
    model.classify(img, totalClasses).then(predictions => {
      ...
      predictions.forEach((data, index) => {
        ...
      });
      container.appendChild(ul);
    });
  });
};

Como había comentado, en este trozo de código solo quiero mostrar lo simple que resulta usar los modelos pre-entrenados de Tensorflow, ya que al final esta el enlace a todo el código.

IBM Watson

Con este servicio podemos hacer entre otras muchas cosas, la clasificación de una imagen como hicimos en el ejemplo anterior.

El servicio ofrecido por IBM nos permite usar todas las características en su plan LITE pero con ciertas limitaciones.

Para realizar nuestra prueba, esas limitaciones no nos influyen.

El siguiente ejemplo lo voy a realizar en NodeJS, para lo cual tendremos que instalar la siguiente librería:

npm install ibm-watson@^5.2.1

Una vez instalada la dependencia, procederemos a usarla en nuestro código.

A continuación el código necesario en la parte de NodeJS para que funcione nuestro servicio:

...
const visualRecognition = new VisualRecognitionV3({
  version: '2018-03-19',
  authenticator: new IamAuthenticator({
    apikey: '{apiKey}',
  }),
  url: '{url}',
});
...
const classifyParams = {
  imagesFile: 'filename.jpg',
  owners: ['IBM', 'me'],
  threshold: 0.1,
};
...
visualRecognition.classify(classifyParams)
.then(response => {
  const classifiedImages = response.result;
  res.status(200).json(classifiedImages);
})
.catch(err => {
  res.status(400).json({ message: err });
  console.log('error:', err);
});
...

Y ahora el código para la parte de Javascript:

const IBMWatsonObjectDetection = () => {
  ...
  // Donde hemos levantado el servidor de NodeJS
  const url = new URL('https://localhost:3000/ibm-watson');
  ...
  fetch(url).then(response => response.json()).then(responseJson => {
    ...
    const { images } = responseJson;
    ...
  });
};

Es algo más de código pero realmente estamos dividiendo el trabajo, ya que en Javascript únicamente estamos pintado el resultado que nos devuelve el script de NodeJS.

Ahora el encargado de todo el trabajo es NodeJS mediante la librería de IBM Watson y su servicio.

En principio estas son las dos opciones que conozco y que puedo probar sin ningún coste directo asociado.

El resto de los servicios los he intentado probar, pero no he podido ver el resultado ya que me solicitan amablemente que realice el abono.

No obstante la cantidad de código necesario para ejecutar cualquiera de los otros servicios no llega a poco mas de 20 lineas.

Como había comentado al principio del artículo, voy a mostrar un pequeño vídeo ya que el servicio de IBM Watson tiene límites y una vez superados deja de funcionar.

Para finalizar el código lo puedes descargar desde su repositorio en Github.

Tensorflow para Javascript usando Tensorflow.js, ml5js y Processing (P5.js)

Empezando con Tensorflow.js, ml5js y Processing (P5.js)

En esta nueva entrada vamos a usar diferentes tecnologías para desarrollar algunos ejemplos muy curiosos y potentes.

Para unir todas estas tecnologías usaremos como punto de unión nuestro querido Javascript.

Antes de empezar con la magia es importante explicar que son y como se usan las diferentes herramientas que explicaremos durante este tutorial.

  • Tensorflow.jsEs una librería de Machine Learning (ML) para Javascript creada por Google.
  • Ml5jsEs una librería que nos proporciona acceso a los algoritmos y modelos de aprendizaje automático usando Javascript y como única dependencia tensorflow.js.
  • P5.jsEs otra librería de Javascript  extremadamente potente que nos permite realizar programación gráfica sin mucha complicación y esta basada en Processing.
  • ProcessingEs un software enfocado en la programación gráfica.

Tensorflow.js

Con esta potente librería para computación numérica podemos construir y entrenar redes neuronales que permiten detectar y descifrar patrones y correlaciones, análogos al aprendizaje y razonamiento usados por los humanos.

Para usarlo en Javascript podemos hacerlo de diferentes formas:

  • Usando el tag <script> en nuestra página.
    • <script src="https://cdn.jsdelivr.net/npm/@tensorflow/[email protected]/dist/tf.min.js"></script>
  • Instalándolo desde NPM / YARN.
    • YARN
      yarn add @tensorflow/tfjs
      
      NPM
      npm install @tensorflow/tfjs
  • Usando NPM/ YARN pero esta vez para Node.js
    • Instalando TensorFlow.js con enlaces nativos de C ++
    • YARN
      yarn add @tensorflow/tfjs-node
      
      NPM
      npm install @tensorflow/tfjs-node
    • Solo para linux y si tienes una tarjeta gráfica NVIDIA GPU con soporte CUDA, puedes usar estas dependencias para un mayor rendimiento.
    • YARN
      yarn add @tensorflow/tfjs-node-gpu
      
      NPM
      npm install @tensorflow/tfjs-node-gpu
    • Instalando la versión para Javascript, que es la opción más lenta en cuanto a rendimiento.
    • YARN
      yarn add @tensorflow/tfjs
      
      NPM
      npm install @tensorflow/tfjs

Si necesitas saber más de Tensorflow.js, en esta guía oficial de Tensorflow.js tienes toda la información necesaria para practicar y profundizar sobre esta impresionante librería.

Para nuestro tutorial usare los modelos pre-entrenados que nos ofrecen desde Tensorflow.

En el siguiente ejemplo usaremos Mobilenet, pero…., ¿que es Mobilenet?

Mobilenet son modelos pequeños, de baja latencia y baja potencia parametrizados para cumplir con las limitaciones de recursos de una variedad de casos de uso, pudiendo realizar la clasificación, detección, incrustaciones y segmentación de forma similar a cómo se utilizan otros modelos populares a gran escala.

La ventaja de usar este modelo de TensorFlow.js es que no requiere que sepas sobre el aprendizaje automático, pudiendo tomar como entrada cualquier tag de imagen basado en el navegador (img, video, canvas) y esta devuelve una serie de predicciones más probables y sus confidencias.

El código fuente esta disponible en Github, no obstante también lo añado en la entrada para un copy/paste rápido.

<!-- index.html -->
<!DOCTYPE html>
<html lang="es">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Clasificación de imágenes</title>
  <link href="https://fonts.googleapis.com/css?family=Montserrat&display=swap" rel="stylesheet">
  <link href="./style.css" rel="stylesheet">
</head>
<body>
  <h1>Clasificación de imágenes usando <b>Tensorflow.js</b> y <b>Mobilenet</b></h1>
  <div>
    <label for="image">Seleccionar una imagen</label>
    <input type="file" id="image" accept=".gif,.jpg,.jpeg,.png">
    <label for="classify" onclick="classify()" class="lock">Clasificar la imagen</label>
  </div>
  <img id="imgPreview" class="hide" />
  <div id="result"></div>
  <div class="loading hide">
    <div class="lds-ripple">
      <div></div>
      <div></div>
    </div>
  </div>
  <script src="https://cdn.jsdelivr.net/npm/@tensorflow/[email protected]"></script>
  <script src="https://cdn.jsdelivr.net/npm/@tensorflow-models/[email protected]"></script>
  <script src="./index.js"></script>
</body>
</html>
/* style.css */
body {
  font-family: 'Montserrat', sans-serif;
}
#imgPreview {
  box-shadow: 0px 5px 10px rgba(0,0,0,0.4);
  padding: 20px;
  margin-top: 20px;
}
input[type="file"]#image {
  width: 0.1px;
  height: 0.1px;
  opacity: 0;
  overflow: hidden;
  position: absolute;
  z-index: -1;
}
label {
  font-size: 14px;
  font-weight: 600;
  color: #ffffff;
  background-color: #106BA0;
  box-shadow: 0px 3px 6px rgba(0,0,0,0.3);
  display: inline-block;
  transition: all .5s;
  cursor: pointer;
  padding: 15px 40px;
  text-transform: uppercase;
  width: fit-content;
  text-align: center;
}
.lock {
  pointer-events: none;
  opacity: 0.3;
}
.hide {
  display: none;
}
.lds-ripple {
  display: inline-block;
  position: absolute;
  width: 80px;
  height: 80px;
  left: calc(50% - 40px);
  top: calc(50% - 40px);
}
.lds-ripple div {
  position: absolute;
  border: 4px solid #e90202;
  opacity: 1;
  border-radius: 50%;
  animation: lds-ripple 1s cubic-bezier(0, 0.2, 0.8, 1) infinite;
}
.lds-ripple div:nth-child(2) {
  animation-delay: -0.5s;
}
@keyframes lds-ripple {
  0% {
    top: 36px;
    left: 36px;
    width: 0;
    height: 0;
    opacity: 1;
  }
  100% {
    top: 0px;
    left: 0px;
    width: 72px;
    height: 72px;
    opacity: 0;
  }
}
.loading {
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  opacity: 0.7;
  background: #cccccc;
}
// index.js
const init = () => {
  document.querySelector("#image").onchange = evt => {
    let reader = new FileReader();
    reader.readAsDataURL(evt.target.files[0]);
    reader.onload = () => {
      const img = document.querySelector('#imgPreview');
      const container = document.querySelector('#result');
      img.setAttribute('src', reader.result);
      img.classList.remove('hide');
      document.querySelector('label[for="classify"]').classList.remove('lock');
      container.innerHTML = '';
    };
  }
};

const classify = () => {
  const loading = document.querySelector('.loading');
  loading.classList.remove('hide');
  const img = document.querySelector('#imgPreview');
  mobilenet.load().then(model => {
    model.classify(img).then(predictions => {
      const body = document.body;
      const container = document.querySelector('#result');
      container.innerHTML = '';
      predictions.forEach(data => {
        const porcent = parseFloat(data.probability * 100).toFixed(2);
        const progress = document.createElement('progress');
        const label = document.createElement('div');
        const info = document.createElement('span');
        label.innerHTML = `<b>Elemento reconocidos:</b> <i>${data.className}</i>`;
        progress.setAttribute('max', 100);
        progress.setAttribute('value', porcent);
        info.innerHTML = ` <b>${porcent}%</b>`;
        container.classList.add('result');
        container.appendChild(label);
        container.appendChild(progress);
        container.appendChild(info);
      });
      body.appendChild(container);
      loading.classList.add('hide');
    });
  });
};

window.onload = init();

Me gustaría seguir profundizando un poco más en el uso de Tensorflow.js, no solo para clasificar imágenes, ya que podríamos hacerlo también sobre videos, detectar objetos, detectar la segmentación de personas, estimación de posiciones, etc…, pero debemos continuar con el resto de las herramientas.

Ml5.js

Como habíamos comentado al principio, ml5.js es una interfaz de alto nivel, muy simple, de código abierto para TensorFlow.js, que nos permite manejar operaciones matemáticas aceleradas por GPU y gestión de memoria para algoritmos de aprendizaje automático.

Viendo el código anterior y lo que se puede conseguir, podríamos pensar que no se puede hacer mas fácil, pero si se puede hacer todavía mas sencillo y sobre todo más potente.

Para empezar usaremos el tag script para acceder al CDN de la librería y poder hacer uso de ella.

<script src="https://unpkg.com/[email protected]/dist/ml5.min.js"></script>

Igual que en el ejemplo de Tensorflow.js, podéis acceder también a su repositorio en Github.

No obstante añadiré el código en el tutorial para un acceso mas rápido.

<!-- index.html -->
<!DOCTYPE html>
<html lang="es">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Ml5.js y P5.js</title>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.9.0/p5.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.9.0/addons/p5.dom.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.9.0/addons/p5.sound.min.js"></script>
  <script src="https://unpkg.com/[email protected]/dist/ml5.min.js"></script>
  <link rel="stylesheet" href="./style.css" />
</head>
<body>
  <div class="loading hide">
    Analizando imagen
  </div>
  <script src="./index.js"></script>
</body>
</html>
/* style.css */
.loading {
  position: absolute;
  left: calc(50% - 100px);
  top: calc(50% - 10px);
  width: 200px;
  text-align: center;
  background: #6677aa;
  padding: 20px 0px;
  border-radius: 100px;
  font-size: 20px;
  color: #ffffff;
}
.hide {
  display: none;
}
.result {
  padding: 10px;
  box-shadow: 0px 6px 12px rgba(0,0,0,0.3);
  margin-top: 20px;
  width: 500px;
}
canvas {
  box-shadow: 0px 6px 12px rgba(0,0,0,0.3);
  margin-bottom: 20px;
}
// index.js
let mobilenet;
let img;
window.onerror = (errorMsg, url, lineNumber) => {
  console.log('----- ERROR ------');
  console.log(errorMsg, url, lineNumber);
  console.log('------------------');
  return false;
}

const show = (el, status) => {
  document.querySelector(el).classList[status ? 'remove' : 'add']('hide');
};

function modelReady() {
  console.log('model is ready!!');
}

function gotResult(error, results) {
  show('.loading', false);
  if (error) {
    console.error(error);
  } else {
    console.log(results);
    const body = document.body;
    const container = document.createElement('div');
    results.forEach(data => {
      const porcent = nf(data.confidence, 0, 4) * 100;
      const progress = document.createElement('progress');
      const label = document.createElement('div');
      const info = document.createElement('span');
      label.innerHTML = `Elemento reconocidos: ${data.label}`;
      progress.setAttribute('max', 100);
      progress.setAttribute('value', porcent);
      info.innerHTML = ` ${porcent}%`;
      container.classList.add('result');
      container.appendChild(label);
      container.appendChild(progress);
      container.appendChild(info);
    });
    body.appendChild(container);
  }
}
window.onload = () => {
  show('.loading', true);
}
function imageReady() {
  image(img,0,0 , width, height);
  mobilenet.predict(img, gotResult);
}
function preload() {
  classifier = ml5.imageClassifier('MobileNet');
  img = loadImage('img1.jpg');
}

function setup() {
  createCanvas(640, 480);
  img = createImg('img1.jpg', imageReady);
  img.hide();
  background(0);
  mobilenet = ml5.imageClassifier('MobileNet',modelReady);
}

Si comparáis el código y el resultado, ambos realizan la misma acción, clasificar una imagen.

La diferencia esta en que usando la librería ml5.js podemos hacer uso de la GPU, y usando p5.js podemos crear canvas y realizar una programación gráfica mucho mas rápida ya que no tenemos que complicarnos con el canvas y como pintar en el, que aunque para este ejemplo es muy simple para otros puede ser algo más doloroso.

Como he dicho en el punto anterior, me gustaría continuar profundizando pero debemos continuar con la última herramienta.

Processing (p5.js)

Processing es un software que nos permite programar de una forma muy simple pero obteniendo unos resultado bastante buenos.

Esto suena maravilloso pero como siempre digo, «el movimiento se demuestra andando».

 

Puedes encontrar el código en Github y para un acceso rápido añado también el código en la página.

<!-- index.html -->
<!DOCTYPE html>
<html lang="es">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Processing P5.JS</title>
</head>
<body>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.9.0/p5.min.js"></script>
  <script src="./index.js"></script>
</body>
</html>
// index.js
function setup() {
  createCanvas(710, 400, WEBGL);
}

function draw() {
  background(0);

  translate(-240, -100, 0);
  normalMaterial();
  push();
  rotateZ(frameCount * 0.01);
  rotateX(frameCount * 0.01);
  rotateY(frameCount * 0.01);
  plane(70);
  pop();

  translate(240, 0, 0);
  push();
  rotateZ(frameCount * 0.01);
  rotateX(frameCount * 0.01);
  rotateY(frameCount * 0.01);
  box(70, 70, 70);
  pop();

  translate(240, 0, 0);
  push();
  rotateZ(frameCount * 0.01);
  rotateX(frameCount * 0.01);
  rotateY(frameCount * 0.01);
  cylinder(70, 70);
  pop();

  translate(-240 * 2, 200, 0);
  push();
  rotateZ(frameCount * 0.01);
  rotateX(frameCount * 0.01);
  rotateY(frameCount * 0.01);
  cone(70, 70);
  pop();

  translate(240, 0, 0);
  push();
  rotateZ(frameCount * 0.01);
  rotateX(frameCount * 0.01);
  rotateY(frameCount * 0.01);
  torus(70, 20);
  pop();

  translate(240, 0, 0);
  push();
  rotateZ(frameCount * 0.01);
  rotateX(frameCount * 0.01);
  rotateY(frameCount * 0.01);
  sphere(70);
  pop();
}

Como has podido comprobar el resultado es muy llamativo, pero lo mas llamativo son las pocas lineas de código que han sido necesarias para generar este ejemplo.

Con Processing (P5.js) damos por finalizado este pequeño tutorial de Tensorflow.js, no obstante en breve intentare publicar otra entrada con mas detalle sobre sobre Tensorflow.js y el ecosistema que ofrece.

IBM Watson y su inteligencia artificial

IBM Watson, ¿que es?

Según wikipedia:

Watson es un sistema informático de inteligencia artificial que es capaz de responder a preguntas formuladas en lenguaje natural.​ Esta desarrollado por la corporación estadounidense IBM y forma parte del proyecto del equipo de investigación DeepQA, liderado por el investigador principal David Ferruci. Lleva su nombre en honor del fundador y primer presidente de IBM, Thomas J. Watson.

Efectivamente, más inteligencia artificial, y ademas es una de las 7 grandes empresas que junto a Google(Alphabet), Apple, Sentient Technologies, Facebook, Microsoft y Amazon luchan por tener la más rápida y potente inteligencia artificial del mundo.

Gracias a la lucha de estas empresas, hoy tenemos acceso publico y gratuito (casi gratuito) a casi toda su potencia y/o casi todos sus servicios.

Muy bonito, ¿Por donde comienzo?

Para acceder a los servicios que ofrece IBM haremos clic aquí y nos registramos para tener acceso a nuestro panel de control.

Una vez finalizado el proceso de registro accederemos a nuestro dashboard y desde allí iniciaremos nuestro producto/servicio de IBM Cloud

La siguiente pantalla sera nuestro panel de control y es donde gestionamos todos los servicios, recursos, etc…, que ofrece IBM. La primera vez que entras no se mostrara ningún recurso ya que acabamos de iniciar y todavía no hemos creado nada.

Para continuar necesitamos Crear un recurso, así que vamos a pulsar sobre Crear recurso

En la siguiente pantalla podemos ver que IBM tiene todo tipo de servicios, pero nosotros vamos a centrarnos en la parte de inteligencia artificial: Watson

Cuando seleccionemos Watson se mostraran los diferentes servicios que IBM tiene relacionado con la inteligencia artificial, pero para este ejemplo vamos a elegir el servicio de reconocimiento visual ( visual recognition )

En la siguiente pantalla  aparecerá toda la información sobre el servicio, limitaciones, versiones beta, etc…

Pulsando en el botón Crear  finalizaremos el proceso.

Para entrar en profundidad y conocer todos los detalles sobre cualquier servicio, IBM ofrece una guía y la documentación API de como usar cada servicio, dentro del propio servicio.

Ahora con nuestro servicio y el api_key creado solo queda empezar a escribir un poco de código.

Probando el servicio de forma simple (solo local)

¿¡¡Pero!!?, ¿porque solo local?. Pues la respuesta es muy sencilla, el primer ejemplo es tan simple que no requiere de programación, solo es necesario realizar una llamada al API desde un formulario en HTML, y salvo que quieras que tu api_key la conozca todo el mundo, no te recomiendo esta opción.

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Imagen 0</title>
</head>

<body>
    <form method="POST" enctype="multipart/form-data" action="https://gateway-a.watsonplatform.net/visual-recognition/api/v3/classify?api_key={api_key}&version=2018-03-19">
        <label>Imagen</label>
        <input type="file" name="imagen">
        <input type="submit" value="Clasificar imagen">
    </form>
    <form method="POST" enctype="multipart/form-data" action="https://gateway-a.watsonplatform.net/visual-recognition/api/v3/detect_faces?api_key={api_key}&version=2018-03-19">
        <label>Imagen</label>
        <input type="file" name="imagen">
        <input type="submit" value="Faces">
    </form>
</body>

</html>

{api_key} -> cambiar por vuestra api_key.

Y con esto ya tenemos un sistema de clasificación de objetos y reconocimiento facial dentro de una imagen, CHAS!!!!.

Para este ejemplo he puesto un vídeo para comprobar como funciona el servicio y el respuesta que nos devuelve, porque como decía antes, las api keys están en el propio código.

Ahora si!!, usando Node para realizar la consulta

Para probar el API de reconocimiento visual de IBM he creado una página que comprueba el fichero a subir.

Cuando abrimos la página desde un ordenador se abre el explorador de ficheros para seleccionar una imagen, pero si se usa el móvil nos permite usar también la cámara del móvil.

Si todo es correcto nos mostrara en la página la imagen que vamos a enviar para su clasificación.

Cuando pulsamos sobre el botón clasificar fotografía se realizara una petición ajax a un servidor creado en Node que sera el encargado de subir el fichero y enviarlo al API de reconocimiento visual de IBM.

Si todo el proceso es correcto tendríamos una respuesta en JSON con toda la información que ha podido extraer y clasificar el servicio de reconocimiento visual de IBM.

Finalmente desde la página web tramitaremos esa respuesta y mostrar los resultados.

Aunque voy a poner todo el código en la web siempre me gusta dejar un repositorio de todo lo que hago, así que desde aquí accedes al repositorio y en este enlace puedes probar la aplicación.

A continuación todo el código del proyecto:

[Página estática que se carga desde Node]

<!DOCTYPE html>
<html lang="es">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>CLASIFICADOR WATSON</title>
    <!--<link href="style.css" rel="stylesheet">-->
    <link href="https://fonts.googleapis.com/css?family=Montserrat" rel="stylesheet">
    <style>
        body {
            font-family: 'Montserrat', sans-serif;
        }
        
        #resultado div {
            width: 100%;
            float: left;
        }
        
        .clasificacion b {
            text-transform: capitalize;
        }
        
        .clasificacion ul {
            list-style: none;
            padding: 0;
        }
        
        .loader {
            border: 10px solid #f3f3f3;
            border-radius: 50%;
            border-top: 10px solid #3498db;
            width: 60px;
            height: 60px;
            -webkit-animation: spin 2s linear infinite;
            animation: spin 2s linear infinite;
            position: absolute;
            left: calc(50% - 30px);
            top: calc(50% - 30px);
            display: none;
        }
        
        @-webkit-keyframes spin {
            0% {
                -webkit-transform: rotate(0deg);
            }
            100% {
                -webkit-transform: rotate(360deg);
            }
        }
        
        @keyframes spin {
            0% {
                transform: rotate(0deg);
            }
            100% {
                transform: rotate(360deg);
            }
        }
        
        input {
            width: 100%;
            max-width: 300px;
            box-shadow: 1px 0px 10px rgba(0, 0, 0, 0.3);
            margin: 5px;
        }
    </style>
</head>

<body>
    <main>
        <form>
            <input type="file" name="photo" accept="image/*"><br>
            <input type="submit" value="Clasificar fotografía" disabled><br>
        </form>
        <div id="resultado">
            <div class="imagen"><img></div>
            <div class="clasificacion"></div>
        </div>
        <div class="loader"></div>
    </main>
    <script>
        var WATSON = WATSON || {};

        WATSON = {
            showLoading: function(status) {
                document.querySelector(".loader").style.display = status ? "block" : "none";
            },
            ajax: function(url, evt) {
                return new Promise(function(resolve, reject) {
                    var request = new XMLHttpRequest();
                    request.open('POST', url, true);
                    request.onreadystatechange = function(aEvt) {
                        if (request.readyState == 4) {
                            var html = "";
                            if (request.status == 200) {
                                var responseJSON = JSON.parse(request.responseText);
                                html += "<h3>Imagenes procesadas: " + responseJSON.images_processed + "</h3>";
                                var clasi = responseJSON.images[0]["classifiers"][0]["classes"];
                                clasi.sort(function(a, b) {
                                    return b.score - a.score;
                                });
                                for (var propiedad in clasi) {
                                    if (clasi.hasOwnProperty(propiedad)) {
                                        html += "<ul>";
                                        typeof clasi[propiedad].class !== "undefined" ? html += "<li><b>" + clasi[propiedad].class + "</b></li>" : html += "";
                                        typeof clasi[propiedad].score !== "undefined" ? html += "<li><progress value='" + (clasi[propiedad].score * 100) + "' max='100'></progress> <b>" + clasi[propiedad].score + "</b></li>" : html += "";
                                        //typeof clasi[propiedad].type_hierarchy !== "undefined" ? html += "<b>" + clasi[propiedad].type_hierarchy + "</b><br>" : html += "<br>";
                                        html += "</ul>";
                                    }
                                }
                                resolve(html);
                            } else {
                                html += "Error loading page";
                                reject(html);

                            }
                        }
                    };
                    request.send(new FormData(evt.target));
                });
            }
        };
        window.onload = function() {
            var form = document.querySelector('form');
            var submit = document.querySelector("input[type='file']");
            form.addEventListener('submit', function(e) {
                e.preventDefault();
                WATSON.showLoading(true);
                WATSON.ajax('http://tecnops.es:17202/uploadImage', e).then(function(success) {
                    WATSON.showLoading(false);
                    document.querySelector(".clasificacion").innerHTML = success;
                }).catch(function(err) {
                    WATSON.showLoading(false);
                    document.querySelector(".clasificacion").innerHTML = err;
                });
            });

            submit.addEventListener("change", function(evt) {
                var files = evt.target.files;
                for (var data in files) {
                    if (files.hasOwnProperty(data) && files[data].type.match("image.*")) {
                        var reader = new FileReader();
                        reader.onload = (function(theFile) {
                            return function(e) {
                                var img = document.querySelector("img");
                                img.src = e.target.result;
                                img.title = escape(theFile.name);
                                img.classList.add("show");
                                document.querySelector("input[type='submit']").removeAttribute("disabled");
                            };
                        })(files[data]);
                        reader.readAsDataURL(files[data]);
                    }
                }
            }, false);
        };
    </script>
</body>

</html>

Para que funcione el API de IBM de reconocimiento visual en el servidor de Node necesitaremos instalar la librería de acceso a los servicios de IBM Watson.

Como este ejemplo esta creado en Node usaremos NPM: npm install –save watson-developer-cloud

No obstante toda la documentación de uso viene especificada en cada servicio y con pequeños ejemplos de uso. Desde aquí puedes acceder a todo el API de reconocimiento visual.

[Servidor Node que carga la página estática y realiza la llamada a el servicio de IBM]

// Dependencias para usar IBM Watson
var VisualRecognitionV3 = require('watson-developer-cloud/visual-recognition/v3');

// Crear servidor en Node
var http = require('http');

// Obtener rutas
var ruta = require("path");

// Modulo de parseo de los datos de un formulario, incluyendo la subida de ficheros (multipart/form-data).
var formidable = require('formidable');

// Sistema de ficheros
var fs = require('fs');

// Puerto para el servidor
var port = process.env.PORT || 17202;

// Creamos el servidor
http.createServer(function(req, res) {
    if (req.url == "/") {
        fs.readFile('index.html', function(error, contenido_archivo) {
            if (error) {
                res.writeHead(500, 'text/plain');
                res.end('Error interno.');
            } else {
                res.writeHead(200, { 'Content-Type': 'text/html' });
                res.end(contenido_archivo);
            }
        });
    } else if (req.url == "/uploadImage") {

        // Creamos un nuevo formulario de entrada
        var form = new formidable.IncomingForm();

        // Analiza una solicitud entrante de node.js que contiene datos de formulario (Enviando archivos y campos)
        form.parse(req, function(err, fields, files) {
            // Error
            if (err) throw err;

            // API DE IBM Watson
            // 1 - Se autentica en la API de reconocimiento visual al proporcionar la clave API para la instancia de servicio que desea utilizar. 
            var visualRecognition = new VisualRecognitionV3({
                version: '2018-03-19',
                iam_apikey: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
            });

            // La función fs.createReadStream () le permite abrir una secuencia legible de una manera muy simple. Todo lo que tiene que hacer es pasar la ruta del archivo para comenzar a transmitir
            var images_file = fs.createReadStream(files.photo.path);

            // La puntuación mínima que una clase debe tener para mostrarse en la respuesta 0.0 => ignora la clasificación y devuelve todo
            var threshold = 0.0;

            // Parametros (documentacion muy bien explicada)
            var params = { images_file: images_file, threshold: threshold, accept_language: "es" };

            // Comienza la clasificación
            visualRecognition.classify(params, function(err, response) {
                res.writeHead(200, { 'Content-Type': 'application/json' });
                res.end(JSON.stringify(response));
            });
        });
    } else {
        var codigo_html = '';
        res.writeHead(200, 'text/html');
        res.end(codigo_html);
    }
}).listen(port);
console.log(`Servidor funcionando en el puerto ${port}`);

Con esta pequeña introducción y la gran documentación que ofrece IBM espero que te animes a probar todo lo que IBM pone a nuestra disposición.

ACTUALIZACIÓN [07/03/2019]

Gracias al comentario de Antonio indicando que tenia problemas para ejecutar el proyecto, he realizado algunos cambios en el código ya que IBM Watson ha cambiado la clave api_key por iam_apikey.

Para comprobar que es correcta la solución, ademas de un vídeo con el proyecto en funcionamiento también he actualizado el repositorio de github con los cambios, he añadido el package.json con las dependencias necesarias y he modificado el código de los gist de este artículo con los últimos cambios.

chatbot cover

Primer chatbot con Dialogflow y Nodejs

Primer chatbot con Dialogflow y Nodejs

Después de estar unos días trasteando con Dialogflow y con Nodejs, he creado un pequeño chatbot que te dice la temperatura de cualquier lugar del mundo.

El ejemplo es muy sencillo pero muestra la gran potencia que tiene Dialogflow.

Comenzaremos creando un Agente, que para este ejemplo he usado el nombre de Curso01.

En este ejemplo usaremos para el nombre del Agente Curso01, pero podemos usar cualquier nombre.

Para el idioma y la zona horaria, usaremos la que nos corresponda. Finalmente para el proyecto Google, podemos crear uno nuevo (recomendado) o usar un proyecto existente.

A continuación crearemos un Intent, que llamaremos para esta prueba El tiempo

Ahora toca el momento de empezar añadir las frases para entrenar a nuestro agente.

En mi caso estoy haciendo una prueba de una aplicación para saber el tiempo de cualquier punto geográfico, así que usare diferentes formas de preguntar el tiempo.

Como en este ejemplo solo quiero que me diga la temperatura del día actual, únicamente usare como parámetro el nombre de la ubicación.

 

Dentro de acciones y parámetros nos vamos a centrar en 3 partes. La primera es parameter name, ese valor es el que nos interesa para este ejemplo ya que sera el que se

enviara en el JSON a nuestro fichero en el servidor. Entity es una herramienta potente que se utiliza para extraer los valores de los parámetros de entrada.

En la frase «¿Que temperatura hace en Madrid?, Madrid es nuestro parámetro y en este ejemplo uso del tipo any aunque lo correcto debería ser city, geo-city, etc..

Para finalizar el Value, aunque en este ejemplo no lo vamos a usar, este valor lo usamos dentro de response para personalizar la respuesta.

A continuación un ejemplo de como sería el flujo:

  • Pregunta: ¿Que tiempo hace en Londres?
  • Respuesta: En $any (Londres) hace una temperatura de…. (Aquí añadimos las diferentes respuesta que necesitemos para conseguir una apariencia lo mas humana posible)

Como decía antes, en este ejemplo no vamos hacer uso de responses desde Dialogflow, usaremos nuestro script externo (webhook).

Para poder gestionar desde fuera de dialogflow una respuesta es necesario añadir un webhook y activar en la parte de fulfillment el uso de webhook para este intent.

Integrando nuestro bot

Yo voy a usar Slack por comodidad

 

Accedemos a la parte de integración

Configuramos Slack para hacer la integración del bot

Ahora un video de como funciona el bot en Slack:

En el video uso varias localizaciones validas e invalidas para comprobar el comportamiento del bot.

Usando nuestro servicio externo

Ahora vamos a la parte de Fulfillment

 

En el campo URL añadiremos la url donde esta nuestro servicio que usara el JSON que envía dialogflow y que para este ejemplo sera el único campo que usemos.

 

Ahora el flujo de dialogflow:

  1. Añadimos una frase de prueba para comprobar que respuesta nos da dialogflow
  2. Nos muestra la frase que hemos usado
  3. Aparece la respuesta (en este caso de un servicio externo). Si usamos el propio dialogflow nos respondería con el texto ubicado en response
  4. El intent que esta usando
  5. El parámetro y el valor del parámetro (definido en la parte de parámetros y acciones)
  6. Mostrar el json que genera dialogflow
  7. Contenido del json

Hasta este punto todo lo que hemos hecho ha sido con dialogflow, ahora toca crear el código que gestionara esos datos y que en la parte de Fulfillment definimos.

Creando nuestro servicio con Node

Aunque la finalidad de este articulo es tener una idea básica de Dialogflow, voy a explicar de forma sencilla como montar una pequeña API REST con Node para poder ver el comportamiento de dialogflow con un servicio externo.

Para el servicio externo podemos usar cualquier lenguaje de lado del servidor (Node, PHP, Java, etc…).

Lo primero que necesitamos es instalar Node y npm.

Una vez instalado podemos comprobar si funciona usando los siguientes comandos, node -v para ver la versión de node y npm -v para comprobar la versión de npm.

Creamos la carpeta donde vamos a crear el script y ejecutamos el siguiente comando: npm init -y, con este comando estamos generando el fichero package.json con los valores por defecto.

El fichero package.json es un fichero que contiene la configuración del proyecto en Node

Para este ejemplo necesitamos los siguiente paquetes y que instalaremos de la siguiente forma

  • npm i -D express
  • npm i -D body-parser
  • npm i -D request
  • npm i -D google-translate-api

Comenzamos con el código del servicio en Node:

servicio.js

'use strict';

// Libreria express para crear un api rest
const express = require("express");
const bodyParser = require("body-parser");

// Para hacer peticiones http de forma simple
const request = require('request');

// Para usar express dentro de Node
const app = express();

// Definimos el puerto
const port = process.env.PORT || 8899;

// Traducción en tiempo real
const translate = require('google-translate-api');

// Middleware de análisis del cuerpo de Node.js 
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());

// Métodos de ruta (VERBOS HTTP: POST, GET, PUT, DELETE, etc...). Endpoint
app.post("/api/tiempo", (req, res) => {

    // JSON QUE ENVIA DIALOGFLOW
    let ubicacion = req.body.result.parameters["any"];

    // Valor de kelvin para hacer la transformación a centígrados
    let kelvin = 273.15;

    // URL del API para la consulta de la temperatura por la posición geográfica
    let url = `http://api.openweathermap.org/data/2.5/forecast?q=${ubicacion}&APPID=apikey`;

    // Realizamos la petición
    request(url, function(error, response, body) {
        // Convertimos a JSON, la respuesta del servicio
        let _body = JSON.parse(body);

        // Que no de error el servicio externo
        if (_body.cod === '200') {

            // Pequeñas conversiones
            let meses = ["Enero", "Febrero", "Marzo", "Abril", "Mayo", "Junio", "Julio", "Agosto", "Septiembre", "Octubre", "Noviembre", "Diciembre"];
            let mesTxt = meses[parseInt(_body.list[0].dt_txt.split(" ")[0].split("-")[1]) - 1];
            let fecha = `${_body.list[0].dt_txt.split(" ")[0].split("-")[2]} de ${mesTxt} de ${_body.list[0].dt_txt.split(" ")[0].split("-")[0]}`;
            let temperatura = _body.list[0].main.temp - kelvin;

            // Formamos la respuesta que enviaremos a Dialogflow
            let _response = new Object();

            // DEFAULT RESPONSE EN DIALOGFLOW
            _response.speech = `La temperatura prevista para el día ${fecha} (${_body.list[0].dt_txt.split(" ")[1]}) en ${_body.city.name} es de ${temperatura.toFixed(1)} grados `;
            _response.displayText = _response.speech;
            _response.source = "webhook";

            // Enviamos la respuesta 
            res.status(_body.cod).send(_response);
        } else {
            // ERROR!!!
            translate(_body.message, { to: 'es' }).then(resTra) => {
                let _response = new Object();
                _response.speech = resTra.text;
                _response.displayText = resTra.text;
                _response.source = "webhook";
                res.status(200).send(_response);
            }).catch(err) => {
                console.error(err);
            });
        }
    });
});

// Escuchando nuestro servidor Node
app.listen(port, () => {
    console.log(`API REST en el puerto: http://localhost:${port}`);
});

Cuando este creado el fichero con el código, solo quedaría ejecutar node servicio.js. 

En ese momento deberíamos tener en el puerto 8899 nuestro servidor corriendo a la espera de los datos.

Nuestro primer bot funcionando

Para poder ejecutar este ejemplo y que se puede comprobar su funcionamiento, además de la integración con slack voy a crear una integración web para  ejecutar directamente desde esta entrada.

Aunque casi todo el trabajo esta hecho en dialogflow, como siempre dejo el enlace a github con el código.

Recordad que para este ejemplo únicamente he usado dos tipos de variaciones para solicitar la temperatura, que tiempo hace…. y que temperatura hace…

chatbot cover

Chatbot, toma de contacto con Dialogflow

Comenzando con nuestro chatbot

– ¿Sabes lo que es la prueba de Turing?
– Sí. Sé lo que es. Es cuando un humano interactúa con una computadora. Y si no se da cuenta de que es una computadora la prueba es exitosa.
– ¿Qué implica el que sea exitosa?
– Que la computadora tiene inteligencia artificial.

El texto anterior corresponde a una de las conversaciones de la película Ex Machina.

Quiero aprovechar la temática de la película para empezar con una de mis muchas tareas pendientes y que poco a poco voy realizando, en esta ocasión le toca a la INTELIGENCIA ARTIFICIAL.

Para comenzar me gustaría indicar que todas las definiciones y conocimientos aquí expuestos están sacados de la página oficial de dialogflow, y que esta guía únicamente intenta resumir y marcar un guión que a mi personalmente me sirve para tener mas claro este tremenda herramienta.

Una vez aclarado el origen de la información, lo primero que necesitamos es tener una cuenta de Google para poder usar Dialogflow y de esta forma empezar a dar forma a nuestro chatbot.

Con nuestra cuenta de Google y haciendo click aqui accederemos a la web de Dialogflow, desde donde tendremos que acceder a la consola.

Una vez dentro crearemos un agente, pero antes de continuar, ¿que es un agente?.

¿Que es un agente?

Los agentes se describen mejor como módulos NLU (Natural Language Understanding). Estos se pueden incluir en su aplicación, producto o servicio y transformar las solicitudes de los usuarios naturales en datos procesables.

Esta transformación ocurre cuando la entrada de un usuario coincide con una de las intenciones dentro de su agente. Los intentos son los componentes predefinidos o definidos por el desarrollador de los agentes que procesan la solicitud de un usuario.

Los agentes también pueden diseñarse para gestionar un flujo de conversación de una manera específica. Esto puede hacerse con la ayuda de contextos, prioridades de intención, llenado de espacios, responsabilidades y cumplimiento a través de webhook.

 

En esta pantalla indicaremos el nombre del Agente, el idioma por defecto, la zona horaria y el proyecto al que vincularemos Dialogflow si existe o creara un nuevo proyecto. Para realizar este ejemplo he usado los siguientes datos:

  • Agent Name: Curso01
  • Default Language: Spain – es
  • Default Time Zone: Europe / Madrid
  • Google Project: Create a new Google Project

Cuando se crea el agente por defecto se crean dos intents por defecto, ¿pero que son los intents?

¿Que es un intent?

Un intent representa un mapeo entre lo que dice un usuario y qué acción debe tomar su software.

Las interfaces de intención tienen las siguientes secciones:

  • Frases de entrenamiento
  • Acción
  • Respuesta
  • Contextos

Ahora sabemos que son los intents y podemos comprobar el contenido de los intents que se crean por defecto. El primer intent que se crea por defecto es Fallback y se usa para obtener frases de respuesta por parte del bot cuando algo no lo entiende o lo desconoce y el segundo intent es Wellcome, que es un intent para dar la bienvenida.

A continuación vamos a ver la estructura de un intent

 ¿Que es el contexto?

Los contextos representan el contexto actual de la solicitud de un usuario. Esto es útil para diferenciar frases que pueden ser vagas o tener diferentes significados según las preferencias del usuario, la ubicación geográfica, la página actual en una aplicación o el tema de conversación.

Por ejemplo, si un usuario está escuchando música y encuentra una banda que atrae su interés, podría decir algo como: «Quiero escuchar más de ellos». Como desarrollador, puede incluir el nombre de la banda en el contexto de la solicitud, de modo que el agente pueda usarla en otros aspectos.

O digamos que usted es un fabricante de dispositivos domésticos inteligentes, y tiene una aplicación que controla de forma remota las luces y los electrodomésticos. Un usuario puede decir, «Encienda la luz del porche delantero», seguido de «Apagarlo». Al establecer un contexto, la aplicación comprenderá que la segunda frase se refiere a la luz de la primera solicitud. Más tarde, si el usuario dice «Encienda la cafetera» y luego «Desactívela», se producirá una acción diferente a la anterior debido al nuevo contexto.

chatbot cover

1 – Hola chatbot!!!. Una pequeña introducción

Iron Man y los Chatbots

Bienvenido señor, felicidades por el éxito de la ceremonia de inauguración, lo mismo que su comparecencia ante el Senado. Y debo añadir lo reconfortante que resulta verle por fin en un vídeo con la ropa puesta, señor. J.A.R.V.I.S.

No quería comenzar esta entrada sin hacer referencia a el chatbot e inteligencia artificial mas famosa del cine, J.A.R.V.I.S. Un chatbot lo podemos definir como un sistema informático que tiene la capacidad de mantener una conversación mediante un lenguaje natural con una persona o con otro chatbot. Esta capacidad para entender y procesar un dialogo es conocida como NLP (Natural Language Processing) y el AI (Aritficial Intelligent).

Casos de uso

Los usos mas habituales para un chatbot a día de hoy son:

  • Sustituir y/o complementar un servicio de atención al cliente
  • Un posible canal de ventas
  • Un generador de leads, aprovechando el dialogo para obtener información clave.

Consejos

Para poder diseñar un buen chatbot debemos fijarnos bien en los siguiente consejos:

  • Diseño del diálogo:  dediquemos la mayor parte del tiempo a diseñar cómo será el diálogo entre bot humano, debe ser lo más simple posible y que requiera el mínimo proceso de aprendizaje por parte del humano(es el bot quien debe aprender cómo dialogar con el humano y no al revés). También puedes ser apropiado contar en el equipo con un sociólogo.
  • Inteligencia artificial:  la inteligencia artificial (capacidad del bot para interpretar las respuestas y decidir en base a las mismas) es vital en el largo plazo, pero sugerir posibles respuestas al usuario para que de forma casi inconsciente nos facilite el trabajo es súper importante, conseguiremos resultados rápidos y facilitaremos al humano la interacción con el chatbot.
  • Programación y despliegue: Debemos programar lógica e inteligencia del bot sólo una vez, independientemente de la plataforma de mensajería donde se ejecute. Lógicamente debemos adaptar las respuestas según las oportunidades y limitaciones que aporta cada plataforma, pero la Inteligencia Artificial del bot, lo que realmente define el Procesamiento del Lenguaje Natural debe ser única e independiente a cada plataforma.
  • Entrenamiento: Esto no termina el día que desplegamos el bot las apps de mensajería, es sólo el comienzo. Cada paso del diálogo tiene miles de posibles respuestas por parte del usuario, por muy buen trabajo de Diseño del Diálogo que hayamos hecho… es imposible conocer todas las respuestas, por ello es vital registrar qué responde el usuario en qué pasos, a fin de re-programar (educar, entrenar) nuestro chatbot para que pueda procesar esas respuestas y tomar decisiones (añadirla a la lista de posibles respuestas, crear un nuevo paso del diálogo, volver a un estado anterior…). Este trabajo es muy costoso, por ello lo habitual es conectar nuestro chatbot a un motor de Inteligencia Artificial capaz de ayudarnos en el proceso. Existen varios motores pertenecientes a las principales compañías de Internet (google, IBM, google…)