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

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

다양한 위젯이 있는 대화상자
그림 1: 연락처 정보를 수집하기 위해 대화상자를 여는 샘플 Chat 앱

Chat 앱은 다음과 같은 방법을 포함하여 Chat 안팎에서 작업을 실행하기 위해 사용자에게 정보를 요청합니다.

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

기본 요건

Node.js

대화형 기능이 사용 설정된 Google Chat 앱 HTTP 서비스를 사용하여 대화형 Chat 앱을 만들려면 이 빠른 시작을 완료하세요.

Python

대화형 기능이 사용 설정된 Google Chat 앱 HTTP 서비스를 사용하여 대화형 Chat 앱을 만들려면 이 빠른 시작을 완료하세요.

자바

대화형 기능이 사용 설정된 Google Chat 앱 HTTP 서비스를 사용하여 대화형 Chat 앱을 만들려면 이 빠른 시작을 완료하세요.

Apps Script

대화형 기능이 사용 설정된 Google Chat 앱 Apps Script에서 양방향 Chat 앱을 만들려면 이 빠른 시작을 완료하세요.

카드를 사용하여 양식 만들기

정보를 수집하기 위해 Chat 앱은 양식과 입력란을 설계하고 카드에 빌드합니다. 사용자에게 카드를 표시하기 위해 Chat 앱은 다음 Chat 인터페이스를 사용할 수 있습니다.

  • 카드를 하나 이상 포함하는 메시지
  • 홈페이지: Chat 앱의 채팅 메시지에서 탭에 표시되는 카드입니다.
  • 대화상자: 메시지 및 홈페이지에서 새 창으로 열리는 카드입니다.

Chat 앱은 다음 위젯을 사용하여 카드를 빌드할 수 있습니다.

  • 사용자에게 정보를 요청하는 양식 입력 위젯 원하는 경우 양식 입력 위젯에 유효성 검사를 추가하여 사용자가 정보를 올바르게 입력하고 형식을 지정하도록 할 수 있습니다. 채팅 앱은 다음과 같은 양식 입력 위젯을 사용할 수 있습니다.

    • 자유 형식 또는 추천 텍스트용 텍스트 입력(textInput)
    • 선택 입력(selectionInput)은 체크박스, 라디오 버튼, 드롭다운 메뉴와 같이 선택 가능한 UI 요소입니다. 선택 입력 위젯은 정적 또는 동적 데이터 소스의 항목을 채울 수도 있습니다. 예를 들어 사용자는 자신이 참여 중인 Chat 스페이스 목록에서 선택할 수 있습니다.
    • 날짜 및 시간 항목의 날짜 시간 선택기(dateTimePicker)
  • 사용자가 카드에 입력한 값을 제출할 수 있는 버튼 위젯입니다. 사용자가 버튼을 클릭하면 Chat 앱에서 수신한 정보를 처리할 수 있습니다.

다음 예에서 카드는 텍스트 입력란, 날짜 시간 선택 도구, 선택 입력란을 사용하여 연락처 정보를 수집합니다.

이 연락처 양식을 사용하는 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/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 앱은 상호작용에 관한 정보가 포함된 CARD_CLICKED 상호작용 이벤트를 수신합니다. CARD_CLICKED 상호작용 이벤트의 페이로드에는 사용자가 입력한 값이 포함된 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 앱은 상호작용 이벤트를 처리하여 사용자가 위젯에 입력한 값을 가져옵니다. 다음 표는 지정된 양식 입력 위젯의 값을 가져오는 방법을 보여줍니다. 각 위젯의 경우 위젯이 허용하는 데이터 유형, 값이 상호작용 이벤트에 저장되는 위치, 예시 값이 표에 표시됩니다.

양식 입력 위젯 입력 데이터 유형 상호작용 이벤트의 입력 값 예시 값
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 앱은 약속 이유를 요청하는 첫 번째 카드를 표시한 다음 약속 유형에 따라 사용 가능한 시간을 제공하는 다른 카드를 채울 수 있습니다.

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

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/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 앱은 수신 확인 또는 오류 반환으로 응답합니다.

다음 예에서는 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.
if (!contactName) {
  const errorMessage = "Don't forget to name your new contact!";
  if (event.dialogEventType === "SUBMIT_DIALOG") {
    return { actionResponse: {
      type: "DIALOG",
      dialogAction: { actionStatus: {
        statusCode: "INVALID_ARGUMENT",
        userFacingMessage: errorMessage
      }}
    }};
  } else {
    return {
      privateMessageViewer: event.user,
      text: 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.
if contact_name == "":
  error_message = "Don't forget to name your new contact!"
  if "SUBMIT_DIALOG" == event.get('dialogEventType'):
    return { 'actionResponse': {
      'type': "DIALOG",
      'dialogAction': { 'actionStatus': {
        'statusCode': "INVALID_ARGUMENT",
        'userFacingMessage': error_message
      }}
    }}
  else:
    return {
      'privateMessageViewer': event.get('user'),
      'text': error_message
    }

자바

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.
if (contactName.isEmpty()) {
  String errorMessage = "Don't forget to name your new contact!";
  if (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))));
  } else {
    return new Message()
      .setPrivateMessageViewer(new User().setName(event.at("/user/name").asText()))
      .setText(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.
if (!contactName) {
  const errorMessage = "Don't forget to name your new contact!";
  if (event.dialogEventType === "SUBMIT_DIALOG") {
    return { actionResponse: {
      type: "DIALOG",
      dialogAction: { actionStatus: {
        statusCode: "INVALID_ARGUMENT",
        userFacingMessage: errorMessage
      }}
    }};
  } else {
    return {
      privateMessageViewer: event.user,
      text: errorMessage
    };
  }
}

대화상자를 처리하고 닫으려면 확인 메시지를 보내거나, 원본 메시지 또는 카드를 업데이트하거나, 대화상자를 닫을지 여부를 지정하는 ActionResponse 객체를 반환합니다. 단계는 대화상자 닫기를 참고하세요.

문제 해결

Google Chat 앱 또는 카드가 오류를 반환하면 Chat 인터페이스에 '문제가 발생했습니다'라는 메시지가 표시됩니다. 또는 '요청을 처리할 수 없습니다.' Chat UI에 오류 메시지가 표시되지 않지만 Chat 앱 또는 카드에서 예기치 않은 결과가 발생하는 경우가 있습니다. 예를 들어 카드 메시지가 표시되지 않을 수 있습니다.

Chat UI에 오류 메시지가 표시되지 않을 수 있지만 Chat 앱의 오류 로깅이 사용 설정된 경우 오류를 수정하는 데 도움이 되는 설명 오류 메시지와 로그 데이터를 사용할 수 있습니다. 오류를 보고, 디버그하고, 수정하는 방법에 관한 도움말은 Google Chat 오류 문제 해결하기를 참고하세요.