Исследуйте в Dialogflow
Нажмите «Продолжить» , чтобы импортировать образец ответов в Dialogflow. Затем выполните следующие действия, чтобы развернуть и протестировать образец:
- Введите имя агента и создайте новый агент Dialogflow для образца.
- После завершения импорта агента нажмите Перейти к агенту .
- В главном навигационном меню перейдите к Выполнение .
- Включите встроенный редактор , затем нажмите «Развернуть» . Редактор содержит пример кода.
- В главном меню навигации выберите «Интеграции» и нажмите «Google Ассистент» .
- В появившемся модальном окне включите автоматический предварительный просмотр изменений и нажмите «Тест» , чтобы открыть симулятор действий.
- В симуляторе введите
Talk to my test app
, чтобы протестировать образец!
Используйте расширенный ответ, если вы хотите отображать визуальные элементы для улучшения взаимодействия пользователей с вашим действием. Эти визуальные элементы могут дать подсказки о том, как продолжить разговор.
Расширенные ответы могут отображаться только на экране или в аудио и на экране. Они могут содержать следующие компоненты:
- Один или два простых ответа (пузыри чата).
- Необязательная базовая карта .
- Дополнительные фишки предложений .
- Дополнительный выходной чип.
Вы также можете ознакомиться с нашими рекомендациями по дизайну бесед , чтобы узнать, как использовать эти визуальные элементы в своем действии.
Характеристики
Расширенные ответы имеют следующие требования и дополнительные свойства, которые вы можете настроить:
- Поддерживается на поверхностях с возможностью
actions.capability.SCREEN_OUTPUT
. - Первым элементом расширенного ответа должен быть простой ответ .
- Максимум два простых ответа.
- Не более одной базовой карты или
StructuredResponse
. - Не более 8 фишек предложений .
- Чипы предложений не допускаются в
FinalResponse
- Связывание с Интернетом с интеллектуальных дисплеев в настоящее время не поддерживается.
В следующих разделах показано, как создавать различные типы расширенных ответов.
Базовая карта

Базовая карточка отображает информацию, которая может включать следующее:
- Изображение
- Заголовок
- Подзаголовок
- Текстовое тело
- Кнопка ссылки
- Граница
Используйте базовые карты в основном для демонстрации. Они предназначены для того, чтобы быть краткими, чтобы предоставить пользователям ключевую (или сводную) информацию и позволить пользователям узнать больше, если вы выберете (используя веб-ссылку).
В большинстве случаев вам следует добавить фишки с предложениями под карточками, чтобы продолжить или развернуть разговор.
Избегайте повторения информации, представленной в карточке, в пузыре чата любой ценой.
Характеристики
Базовый тип ответа карты имеет следующие требования и дополнительные свойства, которые можно настроить:
- Поддерживается на поверхностях с возможностью
actions.capability.SCREEN_OUTPUT
. - Форматированный текст (обязательно, если нет изображения)
- Обычный текст по умолчанию.
- Не должен содержать ссылку.
- Ограничение 10 строк с изображением, ограничение 15 строк без изображения. Это примерно 500 (с изображением) или 750 (без изображения) символов. Телефоны с меньшим экраном также обрезают текст раньше, чем телефоны с большим экраном. Если текст содержит слишком много строк, он усекается в месте разрыва последнего слова многоточием.
- Поддерживается ограниченное подмножество уценки:
- Новая строка с двойным пробелом, за которым следует \n
-
**bold**
-
*italics*
- Изображение (обязательно, если нет форматированного текста)
- Все изображения должны быть высотой 192 dp.
- Если соотношение сторон изображения отличается от соотношения сторон экрана, изображение центрируется серыми полосами по вертикальным или горизонтальным краям.
- Источник изображения — это URL.
- GIF-файлы с движением разрешены.
Необязательный
- Заголовок
- Простой текст.
- Фиксированный шрифт и размер.
- Не более одной строки; лишние символы обрезаются.
- Высота карточки сворачивается, если заголовок не указан.
- Подзаголовок
- Простой текст.
- Фиксированный шрифт и размер шрифта.
- Не более одной строки; лишние символы обрезаются.
- Высота карточки сворачивается, если не указан подзаголовок.
- Кнопка ссылки
- Название ссылки обязательно
- Не более одной ссылки
- Разрешены ссылки на сайты вне домена разработчика.
- Текст ссылки не может вводить в заблуждение. Это проверяется в процессе утверждения.
- Базовая карта не имеет возможности взаимодействия без ссылки. Тап по ссылке отправляет пользователя по ссылке, при этом основная часть карточки остается неактивной.
- Граница
- Границу между картой и контейнером изображения можно настроить, чтобы настроить представление вашей базовой карты.
- Настраивается путем установки свойства строки JSON
imageDisplayOptions

