Update app.py
Browse files
app.py
CHANGED
@@ -128,57 +128,61 @@ class SpeechAnalyzer:
|
|
128 |
return aggregated_scores
|
129 |
|
130 |
def analyze_emotional_trajectory(self, text, window_size=5):
|
131 |
-
"""Enhanced emotional trajectory analysis
|
132 |
segments = self.split_text(text, max_length=512)
|
133 |
sentiment_scores = []
|
|
|
|
|
|
|
|
|
134 |
|
135 |
for segment in segments:
|
136 |
-
# Split into sentences using NLTK
|
137 |
sentences = nltk.sent_tokenize(segment)
|
138 |
-
|
139 |
-
# Process sentences in batches
|
140 |
batch_size = 64
|
141 |
segment_scores = []
|
|
|
142 |
|
143 |
for i in range(0, len(sentences), batch_size):
|
144 |
batch = sentences[i:i+batch_size]
|
|
|
|
|
145 |
|
|
|
146 |
try:
|
147 |
-
# Pad or truncate sentences to ensure consistent length
|
148 |
-
batch = [sent[:512] for sent in batch] # Truncate to max model input
|
149 |
-
|
150 |
-
# Ensure all sentences are strings and non-empty
|
151 |
-
batch = [sent if sent.strip() else "." for sent in batch]
|
152 |
-
|
153 |
results = self.sentiment_pipeline(batch)
|
154 |
-
|
155 |
-
# Process batch results
|
156 |
batch_scores = []
|
157 |
for result in results:
|
158 |
-
# Convert to signed score (-1 to 1 range)
|
159 |
score = result['score']
|
160 |
-
|
|
|
|
|
|
|
|
|
161 |
batch_scores.append(score)
|
162 |
-
|
163 |
segment_scores.extend(batch_scores)
|
164 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
165 |
except Exception as e:
|
166 |
print(f"Batch processing error: {e}")
|
167 |
-
|
168 |
-
|
169 |
-
try:
|
170 |
-
result = self.sentiment_pipeline(sent)[0]
|
171 |
-
score = result['score']
|
172 |
-
score = score * 2 - 1 if result['label'] == 'POSITIVE' else -score
|
173 |
-
segment_scores.append(score)
|
174 |
-
except:
|
175 |
-
segment_scores.append(0)
|
176 |
|
177 |
-
|
178 |
-
|
179 |
-
|
|
|
|
|
|
|
180 |
|
181 |
-
return sentiment_scores
|
182 |
|
183 |
def detect_named_entities(self, text):
|
184 |
"""Detect named entities in the text"""
|
@@ -331,78 +335,68 @@ def main():
|
|
331 |
st.write(f"**{MORAL_FOUNDATIONS[foundation]}**: {score:.2%}")
|
332 |
|
333 |
with tab2:
|
334 |
-
status_text.text('Processing Emotional Trajectory...')
|
335 |
-
progress_bar.progress(40)
|
336 |
st.subheader("Speech Trajectory Analysis")
|
337 |
-
col1, col2 = st.columns(
|
338 |
|
339 |
-
# Create consistent segments for both analyses
|
340 |
segments = analyzer.split_text(text, max_length=512)
|
341 |
num_segments = len(segments)
|
342 |
segment_labels = [f"{i+1}" for i in range(num_segments)]
|
343 |
|
|
|
|
|
344 |
with col1:
|
345 |
-
st.write("###
|
346 |
-
|
347 |
-
|
348 |
-
trajectory_fig = go.Figure(data=go.Scatter(
|
349 |
x=segment_labels,
|
350 |
y=sentiment_scores,
|
351 |
mode='lines+markers',
|
352 |
line=dict(color='#1f77b4', width=3),
|
353 |
-
marker=dict(
|
|
|
|
|
|
|
|
|
354 |
))
|
355 |
|
356 |
-
|
357 |
-
title='
|
358 |
xaxis_title='Speech Segments',
|
359 |
-
yaxis_title='
|
360 |
yaxis=dict(
|
361 |
-
ticktext=['
|
362 |
-
tickvals=[
|
363 |
-
range=[
|
364 |
gridcolor='lightgray'
|
365 |
),
|
366 |
-
hovermode='x unified',
|
367 |
-
showlegend=False,
|
368 |
plot_bgcolor='white'
|
369 |
)
|
370 |
-
|
371 |
-
st.plotly_chart(trajectory_fig)
|
372 |
|
373 |
-
|
374 |
-
|
375 |
-
|
376 |
-
|
377 |
-
|
378 |
-
|
379 |
-
|
380 |
-
|
381 |
|
382 |
-
|
383 |
-
|
384 |
-
|
385 |
-
|
386 |
-
|
387 |
-
|
388 |
-
|
389 |
-
|
390 |
|
391 |
-
|
392 |
-
title='Moral Foundations Flow',
|
393 |
xaxis_title='Speech Segments',
|
394 |
-
yaxis_title='
|
395 |
-
hovermode='x unified',
|
396 |
-
plot_bgcolor='white',
|
397 |
showlegend=True,
|
398 |
-
|
399 |
-
yanchor="top",
|
400 |
-
y=0.99,
|
401 |
-
xanchor="left",
|
402 |
-
x=1.05
|
403 |
-
)
|
404 |
)
|
405 |
-
st.plotly_chart(
|
406 |
|
407 |
with tab3:
|
408 |
status_text.text('Analyzing Linguistic Features...')
|
|
|
128 |
return aggregated_scores
|
129 |
|
130 |
def analyze_emotional_trajectory(self, text, window_size=5):
|
131 |
+
"""Enhanced emotional trajectory analysis with basic emotions"""
|
132 |
segments = self.split_text(text, max_length=512)
|
133 |
sentiment_scores = []
|
134 |
+
basic_emotions = []
|
135 |
+
|
136 |
+
# Add emotion classifier pipeline
|
137 |
+
emotion_classifier = pipeline("text-classification", model="j-hartmann/emotion-english-distilroberta-base", return_all_scores=True)
|
138 |
|
139 |
for segment in segments:
|
|
|
140 |
sentences = nltk.sent_tokenize(segment)
|
|
|
|
|
141 |
batch_size = 64
|
142 |
segment_scores = []
|
143 |
+
segment_emotions = []
|
144 |
|
145 |
for i in range(0, len(sentences), batch_size):
|
146 |
batch = sentences[i:i+batch_size]
|
147 |
+
batch = [sent[:512] for sent in batch]
|
148 |
+
batch = [sent if sent.strip() else "." for sent in batch]
|
149 |
|
150 |
+
# Get sentiment scores
|
151 |
try:
|
|
|
|
|
|
|
|
|
|
|
|
|
152 |
results = self.sentiment_pipeline(batch)
|
|
|
|
|
153 |
batch_scores = []
|
154 |
for result in results:
|
|
|
155 |
score = result['score']
|
156 |
+
# Enhanced score scaling for better visualization
|
157 |
+
if result['label'] == 'POSITIVE':
|
158 |
+
score = 0.5 + (score * 0.5) # Scale from 0.5 to 1.0
|
159 |
+
else:
|
160 |
+
score = 0.5 - (score * 0.5) # Scale from 0.0 to 0.5
|
161 |
batch_scores.append(score)
|
|
|
162 |
segment_scores.extend(batch_scores)
|
163 |
+
|
164 |
+
# Get emotion classifications
|
165 |
+
emotion_results = emotion_classifier(batch)
|
166 |
+
batch_emotions = []
|
167 |
+
for result in emotion_results:
|
168 |
+
# Get the dominant emotion
|
169 |
+
dominant_emotion = max(result[0], key=lambda x: x['score'])
|
170 |
+
batch_emotions.append(dominant_emotion['label'])
|
171 |
+
segment_emotions.extend(batch_emotions)
|
172 |
+
|
173 |
except Exception as e:
|
174 |
print(f"Batch processing error: {e}")
|
175 |
+
segment_scores.extend([0.5] * len(batch))
|
176 |
+
segment_emotions.extend(['neutral'] * len(batch))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
177 |
|
178 |
+
sentiment_scores.append(np.mean(segment_scores))
|
179 |
+
# Get most frequent emotion in segment
|
180 |
+
if segment_emotions:
|
181 |
+
basic_emotions.append(max(set(segment_emotions), key=segment_emotions.count))
|
182 |
+
else:
|
183 |
+
basic_emotions.append('neutral')
|
184 |
|
185 |
+
return sentiment_scores, basic_emotions
|
186 |
|
187 |
def detect_named_entities(self, text):
|
188 |
"""Detect named entities in the text"""
|
|
|
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...')
|