Mukul Rayana commited on
Commit ·
15920d0
1
Parent(s): 632052b
Add conversation memory, fix Gradio stack, improve SYSTEM_PROMPT, log human eval turns
Browse files- demo/app.py +158 -267
- eval/bertscore_results.json +311 -0
- eval/human_eval_log.jsonl +11 -0
demo/app.py
CHANGED
|
@@ -1,30 +1,19 @@
|
|
| 1 |
"""
|
| 2 |
demo/app.py
|
| 3 |
-
EmpathRAG
|
| 4 |
-
|
| 5 |
-
IG ASYNC PATTERN:
|
| 6 |
-
When the guardrail fires (crisis detected), the safe response must appear in <1 second.
|
| 7 |
-
Integrated Gradients (IG) attribution takes ~30-45 seconds on CPU.
|
| 8 |
-
|
| 9 |
-
Implementation:
|
| 10 |
-
1. Monkey-patch pipeline.guardrail.check to force skip_ig=True during pipeline.run()
|
| 11 |
-
2. First yield: safe response + loading placeholder in IG panel
|
| 12 |
-
3. Run real IG check (skip_ig=False) in same generator after yielding
|
| 13 |
-
4. Second yield: same response + populated IG panel with token highlights
|
| 14 |
-
|
| 15 |
-
This uses a generator function with conditional double-yield.
|
| 16 |
-
Gradio 4.21 doesn't have gr.Timer, so we use synchronous IG after first yield.
|
| 17 |
-
The user sees the safe response instantly; IG completes in background of same request.
|
| 18 |
"""
|
| 19 |
|
| 20 |
import sys
|
| 21 |
sys.path.insert(0, "src")
|
| 22 |
|
| 23 |
import gradio as gr
|
|
|
|
|
|
|
|
|
|
|
|
|
| 24 |
from pipeline.pipeline import EmpathRAGPipeline
|
| 25 |
|
| 26 |
-
#
|
| 27 |
-
|
| 28 |
LABEL_NAMES = ["distress", "anxiety", "frustration", "neutral", "hopeful"]
|
| 29 |
LABEL_COLORS = {
|
| 30 |
"distress": "#e74c3c",
|
|
@@ -33,345 +22,247 @@ LABEL_COLORS = {
|
|
| 33 |
"neutral": "#95a5a6",
|
| 34 |
"hopeful": "#27ae60",
|
| 35 |
}
|
|
|
|
| 36 |
|
| 37 |
-
#
|
| 38 |
-
|
| 39 |
print("[Demo] Initialising EmpathRAG pipeline...")
|
| 40 |
pipeline = EmpathRAGPipeline(use_real_guardrail=True, guardrail_threshold=0.5)
|
| 41 |
print("[Demo] Pipeline ready.")
|
| 42 |
|
| 43 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 44 |
|
| 45 |
-
# ── HTML Formatters ───────────────────────────────────────────────────────────
|
| 46 |
|
| 47 |
-
def
|
| 48 |
-
"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 49 |
if not history:
|
| 50 |
return "<div style='color:#888;font-size:13px;padding:8px;'>No emotions detected yet.</div>"
|
| 51 |
|
| 52 |
-
trajectory = pipeline.tracker.trajectory()
|
| 53 |
trajectory_badge_colors = {
|
| 54 |
"stable": "#95a5a6",
|
| 55 |
"stable_positive": "#27ae60",
|
| 56 |
"stable_negative": "#e74c3c",
|
| 57 |
"escalating": "#c0392b",
|
| 58 |
"de_escalating": "#16a085",
|
| 59 |
-
"volatile": "#f39c12"
|
| 60 |
}
|
|
|
|
| 61 |
traj_color = trajectory_badge_colors.get(trajectory, "#95a5a6")
|
|
|
|
|
|
|
| 62 |
|
| 63 |
-
|
| 64 |
-
|
| 65 |
-
|
| 66 |
-
</div>
|
| 67 |
-
|
| 68 |
|
| 69 |
-
|
| 70 |
-
|
| 71 |
-
|
| 72 |
-
<span style='
|
| 73 |
-
display:inline-block;
|
| 74 |
-
background:{entry["color"]};
|
| 75 |
-
color:white;
|
| 76 |
-
font-size:12px;
|
| 77 |
-
padding:4px 10px;
|
| 78 |
-
margin:3px;
|
| 79 |
-
border-radius:12px;
|
| 80 |
-
white-space:nowrap;
|
| 81 |
-
'>T{entry["turn"]}: {entry["label_name"]}</span>
|
| 82 |
-
"""
|
| 83 |
-
pills.append(pill)
|
| 84 |
-
|
| 85 |
-
pills_html = f"<div style='display:flex;flex-wrap:wrap;gap:4px;'>{''.join(pills)}</div>"
|
| 86 |
-
return header + pills_html
|
| 87 |
-
|
| 88 |
-
|
| 89 |
-
def format_ig_panel(is_crisis: bool, confidence: float, ig_tokens: list, loading: bool) -> str:
|
| 90 |
-
"""Returns HTML for the crisis + IG attribution panel."""
|
| 91 |
if not is_crisis:
|
| 92 |
return "<div style='color:#888;font-size:13px;padding:8px;'>No crisis detected this session.</div>"
|
| 93 |
|
| 94 |
if loading:
|
| 95 |
-
#
|
| 96 |
-
return f"""
|
| 97 |
-
<div style='
|
| 98 |
-
background:#fff3cd;
|
| 99 |
-
border-left:4px solid #ffc107;
|
| 100 |
-
padding:12px;
|
| 101 |
-
border-radius:6px;
|
| 102 |
-
margin-bottom:8px;
|
| 103 |
-
'>
|
| 104 |
-
<div style='font-weight:600;color:#856404;margin-bottom:6px;'>
|
| 105 |
-
🚨 Crisis signal detected — confidence: {confidence:.1%}
|
| 106 |
-
</div>
|
| 107 |
-
<div style='font-family:monospace;font-size:12px;color:#856404;'>
|
| 108 |
-
⏳ Computing token attributions...
|
| 109 |
-
</div>
|
| 110 |
-
</div>
|
| 111 |
-
"""
|
| 112 |
-
|
| 113 |
-
# Fully loaded - show confidence bar + token highlights
|
| 114 |
-
conf_pct = int(confidence * 100)
|
| 115 |
-
bar_color = "#e74c3c" if confidence >= 0.7 else "#f39c12"
|
| 116 |
-
|
| 117 |
-
conf_bar = f"""
|
| 118 |
-
<div style='margin-bottom:12px;'>
|
| 119 |
-
<div style='font-size:13px;font-weight:600;color:#333;margin-bottom:4px;'>
|
| 120 |
-
Crisis Confidence: {confidence:.1%}
|
| 121 |
-
</div>
|
| 122 |
-
<div style='background:#eee;border-radius:8px;overflow:hidden;height:20px;'>
|
| 123 |
-
<div style='background:{bar_color};height:100%;width:{conf_pct}%;transition:width 0.3s;'></div>
|
| 124 |
-
</div>
|
| 125 |
-
</div>
|
| 126 |
-
"""
|
| 127 |
-
|
| 128 |
-
if not ig_tokens:
|
| 129 |
-
# IG was skipped or no tokens
|
| 130 |
-
return f"""
|
| 131 |
-
<div style='
|
| 132 |
-
background:#f8d7da;
|
| 133 |
-
border-left:4px solid #e74c3c;
|
| 134 |
-
padding:12px;
|
| 135 |
-
border-radius:6px;
|
| 136 |
-
'>
|
| 137 |
-
{conf_bar}
|
| 138 |
-
<div style='font-size:12px;color:#721c24;'>
|
| 139 |
-
Token attributions unavailable.
|
| 140 |
-
</div>
|
| 141 |
-
</div>
|
| 142 |
-
"""
|
| 143 |
-
|
| 144 |
-
# Build token highlight spans
|
| 145 |
-
# Filter out special tokens and compute max score for normalization
|
| 146 |
-
filtered_tokens = [
|
| 147 |
-
(tok, score) for tok, score in ig_tokens
|
| 148 |
-
if not (tok.startswith("▁") and len(tok.strip("▁")) == 0)
|
| 149 |
-
]
|
| 150 |
-
|
| 151 |
-
if not filtered_tokens:
|
| 152 |
-
token_section = "<div style='font-size:12px;color:#721c24;'>No significant tokens.</div>"
|
| 153 |
-
else:
|
| 154 |
-
max_score = max(score for _, score in filtered_tokens)
|
| 155 |
-
token_spans = []
|
| 156 |
-
for tok, score in filtered_tokens[:10]: # Top 10
|
| 157 |
-
opacity = 0.25 + 0.75 * (score / max_score if max_score > 0 else 0)
|
| 158 |
-
# Clean up token display - remove leading underscore for word pieces
|
| 159 |
-
display_tok = tok.replace("▁", " ").strip()
|
| 160 |
-
if not display_tok:
|
| 161 |
-
continue
|
| 162 |
-
span = f"""
|
| 163 |
-
<span style='
|
| 164 |
-
background:rgba(231,76,60,{opacity:.2f});
|
| 165 |
-
padding:3px 6px;
|
| 166 |
-
margin:2px;
|
| 167 |
-
border-radius:4px;
|
| 168 |
-
font-size:12px;
|
| 169 |
-
font-family:monospace;
|
| 170 |
-
display:inline-block;
|
| 171 |
-
'>{display_tok}</span>
|
| 172 |
-
"""
|
| 173 |
-
token_spans.append(span)
|
| 174 |
-
|
| 175 |
-
token_section = f"""
|
| 176 |
-
<div style='margin-top:8px;'>
|
| 177 |
-
<div style='font-size:12px;font-weight:600;color:#721c24;margin-bottom:6px;'>
|
| 178 |
-
Top Crisis Signals:
|
| 179 |
-
</div>
|
| 180 |
-
<div style='line-height:1.8;'>
|
| 181 |
-
{''.join(token_spans)}
|
| 182 |
-
</div>
|
| 183 |
-
</div>
|
| 184 |
-
"""
|
| 185 |
-
|
| 186 |
-
return f"""
|
| 187 |
-
<div style='
|
| 188 |
-
background:#f8d7da;
|
| 189 |
-
border-left:4px solid #e74c3c;
|
| 190 |
-
padding:12px;
|
| 191 |
-
border-radius:6px;
|
| 192 |
-
'>
|
| 193 |
-
{conf_bar}
|
| 194 |
-
{token_section}
|
| 195 |
-
</div>
|
| 196 |
-
"""
|
| 197 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 198 |
|
| 199 |
-
# ── Core Logic ────────────────────────────────────────────────────────────────
|
| 200 |
|
| 201 |
def respond(message, chat_history):
|
| 202 |
"""
|
| 203 |
-
Generator function
|
| 204 |
-
|
| 205 |
-
Normal flow: single yield with all outputs.
|
| 206 |
-
Crisis flow:
|
| 207 |
-
- yield 1: instant safe response + IG loading panel
|
| 208 |
-
- yield 2: same response + populated IG panel (after IG completes)
|
| 209 |
"""
|
|
|
|
|
|
|
| 210 |
# Validate input
|
| 211 |
-
if not message
|
| 212 |
-
yield (
|
| 213 |
-
|
| 214 |
-
|
| 215 |
-
|
| 216 |
-
|
| 217 |
-
)
|
| 218 |
return
|
| 219 |
|
| 220 |
-
#
|
| 221 |
original_check = pipeline.guardrail.check
|
| 222 |
def fast_check(text, threshold=0.5, skip_ig=False):
|
| 223 |
return original_check(text, threshold=threshold, skip_ig=True)
|
| 224 |
pipeline.guardrail.check = fast_check
|
| 225 |
|
| 226 |
-
# Run pipeline with fast guardrail check
|
| 227 |
result = pipeline.run(message)
|
| 228 |
|
| 229 |
-
# Restore original guardrail
|
| 230 |
pipeline.guardrail.check = original_check
|
| 231 |
|
| 232 |
# Update chat history
|
| 233 |
chat_history.append((message, result["response"]))
|
| 234 |
|
| 235 |
-
# Update emotion
|
| 236 |
-
turn = len(emotion_history) + 1
|
| 237 |
emotion_history.append({
|
| 238 |
-
"turn":
|
| 239 |
"label_name": result["emotion_name"],
|
| 240 |
-
"color": LABEL_COLORS[result["emotion_name"]]
|
| 241 |
})
|
| 242 |
|
| 243 |
-
|
| 244 |
-
|
|
|
|
|
|
|
|
|
|
| 245 |
|
| 246 |
-
# Handle crisis vs non-crisis
|
| 247 |
if result["crisis"]:
|
| 248 |
-
#
|
| 249 |
-
|
| 250 |
-
|
| 251 |
-
|
| 252 |
-
|
| 253 |
-
|
| 254 |
-
|
| 255 |
-
|
| 256 |
-
|
| 257 |
-
|
| 258 |
-
|
| 259 |
-
|
| 260 |
-
|
| 261 |
-
|
| 262 |
-
|
| 263 |
-
|
| 264 |
-
_, confidence, ig_tokens = pipeline.guardrail.check(
|
| 265 |
-
message,
|
| 266 |
-
threshold=0.5,
|
| 267 |
-
skip_ig=False,
|
| 268 |
-
)
|
| 269 |
-
|
| 270 |
-
# SECOND YIELD: Same response, populated IG panel
|
| 271 |
-
crisis_panel_final = format_ig_panel(
|
| 272 |
-
True,
|
| 273 |
-
confidence,
|
| 274 |
-
ig_tokens,
|
| 275 |
-
loading=False,
|
| 276 |
-
)
|
| 277 |
-
yield (
|
| 278 |
-
chat_history,
|
| 279 |
-
timeline_html,
|
| 280 |
-
trajectory_text,
|
| 281 |
-
crisis_panel_final,
|
| 282 |
-
)
|
| 283 |
else:
|
| 284 |
-
#
|
| 285 |
-
|
| 286 |
-
|
| 287 |
-
|
| 288 |
-
|
| 289 |
-
|
| 290 |
-
|
| 291 |
-
|
| 292 |
-
|
| 293 |
-
|
| 294 |
-
|
| 295 |
-
|
| 296 |
-
global emotion_history
|
| 297 |
emotion_history = []
|
| 298 |
pipeline.reset_session()
|
|
|
|
| 299 |
|
| 300 |
-
|
| 301 |
-
|
| 302 |
-
"<div style='color:#888;font-size:13px;padding:8px;'>No emotions detected yet.</div>", # timeline
|
| 303 |
-
"stable", # trajectory
|
| 304 |
-
"<div style='color:#888;font-size:13px;padding:8px;'>No crisis detected this session.</div>", # crisis panel
|
| 305 |
-
)
|
| 306 |
|
|
|
|
| 307 |
|
| 308 |
-
# ── Gradio Interface ──────────────────────────────────────────────────────────
|
| 309 |
|
|
|
|
| 310 |
with gr.Blocks(theme=gr.themes.Soft(), title="EmpathRAG Demo") as demo:
|
| 311 |
-
gr.Markdown("
|
| 312 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 313 |
|
| 314 |
with gr.Row():
|
| 315 |
-
# Left column
|
| 316 |
with gr.Column(scale=2):
|
| 317 |
-
chatbot = gr.Chatbot(
|
| 318 |
-
label="Conversation",
|
| 319 |
-
height=450,
|
| 320 |
-
bubble_full_width=False,
|
| 321 |
-
)
|
| 322 |
msg_box = gr.Textbox(
|
| 323 |
placeholder="How are you feeling today?",
|
| 324 |
label="",
|
| 325 |
-
autofocus=True
|
| 326 |
)
|
| 327 |
with gr.Row():
|
| 328 |
send_btn = gr.Button("Send", variant="primary")
|
| 329 |
reset_btn = gr.Button("Reset Session")
|
| 330 |
|
| 331 |
-
# Right column
|
| 332 |
with gr.Column(scale=1):
|
| 333 |
-
gr.Markdown("##
|
| 334 |
-
|
| 335 |
-
gr.
|
| 336 |
-
timeline_out = gr.HTML(
|
| 337 |
-
value="<div style='color:#888;font-size:13px;padding:8px;'>No emotions detected yet.</div>"
|
| 338 |
-
)
|
| 339 |
-
|
| 340 |
-
trajectory_out = gr.Textbox(
|
| 341 |
-
label="Trajectory",
|
| 342 |
-
value="stable",
|
| 343 |
-
interactive=False,
|
| 344 |
-
)
|
| 345 |
|
| 346 |
-
gr.Markdown("###
|
| 347 |
-
crisis_out = gr.HTML(
|
| 348 |
-
value="<div style='color:#888;font-size:13px;padding:8px;'>No crisis detected this session.</div>"
|
| 349 |
-
)
|
| 350 |
|
| 351 |
-
# Wire up
|
| 352 |
msg_box.submit(
|
| 353 |
respond,
|
| 354 |
inputs=[msg_box, chatbot],
|
| 355 |
-
outputs=[chatbot, timeline_out, trajectory_out, crisis_out
|
| 356 |
).then(
|
| 357 |
lambda: "",
|
| 358 |
-
outputs=msg_box
|
| 359 |
)
|
| 360 |
|
| 361 |
send_btn.click(
|
| 362 |
respond,
|
| 363 |
inputs=[msg_box, chatbot],
|
| 364 |
-
outputs=[chatbot, timeline_out, trajectory_out, crisis_out
|
| 365 |
).then(
|
| 366 |
lambda: "",
|
| 367 |
-
outputs=msg_box
|
| 368 |
)
|
| 369 |
|
| 370 |
reset_btn.click(
|
| 371 |
-
|
| 372 |
-
outputs=[chatbot, timeline_out, trajectory_out, crisis_out
|
| 373 |
)
|
| 374 |
|
| 375 |
|
| 376 |
if __name__ == "__main__":
|
| 377 |
-
|
|
|
|
|
|
| 1 |
"""
|
| 2 |
demo/app.py
|
| 3 |
+
Gradio interface for EmpathRAG - Empathetic Student Support System
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4 |
"""
|
| 5 |
|
| 6 |
import sys
|
| 7 |
sys.path.insert(0, "src")
|
| 8 |
|
| 9 |
import gradio as gr
|
| 10 |
+
import json
|
| 11 |
+
import uuid
|
| 12 |
+
import datetime
|
| 13 |
+
import os
|
| 14 |
from pipeline.pipeline import EmpathRAGPipeline
|
| 15 |
|
| 16 |
+
# Constants
|
|
|
|
| 17 |
LABEL_NAMES = ["distress", "anxiety", "frustration", "neutral", "hopeful"]
|
| 18 |
LABEL_COLORS = {
|
| 19 |
"distress": "#e74c3c",
|
|
|
|
| 22 |
"neutral": "#95a5a6",
|
| 23 |
"hopeful": "#27ae60",
|
| 24 |
}
|
| 25 |
+
LOG_PATH = "eval/human_eval_log.jsonl"
|
| 26 |
|
| 27 |
+
# Initialize pipeline (runs once at module load)
|
|
|
|
| 28 |
print("[Demo] Initialising EmpathRAG pipeline...")
|
| 29 |
pipeline = EmpathRAGPipeline(use_real_guardrail=True, guardrail_threshold=0.5)
|
| 30 |
print("[Demo] Pipeline ready.")
|
| 31 |
|
| 32 |
+
# Module-level state (not using gr.State)
|
| 33 |
+
emotion_history = []
|
| 34 |
+
session_id = ""
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
def new_session_id() -> str:
|
| 38 |
+
"""Generate 6-character alphanumeric session ID"""
|
| 39 |
+
return uuid.uuid4().hex[:6].upper()
|
| 40 |
+
|
| 41 |
+
|
| 42 |
+
# Initialize session ID
|
| 43 |
+
session_id = new_session_id()
|
| 44 |
|
|
|
|
| 45 |
|
| 46 |
+
def log_turn(session_id, turn, user_message, result):
|
| 47 |
+
"""Append turn to human evaluation log (JSONL format)"""
|
| 48 |
+
try:
|
| 49 |
+
log_entry = {
|
| 50 |
+
"session_id": session_id,
|
| 51 |
+
"turn": turn,
|
| 52 |
+
"timestamp": datetime.datetime.utcnow().isoformat(),
|
| 53 |
+
"user_message": user_message,
|
| 54 |
+
"response": result["response"],
|
| 55 |
+
"emotion_label": result["emotion"],
|
| 56 |
+
"emotion_name": result["emotion_name"],
|
| 57 |
+
"trajectory": result["trajectory"],
|
| 58 |
+
"crisis_fired": result["crisis"],
|
| 59 |
+
"crisis_confidence": result["crisis_confidence"]
|
| 60 |
+
}
|
| 61 |
+
with open(LOG_PATH, "a", encoding="utf-8") as f:
|
| 62 |
+
f.write(json.dumps(log_entry) + "\n")
|
| 63 |
+
except Exception as e:
|
| 64 |
+
print(f"[Warning] Failed to log turn: {e}")
|
| 65 |
+
|
| 66 |
+
|
| 67 |
+
def format_emotion_timeline(history, trajectory) -> str:
|
| 68 |
+
"""Format emotion timeline as HTML"""
|
| 69 |
if not history:
|
| 70 |
return "<div style='color:#888;font-size:13px;padding:8px;'>No emotions detected yet.</div>"
|
| 71 |
|
|
|
|
| 72 |
trajectory_badge_colors = {
|
| 73 |
"stable": "#95a5a6",
|
| 74 |
"stable_positive": "#27ae60",
|
| 75 |
"stable_negative": "#e74c3c",
|
| 76 |
"escalating": "#c0392b",
|
| 77 |
"de_escalating": "#16a085",
|
| 78 |
+
"volatile": "#f39c12"
|
| 79 |
}
|
| 80 |
+
|
| 81 |
traj_color = trajectory_badge_colors.get(trajectory, "#95a5a6")
|
| 82 |
+
html = f"<div style='margin-bottom:10px;padding:6px 10px;background:{traj_color};color:white;border-radius:4px;font-size:12px;font-weight:600;'>Session: {trajectory}</div>"
|
| 83 |
+
html += "<div style='display:flex;flex-wrap:wrap;gap:6px;'>"
|
| 84 |
|
| 85 |
+
for item in history:
|
| 86 |
+
html += f"<span style='padding:4px 8px;background:{item['color']};color:white;border-radius:3px;font-size:11px;'>T{item['turn']}: {item['label_name']}</span>"
|
| 87 |
+
|
| 88 |
+
html += "</div>"
|
| 89 |
+
return html
|
| 90 |
|
| 91 |
+
|
| 92 |
+
def format_ig_panel(is_crisis, confidence, ig_tokens, loading) -> str:
|
| 93 |
+
"""Format Integrated Gradients crisis panel as HTML"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 94 |
if not is_crisis:
|
| 95 |
return "<div style='color:#888;font-size:13px;padding:8px;'>No crisis detected this session.</div>"
|
| 96 |
|
| 97 |
if loading:
|
| 98 |
+
return f"<div style='background:#fff3cd;border:1px solid #ffc107;padding:10px;border-radius:4px;'><div style='font-weight:600;color:#856404;margin-bottom:4px;'>Crisis signal detected - confidence: {confidence:.1%}</div><div style='color:#856404;font-size:12px;'>Computing token attributions...</div></div>"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 99 |
|
| 100 |
+
# Not loading, show full IG panel
|
| 101 |
+
conf_pct = int(confidence * 100)
|
| 102 |
+
html = f"<div style='background:#f8d7da;border:1px solid #e74c3c;padding:10px;border-radius:4px;'>"
|
| 103 |
+
html += f"<div style='font-weight:600;color:#721c24;margin-bottom:8px;'>Crisis Confidence: {confidence:.1%}</div>"
|
| 104 |
+
html += f"<div style='background:#fff;height:8px;border-radius:4px;overflow:hidden;margin-bottom:10px;'><div style='background:#e74c3c;height:100%;width:{conf_pct}%;'></div></div>"
|
| 105 |
+
|
| 106 |
+
if ig_tokens:
|
| 107 |
+
# Filter out empty/whitespace tokens
|
| 108 |
+
valid_tokens = [(tok, score) for tok, score in ig_tokens if tok.strip()]
|
| 109 |
+
if valid_tokens:
|
| 110 |
+
max_score = max(score for _, score in valid_tokens)
|
| 111 |
+
html += "<div style='font-size:11px;color:#721c24;margin-bottom:4px;font-weight:600;'>Top Crisis Signals:</div>"
|
| 112 |
+
html += "<div style='display:flex;flex-wrap:wrap;gap:4px;'>"
|
| 113 |
+
for tok, score in valid_tokens[:10]:
|
| 114 |
+
opacity = score / max_score if max_score > 0 else 0.5
|
| 115 |
+
bg_color = f"rgba(231,76,60,{opacity:.2f})"
|
| 116 |
+
html += f"<span style='padding:2px 6px;background:{bg_color};border:1px solid #e74c3c;border-radius:3px;font-size:10px;'>{tok}</span>"
|
| 117 |
+
html += "</div>"
|
| 118 |
+
|
| 119 |
+
html += "</div>"
|
| 120 |
+
return html
|
| 121 |
|
|
|
|
| 122 |
|
| 123 |
def respond(message, chat_history):
|
| 124 |
"""
|
| 125 |
+
Generator function - yields UI state after each update.
|
| 126 |
+
Yields tuple of 5 values: (chatbot, timeline_html, trajectory, crisis_html, session_id)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 127 |
"""
|
| 128 |
+
global emotion_history, session_id
|
| 129 |
+
|
| 130 |
# Validate input
|
| 131 |
+
if not message.strip():
|
| 132 |
+
yield (chat_history,
|
| 133 |
+
format_emotion_timeline(emotion_history, pipeline.tracker.trajectory()),
|
| 134 |
+
pipeline.tracker.trajectory(),
|
| 135 |
+
format_ig_panel(False, 0.0, [], False),
|
| 136 |
+
session_id)
|
|
|
|
| 137 |
return
|
| 138 |
|
| 139 |
+
# Fast first pass - skip IG computation
|
| 140 |
original_check = pipeline.guardrail.check
|
| 141 |
def fast_check(text, threshold=0.5, skip_ig=False):
|
| 142 |
return original_check(text, threshold=threshold, skip_ig=True)
|
| 143 |
pipeline.guardrail.check = fast_check
|
| 144 |
|
|
|
|
| 145 |
result = pipeline.run(message)
|
| 146 |
|
| 147 |
+
# Restore original guardrail check immediately
|
| 148 |
pipeline.guardrail.check = original_check
|
| 149 |
|
| 150 |
# Update chat history
|
| 151 |
chat_history.append((message, result["response"]))
|
| 152 |
|
| 153 |
+
# Update emotion history
|
|
|
|
| 154 |
emotion_history.append({
|
| 155 |
+
"turn": len(emotion_history) + 1,
|
| 156 |
"label_name": result["emotion_name"],
|
| 157 |
+
"color": LABEL_COLORS[result["emotion_name"]]
|
| 158 |
})
|
| 159 |
|
| 160 |
+
# Log turn
|
| 161 |
+
log_turn(session_id, len(emotion_history), message, result)
|
| 162 |
+
|
| 163 |
+
# Format timeline
|
| 164 |
+
timeline_html = format_emotion_timeline(emotion_history, result["trajectory"])
|
| 165 |
|
|
|
|
| 166 |
if result["crisis"]:
|
| 167 |
+
# First yield: show loading state
|
| 168 |
+
yield (chat_history,
|
| 169 |
+
timeline_html,
|
| 170 |
+
result["trajectory"],
|
| 171 |
+
format_ig_panel(True, result["crisis_confidence"], [], loading=True),
|
| 172 |
+
session_id)
|
| 173 |
+
|
| 174 |
+
# Compute real IG
|
| 175 |
+
_, confidence, ig_tokens = pipeline.guardrail.check(message, threshold=0.5, skip_ig=False)
|
| 176 |
+
|
| 177 |
+
# Second yield: show full IG panel
|
| 178 |
+
yield (chat_history,
|
| 179 |
+
timeline_html,
|
| 180 |
+
result["trajectory"],
|
| 181 |
+
format_ig_panel(True, confidence, ig_tokens, loading=False),
|
| 182 |
+
session_id)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 183 |
else:
|
| 184 |
+
# Single yield for non-crisis
|
| 185 |
+
yield (chat_history,
|
| 186 |
+
timeline_html,
|
| 187 |
+
result["trajectory"],
|
| 188 |
+
format_ig_panel(False, 0.0, [], False),
|
| 189 |
+
session_id)
|
| 190 |
+
|
| 191 |
+
|
| 192 |
+
def reset_session_handler():
|
| 193 |
+
"""Reset session - returns 5 values matching respond() outputs"""
|
| 194 |
+
global emotion_history, session_id
|
| 195 |
+
|
|
|
|
| 196 |
emotion_history = []
|
| 197 |
pipeline.reset_session()
|
| 198 |
+
session_id = new_session_id()
|
| 199 |
|
| 200 |
+
placeholder_timeline = "<div style='color:#888;font-size:13px;padding:8px;'>No emotions detected yet.</div>"
|
| 201 |
+
placeholder_crisis = "<div style='color:#888;font-size:13px;padding:8px;'>No crisis detected this session.</div>"
|
|
|
|
|
|
|
|
|
|
|
|
|
| 202 |
|
| 203 |
+
return ([], placeholder_timeline, "stable", placeholder_crisis, session_id)
|
| 204 |
|
|
|
|
| 205 |
|
| 206 |
+
# Gradio UI
|
| 207 |
with gr.Blocks(theme=gr.themes.Soft(), title="EmpathRAG Demo") as demo:
|
| 208 |
+
gr.Markdown("""
|
| 209 |
+
# EmpathRAG - Empathetic Student Support
|
| 210 |
+
Emotion-aware conversational support system for graduate students
|
| 211 |
+
""")
|
| 212 |
+
|
| 213 |
+
session_id_box = gr.Textbox(
|
| 214 |
+
label="Session ID (use this in the feedback form)",
|
| 215 |
+
interactive=False,
|
| 216 |
+
value=session_id
|
| 217 |
+
)
|
| 218 |
|
| 219 |
with gr.Row():
|
| 220 |
+
# Left column - chat interface
|
| 221 |
with gr.Column(scale=2):
|
| 222 |
+
chatbot = gr.Chatbot(label="Conversation", height=420, bubble_full_width=False)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 223 |
msg_box = gr.Textbox(
|
| 224 |
placeholder="How are you feeling today?",
|
| 225 |
label="",
|
| 226 |
+
autofocus=True
|
| 227 |
)
|
| 228 |
with gr.Row():
|
| 229 |
send_btn = gr.Button("Send", variant="primary")
|
| 230 |
reset_btn = gr.Button("Reset Session")
|
| 231 |
|
| 232 |
+
# Right column - emotion tracking and crisis panel
|
| 233 |
with gr.Column(scale=1):
|
| 234 |
+
gr.Markdown("### Emotion Timeline")
|
| 235 |
+
timeline_out = gr.HTML(value="<div style='color:#888;font-size:13px;padding:8px;'>No emotions detected yet.</div>")
|
| 236 |
+
trajectory_out = gr.Textbox(label="Trajectory", value="stable", interactive=False)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 237 |
|
| 238 |
+
gr.Markdown("### Safety Guardrail")
|
| 239 |
+
crisis_out = gr.HTML(value="<div style='color:#888;font-size:13px;padding:8px;'>No crisis detected this session.</div>")
|
|
|
|
|
|
|
| 240 |
|
| 241 |
+
# Wire up interactions
|
| 242 |
msg_box.submit(
|
| 243 |
respond,
|
| 244 |
inputs=[msg_box, chatbot],
|
| 245 |
+
outputs=[chatbot, timeline_out, trajectory_out, crisis_out, session_id_box]
|
| 246 |
).then(
|
| 247 |
lambda: "",
|
| 248 |
+
outputs=msg_box
|
| 249 |
)
|
| 250 |
|
| 251 |
send_btn.click(
|
| 252 |
respond,
|
| 253 |
inputs=[msg_box, chatbot],
|
| 254 |
+
outputs=[chatbot, timeline_out, trajectory_out, crisis_out, session_id_box]
|
| 255 |
).then(
|
| 256 |
lambda: "",
|
| 257 |
+
outputs=msg_box
|
| 258 |
)
|
| 259 |
|
| 260 |
reset_btn.click(
|
| 261 |
+
reset_session_handler,
|
| 262 |
+
outputs=[chatbot, timeline_out, trajectory_out, crisis_out, session_id_box]
|
| 263 |
)
|
| 264 |
|
| 265 |
|
| 266 |
if __name__ == "__main__":
|
| 267 |
+
os.makedirs("eval", exist_ok=True)
|
| 268 |
+
demo.launch(share=True)
|
eval/bertscore_results.json
ADDED
|
@@ -0,0 +1,311 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"mean_precision": 0.8074,
|
| 3 |
+
"mean_recall": 0.8469,
|
| 4 |
+
"mean_f1": 0.8266,
|
| 5 |
+
"target": 0.72,
|
| 6 |
+
"pass": true,
|
| 7 |
+
"n_evaluated": 50,
|
| 8 |
+
"n_skipped": 0,
|
| 9 |
+
"per_prompt": [
|
| 10 |
+
{
|
| 11 |
+
"prompt_id": "d01",
|
| 12 |
+
"f1": 0.8284,
|
| 13 |
+
"precision": 0.8111,
|
| 14 |
+
"recall": 0.8465
|
| 15 |
+
},
|
| 16 |
+
{
|
| 17 |
+
"prompt_id": "d02",
|
| 18 |
+
"f1": 0.8305,
|
| 19 |
+
"precision": 0.8167,
|
| 20 |
+
"recall": 0.8447
|
| 21 |
+
},
|
| 22 |
+
{
|
| 23 |
+
"prompt_id": "d03",
|
| 24 |
+
"f1": 0.8158,
|
| 25 |
+
"precision": 0.8077,
|
| 26 |
+
"recall": 0.8241
|
| 27 |
+
},
|
| 28 |
+
{
|
| 29 |
+
"prompt_id": "d04",
|
| 30 |
+
"f1": 0.8302,
|
| 31 |
+
"precision": 0.8085,
|
| 32 |
+
"recall": 0.8531
|
| 33 |
+
},
|
| 34 |
+
{
|
| 35 |
+
"prompt_id": "d05",
|
| 36 |
+
"f1": 0.8302,
|
| 37 |
+
"precision": 0.8104,
|
| 38 |
+
"recall": 0.851
|
| 39 |
+
},
|
| 40 |
+
{
|
| 41 |
+
"prompt_id": "d06",
|
| 42 |
+
"f1": 0.8468,
|
| 43 |
+
"precision": 0.8238,
|
| 44 |
+
"recall": 0.8711
|
| 45 |
+
},
|
| 46 |
+
{
|
| 47 |
+
"prompt_id": "d07",
|
| 48 |
+
"f1": 0.8198,
|
| 49 |
+
"precision": 0.805,
|
| 50 |
+
"recall": 0.8351
|
| 51 |
+
},
|
| 52 |
+
{
|
| 53 |
+
"prompt_id": "d08",
|
| 54 |
+
"f1": 0.8247,
|
| 55 |
+
"precision": 0.8091,
|
| 56 |
+
"recall": 0.8408
|
| 57 |
+
},
|
| 58 |
+
{
|
| 59 |
+
"prompt_id": "d09",
|
| 60 |
+
"f1": 0.8389,
|
| 61 |
+
"precision": 0.8113,
|
| 62 |
+
"recall": 0.8684
|
| 63 |
+
},
|
| 64 |
+
{
|
| 65 |
+
"prompt_id": "d10",
|
| 66 |
+
"f1": 0.8184,
|
| 67 |
+
"precision": 0.8081,
|
| 68 |
+
"recall": 0.829
|
| 69 |
+
},
|
| 70 |
+
{
|
| 71 |
+
"prompt_id": "a01",
|
| 72 |
+
"f1": 0.8105,
|
| 73 |
+
"precision": 0.8055,
|
| 74 |
+
"recall": 0.8156
|
| 75 |
+
},
|
| 76 |
+
{
|
| 77 |
+
"prompt_id": "a02",
|
| 78 |
+
"f1": 0.813,
|
| 79 |
+
"precision": 0.8102,
|
| 80 |
+
"recall": 0.8158
|
| 81 |
+
},
|
| 82 |
+
{
|
| 83 |
+
"prompt_id": "a03",
|
| 84 |
+
"f1": 0.8343,
|
| 85 |
+
"precision": 0.8141,
|
| 86 |
+
"recall": 0.8555
|
| 87 |
+
},
|
| 88 |
+
{
|
| 89 |
+
"prompt_id": "a04",
|
| 90 |
+
"f1": 0.8291,
|
| 91 |
+
"precision": 0.8113,
|
| 92 |
+
"recall": 0.8476
|
| 93 |
+
},
|
| 94 |
+
{
|
| 95 |
+
"prompt_id": "a05",
|
| 96 |
+
"f1": 0.8219,
|
| 97 |
+
"precision": 0.8127,
|
| 98 |
+
"recall": 0.8313
|
| 99 |
+
},
|
| 100 |
+
{
|
| 101 |
+
"prompt_id": "a06",
|
| 102 |
+
"f1": 0.8298,
|
| 103 |
+
"precision": 0.8211,
|
| 104 |
+
"recall": 0.8387
|
| 105 |
+
},
|
| 106 |
+
{
|
| 107 |
+
"prompt_id": "a07",
|
| 108 |
+
"f1": 0.847,
|
| 109 |
+
"precision": 0.8211,
|
| 110 |
+
"recall": 0.8746
|
| 111 |
+
},
|
| 112 |
+
{
|
| 113 |
+
"prompt_id": "a08",
|
| 114 |
+
"f1": 0.8055,
|
| 115 |
+
"precision": 0.783,
|
| 116 |
+
"recall": 0.8293
|
| 117 |
+
},
|
| 118 |
+
{
|
| 119 |
+
"prompt_id": "a09",
|
| 120 |
+
"f1": 0.8382,
|
| 121 |
+
"precision": 0.8194,
|
| 122 |
+
"recall": 0.8579
|
| 123 |
+
},
|
| 124 |
+
{
|
| 125 |
+
"prompt_id": "a10",
|
| 126 |
+
"f1": 0.8382,
|
| 127 |
+
"precision": 0.8194,
|
| 128 |
+
"recall": 0.8579
|
| 129 |
+
},
|
| 130 |
+
{
|
| 131 |
+
"prompt_id": "f01",
|
| 132 |
+
"f1": 0.82,
|
| 133 |
+
"precision": 0.8009,
|
| 134 |
+
"recall": 0.8401
|
| 135 |
+
},
|
| 136 |
+
{
|
| 137 |
+
"prompt_id": "f02",
|
| 138 |
+
"f1": 0.825,
|
| 139 |
+
"precision": 0.8142,
|
| 140 |
+
"recall": 0.836
|
| 141 |
+
},
|
| 142 |
+
{
|
| 143 |
+
"prompt_id": "f03",
|
| 144 |
+
"f1": 0.8332,
|
| 145 |
+
"precision": 0.8084,
|
| 146 |
+
"recall": 0.8595
|
| 147 |
+
},
|
| 148 |
+
{
|
| 149 |
+
"prompt_id": "f04",
|
| 150 |
+
"f1": 0.813,
|
| 151 |
+
"precision": 0.8102,
|
| 152 |
+
"recall": 0.8158
|
| 153 |
+
},
|
| 154 |
+
{
|
| 155 |
+
"prompt_id": "f05",
|
| 156 |
+
"f1": 0.819,
|
| 157 |
+
"precision": 0.7934,
|
| 158 |
+
"recall": 0.8462
|
| 159 |
+
},
|
| 160 |
+
{
|
| 161 |
+
"prompt_id": "f06",
|
| 162 |
+
"f1": 0.8167,
|
| 163 |
+
"precision": 0.7949,
|
| 164 |
+
"recall": 0.8397
|
| 165 |
+
},
|
| 166 |
+
{
|
| 167 |
+
"prompt_id": "f07",
|
| 168 |
+
"f1": 0.8316,
|
| 169 |
+
"precision": 0.8077,
|
| 170 |
+
"recall": 0.8569
|
| 171 |
+
},
|
| 172 |
+
{
|
| 173 |
+
"prompt_id": "f08",
|
| 174 |
+
"f1": 0.8144,
|
| 175 |
+
"precision": 0.7878,
|
| 176 |
+
"recall": 0.8428
|
| 177 |
+
},
|
| 178 |
+
{
|
| 179 |
+
"prompt_id": "f09",
|
| 180 |
+
"f1": 0.8276,
|
| 181 |
+
"precision": 0.8194,
|
| 182 |
+
"recall": 0.836
|
| 183 |
+
},
|
| 184 |
+
{
|
| 185 |
+
"prompt_id": "f10",
|
| 186 |
+
"f1": 0.8198,
|
| 187 |
+
"precision": 0.8101,
|
| 188 |
+
"recall": 0.8297
|
| 189 |
+
},
|
| 190 |
+
{
|
| 191 |
+
"prompt_id": "n01",
|
| 192 |
+
"f1": 0.8341,
|
| 193 |
+
"precision": 0.7951,
|
| 194 |
+
"recall": 0.8771
|
| 195 |
+
},
|
| 196 |
+
{
|
| 197 |
+
"prompt_id": "n02",
|
| 198 |
+
"f1": 0.8038,
|
| 199 |
+
"precision": 0.777,
|
| 200 |
+
"recall": 0.8325
|
| 201 |
+
},
|
| 202 |
+
{
|
| 203 |
+
"prompt_id": "n03",
|
| 204 |
+
"f1": 0.8074,
|
| 205 |
+
"precision": 0.788,
|
| 206 |
+
"recall": 0.8279
|
| 207 |
+
},
|
| 208 |
+
{
|
| 209 |
+
"prompt_id": "n04",
|
| 210 |
+
"f1": 0.8328,
|
| 211 |
+
"precision": 0.795,
|
| 212 |
+
"recall": 0.8744
|
| 213 |
+
},
|
| 214 |
+
{
|
| 215 |
+
"prompt_id": "n05",
|
| 216 |
+
"f1": 0.7861,
|
| 217 |
+
"precision": 0.768,
|
| 218 |
+
"recall": 0.8051
|
| 219 |
+
},
|
| 220 |
+
{
|
| 221 |
+
"prompt_id": "n06",
|
| 222 |
+
"f1": 0.8336,
|
| 223 |
+
"precision": 0.8076,
|
| 224 |
+
"recall": 0.8614
|
| 225 |
+
},
|
| 226 |
+
{
|
| 227 |
+
"prompt_id": "n07",
|
| 228 |
+
"f1": 0.8071,
|
| 229 |
+
"precision": 0.7869,
|
| 230 |
+
"recall": 0.8285
|
| 231 |
+
},
|
| 232 |
+
{
|
| 233 |
+
"prompt_id": "n08",
|
| 234 |
+
"f1": 0.8011,
|
| 235 |
+
"precision": 0.7939,
|
| 236 |
+
"recall": 0.8085
|
| 237 |
+
},
|
| 238 |
+
{
|
| 239 |
+
"prompt_id": "n09",
|
| 240 |
+
"f1": 0.8321,
|
| 241 |
+
"precision": 0.8052,
|
| 242 |
+
"recall": 0.8609
|
| 243 |
+
},
|
| 244 |
+
{
|
| 245 |
+
"prompt_id": "n10",
|
| 246 |
+
"f1": 0.8337,
|
| 247 |
+
"precision": 0.8108,
|
| 248 |
+
"recall": 0.8578
|
| 249 |
+
},
|
| 250 |
+
{
|
| 251 |
+
"prompt_id": "h01",
|
| 252 |
+
"f1": 0.8436,
|
| 253 |
+
"precision": 0.8268,
|
| 254 |
+
"recall": 0.8612
|
| 255 |
+
},
|
| 256 |
+
{
|
| 257 |
+
"prompt_id": "h02",
|
| 258 |
+
"f1": 0.8419,
|
| 259 |
+
"precision": 0.813,
|
| 260 |
+
"recall": 0.8729
|
| 261 |
+
},
|
| 262 |
+
{
|
| 263 |
+
"prompt_id": "h03",
|
| 264 |
+
"f1": 0.8342,
|
| 265 |
+
"precision": 0.8128,
|
| 266 |
+
"recall": 0.8567
|
| 267 |
+
},
|
| 268 |
+
{
|
| 269 |
+
"prompt_id": "h04",
|
| 270 |
+
"f1": 0.8415,
|
| 271 |
+
"precision": 0.8158,
|
| 272 |
+
"recall": 0.8689
|
| 273 |
+
},
|
| 274 |
+
{
|
| 275 |
+
"prompt_id": "h05",
|
| 276 |
+
"f1": 0.8396,
|
| 277 |
+
"precision": 0.8188,
|
| 278 |
+
"recall": 0.8614
|
| 279 |
+
},
|
| 280 |
+
{
|
| 281 |
+
"prompt_id": "h06",
|
| 282 |
+
"f1": 0.8296,
|
| 283 |
+
"precision": 0.8308,
|
| 284 |
+
"recall": 0.8284
|
| 285 |
+
},
|
| 286 |
+
{
|
| 287 |
+
"prompt_id": "h07",
|
| 288 |
+
"f1": 0.8432,
|
| 289 |
+
"precision": 0.8197,
|
| 290 |
+
"recall": 0.8682
|
| 291 |
+
},
|
| 292 |
+
{
|
| 293 |
+
"prompt_id": "h08",
|
| 294 |
+
"f1": 0.8367,
|
| 295 |
+
"precision": 0.8078,
|
| 296 |
+
"recall": 0.8678
|
| 297 |
+
},
|
| 298 |
+
{
|
| 299 |
+
"prompt_id": "h09",
|
| 300 |
+
"f1": 0.8332,
|
| 301 |
+
"precision": 0.8084,
|
| 302 |
+
"recall": 0.8595
|
| 303 |
+
},
|
| 304 |
+
{
|
| 305 |
+
"prompt_id": "h10",
|
| 306 |
+
"f1": 0.8419,
|
| 307 |
+
"precision": 0.813,
|
| 308 |
+
"recall": 0.8729
|
| 309 |
+
}
|
| 310 |
+
]
|
| 311 |
+
}
|
eval/human_eval_log.jsonl
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{"session_id": "71AFBD", "turn": 1, "timestamp": "2026-04-10T07:16:15.293813", "user_message": "I've been feeling really overwhelmed lately with my thesis", "response": "I'm really sorry to hear that you've been feeling overwhelmed and anxious about your thesis. It's completely normal to feel stressed during such a significant project, but I can imagine how challenging it can be when these feelings are compounded by your full-time job and the demands of your classes.\n\nFirst and foremost, I want to validate your feelings and let you know that it's okay to feel this way. Anxiety can be incredibly draining and it's important to acknowledge the toll it's taking on your energy levels.\n\nOne thing that may help is breaking down your thesis into smaller tasks. It can be easier to focus on one piece at a time rather than trying to tackle the entire project all at once. Additionally, setting realistic goals for yourself and prioritizing your tasks can help reduce feelings of being overwhelmed.\n\nIt's also important to take care of yourself during this time. Make sure you're getting enough sleep, eating well, and taking breaks throughout the day to recharge. Engaging in activities that bring you joy or help you relax, such as reading, taking a walk, or practicing meditation or yoga, can also be helpful.\n\nIf you're finding it hard to concentrate or focus due to your anxiety, it might be helpful to try some relaxation techniques. Deep breathing exercises, progressive muscle relaxation, or visualization can all help calm the mind and reduce feelings of tension in the body.\n\nLastly, it's important to remember that it's okay to ask for help when you need it. Whether that means reaching out to a trusted friend or family member, seeking support from a mental health professional, or talking to your", "emotion_label": 1, "emotion_name": "anxiety", "trajectory": "stable", "crisis_fired": false, "crisis_confidence": 0.0}
|
| 2 |
+
{"session_id": "22E21D", "turn": 1, "timestamp": "2026-04-10T07:24:28.835886", "user_message": "I've been feeling really overwhelmed lately with my thesis", "response": "I'm really sorry to hear that you've been feeling overwhelmed with your thesis lately. It's completely normal to feel anxious or stressed when we're facing big projects and heavy workloads. Your feelings are valid and understandable given the circumstances.\n\nOne practical thing that might help is breaking down your thesis into smaller, manageable tasks. Instead of focusing on the entire project, try focusing on one section at a time. This can make the work seem less daunting and help you make steady progress. Have you considered creating a timeline or a schedule for your thesis work? It might help you stay on track and reduce some of the anxiety.\n\nWhat other strategies have you found helpful for managing your anxiety and staying focused on your work? How have you coped with feeling overwhelmed in the past?", "emotion_label": 1, "emotion_name": "anxiety", "trajectory": "stable", "crisis_fired": false, "crisis_confidence": 0.0}
|
| 3 |
+
{"session_id": "B93A70", "turn": 1, "timestamp": "2026-04-10T07:34:01.182927", "user_message": "I've been feeling really overwhelmed lately with my thesis", "response": "I'm really sorry to hear that you've been feeling overwhelmed with your thesis lately. It's a common feeling among graduate students, especially during the final stages of their degree. [From context 2], another student shared how anxiety and stress have been keeping them up at night and making it hard to focus on their work. [From context 5], yet another student expressed the same sense of being overwhelmed and unable to concentrate due to anxiety. You're not alone in this experience, and it's completely normal to feel this way given the demanding nature of graduate studies.\n\nHave you identified any specific aspects of your thesis that are causing you the most stress or anxiety right now? Sharing more about that could help us better understand your situation and offer some support.", "emotion_label": 1, "emotion_name": "anxiety", "trajectory": "stable", "crisis_fired": false, "crisis_confidence": 0.0}
|
| 4 |
+
{"session_id": "B93A70", "turn": 2, "timestamp": "2026-04-10T07:34:57.574565", "user_message": "I finally submitted my chapter draft today, I feel so relieved", "response": "I'm thrilled to hear that you took a significant step forward by submitting your chapter draft today. That's a major accomplishment! (student's emotion: relief)\n\nIt's amazing how the progress we make, no matter how small, can make a tremendous difference in our confidence and overall well-being. I've noticed that others have also shared their feelings of accomplishment and relief in the face of challenges they've overcome. (drawing from context: [1], [2], [4], [5])\n\nNow, what's the next project or goal that feels particularly important to you? I'd be curious to hear more about that.", "emotion_label": 4, "emotion_name": "hopeful", "trajectory": "de_escalating", "crisis_fired": false, "crisis_confidence": 0.0}
|
| 5 |
+
{"session_id": "B93A70", "turn": 3, "timestamp": "2026-04-10T07:35:27.462982", "user_message": "I don't know how much longer I can keep going like this, everything feels pointless", "response": "I can hear that you're going through something really difficult. You're not alone in this. Please reach out to the 988 Suicide & Crisis Lifeline by calling or texting 988 \u2014 they're available 24/7. If you're a student, your campus counseling center is also a great resource. Would you like help finding their contact info?", "emotion_label": 1, "emotion_name": "anxiety", "trajectory": "volatile", "crisis_fired": true, "crisis_confidence": 0.8772576451301575}
|
| 6 |
+
{"session_id": "44908E", "turn": 1, "timestamp": "2026-04-10T21:43:14.805449", "user_message": "I've been feeling really overwhelmed lately with my thesis", "response": "I'm really sorry to hear that you've been feeling overwhelmed with your thesis. It's a common feeling among graduate students, and the pressure of completing a significant project while balancing other responsibilities can be challenging. Have you tried reaching out to your professors or peers for support or discussing your concerns with them? It might help to lighten the load or provide some perspective on your situation. How about sharing more about what specifically is causing you to feel overwhelmed?", "emotion_label": 1, "emotion_name": "anxiety", "trajectory": "stable", "crisis_fired": false, "crisis_confidence": 0.0}
|
| 7 |
+
{"session_id": "8727D9", "turn": 1, "timestamp": "2026-04-11T04:22:51.670438", "user_message": "I've been feeling really overwhelmed lately with my thesis", "response": "Thesis work can truly be an emotional rollercoaster, and the feeling of being overwhelmed is something many grad students have experienced.\n\nWhat's been specifically challenging for you about your thesis lately?", "emotion_label": 1, "emotion_name": "anxiety", "trajectory": "stable", "crisis_fired": false, "crisis_confidence": 0.0}
|
| 8 |
+
{"session_id": "8727D9", "turn": 2, "timestamp": "2026-04-11T04:23:33.658171", "user_message": "It's the deadline and the ideas I get are not that great at all, So i'm very frustrated!", "response": "Deadlines can be a powerful motivator, but when the ideas just don't seem to flow, it can be a frustrating experience.\n\nWhat specifically about the ideas for your assignment is causing you frustration? Is there a particular aspect that you're struggling with?", "emotion_label": 2, "emotion_name": "frustration", "trajectory": "de_escalating", "crisis_fired": false, "crisis_confidence": 0.0}
|
| 9 |
+
{"session_id": "7CF2E4", "turn": 1, "timestamp": "2026-04-11T07:44:55.653777", "user_message": "I've been feeling really overwhelmed lately with my thesis", "response": "Thesis work can truly be an emotional rollercoaster, and the feeling of being overwhelmed is something many grad students have experienced.\n\nWhat's been specifically challenging for you about your thesis lately?", "emotion_label": 1, "emotion_name": "anxiety", "trajectory": "stable", "crisis_fired": false, "crisis_confidence": 0.0}
|
| 10 |
+
{"session_id": "7CF2E4", "turn": 2, "timestamp": "2026-04-11T07:45:11.989209", "user_message": "It's the deadlines mostly, I have three chapters due next week", "response": "Deadlines can add a lot of pressure, especially when you have multiple chapters due in a short amount of time.\n\nHow have you been managing your time for these chapters so far? What's been working, and what areas could use some improvement?", "emotion_label": 3, "emotion_name": "neutral", "trajectory": "de_escalating", "crisis_fired": false, "crisis_confidence": 0.0}
|
| 11 |
+
{"session_id": "7CF2E4", "turn": 3, "timestamp": "2026-04-11T07:45:46.676207", "user_message": "My advisor keeps changing requirements and it's driving me crazy", "response": "It's understandable to feel frustrated when your advisor changes requirements, as it can make it difficult to focus on your work and meet deadlines.\n\nHave you tried having an open and honest conversation with your advisor about your concerns? They may not realize the impact of their changes on you, and discussing your situation could help bring clarity and find a solution.", "emotion_label": 2, "emotion_name": "frustration", "trajectory": "de_escalating", "crisis_fired": false, "crisis_confidence": 0.0}
|