به عنوان یک برنامه چت Google به دستورات اسلش پاسخ دهید

این صفحه نحوه تنظیم و پاسخ به دستورات اسلش را برای برنامه Google Chat توضیح می دهد.

دستور اسلش روشی متداول است که کاربران با آن برنامه چت را فراخوانی کرده و با آن تعامل دارند. دستورات اسلش همچنین به کاربران کمک می کند تا ویژگی های کلیدی یک برنامه چت را کشف کرده و از آنها استفاده کنند.

برای استفاده از دستور اسلش، کاربران یک اسلش ( / ) و سپس یک دستور متن کوتاه مانند /about تایپ می کنند تا اطلاعاتی در مورد برنامه چت دریافت کنند. کاربران می توانند با تایپ یک اسلش در Google Chat، دستورات اسلش موجود را پیدا کنند، که پنجره ای را نشان می دهد که دستورات موجود برای برنامه Chat را فهرست می کند:

اسلش پنجره فرمان
شکل 1 : پنجره ای که وقتی کاربران یک اسلش در چت گوگل تایپ می کنند ظاهر می شود.

برای تصمیم گیری در مورد اینکه آیا باید دستورات اسلش را تنظیم کنید یا نه و برای درک نحوه طراحی تعاملات کاربر، به اصول طراحی چت Google مراجعه کنید.

پیش نیازها

Node.js

اسکریپت برنامه ها

پایتون

یک دستور اسلش را تنظیم کنید

این بخش نحوه تکمیل مراحل زیر را برای تنظیم دستور اسلش توضیح می دهد:

  1. یک نام برای دستور اسلش خود ایجاد کنید .
  2. دستور اسلش را در Google Chat API پیکربندی کنید .

دستور اسلش خود را نام ببرید

نام یک دستور اسلش همان چیزی است که کاربران در پیام چت برای فراخوانی برنامه چت تایپ می کنند. توضیحات کوتاهی نیز در زیر نام ظاهر می شود تا کاربران را در مورد نحوه استفاده از دستور بیشتر راهنمایی کند:

نام و توضیحات دستور اسلش
شکل 2 : نام و توضیحات یک دستور اسلش.

هنگام انتخاب نام و توضیحات برای دستور اسلش، توصیه های زیر را در نظر بگیرید:

  • برای نامگذاری دستور اسلش:

    • از کلمات یا عبارات کوتاه، توصیفی و کاربردی استفاده کنید تا دستورات برای کاربر واضح و ساده باشد. به عنوان مثال، به جای گفتن /createAReminder ، از /remindMe استفاده کنید.
    • اگر دستور شما حاوی بیش از یک کلمه است، با استفاده از تمام حروف کوچک برای کلمه اول و سپس بزرگ کردن حرف اول کلمات اضافی به کاربران کمک کنید دستور را بخوانند. به عنوان مثال، به جای /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، مراحل زیر را انجام دهید:

  1. در کنسول Google Cloud، روی > APIs & Services > Enabled APIs & Services > Google Chat API کلیک کنید.

    به صفحه Google Chat API بروید

  2. روی پیکربندی کلیک کنید.

  3. در زیر دستورات اسلش ، روی افزودن دستور اسلش کلیک کنید.

  4. نام، شناسه فرمان و توضیحات دستور را وارد کنید:

    1. نام: نام نمایشی دستور و آنچه کاربران برای فراخوانی برنامه شما تایپ می کنند. باید با اسلش شروع شود، فقط حاوی متن باشد و حداکثر 50 کاراکتر باشد.
    2. توضیحات: متنی که نحوه استفاده و قالب بندی دستور را توضیح می دهد. توضیحات می تواند حداکثر 50 کاراکتر باشد.
    3. شناسه فرمان: عددی از 1 تا 1000 که برنامه چت شما از آن برای تشخیص دستور اسلش و برگرداندن پاسخ استفاده می کند.
  5. اختیاری: اگر می‌خواهید برنامه چت شما به فرمان با یک گفتگو پاسخ دهد، کادر باز کردن یک گفتگو را انتخاب کنید.

  6. روی ذخیره کلیک کنید.

دستور اسلش اکنون برای برنامه چت پیکربندی شده است.

به یک دستور اسلش پاسخ دهید

وقتی کاربران یک پیام گپ حاوی دستور اسلش ایجاد می‌کنند، برنامه گپ شما یک رویداد تعاملی 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.runFunction; // The response to the slash command.
    }
  }

اسکریپت برنامه ها

/**
* 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.
    }
  }
}

پایتون

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

برای استفاده از کد، کد زیر را جایگزین کنید:

اختیاری: با یک پیام خصوصی پاسخ دهید

در بسیاری از موارد، کاربران نمی‌خواهند یا انتظار دارند که برنامه چت به دستور اسلش با پیامی پاسخ دهد که برای همه افراد حاضر در فضا قابل مشاهده است.

به عنوان مثال، اگر تیمی از یک برنامه چت استفاده می‌کند که خدمات پشتیبانی مشتری را مدیریت می‌کند، کاربران می‌توانند از دستور اسلش مانند /myCases برای مشاهده موارد پشتیبانی اختصاص داده شده به آنها استفاده کنند. اگر تیم برنامه Chat را به یک فضا اضافه کند، کاربری که از این دستور اسلش در فضا استفاده می‌کند ممکن است بخواهد برنامه چت فقط به آنها پاسخ دهد. برای جلوگیری از ارسال موارد پشتیبانی کاربر به همه افراد حاضر در فضا، برنامه چت می تواند به صورت خصوصی پاسخ دهد.

برای پاسخ دادن به دستور اسلش به صورت خصوصی، به ارسال پیام خصوصی به کاربران گپ Google مراجعه کنید.

مثال کامل: با استفاده از برنامه Rolodex Chat مخاطبین را تنظیم کنید

مثال زیر یک برنامه چت را نشان می دهد که به دستورات اسلش زیر پاسخ می دهد:

  • فرمان /help یک پیام متنی برمی گرداند که نحوه دریافت پشتیبانی با برنامه چت را توضیح می دهد. شناسه فرمان روی 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.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/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)
          }
        }
      }
    };
  }
}

پایتون

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