alatest / index.html
MIragE-Ala's picture
Add 2 files
8973425 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Token Uncertainty Visualization</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
:root {
--primary-color: #4a6fa5;
--secondary-color: #6c757d;
--success-color: #28a745;
--danger-color: #dc3545;
--warning-color: #ffc107;
--info-color: #17a2b8;
--light-bg: #f8f9fa;
--dark-bg: #343a40;
--border-radius: 4px;
--box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
--transition: all 0.3s ease;
}
/* Added new color classes for better visualization */
.color-percentile-0 { background-color: #2ecc71; } /* 0-33%: Green */
.color-percentile-1 { background-color: #f39c12; } /* 33-66%: Orange */
.color-percentile-2 { background-color: #e74c3c; } /* 66-100%: Red */
/* For probability (higher is better) */
.color-percentile-prob-0 { background-color: #e74c3c; } /* 0-33%: Red (low probability) */
.color-percentile-prob-1 { background-color: #f39c12; } /* 33-66%: Orange */
.color-percentile-prob-2 { background-color: #2ecc71; } /* 66-100%: Green (high probability) */
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
line-height: 1.6;
margin: 0;
padding: 0;
background-color: #f5f7fa;
color: #333;
}
.container {
max-width: 1200px;
margin: 0 auto;
padding: 20px;
}
header {
background-color: var(--primary-color);
color: white;
padding: 20px 0;
text-align: center;
margin-bottom: 30px;
border-radius: 0 0 var(--border-radius) var(--border-radius);
box-shadow: var(--box-shadow);
}
h1 {
margin: 0;
font-size: 2.2rem;
}
.subtitle {
font-size: 1rem;
opacity: 0.9;
margin-top: 8px;
}
.card {
background-color: white;
border-radius: var(--border-radius);
box-shadow: var(--box-shadow);
overflow: hidden;
margin-bottom: 20px;
}
.card-header {
padding: 15px 20px;
background-color: var(--light-bg);
border-bottom: 1px solid #e9ecef;
display: flex;
justify-content: space-between;
align-items: center;
}
.card-title {
margin: 0;
font-size: 1.25rem;
color: var(--primary-color);
}
.card-body {
padding: 20px;
}
.controls {
display: flex;
gap: 15px;
margin-bottom: 20px;
align-items: center;
flex-wrap: wrap;
}
.control-group {
display: flex;
gap: 5px;
align-items: center;
}
label {
font-weight: 500;
font-size: 0.9rem;
}
input, select {
padding: 8px 12px;
border: 1px solid #ced4da;
border-radius: var(--border-radius);
font-size: 0.9rem;
}
button {
background-color: var(--primary-color);
color: white;
border: none;
padding: 8px 15px;
border-radius: var(--border-radius);
cursor: pointer;
font-size: 0.9rem;
transition: var(--transition);
}
button:hover {
background-color: #3a5a80;
}
.token-container {
display: flex;
flex-wrap: wrap;
gap: 8px;
margin-bottom: 20px;
}
.token {
position: relative;
background-color: #e9ecef;
padding: 6px 12px;
border-radius: 20px;
font-size: 0.9rem;
cursor: pointer;
transition: var(--transition);
border: 1px solid transparent;
}
.token:hover {
transform: translateY(-2px);
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}
.token.active {
border-color: var(--primary-color);
background-color: #e3f2fd;
}
.uncertainty-marker {
position: absolute;
bottom: -4px;
left: 0;
width: 100%;
height: 3px;
background-color: var(--danger-color);
opacity: 0.7;
transition: var(--transition);
}
.detail-panel {
display: none;
background-color: white;
border-radius: var(--border-radius);
padding: 20px;
box-shadow: var(--box-shadow);
margin-top: 20px;
}
.detail-panel.active {
display: block;
animation: fadeIn 0.3s ease;
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(10px); }
to { opacity: 1; transform: translateY(0); }
}
.metric-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
gap: 15px;
margin-bottom: 20px;
}
.metric-item {
background-color: var(--light-bg);
padding: 10px;
border-radius: var(--border-radius);
text-align: center;
}
.metric-value {
font-weight: bold;
font-size: 1.25rem;
color: var(--primary-color);
margin: 5px 0;
}
.metric-label {
font-size: 0.8rem;
color: var(--secondary-color);
}
.heatmap-container {
margin-top: 20px;
}
.heatmap-row {
display: flex;
margin-bottom: 5px;
align-items: center;
}
.heatmap-label {
width: 120px;
font-size: 0.8rem;
margin-right: 10px;
color: var(--secondary-color);
}
.heatmap-bars {
flex-grow: 1;
display: flex;
}
.heatmap-bar {
height: 20px;
margin-right: 2px;
transition: var(--transition);
position: relative;
}
.heatmap-bar:hover {
transform: scaleY(1.2);
}
.heatmap-tooltip {
position: absolute;
bottom: 100%;
left: 50%;
transform: translateX(-50%);
background-color: var(--dark-bg);
color: white;
padding: 5px 10px;
border-radius: var(--border-radius);
font-size: 0.7rem;
white-space: nowrap;
opacity: 0;
pointer-events: none;
transition: var(--transition);
}
.heatmap-bar:hover .heatmap-tooltip {
opacity: 1;
bottom: 120%;
}
/* Color scales */
.color-low {
background-color: #2ecc71;
}
.color-medium {
background-color: #f39c12;
}
.color-high {
background-color: #e74c3c;
}
/* Responsive design */
@media (max-width: 768px) {
.metric-grid {
grid-template-columns: 1fr 1fr;
}
.controls {
flex-direction: column;
align-items: flex-start;
}
}
@media (max-width: 576px) {
.metric-grid {
grid-template-columns: 1fr;
}
}
/* Tabs */
.tabs {
display: flex;
border-bottom: 1px solid #dee2e6;
margin-bottom: 15px;
overflow-x: auto;
}
.tab {
padding: 10px 15px;
cursor: pointer;
border: 1px solid transparent;
border-bottom: none;
border-radius: 4px 4px 0 0;
margin-right: 5px;
background-color: transparent;
transition: var(--transition);
flex-shrink: 0;
}
.tab:hover {
background-color: #f8f9fa;
}
.tab.active {
background-color: white;
border-color: #dee2e6 #dee2e6 white;
color: var(--primary-color);
font-weight: bold;
}
.chart-container {
height: 300px;
margin-top: 20px;
}
/* Token info panel */
.token-info {
background-color: white;
border-radius: var(--border-radius);
padding: 15px;
box-shadow: var(--box-shadow);
margin-top: 15px;
}
.token-info-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 10px;
}
.token-info-title {
font-size: 1rem;
margin: 0;
color: var(--primary-color);
}
.token-info-content {
font-size: 0.9rem;
line-height: 1.5;
}
/* Legend */
.legend {
display: flex;
justify-content: center;
margin: 15px 0;
flex-wrap: wrap;
gap: 15px;
}
.legend-item {
display: flex;
align-items: center;
font-size: 0.8rem;
}
.legend-color {
width: 16px;
height: 16px;
border-radius: 3px;
margin-right: 5px;
}
.toggle-btn {
background-color: transparent;
color: var(--secondary-color);
border: 1px solid #ced4da;
padding: 5px 10px;
font-size: 0.8rem;
}
.toggle-btn.active {
background-color: var(--primary-color);
color: white;
border-color: var(--primary-color);
}
.file-input-wrapper {
position: relative;
overflow: hidden;
display: inline-block;
}
.file-input-wrapper input[type="file"] {
font-size: 100px;
position: absolute;
left: 0;
top: 0;
opacity: 0;
}
.loading {
display: none;
text-align: center;
padding: 20px;
}
.loading.active {
display: block;
}
.spinner {
border: 4px solid rgba(0, 0, 0, 0.1);
border-radius: 50%;
border-top: 4px solid var(--primary-color);
width: 30px;
height: 30px;
animation: spin 1s linear infinite;
margin: 0 auto 10px;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
.error-message {
color: var(--danger-color);
background-color: #f8d7da;
padding: 10px;
border-radius: var(--border-radius);
margin: 10px 0;
display: none;
}
.file-info {
font-size: 0.8rem;
color: var(--secondary-color);
margin-left: 10px;
}
/* Range slider */
.range-slider {
width: 200px;
margin: 0 10px;
}
.range-value {
min-width: 30px;
text-align: center;
}
/* Progress bar */
.progress-container {
width: 100%;
background-color: #e9ecef;
border-radius: 4px;
margin: 10px 0;
}
.progress-bar {
height: 20px;
background-color: var(--primary-color);
border-radius: 4px;
width: 0%;
transition: width 0.3s ease;
}
</style>
</head>
<body>
<header>
<div class="container">
<h1>Token Uncertainty Visualization</h1>
<p class="subtitle">Analyze model confidence for JSONL files with question/answer data</p>
</div>
</header>
<div class="container">
<div class="card">
<div class="card-header">
<h2 class="card-title">Data Selection</h2>
<div class="legend">
<div class="legend-item">
<div class="legend-color color-low"></div>
<span>Low Uncertainty</span>
</div>
<div class="legend-item">
<div class="legend-color color-medium"></div>
<span>Medium Uncertainty</span>
</div>
<div class="legend-item">
<div class="legend-color color-high"></div>
<span>High Uncertainty</span>
</div>
</div>
</div>
<div class="card-body">
<div class="controls">
<div class="control-group">
<div class="file-input-wrapper">
<button type="button" id="uploadBtn">
<i class="fas fa-upload"></i> Upload JSONL File
</button>
<input type="file" id="fileInput" accept=".jsonl,.json">
</div>
<span class="file-info" id="fileInfo">No file selected</span>
</div>
<div class="control-group">
<label for="questionId">Question ID:</label>
<input type="number" id="questionId" min="0" value="0">
<button id="loadQuestionBtn">Load</button>
</div>
<div class="control-group">
<label for="autoToggle">Auto Load:</label>
<button id="autoToggle" class="toggle-btn">Off</button>
</div>
<div class="control-group">
<label for="heatmapType">Heatmap:</label>
<select id="heatmapType">
<option value="prob">Probability</option>
<option value="entropy">Entropy</option>
<option value="au">Aleatoric Uncertainty</option>
<option value="eu">Epistemic Uncertainty</option>
</select>
<button id="updateHeatmapBtn">Update</button>
</div>
</div>
<div class="progress-container" id="fileProgressContainer">
<div class="progress-bar" id="fileProgressBar"></div>
</div>
<div class="error-message" id="errorMessage"></div>
<div class="loading" id="loadingIndicator">
<div class="spinner"></div>
<p>Processing data...</p>
</div>
<div class="token-container" id="tokenContainer">
<!-- Tokens will be inserted here by JavaScript -->
</div>
<div class="detail-panel" id="detailPanel">
<div class="tabs">
<button class="tab active" data-tab="metrics">Metrics</button>
<button class="tab" data-tab="probability">Probability</button>
<button class="tab" data-tab="entropy">Entropy</button>
<button class="tab" data-tab="au">Aleatoric Uncertainty</button>
<button class="tab" data-tab="eu">Epistemic Uncertainty</button>
<button class="tab" data-tab="logits">Top Logits</button>
<button class="tab" data-tab="rawData">Raw Data</button>
</div>
<div id="metricsTab" class="tab-content active">
<div class="metric-grid">
<div class="metric-item">
<div class="metric-label">Probability</div>
<div class="metric-value" id="probValue">0.00</div>
<div class="metric-note">Confidence score (0-1)</div>
</div>
<div class="metric-item">
<div class="metric-label">Entropy</div>
<div class="metric-value" id="entropyValue">0.00</div>
<div class="metric-note">Uncertainty measure</div>
</div>
<div class="metric-item">
<div class="metric-label">AU</div>
<div class="metric-value" id="auValue">0.00</div>
<div class="metric-note">Aleatoric Uncertainty</div>
</div>
<div class="metric-item">
<div class="metric-label">EU</div>
<div class="metric-value" id="euValue">0.00</div>
<div class="metric-note">Epistemic Uncertainty</div>
</div>
</div>
<div class="heatmap-container">
<h4>Uncertainty Heatmap</h4>
<div class="heatmap-row">
<div class="heatmap-label" id="currentHeatmapLabel">Probability</div>
<div class="heatmap-bars" id="currentHeatmap"></div>
</div>
</div>
</div>
<div id="probabilityTab" class="tab-content">
<div class="token-info">
<div class="token-info-header">
<h3 class="token-info-title">Probability Distribution</h3>
</div>
<div class="token-info-content">
<p>The model predicted this token with a probability of <strong id="probValue2">0.00</strong>.</p>
<p>Higher probability values indicate greater confidence in the predicted token.</p>
<div class="heatmap-container">
<div class="heatmap-row">
<div class="heatmap-label">Probability</div>
<div class="heatmap-bars" id="probHeatmap"></div>
</div>
</div>
</div>
</div>
</div>
<div id="entropyTab" class="tab-content">
<div class="token-info">
<div class="token-info-header">
<h3 class="token-info-title">Entropy Analysis</h3>
</div>
<div class="token-info-content">
<p>This token has an entropy value of <strong id="entropyValue2">0.00</strong>.</p>
<p>Higher entropy values indicate greater uncertainty in the prediction.</p>
<div class="heatmap-container">
<div class="heatmap-row">
<div class="heatmap-label">Entropy</div>
<div class="heatmap-bars" id="entropyHeatmap"></div>
</div>
</div>
</div>
</div>
</div>
<div id="auTab" class="tab-content">
<div class="token-info">
<div class="token-info-header">
<h3 class="token-info-title">Aleatoric Uncertainty</h3>
</div>
<div class="token-info-content">
<p>This token has an Aleatoric Uncertainty (AU) value of <strong id="auValue2">0.00</strong>.</p>
<p>AU represents the inherent noise in the data that cannot be reduced.</p>
<div class="heatmap-container">
<div class="heatmap-row">
<div class="heatmap-label">Aleatoric Uncertainty</div>
<div class="heatmap-bars" id="auHeatmap"></div>
</div>
</div>
</div>
</div>
</div>
<div id="euTab" class="tab-content">
<div class="token-info">
<div class="token-info-header">
<h3 class="token-info-title">Epistemic Uncertainty</h3>
</div>
<div class="token-info-content">
<p>This token has an Epistemic Uncertainty (EU) value of <strong id="euValue2">0.00</strong>.</p>
<p>EU represents uncertainty due to limited knowledge and can be reduced with more data.</p>
<div class="heatmap-container">
<div class="heatmap-row">
<div class="heatmap-label">Epistemic Uncertainty</div>
<div class="heatmap-bars" id="euHeatmap"></div>
</div>
</div>
</div>
</div>
</div>
<div id="logitsTab" class="tab-content">
<div class="token-info">
<div class="token-info-header">
<h3 class="token-info-title">Top Alternative Predictions</h3>
</div>
<div class="token-info-content">
<p>These are the other most likely tokens the model considered (logits):</p>
<table id="logitsTable" style="width:100%; font-size:0.8rem; border-collapse: collapse;">
<thead>
<tr style="background-color: #f8f9fa; border-top: 1px solid #dee2e6; border-bottom: 1px solid #dee2e6;">
<th style="padding: 8px; text-align: left;">Rank</th>
<th style="padding: 8px; text-align: left;">Token ID</th>
<th style="padding: 8px; text-align: left;">Logit Value</th>
</tr>
</thead>
<tbody>
<!-- Will be populated by JavaScript -->
</tbody>
</table>
</div>
</div>
</div>
<div id="rawDataTab" class="tab-content">
<div class="token-info">
<div class="token-info-header">
<h3 class="token-info-title">Complete Question Data</h3>
</div>
<div class="token-info-content">
<p>Full JSON data for the selected question:</p>
<pre id="rawData" style="background-color: #f8f9fa; padding: 10px; border-radius: var(--border-radius); overflow-x: auto; max-height: 300px;"></pre>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
// DOM elements
const fileInput = document.getElementById('fileInput');
const uploadBtn = document.getElementById('uploadBtn');
const fileInfo = document.getElementById('fileInfo');
const questionIdInput = document.getElementById('questionId');
const loadQuestionBtn = document.getElementById('loadQuestionBtn');
const autoToggle = document.getElementById('autoToggle');
const heatmapTypeSelect = document.getElementById('heatmapType');
const updateHeatmapBtn = document.getElementById('updateHeatmapBtn');
const tokenContainer = document.getElementById('tokenContainer');
const detailPanel = document.getElementById('detailPanel');
const loadingIndicator = document.getElementById('loadingIndicator');
const errorMessage = document.getElementById('errorMessage');
const fileProgressBar = document.getElementById('fileProgressBar');
const fileProgressContainer = document.getElementById('fileProgressContainer');
// State variables
let jsonlData = null;
let currentQuestionIndex = 0;
let autoLoadEnabled = false;
let currentHeatmapType = 'prob';
let questionDataCache = {};
let sortedRanks = {
prob: [],
entropy: [],
au: [],
eu: []
};
// Initialize the application
init();
function init() {
// Event listeners
fileInput.addEventListener('change', handleFileUpload);
uploadBtn.addEventListener('click', () => fileInput.click());
loadQuestionBtn.addEventListener('click', loadCurrentQuestion);
autoToggle.addEventListener('click', toggleAutoLoad);
questionIdInput.addEventListener('change', handleQuestionIdChange);
heatmapTypeSelect.addEventListener('change', updateHeatmapSelection);
updateHeatmapBtn.addEventListener('click', updateCurrentHeatmap);
// Initialize with no progress bar visible
fileProgressContainer.style.display = 'none';
}
function handleFileUpload(event) {
const file = event.target.files[0];
if (!file) return;
fileInfo.textContent = file.name;
loadingIndicator.classList.add('active');
errorMessage.style.display = 'none';
// Show progress bar
fileProgressContainer.style.display = 'block';
fileProgressBar.style.width = '0%';
let lineCount = 0;
let processedLines = 0;
const reader = new FileReader();
// First pass to count lines
const countReader = new FileReader();
countReader.onload = function(e) {
const text = e.target.result;
lineCount = text.split('\n').filter(line => line.trim()).length;
// Now process the file
reader.onload = function(e) {
try {
// Parse JSONL file (each line is a separate JSON object)
const lines = e.target.result.split('\n').filter(line => line.trim());
jsonlData = [];
lines.forEach((line, index) => {
try {
const data = JSON.parse(line);
jsonlData.push(data);
processedLines++;
// Update progress
const progress = Math.round((processedLines / lineCount) * 100);
fileProgressBar.style.width = `${progress}%`;
// Every 10% or when complete, update the UI
if (progress % 10 === 0 || progress === 100) {
setTimeout(() => {
// Force UI update
}, 0);
}
} catch (parseError) {
console.error(`Error parsing line ${index}:`, parseError);
}
});
// Sort data by question_id for easier navigation
jsonlData.sort((a, b) => a.question_id - b.question_id);
// Update the question ID input range
if (jsonlData.length > 0) {
const minId = jsonlData[0].question_id;
const maxId = jsonlData[jsonlData.length - 1].question_id;
questionIdInput.min = minId;
questionIdInput.max = maxId;
questionIdInput.value = minId;
// Load the first question
loadCurrentQuestion();
}
loadingIndicator.classList.remove('active');
fileProgressContainer.style.display = 'none';
} catch (error) {
showError("Error parsing JSONL file. Please check the file format.");
console.error(error);
loadingIndicator.classList.remove('active');
fileProgressContainer.style.display = 'none';
}
};
reader.onerror = function() {
showError("Error reading file. Please try again.");
loadingIndicator.classList.remove('active');
fileProgressContainer.style.display = 'none';
};
reader.readAsText(file);
};
countReader.readAsText(file);
}
function handleQuestionIdChange() {
if (autoLoadEnabled) {
loadCurrentQuestion();
}
}
function loadCurrentQuestion() {
if (!jsonlData || jsonlData.length === 0) {
showError("No data loaded. Please upload a JSONL file first.");
return;
}
const questionId = parseInt(questionIdInput.value);
const questionData = jsonlData.find(item => item.question_id === questionId);
if (questionData) {
currentQuestionIndex = questionId;
renderQuestionData(questionData);
} else {
showError(`Question with ID ${questionId} not found in the file.`);
}
}
function toggleAutoLoad() {
autoLoadEnabled = !autoLoadEnabled;
autoToggle.textContent = autoLoadEnabled ? 'On' : 'Off';
autoToggle.classList.toggle('active', autoLoadEnabled);
}
function updateHeatmapSelection() {
currentHeatmapType = heatmapTypeSelect.value;
updateCurrentHeatmap();
}
function updateCurrentHeatmap() {
if (!questionDataCache || !questionDataCache[currentHeatmapType]) return;
document.getElementById('currentHeatmapLabel').textContent =
currentHeatmapType === 'prob' ? 'Probability' :
currentHeatmapType === 'entropy' ? 'Entropy' :
currentHeatmapType === 'au' ? 'Aleatoric Uncertainty' : 'Epistemic Uncertainty';
createPercentileHeatmap(
'currentHeatmap',
questionDataCache[currentHeatmapType],
sortedRanks[currentHeatmapType],
currentHeatmapType === 'prob' // Reverse for probability (higher is better)
);
// NEW: Update all token markers based on the current heatmap selection
updateTokenMarkers();
}
function updateTokenMarkers() {
const tokens = document.querySelectorAll('.token');
tokens.forEach(tokenEl => {
const index = parseInt(tokenEl.dataset.index);
const marker = tokenEl.querySelector('.uncertainty-marker');
if (marker) {
const percentile = getPercentile(index, currentHeatmapType);
// Clear previous color classes
marker.className = 'uncertainty-marker';
// Add appropriate color class based on percentile and metric type
if (currentHeatmapType === 'prob') {
// For probability - higher is better (red to green)
if (percentile < 0.33) marker.classList.add('color-percentile-prob-0');
else if (percentile < 0.66) marker.classList.add('color-percentile-prob-1');
else marker.classList.add('color-percentile-prob-2');
} else {
// For entropy, AU, EU - higher is worse (green to red)
if (percentile < 0.33) marker.classList.add('color-percentile-0');
else if (percentile < 0.66) marker.classList.add('color-percentile-1');
else marker.classList.add('color-percentile-2');
}
}
});
}
function showError(message) {
errorMessage.textContent = message;
errorMessage.style.display = 'block';
}
function renderQuestionData(data) {
// Cache the current question data
questionDataCache = data;
// Update the raw data display
document.getElementById('rawData').textContent = JSON.stringify(data, null, 2);
// Clear existing tokens
tokenContainer.innerHTML = '';
// Check if the required data fields exist
if (!data.token_char_list || !data.prob || !data.entropy || !data.au || !data.eu) {
showError("The selected question doesn't contain the required token analysis data.");
detailPanel.classList.remove('active');
return;
}
// Calculate sorted rankings for each metric
sortedRanks.prob = getSortedRanks(data.prob, false); // Higher is better
sortedRanks.entropy = getSortedRanks(data.entropy, true); // Higher is worse
sortedRanks.au = getSortedRanks(data.au, true); // Higher is worse
sortedRanks.eu = getSortedRanks(data.eu, true); // Higher is worse
// Initialize the token display
data.token_char_list.forEach((token, index) => {
const tokenEl = document.createElement('div');
tokenEl.className = 'token';
tokenEl.textContent = token;
tokenEl.dataset.index = index;
// Add uncertainty marker that will be styled dynamically
const marker = document.createElement('div');
marker.className = 'uncertainty-marker';
tokenEl.appendChild(marker);
tokenEl.addEventListener('click', () => showTokenDetails(index));
tokenContainer.appendChild(tokenEl);
});
// Create all heatmaps
createPercentileHeatmap('probHeatmap', data.prob, sortedRanks.prob, true);
createPercentileHeatmap('entropyHeatmap', data.entropy, sortedRanks.entropy, false);
createPercentileHeatmap('auHeatmap', data.au, sortedRanks.au, false);
createPercentileHeatmap('euHeatmap', data.eu, sortedRanks.eu, false);
// Set current heatmap to show probability by default
updateCurrentHeatmap();
// Show details for first token by default
if (data.token_char_list.length > 0) {
showTokenDetails(0);
} else {
detailPanel.classList.remove('active');
}
updateTokenMarkers();
}
function getSortedRanks(values, higherIsWorse = true) {
// Create an array of indices and sort them based on values
const indices = Array.from({length: values.length}, (_, i) => i);
// Sort indices based on the values
indices.sort((a, b) => higherIsWorse ?
(values[b] - values[a]) : // Higher values come first for entropy/au/eu
(values[a] - values[b])); // Lower values come first for probability
// Create a rank array where rank[i] is the position of the i-th element in the sorted array
const ranks = new Array(values.length);
indices.forEach((originalIndex, sortedPos) => {
ranks[originalIndex] = sortedPos;
});
return ranks;
}
function getPercentile(index, metricType) {
if (!sortedRanks[metricType] || sortedRanks[metricType].length <= index) {
return 0;
}
// Calculate percentile (0 to 1) based on rank
const rank = sortedRanks[metricType][index];
const total = sortedRanks[metricType].length;
return rank / (total - 1); // Normalize to 0-1 range
}
function showTokenDetails(index) {
const data = questionDataCache;
if (!data || index >= (data.token_char_list?.length || 0)) {
return;
}
// Update active token styling
document.querySelectorAll('.token').forEach(token => token.classList.remove('active'));
const activeToken = document.querySelector(`.token[data-index="${index}"]`);
if (activeToken) {
activeToken.classList.add('active');
// Scroll the selection into view if needed
activeToken.scrollIntoView({
behavior: 'smooth',
block: 'nearest'
});
}
// Show the detail panel if hidden
detailPanel.classList.add('active');
// Update metrics
document.getElementById('probValue').textContent = data.prob[index].toFixed(4);
document.getElementById('probValue2').textContent = data.prob[index].toFixed(4);
document.getElementById('entropyValue').textContent = data.entropy[index].toFixed(4);
document.getElementById('entropyValue2').textContent = data.entropy[index].toFixed(4);
document.getElementById('auValue').textContent = data.au[index].toFixed(4);
document.getElementById('auValue2').textContent = data.au[index].toFixed(4);
document.getElementById('euValue').textContent = data.eu[index].toFixed(4);
document.getElementById('euValue2').textContent = data.eu[index].toFixed(4);
// Highlight the current token in all heatmaps
highlightHeatmapToken('probHeatmap', index, sortedRanks.prob, true);
highlightHeatmapToken('entropyHeatmap', index, sortedRanks.entropy, false);
highlightHeatmapToken('auHeatmap', index, sortedRanks.au, false);
highlightHeatmapToken('euHeatmap', index, sortedRanks.eu, false);
highlightHeatmapToken('currentHeatmap', index, sortedRanks[currentHeatmapType], currentHeatmapType === 'prob');
// Update logits table if data exists
const logitsTable = document.querySelector('#logitsTable tbody');
logitsTable.innerHTML = '';
if (data.Token_logit_dict && data.Token_logit_dict[index]) {
const logits = data.Token_logit_dict[index];
const topValues = logits.top_values || [];
const topIndices = logits.top_indices || [];
for (let i = 0; i < topValues.length; i++) {
const row = document.createElement('tr');
row.style.borderBottom = '1px solid #dee2e6';
const rankCell = document.createElement('td');
rankCell.textContent = i + 1;
rankCell.style.padding = '8px';
const idCell = document.createElement('td');
idCell.textContent = topIndices[i] || 'N/A';
idCell.style.padding = '8px';
const valueCell = document.createElement('td');
valueCell.textContent = topValues[i] ? topValues[i].toFixed(4) : 'N/A';
valueCell.style.padding = '8px';
row.appendChild(rankCell);
row.appendChild(idCell);
row.appendChild(valueCell);
logitsTable.appendChild(row);
}
}
}
function createPercentileHeatmap(containerId, values, ranks, reverseColor = false) {
const container = document.getElementById(containerId);
container.innerHTML = '';
if (!values || !ranks || values.length !== ranks.length) return;
for (let i = 0; i < values.length; i++) {
const percentile = ranks[i] / (ranks.length - 1); // 0 to 1
const color = getUncertaintyColor(percentile, reverseColor);
const value = values[i];
const bar = createHeatmapBar(value, percentile, color, i);
container.appendChild(bar);
}
}
function highlightHeatmapToken(containerId, index, ranks, reverseColor = false) {
const container = document.getElementById(containerId);
if (!container || !container.children[index]) return;
// Reset all bars first
Array.from(container.children).forEach(bar => {
bar.style.opacity = '1';
bar.style.border = 'none';
});
// Highlight the selected bar
const bar = container.children[index];
bar.style.opacity = '1';
bar.style.border = '2px solid var(--primary-color)';
bar.style.boxSizing = 'border-box';
// Scroll to make the bar visible if needed
bar.scrollIntoView({
behavior: 'smooth',
block: 'nearest',
inline: 'center'
});
}
function createHeatmapBar(value, percentile, color, index) {
const bar = document.createElement('div');
bar.className = 'heatmap-bar';
bar.style.width = '10px';
bar.style.height = '20px';
bar.style.backgroundColor = color;
bar.dataset.index = index;
const tooltip = document.createElement('div');
tooltip.className = 'heatmap-tooltip';
tooltip.textContent = `Token ${index}: ${value.toFixed(4)} (Top ${Math.round((1 - percentile) * 100)}%)`;
bar.appendChild(tooltip);
// Make bars clickable to select tokens
bar.addEventListener('click', function() {
showTokenDetails(index);
});
return bar;
}
function getUncertaintyColor(percentile, higherIsBetter = false) {
// If higher is better (like probability), invert the percentile
const effectivePercentile = higherIsBetter ? (1 - percentile) : percentile;
// Returns a color based on the percentile (0-1)
if (effectivePercentile < 0.33) return '#2ecc71'; // Green - low uncertainty
if (effectivePercentile < 0.66) return '#f39c12'; // Orange - medium uncertainty
return '#e74c3c'; // Red - high uncertainty
}
// Tab switching functionality
const tabs = document.querySelectorAll('.tab');
tabs.forEach(tab => {
tab.addEventListener('click', () => {
// Remove active class from all tabs and content
tabs.forEach(t => t.classList.remove('active'));
document.querySelectorAll('.tab-content').forEach(c => c.classList.remove('active'));
// Add active class to clicked tab and corresponding content
tab.classList.add('active');
const tabId = tab.dataset.tab + 'Tab';
document.getElementById(tabId).classList.add('active');
});
});
});
</script>
<p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: absolute; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">This website has been generated by <a href="https://enzostvs-deepsite.hf.space" style="color: #fff;" target="_blank" >DeepSite</a> <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;"></p></body>
</html>