打开互动对话框

本页介绍了 Chat 应用如何打开对话框 来响应用户

对话框是基于卡片的窗口式界面 通过 Chat 聊天室或消息打开的应用。该对话框及其 内容仅对打开它的用户可见。

聊天应用可以使用对话框向以下对象请求信息并从中收集信息: Chat 用户,包括多步骤表单。了解详情 如需了解如何构建表单输入,请参阅收集和处理用户信息

前提条件

Node.js

  • 一款已启用互动功能的 Google Chat 应用。要创建 交互式 Chat 应用,请完成此快速入门

Python

  • 一款已启用互动功能的 Google Chat 应用。要创建 交互式 Chat 应用,请完成此快速入门

Apps 脚本

  • 一款已启用互动功能的 Google Chat 应用。要创建 交互式聊天应用,请完成此快速入门

打开对话框

一个显示各种不同微件的对话框。
图 1:收集联系信息的对话框。

本部分介绍了如何通过执行以下操作来响应和设置对话框:

  1. 通过用户互动触发对话请求。
  2. 通过返回并打开一个对话框来处理请求。
  3. 用户提交信息后,通过关闭 对话框或返回另一个对话框。

触发对话请求

Chat 应用只能打开对话框来回复用户 互动,例如斜杠命令或点击卡片消息中的按钮。

如要使用对话框回复用户,Chat 应用必须 构建可触发对话框请求的交互,例如:

  • 响应斜杠命令。若要通过斜杠命令触发请求,请执行以下操作: 配置此命令时,您必须选中打开对话框复选框。
  • 消息、 以卡片形式显示或在邮件底部显示要触发 请求,您可以配置 按钮的onClick 操作(将其 interaction 设置为 OPEN_DIALOG)。
  • 响应 Chat 应用首页中的按钮点击。 要了解如何从首页打开对话框,请参阅 为 Google Chat 应用构建首页
。 <ph type="x-smartling-placeholder">
</ph> 用于触发对话框的按钮
图 2:Chat 应用发送一条消息,提示用户使用 /addContact 斜杠命令。
该消息还包含一个按钮,用户点击该按钮即可触发相应命令。

以下 JSON 展示了如何通过 卡片消息。要打开该对话框, button.interaction 字段设置为 OPEN_DIALOG

{
  "buttonList": { "buttons": [{
    "text": "BUTTON_TEXT",
    "onClick": { "action": {
      "function": "FUNCTION_NAME",
      "interaction": "OPEN_DIALOG"
    }}
  }]}
}

其中 BUTTON_TEXT 是显示在按钮中的文本 FUNCTION_NAME 是运行以打开初始 对话框。

打开初始对话框

当用户触发对话框请求时,您的 Chat 应用 它收到一个互动事件,表示为 event Chat API。如果互动触发了对话框请求,事件的 dialogEventType 字段设置为 REQUEST_DIALOG

为了打开对话框,您的 Chat 应用可以响应 来发送请求 actionResponse 对象,其中 type 设置为 DIALOGMessage 对象。要指定对话框的内容,请添加以下内容 对象:

  • actionResponse 该对象的 type 设置为 DIALOG
  • dialogAction 对象。body 字段包含 卡片中显示的内容, sections 的 widget。 要从用户处收集信息,您可以指定表单输入微件和 按钮微件。如需详细了解如何设计表单输入,请参阅 收集和处理用户信息

以下 JSON 展示了 Chat 应用如何返回 打开对话框的响应:

{ "actionResponse": {
  "type": "DIALOG",
  "dialogAction": { "dialog": { "body": { "sections": [{
    "widgets": [{
      WIDGETS,
      { "buttonList": { "buttons": [{
        "text": "BUTTON_TEXT",
        "onClick": {
          "action": {"function": "FUNCTION_NAME"}
        }
      }]}}
    }]
  }]}}}
}}

其中 BUTTON_TEXT 是在按钮中显示的文本(例如 NextSubmit),WIDGETS 表示一个或多个 表单输入 widget 以及 FUNCTION_NAME 是在用户点击按钮时运行的函数。

处理对话框提交

