Google Chat ユーザーから情報を収集して処理する

このガイドでは、Google Chat 用アプリがカードベースのインターフェースでフォーム入力を構築して、ユーザーから情報を収集して処理する方法について説明します。

さまざまなウィジェットが表示されたダイアログ。
図 1: 連絡先情報を収集するためのダイアログを開くチャットアプリ。

Chat 用アプリは、Chat 内外でアクションを実行するために、次のような方法でユーザーに情報をリクエストします。

  • 設定を行います。たとえば、ユーザーが通知設定をカスタマイズしたり、Chat 用アプリを 1 つ以上のスペースに構成して追加したりできるようにします。
  • 他の Google Workspace アプリケーションで情報を作成または更新します。たとえば、ユーザーが Google カレンダーの予定を作成できるようにします。
  • 他のアプリやウェブ サービスのリソースにアクセスして更新できるようにします。たとえば、Chat アプリを使用すると、Chat スペースから直接サポート チケットのステータスを更新できます。

前提条件

HTTP

Google Chat を拡張する Google Workspace アドオン。作成するには、HTTP クイックスタートを完了します。

Apps Script

Google Chat を拡張する Google Workspace アドオン。作成するには、Apps Script のクイックスタートを完了します。

カードを使用してフォームを作成する

情報を収集するために、Chat 用アプリはフォームとその入力を設計し、カードに組み込みます。ユーザーにカードを表示するために、Chat 用アプリは次の Chat インターフェースを使用できます。

  • 1 つ以上のカードを含む Chat メッセージ。
  • ダイアログ: メッセージやホームページから新しいウィンドウで開くカード。

Chat 用アプリは、次のウィジェットを使用してカードを構築できます。

  • ユーザーに情報をリクエストするフォーム入力ウィジェット。必要に応じて、フォーム入力ウィジェットに検証を追加して、ユーザーが情報を正しく入力してフォーマットできるようにすることができます。Chat 用アプリでは、次のフォーム入力ウィジェットを使用できます。

    • 自由形式または候補のテキスト用のテキスト入力textInput)。
    • 選択入力selectionInput)は、チェックボックス、ラジオボタン、プルダウン メニューなどの選択可能な UI 要素です。選択入力ウィジェットは、Google Workspace データ(Chat スペースなど)または動的データソースから項目を入力して候補を表示することもできます。詳しくは、次のセクション 複数選択メニューを追加するをご覧ください。

    • 日付と時刻のエントリ用の日時ピッカーdateTimePicker)。

  • ユーザーがカードに入力した値を送信できるようにする button ウィジェット。ユーザーがボタンをクリックすると、Chat 用アプリは受信した情報を処理できます。

次の例では、カードがテキスト入力、日時選択ツール、選択入力を使用して連絡先情報を収集しています。

情報を収集するために使用できるインタラクティブ ウィジェットの例については、Google Chat API ドキュメントのインタラクティブなカードやダイアログの設計をご覧ください。

複数選択メニューを追加する

選択項目をカスタマイズしたり、ユーザーが動的データソースから項目を選択できるようにするには、Chat 用アプリで複数選択メニューを使用できます。これは SelectionInput ウィジェットの一種です。たとえば、次のカードには、ユーザーが連絡先リストから動的に選択できる複数選択メニューが表示されます。

マルチセレクト メニューの項目は、次のデータソースから設定できます。

  • Google Workspace データ。ユーザーまたはユーザーがメンバーになっている Chat スペースが含まれます。メニューには、同じ Google Workspace 組織のアイテムのみが表示されます。
  • リレーショナル データベースなどの外部データソース。たとえば、顧客管理(CRM)システムの販売見込み顧客のリストからユーザーが選択できるように、複数選択メニューを使用できます。

Google Workspace データソースからアイテムを入力する

Google Workspace データソースを使用するには、SelectionInput ウィジェットで platformDataSource フィールドを指定します。他の選択入力タイプとは異なり、これらの選択項目は Google Workspace から動的に取得されるため、SelectionItem オブジェクトは省略します。

次のコードは、Google Workspace ユーザーの複数選択メニューを示しています。ユーザーを入力するには、選択入力で commonDataSourceUSER に設定します。

JSON

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

次のコードは、Chat スペースの複数選択メニューを示しています。スペースを入力するには、選択入力で hostAppDataSource フィールドを指定します。マルチ選択メニューでは、defaultToCurrentSpacetrue に設定されます。これにより、現在のスペースがメニューのデフォルトの選択になります。

JSON

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

外部データソースからアイテムを入力する

