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()