ตอบกลับคําสั่งเครื่องหมายทับในรูปแบบแอป Google Chat

หน้านี้จะอธิบายถึงวิธีตั้งค่าและตอบกลับคำสั่งเครื่องหมายทับ แอป Google Chat

คำสั่งเครื่องหมายทับเป็นวิธีทั่วไปที่ผู้ใช้เรียกใช้และโต้ตอบกับแท็ก แอป Chat คําสั่งเครื่องหมายทับยังช่วยให้ผู้ใช้ค้นพบและ ใช้ฟีเจอร์สำคัญของแอป Chat

หากต้องการใช้คำสั่งเครื่องหมายทับ ให้ผู้ใช้พิมพ์เครื่องหมายทับ (/) ตามด้วยคำสั่งข้อความสั้นๆ เช่น /about เพื่อดูข้อมูลเกี่ยวกับแอป Chat ผู้ใช้ค้นหาคำสั่งเครื่องหมายทับที่พร้อมใช้งานได้ด้วยการพิมพ์เครื่องหมายทับลงใน Google Chat ซึ่งแสดงหน้าต่างแสดงรายการคำสั่งที่ใช้ได้สำหรับ แอปแชท:

หน้าต่างคำสั่งเครื่องหมายทับ
รูปที่ 1: หน้าต่างที่ปรากฏขึ้นเมื่อผู้ใช้พิมพ์เครื่องหมายทับลงใน Google Chat

เมื่อผู้ใช้ส่งข้อความที่มีคำสั่งเครื่องหมายทับ ข้อความจะมีเฉพาะ ที่ผู้ใช้และแอป Chat มองเห็นได้

เพื่อตัดสินใจว่าคุณควรตั้งค่าคำสั่งเครื่องหมายทับหรือไม่ และเพื่อทำความเข้าใจวิธี ออกแบบการโต้ตอบของผู้ใช้ กําหนดเส้นทางทั้งหมดของผู้ใช้

ข้อกำหนดเบื้องต้น

Node.js

แอป Google Chat ที่เปิดใช้ฟีเจอร์แบบอินเทอร์แอกทีฟ วิธีสร้าง แอป Chat แบบอินเทอร์แอกทีฟที่ใช้บริการ HTTP ให้ทำการเริ่มต้นอย่างรวดเร็วนี้ให้เสร็จสมบูรณ์

Apps Script

แอป Google Chat ที่เปิดใช้ฟีเจอร์แบบอินเทอร์แอกทีฟ วิธีสร้าง แอป Chat แบบอินเทอร์แอกทีฟใน Apps Script โปรดกรอกข้อมูลในการเริ่มต้นอย่างรวดเร็วนี้

Python

แอป Google Chat ที่เปิดใช้ฟีเจอร์แบบอินเทอร์แอกทีฟ วิธีสร้าง แอป Chat แบบอินเทอร์แอกทีฟที่ใช้บริการ HTTP ให้ทำการเริ่มต้นอย่างรวดเร็วนี้ให้เสร็จสมบูรณ์

ตั้งค่าคำสั่งเครื่องหมายทับ

ส่วนนี้จะอธิบายวิธีทำตามขั้นตอนต่อไปนี้เพื่อตั้งค่าเครื่องหมายทับ คำสั่ง:

  1. สร้างชื่อให้คําสั่งเครื่องหมายทับ
  2. กำหนดค่าคำสั่งเครื่องหมายทับใน Google Chat API

ตั้งชื่อคำสั่งเครื่องหมายทับ

ชื่อของคําสั่งเครื่องหมายทับคือสิ่งที่ผู้ใช้พิมพ์ในข้อความ Chat เพื่อเรียกใช้แอป Chat และใส่คำอธิบายสั้นๆ ด้วย ปรากฏใต้ชื่อ เพื่อแจ้งผู้ใช้เพิ่มเติมเกี่ยวกับวิธีใช้คําสั่ง

ชื่อและคำอธิบายคำสั่งเครื่องหมายทับ
รูปที่ 2: ชื่อและคำอธิบายของคำสั่งเครื่องหมายทับ

