運用 Google Chat、Vertex AI 與 Apps Script 針對事件做出回應

本教學課程說明如何建立 Google Chat 擴充應用程式,即時回應各種事件。回報事件時,應用程式會建立並填入 Chat 聊天室、透過訊息、斜線指令和對話方塊協助解決事件,並使用 AI 產生 Google 文件,彙整事件回應內容。

事件是指需要團隊立即處理的事件,事件範例包括:

  • 在客戶關係管理 (CRM) 平台中建立時效性案件,需要服務團隊合作解決。
  • 系統離線,並向一組網站穩定性工程師 (SRE) 發出快訊,讓他們可以共同作業,使系統恢復連線。
  • 發生強震,緊急應變人員需要協調應變措施。

在本教學課程中,當使用者在網頁上點選按鈕回報事件時,就會觸發事件快訊。網頁會要求使用者輸入基本事件資訊 (標題、說明和回應者的電子郵件地址),模擬事件發生情況。

查看事件管理 Chat 應用程式的實際運作情形:

  • 啟動事件的網站。
    圖 1. 使用者可透過這個網站回報事件。
  • 系統會通知您已建立事件 Chat 聊天室。
    圖 2. 系統會通知您已建立事件 Chat 聊天室。
  • 事件回應 Chat 聊天室。
    圖 3. 事件應變 Chat 聊天室。
  • 使用斜線指令解決事件。
    圖 4. 使用斜線指令解決事件。
  • 「事件解決」對話方塊。
    圖 5. 事件解決對話方塊。
  • 在聊天室中分享事件解決方案的 Google 文件。
    圖 6. 聊天室中分享的事件解決方式 Google 文件。
  • AI 摘要事件解決 Google 文件。
    圖 7. AI 摘要事件解決 Google 文件。

必要條件

如需為貴機構啟用上述任一必要條件,請要求 Google Workspace 管理員啟用:

  • 具有 Google Chat 存取權的 Business 或 Enterprise 版 Google Workspace 帳戶。
  • 為 Google Workspace 啟用目錄 (聯絡人共用) 功能。事件應用程式會使用目錄查詢事件回應者的聯絡資訊,例如姓名和電子郵件地址。事件回應人員必須是 Google Workspace 機構中擁有 Google Chat 帳戶的使用者。

目標

  • 建構可回應事件的 Chat 應用程式。
  • 請按照下列步驟,協助使用者回應事件:
    • 建立事件回應空間。
    • 發布訊息,總結事件和回應。
    • 透過互動式 Chat 應用程式功能,支援協作。
  • 使用 Vertex AI 產生對話和解決方案摘要。

架構

下圖顯示事件回應 Google Chat 應用程式使用的 Google Workspace 和 Google Cloud 資源架構。

事件回應 Google Chat 應用程式的架構

這個架構說明事件回應 Google Chat 應用程式如何處理事件和解決問題。

  1. 使用者透過以 Apps Script 代管的外部網站啟動事件。

  2. 網站會將非同步 HTTP 要求傳送至 Google Chat 應用程式,該應用程式也託管於 Apps Script。

  3. 事件回應 Google Chat 應用程式會處理要求:

    1. Apps Script Admin SDK 服務會取得團隊成員資訊,例如使用者 ID 和電子郵件地址。

    2. 透過 Apps Script Advanced Chat 服務對 Chat API 發出 HTTP 要求,事件回應 Google Chat 應用程式就會建立事件 Chat 聊天室、加入團隊成員,並傳送訊息到該聊天室。

  4. 團隊成員在 Chat 聊天室中討論事件。

  5. 團隊成員叫用斜線指令,表示事件已解決。

    1. 使用 Apps Script Advanced Chat 服務對 Chat API 進行 HTTP 呼叫,即可列出所有 Chat 聊天室的訊息。

    2. Vertex AI 會收到列出的訊息,並生成摘要。

    3. Apps Script DocumentApp 服務會建立 Google 文件,並在文件中加入 Vertex AI 產生的摘要。

    4. 事件回應 Google Chat 應用程式會呼叫 Chat API,傳送訊息並分享摘要 Google 文件連結。

準備環境

本節說明如何為 Chat 應用程式建立及設定 Google Cloud 專案。

建立 Google Cloud 專案

