建構使用 Pub/Sub 的 Google Chat 應用程式

本頁面說明如何建立 Chat 應用程式,透過 Cloud Pub/Sub 接收 Chat 的事件。如果您的 Chat 應用程式位於防火牆後方,或是想透過 Google Workspace Events API 傳送或接收有關 Chat 聊天室或使用者的事件,這個架構就非常實用。

下圖顯示以 Pub/Sub 建構的即時通訊應用程式架構:

使用 Pub/Sub 實作的 Chat 應用程式架構。

在上圖中,使用者與 Pub/Sub Chat 應用程式互動時,資訊流程如下:

  1. 使用者與 Chat 應用程式互動,例如傳送訊息、發出指令,或在 Chat 聊天室中新增/移除應用程式。

  2. Chat 會將訊息傳送至 Pub/Sub 主題。

  3. 應用程式伺服器 (即包含 Chat 應用程式邏輯的雲端或地端系統) 會訂閱 Pub/Sub 主題,以便透過防火牆接收訊息。

  4. Chat 應用程式可以選擇呼叫 Chat API,以非同步方式發布訊息或執行其他作業。

必要條件

Node.js

Python

Java

啟用 API

使用 Google API 前,您需要在 Google Cloud 專案中啟用這些 API。 您可以在單一 Google Cloud 專案中啟用一或多個 API。
  • 在 Google Cloud 控制台中,啟用 Google Chat API 和 Pub/Sub API。

    啟用 API

設定 Pub/Sub

  1. 建立 Pub/Sub 主題,供 Chat API 傳送訊息。建議每個 Chat 應用程式使用單一主題。

  2. 建立服務帳戶,供 Chat 應用程式向 Pub/Sub 和 Chat 授權,並將私密金鑰檔案儲存至工作目錄。

  3. 建立主題的提取訂閱項目

  4. 在訂閱項目中,為先前建立的服務帳戶指派 Pub/Sub 訂閱者角色

編寫指令碼

在本節中,您將定義 Chat 應用程式的應用程式邏輯,並編寫指令碼,向 Google Cloud 進行驗證,然後訂閱 Pub/Sub 主題,接收來自 Chat 的事件,例如使用者傳送訊息給 Chat 應用程式時。

指令碼收到訊息時,會處理事件資料,並使用 Google Chat API 將回覆傳送給使用者或聊天室。完成這項設定後,您的 Chat 應用程式就能在防火牆後方運作,同時與 Chat 使用者互動。