เมื่อเลือกชื่อและคำอธิบายสำหรับคำสั่งเครื่องหมายทับ ให้พิจารณาถึง คำแนะนำต่อไปนี้

  • วิธีตั้งชื่อคำสั่งเครื่องหมายทับ

    • ใช้คำหรือวลีสั้นๆ ที่สื่อความหมาย และนำไปใช้ได้จริงเพื่อ เป็นคำสั่งที่ชัดเจนและง่ายสำหรับผู้ใช้ ตัวอย่างเช่น แทนที่จะพูดว่า /createAReminder ใช้ /remindMe
    • หากคำสั่งของคุณมีมากกว่า 1 คำ โปรดช่วยให้ผู้ใช้อ่านคำสั่ง โดยใช้อักษรตัวพิมพ์เล็กทั้งหมดกับคำแรก แล้วตามด้วยตัวพิมพ์ใหญ่ขึ้นต้น ตัวอักษรเพิ่มเติม ตัวอย่างเช่น แทนที่จะเป็น /updatecontact ใช้ /updateContact
    • พิจารณาว่าจะใช้ชื่อเฉพาะหรือชื่อทั่วไปสำหรับคำสั่งของคุณ ถ้า คำสั่งของคุณจะอธิบายการโต้ตอบหรือคุณลักษณะทั่วไป คุณสามารถใช้ ชื่อทั่วไปที่ผู้ใช้รู้จักและคาดหวัง เช่น /settingsหรือ /feedback มิฉะนั้น ให้ลองใช้ชื่อคำสั่งที่ไม่ซ้ำ เพราะถ้า ชื่อคำสั่งเหมือนกับแอป Chat อื่นๆ ผู้ใช้ต้อง กรองด้วยคำสั่งที่คล้ายกันเพื่อค้นหาและใช้คำสั่งของคุณ
  • หากต้องการอธิบายคำสั่งเครื่องหมายทับ ให้ทำดังนี้

    • เขียนคำอธิบายให้สั้นและชัดเจนเพื่อให้ผู้ใช้รู้ว่าควรคาดหวังสิ่งใด เมื่อเรียกใช้คำสั่ง
    • แจ้งให้ผู้ใช้ทราบหากมีข้อกําหนดการจัดรูปแบบสําหรับคําสั่งนี้ เช่น หากคุณสร้างคำสั่ง /remindMe ที่ต้องใช้อาร์กิวเมนต์ ข้อความ ให้กำหนดคำอธิบายเป็น Remind me to do [something] at [time]
    • แจ้งให้ผู้ใช้ทราบว่าแอป Chat ตอบกลับ ทุกคนในพื้นที่ทำงาน หรือแบบส่วนตัวสำหรับผู้ใช้ที่เรียกใช้คำสั่ง ตัวอย่างเช่น สำหรับคำสั่งเครื่องหมายทับ /about คุณสามารถอธิบายเป็น Learn about this app (Only visible to you) เพื่อตอบกลับแบบส่วนตัวกับ ดูส่วนตอบกลับด้วยข้อความส่วนตัว

กำหนดค่าคำสั่งเครื่องหมายทับใน Google Chat API

หากต้องการสร้างคำสั่งเครื่องหมายทับ คุณต้องระบุข้อมูลเกี่ยวกับคำสั่งใน การกำหนดค่า Google Chat API ของแอป Chat

หากต้องการกำหนดค่าคำสั่งเครื่องหมายทับใน Google Chat API ให้ทำตามขั้นตอนต่อไปนี้ ขั้นตอน:

  1. ในคอนโซล Google Cloud ให้คลิกเมนู > API และ บริการ > API ที่เปิดใช้และ บริการ > Google Chat API

    ไปที่หน้า Google Chat API

  2. คลิกการกำหนดค่า

  3. คลิกเพิ่มคำสั่งเครื่องหมายทับในส่วนคำสั่งเครื่องหมายทับ

  4. ป้อนชื่อ รหัสคำสั่ง และคำอธิบายคำสั่ง

    1. ชื่อ: ชื่อที่แสดงของคำสั่งและสิ่งที่ผู้ใช้พิมพ์ เพื่อเรียกใช้แอปของคุณ ต้องขึ้นต้นด้วยเครื่องหมายทับ มีได้เฉพาะข้อความเท่านั้น และสามารถ ไม่เกิน 50 อักขระ
    2. คำอธิบาย: ข้อความที่อธิบายวิธีใช้และจัดรูปแบบ คำสั่ง คำอธิบายมีอักขระได้สูงสุด 50 ตัว
    3. รหัสคำสั่ง: ตัวเลขตั้งแต่ 1 ถึง 1000 ที่ แอป Chat ใช้เพื่อจดจำคำสั่งเครื่องหมายทับ และแสดงคำตอบ
  5. ไม่บังคับ: หากต้องการให้แอป Chat ตอบกลับ คำสั่งที่มีกล่องโต้ตอบ ให้เลือก ช่องทำเครื่องหมายเปิดกล่องโต้ตอบ

  6. คลิกบันทึก

กำหนดค่าคำสั่งเครื่องหมายทับสำหรับแอป Chat แล้ว

ตอบกลับคำสั่งเครื่องหมายทับ

เมื่อผู้ใช้สร้างข้อความใน Chat ที่มีคําสั่งเครื่องหมายทับ แอป Chat ของคุณได้รับเหตุการณ์การโต้ตอบ MESSAGE เพย์โหลดเหตุการณ์มีข้อมูลเกี่ยวกับคำสั่งเครื่องหมายทับ รวมถึง slashCommand และ slashCommandMetadata ด้วย คุณสามารถใช้ช่องเหล่านี้เพื่อระบุรหัสคำสั่งและแสดงผลรหัสคำสั่งที่กำหนดเอง คำตอบ