Google Cloud 控制台

  1. 前往 Google Cloud 控制台,依序點選「選單」圖示 >「IAM 與管理」 >「建立專案」

    前往「建立專案」

  2. 在「Project Name」(專案名稱) 欄位中,輸入專案的描述性名稱。

    選用:如要編輯「專案 ID」,請按一下「編輯」。專案建立後就無法變更專案 ID,因此請選用符合專案執行期間需求的 ID。

  3. 在「Location」(位置) 欄位中,按一下「Browse」(瀏覽),顯示專案的可能位置。然後按一下「選取」
  4. 按一下「建立」,Google Cloud 控制台會前往「資訊主頁」頁面,並在幾分鐘內建立專案。

gcloud CLI

在下列任一開發環境中,存取 Google Cloud CLI (gcloud):

  • Cloud Shell:如要使用已設定 gcloud CLI 的線上終端機,請啟用 Cloud Shell。
    啟用 Cloud Shell
  • 本機殼層:如要使用本機開發環境,請安裝初始化 gcloud CLI。
    如要建立 Cloud 專案,請使用 gcloud projects create 指令:
    gcloud projects create PROJECT_ID
    PROJECT_ID 替換為要建立的專案 ID。

啟用 Cloud 專案的計費功能

Google Cloud 控制台

  1. 前往 Google Cloud 控制台的「帳單」頁面。依序點選「選單」「帳單」「我的專案」

    前往「我的專案」的帳單頁面

  2. 在「選取機構」中,選擇與 Google Cloud 專案相關聯的機構。
  3. 在專案列中開啟「動作」選單 (),然後按一下「變更帳單」,並選擇 Cloud 帳單帳戶。
  4. 按一下 [設定帳戶]

gcloud CLI

  1. 如要列出可用的帳單帳戶,請執行下列指令:
    gcloud billing accounts list
  2. 將帳單帳戶連結至 Google Cloud 專案:
    gcloud billing projects link PROJECT_ID --billing-account=BILLING_ACCOUNT_ID

    更改下列內容:

    • PROJECT_ID 是要啟用計費功能的 Cloud 專案的專案 ID
    • BILLING_ACCOUNT_ID 是要連結至 Google Cloud 專案的帳單帳戶 ID

啟用 API

Google Cloud 控制台

  1. 在 Google Cloud 控制台中,啟用 Google Chat API、Google 文件 API、Admin SDK API 和 Vertex AI API。

    啟用 API

  2. 確認您要在正確的 Cloud 專案中啟用 API,然後按一下「下一步」

  3. 確認要啟用的 API 正確無誤,然後按一下「啟用」

gcloud CLI

  1. 如有必要,請使用 gcloud config set project 指令,將目前的 Cloud 專案設為您建立的專案:

    gcloud config set project PROJECT_ID

    PROJECT_ID 替換為您建立的 Cloud 專案的專案 ID

  2. 使用 gcloud services enable 指令啟用 Google Chat API、Google Docs API、Admin SDK API 和 Vertex AI API:

    gcloud services enable chat.googleapis.com docs.googleapis.com admin.googleapis.com aiplatform.googleapis.com

設定驗證與授權

驗證和授權可讓 Chat 應用程式存取 Google Workspace 和 Google Cloud 中的資源,以處理事件回應。

