使用 Cloud Functions 构建 HTTP Google Chat 应用

本页介绍如何创建 HTTP 聊天应用。您可以通过多种方式实现此架构。在 Google Cloud 上,您可以使用 Cloud Functions、Cloud Run 和 App Engine。在本快速入门中,您将编写和部署一个 Cloud Functions 函数,供 Chat 应用用于回复用户的消息。

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

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

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

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

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

目标

  • 设置环境。
  • 创建和部署 Cloud Functions 函数。
  • 将应用发布到 Chat。
  • 测试应用。

前提条件

  • 在 Google Workspace 组织中有权访问 Google ChatGoogle Workspace 帐号,并且允许未经身份验证的 Google Cloud Functions 函数调用。

设置环境

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

    启用 API

创建和部署 Cloud Functions 函数

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

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

Node.js

  1. 在 Google Cloud 控制台中,转到 Cloud Functions 页面:

    转到 Cloud Functions

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

  2. 点击 创建函数

  3. 在“创建函数”页面上,设置您的函数:

    1. 环境中,选择第 2 代
    2. 函数名称中,输入 QuickStartChatApp
    3. 区域中,选择一个区域。
    4. 在“身份验证”下,选择允许未通过身份验证的调用
    5. 点击下一步
  4. 运行时中,选择 Node.js 20

  5. 源代码中,选择內嵌编辑器

  6. 入口点中,删除默认文本,然后输入 helloChat

  7. index.js 的内容替换为以下代码:

    node/avatar-app/index.js
    /**
     * Google Cloud Function that responds to messages sent from a
     * Google Chat room.
     *
     * @param {Object} req Request sent from Google Chat room
     * @param {Object} res Response to send back
     */
    exports.helloChat = function helloChat(req, res) {
      if (req.method === 'GET' || !req.body.message) {
        res.send('Hello! This function is meant to be used in a Google Chat ' +
          'Room.');
      }
    
      const sender = req.body.message.sender.displayName;
      const image = req.body.message.sender.avatarUrl;
    
      const data = createMessage(sender, image);
    
      res.send(data);
    };
    
    /**
     * Creates a card with two widgets.
     * @param {string} displayName the sender's display name
     * @param {string} imageUrl the URL for the sender's avatar
     * @return {Object} a card with the user's avatar.
     */
    function createMessage(displayName, imageUrl) {
      const cardHeader = {
        title: `Hello ${displayName}!`,
      };
    
      const avatarWidget = {
        textParagraph: {text: 'Your avatar picture: '},
      };
    
      const avatarImageWidget = {
        image: {imageUrl},
      };
    
      const avatarSection = {
        widgets: [
          avatarWidget,
          avatarImageWidget,
        ],
      };
    
      return {
        text: 'Here\'s your avatar',
        cardsV2: [{
          cardId: 'avatarCard',
          card: {
            name: 'Avatar Card',
            header: cardHeader,
            sections: [avatarSection],
          }
        }],
      };
    }

  8. 点击部署

Python

  1. 在 Google Cloud 控制台中,转到 Cloud Functions 页面:

    转到 Cloud Functions

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

  2. 点击 创建函数

  3. 在“创建函数”页面上,设置您的函数:

    1. 函数名称中,输入 QuickStartChatApp
    2. 触发器类型中,选择 HTTP
    3. 在“身份验证”下,选择允许未通过身份验证的调用
    4. 点击保存
    5. 点击下一步
  4. 运行时中,选择 Python 3.10

  5. 源代码中,选择內嵌编辑器

  6. 入口点中,删除默认文本,然后输入 hello_chat

  7. main.py 的内容替换为以下代码:

    python/avatar-app/main.py
    from typing import Any, Mapping
    
    import flask
    import functions_framework
    
    
    # Google Cloud Function that responds to messages sent in
    # Google Chat.
    #
    # @param {Object} req Request sent from Google Chat.
    # @param {Object} res Response to send back.
    @functions_framework.http
    def hello_chat(req: flask.Request) -> Mapping[str, Any]:
      if req.method == "GET":
        return "Hello! This function must be called from Google Chat."
    
      request_json = req.get_json(silent=True)
    
      display_name = request_json["message"]["sender"]["displayName"]
      avatar = request_json["message"]["sender"]["avatarUrl"]
    
      response = create_message(name=display_name, image_url=avatar)
    
      return response
    
    
    # Creates a card with two widgets.
    # @param {string} name the sender's display name.
    # @param {string} image_url the URL for the sender's avatar.
    # @return {Object} a card with the user's avatar.
    def create_message(name: str, image_url: str) -> Mapping[str, Any]:
      avatar_image_widget = {"image": {"imageUrl": image_url}}
      avatar_text_widget = {"textParagraph": {"text": "Your avatar picture:"}}
      avatar_section = {"widgets": [avatar_text_widget, avatar_image_widget]}
    
      header = {"title": f"Hello {name}!"}
    
      cards = {
          "text": "Here's your avatar",
          "cardsV2": [
              {
                  "cardId": "avatarCard",
                  "card": {
                      "name": "Avatar Card",
                      "header": header,
                      "sections": [avatar_section],
                  },
              }
          ]
      }
    
      return cards

  8. 点击部署

