Как собирать и обрабатывать информацию пользователей Google Chat

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

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

Приложения Chat запрашивают у пользователей информацию для выполнения действий в Chat или за его пределами, в том числе следующими способами:

  • Задайте настройки. Например, чтобы пользователи могли настраивать уведомления или добавлять приложение Chat в чат-группы.
  • создавать и обновлять информацию в других приложениях Google Workspace; Например, разрешите пользователям создавать мероприятия в Google Календаре.
  • Предоставлять пользователям доступ к ресурсам в других приложениях или веб-сервисах и возможность обновлять их. Например, приложение Chat может помочь пользователям обновить статус запроса в службу поддержки прямо из чат-группы Chat.

Требования

HTTP

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

Apps Script

Приложение Google Chat, которое получает взаимодействия пользователей и отвечает на них. Чтобы создать его, ознакомьтесь с кратким руководством по Apps Script.

Создание форм с помощью карточек

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

  • Сообщения, содержащие одну или несколько карточек.
  • Главные страницы – карточки, которые появляются на вкладке Главная в прямых переписках с приложением Chat.
  • Диалоговые окна – карточки, которые открываются в новом окне из сообщений и главных страниц.

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

  • Виджеты ввода формы, запрашивающие информацию у пользователей. При необходимости вы можете добавить проверку для виджетов ввода формы, чтобы убедиться, что пользователи вводят и форматируют информацию правильно. Приложения Chat могут использовать следующие виджеты ввода формы:

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

В следующем примере карточка собирает контактную информацию с помощью текстового ввода, средства выбора даты и времени и ввода выбора:

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

Как добавить раскрывающееся меню

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

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

Как заполнить элементы из источника данных Google Workspace

Чтобы заполнить элементы из источников данных Google Workspace, например пользователей Google Workspace, укажите поле platformDataSource в объекте DataSourceConfig. В отличие от других типов полей ввода, объекты SelectionItem опускаются, поскольку эти элементы выбора динамически извлекаются из Google Workspace.

В следующем коде показано раскрывающееся меню пользователей Google Workspace:

JSON

{
  "sections": [
    {
      "header": "Section Header",
      "widgets": [
        {
          "selectionInput": {
            "name": "contacts",
            "type": "DROPDOWN",
            "label": "Select contact from organization",
            "dataSourceConfigs": [
              {
                "platformDataSource": {
                  "commonDataSource": "USER"
                },
                "minCharactersTrigger": 1
              }
            ]
          }
        }
      ]
    }
  ]
}

Заполнить элементы из внешнего источника данных

Раскрывающиеся меню также могут заполнять элементы из стороннего или внешнего источника данных. Чтобы использовать внешний источник данных, укажите поле remoteDataSource в объекте DataSourceConfig, который содержит функцию, запрашивающую и возвращающую элементы из источника данных.

Чтобы сократить количество запросов к внешнему источнику данных, вы можете включить рекомендуемые элементы, которые появляются в раскрывающемся меню до того, как пользователи начнут вводить текст. Чтобы заполнить список рекомендуемых объектов из внешнего источника данных, укажите статические объекты SelectionItem.

В приведенном ниже коде показано раскрывающееся меню, которое запрашивает и заполняет элементы из внешнего источника данных:

JSON

{
  "sections": [
    {
      "header": "Section Header",
      "widgets": [
        {
          "selectionInput": {
            "name": "crm_leads",
            "type": "DROPDOWN",
            "label": "Select CRM Lead",
            "dataSourceConfigs": [
              {
                "remoteDataSource": {
                  "function": "getCrmLeads"
                },
                "minCharactersTrigger": 2
              }
            ],
            "items": [
              {
                "text": "Suggested Lead 1",
                "value": "lead-1"
              }
            ]
          }
        }
      ]
    }
  ]
}

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

Как добавить меню с множественным выбором

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

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

  • Данные Google Workspace, в том числе пользователи или чат-группы, в которых состоит пользователь. В меню будут показаны только объекты, принадлежащие той же организации Google Workspace.
  • Внешние источники данных, например реляционная база данных. Например, с помощью меню с множественным выбором пользователь может выбрать нужные варианты из списка потенциальных клиентов в системе управления взаимоотношениями с клиентами (CRM).

Как заполнить элементы из источника данных Google Workspace

Чтобы использовать источники данных Google Workspace, укажите поле platformDataSource в виджете SelectionInput. В отличие от других типов полей ввода, объекты SelectionItem опускаются, поскольку эти элементы выбора динамически извлекаются из Google Workspace.

В коде ниже показано меню множественного выбора пользователей Google Workspace. Чтобы заполнить список пользователей, в поле ввода задается значение USER для commonDataSource:

JSON

{
  "selectionInput": {
    "name": "contacts",
    "type": "MULTI_SELECT",
    "label": "Selected contacts",
    "multiSelectMaxSelectedItems": 5,
    "multiSelectMinQueryLength": 1,
    "platformDataSource": {
      "commonDataSource": "USER"
    }
  }
}

