Modificando um diálogo usando a API

A API REST suporta modificar seu diálogo programaticamente. É possível usar a API /dialog_nodes para criar, excluir ou modificar nós de diálogo.

Um diálogo é uma árvore de nós interconectados e deve estar em conformidade com determinadas regras para ser válido. Qualquer mudança feita em um nó de diálogo pode ter efeitos em cascata em outros nós ou na estrutura de seu diálogo. Antes de usar a API /dialog_nodes para modificar seu diálogo, certifique-se de entender como suas mudanças afetam o restante do diálogo. É possível fazer uma cópia de backup do diálogo atual. Para obter mais informações, consulte Fazendo backup e restaurando dados

Um diálogo válido sempre satisfaz os critérios a seguir:

  • Cada nó do diálogo possui um ID exclusivo (a propriedade dialog_node).

  • Um nó-filho está ciente de seu nó pai (a propriedade parent). No entanto, um nó pai não está ciente de seus filhos.

  • Um nó está ciente de seu irmão anterior imediato, se houver (a propriedade previous_sibling). Todos os irmãos que compartilham o pai formam uma lista vinculada com cada nó apontando para o nó anterior.

  • Apenas um filho de um pai pode ser o primeiro irmão (o que significa que seu previous_sibling é nulo.

  • Um nó não pode apontar para um irmão anterior que seja um filho de um pai diferente.

  • Dois nós não podem apontar para o mesmo irmão anterior.

  • Um nó pode especificar outro nó que deve ser executado em seguida (a propriedade next_step ).

  • Um nó não pode ser seu próprio pai ou seu próprio irmão.

  • Um nó deve ter uma propriedade de tipo que contenha um dos valores a seguir. Se nenhuma propriedade de tipo for especificada, o tipo será standard.

    • event_handler: um manipulador que está definido para um nó de quadro ou um nó de intervalo individual.

    Na ferramenta, é possível definir um manipulador de nó de quadro clicando no link Gerenciar manipuladores em um nó com intervalos. (A interface com o usuário da ferramenta não expõe o manipulador de eventos de nível de intervalo, mas é possível definir um por meio da API.)

    • frame: um nó com um ou mais nós-filhos do tipo slot. Quaisquer nós-filhos de intervalo necessários devem ser preenchidos antes que o serviço possa sair do nó de quadro.

    O tipo de nó do quadro é representado como um nó com intervalos na ferramenta. O nó que contém os slots é representado como um nó de type=frame. É o nó pai para cada slot, que é representado como um nó filho do tipo slot.

    • response_condition: uma resposta condicional.

    Na ferramenta, é possível incluir uma ou mais respostas condicionais em um nó. Cada resposta condicional que você define é representada no JSON subjacente como um nó individual de type=response_condition.

    • slot: um nó-filho de um nó do tipo frame.

    Esse tipo de nó é representado na ferramenta como sendo um dos vários slots que são incluídos em um único nó Esse único nó é representado no JSON como um nó pai do tipo frame.

    • standard: um nó de diálogo típico. Este é o tipo padrão.
  • Para nós do tipo slot que possuem o mesmo nó pai, a ordem irmã (especificada pela propriedade previous_sibling ) reflete a ordem na qual os slots são processados.

  • Um nó do tipo slot deve ter um nó pai do tipo frame.

  • Um nó do tipo frame deve ter pelo menos um nó-filho do tipo slot.

  • Um nó do tipo response_condition deve ter um nó pai do tipo standard ou frame.

  • Os nós do tipo response_condition e event_handler não podem ter filhos.

  • Um nó do tipo event_handler também deve ter uma propriedade event_name que contém um dos valores a seguir para identificar o tipo de evento do nó:

    • filled: define o que fazer se o usuário fornecer um valor que atenda à condição especificada no campo Verificar de um slot e o slot for preenchido. Um manipulador com esse nome estará presente somente se uma condição de Localizado estiver definida para o intervalo.
    • focus: Define a pergunta para mostrar que solicita que o usuário forneça as informações necessárias pelo slot. Um manipulador com esse nome estará presente somente se o intervalo for necessário.
    • generic: define uma condição para observar que pode direcionar questões não relacionadas que os usuários podem perguntar ao preencher um intervalo ou nó com intervalos.
    • input: atualiza o contexto da mensagem para incluir uma variável de contexto com o valor que é coletado do usuário para preencher o intervalo. Um manipulador com esse nome deve estar presente para cada intervalo no nó de quadro.
    • nomatch: define o que fazer se a resposta do usuário para o prompt de intervalo não contém um valor válido. Um manipulador com esse nome está presente somente se uma condição de Não localizado está definida para o intervalo.

    O diagrama a seguir ilustra onde na interface com o usuário da ferramenta você define o código que é acionado para cada evento nomeado.

    Local da UI no qual o código que é acionado por manipuladores de eventos nomeados é criado
    Manipuladores de Eventos

  • Um nó do tipo event_handler com um event_name de generic pode ter um pai do tipo slot ou frame.

  • Um nó do tipo event_handler com um event_name de focus, input, filled ou nomatch deve ter um pai do tipo slot.

  • Se mais de um event_handler com o mesmo event_name estiver associado ao mesmo nó pai, a ordem dos irmãos será a ordem na qual os manipuladores de eventos são executados.

  • Para os nós event_handler com o mesmo nó pai de intervalo, a ordem de execução é a mesma independentemente do posicionamento das definições de nó. Os eventos são acionados nesta ordem por event_name:

    1. foco
    2. entrada
    3. filled
    4. generic*
    5. nomatch

    *Se um event_handler com o event_name generic for definido para esse slot ou para o quadro pai, ele será executado entre os nós event_handler preenchido e nomatch.

Os exemplos a seguir mostram como várias modificações podem causar mudanças em cascata.

Criando um nó

Considere a árvore de diálogo simples a seguir:

Diálogo Exemplo
Diálogo de Exemplo

Podemos criar um novo nó ao fazer uma solicitação POST para /dialog_nodes com o corpo a seguir:

{
  "dialog_node": "node_8"
}

O diálogo agora é semelhante a este:

Diálogo de Exemplo 2
Diálogo de Exemplo 2
.

Como o node_8 foi criado sem especificar um valor para parent ou previous_sibling, ele agora é o primeiro nó no diálogo. Além de criar node_8, o serviço também modificou node_1 para que sua propriedade previous_sibling aponte para o novo nó.

É possível criar um nó em outro lugar no diálogo especificando o pai e irmão anteriores:

{
  "dialog_node": "node_9",
  "parent": "node_2",
  "previous_sibling": "node_5"
}

Os valores especificados para parent e previous_node devem ser válidos:

  • Ambos os valores devem referir-se a nós existentes.
  • O pai especificado deve ser o mesmo que o pai do irmão anterior (ou null se o irmão anterior não tiver pai).
  • O pai não pode ser um nó do tipo response_condition ou event_handler.

O diálogo resultante é semelhante a este:

Diálogo Exemplo 3
Diálogo Exemplo 3

Além de criar o node_9, o serviço atualiza automaticamente a propriedade previous_sibling de node_6 para que aponte para o novo nó.

Movendo um nó para um pai diferente

Mova node_5 para um pai diferente usando o método POST /dialog_nodes/node_5 com o corpo a seguir:

{
  "parent": "node_1"
}

O valor especificado para parent deve ser válido:

  • Ele deve referir-se a um nó existente.
  • Ele não deve fazer referência ao nó modificado (um nó não pode ser seu próprio pai).
  • Ele não deve fazer referência a um descendente do nó modificado.
  • Ele não deve referir-se a um nó do tipo response_condition ou event_handler.

Isso resulta na estrutura mudada a seguir:

Diálogo Exemplo 4
Diálogo Exemplo 4

Várias coisas aconteceram aqui:

  • Quando node_5 mudou para seu novo pai, node_7 foi com ele (porque o valor de parent para node_7 não mudou). Quando você move um nó, todos os descendentes desse nó permanecem com ele.
  • Como nós não especificamos um valor previous_sibling para node_5, agora ele é o primeiro irmão sob node_1.
  • A propriedade previous_sibling de node_4 foi atualizada para node_5.
  • A propriedade previous_sibling de node_9 foi atualizada para null porque agora é o primeiro irmão sob node_2.

Resequenciando irmãos

Agora configure node_5 como o segundo irmão em vez do primeiro usando o método POST /dialog_nodes/node_5 com o corpo a seguir:

{
  "previous_sibling": "node_4"
}

Quando você modifica previous_sibling, o novo valor deve ser válido:

  • Ele deve referir-se a um nó existente
  • Ele não deve fazer referência ao nó que é modificado (um nó não pode ser seu próprio irmão)
  • Ele deve referir-se a um filho do mesmo pai (todos os irmãos devem ter o mesmo pai)

A estrutura muda conforme a seguir:

Diálogo Exemplo 5
Diálogo Exemplo 5

O Node_7 permanece com seu pai Além disso, node_4 é modificado para que seu previous_sibling seja null porque agora ele é o primeiro irmão.

Excluindo um nó

Exclua node_1 usando o método DELETE /dialog_nodes/node_1.

O resultado é:

Exemplo de diálogo 6
Exemplo de diálogo 6
.

Node_1, node_4, node_5 e node_7 foram todos excluídos. Quando você exclui um nó, todos os descendentes desse nó são excluídos também. Portanto, se você excluir um nó raiz, estará excluindo uma ramificação inteira da árvore de diálogo.. Quaisquer outras referências ao nó excluído (como referências next_step) serão mudadas para null.

Além disso, node_2 é atualizado para apontar para node_8 como seu novo irmão anterior.

Renomeando um nó

Renomeie node_2 usando o método POST /dialog_nodes/node_2 com o corpo a seguir:

{
  "dialog_node": "node_X"
}

Diálogo Exemplo 7
Diálogo Exemplo 7

A estrutura do diálogo não foi alterada, mas vários nós foram modificados para refletir o nome alterado:

  • As propriedades parent de node_9 e node_6
  • A propriedade previous_sibling de node_3

Quaisquer outras referências ao nó excluído (como referências next_step) também são mudadas.