Hace no mucho los desarrolladores construíamos aplicaciones monolíticas, que más tarde fueron divididas en código cliente y servidor usando APIs. Después refactorizamos los back-ends construyendo microservicios para tener alta disponibilidad y ser más escalable.
Recientemente estaba en una charla y el ponente habló de las Olas Tecnológicas. Ahora ya puedes pensar cuantas de ellas has vivido a lo largo de tu experiencia profesional.
Hace unos meses me uní a un equipo nuevo donde construimos prototipos rápidos para probar conceptos y aprender para aplicarlo a un producto. A veces acabamos testeando estos conceptos en dispositivos para tener un feeling más exacto de como será la experiencia final.
La Ola Tecnológica en que ahora mismo vivimos me atrevo a decir que trata de explotar los términos Inteligencia Artificial y Bots y desde nuestro equipo no queríamos quedarnos atrás. Empezamos a pensar sobre como enganchar esa inteligencia en diversos dispositivos.
Una prueba de concepto simple, flexible y portable que pudiera ser usado para diferentes propósitos con un mínimo de adaptación.
La idead de usar un Procesador de Lenguaje Natural ( NLP ), que pudiera ser llamado via HTTP API desde una aplicación cliente. La idea sería algo así como, el servicio NLP contestaría nuestras peticiones; la aplicación cliente necesitará un reconocedor de voz para el usuario, transformar esa voz a texto y realizar una petición al servicio NLP, que nos responderá y convertiremos esa repuesta a voz.
Este experimento nos permitirá ver como es la interacción de nuestros usuarios mediante voz y tener feedback rápido de nuestros usuarios en aspectos como: problemas en el reconocimiento, ruido en la comunicación, expectativas con esta nueva tecnología y algunos otros más datos relevantes para el equipo.
Veamos las piezas de puzzle en detalle.
Tabla de contenidos
1. El servicio NLP
En esta ocasión probaremos DialogFlow, que es un servicio NLP de Google, tiene muchas integraciones disponibles, SDK para muchos lenguajes y agentes ya cargados que nos facilitan la prueba. Se integra especialmente bien con Google Assistant.
Antes de seguir me gustaría revisar algunos conceptos:
- Intent: Es un patrón detectado por el servicio NLP mediante el uso de utterances que son un conjunto de sentencias que definen un modelo de comportamiento. Normalmente esos intents son palabras clave que tu puedes acomodar a tu sistema.
- El servicio NLP define algunos intents y algunas utterances que son usadas por el servicio para responder a nuestras peticiones. El servicio NLP permite peticiones via HTTP API, y eso is lo que necesitamos para la prueba.
Intent Menu
Se pueden añadir nuevos intents.
Intent creation Menu.
Hay una consola en un lateral desde la que puedes testear tus intents y utterances manualmente y siguiendo la documentación se puede encontrar como hacer las peticiones HTTP:
Dialogflow SDKs | Dialogflow
Voice interface is cross-platform. Your agent will understand your users no matter what device you’re using. You design…
dialogflow.com
dialogflow/dialogflow-javascript-client
dialogflow-javascript-client – JavaScript Web SDK for Dialogflow
github.com
2. El Cliente
Como hemos mencionado anteriormente a veces usamos dispositivos para test finales. Ser portable es siempre bueno para construir prototipos que demuestran ciertas hipótesis y React-Native cubre nuestras necesidades. En este caso testearemos sobre una plataforma android por disponibilidad.
Asumimos que has instalado ya react-native-cli y has comenzado un proyecto Android. Si no puedes seguir esta documentación que te muestra los pasos:
Getting Started – React Native
This page will help you install and build your first React Native app. If you already have React Native installed, you…
facebook.github.io
Primero vamos a ensamblar los módulos:
- Para reconocimiento de voz optamos por este módulo, https://github.com/JoaoCnh/react-native-android-voice
- Para convertir el texto en voz por este otro, https://github.com/ak1394/react-native-tts
Lo que acaba reflejado en unos cuantos cambios en la configuración de proyecto:
apply plugin: "com.android.application" import com.android.build.OutputFile apply from: "../../node_modules/react-native/react.gradle" def enableSeparateBuildPerCPUArchitecture = false def enableProguardInReleaseBuilds = false android { compileSdkVersion 23 buildToolsVersion "23.0.1" defaultConfig { applicationId "com.rnauratest" minSdkVersion 16 targetSdkVersion 22 versionCode 1 versionName "1.0" ndk { abiFilters "armeabi-v7a", "x86" } } splits { abi { reset() enable enableSeparateBuildPerCPUArchitecture universalApk false // If true, also generate a universal APK include "armeabi-v7a", "x86" } } buildTypes { release { minifyEnabled enableProguardInReleaseBuilds proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" } } // applicationVariants are e.g. debug, release applicationVariants.all { variant -> variant.outputs.each { output -> // For each separate APK per architecture, set a unique version code as described here: // http://tools.android.com/tech-docs/new-build-system/user-guide/apk-splits def versionCodes = ["armeabi-v7a":1, "x86":2] def abi = output.getFilter(OutputFile.ABI) if (abi != null) { // null for the universal-debug, universal-release variants output.versionCodeOverride = versionCodes.get(abi) * 1048576 + defaultConfig.versionCode } } } } dependencies { compile project(':react-native-tts') compile fileTree(dir: "libs", include: ["*.jar"]) compile "com.android.support:appcompat-v7:23.0.1" compile "com.facebook.react:react-native:+" // From node_modules compile project(':VoiceModule') // Add voice module package } // Run this once to be able to run the application with BUCK // puts all compile dependencies into folder libs for BUCK to use task copyDownloadableDepsToLibs(type: Copy) { from configurations.compile into 'libs' }
rootProject.name = 'popiggTest' include ':react-native-tts' project(':react-native-tts').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-tts/android') include ':VoiceModule', ':app' project(':VoiceModule').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-android-voice')
package com.popiggtest; import android.app.Application; import com.facebook.react.ReactApplication; import com.facebook.react.ReactNativeHost; import com.facebook.react.ReactPackage; import com.facebook.react.shell.MainReactPackage; import com.facebook.soloader.SoLoader; import com.wmjmc.reactspeech.VoicePackage; // voice recognition package import net.no_mad.tts.TextToSpeechPackage; // test to speech package import java.util.Arrays; import java.util.List; public class MainApplication extends Application implements ReactApplication { private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) { @Override public boolean getUseDeveloperSupport() { return BuildConfig.DEBUG; } @Override protected List<ReactPackage> getPackages() { return Arrays.<ReactPackage>asList( new MainReactPackage(), new VoicePackage(), // voice recognition package new TextToSpeechPackage() // test to speech package ); } }; @Override public ReactNativeHost getReactNativeHost() { return mReactNativeHost; } @Override public void onCreate() { super.onCreate(); SoLoader.init(this, /* native exopackage */ false); } }
3. Último paso
Una vez que todos los módulos están listos veamos como integrarlo dentro de nuestra app:
Con no muchas líneas hemos construido nuestro propio asistente de voz en Android. Pero no todo funciona siempre a la primera.
4. Problemas potenciales y puntos fuertes
Ahora que acabamos de construir nuestro asistente en Android, flexible y ajustable en términos de intents y respuestas, con una interfaz es tiempo de la revisión.
- Puede ser que la cache juegue en tu contra cuando haces debug de tu aplicación. Las dependencias externas se pueden complicar sumado a la caché de NPM. Atención a esto, borra y reinstala las dependencias, eso suele funcionar.
- DialogFlow SDK: Finalmente decidimos realizar las peticiones usando Fetch de React-Native porque el SDK no funcionaba fácilmente. La documentación no es la mejor para este caso puntual pero la parte que hay de HTML + JS está muy bien para nuestra demo.
- El punto clave es el debugger remoto de React-Native. Con un simple console.log, console.warn y console.error, se pueden trazar las acciones y lo que sucede entre bambalinas en tu aplicación con el navegador. Por ejemplo en esta demo es importante saber como van las peticiones y respuestas en la aplicación. También como se está reconociendo la voz.
React-Native remote debug
- Dialogflow es impresionante, tiene una interfaz sencilla, es fácil de usar, está disponible en varios lenguages y es suficientemente flexible para extender las respuestas del servicio NLP con tus propias respuestas.
Si te ha gustado y quieres ver un poco más profundo como está montado aquí está el código de la demo.
popigg/DialogflowReactNative
DialogflowReactNative – Your voice assistant in ReactNative & DialogFlow
github.com
Espero que te guste, si así es, puedes compartirlo.
Gracias por leerlo.