Explorar en Dialogflow
Haz clic en Continuar para importar nuestra muestra de respuestas en Dialogflow. Luego, sigue la para implementar y probar la muestra:
- Ingresa un nombre de agente y crea un agente de Dialogflow nuevo para la muestra.
- Después de que el agente termine de importar, haz clic en Ir al agente.
- En el menú de navegación principal, ve a Entrega.
- Habilita el Editor intercalado y, luego, haz clic en Implementar. El editor contiene la muestra código.
- En el menú de navegación principal, ve a Integrations (Integraciones) y, luego, haz clic en Google Asistente
- En la ventana modal que aparece, habilita Cambios en la vista previa automática y haz clic en Probar. para abrir el simulador de Actions.
- En el simulador, ingresa
Talk to my test app
para probar la muestra.
Usa una respuesta enriquecida si quieres mostrar elementos visuales para mejorar el rendimiento interacciones con tu Acción. Estos elementos visuales pueden brindar pistas sobre cómo para continuar una conversación.
Las respuestas enriquecidas pueden aparecer en solo pantalla o en experiencias de audio y pantalla. Ellas puede contener los siguientes componentes:
- Una o dos respuestas simples (burbujas de chat).
- Una tarjeta básica opcional.
- Chips de sugerencias opcionales.
- Un chip de vínculo de salida opcional.
También puedes revisar nuestros lineamientos de diseño de conversación para obtener más información cómo incorporar estos elementos visuales en tu Acción.
Propiedades
Las respuestas enriquecidas tienen los siguientes requisitos y son opcionales que puedes configurar:
- Es compatible con plataformas que admiten la función
actions.capability.SCREEN_OUTPUT
. - El primer elemento de una respuesta enriquecida debe ser una respuesta simple.
- Dos respuestas simples como máximo.
- Como máximo, una tarjeta básica o
StructuredResponse
. - 8 chips de sugerencias como máximo.
- No se permiten chips de sugerencias en una
FinalResponse
- Actualmente, no se admite la vinculación a la Web desde pantallas inteligentes.
En las siguientes secciones, se muestra cómo compilar varios tipos de respuestas enriquecidas.
Tarjeta básica
Una tarjeta básica muestra información que puede incluir lo siguiente:
- Imagen
- Título
- Subtítulo
- Cuerpo del texto
- Botón para vincular
- Borde
Usar tarjetas básicas principalmente para fines de visualización Están diseñados para ser concisos, para presentar información clave (o resumida) a los usuarios y permitirles que aprendan más si lo deseas (mediante un vínculo web).
En la mayoría de las situaciones, debes agregar chips de sugerencias a continuación. las tarjetas para continuar o reorientar la conversación.
Evitar repetir en absoluto la información presentada en la tarjeta en el cuadro de chat de los costos.
Propiedades
El tipo de respuesta de tarjeta básica tiene los siguientes requisitos y es opcional que puedes configurar:
- Es compatible con plataformas que admiten la función
actions.capability.SCREEN_OUTPUT
. - Texto con formato (obligatorio si no hay una imagen)
- Texto sin formato de forma predeterminada.
- No debe incluir un vínculo.
- Límite de 10 líneas con una imagen y límite de 15 líneas sin una imagen. Se trata de 500 (con imagen) o 750 (sin imagen). Teléfonos con pantallas más pequeñas también trunca el texto antes que en los teléfonos con pantallas más grandes. Si el texto contiene demasiado muchas líneas, se trunca en la última palabra con puntos suspensivos.
- Se admite un subconjunto limitado de Markdown:
- Nueva línea con doble espacio seguido de \n
**bold**
*italics*
- Imagen (obligatoria si no hay texto con formato)
- Todas las imágenes se forzaron a tener una altura de 192 dp.
- Si la relación de aspecto de la imagen es diferente a la de la pantalla, la imagen es centrado con barras grises en los bordes verticales u horizontales.
- La fuente de la imagen es una URL.
- Se permiten los GIF en movimiento.
Opcional
- Título
- Texto sin formato
- Se corrigieron la fuente y el tamaño.
- Una línea como máximo; se truncan los caracteres adicionales.
- La altura de la tarjeta se contrae si no se especifica un título.
- Subtítulo
- Texto sin formato
- Se corrigieron la fuente y el tamaño de fuente.
- Una línea como máximo; se truncan los caracteres adicionales.
- La altura de la tarjeta se contrae si no se especifica ningún subtítulo.
- Botón de vínculo
- El título del vínculo es obligatorio
- Un vínculo como máximo
- Se permiten los vínculos a sitios fuera del dominio del desarrollador.
- El texto del vínculo no puede ser engañoso. Esto se verifica en el proceso de aprobación.
- Una tarjeta básica no tiene capacidades de interacción sin un vínculo. Presionando el vínculo envía al usuario al vínculo, mientras que el cuerpo principal de la tarjeta permanece inactiva.
- Borde
- El borde entre la tarjeta y el contenedor de imágenes se puede ajustar para personalizar la presentación de tu tarjeta básica.
- Se configura con la propiedad de string JSON
imageDisplayOptions
Código de muestra
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?'); });
Java
@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?');
Java
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
Ten en cuenta que el siguiente JSON describe una respuesta de webhook.
{ "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
Ten en cuenta que el siguiente JSON describe una respuesta de webhook.
{ "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?" } } ] } } } ] }
Carrusel de navegación
Un carrusel de navegación es una respuesta enriquecida que permite a los usuarios desplazarse verticalmente y selecciona un mosaico de una colección. Los carruseles de navegación están diseñados específicamente para contenido web abriendo la tarjeta seleccionada en un navegador web (o un navegador de AMP) si todos los mosaicos están habilitados para AMP). El carrusel de navegación también persiste en la plataforma de Asistente del usuario para navegar más tarde.
Propiedades
El tipo de respuesta del carrusel de navegación tiene los siguientes requisitos y es opcional que puedes configurar:
- Compatible con plataformas que tienen
actions.capability.SCREEN_OUTPUT
. yactions.capability.WEB_BROWSER
. Este tipo de respuesta es no está disponible actualmente en pantallas inteligentes. - Carrusel de navegación
- Un máximo de diez mosaicos
- Un mínimo de dos mosaicos.
- Todos los mosaicos del carrusel deben estar vinculados a contenido web (contenido de AMP)
(recomendado).
- Para que se dirija al usuario a un visor de AMP, el elemento
urlHintType
en mosaicos de contenido de AMP debe establecerse en "AMP_CONTENT".
- Para que se dirija al usuario a un visor de AMP, el elemento
- Navegación por los mosaicos del carrusel
- Coherencia con los mosaicos (obligatorio):
- Todos los mosaicos de un carrusel de navegación deben tener los mismos componentes. Por ejemplo, si una tarjeta tiene un campo de imagen, el resto de los mosaicos del carrusel deben tener campos de imagen.
- Si todos los mosaicos del carrusel de navegación vinculan a contenido habilitado para AMP, se dirige al usuario a un navegador de AMP con funciones adicionales. Si alguna tarjeta se vincula a contenido que no es de AMP, todas las tarjetas dirigen a los usuarios. a un navegador web.
- Imagen (opcional)
- La imagen se fuerza para que sea de 128 dp de alto x 232 dp de ancho.
- Si la relación de aspecto no coincide con el cuadro de límite de la imagen, luego, la imagen se centra con barras a cada lado. En los smartphones la imagen está centrada en un cuadrado con esquinas redondeadas.
- Si el vínculo de una imagen no funciona, se usa una imagen de marcador de posición.
- Se requiere texto alternativo en una imagen.
- Título (obligatorio)
- Las mismas opciones de formato que la tarjeta de texto básica.
- Los títulos deben ser únicos (para admitir la selección de voz).
- Se permite un máximo de dos líneas de texto.
- Tamaño de la fuente: 16 sp.
- Descripción (opcional)
- Las mismas opciones de formato que la tarjeta de texto básica.
- Se permite un máximo de cuatro líneas de texto.
- Truncada con puntos suspensivos (...)
- Tamaño de fuente 14 sp, color gris
- Pie de página (opcional)
- Se corrigieron la fuente y el tamaño de fuente.
- Se permite un máximo de una línea de texto.
- Truncada con puntos suspensivos (...)
- Anclados en la parte inferior, por lo que los mosaicos con menos líneas de cuerpo de texto pueden tener un espacio en blanco sobre el subtexto.
- Tamaño de fuente 14 sp, color gris
- Coherencia con los mosaicos (obligatorio):
- Interacción
- El usuario puede desplazarse verticalmente para ver los elementos.
- Presionar la tarjeta: al presionar un elemento, el usuario se dirige a un navegador y muestra la página vinculada.
- Entrada de voz
- Comportamiento del micrófono
- El micrófono no se vuelve a abrir cuando se envía un carrusel de navegación al usuario.
- El usuario aún puede presionar el micrófono o invocar al Asistente ("Hey Google"). para volver a abrir el micrófono.
- Comportamiento del micrófono
Orientación
De forma predeterminada, el micrófono permanece cerrado después de que se envía un carrusel de navegación. Si quieres Para continuar la conversación, te recomendamos encarecidamente agregar chips de sugerencias debajo del carrusel.
Nunca repitas las opciones presentadas en la lista como chips de sugerencias. Patatas fritas este contexto se utilizan para reorientar la conversación (no para la selección de opciones).
Al igual que con las listas, el cuadro de chat que acompaña a la tarjeta del carrusel es subconjunto del audio (TTS/SSML). El audio (TTS/SSML) integra los primeros mosaico en el carrusel, ni evitar la lectura de todos los elementos del carrusel. Es mejor mencionar el primer elemento y el motivo está ahí (por ejemplo, el más popular, el que se compró más recientemente, el de las que hablamos).
Código de muestra
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', }), ], })); });
Java
@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', }), ], }));
Java
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
Ten en cuenta que el siguiente JSON describe una respuesta de webhook.
{ "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
Ten en cuenta que el siguiente JSON describe una respuesta de webhook.
{ "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" } ] } ] }
Procesando el artículo seleccionado
No es necesario realizar un seguimiento de las interacciones de los usuarios con el carrusel de exploración. ya que el carrusel se encarga del traspaso del navegador. Ten en cuenta que el micrófono no volverá a abrirse después de que el usuario interactúe con un elemento del carrusel de navegación, por lo que deberían terminar la conversación o incluir chips de sugerencias en tu respuesta, según las indicaciones anteriores.
Chips de sugerencias
Usa chips de sugerencias para sugerir respuestas y, así, continuar o reorientar la conversación. Si durante la conversación hay un llamado a la acción principal, considera enumerar como el primer chip de sugerencias.
Siempre que sea posible, debes incorporar una sugerencia clave como parte del chat. pero solo si la respuesta o la conversación de chat te parecen naturales.
Propiedades
Estos chips tienen los siguientes requisitos y opcionales que puedes configurar:
- Es compatible con plataformas que admiten la función
actions.capability.SCREEN_OUTPUT
. - Para vincular chips de sugerencias a la Web, las plataformas también deben tener la
actions.capability.WEB_BROWSER
. Por el momento, esta función disponible en pantallas inteligentes. - Se admite un máximo de ocho chips.
- La longitud máxima del texto es de 25 caracteres.
Solo admite texto sin formato.
Código de muestra
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?'); ; });
Java
@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?');
Java
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
Ten en cuenta que el siguiente JSON describe una respuesta de webhook.
{ "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
Ten en cuenta que el siguiente JSON describe una respuesta de webhook.
{ "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/" } } } } ] }
Respuestas multimedia
Las respuestas multimedia permiten que tus acciones reproduzcan contenido de audio con una duración de reproducción mayores que el límite de 240 segundos del SSML. El componente principal de un contenido multimedia es la tarjeta de una sola pista. La tarjeta le permite al usuario realizar estas operaciones:
- Volver a reproducir los últimos 10 segundos
- Avanzar 30 segundos.
- Consulta la duración total del contenido multimedia.
- Ver un indicador de progreso de la reproducción de audio
- Consulta el tiempo de reproducción transcurrido.
Las respuestas multimedia admiten los siguientes controles de audio para la interacción por voz:
- "Hey Google, reproduce".
- "Hey Google, pausa".
- "Hey Google, detente".
- "Hey Google, vuelve a empezar".
Los usuarios también pueden controlar el volumen con frases como "Hey Google, enciende el sube el volumen" o "Hey Google, sube el volumen al 50%". en tus La acción tiene prioridad si manejan frases de entrenamiento similares. Permitir Asistente Administrar estas solicitudes de usuario, a menos que tu Acción tenga un motivo específico para hacerlo
Propiedades
Las respuestas multimedia tienen los siguientes requisitos y propiedades opcionales que que puedes configurar:
- Compatible con plataformas con
actions.capability.MEDIA_RESPONSE_AUDIO
. de recuperación ante desastres. - El audio de reproducción debe estar en un archivo
.mp3
con el formato correcto. Transmisiones en vivo no se admite la transmisión. - El archivo multimedia para la reproducción debe especificarse como una URL HTTPS.
- Imagen (opcional)
- De manera opcional, puedes incluir un ícono o una imagen.
- Ícono
- El ícono aparece como una miniatura sin bordes a la derecha del contenido multimedia. tarjeta de jugador.
- El tamaño debe ser de 36 × 36 dp. El tamaño de las imágenes más grandes se ajusta para ajustarse.
- Imagen
- El contenedor de la imagen será de 192 dp.
- Tu imagen aparece en la parte superior de la tarjeta del reproductor multimedia y abarca ancho total de la tarjeta. La mayoría de las imágenes aparecerán con barras a lo largo del la parte superior o los lados.
- Se permiten los GIF en movimiento.
- Debes especificar la fuente de la imagen como una URL.
- Se requiere texto alternativo en todas las imágenes.
Comportamiento en plataformas
Las respuestas multimedia son compatibles con teléfonos Android y Google Home. El El comportamiento de las respuestas multimedia depende de la superficie en la que interactúan los usuarios. con tus Actions.
En teléfonos Android, los usuarios pueden ver las respuestas multimedia cuando cualquiera de estas condiciones se cumplen:
- Asistente de Google está en primer plano, y la pantalla del teléfono está encendida.
- El usuario sale de Asistente de Google mientras se reproduce el audio y vuelve a Asistente de Google dentro de los 10 minutos posteriores a que se complete la reproducción Al volver a Asistente de Google, el usuario ve la tarjeta multimedia y los chips de sugerencias.
- El Asistente permite que los usuarios controlen el volumen del dispositivo en tu acción de conversación diciendo cosas como "sube el volumen" o "establece volumen al 50%". Si tienes intents que manejan frases de entrenamiento similares, tus intents tendrán prioridad. Te recomendamos que permitas que Asistente se encargue de estas de usuario, a menos que tu Acción tenga un motivo específico.
Los controles multimedia están disponibles mientras el teléfono está bloqueado. En Android, los controles también aparecerán en el área de notificación.
Código de muestra
En la siguiente muestra de código, se muestra cómo puedes actualizar tus respuestas enriquecidas para incluyen contenido multimedia.
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'])); });
Java
@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']));
Java
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
Ten en cuenta que el siguiente JSON describe una respuesta de webhook.
{ "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
Ten en cuenta que el siguiente JSON describe una respuesta de webhook.
{ "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" } ] } } } ] }
Orientación
Tu respuesta debe incluir un mediaResponse
con un mediaType
de AUDIO
.
que contiene un mediaObject
dentro del array de elementos de la respuesta enriquecida. Un elemento multimedia
admite un solo objeto multimedia. Un objeto multimedia debe incluir el contenido
Es la URL del archivo de audio. Un objeto multimedia puede incluir, de manera opcional, un nombre, un subtexto
(descripción) y una URL de ícono o imagen.
En los teléfonos y Google Home, cuando la acción finalice la reproducción de audio,
Asistente de Google verifica si la respuesta multimedia es FinalResponse
.
De lo contrario, envía una devolución de llamada a tu entrega, lo que te permite responder al
usuario.
Tu acción debe incluir chips de sugerencias si la
no es FinalResponse
.
Cómo controlar la devolución de llamada después de completar la reproducción
Tu acción debe controlar el intent actions.intent.MEDIA_STATUS
para solicitar
al usuario para hacer un seguimiento (por ejemplo, para reproducir otra canción). Tu Acción recibe
esta devolución de llamada una vez que se complete la reproducción de contenido multimedia. En la devolución de llamada, el
El argumento MEDIA_STATUS
contiene información de estado sobre el contenido multimedia actual. El
el valor de estado será FINISHED
o STATUS_UNSPECIFIED
.
Usa Dialogflow
Si quieres realizar una ramificación de conversación en Dialogflow, deberás
configura un contexto de entrada de actions_capability_media_response_audio
en el
para asegurarte de que solo se active en plataformas que admitan una respuesta multimedia.
Cómo crear tu entrega
El siguiente fragmento de código muestra cómo podrías escribir el código de entrega para tu
Acción. Si usas Dialogflow, reemplaza actions.intent.MEDIA_STATUS
.
con el nombre de acción especificado en el intent que recibe el
actions_intent_MEDIA_STATUS
(por ejemplo, “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?'); });
Java
@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?'); });
Java
@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
Ten en cuenta que el siguiente JSON describe una solicitud de webhook.
{ "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
Ten en cuenta que el siguiente JSON describe una solicitud de webhook.
{ "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" }
Tarjetas de mesa
Las tarjetas de tabla te permiten mostrar datos tabulares en tu respuesta (por ejemplo, posiciones deportivas, resultados de elecciones y vuelos). Puedes definir columnas y filas (hasta 3 cada una) que el Asistente debe mostrar en la tarjeta de la tabla. También puedes definir columnas y filas adicionales junto con su priorización.
Las tablas son diferentes de las listas verticales porque muestran datos estáticos y como los elementos de lista.
Propiedades
Las tarjetas de tabla tienen los siguientes requisitos y propiedades opcionales que puedes configurar:
- Es compatible con plataformas que admiten la función
actions.capability.SCREEN_OUTPUT
.
En la siguiente sección, se resume cómo puedes personalizar los elementos de una tabla. tarjeta.
Nombre | Es opcional | Se puede personalizar | Notas de personalización |
---|---|---|---|
title |
Sí | Sí | Título general de la tabla. Se debe establecer si se configuraron los subtítulos. Puedes personalizar la familia de fuentes y el color. |
subtitle |
Sí | No | Subtítulo de la tabla. |
image |
Sí | Sí | Imagen asociada con la tabla. |
Row |
No | Sí |
Datos de las filas de la tabla. Consiste en un array de Se garantiza que se mostrarán las primeras 3 filas, pero es posible que otras no en determinadas plataformas. Prueba con el simulador para ver qué filas se muestran en un determinado
en una superficie determinada. En plataformas que admiten |
ColumnProperties |
Sí | Sí | Encabezado y alineación para una columna. Consiste en un header
(que representa el texto del encabezado de una columna) y una
Propiedad horizontal_alignment (de tipo
HorizontalAlignment ). |
Cell |
No | Sí | Describe una celda en una fila. Cada celda contiene una cadena que representa un valor de texto. Puedes personalizar el texto de la celda. |
Button |
Sí | Sí | Objeto de botón que suele aparecer en la parte inferior de una tarjeta. Una mesa la tarjeta solo puede tener 1 botón. Puedes personalizar el color del botón. |
HorizontalAlignment |
Sí | Sí | Alineación horizontal del contenido dentro de la celda. Los valores pueden ser
LEADING , CENTER o TRAILING . Si
sin especificar, el contenido se alinea con el borde inicial de la celda. |
Código de muestra
En los siguientes fragmentos, se muestra cómo implementar una tarjeta de tabla simple:
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?'); });
Java
@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?');
Java
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
Ten en cuenta que el siguiente JSON describe una respuesta de webhook.
{ "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
Ten en cuenta que el siguiente JSON describe una respuesta de webhook.
{ "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" } ] } ] }
En los siguientes fragmentos, se muestra cómo implementar una tarjeta de tabla compleja:
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?'); });
Java
@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?');
Java
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
Ten en cuenta que el siguiente JSON describe una respuesta de webhook.
{ "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
Ten en cuenta que el siguiente JSON describe una respuesta de webhook.
{ "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?" } } ] } } } ] }
Cómo personalizar tus respuestas
Para cambiar el aspecto de tus respuestas enriquecidas, crea un tema personalizado. Si defines un tema para tu proyecto de acciones, las respuestas enriquecidas a través de las Acciones de tu proyecto tendrán un estilo según tu tema. Este desarrollo de la marca personalizado puede ser útil para definir un aspecto único en la conversación cuando los usuarios invocar tus acciones en una superficie con una pantalla.
Para establecer un tema de respuesta personalizado, haz lo siguiente:
- En la Consola de Actions, ve a Desarrollar > Personalización de temas.
- Configura alguna de las siguientes opciones o todas ellas:
- Color de fondo para usar como fondo en tus tarjetas. En general, debes usar un color claro como fondo para que la imagen de la tarjeta del contenido sea fácil de leer.
- El color principal es el color principal de las tarjetas IU y textos de encabezado o de terceros. En general, debes usar un color primario más oscuro para contrastar en segundo plano.
- La familia de fuentes describe el tipo de fuente que se utiliza en los títulos y otras los elementos de texto destacados.
- El estilo de la esquina de la imagen puede alterar el aspecto de las tarjetas esquinas.
- La imagen de fondo utiliza una imagen personalizada en lugar del fondo color. Deberás proporcionar dos imágenes diferentes para cuando de superficie esté en modo horizontal o vertical, respectivamente. Ten en cuenta que si usas una imagen de fondo, el color primario se establece en blanco.
- Haz clic en Guardar.