Asterisk. Revisando Opciones de Text To Speech

Asterisk: Tenia programado escribir en dos partes, sobre ASR y ahora sobre TTS (serian las dos cara de la moneda)

Siguiendo con la linea de programacion con AGI, ahora se me ocurre la opcion de dotar de un servicio de Text To Speech a nuestro Asterisk, del nivel AT&T Natural Voices utilizando el mismo sistema que aplicamos con nuestro sistema ASR en el anterior mensaje (como es un servicio con un modelo ASP evidentemente no tendremos problemas de licencias siempre y cuando ese sistema permanezca en activo). Lo malo, claro esta, que si ese servicio se modifica (la URL por ejemplo), nos quedamos sin “negocio”. Por eso que es conveniente si el sistema lo utilizamos en produccion y somos capaces de rentabilizarlo, pasar a un sistema de TTS local en nuestro sistema.

Para mantenernos en una linea open source como Asterisk, tenemos la opcion de Festival, el problema es que es de muy baja calidad comparado a soluciones de pago o la que voy a proponer aqui, a traves del TTS de Google

Texto a Voz con Google TTS

Vamos manos a la obra partiendo de la base AGI voy a obviar que se hicieron todos los pasos del mensaje anterior para instalar lo necesario (php-curl, y php-agi lo mas importante), hacemos lo siguiente:

Primero vamos a descargar un sistema para convertir de MP3 a WAV.

# aptitude install lame

Vamos a crear un Script PHP en /var/lib/asterisk/agi-bin/ podemos llamarlo por ejemplo asterisk-tts.php:


#!/usr/bin/php -q
<?php
require_once('phpagi-2.20/phpagi.php');
$agi = new AGI();

# Necesitamos pasarle la Cadena de Texto desde el Asterisk, y la recogemos con esta variable.
$traduccion = $argv[1];

# Aqui descargamos el fichero Mp3 haciendo pensar a Google que somos un Navegador
shell_exec("wget --header='User-Agent:Mozilla/4.0' 'http://translate.google.com/translate_tts?tl=es&q=".$traduccion."' -O /var/lib/asterisk/sounds/google-tts.mp3");
# Y convertimos el fichero con "lame" a wav que es reconocible por Asterisk
shell_exec("lame -h --decode /var/lib/asterisk/sounds/google-tts.mp3 /var/lib/asterisk/sounds/google-tts.wav");
$retString = "Fin de la conversion";
$agi->verbose($retString);
?>

Finalmente creamos una extension en nuestro DialPlan de Asterisk para que haga esta “gestion”:


exten => 2000,1,Answer()
same => n,Set(TTSVAR = "Lo que queramos convertir")
same => n,AGI(asterisk-tts.php,${TTSVAR})
same => n,Playback(google-tts)
same => n,Hangup()

Y ya esta, recargamos el dialplan de Asterisk como siempre, y marcando la extension 2000 oiremos con una voz muy sensual: “Lo que queramos convertir” … o algo asi 馃檪

Como veis la dificultad de implantacion es nula, y eso es lo que mas me ha gustado de AGI, que no hace falta estar creando aplicaciones en C-Arcaico y recompilando el Asterisk con la app_c_arcaico y podemos tener una funcionalidad semejante (aunque no nativa y para los mas sibaritas, con menos rendimiento en terminos de picosegundos). Lo que tampoco tengo muy claro es que Google este feliz que esten utilizando su TTS masivamente, aunque estoy seguro que ya habra por ahi algun Call-Center que lo este haciendo. Si tienen experiencia me gustaria que me lo comentaran.

Texto a Voz con Festival TTS

Ahora os voy a explicar como hacer lo mismo, pero con el sistema TTS Festival en local, que os comente antes, y asi podeis comparar que os gusta mas:

Festival TTS digamos que fue desarrollado por una universidad e incorporado nativamente en Asterisk, asi que eso simplifica bastante las cosas ya que existe una Aplicacion especifica para el tratamiento de Texto a Voz directamente para el dial Plan de Asterisk (el modulo app_festival.so). Primero tenemos que comprobar si lo tenemos preparado.

Desde el CLI> module show like festival

