Uddiii commited on
Commit
2c8be6b
Β·
verified Β·
1 Parent(s): e91c699

Update ER_MAP/dashboard.py

Browse files

Added the dashboard we had in demo video to hf space UI for judges to interact previously it had a static html page

Files changed (1) hide show
  1. ER_MAP/dashboard.py +85 -0
ER_MAP/dashboard.py CHANGED
@@ -1070,6 +1070,8 @@ HTML_PAGE = r"""<!DOCTYPE html>
1070
  const [outcome, setOutcome] = useState(null);
1071
  const [persona, setPersona] = useState(null);
1072
  const [modelSource, setModelSource] = useState(null);
 
 
1073
 
1074
  // refs (audio + loop control β€” never trigger re-render)
1075
  const audioQueueRef = useRef([]);
@@ -1077,6 +1079,11 @@ HTML_PAGE = r"""<!DOCTYPE html>
1077
  const renderedCountRef = useRef(0);
1078
  const stopRef = useRef(false);
1079
 
 
 
 
 
 
1080
  // ---------------- Audio queue (drives card activation) ----------------
1081
  const processQueue = useCallback(async () => {
1082
  if (isPlayingRef.current || audioQueueRef.current.length === 0) return;
@@ -1089,6 +1096,21 @@ HTML_PAGE = r"""<!DOCTYPE html>
1089
  body: JSON.stringify({ text: item.text, agent: item.agent }),
1090
  });
1091
  if (!res.ok) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1092
  isPlayingRef.current = false;
1093
  processQueue();
1094
  return;
@@ -1096,6 +1118,7 @@ HTML_PAGE = r"""<!DOCTYPE html>
1096
  const blob = await res.blob();
1097
  const url = URL.createObjectURL(blob);
1098
  const audio = new Audio(url);
 
1099
 
1100
  let finished = false;
1101
  const finish = () => {
@@ -1117,6 +1140,21 @@ HTML_PAGE = r"""<!DOCTYPE html>
1117
  playPromise.catch(() => { clearTimeout(watchdog); finish(); });
1118
  }
1119
  } catch (e) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1120
  isPlayingRef.current = false;
1121
  processQueue();
1122
  }
@@ -1149,6 +1187,7 @@ HTML_PAGE = r"""<!DOCTYPE html>
1149
  setTotalReward(0);
1150
  setPhasesDone([]);
1151
  setCurrentPhase(null);
 
1152
  setStepCount(0);
1153
  renderedCountRef.current = 0;
1154
  audioQueueRef.current = [];
@@ -1213,6 +1252,10 @@ HTML_PAGE = r"""<!DOCTYPE html>
1213
  if (stepData.phases_done) setPhasesDone(stepData.phases_done);
1214
  if (stepData.current_phase !== undefined) setCurrentPhase(stepData.current_phase);
1215
 
 
 
 
 
1216
  if (stepData.done) {
1217
  await waitForAudioDrained();
1218
  break;
@@ -1368,6 +1411,48 @@ HTML_PAGE = r"""<!DOCTYPE html>
1368
  </div>
1369
  </div>
1370
  )}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1371
  </div>
1372
  </div>
1373
 
 
1070
  const [outcome, setOutcome] = useState(null);
1071
  const [persona, setPersona] = useState(null);
1072
  const [modelSource, setModelSource] = useState(null);
1073
+ const [conversationLog, setConversationLog] = useState([]);
1074
+ const logEndRef = useRef(null);
1075
 
1076
  // refs (audio + loop control β€” never trigger re-render)
1077
  const audioQueueRef = useRef([]);
 
1079
  const renderedCountRef = useRef(0);
1080
  const stopRef = useRef(false);
1081
 
1082
+ // Auto-scroll conversation log
1083
+ useEffect(() => {
1084
+ if (logEndRef.current) logEndRef.current.scrollIntoView({ behavior: 'smooth' });
1085
+ }, [conversationLog]);
1086
+
1087
  // ---------------- Audio queue (drives card activation) ----------------
1088
  const processQueue = useCallback(async () => {
1089
  if (isPlayingRef.current || audioQueueRef.current.length === 0) return;
 
1096
  body: JSON.stringify({ text: item.text, agent: item.agent }),
1097
  });
1098
  if (!res.ok) {
1099
+ // ElevenLabs unavailable β€” use browser speech
1100
+ try {
1101
+ const synth = window.speechSynthesis;
1102
+ if (synth) {
1103
+ const utter = new SpeechSynthesisUtterance(item.text);
1104
+ utter.rate = 1.05;
1105
+ utter.pitch = item.agent === 'patient' ? 0.9 : item.agent === 'nurse' ? 1.1 : 1.0;
1106
+ utter.volume = 1.0;
1107
+ setActiveAgent(item.agent);
1108
+ utter.onend = () => { setActiveAgent(null); isPlayingRef.current = false; processQueue(); };
1109
+ utter.onerror = () => { setActiveAgent(null); isPlayingRef.current = false; processQueue(); };
1110
+ synth.speak(utter);
1111
+ return;
1112
+ }
1113
+ } catch (_) {}
1114
  isPlayingRef.current = false;
1115
  processQueue();
1116
  return;
 
1118
  const blob = await res.blob();
1119
  const url = URL.createObjectURL(blob);
1120
  const audio = new Audio(url);
1121
+ audio.volume = 1.0;
1122
 
1123
  let finished = false;
1124
  const finish = () => {
 
1140
  playPromise.catch(() => { clearTimeout(watchdog); finish(); });
1141
  }
1142
  } catch (e) {
1143
+ // ElevenLabs TTS failed β€” use browser Web Speech API as fallback
1144
+ try {
1145
+ const synth = window.speechSynthesis;
1146
+ if (synth) {
1147
+ const utter = new SpeechSynthesisUtterance(item.text);
1148
+ utter.rate = 1.05;
1149
+ utter.pitch = item.agent === 'patient' ? 0.9 : item.agent === 'nurse' ? 1.1 : 1.0;
1150
+ utter.volume = 1.0;
1151
+ setActiveAgent(item.agent);
1152
+ utter.onend = () => { setActiveAgent(null); isPlayingRef.current = false; processQueue(); };
1153
+ utter.onerror = () => { setActiveAgent(null); isPlayingRef.current = false; processQueue(); };
1154
+ synth.speak(utter);
1155
+ return;
1156
+ }
1157
+ } catch (_) {}
1158
  isPlayingRef.current = false;
1159
  processQueue();
1160
  }
 
1187
  setTotalReward(0);
1188
  setPhasesDone([]);
1189
  setCurrentPhase(null);
1190
+ setConversationLog([]);
1191
  setStepCount(0);
1192
  renderedCountRef.current = 0;
1193
  audioQueueRef.current = [];
 
1252
  if (stepData.phases_done) setPhasesDone(stepData.phases_done);
1253
  if (stepData.current_phase !== undefined) setCurrentPhase(stepData.current_phase);
1254
 
1255
+ // Update conversation log
1256
+ const allMsgs = stepData.conversation || [];
1257
+ setConversationLog(allMsgs);
1258
+
1259
  if (stepData.done) {
1260
  await waitForAudioDrained();
1261
  break;
 
1411
  </div>
1412
  </div>
1413
  )}
