Визуальный выбор ответов

Используйте ответ визуального выбора, если вы хотите, чтобы пользователь выбрал один из нескольких вариантов, чтобы продолжить ваше действие. В качестве части подсказки можно использовать следующие типы ответов визуального выбора:

  • Список
  • Коллекция
  • Просмотр коллекции

При определении ответа визуального выбора используйте кандидата с поверхностной возможностью RICH_RESPONSE , чтобы Google Assistant возвращал ответ только на поддерживаемых устройствах. Вы можете использовать только один расширенный ответ для каждого объекта content в приглашении.

Добавление ответа визуального выбора

В ответах на визуальный выбор используется заполнение слотов в сцене как для представления параметров, которые пользователь может выбрать, так и для обработки выбранного элемента. Когда пользователи выбирают элемент, Ассистент передает значение выбранного элемента вашему веб-перехватчику в качестве аргумента. Затем в значении аргумента вы получаете ключ для выбранного элемента.

Прежде чем вы сможете использовать ответ визуального выбора, вы должны определить тип , который представляет ответ, который пользователь позже выбирает. В вебхуке вы переопределяете этот тип содержимым, которое хотите отобразить для выбора.

Чтобы добавить ответ визуального выбора в сцену в Actions Builder, выполните следующие действия:

  1. В сцене добавьте слот в раздел Заполнение слотов .
  2. Выберите ранее определенный тип ответа визуального выбора и дайте ему имя. Ваш вебхук использует это имя слота для ссылки на тип позже.
  3. Установите флажок Вызов веб-перехватчика и укажите имя обработчика событий в веб-перехватчике, который вы хотите использовать для ответа визуального выбора.
  4. Установите флажок «Отправлять подсказки» .
  5. В приглашении укажите соответствующий контент JSON или YAML на основе ответа визуального выбора, который вы хотите вернуть.
  6. В веб-перехватчике выполните действия, описанные в разделе «Обработка выбранных элементов» .

См. разделы списка , коллекции и просмотра коллекции ниже, чтобы узнать о доступных свойствах приглашения и примерах переопределяющих типов.

Обработка выбранных элементов

Ответы на визуальный выбор требуют, чтобы вы обрабатывали выбор пользователя в коде веб-перехватчика. Когда пользователь выбирает что-то из ответа визуального выбора, Google Assistant заполняет слот этим значением.

В следующем примере код веб-перехватчика получает и сохраняет выбранную опцию в переменной:

Node.js

app.handle('Option', conv => {
  // Note: 'prompt_option' is the name of the slot.
  const selectedOption = conv.session.params.prompt_option;
  conv.add(`You selected ${selectedOption}.`);
});

JSON

{
  "responseJson": {
    "session": {
      "id": "session_id",
      "params": {
        "prompt_option": "ITEM_1"
      }
    },
    "prompt": {
      "override": false,
      "firstSimple": {
        "speech": "You selected ITEM_1.",
        "text": "You selected ITEM_1."
      }
    }
  }
}

Список

Пример ответа выбора списка на мобильном устройстве

Список представляет пользователям вертикальный список из нескольких элементов и позволяет им выбирать один с помощью касания или голосового ввода. Когда пользователь выбирает элемент из списка, Ассистент генерирует пользовательский запрос (пузырь чата), содержащий заголовок элемента списка.

Списки хороши, когда важно устранить неоднозначность параметров или когда пользователю нужно выбрать между параметрами, которые необходимо просмотреть полностью. Например, с каким «Питером» вам нужно поговорить: с Питером Йонсом или Питером Хансом?

Списки должны содержать минимум 2 и максимум 30 элементов списка. Количество изначально отображаемых элементов зависит от устройства пользователя, обычное начальное число составляет 10 элементов.

Создание списка

При создании списка в приглашении содержатся только ключи для каждого элемента, который может выбрать пользователь. В веб-перехватчике вы определяете элементы, соответствующие этим ключам, на основе типа Entry .

