import gradio as gr
import torch
import torch.nn as nn
from transformers import AutoTokenizer, AutoModel
import numpy as np
# Configuration
MODEL_NAME = "roberta-base"
MAX_LEN = 200
EMOTIONS = ["anger", "fear", "joy", "sadness", "surprise"]
EMOTION_EMOJIS = ["๐ ", "๐จ", "๐", "๐ข", "๐ฒ"]
EMOTION_COLORS = ["#ef4444", "#f59e0b", "#10b981", "#3b82f6", "#8b5cf6"]
# Model Architecture (MUST MATCH TRAINING)
class RobertaEmotion(nn.Module):
def __init__(self, model_name=MODEL_NAME, dropout=0.35, num_labels=5):
super().__init__()
self.backbone = AutoModel.from_pretrained(model_name)
hidden_size = self.backbone.config.hidden_size
self.dropout = nn.Dropout(dropout)
self.head = nn.Linear(hidden_size, num_labels)
def forward(self, input_ids, attention_mask):
out = self.backbone(input_ids=input_ids, attention_mask=attention_mask)
if hasattr(out, "pooler_output") and out.pooler_output is not None:
pooled = out.pooler_output
else:
pooled = out.last_hidden_state[:, 0]
x = self.dropout(pooled)
logits = self.head(x)
return logits
# Load model and tokenizer
print("๐ Loading EmotiScan model...")
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
print(f"๐ฑ Device: {device}")
try:
tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME)
model = RobertaEmotion(num_labels=len(EMOTIONS))
# Load trained weights
state_dict = torch.load('roberta.pth', map_location=device)
model.load_state_dict(state_dict)
model = model.to(device)
model.eval()
print("โ
EmotiScan ready!")
except Exception as e:
print(f"โ ๏ธ Error loading model: {e}")
raise e
# Optimized thresholds from training
BEST_THRESHOLDS = np.array([0.5, 0.5, 0.5, 0.5, 0.5])
def predict_emotions(text):
"""Predict emotions from text with enhanced visualization"""
if not text or not text.strip():
return """
๐ค
Waiting for your text...
Enter some text above to analyze emotions
"""
try:
# Tokenize
encoding = tokenizer(
text,
truncation=True,
padding="max_length",
max_length=MAX_LEN,
return_tensors="pt"
)
input_ids = encoding["input_ids"].to(device)
attention_mask = encoding["attention_mask"].to(device)
# Predict
with torch.no_grad():
logits = model(input_ids, attention_mask)
probs = torch.sigmoid(logits).cpu().numpy()[0]
# Apply thresholds
predictions = (probs > BEST_THRESHOLDS).astype(int)
# Build beautiful HTML output
html = """
"""
# Detected emotions section
detected = [(emotion, emoji, prob, color) for emotion, emoji, prob, pred, color
in zip(EMOTIONS, EMOTION_EMOJIS, probs, predictions, EMOTION_COLORS) if pred == 1]
if detected:
html += """
๐ฏ Detected Emotions
"""
for emotion, emoji, prob, color in detected:
html += f"""
{emoji}
{emotion}
{prob:.0%}
"""
html += "
"
else:
html += """
๐
No Strong Emotions Detected
All emotions below threshold
"""
# All emotions with progress bars
html += """
๐ Emotion Breakdown
"""
for emotion, emoji, prob, color in zip(EMOTIONS, EMOTION_EMOJIS, probs, EMOTION_COLORS):
html += f"""
{emoji}
{emotion}
{prob:.1%}
"""
html += "
"
return html
except Exception as e:
return f"""
โ ๏ธ
Analysis Error
{str(e)}
"""
# Example texts
examples = [
["I just got promoted at work! I can't believe it!"],
["I'm so worried about the exam tomorrow. What if I fail?"],
["This is absolutely unacceptable! I demand to speak to the manager!"],
["I miss my family so much. It's been months since I've seen them."],
["Wow! I never expected to see you here!"],
["I'm excited but also nervous about starting my new job next week."],
]
# Create Gradio Interface
with gr.Blocks() as demo:
gr.HTML("""
๐ญ
EmotiScan
AI-Powered Multi-Emotion Detection
๐ Anger
๐จ Fear
๐ Joy
๐ข Sadness
๐ฒ Surprise
""")
with gr.Row():
with gr.Column(scale=1):
text_input = gr.Textbox(
label="๐ Your Text",
placeholder="Type or paste your text here to discover the emotions within...",
lines=8,
max_lines=12
)
with gr.Row():
analyze_btn = gr.Button("๐ฎ Analyze Emotions", variant="primary", size="lg")
clear_btn = gr.Button("๐๏ธ Clear", size="lg")
with gr.Column(scale=1):
output = gr.HTML(label="Analysis Results", value="""
๐ญ
Welcome to EmotiScan
Enter text to begin emotional analysis
""")
gr.Examples(
examples=examples,
inputs=text_input,
outputs=output,
fn=predict_emotions,
cache_examples=False,
label="๐ก Try These Examples"
)
gr.HTML("""
๐ง About EmotiScan
EmotiScan uses state-of-the-art deep learning to detect multiple emotions simultaneously in text.
Unlike traditional single-emotion classifiers, our model recognizes that human expression is complex
and nuancedโone piece of text can convey multiple emotions at once.
๐ค
Model
RoBERTa-base (125M params)
๐ฏ
Accuracy
Optimized F1-Score per class
โก
Speed
Real-time inference
๐ Technical Details
- Architecture: Transformer encoder with classification head
- Training: BCE Loss with label smoothing (0.05)
- Max Tokens: 200 tokens per input
- Dropout: 0.35 for regularization
- Multi-Label: Each emotion is independently predicted
Built with PyTorch โข Transformers โข Gradio
2025 Sep DLGenAI Course Project
""")
# Event handlers
analyze_btn.click(fn=predict_emotions, inputs=text_input, outputs=output)
clear_btn.click(
fn=lambda: ("", """
๐ญ
Welcome to EmotiScan
Enter text to begin emotional analysis
"""),
inputs=None,
outputs=[text_input, output]
)
text_input.submit(fn=predict_emotions, inputs=text_input, outputs=output)
if __name__ == "__main__":
demo.launch(share=True, server_name="0.0.0.0")