在本教學課程中,您會發布內部應用程式,因此可以使用預留位置資訊。對外發布應用程式前,請將同意畫面中的預留位置資訊換成實際資訊。

  1. 在 Google Cloud 控制台中,依序前往「選單」圖示 > > 「品牌」

    前往「品牌宣傳」

  2. 如果您已設定,可以在「品牌」、「目標對象」和「資料存取權」中,設定下列 OAuth 同意畫面設定。 如果看到「尚未設定」 訊息,請按一下「開始使用」

    1. 在「App Information」(應用程式資訊) 下方的「App name」(應用程式名稱) 中,輸入 Incident Management
    2. 在「使用者支援電子郵件」中,選取您的電子郵件地址或適當的 Google 群組。
    3. 點選 [下一步]。
    4. 在「目標對象」下方,選取「內部」。如果無法選取「Internal」(內部),請選取「External」(外部)
    5. 點選 [下一步]。
    6. 在「聯絡資訊」下方,輸入「電子郵件地址」,以便在專案有任何異動時收到通知。
    7. 點選 [下一步]。
    8. 在「完成」下方,詳閱《Google API 服務使用者資料政策》,然後選取「我同意《Google API 服務:使用者資料政策》」
    9. 按一下「繼續」
    10. 點選「建立」
    11. 如果為使用者類型選取「外部」,請新增測試使用者:
      1. 按一下「目標對象」
      2. 在「測試使用者」下方,按一下「新增使用者」
      3. 輸入您的電子郵件地址和任何其他授權測試使用者,然後按一下「儲存」
  3. 依序點選「資料存取權」>「新增或移除範圍」。系統會顯示面板,列出您在 Google Cloud 專案中啟用的各項 API 範圍。

    1. 在「手動新增範圍」下方,貼上下列範圍:

      • https://www.googleapis.com/auth/chat.spaces.create
      • https://www.googleapis.com/auth/chat.memberships
      • https://www.googleapis.com/auth/chat.memberships.app
      • https://www.googleapis.com/auth/chat.messages
      • https://www.googleapis.com/auth/documents
      • https://www.googleapis.com/auth/admin.directory.user.readonly
      • https://www.googleapis.com/auth/script.external_request
      • https://www.googleapis.com/auth/userinfo.email
      • https://www.googleapis.com/auth/cloud-platform
    2. 按一下「新增至表格」

    3. 按一下「更新」

    4. 選取應用程式所需的範圍後,請在「資料存取」 頁面按一下「儲存」

建立及部署 Chat 應用程式

在下一節中,您將複製並更新整個 Apps Script 專案,其中包含 Chat 應用程式所需的所有應用程式程式碼,因此不必複製及貼上每個檔案。

部分函式名稱結尾會加上底線,例如 ChatApp.gs 中的 processSlashCommand_()。在瀏覽器中開啟事件初始化網頁時,底線會隱藏函式。詳情請參閱「私人函式」。

Apps Script 支援兩種檔案類型:.gs 指令碼和 .html 檔案。為遵守這項支援規定,應用程式的用戶端 JavaScript 會納入 <script /> 標記內,而 CSS 則會納入 HTML 檔案內的 <style /> 標記內。

您也可以選擇在 GitHub 上查看整個專案。

前往 GitHub 查看

以下簡要說明各個檔案:

Consts.gs

定義其他程式碼檔案參照的常數,包括 Cloud 專案 ID、Vertex AI 位置 ID,以及用於結案事件的斜線指令 ID。

查看 Consts.gs 程式碼

apps-script/incident-response/Consts.gs
const PROJECT_ID = 'replace-with-your-project-id';
const VERTEX_AI_LOCATION_ID = 'us-central1';
const CLOSE_INCIDENT_COMMAND_ID = 1;
ChatApp.gs

處理 Chat 互動事件,包括訊息、資訊卡點擊、斜線指令和對話方塊。回應 /closeIncident 斜線指令,開啟對話方塊來收集事件解決詳細資料。呼叫 Chat API 中的 spaces.messages.list 方法,讀取聊天室中的訊息。使用 Apps Script 中的 Admin SDK Directory 服務取得使用者 ID。

查看 ChatApp.gs 程式碼

apps-script/incident-response/ChatApp.gs
/**
 * Responds to a MESSAGE event in Google Chat.
 *
 * This app only responds to a slash command with the ID 1 ("/closeIncident").
 * It will respond to any other message with a simple "Hello" text message.
 *
 * @param {Object} event the event object from Google Chat
 */
function onMessage(event) {
  if (event.message.slashCommand) {
    return processSlashCommand_(event);
  }
  return { "text": "Hello from Incident Response app!" };
}

/**
 * Responds to a CARD_CLICKED event in Google Chat.
 *
 * This app only responds to one kind of dialog (Close Incident).
 *
 * @param {Object} event the event object from Google Chat
 */
function onCardClick(event) {
  if (event.isDialogEvent) {
    if (event.dialogEventType == 'SUBMIT_DIALOG') {
      return processSubmitDialog_(event);
    }
    return {
      actionResponse: {
        type: "DIALOG",
        dialogAction: {
          actionStatus: "OK"
        }
      }
    };
  }
}

/**
 * Responds to a MESSAGE event with a Slash command in Google Chat.
 *
 * This app only responds to a slash command with the ID 1 ("/closeIncident")
 * by returning a Dialog.
 *
 * @param {Object} event the event object from Google Chat
 */
