Google Chat 사용자로부터 정보 수집 및 처리

이 가이드에서는 Google Chat 앱이 카드 기반 인터페이스에서 양식 입력을 빌드하여 사용자로부터 정보를 수집하고 처리하는 방법을 설명합니다.

다양한 위젯이 표시된 대화상자
그림 1: 연락처 정보를 수집하는 대화상자를 여는 채팅 앱

채팅 앱은 다음과 같은 방법으로 Chat 내부 또는 외부에서 작업을 실행하기 위해 사용자에게 정보를 요청합니다.

  • 설정을 구성합니다. 예를 들어 사용자가 알림 설정을 맞춤설정하거나 하나 이상의 스페이스에 Chat 앱을 구성하고 추가할 수 있습니다.
  • 다른 Google Workspace 애플리케이션에서 정보를 만들거나 업데이트합니다. 예를 들어 사용자가 Google Calendar 일정을 만들 수 있도록 합니다.
  • 사용자가 다른 앱 또는 웹 서비스의 리소스에 액세스하고 업데이트할 수 있도록 허용합니다. 예를 들어 Chat 앱을 사용하면 사용자가 Chat 스페이스에서 직접 지원 티켓의 상태를 업데이트할 수 있습니다.

기본 요건

HTTP

Google Chat을 확장하는 Google Workspace 부가기능 이를 빌드하려면 HTTP 빠른 시작을 완료하세요.

Apps Script

Google Chat을 확장하는 Google Workspace 부가기능 하나를 빌드하려면 Apps Script 빠른 시작을 완료하세요.

카드를 사용하여 양식 빌드

정보를 수집하기 위해 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"
    }
  }
}

다음 코드는 채팅 스페이스의 다중 선택 메뉴를 보여줍니다. 스페이스를 채우기 위해 선택 입력은 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. 사용자가 메뉴에 입력할 때 채팅 앱이 수신하는 이벤트 객체를 처리합니다.
  2. 이벤트 객체에서 사용자가 입력한 값을 가져옵니다. 이 값은 event.commonEventObject.parameters["autocomplete_widget_query"] 필드에 표시됩니다.
  3. 사용자 입력 값을 사용하여 데이터 소스를 쿼리하여 사용자에게 제안할 하나 이상의 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
  };
}

다른 카드로 데이터 전송

사용자가 카드 정보를 제출한 후 다음 작업을 실행하려면 추가 카드를 반환해야 할 수 있습니다.

  • 사용자가 명확한 섹션을 만들어 더 긴 양식을 작성할 수 있도록 지원합니다.
  • 사용자가 제출하기 전에 답변을 검토할 수 있도록 초기 카드에서 정보를 미리 보고 확인할 수 있도록 합니다.
  • 양식의 나머지 부분을 동적으로 채웁니다. 예를 들어 사용자가 약속을 만들도록 유도하기 위해 채팅 앱은 약속 이유를 묻는 초기 카드를 표시한 다음 약속 유형에 따라 사용 가능한 시간을 제공하는 다른 카드를 채울 수 있습니다.

초기 카드에서 입력된 데이터를 전송하려면 다음 예와 같이 위젯의 name와 사용자가 입력한 값을 포함하는 actionParametersbutton 위젯을 빌드하면 됩니다.

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 앱이나 카드에서 예기치 않은 결과가 발생하는 경우가 있습니다. 예를 들어 카드 메시지가 표시되지 않을 수 있습니다.

채팅 UI에 오류 메시지가 표시되지 않을 수도 있지만, 채팅 앱의 오류 로깅이 사용 설정된 경우 오류를 수정하는 데 도움이 되는 설명이 포함된 오류 메시지와 로그 데이터를 사용할 수 있습니다. 오류를 확인하고, 디버그하고, 수정하는 데 도움이 필요하면 Google Chat 오류 문제 해결 및 수정을 참고하세요.