Explorar en Dialogflow
Haz clic en Continuar para importar nuestra muestra de respuestas en Dialogflow. Luego, sigue los pasos que se indican a continuación para implementar y probar la muestra:
- Ingresa un nombre de agente y crea un agente de Dialogflow nuevo para la muestra.
- Cuando el agente termine de importarse, haz clic en Ir al agente.
- En el menú de navegación principal, ve a Fulfillment (Entrega).
- Habilita el Editor intercalado y, luego, haz clic en Implementar. El editor contiene el código de muestra.
- En el menú de navegación principal, ve a Integraciones y, luego, haz clic en Asistente de Google.
- En la ventana modal que aparece, habilita la opción Vista previa automática de cambios 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 las interacciones del usuario con tu acción. Estos elementos visuales pueden proporcionar sugerencias para continuar una conversación.
Las respuestas enriquecidas pueden aparecer en experiencias de audio y pantalla solamente. Pueden tener 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 opcional.
También puedes consultar nuestros lineamientos de diseño de conversación para aprender a incorporar estos elementos visuales a tu acción.
Propiedades
Las respuestas enriquecidas tienen los siguientes requisitos y propiedades opcionales que puedes configurar:
- Compatible con superficies que tienen la función
actions.capability.SCREEN_OUTPUT
. - El primer elemento de una respuesta enriquecida debe ser una respuesta simple.
- Como máximo, dos respuestas simples.
- Como máximo, una tarjeta básica o
StructuredResponse
. - Como máximo, 8 chips de sugerencias.
- No se permiten los chips de sugerencias en un
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 la siguiente información:
- Imagen
- Título
- Subtítulo
- Cuerpo del texto
- Botón para vincular
- Border
Usa las tarjetas básicas principalmente para fines de visualización. Están diseñados para ser concisos, presentar información clave (o resumen) a los usuarios y permitir que estos obtengan más información si así lo desean (mediante un vínculo web).
En la mayoría de las situaciones, debes agregar chips de sugerencias debajo de las tarjetas para continuar o reorientar la conversación.
Evita repetir la información que se presenta en la tarjeta del cuadro de chat a cualquier costo.
Propiedades
El tipo de respuesta básica de la tarjeta tiene los siguientes requisitos y propiedades opcionales que puedes configurar:
- Compatible con superficies que tienen la función
actions.capability.SCREEN_OUTPUT
. - Texto con formato (obligatorio si no hay una imagen)
- Texto sin formato de forma predeterminada.
- No debe contener un vínculo.
- Límite de 10 líneas con una imagen, límite de 15 líneas sin una imagen. Se trata de unos 500 caracteres (con imagen) o 750 (sin imagen). Los teléfonos de pantalla más pequeña también truncan el texto antes que los más grandes. Si el texto contiene demasiadas líneas, se truncará en la última pausa de 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 deben tener 192 dp de alto.
- Si la relación de aspecto de la imagen es diferente de la de la pantalla, esta se centra 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
- Fuente y tamaño fijos
- Como máximo, una línea; los caracteres adicionales están truncados.
- La altura de la tarjeta se contrae si no se especifica un título.
- Subtítulo
- Texto sin formato
- Fuente y tamaño de fuente fijos
- Como máximo, una línea; los caracteres adicionales están truncados.
- La altura de la tarjeta se contrae si no se especifica un subtítulo.
- Botón de vínculo
- El título del vínculo es obligatorio
- Como máximo, un vínculo
- Se permiten 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. Cuando el usuario presiona el vínculo, se lo envía al vínculo, mientras que el cuerpo principal de la tarjeta permanece inactivo.
- Borde
- Se puede ajustar el borde entre la tarjeta y el contenedor de la imagen a fin de personalizar la presentación de la tarjeta básica.
- Se configura configurando la propiedad de la 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 JSON a continuación 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 JSON a continuación 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 seleccionar una tarjeta 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 todas las tarjetas están habilitadas para AMP). El carrusel de navegación también persiste en la superficie de Asistente del usuario para navegar más tarde.
Propiedades
El tipo de respuesta de carrusel de navegación tiene los siguientes requisitos y propiedades opcionales que puedes configurar:
- Compatible con plataformas que tienen las capacidades
actions.capability.SCREEN_OUTPUT
yactions.capability.WEB_BROWSER
. Por el momento, este tipo de respuesta no está disponible en pantallas inteligentes. - Carrusel de navegación
- Máximo de diez mosaicos.
- Mínimo de dos mosaicos
- Todas las tarjetas del carrusel deben vincularse a contenido web (se recomienda el contenido de AMP).
- Para que el usuario pueda acceder a un visor de AMP, la
urlHintType
en los mosaicos de contenido de AMP debe establecerse como "AMP_CONTENT".
- Para que el usuario pueda acceder a un visor de AMP, la
- Navegación por los mosaicos de carrusel
- Coherencia de tarjetas (obligatoria):
- Todos los mosaicos de un carrusel de navegación deben tener los mismos componentes. Por ejemplo, si un mosaico tiene un campo de imagen, el resto de los mosaicos del carrusel también deben tener campos de imagen.
- Si todas las tarjetas del carrusel de navegación se vinculan a contenido habilitado para AMP, se dirige al usuario a un navegador de AMP con funciones adicionales. Si algún mosaico vincula a contenido que no es de AMP, todos los mosaicos dirigen a los usuarios a un navegador web.
- Imagen (opcional)
- La imagen debe tener 128 dp de alto x 232 dp de ancho.
- Si la relación de aspecto de la imagen no coincide con el cuadro de límite de la imagen, la imagen se centrará con barras en ambos lados. En los smartphones, la imagen se centra en un cuadrado con esquinas redondeadas.
- Si el vínculo de una imagen está roto, se usa una imagen de marcador de posición.
- El texto alternativo es obligatorio 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 por voz).
- Máximo de dos líneas de texto.
- Tamaño de fuente 16 sp.
- Descripción (opcional)
- Las mismas opciones de formato que la tarjeta de texto básica.
- Máximo de cuatro líneas de texto.
- Truncados con puntos suspensivos (...)
- Tamaño de fuente 14sp, color gris.
- Pie de página (opcional)
- Fuente y tamaño de fuente fijos
- Máximo de una línea de texto.
- Truncados con puntos suspensivos (...)
- Están fijas en la parte inferior, por lo que los mosaicos con menos líneas de texto del cuerpo pueden tener espacio en blanco sobre el subtexto.
- Tamaño de fuente 14sp, color gris.
- Coherencia de tarjetas (obligatoria):
- Interacción
- El usuario puede desplazarse verticalmente para ver los elementos.
- Presionar la tarjeta: Cuando el usuario presiona un elemento, se lo redirecciona a un navegador en el que se muestra la página vinculada.
- Entrada de voz
- Comportamiento del micrófono
- El micrófono no se vuelve a activar cuando se envía un carrusel de navegación al usuario.
- El usuario puede presionar el micrófono o invocar al Asistente ("Hey Google") para volver a activarlo.
- 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 continuar la conversación después, te recomendamos que agregues chips de sugerencias debajo del carrusel.
Nunca repitas las opciones que se presentan en la lista como chips de sugerencias. Los chips en este contexto se usan para reorientar la conversación (no para la selección de la opción).
Al igual que con las listas, la burbuja de chat que acompaña a la tarjeta del carrusel es un subconjunto del audio (TTS/SSML). En este caso, el audio (TTS/SSML) integra el primer mosaico del carrusel, por lo que no recomendamos leer todos los elementos del carrusel. Es mejor mencionar el primer artículo y el motivo por el que está en él (por ejemplo, el más popular, el más reciente comprado, el más comentado).
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 JSON a continuación 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 JSON a continuación 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" } ] } ] }
Manejo del elemento seleccionado
No se necesita completar la entrega para las interacciones del usuario con los elementos del carrusel de navegación, ya que el carrusel controla el traspaso del navegador. Ten en cuenta que el micrófono no se volverá a activar después de que el usuario interactúe con un elemento del carrusel de navegación, por lo que debes finalizar la conversación o incluir chips de sugerencias en la respuesta, como se indica en la guía anterior.
Chips de sugerencias