Node.js

  1. 在 CLI 中提供服務帳戶憑證

    export GOOGLE_APPLICATION_CREDENTIALS=SERVICE_ACCOUNT_FILE_PATH
    
  2. 在 CLI 中,提供 Google Cloud 專案 ID:

    export PROJECT_ID=PROJECT_ID
    
  3. 在 CLI 中,提供您先前建立的 Pub/Sub 訂閱項目 ID:

    export SUBSCRIPTION_ID=SUBSCRIPTION_ID
    
  4. 在工作目錄中,建立名為 package.json 的檔案。

  5. package.json 檔案中貼上下列程式碼:

    {
      "name": "pub-sub-app",
      "version": "1.0.0",
      "description": "Google Chat App that listens for messages via Cloud Pub/Sub",
      "main": "index.js",
      "scripts": {
        "start": "node index.js",
        "test": "echo \"Error: no test specified\" && exit 1"
      },
      "dependencies": {
        "@google-apps/chat": "^0.4.0",
        "@google-cloud/pubsub": "^4.5.0"
      },
      "license": "Apache-2.0"
    }
    
  6. 在工作目錄中,建立名為 index.js 的檔案。

  7. index.js 中貼上下列程式碼:

    const {ChatServiceClient} = require('@google-apps/chat');
    const {MessageReplyOption} = require('@google-apps/chat').protos.google.chat.v1.CreateMessageRequest;
    const {PubSub} = require('@google-cloud/pubsub');
    const {SubscriberClient} = require('@google-cloud/pubsub/build/src/v1');
    
    // Receives messages from a pull subscription.
    function receiveMessages() {
      const chat = new ChatServiceClient({
        keyFile: process.env.GOOGLE_APPLICATION_CREDENTIALS,
        scopes: ['https://www.googleapis.com/auth/chat.bot'],
      });
    
      const subscriptionPath = new SubscriberClient()
        .subscriptionPath(process.env.PROJECT_ID, process.env.SUBSCRIPTION_ID)
      const subscription = new PubSub()
        .subscription(subscriptionPath);
    
      // Handle incoming message, then acknowledge the received message
      const messageHandler = message => {
        console.log(`Id : ${message.id}`);
        const event = JSON.parse(message.data);
        console.log(`Data : ${JSON.stringify(event)}`);
    
        // Post the response to Google Chat.
        const request = formatRequest(event);
        if (request != null) {
          chat.createMessage(request);
        }
    
        // Acknowledge the message.
        message.ack();
      }
    
      subscription.on('message', messageHandler);
      console.log(`Listening for messages on ${subscriptionPath}`);
    
      // Keep main thread from exiting while waiting for messages
      setTimeout(() => {
        subscription.removeListener('message', messageHandler);
        console.log(`Stopped listening for messages.`);
      }, 60 * 1000);
    }
    
    // Send message to Google Chat based on the type of event
    function formatRequest(event) {
      const chatEvent = event.chat || {};
    
      // If the app was removed, we don't respond.
      if (chatEvent.removedFromSpacePayload) {
        console.log(`App removed from space.`);
        return null;
      }
    
      const payload = chatEvent.messagePayload || chatEvent.addedToSpacePayload;
      const spaceName = payload?.space?.name;
    
      if (!spaceName) {
        console.log('No space name in event.');
        return null;
      }
    
      if (chatEvent.addedToSpacePayload) {
        // An app can also be added to a space by @mentioning it in a
        // message. In that case, we fall through to the message case
        // and let the app respond. If the app was added using the
        // invite flow, we just post a thank you message in the space.
        return {
          parent: spaceName,
          message: { text: 'Thank you for adding me!' },
        };
      } else if (chatEvent.messagePayload) {
        // In case of message, post the response in the same thread.
        const message = chatEvent.messagePayload.message;
        return {
          parent: spaceName,
          messageReplyOption: MessageReplyOption.REPLY_MESSAGE_FALLBACK_TO_NEW_THREAD,
          message: {
            text: 'You said: `' + message.text + '`',
            thread: { name: message.thread.name },
          },
        };
      }
    }
    
    if (!process.env.PROJECT_ID) {
      console.log('Missing PROJECT_ID env var.');
      process.exit(1);
    }
    if (!process.env.SUBSCRIPTION_ID) {
      console.log('Missing SUBSCRIPTION_ID env var.');
      process.exit(1);
    }
    if (!process.env.GOOGLE_APPLICATION_CREDENTIALS) {
      console.log('Missing GOOGLE_APPLICATION_CREDENTIALS env var.');
      process.exit(1);
    }
    
    receiveMessages();
    

