lunes, 26 de julio de 2010

Delivery, un enfoque informático

Yo personalmente uso mucho el delivery de comidas de cierto conocido local comercial que no vale la pena mencionar. El problema con esto es que después de convertirte en un cliente frecuente que llama siempre a pedir lo mismo o que si cambia sus gustos sabe bien que pedir, que te atienda la operadora con ese infernal ruido, te pregunte tu número de teléfono (what, again?!) y te haga repetir mil veces lo que pediste se vuelve algo tedioso y con consecuencias nerviosas difíciles de ocultar.

Que tal si te atiende un operador inteligente que te liste los menús mas comunes y te pase con la operadora ruidosa solo cuando lo que escuchaste no esta ahí (poco probable) ?. Bueno, a mi me encanta la idea.

¿Cómo solucionamos esto?

La verdad que es un poco complicado pero básicamente necesitamos lo siguiente:
  1. Una entrada de línea telefónica a través de un media gateway que nos haga de pasarela entre la red celular (GSM) y/o fija (PSTN).
  2. Un PBX, pero no cualquier PBX, tiene que ser un IPPBX porque queremos poder programarlo y no gastar ni un guaraní en adquirirlo e instalarlo. Para esto tenemos varias opciones pero mi favorita es Asterisk .
  3. Las voces del IVR . Son las grabaciones que se reproducirán cuando alguien llame e interactúe con la central.Enlace
  4. Nuestro cerebro e Internet para programar el dialplan que básicamente, es lo más dificil en todo esto.
Necesitamos saber quién es el cliente que llama, para esto tenemos su caller-id. Con ese dato podemos ir a tratar de identificarlo en una base de datos (MySQL en mi caso) buscando su nombre y dirección particular. Si no lo encontramos, lo derivamos directamente con la operadora para que le tome sus datos y lo dé de alta en el sistema, cosa que se hace siempre cuando llamas por primera vez.

Si el cliente ya está registrado, le reproducimos el menú estadísticamente más pedido o todo el menú si quieren (no es buena idea). Por ejemplo:
  • Llamo y me atiende una IVR deciéndome: "Bienvenido al bar X" y me reproduce el menú.
  • "Presione 1 para pizzas, 2 para lomitos, 3 para bebidas, 0 (cero) para hablar con un operador".
  • Me gustaría comer pizza y presiono 1 reproduciéndome...
  • "Presione 1 para napolitana, 2 para cuatro quesos, 3 para muzarela, 4 para peperoni."
  • Me gusta la de 4 quesos y presiono 2 y me reproduce...
  • "Seleccione la cantidad que desea"
  • Bueno, estoy con algunas personas y quiero tres, entonces aprieto 3...
  • "Usted ha pedido 3 pizzas de cuatro quesos, el precio total es, 90 mil guaraníes, presione 1 para confirmar, 2 para cambiar el pedido, 3 para salir"
  • Quiero confirmar, presiono 1...
  • "Su pedido ha sido procesado con éxito, adiós", y termina la transacción. Opcionalmente, recibís un SMS que te confirma que tu pedido fue atendido y otro mensaje cuando se encuentra en tránsito, es decir, cuando el delivery guy se está yendo a tu casa en su moto.
Cuando llega un nuevo pedido se levanta un ticket o alerta que la cajera o algún encargado puede ver en su pantalla y éste se procesa como cualquier otro pedido hecho físicamente en la caja.

¿Cuánto tiempo tardé en pedir?

Escuchar toda la grabación me tomó 30 segundos o menos, tiempo decente pero, cuando me sepa de memoria el menú, al llamar puedo presionar 123 (1 + 2 + 3) de seguido y lo siguiente que escucharé será: "Usted ha pedido 3 pizzas de cuatro quesos, el precio total es, 90 mil guaraníes, presione 1 para confirmar, 2 para cambiar el pedido, 3 para salir", entonces, presiono 1 y listo. Cuánto tardé?, menos de 10 segundos.

Como había dicho, lo más difícil de programar fue el dialplan. Tenía 4 opciones para esto, usar el seudolenguaje de programación de extensiones (no!!!), AEL (tampoco, pero lo usé solo para algunas operaciones de muy bajo nivel), AGI (mucho mejor, pero no) y FastAGI, el ganador.

Por qué fastAGI? porque utiliza sockets sobre IP lo que me permite manejar la carga en una suerte de computación distribuida, mucho mas escalable y encima elegante.

Hay demasiadas cosas por explicar sobre cómo funciona Asterisk y fastAGI. tal vez en otra ocasión me siente a hacer un ensayo, pero por ahora les dejo un snippet esencial para el manejo de pedidos, hecho en C#, para que se den una idea.


