entropy25 commited on
Commit
71b3ce2
·
verified ·
1 Parent(s): 3b49170

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +285 -91
app.py CHANGED
@@ -21,6 +21,8 @@ import nltk
21
  from nltk.corpus import stopwords
22
  import langdetect
23
  import pandas as pd
 
 
24
 
25
  # Configuration
26
  @dataclass
@@ -43,7 +45,8 @@ class Config:
43
 
44
  MODELS = {
45
  'en': "cardiffnlp/twitter-roberta-base-sentiment-latest",
46
- 'multilingual': "cardiffnlp/twitter-xlm-roberta-base-sentiment"
 
47
  }
48
 
49
  # Color themes
@@ -77,22 +80,33 @@ class ModelManager:
77
  self._load_default_model()
78
 
79
  def _load_default_model(self):
80
- """Load the default English model"""
81
  try:
82
- model_name = config.MODELS['multilingual'] # Use multilingual as default
 
83
  self.tokenizers['default'] = AutoTokenizer.from_pretrained(model_name)
84
  self.models['default'] = AutoModelForSequenceClassification.from_pretrained(model_name)
85
  self.models['default'].to(self.device)
86
  logger.info(f"Default model loaded: {model_name}")
 
 
 
 
 
 
 
 
87
  except Exception as e:
88
- logger.error(f"Failed to load default model: {e}")
89
  raise
90
 
91
  def get_model(self, language='en'):
92
  """Get model for specific language"""
93
- if language in ['en', 'auto'] or language not in config.SUPPORTED_LANGUAGES:
 
 
94
  return self.models['default'], self.tokenizers['default']
95
- return self.models['default'], self.tokenizers['default'] # Use multilingual for all
96
 
97
  @staticmethod
98
  def detect_language(text: str) -> str:
@@ -318,7 +332,166 @@ class SentimentAnalyzer:
318
  })
319
  return results
320
 
321
- class PlotlyVisualizer:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
322
  """Enhanced visualizations with Plotly"""
323
 
324
  @staticmethod
