kambris commited on
Commit
4521b2e
·
verified ·
1 Parent(s): a0b6552

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +175 -51
app.py CHANGED
@@ -62,19 +62,24 @@ RHETORICAL_DEVICES = {
62
 
63
  class SpeechAnalyzer:
64
  def __init__(self):
65
- # Load MoralFoundations model
66
  self.moral_model_path = "MMADS/MoralFoundationsClassifier"
67
  self.moral_tokenizer = RobertaTokenizer.from_pretrained(self.moral_model_path)
68
  self.moral_model = RobertaForSequenceClassification.from_pretrained(self.moral_model_path)
69
 
70
- # Define label names directly
71
  self.label_names = ['care', 'fairness', 'loyalty', 'authority', 'sanctity']
72
-
73
  # Other pipelines remain the same
74
  self.sentiment_pipeline = pipeline("sentiment-analysis")
75
  self.ner_tokenizer = AutoTokenizer.from_pretrained("dslim/bert-base-NER")
76
  self.ner_model = AutoModelForTokenClassification.from_pretrained("dslim/bert-base-NER")
77
  self.ner_pipeline = pipeline("ner", model=self.ner_model, tokenizer=self.ner_tokenizer)
 
 
 
 
 
78
 
79
  def split_text(self, text, max_length=256, overlap=50):
80
  """Split long text into overlapping segments"""
@@ -335,68 +340,187 @@ def main():
335
  st.write(f"**{MORAL_FOUNDATIONS[foundation]}**: {score:.2%}")
336
 
337
  with tab2:
 
 
338
  st.subheader("Speech Trajectory Analysis")
339
- col1, col2, col3 = st.columns(3)
340
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
341
  segments = analyzer.split_text(text, max_length=512)
342
  num_segments = len(segments)
343
  segment_labels = [f"{i+1}" for i in range(num_segments)]
344
 
345
- sentiment_scores, basic_emotions = analyzer.analyze_emotional_trajectory(text)
346
 
347
- with col1:
348
- st.write("### Sentiment Flow")
349
- sentiment_fig = go.Figure(data=go.Scatter(
350
- x=segment_labels,
351
- y=sentiment_scores,
352
- mode='lines+markers',
353
- line=dict(color='#1f77b4', width=3),
354
- marker=dict(
355
- size=8,
356
- color=['#ff0000' if score < 0.4 else '#00ff00' if score > 0.6 else '#888888' for score in sentiment_scores],
357
- symbol='circle'
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
358
  )
359
- ))
360
-
361
- sentiment_fig.update_layout(
362
- title='Sentiment Throughout Speech',
363
- xaxis_title='Speech Segments',
364
- yaxis_title='Sentiment',
365
- yaxis=dict(
366
- ticktext=['Very Negative', 'Negative', 'Neutral', 'Positive', 'Very Positive'],
367
- tickvals=[0, 0.25, 0.5, 0.75, 1],
368
- range=[0, 1],
369
- gridcolor='lightgray'
370
- ),
371
- plot_bgcolor='white'
372
- )
373
- st.plotly_chart(sentiment_fig)
374
-
375
- # Rest of the code remains the same for col2 (Moral Foundations)
376
 
377
- with col3:
378
- st.write("### Basic Emotions")
379
- emotions_df = pd.DataFrame({
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
380
  'Segment': segment_labels,
381
- 'Emotion': basic_emotions
 
382
  })
383
 
384
- emotions_fig = px.bar(
385
- emotions_df,
386
- x='Segment',
387
- y='Emotion',
388
- color='Emotion',
389
- title='Basic Emotions Flow',
390
- category_orders={'Emotion': ['joy', 'sadness', 'anger', 'fear', 'surprise', 'neutral']}
391
- )
392
 
393
- emotions_fig.update_layout(
394
- xaxis_title='Speech Segments',
395
- yaxis_title='Emotion',
396
- showlegend=True,
397
- plot_bgcolor='white'
 
398
  )
399
- st.plotly_chart(emotions_fig)
400
 
401
  with tab3:
402
  status_text.text('Analyzing Linguistic Features...')
 
62
 
63
  class SpeechAnalyzer:
64
  def __init__(self):
65
+ # Load MoralFoundations model
66
  self.moral_model_path = "MMADS/MoralFoundationsClassifier"
67
  self.moral_tokenizer = RobertaTokenizer.from_pretrained(self.moral_model_path)
68
  self.moral_model = RobertaForSequenceClassification.from_pretrained(self.moral_model_path)
69
 
70
+ # Define label names directly
71
  self.label_names = ['care', 'fairness', 'loyalty', 'authority', 'sanctity']
72
+
73
  # Other pipelines remain the same
74
  self.sentiment_pipeline = pipeline("sentiment-analysis")
75
  self.ner_tokenizer = AutoTokenizer.from_pretrained("dslim/bert-base-NER")
76
  self.ner_model = AutoModelForTokenClassification.from_pretrained("dslim/bert-base-NER")
77
  self.ner_pipeline = pipeline("ner", model=self.ner_model, tokenizer=self.ner_tokenizer)
78
+
79
+ # Add emotion classifier
80
+ self.emotion_classifier = pipeline("text-classification",
81
+ model="j-hartmann/emotion-english-distilroberta-base")
82
+
83
 
84
  def split_text(self, text, max_length=256, overlap=50):
85
  """Split long text into overlapping segments"""
 
340
  st.write(f"**{MORAL_FOUNDATIONS[foundation]}**: {score:.2%}")
341
 
342
  with tab2:
343
+ status_text.text('Processing Emotional Trajectory...')
344
+ progress_bar.progress(40)
345
  st.subheader("Speech Trajectory Analysis")
 
346
 
347
+ compare_mode = st.toggle("Enable Side-by-Side Comparison", value=False)
348
+
349
+ viz_options = st.multiselect(
350
+ "Select visualizations to display:",
351
+ ["Sentiment Flow", "Moral Foundations Flow", "Basic Emotions Flow"],
352
+ default=["Sentiment Flow"]
353
+ )
354
+
355
+ if len(viz_options) > 1 and compare_mode:
356
+ cols = st.columns(len(viz_options))
357
+ else:
358
+ cols = [st] # Single column mode
359
+
360
+ # Create consistent segments for analyses
361
  segments = analyzer.split_text(text, max_length=512)
362
  num_segments = len(segments)
363
  segment_labels = [f"{i+1}" for i in range(num_segments)]
364
 
365
+ current_col = 0
366
 
367
+ if "Sentiment Flow" in viz_options:
368
+ with cols[current_col]:
369
+ sentiment_scores = analyzer.analyze_emotional_trajectory(text)
370
+
371
+ trajectory_fig = go.Figure(data=go.Scatter(
372
+ x=segment_labels,
373
+ y=sentiment_scores,
374
+ mode='lines+markers',
375
+ line=dict(color='#1f77b4', width=3),
376
+ marker=dict(
377
+ size=8,
378
+ color=['#ff4444' if score < -0.3 else '#44ff44' if score > 0.3 else '#888888' for score in sentiment_scores],
379
+ symbol='circle'
380
+ )
381
+ ))
382
+
383
+ trajectory_fig.update_layout(
384
+ title='Emotional Flow Throughout the Speech',
385
+ xaxis_title='Speech Segments',
386
+ yaxis_title='Emotional Tone',
387
+ yaxis=dict(
388
+ ticktext=['Very Negative', 'Negative', 'Neutral', 'Positive', 'Very Positive'],
389
+ tickvals=[-1, -0.5, 0, 0.5, 1],
390
+ range=[-1.1, 1.1],
391
+ gridcolor='lightgray'
392
+ ),
393
+ hovermode='x unified',
394
+ showlegend=False,
395
+ plot_bgcolor='white',
396
+ height=500
397
  )
398
+
399
+ trajectory_fig.update_traces(
400
+ hovertemplate="Segment: %{x}<br>Score: %{y:.2f}<extra></extra>"
401
+ )
402
+
403
+ st.plotly_chart(trajectory_fig, use_container_width=True)
404
+ if compare_mode:
405
+ current_col += 1
 
 
 
 
 
 
 
 
 
406
 
407
+ if "Moral Foundations Flow" in viz_options:
408
+ with cols[current_col]:
409
+ moral_trajectories = {
410
+ 'care': [], 'fairness': [], 'loyalty': [],
411
+ 'authority': [], 'sanctity': []
412
+ }
413
+
414
+ for segment in segments:
415
+ moral_scores = analyzer.analyze_moral_foundations(segment)
416
+ for foundation in moral_trajectories.keys():
417
+ moral_trajectories[foundation].append(moral_scores[foundation])
418
+
419
+ moral_fig = go.Figure()
420
+ colors = px.colors.qualitative.Set3[:5]
421
+
422
+ for idx, (foundation, scores) in enumerate(moral_trajectories.items()):
423
+ moral_fig.add_trace(go.Scatter(
424
+ x=segment_labels,
425
+ y=scores,
426
+ name=MORAL_FOUNDATIONS[foundation],
427
+ mode='lines+markers',
428
+ line=dict(color=colors[idx], width=2),
429
+ marker=dict(size=6, color=colors[idx])
430
+ ))
431
+
432
+ moral_fig.update_layout(
433
+ title='Moral Foundations Flow',
434
+ xaxis_title='Speech Segments',
435
+ yaxis_title='Foundation Strength',
436
+ yaxis=dict(range=[0, 1]),
437
+ hovermode='x unified',
438
+ plot_bgcolor='white',
439
+ showlegend=True,
440
+ height=500,
441
+ legend=dict(
442
+ orientation="h",
443
+ yanchor="bottom",
444
+ y=1.02,
445
+ xanchor="right",
446
+ x=1
447
+ )
448
+ )
449
+
450
+ moral_fig.update_traces(
451
+ hovertemplate="Segment: %{x}<br>Strength: %{y:.2f}<extra></extra>"
452
+ )
453
+
454
+ st.plotly_chart(moral_fig, use_container_width=True)
455
+ if compare_mode:
456
+ current_col += 1
457
+
458
+ if "Basic Emotions Flow" in viz_options:
459
+ with cols[current_col]:
460
+ emotions = []
461
+ for segment in segments:
462
+ try:
463
+ result = analyzer.emotion_classifier(segment[:512])[0]
464
+ emotions.append(result['label'])
465
+ except:
466
+ emotions.append('neutral')
467
+
468
+ emotions_df = pd.DataFrame({
469
+ 'Segment': segment_labels,
470
+ 'Emotion': emotions
471
+ })
472
+
473
+ emotions_fig = px.bar(
474
+ emotions_df,
475
+ x='Segment',
476
+ y='Emotion',
477
+ color='Emotion',
478
+ title='Basic Emotions Flow',
479
+ color_discrete_sequence=px.colors.qualitative.Set2
480
+ )
481
+
482
+ emotions_fig.update_layout(
483
+ xaxis_title='Speech Segments',
484
+ yaxis_title='Emotion',
485
+ showlegend=True,
486
+ plot_bgcolor='white',
487
+ height=500,
488
+ legend=dict(
489
+ orientation="h",
490
+ yanchor="bottom",
491
+ y=1.02,
492
+ xanchor="right",
493
+ x=1
494
+ )
495
+ )
496
+
497
+ emotions_fig.update_traces(
498
+ hovertemplate="Segment: %{x}<br>Emotion: %{y}<extra></extra>"
499
+ )
500
+
501
+ st.plotly_chart(emotions_fig, use_container_width=True)
502
+ if compare_mode:
503
+ current_col += 1
504
+
505
+ # Add download button
506
+ if viz_options:
507
+ results_df = pd.DataFrame({
508
  'Segment': segment_labels,
509
+ 'Sentiment': sentiment_scores if "Sentiment Flow" in viz_options else None,
510
+ 'Emotion': emotions if "Basic Emotions Flow" in viz_options else None
511
  })
512
 
513
+ if "Moral Foundations Flow" in viz_options:
514
+ for foundation, scores in moral_trajectories.items():
515
+ results_df[f'Moral_{foundation}'] = scores
 
 
 
 
 
516
 
517
+ csv = results_df.to_csv(index=False)
518
+ st.download_button(
519
+ label="Download Analysis Results",
520
+ data=csv,
521
+ file_name="speech_analysis_results.csv",
522
+ mime="text/csv"
523
  )
 
524
 
525
  with tab3:
526
  status_text.text('Analyzing Linguistic Features...')