function processSlashCommand_(event) {
  if (event.message.slashCommand.commandId != CLOSE_INCIDENT_COMMAND_ID) {
    return {
      "text": "Command not recognized. Use the command `/closeIncident` to close the incident managed by this space."
    };
  }
  const sections = [
    {
      header: "Close Incident",
      widgets: [
        {
          textInput: {
            label: "Please describe the incident resolution",
            type: "MULTIPLE_LINE",
            name: "description"
          }
        },
        {
          buttonList: {
            buttons: [
              {
                text: "Close Incident",
                onClick: {
                  action: {
                    function: "closeIncident"
                  }
                }
              }
            ]
          }
        }
      ]
    }
  ];
  return {
    actionResponse: {
      type: "DIALOG",
      dialogAction: {
        dialog: {
          body: {
            sections,
          }
        }
      }
    }
  };
}

/**
 * Responds to a CARD_CLICKED event with a Dialog submission in Google Chat.
 *
 * This app only responds to one kind of dialog (Close Incident).
 * It creates a Doc with a summary of the incident information and posts a message
 * to the space with a link to the Doc.
 *
 * @param {Object} event the event object from Google Chat
 */
function processSubmitDialog_(event) {
  const resolution = event.common.formInputs.description[""].stringInputs.value[0];
  const chatHistory = concatenateAllSpaceMessages_(event.space.name);
  const chatSummary = summarizeChatHistory_(chatHistory);
  const docUrl = createDoc_(event.space.displayName, resolution, chatHistory, chatSummary);
  return {
    actionResponse: {
      type: "NEW_MESSAGE",
    },
    text: `Incident closed with the following resolution: ${resolution}\n\nHere is the automatically generated post-mortem:\n${docUrl}`
  };
}

/**
 * Lists all the messages in the Chat space, then concatenate all of them into
 * a single text containing the full Chat history.
 *
 * For simplicity for this demo, it only fetches the first 100 messages.
 *
 * Messages with slash commands are filtered out, so the returned history will
 * contain only the conversations between users and not app command invocations.
 *
 * @return {string} a text containing all the messages in the space in the format:
 *          Sender's name: Message
 */
function concatenateAllSpaceMessages_(spaceName) {
  // Call Chat API method spaces.messages.list
  const response = Chat.Spaces.Messages.list(spaceName, { 'pageSize': 100 });
  const messages = response.messages;
  // Fetch the display names of the message senders and returns a text
  // concatenating all the messages.
  let userMap = new Map();
  return messages
    .filter(message => message.slashCommand === undefined)
    .map(message => `${getUserDisplayName_(userMap, message.sender.name)}: ${message.text}`)
    .join('\n');
}

/**
 * Obtains the display name of a user by using the Admin Directory API.
 *
 * The fetched display name is cached in the provided map, so we only call the API
 * once per user.
 *
 * If the user does not have a display name, then the full name is used.
 *
 * @param {Map} userMap a map containing the display names previously fetched
 * @param {string} userName the resource name of the user
 * @return {string} the user's display name
 */
function getUserDisplayName_(userMap, userName) {
  if (userMap.has(userName)) {
    return userMap.get(userName);
  }
  let displayName = 'Unknown User';
  try {
    const user = AdminDirectory.Users.get(
      userName.replace("users/", ""),
      { projection: 'BASIC', viewType: 'domain_public' });
    displayName = user.name.displayName ? user.name.displayName : user.name.fullName;
  } catch (e) {
    // Ignore error if the API call fails (for example, because it's an
    // out-of-domain user or Chat app)) and just use 'Unknown User'.
  }
  userMap.set(userName, displayName);
  return displayName;
}
ChatSpaceCreator.gs

接收使用者在事件初始化網頁上輸入的表單資料,並使用這些資料建立及填入 Chat 空間,然後發布事件相關訊息。

查看 ChatSpaceCreator.gs 程式碼

apps-script/incident-response/ChatSpaceCreator.gs
/**
 * Creates a space in Google Chat with the provided title and members, and posts an
 * initial message to it.
 *
 * @param {Object} formData the data submitted by the user. It should contain the fields
 *                          title, description, and users.
 * @return {string} the resource name of the new space.
 */
