Reconocimiento y síntesis de voz en el navegador

7
14134

Trata de reconocimiento de voz desde el navegador, ​navegación por una web a través de ​comandos hablados y síntesis de voz a partir de un texto dado. Continuación del artículo dedicado a la manipulación de audio (y vídeo) con HTML5 y JavaScript

[alert type=»warning» close=»false»]Este post es la continuación de Manejando audio (y vídeo) con HTML5[/alert]

Índice de contenidos

5. Dictándole al navegador

La API que se encarga del reconocimiento de voz es la Web Speech API. Pero antes de presentarla, vamos a ver cómo de sencillo resulta indicarle al navegador que reconozca nuestra voz.

var SpeechRecognition = SpeechRecognition || webkitSpeechRecognition;
var recognition = new SpeechRecognition();

recognition.lang = "es-ES";
recognition.continuous = false;
recognition.interimResults = true;

recognition.onresult = function(event) {
  for (var i = event.resultIndex; i < event.results.length; i++) {
    if (event.results[i].isFinal){
      document.getElementById("text").innerHTML +=
        event.results[i][0].transcript;
    }
  }
}

Ver ejemplo 5: dictándole al navegador

Evidentemente, hay otros eventos que podemos controlar, a parte de onresult, pero es en éste donde se produce casi toda la chicha.

recognition.onstart = function(event) { console.log(event); }
recognition.onerror = function(event) { console.log(event); }
recognition.onend = function(event) { console.log(event); }

En el ejemplo anterior, se puede observar que el objeto recognition define algunas propiedades en su configuración:

  • lang: idioma en formato locale, ya que tiene importancia el acento del locutor, que puede ser distinto dependiendo del país o región. No es lo mismo español de España (es_ES), que español de Argentina (es_AR). La pronunciación, acentos y localismos, pueden variar.
  • continuous: indica si el reconocimiento se hace de forma continuada o no. Es decir, si se detiene cuando el usuario deje de hablar. Por defecto, su valor es false, de forma que si deseamos que el reconocimiento se haga continuado, debemos inicializarla a true.
  • interimResults: valor booleano que señala si se desean mostrar los valores provisionales o no sobre el texto reconocido. Hay que tener en cuenta, que el resultado puede cambiar.

Ahora vamos a centrar nuestra atención en el evento onresult, donde recibimos un array de results con longitud resultIndex, que se corresponden con cada uno de los textos que ha reconocido. A su vez, este array contiene información sobre cada “pieza”.

  • isFinal: indica si ha terminado de decidir qué texto ha reconocido.
  • a su vez contiene un array con los posibles textos que ha creído reconocer, cuya transcripción está en la propiedad transcript, y cuya fiabilidad se mide en la propiedad confidence, que es la probabilidad entre 0 y 1 de que la transcripción sea correcta.

Jugando con estas propiedades, podemos discernir cuando isFinal y cuando no, y utilizarlo para introducir puntos y seguidos. Pero para introducir otros signos de puntuación, sólo se me ocurre midiendo las pausas en la dicción, y para eso habría que medir los tiempos que se producen entre eventos, y extraer un patrón en ellos.

En el siguiente ejemplo, he hecho una versión rudimentaria, para transformar lo dictado a frases.

Ver ejemplo 6: Speech Recognition and transform in phrases

6. Comandos y navegación por voz.

Ya hemos experimentado cómo el navegador puede reconocer nuestra voz. Ahora cabría preguntarse, si podemos vincular ciertas palabras a comandos de voz. La intuición nos parece indicar, que si el navegador puede reconocer una palabra, siempre podremos despachar un evento vinculado a dicha palabra que dispare un determinado método. Pero en ese caso, tendríamos que estar atentos a todas las palabras que se le pueda decir al navegador.

Para facilitar eso, lo que se puede hacer, es restringir la lista de posibles palabras que pueda reconocer el browser, definiendo una gramática. Para esto también hay un estándar: el JSpeech Grammar Format. Tiene una pinta a lo que sigue:

var grammar = '#JSGF V1.0; grammar actions; public <action> = siguiente | anterior | volver | inicio | baja | arriba;';

