Halaman ini menjelaskan cara menyiapkan perintah garis miring untuk aplikasi Google Chat.
Perintah garis miring adalah cara umum untuk memanggil dan berinteraksi dengan aplikasi Chat. Perintah garis miring juga membantu pengguna menemukan dan menggunakan fitur utama aplikasi Chat.
Untuk menggunakan perintah garis miring, pengguna harus mengetik garis miring (/
), lalu perintah teks singkat,
seperti /about
untuk mendapatkan informasi tentang aplikasi Chat.
Pengguna dapat menemukan perintah garis miring yang tersedia dengan mengetik garis miring ke
Google Chat, yang menampilkan jendela yang mencantumkan perintah yang tersedia untuk
aplikasi Chat:

Untuk menentukan apakah Anda harus menyiapkan perintah garis miring, dan memahami cara mendesain interaksi pengguna, lihat Prinsip desain Google Chat.
Prasyarat
Node.js
- Akun Google Workspace dengan akses ke Google Chat.
- Aplikasi Chat. Untuk membuat aplikasi Chat, ikuti panduan memulai ini.
Apps Script
- Akun Google Workspace dengan akses ke Google Chat.
- Aplikasi Chat. Untuk membuat aplikasi Chat, ikuti panduan memulai ini.
Python
- Akun Google Workspace dengan akses ke Google Chat.
- Aplikasi Chat. Untuk membuat aplikasi Chat, ikuti panduan memulai ini.
Menyiapkan perintah garis miring
Untuk menyiapkan perintah garis miring, selesaikan langkah-langkah berikut:
- Buat nama untuk perintah garis miring.
- Konfigurasi perintah garis miring di Google Chat API.
- Buat respons untuk perintah garis miring, seperti pesan teks atau kartu.
Bagian ini menjelaskan langkah-langkah untuk menyiapkan perintah garis miring.
Beri nama perintah garis miring
Nama perintah garis miring adalah apa yang diketik pengguna dalam pesan Chat untuk memanggil aplikasi Chat. Deskripsi singkat juga muncul di bawah nama, untuk meminta pengguna lebih lanjut tentang cara menggunakan perintah tersebut:

