HTML 5 Web Speech API

A partir de la versión 25 de Chrome se lanzó una de las características más espectaculares de la especificación de HTML 5 llamada Web Speech API. Se trata de una API que nos permite el reconocimiento de voz y la transformación del ésta en texto.

Todas aquellas personas que hagan uso de Chrome de manera regular, se habrán percatado del icono con forma de micrófono que aparece tanto en el campo de búsqueda de Google:

Busqueda por voz Google Chrome

Como en su navegador para smartphones donde podemos también hacer uso de esta utilidad:

iphone

En este post vamos a ver cómo podemos hacer uso de Web Speech API, inicialmente disponible sólo en Chrome.

Speech Recognition Demo



Interfaz SpeechRecognition

Antes de ver el código, es importante que podamos comprobar como funciona. En este ejemplo básicamente hay dos elementos textarea donde, en el primero, se observa las palabras que se van detectando y, en el segundo, el resultado final del reconocimiento. Para activarlo basta con hacer clic sobre el micrófono y el navegador pedirá autorización para hacer uso del micrófono de nuestro equipo. Una vez habilitado podemos comenzar a hablar 🙂 Para finalizar la demo, basta con decir «terminar» y veremos como el micrófono queda deshabilitado de nuevo 🙂

Implementación

Para poder activar esta característica es necesario trabajar con SpeechRecognition. En Chrome está prefijada como webkitSpeechRecognition y tiene asociada una serie de propiedades y métodos que trataremos de ahora en adelante. El ejemplo más sencillo para empezar a trabajar con esta Api podría ser el siguiente:

<!DOCTYPE html>
<html>
<head>
    <title></title>
    <link href="style.css" rel="stylesheet" />
</head>
<body>
    <h2>Speech Recognition Demo</h2>
    <section>
        <textarea id="areaResult"></textarea>
        <textarea id="finalTranscript"></textarea>
        <div id="mic"></div>
    </section>
    <script>
        window.onload = function () {
            var recognition = new webkitSpeechRecognition();
            recognition.continuous = true;
            recognition.interimResults = true;
            recognition.lang = "es";
            mic.addEventListener('click', function () {
                areaResult.focus();
                recognition.start();
            });
            //events
            recognition.onaudiostart = function (event) {
                console.log("onaudiostart");
            };
            recognition.onsoundstart = function (event) {
                console.log("onsoundstart");
            };
            recognition.onspeechstart = function (event) {
                console.log("onspeechstart");
            };
            recognition.onspeechend = function (event) {
                console.log("onspeechend");
            };
            recognition.onsoundend = function (event) {
                console.log("onsoundend");
            };
            recognition.onaudioend = function (event) {
                console.log("onaudioend");
            };
            recognition.onresult = function (event) {
                console.log("onresult");
                var interimResult = '',
                    finalResult = '';
                for (var i = event.resultIndex; i < event.results.length; ++i) {
                    if (event.results[i].isFinal) {
                        finalResult = event.results[i][0].transcript;
                    } else {
                        interimResult += event.results[i][0].transcript;
                    }
                }
                finalTranscript.value = finalResult;
                areaResult.value = interimResult;
                if (interimResult.indexOf('terminar') != -1)
                    recognition.stop();
            };
            recognition.onnomatch = function (event) {
                console.log("onnomatch");
            };
            recognition.onerror = function (event) {
                console.log("onerror: " + event);
            };
            recognition.onstart = function (event) {
                console.log("onstart");
            };
            recognition.onend = function (event) {
                console.log("onend");
            };
        };
    </script>
</body>
</html>

Como se puede ver en el código anterior, he creado dos elementos de tipo textarea y un div con la imagen del micrófono que habilitará el reconocimiento.
Cuando la página esté lista, se creará un objeto del tipo webkitSpeechRecognition y asignaremos algunas de las propiedades que por defecto no están habilitadas:

    • continuous: Se trata de un valor que por defecto es false y lo que permite es que la Api siga a la escucha aunque se haya finalizado la oración (ha ocurrido una pausa). Con el valor a true nos aseguramos de que el reconocimiento de voz finalice programáticamente.
    • interimResults: Nos permite recuperar las palabras reconocidas hasta el momento, aunque no haya finalizado.
    • lang:

Nos permite configurar el lenguaje para el reconocimiento. Por defecto, se adquiere el del navegador.

Existen otras propiedades, las cuales podéis revisar en el siguiente listado.

Para iniciar el reconocimiento he utilizado el evento click sobre el micrófono para posicionar además el foco en el textarea donde se mostrarán las palabras que se están detectando. Se utiliza el método start(), a través del cual el navegador solicitará permiso para acceder a nuestro micrófono. A partir de ese momento comienza el reconocimiento 🙂

Eventos

En el código anterior se ha asociado un método a cada uno de los eventos que puede dar lugar durante el proceso, por orden de llegada. En este enlace se puede ver el motivo de cada uno de ellos.
El más interesante de ellos es el evento result donde va llegando la información que la Api va recuperando y reconociendo de nuestro micrófono:

            recognition.onresult = function (event) {
                console.log("onresult");
                var interimResult = '',
                    finalResult = '';
                for (var i = event.resultIndex; i < event.results.length; ++i) {
                    if (event.results[i].isFinal) {
                        finalResult = event.results[i][0].transcript;
                    } else {
                        interimResult += event.results[i][0].transcript;
                    }
                }
                finalTranscript.value = finalResult;
                areaResult.value = interimResult;
                if (interimResult.indexOf('terminar') != -1)
                    recognition.stop();
            };

En él se comprueba si el reconocimiento ha finalizado para mostrar la información en un textarea u otro a través de la propiedad transcript. Para finalizar, estoy comprobando si se reconoce la palabra «terminar» para finalizar el reconocimiento en lugar de utilizar un botón para hacerlo 😛

Como podéis ver se trata de una utilidad muy potente y nos permite incluso cosas como la interacción con web apps, de la misma manera que podríamos hacerlo con dispositivos móviles, videoconsolas, etcétera.

Plan B: input x-webkit-speech

Otra opción mucho más sencilla dentro del mundo Chrome es hacer uso de un input con la etiqueta x-webkit-speech, la cual es reconocida por este navegador y nos aporta toda la funcionalidad comentada anteriormente sin tener que escribir una sola línea de código. Este atributo sólo es útil cuando queremos mostrar en el mismo input el reconocimiento en formato texto, sin necesidad de tratarlo.

<input x-webkit-speech lang="es"></input>

En este caso, Chrome no solicitará acceso a nuestro micrófono y mostrará un control personalizado con el que podremos interacturar:

Espero que haya sido de utilidad 🙂

¡Saludos!