当用户点击用于提交对话框的按钮时,您的 Chat 应用接收 CARD_CLICKED 互动 事件,其中 dialogEventTypeSUBMIT_DIALOG

您的 Chat 应用必须通过以下方式处理互动事件: 执行以下操作之一:

可选:返回其他对话框

用户提交初始对话框后,Chat 应用可以执行以下操作 返回一个或多个其他对话框,帮助用户 提交表单、填写多步骤表单或动态填充表单内容。

要加载用户在初始对话框中输入的任何数据,您必须添加 将参数传递给用于打开下一个对话框的按钮,或者将原始 CARD_CLICKED 互动事件。有关详情,请参阅 将数据转移到其他卡

在此示例中,Chat 应用打开一个对话框 在提交之前返回第二个对话框。要加载输入数据, Chat 应用传递 CARD_CLICKED 互动事件 作为用于打开下一个对话框的函数的参数:

Node.js

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

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

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

/**
* Opens and starts a dialog that lets users add details about a contact.
*
* @param {object} event the event object from Google Chat.
*
* @return {object} open a dialog.
*/
function openDialog(event) {
  res.json({ "actionResponse": {
    "type": "DIALOG",
    "dialogAction": { "dialog": { "body": { "sections": [{ "widgets": [
      WIDGETS,
      { "buttonList": { "buttons": [{
        "text": "Next",
        "onClick": { "action": {
          "function": "openNextDialog"
        }}
      }]}}
    ]}]}}}
  }});
};

/**
* Opens a second dialog that lets users add more contact details.
*
* @param {object} event the event object from Google Chat.
*
* @return {object} open a dialog.
*/
function openNextDialog(event) {
  res.json({ "actionResponse": {
    "type": "DIALOG",
    "dialogAction": { "dialog": { "body": { "sections": [{ "widgets": [
      WIDGETS,
      {
        "horizontalAlignment": "END",
        "buttonList": { "buttons": [{
          "text": "Submit",
          "onClick": { "action": {
            "function": "submitDialog"
          }}
        }]}
      }
    ]}]}}}
  }});
}

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_next_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 { "actionResponse": {
    "type": "DIALOG",
    "dialogAction": { "dialog": { "body": { "sections": [{ "widgets": [
      WIDGETS,
      { "buttonList": { "buttons": [{
        "text": "Next",
        "onClick": { "action": {
          "function": "open_next_dialog"
        }}
      }]}}
    ]}]}}}
  }}