function createChatSpace(formData) {
  const users = formData.users.trim().length > 0 ? formData.users.split(',') : [];
  const spaceName = setUpSpace_(formData.title, users);
  addAppToSpace_(spaceName);
  createMessage_(spaceName, formData.description);
  return spaceName;
}

/**
 * Creates a space in Google Chat with the provided display name and members.
 *
 * @return {string} the resource name of the new space.
 */
function setUpSpace_(displayName, users) {
  const memberships = users.map(email => ({
    member: {
      name: `users/${email}`,
      type: "HUMAN"
    }
  }));
  const request = {
    space: {
      displayName: displayName,
      spaceType: "SPACE",
      externalUserAllowed: true
    },
    memberships: memberships
  };
  // Call Chat API method spaces.setup
  const space = Chat.Spaces.setup(request);
  return space.name;
}

/**
 * Adds this Chat app to the space.
 *
 * @return {string} the resource name of the new membership.
 */
function addAppToSpace_(spaceName) {
  const request = {
    member: {
      name: "users/app",
      type: "BOT"
    }
  };
  // Call Chat API method spaces.members.create
  const membership = Chat.Spaces.Members.create(request, spaceName);
  return membership.name;
}

/**
 * Posts a text message to the space on behalf of the user.
 *
 * @return {string} the resource name of the new message.
 */
function createMessage_(spaceName, text) {
  const request = {
    text: text
  };
  // Call Chat API method spaces.messages.create
  const message = Chat.Spaces.Messages.create(request, spaceName);
  return message.name;
}
DocsApi.gs

呼叫 Google 文件 API,在使用者 Google 雲端硬碟中建立 Google 文件,並將 VertexAiApi.gs 中建立的事件資訊摘要寫入該文件。

查看 DocsApi.gs 程式碼

apps-script/incident-response/DocsApi.gs
/**
 * Creates a Doc in the user's Google Drive and writes a summary of the incident information to it.
 *
 * @param {string} title The title of the incident
 * @param {string} resolution Incident resolution described by the user
 * @param {string} chatHistory The whole Chat history be included in the document
 * @param {string} chatSummary A summary of the Chat conversation to be included in the document
 * @return {string} the URL of the created Doc
 */
function createDoc_(title, resolution, chatHistory, chatSummary) {
  let doc = DocumentApp.create(title);
  let body = doc.getBody();
  body.appendParagraph(`Post-Mortem: ${title}`).setHeading(DocumentApp.ParagraphHeading.TITLE);
  body.appendParagraph("Resolution").setHeading(DocumentApp.ParagraphHeading.HEADING1);
  body.appendParagraph(resolution);
  body.appendParagraph("Summary of the conversation").setHeading(DocumentApp.ParagraphHeading.HEADING1);
  body.appendParagraph(chatSummary);
  body.appendParagraph("Full Chat history").setHeading(DocumentApp.ParagraphHeading.HEADING1);
  body.appendParagraph(chatHistory);
  return doc.getUrl();
}
VertexAiApi.gs

使用 Vertex AI 摘要顯示 Google Chat 空間中的對話。這份摘要會發布在 DocsAPI.gs 中特別建立的文件。

查看 VertexAiApi.gs 程式碼

apps-script/incident-response/VertexAiApi.gs
/**
 * Summarizes a Chat conversation using the Vertex AI text prediction API.
 *
 * @param {string} chatHistory The Chat history that will be summarized.
 * @return {string} The content from the text prediction response.
 */
function summarizeChatHistory_(chatHistory) {
  const prompt =
    "Summarize the following conversation between Engineers resolving an incident"
      + " in a few sentences. Use only the information from the conversation.\n\n"
      + chatHistory;
  const request = {
    instances: [
      { prompt: prompt }
    ],
    parameters: {
      temperature: 0.2,
      maxOutputTokens: 256,
      topK: 40,
      topP: 0.95
    }
  }
  const fetchOptions = {
    method: 'POST',
    headers: { Authorization: 'Bearer ' + ScriptApp.getOAuthToken() },
    contentType: 'application/json',
    payload: JSON.stringify(request)
  }
  const response = UrlFetchApp.fetch(
    `https://${VERTEX_AI_LOCATION_ID}-aiplatform.googleapis.com/v1`
      + `/projects/${PROJECT_ID}/locations/${VERTEX_AI_LOCATION_ID}`
      + "/publishers/google/models/text-bison:predict",
    fetchOptions);
  const payload = JSON.parse(response.getContentText());
  return payload.predictions[0].content;
}
WebController.gs

