Spaces:
Sleeping
Sleeping
File size: 21,610 Bytes
67f1b99 fde3c7b 67f1b99 fde3c7b 67f1b99 fde3c7b 67f1b99 fde3c7b 35b4db1 fde3c7b 67f1b99 fde3c7b 67f1b99 fde3c7b 67f1b99 fde3c7b 67f1b99 fde3c7b 67f1b99 fde3c7b 67f1b99 fde3c7b 67f1b99 fde3c7b 67f1b99 fde3c7b 67f1b99 fde3c7b 67f1b99 fde3c7b 67f1b99 fde3c7b 67f1b99 fde3c7b 67f1b99 fde3c7b 67f1b99 fde3c7b 67f1b99 fde3c7b 67f1b99 fde3c7b 67f1b99 fde3c7b 67f1b99 fde3c7b 67f1b99 fde3c7b 67f1b99 fde3c7b 67f1b99 fde3c7b 67f1b99 fde3c7b 67f1b99 fde3c7b 67f1b99 fde3c7b 67f1b99 fde3c7b 67f1b99 fde3c7b 67f1b99 fde3c7b 67f1b99 fde3c7b 67f1b99 35b4db1 67f1b99 35b4db1 67f1b99 fde3c7b 67f1b99 35b4db1 67f1b99 fde3c7b 67f1b99 35b4db1 67f1b99 fde3c7b 67f1b99 35b4db1 |
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 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 |
# app.py
import gradio as gr
import torch
from transformers import pipeline, AutoTokenizer, AutoModelForSequenceClassification
import pandas as pd
import numpy as np
from datetime import datetime
import plotly.express as px
import plotly.graph_objects as go
from plotly.subplots import make_subplots
import json
class AdvancedSentimentAnalyzer:
def __init__(self, model_name="tabularisai/multilingual-sentiment-analysis"):
print("Loading model and tokenizer...")
self.model_name = model_name
try:
self.tokenizer = AutoTokenizer.from_pretrained(model_name)
self.model = AutoModelForSequenceClassification.from_pretrained(model_name)
# Use the modern pipeline syntax
self.classifier = pipeline(
"text-classification",
model=self.model,
tokenizer=self.tokenizer,
top_k=None # This replaces return_all_scores=True
)
except Exception as e:
print(f"Error loading model: {e}")
# Fallback to basic sentiment analysis
self.classifier = None
self.sentiment_map = {
0: "Very Negative",
1: "Negative",
2: "Neutral",
3: "Positive",
4: "Very Positive"
}
self.sentiment_colors = {
"Very Negative": "#FF6B6B",
"Negative": "#FFA8A8",
"Neutral": "#FFD93D",
"Positive": "#6BCF7F",
"Very Positive": "#4ECDC4"
}
self.language_detection_keywords = {
'english': ['the', 'and', 'is', 'in', 'to', 'of', 'a', 'for'],
'spanish': ['el', 'la', 'de', 'que', 'y', 'en', 'un', 'por'],
'french': ['le', 'la', 'de', 'et', 'que', 'en', 'un', 'pour'],
'german': ['der', 'die', 'das', 'und', 'zu', 'in', 'den', 'mit'],
'italian': ['il', 'la', 'di', 'e', 'che', 'in', 'un', 'per'],
'portuguese': ['o', 'a', 'de', 'e', 'que', 'em', 'um', 'para'],
'dutch': ['de', 'het', 'en', 'van', 'te', 'in', 'een', 'voor'],
'russian': ['ะธ', 'ะฒ', 'ะฝะต', 'ะฝะฐ', 'ั', 'ััะพ', 'ะพะฝ', 'ั'],
'chinese': ['็', 'ๆฏ', 'ๅจ', 'ไบ', 'ๆ', 'ๅ', 'ไธบ', 'ๆ'],
'japanese': ['ใฎ', 'ใซ', 'ใฏ', 'ใ', 'ใ', 'ใ', 'ใง', 'ใฆ'],
'korean': ['์ด', '์', 'ใฏ', 'ใ', '๋ค', 'ใ', 'ใง', 'ใฆ'],
'arabic': ['ุงู', 'ูู', 'ู
ู', 'ุนูู', 'ุฃู', 'ู
ุง', 'ูู', 'ุฅูู'],
'hindi': ['เคเฅ', 'เคธเฅ', 'เคนเฅ', 'เคเคฐ', 'เคเฅ', 'เคฎเฅเค', 'เคฏเคน', 'เคเฅ'],
'turkish': ['ve', 'bir', 'bu', 'ile', 'iรงin', 'ama', 'da', 'de']
}
print("Model loaded successfully!")
def detect_language(self, text):
"""Simple language detection based on common words"""
if not text or not isinstance(text, str):
return 'Unknown'
text_lower = text.lower()
scores = {}
for lang, keywords in self.language_detection_keywords.items():
score = sum(1 for keyword in keywords if keyword in text_lower)
scores[lang] = score
# Only return a language if we have reasonable confidence
detected_lang = max(scores, key=scores.get) if scores and max(scores.values()) > 0 else 'unknown'
return detected_lang.capitalize()
def analyze_sentiment(self, text):
"""Advanced sentiment analysis with detailed metrics"""
if not text or not text.strip():
return {
'text': text,
'sentiment': 'Neutral',
'confidence': 0.0,
'scores': {sent: 0.2 for sent in self.sentiment_map.values()},
'sentiment_score': 0,
'language': 'Unknown',
'emotional_intensity': 0.0,
'error': 'No text provided'
}
try:
# Get predictions using modern pipeline syntax
predictions = self.classifier(text)[0]
# Convert to structured format - ensure proper mapping
sentiment_scores = {}
for pred in predictions:
label = pred['label']
score = pred['score']
# Map label to our sentiment scale
if 'very negative' in label.lower() or label == 'LABEL_0':
sentiment_scores["Very Negative"] = score
elif 'negative' in label.lower() or label == 'LABEL_1':
sentiment_scores["Negative"] = score
elif 'neutral' in label.lower() or label == 'LABEL_2':
sentiment_scores["Neutral"] = score
elif 'positive' in label.lower() or label == 'LABEL_3':
sentiment_scores["Positive"] = score
elif 'very positive' in label.lower() or label == 'LABEL_4':
sentiment_scores["Very Positive"] = score
else:
# Fallback: assign by order
sentiment_keys = list(self.sentiment_map.values())
for i, key in enumerate(sentiment_keys):
if key not in sentiment_scores:
sentiment_scores[key] = score
break
# Ensure all sentiment categories are present
for sentiment in self.sentiment_map.values():
if sentiment not in sentiment_scores:
sentiment_scores[sentiment] = 0.0
# Determine dominant sentiment
dominant_sentiment = max(sentiment_scores, key=sentiment_scores.get)
confidence = sentiment_scores[dominant_sentiment]
# Calculate sentiment score (-2 to +2 scale)
sentiment_score = (
sentiment_scores["Very Positive"] * 2 +
sentiment_scores["Positive"] * 1 +
sentiment_scores["Neutral"] * 0 +
sentiment_scores["Negative"] * -1 +
sentiment_scores["Very Negative"] * -2
)
# Detect language
detected_language = self.detect_language(text)
# Emotional intensity
emotional_intensity = max(sentiment_scores.values()) - min(sentiment_scores.values())
return {
'text': text,
'sentiment': dominant_sentiment,
'confidence': confidence,
'scores': sentiment_scores,
'sentiment_score': sentiment_score,
'language': detected_language,
'emotional_intensity': emotional_intensity,
'timestamp': datetime.now().isoformat()
}
except Exception as e:
print(f"Error in sentiment analysis: {e}")
return {
'text': text,
'sentiment': 'Neutral',
'confidence': 0.0,
'scores': {sent: 0.2 for sent in self.sentiment_map.values()},
'sentiment_score': 0,
'language': 'Unknown',
'emotional_intensity': 0.0,
'error': str(e)
}
def batch_analyze(self, texts):
"""Analyze multiple texts"""
results = []
for i, text in enumerate(texts):
if i % 10 == 0:
print(f"Processing {i}/{len(texts)}...")
results.append(self.analyze_sentiment(text))
return results
# Initialize analyzer
print("Initializing sentiment analyzer...")
analyzer = AdvancedSentimentAnalyzer()
def create_sentiment_chart(scores):
"""Create beautiful sentiment distribution chart"""
try:
fig = go.Figure(data=[
go.Bar(
x=list(scores.keys()),
y=list(scores.values()),
marker_color=[analyzer.sentiment_colors[sent] for sent in scores.keys()],
text=[f'{score:.1%}' for score in scores.values()],
textposition='auto',
)
])
fig.update_layout(
title="Sentiment Distribution",
xaxis_title="Sentiment",
yaxis_title="Confidence Score",
template="plotly_white",
height=300
)
return fig
except Exception as e:
print(f"Error creating chart: {e}")
return None
def create_radar_chart(scores):
"""Create radar chart for sentiment analysis"""
try:
fig = go.Figure(data=go.Scatterpolar(
r=list(scores.values()),
theta=list(scores.keys()),
fill='toself',
line=dict(color='#4ECDC4'),
marker=dict(size=8)
))
fig.update_layout(
polar=dict(
radialaxis=dict(
visible=True,
range=[0, 1]
)),
showlegend=False,
template="plotly_white",
height=300
)
return fig
except Exception as e:
print(f"Error creating radar chart: {e}")
return None
def analyze_single_review(review_text):
"""Analyze single review with enhanced visualization"""
if not review_text or not review_text.strip():
return "โ Please enter some text to analyze.", None, None
print(f"Analyzing: {review_text[:100]}...")
result = analyzer.analyze_sentiment(review_text)
# Create main output
sentiment_color = analyzer.sentiment_colors.get(result['sentiment'], '#FFD93D')
output_html = f"""
<div style="padding: 25px; border-radius: 15px; background: linear-gradient(135deg, {sentiment_color}20, {sentiment_color}40); border-left: 5px solid {sentiment_color};">
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 15px;">
<h3 style="margin: 0; color: #2D3748;">๐ฏ Analysis Result</h3>
<span style="background-color: {sentiment_color}; color: white; padding: 5px 15px; border-radius: 20px; font-weight: bold;">
{result['sentiment'].upper()}
</span>
</div>
<div style="background: white; padding: 15px; border-radius: 10px; margin: 10px 0;">
<p style="margin: 0; font-style: italic;">"{result['text']}"</p>
</div>
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 15px; margin-top: 20px;">
<div style="background: white; padding: 15px; border-radius: 10px; text-align: center;">
<div style="font-size: 24px; color: {sentiment_color}; margin-bottom: 5px;">๐</div>
<div style="font-weight: bold; color: #4A5568;">Confidence</div>
<div style="font-size: 18px; color: #2D3748;">{result['confidence']:.1%}</div>
</div>
<div style="background: white; padding: 15px; border-radius: 10px; text-align: center;">
<div style="font-size: 24px; color: {sentiment_color}; margin-bottom: 5px;">๐</div>
<div style="font-weight: bold; color: #4A5568;">Language</div>
<div style="font-size: 18px; color: #2D3748;">{result['language']}</div>
</div>
<div style="background: white; padding: 15px; border-radius: 10px; text-align: center;">
<div style="font-size: 24px; color: {sentiment_color}; margin-bottom: 5px;">โก</div>
<div style="font-weight: bold; color: #4A5568;">Intensity</div>
<div style="font-size: 18px; color: #2D3748;">{result['emotional_intensity']:.2f}</div>
</div>
</div>
</div>
"""
# Create charts
bar_chart = create_sentiment_chart(result['scores'])
radar_chart = create_radar_chart(result['scores'])
return output_html, bar_chart, radar_chart
def analyze_csv_file(csv_file):
"""Analyze reviews from CSV file with advanced analytics"""
try:
if csv_file is None:
return "โ Please upload a CSV file.", None, None
print("Reading CSV file...")
df = pd.read_csv(csv_file.name)
# Assume first column contains reviews
review_column = df.columns[0]
reviews = df[review_column].dropna().tolist()
if not reviews:
return "โ No reviews found in the CSV file.", None, None
print(f"Analyzing {len(reviews)} reviews...")
results = analyzer.batch_analyze(reviews)
# Create comprehensive results dataframe
results_df = pd.DataFrame({
'Review': [r['text'] for r in results],
'Sentiment': [r['sentiment'] for r in results],
'Confidence': [r['confidence'] for r in results],
'Sentiment_Score': [r['sentiment_score'] for r in results],
'Language': [r['language'] for r in results],
'Emotional_Intensity': [r['emotional_intensity'] for r in results],
'Very_Negative_Score': [r['scores']['Very Negative'] for r in results],
'Negative_Score': [r['scores']['Negative'] for r in results],
'Neutral_Score': [r['scores']['Neutral'] for r in results],
'Positive_Score': [r['scores']['Positive'] for r in results],
'Very_Positive_Score': [r['scores']['Very Positive'] for r in results],
})
# Generate analytics
sentiment_counts = results_df['Sentiment'].value_counts()
avg_confidence = results_df['Confidence'].mean()
avg_sentiment_score = results_df['Sentiment_Score'].mean()
language_distribution = results_df['Language'].value_counts()
# Create summary visualization
fig = make_subplots(
rows=2, cols=2,
subplot_titles=('Sentiment Distribution', 'Language Distribution',
'Confidence Distribution', 'Sentiment Scores'),
specs=[[{"type": "pie"}, {"type": "pie"}],
[{"type": "histogram"}, {"type": "histogram"}]]
)
# Sentiment pie chart
fig.add_trace(
go.Pie(
labels=sentiment_counts.index,
values=sentiment_counts.values,
marker_colors=[analyzer.sentiment_colors.get(sent, '#FFD93D') for sent in sentiment_counts.index]
), 1, 1
)
# Language pie chart (top 10 languages)
top_languages = language_distribution.head(10)
fig.add_trace(
go.Pie(labels=top_languages.index, values=top_languages.values),
1, 2
)
# Confidence histogram
fig.add_trace(go.Histogram(x=results_df['Confidence'], nbinsx=20), 2, 1)
# Sentiment score histogram
fig.add_trace(go.Histogram(x=results_df['Sentiment_Score'], nbinsx=20), 2, 2)
fig.update_layout(height=600, showlegend=False, template="plotly_white")
# Save results
output_filename = f"advanced_sentiment_analysis_{datetime.now().strftime('%Y%m%d_%H%M%S')}.csv"
results_df.to_csv(output_filename, index=False)
# Generate comprehensive summary
summary = f"""
## ๐ BATCH ANALYSIS COMPLETE
**Dataset Overview:**
- ๐ **Total Reviews Analyzed:** {len(results):,}
- ๐ **Languages Detected:** {len(language_distribution)}
- โฑ๏ธ **Analysis Timestamp:** {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
**Sentiment Breakdown:**
- ๐ข **Very Positive:** {sentiment_counts.get('Very Positive', 0):,}
- ๐ก **Positive:** {sentiment_counts.get('Positive', 0):,}
- โช **Neutral:** {sentiment_counts.get('Neutral', 0):,}
- ๐ **Negative:** {sentiment_counts.get('Negative', 0):,}
- ๐ด **Very Negative:** {sentiment_counts.get('Very Negative', 0):,}
**Performance Metrics:**
- ๐ **Average Confidence:** {avg_confidence:.1%}
- ๐ฏ **Average Sentiment Score:** {avg_sentiment_score:.2f}
- ๐ **Most Common Language:** {language_distribution.index[0] if len(language_distribution) > 0 else 'N/A'}
**Files Generated:**
- ๐พ **Results CSV:** `{output_filename}`
- ๐ **Analytics Dashboard:** See chart below
**Next Steps:**
- Download the CSV for detailed analysis
- Use filters to segment by sentiment or language
- Identify trends and patterns in customer feedback
"""
return summary, output_filename, fig
except Exception as e:
error_msg = f"โ Error processing file: {str(e)}"
print(error_msg)
return error_msg, None, None
# Create simple Gradio interface without any unsupported parameters
with gr.Blocks() as demo:
gr.Markdown("""
# ๐ Advanced Multilingual Sentiment Analysis
*Powered by fine-tuned multilingual transformer model supporting 23 languages*
Analyze customer reviews, social media posts, and feedback across multiple languages with state-of-the-art accuracy.
""")
with gr.Tab("๐ Single Review Analysis"):
with gr.Row():
with gr.Column():
gr.Markdown("### ๐ฅ Input Review")
single_review = gr.Textbox(
label="Enter text in any supported language",
placeholder="Type your review here... (Supports 23 languages including English, Spanish, Chinese, French, German, Arabic, etc.)",
lines=4
)
analyze_btn = gr.Button("๐ Analyze Sentiment", variant="primary")
gr.Markdown("""
**Supported Languages:**
English, Chinese, Spanish, Hindi, Arabic, Bengali, Portuguese, Russian,
Japanese, German, Malay, Telugu, Vietnamese, Korean, French, Turkish,
Italian, Polish, Ukrainian, Tagalog, Dutch, Swiss German, Swahili
""")
with gr.Column():
gr.Markdown("### ๐ Analysis Results")
output_html = gr.HTML(label="Detailed Analysis")
with gr.Row():
bar_chart = gr.Plot(label="Sentiment Distribution")
radar_chart = gr.Plot(label="Sentiment Radar")
analyze_btn.click(
analyze_single_review,
inputs=single_review,
outputs=[output_html, bar_chart, radar_chart]
)
with gr.Tab("๐ Batch CSV Analysis"):
with gr.Row():
with gr.Column():
gr.Markdown("### ๐ค Upload CSV File")
csv_upload = gr.File(
label="Upload CSV file with reviews",
file_types=[".csv"]
)
gr.Markdown("""
**CSV Format Requirements:**
- First column should contain the review text
- File should be UTF-8 encoded
- Maximum file size: 100MB
- Supports up to 10,000 reviews per batch
""")
batch_analyze_btn = gr.Button("๐ Analyze Batch", variant="primary")
with gr.Column():
gr.Markdown("### ๐ Analysis Summary")
batch_output = gr.Markdown(label="Batch Summary")
download_output = gr.File(label="Download Results")
batch_chart = gr.Plot(label="Batch Analytics")
batch_analyze_btn.click(
analyze_csv_file,
inputs=csv_upload,
outputs=[batch_output, download_output, batch_chart]
)
with gr.Tab("โน๏ธ About & Instructions"):
gr.Markdown("""
## ๐ฏ About This Tool
This advanced sentiment analysis system uses a fine-tuned multilingual transformer model to analyze text in 23 languages.
### ๐ Key Features
- **Multilingual Support**: Analyze sentiment in 23 languages
- **5-Point Scale**: Very Negative โ Negative โ Neutral โ Positive โ Very Positive
- **Advanced Analytics**: Confidence scores, emotional intensity, language detection
- **Batch Processing**: Analyze thousands of reviews via CSV upload
- **Visual Analytics**: Interactive charts and comprehensive dashboards
### ๐ Use Cases
- **E-commerce**: Product reviews from global marketplaces
- **Customer Support**: Analyze support tickets and feedback
- **Social Media**: Monitor brand sentiment across languages
- **Market Research**: Understand international customer opinions
### ๐ง Technical Details
- **Base Model**: DistilBERT Multilingual
- **Languages**: 23 languages
- **Sentiment Scale**: 5-point (Very Negative to Very Positive)
- **Processing**: Real-time analysis with batch capabilities
""")
# Launch the application
if __name__ == "__main__":
demo.launch(share=False, debug=True) |