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

14 thoughts on “Asterisk. Revisando Opciones de Text To Speech

  1. Hola, lo primero gracias por el blog, las excelentes explicaciones y la impecable programación. Necesitaba utilizar el TTS de Google para una aplicación y este artículo me ha servido de mucha ayuda. He tenido algunos problemas que he resuelto de la siguiente manera:

    1 – Además de instalar “php-curl” y “php-agi”, he tenido que instalar “php5”, para poder ejecutar el script php

    2 – El shell_exec(wget) no me descargaba el mp3 tal como está redactado en el artículo, lo he cambiado por:

    shell_exec(‘wget -q -N -U Mozilla -O ../var/lib/asterisk/sounds/google-tts.mp3 “http://translate.google.com/translate_tts?tl=es&q=’.$traduccion.'”‘);
    ojo! el -N es importante si se quiere sobreescribir el mp3 varias veces

    3 – El “wav” generado por lame no lo reproducía el asterisk, así que he utilizado ffshow y va de lujo:

    shell_exec(“ffmpeg -v 0 -y -i ../var/lib/asterisk/sounds/google-tts.mp3 -ab 32 -ar 8000 ../var/lib/asterisk/sounds/google-tts.wav”);
    -y para sobreescribir sin preguntar

    Saludos!

  2. Hola Edu, te comento
    1. Sobre el tema del php5, como este mensaje venia un poco relacionado a articulos anteriores, sobreentendia que php5 ya estaba instalado en el sistema, porque yo recomiendo instalar el paquete LAMP (aunque luego mysql o apache no se usen, como estan “vacios” tampoco es que sea significativo su consumo, aunque efectivamente no es obligatorio, y como comentas, con php5 es suficiente para este ejemplo
    2. Tengo que probar de nuevo eso del shell_exec porque la verdad es que como me funciono a la primera, tampoco hice muchas mas pruebas intensivas.
    3. A mi me me reproducia sin problemas en wav generado por lame. Quiza haya alguna incompatibilidad con codecs, quiza sea por version de Asterisk o algo asi. De todas formas pondre tu solucion de ffshow como alternativa para prevenir como posible inconvencia
    Gracias por todos los comentarios
    Saludos

  3. Ah, y un truquito más, para que TTS de google pronuncie bien las eñes y caracteres especiales! desde el script php:

    shell_exec(‘wget -q -N -U Mozilla -O ../var/lib/asterisk/sounds/google-tts.mp3 “http://translate.google.com/translate_tts?tl=es&ie=UTF-8&q=’.urlencode($traduccion).’”‘);

    Así me funcionó a mi.

  4. Si es curioso Ricardo, lo vi en el blog del Elio Rojano. El primer commit lo hicieron el dia 27 de noviembre y yo escribi este articulo el 9 de diciembre. Se ve que nos iluminamos casi al mismo tiempo el Lefteris Zafiris y yo, aparte que el lo hizo mucho mas bonito con un repositorio Git 🙂 Lo que sigo preguntandome es hasta que punto Google disfruta con todo esto.

  5. Me pueden ayuda, no se porque razon no me descarga el audio, podrian mandarme su agu , adjunto por favor.

  6. Tampoco se de descarga bien el audio .mp3 de hecho luego de lanzar el wget con las dos formas que recomiendan , se descarga el google-tts.mp3 dentro de /var/lib/asterisk/sounds pero se descarga con CERO bytes , alguna sugerencia …

    Muchas Gracias

  7. AlejandroZ, el problema lo tienes durante el wget evidentemente.

    Ten cuidado con los simbolos de puntuacion de la linea

    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");

    Especialmente las comillas dobles y las comillas simples. Si haces copy-paste es probable que tengas problemas. Tengo que revisar las plantillas de escritura del Blog porque son origen de problemas para muchos.

    Tambien tengo este ejemplo aqui:
    http://wikiasterisk.com/index.php?title=TTS_y_ASR

  8. Saludos SirLouen,

    Gracias por tu respuesta, sabes mil disculpas por no ser mas explicito y anotar que si cambie los caracteres especiales que mencionas, es mas luego de cambiar estos carateres le hice al archivo que contiene el codigo un #dos2unix archivo.php …. Luego tambien probe solo en la consola el comando poniendo lo siguiente … me descarga el archivo pero igual con CERO BYTES
    #wget -q -N -U Mozilla -O /var/lib/asterisk/sounds/google-tts.mp3 http://translate.google.com/translate_tts?tl=es&q='holamundo

  9. AlejandroZ, insisto, tienes que escribir el comando wget en condiciones, si quieres lanzar el comando wget para probar:

    wget --header='User-Agent:Mozilla/4.0' -O /var/lib/asterisk/sounds/google-tts.mp3 'http://translate.google.com/translate_tts?tl=es&q=holamundo'

    Respeta las comillas simples como mínimo. Ademas el Header con lo de Mozilla/4.0 es importante para “engañar” a Google, para que piense que eres un navegador web y no un “downloader” generico.

  10. Hola! primero felicitar al autor del blog, muy bueno! tengo un par de dudas ya que no me funciona ni el festival ni el google traslalate;

    TTS Google

    me he descargado php5, php5-curl y phpagi-2.20 (y he descomprimido el archivo en /var/lib/asterisk/agi-bin).
    he creado el scritp tambien en agi-bin, llamado asterisk asi: asterisk-tts.php. Editandolo con vi he escrito lo siguiente:

    #!/usr/bin/php -q
    verbose($retString);
    ?>

    Atendiendo al compañero Edu, al principio lo puse como el autor del blog pero tampoco me funcionó. El dialphan es identico al del blog, reinicio asterisk y llamado a extension 2000 y me sale lo siguiente:

    — Executing [2000@users:1] Answer(“SIP/alex-00000006”, “”) in new stack
    > 0x93d36e8 — Probation passed – setting RTP source address to 192.168.121.1:8000
    — Executing [2000@users:2] Set(“SIP/alex-00000006”, “TTSVAR = “Lo que queramos convertir””) in new stack
    [Mar 22 08:01:30] WARNING[6246][C-00000006]: pbx.c:11684 pbx_builtin_setvar: Please avoid unnecessary spaces on variables as it may lead to unexpected results (‘TTSVAR ‘ set to ‘ “Lo que queramos convertir”‘).
    — Executing [2000@users:3] AGI(“SIP/alex-00000006”, “asterisk-tts.php,”) in new stack
    — Launched AGI Script /var/lib/asterisk/agi-bin/asterisk-tts.php
    asterisk-tts.php,: Failed to execute ‘/var/lib/asterisk/agi-bin/asterisk-tts.php’: Permission denied
    — Executing [2000@users:4] Playback(“SIP/alex-00000006”, “google-tts”) in new stack
    [Mar 22 08:01:30] WARNING[6246][C-00000006]: file.c:701 ast_openstream_full: File google-tts does not exist in any format
    [Mar 22 08:01:30] WARNING[6246][C-00000006]: file.c:1017 ast_streamfile: Unable to open google-tts (format (alaw)): No such file or directory
    [Mar 22 08:01:30] WARNING[6246][C-00000006]: app_playback.c:484 playback_exec: ast_streamfile failed on SIP/alex-00000006 for google-tts
    — Executing [2000@users:5] Hangup(“SIP/alex-00000006”, “”) in new stack
    == Spawn extension (users, 2000, 5) exited non-zero on ‘SIP/alex-00000006’

    Alguien podria echarme una mano? soy novata en asterisk.

    Por otro lado, FESTIVAL, tengo la configuracion exactamente igual y he sido cuidosa en seguir todos los pasos, me sale esto en asterisk:

    == Using SIP RTP CoS mark 5
    — Executing [3000@users:1] Answer(“SIP/alex-00000007”, “”) in new stack
    > 0x93d36e8 — Probation passed – setting RTP source address to 192.168.121.1:8000
    — Executing [3000@users:2] Festival(“SIP/alex-00000007”, “hola esto es una pruenba”) in new stack
    == Parsing ‘/etc/asterisk/festival.conf’: Found
    [Mar 22 08:12:12] WARNING[6307][C-00000007]: app_festival.c:404 festival_exec: festival_client: connect to server failed
    == Spawn extension (users, 3000, 2) exited non-zero on ‘SIP/alex-00000007’

    ¿Alguien sabe que estoy obviando/haciendo mal? gracias por adelantado!!!

  11. parece que no copie bien el scritp de php, aqui lo mando de nuevo:

    #!/usr/bin/php -q
    verbose($retString);
    ?>

    perdón por la confusión!

  12. jajajajaja no se publica bien el texto, bueno es igual al del autor, pero con las modificaciones de Edu. Gracias!

  13. asterisk-tts.php,: Failed to execute ‘/var/lib/asterisk/agi-bin/asterisk-tts.php’: Permission denied
    Tiene pinta que el script no tiene permisos de ejecución
    sudo chmod +x /var/lib/asterisk/agi-bin/asterisk-tts.php
    También te aconsejo que mires el log de apache php y tambien prueubes a ejecutar el script directamente desde shell para ver si te reporta errores de parseo que asterisk no reporta

Leave a Reply

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *