Открытие интерактивных диалогов

На этой странице описано, как ваше приложение чата может открывать диалоговые окна для ответа пользователям.

Диалоги представляют собой оконные интерфейсы на основе карточек, которые открываются из чата или сообщения. Диалог и его содержимое видны только пользователю, который его открыл.

Приложения чата могут использовать диалоговые окна для запроса и сбора информации от пользователей чата, включая многоэтапные формы. Дополнительные сведения о создании входных данных формы см. в разделе Сбор и обработка информации от пользователей .

Предварительные условия

Node.js

  • Приложение Google Chat с интерактивными функциями. Чтобы создать интерактивное приложение чата с использованием службы HTTP, выполните это краткое руководство .

Питон

  • Приложение Google Chat с интерактивными функциями. Чтобы создать интерактивное приложение чата с использованием службы HTTP, выполните это краткое руководство .

Скрипт приложений

  • Приложение Google Chat с интерактивными функциями. Чтобы создать интерактивное приложение чата с помощью Apps Script, выполните это краткое руководство .

Открыть диалог

Диалог с множеством различных виджетов.
Рис. 1. Пример приложения чата , открывающего диалоговое окно для сбора контактной информации.

В этом разделе объясняется, как ответить и настроить диалог, выполнив следующие действия:

  1. Запускайте запрос диалога при взаимодействии с пользователем.
  2. Обработайте запрос, вернувшись и открыв диалоговое окно.
  3. После того как пользователи отправят информацию, обработайте отправку, закрыв диалоговое окно или вернув другое диалоговое окно.

Запустить запрос диалога

Приложение чата может открывать диалоговые окна только для ответа на взаимодействие с пользователем, например на команду косой черты или нажатие кнопки в сообщении на карточке.

Чтобы ответить пользователям с помощью диалогового окна, приложение Chat должно создать взаимодействие, которое запускает запрос диалогового окна, например следующее:

  • Ответить на команду косой черты. Чтобы инициировать запрос слэш-команды, необходимо установить флажок «Открывает диалог» при настройке команды .
  • Ответьте на нажатие кнопки в сообщении , либо в карточке, либо в нижней части сообщения. Чтобы инициировать запрос от кнопки в сообщении, вы настраиваете действие кнопки onClick , устанавливая для ее interaction значение OPEN_DIALOG .
  • Ответьте на нажатие кнопки на главной странице приложения Chat . Подробнее об открытии диалоговых окон с домашних страниц см. в разделе Создание домашней страницы для приложения Google Chat .
Кнопка, вызывающая диалог
Рис. 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 , установленным в DIALOG и объект Message . Чтобы указать содержимое диалога, вы включаете следующие объекты:

  • Объект actionResponse с type DIALOG .
  • Объект dialogAction . Поле body содержит элементы пользовательского интерфейса (UI), которые будут отображаться на карточке, включая один или несколько sections виджетов. Для сбора информации от пользователей вы можете указать виджеты ввода формы и виджет кнопки. Дополнительные сведения о разработке входных данных для форм см. в разделе Сбор и обработка информации от пользователей .

Следующий JSON показывает, как приложение Chat возвращает ответ, открывающий диалоговое окно:

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

Где BUTTON_TEXT — это текст, который отображается на кнопке (например, Next или Submit »), WIDGETS представляет собой один или несколько виджетов ввода формы , а FUNCTION_NAME — это функция, которая запускается, когда пользователи нажимают кнопку.

Обработка отправки диалога

Когда пользователи нажимают кнопку, которая отправляет диалоговое окно, ваше приложение Chat получает событие взаимодействия CARD_CLICKED , где для dialogEventType установлено значение SUBMIT_DIALOG .

Ваше приложение чата должно обрабатывать событие взаимодействия, выполнив одно из следующих действий:

Необязательно: вернуть другое диалоговое окно.

После того как пользователи отправят исходное диалоговое окно, приложения чата могут вернуть одно или несколько дополнительных диалоговых окон, которые помогут пользователям просмотреть информацию перед отправкой, заполнить многоэтапные формы или динамически заполнить содержимое формы.

Чтобы загрузить любые данные, которые пользователи вводят из начального диалогового окна, необходимо добавить параметры к кнопке, открывающей следующее диалоговое окно, или передать исходное событие взаимодействия CARD_CLICKED из начального диалогового окна. Подробности см. в разделе Перенос данных на другую карту .

В этом примере приложение чата открывает диалоговое окно, которое возвращает второе диалоговое окно перед отправкой. Чтобы загрузить входные данные, приложение 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"
          }}
        }]}
      }
    ]}]}}}
  }});
}

Питон

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"
          }}
        }]}
      }
    ]}]}}}
  }}

Скрипт приложений

В этом примере отправляется карточное сообщение, возвращая card JSON . Вы также можете использовать службу карточек 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 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 получает событие взаимодействия со следующей информацией:

  • eventTypeCARD_CLICKED .
  • dialogEventTypeSUBMIT_DIALOG .
  • common.formInputs содержит любые данные, которые пользователи вводят с помощью виджетов.

В следующих разделах объясняется, как проверить данные, вводимые пользователями, и закрыть диалоговое окно.

Подтвердите введенные пользователем данные и закройте диалоговое окно.

Для обработки данных, вводимых пользователями, приложение Chat использует объект event.common.formInputs . Дополнительные сведения о получении значений из виджетов ввода см. в разделе Сбор и обработка информации от пользователей .

Если пользователь пропустит обязательное поле или введет неправильные значения, приложение Chat может ответить ошибкой, вернув ActionResponse со значением "actionStatus": " ERROR MESSAGE " .

В следующем примере проверяется, вводит ли пользователь значение для виджета, который принимает строки ( stringInputs ), например виджет textInput . Если оно отсутствует, приложение «Чат» возвращает ошибку. Если оно присутствует, приложение 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"
        }
      }
    });
  }
}

Питон

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'
                }
              }
            }

Скрипт приложений

В этом примере отправляется карточное сообщение, возвращая card JSON . Вы также можете использовать службу карточек 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 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 виджета (например, contactName ), а ERROR_MESSAGE представляет содержимое сообщения об ошибке (например, Don't forget to name your contact »). Подробную информацию об обработке входных данных из виджетов см. в разделе Получение данных от интерактивных виджетов .

Необязательно: отправьте сообщение с подтверждением.

Закрывая диалоговое окно, вы также можете отправить новое сообщение или обновить существующее.

Чтобы отправить новое сообщение, верните объект ActionResponse с type NEW_MESSAGE . Например, чтобы закрыть диалоговое окно и отправить текстовое сообщение, верните следующее:

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

Чтобы обновить сообщение, верните объект actionResponse , который содержит обновленное сообщение и задает один из следующих type :

Устранение неполадок

Когда приложение или карточка Google Chat возвращает ошибку, в интерфейсе Chat отображается сообщение «Что-то пошло не так». или «Невозможно обработать ваш запрос». Иногда в пользовательском интерфейсе чата не отображается сообщение об ошибке, но приложение или карточка чата выдает неожиданный результат; например, сообщение с карточкой может не появиться.

Хотя сообщение об ошибке может не отображаться в пользовательском интерфейсе чата, доступны описательные сообщения об ошибках и данные журнала, которые помогут вам исправить ошибки, если включено ведение журнала ошибок для приложений чата. Информацию о просмотре, отладке и исправлении ошибок см. в разделе «Устранение неполадок и исправление ошибок Google Chat» .