El intérprete de Omu es el pilar principal de la aplicación, visto desde fuera parece algo sencillo: un personaje 3D animado que signa en LSE (Lengua de Signos Española). Y es por esa aparente sencillez que queremos mostrar al mundo cómo funciona el intérprete de Omu. Si tienes curiosidad sobre la LSE hemos hecho un post hablando del tema: ¿Qué es la LSE?.
A grandes rasgos el flujo que sigue el sistema es el siguiente, primero se graba la voz, esta se transcribe a texto y se procesa para obtener el lema de cada palabra. Una vez procesado se clasifica cada palabra y se envía a una cola de acciones, las cuales están asociadas cada una a su respectiva animación.
Pero como esto nos sabe a poco, vamos a explicar mejor qué pasa detrás de cada proceso.
Grabando la voz 🗣️ 🎤
Al principio hicimos pruebas con algún modulo de Angular pero optamos por usar la librería de JavaScript p5.js para grabar el audio, funcionaba pero no terminó de gustarnos el resultado. Con el tiempo decidimos cambiarlo y acabamos usando otra librería de JavaScript, MediaStreamRecorder.js mezclado con las funciones nativas del navegador para acceder al micrófono.
El funcionamiento no tiene mucho misterio, una vez se hace click en «Iniciar» se piden permisos de acceso al micrófono usando el método del navegador getUserMedia(). En el momento en el que se acepta el acceso se comienza a grabar, se crea un MediaStreamRecorder (de la librería mencionada) de tipo «audio/wav» indicando que almacene en un objeto blob el audio cada 5 segundos.
Finalmente este objeto blob de audio se envía a nuestro servidor.
var mediaConstraints = { audio: true };
function grabar() {
if (navigator.mediaDevices) {
captureUserMedia(mediaConstraints, onMediaSuccess, onMediaError);
}
function captureUserMedia(mediaConstraints, successCallback, errorCallback) {
navigator.mediaDevices.getUserMedia(mediaConstraints)
.then(successCallback).catch(errorCallback);
}
function onMediaSuccess(stream) {
mediaRecorder = new MediaStreamRecorder(stream);
mediaRecorder.mimeType = 'audio/wav';
mediaRecorder.audioChannels = 1;
crearFormData();
mediaRecorder.start(5000);
}
function crearFormData() {
// new FormData()
// enviarAudio([...])
}
Transcibiendo el audio a texto 💬 📝
Para transcribir la voz a texto usamos el servicio «speech» de wit.ai, un framework dedicado a la creación de bots con procesamiento de lenguaje natural avanzado.
Cuando se recibe el audio en el servidor de Omu se hace una petición a wit.ai y una vez realizada la transcipción se procesa el texto con RASA.
Procesando el texto, lematizando con RASA 🔎 📄
Para procesar la cadena de texto que llega desde wit.ai se usa RASA + spaCy, pero antes de nada, ¿qué es RASA y spaCy?
RASA es una herramienta de código abierto de procesamiento de lenguaje natural, generalmente de usa para crear bots y asistentes virtuales.
Spacy es una librería de código abierto para python dedicada al procesamiento de lenguaje natural.
Gracias a estas dos tecnologías se ha podido formar lo que es el núcleo del intérprete. Este núcleo está montado por nuestro equipo desde cero en un Docker. Docker es, a grandes rasgos, un contenedor de software para despliegue de aplicaciones.
El Docker que contiene RASA y spaCy está desplegado en nuestro servidor y es únicamente accesible desde el mismo, es decir, de forma local. Una vez recibida la cadena de texto se vuelca la información al servicio de RASA para ejecutar un script. El script se encarga de sacar el lema de cada una de las palabras del texto usando la librería de spaCy.
Cabe mencionar que para la comunicación interna del servidor se usa axios, una librería de JavaScript para crear peticiones HTTP asíncronas hacia puntos finales (endpoints) REST.
// PETICIÓN A RASA
axios.post(baseUrl + '/rasa/', {
name: response.data.
}).then(function (response) {
var leer = response;
return res.json({
"original": leer.data.original,
"lemma": leer.data.lemma
})
})
Clasificando palabras y enviando al usuario 📄 📨 💻
En el momento en el que el servicio de RASA devuelve el texto lematizado queda el último paso en la parte del servidor: clasificar las palabras.
En lengua de signos el orden difiere de la lengua española además de que no todas las palabras se signan, pero debido a que la aplicación es un prototipo se ha decidio dejar esta parte como mejora para una versión comercial.
El proceso de clasificación consiste en seleccionar aquellas palabras asociadas a un signo de las que se tiene una animación creada. Finalmente se envían al usuario las palabras clasificadas y el texto original para mostrar como subtítulos.
Mostrando las animaciones y subtítulos 🧏 & 💬
En el momento en el que se reciben las palabras clasificadas y el texto original, las primeras van a lo que llamamos «la cola de animaciones«, mientras que el texto original se muestra en forma de subtítulos.
La cola de animaciones funciona de la misma forma que funciona la cola del super: cuando llegas a caja pagas. Solo que aquí en vez de pagar pides la animación que toca.
A la hora de mostrar las animaciones en nuestro motor gráfico, que por cierto está hecho desde cero con WebGL, existen dos casos. Primer caso: la animación pedida es la primera vez que se muestra. Segundo caso: la animación ya se ha pedido antes durante la sesión.
Antes de nada, debo mencionar el gestor de recursos del motor gráfico, este se encarga de administrar los elementos que se descargan del servidor. De esta forma se pueden mostrar en pantalla sin tener que descargarlos todo el rato, es decir, se almacenan temporalmente.
Cuando se pide una animación primero se comprueba si está en el gestor de recursos. Si no está en el gestor se pide al servidor, una vez ha sido descargada se añade al gestor de recursos y se muestra por pantalla con los subtítulos. En el caso de encontrarse la animación en el gestor ya no hace falta descargarla, simplemente se pide al gestor de recursos y se muestra por pantalla.
Y así es como funciona el intérprete de Omu. Después de meses de diseño e implementación estamos bastante contentos con el resultado. También hay que tener en cuenta que solo es una primera versión funcional y se puede mejorar.
Esperamos que haya quedado todo claro, si tienes alguna duda o comentario puedes dejarlo en la sección de comentarios o usar nuestras redes sociales de twitter e instagram. ¡Hasta pronto!