Como renderizar uma lista retornada de um webhook

Nov 06 2020

Estou usando o Google Actions. Estou retornando JSON do meu webhook e recebendo o seguinte erro ao testar minha ação no simulador:

"Falha ao renderizar o prompt de Lista ou Coleção devido à falta de Substituição de Tipo para um slot. Nota, Lista e Coleção devem ser usadas apenas no preenchimento de slot. Deve haver uma Substituição de Tipo correspondente que descreve como renderizar a Lista ou Coleção para este Tipo. "

O JSON é uma amostra ligeiramente modificada retirada dos documentos em https://developers.google.com/assistant/conversational/prompts-selection.

O nome typeOverrides 'items' corresponde a um nome de slot para a cena.

Aqui está a solicitação do webhook e a resposta JSON.

*** SOLICITAÇÃO ***

 {
  "handler": {
    "name": "aa"
  },
  "intent": {
    "name": "searchIntent",
    "params": {
      "searchParm": {
        "original": "milk",
        "resolved": "milk"
      }
    },
    "query": "milk"
  },
  "scene": {
    "name": "Start",
    "slotFillingStatus": "UNSPECIFIED",
    "slots": {},
    "next": {
      "name": "SearchScene"
    }
  },
  "session": {
    "id": "ABwppHGln0UTzfUPqJ1SMr1Cuw2TyPjJQoGUkULazcObus3vUwJCJCpba--5PSRwjqMQelRqMAUnwPvl",
    "params": {},
    "typeOverrides": [],
    "languageCode": ""
  },
  "user": {
    "locale": "en-AU",
    "params": {},
    "accountLinkingStatus": "ACCOUNT_LINKING_STATUS_UNSPECIFIED",
    "verificationStatus": "VERIFIED",
    "packageEntitlements": [],
    "lastSeenTime": "2020-11-05T21:24:16Z"
  },
  "home": {
    "params": {}
  },
  "device": {
    "capabilities": [
      "SPEECH",
      "RICH_RESPONSE",
      "LONG_FORM_AUDIO"
    ]
  }
}

*** RESPOSTA ***

{
  "session": {
    "id": "ABwppHGln0UTzfUPqJ1SMr1Cuw2TyPjJQoGUkULazcObus3vUwJCJCpba--5PSRwjqMQelRqMAUnwPvl",
    "params": {},
    "typeOverrides": [
      {
        "name": "items",
        "synonym": {
          "entries": [
            {
              "name": "ITEM_1",
              "synonyms": [
                "Item 1",
                "First item"
              ],
              "display": {
                "title": "Item #1",
                "description": "Description of Item #1",
                "image": {
                  "alt": "Google Assistant logo",
                  "height": 0,
                  "url": "https://developers.google.com/assistant/assistant_96.png",
                  "width": 0
                }
              }
            },
            {
              "name": "ITEM_2",
              "synonyms": [
                "Item 2",
                "Second item"
              ],
              "display": {
                "title": "Item #2",
                "description": "Description of Item #2",
                "image": {
                  "alt": "Google Assistant logo",
                  "height": 0,
                  "url": "https://developers.google.com/assistant/assistant_96.png",
                  "width": 0
                }
              }
            },
            {
              "name": "ITEM_3",
              "synonyms": [
                "Item 3",
                "Third item"
              ],
              "display": {
                "title": "Item #3",
                "description": "Description of Item #3",
                "image": {
                  "alt": "Google Assistant logo",
                  "height": 0,
                  "url": "https://developers.google.com/assistant/assistant_96.png",
                  "width": 0
                }
              }
            },
            {
              "name": "ITEM_4",
              "synonyms": [
                "Item 4",
                "Fourth item"
              ],
              "display": {
                "title": "Item #4",
                "description": "Description of Item #4",
                "image": {
                  "alt": "Google Assistant logo",
                  "height": 0,
                  "url": "https://developers.google.com/assistant/assistant_96.png",
                  "width": 0
                }
              }
            }
          ]
        },
        "typeOverrideMode": "TYPE_REPLACE"
      }
    ]
  },
  "prompt": {
    "override": false,
    "content": {
      "list": {
        "items": [
          {
            "key": "ITEM_1"
          },
          {
            "key": "ITEM_2"
          },
          {
            "key": "ITEM_3"
          },
          {
            "key": "ITEM_4"
          }
        ],
        "subtitle": "List subtitle",
        "title": "List title"
      }
    },
    "firstSimple": {
      "speech": "This is a list.",
      "text": "This is a list."
    }
  }
}

Respostas

Prisoner Nov 06 2020 at 18:39

O nome TypeOverride deve corresponder ao tipo do slot, não ao nome do slot.

CarlosHerrera Nov 27 2020 at 14:39

Compartilho com todos vocês a solução para isso.

É verdade que a documentação omite certas partes para fazer isso funcionar, mas se prestarmos atenção para ler e seguir ao pé da letra realmente funciona.

Assim que tivermos nosso projeto Actions Builder, a primeira coisa que faremos é criar uma entidade na seção de tipos. Apenas isso, não precisamos adicionar entradas ou valores, apenas criar o tipo.

O próximo passo é preparar a cena onde mostraremos nossa coleção. Neste caso, criei um chamado INTRO.

É aqui que você tem o erro. Você está tentando exibir a coleção no webhook que dispara quando você entra em cena. Nada deve ser colocado lá, deve estar vazio.

A próxima etapa é adicionar o tipo de slot e um nome. Devemos também configurar mais 2 coisas, uma é tornar o referido slot obrigatório e a outra é ativar a caixa de seleção para que ele chame o nosso handler que está encarregado de pintar a coleção.

Se você notar, chamei o slot de: type_option e é do tipo prompt_type , ou seja, o tipo que declarei na primeira etapa. Em seguida, marquei esse slot como necessário e, finalmente, o ativei para chamar o manipulador chamado LaunchRequest que está em meu webhook.

Agora vamos ver o código.

const LaunchRequestHandler = app => {

  app.handle('LaunchRequest', conv => {
    conv.session.typeOverrides = [
      {
        name: 'prompt_option', // We reference the type of slot, not the name
        mode: 'TYPE_REPLACE',
        synonym: {
          entries: [
            {
              name: 'ITEM_1',
              synonyms: ['Item 1', 'First item'],
              display: {
                title: 'Element 1',
                description: 'This is the element 1',
                image: new Image({
                  url: '<YOUR URL>',
                  alt: 'example'
                })
              }
            },
            {
              name: 'ITEM_2',
              synonyms: ['Item 2', 'Second item'],
              display: {
                title: 'Element 2',
                description: 'This is the element 2',
                image: new Image({
                  url: '<YOUR URL>',
                  alt: 'example 2'
                })
              }
            }
          ]
        }
      }
    ];

    const items = [{ key: 'ITEM_1' }, { key: 'ITEM_2' }]

    conv.add(new Collection({ title: '<YOUR TITLE>', subtitle: '<YOUR SUBTITLE>', items }))
  })
}

Este é o trecho de código que configuramos para ser chamado quando quisermos apresentar a coleção. Se olharmos com atenção, nos referimos ao tipo e não ao nome do slot.

Com isso, tudo deve funcionar, se fizermos o teste do simulador. Tudo é perfeito.

Espero que minha ajuda tenha lhe servido bem.