Abrir diálogos interactivos

En esta guía, se describe cómo implementar diálogos para tu app de Chat.

Los diálogos son interfaces basadas en tarjetas y con ventanas que las apps de chat abren para interactuar con los usuarios. Para ayudar a los usuarios a completar procesos de varios pasos, las apps pueden abrir diálogos secuenciales.

Los diálogos son útiles para muchos tipos de interacciones del usuario, como los siguientes:

  • Recopilación de información de los usuarios
  • Autentica usuarios con servicios web
  • Configura la app de Chat

Requisitos previos

Node.js

Apps Script

Python

Cómo funcionan los diálogos

Cuando un usuario hace clic en un botón de una tarjeta o emite un comando de barra, la app de Chat puede abrir un diálogo para interactuar con él.

Haz clic en un botón de una tarjeta para abrir un cuadro de diálogo.
Figura 1: Haz clic en un botón de una tarjeta para abrir un diálogo.
Haz clic en un botón de una tarjeta para abrir un cuadro de diálogo.
Figura 2: Emite un comando de barra para abrir un diálogo.

El diálogo facilita la interacción del usuario, ya que permite que los usuarios ingresen información con widgets, como campos de entrada de texto. Cuando recopilan mucha información de los usuarios, las apps de chat pueden abrir diálogos secuenciales.

Un cuadro de diálogo con una variedad de widgets diferentes.
Figura 3: Un diálogo abierto que le solicita al usuario que agregue un contacto.
Un cuadro de diálogo con una variedad de widgets diferentes.
Figura 4: Un segundo diálogo le solicita más información al usuario.

Cuando finalice, la app de chat recibirá los valores que los usuarios ingresaron en el diálogo como JSON. Informa a los usuarios que su interacción tuvo éxito mediante un mensaje de texto o una tarjeta.

Abrir un diálogo

Tu app de Chat puede abrir un diálogo en respuesta a un usuario:

Cuando un usuario solicita un diálogo, tu app de Chat recibe una Event de Google Chat en la cual se realiza lo siguiente:

  • isDialogEvent es true.
  • DialogEventType especifica si un usuario abre un diálogo (REQUEST_DIALOG), hace clic en un botón de un diálogo (SUBMIT_DIALOG) o cancela un diálogo (CANCEL_DIALOG).

Por ejemplo, cuando un usuario abre un diálogo, tu app de Chat recibe una Event como esta de Google Chat:

JSON

{
  "type": enum (EventType),
  "eventTime": string,
  "threadKey": string,
  "message": {
    object (Message)
  },
  "user": {
    object (User)
  },
  "space": {
    object (Space)
  },
  "action": {
    object (FormAction)
  },
  "configCompleteRedirectUrl": string,
  "isDialogEvent": true,
  "dialogEventType": "REQUEST_DIALOG",
  "common": {
    object (CommonEventObject)
  }
}

Tu app de Chat puede abrir un diálogo si muestra una ActionResponse de "type": "DIALOG" con un DialogAction que incluya una descripción JSON del diálogo:

JSON

{
  "action_response": {
    "type": "DIALOG",
    "dialog_action": {
      "dialog": {
        "body": {
          "sections": [
            {
              "header": "Add new contact",
              "widgets": [
                {
                  "textInput": {
                    "label": "Name",
                    "type": "SINGLE_LINE",
                    "name": "contactName"
                  }
                },
                {
                  "textInput": {
                    "label": "Address",
                    "type": "MULTIPLE_LINE",
                    "name": "address"
                  }
                },
                {
                  "decoratedText": {
                    "text": "Add to favorites",
                    "switchControl": {
                      "controlType": "SWITCH",
                      "name": "saveFavorite"
                    }
                  }
                },
                {
                  "decoratedText": {
                    "text": "Merge with existing contacts",
                    "switchControl": {
                      "controlType": "SWITCH",
                      "name": "mergeContact",
                      "selected": true
                    }
                  }
                },
                {
                  "buttonList": {
                    "buttons": [
                      {
                        "text": "Next",
                        "onClick": {
                          "action": {
                            "function": "openSequentialDialog"
                          }
                        }
                      }
                    ]
                  }
                }
              ]
            }
          ]
        }
      }
    }
  }
}

Abrir un diálogo en respuesta a un clic en un botón de una tarjeta

Cuando un usuario hace clic en un botón de una tarjeta, la app recibe una Event que:

Para abrir un diálogo, especifica:

En este ejemplo, una app de Chat responde a un Event de MESSAGE con una tarjeta que tiene un botón que abre un diálogo:

Node.js