ตัวอย่างต่อไปนี้แสดงเพย์โหลด JSON สำหรับเหตุการณ์การโต้ตอบ MESSAGE ที่มีคำสั่งเครื่องหมายทับ /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

หากต้องการใช้โค้ด ให้แทนที่รายการต่อไปนี้:

ไม่บังคับ: ตอบกลับด้วยข้อความส่วนตัว

ข้อความที่มีคำสั่งเครื่องหมายทับจะปรากฏแก่ผู้ใช้ที่ส่ง และแอป Chat ที่ได้รับคำสั่ง ถ้า คุณได้กำหนดค่าแอปใน Chat ให้เพิ่มลงในพื้นที่ทำงานแล้ว กับคนหลายคน คุณอาจต้องตอบคําสั่งเครื่องหมายทับ อย่างเป็นส่วนตัว เพื่อให้การโต้ตอบระหว่างผู้ใช้กับ แอป Chat

เช่น หากทีมใช้แอป Chat ที่จัดการ บริการสนับสนุนลูกค้า ผู้ใช้สามารถเรียกใช้คำสั่งเครื่องหมายทับ เช่น /myCasesเพื่อดูเคสขอรับความช่วยเหลือที่มอบหมาย หากทีมเพิ่มส่วน แชทในแอปกับพื้นที่ทำงาน ซึ่งเป็นผู้ใช้ที่ใช้คำสั่งเครื่องหมายทับนี้ ในพื้นที่ทำงานอาจต้องการให้แอป Chat ตอบสนองต่อ ให้พวกเขา เพื่อหลีกเลี่ยงการโพสต์เคสขอรับความช่วยเหลือของผู้ใช้ไปยังทุกคนในพื้นที่ทำงาน แอปแชทจะตอบกลับแบบส่วนตัวได้

หากต้องการตอบกลับคำสั่งเครื่องหมายทับแบบส่วนตัว โปรดดู ส่งข้อความส่วนตัวไปยังผู้ใช้ Google Chat

ตัวอย่างที่สมบูรณ์: การตั้งค่ารายชื่อติดต่อโดยใช้แอป Rolodex Chat

ตัวอย่างต่อไปนี้แสดงแอปใน Chat ที่ตอบสนองต่อ คำสั่งเครื่องหมายทับต่อไปนี้

  • คำสั่ง /help จะแสดง SMS ที่อธิบายวิธีเรียก การสนับสนุนสำหรับแอป Chat กำหนดรหัสคำสั่งแล้ว ไปยัง 1
  • คำสั่ง /createContact จะเปิดกล่องโต้ตอบที่ผู้ใช้ป้อนได้ รายละเอียดเกี่ยวกับผู้ติดต่อ รหัสคำสั่งตั้งค่าเป็น 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

apps-script/dialogs/rolodex.gs
/**
* 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") {
    const contactName = fetchFormValue(event, "contactName");
    const address = fetchFormValue(event, "address");
    return openSequentialDialog(contactName, address);
  }

  if (event.common.invokedFunction === "receiveDialog") {
    const parameters = event.common.parameters;
    parameters["contactType"] = fetchFormValue(event, "contactType");
    parameters["notes"] = fetchFormValue(event, "notes");
    return receiveDialog(parameters);
  }
}

/**
 * Extracts form input value for a given widget
 * 
 * @param {Object} event the event object from Google Chat
 * @param {String} widgetName the widget name
 * @returns the form input value for the widget
 */
function fetchFormValue(event, widgetName) {
  const widget = event.common.formInputs[widgetName];
  if (widget) {
    return widget[""]["stringInputs"]["value"][0];
  }
}

/**
* 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 {String} contactName the contact name from the previous dialog.
* @param {String} address the address from the previous dialog.
*
* @return {Object} open a dialog.
*/
function openSequentialDialog(contactName, address) {
  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": "contactName",
                                  "value": contactName
                                },
                                {
                                  "key": "address",
                                  "value": address
                                }
                              ]
                            }
                          }
                        }
                      ]
                    },
                    "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} parameters the form input values.
*
* @return {Object} open a Dialog in Google Chat.
*/
function receiveDialog(parameters) {

  // Checks to make sure the user entered a name
  // in a dialog. If no name value detected, returns
  // an error message.
  if (!parameters.contactName) {
    return {
      "actionResponse": {
        "type": "DIALOG",
        "dialogAction": {
          "actionStatus": {
            "statusCode": "INVALID_ARGUMENT",
            "userFacingMessage": "Don't forget to name your new contact!"
          }
        }
      }
    };

    // Otherwise the Chat 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": {
            "statusCode": "OK",
            "userFacingMessage": "Success " + JSON.stringify(parameters)
          }
        }
      }
    };
  }
}

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!"
        }
      }
    }