В коде ниже показано меню чат-групп Chat с множественным выбором. Чтобы заполнить чат-группы, в виджете выбора указывается поле hostAppDataSource. В меню множественного выбора также задается значение true для defaultToCurrentSpace, чтобы текущая чат-группа была выбрана в меню по умолчанию:

JSON

{
  "selectionInput": {
    "name": "spaces",
    "type": "MULTI_SELECT",
    "label": "Selected contacts",
    "multiSelectMaxSelectedItems": 3,
    "multiSelectMinQueryLength": 1,
    "platformDataSource": {
      "hostAppDataSource": {
        "chatDataSource": {
          "spaceDataSource": {
            "defaultToCurrentSpace": true
          }
        }
      }
    }
  }
}

Заполнить элементы из внешнего источника данных

Меню с множественным выбором также могут заполнять элементы из стороннего или внешнего источника данных. Чтобы использовать внешний источник данных, укажите поле externalDataSource в виджете SelectionInput, который содержит функцию, запрашивающую и возвращающую элементы из источника данных.

Чтобы сократить количество запросов к внешнему источнику данных, вы можете включить рекомендуемые элементы, которые появляются в меню множественного выбора до того, как пользователи начнут вводить текст. Например, вы можете заполнить список контактов, которые пользователь недавно искал. Чтобы заполнить список рекомендуемых объектов из внешнего источника данных, укажите статические объекты SelectionItem.

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

Node.js

node/chat/selection-input/index.js
selectionInput: {
  name: "contacts",
  type: "MULTI_SELECT",
  label: "Selected contacts",
  multiSelectMaxSelectedItems: 3,
  multiSelectMinQueryLength: 1,
  externalDataSource: { function: FUNCTION_URL },
  // Suggested items loaded by default.
  // The list is static here but it could be dynamic.
  items: [getSuggestedContact("3")]
}

Замените FUNCTION_URL конечной точкой HTTP, которая запрашивает внешний источник данных.

Python

python/chat/selection-input/main.py
'selectionInput': {
  'name': "contacts",
  'type': "MULTI_SELECT",
  'label': "Selected contacts",
  'multiSelectMaxSelectedItems': 3,
  'multiSelectMinQueryLength': 1,
  'externalDataSource': { 'function': FUNCTION_URL },
  # Suggested items loaded by default.
  # The list is static here but it could be dynamic.
  'items': [get_suggested_contact("3")]
}

Замените FUNCTION_URL конечной точкой HTTP, которая запрашивает внешний источник данных.

Java

java/chat/selection-input/src/main/java/com/google/chat/selectionInput/App.java
.setSelectionInput(new GoogleAppsCardV1SelectionInput()
  .setName("contacts")
  .setType("MULTI_SELECT")
  .setLabel("Selected contacts")
  .setMultiSelectMaxSelectedItems(3)
  .setMultiSelectMinQueryLength(1)
  .setExternalDataSource(new GoogleAppsCardV1Action().setFunction(FUNCTION_URL))
  // Suggested items loaded by default.
  // The list is static here but it could be dynamic.
  .setItems(List.of(getSuggestedContact("3")))))))))));

Замените FUNCTION_URL конечной точкой HTTP, которая запрашивает внешний источник данных.

Apps Script

В этом примере отправляется сообщение в виде карточки, возвращая JSON карточки. Вы также можете использовать сервис карточек Apps Script.

apps-script/chat/selection-input/selection-input.gs
selectionInput: {
  name: "contacts",
  type: "MULTI_SELECT",
  label: "Selected contacts",
  multiSelectMaxSelectedItems: 3,
  multiSelectMinQueryLength: 1,
  externalDataSource: { function: "queryContacts" },
  // Suggested items loaded by default.
  // The list is static here but it could be dynamic.
  items: [getSuggestedContact("3")]
}

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

Получать данные из интерактивных виджетов.

Когда пользователь нажимает кнопку, запускается действие приложения Chat, которое передает информацию о взаимодействии. В объекте commonEventObject полезной нагрузки события объект formInputs содержит все значения, введенные пользователем.

Вы можете получить значения из объекта event.commonEventObject.formInputs.WIDGET_NAME, где WIDGET_NAME – это поле name, которое вы указали для виджета. Значения возвращаются в виде определенного типа данных для виджета.

Ниже показана часть объекта события, в котором пользователь ввел значения для каждого виджета:

{
  "commonEventObject": { "formInputs": {
    "contactName": { "stringInputs": {
      "value": ["Kai 0"]
    }},
    "contactBirthdate": { "dateInput": {
      "msSinceEpoch": 1000425600000
    }},
    "contactType": { "stringInputs": {
      "value": ["Personal"]
    }}
  }}
}

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

Виджет ввода формы Тип входных данных Входное значение из объекта события Пример значения
textInput stringInputs event.commonEventObject.formInputs.contactName.stringInputs.value[0] Kai O
selectionInput stringInputs Чтобы получить первое или единственное значение, используйте event.commonEventObject.formInputs.contactType.stringInputs.value[0]. Personal
dateTimePicker, в котором принимаются только даты. dateInput event.commonEventObject.formInputs.contactBirthdate.dateInput.msSinceEpoch. 1000425600000

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

Предлагать варианты выбора

