Lakssssshya's picture
Update app.py
32ffe5a verified
"""
Complete Gradio App for Emotion Detection
Deploy to Hugging Face Spaces
"""
import os
# --- Runtime repair to fix Hugging Face dependency override ---
os.system(
"pip install -U gradio==4.44.0 huggingface_hub==0.20.3 transformers==4.39.3 --no-cache-dir > /dev/null"
)
# ---------------------------------------------------------------------
import gradio as gr
import torch
import torch.nn as nn
from transformers import RobertaTokenizer, RobertaModel
from huggingface_hub import hf_hub_download
import json
import numpy as np
# ==================== Model Architecture ====================
class RobertaForMultiLabelClassification(nn.Module):
def __init__(self, model_name, num_labels, dropout_rate=0.3, use_mean_pooling=True):
super().__init__()
self.roberta = RobertaModel.from_pretrained(model_name)
self.use_mean_pooling = use_mean_pooling
hidden_size = self.roberta.config.hidden_size
self.dropout1 = nn.Dropout(dropout_rate)
self.fc1 = nn.Linear(hidden_size, hidden_size // 2)
self.relu = nn.ReLU()
self.dropout2 = nn.Dropout(dropout_rate)
self.fc2 = nn.Linear(hidden_size // 2, num_labels)
def mean_pooling(self, token_embeddings, attention_mask):
input_mask_expanded = attention_mask.unsqueeze(-1).expand(token_embeddings.size()).float()
sum_embeddings = torch.sum(token_embeddings * input_mask_expanded, 1)
sum_mask = torch.clamp(input_mask_expanded.sum(1), min=1e-9)
return sum_embeddings / sum_mask
def forward(self, input_ids, attention_mask):
outputs = self.roberta(input_ids, attention_mask=attention_mask)
if self.use_mean_pooling:
pooled_output = self.mean_pooling(outputs.last_hidden_state, attention_mask)
else:
pooled_output = outputs.pooler_output
x = self.dropout1(pooled_output)
x = self.fc1(x)
x = self.relu(x)
x = self.dropout2(x)
logits = self.fc2(x)
return logits
# ==================== Emotion Predictor ====================
class EmotionPredictor:
def __init__(self, model_name="Lakssssshya/roberta-large-goemotions"):
print(f"πŸ”„ Loading model: {model_name}")
self.device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
print(f"πŸ“ Using device: {self.device}")
self.tokenizer = RobertaTokenizer.from_pretrained(model_name)
# Load config
config_path = hf_hub_download(repo_id=model_name, filename="config.json")
with open(config_path, 'r') as f:
config = json.load(f)
self.num_labels = config['num_labels']
self.model = RobertaForMultiLabelClassification(
model_name='roberta-large',
num_labels=self.num_labels,
dropout_rate=config.get('dropout_rate', 0.3),
use_mean_pooling=config.get('use_mean_pooling', True)
)
# Load weights
weights_path = hf_hub_download(repo_id=model_name, filename="pytorch_model.bin")
state_dict = torch.load(weights_path, map_location=self.device)
self.model.load_state_dict(state_dict)
self.model.to(self.device)
self.model.eval()
# Load thresholds
try:
thresholds_path = hf_hub_download(repo_id=model_name, filename="optimal_thresholds.json")
with open(thresholds_path, 'r') as f:
self.thresholds = np.array(json.load(f))
except:
self.thresholds = np.ones(self.num_labels) * 0.5
self.emotion_labels = [
'admiration', 'amusement', 'anger', 'annoyance', 'approval',
'caring', 'confusion', 'curiosity', 'desire', 'disappointment',
'disapproval', 'disgust', 'embarrassment', 'excitement', 'fear',
'gratitude', 'grief', 'joy', 'love', 'nervousness',
'optimism', 'pride', 'realization', 'relief', 'remorse',
'sadness', 'surprise', 'neutral'
]
print("βœ… Model loaded successfully!")
def predict(self, text, top_k=5):
inputs = self.tokenizer(text, return_tensors='pt', truncation=True, max_length=128, padding=True)
inputs = {k: v.to(self.device) for k, v in inputs.items()}
with torch.no_grad():
logits = self.model(input_ids=inputs['input_ids'], attention_mask=inputs['attention_mask'])
probs = torch.sigmoid(logits).cpu().numpy()[0]
predictions = (probs > self.thresholds).astype(int)
predicted_emotions = [self.emotion_labels[i] for i in range(len(predictions)) if predictions[i] == 1]
top_indices = np.argsort(probs)[::-1][:top_k]
top_emotions = [
{
'emotion': self.emotion_labels[idx],
'score': float(probs[idx]),
'predicted': bool(predictions[idx])
}
for idx in top_indices
]
return {
'text': text,
'emotions': predicted_emotions,
'top_emotions': top_emotions
}
# ==================== Initialize Predictor ====================
print("πŸš€ Initializing Emotion Predictor...")
predictor = EmotionPredictor()
# ==================== Gradio Interface Functions ====================
def predict_emotions(text):
"""Main prediction function for Gradio"""
if not text.strip():
return "⚠️ Please enter some text to analyze!"
result = predictor.predict(text, top_k=5)
# Format output as markdown
output = "## 🎯 Detected Emotions\n\n"
if result['emotions']:
output += ", ".join([f"**{e}**" for e in result['emotions']])
else:
output += "**neutral**"
output += "\n\n---\n\n## πŸ“Š Top 5 Emotions by Confidence\n\n"
for emotion_data in result['top_emotions']:
bar_length = int(emotion_data['score'] * 20)
bar = "β–ˆ" * bar_length + "β–‘" * (20 - bar_length)
check = "βœ“" if emotion_data['predicted'] else " "
score_pct = emotion_data['score'] * 100
output += f"{check} **{emotion_data['emotion']}** `{bar}` {score_pct:.1f}%\n\n"
return output
# ==================== Gradio Interface ====================
with gr.Blocks(theme=gr.themes.Soft()) as demo:
gr.Markdown("""
# 🎭 Emotion Detector
### Multi-label emotion classification using RoBERTa-Large GoEmotions
This model detects 28 different emotions from your text using state-of-the-art NLP.
""")
with gr.Row():
with gr.Column():
text_input = gr.Textbox(
label="πŸ“ Enter your text",
placeholder="Type something here... (e.g., 'I'm so proud and excited about this achievement!')",
lines=5
)
analyze_btn = gr.Button("πŸ” Analyze Emotions", variant="primary", size="lg")
gr.Markdown("### πŸ’‘ Try these examples:")
with gr.Row():
example1 = gr.Button("πŸ† Achievement", size="sm")
example2 = gr.Button("πŸ˜” Regret", size="sm")
example3 = gr.Button("😲 Surprise", size="sm")
with gr.Row():
example4 = gr.Button("πŸ™ Gratitude", size="sm")
example5 = gr.Button("🀒 Disgust", size="sm")
example6 = gr.Button("❀️ Love", size="sm")
with gr.Column():
output = gr.Markdown(label="Results")
# Button actions
analyze_btn.click(fn=predict_emotions, inputs=text_input, outputs=output)
# Example buttons
example1.click(
lambda: "I'm so proud and excited about this achievement!",
outputs=text_input
)
example2.click(
lambda: "I really regret saying that earlier.",
outputs=text_input
)
example3.click(
lambda: "I can't believe this happened!",
outputs=text_input
)
example4.click(
lambda: "Thank you so much for all your help and support!",
outputs=text_input
)
example5.click(
lambda: "This is absolutely disgusting and infuriating!",
outputs=text_input
)
example6.click(
lambda: "I love spending time with you!",
outputs=text_input
)
gr.Markdown("""
---
### πŸ“Š About This Model
- **Model**: [Lakssssshya/roberta-large-goemotions](https://huggingface.co/Lakssssshya/roberta-large-goemotions)
- **Architecture**: RoBERTa-Large with optimized thresholds
- **Training**: Focal loss + per-label threshold optimization
- **Emotions**: 28 labels from GoEmotions dataset
Built with ❀️ using Hugging Face Transformers
""")
# ==================== Launch ====================
if __name__ == "__main__":
demo.launch()