Python

  1. 在 CLI 中提供服務帳戶憑證

    export GOOGLE_APPLICATION_CREDENTIALS=SERVICE_ACCOUNT_FILE_PATH
    
  2. 在 CLI 中,提供 Google Cloud 專案 ID:

    export PROJECT_ID=PROJECT_ID
    
  3. 在 CLI 中,提供您先前建立的 Pub/Sub 訂閱項目 ID:

    export SUBSCRIPTION_ID=SUBSCRIPTION_ID
    
  4. 在工作目錄中,建立名為 requirements.txt 的檔案。

  5. requirements.txt 檔案中貼上下列程式碼:

    google-cloud-pubsub>=2.23.0
    google-apps-chat==0.1.9
    
  6. 在工作目錄中,建立名為 app.py 的檔案。

  7. app.py 中貼上下列程式碼:

    import json
    import logging
    import os
    import sys
    import time
    from google.apps import chat_v1 as google_chat
    from google.cloud import pubsub_v1
    from google.oauth2.service_account import Credentials
    
    def receive_messages():
      """Receives messages from a pull subscription."""
    
      scopes = ['https://www.googleapis.com/auth/chat.bot']
      service_account_key_path = os.environ.get('GOOGLE_APPLICATION_CREDENTIALS')
      creds = Credentials.from_service_account_file(service_account_key_path)
      chat = google_chat.ChatServiceClient(
          credentials=creds, client_options={'scopes': scopes}
      )
    
      project_id = os.environ.get('PROJECT_ID')
      subscription_id = os.environ.get('SUBSCRIPTION_ID')
      subscriber = pubsub_v1.SubscriberClient()
      subscription_path = subscriber.subscription_path(project_id, subscription_id)
    
      # Handle incoming message, then acknowledge the received message
      def callback(message):
        event = json.loads(message.data)
        logging.info('Data : %s', event)
    
        # Post the response to Google Chat.
        request = format_request(event)
        if request is not None:
          chat.create_message(request)
    
        # Acknowledge the message.
        message.ack()
    
      subscriber.subscribe(subscription_path, callback = callback)
      logging.info('Listening for messages on %s', subscription_path)
    
      # Keep main thread from exiting while waiting for messages
      while True:
        time.sleep(60)
    
    def format_request(event):
      """Send message to Google Chat based on the type of event.
      Args:
        event: A dictionary with the event data.
      """
      chat_event = event.get('chat', {})
    
      # If the app was removed, we don't respond.
      if 'removedFromSpacePayload' in chat_event:
        logging.info('App removed from space.')
        return
    
      payload = chat_event.get('messagePayload') or chat_event.get(
          'addedToSpacePayload'
      )
      space_name = payload.get('space', {}).get('name') if payload else None
    
      if not space_name:
        logging.warning('No space name in event.')
        return
    
      if 'addedToSpacePayload' in chat_event:
        # An app can also be added to a space by @mentioning it in a
        # message. In that case, we fall through to the message case
        # and let the app respond. If the app was added using the
        # invite flow, we just post a thank you message in the space.
        return google_chat.CreateMessageRequest(
            parent = space_name,
            message = {
              'text': 'Thank you for adding me!'
            }
        )
      elif 'messagePayload' in chat_event:
        # In case of message, post the response in the same thread.
        message = chat_event['messagePayload']['message']
        return google_chat.CreateMessageRequest(
            parent = space_name,
            message_reply_option = google_chat.CreateMessageRequest.MessageReplyOption.REPLY_MESSAGE_FALLBACK_TO_NEW_THREAD,
            message = {
              'text': 'You said: `' + message['text'] + '`',
              'thread': {
                'name': message['thread']['name']
              }
            }
        )
    
    if __name__ == '__main__':
      if 'PROJECT_ID' not in os.environ:
        logging.error('Missing PROJECT_ID env var.')
        sys.exit(1)
    
      if 'SUBSCRIPTION_ID' not in os.environ:
        logging.error('Missing SUBSCRIPTION_ID env var.')
        sys.exit(1)
    
      if 'GOOGLE_APPLICATION_CREDENTIALS' not in os.environ:
        logging.error('Missing GOOGLE_APPLICATION_CREDENTIALS env var.')
        sys.exit(1)
    
      logging.basicConfig(
          level=logging.INFO,
          style='{',
          format='{levelname:.1}{asctime} {filename}:{lineno}] {message}')
      receive_messages()
    

