이 페이지에서는 Google Chat 앱
슬래시 명령어는 사용자가 채팅 앱 또한 슬래시 명령어를 사용하면 채팅 앱의 주요 기능 사용
슬래시 명령어를 사용하려면 슬래시 (/
)를 입력한 후 짧은 텍스트 명령어를 입력합니다.
채팅 앱에 관한 정보를 얻는 방법(예: /about
)
사용자는 슬래시를 입력하여 사용 가능한 슬래시 명령어를 찾을 수 있습니다.
Google Chat - 사용 가능한 명령어를 나열하는 창이 표시됨
채팅 앱:
![슬래시 명령어 창](https://developers-dot-devsite-v2-prod.appspot.com/static/workspace/chat/images/slash-command-window.png?authuser=6&hl=ko)
사용자가 슬래시 명령어가 포함된 메일을 보내면 사용자 및 채팅 앱에 표시됩니다.
슬래시 명령어의 설정 여부를 결정하고 사용자 상호작용을 설계하고 모든 사용자 여정을 정의합니다.
기본 요건
Node.js
양방향 기능이 사용 설정된 Google Chat 앱 대화형 채팅 앱을 사용하려면 이 빠른 시작을 완료하세요.
Apps Script
양방향 기능이 사용 설정된 Google Chat 앱 Apps Script에서 대화형 채팅 앱을 사용하려면 이 빠른 시작을 완료하세요.
Python
양방향 기능이 사용 설정된 Google Chat 앱 대화형 채팅 앱을 사용하려면 이 빠른 시작을 완료하세요.
슬래시 명령어 설정
이 섹션에서는 슬래시 설정을 위한 다음 단계를 완료하는 방법을 설명합니다. 명령어:
- 슬래시 명령어의 이름을 만듭니다.
- Google Chat API에서 슬래시 명령어를 구성합니다.
슬래시 명령어 이름 지정
슬래시 명령어의 이름은 사용자가 Chat 메시지에 입력하는 이름입니다 채팅 앱을 호출합니다. 간단한 설명도 이 이름 아래에 표시되어 사용자에게 명령어 사용 방법에 관한 추가 메시지를 표시합니다.
![슬래시 명령어 이름 및 설명](https://developers-dot-devsite-v2-prod.appspot.com/static/workspace/chat/images/slash-command-description.png?authuser=6&hl=ko)
슬래시 명령어의 이름과 설명을 선택할 때는 다음 권장 사항을 참고하세요.
슬래시 명령어의 이름을 지정하려면 다음 안내를 따르세요.
- 짧고, 설명적이고, 실행 가능한 단어나 문구를 사용하여
사용자에게 명확하고 간단한 명령을 내릴 수 있습니다. 예를 들어,
/createAReminder
,/remindMe
사용 - 명령어에 단어가 2개 이상 포함된 경우 사용자가 명령어를 읽을 수 있도록 돕습니다.
첫 번째 단어는 모두 소문자를 사용하고 첫 번째 단어는 대문자로 표기해야 합니다.
추가 단어의 문자입니다. 예를 들어
/updatecontact
대신/updateContact
사용 - 명령어에 고유한 이름을 사용할지, 일반 이름을 사용할지 고려합니다. 만약
명령이 일반적인 상호작용이나 기능을 설명하는 경우
사용자가 알아보고 예상하는 일반적인 이름(예:
/settings
또는/feedback
입니다. 그렇지 않으면 고유한 명령 이름을 사용하는 것이 좋습니다. 명령어 이름이 다른 채팅 앱과 동일하다면 사용자는 비슷한 명령어를 필터링하여 사용하는 명령어를 찾고 사용하세요.
- 짧고, 설명적이고, 실행 가능한 단어나 문구를 사용하여
사용자에게 명확하고 간단한 명령을 내릴 수 있습니다. 예를 들어,
슬래시 명령어를 설명하는 방법은 다음과 같습니다.
- 사용자가 내용을 이해할 수 있도록 설명을 짧고 명확하게 작성합니다. 메시지가 표시될 수 있습니다
- 명령어에 형식 요구사항이 있는지 사용자에게 알립니다.
예를 들어 인수가 필요한
/remindMe
명령어를 만드는 경우 설명을Remind me to do [something] at [time]
와 같이 설정하세요. - 채팅 앱이 답장하면 사용자에게 알립니다.
스페이스에 있는 모든 사용자 또는 명령어를 호출하는 사용자에게 비공개로
표시합니다
예를 들어 슬래시 명령어
/about
의 경우 다음과 같이 설명할 수 있습니다.Learn about this app (Only visible to you)
입니다. 비공개 메시지로 응답 섹션을 참고하세요.
Google Chat API에서 슬래시 명령어 구성
슬래시 명령어를 만들려면 명령어에 대한 정보를 Google Chat API에 대한 채팅 앱 구성
Google Chat API에서 슬래시 명령어를 구성하려면 다음을 완료합니다. 단계:
Google Cloud 콘솔에서 메뉴를 클릭합니다. > API 및 서비스 > 사용 설정된 API 및 서비스 > Google Chat API
구성을 클릭합니다.
슬래시 명령어에서 슬래시 명령어 추가를 클릭합니다.
명령어의 이름, 명령어 ID, 설명을 입력합니다.
- 이름: 명령어의 표시 이름 및 사용자가 입력하는 내용 앱을 호출할 수 있습니다. 슬래시로 시작하고 텍스트만 포함해야 하며 최대 50자(영문 기준)여야 합니다
- 설명: 사용 및 형식 지정 방법을 설명하는 텍스트입니다. 실행할 수 있습니다 설명은 최대 50자(영문 기준)까지 입력할 수 있습니다.
- 명령어 ID: 명령어를 실행할 1~1,000 사이의 숫자 채팅 앱이 슬래시 명령어를 인식하는 데 사용합니다. 응답을 반환합니다
선택사항: 채팅 앱에서 대화상자가 있는 명령어를 실행하려면 대화상자 열기 체크박스
저장을 클릭합니다.
이제 채팅 앱에 슬래시 명령어가 구성되었습니다.
슬래시 명령어에 응답
사용자가 슬래시 명령어가 포함된 Chat 메시지를 작성하는 경우
채팅 앱이 MESSAGE
상호작용 이벤트를 수신합니다.
이벤트 페이로드에는 슬래시 명령어,
slashCommand
포함
및 slashCommandMetadata
있습니다. 이러한 필드를 사용하여 명령어 ID를 식별하고 커스텀
있습니다.
다음 예시는 MESSAGE
상호작용 이벤트의 JSON 페이로드를 보여줍니다.
슬래시 명령어 /vote
가 포함된 다음 명령어를 실행합니다.
{
...
"message": {
...
"text": "/vote yes",
"argumentText": " yes",
"slashCommand": {
"commandId": 2
},
"annotations": [
{
"length": 5,
"startIndex": 0,
"type": "SLASH_COMMAND",
"slashCommand": {
"commandName":"/vote",
"commandId":1,
"type": "INVOKE",
"bot": {
"avatarUrl": "https://www.example.com/images/vote-app-icon.png",
"displayName": "Voter Chat App",
"name": "users/1234567890987654321",
"type": "BOT"
}
}
}
]
}
}
슬래시 명령어에 응답하려면 slashCommand
필드가
있는 경우, 명령에 대한 응답을 반환합니다.
다음 코드 샘플은 MESSAGE
상호작용 이벤트에 응답하는 방법을 보여줍니다.
슬래시 명령:
Node.js
/**
* Responds to a MESSAGE event in Google Chat.
*
* @param {Object} event the event object from Chat API.
*
* @return {object} function in response to a slash command.
*/
exports.onMessage = function onMessage(req, res) {
// Stores the Google Chat event as a variable.
var event = req.body;
// Checks for the presence of event.message.slashCommand.
if (event.message.slashCommand) {
switch (event.message.slashCommand.commandId) {
case ID: // The ID for your slash command
res.json(runFunction); // The response to the slash command.
}
}
Apps Script
/**
* Responds to a MESSAGE event in Google Chat.
*
* @param {Object} event the event object from Chat API.
*
* @return {object} function in response to a slash command.
*/
function onMessage(event) {
// Checks for the presence of event.message.slashCommand
if (event.message.slashCommand) {
switch (event.message.slashCommand.commandId) {
case ID: // The ID for your slash command
return runFunction; // The response to the slash command.
}
}
}
Python
from typing import Any, Mapping
import flask
import functions_framework
@functions_framework.http
def main(req: flask.Request) -> Mapping[str, Any]:
"""Responds to a MESSAGE event in Google Chat that includes a slash command.
Args:
req (flask.Request): the event object from Chat API.
Returns:
Mapping[str, Any]: function in response to a slash command.
"""
if req.method == 'GET':
return 'Sorry, this function must be called from a Google Chat.'
request = req.get_json(silent=True)
if slash_command := request.get('message', dict()).get('slashCommand'):
command_id = slash_command['commandId']
if command_id == ID:
return runFunction
코드를 사용하려면 다음을 바꿉니다.
ID
: 작업을 실행할 때 지정하는 명령어 ID입니다. Google Chat API에서 슬래시 명령어를 구성합니다.runFunction
: 다음에 대한 응답을 만드는 함수입니다. 사용할 수 있습니다
선택사항: 비공개 메시지로 응답
슬래시 명령어가 포함된 메일은 메시지 및 명령어를 수신하는 채팅 앱이 생성됩니다. 만약 채팅 앱이 스페이스에 추가되도록 구성함 슬래시 명령에 응답하려면 비공개로 설정하여 사용자와 채팅 앱
예를 들어 팀에서 대화를 관리하는 채팅 앱을
고객 지원 서비스의 경우 사용자는 슬래시 명령을 호출할 수 있습니다.
/myCases
하여 할당된 지원 케이스를 볼 수 있습니다. 팀이
이 슬래시 명령어를 사용하는 사용자인 스페이스에 대한 채팅 앱
채팅 앱이 특정 사용자에게만 응답하도록 할 수 있습니다
있습니다. 사용자의 지원 케이스가 스페이스의 모든 사용자에게 게시되지 않도록 하려면
채팅 앱이 비공개로 응답할 수 있습니다.
슬래시 명령어에 비공개로 응답하려면 다음을 참조하세요. Google Chat 사용자에게 비공개 메시지 보내기
전체 예: Rolodex Chat 앱을 사용하여 연락처 설정하기
다음 예는 다음과 같이 응답하는 채팅 앱을 보여줍니다. 다음 슬래시 명령어를 사용합니다.
/help
명령어는 채팅 앱 지원에 대해 이야기해 보겠습니다 명령어 ID는1
에게 전송합니다./createContact
명령어는 사용자가 명령어를 입력할 수 있는 대화상자를 엽니다. 세부정보를 확인할 수 있습니다. 명령어 ID는2
로 설정됩니다.
이 샘플을 실행하기 전에 다음 단계를 따르세요. Google Chat API에서 슬래시 명령어를 구성합니다.
Node.js
/**
* Responds to messages that have links whose URLs
* match URL patterns configured for link previews.
*
* @param {Object} event The event object from Chat
* API.
*
* @return {Object} Response from the Chat app
* attached to the message with the previewed link.
*/
exports.onMessage = function onMessage(req, res) {
// Store the Google Chat event as a variable.
const event = req.body;
if (req.method === "GET" || !event.message) {
res.send("Hello! This function is meant to be used in a Google Chat " +
"Space.");
}
// Checks for the presence of event.message.slashCommand.
// If the slash command is "/help", responds with a text message.
// If the slash command is "/createContact", opens a dialog.
if (event.message.slashCommand) {
switch (event.message.slashCommand.commandId) {
case 1: // /help
res.json({"text": "Contact bot helps you update your address book!"});
case 2: // /createContact
res.json(openDialog(event));
}
}
// If the Chat app doesn"t detect a slash command, it responds
// with a card that prompts the user to add a contact
else {
res.json({
"cardsV2": [{
"cardId": "addContact",
"card": {
"header": {
"title": "Rolodex",
"subtitle": "Manage your contacts!",
"imageUrl": "https://www.gstatic.com/images/branding/product/2x/contacts_48dp.png",
"imageType": "CIRCLE"
},
"sections": [
{
"widgets": [
{
"buttonList": {
"buttons": [
{
"text": "Add Contact",
"onClick": {
"action": {
"function": "openDialog",
"interaction": "OPEN_DIALOG"
}
}
}
]
}
}
]
}
]
}
}]
});
}
// Respond to button clicks on attached cards
if (event.type === "CARD_CLICKED") {
if (event.common.invokedFunction === "openDialog") {
res.json(openDialog(event));
}
if (event.common.invokedFunction === "openSequentialDialog") {
res.json(openSequentialDialog(event));
}
if (event.common.invokedFunction === "confirmDialogSuccess") {
res.json(confirmDialogSuccess(event));
}
}
};
/**
* Opens and starts a dialog that lets users add details about a contact.
*
* @param {object} event the event object from Google Chat.
*
* @return {object} open a dialog.
*/
function openDialog(event) {
return {
"action_response": {
"type": "DIALOG",
"dialog_action": {
"dialog": {
"body": {
"sections": [
{
"header": "Add new contact",
"widgets": [
{
"textInput": {
"label": "Name",
"type": "SINGLE_LINE",
"name": "name"
}
},
{
"textInput": {
"label": "Address",
"type": "MULTIPLE_LINE",
"name": "address"
}
},
{
"decoratedText": {
"text": "Add to favorites",
"switchControl": {
"controlType": "SWITCH",
"name": "saveFavorite"
}
}
},
{
"decoratedText": {
"text": "Merge with existing contacts",
"switchControl": {
"controlType": "SWITCH",
"name": "mergeContact",
"selected": true
}
}
},
{
"buttonList": {
"buttons": [
{
"text": "Next",
"onClick": {
"action": {
"function": "openSequentialDialog"
}
}
}
]
}
}
]
}
]
}
}
}
}
};
};
/**
* Opens a second dialog that lets users add more contact details.
*
* @param {object} event the event object from Google Chat.
*
* @return {object} open a dialog.
*/
function openSequentialDialog(event) {
return {
"action_response": {
"type": "DIALOG",
"dialog_action": {
"dialog": {
"body": {
"sections": [
{
"header": "Add new contact",
"widgets": [
{
"textInput": {
"label": "Notes",
"type": "MULTIPLE_LINE",
"name": "notes"
}
},
{
"selectionInput": {
"type": "RADIO_BUTTON",
"label": "Contact type",
"name": "contactType",
"items": [
{
"text": "Work",
"value": "Work",
"selected": false
},
{
"text": "Personal",
"value": "Personal",
"selected": false
}
]
}
},
{
"buttonList": {
"buttons": [
{
"text": "Submit",
"onClick": {
"action": {
"function": "confirmDialogSuccess",
"parameters": [
{
"key": "confirmDialogSuccess",
"value": "confirmDialogSuccess"
}
]
}
}
}
]
},
"horizontalAlignment": "END"
}
]
}
]
}
}
}
}
};
}
/**
* Checks for a form input error, the absence of
* a "name" value, and returns an error if absent.
* Otherwise, confirms successful receipt of a dialog.
*
* Confirms successful receipt of a dialog.
*
* @param {Object} event the event object from Chat API.
*
* @return {object} open a Dialog in Google Chat.
*/
function receiveDialog(event) {
// Checks to make sure the user entered a name
// in a dialog. If no name value detected, returns
// an error message.
if (event.common.formInputs.contactName.stringInputs.value[0] === "") {
return {
"actionResponse": {
"type": "DIALOG",
"dialogAction": {
"actionStatus": {
"statusCode": "OK",
"userFacingMessage": "Don't forget to name your new contact!"
}
}
}
};
// Otherwise the app indicates that it received
// form data from the dialog. Any value other than "OK"
// gets returned as an error. "OK" is interpreted as
// code 200, and the dialog closes.
} else {
return {
"actionResponse": {
"type": "DIALOG",
"dialogAction": {
"actionStatus": "OK"
}
}
};
}
}
Apps Script
이 예시에서는 카드 JSON과 함께 사용합니다. 또한 Apps Script 카드 서비스.
Python
from typing import Any, Mapping
import flask
import functions_framework
@functions_framework.http
def main(req: flask.Request) -> Mapping[str, Any]:
"""Responds to a MESSAGE event in Google Chat that includes the /createContact
slash command by opening a dialog.
Args:
req (flask.Request): the event object from Chat API.
Returns:
Mapping[str, Any]: open a Dialog in response to a card's button click.
"""
if req.method == 'GET':
return 'Sorry, this function must be called from a Google Chat.'
request = req.get_json(silent=True)
if request.get('type') == 'CARD_CLICKED':
invoked_function = request.get('common', dict()).get('invokedFunction')
if invoked_function == 'open_dialog':
return open_dialog(request)
elif invoked_function == 'open_sequential_dialog':
return open_dialog(request)
elif invoked_function == "receive_dialog":
return receive_dialog(request)
else:
return {
'cardsV2': [{
'cardId': 'addContact',
'card': {
'header': {
'title': 'Rolodex',
'subtitle': 'Manage your contacts!',
'imageUrl': 'https://www.gstatic.com/images/branding/product/2x/contacts_48dp.png',
'imageType': 'CIRCLE'
},
'sections': [
{
'widgets': [
{
'buttonList': {
'buttons': [
{
'text': 'Add Contact',
'onClick': {
'action': {
'function': 'open_dialog',
'interaction': 'OPEN_DIALOG'
}
}
}
]
}
}
]
}
]
}
}]
}
def open_dialog(request: Mapping[str, Any]) -> Mapping[str, Any]:
"""Opens a dialog in Google Chat.
Args:
request (Mapping[str, Any]): the event object from Chat API.
Returns:
Mapping[str, Any]: open a Dialog in response to a card's button click.
"""
return {
'action_response': {
'type': 'DIALOG',
'dialog_action': {
'dialog': {
'body': {
'sections': [
{
'header': 'Add new contact',
'widgets': [
{
'textInput': {
'label': 'Name',
'type': 'SINGLE_LINE',
'name': 'name'
}
},
{
'textInput': {
'label': 'Address',
'type': 'MULTIPLE_LINE',
'name': 'address'
}
},
{
'decoratedText': {
'text': 'Add to favorites',
'switchControl': {
'controlType': 'SWITCH',
'name': 'saveFavorite'
}
}
},
{
'decoratedText': {
'text': 'Merge with existing contacts',
'switchControl': {
'controlType': 'SWITCH',
'name': 'mergeContact',
'selected': True
}
}
},
{
'buttonList': {
'buttons': [
{
'text': 'Next',
'onClick': {
'action': {
'function': 'open_sequential_dialog'
}
}
}
]
}
}
]
}
]
}
}
}
}
}
def open_sequential_dialog(request: Mapping[str, Any]) -> Mapping[str, Any]:
"""Opens a second dialog that lets users add more contact details.
Args:
request (Mapping[str, Any]): the event object from Chat API.
Returns:
Mapping[str, Any]: open a Dialog in response to a card's button click.
"""
return {
'action_response': {
'type': 'DIALOG',
'dialog_action': {
'dialog': {
'body': {
'sections': [
{
'header': 'Add new contact',
'widgets': [
{
'textInput': {
'label': 'Notes',
'type': 'MULTIPLE_LINE',
'name': 'notes'
}
},
{
'selectionInput': {
'type': 'RADIO_BUTTON',
'label': 'Contact type',
'name': 'contactType',
'items': [
{
'text': 'Work',
'value': 'Work',
'selected': False
},
{
'text': 'Personal',
'value': 'Personal',
'selected': False
}
]
}
},
{
'buttonList': {
'buttons': [
{
'text': 'Submit',
'onClick': {
'action': {
'function': 'receive_dialog',
'parameters': [
{
'key': 'receiveDialog',
'value': 'receiveDialog'
}
]
}
}
}
]
},
'horizontalAlignment': 'END'
}
]
}
]
}
}
}
}
}
def receive_dialog(event: Mapping[str, Any]) -> Mapping[str, Any]:
"""Checks for a form input error, the absence of a "name" value, and returns
an error if absent. Otherwise, confirms successful receipt of a dialog.
Args:
event (Mapping[str, Any]): the event object from Chat API.
Returns:
Mapping[str, Any]: the response.
"""
if event.get('common', dict()) \
.get('formInputs', dict()).get('contactName', dict()) \
.get('stringInputs').get('value', list()):
return {
'actionResponse': {
'type': 'DIALOG',
'dialogAction': {
'actionStatus': 'OK'
}
}
}
else:
return {
'actionResponse': {
'type': 'DIALOG',
'dialogAction': {
'actionStatus': "Don't forget to name your new contact!"
}
}
}