Ejemplos útiles¶
List y Dicts¶
Iterar en una lista¶
COmo podrías haber visto, en botlang no existe el operador for o while por lo que necesitaremos mapear en una lista.
Este map
tiene dos parámetros: una función (fun (item) (fun1))
donde item es un elemento de la lista y fun1 lo
que haremos con este elemento; y la lista sobre la que iteraremos.
1 2 3 4 5 | (map [fun (item) (+ item 1)] (list 1 2 3) ) >> (list 2 3 4) |
Encontrar un dict en una lista de diccionarios, a partir del valor de una llave¶
Suena complicado pero es bastante util, especialmente cuando estamos trabajando con estructuras JSON para los datos. Asi que, para este ejemplo tenemos la siguiente lista de opciones:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | { "label": "Servicios Residenciales", "payload": "multimedia", "type": "terminal" }, { "label": "Servicios móviles", "payload": "movil", "type": "terminal" }, { "label": "Interesado en contrarar o renovar", "payload": "ventas", "type": "terminal" } |
Entonces, tenemos una lista con tres diccionarios y deseamos encontrar aquel cuyo valor de su llave payload sea igual a 'ventas', veamos como hacer esto:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | (define find-by-payload-value [fun () ; imaginemos que options tiene la estuctura ; de opciones que vimos arriba [define options the-upper-structure] [define found (make-dict)] ; iniciar un diccionario vacío (map (fun (option) (cond [(equal? "ventas" (get option "payload")) (put! found "found-option" option) ; cuando el diccionario es encontrado, ; lo agregamos al diccionario vacío como ; el valor de la llava 'found-option' ] ) ) options ) ; ahora entregame el diccionario encontado o nil si no estaba (get-or-nil context "found-option") ] ) |
BotNode¶
Ahora, como integramos todo lo que hemos visto: listas, funciones, OOP y bot-nodes? Yo tampoco lo sabía en su momento así que aquí van algunas ayudas.
Transición entre nodos¶
Imaginemos que necesitamos dos interacciones diferentes en nuestro bot: primero, aquel que inicia todo en respuesta de cualquier cosa que mande el usuario (guardado en 'message'), dandole una lista de botones para elegir algo; una vez el usuario elija, necesiaremos el segundo nodo para manejar la respuesta dependiendo de lo elegido.
Si el caso no quedó muy claro espero que el siguiente código lo explique mejor:
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 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 | ;;;;;;;;;;;;;;; parte del JSON de contexto ;;;;;;;;;;; { "current-tree": { "header": "Qué opción?", "options": [ { "label": "Opcion 1", "payload": "opc1" }, { "label": "Opcion 2", "payload": "opc2" } ] }, "selected-option":nil, "skill":nil, ... } ;;;;;;;;;;;;;;; fin del JSON de contexto ;;;;;;;;;;;;; (define first-node (bot-node (context message) ; agregamos las opciones a la variable ; de contexto 'current-options' (put! context "current-options" options) ; ahora, node-result tiene tres parámentros: ; contexto, mensaje y próximo nodo (node-result context ; q-reply entrega la estructura quick-reply con las opciones (list (q-reply context)) ; y una vez que el usuario interactua con la butonera, ; manda un mensaje al siguiente nodo second-node ) ) ) (define reply-node (bot-node (context message) ; primero llamamos a 'find-by-payload' que nos entregará ; el diccionario de la opción, con las llaves: label y payload; ; que coincida con el payload de la opción elegida, ; o nil si no la encontró [define option (find-by-payload context message)] (cond [(nil? option) ; si el payload no era válido reiterará y ; enviará denuevo la butonera (node-result context (list (q-reply context)) reply-node ) ] [else (begin ; guardamos la opción elegida y su 'label' en el contexto (put! context "selected-option" option) (put! context "skill" (get-or-nil context "selected-option.label") ) [node-result context ; modificamos el 'end_message' del contexto (translate context (get context "menu.end_message")) ; y enviamos el valor de 'payload' al terminal, ; y cerramos el bot (terminal-node message) ] ) ] ) ) ) first-node ; este nodo se ajecutará primero |
translate¶
En el ejemplo anterior vimos la función translate, pero qué hace? Es un truco muy útil que explicaremos con el siguiente ejemplo:
1 2 3 4 5 6 7 8 9 10 11 12 13 | ;;;;;;;;;;;;;;; JSON de contexto ;;;;;;;;;;;;;;;;;;;; { "end-message":"You choose the option {{skill}}", "skill":"", "nodes-visited":{...}, "user": {...}, ... } ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (put! context "skill" "potato") (translate context (get context "end-message")) ; ahora el 'end-message' dice 'You choose the option potato' |
Ahora, para explicarlo mejor, en 'end-message' hay una referencia a variable en {{skill}}
,
esta variable 'skill' debe estar en el contexto; y translate buscará la variable 'skill' y luego
en 'end-message' reemplazará la referencia con su valor.
Agregar botoneras al chat¶
Hagamos una lista de botones que, una ves se aprete un botón, se borrará de la pantalla. Útil, cierto?
Este tipo de botoneras se llama quick-reply
y iene tres parámetros: el infltable contexto, un string
con el header (la pregunta) y la lista con botones.
Ahora en el siguiente código veremos dos funciones: una para crear el elemento quick-reply
y otro para
obtener las opciones desde el contexto.
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 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | (define q-reply [fun (context) ; obtenemos las opciones del contexto, ; desde el 'current-tree' [define options (get context "current-tree.options")] (quick-reply context "Choose an option" (get_options context options) ) ] ) ; Recordemos que las opciones son una lista de diccionarios ; con las llaves: label y payload (define get_options (fun (context options) [define btns (map (fun (option) ; get a single dictionary (text-button context ; el texto visible en el botón (get option "label") ; el mensage que se enviará al bot-node si la opción ; es elegida (get option "payload") ) ) options ; la lista de diccionarios de opciones ) ] btns ; lista de (text-button context label payload) ) ) ; ahora el bot (define first-node (bot-node (context message) (node-result context (list (q-reply context)) second-node ) ) ) first-node |
Respuestas mútliples¶
translate
nos ayudará a hacer otro truco! Usar el módulo
en 'Plantillas > Texto', pero ¿Qué hace?
Bueno, digamos que queremos un bot que salude a los usuarios cada vez que ellos inicien una conversación, pero decir 'hola' todas estas veces se vuelve aburrido y hasta molesto, cierto? Por esto queremos que salude diferente la mayoria de las veces como: 'hi', hello', 'sup!', 'good day to you', 'may the force be with you, today' o 'join the dark side'.
Aquí es cuando 'Texto' viene a salvar a nuestro bot, como podrán ver más abajo hay una variable 'ID' que identificará a nuestro texto, y los posibles textos, que cuando lo llamemos elegirá uno de manera aleatoria.
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 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | ;;;;;;;;;;;;;;;;;; Textos's variables ;;;;;;;;;;;;;;;;;;;;;;;;; ID: "salute" Textos: 'hi', 'hello', 'sup!', 'good day to you', 'may the force be with you, today', 'join the dark side' ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; [define salute-bot (bot-node (context message) (node-result context "salute" end-node ) )] salute-bot ;;En el chat hello << >> good day to you ENDBOT hi << >> hello ENDBOT ; Otro ejemplo útil es cuando los textos de 'Textos' ; tienen variables para el translate ;;;;;;;;;;;;;;;;;; Textos's variables ;;;;;;;;;;;;;;;;;;;;;;;;; ID: "to_translate" Textos: 'Some text and {{var}}','Just the {{var}}' ;;;;;;;;;;;;;;;;;;;;;;; JSON context ;;;;;;;;;;;;;;;;;;;;;;;;;; { ... "var":"texto", ... } ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; [define other-bot (bot-node (context message) (node-result context (translate context "to_translate") end-node ) )] other-bot ;;En el chat hello << >> Just the texto ENDBOT |