Coletar e processar informações dos usuários do Google Chat

Este guia descreve como os apps do Google Chat podem coletar e processar informações dos usuários criando entradas de formulário em interfaces baseadas em cards.

Uma caixa de diálogo com vários widgets diferentes.
Figura 1: um app de chat que abre uma caixa de diálogo para coletar informações de contato.

Os apps de chat pedem informações aos usuários para realizar ações dentro ou fora do Chat, incluindo das seguintes maneiras:

  • Defina as configurações. Por exemplo, para permitir que os usuários personalizem as configurações de notificação ou configurem e adicionem o app Chat a um ou mais espaços.
  • Criar ou atualizar informações em outros aplicativos do Google Workspace. Por exemplo, permita que os usuários criem um evento do Google Agenda.
  • Permitir que os usuários acessem e atualizem recursos em outros apps ou serviços da Web. Por exemplo, um app do Chat pode ajudar os usuários a atualizar o status de um tíquete de suporte diretamente em um espaço do Chat.

Pré-requisitos

HTTP

Um complemento do Google Workspace que estende o Google Chat. Para criar um, conclua o início rápido de HTTP.

Apps Script

Um complemento do Google Workspace que estende o Google Chat. Para criar um, conclua o guia de início rápido do Apps Script.

Criar formulários usando cards

Para coletar informações, os apps do Chat criam formulários e entradas, e os transformam em cards. Para mostrar cards aos usuários, os apps do Chat podem usar as seguintes interfaces do Chat:

  • Mensagens de chat que contêm um ou mais cards.
  • Caixas de diálogo, que são cards abertos em uma nova janela de mensagens e páginas iniciais.

Os apps de chat podem criar os cards usando os seguintes widgets:

  • Widgets de entrada de formulário que solicitam informações dos usuários. Se quiser, adicione validação aos widgets de entrada de formulário para garantir que os usuários insiram e formatem as informações corretamente. Os apps de chat podem usar os seguintes widgets de entrada de formulário:

    • Entradas de texto (textInput) para texto livre ou sugerido.
    • Entradas de seleção (selectionInput) são elementos da interface selecionáveis, como caixas de seleção, botões de opção e menus suspensos. Os widgets de entrada de seleção também podem preencher e sugerir itens de dados do Google Workspace (como um espaço do Chat) ou de uma fonte de dados dinâmica. Para mais detalhes, consulte a seção Adicionar um menu de multisseleção.

    • Seletores de data e hora (dateTimePicker) para entradas de data e hora.

  • Um widget de botão para que os usuários possam enviar os valores inseridos no card. Depois que um usuário clica no botão, o app Chat pode processar as informações recebidas.

No exemplo a seguir, um card coleta informações de contato usando uma entrada de texto, um seletor de data e hora e uma entrada de seleção:

Para mais exemplos de widgets interativos que podem ser usados para coletar informações, consulte Criar um card ou uma caixa de diálogo interativa na documentação da API Google Chat.

Adicionar um menu de seleção múltipla

Para personalizar itens de seleção ou permitir que os usuários selecionem itens de uma fonte de dados dinâmica, os apps do Chat podem usar menus de seleção múltipla, que são um tipo de widget SelectionInput. Por exemplo, o card a seguir mostra um menu de seleção múltipla em que os usuários podem selecionar dinamicamente em uma lista de contatos:

É possível preencher itens para um menu de seleção múltipla com as seguintes fontes de dados:

  • Dados do Google Workspace, que incluem usuários ou espaços do Chat de que o usuário participa. O menu só preenche itens da mesma organização do Google Workspace.
  • Fontes de dados externas, como um banco de dados relacional. Por exemplo, você pode usar menus de seleção múltipla para ajudar um usuário a escolher em uma lista de leads de vendas de um sistema de gestão de relacionamento com o cliente (CRM).

Preencher itens de uma fonte de dados do Google Workspace

Para usar fontes de dados do Google Workspace, especifique o campo platformDataSource no widget SelectionInput. Ao contrário de outros tipos de entrada de seleção, você omite objetos SelectionItem porque esses itens são originados dinamicamente do Google Workspace.

O código a seguir mostra um menu de seleção múltipla de usuários do Google Workspace. Para preencher os usuários, a entrada de seleção define commonDataSource como USER:

JSON

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

O código a seguir mostra um menu de seleção múltipla de espaços do Chat. Para preencher espaços, a entrada de seleção especifica o campo hostAppDataSource. O menu de seleção múltipla também define defaultToCurrentSpace como true, o que faz com que o espaço atual seja a seleção padrão no menu:

JSON

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

Preencher itens de uma fonte de dados externa

Os menus de seleção múltipla também podem preencher itens de uma fonte de dados externa ou de terceiros. Para usar uma fonte de dados externa, especifique o campo externalDataSource no widget SelectionInput que contém a função que consulta e retorna itens da fonte de dados.

