Modificación de un diálogo utilizando la API
La API REST da soporte a la modificación del diálogo mediante programación. Puede utilizar la API de /dialog_nodes para crear, suprimir o modificar nodos de diálogo.
Un diálogo es un árbol de nodos interconectados, y que debe ajustarse a determinadas reglas para ser válido. Cualquier cambio que realice en un nodo de diálogo puede tener efectos en cascada en otros nodos o en la estructura del diálogo. Antes
de utilizar la API de /dialog_nodes para modificar el diálogo, asegúrese de que comprende cómo afectan los cambios al resto del diálogo. Puede realizar una copia de seguridad del diálogo actual. Para obtener más información, consulte
Copia de seguridad y restauración de datos.
Un diálogo válido siempre satisface los siguientes criterios:
-
Cada nodo del diálogo tiene un ID exclusivo (propiedad
dialog_node). -
Un nodo hijo es consciente de su nodo padre (propiedad
parent). Sin embargo, un nodo padre no es consciente de sus hijos. -
Un nodo es consciente de su hermano inmediatamente anterior, si lo hay (propiedad
previous_sibling). Todos los hermanos que comparten el padre forman una lista enlazada, con cada nodo apuntando al nodo anterior. -
Sólo un hijo de un padre puede ser el primer hermano (lo que significa que su
previous_siblinges nulo). -
Un nodo no puede apuntar a un hermano anterior que sea hijo de otro padre.
-
Dos nodos no pueden apuntar al mismo hermano anterior.
-
Un nodo puede especificar otro nodo que se va a ejecutar a continuación (la propiedad
next_step). -
Un nodo no puede ser su propio padre ni su propio hermano.
-
Un nodo debe tener una propiedad de tipo que contenga uno de los siguientes valores. Si no se especifica el tipo de propiedad, el tipo es
standard.event_handler: Manejador definido para un nodo marco o un nodo de ranura individual.
En la herramienta, puede definir un manejador de nodo marco pulsando el enlace Gestionar manejadores desde un nodo con ranuras. (La interfaz de usuario de la herramienta no expone el manejador de sucesos a nivel de ranura, pero puede definir uno a través de la API.)
frame: Nodo con uno o varios nodos hijo del tiposlot. Todos los nodos hijos necesarios deben ser cumplimentados antes de que el servicio pueda salir del nodo marco.
En la herramienta, el tipo de nodo marco se representa como un nodo con ranuras. El nodo que contiene las ranuras se representa como un nodo de tipo=
frame. Es el nodo padre de cada ranura, que se representa como un nodo hijo de tiposlot.response_condition: Respuesta condicional.
En la herramienta es posible añadir una o varias respuestas condicionales a un nodo. Cada respuesta condicional que defina está representada en el JSON subyacente como un nodo individual de type=
response_condition.slot: Nodo hijo de un nodo de tipoframe.
Este tipo de nodo se representa en la herramienta como una de varias ranuras que se añaden a un único nodo. Este nodo individual está representado en el JSON como un nodo padre de tipo
frame.standard: Nodo típico del diálogo. Este es el tipo predeterminado.
-
Para los nodos de tipo
slotque tienen el mismo nodo padre, el orden hermano (especificado por la propiedadprevious_sibling) refleja el orden en el que se procesan las ranuras. -
Un nodo del tipo
slotdebe tener un nodo padre del tipoframe. -
Un nodo de tipo
framedebe tener como mínimo un nodo hijo del tiposlot. -
Un nodo del tipo
response_conditiondebe tener un nodo padre del tipostandardoframe. -
Nodos del tipo
response_conditionyevent_handlerno pueden tener nodos hijo. -
Un nodo del tipo
event_handlertambién debe tener una propiedadevent_nameque contenga uno de los siguientes valores para identificar el tipo del suceso del nodo:filled: Define qué hacer si el usuario proporciona un valor que cumple la condición especificada en el campo Comprobar de una ranura y la ranura se llena. Únicamente hay presente un manejador con este nombre si se ha definido una condición de Encontrado para esta ranura.focus: Define la pregunta para mostrar que solicita al usuario que proporcione la información necesaria para la ranura. Únicamente hay presente un manejador con este nombre si la ranura es obligatoria.generic: Define una condición para que permita tratar preguntas no relacionadas que el usuario podría realizar al cumplimentar una ranura o un nodo con ranuras.input: Actualiza el contexto del mensaje para incluir una variable de contexto con el valor que se recopila de los usuarios para cumplimentar la ranura. Debe existir un manejador con este nombre para cada ranura en el nodo marco.nomatch: Define qué hacer si la respuesta del usuario para la solicitud de la ranura no contiene un valor válido. Únicamente hay presente un manejador con este nombre si se ha definido una condición de No encontrado para esta ranura.
El diagrama siguiente ilustra dónde en la interfaz de usuario de la herramienta se define el código que se desencadena para cada suceso con nombre.
Manejadores de sucesos -
Un nodo de tipo
event_handlercon un event_namegenericpuede tener un padre del tiposlotoframe. -
Un nodo de tipo
event_handlercon un event_name defocus,input,filledonomatchdebe tener un padre del tiposlot. -
Si hay más de un event_handler con el mismo event_name asociado con el mismo nodo padre, el orden de los hermanos es el orden en el que se ejecutan los manejadores de sucesos.
-
Para los nodos de
event_handlercon el mismo nodo de ranura padre, el orden de ejecución es el mismo independientemente de la ubicación de las definiciones de nodo. Los sucesos se desencadenan en este orden por event_name:- focus
- entrada
- filled
- generic*
- nomatch
*Si se define un
event_handlercon el event_namegenericpara esta ranura o para el marco padre, se ejecuta entre los nodos event_handler rellenado y nomatch.
En los ejemplos siguientes se muestra cómo diversas modificaciones pueden provocar cambios en cascada.
Creación de un nodo
Supongamos que tenemos el siguiente árbol de diálogo sencillo:
Podemos crear un nodo nuevo realizando una solicitud POST a /dialog_nodes con el siguiente cuerpo:
{
"dialog_node": "node_8"
}
Ahora el diálogo tiene este aspecto:
Como node_8 se ha creado sin especificar un valor para parent o previous_sibling, ahora es el primer nodo del diálogo. Además de crear node_8, el servicio también ha modificado node_1 para que su propiedad previous_sibling apunte al nuevo nodo.
Puede crear un nodo en otro lugar del diálogo especificando el padre y el hermano anterior:
{
"dialog_node": "node_9",
"parent": "node_2",
"previous_sibling": "node_5"
}
Los valores que especifique para parent y previous_node deben ser válidos:
- Ambos valores deben hacer referencia a nodos existentes.
- El padre especificado debe ser el mismo que el del hermano anterior (o
null, si el hermano anterior no tiene padre). - El padre no puede ser un nodo de tipo
response_conditionnievent_handler.
El diálogo resultante tiene este aspecto:
Además de crear node_9, el servicio actualiza automáticamente la propiedad previous_sibling de node_6 para que apunte al nuevo nodo.
Cómo mover un nodo a otro padre
Mueva node_5 a un padre diferente utilizando el método POST /dialog_nodes/node_5 con el siguiente cuerpo:
{
"parent": "node_1"
}
El valor que se especifique para parent debe ser válido:
- Debe hacer referencia a un nodo existente.
- No debe hacer referencia al nodo que se modifica (un nodo no puede ser su propio padre).
- No debe hacer referencia a un descendiente del nodo que se modifica.
- No debe hacer referencia a un nodo de tipo
response_conditionnievent_handler.
Esto da lugar a la siguiente estructura modificada:
Varias cosas sucedieron aquí:
- Cuando node_5 se ha movido a su nuevo padre, node_7 se ha movido con él (porque el
parentde node_7 no ha cambiado). Cuando se mueve un nodo, todos los descendientes de dicho nodo permanecen junto a él. - Puesto que no se ha especificado un valor
previous_siblingpara node_5, ahora es el primer hermano bajo node_1. - La propiedad
previous_siblingde node_4 se ha actualizado anode_5. - La propiedad
previous_siblingde node_9 se ha actualizado anullporque ahora es el primer hermano bajo node_2.
Reordenación de hermanos
Ahora establezca node_5 como segundo hermano en lugar del primero utilizando el método POST /dialog_nodes/node_5 con el siguiente cuerpo:
{
"previous_sibling": "node_4"
}
Cuando se modifica previous_sibling, el nuevo valor debe ser válido:
- Debe hacer referencia a un nodo existente
- No debe hacer referencia al nodo que se ha modificado (un nodo no puede ser su propio hermano)
- Debe hacer referencia a un hijo del mismo padre (todos los hermanos deben tener el mismo padre)
La estructura cambia del siguiente modo:
Node_7 permanece con su padre. Además, node_4 se modifica para que su previous_sibling sea null porque ahora es el primer hermano.
Supresión de un nodo
Suprima node_1 utilizando el método DELETE /dialog_nodes/node_1.
El resultado es:
Node_1, node_4, node_5 y node_7 se han suprimido todos. Cuando se suprime un nodo, también se suprimen todos los descendientes de dicho nodo. Por lo tanto, si suprime un nodo
raíz, está suprimiendo una rama entera del árbol de diálogo. Cualquier otra referencia al nodo suprimido (como las referencias next_step) se cambian por null.
Además, node_2 se actualiza para que apunte a node_8 como su nuevo hermano anterior.
Cambio del nombre de un nodo
Cambie el nombre del node_2 utilizando el método POST /dialog_nodes/node_2 con el siguiente cuerpo:
{
"dialog_node": "node_X"
}
La estructura del diálogo no ha cambiado, pero se han modificado varios nodos para reflejar el nombre cambiado:
- Las propiedades
parentde node_9 y node_6 - La propiedad
previous_siblingde node_3
Cualquier otra referencia al nodo suprimido (como las referencias next_step) también se han modificado.