525GradioApp / visualization /roberta_visualizer.py
Ryan
update
4973fc0
"""
Visualization components for RoBERTa sentiment analysis
"""
import gradio as gr
import pandas as pd
import plotly.express as px
import plotly.graph_objects as go
from plotly.subplots import make_subplots
import numpy as np
import json
def create_sentiment_visualization(analysis_results):
"""
Create visualizations for RoBERTa sentiment analysis results
Args:
analysis_results (dict): Analysis results from the sentiment analysis
Returns:
list: List of gradio components with visualizations
"""
print("Starting create_sentiment_visualization function")
output_components = []
# Check if we have valid results
if not analysis_results or "analyses" not in analysis_results:
print("No analysis results found.")
return [gr.Markdown("No analysis results found.")]
# Add debug print for each step
print(f"Number of prompts: {len(analysis_results['analyses'])}")
# Process each prompt
for prompt, analyses in analysis_results["analyses"].items():
output_components.append(gr.Markdown(f"## Analysis of Prompt: \"{prompt[:100]}{'...' if len(prompt) > 100 else ''}\""))
# Process RoBERTa sentiment analysis if available
if "roberta_sentiment" in analyses:
sentiment_results = analyses["roberta_sentiment"]
# Check if there's an error
if "error" in sentiment_results:
output_components.append(gr.Markdown(f"**Error in sentiment analysis:** {sentiment_results['error']}"))
continue
# Show models being compared
models = sentiment_results.get("models", [])
if len(models) >= 2:
output_components.append(gr.Markdown(f"### RoBERTa Sentiment Analysis: Comparing {models[0]} and {models[1]}"))
# Create text-based summary of sentiment scores
sa_data = sentiment_results.get("sentiment_analysis", {})
if sa_data and len(models) >= 2:
# Extract sentiment scores and labels for comparison
model_data = []
summary_html = "<div style='margin: 20px 0; padding: 15px; background-color: #f8f9fa; border-radius: 5px;'>"
summary_html += "<h4 style='margin-top: 0;'>Sentiment Score Comparison</h4>"
summary_html += "<table style='width: 100%; border-collapse: collapse;'>"
summary_html += "<tr><th style='text-align: left; padding: 8px; border-bottom: 1px solid #ddd;'>Model</th>"
summary_html += "<th style='text-align: center; padding: 8px; border-bottom: 1px solid #ddd;'>Sentiment Score</th>"
summary_html += "<th style='text-align: center; padding: 8px; border-bottom: 1px solid #ddd;'>Label</th></tr>"
for model_name in models:
if model_name in sa_data:
model_result = sa_data.get(model_name)
if model_result is not None:
score = model_result.get("sentiment_score", 0)
label = model_result.get("label", "neutral").capitalize()
else:
score = 0
label = "Neutral"
# Set color based on sentiment
if label.lower() == "positive":
color = "green"
elif label.lower() == "negative":
color = "red"
else:
color = "gray"
summary_html += f"<tr>"
summary_html += f"<td style='padding: 8px; border-bottom: 1px solid #ddd;'>{model_name}</td>"
summary_html += f"<td style='text-align: center; padding: 8px; border-bottom: 1px solid #ddd;'>{score:.2f}</td>"
summary_html += f"<td style='text-align: center; padding: 8px; border-bottom: 1px solid #ddd; color: {color}; font-weight: bold;'>{label}</td>"
summary_html += f"</tr>"
summary_html += "</table></div>"
output_components.append(gr.HTML(summary_html))
# Create HTML-based score comparison gauge
model_scores = []
for model_name in models:
if model_name in sa_data:
model_result = sa_data.get(model_name)
if model_result is not None:
score = model_result.get("sentiment_score", 0)
model_scores.append((model_name, score))
if len(model_scores) >= 2:
gauge_html = "<div style='margin: 20px 0; padding: 15px; background-color: #f8f9fa; border-radius: 5px;'>"
gauge_html += "<h4 style='text-align: center; margin-top: 0;'>Sentiment Scale</h4>"
gauge_html += "<div style='display: flex; justify-content: space-between; margin-bottom: 5px;'>"
gauge_html += "<span>Very Negative (-2.0)</span>"
gauge_html += "<span>Neutral (0.0)</span>"
gauge_html += "<span>Very Positive (2.0)</span>"
gauge_html += "</div>"
# Create the gauge background
gauge_html += "<div style='position: relative; width: 100%; height: 30px; background: linear-gradient(to right, #d73027, #f46d43, #fdae61, #fee08b, #ffffbf, #d9ef8b, #a6d96a, #66bd63, #1a9850); border-radius: 5px;'>"
# Add model markers
for model_name, score in model_scores:
# Calculate position (0-100%)
position = ((score + 2.0) / 4.0) * 100
position = max(0, min(100, position)) # Clamp between 0-100%
# Calculate color
if score > 0.5:
color = "#006400" # Dark green
elif score < -0.5:
color = "#8B0000" # Dark red
else:
color = "#000000" # Black
gauge_html += f"<div style='position: absolute; left: {position}%; transform: translateX(-50%); top: 0;'>"
gauge_html += f"<div style='width: 3px; height: 30px; background-color: {color};'></div>"
gauge_html += f"<div style='position: absolute; top: 100%; left: 50%; transform: translateX(-50%); white-space: nowrap; font-weight: bold; color: {color};'>{model_name}: {score:.2f}</div>"
gauge_html += "</div>"
gauge_html += "</div></div>"
output_components.append(gr.HTML(gauge_html))
# Display comparison summary
if "comparison" in sentiment_results:
comparison = sentiment_results["comparison"]
summary_html = """
<div style="margin: 20px 0; padding: 15px; background-color: #f8f9fa; border-radius: 5px;">
<h4 style="margin-top: 0;">Sentiment Comparison Summary</h4>
"""
# Add difference direction
if "difference_direction" in comparison:
summary_html += f"""
<p style="font-weight: 500; margin-bottom: 10px;">
{comparison["difference_direction"]}
</p>
"""
# Add significance info
if "significant_difference" in comparison:
color = "red" if comparison["significant_difference"] else "green"
significance = "Significant" if comparison["significant_difference"] else "Minor"
summary_html += f"""
<p>
<span style="font-weight: bold; color: {color};">{significance} difference</span> in sentiment
(difference score: {comparison.get("sentiment_difference", 0):.2f})
</p>
"""
summary_html += "</div>"
output_components.append(gr.HTML(summary_html))
# Display sentence-level sentiment analysis for both responses
model_sentences = {}
for model_name in models:
if model_name in sa_data:
model_result = sa_data.get(model_name)
if model_result is not None and "sentence_scores" in model_result:
sentence_scores = model_result.get("sentence_scores")
if sentence_scores:
model_sentences[model_name] = sentence_scores
if model_sentences and any(len(sentences) > 0 for sentences in model_sentences.values()):
output_components.append(gr.Markdown("### Sentence-Level Sentiment Analysis"))
for model_name, sentences in model_sentences.items():
if sentences:
output_components.append(gr.Markdown(f"#### {model_name} Response Breakdown"))
# Create HTML visualization for sentences with sentiment
sentences_html = """
<div style="margin-bottom: 20px;">
"""
for i, sentence in enumerate(sentences):
score = sentence.get("score", 0)
label = sentence.get("label", "neutral")
text = sentence.get("text", "")
# Skip very short sentences or empty text
if len(text.split()) < 3:
continue
# Color based on sentiment
if label == "positive":
color = f"rgba(0, 128, 0, {min(1.0, abs(score) * 0.5)})"
border = "rgba(0, 128, 0, 0.3)"
elif label == "negative":
color = f"rgba(255, 0, 0, {min(1.0, abs(score) * 0.5)})"
border = "rgba(255, 0, 0, 0.3)"
else:
color = "rgba(128, 128, 128, 0.1)"
border = "rgba(128, 128, 128, 0.3)"
sentences_html += f"""
<div style="padding: 10px; margin-bottom: 10px; background-color: {color};
border-radius: 5px; border: 1px solid {border};">
<div style="display: flex; justify-content: space-between;">
<span>{text}</span>
<span style="margin-left: 10px; font-weight: bold;">
{score:.2f} ({label.capitalize()})
</span>
</div>
</div>
"""
sentences_html += "</div>"
output_components.append(gr.HTML(sentences_html))
# If no components were added, show a message
if len(output_components) <= 1:
output_components.append(gr.Markdown("No detailed sentiment analysis found in results."))
return output_components
def process_and_visualize_sentiment_analysis(analysis_results):
"""
Process the sentiment analysis results and create visualization components
Args:
analysis_results (dict): The analysis results
Returns:
list: List of gradio components for visualization
"""
try:
print(f"Starting visualization of sentiment analysis results")
components = create_sentiment_visualization(analysis_results)
return components
except Exception as e:
import traceback
error_msg = f"Sentiment visualization error: {str(e)}\n{traceback.format_exc()}"
print(error_msg)
return [
gr.Markdown(f"**Error during sentiment visualization:**"),
gr.HTML(f"<div style='background-color: #FEE; padding: 10px; border-radius: 5px; border: 1px solid #F88;'>" +
f"<pre style='white-space: pre-wrap; overflow-wrap: break-word;'>{str(e)}</pre></div>")
]