1414
+
1415
+ {/* Section D: Live Conversation Log */}
1416
+ <div className="border-t border-slate-800/50 pt-6 pb-4">
1417
+ <div className="flex items-center justify-between mb-3">
1418
+ <h3 className="text-xs font-semibold text-slate-300 uppercase tracking-wider">Agent Conversation</h3>
1419
+ <span className="text-[10px] text-slate-500 font-mono">{conversationLog.length} msgs</span>
1420
+ </div>
1421
+ <div className="bg-slate-950/40 rounded-xl border border-slate-800/50 p-3 max-h-[280px] overflow-y-auto custom-scrollbar shadow-inner space-y-2">
1422
+ {conversationLog.length === 0 && (
1423
+ <div className="text-slate-600 italic text-[11px] text-center py-4">Start a case to see the conversation...</div>
1424
+ )}
1425
+ {conversationLog.map((m, i) => {
1426
+ const colors = {
1427
+ doctor: { bg: 'bg-indigo-500/10', border: 'border-indigo-500/20', name: 'text-indigo-400', icon: '🩺' },
1428
+ nurse: { bg: 'bg-blue-500/10', border: 'border-blue-500/20', name: 'text-blue-400', icon: 'πŸ‘©β€βš•οΈ' },
1429
+ patient: { bg: 'bg-amber-500/10', border: 'border-amber-500/20', name: 'text-amber-400', icon: 'πŸ₯' },
1430
+ system: { bg: 'bg-slate-800/30', border: 'border-slate-700/30', name: 'text-slate-400', icon: 'βš™οΈ' },
1431
+ };
1432
+ const c = colors[m.agent] || colors.system;
1433
+ return (
1434
+ <div key={i} className={`${c.bg} border ${c.border} rounded-lg p-2`}>
1435
+ <div className="flex items-center gap-1.5 mb-1">
1436
+ <span className="text-[10px]">{c.icon}</span>
1437
+ <span className={`text-[10px] font-bold uppercase tracking-wider ${c.name}`}>{m.agent}</span>
1438
+ {m.type && m.type !== 'speak_to' && (
1439
+ <span className="text-[8px] bg-slate-800/50 text-slate-500 px-1.5 py-0.5 rounded-full font-mono">{m.type}</span>
1440
+ )}
1441
+ {m.target && m.target !== m.agent && (
1442
+ <span className="text-[8px] text-slate-600">β†’ {m.target}</span>
1443
+ )}
1444
+ </div>
1445
+ {m.thought && (
1446
+ <div className="text-[9px] text-slate-500 italic mb-1 pl-4 border-l border-slate-700/30">πŸ’­ {m.thought}</div>
1447
+ )}
1448
+ <div className="text-[10px] text-slate-300 leading-relaxed pl-4">{m.message || '(no message)'}</div>
1449
+ </div>
1450
+ );
1451
+ })}
1452
+ <div ref={logEndRef} />
1453
+ </div>
1454
+ </div>
1455
+
1456
  </div>
1457
  </div>
1458