Saat memilih nama dan deskripsi untuk perintah garis miring, pertimbangkan rekomendasi berikut:
Untuk memberi nama perintah garis miring:
- Gunakan kata atau frasa yang singkat, deskriptif, dan dapat ditindaklanjuti untuk membuat
perintah menjadi jelas dan sederhana bagi pengguna. Misalnya, gunakan
/remindMe
, bukan/createAReminder
. - Jika perintah Anda berisi lebih dari satu kata, bantu pengguna membaca perintah tersebut
dengan menggunakan huruf kecil untuk kata pertama, lalu gunakan huruf besar untuk huruf pertama
kata tambahan. Misalnya, gunakan
/updateContact
, bukan/updatecontact
. - Pertimbangkan apakah akan menggunakan nama yang unik atau umum untuk perintah Anda. Jika
perintah Anda menjelaskan interaksi atau fitur standar, Anda dapat menggunakan
nama umum yang dikenali dan diharapkan pengguna, seperti
/settings
atau/feedback
. Jika tidak, coba gunakan nama perintah yang unik, karena jika nama perintah Anda sama untuk aplikasi Chat lainnya, pengguna harus memfilter perintah serupa untuk menemukan dan menggunakan perintah Anda.
- Gunakan kata atau frasa yang singkat, deskriptif, dan dapat ditindaklanjuti untuk membuat
perintah menjadi jelas dan sederhana bagi pengguna. Misalnya, gunakan
Untuk mendeskripsikan perintah garis miring:
- Buat deskripsi yang singkat dan jelas sehingga pengguna tahu apa yang diharapkan saat mereka memanggil perintah.
- Beri tahu pengguna jika ada persyaratan format untuk perintah tersebut.
Misalnya, jika Anda membuat perintah
/remindMe
yang memerlukan teks argumen, tetapkan deskripsi ke sesuatu sepertiRemind me to do [something] at [time]
.
Mengonfigurasi perintah garis miring di Google Chat API
Untuk membuat perintah garis miring, Anda perlu menentukan informasi tentang perintah tersebut dalam konfigurasi aplikasi Chat Anda untuk Google Chat API.
Untuk mengonfigurasi perintah garis miring di Google Chat API, selesaikan langkah-langkah berikut:
Di konsol Google Cloud, klik Menu > APIs & Services > Enabled APIs & Services > Google Chat API
Klik Configuration.
Di bagian Perintah garis miring, klik Tambahkan perintah garis miring.
Masukkan nama, ID perintah, dan deskripsi untuk perintah tersebut:
- Name: nama tampilan untuk perintah, dan yang diketik pengguna untuk memanggil aplikasi Anda. Harus diawali dengan garis miring, hanya berisi teks, dan dapat berisi maksimal 50 karakter.
- Deskripsi: teks yang menjelaskan cara menggunakan dan memformat perintah. Deskripsi dapat berisi hingga 50 karakter.
- Command ID: angka dari 1 hingga 1000 yang digunakan aplikasi Chat Anda untuk mengenali perintah garis miring dan menampilkan respons.
Opsional: Jika Anda ingin aplikasi Chat merespons perintah dengan dialog, pilih kotak centang Open a dialog.
Klik Simpan.
Perintah garis miring kini dikonfigurasi untuk aplikasi Chat.
Merespons perintah garis miring
Saat pengguna membuat pesan Chat yang berisi perintah garis miring, aplikasi Chat Anda akan menerima peristiwa interaksi MESSAGE
.
Payload peristiwa berisi informasi tentang perintah garis miring, termasuk kolom slashCommand
dan slashCommandMetadata
. Anda menggunakan kolom ini untuk mengidentifikasi command ID dan menampilkan respons
kustom.
Contoh berikut menunjukkan payload JSON untuk peristiwa interaksi MESSAGE
yang menyertakan perintah garis miring /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"
}
}
}
]
}
}
Untuk merespons perintah garis miring, Anda dapat mendeteksi apakah kolom slashCommand
ada dalam payload peristiwa, dan jika ya, tampilkan respons atas perintah tersebut.
Contoh kode berikut menunjukkan cara merespons peristiwa interaksi MESSAGE
yang berisi perintah garis miring:
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.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
Untuk menggunakan kode ini, ganti kode berikut:
ID
: ID perintah yang Anda tentukan saat mengonfigurasi perintah garis miring di Google Chat API.runFunction
: fungsi yang membuat respons terhadap perintah garis miring.
Contoh lengkap: Menyiapkan kontak menggunakan aplikasi Rolodex Chat
Contoh berikut menunjukkan aplikasi Chat yang merespons perintah garis miring berikut:
- Perintah
/help
menampilkan pesan teks yang menjelaskan cara mendapatkan dukungan dengan aplikasi Chat. ID perintah ditetapkan ke1
. - Perintah
/createContact
membuka dialog tempat pengguna dapat memasukkan detail tentang kontak. ID perintah ditetapkan ke2
.
Sebelum menjalankan contoh ini, ikuti langkah-langkah untuk mengonfigurasi perintah garis miring di 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.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.openDialog(event);
}
if (event.common.invokedFunction === "openSequentialDialog") {
res.openSequentialDialog(event);
}
if (event.common.invokedFunction === "confirmDialogSuccess") {
res.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) {
res.json({
"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) {
res.json({
"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 {
res.json({
"actionResponse": {
"type": "DIALOG",
"dialogAction": {
"actionStatus": "OK"
}
}
});
}
}
Apps Script
/**
* Responds to a MESSAGE event in Google Chat.
*
* @param {Object} event the event object from Chat API.
*
* @return {object} open a Dialog in response to a slash command
* or a card"s button click.
*/
function onMessage(event) {
// 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
return {"text": "Contact bot helps you update your address book!"}
case 2: // /createContact
return 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 {
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": "openDialog",
"interaction": "OPEN_DIALOG"
}
}
}
]
}
}
]
}
]
}
}]
};
}
}
/**
* Responds to a CARD_CLICKED event in Google Chat.
*
* @param {Object} event the event object from Google Chat
*/
function onCardClick(event) {
if (event.common.invokedFunction === "openDialog") {
return openDialog(event);
}
if (event.common.invokedFunction === "openSequentialDialog") {
return openSequentialDialog(event);
}
if (event.common.invokedFunction === "receiveDialog") {
return receiveDialog(event);
}
}
/**
* Opens and starts a dialog that lets users add details about a contact.
*
*
* @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": "contactName"
}
},
{
"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": "receiveDialog",
"parameters": [
{
"key": "receiveDialog",
"value": "receiveDialog"
}
]
}
}
}
]
},
"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": "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"
}
}
};
}
}
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!"
}
}
}