Если карточка содержит меню с возможностью выбора нескольких вариантов или раскрывающееся меню, которое заполняет элементы из внешнего источника данных, приложение Chat может возвращать предлагаемые элементы на основе того, что пользователи вводят в меню. Например, если пользователь начинает вводить Atl для меню, в котором заполняются города в США, ваше приложение Chat может автоматически предложить Atlanta до того, как пользователь закончит вводить текст. Приложение Chat может предложить до 100 элементов.

Чтобы предлагать и динамически заполнять элементы в поле выбора, виджет SelectionInput на карточке должен указывать функцию, которая запрашивает внешний источник данных. Для меню с множественным выбором укажите поле externalDataSource. Для раскрывающихся меню нужно указать поле remoteDataSource в объекте DataSourceConfig.

Вы также можете настроить количество символов, которые пользователь должен ввести, прежде чем в меню появятся подсказки. Для меню с множественным выбором задайте поле multiSelectMinQueryLength. Для раскрывающихся меню задайте поле min_characters_trigger в DataSourceConfig.

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

  1. Обрабатывать объект события, который приложение Chat получает, когда пользователи вводят текст в меню.
  2. Из объекта события получите значение, которое вводит пользователь. Оно представлено в поле event.commonEventObject.parameters["autocomplete_widget_query"].
  3. Запросите источник данных, используя значение, введенное пользователем, чтобы получить один или несколько объектов SelectionItems, которые будут предложены пользователю.
  4. Чтобы вернуть рекомендуемые товары, верните действие RenderActions с объектом modifyCard.

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

Node.js

node/chat/selection-input/index.js
/**
 * Web app that responds to events sent from a Google Chat space.
 *
 * @param {Object} req Request sent from Google Chat space
 * @param {Object} res Response to send back
 */
app.post('/', async (req, res) => {
  // Stores the Google Chat event
  const chatEvent = req.body.chat;

  // Handle user interaction with multiselect.
  if(chatEvent.widgetUpdatedPayload) {
    return res.json(queryContacts(req.body));
  }

  // Replies with a card that contains the multiselect menu.
  return res.json({ hostAppDataAction: { chatDataAction: { createMessageAction: { message: {
    cardsV2: [{
      cardId: "contactSelector",
      card: { sections:[{ widgets: [{
        selectionInput: {
          name: "contacts",
          type: "MULTI_SELECT",
          label: "Selected contacts",
          multiSelectMaxSelectedItems: 3,
          multiSelectMinQueryLength: 1,
          externalDataSource: { function: FUNCTION_URL },
          // Suggested items loaded by default.
          // The list is static here but it could be dynamic.
          items: [getSuggestedContact("3")]
        }
      }]}]}
    }]
  }}}}});
});

/**
 * Get contact suggestions based on text typed by users.
 *
 * @param {Object} event the event object that contains the user's query
 * @return {Object} suggestions
 */
function queryContacts(event) {
  const query = event.commonEventObject.parameters["autocomplete_widget_query"];
  return { action: { modifyOperations: [{ updateWidget: { selectionInputWidgetSuggestions: { suggestions: [
    // The list is static here but it could be dynamic.
    getSuggestedContact("1"), getSuggestedContact("2"), getSuggestedContact("3"), getSuggestedContact("4"), getSuggestedContact("5")
  // Only return items based on the query from the user.
  ].filter(e => !query || e.text.includes(query)) }}}]}};
}

/**
 * Generate a suggested contact given an ID.
 *
 * @param {String} id The ID of the contact to return.
 * @return {Object} The contact formatted as a selection item in the menu.
 */
function getSuggestedContact(id) {
  return {
    value: id,
    startIconUri: "https://www.gstatic.com/images/branding/product/2x/contacts_48dp.png",
    text: "Contact " + id
  };
}

Замените FUNCTION_URL конечной точкой HTTP, которая запрашивает внешний источник данных.

Python

python/chat/selection-input/main.py
@app.route('/', methods=['POST'])
def post() -> Mapping[str, Any]:
  """Handle requests from Google Chat

  Returns:
      Mapping[str, Any]: The response
  """
  # Stores the Google Chat event
  chatEvent = request.get_json().get('chat')

  # Handle user interaction with multiselect.
  if chatEvent.get('widgetUpdatedPayload') is not None:
    return json.jsonify(query_contacts(request.get_json()))

  # Replies with a card that contains the multiselect menu.
  return json.jsonify({ 'hostAppDataAction': { 'chatDataAction': { 'createMessageAction': {
    'message': { 'cardsV2': [{
      'cardId': "contactSelector",
      'card': { 'sections':[{ 'widgets': [{
        'selectionInput': {
          'name': "contacts",
          'type': "MULTI_SELECT",
          'label': "Selected contacts",
          'multiSelectMaxSelectedItems': 3,
          'multiSelectMinQueryLength': 1,
          'externalDataSource': { 'function': FUNCTION_URL },
          # Suggested items loaded by default.
          # The list is static here but it could be dynamic.
          'items': [get_suggested_contact("3")]
        }
      }]}]}
    }]}
  }}}})


