Skip to content

Commit

Permalink
Update Code.js post-linting (googleworkspace#55)
Browse files Browse the repository at this point in the history
* Update Code.js

* Update README.md

Test links
  • Loading branch information
aliciawilliams authored and asrivas committed Aug 28, 2019
1 parent 7597176 commit 6437e31
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 46 deletions.
4 changes: 2 additions & 2 deletions feedback-sentiment-analysis/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@ Google Sheets can come from many sources: Google Form responses, notes columns,
descriptions, and more. As humans we can make sense of this data by reading it,
but this becomes difficult as your data grows into hundreds or thousands of rows.

The [Cloud Natural Language API](https://cloud.google.com/natural-language/docs/)
The <a href="https://cloud.google.com/natural-language/docs/" target="_blank">Cloud Natural Language API</a>
takes the machine learning technology used by Google Search and Google Assistant
and makes it possible for anyone to perform sentiment and entity analysis on
their own data.

This solution uses [Apps Script](https://developers.google.com/apps-script/) in
This solution uses <a href="https://developers.google.com/apps-script/" target="_blank">Apps Script</a> in
a Google Sheet to perform entity and sentiment analysis on vacation rental reviews
using the Cloud Natural Language API.

Expand Down
91 changes: 47 additions & 44 deletions feedback-sentiment-analysis/src/Code.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,22 @@ var COLUMN_NAME = {
LANGUAGE: 'language_detected',
TRANSLATION: 'comments_english',
ENTITY: 'entity_sentiment',
ID: 'id'
ID: 'id',
};

/**
* Creates a Demo menu in Google Spreadsheets.
*/
function onOpen() {
SpreadsheetApp.getUi()
.createMenu('Demo Tools')
.addItem('Mark entities and sentiment', 'markEntitySentiment')
.addToUi();
.createMenu('Demo Tools')
.addItem('Mark entities and sentiment', 'markEntitySentiment')
.addToUi();
};

/**
* Analyzes entities and sentiment for each comment in
* Review Data sheet and copies results into the
* Analyzes entities and sentiment for each comment in
* Review Data sheet and copies results into the
* Entity Sentiment Data sheet.
*/
function markEntitySentiment() {
Expand All @@ -33,81 +33,84 @@ function markEntitySentiment() {
var numRows = rows.getNumRows();
var values = rows.getValues();
var headerRow = values[0];

// Checks to see if "Entity Sentiment Data" sheet is present, and
// if not, creates a new sheet and sets the header row.
var entitySheet = ss.getSheetByName('Entity Sentiment Data');
if (entitySheet == null) {
ss.insertSheet('Entity Sentiment Data');
var entitySheet = ss.getSheetByName('Entity Sentiment Data');
var esHeaderRange = entitySheet.getRange(1,1,1,6);
var esHeader = [['Review ID','Entity','Salience','Sentiment Score',
'Sentiment Magnitude','Number of mentions']];
esHeaderRange.setValues(esHeader);
ss.insertSheet('Entity Sentiment Data');
var entitySheet = ss.getSheetByName('Entity Sentiment Data');
var esHeaderRange = entitySheet.getRange(1, 1, 1, 6);
var esHeader = [['Review ID', 'Entity', 'Salience', 'Sentiment Score',
'Sentiment Magnitude', 'Number of mentions']];
esHeaderRange.setValues(esHeader);
};
// Finds the column index for comments, language_detected,

// Finds the column index for comments, language_detected,
// and comments_english columns.
var translationColumnIdx = headerRow.indexOf(COLUMN_NAME.TRANSLATION);
var entityColumnIdx = headerRow.indexOf(COLUMN_NAME.ENTITY);
var idColumnIdx = headerRow.indexOf(COLUMN_NAME.ID);
if (entityColumnIdx == -1) {
Browser.msgBox("Error: Could not find the column named " + COLUMN_NAME.ENTITY +
". Please create and empty column with header \"entity_sentiment\" on the Review Data tab.");
Browser.msgBox('Error: Could not find the column named ' + COLUMN_NAME.ENTITY +
'. Please create and empty column with header "entity_sentiment" '+
'on the Review Data tab.');
return; // bail
};
ss.toast("Analyzing entities and sentiment...");

ss.toast('Analyzing entities and sentiment...');
for (var i = 0; i < numRows; ++i) {
var value = values[i];
var commentEnCellVal = value[translationColumnIdx];
var entityCellVal = value[entityColumnIdx];
var reviewId = value[idColumnIdx];
// Calls retrieveEntitySentiment function for each row that has a comment

// Calls retrieveEntitySentiment function for each row that has a comment
// and also an empty entity_sentiment cell value.
if(commentEnCellVal && !entityCellVal) {
var nlData = retrieveEntitySentiment(commentEnCellVal);
// Pastes each entity and sentiment score into Entity Sentiment Data sheet.
var newValues = []
for each (var entity in nlData.entities) {
var row = [reviewId, entity.name, entity.salience, entity.sentiment.score,
entity.sentiment.magnitude, entity.mentions.length
];
newValues.push(row);
}
if(newValues.length) {
entitySheet.getRange(entitySheet.getLastRow() + 1, 1, newValues.length, newValues[0].length).setValues(newValues);
if (commentEnCellVal && !entityCellVal) {
var nlData = retrieveEntitySentiment(commentEnCellVal);
// Pastes each entity and sentiment score into Entity Sentiment Data sheet.
var newValues = [];
var entities = nlData.entities;
entities.forEach(function(entity) {
var row = [reviewId, entity.name, entity.salience, entity.sentiment.score,
entity.sentiment.magnitude, entity.mentions.length,
];
newValues.push(row);
});
if (newValues.length) {
entitySheet.getRange(entitySheet.getLastRow() + 1, 1, newValues.length,
newValues[0].length).setValues(newValues);
}
// Pastes "complete" into entity_sentiment column to denote completion of NL API call.
dataSheet.getRange(i+1, entityColumnIdx+1).setValue("complete");
}
}
// Pastes "complete" into entity_sentiment column to denote completion of NL API call.
dataSheet.getRange(i+1, entityColumnIdx+1).setValue('complete');
}
}
};

/**
* Calls the Cloud Natural Language API with a string of text to analyze
* entities and sentiment present in the string.
* @param {String} the string for entity sentiment analysis
* @param {String} line - the string for entity sentiment analysis
* @return {Object} the entities and related sentiment present in the string
*/
function retrieveEntitySentiment (line) {
function retrieveEntitySentiment(line) {
var apiKey = myApiKey;
var apiEndpoint = 'https://language.googleapis.com/v1/documents:analyzeEntitySentiment?key=' + apiKey;
// Creates a JSON request, with text string, language, type and encoding
var nlData = {
document: {
language: 'en-us',
type: 'PLAIN_TEXT',
content: line
content: line,
},
encodingType: 'UTF8'
encodingType: 'UTF8',
};
// Packages all of the options and the data together for the API call.
var nlOptions = {
method : 'post',
contentType: 'application/json',
payload : JSON.stringify(nlData)
method: 'post',
contentType: 'application/json',
payload: JSON.stringify(nlData),
};
// Makes the API call.
var response = UrlFetchApp.fetch(apiEndpoint, nlOptions);
Expand Down

0 comments on commit 6437e31

Please sign in to comment.