Skip to content

Commit 3a9c681

Browse files
committed
chore: Update Gmail sentiment analysis for the lab
1 parent 82f025b commit 3a9c681

File tree

4 files changed

+58
-39
lines changed

4 files changed

+58
-39
lines changed

gmail-sentiment-analysis/Cards.gs

+5-10
Original file line numberDiff line numberDiff line change
@@ -16,28 +16,24 @@ limitations under the License.
1616

1717

1818
/**
19-
* Builds the card for to display in the sidepanel of gmail.
19+
* Builds the card to display in the sidepanel of gmail.
2020
* @return {CardService.Card} The card to show to the user.
2121
*/
2222

2323
function buildCard_GmailHome(notifyOk = false) {
24-
const imageUrl = 'https://icons.iconarchive.com/icons/roundicons/100-free-solid/48/spy-icon.png';
25-
const image = CardService.newImage()
26-
.setImageUrl(imageUrl);
24+
const imageUrl = 'https://fonts.gstatic.com/s/i/googlematerialicons/dynamic_feed/v6/black-24dp/1x/gm_dynamic_feed_black_24dp.png';
2725

2826
const cardHeader = CardService.newCardHeader()
2927
.setImageUrl(imageUrl)
3028
.setImageStyle(CardService.ImageStyle.CIRCLE)
3129
.setTitle("Analyze your GMail");
3230

33-
const action = CardService.newAction()
34-
.setFunctionName('analyzeSentiment');
31+
const action = CardService.newAction().setFunctionName('analyzeSentiment');
3532
const button = CardService.newTextButton()
3633
.setText('Identify angry customers')
3734
.setOnClickAction(action)
3835
.setTextButtonStyle(CardService.TextButtonStyle.FILLED);
39-
const buttonSet = CardService.newButtonSet()
40-
.addButton(button);
36+
const buttonSet = CardService.newButtonSet().addButton(button);
4137

4238
const section = CardService.newCardSection()
4339
.setHeader("Emails sentiment analysis")
@@ -51,9 +47,8 @@ function buildCard_GmailHome(notifyOk = false) {
5147
* This builds the card that contains the footer that informs
5248
* the user about the successful execution of the Add-on.
5349
*/
54-
5550
if (notifyOk == true) {
56-
let fixedFooter = CardService.newFixedFooter()
51+
const fixedFooter = CardService.newFixedFooter()
5752
.setPrimaryButton(
5853
CardService.newTextButton()
5954
.setText("Analysis complete")

gmail-sentiment-analysis/Gmail.gs

+33-17
Original file line numberDiff line numberDiff line change
@@ -20,30 +20,46 @@ limitations under the License.
2020
*/
2121

2222
function analyzeSentiment() {
23-
emailSentiment();
23+
analyzeAndLabelEmailSentiment();
2424
return buildCard_GmailHome(true);
2525
}
2626

2727
/**
28-
* Gets the last 10 threads in the inbox and the corresponding messages.
29-
* Fetches the label that should be applied to negative messages.
30-
* The processSentiment is called on each message
31-
* and tested with RegExp to check for a negative answer from the model
28+
* Analyzes the sentiment of recent emails in the inbox and labels threads with
29+
* negative sentiment as "UPSET TONE 😡".
3230
*/
31+
function analyzeAndLabelEmailSentiment() {
32+
const labelName = "UPSET TONE 😡";
33+
const maxThreads = 10;
3334

34-
function emailSentiment() {
35-
const threads = GmailApp.getInboxThreads(0, 10);
36-
const msgs = GmailApp.getMessagesForThreads(threads);
37-
const label_upset = GmailApp.getUserLabelByName("UPSET TONE 😡");
38-
let currentPrediction;
39-
40-
for (let i = 0; i < msgs.length; i++) {
41-
for (let j = 0; j < msgs[i].length; j++) {
42-
let emailText = msgs[i][j].getPlainBody();
43-
currentPrediction = processSentiment(emailText);
44-
if (currentPrediction === true) {
45-
label_upset.addToThread(msgs[i][j].getThread());
35+
// Get the label, or create it if it doesn't exist.
36+
const label = GmailApp.getUserLabelByName(labelName) || GmailApp.createLabel(labelName);
37+
38+
// Get the first 'maxThreads' threads from the inbox.
39+
const threads = GmailApp.getInboxThreads(0, maxThreads);
40+
41+
// Process each thread.
42+
for (const thread of threads) {
43+
const messages = thread.getMessages();
44+
45+
// Process each message within the thread.
46+
for (const message of messages) {
47+
const emailText = message.getPlainBody();
48+
const isUpset = isNegativeSentiment(emailText);
49+
50+
if (isUpset) {
51+
label.addToThread(thread);
4652
}
4753
}
4854
}
4955
}
56+
57+
/**
58+
* Determines if the given text has a negative sentiment.
59+
*
60+
* @param {string} text - The text to analyze.
61+
* @returns {boolean} True if the sentiment is negative, false otherwise.
62+
*/
63+
function isNegativeSentiment(text) {
64+
return processSentiment(text);
65+
}

gmail-sentiment-analysis/Vertex.gs

+19-10
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ See the License for the specific language governing permissions and
1414
limitations under the License.
1515
*/
1616

17-
const PROJECT_ID = '[ADD YOUR GCP PROJECT ID HERE]';
18-
const VERTEX_AI_LOCATION = 'europe-west2';
17+
const PROJECT_ID = 'qwiklabs-gcp-01-e6ca251b4715';
18+
const VERTEX_AI_LOCATION = 'us-central1';
1919
const MODEL_ID = 'gemini-1.5-pro-002';
2020

2121
/**
@@ -28,11 +28,7 @@ const MODEL_ID = 'gemini-1.5-pro-002';
2828
*/
2929

3030
function processSentiment(emailText) {
31-
const prompt = `
32-
Analyze the following message: ${emailText}.
33-
If the sentiment of this message is negative, answer with FALSE.
34-
If the sentiment of this message is neutral or positive, answer with TRUE.
35-
Do not use any other words than the ones requested in this prompt as a response!`;
31+
const prompt = `Analyze the sentiment of the following message: ${emailText}`;
3632

3733
const request = {
3834
"contents": [{
@@ -44,6 +40,20 @@ function processSentiment(emailText) {
4440
"generationConfig": {
4541
"temperature": 0.9,
4642
"maxOutputTokens": 1024,
43+
"responseMimeType": "application/json",
44+
"responseSchema": {
45+
"type": "object",
46+
"properties": {
47+
"response": {
48+
"type": "string",
49+
"enum": [
50+
"positive",
51+
"negative",
52+
"neutral",
53+
]
54+
}
55+
}
56+
}
4757
}
4858
};
4959

@@ -62,8 +72,7 @@ function processSentiment(emailText) {
6272

6373
const response = UrlFetchApp.fetch(url, fetchOptions);
6474
const payload = JSON.parse(response.getContentText());
75+
const text = JSON.parse(payload.candidates[0].content.parts[0].text);
6576

66-
const regex = /FALSE/;
67-
68-
return regex.test(payload.candidates[0].content.parts[0].text);
77+
return text.response === 'negative';
6978
}

gmail-sentiment-analysis/appsscript.json

+1-2
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,13 @@
55
"https://www.googleapis.com/auth/cloud-platform",
66
"https://www.googleapis.com/auth/script.locale",
77
"https://www.googleapis.com/auth/gmail.addons.execute",
8-
"https://mail.google.com/",
98
"https://www.googleapis.com/auth/gmail.labels",
109
"https://www.googleapis.com/auth/gmail.modify"
1110
],
1211
"addOns": {
1312
"common": {
1413
"name": "Productivity toolbox",
15-
"logoUrl": "https://icons.iconarchive.com/icons/roundicons/100-free-solid/64/spy-icon.png",
14+
"logoUrl": "https://fonts.gstatic.com/s/i/googlematerialicons/dynamic_feed/v6/black-24dp/1x/gm_dynamic_feed_black_24dp.png",
1615
"useLocaleFromApp": true
1716
},
1817
"gmail": {

0 commit comments

Comments
 (0)