Usa los chips de sugerencias para sugerir respuestas a fin de continuar o reorientar la conversación. Si durante la conversación hay un llamado a la acción principal, considera enumerarlo como el primer chip de sugerencias.
Siempre que sea posible, debes incorporar una sugerencia clave como parte de la burbuja de chat, pero hazlo solo si la respuesta o la conversación de chat se sienten naturales.
Propiedades
Los chips de sugerencias tienen los siguientes requisitos y propiedades opcionales que puedes configurar:
- Compatible con superficies que tienen la función
actions.capability.SCREEN_OUTPUT
. - Para vincular chips de sugerencias a la Web, las plataformas también deben tener la capacidad
actions.capability.WEB_BROWSER
. Por el momento, esta función no está disponible en pantallas inteligentes. - 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 JSON a continuación 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 JSON a continuación 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 superior al límite de 240 segundos del SSML. El componente principal de una respuesta 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 durante 30 segundos
- Permite ver la duración total del contenido multimedia.
- Consulta un indicador de progreso para 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 diciendo frases como: "Hey Google, sube el volumen" o "Hey Google, establece el volumen al 50%". Los intents de tu acción tienen prioridad si controlan frases de entrenamiento similares. Permite que Asistente maneje estas solicitudes de usuario, a menos que tu acción tenga un motivo específico.
Propiedades
Las respuestas multimedia tienen los siguientes requisitos y propiedades opcionales que puedes configurar:
- Compatible con superficies con la capacidad
actions.capability.MEDIA_RESPONSE_AUDIO
. - El audio para la reproducción debe estar en un archivo
.mp3
con el formato correcto. No se admite la transmisión en vivo. - El archivo multimedia para la reproducción debe especificarse como una URL HTTPS.
- Imagen (opcional)
- De forma opcional, puedes incluir un ícono o una imagen.
- Ícono
- Tu ícono aparece como una miniatura sin bordes a la derecha de la tarjeta del reproductor de contenido multimedia.
- El tamaño debe ser de 36 x 36 dp. Las imágenes de mayor tamaño se ajustan para adaptarse.
- Imagen
- El contenedor de la imagen tendrá 192 dp de altura.
- Tu imagen aparece en la parte superior de la tarjeta del reproductor de contenido multimedia y abarca todo el ancho de la tarjeta. La mayoría de las imágenes aparecerán con barras en la parte superior o laterales.
- Se permiten los GIF en movimiento.
- Debes especificar la fuente de la imagen como una URL.
- El texto alternativo es obligatorio en todas las imágenes.
Comportamiento en plataformas
Las respuestas multimedia son compatibles con teléfonos Android y Google Home. El comportamiento de las respuestas multimedia depende de la superficie en la que los usuarios interactúan con tus acciones.
En teléfonos Android, los usuarios pueden ver las respuestas multimedia cuando se cumple alguna de las siguientes condiciones:
- Asistente de Google está en primer plano y la pantalla del teléfono está encendida.
- El usuario sale del Asistente de Google mientras se reproduce un audio y vuelve al Asistente de Google durante los 10 minutos posteriores a la finalización de la reproducción. Cuando regresa al Asistente de Google, el usuario ve la tarjeta multimedia y los chips de sugerencias.
- Asistente permite a los usuarios controlar el volumen del dispositivo en tu acción de conversación diciendo "sube el volumen" o "establece el volumen al 50%". Si tienes intents que controlan frases de entrenamiento similares, los intents tienen prioridad. Te recomendamos que permitas que Asistente controle estas solicitudes de usuario, a menos que tu acción tenga un motivo específico.
Los controles de contenido multimedia están disponibles mientras el teléfono está bloqueado. En Android, los controles también aparecen en el área de notificaciones.