def query_contacts(event: dict) -> dict:
  """Get contact suggestions based on text typed by users.

  Args:
      event (Mapping[str, Any]): The event object that contains the user's query

  Returns:
      Mapping[str, Any]: The response with contact suggestions.
  """
  query = event.get("commonEventObject").get("parameters").get("autocomplete_widget_query")
  return { 'action': { 'modifyOperations': [{ 'updateWidget': { 'selectionInputWidgetSuggestions': { 'suggestions': list(
    filter(lambda e: query is None or query in e["text"], [
      # The list is static here but it could be dynamic.
      get_suggested_contact("1"), get_suggested_contact("2"), get_suggested_contact("3"), get_suggested_contact("4"), get_suggested_contact("5")
    # Only return items based on the query from the user
    ])
  )}}}]}}


def get_suggested_contact(id: str) -> dict:
  """Generate a suggested contact given an ID.

  Args:
      id (str): The ID of the contact to return.

  Returns:
      Mapping[str, Any]: The contact formatted as a selection item in the menu.
  """
  return {
    'value': id,
    'startIconUri': "https://www.gstatic.com/images/branding/product/2x/contacts_48dp.png",
    'text': "Contact " + id
  }

Замените FUNCTION_URL конечной точкой HTTP, которая запрашивает внешний источник данных.

Java

java/chat/selection-input/src/main/java/com/google/chat/selectionInput/App.java
@SpringBootApplication
@RestController
// Web app that responds to events sent from a Google Chat space.
public class App {
  private static final String FUNCTION_URL = "your-function-url";

  public static void main(String[] args) {
    SpringApplication.run(App.class, args);
  }

  /**
   * Handle requests from Google Chat
   * 
   * @param event the event object sent by Google Chat
   * @return The response to be sent back to Google Chat
   */
  @PostMapping("/")
  @ResponseBody
  public GenericJson onEvent(@RequestBody JsonNode event) throws Exception {
    // Stores the Google Chat event
    JsonNode chatEvent = event.at("/chat");

    // Handle user interaction with multiselect.
    if (!chatEvent.at("/widgetUpdatedPayload").isEmpty()) {
      return queryContacts(event);
    }

    // Replies with a card that contains the multiselect menu.
    Message message = new Message().setCardsV2(List.of(new CardWithId()
      .setCardId("contactSelector")
      .setCard(new GoogleAppsCardV1Card()
        .setSections(List.of(new GoogleAppsCardV1Section().setWidgets(List.of(new GoogleAppsCardV1Widget()
          .setSelectionInput(new GoogleAppsCardV1SelectionInput()
            .setName("contacts")
            .setType("MULTI_SELECT")
            .setLabel("Selected contacts")
            .setMultiSelectMaxSelectedItems(3)
            .setMultiSelectMinQueryLength(1)
            .setExternalDataSource(new GoogleAppsCardV1Action().setFunction(FUNCTION_URL))
            // Suggested items loaded by default.
            // The list is static here but it could be dynamic.
            .setItems(List.of(getSuggestedContact("3")))))))))));

    return new GenericJson() {{
      put("hostAppDataAction", new GenericJson() {{
        put("chatDataAction", new GenericJson() {{
          put("createMessageAction", new GenericJson() {{
            put("message", message);
          }});
        }});
      }});
    }};
  }

  /**
   * Get contact suggestions based on text typed by users.
   *
   * @param event the event object that contains the user's query.
   * @return The response with contact suggestions.
   */
  GenericJson queryContacts(JsonNode event) throws Exception {
    String query = event.at("/commonEventObject/parameters/autocomplete_widget_query").asText();
    List<GoogleAppsCardV1SelectionItem> suggestions = List.of(
      // The list is static here but it could be dynamic.
      getSuggestedContact("1"), getSuggestedContact("2"), getSuggestedContact("3"), getSuggestedContact("4"), getSuggestedContact("5")
    // Only return items based on the query from the user
    ).stream().filter(e -> query == null || e.getText().indexOf(query) > -1).toList();

    return new GenericJson() {{
      put("action", new GenericJson() {{
        put("modifyOperations", List.of(new GenericJson() {{
          put("updateWidget", new GenericJson() {{
            put("selectionInputWidgetSuggestions", new GenericJson() {{
              put("suggestions", suggestions);
            }});
          }});
        }}));
      }});
    }};
  }

  /**
   * Generate a suggested contact given an ID.
   * 
   * @param id The ID of the contact to return.
   * @return The contact formatted as a selection item in the menu.
   */
  GoogleAppsCardV1SelectionItem getSuggestedContact(String id) {
    return new GoogleAppsCardV1SelectionItem()
      .setValue(id)
      .setStartIconUri("https://www.gstatic.com/images/branding/product/2x/contacts_48dp.png")
      .setText("Contact " + id);
  }
}

Замените FUNCTION_URL конечной точкой HTTP, которая запрашивает внешний источник данных.

Apps Script

В этом примере отправляется сообщение в виде карточки, возвращая JSON карточки. Вы также можете использовать сервис карточек Apps Script.