@@ -675,12 +848,12 @@ def analyze_batch_texts(batch_text: str, language: str, theme: str,
675
  logger.error(f"Batch analysis failed: {e}")
676
  return f"Error: {str(e)}", None, None, None
677
 
678
- def analyze_advanced_text(text: str, language: str, theme: str, include_keywords: bool,
679
- keyword_count: int, min_confidence: float):
680
- """Advanced analysis with additional features"""
681
  try:
682
  if not text.strip():
683
- return "Please enter text", None, None
684
 
685
  # Map display names back to language codes
686
  language_map = {
@@ -694,14 +867,31 @@ def analyze_advanced_text(text: str, language: str, theme: str, include_keywords
694
  }
695
  language_code = language_map.get(language, 'auto')
696
 
 
697
  result = SentimentAnalyzer.analyze_text(text, language_code)
698
 
699
- # Advanced keyword extraction
700
- if include_keywords:
701
- result['keywords'] = TextProcessor.extract_keywords(text, keyword_count)
 
 
 
 
 
 
 
 
 
 
 
 
702
 
703
- # Confidence filtering
704
- meets_confidence = result['confidence'] >= min_confidence
 
 
 
 
705
 
706
  # Add to history
707
  history_entry = {
@@ -715,39 +905,45 @@ def analyze_advanced_text(text: str, language: str, theme: str, include_keywords
715
  'language': result['language'],
716
  'timestamp': datetime.now().isoformat(),
717
  'analysis_type': 'advanced',
718
- 'meets_confidence_threshold': meets_confidence
719
  }
720
  history_manager.add_entry(history_entry)
721
 
722
- # Create visualizations
723
  gauge_fig = PlotlyVisualizer.create_sentiment_gauge(result, theme)
724
  bars_fig = PlotlyVisualizer.create_probability_bars(result, theme)
725
 
726
  # Create detailed info text
727
- confidence_status = "✅ High Confidence" if meets_confidence else "⚠️ Low Confidence"
728
-
729
  info_text = f"""
730
  **Advanced Analysis Results:**
731
  - **Sentiment:** {result['sentiment']} ({result['confidence']:.3f} confidence)
732
- - **Confidence Status:** {confidence_status}
733
  - **Language:** {result['language'].upper()}
734
  - **Text Statistics:**
735
  - Words: {result['word_count']}
736
  - Characters: {result['char_count']}
737
  - Average word length: {result['char_count']/max(result['word_count'], 1):.1f}
 
 
 
738
  """
739
 
740
- if include_keywords:
741
- info_text += f"\n- **Top Keywords:** {', '.join(result['keywords'])}"
 
 
 
742
 
743
- if not meets_confidence:
744
- info_text += f"\n\n⚠️ **Note:** Confidence ({result['confidence']:.3f}) is below threshold ({min_confidence})"
 
 
 
745
 
746
- return info_text, gauge_fig, bars_fig
747
 
748
  except Exception as e:
749
  logger.error(f"Advanced analysis failed: {e}")
750
- return f"Error: {str(e)}", None, None
751
 
752
  def get_history_stats():
753
  """Get enhanced history statistics"""
@@ -868,36 +1064,35 @@ def get_recent_analyses():
868
 
869
  return summary_text
870
 
 
871
  SAMPLE_TEXTS = [
872
  # Auto Detect
873
- ["The film had its moments, but overall it felt a bit too long and lacked emotional depth. Some scenes were visually impressive, yet they failed to connect emotionally. By the end, I found myself disengaged and unsatisfied."],
874
 
875
  # English
876
- ["I was completely blown away by the movie — the performances were raw and powerful, and the story stayed with me long after the credits rolled. Every scene felt purposeful, and the emotional arc was handled with incredible nuance. It's the kind of film that makes you reflect deeply on your own life."],
877
 
878
  # Chinese
879
- ["这部电影节奏拖沓,剧情老套,完全没有让我产生任何共鸣,是一次失望的观影体验。演员的表演也显得做作,缺乏真实感。看到最后甚至有点不耐烦,整体表现乏善可陈。"],
880
 
881
  # Spanish
882
- ["Una obra maestra del cine contemporáneo, con actuaciones sobresalientes, un guion bien escrito y una dirección impecable. Cada plano parecía cuidadosamente pensado, y la historia avanzaba con una intensidad emocional que mantenía al espectador cautivado. Definitivamente una película que vale la pena volver a ver."],
883
 
884
  # French
885
- ["Je m'attendais à beaucoup mieux. Le scénario était confus, les dialogues ennuyeux, et je me suis presque endormi au milieu du film. Même la mise en scène, habituellement un point fort, manquait cruellement d'inspiration cette fois-ci."],
886
 
887
  # German
888
- ["Der Film war ein emotionales Erlebnis mit großartigen Bildern, einem mitreißenden Soundtrack und einer Geschichte, die zum Nachdenken anregt. Besonders beeindruckend war die schauspielerische Leistung der Hauptdarsteller, die eine tiefe Menschlichkeit vermittelten. Es ist ein Film, der lange nachwirkt."],
889
 
890
  # Swedish
891
- ["Filmen var en besvikelse – tråkig handling, överdrivet skådespeleri och ett slut som inte gav något avslut alls. Den kändes forcerad och saknade en tydlig röd tråd. Jag gick från biografen med en känsla av tomhet och frustration."]
892
  ]
893
 
894
-
895
- BATCH_SAMPLE = """I love this product! It works perfectly and exceeded my expectations. I've been using it every day and it hasn’t let me down once.
896
- The service was terrible and slow. I had to wait over an hour, and no one seemed to care about helping me. Really frustrating experience overall.
897
- Not sure if I like it or not. Some features are nice, but others are confusing or don’t work as expected. I’m still deciding whether it’s worth keeping.
898
- Amazing quality and fast delivery! The packaging was secure, and the product looked even better than in the pictures. I’ll definitely order from here again.
899
- Could be better, but it's okay. It does the job, but there are some issues with the build quality. Not bad, just not great either."""
900
-
901
 
902
  # Gradio Interface
903
  with gr.Blocks(theme=gr.themes.Soft(), title="Advanced Multilingual Sentiment Analyzer") as demo:
@@ -945,6 +1140,53 @@ with gr.Blocks(theme=gr.themes.Soft(), title="Advanced Multilingual Sentiment An
945
  gauge_plot = gr.Plot(label="Sentiment Gauge")
946
  bars_plot = gr.Plot(label="Probability Distribution")
947
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
948
  with gr.Tab("📊 Batch Analysis"):
949
  with gr.Row():
950
  with gr.Column(scale=2):
@@ -992,54 +1234,6 @@ with gr.Blocks(theme=gr.themes.Soft(), title="Advanced Multilingual Sentiment An
992
  batch_summary_plot = gr.Plot(label="Sentiment Summary")
993
  batch_confidence_plot = gr.Plot(label="Confidence Distribution")
994
 
995
- with gr.Tab("🔬 Advanced Analysis"):
996
- with gr.Row():
997
- with gr.Column(scale=2):
998
- advanced_input = gr.Textbox(
999
- label="Text for Advanced Analysis",
1000
- placeholder="Enter text for detailed analysis...",
1001
- lines=4
1002
- )
1003
-
1004
- with gr.Row():
1005
- advanced_language = gr.Dropdown(
1006
- choices=['Auto Detect', 'English', 'Chinese', 'Spanish', 'French', 'German', 'Swedish'],
1007
- value='Auto Detect',
1008
- label="Language"
1009
- )
1010
- advanced_theme = gr.Dropdown(
1011
- choices=list(config.THEMES.keys()),
1012
- value='default',
1013
- label="Theme"
1014
- )
1015
-
1016
- with gr.Row():
1017
- include_keywords = gr.Checkbox(label="Extract Keywords", value=True)
1018
- keyword_count = gr.Slider(
1019
- minimum=3,
1020
- maximum=10,
1021
- value=5,
1022
- step=1,
1023
- label="Number of Keywords"
1024
- )
1025
-
1026
- min_confidence_slider = gr.Slider(
1027
- minimum=0.0,
1028
- maximum=1.0,
1029
- value=0.7,
1030
- step=0.1,
1031
- label="Minimum Confidence Threshold"
1032
- )
1033
-
1034
- advanced_analyze_btn = gr.Button("🔬 Advanced Analyze", variant="primary", size="lg")
1035
-
1036
- with gr.Column(scale=1):
1037
- advanced_result_info = gr.Markdown("Configure settings and click Advanced Analyze")
1038
-
1039
- with gr.Row():
1040
- advanced_gauge_plot = gr.Plot(label="Sentiment Gauge")
1041
- advanced_bars_plot = gr.Plot(label="Probability Distribution")
1042
-
1043
  with gr.Tab("📈 History & Analytics"):
1044
  with gr.Row():
1045
  with gr.Column():
@@ -1109,8 +1303,8 @@ with gr.Blocks(theme=gr.themes.Soft(), title="Advanced Multilingual Sentiment An
1109
  # Advanced Analysis
1110
  advanced_analyze_btn.click(
1111
  analyze_advanced_text,
1112
- inputs=[advanced_input, advanced_language, advanced_theme, include_keywords, keyword_count, min_confidence_slider],
1113
- outputs=[advanced_result_info, advanced_gauge_plot, advanced_bars_plot]
1114
  )
1115
 
1116
  # History & Analytics
 
21
  from nltk.corpus import stopwords
22
  import langdetect
23
  import pandas as pd
24
+ import shap
25
+ from lime.lime_text import LimeTextExplainer
26
 
27
  # Configuration
28
  @dataclass
 
45
 
46
  MODELS = {
47
  'en': "cardiffnlp/twitter-roberta-base-sentiment-latest",
48
+ 'multilingual': "cardiffnlp/twitter-xlm-roberta-base-sentiment",
49
+ 'zh': "uer/roberta-base-finetuned-dianping-chinese"
50
  }
51
 
52
  # Color themes
 
80
  self._load_default_model()
81
 
82
  def _load_default_model(self):
83
+ """Load the default models"""
84
  try:
85
+ # Load multilingual model as default
86
+ model_name = config.MODELS['multilingual']
87
  self.tokenizers['default'] = AutoTokenizer.from_pretrained(model_name)
88
  self.models['default'] = AutoModelForSequenceClassification.from_pretrained(model_name)
89
  self.models['default'].to(self.device)
90
  logger.info(f"Default model loaded: {model_name}")
91
+
92
+ # Load Chinese model
93
+ zh_model_name = config.MODELS['zh']
94
+ self.tokenizers['zh'] = AutoTokenizer.from_pretrained(zh_model_name)
95
+ self.models['zh'] = AutoModelForSequenceClassification.from_pretrained(zh_model_name)
96
+ self.models['zh'].to(self.device)
97
+ logger.info(f"Chinese model loaded: {zh_model_name}")
98
+
99
  except Exception as e:
100
+ logger.error(f"Failed to load models: {e}")
101
  raise
102
 
103
  def get_model(self, language='en'):
104
  """Get model for specific language"""
105
+ if language == 'zh':
106
+ return self.models['zh'], self.tokenizers['zh']
107
+ elif language in ['en', 'auto'] or language not in config.SUPPORTED_LANGUAGES:
108
  return self.models['default'], self.tokenizers['default']
109
+ return self.models['default'], self.tokenizers['default'] # Use multilingual for other languages
110
 
111
  @staticmethod
112
  def detect_language(text: str) -> str:
 
332
  })
333
  return results
334
 
335
+ class ExplainabilityAnalyzer:
336
+ """SHAP and LIME explainability analysis"""
337
+
338
+ @staticmethod
339
+ def create_prediction_function(model, tokenizer, device):
340
+ """Create prediction function for LIME"""
341
+ def predict_proba(texts):
342
+ if isinstance(texts, str):
343
+ texts = [texts]
344
+
345
+ results = []
346
+ for text in texts:
347
+ inputs = tokenizer(text, return_tensors="pt", padding=True,
348
+ truncation=True, max_length=config.MAX_TEXT_LENGTH).to(device)
349
+ with torch.no_grad():
350
+ outputs = model(**inputs)
351
+ probs = torch.nn.functional.softmax(outputs.logits, dim=-1).cpu().numpy()[0]
352
+ results.append(probs)
353
+
354
+ return np.array(results)
355
+ return predict_proba
356
+
357
+ @staticmethod
358
+ def analyze_with_lime(text: str, model, tokenizer, device, num_features: int = 10) -> Dict:
359
+ """Analyze text with LIME"""
360
+ try:
361
+ # Create prediction function
362
+ predict_fn = ExplainabilityAnalyzer.create_prediction_function(model, tokenizer, device)
363
+
364
+ # Initialize LIME explainer
365
+ explainer = LimeTextExplainer(class_names=['Negative', 'Neutral', 'Positive'] if len(predict_fn([text])[0]) == 3 else ['Negative', 'Positive'])
366
+
367
+ # Generate explanation
368
+ explanation = explainer.explain_instance(
369
+ text,
370
+ predict_fn,
371
+ num_features=num_features,
372
+ num_samples=100
373
+ )
374
+
375
+ # Extract feature importance
376
+ feature_importance = explanation.as_list()
377
+
378
+ return {
379
+ 'method': 'LIME',
380
+ 'feature_importance': feature_importance,
381
+ 'explanation': explanation
382
+ }
383
+
384
+ except Exception as e:
385
+ logger.error(f"LIME analysis failed: {e}")
386
+ return {'method': 'LIME', 'error': str(e)}
387
+
388
+ @staticmethod
389
+ def analyze_with_attention(text: str, model, tokenizer, device) -> Dict:
390
+ """Analyze text with attention weights"""
391
+ try:
392
+ # Tokenize input
393
+ inputs = tokenizer(text, return_tensors="pt", padding=True,
394
+ truncation=True, max_length=config.MAX_TEXT_LENGTH,
395
+ return_attention_mask=True).to(device)
396
+
397
+ # Get model outputs with attention
398
+ with torch.no_grad():
399
+ outputs = model(**inputs, output_attentions=True)
400
+ attentions = outputs.attentions
401
+
402
+ # Get tokens
403
+ tokens = tokenizer.convert_ids_to_tokens(inputs['input_ids'][0])
404
+
405
+ # Average attention across layers and heads
406
+ avg_attention = torch.mean(torch.stack(attentions), dim=(0, 1, 2)).cpu().numpy()
407
+
408
+ # Create attention weights for each token
409
+ attention_weights = []
410
+ for i, token in enumerate(tokens):
411
+ if i < len(avg_attention):
412
+ attention_weights.append((token, float(avg_attention[i])))
413
+
414
+ return {
415
+ 'method': 'Attention',
416
+ 'tokens': tokens,
417
+ 'attention_weights': attention_weights
418
+ }
419
+
420
+ except Exception as e:
421
+ logger.error(f"Attention analysis failed: {e}")
422
+ return {'method': 'Attention', 'error': str(e)}
423
+
424
+ class AdvancedVisualizer:
425
+ """Visualizations for explainability analysis"""
426
+
427
+ @staticmethod
428
+ def create_lime_plot(lime_result: Dict, theme: str = 'default') -> go.Figure:
429
+ """Create LIME feature importance plot"""
430
+ if 'error' in lime_result:
431
+ fig = go.Figure()
432
+ fig.add_annotation(text=f"LIME Error: {lime_result['error']}",
433
+ x=0.5, y=0.5, showarrow=False)
434
+ return fig
435
+
436
+ features, scores = zip(*lime_result['feature_importance'])
437
+ colors = ['red' if score < 0 else 'green' for score in scores]
438
+
439
+ fig = go.Figure(data=[
440
+ go.Bar(
441
+ y=features,
442
+ x=scores,
443
+ orientation='h',
444
+ marker_color=colors,
445
+ text=[f'{score:.3f}' for score in scores],
446
+ textposition='auto'
447
+ )
448
+ ])
449
+
450
+ fig.update_layout(
451
+ title="LIME Feature Importance",
452
+ xaxis_title="Importance Score",
453
+ yaxis_title="Features",
454
+ height=400,
455
+ showlegend=False
456
+ )
457
+
458
+ return fig
459
+
460
+ @staticmethod
461
+ def create_attention_plot(attention_result: Dict, theme: str = 'default') -> go.Figure:
462
+ """Create attention weights visualization"""
463
+ if 'error' in attention_result:
464
+ fig = go.Figure()
465
+ fig.add_annotation(text=f"Attention Error: {attention_result['error']}",
466
+ x=0.5, y=0.5, showarrow=False)
467
+ return fig
468
+
469
+ tokens, weights = zip(*attention_result['attention_weights'])
470
+
471
+ # Normalize weights for better visualization
472
+ weights = np.array(weights)
473
+ normalized_weights = (weights - weights.min()) / (weights.max() - weights.min()) if weights.max() > weights.min() else weights
474
+
475
+ fig = go.Figure(data=[
476
+ go.Bar(
477
+ x=list(range(len(tokens))),
478
+ y=normalized_weights,
479
+ text=tokens,
480
+ textposition='outside',
481
+ marker_color=normalized_weights,
482
+ colorscale='Viridis'
483
+ )
484
+ ])
485
+
486
+ fig.update_layout(
487
+ title="Attention Weights",
488
+ xaxis_title="Token Position",
489
+ yaxis_title="Attention Weight (Normalized)",
490
+ height=400,
491
+ showlegend=False
492
+ )
493
+
494
+ return fig
495
  """Enhanced visualizations with Plotly"""
496
 
497
  @staticmethod
 
848
  logger.error(f"Batch analysis failed: {e}")
849
  return f"Error: {str(e)}", None, None, None
850
 
851
+ def analyze_advanced_text(text: str, language: str, theme: str, use_lime: bool,
852
+ use_attention: bool, lime_features: int):
853
+ """Advanced analysis with SHAP and LIME explainability"""
854
  try:
855
  if not text.strip():
856
+ return "Please enter text", None, None, None, None
857
 
858
  # Map display names back to language codes
859
  language_map = {
 
867
  }
868
  language_code = language_map.get(language, 'auto')
869
 
870
+ # Basic sentiment analysis
871
  result = SentimentAnalyzer.analyze_text(text, language_code)
872
 
873
+ # Get model for explainability analysis
874
+ model, tokenizer = model_manager.get_model(language_code)
875
+
876
+ # Initialize explainability results
877
+ lime_result = None
878
+ attention_result = None
879
+ lime_plot = None
880
+ attention_plot = None
881
+
882
+ # LIME Analysis
883
+ if use_lime:
884
+ lime_result = ExplainabilityAnalyzer.analyze_with_lime(
885
+ text, model, tokenizer, model_manager.device, lime_features
886
+ )
887
+ lime_plot = AdvancedVisualizer.create_lime_plot(lime_result, theme)
888
 
889
+ # Attention Analysis
890
+ if use_attention:
891
+ attention_result = ExplainabilityAnalyzer.analyze_with_attention(
892
+ text, model, tokenizer, model_manager.device
893
+ )
894
+ attention_plot = AdvancedVisualizer.create_attention_plot(attention_result, theme)
895
 
896
  # Add to history
897
  history_entry = {
 
905
  'language': result['language'],
906
  'timestamp': datetime.now().isoformat(),
907
  'analysis_type': 'advanced',
908
+ 'explainability_used': use_lime or use_attention
909
  }
910
  history_manager.add_entry(history_entry)
911
 
912
+ # Create basic visualizations
913
  gauge_fig = PlotlyVisualizer.create_sentiment_gauge(result, theme)
914
  bars_fig = PlotlyVisualizer.create_probability_bars(result, theme)
915
 
916
  # Create detailed info text
 
 
917
  info_text = f"""
918
  **Advanced Analysis Results:**
919
  - **Sentiment:** {result['sentiment']} ({result['confidence']:.3f} confidence)
 
920
  - **Language:** {result['language'].upper()}
921
  - **Text Statistics:**
922
  - Words: {result['word_count']}
923
  - Characters: {result['char_count']}
924
  - Average word length: {result['char_count']/max(result['word_count'], 1):.1f}
925
+ - **Keywords:** {', '.join(result['keywords'])}
926
+
927
+ **Explainability Analysis:**
928
  """
929
 
930
+ if use_lime:
931
+ if 'error' not in lime_result:
932
+ info_text += f"\n- **LIME:** ✅ Analyzed top {lime_features} features"
933
+ else:
934
+ info_text += f"\n- **LIME:** ❌ Error occurred"
935
 
936
+ if use_attention:
937
+ if 'error' not in attention_result:
938
+ info_text += f"\n- **Attention:** ✅ Token-level attention weights computed"
939
+ else:
940
+ info_text += f"\n- **Attention:** ❌ Error occurred"
941
 
942
+ return info_text, gauge_fig, bars_fig, lime_plot, attention_plot
943
 
944
  except Exception as e:
945
  logger.error(f"Advanced analysis failed: {e}")
946
+ return f"Error: {str(e)}", None, None, None, None
947
 
948
  def get_history_stats():
949
  """Get enhanced history statistics"""
 
1064
 
1065
  return summary_text
1066
 
1067
+ # Sample data
1068
  SAMPLE_TEXTS = [
1069
  # Auto Detect
1070
+ ["The film had its moments, but overall it felt a bit too long and lacked emotional depth."],
1071
 
1072
  # English
1073
+ ["I was completely blown away by the movie — the performances were raw and powerful, and the story stayed with me long after the credits rolled."],
1074
 
1075
  # Chinese
1076
+ ["这部电影节奏拖沓,剧情老套,完全没有让我产生任何共鸣,是一次失望的观影体验。"],
1077
 
1078
  # Spanish
1079
+ ["Una obra maestra del cine contemporáneo, con actuaciones sobresalientes, un guion bien escrito y una dirección impecable."],
1080
 
1081
  # French
1082
+ ["Je m'attendais à beaucoup mieux. Le scénario était confus, les dialogues ennuyeux, et je me suis presque endormi au milieu du film."],
1083
 
1084
  # German
1085
+ ["Der Film war ein emotionales Erlebnis mit großartigen Bildern, einem mitreißenden Soundtrack und einer Geschichte, die zum Nachdenken anregt."],
1086
 
1087
  # Swedish
1088
+ ["Filmen var en besvikelse – tråkig handling, överdrivet skådespeleri och ett slut som inte gav något avslut alls."]
1089
  ]
1090
 
1091
+ BATCH_SAMPLE = """I love this product! It works perfectly.
1092
+ The service was terrible and slow.
1093
+ Not sure if I like it or not.
1094
+ Amazing quality and fast delivery!
1095
+ Could be better, but it's okay."""
 
 
1096
 
1097
  # Gradio Interface
1098
  with gr.Blocks(theme=gr.themes.Soft(), title="Advanced Multilingual Sentiment Analyzer") as demo:
 
1140
  gauge_plot = gr.Plot(label="Sentiment Gauge")
1141
  bars_plot = gr.Plot(label="Probability Distribution")
1142
 
1143
+ with gr.Tab("🔬 Advanced Analysis"):
1144
+ with gr.Row():
1145
+ with gr.Column(scale=2):
1146
+ advanced_input = gr.Textbox(
1147
+ label="Text for Advanced Analysis",
1148
+ placeholder="Enter text for explainability analysis...",
1149
+ lines=4
1150
+ )
1151
+
1152
+ with gr.Row():
1153
+ advanced_language = gr.Dropdown(
1154
+ choices=['Auto Detect', 'English', 'Chinese', 'Spanish', 'French', 'German', 'Swedish'],
1155
+ value='Auto Detect',
1156
+ label="Language"
1157
+ )
1158
+ advanced_theme = gr.Dropdown(
1159
+ choices=list(config.THEMES.keys()),
1160
+ value='default',
1161
+ label="Theme"
1162
+ )
1163
+
1164
+ gr.Markdown("### 🔍 Explainability Options")
1165
+ with gr.Row():
1166
+ use_lime = gr.Checkbox(label="Use LIME Analysis", value=True)
1167
+ use_attention = gr.Checkbox(label="Use Attention Weights", value=True)
1168
+
1169
+ lime_features = gr.Slider(
1170
+ minimum=5,
1171
+ maximum=20,
1172
+ value=10,
1173
+ step=1,
1174
+ label="LIME Features Count"
1175
+ )
1176
+
1177
+ advanced_analyze_btn = gr.Button("🔬 Advanced Analyze", variant="primary", size="lg")
1178
+
1179
+ with gr.Column(scale=1):
1180
+ advanced_result_info = gr.Markdown("Configure explainability settings and click Advanced Analyze")
1181
+
1182
+ with gr.Row():
1183
+ advanced_gauge_plot = gr.Plot(label="Sentiment Gauge")
1184
+ advanced_bars_plot = gr.Plot(label="Probability Distribution")
1185
+
1186
+ with gr.Row():
1187
+ lime_plot = gr.Plot(label="LIME Feature Importance")
1188
+ attention_plot = gr.Plot(label="Attention Weights")
1189
+
1190
  with gr.Tab("📊 Batch Analysis"):
1191
  with gr.Row():
1192
  with gr.Column(scale=2):
 
1234
  batch_summary_plot = gr.Plot(label="Sentiment Summary")
1235
  batch_confidence_plot = gr.Plot(label="Confidence Distribution")
1236
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1237
  with gr.Tab("📈 History & Analytics"):
1238
  with gr.Row():
1239
  with gr.Column():
 
1303
  # Advanced Analysis
1304
  advanced_analyze_btn.click(
1305
  analyze_advanced_text,
1306
+ inputs=[advanced_input, advanced_language, advanced_theme, use_lime, use_attention, lime_features],
1307
+ outputs=[advanced_result_info, advanced_gauge_plot, advanced_bars_plot, lime_plot, attention_plot]
1308
  )
1309
 
1310
  # History & Analytics