1. 准备工作
什么是内置 AI 的 Google Chat 应用?
内置 AI 的 Google Chat 应用具有以下功能:
- 将服务和资源引入 Google Chat,让用户无需离开对话即可获取信息和执行操作。
- 与生成式 AI 模型集成,以创建、搜索和修改文本或图片等数据。
- 应用对话式 AI 概念,打造更实用、更自然、更精细、更贴心的互动,从而支持代理式体验。
为什么要将 Google Chat 应用与 AI 集成?
典型使用场景分为以下几类:
- 内容创建和编辑。生成营销文案、撰写社交媒体帖子、创建逼真的图像、创作音乐或协助创作视频内容。
- 数据搜索和分析。从非结构化知识库中提取关键的数据洞见,总结长文本,对内容进行分类或翻译语言,且准确率更高、速度更快。
- 对话。像与助理对话一样,进行自然流畅、信息丰富且高效的对话。
- 任务自动化。代表用户执行操作,例如创建新的日历活动、发送文档或管理外部系统中的工单。
对于任何想要提升其用户体验和工作效率的人来说,能够直接在熟悉的 Google Chat 界面中集成这些功能都是一个巨大的机遇。
前提条件
- 具备 Google Cloud 和 Node.js 的基础知识。
- 具备 Google Chat 应用的基础知识,包括消息、卡片、身份验证、API 和 HTTP 端点。
构建内容
在此 Codelab 中,您将构建八款极简的 Google Chat 应用,这些应用集成了基本的 AI 概念,可展示如何在实际应用中应用这些概念。它们都是作为 Google Workspace 加购项构建的,并且依赖于 HTTP 架构:
具体运作方式如下:
- 用户在 Google Chat 中通过私信或在 Chat 聊天室中向 Chat 应用发送消息。
- 系统会向作为 Node.js Google Cloud Run 函数运行且包含 Chat 应用逻辑的网络服务器发送 HTTP 请求。
- 聊天应用逻辑可以选择性地与 Google Workspace 服务(如 Google 日历和 Google 表格)、其他 Google 服务(如 Google 地图、YouTube 和 Vertex AI)或其他 Web 服务(如项目管理系统或工单工具)集成。
- 网络服务器会向 Chat 中的 Chat 应用服务发回 HTTP 响应。
- 响应会传递给用户。
- Chat 应用可以选择调用 Chat API 来异步发布消息或执行其他操作。
每个 Google Chat 应用的 Node.js Google Cloud Run 函数都包含以下源文件的自有版本,以便在上述第 3 步和第 6 步中执行必要的操作:
package.json
:充当 Node.js 项目蓝图的中央清单。用于定义元数据、依赖项和脚本。env.js
:用于设置执行所需常量的脚本。应根据环境和配置进行修改。index.js:
用于处理 Google Chat 互动事件逻辑的主脚本。在此 Codelab 中,仅实现了消息事件类型,但在实际应用中,通常会包含其他类型,例如卡片点击、斜杠命令和对话框。
Prompt 应用
此应用依靠 Gemini 模型使用简洁明了的文本答案以用户的自然语言与用户对话。
格式化应用
此应用以 Prompt app
为基础,添加了对富文本答案的支持,这些答案符合 Google Chat 消息的特定文本格式。
地面应用
此应用基于 Format app
构建,添加了对 Google 搜索工具的支持,并以卡片形式在回答消息中返回来源。
MCP 应用
此应用以 Format app
为基础,添加了对 Google Workspace Developer Assist Model Context Protocol (MCP) 的支持。
多轮应用
此应用以 Format app
为基础,通过 Google Cloud Firestore 数据库添加了对对话记忆的支持。
自定义工具应用
此应用以 Multi-turn app
为基础,添加了对函数调用自定义工具的支持,该工具可根据用户提供的信息调用 Google Workspace Calendar API。
在线影音应用
此应用依靠 Gemini 模型根据用户提供的主题生成短篇故事。Google Chat API 用于在取得进展时以消息形式发送结果和状态。
多模态应用
此应用依赖于 Gemini 模型,可根据用户的文本指令编辑图片。Google Chat API 用于下载和上传图片作为消息附件。
学习内容
- 基本 AI 概念与 Google Chat 应用及其应用方式相关。
- 使用 Google Gen AI SDK 访问 Vertex AI。
- 使用 Google Workspace API 开发令人愉悦且功能强大的功能。
- 利用 Cloud Run 构建可扩缩的 Google Chat 应用。
所需条件
- 已完成使用 Node.js 构建 HTTP Google Chat 应用快速入门 Codelab。此 Codelab 基于生成的 Google Cloud 项目、Google Chat 应用和 Google Cloud Run 函数构建而成。
2. 进行设置
初始化和访问资源
在本部分中,您可以使用自己偏好的网络浏览器访问和配置以下资源。
Google Chat API 配置
在新标签页中打开 Google Cloud 控制台,然后按以下步骤操作:
- 选择您的项目。
- 在 Google Cloud 搜索字段中,搜索“Google Chat API”,然后依次点击 Google Chat API、管理和配置。
- 将应用名称和说明设置为
Gen AI App
。 - 点击保存。
Google Chat 聊天室
在新标签页中打开 Google Chat,然后按以下步骤操作:
- 如果尚未完成,请打开与 Chat 应用的私信对话。
- 输入
Hello
,然后按enter
,Chat 应用应会回复您的姓名和头像图片。
Google Cloud Run 函数服务
在新标签页中打开 Google Cloud 控制台,然后按以下步骤操作:
- 选择您的项目。
- 依次点击菜单 ☰ > Cloud Run > 服务。
- 在服务列表中,点击 addonchatapp,然后打开来源标签页。
将源代码和资源下载到本地
- 下载此 GitHub 代码库。
- 在您偏好的本地开发环境中,打开
node/chat/gen-ai-apps
目录。
3. 提示应用
此应用会提示 Vertex AI 上的 Gemini 使用简洁明了的文本回答以自然语言与用户对话。该实现依赖于适用于 Node.js 的 Google Gen AI SDK。
查看概念
自然语言
与人工或计算机语言相比,人类为日常交流而使用的任一口头或书面语言。
Cloud Run functions
Cloud Run functions 非常适合构建无服务器后端、执行实时数据处理和创建智能应用。无需配置、管理、修补或更新服务器。它们可以自动扩缩,并且具备高可用性和容错性。
提示
提示是指设计输入(提示)以引导生成式 AI 模型生成所需输出的技术。它通常涉及精心措辞问题、提供背景信息、给出指令或提供示例,以从模型中获得具体且相关的回答。
Vertex AI
Vertex AI 提供构建和使用生成式 AI 所需的一切内容,包括 AI 解决方案、搜索和对话、130 多个基础模型以及统一的 AI 平台。
Gemini
Gemini 是 Google 推出的一款多模态 LLM,可通过 Vertex AI 访问。它能帮助人们释放潜力,从而加强想象力、增加好奇心并提高工作效率。
Google Gen AI SDK
Google Gen AI SDK 专为开发者设计,用于构建由 Gemini 赋能的应用,它提供了一个统一的接口,可同时与 Gemini Developer API 和 Vertex AI 兼容。它随附 Python、Go、Node.js 和 Java 客户端库。
查看流程
查看源代码
env.js
...
// Replace with your GCP project ID.
projectID: process.env.PROJECT_ID || 'your-google-cloud-project-id',
// Replace with your GCP project location.
location: process.env.LOCATION || 'your-google-cloud-project-location',
// Replace with the Gemini model to use.
model: process.env.MODEL || 'gemini-2.5-flash-lite',
...
index.js
// Import the Google Gen AI SDK.
import { GoogleGenAI } from '@google/genai';
...
// Use Vertex AI.
const genAI = new GoogleGenAI({vertexai: true, project: env.projectID, location: env.location});
http('gen-ai-app', async (req, res) => {
// Send a new Chat message with the generated answer
return res.send({ hostAppDataAction: { chatDataAction: { createMessageAction: { message: {
text: await generateAnswer(req.body.chat.messagePayload.message.text)
}}}}});
});
async function generateAnswer(message) {
// The prompt is made of the user's message and specific instructions for the model.
const prompt = 'In a consice and with plain text only (no formatting), '
+ 'answer the following message in the same language: ' + message;
const aiResponse = await genAI.models.generateContent({model: env.model, contents: prompt});
return aiResponse.candidates[0].content.parts[0].text;
};
...
package.json
...
"main": "index.js",
"type": "module",
"scripts": {
"start": "node index.js"
},
"dependencies": {
"@google-cloud/functions-framework": "^4.0.0",
"@google/genai": "1.15.0"
},
...
启用 Vertex AI API
- 在 Google Cloud 控制台中,启用 Vertex AI API:
- 依次点击菜单 ☰ > API 和服务 > 已启用的 API 和服务,然后确认列表中包含 Vertex AI API。
更新 Google Cloud Run Node.js 函数
- 在本地开发环境中,将当前目录更改为
node/chat/gen-ai-apps/1-prompt
。它包含整个源代码和资源。 - 在编辑器中打开
env.js
并设置以下内容: - projectID:您的 Google Cloud 项目的 ID。您可以从 Google Cloud 控制台的欢迎页面检索此信息。
- 位置:Google Cloud Run 函数服务的区域。您可以从 Google Cloud Run 函数服务详情页面检索该网址。
- model:要使用的模型。您可以从 Vertex AI 文档中找到所有可用模型。默认设置的模型是 Flash,可实现快速且低成本的执行。
- 前往 Google Cloud Run 函数服务详情页面的源代码标签页。
- 点击修改来源。
- 将函数入口点设置为
gen-ai-app
。 - 点击 ➕,输入
env.js
,然后点击 ✔️ 以创建缺少的源文件。 - 将
index.js
、env.js
和package.json
文件的全部内容替换为本地开发环境中的相应内容。 - 点击保存并重新部署。
- 等待修订版本部署成功完成。
试试看
- 在 Google Chat 中与 Chat 应用来往的私信聊天室中,输入
Hello, how are you?
,然后按enter
。应用应根据提示中的说明,以纯文本形式简明扼要地回答问题。
- 在 Google Chat 中与 Chat 应用来往的私信聊天室中,输入
Bonjour comment allez-vous?
,然后按enter
。应用应根据提示中的说明以法语回答。
4. 格式化应用
此应用以 Prompt app
为基础,添加了对符合 Google Chat 文本消息格式的富文本答案的支持。提示中的指令会更新,其中包含模型可使用的不同选项的详尽说明。
查看概念
Google Chat 短信
Google Chat 短信支持多种格式设置选项,让您直接在 Google Chat 界面中发送更清晰、更具表现力的消息。它们基于特定的 Markdown 规则,用于应用粗体、斜体、删除线、创建超链接等。
查看流程
查看源代码
index.js
...
async function generateAnswer(message) {
// Specify formatting options that are compatible with Google Chat messages
// https://developers.google.com/workspace/chat/format-messages#format-texts
const prompt = `Use simple text for concise answers. The only formatting options you can use is to
(1) surround some text with a single star for bold such as *text* for strong emphasis
(2) surround some text with a single underscore for italic such as _text_ for gentle emphasis
(3) surround some text with a single tild for strikethrough such as ~text~ for removal
(4) use a less than before followed by a URL followed by a pipe followed by a link text followed
by a more than for a hyperlink such as <https://example.com|link text> for resource referencing
(5) use a backslash followed by the letter n for a new line such as \n for readibility
(6) surround some text with a single backquote such as \`text\` for quoting code
(7) surround an entire paragraph with three backquotes in dedicated lines such as
\`\`\`\nparagraph\n\`\`\` for quoting code
(8) prepend lines with list items with a single star or hyphen followed by a single space
such as * list item or - list item for bulleting ;
DO NOT USE ANY OTHER FORMATTING OTHER THAN THOSE.
Answer the following message in the same language: ${message}`;
...
};
...
更新 Google Cloud Run Node.js 函数
- 在本地开发环境中,将当前目录更改为
node/chat/gen-ai-apps/2-format
。它包含整个源代码和资源。 - 前往 Google Cloud Run 函数服务详情页面的源代码标签页。
- 点击修改来源。
- 将
index.js
文件的全部内容替换为本地开发环境中的内容。 - 点击保存并重新部署。
- 等待修订版本部署成功完成。
试试看
- 在 Google Chat 中与 Chat 应用来往的私信聊天室中,输入
Showcase all formatting options you have with one paragraph each
,然后按enter
。应用应根据提示中的指令,以格式化示例的形式回答。
- 在 Google Chat 中与 Chat 应用来往的私信聊天室中,输入
What are Google Chat apps? What's great about them?
,然后按enter
。在有用时,应用应以格式化方式回答。
5. 地面应用
此应用基于 Format app
构建,增加了对事实依据和返回来源的支持。它会运行 Google 搜索工具,并附上包含答案链接的卡片。
查看概念
标准答案关联
接地是一种将模型与信息源相关联的技术。它通常用于实际应用中,通过参考真实世界的数据来提高生成内容的准确性和相关性,从而防止模型产生幻觉或生成不符合事实的信息。
Google 搜索工具
Google 搜索工具可让模型在网络上搜索实时信息,从而增强接地功能,确保回答准确且最新。
Google Workspace 卡片框架
Google Workspace 中的 Card 框架可让开发者创建丰富多样的互动式界面。借助它,您可以构建包含文本、图片、按钮和其他 widget 的有条理且美观的卡片。这些卡片可提供结构化信息,并直接在对话中启用快捷操作,从而提升用户体验。
查看流程
查看源代码
index.js
...
const aiResponse = await genAI.models.generateContent({
model: env.model,
contents: prompt,
// Google Search tool is enabled
config: { tools: [{ googleSearch: {}}]}
});
let groundingCardsV2 = undefined;
const grounding = aiResponse.candidates[0].groundingMetadata;
// Go through the grounding metadata if any
if (grounding && grounding.groundingChunks && grounding.groundingChunks.length > 0) {
let linkButtons = [];
grounding.groundingChunks.forEach(groundingChunk => {
if (groundingChunk.web) {
// Create one link button per web URL returned
linkButtons.push({
text: groundingChunk.web.domain,
onClick: { openLink: { url: groundingChunk.web.uri}}
});
}
});
// Create a card with link buttons
groundingCardsV2 = [{
cardId: "sourcesCard",
card: { sections: [{
header: "Sources",
widgets: [{ buttonList: { buttons: linkButtons}}]
}]}
}];
}
// Send a Chat message with the generated answer
return res.send({ hostAppDataAction: { chatDataAction: { createMessageAction: { message: {
text: aiResponse.candidates[0].content.parts[0].text,
// The sources are referenced in the card
cardsV2: groundingCardsV2
}}}}});
...
更新 Google Cloud Run Node.js 函数
- 在本地开发环境中,将当前目录更改为
node/chat/gen-ai-apps/3-ground
。它包含整个源代码和资源。 - 前往 Google Cloud Run 函数服务详情页面的源代码标签页。
- 点击修改来源。
- 将
index.js
文件的全部内容替换为本地开发环境中的内容。 - 点击保存并重新部署。
- 等待修订版本部署成功完成。
试试看
在 Google Chat 中与 Chat 应用来往的私信聊天室中,输入 What's the world population?
,然后按 enter
。应用应通过在卡片中附上来源链接来回答问题。
6. MCP 应用
此应用以 Format app
为基础,添加了对远程托管的 Model Context Protocol (MCP) 服务器提供的工具的支持。它会连接到 Google Workspace 开发者助理 MCP,该 MCP 提供用于访问和搜索 Google Workspace 开发者文档的工具。
查看概念
Model Context Protocol (MCP)
Model Context Protocol 是一种开源框架,可将模型与外部服务以标准化方式集成。模型可以以编程方式发现、理解和使用各种工具,从而扩展自身能力、执行实际操作并访问最新信息。
MCP TypeScript SDK
TypeScript SDK 实现了完整的 MCP 规范,可简化 MCP 客户端的创建,以便连接到任何 MCP 服务器。它还支持开发可提供对资源、提示和工具的访问权限的 MCP 服务器。
查看流程
查看源代码
index.js
// Import the MCP TypeScript SDK.
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";
...
// Create and connect the MCP client from the URL.
const mcpServerUrl = new URL("https://workspace-developer.goog/mcp");
const client = new Client({ name: "gen-ai-app-mcp", version: "1.0.0" });
// Try Streamable HTTP first (new) and SSE (old) as fallback for transport
try {
await client.connect(new StreamableHTTPClientTransport(mcpServerUrl));
} catch (error) {
await client.connect(new SSEClientTransport(mcpServerUrl));
}
http('gen-ai-app', async (req, res) => {
...
const aiResponse = await genAI.models.generateContent({
model: env.model,
contents: prompt,
// MCP tools are enabled
config: { tools: [mcpToTool(client)]}
});
...
}
...
package.json
...
"dependencies": {
...
"@modelcontextprotocol/sdk": "^1.18.1"
},
...
更新 Google Cloud Run Node.js 函数
- 在本地开发环境中,将当前目录更改为
node/chat/gen-ai-apps/4-mcp
。它包含整个源代码和资源。 - 前往 Google Cloud Run 函数服务详情页面的源代码标签页。
- 点击修改来源。
- 将
index.js
和package.json
文件的全部内容替换为本地开发环境中的相应内容。 - 点击保存并重新部署。
- 等待修订版本部署成功完成。
试试看
- 在 Google Chat 中与 Chat 应用来往的私信聊天室中,输入
What can you do for me?
,然后按enter
。应用应说明其能够执行的操作(MCP 工具)。
- 在 Google Chat 中与 Chat 应用来往的私信聊天室中,输入
I would like to get the latest official documentation for the Google Sheets API append values
,然后按enter
。应用应使用 MCP 工具回答并提供所请求的文档。
7. 多轮应用
此应用以 Format app
为基础,通过跟踪聊天互动历史记录来添加对对话记忆的支持。它可提供更自然、智能且个性化的体验。该应用使用与其 Google Cloud 项目关联的默认 Google Cloud Firestore 数据库进行存储。
查看概念
多轮
多轮概念是指模型在多次交流和对话中保持上下文和连贯性的能力。这是支持复杂对话、精密的 AI 驱动功能和自然用户体验的必备功能。
Google Cloud Firestore
Google Cloud Firestore 是一种灵活且可扩缩的 NoSQL 云数据库,适用于进行移动、Web 和服务器开发。它将数据存储在文档中,并以集合的形式进行整理,同时支持实时同步和离线支持。
查看流程
查看源代码
index.js
// Import the Google Cloud Firestore client library.
import { Firestore } from '@google-cloud/firestore';
...
// Configure DB
const USERS_PREFIX = 'users/';
const CHATS_COLLECTION = 'chats';
const db = new Firestore();
...
// Create or update data for a given user
async function createOrUpdateChatHistory(userId, data) {
await db.collection(CHATS_COLLECTION).doc(userId.replace(USERS_PREFIX, '')).set(data);
};
// Retrieve data snapshot for a given user
async function getChatHistory(userId) {
return await db.collection(CHATS_COLLECTION).doc(userId.replace(USERS_PREFIX, '')).get();
};
...
...
http('gen-ai-app', async (req, res) => {
// Retrieve the chat history of the user
const chatHistory = await getChatHistory(userId);
const chat = genAI.chats.create({
model: env.model,
// Initiate the model with chat history for context
history: chatHistory.exists ? chatHistory.data().contents : []
});
// If no history, send a first message to the model with instructions on how to behave
if(!chatHistory.exists) {
const preambule = 'The only formatting options you can use is to '
+ ...
+ 'DO NOT USE ANY OTHER FORMATTING OTHER THAN THOSE. '
+ 'Answer in the same language that I use.';
// The answer to this message is ignored
await chat.sendMessage({message: preambule});
}
// Send the user's message to the model to generate the answer
const aiResponse = await chat.sendMessage({message: userMessage});
// Persist the updated chat history of the user
await createOrUpdateChatHistory(userId, {contents: chat.getHistory({curated: true})});
// Send a Chat message with the generated answer
return res.send({ hostAppDataAction: { chatDataAction: { createMessageAction: { message: {
text: aiResponse.candidates[0].content.parts[0].text
}}}}});
});
...
package.json
...
"dependencies": {
...
"@google-cloud/firestore": "^7.11.5"
},
...
启用 Google Cloud Firestore API
- 依次点击菜单 ☰ > API 和服务 > 已启用的 API 和服务,然后确认列表中包含 Cloud Firestore API。
创建 Cloud Firestore 数据库
- 在 Google Cloud 控制台中,依次点击菜单 ☰ > Firestore
- 点击创建 Firestore 数据库
- 保留默认配置,然后点击创建数据库
更新 Google Cloud Run Node.js 函数
- 在本地开发环境中,将当前目录更改为
node/chat/gen-ai-apps/5-multi-turn
。它包含整个源代码和资源。 - 前往 Google Cloud Run 函数服务详情页面的源代码标签页。
- 点击修改来源。
- 将
index.js
和package.json
文件的全部内容替换为本地开发环境中的相应内容。 - 点击保存并重新部署。
- 等待修订版本部署成功完成。
试试看
- 在 Google Chat 中与 Chat 应用来往的私信聊天室中,输入
Can you speak with the English from the 80's for now on?
,然后按enter
。应用应做出肯定回答。
- 在 Google Chat 中与 Chat 应用来往的私信聊天室中,输入
Define what Google Chat apps are in one sentence
,然后按enter
。应用应继续以 80 年代的英语回答。
8. 自定义工具应用
此应用以 Multi-turn app
为基础,添加了对函数调用自定义工具的支持,该工具依赖于 Google Workspace Calendar API 从公开日历中检索下一个活动。模型管理所有用户互动,包括接收输入和提供来自工具的输出。不过,应用仍负责执行必要的 API 调用,并在收到请求时向模型提供结果。该应用使用 Google API 密钥,因为无需用户凭据即可提取公开日历数据。
查看概念
函数调用
借助函数调用功能,模型可以检测到用户的请求何时可以通过外部工具或 API 来满足。然后,模型会提供调用该工具所需的参数,从而将外部功能集成到其回答中。
Google Workspace API
借助 Google Workspace API,开发者可以将自己的应用与各种 Google Workspace 服务集成。这些 API 可让您以编程方式访问 Gmail、Chat、Google 日历、云端硬盘、Google 文档、Google 表格等产品中的功能,从而实现自动化、数据同步和自定义工作流。
查看流程
查看源代码
env.js
...
// Replace with your Google API key.
googleApiKey: process.env.GOOGLE_API_KEY || 'your-google-api-key',
...
index.js
// Import parameter type definitions from Google Gen AI SDK.
import { GoogleGenAI, Type } from '@google/genai';
// Import Google APIs that include the Google Calendar API.
import { google } from 'googleapis';
...
// Create a Google Calendar API client using a Google API key.
const calendar = google.calendar({version: 'v3', auth: env.googleApiKey});
...
// Define the tool used for function calling
const getNextPublicCalendarEventTitleFunctionDeclaration = {
name: 'getNextPublicCalendarEventTitle',
parameters: {
type: Type.OBJECT,
description: 'Get the title of the next event of a public calendar.',
properties: {
calendarId: {
type: Type.STRING,
description: 'ID of the public calendar to get the next event title.',
}
},
required: ['calendarId']
}
};
// The function referenced in the tool definition
async function getNextPublicCalendarEventTitle(calendarId) {
// Use Calendar API to retrieve the next event in the given calendar
const response = await calendar.events.list({
calendarId: calendarId,
timeMin: new Date().toISOString(),
maxResults: 1,
singleEvents: true,
orderBy: 'startTime',
});
const events = response.data.items;
if (!events || events.length === 0) {
return null;
}
return `${events[0].summary}`;
};
...
...
http('gen-ai-app', async (req, res) => {
...
// Send the user's message to the model to generate the answer
let aiResponse = await chat.sendMessage({
message: userMessage,
// The tool used for function calling is enabled
config: { tools: [{ functionDeclarations: [getNextPublicCalendarEventTitleFunctionDeclaration]}]}
});
// Handle the function calling turn with the model if any
const functionCall = aiResponse.candidates[0].content.parts[0].functionCall;
if (functionCall) {
let functionResult = null;
switch(functionCall.name) {
case 'getNextPublicCalendarEventTitle':
// Make the function call as per model request
functionResult = await getNextPublicCalendarEventTitle(functionCall.args['calendarId']);
break;
default:
}
// Finish the function calling turn by sending the execution result to the model
aiResponse = await chat.sendMessage({ message: { functionResponse: {
name: functionCall.name,
response: { output: functionResult }
}}});
}
...
// Send a Chat message with the generated answer
return res.send({ hostAppDataAction: { chatDataAction: { createMessageAction: { message: {
text: aiResponse.candidates[0].content.parts[0].text
}}}}});
});
...
package.json
...
"dependencies": {
...
"googleapis": "^160.0.0"
},
...
启用 Calendar API
- 依次点击菜单 ☰ > API 和服务 > 已启用的 API 和服务,然后确认列表中包含 Google 日历 API。
创建 Google API 密钥
在 Google Cloud 控制台中,按以下步骤操作:
- 依次点击菜单 ☰ > API 和服务 > 凭据。
- 点击 + 创建凭据,然后选择 API 密钥。
- 等待操作完成。
- 在确认对话框中,找到您的 API 密钥文本字段,然后点击复制到剪贴板。
更新 Google Cloud Run Node.js 函数
- 在本地开发环境中,将当前目录更改为
node/chat/gen-ai-apps/6-custom-tool
。它包含整个源代码和资源。 - 前往 Google Cloud Run 函数服务详情页面的源代码标签页。
- 点击修改来源。
- 将
index.js
和package.json
文件的全部内容替换为本地开发环境中的相应内容。 - 打开
env.js
文件并执行以下操作 - 将 googleApiKey 添加到导出的字段
export const env = {
...
googleApiKey: 'your-google-api-key',
};
- 将
your-google-api-key
替换为在上一步中复制的 Google API 密钥。您可以点击 Google Cloud 凭据页面中的显示密钥来检索该密钥。
- 点击保存并重新部署。
- 等待修订版本部署成功完成。
试试看
- 在 Google 日历中,按以下步骤操作:
- 在其他日历下,点击 +,然后点击创建新日历。
- 将名称设置为
My Public Calendar
- 点击创建日历
- 等待操作完成。
- 在我的日历设置下方,选择新创建的日历我的公开日历
- 在活动的访问权限下方,选择公开此日历,然后在警告对话框中点击确定。
- 在活动的访问权限下方,从公开此日历选项旁边的下拉菜单中选择查看所有活动详情
- 在集成日历下,将日历 ID 字段的值复制到剪贴板
- 点击左上角的向左箭头,退出设置。
- 点击日历,为明天创建新活动,输入
Important meeting
,从下拉菜单中选择我的公开日历,然后点击保存 - 在 Google Chat 中与 Chat 应用来往的私信聊天室中,输入
When is the next meeting?
,然后按enter
。应用应请求精度,因为不清楚所指的是哪个日历。
- 在 Google Chat 中与 Chat 应用的私信对话框中,粘贴您之前复制到剪贴板的日历 ID,然后按
enter
。应用应回答之前创建的活动的详细信息。
9. 流式传输应用
此应用依靠 Gemini 模型根据用户提供的主题生成 2 分钟的故事。由于生成完整答案需要时间,因此应用会以流式模式调用模型,并依赖 Google Chat API 在取得进展时在消息中发送内容和状态。
查看概念
Google Chat API
借助 Google Chat API,开发者可以以编程方式与 Google Chat 进行互动,从而能够发送消息、创建聊天室、管理成员等,以构建自定义集成和聊天机器人。
流式
流式传输是指以连续流的形式接收数据,而不是等待生成整个响应。在 AI 模型调用方面,流式传输允许应用在部分结果可用时立即向用户显示,从而提升感知性能和用户体验,尤其是在生成任务耗时较长的情况下。这对于可能需要花费大量时间才能生成完整输出的生成式 AI 模型尤为重要。
查看流程
查看源代码
index.js
// Import Google Auth library used to create Google Chat API client
import { GoogleAuth } from 'google-auth-library';
...
http('gen-ai-app', async (req, res) => {
// Use app authentication.
// Application Default Credentials (ADC) will use the Cloud Run function's
// default service account, we just need to specify the Chat API app auth scopes.
const auth = new GoogleAuth({
// Chat API app authentication scopes
scopes: ['https://www.googleapis.com/auth/chat.bot']
});
// Create Chat service client with application credentials
const chatClient = google.chat({
version: 'v1',
auth: await auth.getClient()
});
// Send a server streaming request to generate the answer
const aiResponse = await genAI.models.generateContentStream({
model: env.model,
contents: `Generate a story about a ${userMessage}. `
+ `It should take 2 minutes to read it out loud.`
});
// Send a first Chat message to summarize what will be done
await chatClient.spaces.messages.create({
parent: spaceName,
requestBody: { text: `Sure, let me work on generating a short story `
+ `about a ${userMessage} like you requested.`}
});
// Go through the response chunks received from the stream
let messageName = undefined;
let answer = "";
for await (const chunk of aiResponse) {
const text = chunk.text;
if (text) {
// Update the answer by concatenating the response chunks
answer += text;
// The Chat message request body is the same for message creation and update
const responseBody = {
text: answer,
accessoryWidgets: [getStatusAccessoryWidget('Generating story...', 'progress_activity')]
}
if (!messageName) {
// Create a Chat message dedicated to the generated content
const messageResponse = await chatClient.spaces.messages.create({
parent: spaceName,
requestBody: responseBody
});
messageName = messageResponse.data.name;
} else {
// Update the Chat message dedicated to the generated content
await chatClient.spaces.messages.patch({
name: messageName,
updateMask: 'text,accessory_widgets',
requestBody: responseBody
});
}
}
}
// Update the accessory widget with final progress status
await chatClient.spaces.messages.patch({
name: messageName,
updateMask: 'accessory_widgets',
requestBody: {
accessoryWidgets: [getStatusAccessoryWidget('Story is fully generated', 'check')]
}
});
// Send a last Chat message to confirm it's done
return res.send({ hostAppDataAction: { chatDataAction: { createMessageAction: { message: {
text: 'All done, I hope you like it!'
}}}}});
});
// Create an accessory widget with progress status
function getStatusAccessoryWidget(text, icon) {
return { buttonList: { buttons: [{
text: text,
icon: { materialIcon: { name: icon}},
// This is a workaround to have the icon shown, it's not clickable
onClick: { openLink: { url: "https://google.com"}},
disabled: true
}]}};
}
package.json
...
"dependencies": {
...
"google-auth-library": "^10.3.0"
},
...
更新 Google Cloud Run Node.js 函数
- 在本地开发环境中,将当前目录更改为
node/chat/gen-ai-apps/7-stream
。它包含整个源代码和资源。 - 前往 Google Cloud Run 函数服务详情页面的源代码标签页。
- 点击修改来源。
- 将
index.js
和package.json
文件的全部内容替换为本地开发环境中的相应内容。 - 点击保存并重新部署。
- 等待修订版本部署成功完成。
试试看
在 Google Chat 中与 Chat 应用来往的私信聊天室中,输入 turtle
,然后按 enter
。应用应回答确认消息、生成状态为“正在进行”的故事,以及完成确认消息。
10. 多模态应用
此应用依赖于一个模型,可根据用户的文本指令编辑图片。用户和应用都会将自己的图片作为 Google Chat 消息附件添加以进行交换。该应用依赖于 Google Chat API 以编程方式下载和上传图片。
查看概念
Google Chat 消息附件
Google Chat 消息附件是指上传到 Google Chat 消息中的文件,例如图片或视频。这些附件可以通过编程方式进行管理,从而使应用能够直接在对话中与富媒体进行交互。
网域范围内的委托 (DWD)
全网域授权 (DWD) 允许服务账号模拟 Google Workspace 网域中的用户,使应用能够代表这些用户执行操作,而无需直接授权。对于需要在用户上下文中访问用户数据或执行操作(例如将附件上传到 Google Chat)的应用,即使在用户未主动参与的情况下,通过授予服务账号对整个网域的广泛访问权限,也能实现此目的。
查看流程
查看源代码
env.js
...
// Replace with the Gemini model to use.
model: process.env.MODEL || 'gemini-2.0-flash-preview-image-generation',
...
index.js
...
// Import byte stream management libraries.
import { Buffer } from 'buffer';
import { Readable } from 'stream';
...
// Download a Google Chat attachment as base 64 string.
async function downloadFile(appChatClient, attachmentName) {
const response = await appChatClient.media.download({
resourceName: attachmentName,
alt: 'media'
}, {
responseType: 'stream'
});
const chunks = [];
return new Promise((resolve) => {
response.data.on('data', (chunk) => {
chunks.push(chunk);
});
response.data.on('end', () => {
const fileBuffer = Buffer.concat(chunks);
const base64String = fileBuffer.toString('base64');
resolve(base64String);
});
});
}
// Upload a base 64 string as Google Chat attachment of a space.
async function uploadFile(useChatClient, spaceName, data) {
const filename = 'generated_image.png';
return await userChatClient.media.upload({
parent: spaceName,
requestBody: { filename: filename },
media: {
mimeType: 'image/png',
body: Readable.from(Buffer.from(data, 'base64'))
}
});
}
...
...
http('gen-ai-app', async (req, res) => {
const userEmail = req.body.chat.user.email;
const spaceName = req.body.chat.messagePayload.space.name;
const userMessage = req.body.chat.messagePayload.message.text;
const attachmentName = req.body.chat.messagePayload.message.attachment[0].attachmentDataRef.resourceName;
const attachmentContentType = req.body.chat.messagePayload.message.attachment[0].contentType;
// Set up app authentication used to download the attachment input
// Application Default Credentials (ADC) will use the Cloud Run function's
// default service account.
const appAuth = new GoogleAuth({
// Specify the Chat API app authentication scopes
scopes: ['https://www.googleapis.com/auth/chat.bot']
});
// Create Chat service client with application credentials
const appChatClient = google.chat({
version: 'v1',
auth: await appAuth.getClient()
});
// Send a request to generate the answer with both text and image contents
const aiResponse = await genAI.models.generateContent({
model: env.model,
contents: [{
role: 'USER',
parts: [
// The text content of the message
{ text: userMessage },
// The attachment of the message is downloaded and added inline
{ inlineData: {
data: await downloadFile(appChatClient, attachmentName),
mimeType: attachmentContentType
}}
]
}],
config: { responseModalities: ['TEXT', 'IMAGE']}
});
// Set up user impersonation authentication used to upload the attachment output
// and send the response.
const impersonatedUserAuth = new GoogleAuth({
// Specify the Chat API user authentication scopes
scopes: ['https://www.googleapis.com/auth/chat.messages'],
keyFile: './credentials.json',
clientOptions: {
// Impersonate the user who sent the original message
subject: userEmail
}
});
// Create Chat service client with impersonated user credentials
const userChatClient = google.chat({
version: 'v1',
auth: await impersonatedUserAuth.getClient()
});
let responseText = undefined;
let responseAttachment = undefined;
// Go through the response parts received
for (const part of aiResponse.candidates[0].content.parts) {
if (part.inlineData) {
// The resulting image is retrieved inline and uploaded
const mediaResponse = await uploadFile(userChatClient, spaceName, part.inlineData.data);
responseAttachment = mediaResponse.data;
} else {
responseText = part.text;
}
}
// Create a Chat message dedicated to the generated content
await userChatClient.spaces.messages.create({
parent: spaceName,
requestBody: {
text: responseText ? responseText : 'Here it is!',
// The uploaded image is referenced as attachment
attachment: responseAttachment ? [responseAttachment] : undefined
}
});
// Send a last Chat message to confirm it's done
return res.send({ hostAppDataAction: { chatDataAction: { createMessageAction: { message: {
text: 'Done, feel free to let me know if you need anything else!'
}}}}});
});
...
配置服务账号并导出私钥
- 委托 Cloud Run 默认服务账号为用户管理 Google Chat 消息。按照说明操作,并使用 https://www.googleapis.com/auth/chat.messages 范围。如需检索 Cloud Run 默认服务账号的客户端 ID,请按以下步骤操作:
- 依次点击菜单 ☰ > IAM 和管理 > 服务账号
- 点击名为默认计算服务账号的服务账号。
- 展开高级设置部分
- 将客户端 ID 复制到剪贴板。
- 为 Cloud Run 默认服务账号创建并下载新的私钥
- 依次点击菜单 ☰ > IAM 和管理 > 服务账号
- 点击名为默认计算服务账号的服务账号。
- 选择密钥标签页,点击添加密钥,然后点击创建新密钥。
- 选择 JSON,然后点击创建。
- 系统会生成新的公钥/私钥对,并以新文件的形式下载到您的计算机。保存下载的 JSON 文件,并将其内容复制到剪贴板。此文件是相应密钥的唯一副本。如需了解如何安全地存储密钥,请参阅管理服务账号密钥。
更新 Google Cloud Run Node.js 函数
- 在本地开发环境中,将当前目录更改为
node/chat/gen-ai-apps/8-multimodal
。它包含整个源代码和资源。 - 前往 Google Cloud Run 函数服务详情页面的源代码标签页。
- 点击修改来源。
- 点击 ➕,输入
credentials.json
,然后点击 ✔️ 以创建缺少的资源文件。 - 将上一步中下载的 JSON 文件的内容粘贴到新创建的
credentials.json
文件中。 - 将
index.js
文件的全部内容替换为本地开发环境中的内容。 - 打开
env.js
文件,并将模型的值设置为gemini-2.0-flash-preview-image-generation
。
...
model: 'gemini-2.0-flash-preview-image-generation',
...
- 点击保存并重新部署。
- 等待修订版本部署成功完成。
试用一下
在 Google Chat 中与 Chat 应用的私信聊天室中,上传一张 PNG 格式的个人竖屏照片,输入 Change the background color to blue
,然后按 enter
。应用应回答一张蓝色背景的照片,并显示完成确认消息。
11. 清理
删除 Google Cloud 项目
为避免系统因此 Codelab 中使用的资源向您的 Google Cloud 账号收取费用,我们建议您删除该 Google Cloud 项目。
在 Google Cloud 控制台中,按以下步骤操作:
- 依次点击菜单 ☰ > IAM 和管理 > 设置。
- 点击关停。
- 输入项目 ID。
- 点击仍要关停。
12. 恭喜
恭喜!您以 Google Workspace 插件的形式构建了 Google Chat 应用,其中集成了基本的 AI 概念!
后续操作
在此 Codelab 中,我们仅展示了极简的用例,但您或许需要在您的 Google Chat 应用中考虑很多值得扩展的地方,例如:
- 支持其他类型的媒体,例如音频和视频。
- 与在 Vertex AI 等专用平台上托管的其他 AI 模型(包括自定义模型)集成。
- 与代理(包括自定义代理)集成,这些代理托管在 Agentspace 和 Dialogflow CX 等专用平台上。
- 依靠反馈环和分类来监控和提升效果。
- 在 Marketplace 上发布,以赋能团队、组织或公开用户。
了解详情
我们为开发者提供了大量资源,例如 YouTube 视频、文档网站、代码示例和教程: