构建 HTTP Google Chat 应用

本页面介绍了如何使用 HTTP 服务构建可在 Google Chat 中运行的 Google Workspace 插件。

本快速入门介绍了如何使用 Google Cloud 服务构建 HTTP 服务。如需构建 Chat 应用,您需要编写并部署一个 Cloud Run 函数 ,Chat 应用会使用该函数来响应用户的消息。

借助 HTTP 架构,您可以配置 Chat 以使用 HTTP 与 Google Cloud 或本地服务器集成,如下图所示:

使用本地服务器中的 Web 服务的 Chat 应用的架构。

在上图中,与 HTTP Chat 应用互动的用户具有以下信息流:

  1. 用户通过私信或 Chat 聊天室向 Chat 应用发送消息。
  2. 系统会向 Web 服务器发送 HTTP 请求,该服务器可以是包含 Chat 应用逻辑的云端或本地系统。
  3. (可选)Chat 应用逻辑可以与 Google Workspace 服务(例如日历和表格)、其他 Google 服务(例如地图、YouTube 和 Vertex AI)或其他 Web 服务(例如项目管理系统或工单工具)集成。
  4. Web 服务器会将 HTTP 响应发送回 Chat 中的 Chat 应用服务。
  5. 响应会传递给用户。
  6. (可选)Chat 应用可以调用 Chat API 以异步发布消息或执行其他操作。

此架构具有灵活性,可使用系统中已有的库和组件,因为这些 Chat 应用可以使用不同的编程语言进行设计。

目标

  • 设置环境。
  • 创建和部署 Cloud Run 函数。
  • 为 Chat 应用配置 Google Workspace 插件。
  • 测试应用。

前提条件

设置环境

在使用 Google API 之前,您需要在 Google 云项目中启用它们。您可以在单个 Google Cloud 项目中启用一个或多个 API。
  • 在 Google Cloud 控制台中,启用 Cloud Build API、Cloud Functions API、 Cloud Pub/Sub API、Cloud Logging API、Artifact Registry API 和 Cloud Run API。

    启用 API

创建和部署 Cloud Run 函数

创建并部署一个 Cloud Run 函数,该函数会生成一个 Chat 卡片,其中包含发送者的显示名称和头像图片。当 Chat 应用收到消息时,它会运行该函数并使用该卡片进行响应。

如需为 Chat 应用创建和部署函数,请完成以下步骤:

Node.js

  1. 在 Google Cloud 控制台中,转到 Cloud Run 页面。

    转到 Cloud Run

    确保已选择 Chat 应用的项目。

  2. 点击编写函数

  3. 创建服务 页面上,设置函数:

    1. 服务名称 字段中,输入 addonchatapp
    2. 区域 列表中,选择一个区域。
    3. 运行时 列表中,选择最新版本的 Node.js。
    4. 身份验证 部分中,选择需要进行身份验证
    5. 点击创建,然后等待 Cloud Run 创建服务。 控制台会将您重定向到来源 标签页。
  4. 来源 标签页中:

    1. 入口点 中,删除默认文本并输入 avatarApp
    2. index.js 的内容替换为以下代码:
    node/chat/avatar-app/index.js
    import { http } from '@google-cloud/functions-framework';
    
    // The ID of the slash command "/about".
    // You must use the same ID in the Google Chat API configuration.
    const ABOUT_COMMAND_ID = 1;
    
    /**
     * Handle requests from Google Workspace add on
     *
     * @param {Object} req Request sent by Google Chat
     * @param {Object} res Response to be sent back to Google Chat
     */
    http('avatarApp', (req, res) => {
      const chatEvent = req.body.chat;
      let message;
      if (chatEvent.appCommandPayload) {
        message = handleAppCommand(chatEvent);
      } else {
        message = handleMessage(chatEvent);
      }
      res.send({ hostAppDataAction: { chatDataAction: { createMessageAction: {
        message: message
      }}}});
    });
    
    /**
     * Responds to an APP_COMMAND event in Google Chat.
     *
     * @param {Object} event the event object from Google Chat
     * @return the response message object.
     */
    function handleAppCommand(event) {
      switch (event.appCommandPayload.appCommandMetadata.appCommandId) {
        case ABOUT_COMMAND_ID:
          return {
            text: 'The Avatar app replies to Google Chat messages.'
          };
      }
    }
    
    /**
     * Responds to a MESSAGE event in Google Chat.
     *
     * @param {Object} event the event object from Google Chat
     * @return the response message object.
     */
    function handleMessage(event) {
      // Stores the Google Chat user as a variable.
      const chatUser = event.messagePayload.message.sender;
      const displayName = chatUser.displayName;
      const avatarUrl = chatUser.avatarUrl;
      return {
        text: 'Here\'s your avatar',
        cardsV2: [{
          cardId: 'avatarCard',
          card: {
            name: 'Avatar Card',
            header: {
              title: `Hello ${displayName}!`,
            },
            sections: [{ widgets: [{
              textParagraph: { text: 'Your avatar picture: ' }
            }, {
              image: { imageUrl: avatarUrl }
            }]}]
          }
        }]
      };
    }
    1. 点击保存并重新部署