Este ejemplo, podría definir los comandos para navegar por voz en un blog. Esto puede ser útil, por ejemplo, en los navegadores de las SmartTVs, o para personas con problemas motores.

	var SpeechRecognition = SpeechRecognition || webkitSpeechRecognition;
	var SpeechGrammarList = SpeechGrammarList || webkitSpeechGrammarList;

	var grammar = '#JSGF V1.0; grammar actions; public <action> = siguiente | anterior | volver | inicio | baja | arriba;';

	var speechRecognitionList = new SpeechGrammarList();
	    speechRecognitionList.addFromString(grammar, 1);

	var recognition = new SpeechRecognition();
	    recognition.grammars = speechRecognitionList;
	    recognition.lang = 'es-ES';
	    recognition.interimResults = false;
	    recognition.maxAlternatives = 1;

	recognition.onresult = function(event) {
	  eval("myCommand." + event.results[0][0].transcript + "()");
	}
	recognition.onend = function() {
	  recognition.start();
	}
	recognition.start();

	var myCommand = {
	  siguiente : function(){
	  	//go to the next post
	  	this.writeCommand("siguiente");
	  },
	  anterior : function(){
	  	//go to previous post
	  	this.writeCommand("anterior");
	  },
	  volver : function(){
	  	//history.go(-1);
	  	this.writeCommand("volver");
	  },
	  inicio : function(){
	  	//go to the homepage
	  	this.writeCommand("inicio");
	  },
	  baja : function(){
	  	//scroll down
	  	this.writeCommand("baja");
	  },
	  arriba : function(){
	      //scroll to top
	  	this.writeCommand("arriba");
	  },
	  writeCommand : function(_command){
	    var comma = ", ";
	    if (document.querySelector("#text").innerHTML.length == 0){
	    	comma = "";
	    }
	    document.querySelector("#text").innerHTML += comma + _command;
	    console.log(recognition);
	  }
	}

Ver ejemplo 7: Voice command test with JSpeech Grammar Format

En este ejemplo, la gramática es muy simple, pero JSGF permite definir gramáticas mucho más complejas. Su definición sigue reglas semejantes a las de las expresiones regulares:

  • separador de conjunciones disyuntivas (OR) es la barra |
  • para conjunciones copulativas (AND) es el ampersand &
  • para cuando hay tokens opcionales, los corchetes [ ]
  • para el cierre de Klein (repeticiones de 0 … n), el asterisco *
  • para el cierre de Klein positivo el + (1 repetición o más)
  • unas reglas pueden componerse con otras ya definidas anteriormente.

De esta forma, se puede llegar a tener gramáticas amplias, y bien definidas, que podemos emplear desde para una navegación por voz, a definir un juego de instrucciones o comandos para una determinada aplicación web.

7. Síntesis de voz a partir de un texto

Una vez recorrido el camino hasta aquí, cabría la posibilidad de preguntarse por la función inversa “¿y leer un texto? ¿es posible que dado un texto lo pueda convertir a una locución?”. Y la respuesta es afirmativa. Sí se puede. Dentro de la Web Speech Api, está el objeto SpeechSynthesis, que a su vez tiene un array de objetos de tipo SpeechSynthsisVoice con las distintas voces que disponemos en nuestro navegador.

Una prueba rápida con el siguiente código, muestra que dispongo de más de 80 voces en Google Chrome

var synth = window.speechSynthesis;
var voices = synth.getVoices();

Aunque no todas en español. Además, al hacer una prueba con Firefox, para ver de cuántas voces disponen otros navegadores, me doy cuenta de que la prueba parece que no funciona. ¿y eso por qué? Leyendo descubro que mozilla considera esta tecnología experimental y viene implementada a partir de la versión 45. En versiones anteriores hay que habilitarla específicamente en el navegador en about:config en el flag media.webspeech.synth.enabled = true;. Hecho ésto, ya funciona también en Firefox.

Después de solventar este pequeño inconveniente, quería ver cuáles son las voces de que dispongo en en español. Para lo que me hice una pequeña prueba:

Ver ejemplo 8: Spanish voices in my browser

Lo primero que veo es que Google Chrome me devuelve 2 voces más que firefox.

[one_half]Voces en chrome[/one_half]
[one_half_last]Voces en firefox[/one_half_last]

Google Chrome añade un par de voces más: una con español de España y otra con español de ¿Estados Unidos?.