提供事件初始化網站。

查看 WebController.gs 程式碼

apps-script/incident-response/WebController.gs
/**
 * Serves the web page from Index.html.
 */
function doGet() {
  return HtmlService
    .createTemplateFromFile('Index')
    .evaluate();
}

/**
 * Serves the web content from the specified filename.
 */
function include(filename) {
  return HtmlService
    .createHtmlOutputFromFile(filename)
    .getContent();
}

/**
 * Returns the email address of the user running the script.
 */
function getUserEmail() {
  return Session.getActiveUser().getEmail();
}
Index.html

組成事件初始化網站的 HTML。

查看 Index.html 程式碼

apps-script/incident-response/Index.html
<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
    <link href='https://fonts.googleapis.com/css?family=Roboto' rel='stylesheet'>
    <?!= include('Stylesheet'); ?>
  </head>
  <body>
    <div class="container">
      <div class="content">
        <h1>Incident Manager</h1>
        <form id="incident-form" onsubmit="handleFormSubmit(this)">
          <div id="form">
            <p>
              <label for="title">Incident title</label><br/>
              <input type="text" name="title" id="title" />
            </p>
            <p>
              <label for="users">Incident responders</label><br/>
              <small>
                Please enter a comma-separated list of email addresses of the users
                that should be added to the space.
                Do not include <?= getUserEmail() ?> as it will be added automatically.
              </small><br/>
              <input type="text" name="users" id="users" />
            </p>
            <p>
              <label for="description">Initial message</label></br>
              <small>This message will be posted after the space is created.</small><br/>
              <textarea name="description" id="description"></textarea>
            </p>
            <p class="text-center">
              <input type="submit" value="CREATE CHAT SPACE" />
            </p>
          </div>
          <div id="output" class="hidden"></div>
          <div id="clear" class="hidden">
            <input type="reset" value="CREATE ANOTHER INCIDENT" onclick="onReset()" />
          </div>
        </form>
      </div>
    </div>
    <?!= include('JavaScript'); ?>
  </body>
</html>
JavaScript.html

處理表單行為,包括提交、錯誤和清除,適用於事件初始化網站。WebController.gs 中的自訂 include 函式會將其納入 Index.html

查看 JavaScript.html 程式碼

apps-script/incident-response/JavaScript.html
<script>
  var formDiv = document.getElementById('form');
  var outputDiv = document.getElementById('output');
  var clearDiv = document.getElementById('clear');

  function handleFormSubmit(formObject) {
    event.preventDefault();
    outputDiv.innerHTML = 'Please wait while we create the space...';
    hide(formDiv);
    show(outputDiv);
    google.script.run
      .withSuccessHandler(updateOutput)
      .withFailureHandler(onFailure)
      .createChatSpace(formObject);
  }

  function updateOutput(response) {
    var spaceId = response.replace('spaces/', '');
    outputDiv.innerHTML =
      '<p>Space created!</p><p><a href="https://mail.google.com/chat/#chat/space/'
        + spaceId
        + '" target="_blank">Open space</a></p>';
    show(outputDiv);
    show(clearDiv);
  }

  function onFailure(error) {
    outputDiv.innerHTML = 'ERROR: ' + error.message;
    outputDiv.classList.add('error');
    show(outputDiv);
    show(clearDiv);
  }

  function onReset() {
    outputDiv.innerHTML = '';
    outputDiv.classList.remove('error');
    show(formDiv);
    hide(outputDiv);
    hide(clearDiv);
  }

  function hide(element) {
    element.classList.add('hidden');
  }

  function show(element) {
    element.classList.remove('hidden');
  }
</script>
Stylesheet.html

事件初始化網站的 CSS。自訂 include 函式會將其納入 WebController.gsIndex.html

查看 Stylesheet.html 程式碼

