Skip to content

Métodos

Sistema de Alarmas

El sistema de alarmas de BotCenter permite programar la ejecución diferida de nodos del bot en un momento específico en el futuro. Este sistema está diseñado para casos de uso como recordatorios, timeouts, seguimientos automáticos, y cualquier funcionalidad que requiera ejecutar acciones después de un período determinado.

Arquitectura del Sistema

El sistema de alarmas utiliza una arquitectura distribuida basada en AWS SQS (Simple Queue Service) para garantizar la confiabilidad y escalabilidad:

  1. Programación de Alarmas: Cuando se ejecuta set-alarm, se envía un mensaje a una cola SQS de AWS
  2. Procesamiento Externo: Un servicio externo procesa los mensajes programados en la fecha/hora especificada
  3. Activación: Cuando llega el momento, se realiza una llamada HTTP POST al endpoint /api/v2/bot/trigger_node
  4. Ejecución: El nodo especificado se ejecuta con el contexto original preservado

Componentes Técnicos

  • AlarmScheduler: Maneja la comunicación con AWS SQS
  • AlarmsHandler: Gestiona la configuración y programación de alarmas
  • ApiV2TriggerNode: Endpoint que recibe y procesa las alarmas activadas
  • Cola SQS: actions-to-schedule (configurable por ambiente)

set-alarm

Esta función programa la ejecución de un bot-node después de un tiempo específico. set-alarm tiene cuatro parámetros:

  1. context: El contexto actual del bot (requerido)
  2. function_name: El nombre del bot-node que se ejecutará (requerido)
  3. alarm_due_time: Fecha y hora de ejecución en formato %Y-%m-%dT%H:%M:%S (año, mes, día, hora, minuto, segundo)
  4. alarm_key: Identificador único de la alarma para propósitos de logging y tracking

Ejemplo Básico

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
#!scheme

(bot my-alarm (context message)
    (node-result context "¡Alarma activada!" end-node)
)

(bot-node (context message)
    (define alarm-set 
        (set-alarm 
            context
            "my-alarm"
            (time-to-string (time-now) "%Y-%m-%dT%H:%M:%S")
            "ALARM_KEY"
        )
    )
    (node-result
        context
        (if alarm-set "Alarma activada" "Alarma no activada")
        end-node
    )
)

Ejemplo con Delay

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#!scheme

(bot reminder-node (context message)
    (node-result context "¡Recordatorio! No olvides completar tu tarea." end-node)
)

(bot-node (context message)
    ; Programar alarma para 1 hora después
    (define future-time 
        (time-add (time-now) 
                  (time-from-seconds 3600))) ; 3600 segundos = 1 hora

    (define alarm-scheduled
        (set-alarm 
            context
            "reminder-node"
            (time-to-string future-time "%Y-%m-%dT%H:%M:%S")
            "REMINDER_1H"
        )
    )

    (node-result
        context
        (if alarm-scheduled 
            "Te recordaré en 1 hora" 
            "No se pudo programar el recordatorio")
        end-node
    )
)

Casos de Uso Comunes

  1. Recordatorios: Enviar mensajes de seguimiento después de un período específico
  2. Timeouts: Manejar sesiones que han estado inactivas por mucho tiempo
  3. Seguimientos: Contactar usuarios después de completar una acción
  4. Escalación: Transferir conversaciones no resueltas después de un tiempo límite

Requisitos y Limitaciones

Requisitos

  • Datos del Usuario: La alarma solo se programa si el contexto contiene información válida del usuario (canal, ID de usuario)
  • Bot Desplegado: Las alarmas funcionan tanto en desarrollo como en producción
  • Conectividad: Requiere acceso a AWS SQS y conectividad HTTP para la activación

Limitaciones

  • Precisión Temporal: La precisión depende del servicio externo que procesa la cola SQS
  • Contexto Estático: El contexto se preserva tal como estaba al momento de programar la alarma
  • Sin Cancelación: No existe funcionalidad nativa para cancelar alarmas una vez programadas

¿Se Puede Cancelar una Alarma?

Respuesta: No, actualmente no existe funcionalidad para cancelar alarmas.

El sistema actual no proporciona: - Función cancel-alarm - Función remove-alarm - Función delete-alarm - Ningún mecanismo para cancelar alarmas programadas

Una vez que se ejecuta set-alarm exitosamente, la alarma quedará programada y se ejecutará en el momento especificado. Esto es una limitación del diseño actual del sistema.

Posibles Alternativas

Si necesitas funcionalidad similar a cancelación de alarmas, puedes:

  1. Validación en el Nodo de Alarma: Verificar condiciones en el nodo que se ejecuta cuando se activa la alarma
  2. Estados en Contexto: Usar variables de contexto para determinar si la acción de la alarma debe ejecutarse
  3. Logging: Usar alarm_key para identificar y rastrear alarmas específicas en los logs
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
#!scheme

