File size: 10,021 Bytes
8edd645 f05ed74 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 | import gradio as gr
import pandas as pd
from transformers import pipeline
import warnings
import os
warnings.filterwarnings("ignore")
# Initialize the models
print("Loading ABSA models for Hugging Face Spaces...")
token_classifier = pipeline(
model="sdf299/abte-restaurants-distilbert-base-uncased",
aggregation_strategy="simple"
)
classifier = pipeline(
model="sdf299/absa-restaurants-distilbert-base-uncased"
)
print("Models loaded successfully!")
def get_sentiment_color(sentiment_label):
"""Return color based on sentiment label."""
sentiment_lower = sentiment_label.lower()
if 'positive' in sentiment_lower:
return "#28a745", "π’" # Green
elif 'negative' in sentiment_lower:
return "#dc3545", "π΄" # Red
else:
return "#6c757d", "βͺ" # Gray for neutral
def analyze_sentiment(sentence):
"""
Perform aspect-based sentiment analysis on the input sentence.
Args:
sentence (str): Input sentence to analyze
Returns:
tuple: (formatted_results, aspects_summary, detailed_dataframe)
"""
if not sentence.strip():
return "Please enter a sentence to analyze.", "", pd.DataFrame()
try:
# Extract aspects using token classifier
results = token_classifier(sentence)
if not results:
return "No aspects found in the sentence.", "", pd.DataFrame()
# Get unique aspects
aspects = list(set([result['word'] for result in results]))
# Analyze sentiment for each aspect
detailed_results = []
formatted_output = f"**π Input Sentence:** {sentence}\n\n"
formatted_output += "## π― Analysis Results:\n\n"
# Count sentiments for summary
sentiment_counts = {'positive': 0, 'negative': 0, 'neutral': 0}
for aspect in aspects:
# Classify sentiment for this aspect
sentiment_result = classifier(f'{sentence} [SEP] {aspect}')
# Extract sentiment label and confidence
sentiment_label = sentiment_result[0]['label']
confidence = sentiment_result[0]['score']
# Get color and emoji for this sentiment
color, emoji = get_sentiment_color(sentiment_label)
# Count sentiments
if 'positive' in sentiment_label.lower():
sentiment_counts['positive'] += 1
elif 'negative' in sentiment_label.lower():
sentiment_counts['negative'] += 1
else:
sentiment_counts['neutral'] += 1
# Format the result with colors
formatted_output += f'<div style="margin: 15px 0; padding: 15px; border-left: 4px solid {color}; background-color: {color}15; border-radius: 5px;">'
formatted_output += f'<strong style="color: {color};">{emoji} Aspect: {aspect}</strong><br>'
formatted_output += f'<span style="color: {color}; font-weight: bold;">Sentiment: {sentiment_label}</span> '
formatted_output += f'<span style="color: #666; font-size: 0.9em;">(Confidence: {confidence:.3f})</span>'
formatted_output += '</div>\n\n'
# Store for dataframe with colored styling
detailed_results.append({
'Aspect': aspect,
'Sentiment': sentiment_label,
'Confidence': f"{confidence:.3f}",
'Color': color,
'Emoji': emoji
})
# Create colorful summary
aspects_summary = "## π Summary:\n\n"
aspects_summary += f"**π Total Aspects Found:** {len(aspects)}\n\n"
# Add sentiment breakdown
if sentiment_counts['positive'] > 0:
aspects_summary += f"π’ **Positive:** {sentiment_counts['positive']} aspects\n\n"
if sentiment_counts['negative'] > 0:
aspects_summary += f"π΄ **Negative:** {sentiment_counts['negative']} aspects\n\n"
if sentiment_counts['neutral'] > 0:
aspects_summary += f"βͺ **Neutral:** {sentiment_counts['neutral']} aspects\n\n"
aspects_summary += f"**π Identified Aspects:** {', '.join(aspects)}"
# Create dataframe for tabular view (simplified for table)
df_data = []
for result in detailed_results:
df_data.append({
'Aspect': result['Aspect'],
'Sentiment': f"{result['Emoji']} {result['Sentiment']}",
'Confidence': result['Confidence']
})
df = pd.DataFrame(df_data)
return formatted_output, aspects_summary, df
except Exception as e:
error_msg = f"β **Error during analysis:** {str(e)}\n\nPlease try again with a different sentence."
return error_msg, "", pd.DataFrame()
# Create the Gradio interface
with gr.Blocks(
title="π½οΈ Restaurant Review Analyzer - ABSA",
theme=gr.themes.Soft(),
css="""
.gradio-container {
font-family: 'Arial', sans-serif;
max-width: 1200px;
}
.main-header {
text-align: center;
margin-bottom: 30px;
}
.sentiment-positive {
color: #28a745 !important;
background-color: #d4edda;
border-color: #c3e6cb;
}
.sentiment-negative {
color: #dc3545 !important;
background-color: #f8d7da;
border-color: #f5c6cb;
}
.sentiment-neutral {
color: #6c757d !important;
background-color: #f8f9fa;
border-color: #dee2e6;
}
"""
) as demo:
gr.HTML("""
<div class="main-header">
<h1>π½οΈ Restaurant Review Analyzer</h1>
<h3>π¨ Colorful Aspect-Based Sentiment Analysis</h3>
<p>Analyze restaurant reviews to identify specific aspects and their sentiments with beautiful color coding!</p>
<div style="margin: 15px 0; padding: 10px; background-color: #f8f9fa; border-radius: 8px; border: 1px solid #dee2e6;">
<p style="margin: 5px 0;"><strong>π¨ Color Guide:</strong></p>
<span style="color: #28a745; font-weight: bold;">π’ Positive</span> |
<span style="color: #dc3545; font-weight: bold;">π΄ Negative</span> |
<span style="color: #6c757d; font-weight: bold;">βͺ Neutral</span>
</div>
<p><em>Powered by DistilBERT models fine-tuned on restaurant reviews</em></p>
</div>
""")
with gr.Row():
with gr.Column(scale=2):
# Input section
sentence_input = gr.Textbox(
label="π½οΈ Enter Restaurant Review",
placeholder="e.g., The services here is wonderful, but I hate the food. However, I still love the atmosphere here.",
lines=3,
max_lines=5
)
analyze_btn = gr.Button("π Analyze Sentiment", variant="primary", size="lg")
# Example sentences
gr.Examples(
examples=[
["The services here is wonderful, but I hate the food. However, I still love the atmosphere here."],
["The food was amazing and the staff was very friendly, but the restaurant was too noisy."],
["Great location and delicious pizza, but the service was slow and the prices are too high."],
["The ambiance is perfect for a romantic dinner, excellent wine selection, but the dessert was disappointing."],
["Fast service and good value for money, but the food quality could be better."],
["Excellent sushi and attentive waiters, though the wait time was quite long."],
["Beautiful decor and reasonable prices, but the pasta was overcooked."],
["Outstanding customer service and fresh ingredients, highly recommend this place!"],
["Terrible experience - rude staff, cold food, and dirty tables. Never coming back."]
],
inputs=sentence_input,
label="π‘ Try these examples:"
)
with gr.Column(scale=3):
# Output section
with gr.Tab("π¨ Colorful Results"):
results_output = gr.HTML(label="Visual Analysis Results")
with gr.Tab("π Summary Dashboard"):
aspects_output = gr.Markdown(label="Quick Summary")
with gr.Tab("π Data Table"):
table_output = gr.Dataframe(
label="Results Table",
headers=["Aspect", "Sentiment", "Confidence"]
)
# Event handlers
analyze_btn.click(
fn=analyze_sentiment,
inputs=[sentence_input],
outputs=[results_output, aspects_output, table_output]
)
sentence_input.submit(
fn=analyze_sentiment,
inputs=[sentence_input],
outputs=[results_output, aspects_output, table_output]
)
# Footer with model information
gr.HTML("""
<div style="text-align: center; margin-top: 30px; padding: 20px; border-top: 1px solid #eee;">
<p><strong>π€ Models Used:</strong></p>
<p>π€ Aspect Extraction: <a href="https://huggingface.co/sdf299/abte-restaurants-distilbert-base-uncased" target="_blank">sdf299/abte-restaurants-distilbert-base-uncased</a></p>
<p>π Sentiment Classification: <a href="https://huggingface.co/sdf299/absa-restaurants-distilbert-base-uncased" target="_blank">sdf299/absa-restaurants-distilbert-base-uncased</a></p>
<p style="margin-top: 15px; font-size: 0.9em; color: #666;">
β¨ This app demonstrates colorful aspect-based sentiment analysis for restaurant reviews using fine-tuned DistilBERT models.
</p>
</div>
""")
# Launch the app
if __name__ == "__main__":
demo.launch() |