マルチセレクト メニューには、サードパーティまたは外部のデータソースから項目を入力することもできます。外部データソースを使用するには、データソースからアイテムをクエリして返す関数を含む SelectionInput ウィジェットで externalDataSource フィールドを指定します。

外部データソースへのリクエストを減らすには、ユーザーがメニューに入力する前に、マルチセレクト メニューに表示される候補アイテムを含めることができます。たとえば、ユーザーが最近検索した連絡先を自動入力できます。外部データソースから候補アイテムを入力するには、静的 SelectionItem オブジェクトを指定します。

次のコードは、外部データソースからアイテムをクエリして入力する複数選択メニューを示しています。

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

FUNCTION は、外部データベースをクエリする HTTP URL または Apps Script 関数名に置き換えます。候補アイテムを返す方法を示す完全な例については、複数選択アイテムを提案するのセクションをご覧ください。

インタラクティブ ウィジェットからデータを受け取る

ユーザーがボタンをクリックするたびに、その Chat 用アプリのアクションがトリガーされ、操作に関する情報が渡されます。イベント ペイロードの commonEventObject で、formInputs オブジェクトにはユーザーが入力した値が含まれます。

オブジェクト 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 ウィジェットで、外部データソースをクエリする関数を指定する必要があります。候補アイテムを返すには、関数で次の処理を行う必要があります。

  1. ユーザーがメニューに入力したときに Chat 用アプリが受け取るイベント オブジェクトを処理します。
  2. イベント オブジェクトから、ユーザーが入力した値を取得します。この値は event.commonEventObject.parameters["autocomplete_widget_query"] フィールドで表されます。
  3. ユーザー入力値を使用してデータソースにクエリを実行し、ユーザーに提案する 1 つ以上の SelectionItems を取得します。
  4. modifyCard オブジェクトを含むアクション RenderActions を返すことで、提案アイテムを返します。

次のコードサンプルは、Chat 用アプリがカードのマルチセレクト メニューで項目を動的に提案する方法を示しています。ユーザーがメニューに入力すると、ウィジェットの externalDataSource フィールドで指定された関数またはエンドポイントが外部データソースにクエリを実行し、ユーザーが選択できる項目を提案します。

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

FUNCTION_URL は、外部データソースをクエリする HTTP エンドポイントに置き換えます。

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

別のカードにデータを転送する

ユーザーがカードから情報を送信した後、次のいずれかを行うために追加のカードを返す必要がある場合があります。

  • 長いフォームを複数のセクションに分割して、ユーザーが入力しやすくします。
  • ユーザーが最初のカードの情報をプレビューして確認できるようにします。これにより、ユーザーは回答を送信する前に確認できます。
  • フォームの残りの部分を動的に入力します。たとえば、ユーザーに予定の作成を促すために、Chat 用アプリは、予定の理由を尋ねる最初のカードを表示し、予定の種類に基づいて利用可能な時間を表示する別のカードに入力します。

最初のカードから入力されたデータを転送するには、次の例に示すように、ウィジェットの name とユーザーが入力した値を含む actionParameters を使用して button ウィジェットをビルドします。

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

ここで、WIDGET_NAME はウィジェットの name で、USER_INPUT_VALUE はユーザーが入力したものです。たとえば、個人の名前を収集するテキスト入力の場合、ウィジェット名は contactName で、値の例は Kai O です。

ユーザーがボタンをクリックすると、Chat 用アプリはイベント オブジェクトを受け取ります。このオブジェクトからデータを受け取ることができます。

フォームの送信に対応する

カード メッセージまたはダイアログからデータを受信すると、Chat 用アプリは受信を確認するか、エラーを返して応答します。

次の例では、Chat 用アプリがテキスト メッセージを送信して、カード メッセージから送信されたフォームを正常に受信したことを確認しています。

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."
  }}}}};
}

ダイアログを処理して閉じるには、確認メッセージを送信するか、元のメッセージまたはカードを更新するか、ダイアログを閉じるだけかを指定する RenderActions オブジェクトを返します。手順については、ダイアログを閉じるをご覧ください。

トラブルシューティング

Google Chat 用アプリまたはカードがエラーを返すと、Chat インターフェースに「エラーが発生しました」というメッセージが表示されます。または「リクエストを処理できません。」と表示されることがあります。Chat UI にエラー メッセージが表示されない場合でも、Chat 用アプリやカードで予期しない結果が生じることがあります。たとえば、カード メッセージが表示されないことがあります。

Chat UI にエラー メッセージが表示されない場合でも、Chat 用アプリのエラー ロギングが有効になっている場合は、エラーの修正に役立つ説明的なエラー メッセージとログデータを利用できます。エラーの表示、デバッグ、修正については、Google Chat のエラーのトラブルシューティングと修正をご覧ください。