(bot cancellable-alarm (context message)
    ; Verificar si la alarma debe ejecutarse
    (define should-execute (get-or-nil context "alarm_active"))

    (node-result 
        context 
        (if should-execute 
            "Ejecutando alarma programada"
            "Alarma cancelada - no se ejecuta")
        end-node
    )
)

Configuración Técnica

Variables de Entorno

1
2
3
4
AWS_SCHEDULED_ACTIONS_KEY=your_aws_access_key
AWS_SCHEDULED_ACTIONS_SECRET=your_aws_secret_key
ACTIONS_TO_SCHEDULE=actions-to-schedule_prod  # Nombre de la cola SQS
BOTCENTER_URL=https://api.botcenter.io  # URL base para callbacks

Estructura del Mensaje SQS

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
{
    "due_date": "2024-01-15T10:30:00",
    "action_data": {
        "action_type": "HTTP_REQUEST",
        "subject": "whatsapp_56976591991",
        "alarm_key": "REMINDER_KEY",
        "payload": {
            "url": "https://api.botcenter.io/api/v2/bot/trigger_node",
            "method": "POST",
            "headers": {
                "ApiKey": "bot_access_token",
                "Content-Type": "application/json"
            },
            "body": {
                "channel": "whatsapp",
                "account_id": "bot_id",
                "user_id": "56976591991",
                "node": "my-alarm",
                "message": "ALARM",
                "context": {...},
                "store_message": true
            }
        }
    }
}

Debugging y Monitoreo

  • Logs: Buscar por alarm_key en los logs del sistema
  • Subject: El campo subject combina el canal y user_id para identificación única
  • Contexto: El contexto original se preserva completamente en la activación

translate

Esta función nos permite reemplazar un substring por el valor de una valiable del contexto, entregándo el resultado. translate tiene dos parámetros: el contexxto y el string que será modificado, éste último debe tener el siguiente formato: 'Algún texto y la {{VARIEBLE-DE-CONTEXTO}}' donde el texto entre llaves es el nombre de la variable en contexto.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
#!scheme

;;;;;;;;;;;;;;;; Contexto ;;;;;;;;;;;;;;;;
'string': 'texto',
'float': 3.14,
'int': 3,
'list': ['1', '2', 3],
'single': ['1'],
'STRING_ENTRY': ['Aquí debería haber un {{string}}'],
'NUMBERS_ENTRY': ['Pi es {{float}} aproximadamente y su unidad es {{int}}'],
'LIST_ENTRY': ['Tenemos la lista con tres elementos: {{list}} y empieza con {{single}}']
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(translate context STRING_ENTRY)
>> 'Aquí debería haber un texto'

(translate context NUMBERS_ENTRY)
>> 'Pi es 3.14 aproximadamente y su unidad es 3'

(translate context LIST_ENTRY)
>> 'Tenemos la lista con tres elementos: 1, 2, 3 y empieza con 1'

answer-for-intent

Esta función te entrega una respuesta a una 'Intención' para que funcione, necesitamos entregarle el contexto y el identificador de la intención. Así, una vez hemos definido la relación Pregunta y Respuesta, cuando llamemos esta función recibiremos una de las posibles respuestas para esa intención.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#!scheme

;;;;;;;;;;;;;;;;;; Textos ;;;;;;;;;;;;;;;;;;;;;
'WELCOME': ['¡Hola {{first-name}}! ¿en qué puedo ayudarte?']
'WAIT': ['Ok. Espera un momento.']
;;;;;;;;;;;;;;;;;;; Intenciones ;;;;;;;;;;;;;;;;
'INTENT_1', 'INTENT_2'
;;;;;;;;;; Preguntas y Respuestas ;;;;;;;;;;;;;;
{ identifier:'INTENT_1', texts:'WELCOME' }
{ identifier:'INTENT_2', texts:'WAIT' }
;;;;;;;;;;;;;;;;;;; Contexto ;;;;;;;;;;;;;;;;;;;;
'first-name': 'Sergio'
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(bot-node (data)
    (node-result
        data
        (answer-for-intent data "INTENT_1")
        end-node
    )
)
>> '¡Hola Sergio! ¿en qué puedo ayudarte?'

(bot-node (data)
    (node-result
        data
        (answer-for-intent data "INTENT_2")
        end-node
    )
)
>> 'Ok. Espera un momento.'

string-find-similar

string-find-similar requiere dos parametros: la palabra que usaremos para buscar como string y una lista de strings con las opciones de palabras a encontrar. Esta función retornará la palabra de la lista que sea más similar a la palabra buscada, de no encontrar algo lo suficientemente similar en la lista retornará vacío (nil)

1
2
3
4
5
6
7
8
9
#!scheme

[define lista (list "Telefonía móvil" "Telefonía fija" "Servicio de internet")]

(string-find-similar "movil" lista)
>> "Telefonía móvil"

(string-find-similar "potato" lista)
>> nil