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

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

Google Chat では、アドオンは Google Chat アプリとしてユーザーに表示されます。詳細については、Google Chat の拡張機能の概要をご覧ください。

さまざまなウィジェットを備えたダイアログ。
図 1: ダイアログを開いて連絡先情報を収集するチャットアプリ。

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

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

前提条件

Node.js

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)。

  • ボタン ウィジェット。ユーザーがカードに入力した値を送信できるようにします。ユーザーがボタンをクリックすると、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 を自動的に候補として表示できます。チャットアプリでは、最大 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 interactive event.
* @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 ウィジェットを作成します。

{
  "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 アプリまたはカードで予期しない結果が生成されることがあります(カード メッセージが表示されないなど)。

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