Элементы списка, определенные как объекты Entry имеют следующие характеристики отображения:

  • Заголовок
    • Фиксированный шрифт и размер шрифта
    • Максимальная длина: 1 строка (обрезанная многоточием...)
    • Должно быть уникальным (для поддержки голосового выбора).
  • Описание (необязательно)
    • Фиксированный шрифт и размер шрифта
    • Максимальная длина: 2 строки (обрезанные многоточием…)
  • Изображение (необязательно)
    • Размер: 48x48 пикселей

Ответы на визуальный выбор требуют переопределить тип по имени его слота, используя тип времени выполнения в режиме TYPE_REPLACE . В обработчике событий веб-перехватчика укажите тип для переопределения по имени его слота (определенному в разделе Добавление ответов выбора ) в свойстве name .

После перезаписи типа результирующий тип представляет собой список элементов, которые ваш пользователь может выбрать из отображаемых Ассистентом.

Характеристики

Тип ответа списка имеет следующие свойства:

Свойство Тип Требование Описание
items массив ListItem Необходимый Представляет элемент в списке, который могут выбрать пользователи. Каждый ListItem содержит ключ, который соответствует ссылочному типу элемента списка.
title нить Необязательный Простой текстовый заголовок списка, ограниченный одной строкой. Если заголовок не указан, высота карты сворачивается.
subtitle нить Необязательный Обычный текстовый подзаголовок списка.

Пример кода

Следующие примеры определяют содержимое приглашения в коде веб-перехватчика или в JSON webhookResponse. Однако вместо этого вы также можете определить содержимое приглашения в Actions Builder (как YAML или JSON).

Node.js

const ASSISTANT_LOGO_IMAGE = new Image({
  url: 'https://developers.google.com/assistant/assistant_96.png',
  alt: 'Google Assistant logo'
});

app.handle('List', conv => {
  conv.add('This is a list.');

  // Override type based on slot 'prompt_option'
  conv.session.typeOverrides = [{
    name: 'prompt_option',
    mode: 'TYPE_REPLACE',
    synonym: {
      entries: [
        {
          name: 'ITEM_1',
          synonyms: ['Item 1', 'First item'],
          display: {
             title: 'Item #1',
             description: 'Description of Item #1',
             image: ASSISTANT_LOGO_IMAGE,
                }
        },
        {
          name: 'ITEM_2',
          synonyms: ['Item 2', 'Second item'],
          display: {
             title: 'Item #2',
             description: 'Description of Item #2',
             image: ASSISTANT_LOGO_IMAGE,
                }
        },
        {
          name: 'ITEM_3',
          synonyms: ['Item 3', 'Third item'],
          display: {
             title: 'Item #3',
             description: 'Description of Item #3',
             image: ASSISTANT_LOGO_IMAGE,
                }
        },
        {
          name: 'ITEM_4',
          synonyms: ['Item 4', 'Fourth item'],
          display: {
             title: 'Item #4',
             description: 'Description of Item #4',
             image: ASSISTANT_LOGO_IMAGE,
                }
        },
        ]
    }
  }];

  // Define prompt content using keys
  conv.add(new List({
    title: 'List title',
    subtitle: 'List subtitle',
    items: [
      {
        key: 'ITEM_1'
      },
      {
        key: 'ITEM_2'
      },
      {
        key: 'ITEM_3'
      },
      {
        key: 'ITEM_4'
      }
    ],
  }));
});

JSON