Образец кода
Node.js
app.intent('Basic Card', (conv) => { if (!conv.screen) { conv.ask('Sorry, try this on a screen device or select the ' + 'phone surface in the simulator.'); conv.ask('Which response would you like to see next?'); return; } conv.ask(`Here's an example of a basic card.`); conv.ask(new BasicCard({ text: `This is a basic card. Text in a basic card can include "quotes" and most other unicode characters including emojis. Basic cards also support some markdown formatting like *emphasis* or _italics_, **strong** or __bold__, and ***bold itallic*** or ___strong emphasis___ as well as other things like line \nbreaks`, // Note the two spaces before '\n' required for // a line break to be rendered in the card. subtitle: 'This is a subtitle', title: 'Title: this is a title', buttons: new Button({ title: 'This is a button', url: 'https://assistant.google.com/', }), image: new Image({ url: 'https://storage.googleapis.com/actionsresources/logo_assistant_2x_64dp.png', alt: 'Image alternate text', }), display: 'CROPPED', })); conv.ask('Which response would you like to see next?'); });
Джава
@ForIntent("Basic Card") public ActionResponse basicCard(ActionRequest request) { ResponseBuilder responseBuilder = getResponseBuilder(request); if (!request.hasCapability(Capability.SCREEN_OUTPUT.getValue())) { return responseBuilder .add("Sorry, try ths on a screen device or select the phone surface in the simulator.") .add("Which response would you like to see next?") .build(); } // Prepare formatted text for card String text = "This is a basic card. Text in a basic card can include \"quotes\" and\n" + " most other unicode characters including emoji \uD83D\uDCF1. Basic cards also support\n" + " some markdown formatting like *emphasis* or _italics_, **strong** or\n" + " __bold__, and ***bold itallic*** or ___strong emphasis___ as well as other\n" + " things like line \\nbreaks"; // Note the two spaces before '\n' required for // a line break to be rendered in the card. responseBuilder .add("Here's an example of a basic card.") .add( new BasicCard() .setTitle("Title: this is a title") .setSubtitle("This is a subtitle") .setFormattedText(text) .setImage( new Image() .setUrl( "https://storage.googleapis.com/actionsresources/logo_assistant_2x_64dp.png") .setAccessibilityText("Image alternate text")) .setImageDisplayOptions("CROPPED") .setButtons( new ArrayList<Button>( Arrays.asList( new Button() .setTitle("This is a Button") .setOpenUrlAction( new OpenUrlAction().setUrl("https://assistant.google.com")))))) .add("Which response would you like to see next?"); return responseBuilder.build(); }
Node.js
if (!conv.screen) { conv.ask('Sorry, try this on a screen device or select the ' + 'phone surface in the simulator.'); conv.ask('Which response would you like to see next?'); return; } conv.ask(`Here's an example of a basic card.`); conv.ask(new BasicCard({ text: `This is a basic card. Text in a basic card can include "quotes" and most other unicode characters including emojis. Basic cards also support some markdown formatting like *emphasis* or _italics_, **strong** or __bold__, and ***bold itallic*** or ___strong emphasis___ as well as other things like line \nbreaks`, // Note the two spaces before '\n' required for // a line break to be rendered in the card. subtitle: 'This is a subtitle', title: 'Title: this is a title', buttons: new Button({ title: 'This is a button', url: 'https://assistant.google.com/', }), image: new Image({ url: 'https://storage.googleapis.com/actionsresources/logo_assistant_2x_64dp.png', alt: 'Image alternate text', }), display: 'CROPPED', })); conv.ask('Which response would you like to see next?');
Джава
ResponseBuilder responseBuilder = getResponseBuilder(request); if (!request.hasCapability(Capability.SCREEN_OUTPUT.getValue())) { return responseBuilder .add("Sorry, try ths on a screen device or select the phone surface in the simulator.") .add("Which response would you like to see next?") .build(); } // Prepare formatted text for card String text = "This is a basic card. Text in a basic card can include \"quotes\" and\n" + " most other unicode characters including emoji \uD83D\uDCF1. Basic cards also support\n" + " some markdown formatting like *emphasis* or _italics_, **strong** or\n" + " __bold__, and ***bold itallic*** or ___strong emphasis___ as well as other\n" + " things like line \\nbreaks"; // Note the two spaces before '\n' required for // a line break to be rendered in the card. responseBuilder .add("Here's an example of a basic card.") .add( new BasicCard() .setTitle("Title: this is a title") .setSubtitle("This is a subtitle") .setFormattedText(text) .setImage( new Image() .setUrl( "https://storage.googleapis.com/actionsresources/logo_assistant_2x_64dp.png") .setAccessibilityText("Image alternate text")) .setImageDisplayOptions("CROPPED") .setButtons( new ArrayList<Button>( Arrays.asList( new Button() .setTitle("This is a Button") .setOpenUrlAction( new OpenUrlAction().setUrl("https://assistant.google.com")))))) .add("Which response would you like to see next?"); return responseBuilder.build();
JSON
Обратите внимание, что приведенный ниже JSON описывает ответ веб-перехватчика.
{ "payload": { "google": { "expectUserResponse": true, "richResponse": { "items": [ { "simpleResponse": { "textToSpeech": "Here's an example of a basic card." } }, { "basicCard": { "title": "Title: this is a title", "subtitle": "This is a subtitle", "formattedText": "This is a basic card. Text in a basic card can include \"quotes\" and\n most other unicode characters including emojis. Basic cards also support\n some markdown formatting like *emphasis* or _italics_, **strong** or\n __bold__, and ***bold itallic*** or ___strong emphasis___ as well as other\n things like line \nbreaks", "image": { "url": "https://storage.googleapis.com/actionsresources/logo_assistant_2x_64dp.png", "accessibilityText": "Image alternate text" }, "buttons": [ { "title": "This is a button", "openUrlAction": { "url": "https://assistant.google.com/" } } ], "imageDisplayOptions": "CROPPED" } }, { "simpleResponse": { "textToSpeech": "Which response would you like to see next?" } } ] } } } }
JSON
Обратите внимание, что приведенный ниже JSON описывает ответ веб-перехватчика.
{ "expectUserResponse": true, "expectedInputs": [ { "possibleIntents": [ { "intent": "actions.intent.TEXT" } ], "inputPrompt": { "richInitialPrompt": { "items": [ { "simpleResponse": { "textToSpeech": "Here's an example of a basic card." } }, { "basicCard": { "title": "Title: this is a title", "subtitle": "This is a subtitle", "formattedText": "This is a basic card. Text in a basic card can include \"quotes\" and\n most other unicode characters including emojis. Basic cards also support\n some markdown formatting like *emphasis* or _italics_, **strong** or\n __bold__, and ***bold itallic*** or ___strong emphasis___ as well as other\n things like line \nbreaks", "image": { "url": "https://storage.googleapis.com/actionsresources/logo_assistant_2x_64dp.png", "accessibilityText": "Image alternate text" }, "buttons": [ { "title": "This is a button", "openUrlAction": { "url": "https://assistant.google.com/" } } ], "imageDisplayOptions": "CROPPED" } }, { "simpleResponse": { "textToSpeech": "Which response would you like to see next?" } } ] } } } ] }
Просмотр карусели

Карусель просмотра — это расширенный ответ, который позволяет пользователям прокручивать страницу по вертикали и выбирать плитку в коллекции. Карусели просмотра разработаны специально для веб-контента, открывая выбранную плитку в веб-браузере (или в браузере AMP, если все плитки поддерживают AMP). Карусель просмотра также сохраняется на поверхности помощника пользователя для последующего просмотра.
Характеристики
Тип ответа карусели просмотра имеет следующие требования и дополнительные свойства, которые вы можете настроить:
- Поддерживается на поверхностях, которые имеют возможности
actions.capability.SCREEN_OUTPUT
иactions.capability.WEB_BROWSER
. Этот тип ответа в настоящее время недоступен на смарт-дисплеях. - Просмотр карусели
- Максимум десять плиток.
- Минимум две плитки.
- Плитки в карусели должны быть связаны с веб-контентом (рекомендуется AMP-контент).
- Чтобы пользователь был перенаправлен в средство просмотра AMP, для параметра
urlHintType
на плитках контента AMP должно быть установлено значение «AMP_CONTENT».
- Чтобы пользователь был перенаправлен в средство просмотра AMP, для параметра
- Просмотр плиток карусели
- Консистенция плитки (обязательно):
- Все плитки в карусели просмотра должны иметь одинаковые компоненты. Например, если у одной плитки есть поле изображения, остальные плитки в карусели также должны иметь поля изображения.
- Если все плитки в карусели просмотра ссылаются на контент с поддержкой AMP, пользователь попадает в браузер AMP с дополнительными функциями. Если какая-либо плитка ссылается на не-AMP-контент, то все плитки направляют пользователей в веб-браузер.
- Изображение (необязательно)
- Изображение должно быть 128 dp в высоту x 232 dp в ширину.
- Если соотношение сторон изображения не соответствует ограничивающей рамке изображения, изображение центрируется с полосами по обеим сторонам. На смартфонах изображение располагается в центре квадрата со скругленными углами.
- Если ссылка на изображение не работает, вместо нее используется изображение-заполнитель.
- Для изображения требуется альтернативный текст.
- Название (обязательно)
- Те же параметры форматирования, что и для основной текстовой карты.
- Названия должны быть уникальными (для поддержки голосового выбора).
- Максимум две строки текста.
- Размер шрифта 16 сп.
- Описание (необязательно)
- Те же параметры форматирования, что и для основной текстовой карты.
- Максимум четыре строки текста.
- Усечено многоточием (...)
- Размер шрифта 14 сп, цвет серый.
- Нижний колонтитул (необязательно)
- Фиксированный шрифт и размер шрифта.
- Максимум одна строка текста.
- Усечено многоточием (...)
- Закрепляется внизу, поэтому плитки с меньшим количеством строк основного текста могут иметь пустое пространство над подтекстом.
- Размер шрифта 14 сп, цвет серый.
- Консистенция плитки (обязательно):
- Взаимодействие
- Пользователь может прокручивать по вертикали для просмотра элементов.
- Касание карты: При нажатии на элемент пользователь переходит в браузер, где отображается связанная страница.
- Голосовой ввод
- Поведение микрофона
- Микрофон не открывается повторно, когда пользователю отправляется карусель просмотра.
- Пользователь по-прежнему может коснуться микрофона или вызвать помощника («ОК, Google»), чтобы снова открыть микрофон.
- Поведение микрофона
Руководство
По умолчанию микрофон остается закрытым после отправки карусели просмотра. Если вы хотите продолжить разговор позже, мы настоятельно рекомендуем добавить фишки с предложениями под каруселью.
Никогда не повторяйте варианты, представленные в списке в виде фишек-предложений. Фишки в этом контексте используются для поворота разговора (а не для выбора выбора).
Как и в случае списков, всплывающее окно чата, сопровождающее карусельную карточку, является подмножеством аудио (TTS/SSML). Аудио (TTS/SSML) здесь интегрирует первую плитку в карусели, и мы также настоятельно не рекомендуем читать все элементы из карусели. Лучше всего указать первый товар и причину его появления (например, самый популярный, самый последний купленный, самый обсуждаемый).
Образец кода
Node.js
app.intent('Browsing Carousel', (conv) => { if (!conv.screen || !conv.surface.capabilities.has('actions.capability.WEB_BROWSER')) { conv.ask('Sorry, try this on a phone or select the ' + 'phone surface in the simulator.'); conv.ask('Which response would you like to see next?'); return; } conv.ask(`Here's an example of a browsing carousel.`); conv.ask(new BrowseCarousel({ items: [ new BrowseCarouselItem({ title: 'Title of item 1', url: 'https://example.com', description: 'Description of item 1', image: new Image({ url: 'https://storage.googleapis.com/actionsresources/logo_assistant_2x_64dp.png', alt: 'Image alternate text', }), footer: 'Item 1 footer', }), new BrowseCarouselItem({ title: 'Title of item 2', url: 'https://example.com', description: 'Description of item 2', image: new Image({ url: 'https://storage.googleapis.com/actionsresources/logo_assistant_2x_64dp.png', alt: 'Image alternate text', }), footer: 'Item 2 footer', }), ], })); });
Джава
@ForIntent("Browsing Carousel") public ActionResponse browseCarousel(ActionRequest request) { ResponseBuilder responseBuilder = getResponseBuilder(request); if (!request.hasCapability(Capability.SCREEN_OUTPUT.getValue()) || !request.hasCapability(Capability.WEB_BROWSER.getValue())) { return responseBuilder .add("Sorry, try this on a phone or select the phone surface in the simulator.") .add("Which response would you like to see next?") .build(); } responseBuilder .add("Here's an example of a browsing carousel.") .add( new CarouselBrowse() .setItems( new ArrayList<CarouselBrowseItem>( Arrays.asList( new CarouselBrowseItem() .setTitle("Title of item 1") .setDescription("Description of item 1") .setOpenUrlAction(new OpenUrlAction().setUrl("https://example.com")) .setImage( new Image() .setUrl( "https://storage.googleapis.com/actionsresources/logo_assistant_2x_64dp.png") .setAccessibilityText("Image alternate text")) .setFooter("Item 1 footer"), new CarouselBrowseItem() .setTitle("Title of item 2") .setDescription("Description of item 2") .setOpenUrlAction(new OpenUrlAction().setUrl("https://example.com")) .setImage( new Image() .setUrl( "https://storage.googleapis.com/actionsresources/logo_assistant_2x_64dp.png") .setAccessibilityText("Image alternate text")) .setFooter("Item 2 footer"))))); return responseBuilder.build(); }
Node.js
if (!conv.screen || !conv.surface.capabilities.has('actions.capability.WEB_BROWSER')) { conv.ask('Sorry, try this on a phone or select the ' + 'phone surface in the simulator.'); conv.ask('Which response would you like to see next?'); return; } conv.ask(`Here's an example of a browsing carousel.`); conv.ask(new BrowseCarousel({ items: [ new BrowseCarouselItem({ title: 'Title of item 1', url: 'https://example.com', description: 'Description of item 1', image: new Image({ url: 'https://storage.googleapis.com/actionsresources/logo_assistant_2x_64dp.png', alt: 'Image alternate text', }), footer: 'Item 1 footer', }), new BrowseCarouselItem({ title: 'Title of item 2', url: 'https://example.com', description: 'Description of item 2', image: new Image({ url: 'https://storage.googleapis.com/actionsresources/logo_assistant_2x_64dp.png', alt: 'Image alternate text', }), footer: 'Item 2 footer', }), ], }));
Джава
ResponseBuilder responseBuilder = getResponseBuilder(request); if (!request.hasCapability(Capability.SCREEN_OUTPUT.getValue()) || !request.hasCapability(Capability.WEB_BROWSER.getValue())) { return responseBuilder .add("Sorry, try this on a phone or select the phone surface in the simulator.") .add("Which response would you like to see next?") .build(); } responseBuilder .add("Here's an example of a browsing carousel.") .add( new CarouselBrowse() .setItems( new ArrayList<CarouselBrowseItem>( Arrays.asList( new CarouselBrowseItem() .setTitle("Title of item 1") .setDescription("Description of item 1") .setOpenUrlAction(new OpenUrlAction().setUrl("https://example.com")) .setImage( new Image() .setUrl( "https://storage.googleapis.com/actionsresources/logo_assistant_2x_64dp.png") .setAccessibilityText("Image alternate text")) .setFooter("Item 1 footer"), new CarouselBrowseItem() .setTitle("Title of item 2") .setDescription("Description of item 2") .setOpenUrlAction(new OpenUrlAction().setUrl("https://example.com")) .setImage( new Image() .setUrl( "https://storage.googleapis.com/actionsresources/logo_assistant_2x_64dp.png") .setAccessibilityText("Image alternate text")) .setFooter("Item 2 footer"))))); return responseBuilder.build();
JSON
Обратите внимание, что приведенный ниже JSON описывает ответ веб-перехватчика.
{ "payload": { "google": { "expectUserResponse": true, "richResponse": { "items": [ { "simpleResponse": { "textToSpeech": "Here's an example of a browsing carousel." } }, { "carouselBrowse": { "items": [ { "title": "Title of item 1", "openUrlAction": { "url": "https://example.com" }, "description": "Description of item 1", "footer": "Item 1 footer", "image": { "url": "https://storage.googleapis.com/actionsresources/logo_assistant_2x_64dp.png", "accessibilityText": "Image alternate text" } }, { "title": "Title of item 2", "openUrlAction": { "url": "https://example.com" }, "description": "Description of item 2", "footer": "Item 2 footer", "image": { "url": "https://storage.googleapis.com/actionsresources/logo_assistant_2x_64dp.png", "accessibilityText": "Image alternate text" } } ] } } ] } } } }
JSON
Обратите внимание, что приведенный ниже JSON описывает ответ веб-перехватчика.
{ "expectUserResponse": true, "expectedInputs": [ { "inputPrompt": { "richInitialPrompt": { "items": [ { "simpleResponse": { "textToSpeech": "Here's an example of a browsing carousel." } }, { "carouselBrowse": { "items": [ { "description": "Description of item 1", "footer": "Item 1 footer", "image": { "accessibilityText": "Image alternate text", "url": "https://storage.googleapis.com/actionsresources/logo_assistant_2x_64dp.png" }, "openUrlAction": { "url": "https://example.com" }, "title": "Title of item 1" }, { "description": "Description of item 2", "footer": "Item 2 footer", "image": { "accessibilityText": "Image alternate text", "url": "https://storage.googleapis.com/actionsresources/logo_assistant_2x_64dp.png" }, "openUrlAction": { "url": "https://example.com" }, "title": "Title of item 2" } ] } } ] } }, "possibleIntents": [ { "intent": "actions.intent.TEXT" } ] } ] }
Обработка выбранного элемента
Для взаимодействия пользователя с элементами карусели просмотра не требуется никакого последующего выполнения, поскольку карусель обрабатывает передачу обслуживания браузера. Имейте в виду, что микрофон не откроется снова после того, как пользователь взаимодействует с элементом карусели просмотра, поэтому вам следует либо завершить разговор, либо включить в свой ответ подсказки в соответствии с приведенным выше руководством.
Фишки предложения

Используйте чипы предложений, чтобы намекнуть на ответы, чтобы продолжить или повернуть разговор. Если во время разговора есть основной призыв к действию, подумайте о том, чтобы указать его в качестве первой фишки предложения.
Когда это возможно, вы должны включить одно ключевое предложение в чат, но делайте это только в том случае, если ответ или разговор в чате кажутся естественными.
Характеристики
Чипы предложений имеют следующие требования и дополнительные свойства, которые вы можете настроить:
- Поддерживается на поверхностях с возможностью
actions.capability.SCREEN_OUTPUT
. - Чтобы связать чипы предложений с сетью, поверхности также должны иметь возможность
actions.capability.WEB_BROWSER
. В настоящее время эта возможность недоступна на смарт-дисплеях. - Максимум восемь фишек.
- Максимальная длина текста 25 символов.
Поддерживает только обычный текст.

Образец кода
Node.js
app.intent('Suggestion Chips', (conv) => { if (!conv.screen) { conv.ask('Chips can be demonstrated on screen devices.'); conv.ask('Which response would you like to see next?'); return; } conv.ask('These are suggestion chips.'); conv.ask(new Suggestions('Suggestion 1')); conv.ask(new Suggestions(['Suggestion 2', 'Suggestion 3'])); conv.ask(new LinkOutSuggestion({ name: 'Suggestion Link', url: 'https://assistant.google.com/', })); conv.ask('Which type of response would you like to see next?'); ; });
Джава
@ForIntent("Suggestion Chips") public ActionResponse suggestionChips(ActionRequest request) { ResponseBuilder responseBuilder = getResponseBuilder(request); if (!request.hasCapability(Capability.SCREEN_OUTPUT.getValue())) { return responseBuilder .add("Sorry, try ths on a screen device or select the phone surface in the simulator.") .add("Which response would you like to see next?") .build(); } responseBuilder .add("These are suggestion chips.") .addSuggestions(new String[] {"Suggestion 1", "Suggestion 2", "Suggestion 3"}) .add( new LinkOutSuggestion() .setDestinationName("Suggestion Link") .setUrl("https://assistant.google.com/")) .add("Which type of response would you like to see next?"); return responseBuilder.build(); }
Node.js
if (!conv.screen) { conv.ask('Chips can be demonstrated on screen devices.'); conv.ask('Which response would you like to see next?'); return; } conv.ask('These are suggestion chips.'); conv.ask(new Suggestions('Suggestion 1')); conv.ask(new Suggestions(['Suggestion 2', 'Suggestion 3'])); conv.ask(new LinkOutSuggestion({ name: 'Suggestion Link', url: 'https://assistant.google.com/', })); conv.ask('Which type of response would you like to see next?');
Джава
ResponseBuilder responseBuilder = getResponseBuilder(request); if (!request.hasCapability(Capability.SCREEN_OUTPUT.getValue())) { return responseBuilder .add("Sorry, try ths on a screen device or select the phone surface in the simulator.") .add("Which response would you like to see next?") .build(); } responseBuilder .add("These are suggestion chips.") .addSuggestions(new String[] {"Suggestion 1", "Suggestion 2", "Suggestion 3"}) .add( new LinkOutSuggestion() .setDestinationName("Suggestion Link") .setUrl("https://assistant.google.com/")) .add("Which type of response would you like to see next?"); return responseBuilder.build();
JSON
Обратите внимание, что приведенный ниже JSON описывает ответ веб-перехватчика.
{ "payload": { "google": { "expectUserResponse": true, "richResponse": { "items": [ { "simpleResponse": { "textToSpeech": "These are suggestion chips." } }, { "simpleResponse": { "textToSpeech": "Which type of response would you like to see next?" } } ], "suggestions": [ { "title": "Suggestion 1" }, { "title": "Suggestion 2" }, { "title": "Suggestion 3" } ], "linkOutSuggestion": { "destinationName": "Suggestion Link", "url": "https://assistant.google.com/" } } } } }
JSON
Обратите внимание, что приведенный ниже JSON описывает ответ веб-перехватчика.
{ "expectUserResponse": true, "expectedInputs": [ { "possibleIntents": [ { "intent": "actions.intent.TEXT" } ], "inputPrompt": { "richInitialPrompt": { "items": [ { "simpleResponse": { "textToSpeech": "These are suggestion chips." } }, { "simpleResponse": { "textToSpeech": "Which type of response would you like to see next?" } } ], "suggestions": [ { "title": "Suggestion 1" }, { "title": "Suggestion 2" }, { "title": "Suggestion 3" } ], "linkOutSuggestion": { "destinationName": "Suggestion Link", "url": "https://assistant.google.com/" } } } } ] }
Реакция СМИ

Медиа-ответы позволяют вашим действиям воспроизводить аудиоконтент с продолжительностью воспроизведения, превышающей 240-секундный предел SSML. Основным компонентом ответа СМИ является однодорожечная карта. Карта позволяет пользователю выполнять следующие операции:
- Воспроизведите последние 10 секунд.
- Перейти вперед на 30 секунд.
- Просмотр общей длины медиаконтента.
- Просмотрите индикатор выполнения для воспроизведения аудио.
- Просмотр истекшего времени воспроизведения.
Ответы СМИ поддерживают следующие элементы управления звуком для голосового взаимодействия:
- «Окей, Google, играй».
- «Окей, Google, пауза».
- «Окей, Google, остановись».
- «Окей, Google, начни сначала».
Пользователи также могут регулировать громкость, произнося такие фразы, как «Окей, Google, увеличьте громкость». или «Окей, Google, уменьши громкость до 50 процентов». Намерения в вашем действии имеют приоритет, если они обрабатывают похожие обучающие фразы. Позвольте Ассистенту обрабатывать эти запросы пользователей, если у вашего Действия нет особой причины.
Характеристики
Ответы СМИ имеют следующие требования и дополнительные свойства, которые вы можете настроить:
- Поддерживается на поверхностях с возможностью
actions.capability.MEDIA_RESPONSE_AUDIO
. - Аудио для воспроизведения должно быть в правильно отформатированном файле
.mp3
. Прямая трансляция не поддерживается. - Медиафайл для воспроизведения должен быть указан как URL-адрес HTTPS.
- Изображение (необязательно)
- При желании вы можете включить значок или изображение.
- Икона
- Ваш значок отображается в виде миниатюры без полей справа от карточки медиаплеера.
- Размер должен быть 36 x 36 dp. Изображения большего размера изменяются по размеру.
- Изображение
- Контейнер изображения будет иметь высоту 192 dp.
- Ваше изображение появляется в верхней части карточки медиаплеера и занимает всю ширину карточки. Большинство изображений отображаются с полосами вверху или по бокам.
- GIF-файлы с движением разрешены.
- Вы должны указать источник изображения в виде URL-адреса.
- Alt-текст обязателен для всех изображений.
Поведение на поверхностях
Ответы СМИ поддерживаются на телефонах Android и в Google Home. Поведение ответов СМИ зависит от поверхности, на которой пользователи взаимодействуют с вашими действиями.
На телефонах Android пользователи могут видеть ответы СМИ при соблюдении любого из следующих условий:
- Google Assistant находится на переднем плане, а экран телефона включен.
- Пользователь выходит из Google Assistant во время воспроизведения звука и возвращается в Google Assistant в течение 10 минут после завершения воспроизведения. Вернувшись в Google Assistant, пользователь видит медиа-карту и чипы предложений.
- Помощник позволяет пользователям управлять громкостью устройства во время диалогового действия, говоря такие вещи, как «увеличьте громкость» или «установите громкость на 50 процентов» . Если у вас есть намерения, которые обрабатывают похожие обучающие фразы, ваши намерения имеют приоритет. Мы рекомендуем позволить Ассистенту обрабатывать эти запросы пользователей, если у вашего Действия нет особой причины для этого.
Элементы управления мультимедиа доступны, когда телефон заблокирован. На Android элементы управления также отображаются в области уведомлений.

Образец кода
В следующем примере кода показано, как можно обновить расширенные ответы, включив в них мультимедиа.
Node.js
app.intent('Media Response', (conv) => { if (!conv.surface.capabilities .has('actions.capability.MEDIA_RESPONSE_AUDIO')) { conv.ask('Sorry, this device does not support audio playback.'); conv.ask('Which response would you like to see next?'); return; } conv.ask('This is a media response example.'); conv.ask(new MediaObject({ name: 'Jazz in Paris', url: 'https://storage.googleapis.com/automotive-media/Jazz_In_Paris.mp3', description: 'A funky Jazz tune', icon: new Image({ url: 'https://storage.googleapis.com/automotive-media/album_art.jpg', alt: 'Album cover of an ocean view', }), })); conv.ask(new Suggestions(['Basic Card', 'List', 'Carousel', 'Browsing Carousel'])); });
Джава
@ForIntent("Media Response") public ActionResponse mediaResponse(ActionRequest request) { ResponseBuilder responseBuilder = getResponseBuilder(request); if (!request.hasCapability(Capability.MEDIA_RESPONSE_AUDIO.getValue())) { return responseBuilder .add("Sorry, this device does not support audio playback.") .add("Which response would you like to see next?") .build(); } responseBuilder .add("This is a media response example.") .add( new MediaResponse() .setMediaObjects( new ArrayList<MediaObject>( Arrays.asList( new MediaObject() .setName("Jazz in Paris") .setDescription("A funky Jazz tune") .setContentUrl( "https://storage.googleapis.com/automotive-media/Jazz_In_Paris.mp3") .setIcon( new Image() .setUrl( "https://storage.googleapis.com/automotive-media/album_art.jpg") .setAccessibilityText("Album cover of an ocean view"))))) .setMediaType("AUDIO")) .addSuggestions(new String[] {"Basic Card", "List", "Carousel", "Browsing Carousel"}); return responseBuilder.build(); }
Node.js
if (!conv.surface.capabilities .has('actions.capability.MEDIA_RESPONSE_AUDIO')) { conv.ask('Sorry, this device does not support audio playback.'); conv.ask('Which response would you like to see next?'); return; } conv.ask('This is a media response example.'); conv.ask(new MediaObject({ name: 'Jazz in Paris', url: 'https://storage.googleapis.com/automotive-media/Jazz_In_Paris.mp3', description: 'A funky Jazz tune', icon: new Image({ url: 'https://storage.googleapis.com/automotive-media/album_art.jpg', alt: 'Album cover of an ocean view', }), })); conv.ask(new Suggestions(['Basic Card', 'List', 'Carousel', 'Browsing Carousel']));
Джава
ResponseBuilder responseBuilder = getResponseBuilder(request); if (!request.hasCapability(Capability.MEDIA_RESPONSE_AUDIO.getValue())) { return responseBuilder .add("Sorry, this device does not support audio playback.") .add("Which response would you like to see next?") .build(); } responseBuilder .add("This is a media response example.") .add( new MediaResponse() .setMediaObjects( new ArrayList<MediaObject>( Arrays.asList( new MediaObject() .setName("Jazz in Paris") .setDescription("A funky Jazz tune") .setContentUrl( "https://storage.googleapis.com/automotive-media/Jazz_In_Paris.mp3") .setIcon( new Image() .setUrl( "https://storage.googleapis.com/automotive-media/album_art.jpg") .setAccessibilityText("Album cover of an ocean view"))))) .setMediaType("AUDIO")) .addSuggestions(new String[] {"Basic Card", "List", "Carousel", "Browsing Carousel"}); return responseBuilder.build();
JSON
Обратите внимание, что приведенный ниже JSON описывает ответ веб-перехватчика.
{ "payload": { "google": { "expectUserResponse": true, "richResponse": { "items": [ { "simpleResponse": { "textToSpeech": "This is a media response example." } }, { "mediaResponse": { "mediaType": "AUDIO", "mediaObjects": [ { "contentUrl": "https://storage.googleapis.com/automotive-media/Jazz_In_Paris.mp3", "description": "A funky Jazz tune", "icon": { "url": "https://storage.googleapis.com/automotive-media/album_art.jpg", "accessibilityText": "Album cover of an ocean view" }, "name": "Jazz in Paris" } ] } } ], "suggestions": [ { "title": "Basic Card" }, { "title": "List" }, { "title": "Carousel" }, { "title": "Browsing Carousel" } ] } } } }
JSON
Обратите внимание, что приведенный ниже JSON описывает ответ веб-перехватчика.
{ "expectUserResponse": true, "expectedInputs": [ { "possibleIntents": [ { "intent": "actions.intent.TEXT" } ], "inputPrompt": { "richInitialPrompt": { "items": [ { "simpleResponse": { "textToSpeech": "This is a media response example." } }, { "mediaResponse": { "mediaType": "AUDIO", "mediaObjects": [ { "contentUrl": "https://storage.googleapis.com/automotive-media/Jazz_In_Paris.mp3", "description": "A funky Jazz tune", "icon": { "url": "https://storage.googleapis.com/automotive-media/album_art.jpg", "accessibilityText": "Album cover of an ocean view" }, "name": "Jazz in Paris" } ] } } ], "suggestions": [ { "title": "Basic Card" }, { "title": "List" }, { "title": "Carousel" }, { "title": "Browsing Carousel" } ] } } } ] }
Руководство
Ваш ответ должен включать mediaResponse
с mediaType
, равным AUDIO
, и содержащий mediaObject
в массиве элементов расширенного ответа. Медиа-ответ поддерживает один медиа-объект. Медиа-объект должен включать URL-адрес содержимого аудиофайла. Медиа-объект может дополнительно включать имя, подтекст (описание) и URL-адрес значка или изображения.
На телефонах и в Google Home, когда ваше действие завершает воспроизведение звука, Google Assistant проверяет, является ли медиа-ответ FinalResponse
. Если нет, он отправляет обратный вызов на ваше выполнение, позволяя вам ответить пользователю.
Ваше действие должно включать подсказки, если ответ не является FinalResponse
.
Обработка обратного вызова после завершения воспроизведения
Ваше действие должно обрабатывать намерение actions.intent.MEDIA_STATUS
, чтобы предложить пользователю продолжить действие (например, воспроизвести другую песню). Ваше действие получает этот обратный вызов после завершения воспроизведения мультимедиа. В обратном вызове аргумент MEDIA_STATUS
содержит информацию о состоянии текущего носителя. Значение статуса будет либо FINISHED
, либо STATUS_UNSPECIFIED
.
Использование диалогового потока
Если вы хотите выполнить диалоговое ветвление в Dialogflow, вам нужно настроить входной контекст actions_capability_media_response_audio
с намерением, чтобы он срабатывал только на тех поверхностях, которые поддерживают медиа-ответ.
Создание вашего удовлетворения
Фрагмент кода ниже показывает, как вы можете написать код выполнения для своего действия. Если вы используете Dialogflow, замените actions.intent.MEDIA_STATUS
именем действия, указанным в намерении, которое получает событие actions_intent_MEDIA_STATUS
(например, «media.status.update»).
Node.js
app.intent('Media Status', (conv) => { const mediaStatus = conv.arguments.get('MEDIA_STATUS'); let response = 'Unknown media status received.'; if (mediaStatus && mediaStatus.status === 'FINISHED') { response = 'Hope you enjoyed the tune!'; } conv.ask(response); conv.ask('Which response would you like to see next?'); });
Джава
@ForIntent("Media Status") public ActionResponse mediaStatus(ActionRequest request) { ResponseBuilder responseBuilder = getResponseBuilder(request); String mediaStatus = request.getMediaStatus(); String response = "Unknown media status received."; if (mediaStatus != null && mediaStatus.equals("FINISHED")) { response = "Hope you enjoyed the tune!"; } responseBuilder.add(response); responseBuilder.add("Which response would you like to see next?"); return responseBuilder.build(); }
Node.js
app.intent('actions.intent.MEDIA_STATUS', (conv) => { const mediaStatus = conv.arguments.get('MEDIA_STATUS'); let response = 'Unknown media status received.'; if (mediaStatus && mediaStatus.status === 'FINISHED') { response = 'Hope you enjoyed the tune!'; } conv.ask(response); conv.ask('Which response would you like to see next?'); });
Джава
@ForIntent("actions.intent.MEDIA_STATUS") public ActionResponse mediaStatus(ActionRequest request) { ResponseBuilder responseBuilder = getResponseBuilder(request); String mediaStatus = request.getMediaStatus(); String response = "Unknown media status received."; if (mediaStatus != null && mediaStatus.equals("FINISHED")) { response = "Hope you enjoyed the tune!"; } responseBuilder.add(response); responseBuilder.add("Which response would you like to see next?"); return responseBuilder.build(); }
JSON
Обратите внимание, что приведенный ниже JSON описывает запрос веб-перехватчика.
{ "responseId": "151b68df-98de-41fb-94b5-caeace90a7e9-21947381", "queryResult": { "queryText": "actions_intent_MEDIA_STATUS", "parameters": {}, "allRequiredParamsPresent": true, "fulfillmentText": "Webhook failed for intent: Media Status", "fulfillmentMessages": [ { "text": { "text": [ "Webhook failed for intent: Media Status" ] } } ], "outputContexts": [ { "name": "projects/df-responses-kohler/agent/sessions/ABwppHHsebncupHK11oKhsCTgyH96GRNYH-xpeeMTqb-cvOxbd67QenbRlZM4bGAIB8_KXdTfI7-7lYVKN1ovAhCaA/contexts/actions_capability_media_response_audio" }, { "name": "projects/df-responses-kohler/agent/sessions/ABwppHHsebncupHK11oKhsCTgyH96GRNYH-xpeeMTqb-cvOxbd67QenbRlZM4bGAIB8_KXdTfI7-7lYVKN1ovAhCaA/contexts/actions_capability_account_linking" }, { "name": "projects/df-responses-kohler/agent/sessions/ABwppHHsebncupHK11oKhsCTgyH96GRNYH-xpeeMTqb-cvOxbd67QenbRlZM4bGAIB8_KXdTfI7-7lYVKN1ovAhCaA/contexts/actions_capability_web_browser" }, { "name": "projects/df-responses-kohler/agent/sessions/ABwppHHsebncupHK11oKhsCTgyH96GRNYH-xpeeMTqb-cvOxbd67QenbRlZM4bGAIB8_KXdTfI7-7lYVKN1ovAhCaA/contexts/actions_capability_screen_output" }, { "name": "projects/df-responses-kohler/agent/sessions/ABwppHHsebncupHK11oKhsCTgyH96GRNYH-xpeeMTqb-cvOxbd67QenbRlZM4bGAIB8_KXdTfI7-7lYVKN1ovAhCaA/contexts/actions_capability_audio_output" }, { "name": "projects/df-responses-kohler/agent/sessions/ABwppHHsebncupHK11oKhsCTgyH96GRNYH-xpeeMTqb-cvOxbd67QenbRlZM4bGAIB8_KXdTfI7-7lYVKN1ovAhCaA/contexts/google_assistant_input_type_voice" }, { "name": "projects/df-responses-kohler/agent/sessions/ABwppHHsebncupHK11oKhsCTgyH96GRNYH-xpeeMTqb-cvOxbd67QenbRlZM4bGAIB8_KXdTfI7-7lYVKN1ovAhCaA/contexts/actions_intent_media_status", "parameters": { "MEDIA_STATUS": { "@type": "type.googleapis.com/google.actions.v2.MediaStatus", "status": "FINISHED" } } } ], "intent": { "name": "projects/df-responses-kohler/agent/intents/068b27d3-c148-4044-bfab-dfa37eebd90d", "displayName": "Media Status" }, "intentDetectionConfidence": 1, "languageCode": "en" }, "originalDetectIntentRequest": { "source": "google", "version": "2", "payload": { "user": { "locale": "en-US", "lastSeen": "2019-08-04T23:57:15Z", "userVerificationStatus": "VERIFIED" }, "conversation": { "conversationId": "ABwppHHsebncupHK11oKhsCTgyH96GRNYH-xpeeMTqb-cvOxbd67QenbRlZM4bGAIB8_KXdTfI7-7lYVKN1ovAhCaA", "type": "ACTIVE", "conversationToken": "[]" }, "inputs": [ { "intent": "actions.intent.MEDIA_STATUS", "rawInputs": [ { "inputType": "VOICE" } ], "arguments": [ { "name": "MEDIA_STATUS", "extension": { "@type": "type.googleapis.com/google.actions.v2.MediaStatus", "status": "FINISHED" } } ] } ], "surface": { "capabilities": [ { "name": "actions.capability.MEDIA_RESPONSE_AUDIO" }, { "name": "actions.capability.ACCOUNT_LINKING" }, { "name": "actions.capability.WEB_BROWSER" }, { "name": "actions.capability.SCREEN_OUTPUT" }, { "name": "actions.capability.AUDIO_OUTPUT" } ] }, "isInSandbox": true, "availableSurfaces": [ { "capabilities": [ { "name": "actions.capability.WEB_BROWSER" }, { "name": "actions.capability.AUDIO_OUTPUT" }, { "name": "actions.capability.SCREEN_OUTPUT" } ] } ], "requestType": "SIMULATOR" } }, "session": "projects/df-responses-kohler/agent/sessions/ABwppHHsebncupHK11oKhsCTgyH96GRNYH-xpeeMTqb-cvOxbd67QenbRlZM4bGAIB8_KXdTfI7-7lYVKN1ovAhCaA" }
JSON
Обратите внимание, что приведенный ниже JSON описывает запрос веб-перехватчика.
{ "user": { "locale": "en-US", "lastSeen": "2019-08-06T07:38:40Z", "userVerificationStatus": "VERIFIED" }, "conversation": { "conversationId": "ABwppHGcqunXh1M6IE0lu2sVqXdpJfdpC5FWMkMSXQskK1nzb4IkSUSRqQzoEr0Ly0z_G3mwyZlk5rFtd1w", "type": "NEW" }, "inputs": [ { "intent": "actions.intent.MEDIA_STATUS", "rawInputs": [ { "inputType": "VOICE" } ], "arguments": [ { "name": "MEDIA_STATUS", "extension": { "@type": "type.googleapis.com/google.actions.v2.MediaStatus", "status": "FINISHED" } } ] } ], "surface": { "capabilities": [ { "name": "actions.capability.SCREEN_OUTPUT" }, { "name": "actions.capability.WEB_BROWSER" }, { "name": "actions.capability.AUDIO_OUTPUT" }, { "name": "actions.capability.MEDIA_RESPONSE_AUDIO" }, { "name": "actions.capability.ACCOUNT_LINKING" } ] }, "isInSandbox": true, "availableSurfaces": [ { "capabilities": [ { "name": "actions.capability.WEB_BROWSER" }, { "name": "actions.capability.AUDIO_OUTPUT" }, { "name": "actions.capability.SCREEN_OUTPUT" } ] } ], "requestType": "SIMULATOR" }
Настольные карты
Карточки-таблицы позволяют отображать в ответе табличные данные (например, спортивное положение, результаты выборов и перелеты). Вы можете определить столбцы и строки (до 3 в каждом), которые Помощник должен отображать в вашей карточке таблицы. Вы также можете определить дополнительные столбцы и строки вместе с их приоритетами.
Таблицы отличаются от вертикальных списков тем, что таблицы отображают статические данные и не являются интерактивными, как элементы списка.

Характеристики
Карточки таблицы имеют следующие требования и дополнительные свойства, которые можно настроить:
- Поддерживается на поверхностях с возможностью
actions.capability.SCREEN_OUTPUT
.
В следующем разделе кратко описано, как можно настроить элементы в карточке таблицы.
Имя | Является необязательным | Настраиваемый | Примечания по настройке |
---|---|---|---|
title | Да | Да | Общее название таблицы. Должен быть установлен, если субтитры установлены. Вы можете настроить семейство шрифтов и цвет. |
subtitle | Да | Нет | Подзаголовок к таблице. |
image | Да | Да | Изображение, связанное с таблицей. |
Row | Нет | Да | Данные строки таблицы. Состоит из массива объектов Первые 3 строки гарантированно будут отображаться, но другие могут не отображаться на некоторых поверхностях. Пожалуйста, проверьте с помощью симулятора, чтобы увидеть, какие строки отображаются для данной поверхности. На поверхностях, поддерживающих функцию |
ColumnProperties | Да | Да | Заголовок и выравнивание для столбца. Состоит из свойства header (представляющего текст заголовка столбца) и свойства horizontal_alignment (типа HorizontalAlignment ). |
Cell | Нет | Да | Описывает ячейку в строке. Каждая ячейка содержит строку, представляющую текстовое значение. Вы можете настроить текст в ячейке. |
Button | Да | Да | Объект-кнопка, который обычно появляется внизу карточки. Карточка таблицы может иметь только 1 кнопку. Вы можете настроить цвет кнопки. |
HorizontalAlignment | Да | Да | Горизонтальное выравнивание содержимого внутри ячейки. Значения могут быть LEADING , CENTER или TRAILING . Если не указано, содержимое выравнивается по переднему краю ячейки. |
Образец кода
В следующих фрагментах показано, как реализовать простую карточку таблицы:
Node.js
app.intent('Simple Table Card', (conv) => { if (!conv.screen) { conv.ask('Sorry, try this on a screen device or select the ' + 'phone surface in the simulator.'); conv.ask('Which response would you like to see next?'); return; } conv.ask('This is a simple table example.'); conv.ask(new Table({ dividers: true, columns: ['header 1', 'header 2', 'header 3'], rows: [ ['row 1 item 1', 'row 1 item 2', 'row 1 item 3'], ['row 2 item 1', 'row 2 item 2', 'row 2 item 3'], ], })); conv.ask('Which response would you like to see next?'); });
Джава
@ForIntent("Simple Table Card") public ActionResponse simpleTable(ActionRequest request) { ResponseBuilder responseBuilder = getResponseBuilder(request); if (!request.hasCapability(Capability.SCREEN_OUTPUT.getValue())) { return responseBuilder .add("Sorry, try ths on a screen device or select the phone surface in the simulator.") .add("Which response would you like to see next?") .build(); } responseBuilder .add("This is a simple table example.") .add( new TableCard() .setColumnProperties( Arrays.asList( new TableCardColumnProperties().setHeader("header 1"), new TableCardColumnProperties().setHeader("header 2"), new TableCardColumnProperties().setHeader("header 3"))) .setRows( Arrays.asList( new TableCardRow() .setCells( Arrays.asList( new TableCardCell().setText("row 1 item 1"), new TableCardCell().setText("row 1 item 2"), new TableCardCell().setText("row 1 item 3"))), new TableCardRow() .setCells( Arrays.asList( new TableCardCell().setText("row 2 item 1"), new TableCardCell().setText("row 2 item 2"), new TableCardCell().setText("row 2 item 3")))))); return responseBuilder.build(); }
Node.js
if (!conv.screen) { conv.ask('Sorry, try this on a screen device or select the ' + 'phone surface in the simulator.'); conv.ask('Which response would you like to see next?'); return; } conv.ask('This is a simple table example.'); conv.ask(new Table({ dividers: true, columns: ['header 1', 'header 2', 'header 3'], rows: [ ['row 1 item 1', 'row 1 item 2', 'row 1 item 3'], ['row 2 item 1', 'row 2 item 2', 'row 2 item 3'], ], })); conv.ask('Which response would you like to see next?');
Джава
ResponseBuilder responseBuilder = getResponseBuilder(request); if (!request.hasCapability(Capability.SCREEN_OUTPUT.getValue())) { return responseBuilder .add("Sorry, try ths on a screen device or select the phone surface in the simulator.") .add("Which response would you like to see next?") .build(); } responseBuilder .add("This is a simple table example.") .add( new TableCard() .setColumnProperties( Arrays.asList( new TableCardColumnProperties().setHeader("header 1"), new TableCardColumnProperties().setHeader("header 2"), new TableCardColumnProperties().setHeader("header 3"))) .setRows( Arrays.asList( new TableCardRow() .setCells( Arrays.asList( new TableCardCell().setText("row 1 item 1"), new TableCardCell().setText("row 1 item 2"), new TableCardCell().setText("row 1 item 3"))), new TableCardRow() .setCells( Arrays.asList( new TableCardCell().setText("row 2 item 1"), new TableCardCell().setText("row 2 item 2"), new TableCardCell().setText("row 2 item 3")))))); return responseBuilder.build();
JSON
Обратите внимание, что приведенный ниже JSON описывает ответ веб-перехватчика.
{ "payload": { "google": { "expectUserResponse": true, "richResponse": { "items": [ { "simpleResponse": { "textToSpeech": "This is a simple table example." } }, { "tableCard": { "rows": [ { "cells": [ { "text": "row 1 item 1" }, { "text": "row 1 item 2" }, { "text": "row 1 item 3" } ], "dividerAfter": true }, { "cells": [ { "text": "row 2 item 1" }, { "text": "row 2 item 2" }, { "text": "row 2 item 3" } ], "dividerAfter": true } ], "columnProperties": [ { "header": "header 1" }, { "header": "header 2" }, { "header": "header 3" } ] } }, { "simpleResponse": { "textToSpeech": "Which response would you like to see next?" } } ] } } } }
JSON
Обратите внимание, что приведенный ниже JSON описывает ответ веб-перехватчика.
{ "expectUserResponse": true, "expectedInputs": [ { "inputPrompt": { "richInitialPrompt": { "items": [ { "simpleResponse": { "textToSpeech": "This is a simple table example." } }, { "tableCard": { "columnProperties": [ { "header": "header 1" }, { "header": "header 2" }, { "header": "header 3" } ], "rows": [ { "cells": [ { "text": "row 1 item 1" }, { "text": "row 1 item 2" }, { "text": "row 1 item 3" } ], "dividerAfter": true }, { "cells": [ { "text": "row 2 item 1" }, { "text": "row 2 item 2" }, { "text": "row 2 item 3" } ], "dividerAfter": true } ] } }, { "simpleResponse": { "textToSpeech": "Which response would you like to see next?" } } ] } }, "possibleIntents": [ { "intent": "actions.intent.TEXT" } ] } ] }
В следующих фрагментах показано, как реализовать сложную карточку таблицы:
Node.js
app.intent('Advanced Table Card', (conv) => { if (!conv.screen) { conv.ask('Sorry, try this on a screen device or select the ' + 'phone surface in the simulator.'); conv.ask('Which response would you like to see next?'); return; } conv.ask('This is a table with all the possible fields.'); conv.ask(new Table({ title: 'Table Title', subtitle: 'Table Subtitle', image: new Image({ url: 'https://storage.googleapis.com/actionsresources/logo_assistant_2x_64dp.png', alt: 'Alt Text', }), columns: [ { header: 'header 1', align: 'CENTER', }, { header: 'header 2', align: 'LEADING', }, { header: 'header 3', align: 'TRAILING', }, ], rows: [ { cells: ['row 1 item 1', 'row 1 item 2', 'row 1 item 3'], dividerAfter: false, }, { cells: ['row 2 item 1', 'row 2 item 2', 'row 2 item 3'], dividerAfter: true, }, { cells: ['row 3 item 1', 'row 3 item 2', 'row 3 item 3'], }, ], buttons: new Button({ title: 'Button Text', url: 'https://assistant.google.com', }), })); conv.ask('Which response would you like to see next?'); });
Джава
@ForIntent("Advanced Table Card") public ActionResponse advancedTable(ActionRequest request) { ResponseBuilder responseBuilder = getResponseBuilder(request); if (!request.hasCapability(Capability.SCREEN_OUTPUT.getValue())) { return responseBuilder .add("Sorry, try ths on a screen device or select the phone surface in the simulator.") .add("Which response would you like to see next?") .build(); } responseBuilder .add("This is a table with all the possible fields.") .add( new TableCard() .setTitle("Table Title") .setSubtitle("Table Subtitle") .setImage( new Image() .setUrl( "https://storage.googleapis.com/actionsresources/logo_assistant_2x_64dp.png") .setAccessibilityText("Alt text")) .setButtons( Arrays.asList( new Button() .setTitle("Button Text") .setOpenUrlAction( new OpenUrlAction().setUrl("https://assistant.google.com")))) .setColumnProperties( Arrays.asList( new TableCardColumnProperties() .setHeader("header 1") .setHorizontalAlignment("CENTER"), new TableCardColumnProperties() .setHeader("header 2") .setHorizontalAlignment("LEADING"), new TableCardColumnProperties() .setHeader("header 3") .setHorizontalAlignment("TRAILING"))) .setRows( Arrays.asList( new TableCardRow() .setCells( Arrays.asList( new TableCardCell().setText("row 1 item 1"), new TableCardCell().setText("row 1 item 2"), new TableCardCell().setText("row 1 item 3"))) .setDividerAfter(false), new TableCardRow() .setCells( Arrays.asList( new TableCardCell().setText("row 2 item 1"), new TableCardCell().setText("row 2 item 2"), new TableCardCell().setText("row 2 item 3"))) .setDividerAfter(true), new TableCardRow() .setCells( Arrays.asList( new TableCardCell().setText("row 2 item 1"), new TableCardCell().setText("row 2 item 2"), new TableCardCell().setText("row 2 item 3")))))); return responseBuilder.build(); }
Node.js
if (!conv.screen) { conv.ask('Sorry, try this on a screen device or select the ' + 'phone surface in the simulator.'); conv.ask('Which response would you like to see next?'); return; } conv.ask('This is a table with all the possible fields.'); conv.ask(new Table({ title: 'Table Title', subtitle: 'Table Subtitle', image: new Image({ url: 'https://storage.googleapis.com/actionsresources/logo_assistant_2x_64dp.png', alt: 'Alt Text', }), columns: [ { header: 'header 1', align: 'CENTER', }, { header: 'header 2', align: 'LEADING', }, { header: 'header 3', align: 'TRAILING', }, ], rows: [ { cells: ['row 1 item 1', 'row 1 item 2', 'row 1 item 3'], dividerAfter: false, }, { cells: ['row 2 item 1', 'row 2 item 2', 'row 2 item 3'], dividerAfter: true, }, { cells: ['row 3 item 1', 'row 3 item 2', 'row 3 item 3'], }, ], buttons: new Button({ title: 'Button Text', url: 'https://assistant.google.com', }), })); conv.ask('Which response would you like to see next?');
Джава
ResponseBuilder responseBuilder = getResponseBuilder(request); if (!request.hasCapability(Capability.SCREEN_OUTPUT.getValue())) { return responseBuilder .add("Sorry, try ths on a screen device or select the phone surface in the simulator.") .add("Which response would you like to see next?") .build(); } responseBuilder .add("This is a table with all the possible fields.") .add( new TableCard() .setTitle("Table Title") .setSubtitle("Table Subtitle") .setImage( new Image() .setUrl( "https://storage.googleapis.com/actionsresources/logo_assistant_2x_64dp.png") .setAccessibilityText("Alt text")) .setButtons( Arrays.asList( new Button() .setTitle("Button Text") .setOpenUrlAction( new OpenUrlAction().setUrl("https://assistant.google.com")))) .setColumnProperties( Arrays.asList( new TableCardColumnProperties() .setHeader("header 1") .setHorizontalAlignment("CENTER"), new TableCardColumnProperties() .setHeader("header 2") .setHorizontalAlignment("LEADING"), new TableCardColumnProperties() .setHeader("header 3") .setHorizontalAlignment("TRAILING"))) .setRows( Arrays.asList( new TableCardRow() .setCells( Arrays.asList( new TableCardCell().setText("row 1 item 1"), new TableCardCell().setText("row 1 item 2"), new TableCardCell().setText("row 1 item 3"))) .setDividerAfter(false), new TableCardRow() .setCells( Arrays.asList( new TableCardCell().setText("row 2 item 1"), new TableCardCell().setText("row 2 item 2"), new TableCardCell().setText("row 2 item 3"))) .setDividerAfter(true), new TableCardRow() .setCells( Arrays.asList( new TableCardCell().setText("row 2 item 1"), new TableCardCell().setText("row 2 item 2"), new TableCardCell().setText("row 2 item 3")))))); return responseBuilder.build();
JSON
Обратите внимание, что приведенный ниже JSON описывает ответ веб-перехватчика.
{ "payload": { "google": { "expectUserResponse": true, "richResponse": { "items": [ { "simpleResponse": { "textToSpeech": "This is a table with all the possible fields." } }, { "tableCard": { "title": "Table Title", "subtitle": "Table Subtitle", "image": { "url": "https://storage.googleapis.com/actionsresources/logo_assistant_2x_64dp.png", "accessibilityText": "Alt Text" }, "rows": [ { "cells": [ { "text": "row 1 item 1" }, { "text": "row 1 item 2" }, { "text": "row 1 item 3" } ], "dividerAfter": false }, { "cells": [ { "text": "row 2 item 1" }, { "text": "row 2 item 2" }, { "text": "row 2 item 3" } ], "dividerAfter": true }, { "cells": [ { "text": "row 3 item 1" }, { "text": "row 3 item 2" }, { "text": "row 3 item 3" } ] } ], "columnProperties": [ { "header": "header 1", "horizontalAlignment": "CENTER" }, { "header": "header 2", "horizontalAlignment": "LEADING" }, { "header": "header 3", "horizontalAlignment": "TRAILING" } ], "buttons": [ { "title": "Button Text", "openUrlAction": { "url": "https://assistant.google.com" } } ] } }, { "simpleResponse": { "textToSpeech": "Which response would you like to see next?" } } ] } } } }
JSON
Обратите внимание, что приведенный ниже JSON описывает ответ веб-перехватчика.
{ "expectUserResponse": true, "expectedInputs": [ { "possibleIntents": [ { "intent": "actions.intent.TEXT" } ], "inputPrompt": { "richInitialPrompt": { "items": [ { "simpleResponse": { "textToSpeech": "This is a table with all the possible fields." } }, { "tableCard": { "title": "Table Title", "subtitle": "Table Subtitle", "image": { "url": "https://storage.googleapis.com/actionsresources/logo_assistant_2x_64dp.png", "accessibilityText": "Alt Text" }, "rows": [ { "cells": [ { "text": "row 1 item 1" }, { "text": "row 1 item 2" }, { "text": "row 1 item 3" } ], "dividerAfter": false }, { "cells": [ { "text": "row 2 item 1" }, { "text": "row 2 item 2" }, { "text": "row 2 item 3" } ], "dividerAfter": true }, { "cells": [ { "text": "row 3 item 1" }, { "text": "row 3 item 2" }, { "text": "row 3 item 3" } ] } ], "columnProperties": [ { "header": "header 1", "horizontalAlignment": "CENTER" }, { "header": "header 2", "horizontalAlignment": "LEADING" }, { "header": "header 3", "horizontalAlignment": "TRAILING" } ], "buttons": [ { "title": "Button Text", "openUrlAction": { "url": "https://assistant.google.com" } } ] } }, { "simpleResponse": { "textToSpeech": "Which response would you like to see next?" } } ] } } } ] }
Настройка ответов
Вы можете изменить внешний вид расширенных ответов, создав собственную тему. Если вы определите тему для своего проекта Actions, расширенные ответы в Actions вашего проекта будут оформлены в соответствии с вашей темой. Этот пользовательский брендинг может быть полезен для определения уникального внешнего вида беседы, когда пользователи вызывают ваши действия на поверхности с экраном.
Чтобы установить пользовательскую тему ответа, сделайте следующее:
- В консоли действий выберите «Разработка» > «Настройка темы» .
- Установите любой или все из следующих параметров:
- Цвет фона , который будет использоваться в качестве фона ваших карт. Как правило, для фона следует использовать светлый цвет, чтобы содержимое карточки было легко читаемо.
- Основной цвет — это основной цвет для текстов заголовков ваших карточек и элементов пользовательского интерфейса. Как правило, вы должны использовать более темный основной цвет, чтобы контрастировать с фоном.
- Семейство шрифтов описывает тип шрифта, используемый для заголовков и других заметных текстовых элементов.
- Стиль угла изображения может изменить внешний вид углов ваших карт.
- Фоновое изображение использует пользовательское изображение вместо цвета фона. Вам нужно будет предоставить два разных изображения, когда устройство Surface находится в ландшафтном или портретном режиме соответственно. Обратите внимание, что если вы используете фоновое изображение, основным цветом будет белый.
- Нажмите Сохранить .
