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.

6 comentarios en «Un AGI Legendario: Publicacion en Twitter mediante ASR»

  1. Inicie con el desarrollo pero al tratar de convertir con sox, me dice que el formato flac no es soportado, me puedes indicar como proceder?

    Saludos

  2. Buenas, estoy configurando una centralita con Asterisk 11.15.0,utilizo Elastix 2.4.0, tarjeta a configurar una Wildcard AEX410 de Digium (2 puertos FXS y 2 FXO).
    Después de probar y reprobar lo que me dicen en el manual de la tarjeta, lo que me dicen en foros y perder más el tiempo os lo comento a ver si me podéis dar algo de luz y hacer que suene el teléfono…
    Actualmente al detectar Hardware consigo que de tono pero al cabo de unos segundos se corta y no se porqueee!!
    Cuando llamo hacia la centralita me sale la locución de la operadora “numero fuera de servicio, inténtelo de nuevo”. Porqueee!!!
    Empiezo a pensar que sea de la línea de Jazztell, que deba de instalarse de otra forma por ser centralita.
    Os mando mis archivos a ver si podéis detectar por qué no entran ni salen las llamadas, Muchas gracias de antemano por vuestra paciencia que sé que esto es una locura.
    ———————————————————————————————————-
    dahdi-channels.conf
    ; Span 1: WCTDM/0 «Wildcard AEX410″
    ;;; line=»1 WCTDM/0/0 FXSKS»
    signalling=fxs_ks
    callerid=asreceived
    group=0
    context=from-pstn
    channel => 1
    callerid=
    group=
    context=default

    ;;; line=»2 WCTDM/0/1 FXSKS»
    signalling=fxs_ks
    callerid=asreceived
    group=0
    context=from-pstn
    channel => 2
    callerid=
    group=
    context=default

    ;;; line=»3 WCTDM/0/2 FXOKS»
    signalling=fxo_ks
    callerid=»Channel 3″
    mailbox=4003
    group=5
    context=from-internal
    channel => 3
    callerid=
    mailbox=
    group=
    context=default

    ;;; line=»4 WCTDM/0/3 FXOKS»
    signalling=fxo_ks
    callerid=»Channel 4″
    mailbox=4004
    group=5
    context=from-internal
    channel => 4
    callerid=
    mailbox=
    group=
    context=default
    —————————————————————————————————————————–

    chan_dahdi.conf
    [trunkgroups]
    [channels]
    context=from-pstn
    signalling=fxs_ks
    rxwink=300 ; Atlas seems to use long (250ms) winks
    usecallerid=yes
    hidecallerid=no
    callwaiting=yes
    usecallingpres=yes
    callwaitingcallerid=yes
    threewaycalling=yes
    transfer=yes
    canpark=yes
    cancallforward=yes
    callreturn=yes
    echocancel=yes
    echocancelwhenbridged=no
    faxdetect=incoming
    echotraining=800
    rxgain=2.0
    txgain=3.0
    callgroup=1
    pickupgroup=1
    relaxdtmf=yes

    ;Uncomment these lines if you have problems with the disconection of your analog lines
    busydetect=yes
    busycount=6
    busypattern=425,425
    cidsignalling=v23
    cidstart=ring
    ringtimeout=8000
    #include dahdi-channels.conf
    #include chan_dahdi_additional.conf
    indications.conf
    [general]
    country=es
    [es]
    description = Spain
    ringcadence = 1500,3000
    dial = 425
    busy = 425/200,0/200
    ring = 425/1500,0/3000
    congestion = 425/200,0/200,425/200,0/200,425/200,0/600
    callwaiting = 425/175,0/175,425/175,0/3500
    dialrecall = !425/200,!0/200,!425/200,!0/200,!425/200,!0/200,425
    record = 1400/500,0/15000
    info = 950/330,0/1000
    dialout = 500
    extensions.conf
    [from-internal]
    include => interno
    ;include => from-internal-noxfer
    ;include => from-internal-xfer
    ;include => bad-number ; auto-generated
    [interno]
    exten => 4004,1,NoOp()
    exten => 4004,n,Answer
    exten => 4004,n,Dial(DAHDI/4)
    exten => 4004,n,Hangup
    Si necesitais más info os la mando, Un saludo

  3. Hola David
    Esto no es un foro para resolver dudas.
    No tiene nada que ver tu pregunta con el articulo original
    Te recomiendo que entres en las listas de asterisk en español asterisk-es para una duda tan particular como esta

Deja un comentario

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.