Si aparece algo asi como app_festival.so y “1 modules loaded”, entonces ya lo tenemos, sino, nos toca recompilar Asterisk y en la parte de make menuselect tenemos que seleccionar el app_festival antes de hacer el “make && make install”

Ahora vamos a instalar festival

#aptitude install festival

Y ahora necesitamos voces en Espa帽ol para Asterisk. Yo vivo en Andalucia ahora mismo, asi que barriendo para casa tenemos las que usa la junta de andalucia en la forja de Guadalinex:
http://forja.guadalinex.org/frs/?group_id=21

Vamos a descargar las de Silvia, para comparar el grado de sensualidad con respecto a Isabel de Google, todo sea por motivar a nuestros clientes varones.

# wget http://forja.guadalinex.org/frs/download.php/154/festvox-sflpc16k_1.0-1_all.deb
#dpkg -i 聽festvox-sflpc16k_1.0-1_all.deb
Y borramos el fichero de configuracion de festival que crea automaticamente, para poder utilizar mejor, el generico de Festival.
#rm /etc/festival.scm

La voz queda automaticamente instalada en la ruta:
/usr/share/festival/voices/spanish/JuntaDeAndalucia_es_sf_diphone

Ahora necesitamos modificar el archivo de configuracion de Festival por defecto ubicado en /usr/share/festival/festival.scm al final del fichero agregamos:


(set! voice_default 'voice_JuntaDeAndalucia_es_sf_diphone)
(define (tts_textasterisk string mode)
(let ((wholeutt (utt.synth (eval (list 'Utterance 'Text string)))))
(utt.wave.resample wholeutt 8000)
(utt.wave.rescale wholeutt 5)
(utt.send.wave.client wholeutt)))
(set! server_access_list '("localhost\\.localdomain" "localhost"))

Con esto, nos permitira por un lado utilizar la voz de Silvia y por otro lado arrancar el servidor Festival

Ahora necesitamos configurar el servidor Festival, bajamos los ficheros de desarrollo de festival
#aptitude install festival-dev

Y copiamos el fichero de autoarranque de festival a nuestro /etc/init.d para que arranque automaticamente el servidor cada vez que iniciemos nuestra maquina Asterisk:
#cp 聽/usr/share/doc/festival/examples/festival.init /etc/init.d/festival
#chmod +x /etc/init.d/festival

Antes de arrancar el servidor de Festival para Asterisk, necesitamos a帽adir una linea en /etc/default/festival:
RUN_FESTIVAL = yes

Y ahora si podemos arrancar el servidor Festival para Asterisk con exito:
/etc/init.d/festival start

Y para que arranque cada vez que iniciamos el sistema:
#ln -s /etc/init.d/festival /etc/rcS.d/S99festival

Ya esta todo casi listo, solo nos queda la parte mas facil, crear una extension en el DialPlan para ejectuar la aplicacion Festival
exten=> 3000,1,Answer()
same => n,Festival(Lo que queramos convertir)
same => n,Hangup()

Recargamos el dialplan de Asterisk como siempre y si marcamos la extension 3000, tendremos a Silvia dandonos el resultado.

Algunas cosas curiosas que he observado.
La version 1.0-1 de Guadalinex para Pedro parece que esta mal empaquetada. Instala sobre la version de Silvia (es_sf) en vez de (es_pa)
Se puede resolver de varias formas, una es, bajando las fuentes 聽(Archivos de desarrollo de la voz de Pedro) en el directorio correspondiente /usr/share/festival/voices/spanish/JuntaDeAndalucia_es_pa_diphone

Necesitamos desempaquetar tambien el .deb de Pedro con el comando “ar” (#ar x聽festvox-palpc16k_1.0-1_all.deb)
Y luego descomprimir data.tar.gz y a traves de la estructura de directorios llegar a …/usr/share/festival/voices/spanish/JuntaDeAndalucia_es_pa_diphone/group
Cambiamos el nombre al fichero que hay y lo copiamos a un nuevo directorio group dentro de nuestro directorio de Pedro antes creado
#mkdir聽/usr/share/festival/voices/spanish/JuntaDeAndalucia_es_pa_diphone/group
#mv 聽sflpc16k.group /usr/share/festival/voices/spanish/JuntaDeAndalucia_es_pa_diphone/group/palpc16k.group
O lo ideal si a 聽alguien le interesa que arregle ese fichero deb, no voy a ser yo, porque no me gusta demasiado.

Si tuviera que elegir personalmente un fichero para Festival en Espa帽ol para Asterisk, eligiria de hecho, el fichero por defecto de festvox en espa帽ol (el_diphone) que es el que mejor se entiende para mi gusto, aunque es voz masculina asi que no podriamos comparar bien para este ejemplo.
Se puede descargar y configurar siguendo los mismos pasos que antes, pero en el idioma por defecto poner “voice_el_diphone”
# aptitude install festvox-ellpc11k

Ahora puestos a comparar entre Festival TTS y Google TTS, creo que no hay color, pero para gustos los colores. Espero vuestras experiencias en el mundo del TTS.

Asterisk @ 10000 Horas

Un AGI Legendario: Publicacion en Twitter mediante ASR

Para muchos, hoy es un dia de fiesta en Espa帽a, pero para mi, es mi, es como el dia oficial de Asterisk, y me siento especialmente inspirado. Y aprovechando el momento estuve planteando alguna aplicacion curiosa que hacer con AGI.

Echando la mirada atras, durante el penultimo dia del Asterisk Advanced, tuvimos una breve introduccion al AGI (Asterisk Gateway Interface), y porque no decirlo, a mi me resulto de lo mas interesante del curso. Siempre habia sabido que existia tanto AMI como AGI pero hasta ese momento no me “atrevi” a profundizar, sea por desconocimiento, y por complejidad aparente.

De hecho, concretamente en ese mensaje del Dia 4 del curso, no publique nada acerca de estos interfaces de Asterisk, porque me resultaban lo suficientemente interesantes e importantes como para minimo dedicarle uno o varios mensajes a los mismos.

Y aqui va el primero. Durante el curso, la practica basicamente se trataba, de llamando a una extension, esta ejecutaba un script PHP a traves de AGI y se publicaba un tweet generico con cierta informacion en un usuario especifico para el curso (por interes todos van aqui:聽http://twitter.com/#!/agilabtest)

Realmente la practica lo daba todo bastante “masticado”, los scripts hechos, y exactamente lo que era necesario para que funcionara, y lo que habia que modificar en el DialPlan.

Pero ahora, aprovechando esta idea, se me ocurrio ir un paso mas alla y ademas de poder explicarlo todo un poco mas en detalle, ampliar la funcionalidad a algo muy interesante: Poder escribir un tweet en nuestro Twitter, llamando a traves de una extension, y diciendo lo que queremos escribir, con un sistema de Automatic Speech Recognition, ASR, o Reconocimiento de Voz Automatico, y lo mejor de todo, sin coste alguno (驴es posible?). Hoy me quede con la cita “Everything is possible, even impossible is: I’m possible y tambien aporto su granito.

En primer lugar vamos a “preparar” el sistema con algunos componentes basicos.

Por un lado necesitamos una libreria para poder trabajar con PHP a traves de AGI, llamada PHP-AGI. Es posible su descarga desde aqui:
http://phpagi.sourceforge.net/

Para este ejemplo yo recomiendo la version 2.2X puesto que si en un futuro saliera una version superior es posible que el script aqui realizado ya dejara de funcionar
La descargamos 聽http://sourceforge.net/projects/phpagi/files/phpagi/2.20/phpagi-2.20.tgz/download

Y descomprimimos aqui: /var/lib/asterisk/agi-bin/
#mv ./phpagi-2.20.tgz /var/lib/asteirsk/agi-bin/
#cd聽/var/lib/asteirsk/agi-bin/
#tar -xvf phpagi-2.20.tgz

Ahora por otro lado necesitamos un script en php escificamente creado para “operar” con Twitter, 聽(de hecho es generico, serviria incluso para desarrollar nuestras propias aplicaciones en php en relacion a Twitter). 聽Aqui hay varias librerias para Twitter:聽https://dev.twitter.com/docs/twitter-libraries#php聽.

Pero la que nos interesa para este caso es la siguiente:聽http://classes.verkoyen.eu/twitter_oauth

La descargamos:

#mkdir twitter-oauth
#cd twitter-ouath
#wget https://github.com/tijsverkoyen/TwitterOAuth/zipball/2.1.2 -O twitter-oauth.zip
#unzip twitter-oauth.zip
Nos crea un directorio con un nombre sacado de GitHub asi que entramos en ese directorio
# cd 聽<directorio-recien-creado>
# cp twitter.php ../../twitter.php

Asi ya tenemos el script este en nuestro directorio AGI-BIN

Estos scripts utilizan PHP-CURL, asi que, si no lo tenemos instalado es un buen momento para hacerlo:
#aptitude install php5-curl

Tambien nos va a hacer falta un conversor de WAV a FLAC para el Reconocimiento de Voz Automatico. En este caso, instalamos SOX si es que no lo tenemos ya.
#aptitude install sox

Antes de crear el script, necesitamos algo muy importante. Las claves del API de Twitter para el desarrollo de aplicaciones. De hecho necesitamos crear y autorizar una aplicacion en Twitter que va a ser con la que va a operar nuestro Script. Para ello entramos en:
https://dev.twitter.com/user/login?destination=home

Accedemos con nuestra cuenta de Twitter. Le damos a “Create an app”. Ponemos un nombre, una descripcion y una web, si no teneis web, pues poned http://www.10000horas.com para promocionarla !
Despues creamos la aplicacion. Ya en la aplicacion nos vamos a “Settings” y tenemos que picar la opcion: “Read, Write and Access direct messages”. Considerad que vamos a escribir directamente en nuestro tweeter por tanto es fundamental que este permiso este “activado”.

Finalmente necesitamos todas las claves para el script a continuacion y apuntarlas. Son las siguientes
1. Consumer key
2. Consumer secret
Abajo picamos en “Create my access Token” y apareceran dos claves mas:
3.聽Access token
4. Access token secret
Fijaros que abajo del todo ponga Access Level: Read, write, and direct messages, si pone otra cosa, teneis que fijar el tipo de acceso como comente antes, y volver a recrear las claves.

Y ahora nos toca crear dentro de AGI-BIN el script que vamos a ejecutar desde la Aplicacion AGI en el Dialplan

En este caso creamos un fichero llamamosle por ejemplo agitwitter.php, con el siguiente contenido (gran parte esta extraido del contenido del script ofrecido en las practicas del Asterisk Advanced, por eso hemos utilizado el script Twitter-Oauth de Tijs Verkonyen, en vez de cualquier otro, una cuestion de ahorro de tiempo).


#!/usr/bin/php -q

<?php

# Aqui cargamos el script twitter.php y el phpagi que descargamos antes.
require_once('twitter.php');
require_once('phpagi-2.20/phpagi.php');

# Creamos un nuevo objeto tipo AGI聽
$agi = new AGI();
$agi->answer();

# Aqui ponemos las credeciales que obtuvimos antes, en el mismo orden
# Estas que aparecen aqui son las de un usuario que cree de pruebas聽http://twitter.com/#!/pruebasadvanced
$consumerKey = 'xIpIGMm3kP610xh1sJVDCA';
$consumerSecret = 'vBT8eufZInFTPt02tGZeNdrb7o3YFDspCmtknS48JxY';
$accessToken = '414849063-IUB9SgA2fVr6vgk6zpYoJWAxwolGmlyA8qw361Z8';
$accessTokenSecret = 'ofo0kZrUTIXWJ1tul8zazifrNEhc0qTabzqHBADctvA';

# Aqui viene lo mejor del mensaje. Con estas lineas conseguimos un reconocimiento automatico de voz gracias a un servicio que pocos conocen
# y que ofrece el equipo de Google gratuitamente (al menos hasta lo que yo se).
# Creditos por ofrecerme este descubrimiento a聽http://www.ardumania.es

# Primero convertimos el fichero que generamos desde Asterisk a formato FLAC (que es el que admite Google)
shell_exec("sox 聽/var/lib/asterisk/sounds/twitter.wav聽/var/lib/asterisk/sounds/twitter.flac");

# Despues lanzamos una peticion a Google para que nos convierta el fichero FLAC en texto, nos devuelve una cadena de texto formato JSON
$linea = shell_exec("wget --post-file /var/lib/asterisk/sounds/twitter.flac --header='Content-Type: audio/x-flac; rate=8000' -O - 'http://www.google.com/speech-api/v1/recognize?lang=es_ES'");

# Convertimos esa cadena JSON gracias a PHP en un objeto directamente
$obj = json_decode($linea);

# Y conociendo la estructura exacta de ese objeto (contiene mucha mas informacion interesante, como la "calidad" de la conversion), sacamos el texto ya convertido
$tweet = $obj->{"hypotheses"}[0]->{"utterance"};

# Ya en adelante simplemente lo que hacemos es utilizando las funciones del script Twitter-Oauth publicamos en Twitter nustro Tweet
try

{
$t = new Twitter($consumerKey, $consumerSecret);
$t->setOAuthToken($accessToken);
$t->setOAuthTokenSecret($accessTokenSecret);

$retArray = $t->statusesUpdate($tweet);
$retString = "SUCCESS: Tweet id " . $retArray['id_str'] . " posted at " . $retArray['created_at'];
}
catch(Exception $e)
{
$retString = "FAILURE: " . $e->getMessage();
}

# Para terminar reportamos a Asterisk el resultado (si tenemos activada la opcion verbose en nuestro CLI podremos ver el mensaje de exito si salio bien la cosa
$randNum = rand(1000, 9999);

$retString .= ". ID " . $randNum;
$agi->verbose($retString);
$agi->hangup();

?>

Ahora una vez que tenemos el script PHP listo, solo nos falta editar nuestro DialPlan para ejecutarlo. En este caso he creado una extension minima para que podamos obtener el resultado que estamos buscando

exten => 1000,1,Answer()
same => n,Record(twitter.wav)
same => n,AGI(agitwitter.php)
same => n,Hangup()

Recargamos nuestro dialplan (CLI> dialplan reload) y listo!

Un tema muy importante para que todo esto funcione y que creo que a estas alturas sobra decir: ES FUNDAMENTAL TENER ACCESO A INTERNET EN NUESTRA MAQUINA ASTERISK

Esa es la unica “contrapartida” de poder tener un ASR gratuito y de maxima calidad… creo que en muchos casos es asumible. En otro caso tendremos que plantearnos otras alternativas de reconocimiento de voz automatico como por ejemplo Verbio recomendado por Avanzada 7 o LumenVox recomendado por Digium (que son de pago y nada baratos), o buscarnos la vida con CMUSphinx que es OpenSource y no esta mal (aunque 聽de momento es muy inferior tanto al ASR de Google y a los dos de pago).

Ahora desde nuestro telefono solo nos queda hacer esa llamada de cortesia a 聽la extension 1000, suena el tono de hablar, decimos lo que queramos publicar en nuestro tweet (sobra decir que cuanto mas claro hablemos mejor, y si decimos palabra a palabra mejor aun para mejorar el reconocimiento, aunque el ASR de Google para mi gusto es el mejor del mundo y es capaz incluso de reconocer las frase hecha sin demasiada vocalizacion con un amplio numero de aciertos). Despues de hablar pulsamos la Almohadilla (#) para guardar el fichero de Voz (twitter.wav) y finalmente esperamos a que Asterisk haga el resto.

Entramos en nuestro Twitter… y voila! Nuestro mensaje recien escrito (si todo fue bien, sino, como comente, recomiendo activar en el fichero /etc/asterisk/logger.conf para CLI (console =>) la posibilidad de verbose, asi podemos ver los resultados que nos devuelve el script PHP y si hay error, lo que captura el “catch” del script PHP).

Esta vez que con un solo mensaje he matado dos pajaros de un tiro: explicacion de una implementacion de ASR en Asterisk y el funcionamiento de AGI utilizando PHP (que hay que reconocer que a dia de hoy desde que salio PHP5 es el lenguaje de programacion interpretado que mas me gusta, aunque todo esto tambien se podria haber realizado en otros como Ruby On Rails o Python, si os fijasteis en la pagina de scripts para Twitter habia para varios lenguajes).

Y como siempre, y una vez mas, que cualquier comentario sera ampliamente bienvenido! Espero que les sea de provecho.