apps-script/incident-response/Stylesheet.html
<style>
  * {
    box-sizing: border-box;
  }
  body {
    font-family: Roboto, Arial, Helvetica, sans-serif;
  }
  div.container {
    display: flex;
    justify-content: center;
    align-items: center;
    position: absolute;
    top: 0; bottom: 0; left: 0; right: 0;
  }
  div.content {
    width: 80%;
    max-width: 1000px;
    padding: 1rem;
    border: 1px solid #999;
    border-radius: 0.25rem;
    box-shadow: 0 2px 2px 0 rgba(66, 66, 66, 0.08), 0 2px 4px 2px rgba(66, 66, 66, 0.16);
  }
  h1 {
    text-align: center;
    padding-bottom: 1rem;
    margin: 0 -1rem 1rem -1rem;
    border-bottom: 1px solid #999;
  }
 #output {
    text-align: center;
    min-height: 250px;
  }
  div#clear {
    text-align: center;
    padding-top: 1rem;
    margin: 1rem -1rem 0 -1rem;
    border-top: 1px solid #999;
  }
  input[type=text], textarea {
    width: 100%;
    padding: 1rem 0.5rem;
    margin: 0.5rem 0;
    border: 0;
    border-bottom: 1px solid #999;
    background-color: #f0f0f0;
  }
  textarea {
    height: 5rem;
  }
  small {
    color: #999;
  }
  input[type=submit], input[type=reset] {
    padding: 1rem;
    border: none;
    background-color: #6200ee;
    color: #fff;
    border-radius: 0.25rem;
    width: 25%;
  }
  .hidden {
    display: none;
  }
  .text-center {
    text-align: center;
  }
  .error {
    color: red;
  }
</style>

找出 Cloud 專案編號和 ID

  1. 在 Google Cloud 控制台中,前往您的 Cloud 專案。

    前往 Google Cloud 控制台

  2. 依序點選「設定和公用程式」 >「專案設定」

  3. 記下「專案編號」和「專案 ID」欄位中的值。您會在後續章節中使用這些函式。

建立 Apps Script 專案

如要建立 Apps Script 專案並連結至 Cloud 專案,請按照下列步驟操作:

  1. 按一下下列按鈕,開啟「使用 Google Chat 回應事件」Apps Script 專案。
    開啟專案
  2. 按一下「總覽」
  3. 在總覽頁面中,按一下 建立副本的圖示「建立副本」
  4. 為複製的 Apps Script 專案命名:

    1. 按一下「Copy of Respond to incidents with Google Chat」(複製「使用 Google Chat 回報事件」)

    2. 在「Project title」(專案標題) 中輸入 Incident Management Chat app

    3. 按一下 [重新命名]

  5. 在您複製的 Apps Script 專案中,前往 Consts.gs 檔案,然後將 YOUR_PROJECT_ID 替換為 Cloud 專案的 ID。

設定 Apps Script 專案的 Cloud 專案

  1. 在 Apps Script 專案中,按一下 專案設定圖示「專案設定」
  2. 在「Google Cloud Platform (GCP) 專案」下方,按一下「變更專案」
  3. 在「GCP 專案編號」中,貼上 Cloud 專案的專案編號。
  4. 按一下「設定專案」。Cloud 專案和 Apps Script 專案現已連結。

建立 Apps Script 部署作業

所有程式碼都就位後,請部署 Apps Script 專案。在 Google Cloud 中設定 Chat 應用程式時,您會使用部署 ID。

  1. 在 Apps Script 中開啟事件回應應用程式的專案。

    前往 Apps Script

  2. 依序按一下「Deploy」(部署) >「New deployment」(新部署作業)

  3. 如果尚未選取「外掛程式」和「網頁應用程式」,請按一下「選取類型」旁的部署類型 專案設定圖示,然後選取「外掛程式」和「網頁應用程式」

  4. 在「說明」中,輸入這個版本的說明,例如 Complete version of incident management app

  5. 在「執行身分」中,選取「存取網路應用程式的使用者」

  6. 在「誰可以存取」中,選取「Workspace 機構中的任何人」,其中「Workspace 機構」是您的 Google Workspace 機構名稱。

  7. 按一下「Deploy」(部署)。Apps Script 會回報部署作業是否成功,並提供部署作業 ID 和事件初始化網頁的網址。

  8. 記下「Web app」網址,以便稍後啟動事件時造訪。 複製「部署作業 ID」。在 Google Cloud 控制台中設定 Chat 應用程式時,您會使用這個 ID。

  9. 按一下 [完成]。

在 Google Cloud 控制台中設定 Chat 應用程式