def open_next_dialog(request: Mapping[str, Any]) -> Mapping[str, Any]:
  """Opens a second dialog that lets users 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 { "actionResponse": {
    "type": "DIALOG",
    "dialogAction": { "dialog": { "body": { "sections": [{ "widgets": [
      WIDGETS,
      {
        "horizontalAlignment": "END",
        "buttonList": { "buttons": [{
          "text": "Submit",
          "onClick": { "action": {
            "function": "submit_dialog"
          }}
        }]}
      }
    ]}]}}}
  }}

Apps 脚本

此示例通过返回 卡片 JSON。 您还可以使用 Apps 脚本卡片服务

/**
* 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 Chat app checks to see which function to run.
  if (event.common.invokedFunction === "openDialog") {
    return openDialog(event);
  }

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

/**
* Opens and starts a dialog that lets users add details about a contact.
*
* @param {object} event the event object from Google Chat.
*
* @return {object} open a dialog.
*/
function openDialog(event) {
  return { "actionResponse": {
    "type": "DIALOG",
    "dialogAction": { "dialog": { "body": { "sections": [{ "widgets": [
      WIDGETS,
      { "buttonList": { "buttons": [{
        "text": "Next",
        "onClick": { "action": {
          "function": "openNextDialog"
        }}
      }]}}
    ]}]}}}
  }};
}

/**
* Opens a second dialog that lets users add more contact details.
*
* @param {object} event the event object from Google Chat.
*
* @return {object} open a dialog.
*/
function openNextDialog(event) {
  return { "actionResponse": {
    "type": "DIALOG",
    "dialogAction": { "dialog": { "body": { "sections": [{ "widgets": [
      WIDGETS,
      {
        "horizontalAlignment": "END",
        "buttonList": { "buttons": [{
          "text": "Submit",
          "onClick": { "action": {
            "function": "submitDialog"
          }}
        }]}
      }
    ]}]}}}
  }};
}

其中 WIDGETS 表示一个或多个 表单输入微件

关闭对话框

当用户点击对话框中的按钮时,您的 Chat 应用收到与 以下信息:

以下部分介绍了如何验证用户输入的数据 关闭对话框。

验证用户输入数据并关闭对话框

为了处理用户输入的数据,Chat 应用 使用 event.common.formInputs 对象。如需详细了解如何从输入 widget 检索值,请参阅 收集和处理用户信息

如果用户省略了必填字段,或输入了不正确的值, Chat 应用可以返回 ActionResponse 包含 "actionStatus": "ERROR MESSAGE" 的项。

以下示例检查用户是否为微件输入了 接受字符串 (stringInputs),例如 textInput widget。如果没有, Chat 应用返回错误。如果存在, Chat 应用确认对话框提交并 关闭对话框:

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 submitDialog(event) {

  // Checks to make sure the user entered a value
  // in a dialog. If no value detected, returns
  // an error message. Any "actionStatus" value other than "OK"
  // gets returned as an error.
  if (event.common.formInputs.WIDGET_NAME.stringInputs.value[0] === "") {
    res.json({
      "actionResponse": {
        "type": "DIALOG",
        "dialogAction": {
          "actionStatus": "ERROR_MESSAGE"
        }
      }
    });

    // Otherwise the Chat app indicates that it received
    // form data from the dialog. An "actionStatus" of "OK" is
    // interpreted as code 200, and the dialog closes.
  } else {
    res.json({
      "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': 'ERROR_MESSAGE'
                }
              }
            }

Apps 脚本

此示例通过返回 卡片 JSON。 您还可以使用 Apps 脚本卡片服务

/**
* 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 submitDialog(event) {

  // Checks to make sure the user entered a value
  // in a dialog. If no value detected, returns
  // an error message. Any "actionStatus" value other than "OK"
  // gets returned as an error.
  if (event.common.formInputs.WIDGET_NAME[""].stringInputs.value[0] === "") {
    return {
      "actionResponse": {
        "type": "DIALOG",
        "dialogAction": {
          "actionStatus": "ERROR_MESSAGE"
        }
      }
    };

    // Otherwise the Chat app indicates that it received
    // form data from the dialog. An "actionStatus" of "OK" is
    // interpreted as code 200, and the dialog closes.
  } else {
    return {
      "actionResponse": {
        "type": "DIALOG",
        "dialogAction": {
          "actionStatus": "OK"
        }
      }
    };
  }
}

在此例中, WIDGET_NAME 表示 name 字段的 widget(例如 contactName),而 ERROR_MESSAGE 表示 错误消息的内容(例如 Don't forget to name your contact)。 如需详细了解如何处理来自 widget 的输入数据,请参阅 从互动式微件接收数据

可选:发送确认消息

关闭对话框后,您还可以发送新消息或更新 现有资源

要发送新消息,请返回 ActionResponse 并将 type 设置为 NEW_MESSAGE。例如,关闭对话框 并发送短信,则返回以下内容:

  {
    "actionResponse": {
      "type": "NEW_MESSAGE",
    },
    "text": "Your information has been submitted."
  }

如需更新消息,请返回一个 actionResponse 对象,其中包含 更新了消息,并将 type 设置为以下其中一项:

问题排查

当 Google Chat 应用或 card 会返回错误, 聊天界面会显示一条内容为“出了点问题”的消息。 或“无法处理您的请求”。有时,Chat 界面 不会显示任何错误消息,但 Chat 应用或 卡片会产生意外结果;例如,卡片消息 。

虽然 Chat 界面中可能不会显示错误消息, 提供描述性错误消息和日志数据,以帮助您修正错误 启用 Chat 应用的错误日志记录时。如需观看方面的帮助, 请参阅 排查并修正 Google Chat 错误