Python

  1. 在 Google Cloud 控制台中,转到 Cloud Run 页面。

    转到 Cloud Run

    确保已选择 Chat 应用的项目。

  2. 点击编写函数

  3. 创建服务 页面上,设置函数:

    1. 服务名称 字段中,输入 addonchatapp
    2. 区域 列表中,选择一个区域。
    3. 运行时 列表中,选择最新版本的 Python。
    4. 身份验证 部分中,选择需要进行身份验证
    5. 点击创建,然后等待 Cloud Run 创建服务。 控制台会将您重定向到来源 标签页。
  4. 来源 标签页中:

    1. 入口点 中,删除默认文本并输入 avatar_app
    2. main.py 的内容替换为以下代码:
    python/chat/avatar-app/main.py
    from typing import Any, Mapping
    
    import flask
    import functions_framework
    
    # The ID of the slash command "/about".
    # You must use the same ID in the Google Chat API configuration.
    ABOUT_COMMAND_ID = 1
    
    @functions_framework.http
    def avatar_app(req: flask.Request) -> Mapping[str, Any]:
      """Handle requests from Google Workspace add on
    
      Args:
        flask.Request req: the request sent by Google Chat
    
      Returns:
        Mapping[str, Any]: the response to be sent back to Google Chat
      """
      chat_event = req.get_json(silent=True)["chat"]
      if chat_event and "appCommandPayload" in chat_event:
        message = handle_app_command(chat_event)
      else:
        message = handle_message(chat_event)
      return { "hostAppDataAction": { "chatDataAction": { "createMessageAction": {
          "message": message
      }}}}
    
    def handle_app_command(event: Mapping[str, Any]) -> Mapping[str, Any]:
      """Responds to an APP_COMMAND event in Google Chat.
    
      Args:
        Mapping[str, Any] event: the event object from Google Chat
    
      Returns:
        Mapping[str, Any]: the response message object.
      """
      if event["appCommandPayload"]["appCommandMetadata"]["appCommandId"] == ABOUT_COMMAND_ID:
        return {
          "text": "The Avatar app replies to Google Chat messages.",
        }
      return {}
    
    def handle_message(event: Mapping[str, Any]) -> Mapping[str, Any]:
      """Responds to a MESSAGE event in Google Chat.
    
      Args:
        Mapping[str, Any] event: the event object from Google Chat
    
      Returns:
        Mapping[str, Any]: the response message object.
      """
      # Stores the Google Chat user as a variable.
      chat_user = event["messagePayload"]["message"]["sender"]
      display_name = chat_user.get("displayName", "")
      avatar_url = chat_user.get("avatarUrl", "")
      return {
        "text": "Here's your avatar",
        "cardsV2": [{
          "cardId": "avatarCard",
          "card": {
            "name": "Avatar Card",
            "header": {
              "title": f"Hello {display_name}!"
            },
            "sections": [{ "widgets": [
              { "textParagraph": { "text": "Your avatar picture:" }},
              { "image": { "imageUrl": avatar_url }},
            ]}]
          }
        }]
      }
    1. 点击保存并重新部署

