Complete integration guides for backend, frontend, UX, and data science teams. Get your team up and running with SAMO-DL in minutes.
https://samo-unified-api-frrnetyhfa-uc.a.run.app
GET /health
Check API status and model health
POST /predict
Analyze text and return detected emotions
GET /metrics
Prometheus metrics for monitoring
Integrate with Python web frameworks
Integrate with Node.js applications
pip install requests
# or
npm install axios
import requests
def detect_emotion(text: str) -> dict:
"""Integrate with SAMO Emotion API"""
try:
response = requests.post(
"https://samo-unified-api-frrnetyhfa-uc.a.run.app/analyze/journal",
json={"text": text},
headers={"Content-Type": "application/json"},
timeout=10
)
response.raise_for_status()
return response.json()
except requests.exceptions.RequestException as e:
print(f"API Error: {e}")
return {"error": "Failed to analyze emotions"}
# Example usage
emotions = detect_emotion("I'm feeling excited about this project!")
print(emotions) # [{"emotion": "excitement", "confidence": 0.92}]
def safe_emotion_detection(text: str) -> dict:
"""Safe emotion detection with comprehensive error handling"""
if not text or len(text.strip()) == 0:
return {"error": "Empty text provided"}
if len(text) > 1000:
return {"error": "Text too long (max 1000 characters)"}
try:
emotions = detect_emotion(text)
if "error" in emotions:
return emotions
# Validate response format
if not isinstance(emotions, list):
return {"error": "Invalid response format"}
return {"success": True, "emotions": emotions}
except Exception as e:
return {"error": f"Unexpected error: {str(e)}"}
React hooks and components
Vue composables and components
Angular services and components
import React, { useState } from 'react';
// Custom hook for emotion detection
const useEmotionDetection = () => {
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
const [emotions, setEmotions] = useState([]);
const analyzeEmotion = async (text) => {
setLoading(true);
setError(null);
try {
const response = await fetch(
'https://samo-unified-api-frrnetyhfa-uc.a.run.app/analyze/journal',
{
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ text, generate_summary: false })
}
);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
setEmotions(data);
} catch (err) {
setError(err.message);
} finally {
setLoading(false);
}
};
return { analyzeEmotion, emotions, loading, error };
};
// React component
const EmotionAnalyzer = () => {
const [text, setText] = useState('');
const { analyzeEmotion, emotions, loading, error } = useEmotionDetection();
const handleSubmit = (e) => {
e.preventDefault();
if (text.trim()) {
analyzeEmotion(text);
}
};
return (
{error && (
Error: {error}
)}
{emotions.length > 0 && (
Detected Emotions:
{emotions.map((emotion, index) => (
{emotion.emotion}
{Math.round(emotion.confidence * 100)}%
))}
)}
);
};
export default EmotionAnalyzer;
This guide shows UX designers and product managers how to make your app respond to user emotions in real-time. Think of it like giving your app emotional intelligence - it can sense how users feel and adapt accordingly.
Understand how users feel about your product as they use it
Make your app feel like it understands each user personally
First, you need to connect your app to our emotion detection API. This is like giving your app the ability to "read" emotions from text.
// Step 1: Set up your API connection
const ANALYZE_API_URL = 'https://samo-unified-api-frrnetyhfa-uc.a.run.app/analyze/journal';
// This function sends text to our API and gets back emotion data
async function analyzeEmotion(text) {
try {
const response = await fetch(ANALYZE_API_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ text: text, generate_summary: false })
});
if (!response.ok) {
console.error(`HTTP error! status: ${response.status}`);
throw new Error(`HTTP error! status: ${response.status}`);
}
const result = await response.json();
return result; // Returns emotions like: [{emotion: "joy", confidence: 0.95}]
} catch (error) {
console.error('Failed to analyze emotion:', error);
return null;
}
}
This class manages how your app responds to different emotions. Think of it as the "brain" that decides what to change based on user emotions.
// Step 2: Create your emotion-aware UI manager
class EmotionAwareUI {
constructor() {
this.currentEmotion = null;
this.emotionHistory = [];
this.isAnalyzing = false;
this.debounceTimer = null;
this.debounceDelay = 300; // milliseconds, adjust as needed
this.analysisQueue = []; // Queue to prevent race conditions
this.isProcessingQueue = false;
}
// This method analyzes user input and updates the UI
async analyzeUserInput(text) {
// Validate input
if (!text || text.trim() === '') return;
// Debounce: clear any pending analysis and schedule a new one
if (this.debounceTimer) {
clearTimeout(this.debounceTimer);
}
this.debounceTimer = setTimeout(() => {
this.queueAnalysis(text);
}, this.debounceDelay);
}
// Queue analysis to prevent race conditions
async queueAnalysis(text) {
// Add to queue
this.analysisQueue.push(text);
// Process queue if not already processing
if (!this.isProcessingQueue) {
this.processQueue();
}
}
// Process the analysis queue sequentially
async processQueue() {
if (this.isProcessingQueue || this.analysisQueue.length === 0) {
return;
}
this.isProcessingQueue = true;
while (this.analysisQueue.length > 0) {
const text = this.analysisQueue.shift(); // Get next item from queue
if (this.isAnalyzing) {
// If already analyzing, wait for it to complete
await this.waitForAnalysisComplete();
}
await this.performAnalysis(text);
}
this.isProcessingQueue = false;
}
// Wait for current analysis to complete
async waitForAnalysisComplete() {
return new Promise((resolve) => {
const checkComplete = () => {
if (!this.isAnalyzing) {
resolve();
} else {
setTimeout(checkComplete, 50); // Check every 50ms
}
};
checkComplete();
});
}
// Perform the actual emotion analysis
async performAnalysis(text) {
this.isAnalyzing = true;
this.showLoadingIndicator(); // Show user that analysis is happening
try {
const emotions = await analyzeEmotion(text);
if (emotions && emotions.length > 0) {
this.currentEmotion = emotions[0].emotion;
this.emotionHistory.push({
emotion: this.currentEmotion,
confidence: emotions[0].confidence,
timestamp: new Date(),
text: text
});
this.adaptUI(); // Change the UI based on emotion
}
} catch (error) {
console.error('Emotion analysis failed:', error);
this.showError('Unable to analyze emotion at this time');
} finally {
this.isAnalyzing = false;
this.hideLoadingIndicator();
}
}
// This method changes your app's appearance based on emotion
adaptUI() {
const body = document.body;
// Remove old emotion styles
body.classList.remove('emotion-joy', 'emotion-sadness', 'emotion-anger', 'emotion-fear', 'emotion-surprise', 'emotion-disgust');
// Add new emotion style
if (this.currentEmotion) {
body.classList.add(`emotion-${this.currentEmotion}`);
this.updateColorScheme();
this.updateContent();
this.updateInteractions();
}
}
// Change colors based on emotion
updateColorScheme() {
const colorSchemes = {
joy: { primary: '#10b981', secondary: '#34d399', background: '#ecfdf5' },
sadness: { primary: '#3b82f6', secondary: '#60a5fa', background: '#eff6ff' },
anger: { primary: '#ef4444', secondary: '#f87171', background: '#fef2f2' },
fear: { primary: '#f59e0b', secondary: '#fbbf24', background: '#fffbeb' },
surprise: { primary: '#8b5cf6', secondary: '#a78bfa', background: '#f5f3ff' },
disgust: { primary: '#059669', secondary: '#34d399', background: '#ecfdf5' },
neutral: { primary: '#6b7280', secondary: '#d1d5db', background: '#f3f4f6' } // Added neutral color scheme
};
const colors = colorSchemes[this.currentEmotion] || colorSchemes.neutral;
// Apply colors to your app
document.documentElement.style.setProperty('--primary-color', colors.primary);
document.documentElement.style.setProperty('--secondary-color', colors.secondary);
document.documentElement.style.setProperty('--background-color', colors.background);
}
// Change content based on emotion
updateContent() {
const emotionMessages = {
joy: "Great! We're glad you're having a good experience! š",
sadness: "We're here to help. Is there anything we can do to make this better? š",
anger: "We understand your frustration. Let's work together to resolve this. š§",
fear: "Don't worry, we'll guide you through this step by step. š¤",
surprise: "Wow! We're excited about this too! š",
disgust: "We appreciate your feedback. Let's improve this together. š"
};
const fallbackMessage = "Thank you for sharing your feelings with us! We're here to help.";
const messageElement = document.getElementById('emotion-message');
if (messageElement) {
if (emotionMessages[this.currentEmotion]) {
messageElement.textContent = emotionMessages[this.currentEmotion];
} else {
messageElement.textContent = fallbackMessage;
}
messageElement.style.display = 'block';
}
}
// Change how users interact with your app
updateInteractions() {
const interactionStyles = {
joy: { animationSpeed: 'fast', feedbackStyle: 'celebratory' },
sadness: { animationSpeed: 'slow', feedbackStyle: 'gentle' },
anger: { animationSpeed: 'fast', feedbackStyle: 'direct' },
fear: { animationSpeed: 'slow', feedbackStyle: 'reassuring' },
surprise: { animationSpeed: 'fast', feedbackStyle: 'exciting' },
disgust: { animationSpeed: 'normal', feedbackStyle: 'professional' }
};
const style = interactionStyles[this.currentEmotion] || interactionStyles.joy;
// Apply interaction changes
document.body.style.setProperty('--animation-speed', style.animationSpeed);
this.updateFeedbackStyle(style.feedbackStyle);
}
// Helper methods
showLoadingIndicator() {
const loader = document.getElementById('emotion-loader');
if (loader) loader.style.display = 'block';
}
hideLoadingIndicator() {
const loader = document.getElementById('emotion-loader');
if (loader) loader.style.display = 'none';
}
showError(message) {
const errorElement = document.getElementById('emotion-error');
if (errorElement) {
errorElement.textContent = message;
errorElement.style.display = 'block';
}
}
}
Create visual styles that change based on the detected emotion. This makes your app feel more responsive and personalized.
/* Step 3: Add emotion-based CSS styles */
/* Joy - Bright, energetic colors */
.emotion-joy {
--primary-color: #10b981;
--secondary-color: #34d399;
--background-color: #ecfdf5;
}
.emotion-joy .btn-primary {
background: linear-gradient(45deg, #10b981, #34d399);
border: none;
animation: bounce 0.6s ease-in-out;
}
/* Sadness - Calm, supportive colors */
.emotion-sadness {
--primary-color: #3b82f6;
--secondary-color: #60a5fa;
--background-color: #eff6ff;
}
.emotion-sadness .btn-primary {
background: linear-gradient(45deg, #3b82f6, #60a5fa);
border: none;
transition: all 0.3s ease;
}
/* Anger - Direct, action-oriented colors */
.emotion-anger {
--primary-color: #ef4444;
--secondary-color: #f87171;
--background-color: #fef2f2;
}
.emotion-anger .btn-primary {
background: linear-gradient(45deg, #ef4444, #f87171);
border: none;
transform: scale(1.05);
}
/* Fear - Reassuring, gentle colors */
.emotion-fear {
--primary-color: #f59e0b;
--secondary-color: #fbbf24;
--background-color: #fffbeb;
}
.emotion-fear .btn-primary {
background: linear-gradient(45deg, #f59e0b, #fbbf24);
border: none;
box-shadow: 0 4px 12px rgba(245, 158, 11, 0.3);
}
/* Surprise - Exciting, vibrant colors */
.emotion-surprise {
--primary-color: #8b5cf6;
--secondary-color: #a78bfa;
--background-color: #f5f3ff;
}
.emotion-surprise .btn-primary {
background: linear-gradient(45deg, #8b5cf6, #a78bfa);
border: none;
animation: pulse 1s infinite;
}
/* Disgust - Professional, clean colors */
.emotion-disgust {
--primary-color: #059669;
--secondary-color: #34d399;
--background-color: #ecfdf5;
}
.emotion-disgust .btn-primary {
background: linear-gradient(45deg, #059669, #34d399);
border: none;
border-radius: 8px;
}
/* Animations */
@keyframes bounce {
0%, 20%, 60%, 100% { transform: translateY(0); }
40% { transform: translateY(-10px); }
80% { transform: translateY(-5px); }
}
@keyframes pulse {
0% { transform: scale(1); }
50% { transform: scale(1.05); }
100% { transform: scale(1); }
}
Now connect your emotion analysis to user interactions. This is where the magic happens!
// Step 4: Connect everything together
document.addEventListener('DOMContentLoaded', function() {
// Create your emotion-aware UI
const emotionUI = new EmotionAwareUI();
// Connect to text inputs
const textInputs = document.querySelectorAll('input[type="text"], textarea');
textInputs.forEach(input => {
input.addEventListener('blur', function() {
if (this.value.trim()) {
emotionUI.analyzeUserInput(this.value);
}
});
});
// Connect to chat messages
const chatContainer = document.getElementById('chat-messages');
if (chatContainer) {
const observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
mutation.addedNodes.forEach(function(node) {
if (node.nodeType === 1 && node.classList.contains('user-message')) {
const text = node.textContent;
emotionUI.analyzeUserInput(text);
}
});
});
});
observer.observe(chatContainer, { childList: true });
}
// Connect to form submissions
const forms = document.querySelectorAll('form');
forms.forEach(form => {
form.addEventListener('submit', function(e) {
const formData = new FormData(form);
const textInputs = form.querySelectorAll('input[type="text"], textarea');
textInputs.forEach(input => {
if (input.value.trim()) {
emotionUI.analyzeUserInput(input.value);
}
});
});
});
});
Your app now responds to user emotions in real-time! Users will feel like your app understands them personally, leading to better engagement and satisfaction.
Subtle changes work better than dramatic ones. Users should feel the difference, not be distracted by it.
Always test emotion-based changes with real users to ensure they enhance, not hinder, the experience.
Don't analyze every keystroke. Wait for natural pauses (like when users finish typing) to avoid overwhelming them.
Always inform users about emotion analysis and give them the option to opt out if they prefer.
This guide shows data scientists and analysts how to collect, analyze, and derive insights from emotion data. Think of it as a complete toolkit for understanding user emotions at scale and using that data to improve your products.
Collect emotion data efficiently and reliably
Keep your emotion detection model performing at its best
Keep your model learning and improving automatically
Create a robust system to collect emotion data from your API. This is the foundation for all your analysis.
# Step 1: Set up your data collection system
import pandas as pd
import requests
import numpy as np
from datetime import datetime
import logging
import json
import time
from typing import List, Dict, Optional
class EmotionDataCollector:
"""
A smart data collector for emotion analysis results.
Think of this as your "emotion data vacuum" - it sucks up all the emotion data
and stores it in a way that's easy to analyze later.
"""
def __init__(self, api_url: str = "https://samo-unified-api-frrnetyhfa-uc.a.run.app"):
self.api_url = api_url
self.session = requests.Session()
self.logger = logging.getLogger(__name__)
# Set up logging so you can see what's happening
logging.basicConfig(level=logging.INFO)
# Track collection statistics
self.stats = {
'total_requests': 0,
'successful_requests': 0,
'failed_requests': 0,
'total_texts_processed': 0
}
def analyze_single_text(self, text: str) -> Optional[Dict]:
"""
Analyze a single piece of text and return emotion data.
This is like asking the API "what emotions are in this text?"
"""
try:
self.stats['total_requests'] += 1
# Send the text to our emotion API
response = self.session.post(
f"{self.api_url}/predict",
json={"text": text},
timeout=30 # Timeout after 30 seconds
)
response.raise_for_status() # Raise error if request failed
# Get the emotion results
emotions = response.json()
self.stats['successful_requests'] += 1
self.stats['total_texts_processed'] += 1
# Return structured data
return {
'text': text,
'emotions': emotions,
'timestamp': datetime.now().isoformat(),
'status': 'success',
'text_length': len(text),
'emotion_count': len(emotions) if emotions else 0
}
except Exception as e:
self.stats['failed_requests'] += 1
self.logger.error(f"Error analyzing text: {type(e).__name__} - {e}")
return {
'text': text,
'emotions': [],
'timestamp': datetime.now().isoformat(),
'status': 'error',
'error': str(e),
'text_length': len(text),
'emotion_count': 0
}
def analyze_batch(self, texts: List[str], max_retries: int = 3) -> pd.DataFrame:
"""
Analyze multiple texts at once using the batch endpoint.
This is much more efficient than analyzing one text at a time.
"""
self.logger.info(f"Starting batch analysis of {len(texts)} texts...")
for attempt in range(max_retries):
try:
self.stats['total_requests'] += 1
response = self.session.post(
f"{self.api_url}/predict_batch", # Use the batch endpoint
json={"texts": texts},
timeout=60 # Longer timeout for batch requests
)
response.raise_for_status()
results = response.json() # Assuming it returns a list of results for each text
# Process results into a DataFrame
processed_results = []
for i, text in enumerate(texts):
emotions = results[i] if i < len(results) else []
processed_results.append({
'text': text,
'emotions': emotions,
'timestamp': datetime.now().isoformat(),
'status': 'success',
'text_length': len(text),
'emotion_count': len(emotions) if emotions else 0
})
df = pd.DataFrame(processed_results)
self.stats['successful_requests'] += 1
self.stats['total_texts_processed'] += len(texts)
self.logger.info(f"Batch analysis complete! Processed {len(texts)} texts.")
return df
except Exception as e:
self.logger.warning(f"Batch analysis attempt {attempt+1} failed: {e}")
if attempt < max_retries - 1:
wait_time = 2 ** attempt # Exponential backoff
self.logger.info(f"Retrying batch analysis in {wait_time}s...")
time.sleep(wait_time)
else:
self.stats['failed_requests'] += 1
self.logger.error(f"Batch analysis failed after {max_retries} attempts: {e}")
# Create error entries for all texts in the batch
error_results = [{
'text': text,
'emotions': [],
'timestamp': datetime.now().isoformat(),
'status': 'error',
'error': str(e),
'text_length': len(text),
'emotion_count': 0
} for text in texts]
return pd.DataFrame(error_results)
def save_to_csv(self, df: pd.DataFrame, filename: str):
"""Save your emotion data to a CSV file for later analysis."""
df.to_csv(filename, index=False)
self.logger.info(f"Data saved to {filename}")
def get_stats(self) -> Dict:
"""Get collection statistics to see how well things are working."""
return self.stats.copy()
Build tools to analyze the emotion data you've collected. This helps you understand patterns and trends.
# Step 2: Create your data analysis toolkit
import matplotlib.pyplot as plt
import seaborn as sns
from collections import Counter
import plotly.express as px
import plotly.graph_objects as go
class EmotionAnalyzer:
"""
Your emotion data analysis toolkit.
This class helps you understand what your emotion data is telling you.
"""
def __init__(self, data: pd.DataFrame):
self.data = data
self.logger = logging.getLogger(__name__)
def get_emotion_distribution(self) -> pd.DataFrame:
"""
See which emotions are most common in your data.
This helps you understand what emotions your users typically express.
"""
all_emotions = []
for emotions_list in self.data['emotions']:
if isinstance(emotions_list, list):
for emotion in emotions_list:
if isinstance(emotion, dict) and 'emotion' in emotion:
all_emotions.append(emotion['emotion'])
# Count how many times each emotion appears
emotion_counts = Counter(all_emotions)
# Convert to DataFrame for easy analysis
df = pd.DataFrame(list(emotion_counts.items()),
columns=['emotion', 'count'])
df = df.sort_values('count', ascending=False)
return df
def plot_emotion_distribution(self, save_path: str = None):
"""
Create a beautiful chart showing emotion distribution.
This makes it easy to see patterns at a glance.
"""
emotion_df = self.get_emotion_distribution()
# Create a colorful bar chart
plt.figure(figsize=(12, 6))
colors = ['#10b981', '#3b82f6', '#ef4444', '#f59e0b', '#8b5cf6', '#059669']
bars = plt.bar(emotion_df['emotion'], emotion_df['count'],
color=colors[:len(emotion_df)])
plt.title('Distribution of Emotions in Your Data', fontsize=16, fontweight='bold')
plt.xlabel('Emotion', fontsize=12)
plt.ylabel('Count', fontsize=12)
plt.xticks(rotation=45)
# Add value labels on bars
for bar in bars:
height = bar.get_height()
plt.text(bar.get_x() + bar.get_width()/2., height + 0.01,
f'{int(height)}', ha='center', va='bottom')
plt.tight_layout()
if save_path:
plt.savefig(save_path, dpi=300, bbox_inches='tight')
self.logger.info(f"Chart saved to {save_path}")
plt.show()
def analyze_emotion_by_text_length(self):
"""
See if longer texts have different emotions than shorter ones.
This can reveal interesting patterns about how people express emotions.
"""
# Extract emotions and text lengths
emotion_length_data = []
for _, row in self.data.iterrows():
if isinstance(row['emotions'], list):
for emotion in row['emotions']:
if isinstance(emotion, dict) and 'emotion' in emotion:
emotion_length_data.append({
'emotion': emotion['emotion'],
'text_length': row['text_length'],
'confidence': emotion.get('confidence', 0)
})
if emotion_length_data:
df = pd.DataFrame(emotion_length_data)
# Create a scatter plot
plt.figure(figsize=(12, 8))
# Plot each emotion with a different color
emotions = df['emotion'].unique()
colors = plt.cm.Set3(np.linspace(0, 1, len(emotions)))
for emotion, color in zip(emotions, colors):
emotion_data = df[df['emotion'] == emotion]
plt.scatter(emotion_data['text_length'], emotion_data['confidence'],
label=emotion, color=color, alpha=0.7, s=50)
plt.title('Emotion Confidence vs Text Length', fontsize=16, fontweight='bold')
plt.xlabel('Text Length (characters)', fontsize=12)
plt.ylabel('Confidence Score', fontsize=12)
plt.legend()
plt.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
def get_daily_emotion_trends(self):
"""
See how emotions change over time.
This helps you spot trends and seasonal patterns.
"""
# Convert timestamp to datetime safely
self.data['timestamp_parsed'] = pd.to_datetime(self.data['timestamp'], errors='coerce')
self.data['date'] = self.data['timestamp_parsed'].dt.date
# Count emotions by date
daily_emotions = []
for date in self.data['date'].unique():
day_data = self.data[self.data['date'] == date]
for emotions_list in day_data['emotions']:
if isinstance(emotions_list, list):
for emotion in emotions_list:
if isinstance(emotion, dict) and 'emotion' in emotion:
daily_emotions.append({
'date': date,
'emotion': emotion['emotion']
})
if daily_emotions:
df = pd.DataFrame(daily_emotions)
daily_counts = df.groupby(['date', 'emotion']).size().reset_index(name='count')
# Create a line chart
plt.figure(figsize=(15, 8))
emotions = daily_counts['emotion'].unique()
colors = plt.cm.Set3(np.linspace(0, 1, len(emotions)))
for emotion, color in zip(emotions, colors):
emotion_data = daily_counts[daily_counts['emotion'] == emotion]
plt.plot(emotion_data['date'], emotion_data['count'],
label=emotion, color=color, linewidth=2, marker='o')
plt.title('Daily Emotion Trends', fontsize=16, fontweight='bold')
plt.xlabel('Date', fontsize=12)
plt.ylabel('Count', fontsize=12)
plt.legend()
plt.xticks(rotation=45)
plt.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
Create a system to monitor your emotion detection model's performance and catch issues early.
# Step 3: Set up model monitoring
import time
from datetime import datetime, timedelta
import smtplib
from email.mime.text import MIMEText
class EmotionModelMonitor:
"""
Monitor your emotion detection model to make sure it's working well.
This is like having a health check for your AI model.
"""
def __init__(self, api_url: str = "https://samo-unified-api-frrnetyhfa-uc.a.run.app"):
self.api_url = api_url
self.session = requests.Session()
self.logger = logging.getLogger(__name__)
# Performance thresholds
self.thresholds = {
'response_time_max': 5.0, # seconds
'success_rate_min': 0.95, # 95%
'confidence_min': 0.7 # 70%
}
# Store recent performance data
self.performance_history = []
def run_health_check(self) -> Dict:
"""
Run a comprehensive health check on your emotion API.
This tests if everything is working properly.
"""
test_texts = [
"I'm so happy today! š",
"This is really frustrating me.",
"I'm feeling a bit sad about this.",
"Wow, that's amazing!",
"I'm scared about what might happen."
]
results = {
'timestamp': datetime.now(),
'response_times': [],
'success_count': 0,
'total_requests': len(test_texts),
'confidence_scores': [],
'errors': []
}
for text in test_texts:
start_time = time.time()
try:
response = self.session.post(
f"{self.api_url}/predict",
json={"text": text},
timeout=10 # Timeout after 10 seconds
)
response.raise_for_status()
response_time = time.time() - start_time
results['response_times'].append(response_time)
emotions = response.json()
if emotions and len(emotions) > 0:
results['success_count'] += 1
results['confidence_scores'].append(emotions[0].get('confidence', 0))
except Exception as e:
results['errors'].append(f'{type(e).__name__}: {e}')
# Calculate metrics
results['avg_response_time'] = np.mean(results['response_times']) if results['response_times'] else 0
results['success_rate'] = results['success_count'] / results['total_requests']
results['avg_confidence'] = np.mean(results['confidence_scores']) if results['confidence_scores'] else 0
# Check if metrics are within acceptable ranges
results['status'] = 'healthy'
if (results['avg_response_time'] > self.thresholds['response_time_max'] or
results['success_rate'] < self.thresholds['success_rate_min'] or
results['avg_confidence'] < self.thresholds['confidence_min']):
results['status'] = 'warning'
# Store in history
self.performance_history.append(results)
return results
def create_performance_dashboard(self):
"""
Create a visual dashboard showing model performance over time.
This helps you spot trends and issues.
"""
if len(self.performance_history) < 2:
self.logger.warning("Need more data points for dashboard")
return
# Extract data for plotting
timestamps = [r['timestamp'] for r in self.performance_history]
response_times = [r['avg_response_time'] for r in self.performance_history]
success_rates = [r['success_rate'] * 100 for r in self.performance_history] # Convert to percentage
confidences = [r['avg_confidence'] * 100 for r in self.performance_history] # Convert to percentage
# Create subplots
fig, (ax1, ax2, ax3) = plt.subplots(3, 1, figsize=(12, 10))
# Response time plot
ax1.plot(timestamps, response_times, 'b-o', linewidth=2)
ax1.axhline(y=self.thresholds['response_time_max'], color='r', linestyle='--',
label=f'Max threshold ({self.thresholds["response_time_max"]}s)')
ax1.set_title('Average Response Time Over Time', fontweight='bold')
ax1.set_ylabel('Response Time (seconds)')
ax1.legend()
ax1.grid(True, alpha=0.3)
# Success rate plot
ax2.plot(timestamps, success_rates, 'g-o', linewidth=2)
ax2.axhline(y=self.thresholds['success_rate_min'] * 100, color='r', linestyle='--',
label=f'Min threshold ({self.thresholds["success_rate_min"]*100}%)')
ax2.set_title('Success Rate Over Time', fontweight='bold')
ax2.set_ylabel('Success Rate (%)')
ax2.legend()
ax2.grid(True, alpha=0.3)
# Confidence plot
ax3.plot(timestamps, confidences, 'm-o', linewidth=2)
ax3.axhline(y=self.thresholds['confidence_min'] * 100, color='r', linestyle='--',
label=f'Min threshold ({self.thresholds["confidence_min"]*100}%)')
ax3.set_title('Average Confidence Over Time', fontweight='bold')
ax3.set_ylabel('Confidence (%)')
ax3.set_xlabel('Time')
ax3.legend()
ax3.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
def send_alert(self, message: str, email: str = None):
"""
Send an alert when something goes wrong.
This helps you catch problems before they affect users.
"""
self.logger.warning(f"ALERT: {message}")
if email:
# You would configure your email settings here
self.logger.info(f"Alert email would be sent to {email}: {message}")
def run_continuous_monitoring(self, check_interval: int = 3600):
"""
Run continuous monitoring with regular health checks.
This runs in the background to keep an eye on your model.
"""
self.logger.info(f"Starting continuous monitoring (checks every {check_interval} seconds)")
while True:
try:
results = self.run_health_check()
if results['status'] == 'warning':
self.send_alert(f"Model performance warning: {results}")
# Create dashboard every 24 hours
if len(self.performance_history) % 24 == 0:
self.create_performance_dashboard()
time.sleep(check_interval)
except KeyboardInterrupt:
self.logger.info("Monitoring stopped by user")
break
except Exception as e:
self.logger.error(f"Monitoring error: {e}")
time.sleep(check_interval)
Now combine everything into a complete data science workflow that you can run regularly.
# Step 4: Put it all together - Complete workflow
def run_complete_emotion_analysis_workflow():
"""
Complete workflow for emotion data analysis.
Run this regularly to keep track of your emotion data insights.
"""
# Step 1: Collect new data
print("š Step 1: Collecting emotion data...")
collector = EmotionDataCollector()
# Example: Analyze some sample texts
sample_texts = [
"I love this new feature! It's exactly what I needed.",
"This is so frustrating, nothing works properly.",
"I'm really worried about the security of my data.",
"Wow, this is amazing! I can't believe how good this is.",
"I'm feeling a bit sad about the changes you made."
]
# Collect data
emotion_data = collector.analyze_batch(sample_texts)
# Save to file
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
filename = f"emotion_data_{timestamp}.csv"
collector.save_to_csv(emotion_data, filename)
# Step 2: Analyze the data
print("š Step 2: Analyzing emotion patterns...")
analyzer = EmotionAnalyzer(emotion_data)
# Get emotion distribution
emotion_dist = analyzer.get_emotion_distribution()
print("\nEmotion Distribution:")
print(emotion_dist)
# Create visualizations
analyzer.plot_emotion_distribution(f"emotion_distribution_{timestamp}.png")
analyzer.analyze_emotion_by_text_length()
analyzer.get_daily_emotion_trends()
# Step 3: Monitor model health
print("š Step 3: Running model health check...")
monitor = EmotionModelMonitor()
health_results = monitor.run_health_check()
print(f"\nModel Health Status: {health_results['status']}")
print(f"Average Response Time: {health_results['avg_response_time']:.2f}s")
print(f"Success Rate: {health_results['success_rate']*100:.1f}%")
print(f"Average Confidence: {health_results['avg_confidence']*100:.1f}%")
# Step 4: Generate insights report
print("š Step 4: Generating insights report...")
insights = {
'total_texts_analyzed': len(emotion_data),
'most_common_emotion': emotion_dist.iloc[0]['emotion'] if len(emotion_dist) > 0 else 'None',
'model_performance': health_results['status'],
'data_quality': 'Good' if health_results['success_rate'] > 0.9 else 'Needs attention',
'recommendations': []
}
# Add recommendations based on findings
if health_results['avg_response_time'] > 3:
insights['recommendations'].append("Consider optimizing API response time")
if health_results['avg_confidence'] < 0.8:
insights['recommendations'].append("Model confidence is low - consider retraining")
if len(emotion_dist) > 0 and emotion_dist.iloc[0]['count'] > emotion_dist['count'].sum() * 0.5:
insights['recommendations'].append("Emotion distribution is skewed - check data balance")
# Save insights report
insights_filename = f"emotion_insights_{timestamp}.json"
with open(insights_filename, 'w') as f:
json.dump(insights, f, indent=2, default=str)
print(f"\nā
Analysis complete! Files saved:")
print(f" - Data: {filename}")
print(f" - Insights: {insights_filename}")
print(f" - Chart: emotion_distribution_{timestamp}.png")
return insights
# Run the complete workflow
if __name__ == "__main__":
insights = run_complete_emotion_analysis_workflow()
print("\nšÆ Key Insights:")
for key, value in insights.items():
if key != 'recommendations':
print(f" {key}: {value}")
if insights['recommendations']:
print("\nš” Recommendations:")
for rec in insights['recommendations']:
print(f" ⢠{rec}")
You now have a complete toolkit for collecting, analyzing, and monitoring emotion data. Use these insights to improve your products and understand your users better!
Emotion patterns can change over time. Monitor for shifts in emotion distribution that might indicate your model needs retraining.
Connect emotion data to business outcomes like user retention, conversion rates, and customer satisfaction scores.
Always anonymize emotion data and follow data protection regulations. Never store personally identifiable information with emotion data.
Work with psychologists or UX researchers to validate your emotion analysis insights and ensure they make sense in context.