Novax · Bot de ventas con IA
Bot de Inversiones Novax portado de n8n a Python por otro integrante del equipo: atiende por uChat, junta los mensajes en un buffer de Redis, consulta el catálogo en pgvector y, en WhatsApp, responde fuera del horario de los asesores. Mi trabajo fue sobre ese bot en producción. Porté a código el reporte de conversaciones por anuncio que vivía en n8n y lo extendí con una pestaña por mes de campañas y una comparativa semanal. Construí el reparto de chats entre asesores para que cada vendedor tenga una meta diaria medible, y una herramienta para limpiar la bandeja de uChat sin agotar el cupo de API que comparte con el bot. También mantuve los prompts del agente y el formato de las fichas de producto.
La Sheet mezclaba semanas
El flujo de n8n actualizaba solo la columna de hoy por anuncio y nunca limpiaba: el martes seguía mostrando los números del martes anterior. Además la atribución de Meta es de 7 días, así que los días pasados siguen cambiando, y la última corrida del día perdía la última hora. Solución: cada corrida reescribe las pestañas enteras y pide todos los días de la ventana; la pestaña del mes que cerró se sigue reescribiendo hasta el día 7 y después queda fija.
Campañas que siempre daban cero
Las campañas de interacción en publicaciones, como un concurso, no abren conversaciones, así que con la métrica de mensajes salían siempre en 0. Solución: detectarlas por los datos —objetivo de interacción y ninguna conversación iniciada registrada— y contarles interacciones con la publicación en su lugar, marcadas con un sufijo para que no se confundan con conversaciones.
Dos chats a la vez, el mismo asesor
Sin coordinación, dos chats que entran en el mismo instante leen el mismo conteo y caen en el mismo asesor, y tres mensajes seguidos de un cliente —tres webhooks— lo asignarían tres veces. Solución: la elección corre dentro de una transacción con pg_advisory_xact_lock, con una clave de texto para no chocar con los otros bots que comparten el mismo Supabase.
Reparto que sobrevive a un redeploy
La regla es el asesor que menos chats recibió hoy, desempatando por orden de la lista, en vez de un round robin con puntero que se pierde en cada redeploy. Se reparten chats, no mensajes; un cliente que vuelve dentro de la ventana sigue con el mismo asesor, y un chat que ya tiene asesor en uChat se respeta. Para no consultar uChat en cada mensaje, primero se mira la tabla propia.
Limpieza segura por defecto
El script de limpieza de bandeja no cambia nada por defecto: lista los candidatos en un CSV para que el cliente lo apruebe y solo cierra con --aplicar. No cierra chats cuyo último mensaje es del cliente, y respeta el cupo de 1000 pedidos por hora que comparte con el bot con una pausa entre cierres y un tope por corrida.
Un cron que no tumba el servicio
El reporte corre en un loop que nunca propaga errores: falla, registra y reintenta con backoff exponencial de 5 a 60 minutos. Tiene un piso de 10 minutos entre corridas para no agotar el rate limit del token de Meta, y expone su último éxito y error en /admin/estado, porque un token vencido congelaría la Sheet sin aviso.