Java

  1. 在 Google Cloud 控制台中,转到 Cloud Run 页面。

    转到 Cloud Run

    确保已选择 Chat 应用的项目。

  2. 点击编写函数

  3. 创建服务 页面上,设置函数:

    1. 服务名称 字段中,输入 addonchatapp
    2. 区域 列表中,选择一个区域。
    3. 运行时 列表中,选择最新版本的 Java。
    4. 身份验证 部分中,选择需要进行身份验证
    5. 点击创建,然后等待 Cloud Run 创建服务。 控制台会将您重定向到来源 标签页。
  4. 来源 标签页中:

    1. 入口点 中,删除默认文本并输入 App
    2. 将默认 Java 文件重命名为 src/main/java/com/google/chat/avatar/App.java
    3. App.java 的内容替换为以下代码:
    java/chat/avatar-app/src/main/java/com/google/chat/avatar/App.java
    package com.google.chat.avatar;
    
    import com.google.api.services.chat.v1.model.CardWithId;
    import com.google.api.services.chat.v1.model.GoogleAppsCardV1Card;
    import com.google.api.services.chat.v1.model.GoogleAppsCardV1CardHeader;
    import com.google.api.services.chat.v1.model.GoogleAppsCardV1Image;
    import com.google.api.services.chat.v1.model.GoogleAppsCardV1Section;
    import com.google.api.services.chat.v1.model.GoogleAppsCardV1TextParagraph;
    import com.google.api.services.chat.v1.model.GoogleAppsCardV1Widget;
    import com.google.api.services.chat.v1.model.Message;
    import com.google.cloud.functions.HttpFunction;
    import com.google.cloud.functions.HttpRequest;
    import com.google.cloud.functions.HttpResponse;
    import com.google.gson.Gson;
    import com.google.gson.JsonObject;
    import java.util.List;
    
    public class App implements HttpFunction {
      // The ID of the slash command "/about".
      // You must use the same ID in the Google Chat API configuration.
      private static final int ABOUT_COMMAND_ID = 1;
    
      private static final Gson gson = new Gson();
    
      /**
       * Handle requests from Google Workspace add on
       * 
       * @param request the request sent by Google Chat
       * @param response the response to be sent back to Google Chat
       */
      @Override
      public void service(HttpRequest request, HttpResponse response) throws Exception {
        JsonObject event = gson.fromJson(request.getReader(), JsonObject.class);
        JsonObject chatEvent = event.getAsJsonObject("chat");
        Message message;
        if (chatEvent.has("appCommandPayload")) {
          message = handleAppCommand(chatEvent);
        } else {
          message = handleMessage(chatEvent);
        }
        JsonObject createMessageAction = new JsonObject();
        createMessageAction.add("message", gson.fromJson(gson.toJson(message), JsonObject.class));
        JsonObject chatDataAction = new JsonObject();
        chatDataAction.add("createMessageAction", createMessageAction);
        JsonObject hostAppDataAction = new JsonObject();
        hostAppDataAction.add("chatDataAction", chatDataAction);
        JsonObject dataActions = new JsonObject();
        dataActions.add("hostAppDataAction", hostAppDataAction);
        response.getWriter().write(gson.toJson(dataActions));
      }
    
      /**
       * Handles an APP_COMMAND event in Google Chat.
       *
       * @param event the event object from Google Chat
       * @return the response message object.
       */
      private Message handleAppCommand(JsonObject event) throws Exception {
        switch (event.getAsJsonObject("appCommandPayload")
          .getAsJsonObject("appCommandMetadata").get("appCommandId").getAsInt()) {
          case ABOUT_COMMAND_ID:
            return new Message()
              .setText("The Avatar app replies to Google Chat messages.");
          default:
            return null;
        }
      }
    
      /**
       * Handles a MESSAGE event in Google Chat.
       *
       * @param event the event object from Google Chat
       * @return the response message object.
       */
      private Message handleMessage(JsonObject event) throws Exception {
        // Stores the Google Chat user as a variable.
        JsonObject chatUser = event.getAsJsonObject("messagePayload").getAsJsonObject("message").getAsJsonObject("sender");
        String displayName = chatUser.has("displayName") ? chatUser.get("displayName").getAsString() : "";
        String avatarUrl = chatUser.has("avatarUrl") ? chatUser.get("avatarUrl").getAsString() : "";
        return new Message()
          .setText("Here's your avatar")
          .setCardsV2(List.of(new CardWithId()
            .setCardId("avatarCard")
            .setCard(new GoogleAppsCardV1Card()
              .setName("Avatar Card")
              .setHeader(new GoogleAppsCardV1CardHeader()
                .setTitle(String.format("Hello %s!", displayName)))
              .setSections(List.of(new GoogleAppsCardV1Section().setWidgets(List.of(
                new GoogleAppsCardV1Widget().setTextParagraph(new GoogleAppsCardV1TextParagraph()
                  .setText("Your avatar picture:")),
                new GoogleAppsCardV1Widget()
                  .setImage(new GoogleAppsCardV1Image().setImageUrl(avatarUrl)))))))));
      }
    }
  5. pom.xml 的内容替换为以下代码:

    java/chat/avatar-app/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</groupId>
      <artifactId>avatar-app</artifactId>
      <version>1.0-SNAPSHOT</version>
    
      <properties>
        <maven.compiler.target>17</maven.compiler.target>
        <maven.compiler.source>17</maven.compiler.source>
      </properties>
    
      <dependencies>
        <dependency>
          <groupId>com.google.cloud.functions</groupId>
          <artifactId>functions-framework-api</artifactId>
          <version>1.1.4</version>
        </dependency>
        <dependency>
          <groupId>com.google.code.gson</groupId>
          <artifactId>gson</artifactId>
          <version>2.9.1</version>
        </dependency>
        <dependency>
          <groupId>com.google.apis</groupId>
          <artifactId>google-api-services-chat</artifactId>
          <version>v1-rev20230115-2.0.0</version>
        </dependency>
      </dependencies>
    
      <build>
        <plugins>
          <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.8.1</version>
            <configuration>
            <excludes>
              <exclude>.google/</exclude>
            </excludes>
            </configuration>
          </plugin>
        </plugins>
      </build>
    </project>
    1. 点击保存并重新部署