{
 "responseJson": {
   "session": {
     "id": "session_id",
     "params": {},
     "typeOverrides": [
       {
         "name": "prompt_option",
         "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."
     }
   }
 }
}

Коллекция

Коллекция прокручивается горизонтально и позволяет пользователям выбирать один элемент касанием или голосовым вводом. По сравнению со списками коллекции имеют большие плитки и позволяют размещать более богатый контент. Плитки, составляющие коллекцию, аналогичны базовой карточке с изображением. Когда пользователи выбирают элемент из коллекции, Ассистент генерирует пользовательский запрос (пузырь чата), содержащий название элемента.

Коллекции хороши, когда пользователю представлены различные варианты, но прямое сравнение между ними (в отличие от списков) не требуется. В общем, отдавайте предпочтение спискам коллекциям, поскольку списки легче просматривать визуально и с ними легче взаимодействовать с помощью голоса.

Коллекции должны содержать минимум 2 и максимум 10 плиток. На устройствах с дисплеем пользователи могут проводить пальцем влево или вправо, чтобы пролистывать карточки в коллекции перед выбором элемента.

Создание коллекции

При создании коллекции в приглашении содержатся только ключи для каждого элемента, который может выбрать пользователь. В веб-перехватчике вы определяете элементы, соответствующие этим ключам, на основе типа Entry .

Элементы коллекции, определенные как объекты Entry имеют следующие характеристики отображения:

  • Изображение (необязательно)
    • Изображение должно иметь размер 128 dp в высоту и 232 dp в ширину.
    • Если соотношение сторон изображения не соответствует ограничивающей рамке изображения, изображение центрируется с полосами по обе стороны.
    • Если ссылка на изображение не работает, вместо нее используется изображение-заполнитель.
  • Название (обязательно)
    • Обычный текст, Markdown не поддерживается. Те же параметры форматирования, что и в базовом расширенном ответе на карточке.
    • Высота карты сворачивается, если заголовок не указан.
    • Должно быть уникальным (для поддержки голосового выбора).
  • Описание (необязательно)
    • Обычный текст, Markdown не поддерживается. Те же параметры форматирования, что и в базовом расширенном ответе на карточке.

Ответы на визуальный выбор требуют переопределить тип по имени его слота, используя тип времени выполнения в режиме TYPE_REPLACE . В обработчике событий веб-перехватчика укажите тип для переопределения по имени его слота (определенному в разделе Добавление ответов выбора ) в свойстве name .

После перезаписи типа результирующий тип представляет собой коллекцию элементов, которые ваш пользователь может выбрать из отображаемых Ассистентом.

Характеристики

Тип ответа коллекции имеет следующие свойства:

Свойство Тип Требование Описание
items массив CollectionItem Необходимый Представляет элемент в коллекции, который могут выбрать пользователи. Каждый CollectionItem содержит ключ, который соответствует ссылочному типу элемента коллекции.
title нить Необязательный Простое текстовое название коллекции. Заголовки должны быть уникальными в коллекции, чтобы поддерживать голосовой выбор.
subtitle нить Необязательный Простой текстовый подзаголовок коллекции.
image_fill ImageFill Необязательный Граница между карточкой и контейнером изображения, которая будет использоваться, когда соотношение сторон изображения не соответствует соотношению сторон контейнера изображения.

Пример кода

В следующих примерах определяется содержимое приглашения в коде веб-перехватчика или в ответе веб-перехватчика JSON. Однако вместо этого вы также можете определить содержимое приглашения в Actions Builder (как YAML или JSON).

Node.js

const ASSISTANT_LOGO_IMAGE = new Image({
  url: 'https://developers.google.com/assistant/assistant_96.png',
  alt: 'Google Assistant logo'
});

app.handle('Collection', conv => {
  conv.add("This is a collection.");

  // Override type based on slot 'prompt_option'
  conv.session.typeOverrides = [{
    name: 'prompt_option',
    mode: 'TYPE_REPLACE',
    synonym: {
      entries: [
        {
          name: 'ITEM_1',
          synonyms: ['Item 1', 'First item'],
          display: {
             title: 'Item #1',
             description: 'Description of Item #1',
             image: ASSISTANT_LOGO_IMAGE,
                }
        },
        {
          name: 'ITEM_2',
          synonyms: ['Item 2', 'Second item'],
          display: {
             title: 'Item #2',
             description: 'Description of Item #2',
             image: ASSISTANT_LOGO_IMAGE,
                }
        },
        {
          name: 'ITEM_3',
          synonyms: ['Item 3', 'Third item'],
          display: {
             title: 'Item #3',
             description: 'Description of Item #3',
             image: ASSISTANT_LOGO_IMAGE,
                }
        },
        {
          name: 'ITEM_4',
          synonyms: ['Item 4', 'Fourth item'],
          display: {
             title: 'Item #4',
             description: 'Description of Item #4',
             image: ASSISTANT_LOGO_IMAGE,
                }
        },
        ]
    }
  }];

  // Define prompt content using keys
  conv.add(new Collection({
    title: 'Collection Title',
    subtitle: 'Collection subtitle',
    items: [
      {
        key: 'ITEM_1'
      },
      {
        key: 'ITEM_2'
      },
      {
        key: 'ITEM_3'
      },
      {
        key: 'ITEM_4'
      }
    ],
  }));
});

JSON

{
  "responseJson": {
    "session": {
      "id": "ABwppHHz--uQEEy3CCOANyB0J58oF2Yw5JEX0oXwit3uxDlRwzbEIK3Bcz7hXteE6hWovrLX9Ahpqu8t-jYnQRFGpAUqSuYjZ70",
      "params": {},
      "typeOverrides": [
        {
          "name": "prompt_option",
          "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": {
        "collection": {
          "imageFill": "UNSPECIFIED",
          "items": [
            {
              "key": "ITEM_1"
            },
            {
              "key": "ITEM_2"
            },
            {
              "key": "ITEM_3"
            },
            {
              "key": "ITEM_4"
            }
          ],
          "subtitle": "Collection subtitle",
          "title": "Collection Title"
        }
      },
      "firstSimple": {
        "speech": "This is a collection.",
        "text": "This is a collection."
      }
    }
  }
}

Просмотр коллекции

Подобно коллекции , просмотр коллекции — это расширенный ответ, который позволяет пользователям прокручивать карточки опций. Просмотр коллекции разработан специально для веб-контента и открывает выбранную плитку в веб-браузере (или браузере AMP, если все плитки поддерживают AMP).

Ответы на просмотр коллекции содержат минимум 2 и максимум 10 плиток. На устройствах с дисплеем пользователи могут проводить пальцем вверх или вниз, чтобы пролистывать карточки перед выбором элемента.

Создание обзора коллекции

При создании обзора коллекции подумайте, как пользователи будут взаимодействовать с этим приглашением. Каждый item просмотра коллекции открывает определенный URL-адрес, поэтому предоставьте пользователю полезную информацию.

Элементы просмотра коллекции имеют следующие характеристики отображения:

  • Изображение (необязательно)
    • Размер изображения увеличивается до 128 дп в высоту и 232 дп в ширину.
    • Если соотношение сторон изображения не соответствует ограничивающей рамке изображения, изображение центрируется с полосами по бокам или сверху и снизу. Цвет полос определяется свойством просмотра коллекции ImageFill .
    • Если ссылка на изображение не работает, вместо нее используется изображение-заполнитель.
  • Название (обязательно)
  • Описание (необязательно)
  • Нижний колонтитул (необязательно)
    • Обычный текст; Маркдаун не поддерживается.

Характеристики

Тип ответа просмотра коллекции имеет следующие свойства:

Свойство Тип Требование Описание
item объект Необходимый Представляет элемент в коллекции, который могут выбрать пользователи.
image_fill ImageFill Необязательный Граница между карточкой и контейнером изображения, которая будет использоваться, когда соотношение сторон изображения не соответствует соотношению сторон контейнера изображения.

item просмотра коллекции имеет следующие свойства:

Свойство Тип Требование Описание
title нить Необходимый Простое текстовое название элемента коллекции.
description нить Необязательный Описание предмета коллекции.
footer нить Необязательный Текст нижнего колонтитула элемента коллекции, отображаемый под описанием.
image Image Необязательный Изображение, отображаемое для элемента коллекции.
openUriAction OpenUrl Необходимый URI, который открывается при выборе элемента коллекции.

Пример кода

В следующих примерах определяется содержимое приглашения в коде веб-перехватчика или в ответе веб-перехватчика JSON. Однако вместо этого вы также можете определить содержимое приглашения в Actions Builder (как YAML или JSON).

ЯМЛ

candidates:
  - first_simple:
      variants:
        - speech: This is a collection browse.
    content:
      collection_browse:
        items:
          - title: Item #1
            description: Description of Item #1
            footer: Footer of Item #1
            image:
              url: 'https://developers.google.com/assistant/assistant_96.png'
            open_uri_action:
              url: 'https://www.example.com'
          - title: Item #2
            description: Description of Item #2
            footer: Footer of Item #2
            image:
              url:  'https://developers.google.com/assistant/assistant_96.png'
            open_uri_action:
              url: 'https://www.example.com'
        image_fill: WHITE

JSON

{
 "candidates": [
   {
     "firstSimple": {
       "speech": "This is a collection browse.",
       "text": "This is a collection browse."
     },
     "content": {
       "collectionBrowse": {
         "items": [
           {
             "title": "Item #1",
             "description": "Description of Item #1",
             "footer": "Footer of Item #1",
             "image": {
               "url": "https://developers.google.com/assistant/assistant_96.png"
             },
             "openUriAction": {
               "url": "https://www.example.com"
             }
           },
           {
             "title": "Item #2",
             "description": "Description of Item #2",
             "footer": "Footer of Item #2",
             "image": {
               "url": "https://developers.google.com/assistant/assistant_96.png"
             },
             "openUriAction": {
               "url": "https://www.example.com"
             }
           }
         ],
         "imageFill": "WHITE"
       }
     }
   }
 ]
}

Node.js

// Collection Browse
app.handle('collectionBrowse', (conv) => {
  conv.add('This is a collection browse.');
  conv.add(new CollectionBrowse({
    'imageFill': 'WHITE',
    'items':
      [
        {
          'title': 'Item #1',
          'description': 'Description of Item #1',
          'footer': 'Footer of Item #1',
          'image': {
            'url': 'https://developers.google.com/assistant/assistant_96.png'
          },
          'openUriAction': {
            'url': 'https://www.example.com'
          }
        },
        {
          'title': 'Item #2',
          'description': 'Description of Item #2',
          'footer': 'Footer of Item #2',
          'image': {
            'url': 'https://developers.google.com/assistant/assistant_96.png'
          },
          'openUriAction': {
            'url': 'https://www.example.com'
          }
        }
      ]
  }));
});

JSON

{
  "responseJson": {
    "session": {
      "id": "session_id",
      "params": {},
      "languageCode": ""
    },
    "prompt": {
      "override": false,
      "content": {
        "collectionBrowse": {
          "imageFill": "WHITE",
          "items": [
            {
              "title": "Item #1",
              "description": "Description of Item #1",
              "footer": "Footer of Item #1",
              "image": {
                "url": "https://developers.google.com/assistant/assistant_96.png"
              },
              "openUriAction": {
                "url": "https://www.example.com"
              }
            },
            {
              "title": "Item #2",
              "description": "Description of Item #2",
              "footer": "Footer of Item #2",
              "image": {
                "url": "https://developers.google.com/assistant/assistant_96.png"
              },
              "openUriAction": {
                "url": "https://www.example.com"
              }
            }
          ]
        }
      },
      "firstSimple": {
        "speech": "This is a collection browse.",
        "text": "This is a collection browse."
      }
    }
  }
}