Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions gmail-sentiment-analysis/.clasp.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"scriptId": "1Z2gfvr0oYn68ppDtQbv0qIuKKVWhvwOTr-gCE0GFKVjNk8NDlpfJAGAr"
}
38 changes: 19 additions & 19 deletions gmail-sentiment-analysis/Cards.gs
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,16 @@ limitations under the License.
* @return {CardService.Card} The card to show to the user.
*/

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

const cardHeader = CardService.newCardHeader()
.setImageUrl(imageUrl)
.setImageStyle(CardService.ImageStyle.CIRCLE)
.setTitle("Analyze your GMail");

const action = CardService.newAction()
.setFunctionName('analyzeSentiment');
const button = CardService.newTextButton()
Expand All @@ -47,21 +47,21 @@ function buildCard_GmailHome(notifyOk=false){
.setHeader(cardHeader)
.addSection(section);

/**
* This builds the card that contains the footer that informs
* the user about the successful execution of the Add-on.
*/
/**
* This builds the card that contains the footer that informs
* the user about the successful execution of the Add-on.
*/

if(notifyOk==true){
let fixedFooter = CardService.newFixedFooter()
.setPrimaryButton(
CardService.newTextButton()
.setText("Analysis complete")
.setOnClickAction(
CardService.newAction()
.setFunctionName(
"buildCard_GmailHome")));
card.setFixedFooter(fixedFooter);
}
if (notifyOk == true) {
let fixedFooter = CardService.newFixedFooter()
.setPrimaryButton(
CardService.newTextButton()
.setText("Analysis complete")
.setOnClickAction(
CardService.newAction()
.setFunctionName(
"buildCard_GmailHome")));
card.setFixedFooter(fixedFooter);
}
return card.build();
}
}
1 change: 0 additions & 1 deletion gmail-sentiment-analysis/Code.gs
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,3 @@ limitations under the License.
function onHomepage(e) {
return buildCard_GmailHome();
}

8 changes: 4 additions & 4 deletions gmail-sentiment-analysis/Gmail.gs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ limitations under the License.
* @return {CardService.Card} The card to show to the user.
*/

function analyzeSentiment(){
function analyzeSentiment() {
emailSentiment();
return buildCard_GmailHome(true);
}
Expand All @@ -37,13 +37,13 @@ function emailSentiment() {
const label_upset = GmailApp.getUserLabelByName("UPSET TONE 😡");
let currentPrediction;

for (let i = 0 ; i < msgs.length; i++) {
for (let i = 0; i < msgs.length; i++) {
for (let j = 0; j < msgs[i].length; j++) {
let emailText = msgs[i][j].getPlainBody();
currentPrediction = processSentiment(emailText);
if(currentPrediction === true){
if (currentPrediction === true) {
label_upset.addToThread(msgs[i][j].getThread());
}
}
}
}
}
48 changes: 10 additions & 38 deletions gmail-sentiment-analysis/Vertex.gs
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,9 @@ See the License for the specific language governing permissions and
limitations under the License.
*/

const PROJECT_ID = [ADD YOUR GCP PROJECT ID HERE];
const PROJECT_ID = '[ADD YOUR GCP PROJECT ID HERE]';
const VERTEX_AI_LOCATION = 'europe-west2';
const MODEL_ID = 'gemini-1.5-pro-002';
const SERVICE_ACCOUNT_KEY = PropertiesService.getScriptProperties().getProperty('service_account_key');

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

function processSentiment(emailText) {
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!`;
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!`;

const request = {
"contents": [{
"role": "user",
"parts": [{
"text": prompt
"text": prompt,
}]
}],
"generationConfig": {
"temperature": 0.9,
"maxOutputTokens": 1024,

}
};

const credentials = credentialsForVertexAI();

const fetchOptions = {
method: 'POST',
headers: {
'Authorization': `Bearer ${credentials.accessToken}`
'Authorization': `Bearer ${ScriptApp.getOAuthToken()}`
},
contentType: 'application/json',
muteHttpExceptions: true,
payload: JSON.stringify(request)
payload: JSON.stringify(request),
}

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

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

const regex = /FALSE/;

return regex.test(payload.candidates[0].content.parts[0].text);

}

/**
* Gets credentials required to call Vertex API using a Service Account.
* Requires use of Service Account Key stored with project
*
* @return {!Object} Containing the Cloud Project Id and the access token.
*/

function credentialsForVertexAI() {
const credentials = SERVICE_ACCOUNT_KEY;
if (!credentials) {
throw new Error("service_account_key script property must be set.");
}

const parsedCredentials = JSON.parse(credentials);

const service = OAuth2.createService("Vertex")
.setTokenUrl('https://oauth2.googleapis.com/token')
.setPrivateKey(parsedCredentials['private_key'])
.setIssuer(parsedCredentials['client_email'])
.setPropertyStore(PropertiesService.getScriptProperties())
.setScope("https://www.googleapis.com/auth/cloud-platform");
return {
projectId: parsedCredentials['project_id'],
accessToken: service.getAccessToken(),
}
}
22 changes: 11 additions & 11 deletions gmail-sentiment-analysis/appsscript.json
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
{
"timeZone": "Europe/Madrid",
"dependencies": {
"libraries": [
{
"userSymbol": "OAuth2",
"version": "43",
"libraryId": "1B7FSrk5Zi6L1rSxxTDgDEUsPzlukDsi4KGuTMorsTQHhGBzBkMun4iDF"
}
]
},
"timeZone": "America/Los_Angeles",
"oauthScopes": [
"https://www.googleapis.com/auth/script.external_request",
"https://www.googleapis.com/auth/cloud-platform",
"https://www.googleapis.com/auth/script.locale",
"https://www.googleapis.com/auth/gmail.addons.execute",
"https://mail.google.com/",
"https://www.googleapis.com/auth/gmail.labels",
"https://www.googleapis.com/auth/gmail.modify"
],
"addOns": {
"common": {
"name": "Productivity toolbox",
Expand All @@ -24,4 +24,4 @@
},
"exceptionLogging": "STACKDRIVER",
"runtimeVersion": "V8"
}
}
Loading