Para reduzir as solicitações a uma fonte de dados externa, inclua itens sugeridos que aparecem no menu de seleção múltipla antes que os usuários digitem no menu. Por exemplo, você pode preencher os contatos pesquisados recentemente para o usuário. Para preencher itens sugeridos de uma fonte de dados externa, especifique objetos estáticos SelectionItem.

O código a seguir mostra um menu de seleção múltipla que consulta e preenche itens de uma fonte de dados externa:

JSON

{
  "selectionInput": {
    "name": "contacts",
    "type": "MULTI_SELECT",
    "label": "Selected contacts",
    "multiSelectMaxSelectedItems": 3,
    "multiSelectMinQueryLength": 1,
    "externalDataSource": { "function": "FUNCTION" },
    // Suggested items loaded by default.
    // The list is static here but it could be dynamic.
    "items": [FUNCTION]
  }
}

Substitua FUNCTION pelo URL HTTP ou pelo nome da função do Apps Script que consulta o banco de dados externo. Para um exemplo completo que mostra como retornar itens sugeridos, consulte a seção Sugerir itens de seleção múltipla.

Receber dados de widgets interativos

Sempre que os usuários clicam em um botão, a ação dos apps do Chat é acionada com informações sobre a interação. No commonEventObject do payload do evento, o objeto formInputs contém todos os valores inseridos pelo usuário.

É possível recuperar os valores do objeto commonEventObject.formInputs.WIDGET_NAME, em que WIDGET_NAME é o campo name especificado para o widget. Os valores são retornados como um tipo de dados específico para o widget.

A seguir, mostramos uma parte de um objeto de evento em que um usuário inseriu valores para cada widget:

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

Para receber os dados, seu app do Chat processa o objeto de evento para receber os valores que os usuários inserem nos widgets. A tabela a seguir mostra como extrair o valor de um determinado widget de entrada de formulário. Para cada widget, a tabela mostra o tipo de dados que ele aceita, onde o valor é armazenado no objeto de evento e um exemplo de valor.

Widget de entrada de formulário Tipo de dados de entrada Valor de entrada do objeto de evento Valor de exemplo
textInput stringInputs event.commonEventObject.formInputs.contactName.stringInputs.value[0] Kai O
selectionInput stringInputs Para receber o primeiro ou único valor, event.commonEventObject.formInputs.contactType.stringInputs.value[0] Personal
dateTimePicker que aceita apenas datas. dateInput event.commonEventObject.formInputs.contactBirthdate.dateInput.msSinceEpoch. 1000425600000

Depois que o app Chat recebe dados, ele pode fazer o seguinte:

  • Para cards que contêm um menu de seleção múltipla, preencha ou sugira itens com base no que o usuário digita no menu.
  • Transfira os dados para outro card para que o usuário possa revisar as informações ou continuar para a próxima seção do formulário.
  • Responda ao usuário para confirmar que ele concluiu o formulário.

Sugerir itens de multisseleção

Se um card tiver um menu de seleção múltipla que preenche itens de uma fonte de dados externa, o app Chat poderá retornar itens sugeridos com base no que os usuários digitam no menu. Por exemplo, se um usuário começar a digitar Atl para um menu que preenche cidades nos Estados Unidos, seu app do Chat poderá sugerir automaticamente Atlanta antes que o usuário termine de digitar. O app Chat pode sugerir até 100 itens.

Para sugerir e preencher dinamicamente itens em um menu de seleção múltipla, o widget SelectionInput no card precisa especificar uma função que consulte a fonte de dados externa. Para retornar itens sugeridos, a função precisa fazer o seguinte:

  1. Processar um objeto de evento, que o app Chat recebe quando os usuários digitam no menu.
  2. No objeto de evento, extraia o valor digitado pelo usuário, que é representado no campo event.commonEventObject.parameters["autocomplete_widget_query"].
  3. Consulte a fonte de dados usando o valor de entrada do usuário para receber um ou mais SelectionItems para sugerir ao usuário.
  4. Retorne os itens sugeridos retornando a ação RenderActions com um objeto modifyCard.

O exemplo de código a seguir mostra como um app de chat sugere itens dinamicamente no menu de seleção múltipla de um card. Quando um usuário digita no menu, a função ou o endpoint fornecido no campo externalDataSource do widget consulta uma fonte de dados externa e sugere itens que o usuário pode selecionar.

Node.js

/**
 * Google Cloud Function 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
 */
exports.selectionInput = function selectionInput(req, res) {
  if (req.method === 'GET' || !req.body.chat) {
    return res.send('Hello! This function is meant to be used ' +
        'in a Google Chat Space.');
  }
  // Stores the Google Chat event
  const chatEvent = req.body.chat;

  // Handle user interaction with multiselect.
  if(chatEvent.widgetUpdatedPayload) {
    return res.send(queryContacts(req.body));
  }
  // Replies with a card that contains the multiselect menu.
  return res.send({ 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
  };
}

Substitua FUNCTION_URL pelo endpoint HTTP que consulta a fonte de dados externa.

Apps Script

/**
* 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
  };
}

Transferir dados para outro cartão

Depois que um usuário envia informações de um cartão, talvez seja necessário retornar outros cartões para fazer o seguinte:

  • Ajude os usuários a preencher formulários mais longos criando seções distintas.
  • Permita que os usuários visualizem e confirmem as informações do cartão inicial para que possam revisar as respostas antes de enviar.
  • Preencha dinamicamente as partes restantes do formulário. Por exemplo, para pedir que os usuários criem um horário, um app de chat pode mostrar um card inicial que solicita o motivo do horário e, em seguida, preencher outro card com os horários disponíveis com base no tipo de horário.

Para transferir a entrada de dados do card inicial, crie o widget button com actionParameters que contenha o name do widget e o valor inserido pelo usuário, conforme mostrado no exemplo a seguir:

Node.js

{
  "buttonList": { "buttons": [{
    "text": "Submit",
    "onClick": { "action": {
      "function": "FUNCTION_URL", // Must be an `https` endpoint.
      "parameters": [
        {
          "key": "WIDGET_NAME",
          "value": "USER_INPUT_VALUE"
        },
        // Can specify multiple parameters
      ]
    }}
  }]}
}

Apps Script

{
  "buttonList": { "buttons": [{
    "text": "Submit",
    "onClick": { "action": {
      "function": "submitForm",
      "parameters": [
        {
          "key": "WIDGET_NAME",
          "value": "USER_INPUT_VALUE"
        },
        // Can specify multiple parameters
      ]
    }}
  }]}
}

Em que WIDGET_NAME é o name do widget e USER_INPUT_VALUE é o que o usuário insere. Por exemplo, para uma entrada de texto que coleta o nome de uma pessoa, o nome do widget é contactName e um valor de exemplo é Kai O.

Quando um usuário clica no botão, o app Chat recebe um objeto de evento de que você pode receber dados.

Responder a um envio de formulário

Depois de receber os dados de uma mensagem ou caixa de diálogo do cartão, o app Chat responde confirmando o recebimento ou retornando um erro.

No exemplo a seguir, um app de chat envia uma mensagem de texto para confirmar que recebeu um formulário enviado de uma mensagem de card.

Node.js

/**
 * Google Cloud Function that handles all Google Workspace Add On events for
 * the contact manager app.
 *
 * @param {Object} req Request sent from Google Chat space
 * @param {Object} res Response to send back
 */
exports.contactManager = function contactManager(req, res) {
  const chatEvent = req.body.chat;
  const chatMessage = chatEvent.messagePayload.message;

  // Handle message payloads in the event object
  if(chatEvent.messagePayload) {
    return res.send(handleMessage(chatMessage, chatEvent.user));
  // Handle button clicks on the card
  } else if(chatEvent.buttonClickedPayload) {
    switch(req.body.commonEventObject.parameters.actionName) {
        case "openDialog":
            return res.send(openDialog());
        case "openNextCard":
            return res.send(openNextCard(req.body));
        case "submitForm":
            return res.send(submitForm(req.body));
    }
  }
};

/**
 * Submits information from a dialog or card message.
 *
 * @param {Object} event the interactive event with form inputs.
 * @return {Object} a message response that posts a private message.
 */
function submitForm(event) {
  const chatUser = event.chat.user;
  const contactName = event.commonEventObject.parameters["contactName"];

  return { hostAppDataAction: { chatDataAction: { createMessageAction: { message: {
    privateMessageViewer: chatUser,
    text: "✅ " + contactName + " has been added to your contacts."
  }}}}};
}

Apps Script

/**
 * Sends private text message that confirms submission.
 *
 * @param {Object} event the interactive event with form inputs.
 * @return {Object} a message response that posts a private message.
 */
function submitForm(event) {
  const chatUser = event.chat.user;
  const contactName = event.commonEventObject.parameters["contactName"];

  return { hostAppDataAction: { chatDataAction: { createMessageAction: { message: {
    privateMessageViewer: chatUser,
    text: "✅ " + contactName + " has been added to your contacts."
  }}}}};
}

Para processar e fechar uma caixa de diálogo, retorne um objeto RenderActions que especifica se você quer enviar uma mensagem de confirmação, atualizar a mensagem ou o card original ou apenas fechar a caixa de diálogo. Para ver as etapas, consulte Fechar uma caixa de diálogo.

Resolver problemas

Quando um app ou card do Google Chat retorna um erro, a interface do Chat mostra a mensagem "Ocorreu um erro". ou "Não foi possível processar sua solicitação". Às vezes, a interface do Chat não mostra nenhuma mensagem de erro, mas o app ou card do Chat produz um resultado inesperado. Por exemplo, uma mensagem do card pode não aparecer.

Embora uma mensagem de erro não apareça na interface do Chat, mensagens de erro descritivas e dados de registro estão disponíveis para ajudar você a corrigir erros quando o registro de erros para apps do Chat está ativado. Para ajuda com a visualização, depuração e correção de erros, consulte Resolver e corrigir erros do Google Chat.