/**
* Responds to messages that have links whose URLs
* match URL patterns configured for link previews.
*
* @param {Object} event The event object from Chat
* API.
*
* @return {Object} Response from the Chat app
* attached to the message with the previewed link.
*/
exports.onMessage = function onMessage(req, res) {

  // Store the Google Chat event as a variable.
  var event = req.body;

  if (req.method === "GET" || !event.message) {
    res.send("Hello! This function is meant to be used in a Google Chat " +
      "Space.");
  }

  // Responds with a card that prompts the user to add a contact
  else {
    res.json({
      "cardsV2": [{
        "cardId": "addContact",
        "card": {
          "header": {
            "title": "Rolodex",
            "subtitle": "Manage your contacts!",
            "imageUrl": "https://www.gstatic.com/images/branding/product/2x/contacts_48dp.png",
            "imageType": "CIRCLE"
          },
          "sections": [
            {
              "widgets": [
                {
                  "buttonList": {
                    "buttons": [
                      {
                        "text": "Add Contact",
                        "onClick": {
                          "action": {
                            "function": "openDialog",
                            "interaction": "OPEN_DIALOG"
                          }
                        }
                      }
                    ]
                  }
                }
              ]
            }
          ]
        }
      }]

    });
  }

  // Respond to button clicks on attached cards
  if(event.type === "CARD_CLICKED") {

    if (event.common.invokedFunction == "openDialog") {
      res.openDialog(event);
};

/**
 * Opens and starts a dialog that allows users to add details about a contact.
 *
 * @param {object} event the event object from Google Chat.
 *
 * @return {object} open a dialog.
 */
function openDialog(event) {
  res.json({
    "action_response": {
        "type": "DIALOG",
        "dialog_action": {
          "dialog": {
            "body": {
              "sections": [
                {
                  "header": "Add new contact",
                  "widgets": [
                    {
                      "textInput": {
                        "label": "Name",
                        "type": "SINGLE_LINE",
                        "name": "name"
                      }
                    },
                    {
                      "textInput": {
                        "label": "Address",
                        "type": "MULTIPLE_LINE",
                        "name": "address"
                      }
                    },
                    {
                      "decoratedText": {
                        "text": "Add to favorites",
                        "switchControl": {
                          "controlType": "SWITCH",
                          "name": "saveFavorite"
                        }
                      }
                    },
                    {
                      "decoratedText": {
                        "text": "Merge with existing contacts",
                        "switchControl": {
                          "controlType": "SWITCH",
                          "name": "mergeContact",
                          "selected": true
                        }
                      }
                    },
                    {
                      "buttonList": {
                        "buttons": [
                          {
                            "text": "Next",
                            "onClick": {
                              "action": {
                                "function": "openSequentialDialog"
                              }
                            }
                          }
                        ]
                      }
                    }
                  ]
                }
              ]
            }
          }
        }
    }
  });
};

Apps Script

/**
 * Responds to a MESSAGE event in Google Chat with a card with a button
 * that opens a dialog.
 *
 * @param {Object} event the event object from Chat API.
 *
 * @return {object} open a Dialog in response to a card's button click.
 */
function onMessage(event) {
  return {
    "cardsV2": [{
      "cardId": "addContact",
      "card": {
        "header": {
          "title": "Rolodex",
          "subtitle": "Manage your contacts!",
          "imageUrl": "https://www.gstatic.com/images/branding/product/2x/contacts_48dp.png",
          "imageType": "CIRCLE"
        },
        "sections": [
          {
            "widgets": [
              {
                "buttonList": {
                  "buttons": [
                    {
                      "text": "Add Contact",
                      "onClick": {
                        "action": {
                          "function": "openDialog",
                          "interaction": "OPEN_DIALOG"
                        }
                      }
                    }
                  ]
                },
                "horizontalAlignment": "CENTER"
              }
            ]
          }
        ]
      }
    }]
  };
}

/**
 * Responds to a CARD_CLICKED event in Google Chat.
 *
 * @param {Object} event the event object from Google Chat
 */
function onCardClick(event) {
  if (event.common.invokedFunction == "openDialog") {
    return openDialog(event);
  }
}

/**
 * Opens a dialog in Google Chat.
 *
 * @param {Object} event the event object from Chat API.
 *
 * @return {object} open a Dialog in Google Chat.
 */
function openDialog(event) {
  return {
    "action_response": {
      "type": "DIALOG",
      "dialog_action": {
        "dialog": {
          "body": {
            "sections": [
              {
                "header": "Add new contact",
                "widgets": [
                  {
                    "textInput": {
                      "label": "Name",
                      "type": "SINGLE_LINE",
                      "name": "contactName"
                    }
                  },
                  {
                    "textInput": {
                      "label": "Address",
                      "type": "MULTIPLE_LINE",
                      "name": "address"
                    }
                  },
                  {
                    "decoratedText": {
                      "text": "Add to favorites",
                      "switchControl": {
                        "controlType": "SWITCH",
                        "name": "saveFavorite"
                      }
                    }
                  },
                  {
                    "decoratedText": {
                      "text": "Merge with existing contacts",
                      "switchControl": {
                        "controlType": "SWITCH",
                        "name": "mergeContact",
                        "selected": true
                      }
                    }
                  },
                  {
                    "buttonList": {
                      "buttons": [
                        {
                          "text": "Next",
                          "onClick": {
                            "action": {
                              "function": "openSequentialDialog"
                            }
                          }
                        }
                      ]
                    }
                  }
                ]
              }
            ]
          }
        }
      }
    }
  };
}

Python

from typing import Any, Mapping

import flask
import functions_framework

@functions_framework.http
def main(req: flask.Request) -> Mapping[str, Any]:
  """Responds to a MESSAGE event in Google Chat that includes the /createContact
     slash command by opening a dialog.

  Args:
      req (flask.Request): the event object from Chat API.

  Returns:
      Mapping[str, Any]: open a Dialog in response to a card's button click.
  """

  if req.method == 'GET':
    return 'Sorry, this function must be called from a Google Chat.'

  request = req.get_json(silent=True)

  if request.get('type') == 'CARD_CLICKED':
    if request.get('common', dict()).get('invokedFunction') == 'open_dialog':
      return open_dialog(request)

  else:
    return {
      'cardsV2': [{
        'cardId': 'addContact',
        'card': {
          'header': {
            'title': 'Rolodex',
            'subtitle': 'Manage your contacts!',
            'imageUrl': 'https://www.gstatic.com/images/branding/product/2x/contacts_48dp.png',
            'imageType': 'CIRCLE'
          },
          'sections': [
            {
              'widgets': [
                {
                  'buttonList': {
                    'buttons': [
                      {
                        'text': 'Add Contact',
                        'onClick': {
                          'action': {
                            'function': 'open_dialog',
                            'interaction': 'OPEN_DIALOG'
                          }
                        }
                      }
                    ]
                  }
                }
              ]
            }
          ]
        }
      }]
    }

def open_dialog(request: Mapping[str, Any]) -> Mapping[str, Any]:
  """Opens a dialog in Google Chat.

  Args:
      request (Mapping[str, Any]): the event object from Chat API.

  Returns:
      Mapping[str, Any]: open a Dialog in response to a card's button click.
  """
  return {
    'action_response': {
      'type': 'DIALOG',
      'dialog_action': {
        'dialog': {
          'body': {
            'sections': [
              {
                'header': 'Add new contact',
                'widgets': [
                  {
                    'textInput': {
                      'label': 'Name',
                      'type': 'SINGLE_LINE',
                      'name': 'name'
                    }
                  },
                  {
                    'textInput': {
                      'label': 'Address',
                      'type': 'MULTIPLE_LINE',
                      'name': 'address'
                    }
                  },
                  {
                    'decoratedText': {
                      'text': 'Add to favorites',
                      'switchControl': {
                        'controlType': 'SWITCH',
                        'name': 'saveFavorite'
                      }
                    }
                  },
                  {
                    'decoratedText': {
                      'text': 'Merge with existing contacts',
                      'switchControl': {
                        'controlType': 'SWITCH',
                        'name': 'mergeContact',
                        'selected': True
                      }
                    }
                  },
                  {
                    'buttonList': {
                      'buttons': [
                        {
                          'text': 'Next',
                          'onClick': {
                            'action': {
                              'function': 'open_sequential_dialog'
                            }
                          }
                        }
                      ]
                    }
                  }
                ]
              }
            ]
          }
        }
      }
    }
  }

Abrir un diálogo en respuesta a un comando de barra

Cuando un usuario abre un diálogo con un comando barra, tu app recibe un Event en el que:

Para abrir un diálogo, responde lo siguiente:

En este ejemplo, una app de Chat responde al comando de barra /createContact a través de un diálogo:

Node.js

/**
* Responds to messages that have links whose URLs
* match URL patterns configured for link previews.
*
* @param {Object} event The event object from Chat
* API.
*
* @return {Object} Response from the Chat app
* attached to the message with the previewed link.
*/
exports.onMessage = function onMessage(req, res) {

  // Store the Google Chat event as a variable.
  var event = req.body;

  if (req.method === "GET" || !event.message) {
    res.send("Hello! This function is meant to be used in a Google Chat " +
      "Space.");
  }

  // Checks for the presence of event.message.slashCommand.
  // If the slash command is "/help", responds with a text message.
  // If the slash command is "/createContact", opens a dialog.
  if (event.message.slashCommand) {
    switch (event.message.slashCommand.commandId) {
      case 1: // /help
        res.json({"text": "Contact bot helps you update your address book!"});
      case 2:  // /createContact
        res.openDialog(event);
    }
  }
};

/**
 * Opens and starts a dialog that allows users to add details about a contact.
 *
 * @param {object} event the event object from Google Chat.
 *
 * @return {object} open a dialog.
 */
function openDialog(event) {
  res.json({
    "action_response": {
        "type": "DIALOG",
        "dialog_action": {
          "dialog": {
            "body": {
              "sections": [
                {
                  "header": "Add new contact",
                  "widgets": [
                    {
                      "textInput": {
                        "label": "Name",
                        "type": "SINGLE_LINE",
                        "name": "name"
                      }
                    },
                    {
                      "textInput": {
                        "label": "Address",
                        "type": "MULTIPLE_LINE",
                        "name": "address"
                      }
                    },
                    {
                      "decoratedText": {
                        "text": "Add to favorites",
                        "switchControl": {
                          "controlType": "SWITCH",
                          "name": "saveFavorite"
                        }
                      }
                    },
                    {
                      "decoratedText": {
                        "text": "Merge with existing contacts",
                        "switchControl": {
                          "controlType": "SWITCH",
                          "name": "mergeContact",
                          "selected": true
                        }
                      }
                    },
                    {
                      "buttonList": {
                        "buttons": [
                          {
                            "text": "Next",
                            "onClick": {
                              "action": {
                                "function": "openSequentialDialog"
                              }
                            }
                          }
                        ]
                      }
                    }
                  ]
                }
              ]
            }
          }
        }
    }
  });
};

Apps Script

/**
 * Responds to a MESSAGE event in Google Chat that includes the /createContact
 * slash command by opening a dialog.
 *
 * @param {Object} event the event object from Chat API.
 *
 * @return {object} open a Dialog in response to a slash command.
 */
function onMessage(event) {

  // Checks for the presence of event.message.slashCommand.
  // If the slash command is "/help", responds with a text message.
  // If the slash command is "/createContact", opens a dialog.
  if (event.message.slashCommand) {
    switch (event.message.slashCommand.commandId) {
      case 1: // /help
        return {"text": "Contact bot helps you update your address book!"}
      case 2:  // /createContact
        return openDialog(event);
    }
  }
}

/**
 * Opens a dialog in Google Chat.
 *
 * @param {Object} event the event object from Chat API.
 *
 * @return {object} open a Dialog in Google Chat.
 */
function openDialog(event) {
  return {
    "action_response": {
      "type": "DIALOG",
      "dialog_action": {
        "dialog": {
          "body": {
            "sections": [
              {
                "header": "Add new contact",
                "widgets": [
                  {
                    "textInput": {
                      "label": "Name",
                      "type": "SINGLE_LINE",
                      "name": "contactName"
                    }
                  },
                  {
                    "textInput": {
                      "label": "Address",
                      "type": "MULTIPLE_LINE",
                      "name": "address"
                    }
                  },
                  {
                    "decoratedText": {
                      "text": "Add to favorites",
                      "switchControl": {
                        "controlType": "SWITCH",
                        "name": "saveFavorite"
                      }
                    }
                  },
                  {
                    "decoratedText": {
                      "text": "Merge with existing contacts",
                      "switchControl": {
                        "controlType": "SWITCH",
                        "name": "mergeContact",
                        "selected": true
                      }
                    }
                  },
                  {
                    "buttonList": {
                      "buttons": [
                        {
                          "text": "Next",
                          "onClick": {
                            "action": {
                              "function": "openSequentialDialog"
                            }
                          }
                        }
                      ]
                    }
                  }
                ]
              }
            ]
          }
        }
      }
    }
  };
}

Python

from typing import Any, Mapping

import flask
import functions_framework

@functions_framework.http
def main(req: flask.Request) -> Mapping[str, Any]:
  """Responds to a MESSAGE event in Google Chat that includes the /createContact
     slash command by opening a dialog.

  Args:
      req (flask.Request): the event object from Chat API.

  Returns:
      Mapping[str, Any]: open a Dialog in response to a slash command.
  """
  if req.method == 'GET':
    return 'Sorry, this function must be called from a Google Chat.'

  request = req.get_json(silent=True)

  if slash_command := request.get('message', dict()).get('slashCommand'):
    command_id = slash_command['commandId']
    if command_id == 1:
      return {'text': 'Contact bot helps you update your address book!'}

    elif command_id == 2:
      return open_dialog(request)

def open_dialog(request: Mapping[str, Any]) -> Mapping[str, Any]:
  """Opens a dialog in Google Chat.

  Args:
      request (Mapping[str, Any]): the event object from Chat API.

  Returns:
      Mapping[str, Any]: open a Dialog in response to a slash command.
  """
  return {
    'action_response': {
      'type': 'DIALOG',
      'dialog_action': {
        'dialog': {
          'body': {
            'sections': [
              {
                'header': 'Add new contact',
                'widgets': [
                  {
                    'textInput': {
                      'label': 'Name',
                      'type': 'SINGLE_LINE',
                      'name': 'name'
                    }
                  },
                  {
                    'textInput': {
                      'label': 'Address',
                      'type': 'MULTIPLE_LINE',
                      'name': 'address'
                    }
                  },
                  {
                    'decoratedText': {
                      'text': 'Add to favorites',
                      'switchControl': {
                        'controlType': 'SWITCH',
                        'name': 'saveFavorite'
                      }
                    }
                  },
                  {
                    'decoratedText': {
                      'text': 'Merge with existing contacts',
                      'switchControl': {
                        'controlType': 'SWITCH',
                        'name': 'mergeContact',
                        'selected': True
                      }
                    }
                  },
                  {
                    'buttonList': {
                      'buttons': [
                        {
                          'text': 'Next',
                          'onClick': {
                            'action': {
                              'function': 'open_sequential_dialog'
                            }
                          }
                        }
                      ]
                    }
                  }
                ]
              }
            ]
          }
        }
      }
    }
  }

Une varias interfaces de tarjeta

Cuando las interacciones de los usuarios requieren más de una tarjeta, puedes abrir una tarjeta nueva desde el mismo diálogo si muestras otro.

Cuando los usuarios hacen clic en un botón en un diálogo, la app recibe una Event en la que sucede lo siguiente:

Dado que un diálogo ya está abierto, no especifiques onClick.action.interaction como lo haces cuando abres un diálogo desde una tarjeta de conversación. En su lugar, muestra solo onClick.action.function como el nombre de una función que abre un diálogo.

En este ejemplo, una app de Chat responde a un CARD_CLICKED Event desde un clic en un botón de diálogo al abrir otro diálogo:

Node.js

// Respond to button clicks on attached cards
if(event.type === "CARD_CLICKED") {

  // Open the first dialog.
  if (event.common.invokedFunction == "openDialog") {
    res.openDialog(event);
  }

  // Open the second dialog.
  if (event.common.invokedFunction == "openSequentialDialog") {
    res.openSequentialDialog(event);
  }
}

/**
* Opens and starts a dialog that allows users to add details about a contact.
*
* @param {object} event the event object from Google Chat.
*
* @return {object} open a dialog.
*/
function openDialog(event) {
  res.json({
    "action_response": {
        "type": "DIALOG",
        "dialog_action": {
          "dialog": {
            "body": {
              "sections": [
                {
                  "header": "Add new contact",
                  "widgets": [
                    {
                      "textInput": {
                        "label": "Name",
                        "type": "SINGLE_LINE",
                        "name": "name"
                      }
                    },
                    {
                      "textInput": {
                        "label": "Address",
                        "type": "MULTIPLE_LINE",
                        "name": "address"
                      }
                    },
                    {
                      "decoratedText": {
                        "text": "Add to favorites",
                        "switchControl": {
                          "controlType": "SWITCH",
                          "name": "saveFavorite"
                        }
                      }
                    },
                    {
                      "decoratedText": {
                        "text": "Merge with existing contacts",
                        "switchControl": {
                          "controlType": "SWITCH",
                          "name": "mergeContact",
                          "selected": true
                        }
                      }
                    },
                    {
                      "buttonList": {
                        "buttons": [
                          {
                            "text": "Next",
                            "onClick": {
                              "action": {
                                "function": "openSequentialDialog"
                              }
                            }
                          }
                        ]
                      }
                    }
                  ]
                }
              ]
            }
          }
        }
    }
  });
};

/**
* Opens a second dialog that allows users to add more contact details.
*
* @param {object} event the event object from Google Chat.
*
* @return {object} open a dialog.
*/
function openSequentialDialog(event) {
res.json({
  "action_response": {
      "type": "DIALOG",
      "dialog_action": {
        "dialog": {
          "body": {
            "sections": [
              {
                "header": "Add new contact",
                "widgets": [
                  {
                    "textInput": {
                      "label": "Notes",
                      "type": "MULTIPLE_LINE",
                      "name": "notes"
                    }
                  },
                  {
                    "selectionInput": {
                      "type": "RADIO_BUTTON",
                      "label": "Contact type",
                      "name": "contactType",
                      "items": [
                        {
                          "text": "Work",
                          "value": "Work",
                          "selected": false
                        },
                        {
                          "text": "Personal",
                          "value": "Personal",
                          "selected": false
                        }
                      ]
                    }
                  },
                  {
                    "buttonList": {
                      "buttons": [
                        {
                          "text": "Submit",
                          "onClick": {
                            "action": {
                              "function": "confirmDialogSuccess",
                              "parameters": [
                                {
                                  "key": "confirmDialogSuccess",
                                  "value": "confirmDialogSuccess"
                                }
                              ]
                            }
                          }
                        }
                      ]
                    },
                    "horizontalAlignment": "END"
                  }
                ]
              }
            ]
          }
        }
      }
  }
});

Apps Script

/**
 * Responds to a CARD_CLICKED event in Google Chat.
 *
 * @param {Object} event the event object from Google Chat
 */
function onCardClick(event) {

  // When a user clicks a card, the app checks to see which function to run.
  if (event.common.invokedFunction == "openDialog") {
    return openDialog(event);
  }

  if (event.common.invokedFunction == "openSequentialDialog") {
    return openSequentialDialog(event);
  }
}

/**
 * Opens and starts a dialog that allows users to add details about a contact.
 *
 * @param {object} event the event object from Google Chat.
 *
 * @return {object} open a dialog.
 */
function openDialog(event) {
  return {
    "action_response": {
        "type": "DIALOG",
        "dialog_action": {
          "dialog": {
            "body": {
              "sections": [
                {
                  "header": "Add new contact",
                  "widgets": [
                    {
                      "textInput": {
                        "label": "Name",
                        "type": "SINGLE_LINE",
                        "name": "contactName"
                      }
                    },
                    {
                      "textInput": {
                        "label": "Address",
                        "type": "MULTIPLE_LINE",
                        "name": "address"
                      }
                    },
                    {
                      "decoratedText": {
                        "text": "Add to favorites",
                        "switchControl": {
                          "controlType": "SWITCH",
                          "name": "saveFavorite"
                        }
                      }
                    },
                    {
                      "decoratedText": {
                        "text": "Merge with existing contacts",
                        "switchControl": {
                          "controlType": "SWITCH",
                          "name": "mergeContact",
                          "selected": true
                        }
                      }
                    },
                    {
                      "buttonList": {
                        "buttons": [
                          {
                            "text": "Next",
                            "onClick": {
                              "action": {

                                // Specifies which function to run
                                // in response to the card click.
                                "function": "openSequentialDialog"
                              }
                            }
                          }
                        ]
                      }
                    }
                  ]
                }
              ]
            }
          }
        }
    }
  };
}

/**
 * Opens a second dialog that allows users to add more contact details.
 *
 * @param {object} event the event object from Google Chat.
 *
 * @return {object} open a dialog.
 */
function openSequentialDialog(event) {
  return {
    "action_response": {
        "type": "DIALOG",
        "dialog_action": {
          "dialog": {
            "body": {
              "sections": [
                {
                  "header": "Add new contact",
                  "widgets": [
                    {
                      "textInput": {
                        "label": "Notes",
                        "type": "MULTIPLE_LINE",
                        "name": "notes"
                      }
                    },
                    {
                      "selectionInput": {
                        "type": "RADIO_BUTTON",
                        "label": "Contact type",
                        "name": "contactType",
                        "items": [
                          {
                            "text": "Work",
                            "value": "Work",
                            "selected": false
                          },
                          {
                            "text": "Personal",
                            "value": "Personal",
                            "selected": false
                          }
                        ]
                      }
                    },
                    {
                      "buttonList": {
                        "buttons": [
                          {
                            "text": "Submit",
                            "onClick": {
                              "action": {

                                // Specifies which function to run
                                // in response to the card click.
                                "function": "receiveDialog",
                                "parameters": [
                                  {
                                    "key": "receiveDialog",
                                    "value": "receiveDialog"
                                  }
                                ]
                              }
                            }
                          }
                        ]
                      },
                      "horizontalAlignment": "END"
                    }
                  ]
                }
              ]
            }
          }
        }
    }
  };
}

Python

from typing import Any, Mapping

import flask
import functions_framework

@functions_framework.http
def main(req: flask.Request) -> Mapping[str, Any]:
  """Responds to a MESSAGE event in Google Chat that includes the /createContact
     slash command by opening a dialog.

  Args:
      req (flask.Request): the event object from Chat API.

  Returns:
      Mapping[str, Any]: open a Dialog in response to a card's button click.
  """

  if req.method == 'GET':
    return 'Sorry, this function must be called from a Google Chat.'

  request = req.get_json(silent=True)

  if request.get('type') == 'CARD_CLICKED':
    if invoked_function := request.get('common', dict()).get('invokedFunction'):
      if invoked_function == 'open_dialog':
        return open_dialog(request)

      elif invoked_function == 'open_sequential_dialog':
        return open_dialog(request)

def open_dialog(request: Mapping[str, Any]) -> Mapping[str, Any]:
  """Opens a dialog in Google Chat.

  Args:
      request (Mapping[str, Any]): the event object from Chat API.

  Returns:
      Mapping[str, Any]: open a Dialog in response to a card's button click.
  """
  return {
    'action_response': {
      'type': 'DIALOG',
      'dialog_action': {
        'dialog': {
          'body': {
            'sections': [
              {
                'header': 'Add new contact',
                'widgets': [
                  {
                    'textInput': {
                      'label': 'Name',
                      'type': 'SINGLE_LINE',
                      'name': 'name'
                    }
                  },
                  {
                    'textInput': {
                      'label': 'Address',
                      'type': 'MULTIPLE_LINE',
                      'name': 'address'
                    }
                  },
                  {
                    'decoratedText': {
                      'text': 'Add to favorites',
                      'switchControl': {
                        'controlType': 'SWITCH',
                        'name': 'saveFavorite'
                      }
                    }
                  },
                  {
                    'decoratedText': {
                      'text': 'Merge with existing contacts',
                      'switchControl': {
                        'controlType': 'SWITCH',
                        'name': 'mergeContact',
                        'selected': True
                      }
                    }
                  },
                  {
                    'buttonList': {
                      'buttons': [
                        {
                          'text': 'Next',
                          'onClick': {
                            'action': {
                              'function': 'open_sequential_dialog'
                            }
                          }
                        }
                      ]
                    }
                  }
                ]
              }
            ]
          }
        }
      }
    }
  }

def open_sequential_dialog(request: Mapping[str, Any]) -> Mapping[str, Any]:
  """Opens a second dialog that allows users to add more contact details.

  Args:
      request (Mapping[str, Any]): the event object from Chat API.

  Returns:
      Mapping[str, Any]: open a Dialog in response to a card's button click.
  """
  return {
    'action_response': {
      'type': 'DIALOG',
      'dialog_action': {
        'dialog': {
          'body': {
            'sections': [
              {
                'header': 'Add new contact',
                'widgets': [
                  {
                    'textInput': {
                      'label': 'Notes',
                      'type': 'MULTIPLE_LINE',
                      'name': 'notes'
                    }
                  },
                  {
                    'selectionInput': {
                      'type': 'RADIO_BUTTON',
                      'label': 'Contact type',
                      'name': 'contactType',
                      'items': [
                        {
                          'text': 'Work',
                          'value': 'Work',
                          'selected': False
                        },
                        {
                          'text': 'Personal',
                          'value': 'Personal',
                          'selected': False
                        }
                      ]
                    }
                  },
                  {
                    'buttonList': {
                      'buttons': [
                        {
                          'text': 'Submit',
                          'onClick': {
                            'action': {
                              'function': 'receiveDialog',
                              'parameters': [
                                {
                                  'key': 'receiveDialog',
                                  'value': 'receiveDialog'
                                }
                              ]
                            }
                          }
                        }
                      ]
                    },
                    'horizontalAlignment': 'END'
                  }
                ]
              }
            ]
          }
        }
      }
    }
  }

Cómo recibir datos de formularios de diálogos

Cuando los usuarios hacen clic en un botón de un diálogo, los datos que ingresan se envían a la app de Chat, y la app recibe una Event en la que:

Los datos que los usuarios ingresan en el diálogo están disponibles en Event como Event.common.formInputs, un mapa en el que las claves son ID de string asignadas a cada widget de diálogo y a los valores que representan las entradas del usuario para cada widget. Los diferentes objetos representan diferentes tipos de datos de entrada. Por ejemplo, Event.common.formInputs.stringInputs representan entradas de string.

Cuando un usuario envía un diálogo, tu app de Chat recibe una Event como la de Google Chat:

JSON

{
  "type": enum (EventType),
  "eventTime": string,
  "threadKey": string,
  "message": {
    object (Message)
  },
  "user": {
    object (User)
  },
  "space": {
    object (Space)
  },
  "action": {
    object (FormAction)
  },
  "configCompleteRedirectUrl": string,

  // Indicates that this event is dialog-related.
  "isDialogEvent": true,

  // Indicates that a user clicked a button, and all data
  // they entered in the dialog is included in Event.common.formInputs.
  "dialogEventType": "SUBMIT_DIALOG",
  "common": {
    "userLocale": string,
    "hostApp": enum (HostApp),
    "platform": enum (Platform),
    "timeZone": {
      object (TimeZone)
    },

    // Represents user data entered in a dialog
    "formInputs": {

      // Represents string data entered in a dialog, like text input fields
      // and check boxes
      "stringInputs": {

        // An array of strings entered by the user in a dialog.
        "value": [
          string
        ]
      }
    },
    "parameters": {
      string: string,
      ...
    },
    "invokedFunction": string
  }
}

Tu app puede acceder al primer valor ingresado por el usuario en event.common.formInputs.NAME.stringInputs.value[0], donde NAME es el campo name de un widget TextInput.

Después de recibir los datos del formulario de diálogo, la app de Chat debe responder mediante un recibo, un mensaje de texto o una tarjeta, o un error. Para ello, se muestra un ActionResponse:

  • Para confirmar la recepción correcta, responde con una ActionResponse que tenga "actionStatus": "OK".
  • Para responder con un mensaje de texto o una tarjeta, responde con un ActionResponse que tenga un ResponseType de NEW_MESSAGE, UPDATE_MESSAGE o UPDATE_USER_MESSAGE_CARDS. Para obtener más información, consulta Cómo responder a un diálogo.
  • Para mostrar un error, responde con un ActionResponse que tenga "actionStatus": "ERROR MESSAGE".

En el siguiente ejemplo, se comprueba la presencia de un valor "name". Si no aparece, la app muestra un error. Si está presente, la app confirma la recepción de los datos del formulario y cierra el cuadro de diálogo.

Node.js

/**
 * Checks for a form input error, the absence of
 * a "name" value, and returns an error if absent.
 * Otherwise, confirms successful receipt of a dialog.
 *
 * Confirms successful receipt of a dialog.
 *
 * @param {Object} event the event object from Chat API.
 *
 * @return {object} open a Dialog in Google Chat.
 */
function receiveDialog(event) {

  // Checks to make sure the user entered a name
  // in a dialog. If no name value detected, returns
  // an error message.
  if (event.common.formInputs.WIDGET_NAME.stringInputs.value[0] == "") {
    return {
      "actionResponse": {
        "type": "DIALOG",
        "dialogAction": {
          "actionStatus": {
            "statusCode": "OK", 
            "userFacingMessage": "Don't forget to name your new contact!"
        }
      }
    };

  // Otherwise the app indicates that it received
  // form data from the dialog. Any value other than "OK"
  // gets returned as an error. "OK" is interpreted as
  // code 200, and the dialog closes.
  } else {
    res.json({
      "actionResponse": {
        "type": "DIALOG",
        "dialogAction": {
          "actionStatus": "OK"
        }
      }
    });
  }
}

Apps Script

/**
 * Checks for a form input error, the absence of
 * a "name" value, and returns an error if absent.
 * Otherwise, confirms successful receipt of a dialog.
 *
 * Confirms successful receipt of a dialog.
 *
 * @param {Object} event the event object from Chat API.
 *
 * @return {object} open a Dialog in Google Chat.
 */
function receiveDialog(event) {

  // Checks to make sure the user entered a name
  // in a dialog. If no name value detected, returns
  // an error message.
  if (event.common.formInputs.WIDGET_NAME[""].stringInputs.value[0]) {
    return {
      "actionResponse": {
        "type": "DIALOG",
        "dialogAction": {
          "actionStatus": "Don't forget to name your new contact!"
        }
      }
    };

  // Otherwise the app indicates that it received
  // form data from the dialog. Any value other than "OK"
  // gets returned as an error. "OK" is interpreted as
  // code 200, and the dialog closes.
  } else {
    return {
      "actionResponse": {
        "type": "DIALOG",
        "dialogAction": {
          "actionStatus": "OK"
        }
      }
    };
  }
}

Python

def receive_dialog(event: Mapping[str, Any]) -> Mapping[str, Any]:
  """Checks for a form input error, the absence of a "name" value, and returns
     an error if absent. Otherwise, confirms successful receipt of a dialog.

  Args:
      event (Mapping[str, Any]): the event object from Chat API.

  Returns:
      Mapping[str, Any]: the response.
  """

  if common := event.get('common'):
    if form_inputs := common.get('formInputs'):
      if contact_name := form_inputs.get('WIDGET_NAME'):
        if string_inputs := contact_name.get('stringInputs'):
          if name := string_inputs.get('value')[0]:
            return {
              'actionResponse': {
                'type': 'DIALOG',
                'dialogAction': {
                  'actionStatus': 'OK'
                }
              }
            }
          else:
            return {
              'actionResponse': {
                'type': 'DIALOG',
                'dialogAction': {
                  'actionStatus': 'Don\'t forget to name your new contact!'
                }
              }
            }

Cómo responder a un diálogo

Puedes responder a un cuadro de diálogo con un mensaje nuevo o con una actualización de un mensaje existente.

Cómo responder a un diálogo con un mensaje nuevo

Para responder a un envío de formulario de diálogo con un mensaje nuevo, la app de Chat muestra un ActionResponse de tipo NEW_MESSAGE, junto con un lenguaje de marcado que indica el contenido del mensaje nuevo. Después de recibir esta respuesta, el diálogo se cierra y el mensaje nuevo se publica.

El siguiente código es un ejemplo de una respuesta JSON a un diálogo que envía una app de Chat para crear un nuevo mensaje de respuesta:

JSON

{
  "actionResponse": "NEW_MESSAGE",
  "text": "This message is a reply to a dialog form submission.",
  "cardsV2": [
    {
      "cardId" : "reply-card-id",
      "card" : {
        "header": {
          "title": "Reply card title"
        },
        "sections": [
          {
            "widgets" : [
              {
                "textParagraph": {
                  "text": "Reply card message"
                }
              }
            ]
          }
        ]
      }
    }
  ]
}

La app de Chat también puede responder de manera asíncrona con un mensaje de texto simple o una tarjeta. Para hacerlo, autentica con una cuenta de servicio y, luego, envía una respuesta asíncrona llamando a spaces.messages.create mediante la API de Google Chat.

Cómo responder a un diálogo con una actualización de mensaje

Cuando respondes a un diálogo con un mensaje actualizado, puedes actualizar el mensaje de una aplicación existente o una vista previa de un vínculo.

Mensajes de apps

Para responder a un envío de formulario de diálogo con una actualización a un mensaje existente enviado por la app de Chat, muestra un ActionResponse de tipo UPDATE_MESSAGE. La respuesta incluye un lenguaje de marcado que indica el contenido del mensaje actualizado. Cuando se recibe esta respuesta, se cierra el diálogo y el mensaje se actualiza con el contenido nuevo.

El siguiente código es un ejemplo de una respuesta JSON a un diálogo que envía una app de Chat para actualizar un mensaje existente:

JSON

{
  "actionResponse": "UPDATE_MESSAGE",
  "text": "This message has been updated with new content in response to a dialog form submission.",
  "cardsV2": [
    {
      "cardId" : "updated-card-id",
      "card" : {
        "header": {
          "title": "Updated card title"
        },
        "sections": [
          {
            "widgets" : [
              {
                "textParagraph": {
                  "text": "Updated card message"
                }
              }
            ]
          }
        ]
      }
    }
  ]
}

La app de Chat también puede actualizar un mensaje de la app de forma asíncrona con la API de Google Chat.

Para actualizar las vistas previas de vínculos con contenido nuevo en respuesta a los envíos de formularios de diálogo, la app de Chat muestra un ActionResponse de tipo UPDATE_USER_MESSAGE_CARDS. La respuesta incluye un lenguaje de marcado para las tarjetas nuevas con las que se actualizan las vistas previas de los vínculos. Cuando se recibe esta respuesta, se cierra el diálogo, y se actualizan las vistas previas de los vínculos con las nuevas tarjetas.

El siguiente código es un ejemplo de una respuesta JSON a un diálogo que envía una app de Chat. Se usa para actualizar una vista previa de un vínculo con una tarjeta nueva:

JSON

{
  "actionResponse": "UPDATE_USER_MESSAGE_CARDS",
  "cardsV2": [
    {
      "cardId" : "updated-card-id",
      "card" : {
        "header": {
          "title": "Updated card title"
        },
        "sections": [
          {
            "widgets" : [
              {
                "textParagraph": {
                  "text": "Updated card message"
                }
              }
            ]
          }
        ]
      }
    }
  ]
}

Ejemplo completo: Rolodex para administrar la app de Chat

En este ejemplo, una app de Chat abre un cuadro de diálogo para que el usuario pueda agregar detalles sobre un contacto, como el nombre, el correo electrónico y la dirección:

Node.js

/**
* Responds to messages that have links whose URLs
* match URL patterns configured for link previews.
*
* @param {Object} event The event object from Chat
* API.
*
* @return {Object} Response from the Chat app
* attached to the message with the previewed link.
*/
exports.onMessage = function onMessage(req, res) {

  // Store the Google Chat event as a variable.
  var event = req.body;

  if (req.method === "GET" || !event.message) {
    res.send("Hello! This function is meant to be used in a Google Chat " +
      "Space.");
  }

  // Checks for the presence of event.message.slashCommand.
  // If the slash command is "/help", responds with a text message.
  // If the slash command is "/createContact", opens a dialog.
  if (event.message.slashCommand) {
    switch (event.message.slashCommand.commandId) {
      case 1: // /help
        res.json({"text": "Contact bot helps you update your address book!"});
      case 2:  // /createContact
        res.openDialog(event);
    }
  }

  // If the Chat app doesn"t detect a slash command, it responds
  // with a card that prompts the user to add a contact
  else {
    res.json({
      "cardsV2": [{
        "cardId": "addContact",
        "card": {
          "header": {
            "title": "Rolodex",
            "subtitle": "Manage your contacts!",
            "imageUrl": "https://www.gstatic.com/images/branding/product/2x/contacts_48dp.png",
            "imageType": "CIRCLE"
          },
          "sections": [
            {
              "widgets": [
                {
                  "buttonList": {
                    "buttons": [
                      {
                        "text": "Add Contact",
                        "onClick": {
                          "action": {
                            "function": "openDialog",
                            "interaction": "OPEN_DIALOG"
                          }
                        }
                      }
                    ]
                  }
                }
              ]
            }
          ]
        }
      }]

    });
  }

  // Respond to button clicks on attached cards
  if(event.type === "CARD_CLICKED") {

    if (event.common.invokedFunction == "openDialog") {
      res.openDialog(event);
    }

    if (event.common.invokedFunction == "openSequentialDialog") {
      res.openSequentialDialog(event);
    }

    if (event.common.invokedFunction == "confirmDialogSuccess") {
      res.confirmDialogSuccess(event);
    }

  }

};

/**
 * Opens and starts a dialog that allows users to add details about a contact.
 *
 * @param {object} event the event object from Google Chat.
 *
 * @return {object} open a dialog.
 */
function openDialog(event) {
  res.json({
    "action_response": {
        "type": "DIALOG",
        "dialog_action": {
          "dialog": {
            "body": {
              "sections": [
                {
                  "header": "Add new contact",
                  "widgets": [
                    {
                      "textInput": {
                        "label": "Name",
                        "type": "SINGLE_LINE",
                        "name": "name"
                      }
                    },
                    {
                      "textInput": {
                        "label": "Address",
                        "type": "MULTIPLE_LINE",
                        "name": "address"
                      }
                    },
                    {
                      "decoratedText": {
                        "text": "Add to favorites",
                        "switchControl": {
                          "controlType": "SWITCH",
                          "name": "saveFavorite"
                        }
                      }
                    },
                    {
                      "decoratedText": {
                        "text": "Merge with existing contacts",
                        "switchControl": {
                          "controlType": "SWITCH",
                          "name": "mergeContact",
                          "selected": true
                        }
                      }
                    },
                    {
                      "buttonList": {
                        "buttons": [
                          {
                            "text": "Next",
                            "onClick": {
                              "action": {
                                "function": "openSequentialDialog"
                              }
                            }
                          }
                        ]
                      }
                    }
                  ]
                }
              ]
            }
          }
        }
    }
  });
};

/**
 * Opens a second dialog that allows users to add more contact details.
 *
 * @param {object} event the event object from Google Chat.
 *
 * @return {object} open a dialog.
 */
function openSequentialDialog(event) {
  res.json({
    "action_response": {
        "type": "DIALOG",
        "dialog_action": {
          "dialog": {
            "body": {
              "sections": [
                {
                  "header": "Add new contact",
                  "widgets": [
                    {
                      "textInput": {
                        "label": "Notes",
                        "type": "MULTIPLE_LINE",
                        "name": "notes"
                      }
                    },
                    {
                      "selectionInput": {
                        "type": "RADIO_BUTTON",
                        "label": "Contact type",
                        "name": "contactType",
                        "items": [
                          {
                            "text": "Work",
                            "value": "Work",
                            "selected": false
                          },
                          {
                            "text": "Personal",
                            "value": "Personal",
                            "selected": false
                          }
                        ]
                      }
                    },
                    {
                      "buttonList": {
                        "buttons": [
                          {
                            "text": "Submit",
                            "onClick": {
                              "action": {
                                "function": "confirmDialogSuccess",
                                "parameters": [
                                  {
                                    "key": "confirmDialogSuccess",
                                    "value": "confirmDialogSuccess"
                                  }
                                ]
                              }
                            }
                          }
                        ]
                      },
                      "horizontalAlignment": "END"
                    }
                  ]
                }
              ]
            }
          }
        }
    }
  });
}

/**
 * Checks for a form input error, the absence of
 * a "name" value, and returns an error if absent.
 * Otherwise, confirms successful receipt of a dialog.
 *
 * Confirms successful receipt of a dialog.
 *
 * @param {Object} event the event object from Chat API.
 *
 * @return {object} open a Dialog in Google Chat.
 */
function receiveDialog(event) {

  // Checks to make sure the user entered a name
  // in a dialog. If no name value detected, returns
  // an error message.
  if (event.common.formInputs.contactName.stringInputs.value[0] == "") {
    return {
      "actionResponse": {
        "type": "DIALOG",
        "dialogAction": {
          "actionStatus": {
            "statusCode": "OK", 
            "userFacingMessage": "Don't forget to name your new contact!"
        }
      }
    };

  // Otherwise the app indicates that it received
  // form data from the dialog. Any value other than "OK"
  // gets returned as an error. "OK" is interpreted as
  // code 200, and the dialog closes.
  } else {
    res.json({
      "actionResponse": {
        "type": "DIALOG",
        "dialogAction": {
          "actionStatus": "OK"
        }
      }
    });
  }
}

Apps Script

/**
 * Responds to a MESSAGE event in Google Chat.
 *
 * @param {Object} event the event object from Chat API.
 *
 * @return {object} open a Dialog in response to a slash command
 * or a card"s button click.
 */
function onMessage(event) {

  // Checks for the presence of event.message.slashCommand.
  // If the slash command is "/help", responds with a text message.
  // If the slash command is "/createContact", opens a dialog.
  if (event.message.slashCommand) {
    switch (event.message.slashCommand.commandId) {
      case 1: // /help
        return {"text": "Contact bot helps you update your address book!"}
      case 2:  // /createContact
        return openDialog(event);
    }
  }

  // If the Chat app doesn"t detect a slash command, it responds
  // with a card that prompts the user to add a contact
  else {
    return {
      "cardsV2": [{
        "cardId": "addContact",
        "card": {
          "header": {
            "title": "Rolodex",
            "subtitle": "Manage your contacts!",
            "imageUrl": "https://www.gstatic.com/images/branding/product/2x/contacts_48dp.png",
            "imageType": "CIRCLE"
          },
          "sections": [
            {
              "widgets": [
                {
                  "buttonList": {
                    "buttons": [
                      {
                        "text": "Add Contact",
                        "onClick": {
                          "action": {
                            "function": "openDialog",
                            "interaction": "OPEN_DIALOG"
                          }
                        }
                      }
                    ]
                  }
                }
              ]
            }
          ]
        }
      }]

    };
  }
}

/**
 * Responds to a CARD_CLICKED event in Google Chat.
 *
 * @param {Object} event the event object from Google Chat
 */
function onCardClick(event) {

  if (event.common.invokedFunction == "openDialog") {
    return openDialog(event);
  }

  if (event.common.invokedFunction == "openSequentialDialog") {
    return openSequentialDialog(event);
  }

  if (event.common.invokedFunction == "receiveDialog") {
    return receiveDialog(event);
  }
}

/**
 * Opens and starts a dialog that allows users to add details about a contact.
 *
 *
 * @return {object} open a dialog.
 */
function openDialog(event) {
  return {
    "action_response": {
        "type": "DIALOG",
        "dialog_action": {
          "dialog": {
            "body": {
              "sections": [
                {
                  "header": "Add new contact",
                  "widgets": [
                    {
                      "textInput": {
                        "label": "Name",
                        "type": "SINGLE_LINE",
                        "name": "contactName"
                      }
                    },
                    {
                      "textInput": {
                        "label": "Address",
                        "type": "MULTIPLE_LINE",
                        "name": "address"
                      }
                    },
                    {
                      "decoratedText": {
                        "text": "Add to favorites",
                        "switchControl": {
                          "controlType": "SWITCH",
                          "name": "saveFavorite"
                        }
                      }
                    },
                    {
                      "decoratedText": {
                        "text": "Merge with existing contacts",
                        "switchControl": {
                          "controlType": "SWITCH",
                          "name": "mergeContact",
                          "selected": true
                        }
                      }
                    },
                    {
                      "buttonList": {
                        "buttons": [
                          {
                            "text": "Next",
                            "onClick": {
                              "action": {
                                "function": "openSequentialDialog"
                              }
                            }
                          }
                        ]
                      }
                    }
                  ]
                }
              ]
            }
          }
        }
    }
  };
}

/**
 * Opens a second dialog that allows users to add more contact details.
 *
 * @param {object} event the event object from Google Chat.
 *
 * @return {object} open a dialog.
 */
function openSequentialDialog(event) {
  return {
    "action_response": {
        "type": "DIALOG",
        "dialog_action": {
          "dialog": {
            "body": {
              "sections": [
                {
                  "header": "Add new contact",
                  "widgets": [
                    {
                      "textInput": {
                        "label": "Notes",
                        "type": "MULTIPLE_LINE",
                        "name": "notes"
                      }
                    },
                    {
                      "selectionInput": {
                        "type": "RADIO_BUTTON",
                        "label": "Contact type",
                        "name": "contactType",
                        "items": [
                          {
                            "text": "Work",
                            "value": "Work",
                            "selected": false
                          },
                          {
                            "text": "Personal",
                            "value": "Personal",
                            "selected": false
                          }
                        ]
                      }
                    },
                    {
                      "buttonList": {
                        "buttons": [
                          {
                            "text": "Submit",
                            "onClick": {
                              "action": {
                                "function": "receiveDialog",
                                "parameters": [
                                  {
                                    "key": "receiveDialog",
                                    "value": "receiveDialog"
                                  }
                                ]
                              }
                            }
                          }
                        ]
                      },
                      "horizontalAlignment": "END"
                    }
                  ]
                }
              ]
            }
          }
        }
    }
  };
}

/**
 * Checks for a form input error, the absence of
 * a "name" value, and returns an error if absent.
 * Otherwise, confirms successful receipt of a dialog.
 *
 * Confirms successful receipt of a dialog.
 *
 * @param {Object} event the event object from Chat API.
 *
 * @return {object} open a Dialog in Google Chat.
 */
function receiveDialog(event) {

  // Checks to make sure the user entered a name
  // in a dialog. If no name value detected, returns
  // an error message.
  if (event.common.formInputs.contactName.stringInputs.value[0] == "") {
    return {
      "actionResponse": {
        "type": "DIALOG",
        "dialogAction": {
          "actionStatus": "Don't forget to name your new contact!"
        }
      }
    };

  // Otherwise the app indicates that it received
  // form data from the dialog. Any value other than "OK"
  // gets returned as an error. "OK" is interpreted as
  // code 200, and the dialog closes.
  } else {
    return {
      "actionResponse": {
        "type": "DIALOG",
        "dialogAction": {
          "actionStatus": "OK"
        }
      }
    };
  }
}

Python

from typing import Any, Mapping

import flask
import functions_framework

@functions_framework.http
def main(req: flask.Request) -> Mapping[str, Any]:
  """Responds to a MESSAGE event in Google Chat that includes the /createContact
     slash command by opening a dialog.

  Args:
      req (flask.Request): the event object from Chat API.

  Returns:
      Mapping[str, Any]: open a Dialog in response to a card's button click.
  """

  if req.method == 'GET':
    return 'Sorry, this function must be called from a Google Chat.'

  request = req.get_json(silent=True)

  if request.get('type') == 'CARD_CLICKED':
    invoked_function = request.get('common', dict()).get('invokedFunction')
    if invoked_function == 'open_dialog':
      return open_dialog(request)

    elif invoked_function == 'open_sequential_dialog':
      return open_dialog(request)

    elif invoked_function == "receive_dialog":
      return receive_dialog(request)

  else:
    return {
      'cardsV2': [{
        'cardId': 'addContact',
        'card': {
          'header': {
            'title': 'Rolodex',
            'subtitle': 'Manage your contacts!',
            'imageUrl': 'https://www.gstatic.com/images/branding/product/2x/contacts_48dp.png',
            'imageType': 'CIRCLE'
          },
          'sections': [
            {
              'widgets': [
                {
                  'buttonList': {
                    'buttons': [
                      {
                        'text': 'Add Contact',
                        'onClick': {
                                'action': {
                                  'function': 'open_dialog',
                                  'interaction': 'OPEN_DIALOG'
                                }
                        }
                      }
                    ]
                  }
                }
              ]
            }
          ]
        }
      }]
    }

def open_dialog(request: Mapping[str, Any]) -> Mapping[str, Any]:
  """Opens a dialog in Google Chat.

  Args:
      request (Mapping[str, Any]): the event object from Chat API.

  Returns:
      Mapping[str, Any]: open a Dialog in response to a card's button click.
  """
  return {
    'action_response': {
      'type': 'DIALOG',
      'dialog_action': {
        'dialog': {
          'body': {
            'sections': [
              {
                'header': 'Add new contact',
                'widgets': [
                  {
                    'textInput': {
                      'label': 'Name',
                      'type': 'SINGLE_LINE',
                      'name': 'name'
                    }
                  },
                  {
                    'textInput': {
                      'label': 'Address',
                      'type': 'MULTIPLE_LINE',
                      'name': 'address'
                    }
                  },
                  {
                    'decoratedText': {
                      'text': 'Add to favorites',
                      'switchControl': {
                        'controlType': 'SWITCH',
                        'name': 'saveFavorite'
                      }
                    }
                  },
                  {
                    'decoratedText': {
                      'text': 'Merge with existing contacts',
                      'switchControl': {
                        'controlType': 'SWITCH',
                        'name': 'mergeContact',
                        'selected': True
                      }
                    }
                  },
                  {
                    'buttonList': {
                      'buttons': [
                        {
                          'text': 'Next',
                          'onClick': {
                            'action': {
                              'function': 'open_sequential_dialog'
                            }
                          }
                        }
                      ]
                    }
                  }
                ]
              }
            ]
          }
        }
      }
    }
  }

def open_sequential_dialog(request: Mapping[str, Any]) -> Mapping[str, Any]:
  """Opens a second dialog that allows users to add more contact details.

  Args:
      request (Mapping[str, Any]): the event object from Chat API.

  Returns:
      Mapping[str, Any]: open a Dialog in response to a card's button click.
  """
  return {
    'action_response': {
      'type': 'DIALOG',
      'dialog_action': {
        'dialog': {
              'body': {
                'sections': [
                  {
                    'header': 'Add new contact',
                    'widgets': [
                      {
                        'textInput': {
                          'label': 'Notes',
                          'type': 'MULTIPLE_LINE',
                          'name': 'notes'
                        }
                      },
                      {
                        'selectionInput': {
                          'type': 'RADIO_BUTTON',
                          'label': 'Contact type',
                          'name': 'contactType',
                          'items': [
                            {
                              'text': 'Work',
                              'value': 'Work',
                              'selected': False
                            },
                            {
                              'text': 'Personal',
                              'value': 'Personal',
                              'selected': False
                            }
                          ]
                        }
                      },
                      {
                        'buttonList': {
                          'buttons': [
                            {
                              'text': 'Submit',
                              'onClick': {
                                'action': {
                                  'function': 'receive_dialog',
                                  'parameters': [
                                    {
                                      'key': 'receiveDialog',
                                      'value': 'receiveDialog'
                                    }
                                  ]
                                }
                              }
                            }
                          ]
                        },
                        'horizontalAlignment': 'END'
                      }
                    ]
                  }
                ]
              }
        }
      }
    }
  }

def receive_dialog(event: Mapping[str, Any]) -> Mapping[str, Any]:
  """Checks for a form input error, the absence of a "name" value, and returns
     an error if absent. Otherwise, confirms successful receipt of a dialog.

  Args:
      event (Mapping[str, Any]): the event object from Chat API.

  Returns:
      Mapping[str, Any]: the response.
  """

  if event.get('common', dict()) \
      .get('formInputs', dict()).get('contactName', dict()) \
          .get('stringInputs').get('value', list()):
    return {
      'actionResponse': {
        'type': 'DIALOG',
        'dialogAction': {
          'actionStatus': 'OK'
        }
      }
    }
  else:
    return {
      'actionResponse': {
        'type': 'DIALOG',
        'dialogAction': {
          'actionStatus': "Don't forget to name your new contact!"
        }
      }
    }

Límites y consideraciones

Toma nota de estos límites y consideraciones para los diálogos:

  • Las tarjetas v1, que ya no están disponibles, no son compatibles con los diálogos. En su lugar, usa tarjetas v2.
  • No se admiten las sugerencias de autocompletado generadas por el servidor, pero las que se muestran con la respuesta del diálogo sí lo son.
  • No se admite onChangeAction, una propiedad de algunos widgets de tarjetas, como SwitchControl, que especifica un Action para realizar cuando se cambia el widget, como girar un interruptor.

Diálogos de depuración

A medida que implementas los diálogos, es posible que necesites depurar tu app de Chat leyendo los registros de la app. Para leer los registros, visita el Explorador de registros en Google Cloud Console.