apps-script/chat/selection-input/selection-input.gs
/**
* Responds to a Message trigger in Google Chat.
*
* @param {Object} event the event object from Google Chat
* @return {Object} Response from the Chat app.
*/
function onMessage(event) {
  // Replies with a card that contains the multiselect menu.
  return { hostAppDataAction: { chatDataAction: { createMessageAction: { message: {
    cardsV2: [{
      cardId: "contactSelector",
      card: { sections:[{ widgets: [{
        selectionInput: {
          name: "contacts",
          type: "MULTI_SELECT",
          label: "Selected contacts",
          multiSelectMaxSelectedItems: 3,
          multiSelectMinQueryLength: 1,
          externalDataSource: { function: "queryContacts" },
          // Suggested items loaded by default.
          // The list is static here but it could be dynamic.
          items: [getSuggestedContact("3")]
        }
      }]}]}
    }]
  }}}}};
}

/**
* Get contact suggestions based on text typed by users.
*
* @param {Object} event the event object that contains the user's query
* @return {Object} suggestions
*/
function queryContacts(event) {
  const query = event.commonEventObject.parameters["autocomplete_widget_query"];
  return { action: { modifyOperations: [{ updateWidget: { selectionInputWidgetSuggestions: { suggestions: [
    // The list is static here but it could be dynamic.
    getSuggestedContact("1"), getSuggestedContact("2"), getSuggestedContact("3"), getSuggestedContact("4"), getSuggestedContact("5")
  // Only return items based on the query from the user.
  ].filter(e => !query || e.text.includes(query)) }}}]}};
}

/**
* Generate a suggested contact given an ID.
*
* @param {String} id The ID of the contact to return.
* @return {Object} The contact formatted as a selection item in the menu.
*/
function getSuggestedContact(id) {
  return {
    value: id,
    startIconUri: "https://www.gstatic.com/images/branding/product/2x/contacts_48dp.png",
    text: "Contact " + id
  };
}

Перенести данные на другую карту

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

  • Разбивайте длинные формы на разделы.
  • Позвольте пользователям просматривать и подтверждать информацию из начальной карточки, чтобы они могли проверить свои ответы перед отправкой.
  • Динамически заполнять оставшиеся части формы. Например, чтобы предложить пользователям создать встречу, приложение Chat может показать начальную карточку с запросом причины встречи, а затем заполнить другую карточку, в которой указано доступное время в зависимости от типа встречи.

Чтобы перенести данные, введенные в исходной карточке, вы можете создать виджет button с параметрами actionParameters, которые содержат name виджета и значение, введенное пользователем, как показано в следующем примере:

Node.js

node/chat/contact-form-app/index.js
{ buttonList: { buttons: [{
  text: "SUBMIT",
  onClick: { action: {
    function: FUNCTION_URL,
    parameters: [
      { key: "actionName", value: "submitDialog" },
      // Pass input values as parameters for last dialog step (submission)
      { key: "contactName", value: name },
      { key: "contactBirthdate", value: birthdate },
      { key: "contactType", value: type }
    ]
  }}
}]}}

Замените FUNCTION_URL на конечную точку HTTP, которая обрабатывает нажатия кнопок.

Python

python/chat/contact-form-app/main.py
{ 'buttonList': { 'buttons': [{
  'text': "SUBMIT",
  'onClick': { 'action': {
    'function': FUNCTION_URL,
    'parameters': [
      { 'key': "actionName", 'value': "submitDialog" },
      # Pass input values as parameters for last dialog step (submission)
      { 'key': "contactName", 'value': name },
      { 'key': "contactBirthdate", 'value': birthdate },
      { 'key': "contactType", 'value': type }
    ]
  }}
}]}}

Замените FUNCTION_URL на конечную точку HTTP, которая обрабатывает нажатия кнопок.

Java

java/chat/contact-form-app/src/main/java/com/google/chat/contact/App.java
new GoogleAppsCardV1Widget().setButtonList(new GoogleAppsCardV1ButtonList().setButtons(List.of(
  new GoogleAppsCardV1Button()
    .setText("SUBMIT")
    .setOnClick(new GoogleAppsCardV1OnClick().setAction(new GoogleAppsCardV1Action()
      .setFunction(FUNCTION_URL)
      .setParameters(List.of(
        new GoogleAppsCardV1ActionParameter().setKey("actionName").setValue("submitDialog"),
        // Pass input values as parameters for last dialog step (submission)
        new GoogleAppsCardV1ActionParameter().setKey("contactName").setValue(name),
        new GoogleAppsCardV1ActionParameter().setKey("contactBirthdate").setValue(birthdate),
        new GoogleAppsCardV1ActionParameter().setKey("contactType").setValue(type))))))))))));

Замените FUNCTION_URL на конечную точку HTTP, которая обрабатывает нажатия кнопок.

Apps Script

В этом примере отправляется сообщение в виде карточки, возвращая JSON карточки. Вы также можете использовать сервис карточек Apps Script.

apps-script/chat/contact-form-app/Code.gs
{ buttonList: { buttons: [{
  text: "SUBMIT",
  onClick: { action: {
    function: "submitDialog",
    // Pass input values as parameters for last dialog step (submission)
    parameters: [
      { key: "contactName", value: name },
      { key: "contactBirthdate", value: birthdate },
      { key: "contactType", value: type }
    ]
  }}
}]}}

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

