Skip to content

Commit 82f025b

Browse files
authored
chore: Sync Gmail sentiment analyis to an Apps Script project (googleworkspace#510)
1 parent 1e5f10a commit 82f025b

File tree

6 files changed

+47
-73
lines changed

6 files changed

+47
-73
lines changed

gmail-sentiment-analysis/.clasp.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"scriptId": "1Z2gfvr0oYn68ppDtQbv0qIuKKVWhvwOTr-gCE0GFKVjNk8NDlpfJAGAr"
3+
}

gmail-sentiment-analysis/Cards.gs

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -20,16 +20,16 @@ limitations under the License.
2020
* @return {CardService.Card} The card to show to the user.
2121
*/
2222

23-
function buildCard_GmailHome(notifyOk=false){
24-
const imageUrl ='https://icons.iconarchive.com/icons/roundicons/100-free-solid/48/spy-icon.png';
23+
function buildCard_GmailHome(notifyOk = false) {
24+
const imageUrl = 'https://icons.iconarchive.com/icons/roundicons/100-free-solid/48/spy-icon.png';
2525
const image = CardService.newImage()
2626
.setImageUrl(imageUrl);
2727

2828
const cardHeader = CardService.newCardHeader()
2929
.setImageUrl(imageUrl)
3030
.setImageStyle(CardService.ImageStyle.CIRCLE)
3131
.setTitle("Analyze your GMail");
32-
32+
3333
const action = CardService.newAction()
3434
.setFunctionName('analyzeSentiment');
3535
const button = CardService.newTextButton()
@@ -47,21 +47,21 @@ function buildCard_GmailHome(notifyOk=false){
4747
.setHeader(cardHeader)
4848
.addSection(section);
4949

50-
/**
51-
* This builds the card that contains the footer that informs
52-
* the user about the successful execution of the Add-on.
53-
*/
50+
/**
51+
* This builds the card that contains the footer that informs
52+
* the user about the successful execution of the Add-on.
53+
*/
5454

55-
if(notifyOk==true){
56-
let fixedFooter = CardService.newFixedFooter()
57-
.setPrimaryButton(
58-
CardService.newTextButton()
59-
.setText("Analysis complete")
60-
.setOnClickAction(
61-
CardService.newAction()
62-
.setFunctionName(
63-
"buildCard_GmailHome")));
64-
card.setFixedFooter(fixedFooter);
65-
}
55+
if (notifyOk == true) {
56+
let fixedFooter = CardService.newFixedFooter()
57+
.setPrimaryButton(
58+
CardService.newTextButton()
59+
.setText("Analysis complete")
60+
.setOnClickAction(
61+
CardService.newAction()
62+
.setFunctionName(
63+
"buildCard_GmailHome")));
64+
card.setFixedFooter(fixedFooter);
65+
}
6666
return card.build();
67-
}
67+
}

gmail-sentiment-analysis/Code.gs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,3 @@ limitations under the License.
2121
function onHomepage(e) {
2222
return buildCard_GmailHome();
2323
}
24-

gmail-sentiment-analysis/Gmail.gs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ limitations under the License.
1919
* @return {CardService.Card} The card to show to the user.
2020
*/
2121

22-
function analyzeSentiment(){
22+
function analyzeSentiment() {
2323
emailSentiment();
2424
return buildCard_GmailHome(true);
2525
}
@@ -37,13 +37,13 @@ function emailSentiment() {
3737
const label_upset = GmailApp.getUserLabelByName("UPSET TONE 😡");
3838
let currentPrediction;
3939

40-
for (let i = 0 ; i < msgs.length; i++) {
40+
for (let i = 0; i < msgs.length; i++) {
4141
for (let j = 0; j < msgs[i].length; j++) {
4242
let emailText = msgs[i][j].getPlainBody();
4343
currentPrediction = processSentiment(emailText);
44-
if(currentPrediction === true){
44+
if (currentPrediction === true) {
4545
label_upset.addToThread(msgs[i][j].getThread());
4646
}
4747
}
4848
}
49-
}
49+
}

gmail-sentiment-analysis/Vertex.gs

Lines changed: 10 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,9 @@ 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];
17+
const PROJECT_ID = '[ADD YOUR GCP PROJECT ID HERE]';
1818
const VERTEX_AI_LOCATION = 'europe-west2';
1919
const MODEL_ID = 'gemini-1.5-pro-002';
20-
const SERVICE_ACCOUNT_KEY = PropertiesService.getScriptProperties().getProperty('service_account_key');
2120

2221
/**
2322
* Packages prompt and necessary settings, then sends a request to
@@ -29,69 +28,42 @@ const SERVICE_ACCOUNT_KEY = PropertiesService.getScriptProperties().getProperty(
2928
*/
3029

3130
function processSentiment(emailText) {
32-
const prompt = `Analyze the following message: ${emailText}. If the sentiment of this message is negative, answer with FALSE. If the sentiment of this message is neutral or positive, answer with TRUE. Do not use any other words than the ones requested in this prompt as a response!`;
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!`;
3336

3437
const request = {
3538
"contents": [{
3639
"role": "user",
3740
"parts": [{
38-
"text": prompt
41+
"text": prompt,
3942
}]
4043
}],
4144
"generationConfig": {
4245
"temperature": 0.9,
4346
"maxOutputTokens": 1024,
44-
4547
}
4648
};
4749

48-
const credentials = credentialsForVertexAI();
49-
5050
const fetchOptions = {
5151
method: 'POST',
5252
headers: {
53-
'Authorization': `Bearer ${credentials.accessToken}`
53+
'Authorization': `Bearer ${ScriptApp.getOAuthToken()}`
5454
},
5555
contentType: 'application/json',
5656
muteHttpExceptions: true,
57-
payload: JSON.stringify(request)
57+
payload: JSON.stringify(request),
5858
}
5959

6060
const url = `https://${VERTEX_AI_LOCATION}-aiplatform.googleapis.com/v1/projects/${PROJECT_ID}/`
61-
+ `locations/${VERTEX_AI_LOCATION}/publishers/google/models/${MODEL_ID}:generateContent`
61+
+ `locations/${VERTEX_AI_LOCATION}/publishers/google/models/${MODEL_ID}:generateContent`
6262

6363
const response = UrlFetchApp.fetch(url, fetchOptions);
6464
const payload = JSON.parse(response.getContentText());
6565

6666
const regex = /FALSE/;
6767

6868
return regex.test(payload.candidates[0].content.parts[0].text);
69-
7069
}
71-
72-
/**
73-
* Gets credentials required to call Vertex API using a Service Account.
74-
* Requires use of Service Account Key stored with project
75-
*
76-
* @return {!Object} Containing the Cloud Project Id and the access token.
77-
*/
78-
79-
function credentialsForVertexAI() {
80-
const credentials = SERVICE_ACCOUNT_KEY;
81-
if (!credentials) {
82-
throw new Error("service_account_key script property must be set.");
83-
}
84-
85-
const parsedCredentials = JSON.parse(credentials);
86-
87-
const service = OAuth2.createService("Vertex")
88-
.setTokenUrl('https://oauth2.googleapis.com/token')
89-
.setPrivateKey(parsedCredentials['private_key'])
90-
.setIssuer(parsedCredentials['client_email'])
91-
.setPropertyStore(PropertiesService.getScriptProperties())
92-
.setScope("https://www.googleapis.com/auth/cloud-platform");
93-
return {
94-
projectId: parsedCredentials['project_id'],
95-
accessToken: service.getAccessToken(),
96-
}
97-
}
Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
{
2-
"timeZone": "Europe/Madrid",
3-
"dependencies": {
4-
"libraries": [
5-
{
6-
"userSymbol": "OAuth2",
7-
"version": "43",
8-
"libraryId": "1B7FSrk5Zi6L1rSxxTDgDEUsPzlukDsi4KGuTMorsTQHhGBzBkMun4iDF"
9-
}
10-
]
11-
},
2+
"timeZone": "America/Los_Angeles",
3+
"oauthScopes": [
4+
"https://www.googleapis.com/auth/script.external_request",
5+
"https://www.googleapis.com/auth/cloud-platform",
6+
"https://www.googleapis.com/auth/script.locale",
7+
"https://www.googleapis.com/auth/gmail.addons.execute",
8+
"https://mail.google.com/",
9+
"https://www.googleapis.com/auth/gmail.labels",
10+
"https://www.googleapis.com/auth/gmail.modify"
11+
],
1212
"addOns": {
1313
"common": {
1414
"name": "Productivity toolbox",
@@ -24,4 +24,4 @@
2424
},
2525
"exceptionLogging": "STACKDRIVER",
2626
"runtimeVersion": "V8"
27-
}
27+
}

0 commit comments

Comments
 (0)