本節說明如何在 Google Cloud 控制台中設定 Google Chat API,並提供 Chat 應用程式的相關資訊,包括您剛從 Apps Script 專案建立的部署 ID。

  1. 在 Google Cloud 控制台中,依序點選「選單」 >「更多產品」 >「Google Workspace」 >「產品程式庫」 >「Google Chat API」 >「管理」 >「設定」

    前往 Chat API 設定

  2. 在「應用程式名稱」中輸入 Incident Management

  3. 在「Avatar URL」中輸入 https://developers.google.com/chat/images/quickstart-app-avatar.png

  4. 在「Description」(說明) 中輸入 Responds to incidents.

  5. 將「啟用互動功能」切換鈕設為開啟。

  6. 在「功能」下方,選取「加入聊天室和群組對話」

  7. 在「連線設定」下方,選取「Apps Script」

  8. 在「部署作業 ID」中,貼上您先前從 Apps Script 專案部署作業複製的 Apps Script 部署作業 ID。

  9. 註冊完全實作的 Chat 應用程式使用的斜線指令

    1. 在「斜線指令」下方,按一下「新增斜線指令」

    2. 在「Name」(名稱) 中輸入 Close incident

    3. 在「Command ID」(指令 ID) 中輸入 1

    4. 在「說明」中輸入 Closes the incident being discussed in the space.

    5. 在「指令類型」下方,選取「斜線指令」

    6. 在「斜線指令名稱」中輸入 /closeIncident

    7. 選取「開啟對話方塊」

    8. 按一下「完成」,斜線指令已註冊並列出。

  10. 在「瀏覽權限」下方,選取「將這個 Chat 擴充應用程式提供給『您的 Workspace 網域』中的特定使用者和群組」,然後輸入電子郵件地址。

  11. 在「記錄」下方,選取「將錯誤記錄至 Logging」

  12. 按一下 [儲存]。系統會顯示「已儲存設定」訊息,表示應用程式已可供測試。

測試 Chat 應用程式

如要測試事件管理 Chat 應用程式,請從網頁發起事件,並確認 Chat 應用程式運作正常:

  1. 前往 Apps Script 部署作業的網頁應用程式網址。

  2. 當 Apps Script 要求存取資料的權限時,請按一下「檢閱權限」,使用 Google Workspace 網域中適當的 Google 帳戶登入,然後按一下「允許」

  3. 系統會開啟事件初始化網頁。輸入測試資訊:

    1. 在「Incident title」(事件標題) 中,輸入 The First Incident
    2. 視需要輸入事件回應者的電子郵件地址 (位於「事件回應者」)。他們必須是 Google Workspace 機構中的 Google Chat 帳戶使用者,否則無法建立聊天室。請勿輸入自己的電子郵件地址,因為系統會自動加入。
    3. 在「初始訊息」中,輸入 Testing the incident management Chat app.
  4. 按一下「建立聊天室」。畫面上會顯示 creating space 訊息。

  5. 聊天室建立完成後,系統會顯示 Space created! 訊息。按一下「開啟聊天室」,系統會在新的分頁中開啟 Chat 聊天室。

  6. 你和其他事件回應人員可以視需要傳送訊息到該空間。這款應用程式會使用 Vertex AI 摘要這些訊息,並分享回顧文件。

  7. 如要結束事件回應並開始解決程序,請在即時通訊聊天室中輸入 /closeIncident。系統會開啟事件管理對話方塊。

  8. 在「關閉事件」中,輸入事件解決方式的說明, 例如 Test complete

  9. 按一下「Close Incident」(關閉事件)

事件管理應用程式會列出聊天室中的訊息、使用 Vertex AI 歸納訊息重點、將摘要貼到 Google 文件,並在聊天室中分享該文件。

清除所用資源

如要避免系統向您的 Google Cloud 帳戶收取本教學課程中所用資源的相關費用,建議您刪除 Cloud 專案。

  1. 在 Google Cloud 控制台中,前往「管理資源」頁面。依序點選「選單」「IAM 與管理」「管理資源」

    前往 Resource Manager

  2. 在專案清單中選取要刪除的專案,然後按一下「Delete」(刪除) 圖示
  3. 在對話方塊中輸入專案 ID,然後按一下「Shut down」(關閉) 即可刪除專案。