Código de muestra
En la siguiente muestra de código, se indica cómo actualizar las respuestas enriquecidas para incluir 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 JSON a continuación 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 JSON a continuación 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 contenga un mediaObject
dentro del array de elementos de la respuesta enriquecida. Una respuesta multimedia admite un solo objeto multimedia. Un objeto multimedia debe incluir la URL de contenido del archivo de audio. De manera opcional, un objeto multimedia puede incluir un nombre, un subtexto (descripción) y una URL de ícono o imagen.
En teléfonos y Google Home, cuando tu acción completa la reproducción de audio, Asistente de Google comprueba 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 respuesta no es un FinalResponse
.
Cómo controlar la devolución de llamada después de que finaliza la reproducción
Tu acción debería controlar el intent actions.intent.MEDIA_STATUS
a fin de solicitar al usuario que realice un seguimiento (por ejemplo, para reproducir otra canción). La acción recibe esta devolución de llamada una vez que se completa la reproducción de contenido multimedia. En la devolución de llamada, el argumento MEDIA_STATUS
contiene información de estado sobre el contenido multimedia actual. El valor del estado será FINISHED
o STATUS_UNSPECIFIED
.
Usa Dialogflow
Si deseas realizar una ramificación de conversación en Dialogflow, deberás configurar un contexto de entrada de actions_capability_media_response_audio
en el intent para asegurarte de que solo se active en plataformas compatibles con una respuesta de medios.
Cómo compilar tu entrega
En el siguiente fragmento de código, se muestra cómo escribir el código de entrega de tu acción. Si usas Dialogflow, reemplaza actions.intent.MEDIA_STATUS
por el nombre de la acción especificado en el intent que recibe el evento 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 JSON a continuación 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 JSON a continuación 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 de deportes, resultados de elecciones y vuelos). Puedes definir las columnas y las filas (hasta 3 cada una) que el Asistente debe mostrar en la tarjeta de tu tabla. También puedes definir columnas y filas adicionales junto con su priorización.
Las tablas son diferentes de las listas verticales porque las tablas muestran datos estáticos y no son interactivas, como los elementos de lista.