Как ответить на отправленную форму

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

В следующем примере приложение Chat отправляет текстовое сообщение, чтобы подтвердить, что оно успешно получило форму, отправленную из сообщения в виде карточки.

Node.js

node/chat/contact-form-app/index.js
return { hostAppDataAction: { chatDataAction: { createMessageAction: { message: {
  text: "✅ " + event.commonEventObject.parameters["contactName"] + " has been added to your contacts."
}}}}};

Python

python/chat/contact-form-app/main.py
return { 'hostAppDataAction': { 'chatDataAction': { 'createMessageAction': { 'message': {
  'text': "✅ " + event.get('commonEventObject').get('parameters')["contactName"] + " has been added to your contacts."
}}}}}

Java

java/chat/contact-form-app/src/main/java/com/google/chat/contact/App.java
return new GenericJson() {{
  put("hostAppDataAction", new GenericJson() {{
    put("chatDataAction", new GenericJson() {{
      put("createMessageAction", new GenericJson() {{
        put("message", new Message()
          .setText( "✅ " + event.at("/commonEventObject/parameters/contactName").asText() +
                    " has been added to your contacts."));
      }});
    }});
  }});
}};

Apps Script

В этом примере отправляется сообщение в виде карточки, возвращая JSON карточки. Вы также можете использовать сервис карточек Apps Script.

apps-script/chat/contact-form-app/Code.gs
return { hostAppDataAction: { chatDataAction: { createMessageAction: { message: {
  text: "✅ " + event.commonEventObject.parameters["contactName"] + " has been added to your contacts."
}}}}};

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

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

В этом разделе приведены инструкции по устранению неполадок, связанных с определенными кодами ошибок и поведением во время выполнения при взаимодействии с диалоговыми окнами в Chat.

При взаимодействии с диалоговым окном возвращается ошибка "При вызове дополнения возникла неизвестная ошибка"

Если при взаимодействии с диалоговым окном вы видите журналы ошибок с сообщением "Неизвестная ошибка при вызове дополнения" и кодом 13, это обычно указывает на внутреннюю ошибку или на то, что конечной точке HTTP приложения Chat не удалось обработать запрос или вернуть действительный ответ.

Чтобы устранить эту ошибку, выполните следующие действия:

  • Проверьте журналы конечной точки HTTP на наличие необработанных исключений или сбоев.
  • Убедитесь, что конечная точка отвечает на запросы в течение 30 секунд. Если конечная точка выполняется дольше 30 секунд, Chat не может обработать ответ и взаимодействие завершается ошибкой. Подробную информацию можно найти в статье Ограничения частоты запросов и рекомендации.
  • Убедитесь, что конечная точка возвращает действительный ответ. Для отправки диалоговых окон конечная точка должна возвращать объект RenderActions в правильном формате JSON. Если ответ неверно сформирован или не содержит обязательных полей, взаимодействие с диалоговым окном может завершиться ошибкой.

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

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

Приложения Chat, которые не являются дополнениями: чтение данных формы, введенных пользователями на карточках.

Приведенная ниже документация относится к приложениям Chat, которые не являются дополнениями Google Workspace. Чтобы перенести приложение Chat, которое не является дополнением, ознакомьтесь со статьей Как преобразовать приложение Google Chat в дополнение Google Workspace.

Создание форм с помощью карточек

Ниже приведен пример кода приложения Chat, которое не является дополнением и использует форму обратной связи с полем ввода текста, средством выбора даты и времени и полем выбора.

Node.js

node/contact-form-app/index.js
/**
 * The section of the contact card that contains the form input widgets. Used in a dialog and card message.
 * To add and preview widgets, use the Card Builder: https://addons.gsuite.google.com/uikit/builder
 */
const CONTACT_FORM_WIDGETS = [
  {
    "textInput": {
      "name": "contactName",
      "label": "First and last name",
      "type": "SINGLE_LINE"
    }
  },
  {
    "dateTimePicker": {
      "name": "contactBirthdate",
      "label": "Birthdate",
      "type": "DATE_ONLY"
    }
  },
  {
    "selectionInput": {
      "name": "contactType",
      "label": "Contact type",
      "type": "RADIO_BUTTON",
      "items": [
        {
          "text": "Work",
          "value": "Work",
          "selected": false
        },
        {
          "text": "Personal",
          "value": "Personal",
          "selected": false
        }
      ]
    }
  }
];

Python

python/contact-form-app/main.py
# The section of the contact card that contains the form input widgets. Used in a dialog and card message.
# To add and preview widgets, use the Card Builder: https://addons.gsuite.google.com/uikit/builder
CONTACT_FORM_WIDGETS = [
  {
    "textInput": {
      "name": "contactName",
      "label": "First and last name",
      "type": "SINGLE_LINE"
    }
  },
  {
    "dateTimePicker": {
      "name": "contactBirthdate",
      "label": "Birthdate",
      "type": "DATE_ONLY"
    }
  },
  {
    "selectionInput": {
      "name": "contactType",
      "label": "Contact type",
      "type": "RADIO_BUTTON",
      "items": [
        {
          "text": "Work",
          "value": "Work",
          "selected": False
        },
        {
          "text": "Personal",
          "value": "Personal",
          "selected": False
        }
      ]
    }
  }
]

