Sentiment Analysis Using AI
Text-based responses, especially open-ended feedback, can be difficult to analyze in their raw form. To make them easier to interpret, you can apply sentiment analysis to assign a score that reflects how positive or negative the overall tone is. You can also generate word clouds to highlight what respondents are most satisfied with and what they complain about most often. This demo showcases AI-powered text analysis applied to hotel reviews.
Implementation
Sentiment analysis in this example has two parts:
Client side
A SurveyJS Dashboard that requests sentiment statistics from the server and visualizes them.Server side
A backend that stores responses, calculates sentiment scores, and returns the results to the client.
In this demo, responses are submitted on the client side. The AI model that performs sentiment analysis runs on the SurveyJS website, and the following C# code is used to handle server requests:
View Backend Code
private Dictionary<string, int> GetSentimentEntities(AnalyzeSentimentResultCollection reviews, TextSentiment sentiment) {
Dictionary<string, int> complaints = new Dictionary<string, int>();
foreach(AnalyzeSentimentResult review in reviews) {
foreach(SentenceSentiment sentence in review.DocumentSentiment.Sentences) {
foreach(SentenceOpinion opinion in sentence.Opinions) {
if(opinion.Target.Sentiment == sentiment) {
int value = 0;
complaints.TryGetValue(opinion.Target.Text, out value);
complaints[opinion.Target.Text] = value + 1;
}
}
}
}
return complaints;
}
[HttpPost]
[ActionName("sentiment")]
public async Task<IHttpActionResult> GetSentiment([FromBody] RequestTextsDto request) {
List<string> batchedDocuments = request.texts;
var endpoint = "your-endpoint";
var credential = new AzureKeyCredential("your-Azure-credential");
TextAnalyticsClient client = new TextAnalyticsClient(new Uri(endpoint), credential);
AnalyzeSentimentOptions options = new AnalyzeSentimentOptions() { IncludeOpinionMining = true };
Response<AnalyzeSentimentResultCollection> response = await client.AnalyzeSentimentBatchAsync(batchedDocuments, options: options);
AnalyzeSentimentResultCollection reviews = response.Value;
Dictionary<string, int> complaints = GetSentimentEntities(reviews, TextSentiment.Negative);
Dictionary<string, int> praises = GetSentimentEntities(reviews, TextSentiment.Positive);
float averagePositive = reviews.Aggregate((float)0, (a, b) => a + (float)b.DocumentSentiment.ConfidenceScores.Positive) / reviews.Count;
float averageNegative = reviews.Aggregate((float)0, (a, b) => a - (float)b.DocumentSentiment.ConfidenceScores.Negative) / reviews.Count;
float value = reviews.Aggregate((float)0, (a, b) => a + (float)b.DocumentSentiment.ConfidenceScores.Positive - (float)b.DocumentSentiment.ConfidenceScores.Negative) / reviews.Count;
switch(request.visualizer) {
case "complaints":
return Ok(complaints);
case "praises":
return Ok(praises);
case "polarity":
return Ok(new { value = averagePositive });
}
return Ok(new { praises = praises, complaints = complaints, value = value, averagePositive = averagePositive, averageNegative = averageNegative });
}