import matplotlib matplotlib.use('Agg') # Use non-interactive backend import matplotlib.pyplot as plt import pandas as pd import numpy as np from nltk.sentiment.vader import SentimentIntensityAnalyzer import nltk from collections import Counter from utils.model_loader import load_sentiment_analyzer, load_emotion_classifier from utils.helpers import fig_to_html, df_to_html_table def sentiment_handler(text_input): """Show sentiment analysis capabilities.""" output_html = [] # Add result area container output_html.append('
VADER (Valence Aware Dictionary and sEntiment Reasoner) is a lexicon and rule-based sentiment analysis tool specifically attuned to sentiments expressed in social media.
') # Get VADER analyzer vader_analyzer = SentimentIntensityAnalyzer() vader_scores = vader_analyzer.polarity_scores(text_input) # Extract scores compound_score = vader_scores['compound'] pos_score = vader_scores['pos'] neg_score = vader_scores['neg'] neu_score = vader_scores['neu'] # Determine sentiment category if compound_score >= 0.05: sentiment_category = "Positive" sentiment_color = "#4CAF50" # Green sentiment_emoji = "😊" elif compound_score <= -0.05: sentiment_category = "Negative" sentiment_color = "#F44336" # Red sentiment_emoji = "😞" else: sentiment_category = "Neutral" sentiment_color = "#FFC107" # Amber sentiment_emoji = "😐" # Create sentiment gauge display output_html.append(f"""Compound Score: {compound_score:.2f}
{interpretation}
This analysis uses a DistilBERT model fine-tuned on the Stanford Sentiment Treebank dataset.
') try: # Load transformer model sentiment_model = load_sentiment_analyzer() # Maximum text length for transformer model (BERT has a 512 token limit) max_length = 512 # Get prediction truncated_text = text_input[:max_length * 4] # Rough character estimate transformer_result = sentiment_model(truncated_text) if len(text_input) > max_length * 4: output_html.append(f"""⚠️ Note: Text was truncated for analysis as it exceeds the model's length limit.
Confidence: {transformer_score:.2%}
Failed to load or run transformer sentiment model: {str(e)}
Falling back to VADER results only.
Identifying specific emotions in text using a RoBERTa model fine-tuned on the emotion dataset.
') try: # Load emotion classifier emotion_classifier = load_emotion_classifier() # Get predictions truncated_text = text_input[:max_length * 4] # Rough character estimate emotion_result = emotion_classifier(truncated_text) # Extract emotion scores emotion_scores = {} for item in emotion_result[0]: emotion_scores[item['label']] = item['score'] # Create emotion dataframe emotion_df = pd.DataFrame({ 'Emotion': list(emotion_scores.keys()), 'Score': list(emotion_scores.values()) }).sort_values('Score', ascending=False) # Get primary emotion primary_emotion = emotion_df.iloc[0]['Emotion'] primary_score = emotion_df.iloc[0]['Score'] # Emotion color map emotion_colors = { 'joy': '#FFD54F', 'anger': '#EF5350', 'sadness': '#42A5F5', 'fear': '#9C27B0', 'surprise': '#26C6DA', 'love': '#EC407A', 'disgust': '#66BB6A', 'optimism': '#FF9800', 'pessimism': '#795548', 'trust': '#4CAF50', 'anticipation': '#FF7043', 'neutral': '#9E9E9E' } # Emotion emoji map emotion_emojis = { 'joy': '😃', 'anger': '😠', 'sadness': '😢', 'fear': '😨', 'surprise': '😲', 'love': '❤️', 'disgust': '🤢', 'optimism': '🤩', 'pessimism': '😒', 'trust': '🤝', 'anticipation': '🤔', 'neutral': '😐' } # Create bar chart fig = plt.figure(figsize=(10, 6)) bars = plt.barh( emotion_df['Emotion'], emotion_df['Score'], color=[emotion_colors.get(emotion, '#9E9E9E') for emotion in emotion_df['Emotion']] ) plt.xlabel('Score') plt.title('Emotion Scores') # Add value labels for i, bar in enumerate(bars): plt.text(bar.get_width() + 0.01, bar.get_y() + bar.get_height()/2, f"{bar.get_width():.2f}", va='center') plt.xlim(0, 1) plt.tight_layout() # Chart section output_html.append('Score: {primary_score:.2f}
Failed to load or run emotion classifier: {str(e)}
Breaking down sentiment by individual sentences to identify sentiment variations throughout the text.
') # Split text into sentences sentences = nltk.sent_tokenize(text_input) # Minimum 2 sentences to do the analysis if len(sentences) >= 2: # Calculate sentiment for each sentence sentence_sentiments = [] for i, sentence in enumerate(sentences): vader_score = vader_analyzer.polarity_scores(sentence) sentence_sentiments.append({ 'Sentence': sentence, 'Index': i + 1, 'Compound': vader_score['compound'], 'Positive': vader_score['pos'], 'Negative': vader_score['neg'], 'Neutral': vader_score['neu'], 'Sentiment': 'Positive' if vader_score['compound'] >= 0.05 else 'Negative' if vader_score['compound'] <= -0.05 else 'Neutral' }) # Create DataFrame sent_df = pd.DataFrame(sentence_sentiments) # Create line graph of sentiment flow fig = plt.figure(figsize=(10, 6)) plt.plot(sent_df['Index'], sent_df['Compound'], 'o-', color='#1976D2', linewidth=2, markersize=8) plt.axhline(y=0, color='#9E9E9E', linestyle='-', alpha=0.3) plt.axhline(y=0.05, color='#4CAF50', linestyle='--', alpha=0.3) plt.axhline(y=-0.05, color='#F44336', linestyle='--', alpha=0.3) # Annotate with sentiment for i, row in sent_df.iterrows(): if row['Sentiment'] == 'Positive': color = '#4CAF50' elif row['Sentiment'] == 'Negative': color = '#F44336' else: color = '#9E9E9E' plt.scatter(row['Index'], row['Compound'], color=color, s=100, zorder=5) plt.grid(alpha=0.3) plt.xlabel('Sentence Number') plt.ylabel('Compound Sentiment Score') plt.title('Sentiment Flow Through Text') plt.ylim(-1.05, 1.05) plt.tight_layout() # Calculate statistics positive_count = sum(1 for score in sent_df['Compound'] if score >= 0.05) negative_count = sum(1 for score in sent_df['Compound'] if score <= -0.05) neutral_count = len(sent_df) - positive_count - negative_count # Chart section output_html.append('Sentiment Shifts: {sentiment_changes}
The text shows {sentiment_changes} shifts in sentiment between sentences.
| # | Sentence | Sentiment |
|---|---|---|
| {i+1} | ') output_html.append(f'{row["Sentence"]} | ') output_html.append(f'{sentiment_html} | ') output_html.append('
Sentence-level analysis requires at least two sentences. The provided text doesn't have enough sentences for this analysis.
Failed to analyze sentiment: {str(e)}
Sentiment Analysis (also known as opinion mining) is a natural language processing technique that identifies and extracts subjective information from text. It determines whether a piece of text expresses positive, negative, or neutral sentiment.