Propiedades
Las tarjetas de la tabla tienen los siguientes requisitos y propiedades opcionales que puedes configurar:
- Compatible con superficies que tienen la función
actions.capability.SCREEN_OUTPUT
.
En la siguiente sección, se resume cómo puedes personalizar los elementos en una tarjeta de tabla.
Nombre | Es opcional | Se puede personalizar | Notas de personalización |
---|---|---|---|
title |
Sí | Sí | Es el título general de la tabla. Se debe establecer si se configuró el subtítulo. 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 fila de la tabla. Consiste en un array de objetos Se garantiza que se mostrarán las primeras 3 filas, pero es posible que otras no aparezcan en ciertas superficies. Realiza pruebas con el simulador para ver qué filas se muestran en una plataforma determinada. En plataformas compatibles con la función |
ColumnProperties |
Sí | Sí | Encabezado y alineación de una columna Consiste en una propiedad header (que representa el texto del encabezado de una columna) y una propiedad horizontal_alignment (del tipo HorizontalAlignment ). |
Cell |
No | Sí | Describe una celda en una fila. Cada celda contiene una string que representa un valor de texto. Puedes personalizar el texto de la celda. |
Button |
Sí | Sí | Es un objeto de botón que suele aparecer en la parte inferior de una tarjeta. Una tarjeta de la tabla 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 no se especifica, 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 JSON a continuación 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 JSON a continuación 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 JSON a continuación 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 JSON a continuación 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?" } } ] } } } ] }
Personaliza tus respuestas
Puedes crear un tema personalizado para cambiar la apariencia de las respuestas enriquecidas. Si defines un tema para tu proyecto de Actions, las respuestas enriquecidas en las Actions de tu proyecto se diseñarán según tu tema. Este desarrollo de la marca personalizado puede ser útil para definir una apariencia y un estilo únicos en la conversación cuando los usuarios invocan tus Acciones en una superficie con una pantalla.
Para configurar un tema de respuesta personalizada, haz lo siguiente:
- En la Consola de Actions, ve a Desarrollo > Personalización de temas.
- Establece una o varias de las siguientes opciones:
- Color de fondo para usar como fondo de sus tarjetas En general, debes usar un color claro para el fondo de modo que el contenido de la tarjeta sea fácil de leer.
- El Color principal es el color principal de los textos del encabezado y de los elementos de la IU de tus tarjetas. En general, debes usar un color primario más oscuro para contrastar con el fondo.
- La familia de fuentes describe el tipo de fuente que se usa para los títulos y otros elementos de texto destacados.
- El estilo de la esquina de la imagen puede alterar el aspecto de las esquinas de tus tarjetas.
- La imagen de fondo usa una imagen personalizada en lugar del color de fondo. Deberás proporcionar dos imágenes diferentes para cuando el dispositivo de la superficie esté en modo horizontal o vertical, respectivamente. Ten en cuenta que, si usas una imagen de fondo, el color principal se establece como blanco.
- Haz clic en Guardar.
