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
127 changes: 83 additions & 44 deletions gmail-sentiment-analysis/Cards.gs
Original file line number Diff line number Diff line change
Expand Up @@ -15,54 +15,93 @@ limitations under the License.
*/

/**
* Builds the card to display in the side panel of gmail.
* @return {CardService.Card} The card to show to the user.
* Builds the main card displayed on the Gmail homepage.
*
* @returns {Card} - The homepage card.
*/

function buildHomepageCard() {
const imageUrl = 'https://fonts.gstatic.com/s/i/googlematerialicons/dynamic_feed/v6/black-24dp/1x/gm_dynamic_feed_black_24dp.png';

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

const analyzeSentimentAction = CardService.newAction()
.setFunctionName('analyzeSentiment');
const analyzeSentimentBtn = CardService.newTextButton()
.setText('Analyze emails')
.setOnClickAction(analyzeSentimentAction)
.setTextButtonStyle(CardService.TextButtonStyle.FILLED)
.setBackgroundColor('#FF0000');

const generateSampleEmailAction = CardService.newAction()
.setFunctionName('generateSampleEmails');

const generateSampleEmailsBtn = CardService.newTextButton()
.setText('Generate sample emails')
.setOnClickAction(generateSampleEmailAction)
.setTextButtonStyle(CardService.TextButtonStyle.FILLED)
.setBackgroundColor('#34A853');

const buttonSet = CardService.newButtonSet()
.addButton(generateSampleEmailsBtn)
.addButton(analyzeSentimentBtn);

const section = CardService.newCardSection()
.addWidget(buttonSet);

const card = CardService.newCardBuilder()
.setHeader(cardHeader)
.addSection(section);

return card.build();
// 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();
}

function buildNotificationResponse(notificationText) {
const notification = CardService.newNotification().setText(notificationText);
/**
* 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);

const actionResponse = CardService.newActionResponseBuilder()
.setNotification(notification);
// Set the button style to filled
textButton.setTextButtonStyle(CardService.TextButtonStyle.FILLED);

return actionResponse.build();
// 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();
}
8 changes: 5 additions & 3 deletions gmail-sentiment-analysis/Code.gs
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,11 @@ limitations under the License.
*/

/**
* Callback for rendering the homepage card.
* @return {CardService.Card} The card to show to the user.
* 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();
}
}
118 changes: 59 additions & 59 deletions gmail-sentiment-analysis/Gmail.gs
Original file line number Diff line number Diff line change
Expand Up @@ -15,95 +15,95 @@ limitations under the License.
*/

/**
* Callback for initiating the sentiment analysis.
* @return {CardService.Card} The card to show to the user.
* 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 recent emails in the inbox and labels threads with
* the appropriate sentiment label.
* Analyzes the sentiment of emails and applies appropriate labels.
*/
function analyzeAndLabelEmailSentiment() {
const positiveLabelName = "HAPPY TONE 😊";
const neutralLabelName = "NEUTRAL TONE 😐";
const negativeLabelName = "UPSET TONE 😡";
const maxThreads = 10;
// Define label names
const labelNames = ["HAPPY TONE 😊", "NEUTRAL TONE 😐", "UPSET TONE 😡"];

// Get the label, or create it if it doesn't exist.
const positiveLabel = GmailApp.getUserLabelByName(positiveLabelName) || GmailApp.createLabel(positiveLabelName);
const neutralLabel = GmailApp.getUserLabelByName(neutralLabelName) || GmailApp.createLabel(neutralLabelName);
const negativeLabel = GmailApp.getUserLabelByName(negativeLabelName) || GmailApp.createLabel(negativeLabelName);
// 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 'maxThreads' threads from the inbox.
const threads = GmailApp.getInboxThreads(0, maxThreads);
// Get the first 10 threads in the inbox
const threads = GmailApp.getInboxThreads(0, 10);

// Process each thread.
// Iterate through each thread
for (const thread of threads) {
// Iterate through each message in the thread
const messages = thread.getMessages();

// Process each message within the thread.
for (const message of messages) {
const emailText = message.getPlainBody();
const sentiment = processSentiment(emailText);

switch (sentiment) {
case 'positive':
thread.addLabel(positiveLabel);
break;
case 'neutral':
thread.addLabel(neutralLabel);
break;
case 'negative':
thread.addLabel(negativeLabel);
break;
default:
break;
// 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);
}
}
}
}

/**
* Create sample emails
* Generates sample emails for testing the sentiment analysis.
*
* @returns {ActionResponse} - A notification confirming email generation.
*/
function generateSampleEmails() {
// Get active user's email
// Get the current user's email address
const userEmail = Session.getActiveUser().getEmail();

// Send emails
GmailApp.sendEmail(
userEmail,
'Thank you for amazing service!',
'Hi, I really enjoyed working with you. Thank you again!',
// Define sample emails
const sampleEmails = [
{
name: 'Customer A',
subject: 'Thank you for amazing service!',
body: 'Hi, I really enjoyed working with you. Thank you again!',
name: 'Customer A'
},
);

GmailApp.sendEmail(
userEmail,
'Request for information',
'Hello, I need more information on your recent product launch. Thank you.',
{
name: 'Customer B',
subject: 'Request for information',
body: 'Hello, I need more information on your recent product launch. Thank you.',
name: 'Customer B'
},
);

GmailApp.sendEmail(
userEmail,
'Complaint!',
'',
{
name: 'Customer C',
subject: 'Complaint!',
body: '',
htmlBody: `<p>Hello, You are late in delivery, again.</p>
<p>Please contact me ASAP before I cancel our subscription.</p>`,
},
);
<p>Please contact me ASAP before I cancel our subscription.</p>`,
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");
}
}
Loading
Loading