Java

  1. 在 Google Cloud 控制台中,转到 Cloud Functions 页面:

    转到 Cloud Functions

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

  2. 点击 创建函数

  3. 在“创建函数”页面上,设置您的函数:

    1. 函数名称中,输入 QuickStartChatApp
    2. 触发器类型中,选择 HTTP
    3. 在“身份验证”下,选择允许未通过身份验证的调用
    4. 点击保存
    5. 点击下一步
  4. 运行时中,选择 Java 11

  5. 源代码中,选择內嵌编辑器

  6. 入口点中,删除默认文本,然后输入 HelloChat

  7. src/main/java/com/example/Example.java 改名为 src/main/java/HelloChat.java

  8. HelloChat.java 的内容替换为以下代码:

    java/avatar-app/src/main/java/HelloChat.java
    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 HelloChat implements HttpFunction {
      private static final Gson gson = new Gson();
    
      @Override
      public void service(HttpRequest request, HttpResponse response) throws Exception {
        JsonObject body = gson.fromJson(request.getReader(), JsonObject.class);
    
        if (request.getMethod().equals("GET") || !body.has("message")) {
          response.getWriter().write("Hello! This function must be called from Google Chat.");
          return;
        }
    
        JsonObject sender = body.getAsJsonObject("message").getAsJsonObject("sender");
        String displayName = sender.has("displayName") ? sender.get("displayName").getAsString() : "";
        String avatarUrl = sender.has("avatarUrl") ? sender.get("avatarUrl").getAsString() : "";
        Message message = createMessage(displayName, avatarUrl);
    
        response.getWriter().write(gson.toJson(message));
      }
    
      Message createMessage(String displayName, String avatarUrl) {
        GoogleAppsCardV1CardHeader cardHeader = new GoogleAppsCardV1CardHeader();
        cardHeader.setTitle(String.format("Hello %s!", displayName));
    
        GoogleAppsCardV1TextParagraph textParagraph = new GoogleAppsCardV1TextParagraph();
        textParagraph.setText("Your avatar picture: ");
    
        GoogleAppsCardV1Widget avatarWidget = new GoogleAppsCardV1Widget();
        avatarWidget.setTextParagraph(textParagraph);
    
        GoogleAppsCardV1Image image = new GoogleAppsCardV1Image();
        image.setImageUrl(avatarUrl);
    
        GoogleAppsCardV1Widget avatarImageWidget = new GoogleAppsCardV1Widget();
        avatarImageWidget.setImage(image);
    
        GoogleAppsCardV1Section section = new GoogleAppsCardV1Section();
        section.setWidgets(List.of(avatarWidget, avatarImageWidget));
    
        GoogleAppsCardV1Card card = new GoogleAppsCardV1Card();
        card.setName("Avatar Card");
        card.setHeader(cardHeader);
        card.setSections(List.of(section));
    
        CardWithId cardWithId = new CardWithId();
        cardWithId.setCardId("previewLink");
        cardWithId.setCard(card);
    
        Message message = new Message();
        message.setText("Here's your avatar");
        message.setCardsV2(List.of(cardWithId));
    
        return message;
      }
    }

  9. pom.xml 的内容替换为以下代码:

    java/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>cloudfunctions</groupId>
      <artifactId>http-function</artifactId>
      <version>1.0-SNAPSHOT</version>
    
      <properties>
        <maven.compiler.target>11</maven.compiler.target>
        <maven.compiler.source>11</maven.compiler.source>
      </properties>
    
      <dependencies>
        <dependency>
          <groupId>com.google.cloud.functions</groupId>
          <artifactId>functions-framework-api</artifactId>
          <version>1.0.1</version>
        </dependency>
    
        <!-- https://mvnrepository.com/artifact/com.google.code.gson/gson -->
        <dependency>
            <groupId>com.google.code.gson</groupId>
            <artifactId>gson</artifactId>
            <version>2.9.1</version>
        </dependency>
    
        <!-- https://mvnrepository.com/artifact/com.google.apis/google-api-services-chat -->
        <dependency>
          <groupId>com.google.apis</groupId>
          <artifactId>google-api-services-chat</artifactId>
          <version>v1-rev20230115-2.0.0</version>
        </dependency>
      </dependencies>
    
      <!-- Required for Java 11 functions in the inline editor -->
      <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>

  10. 点击部署

Cloud Functions 详情页面随即打开,您的函数会显示两个进度指示器:一个用于构建,一个用于服务。当两个进度指示器都消失并替换为对勾标记时,您的函数已部署并准备就绪。

将应用发布到 Google Chat

部署 Cloud Functions 函数后,请按照以下步骤将其转换为 Google Chat 应用:

  1. 在 Google Cloud 控制台中,点击“菜单”图标 > Cloud Functions

    转到 Cloud Functions

    请务必选择启用了 Cloud Functions 的项目。

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

  3. 在“函数详情”页面上,点击触发器

  4. 触发器网址下方,复制网址。

  5. 搜索“Google Chat API”并点击 Google Chat API,然后点击管理

    前往 Chat API

  6. 点击配置,然后设置 Google Chat 应用:

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

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

测试您的 Chat 应用

如需测试您的 Chat 应用,请向该应用发送私信:

  1. 打开 Google Chat
  2. 如需向应用发送私信,请点击“发起聊天”图标 ,然后在显示的窗口中点击查找应用
  3. 查找应用对话框中,搜索 Quickstart App
  4. 如需打开与应用的私信,请找到快速入门应用,然后依次点击添加 > 聊天
  5. 在私信中输入 Hello,然后按 enter

聊天应用的响应包含一条卡片消息,其中会显示发送者的姓名和头像图片,如下图所示:

聊天应用使用显示发送者显示名称和头像图片的卡片进行响应

排查错误

如需排查和调试 Chat 应用,请参阅排查并修正 Google Chat 应用错误