Cloud Run 服务详情页面随即打开。等待函数部署完毕。

配置插件

部署 Cloud Run 函数后,请按照以下步骤创建插件并部署 Google Chat 应用:

  1. 在 Google Cloud 控制台中,转到 Cloud Run 页面。

    转到 Cloud Run

    确保已选择您为其启用了 Cloud Run 的项目 。

  2. 在函数列表中,点击 addonchatapp

  3. 服务详情 页面上,复制该函数的 网址 。该网址以 run.app 结尾。

  4. 在 Google Cloud 搜索字段中,搜索“Google Chat API”,然后 依次点击 Google Chat API管理

    前往 Chat API

  5. 点击配置并设置 Google Chat 应用:

    1. 应用名称中,输入 Add-on Chat app
    2. 头像网址中,输入 https://developers.google.com/workspace/add-ons/images/quickstart-app-avatar.png
    3. 说明 中,输入 Add-on Chat app
    4. 功能 下,选择加入聊天室和群组对话
    5. 连接设置 下,选择 HTTP 端点网址
    6. 触发器下,选择为所有 触发器使用通用 HTTP 端点网址,然后将 Cloud Run 函数触发器的网址粘贴到 框中。
    7. 公开范围下,选择 面向您网域中的特定人员和 群组提供此 Google Chat 应用,然后输入您的电子邮件地址。
    8. 日志 下,选择将错误记录到 Logging
  6. 点击保存

  7. 连接设置 下,复制服务账号电子邮件地址 。在授权插件调用函数时,您需要此电子邮件地址。

接下来,授权 Chat 应用调用 Cloud Run 函数。

授权 Google Chat 调用函数

如需授权 Google Workspace 插件调用函数,请添加具有 Cloud Run Service Invoker 角色的 Google Workspace 插件服务账号。

  1. 在 Google Cloud 控制台中,转到 Cloud Run 页面。

    转到 Cloud Run

  2. 在 Cloud Run 服务列表中,选中接收 函数旁边的复选框。(请勿点击函数本身。)

  3. 点击权限权限 面板随即打开。

  4. 点击添加主账号

  5. 新主账号中,输入与 Chat 应用关联的 Google Workspace 插件服务账号的电子邮件地址。

    服务账号电子邮件地址位于 Chat API 配置页面的连接设置 > HTTP 端点网址 > 服务账号电子邮件地址 下:

    前往 Chat API 配置

  6. 选择角色 中,选择 Cloud Run > Cloud Run Invoker

  7. 点击保存

Chat 应用已准备好接收和回复 Chat 上的消息。

测试 Chat 应用

如需测试 Chat 应用,请打开与 Chat 应用的私信对话,然后发送消息:

  1. 使用您在将自己添加为可信测试人员时提供的 Google Workspace 账号打开 Google Chat。

    前往 Google Chat

  2. 点击 发起新聊天
  3. 添加 1 位或多位用户 字段中,输入 Chat 应用的名称。
  4. 从结果中选择 Chat 应用。系统会打开私信对话。

  5. 在与该应用的新私信对话中,输入 Hello,然后按 enter

Chat 应用的 消息包含一个卡片,其中显示了 发送者的姓名和头像图片,如下图所示:

聊天应用以卡片形式回复,其中包含发送者的显示名称和头像图片

如需添加可信测试人员并详细了解如何测试互动功能,请参阅 测试 Google Chat 应用的互动功能

问题排查

当 Google Chat 应用或 卡片返回错误时, Chat 界面会显示“出了点问题。” 或“无法处理您的请求。”有时,Chat 界面不会显示任何错误消息,但 Chat 应用或卡片会产生意外结果;例如,卡片消息可能不会显示。

虽然 Chat 界面中可能不会显示错误消息, 但如果启用了 Chat 应用的错误日志记录功能,您可以使用描述性错误消息和日志数据来帮助您修复错误 。如需查看、 调试和修复错误方面的帮助,请参阅 排查和修复 Google Chat 错误

清理

为避免因本教程中使用的资源而向您的 Google Cloud 账号收取费用,我们建议您删除云项目。

  1. 在 Google Cloud 控制台中,前往管理资源 页面。依次点击 菜单 > IAM 和管理 > 管理资源

    转到 Resource Manager

  2. 在项目列表中,选择要删除的项目,然后点击 删除 .
  3. 在对话框中输入项目 ID,然后点击关停 以删除 项目。