public override void Service(AGIRequest param1, AGIChannel param2)
{
try
{
Answer();
StreamFile("pizza/bienvenidos");
if (!IsClientRegistered(param1.CallerId))
{
Console.WriteLine("CallerID {0} is not registered, transferring to operator.", param1.CallerId);
StreamFile("pizza/numero_desconocido");
SetVariable("GO_TO_OPERATOR", "yes");
AddCustomer(param1.CallerId);
return;
}

SetVariable("GO_TO_OPERATOR", "no");

if (CustomerHasPendingOrders(param1.CallerId))
{
StreamOrderStatus();
if (Ask("13", "pizza/1_nuevaorden_3_salir") == ConfirmationRequest.Exit)
throw new Exception("User exited transaction");
}

MenuLevel menu;
PhoneKey pressedKey = '\0';
ConfirmationRequest confimation;
List customerChoice = new List();
bool makeMoreOrders = false;
ulong total = 0;
/*
* Say menu options
*/
while(true)
{
menu = _rootMenu;
makeMoreOrders = false;
while(true)
{
pressedKey = StreamMenu(menu);

if (menu.IsRoot && pressedKey.IsGoToOperator)
{
SetVariable("GO_TO_OPERATOR", "yes");
return;
}

if (!menu.IsRoot && pressedKey.IsGoBack)
{
menu = menu.Parent;
continue;
}

if (!menu.HasSubLevels)
{
MenuOption option = menu[pressedKey];
int quantity = AskForQuantity();

StreamCustomerOrder(option, quantity);

confimation = Ask("123", "pizza/1_confirmar_2_ordenar_3_salir");

if (confimation == ConfirmationRequest.Exit)
throw new Exception("User canceled the transaction");
else if(confimation == ConfirmationRequest.OrderMore)
makeMoreOrders = true;

customerChoice.Add(new SelectedProduct(menu[pressedKey], quantity));
total += option.Price * (ulong) quantity;

break;
}

menu = menu.GetSubMenu(pressedKey);
}

if (makeMoreOrders)
continue;

StreamFile("pizza/costo_total");
SayNumber(total.ToString());
StreamFile("pizza/guaranies");

if (Ask("13", "pizza/1_confirmar_3_salir") == ConfirmationRequest.Exit)
throw new Exception("User canceled transaction in the last minute");

foreach(SelectedProduct selection in customerChoice)
AddOrder(param1.CallerId, selection.SelectedOption.ProductID, selection.Quantity, selection.TotalPrice);

StreamFile("pizza/pedido_procesado_adios");

break;
}
}
catch(Exception ex)
{
Console.WriteLine("PizzaIVR.Service(): {0}", ex.Message);

}

Hangup();
}

Chequeo de pagos, en detalle

En mi post anterior hablé sobre un producto de automatización de chequeo de pagos. Ahora pretendo profundizar un poco más sobre el flujo de datos que se sigue cuando un cobrador llama.

El gráfico da una idea visual de lo que hablo y lo hice tratando de simplificar un diagrama de flujo real que muchas veces resulta inentendible para el que no sabe como leerlo.


  1. Cuando el cobrador llama la central telefónica lo atiende (sin molestar a la secretaria) y dependiendo de si reconoce o no su CID (número desde donde llama) le reproduce un audio que dice: "introduzca su código de usuario" y luego "introduzca su pin". Si el CID es reconocido, entonces directamente le reproduce la segunda grabación.
  2. El cobrador usa el teclado de su teléfono para realizar el proceso de autenticación (digitar usuario y pin) y si el proceso resulta exitoso se salta al siguiente paso, sino, con tres intentos fallidos la central corta la comunicación y registra lo sucedido.
  3. El cobrador autenticado escucha la grabación que le cuenta cuántos pagos tiene disponible, si no tiene ninguno, le reproduce una grabación que le dice esto y la transacción es finalizada por la central.
  4. Si el cobrador cuenta con uno o más pagos disponibles, tiene la opción de escuchar un detalle de los mismos, el monto o cualquier otra información que quiera agregarle.
  5. La central finaliza la transacción y registra la llamada.
Esto es, en lineas generales, lo que sucede internamente cuando el sistema recibe un llamada.

El futuros posts, voy a hablar de la tecnología usada para hacer esto posible.

Tu secretaria está cansada de atender a los cobradores

Las secretarias tienen mucho trabajo que hacer. Además de atender permanentemente el teléfono tienen que estar cumpliendo con otras funciones mas elaboradas como hacer planillas y presentar informes. No sería bueno sacarle un poco de carga y automatizar ciertas funciones que te hagan quedar bien con tus clientes/proveedores y con tu secretaria?, seguramente sí.