Java

java/contact-form-app/src/main/java/com/google/chat/contact/App.java
// The section of the contact card that contains the form input widgets. Used in a dialog and card message.
// To add and preview widgets, use the Card Builder: https://addons.gsuite.google.com/uikit/builder
final static private List<GoogleAppsCardV1Widget> CONTACT_FORM_WIDGETS = List.of(
  new GoogleAppsCardV1Widget().setTextInput(new GoogleAppsCardV1TextInput()
    .setName("contactName")
    .setLabel("First and last name")
    .setType("SINGLE_LINE")),
  new GoogleAppsCardV1Widget().setDateTimePicker(new GoogleAppsCardV1DateTimePicker()
    .setName("contactBirthdate")
    .setLabel("Birthdate")
    .setType("DATE_ONLY")),
  new GoogleAppsCardV1Widget().setSelectionInput(new GoogleAppsCardV1SelectionInput()
    .setName("contactType")
    .setLabel("Contact type")
    .setType("RADIO_BUTTON")
    .setItems(List.of(
      new GoogleAppsCardV1SelectionItem()
        .setText("Work")
        .setValue("Work")
        .setSelected(false),
      new GoogleAppsCardV1SelectionItem()
        .setText("Personal")
        .setValue("Personal")
        .setSelected(false)))));

Apps Script

apps-script/contact-form-app/contactForm.gs
/**
 * The section of the contact card that contains the form input widgets. Used in a dialog and card message.
 * To add and preview widgets, use the Card Builder: https://addons.gsuite.google.com/uikit/builder
 */
const CONTACT_FORM_WIDGETS = [
  {
    "textInput": {
      "name": "contactName",
      "label": "First and last name",
      "type": "SINGLE_LINE"
    }
  },
  {
    "dateTimePicker": {
      "name": "contactBirthdate",
      "label": "Birthdate",
      "type": "DATE_ONLY"
    }
  },
  {
    "selectionInput": {
      "name": "contactType",
      "label": "Contact type",
      "type": "RADIO_BUTTON",
      "items": [
        {
          "text": "Work",
          "value": "Work",
          "selected": false
        },
        {
          "text": "Personal",
          "value": "Personal",
          "selected": false
        }
      ]
    }
  }
];

Получать данные из интерактивных виджетов.

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

  • Если кнопка находится в сообщении или диалоговом окне, приложения Chat, которые не являются дополнениями, получают событие взаимодействия CARD_CLICKED, которое содержит информацию о взаимодействии. Полезная нагрузка событий взаимодействия CARD_CLICKED содержит объект common.formInputs (event.common.formInputs) со всеми значениями, введенными пользователем.

    Вы можете получить значения из объекта common.formInputs.WIDGET_NAME, где WIDGET_NAME – это поле name, которое вы указали для виджета. Значения возвращаются в виде определенного типа данных для виджета (представленного как объект Inputs).

    Ниже показана часть события взаимодействия CARD_CLICKED, в котором пользователь ввел значения для каждого виджета:

    HTTP

    {
      "type": "CARD_CLICKED",
      "common": { "formInputs": {
        "contactName": { "stringInputs": {
          "value": ["Kai 0"]
        }},
        "contactBirthdate": { "dateInput": {
          "msSinceEpoch": 1000425600000
        }},
        "contactType": { "stringInputs": {
          "value": ["Personal"]
        }}
      }}
    }
    

    Apps Script

    {
      "type": "CARD_CLICKED",
      "common": { "formInputs": {
        "contactName": { "": { "stringInputs": {
          "value": ["Kai 0"]
        }}},
        "contactBirthdate": { "": { "dateInput": {
          "msSinceEpoch": 1000425600000
        }}},
          "contactType": { "": { "stringInputs": {
          "value": ["Personal"]
        }}}
      }}
    }
    
  • Если кнопка находится на главной странице, приложения Chat, которые не являются дополнениями, получают событие взаимодействия SUBMIT_FORM. Полезная нагрузка события взаимодействия содержит объект commonEventObject.formInputs (event.commonEventObject.formInputs) со всеми значениями, введенными пользователем.

    Вы можете получить значения из объекта commonEventObject.formInputs.WIDGET_NAME, где WIDGET_NAME – это поле name, которое вы указали для виджета. Значения возвращаются в виде определенного типа данных для виджета (представленного как объект Inputs).

    Ниже показана часть события взаимодействия SUBMIT_FORM, в котором пользователь ввел значения для каждого виджета:

    HTTP

    {
      "type": "SUBMIT_FORM",
      "commonEventObject": { "formInputs": {
        "contactName": { "stringInputs": {
          "value": ["Kai 0"]
        }},
        "contactBirthdate": { "dateInput": {
          "msSinceEpoch": 1000425600000
        }},
        "contactType": { "stringInputs": {
          "value": ["Personal"]
        }}
      }}
    }
    

    Apps Script

    {
      "type": "SUBMIT_FORM",
      "commonEventObject": { "formInputs": {
        "contactName": { "": { "stringInputs": {
          "value": ["Kai 0"]
        }}},
        "contactBirthdate": { "": { "dateInput": {
          "msSinceEpoch": 1000425600000
        }}},
          "contactType": { "": { "stringInputs": {
          "value": ["Personal"]
        }}}
      }}
    }
    

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