En los objetos de tipo voz SpeechSynthsisVoice echo en falta que entre sus propiedades indiquen si la voz es masculina o femenina. Hay que sacarlo por contexto, por el nombre que le han dado a la voz.

Ahora vamos a intentar leer un texto de ejemplo, y para eso está el objeto SpeechSynthesisUtterance

var sampleText = “Esto es un texto para probar la síntesis de voz”;
var utterance = new SpeechSynthesisUtterance(sampleText);

A este objeto, le vamos a indicar que debe leer con la voz de “Mónica”, que es la que disponemos con locale “es-ES”.

	utterance.voice = voices.filter(
	  function(voice) { 
	    return voice.name == 'Monica';
	  })[0];

y le decimos que realice la locución:

window.speechSynthesis.speak(utterance);

Puedes ver este ejemplo funcionando en:

Ver ejemplo 9: Basic speech synthesis

El objeto SpeechSynthesisUtterance nos provee de una serie de eventos con los que controlar la locución. Entre las propiedades cabe mencionar dos:

  • rate: se trata de la velocidad a la que lee. El valor por defecto es 1. Eso significa que 2 es el doble de la velocidad normal, y que 0.5 es la mitad de la velocidad normal. Cualquier valor que se aleje de estas cifras, lo hace anormalmente alto o bajo, siendo la locución demasiado rápida o lenta.
  • pitch: se trata del tono con el que se lee la enunciación. El valor por defecto es 1 y puede tomar valores comprendidos entre 0 y 2, siendo el cero un tono muy bajo, y dos un tono muy alto.

8. Posibles aplicaciones y conclusiones

A través de los anteriores ejemplos, hemos visto que se pueden incluir audios y vídeos en nuestros sites sin hacer uso de Adobe Flash, que se pueden subtitular en distintos idiomas, incluir distintas pistas de audio, que podemos dictarle al navegador, despachar eventos mediante comandos de voz o realizar locuciones a partir de un texto.

La primera aplicación que nos viene a la mente es probablemente el tema de la accesibilidad, que en España está muy orientada al colectivo de invidentes. Pero hay que pensar también en personas con problemas motores, que no puedan usar un teclado o un ratón.

Pienso también en los videotutoriales que tanto proliferan por la red: qué fácil sería subtitularlos a distintos idiomas, o incluso añadirles diferentes pistas de audio con traducciones, llegando así a un colectivo mucho mayor.

En una navegación clásica, entramos a la página web de un cine, navegamos por el menú para consultar la cartelera, elegimos la pelicula y la sesión, y de un mapa de asientos, seleccionamos las butacas libres en las que deseamos sentarnos. ¿No se podría hacer esto mismo mediante comandos de voz? Así podría comprar unas entradas, hablándole a mi móvil mientras voy conduciendo de vuelta a mi casa. Y quien dice el cine, dice reservar un billete de tren, avión u hotel.

9. Enlaces y referencias

7 COMENTARIOS

    • Anónima,
      No entiendo tu comentario.
      Todo esto que cuento en el artículo funciona en firefox. No está dirigido a un navegador concreto, si no a cualquiera que soporte los estándares.

      • Hola Juan excelente tutorial, me funciona y muy bien en chrome, pero no se si estoy haciendo algo mal en Firefox, o el navegadores de moviles, serías tan amable de explicarme que debo hacer para que me funcione enestos, la versión de firefox que tengo actualmente es 72.0.2 (64-bit)

        • Hola,
          Han pasado 4 años desde este artículo. Probablemente hayan cambiado algunas cosas, y es posible que hayan evolucionado sensiblemente los estándares. ¿cuál de los ejemplos es el que te falla? ¿Te salen errores en la consola de desarrollo?

  1. hola, me gusto mucho su pagina me ayudo muchisimo, lo unico que no he logrado hacer es que me reconozca numeros, sera que me puede ayudar con una breve explicacion?

DEJA UNA RESPUESTA

Por favor ingrese su comentario!

He leído y acepto la política de privacidad

Por favor ingrese su nombre aquí

Información básica acerca de la protección de datos

  • Responsable:
  • Finalidad:
  • Legitimación:
  • Destinatarios:
  • Derechos:
  • Más información: Puedes ampliar información acerca de la protección de datos en el siguiente enlace:política de privacidad