Les presento otro de mis proyectos. Esta vez se trata de un sistema de chequeo de pagos disponibles por vía telefónica pero a través de un IVR, totalmente automático. Si tenes varios proveedores que llaman con cierta frecuencia a preguntar sobre cheques o pagos disponibles cada fin de mes o por semana, seguramente tu secretaria esta cansada de responder con "si hay un cheque para usted", "aún no se habilitó el pago" o peor todavía, "espere un momento que me fijo" empezando a buscar entre las decenas de cheques o en una planilla Excel que le toma 30 segundos encontrar y abrir manteniendo al llamador on hold, la linea ocupada y perdiendo clientes.


Cómo funciona



  • En tu empresa, se habilita un acceso telefónico. Puede ser un número de teléfono celular o de línea fija.
  • En una base de datos y a través de una interfaz web o de escritorio, se dan de alta los cobradores, esto es, su nombre o descripción, el número de teléfono desde el cual suelen llamar, su pin (contraseña numérica corta) y cualquier otra información que consideren relevante. Esta carga se hace una sola vez por cada proveedor.
  • Se entrega al cobrador de tu proveedor su código (número de 4 dígitos o menos), su pin y el número de teléfono a donde tienen que llamar para consultar si tiene pagos disponibles y...
  • Cada vez que hay un pago para cierto proveedor, la secretaria actualiza la base de datos con solamente 2 clicks en la interfaz web y listo!.
Con estos pasos tenés un sistema de chequeo de pagos muy elegante y fácil de usar que además facilita la vida de ambas partes, la de la secretaria y la del cobrador.

En mi próxima entrada estaré explicando el flujo que se sigue cuando el cobrador llama.

Elecciones municipales 2010 y una herramienta útil

Es bien sabido por nosotros los paraguayos que nuestro sistema electoral no es el mejor y mucho menos el más moderno.

Muchas veces no tenemos las ganas suficientes para levantarnos un domingo para ir a un lugar desordenado, ruidoso y caótico como son los centros de votación, es perfectamente comprensible eso.

Otro problema muy común en ciudades grandes es saber dónde ir a votar, en qué mesa. Yo estoy fanatizado por saber de antemano qué hacer y evitar la aleatoriedad de la situación que siempre se presta a causar una gran pérdida de tiempo y es por esto que tomé parte de mi tiempo libre en experimentar y desarrollar algo que pretende ser útil, por lo menos mínimamente.

Bueno, como arreglar el tema del desorden en los centros de votación escapa completamente de mis manos, decidí tratar de arreglar el problema de saber en dónde votar y para éste fin desarrollé un sistema basado en SMS (mensajes de texto) de la red GSM que te informa la dirección de tu centro de votación y el número mesa de acuerdo a tu número de Cédula de Identidad enviado por SMS.




El gráfico de arriba muestra que su funcionamiento es bastante sencillo. Por ejemplo, si yo usuario quiero saber dónde ir a votar el día de las elecciones lo único que tengo que hacer es:
  • Envío un mensaje de texto (que cuesta Gs. 65!) con mi número de CI a cierto número, por ejemplo 1234 o 09xx 112233
  • Recibo una respuesta en menos de 30 segundos con mi nombre y apellido, municipio, la dirección donde debo ir a votar y el número de mesa
Entonces, con información en mano, me voy directo donde debería y me ahorro todos los problemas que cité anteriormente y además, contribuyo al orden porque no tengo que andar dando vueltas preguntando y formando filas que no me corresponden.

La tecnología detrás de esta implementación es bastante amplia. A continuación cito las principales involucradas:
  • GSM gateway con un chip de una operadora local
  • SIP Server
  • Linux
  • Aplicación C# corriendo sobre Mono
  • Base de datos MySQL
  • Varias otras herramientas de desarrollo
Si están familiarizados con las herramientas que usé, se darán cuenta que son libres, es decir, no uso Windows, no uso Oracle o SQL Server y uso C# pero no sobre Microsoft CLI (.NET), sino sobre Mono y no usando Visual Studio, sino monodevelop.

Lo que quiero rescatar con esto es que la solución es muy barata y si fuera por mi, publicaría el número para que la gente empiece a utilizarlo pero como no tengo suficientes recursos (saldo) y me autofinancio mis proyectos, necesitaría más bien un esponsor que me ayude a mejorar el mundo :) .

La tecnología está disponible y nos da facilidades. En nuestro país hay muchos talentos, conozco gente brillante que necesita la oportunidad para surgir. Así como podemos sacar buenos jugadores de fútbol, también podemos sacar excelentes ingenieros, pero repito, necesitamos la oportunidad.

En futuras entradas estaré publicando más información sobre el funcionamiento interno, el diseño y el core en general.

Aprovecho también para agradecer a un amigo mío que solucionó una serie de problemas relacionados a la plataforma y por ende, me ayudó a terminar esto.