diff --git a/gmail-sentiment-analysis/.clasp.json b/gmail-sentiment-analysis/.clasp.json new file mode 100644 index 000000000..8206fa91c --- /dev/null +++ b/gmail-sentiment-analysis/.clasp.json @@ -0,0 +1,3 @@ +{ + "scriptId": "1Z2gfvr0oYn68ppDtQbv0qIuKKVWhvwOTr-gCE0GFKVjNk8NDlpfJAGAr" +} diff --git a/gmail-sentiment-analysis/Cards.gs b/gmail-sentiment-analysis/Cards.gs index 566c1ca47..6a07c735d 100644 --- a/gmail-sentiment-analysis/Cards.gs +++ b/gmail-sentiment-analysis/Cards.gs @@ -20,8 +20,8 @@ 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); @@ -29,7 +29,7 @@ function buildCard_GmailHome(notifyOk=false){ .setImageUrl(imageUrl) .setImageStyle(CardService.ImageStyle.CIRCLE) .setTitle("Analyze your GMail"); - + const action = CardService.newAction() .setFunctionName('analyzeSentiment'); const button = CardService.newTextButton() @@ -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(); -} \ No newline at end of file +} diff --git a/gmail-sentiment-analysis/Code.gs b/gmail-sentiment-analysis/Code.gs index 7b353e735..b599ca2cf 100644 --- a/gmail-sentiment-analysis/Code.gs +++ b/gmail-sentiment-analysis/Code.gs @@ -21,4 +21,3 @@ limitations under the License. function onHomepage(e) { return buildCard_GmailHome(); } - diff --git a/gmail-sentiment-analysis/Gmail.gs b/gmail-sentiment-analysis/Gmail.gs index 1bf87b1a9..7e4b3c621 100644 --- a/gmail-sentiment-analysis/Gmail.gs +++ b/gmail-sentiment-analysis/Gmail.gs @@ -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); } @@ -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()); } } } -} \ No newline at end of file +} diff --git a/gmail-sentiment-analysis/Vertex.gs b/gmail-sentiment-analysis/Vertex.gs index f6299ecde..25d1994a3 100644 --- a/gmail-sentiment-analysis/Vertex.gs +++ b/gmail-sentiment-analysis/Vertex.gs @@ -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 @@ -29,36 +28,37 @@ 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()); @@ -66,32 +66,4 @@ function processSentiment(emailText) { 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(), - } -} \ No newline at end of file diff --git a/gmail-sentiment-analysis/appsscript.json b/gmail-sentiment-analysis/appsscript.json index 80b231e9a..cf6273f63 100644 --- a/gmail-sentiment-analysis/appsscript.json +++ b/gmail-sentiment-analysis/appsscript.json @@ -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", @@ -24,4 +24,4 @@ }, "exceptionLogging": "STACKDRIVER", "runtimeVersion": "V8" -} \ No newline at end of file +}