|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const SCENARIO_DESCRIPTIONS = { |
|
|
'mimic': 'Exploring clinical patterns and patient outcomes in a large-scale electronic health record (EHR) database.', |
|
|
'10k': 'Extracting deep insights from SEC 10-K annual reports for longitudinal financial performance analysis.', |
|
|
'globem': 'Analyzing multi-modal longitudinal behavioral and sensor data for detecting mental health trends.' |
|
|
}; |
|
|
|
|
|
let currentTrajScenario = 'mimic'; |
|
|
|
|
|
function initTrajectory() { |
|
|
if (typeof TRAJECTORY_DATA === 'undefined') { |
|
|
setTimeout(initTrajectory, 500); |
|
|
return; |
|
|
} |
|
|
|
|
|
|
|
|
if (typeof marked !== 'undefined') { |
|
|
marked.setOptions({ |
|
|
highlight: function (code, lang) { |
|
|
|
|
|
if (lang === 'sql' && typeof sqlFormatter !== 'undefined') { |
|
|
try { |
|
|
code = sqlFormatter.format(code, { language: 'sql', indent: ' ' }); |
|
|
} catch (e) { |
|
|
console.warn('SQL Formatting failed:', e); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (lang && hljs.getLanguage(lang)) { |
|
|
return hljs.highlight(code, { language: lang }).value; |
|
|
} |
|
|
return hljs.highlightAuto(code).value; |
|
|
}, |
|
|
breaks: true, |
|
|
langPrefix: 'hljs language-' |
|
|
}); |
|
|
} |
|
|
|
|
|
|
|
|
document.querySelectorAll('[data-traj-scenario]').forEach(btn => { |
|
|
btn.addEventListener('click', () => { |
|
|
document.querySelectorAll('[data-traj-scenario]').forEach(b => b.classList.remove('active')); |
|
|
btn.classList.add('active'); |
|
|
currentTrajScenario = btn.dataset.trajScenario; |
|
|
|
|
|
|
|
|
const descEl = document.getElementById('trajectory-scenario-description'); |
|
|
if (descEl && SCENARIO_DESCRIPTIONS[currentTrajScenario]) { |
|
|
descEl.textContent = SCENARIO_DESCRIPTIONS[currentTrajScenario]; |
|
|
} |
|
|
|
|
|
renderTrajectory(currentTrajScenario); |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
renderTrajectory('mimic'); |
|
|
} |
|
|
|
|
|
function renderTrajectory(scenario) { |
|
|
const container = document.getElementById('chat-window'); |
|
|
const messages = TRAJECTORY_DATA[scenario]; |
|
|
|
|
|
if (!container || !messages) return; |
|
|
|
|
|
container.innerHTML = ''; |
|
|
|
|
|
messages.forEach((msg, index) => { |
|
|
const msgDiv = document.createElement('div'); |
|
|
msgDiv.className = `chat-message role-${msg.role}`; |
|
|
|
|
|
|
|
|
const roleLabel = document.createElement('div'); |
|
|
roleLabel.className = 'message-role-label'; |
|
|
|
|
|
roleLabel.textContent = msg.role.charAt(0).toUpperCase() + msg.role.slice(1); |
|
|
if (msg.role === 'user') roleLabel.textContent = 'User Prompt'; |
|
|
msgDiv.appendChild(roleLabel); |
|
|
|
|
|
|
|
|
const bubble = document.createElement('div'); |
|
|
bubble.className = 'message-bubble'; |
|
|
|
|
|
|
|
|
let htmlContent = ''; |
|
|
if (typeof marked !== 'undefined') { |
|
|
htmlContent = marked.parse(msg.content); |
|
|
} else { |
|
|
|
|
|
htmlContent = escapeHtml(msg.content).replace(/\n/g, '<br>'); |
|
|
} |
|
|
|
|
|
const contentDiv = document.createElement('div'); |
|
|
contentDiv.innerHTML = htmlContent; |
|
|
bubble.appendChild(contentDiv); |
|
|
msgDiv.appendChild(bubble); |
|
|
container.appendChild(msgDiv); |
|
|
|
|
|
|
|
|
|
|
|
const COLLAPSE_HEIGHT = 200; |
|
|
const isLastMessage = (index === messages.length - 1); |
|
|
|
|
|
|
|
|
if (!isLastMessage && contentDiv.scrollHeight > COLLAPSE_HEIGHT + 20) { |
|
|
contentDiv.style.cssText = `max-height: ${COLLAPSE_HEIGHT}px; overflow: hidden; position: relative; mask-image: linear-gradient(to bottom, black 60%, transparent 100%); -webkit-mask-image: linear-gradient(to bottom, black 60%, transparent 100%);`; |
|
|
|
|
|
const btn = document.createElement('button'); |
|
|
btn.textContent = 'Show More'; |
|
|
btn.style.cssText = 'display:block; margin: 8px auto 0; border:none; background: rgba(0,0,0,0.05); color: #0071e3; border-radius: 12px; padding: 4px 12px; cursor:pointer; font-size:12px; font-weight:500; transition: all 0.2s;'; |
|
|
|
|
|
if (msg.role === 'agent') { |
|
|
btn.style.background = 'rgba(255,255,255,0.2)'; |
|
|
btn.style.color = 'white'; |
|
|
} |
|
|
|
|
|
btn.onclick = () => { |
|
|
if (contentDiv.style.maxHeight !== 'none') { |
|
|
|
|
|
contentDiv.style.maxHeight = 'none'; |
|
|
contentDiv.style.maskImage = 'none'; |
|
|
contentDiv.style.webkitMaskImage = 'none'; |
|
|
btn.textContent = 'Show Less'; |
|
|
} else { |
|
|
|
|
|
contentDiv.style.maxHeight = `${COLLAPSE_HEIGHT}px`; |
|
|
contentDiv.style.maskImage = 'linear-gradient(to bottom, black 60%, transparent 100%)'; |
|
|
contentDiv.style.webkitMaskImage = 'linear-gradient(to bottom, black 60%, transparent 100%)'; |
|
|
btn.textContent = 'Show More'; |
|
|
} |
|
|
}; |
|
|
|
|
|
bubble.appendChild(btn); |
|
|
} |
|
|
}); |
|
|
|
|
|
container.scrollTop = 0; |
|
|
} |
|
|
|
|
|
function escapeHtml(text) { |
|
|
if (!text) return ''; |
|
|
return text |
|
|
.replace(/&/g, "&") |
|
|
.replace(/</g, "<") |
|
|
.replace(/>/g, ">") |
|
|
.replace(/"/g, """) |
|
|
.replace(/'/g, "'"); |
|
|
} |
|
|
|
|
|
document.addEventListener('DOMContentLoaded', () => { |
|
|
initTrajectory(); |
|
|
}); |
|
|
|