Java

  1. 在 CLI 中提供服務帳戶憑證

    export GOOGLE_APPLICATION_CREDENTIALS=SERVICE_ACCOUNT_FILE_PATH
    
  2. 在 CLI 中,提供 Google Cloud 專案 ID:

    export PROJECT_ID=PROJECT_ID
    
  3. 在 CLI 中,提供您先前建立的 Pub/Sub 訂閱項目 ID:

    export SUBSCRIPTION_ID=SUBSCRIPTION_ID
    
  4. 在工作目錄中,建立名為 pom.xml 的檔案。

  5. pom.xml 檔案中貼上下列程式碼:

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
     <modelVersion>4.0.0</modelVersion>
    
     <groupId>com.google.chat.addon</groupId>
     <artifactId>pubsub-addon-chat-app</artifactId>
     <version>0.1.0</version>
    
     <name>pubsub-addon-chat-app-java</name>
    
     <properties>
       <maven.compiler.release>11</maven.compiler.release>
       <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
     </properties>
    
     <dependencyManagement>
       <dependencies>
         <dependency>
           <groupId>com.google.cloud</groupId>
           <artifactId>libraries-bom</artifactId>
           <version>26.41.0</version> <!-- Use a recent BOM version -->
           <type>pom</type>
           <scope>import</scope>
         </dependency>
       </dependencies>
     </dependencyManagement>
    
     <dependencies>
       <!-- Google Chat GAPIC library -->
       <dependency>
         <groupId>com.google.cloud</groupId>
         <artifactId>google-cloud-chat</artifactId>
       </dependency>
       <!-- Google Cloud Pub/Sub library -->
       <dependency>
         <groupId>com.google.cloud</groupId>
         <artifactId>google-cloud-pubsub</artifactId>
       </dependency>
       <!-- Google Apps Add-ons Event Object -->
       <dependency>
         <groupId>com.google.apps.addons.v1</groupId>
         <artifactId>google-apps-addons-v1-java</artifactId>
         <version>0.2.0</version> <!-- Check for latest version -->
       </dependency>
       <!-- Protobuf JSON utility -->
       <dependency>
         <groupId>com.google.protobuf</groupId>
         <artifactId>protobuf-java-util</artifactId>
       </dependency>
       <!-- Google Auth Library -->
       <dependency>
         <groupId>com.google.auth</groupId>
         <artifactId>google-auth-library-oauth2-http</artifactId>
       </dependency>
       <dependency>
         <groupId>com.google.api</groupId>
         <artifactId>gax</artifactId>
       </dependency>
       <!-- JSON utilities for PubSub message (if needed, though protobuf-java-util is primary for EventObject) -->
       <dependency>
         <groupId>com.fasterxml.jackson.core</groupId>
         <artifactId>jackson-databind</artifactId>
         <version>2.14.2</version>
       </dependency>
       <dependency>
         <groupId>org.slf4j</groupId>
         <artifactId>slf4j-jdk14</artifactId>
         <version>1.7.36</version>
         <scope>runtime</scope>
       </dependency>
     </dependencies>
    
     <build>
       <plugins>
         <plugin>
           <groupId>org.apache.maven.plugins</groupId>
           <artifactId>maven-compiler-plugin</artifactId>
           <version>3.13.0</version>
           <configuration>
             <source>11</source>
             <target>11</target>
           </configuration>
         </plugin>
         <plugin>
           <groupId>org.codehaus.mojo</groupId>
           <artifactId>exec-maven-plugin</artifactId>
           <version>3.3.0</version>
           <configuration>
             <mainClass>Main</mainClass>
           </configuration>
         </plugin>
       </plugins>
     </build>
    </project>
    
  6. 在工作目錄中,建立 src/main/java 目錄結構。

  7. src/main/java 目錄中,建立名為 Main.java 的檔案。

  8. Main.java 中貼上下列程式碼:

    import com.fasterxml.jackson.databind.JsonNode;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import com.google.api.gax.core.FixedCredentialsProvider;
    import com.google.auth.oauth2.GoogleCredentials;
    import com.google.chat.v1.ChatServiceClient;
    import com.google.chat.v1.ChatServiceSettings;
    import com.google.chat.v1.CreateMessageRequest;
    import com.google.chat.v1.CreateMessageRequest.MessageReplyOption;
    import com.google.chat.v1.Message;
    import com.google.chat.v1.Thread;
    import com.google.cloud.pubsub.v1.AckReplyConsumer;
    import com.google.cloud.pubsub.v1.MessageReceiver;
    import com.google.cloud.pubsub.v1.Subscriber;
    import com.google.pubsub.v1.ProjectSubscriptionName;
    import com.google.pubsub.v1.PubsubMessage;
    import java.io.FileInputStream;
    import java.util.Collections;
    
    public class Main {
    
      public static final String PROJECT_ID_ENV_PROPERTY = "PROJECT_ID";
      public static final String SUBSCRIPTION_ID_ENV_PROPERTY = "SUBSCRIPTION_ID";
      public static final String CREDENTIALS_PATH_ENV_PROPERTY = "GOOGLE_APPLICATION_CREDENTIALS";
    
      public static void main(String[] args) throws Exception {
        ProjectSubscriptionName subscriptionName =
            ProjectSubscriptionName.of(
                System.getenv(Main.PROJECT_ID_ENV_PROPERTY),
                System.getenv(Main.SUBSCRIPTION_ID_ENV_PROPERTY));
    
        // Instantiate app, which implements an asynchronous message receiver.
        EchoApp echoApp = new EchoApp();
    
        // Create a subscriber for <var>SUBSCRIPTION_ID</var> bound to the message receiver
        final Subscriber subscriber = Subscriber.newBuilder(subscriptionName, echoApp).build();
        System.out.println("Subscriber is listening to events...");
        subscriber.startAsync();
    
        // Wait for termination
        subscriber.awaitTerminated();
      }
    }
    
    /**
     * A demo app which implements {@link MessageReceiver} to receive messages.
     * It echoes incoming messages.
     */
    class EchoApp implements MessageReceiver {
    
      // Path to the private key JSON file of the service account to be used for posting response
      // messages to Google Chat.
      // In this demo, we are using the same service account for authorizing with Cloud Pub/Sub to
      // receive messages and authorizing with Google Chat to post messages. If you are using
      // different service accounts, set the path to the private key JSON file of the service
      // account used to post messages to Google Chat here.
      private static final String SERVICE_ACCOUNT_KEY_PATH =
        System.getenv(Main.CREDENTIALS_PATH_ENV_PROPERTY);
    
      // Developer code for Google Chat API scope.
      private static final String GOOGLE_CHAT_API_SCOPE = "https://www.googleapis.com/auth/chat.bot";
    
      private static final String ADDED_RESPONSE = "Thank you for adding me!";
    
      ChatServiceClient chatServiceClient;
    
      EchoApp() throws Exception {
        GoogleCredentials credential =
            GoogleCredentials.fromStream(new FileInputStream(SERVICE_ACCOUNT_KEY_PATH))
                .createScoped(Collections.singleton(GOOGLE_CHAT_API_SCOPE));
    
        // Create the ChatServiceSettings with the app credentials
        ChatServiceSettings chatServiceSettings =
            ChatServiceSettings.newBuilder()
                .setCredentialsProvider(FixedCredentialsProvider.create(credential))
                .build();
    
        // Set the Chat service client
        chatServiceClient = ChatServiceClient.create(chatServiceSettings);
      }
    
      // Called when a message is received by the subscriber.
      @Override
      public void receiveMessage(PubsubMessage pubsubMessage, AckReplyConsumer consumer) {
        System.out.println("Id : " + pubsubMessage.getMessageId());
        // Handle incoming message, then acknowledge the received message
        try {
          ObjectMapper mapper = new ObjectMapper();
          JsonNode dataJson = mapper.readTree(pubsubMessage.getData().toStringUtf8());
          System.out.println("Data : " + dataJson.toString());
          handle(dataJson);
          consumer.ack();
        } catch (Exception e) {
          System.out.println(e);
          // Negative acknowledgement makes Pub/Sub redeliver the message.
          consumer.nack();
        }
      }
    
      // Send message to Google Chat based on the type of event.
      public void handle(JsonNode eventJson) throws Exception {
        // Google Chat events for add-ons are wrapped in a 'chat' object.
        if (!eventJson.has("chat")) {
          System.out.println("Ignored: Not a Chat event (missing 'chat' field).");
          return;
        }
    
        JsonNode chatNode = eventJson.get("chat");
        CreateMessageRequest createMessageRequest = null;
    
        if (chatNode.has("messagePayload")) {
          // HANDLE MESSAGE
          JsonNode messagePayload = chatNode.get("messagePayload");
          JsonNode message = messagePayload.get("message");
          JsonNode space = messagePayload.get("space");
    
          String spaceName = space.get("name").asText();
          String userText = message.has("text") ? message.get("text").asText() : "";
          String threadName = message.has("thread") ? message.get("thread").get("name").asText() : "";
    
          System.out.println("Received message in " + spaceName + ": " + userText);
    
          createMessageRequest =
              CreateMessageRequest.newBuilder()
                  .setParent(spaceName)
                  .setMessageReplyOption(MessageReplyOption.REPLY_MESSAGE_FALLBACK_TO_NEW_THREAD)
                  .setMessage(
                      Message.newBuilder()
                          .setText("You said: `" + userText + "`")
                          .setThread(Thread.newBuilder().setName(threadName).build())
                          .build())
                  .build();
    
        } else if (chatNode.has("addedToSpacePayload")) {
          // HANDLE ADDED TO SPACE
          JsonNode addedPayload = chatNode.get("addedToSpacePayload");
          JsonNode space = addedPayload.get("space");
          String spaceName = space.get("name").asText();
    
          System.out.println("Added to space: " + spaceName);
    
          createMessageRequest =
              CreateMessageRequest.newBuilder()
                  .setParent(spaceName)
                  .setMessage(Message.newBuilder().setText(ADDED_RESPONSE).build())
                  .build();
    
        } else if (chatNode.has("removedFromSpacePayload")) {
          System.out.println("Removed from space.");
          return;
        } else {
          System.out.println("Ignored: Unhandled Chat event type.");
          return;
        }
    
        if (createMessageRequest != null) {
          // Post the response to Google Chat.
          chatServiceClient.createMessage(createMessageRequest);
          System.out.println("Sent reply.");
        }
      }
    }
    

