Sentiment Analysis with AWS Comprehend | AI/ML Series

In the last post we discussed on how to add speaking ability to our applications using AWS Polly. Let’s extend the same example to analyze the sentiments of the text that user types.

As usual, I recommend to watch the following video before reading this blogpost and use this post as a reference when building out the application by your own.

AWS Comprehend Service

AWS comprehend uses NLP to extract the insight about the content without needing any preprocessing requirements. It is capable of recognizing Entities, Languages, Sentiments, Key Phrases and other common elements of the given text or the document. One of the common use case of AWS Comprehend is to analyze the social media feed about your product and take necessary actions upon analyzing users valid sentiments.

Calling Comprehend API Methods

Let’s use AWS Lambda, our serverless function to talk to AWS Comprehend service and do a sentiment analysis. We are going to be using the API methods detectSentiment and detectDominantLanguage from AWS Comprehend javascript SDK. Refer the full SDK documentation here.

Firstly, we are creating an endpoint that triggers the Lambda function. Goto your serverless.yml and add this piece of code.

functions:
analyze:
handler: handler.analyze
events:
- http:
path: analyze
method: post
cors: true

It will create a new endpoint in the API Gateway with the path /analyze that will trigger analyze Lambda function. Here is the analyze function code which needs to be in the handler.js.

module.exports.analyze = (event, context, callback) => {
let body = JSON.parse(event.body);

const params = {
Text: body.text
};

// Detecting the dominant language of the text
comprehend.detectDominantLanguage(params, function (err, result) {
if (!err) {
const language = result.Languages[0].LanguageCode;

const sentimentParams = {
Text: body.text,
LanguageCode: language
};

// Analyze the sentiment
comprehend.detectSentiment(sentimentParams, function (err, data) {
if (err) {
callback(null, {
statusCode: 400,
headers: {
"Access-Control-Allow-Origin": "*"
},
body: JSON.stringify(err)
});
} else {
callback(null, {
statusCode: 200,
headers: {
"Access-Control-Allow-Origin": "*"
},
body: JSON.stringify(data)
});
}
});
}
});
}

At the top of the handler function, you need a reference to the Comprehend API from AWS-SDK. Then let’s first identify the dominant language of the text by calling detectDominantLanguage API method and pass that language code to the next API call detectSentiment inside the callback of the first method.

As a result, you will get the matching Sentiment and the matching percentage of Negative, Positive, Neutral and Mixed sentiment. Now, send that back to the frontend.

IAM Permission for AWS Comprehend

We are now almost finished with the backend, except we have to add a policy that allows AWS Comprehend permission to the IAM role attached to the Lambda function. If you haven’t read the part 01 of this series, read/watch it where I showed you how to setup an IAM role for the lambda.

Our IAM role was youtube-polly-actual-role. It had an arn and we refereed it in the serverless.yml file as follows.

arn:aws:iam::<account-id>:role/youtube-polly-actual-role

Goto IAM console of your AWS account and attach a new policy to that same role as shown below.

Setting up the Frontend

We have been using an Angular app as the frontend in the earlier project. Let’s continue adding a button below the user text area and call our API endpoint.

Goto app.component.html and add this simple html code to display an additional button next to “speak” button. We will display the returned sentiment value with a color below the button as well.

<div style="margin: auto; padding: 10px; text-align: center;">
<h2>Write Something...</h2>
<div>
<textarea #userInput style="font-size: 15px; padding: 10px;" cols="60" rows="10"></textarea>
</div>
<div>
<select [(ngModel)]="selectedVoice">
<option *ngFor="let voice of voices" [ngValue]="voice">{{voice}}</option>
</select>
</div>
<div style="margin-top: 10px">
<button style="font-size: 15px;" (click)="speakNow(userInput.value)">Speak Now</button>
<button style ="font-size: 15px;" (click)="analyze(userInput.value)">Analyze</button>
</div>

<!-- Following section will show the returned sentiment value with a suitable color -->

<div>
<h2 *ngIf="sentiment=='POSITIVE'" style="color: green;">{{sentiment}}! </h2>
<h2 *ngIf="sentiment=='NEUTRAL'" style="color: orange;">{{sentiment}} </h2>
<h2 *ngIf="sentiment=='NEGATIVE'" style="color: red;">{{sentiment}}! </h2>
</div>
</div>

Let’s add the analyze function in the app.compotent.ts file and make use of a service to call the API Gateway Endpoint.

import { Component } from '@angular/core';
import { APIService } from './api.service'

@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})

export class AppComponent {
sentiment = null;
constructor(private api: APIService){}

analyze(input) {
let
data = {
text: input
}
this
.api.analyze(data).subscribe((result:any) => {
this
.sentiment = result.Sentiment;
});
}

}

Let’s call frontend API service to call the /analyze endpoint and return the data. Goto api.service.ts and add this code.

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';

@Injectable({
providedIn: 'root'
})
export class APIService {

ENDPOINT = 'https://461xegl8zf.execute-api.us-east-1.amazonaws.com/dev';

constructor(private http:HttpClient) {}

speak(data) {
return this.http.post(this.ENDPOINT + '/speak', data);
}

analyze(data) {
return this.http.post(this.ENDPOINT + '/analyze', data);
}
}

Our frontend is now completed. It will send the user input to the backend endpoint and lambda function will figure out the language of the text and send sentiment analysis.

Result

Cheers!

Please follow and like us: