GSP1301

概览
插件可以扩展 Google Workspace 的功能,帮助 Google Workspace 用户提高工作效率并改进工作流程。在本实验中,您将构建一个 Google Workspace 插件,利用 Gemini 和 Vertex AI 的强大功能对 Gmail 邮件进行情感分析。您将设置必要的云资源(包括 Vertex AI API)、配置 Apps 脚本项目并部署插件。
该插件可自动识别并标记语气消极的电子邮件。您可以使用该插件来确定客户服务回复的优先级,或快速识别可能包含敏感信息的电子邮件。
完成本实验后,您将获得一个实用的工具,展示 AI 在业务环境中提高工作效率和沟通能力的实际应用。
学习内容
在本实验中,您需要完成以下操作:
- 构建一个扩展 Gmail 功能的 Google Workspace 插件。
- 将 Vertex AI 与 Google Workspace 集成,以便在 Gmail 插件中使用 Gemini 和 Vertex AI 的自然语言处理功能。
- 实现 OAuth2 身份验证,安全地授权插件访问用户数据。
- 进行情感分析,以编程方式分析电子邮件内容,确定情感基调。
- 利用 Apps 脚本编写代码,与 Gmail 互动、管理用户界面并接入外部 API。
设置和要求
点击“开始实验”按钮前的注意事项
请阅读以下说明。实验是计时的,并且您无法暂停实验。计时器在您点击开始实验后即开始计时,显示 Google Cloud 资源可供您使用多长时间。
此实操实验可让您在真实的云环境中开展实验活动,免受模拟或演示环境的局限。为此,我们会向您提供新的临时凭据,您可以在该实验的规定时间内通过此凭据登录和访问 Google Cloud。
为完成此实验,您需要:
- 能够使用标准的互联网浏览器(建议使用 Chrome 浏览器)。
注意:请使用无痕模式(推荐)或无痕浏览器窗口运行此实验。这可以避免您的个人账号与学生账号之间发生冲突,这种冲突可能导致您的个人账号产生额外费用。
注意:请仅使用学生账号完成本实验。如果您使用其他 Google Cloud 账号,则可能会向该账号收取费用。
如何开始实验并登录 Google Cloud 控制台
-
点击开始实验按钮。如果该实验需要付费,系统会打开一个对话框供您选择支付方式。左侧是“实验详细信息”窗格,其中包含以下各项:
- “打开 Google Cloud 控制台”按钮
- 剩余时间
- 进行该实验时必须使用的临时凭据
- 帮助您逐步完成本实验所需的其他信息(如果需要)
-
点击打开 Google Cloud 控制台(如果您使用的是 Chrome 浏览器,请右键点击并选择在无痕式窗口中打开链接)。
该实验会启动资源并打开另一个标签页,显示“登录”页面。
提示:将这些标签页安排在不同的窗口中,并排显示。
注意:如果您看见选择账号对话框,请点击使用其他账号。
-
如有必要,请复制下方的用户名,然后将其粘贴到登录对话框中。
{{{user_0.username | "<用户名>"}}}
您也可以在“实验详细信息”窗格中找到“用户名”。
-
点击下一步。
-
复制下面的密码,然后将其粘贴到欢迎对话框中。
{{{user_0.password | "<密码>"}}}
您也可以在“实验详细信息”窗格中找到“密码”。
-
点击下一步。
重要提示:您必须使用实验提供的凭据。请勿使用您的 Google Cloud 账号凭据。
注意:在本实验中使用您自己的 Google Cloud 账号可能会产生额外费用。
-
继续在后续页面中点击以完成相应操作:
- 接受条款及条件。
- 由于这是临时账号,请勿添加账号恢复选项或双重验证。
- 请勿注册免费试用。
片刻之后,系统会在此标签页中打开 Google Cloud 控制台。
注意:如需访问 Google Cloud 产品和服务,请点击导航菜单,或在搜索字段中输入服务或产品的名称。
任务 1. 访问实验环境
您已登录 Google Cloud 控制台。现在,您需要登录 Gmail。
- 点击打开 Gmail,打开 Gmail 登录页面。
提示:将这些标签页安排在不同的窗口中,方便查看。
- 使用用户名 和密码 登录 Gmail。
注意:也可以在实验详细信息窗格中找到这些凭据。您已使用这些凭据登录 Google Cloud 控制台。
- 进入 Gmail 后,点击开始使用,然后关闭所有信息窗口。现在,您应该会看到收件箱。
您已设置完毕,可以开始实验活动了!
任务 2. 配置 Google Cloud 环境
在此任务中,您将启用 Vertex AI API,然后配置 OAuth 权限请求页面,定义 Google Workspace 向用户显示的内容。
启用 Vertex AI API
-
在 Google Cloud 控制台的导航菜单中,依次点击 API 和服务 > 库。
-
在搜索 API 和服务框中输入 Vertex AI API,然后在搜索结果中点击 Vertex AI API。
-
点击启用以启用 API。
API/服务详情页面随即打开。
配置 OAuth 权限请求页面
-
在左侧窗格中,点击 OAuth 权限请求页面。
-
点击开始使用。
-
在应用信息部分,设置以下内容,然后点击下一步:
-
应用名称:使用 Gemini 和 Vertex AI 进行 Gmail 情感分析
-
用户支持电子邮件:
- 在受众群体部分,选择内部,然后点击下一步。
- 在联系信息部分,将电子邮件地址设置为 ,然后点击下一步。
- 在完成部分,同意 Google API 服务:用户数据政策,然后点击继续。
- 点击创建。
点击检查我的进度以验证是否完成了以下目标:
配置 OAuth 权限请求页面。
任务 3. 设置 Apps 脚本项目
在此任务中,您将创建插件并配置为 Apps 脚本项目。
获取 Google Cloud 项目编号
如需获取 Google Cloud 项目编号,以便在创建 Apps 脚本项目时使用,请执行以下操作:
-
在导航菜单 (
) 中,依次点击 Cloud 概览 > 信息中心。
-
在“项目信息”部分,记录项目编号,以便稍后在本实验中使用。
创建 Apps 脚本项目
-
在“学员资源”窗格中,点击此链接 script.google.com/,打开 Apps 脚本页面。
-
点击创建项目,创建一个 Apps 脚本项目。
-
为项目命名:
- 点击左上角的“未命名项目”。
- 将项目命名为使用 Gemini 和 Vertex AI 进行 Gmail 情感分析,然后点击重命名。
-
将清单文件设置为可见:
- 在左侧窗格中,点击项目设置 (
)。
- 选择在编辑器中显示“appsscript.json”清单文件。
-
更改 Google Cloud Platform 项目:
- 向下滚动到 Google Cloud Platform (GCP) 项目部分,然后点击更改项目。
- 将 GCP 项目编号设置为您之前记录的项目编号。
- 点击设置项目。
点击检查我的进度以验证是否完成了以下目标:
创建 Apps 脚本项目。
任务 4. 填充代码文件
- 在左侧窗格中,点击编辑器 (
),打开编辑器窗口。
请按照以下说明使用示例代码更新您的项目。
appsscript.json
- 打开
appsscript.json
,并将文件内容替换为以下内容:
{
"timeZone": "America/Toronto",
"oauthScopes": [
"https://www.googleapis.com/auth/cloud-platform",
"https://www.googleapis.com/auth/gmail.addons.execute",
"https://www.googleapis.com/auth/gmail.labels",
"https://www.googleapis.com/auth/gmail.modify",
"https://www.googleapis.com/auth/script.external_request",
"https://www.googleapis.com/auth/userinfo.email"
],
"addOns": {
"common": {
"name": "Sentiment Analysis",
"logoUrl": "https://fonts.gstatic.com/s/i/googlematerialicons/sentiment_extremely_dissatisfied/v6/black-24dp/1x/gm_sentiment_extremely_dissatisfied_black_24dp.png"
},
"gmail": {
"homepageTrigger": {
"runFunction": "onHomepageTrigger",
"enabled": true
}
}
},
"exceptionLogging": "STACKDRIVER",
"runtimeVersion": "V8"
}
- 点击保存
以保存项目。
Code.gs
- 打开 Code.gs,并将内容替换为以下代码:
/*
Copyright 2024-2025 Google LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
https://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Replace with your project ID
const PROJECT_ID = '{{{project_0.project_id | Project ID}}}';
// Location for your Vertex AI model
const VERTEX_AI_LOCATION = 'us-east4';
// Model ID to use for sentiment analysis
const MODEL_ID = 'gemini-2.0-flash';
/**
* Triggered when the add-on is opened from the Gmail homepage.
*
* @param {Object} e - The event object.
* @returns {Card} - The homepage card.
*/
function onHomepageTrigger(e) {
return buildHomepageCard();
}
/**
* Builds the main card displayed on the Gmail homepage.
*
* @returns {Card} - The homepage card.
*/
function buildHomepageCard() {
// Create a new card builder
const cardBuilder = CardService.newCardBuilder();
// Create a card header
const cardHeader = CardService.newCardHeader();
cardHeader.setImageUrl('https://fonts.gstatic.com/s/i/googlematerialicons/mail/v6/black-24dp/1x/gm_mail_black_24dp.png');
cardHeader.setImageStyle(CardService.ImageStyle.CIRCLE);
cardHeader.setTitle("Analyze your Gmail");
// Add the header to the card
cardBuilder.setHeader(cardHeader);
// Create a card section
const cardSection = CardService.newCardSection();
// Create buttons for generating sample emails and analyzing sentiment
const buttonSet = CardService.newButtonSet();
// Create "Generate sample emails" button
const generateButton = createFilledButton('Generate sample emails', 'generateSampleEmails', '#34A853');
buttonSet.addButton(generateButton);
// Create "Analyze emails" button
const analyzeButton = createFilledButton('Analyze emails', 'analyzeSentiment', '#FF0000');
buttonSet.addButton(analyzeButton);
// Add the button set to the section
cardSection.addWidget(buttonSet);
// Add the section to the card
cardBuilder.addSection(cardSection);
// Build and return the card
return cardBuilder.build();
}
/**
* Creates a filled text button with the specified text, function, and color.
*
* @param {string} text - The text to display on the button.
* @param {string} functionName - The name of the function to call when the button is clicked.
* @param {string} color - The background color of the button.
* @returns {TextButton} - The created text button.
*/
function createFilledButton(text, functionName, color) {
// Create a new text button
const textButton = CardService.newTextButton();
// Set the button text
textButton.setText(text);
// Set the action to perform when the button is clicked
const action = CardService.newAction();
action.setFunctionName(functionName);
textButton.setOnClickAction(action);
// Set the button style to filled
textButton.setTextButtonStyle(CardService.TextButtonStyle.FILLED);
// Set the background color
textButton.setBackgroundColor(color);
return textButton;
}
/**
* Creates a notification response with the specified text.
*
* @param {string} notificationText - The text to display in the notification.
* @returns {ActionResponse} - The created action response.
*/
function buildNotificationResponse(notificationText) {
// Create a new notification
const notification = CardService.newNotification();
notification.setText(notificationText);
// Create a new action response builder
const actionResponseBuilder = CardService.newActionResponseBuilder();
// Set the notification for the action response
actionResponseBuilder.setNotification(notification);
// Build and return the action response
return actionResponseBuilder.build();
}
/**
* Generates sample emails for testing the sentiment analysis.
*
* @returns {ActionResponse} - A notification confirming email generation.
*/
function generateSampleEmails() {
// Get the current user's email address
const userEmail = Session.getActiveUser().getEmail();
// Define sample emails
const sampleEmails = [
{
subject: 'Thank you for amazing service!',
body: 'Hi, I really enjoyed working with you. Thank you again!',
name: 'Customer A'
},
{
subject: 'Request for information',
body: 'Hello, I need more information on your recent product launch. Thank you.',
name: 'Customer B'
},
{
subject: 'Complaint!',
body: '',
htmlBody: `Hello, You are late in delivery, again.
Please contact me ASAP before I cancel our subscription.
`,
name: 'Customer C'
}
];
// Send each sample email
for (const email of sampleEmails) {
GmailApp.sendEmail(userEmail, email.subject, email.body, {
name: email.name,
htmlBody: email.htmlBody
});
}
// Return a notification
return buildNotificationResponse("Successfully generated sample emails");
}
/**
* Analyzes the sentiment of the first 10 threads in the inbox
* and labels them accordingly.
*
* @returns {ActionResponse} - A notification confirming completion.
*/
function analyzeSentiment() {
// Analyze and label emails
analyzeAndLabelEmailSentiment();
// Return a notification
return buildNotificationResponse("Successfully completed sentiment analysis");
}
/**
* Analyzes the sentiment of emails and applies appropriate labels.
*/
function analyzeAndLabelEmailSentiment() {
// Define label names
const labelNames = ["HAPPY TONE 😊", "NEUTRAL TONE 😐", "UPSET TONE 😡"];
// Get or create labels for each sentiment
const positiveLabel = GmailApp.getUserLabelByName(labelNames[0]) || GmailApp.createLabel(labelNames[0]);
const neutralLabel = GmailApp.getUserLabelByName(labelNames[1]) || GmailApp.createLabel(labelNames[1]);
const negativeLabel = GmailApp.getUserLabelByName(labelNames[2]) || GmailApp.createLabel(labelNames[2]);
// Get the first 10 threads in the inbox
const threads = GmailApp.getInboxThreads(0, 10);
// Iterate through each thread
for (const thread of threads) {
// Iterate through each message in the thread
const messages = thread.getMessages();
for (const message of messages) {
// Get the plain text body of the message
const emailBody = message.getPlainBody();
// Analyze the sentiment of the email body
const sentiment = processSentiment(emailBody);
// Apply the appropriate label based on the sentiment
if (sentiment === 'positive') {
thread.addLabel(positiveLabel);
} else if (sentiment === 'neutral') {
thread.addLabel(neutralLabel);
} else if (sentiment === 'negative') {
thread.addLabel(negativeLabel);
}
}
}
}
/**
* Sends the email text to Vertex AI for sentiment analysis.
*
* @param {string} emailText - The text of the email to analyze.
* @returns {string} - The sentiment of the email ('positive', 'negative', or 'neutral').
*/
function processSentiment(emailText) {
// Construct the API endpoint URL
const apiUrl = `https://${VERTEX_AI_LOCATION}-aiplatform.googleapis.com/v1/projects/${PROJECT_ID}/locations/${VERTEX_AI_LOCATION}/publishers/google/models/${MODEL_ID}:generateContent`;
// Prepare the request payload
const payload = {
contents: [
{
role: "user",
parts: [
{
text: `Analyze the sentiment of the following message: ${emailText}`
}
]
}
],
generationConfig: {
temperature: 0.9,
maxOutputTokens: 1024,
responseMimeType: "application/json",
// Expected response format for simpler parsing.
responseSchema: {
type: "object",
properties: {
response: {
type: "string",
enum: ["positive", "negative", "neutral"]
}
}
}
}
};
// Prepare the request options
const options = {
method: 'POST',
headers: {
'Authorization': `Bearer ${ScriptApp.getOAuthToken()}`
},
contentType: 'application/json',
muteHttpExceptions: true, // Set to true to inspect the error response
payload: JSON.stringify(payload)
};
// Make the API request
const response = UrlFetchApp.fetch(apiUrl, options);
// Parse the response. There are two levels of JSON responses to parse.
const parsedResponse = JSON.parse(response.getContentText());
const sentimentResponse = JSON.parse(parsedResponse.candidates[0].content.parts[0].text).response;
// Return the sentiment
return sentimentResponse;
}
点击保存
以保存项目。
任务 5. 部署插件
在此任务中,您将部署插件,然后验证安装是否成功。
部署插件
-
在标题栏中,依次点击部署 > 测试部署。
-
确认应用中显示了 Gmail,然后点击安装。
-
点击完成。
验证安装
- 刷新 Gmail 标签页。您应该会在右侧窗格中看到一个图标
。
问题排查
如果您在列表中没有看到该插件,请刷新浏览器窗口。
如果仍未显示插件,请返回 Apps 脚本项目,从测试部署窗口卸载该插件,然后重新安装。
任务 6. 运行插件
插件已准备就绪!在此任务中,您将打开并授权该插件,然后生成电子邮件来验证分析是否有效。
-
在 Gmail 中,在右侧窗格中点击情感分析 (
)。
-
侧边栏打开后,点击授权访问,授予插件运行权限。
系统会打开一个权限请求页面。选择您的电子邮件 (),然后点击屏幕上的选项以允许访问。
允许后,右侧会打开“情感分析”窗格。
- 在“情感分析”窗格中,点击生成示例电子邮件。
插件会生成示例电子邮件来测试分析。生成完成后,系统会显示一条消息,整个过程只需几秒钟。
-
等待收件箱中显示示例电子邮件。您可能需要刷新收件箱才能看到新邮件。
-
收件箱中显示示例电子邮件后,在“情感分析”窗格中,点击分析电子邮件。
插件屏幕底部将显示一条消息,表示分析已完成。
注意:分析电子邮件可能需要一段时间。您可以刷新页面,查看标签的状态。
插件会分析电子邮件,并为收件箱中的邮件添加适当的标签(“HAPPY TONE 😊
”“UPSET TONE 😡
”或“NEUTRAL TONE 😐
”)。
您可能需要刷新 Gmail 才能看到标签。
- 继续实验
您可以使用实验 Gmail 账号向另一个实验 Gmail 账号发送不同情绪(正面、负面、中性)的电子邮件,以测试此插件。不允许使用外部邮箱。观察插件如何分析和标记每封电子邮件。
注意:代码只会从收件箱中提取最近 10 封电子邮件,但您可以更改该值。
-
关闭插件:
使用完插件后,点击侧边栏右上角的 X 即可将其关闭。
点击检查我的进度以验证是否完成了以下目标:
进行情感分析。
恭喜!
您已成功完成“使用 Gemini 和 Vertex AI 进行 Gmail 情感分析”实验。
在本实验中,您学习了如何执行以下任务:
-
构建 Google Workspace 插件:开发一款扩展 Gmail 功能的实用工具。
-
将 Vertex AI 与 Google Workspace 集成:在 Gmail 插件中使用 Gemini 和 Vertex AI 的自然语言处理功能。
-
实现 OAuth2 身份验证:安全地授权插件访问用户数据。
-
进行情感分析:以编程方式分析电子邮件内容,确定情感基调。
-
利用 Apps 脚本:编写代码,与 Gmail 互动、管理用户界面并接入外部 API。
现在,您已经拥有了一个实用的 Gmail 插件,它可以帮助您确定电子邮件的优先级并改进工作流程。欢迎进一步探索此插件,例如自定义情感分析或添加新功能。
Google Cloud 培训和认证
…可帮助您充分利用 Google Cloud 技术。我们的课程会讲解各项技能与最佳实践,可帮助您迅速上手使用并继续学习更深入的知识。我们提供从基础到高级的全方位培训,并有点播、直播和虚拟三种方式选择,让您可以按照自己的日程安排学习时间。各项认证可以帮助您核实并证明您在 Google Cloud 技术方面的技能与专业知识。
本手册的最后更新时间:2025 年 3 月 25 日
本实验的最后测试时间:2025 年 2 月 25 日
版权所有 2025 Google LLC 保留所有权利。Google 和 Google 徽标是 Google LLC 的商标。其他所有公司名和产品名可能是其各自相关公司的商标。