設定 Chat 應用程式

在 Google Cloud 控制台中設定 Chat 應用程式,提供名稱和虛擬人偶等詳細資料,並設定與 Pub/Sub 主題的連線。

連結至 Pub/Sub 主題後,Chat 就能將事件傳送至應用程式。訂閱該主題的指令碼隨後會收到這些事件,並回應使用者。

  1. 在 Google Cloud 控制台中,依序前往「選單」 「>」「API 和服務」 「>」「已啟用的 API 和服務」 「>」「Google Chat API」 「>」「設定」

    前往 Chat API 設定

  2. 設定 Chat 應用程式的 Pub/Sub:

    1. 在「應用程式名稱」中輸入 Add-on Chat App
    2. 在「Avatar URL」中輸入 https://developers.google.com/workspace/add-ons/images/quickstart-app-avatar.png
    3. 在「Description」(說明) 中輸入 Quickstart app
    4. 在「功能」下方,選取「加入聊天室和群組對話」
    5. 在「連線設定」下方,選取「Cloud Pub/Sub」,然後貼上先前建立的 Pub/Sub 主題名稱。
    6. 在「顯示設定」下方,選取「將這個 Google Chat 擴充應用程式提供給網域中的特定使用者和群組」,然後輸入電子郵件地址。
    7. 在「記錄」下方,選取「將錯誤記錄至 Logging」
  3. 按一下 [儲存]

設定 Chat 應用程式後,您必須更新 Pub/Sub 設定。

  1. Chat API 設定頁面的「連線設定」下方,複製「服務帳戶電子郵件」,這是為 Google Cloud 專案產生的專屬電子郵件。
  2. 授予 Chat 發布至主題的權限:將「Pub/Sub 發布者」角色指派給您先前複製的服務帳戶電子郵件地址。

應用程式已準備好接收及回覆 Chat 訊息。

執行指令碼

在 CLI 中,切換至工作目錄並執行指令碼:

Node.js

npm install
npm start

Python

python -m venv env
source env/bin/activate
pip install -r requirements.txt -U
python app.py

Java

mvn compile exec:java -Dexec.mainClass=Main

執行程式碼時,應用程式會開始監聽發布至 Pub/Sub 主題的訊息。

測試 Chat 應用程式

如要測試 Chat 應用程式,請開啟與該應用程式互傳的即時訊息,然後傳送訊息:

  1. 使用您在新增自己為信任測試人員時提供的 Google Workspace 帳戶,開啟 Google Chat。

    前往 Google Chat

  2. 按一下 「發起新即時通訊」
  3. 在「新增 1 位以上使用者」欄位中,輸入 Chat 應用程式的名稱。
  4. 從結果中選取 Chat 應用程式。系統會開啟即時訊息。

  5. 在與應用程式互傳的新即時訊息中,輸入 Hello 並按下 enter

如要新增信任的測試人員,並進一步瞭解如何測試互動式功能,請參閱「測試 Google Chat 應用程式的互動式功能」。

疑難排解

如果 Google Chat 應用程式或資訊卡傳回錯誤,Chat 介面會顯示「發生錯誤」訊息。或「無法處理您的要求。」有時 Chat UI 不會顯示任何錯誤訊息,但 Chat 應用程式或資訊卡會產生非預期的結果,例如資訊卡訊息可能不會顯示。

即使 Chat 使用者介面未顯示錯誤訊息,只要開啟 Chat 應用程式的錯誤記錄功能,系統就會提供說明性錯誤訊息和記錄資料,協助您修正錯誤。如需查看、偵錯及修正錯誤的相關協助,請參閱「排解及修正 Google Chat 錯誤」。

清除所用資源

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

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

    前往 Resource Manager

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