Виджет ввода формы Тип входных данных Входное значение из события взаимодействия Пример значения
textInput stringInputs event.common.formInputs.contactName.stringInputs.value[0] Kai O
selectionInput stringInputs Чтобы получить первое или единственное значение, используйте event.common.formInputs.contactType.stringInputs.value[0]. Personal
dateTimePicker, в котором принимаются только даты. dateInput event.common.formInputs.contactBirthdate.dateInput.msSinceEpoch. 1000425600000

Перенести данные на другую карту

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

Node.js

node/contact-form-app/index.js
buttonList: { buttons: [{
  text: "Submit",
  onClick: { action: {
    function: "submitForm",
    parameters: [{
      key: "contactName", value: name }, {
      key: "contactBirthdate", value: birthdate }, {
      key: "contactType", value: type
    }]
  }}
}]}

Python

python/contact-form-app/main.py
'buttonList': { 'buttons': [{
  'text': "Submit",
  'onClick': { 'action': {
    'function': "submitForm",
    'parameters': [{
      'key': "contactName", 'value': name }, {
      'key': "contactBirthdate", 'value': birthdate }, {
      'key': "contactType", 'value': type
    }]
  }}
}]}

Java

java/contact-form-app/src/main/java/com/google/chat/contact/App.java
new GoogleAppsCardV1Widget().setButtonList(new GoogleAppsCardV1ButtonList().setButtons(List.of(new GoogleAppsCardV1Button()
  .setText("Submit")
  .setOnClick(new GoogleAppsCardV1OnClick().setAction(new GoogleAppsCardV1Action()
    .setFunction("submitForm")
    .setParameters(List.of(
      new GoogleAppsCardV1ActionParameter().setKey("contactName").setValue(name),
      new GoogleAppsCardV1ActionParameter().setKey("contactBirthdate").setValue(birthdate),
      new GoogleAppsCardV1ActionParameter().setKey("contactType").setValue(type))))))))));

Apps Script

apps-script/contact-form-app/main.gs
buttonList: { buttons: [{
  text: "Submit",
  onClick: { action: {
    function: "submitForm",
    parameters: [{
      key: "contactName", value: name }, {
      key: "contactBirthdate", value: birthdate }, {
      key: "contactType", value: type
    }]
  }}
}]}

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

Как ответить на отправленную форму

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

Node.js

node/contact-form-app/index.js
const contactName = event.common.parameters["contactName"];
// Checks to make sure the user entered a contact name.
// If no name value detected, returns an error message.
const errorMessage = "Don't forget to name your new contact!";
if (!contactName && event.dialogEventType === "SUBMIT_DIALOG") {
  return { actionResponse: {
    type: "DIALOG",
    dialogAction: { actionStatus: {
      statusCode: "INVALID_ARGUMENT",
      userFacingMessage: errorMessage
    }}
  }};
}

Python

python/contact-form-app/main.py
contact_name = event.get('common').get('parameters')["contactName"]
# Checks to make sure the user entered a contact name.
# If no name value detected, returns an error message.
error_message = "Don't forget to name your new contact!"
if contact_name == "" and "SUBMIT_DIALOG" == event.get('dialogEventType'):
  return { 'actionResponse': {
    'type': "DIALOG",
    'dialogAction': { 'actionStatus': {
      'statusCode': "INVALID_ARGUMENT",
      'userFacingMessage': error_message
    }}
  }}

Java

java/contact-form-app/src/main/java/com/google/chat/contact/App.java
String contactName = event.at("/common/parameters/contactName").asText();
// Checks to make sure the user entered a contact name.
// If no name value detected, returns an error message.
String errorMessage = "Don't forget to name your new contact!";
if (contactName.isEmpty() && event.at("/dialogEventType") != null && "SUBMIT_DIALOG".equals(event.at("/dialogEventType").asText())) {
  return new Message().setActionResponse(new ActionResponse()
    .setType("DIALOG")
    .setDialogAction(new DialogAction().setActionStatus(new ActionStatus()
      .setStatusCode("INVALID_ARGUMENT")
      .setUserFacingMessage(errorMessage))));
}

Apps Script

apps-script/contact-form-app/main.gs
const contactName = event.common.parameters["contactName"];
// Checks to make sure the user entered a contact name.
// If no name value detected, returns an error message.
const errorMessage = "Don't forget to name your new contact!";
if (!contactName && event.dialogEventType === "SUBMIT_DIALOG") {
  return { actionResponse: {
    type: "DIALOG",
    dialogAction: { actionStatus: {
      statusCode: "INVALID_ARGUMENT",
      userFacingMessage: errorMessage
    }}
  }};
}

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