shivanimatariya
commit
95d4d66
import gradio as gr
import json
import pandas as pd
from openai import OpenAI
import os
from dotenv import load_dotenv
from prompts import emotion_detection_prompt, single_emotion_detection_prompt, evaluation_prompt
load_dotenv()
# Initialize the inference client
client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
def detect_emotions(conversation_text):
"""Parse conversation text and detect emotions for each utterance"""
# Parse the conversation text into structured format
utterances = []
lines = conversation_text.strip().split('\n')
for line in lines:
line = line.strip()
if line and ':' in line:
# Try to extract speaker and utterance
parts = line.split(':', 1)
if len(parts) == 2:
speaker = parts[0].strip()
utterance = parts[1].strip()
if utterance:
utterances.append({
"speaker": speaker,
"utterance": utterance
})
if not utterances:
return "No valid conversation found. Please format as 'Speaker: utterance'"
system_prompt = emotion_detection_prompt
user_prompt = (
"Conversation context:\n"
f"{json.dumps(utterances, indent=2)}\n\n"
"Process the conversation turn by turn."
)
messages = [
{"role": "system", "content": system_prompt},
{"role": "user", "content": user_prompt}
]
try:
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=messages,
temperature=0.0,
)
output = response.choices[0].message.content
parsed_output = json.loads(output)
# Format the output for display
formatted_output = []
for item in parsed_output:
formatted_output.append(f"**{item['speaker']}**: \"{item['utterance']}\"")
formatted_output.append(f" - **Emotion**: {item['emotion']}")
formatted_output.append(f" - **Confidence**: {item['confidence']}")
formatted_output.append(f" - **Reason**: {item['reason']}")
formatted_output.append("") # Empty line for spacing
return "\n".join(formatted_output)
except Exception as e:
return f"Error: {str(e)}"
def predict_single_emotion(utterance):
"""Predict Plutchik emotion for a single utterance"""
system_prompt = single_emotion_detection_prompt
user_prompt = f"Utterance: {utterance}\n\nWhat is the Plutchik emotion? Output only the emotion word:"
messages = [
{"role": "system", "content": system_prompt},
{"role": "user", "content": user_prompt}
]
try:
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=messages,
temperature=0.0,
)
output = response.choices[0].message.content.strip().lower()
# Extract just the emotion word
valid_emotions = ["joy", "trust", "fear", "surprise", "sadness", "disgust", "anger", "anticipation", "neutral"]
for emotion in valid_emotions:
if emotion in output:
return emotion
return output.split()[0] if output else "neutral"
except Exception as e:
return f"Error: {str(e)}"
def map_meld_to_plutchik(meld_emotion):
"""Use LLM to map MELD emotion to Plutchik emotion"""
system_prompt = evaluation_prompt
user_prompt = f"MELD emotion: {meld_emotion}\n\nMap to Plutchik emotion (output only the word):"
messages = [
{"role": "system", "content": system_prompt},
{"role": "user", "content": user_prompt}
]
try:
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=messages,
temperature=0.0,
)
output = response.choices[0].message.content.strip().lower()
valid_emotions = ["joy", "trust", "fear", "surprise", "sadness", "disgust", "anger", "anticipation", "neutral"]
for emotion in valid_emotions:
if emotion in output:
return emotion
return output.split()[0] if output else "neutral"
except Exception as e:
return meld_emotion # Fallback to original
def evaluate_meld_dataset(max_samples=100):
"""Evaluate on MELD dataset using LLM for both prediction and mapping"""
try:
df = pd.read_csv("dev_sent_emo.csv")
rows = []
count = 0
for _, row in df.iterrows():
if count >= max_samples:
break
utterance = str(row.get("Utterance", ""))
meld_emotion = str(row.get("Emotion", "")).lower()
speaker = str(row.get("Speaker", ""))
if not utterance or pd.isna(row.get("Emotion")):
continue
# Predict Plutchik emotion using LLM
pred_emotion = predict_single_emotion(utterance)
# Map MELD emotion to Plutchik using LLM
gold_plutchik = map_meld_to_plutchik(meld_emotion)
# Check match
match = "Yes" if pred_emotion == gold_plutchik else "No"
rows.append({
"Utterance": utterance[:100] + "..." if len(utterance) > 100 else utterance,
"Speaker": speaker,
"MELD_Emotion": meld_emotion.capitalize(),
"Gold_Plutchik": gold_plutchik.capitalize(),
"Predicted_Plutchik": pred_emotion.capitalize(),
"Match": match
})
count += 1
return pd.DataFrame(rows)
except Exception as e:
import traceback
return pd.DataFrame({
"Error": [f"Failed to evaluate: {str(e)}\n{traceback.format_exc()}"]
})
# Create the Gradio interface
with gr.Blocks(title="Emotion Detection System", theme=gr.themes.Soft()) as demo:
gr.Markdown("# 🎭 Emotion Detection System")
gr.Markdown("Analyze emotions in conversations using Plutchik's emotion model")
with gr.Tabs():
with gr.Tab("πŸ’¬ Emotion Detection"):
with gr.Row():
with gr.Column(scale=1):
gr.Markdown("## Input Conversation")
conversation_input = gr.Textbox(
label="Enter conversation (format: Speaker: utterance)",
placeholder="Customer: I received a notice saying my premium is increasing\nSalesperson: I'm sorry for the confusion, let me check what caused the change\nCustomer: It feels unfair because I haven't filed any claims",
lines=8,
value="Customer: I received a notice saying my premium is increasing, and no one explained why\nSalesperson: I'm sorry for the confusion, let me check what caused the change\nCustomer: It feels unfair because I haven't filed any claims\nSalesperson: I understand why that would be upsetting, and I want to clarify it for you\nCustomer: I'm concerned this might keep happening every year\nSalesperson: We can review options that offer more predictable pricing\nCustomer: If there's a way to avoid surprises, I'd be willing to consider it\nSalesperson: That makes sense, and I'll help you find a plan that gives you peace of mind"
)
analyze_btn = gr.Button("πŸ” Analyze Emotions", variant="primary", size="lg")
gr.Markdown("### πŸ“ Format Instructions")
gr.Markdown("""
- Each line should be: `Speaker: utterance`
- Multiple speakers supported
- One utterance per line
- Example: `John: I'm really excited about this!`
""")
with gr.Column(scale=1):
gr.Markdown("## Emotion Analysis Results")
output_display = gr.Textbox(
label="Emotion Analysis Results",
lines=20,
interactive=False
)
# Example conversations
gr.Markdown("## πŸ’‘ Example Conversations")
with gr.Row():
example1 = gr.Button("Customer Service Example", size="sm")
example2 = gr.Button("Team Discussion Example", size="sm")
example3 = gr.Button("Personal Conversation Example", size="sm")
# Define example conversations
example_conversations = {
"Customer Service Example": "Customer: I received a notice saying my premium is increasing, and no one explained why\nSalesperson: I'm sorry for the confusion, let me check what caused the change\nCustomer: It feels unfair because I haven't filed any claims\nSalesperson: I understand why that would be upsetting, and I want to clarify it for you",
"Team Discussion Example": "Manager: We need to finish this project by Friday\nTeam Member: I'm not sure we can meet that deadline\nManager: What challenges are you seeing?\nTeam Member: We're still waiting for the design approval\nManager: I'll follow up with the design team right away",
"Personal Conversation Example": "Friend: I got the job offer yesterday!\nYou: That's amazing news! Congratulations!\nFriend: I'm so excited but also a bit nervous\nYou: You'll do great, you were the best candidate"
}
# Event handlers for main tab
analyze_btn.click(
fn=detect_emotions,
inputs=conversation_input,
outputs=output_display
)
def load_example(example_name):
return example_conversations[example_name]
example1.click(fn=lambda: load_example("Customer Service Example"), outputs=conversation_input)
example2.click(fn=lambda: load_example("Team Discussion Example"), outputs=conversation_input)
example3.click(fn=lambda: load_example("Personal Conversation Example"), outputs=conversation_input)
with gr.Tab("πŸ“Š Evaluation (MELD)"):
gr.Markdown("### Evaluate model on MELD dataset")
gr.Markdown("Uses LLM to map MELD emotions to Plutchik emotions and compares with predictions")
gr.Markdown("**MELD Emotions:** anger, disgust, fear, joy, neutral, sadness, surprise")
sample_slider = gr.Slider(
minimum=10,
maximum=200,
value=50,
step=10,
label="Number of Samples"
)
eval_btn = gr.Button("πŸ“Š Run Evaluation", variant="primary", size="lg")
eval_output = gr.Dataframe(
label="Evaluation Results",
wrap=True
)
eval_btn.click(
fn=evaluate_meld_dataset,
inputs=sample_slider,
outputs=eval_output
)
if __name__ == "__main__":
demo.launch(debug=True)