ahmedyradwan02's picture
feat: add contact email and update test dataset name
79b3b4a
Raw
History Blame Contribute Delete
16.3 kB
// ================================================================
// Theme toggle
// ================================================================
(function () {
var saved = localStorage.getItem('unbias-theme') || 'dark';
document.documentElement.setAttribute('data-theme', saved);
var MOON_ICON = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/></svg>';
var SUN_ICON = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="5"/><line x1="12" y1="1" x2="12" y2="3"/><line x1="12" y1="21" x2="12" y2="23"/><line x1="4.22" y1="4.22" x2="5.64" y2="5.64"/><line x1="18.36" y1="18.36" x2="19.78" y2="19.78"/><line x1="1" y1="12" x2="3" y2="12"/><line x1="21" y1="12" x2="23" y2="12"/><line x1="4.22" y1="19.78" x2="5.64" y2="18.36"/><line x1="18.36" y1="5.64" x2="19.78" y2="4.22"/></svg>';
function updateIcon(theme) {
var btn = document.getElementById('theme-toggle');
if (!btn) return;
btn.innerHTML = theme === 'dark' ? MOON_ICON : SUN_ICON;
btn.title = theme === 'dark' ? 'Switch to light theme' : 'Switch to dark theme';
}
window.toggleTheme = function () {
var current = document.documentElement.getAttribute('data-theme') || 'dark';
var next = current === 'dark' ? 'light' : 'dark';
document.documentElement.setAttribute('data-theme', next);
localStorage.setItem('unbias-theme', next);
updateIcon(next);
};
function init() { updateIcon(saved); }
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else { init(); }
})();
// ================================================================
// Tab switching
// ================================================================
window.showTab = function (tabId, btn) {
document.querySelectorAll('.tab-panel').forEach(function (p) { p.classList.remove('active'); });
document.getElementById(tabId).classList.add('active');
document.querySelectorAll('.tab-btn').forEach(function (b) { b.setAttribute('aria-selected', 'false'); });
btn.setAttribute('aria-selected', 'true');
};
// ================================================================
// Data (ported directly from app.py's MODELS list)
// ================================================================
var MODELS = [
{ name: "Qwen3-8B-UnBias-Plus-SFT-Instruct-V2", base: "Qwen3-8B", params: "8B", tag: "new", dataset: "UnBias-Plus (train_4)",
parse_rate: 98.6, bias_reduction_pct: 56.4, bias_reduction: 1.884, contextual_relevance: 4.023, global_rewrite_quality: 2.936,
rouge_l: 0.726, length_ratio: 0.937, latency_median: 5.711, correct_id_mean: 3.308, correct_id_median: 2.0,
unnecessary_rewrite_mean: 3.913, unnecessary_rewrite_median: 3.0, recall_at_words: 0.842, segment_replace_quality: 3.770,
hallucination_rate: 4.54, duplicate_rate: 0.22 },
{ name: "Qwen3-8B-UnBias-Plus-SFT-Instruct-V2 (D1)", base: "Qwen3-8B", params: "8B", tag: "new", dataset: "UnBias-Plus (train_4)",
parse_rate: 98.3, bias_reduction_pct: 55.7, bias_reduction: 1.868, contextual_relevance: 4.052, global_rewrite_quality: 2.960,
rouge_l: 0.718, length_ratio: 0.946, latency_median: 6.654, correct_id_mean: 3.447, correct_id_median: 2.0,
unnecessary_rewrite_mean: 3.965, unnecessary_rewrite_median: 3.0, recall_at_words: 0.872, segment_replace_quality: 3.751,
hallucination_rate: 3.51, duplicate_rate: 0.37 },
{ name: "Qwen3-8B-UnBias-Plus-SFT-Instruct-V2 (D2)", base: "Qwen3-8B", params: "8B", tag: "new", dataset: "UnBias-Plus (train_4)",
parse_rate: 94.3, bias_reduction_pct: 55.5, bias_reduction: 1.873, contextual_relevance: 4.018, global_rewrite_quality: 2.922,
rouge_l: 0.723, length_ratio: 0.983, latency_median: 5.577, correct_id_mean: 3.939, correct_id_median: 5.0,
unnecessary_rewrite_mean: 4.293, unnecessary_rewrite_median: 5.0, recall_at_words: 0.890, segment_replace_quality: 3.704,
hallucination_rate: 3.40, duplicate_rate: 0.85 },
{ name: "Qwen3-8B-UnBias-Plus-SFT-Instruct-V2 (D3)", base: "Qwen3-8B", params: "8B", tag: "new", dataset: "UnBias-Plus (train_4)",
parse_rate: 98.9, bias_reduction_pct: 57.0, bias_reduction: 1.897, contextual_relevance: 4.040, global_rewrite_quality: 2.960,
rouge_l: 0.715, length_ratio: 0.929, latency_median: 5.477, correct_id_mean: 3.663, correct_id_median: 5.0,
unnecessary_rewrite_mean: 4.105, unnecessary_rewrite_median: 5.0, recall_at_words: 0.898, segment_replace_quality: 3.793,
hallucination_rate: 3.77, duplicate_rate: 0.22 },
{ name: "Qwen3-8B-UnBias-Plus-SFT-Instruct-V2 (D4)", base: "Qwen3-8B", params: "8B", tag: "new", dataset: "UnBias-Plus (train_4)",
parse_rate: 99.4, bias_reduction_pct: 54.3, bias_reduction: 1.851, contextual_relevance: 3.977, global_rewrite_quality: 2.891,
rouge_l: 0.717, length_ratio: 0.930, latency_median: 5.956, correct_id_mean: 3.543, correct_id_median: 5.0,
unnecessary_rewrite_mean: 4.064, unnecessary_rewrite_median: 5.0, recall_at_words: 0.907, segment_replace_quality: 3.687,
hallucination_rate: 2.92, duplicate_rate: 0.0 },
{ name: "Qwen3-4B-UnBias-Plus-SFT-Instruct-V2 (D3)", base: "Qwen3-4B", params: "4B", tag: "new", dataset: "UnBias-Plus (train_4)",
parse_rate: 98.3, bias_reduction_pct: 56.2, bias_reduction: 1.878, contextual_relevance: 4.029, global_rewrite_quality: 2.936,
rouge_l: 0.695, length_ratio: 0.931, latency_median: 6.325, correct_id_mean: 3.006, correct_id_median: 2.0,
unnecessary_rewrite_mean: 3.680, unnecessary_rewrite_median: 3.0, recall_at_words: 0.872, segment_replace_quality: 3.705,
hallucination_rate: 4.38, duplicate_rate: 0.19 },
{ name: "Qwen3-4B-UnBias-Plus-SFT-Instruct-ORPO", base: "Qwen3-4B", params: "4B", tag: "new", dataset: "UnBias-Plus (train_4)",
parse_rate: 80.9, bias_reduction_pct: 52.7, bias_reduction: 1.898, contextual_relevance: 4.020, global_rewrite_quality: 2.925,
rouge_l: 0.629, length_ratio: 0.938, latency_median: 8.046, correct_id_mean: 2.007, correct_id_median: 2.0,
unnecessary_rewrite_mean: 2.985, unnecessary_rewrite_median: 3.0, recall_at_words: 0.476, segment_replace_quality: 3.759,
hallucination_rate: 5.36, duplicate_rate: 0.0 },
{ name: "Qwen3-8B-UnBias-Plus-SFT-Instruct", base: "Qwen3-8B", params: "8B", tag: "new", dataset: "UnBias-Plus (train_3)",
parse_rate: 100.0, bias_reduction_pct: 53.1, bias_reduction: 1.811, contextual_relevance: 4.074, global_rewrite_quality: 3.200,
rouge_l: 0.635, length_ratio: 1.294, latency_median: 22.2, correct_id_mean: 2.451, correct_id_median: 2.0,
unnecessary_rewrite_mean: 3.309, unnecessary_rewrite_median: 3.0, recall_at_words: 0.900, segment_replace_quality: 3.823,
hallucination_rate: 8.5, duplicate_rate: 4.4 },
{ name: "Qwen3.5-4B-UnBias-Plus-SFT-Instruct", base: "Qwen3.5-4B", params: "4B", tag: "new", dataset: "UnBias-Plus (train_3)",
parse_rate: 99.1, bias_reduction_pct: 57.5, bias_reduction: 1.908, contextual_relevance: 4.087, global_rewrite_quality: 3.145,
rouge_l: 0.709, length_ratio: 1.001, latency_median: 19.8, correct_id_mean: 3.443, correct_id_median: 2.0,
unnecessary_rewrite_mean: 3.966, unnecessary_rewrite_median: 3.0, recall_at_words: 0.847, segment_replace_quality: 3.878,
hallucination_rate: 5.3, duplicate_rate: 0.0 },
{ name: "Qwen3-8B-UnBias-Plus-SFT-Instruct (Legacy)", base: "Qwen3-8B", params: "8B", tag: "legacy", dataset: "UnBias-Plus (train_1)",
parse_rate: 99.4, bias_reduction_pct: 60.6, bias_reduction: 1.943, contextual_relevance: 4.178, global_rewrite_quality: 3.080,
rouge_l: 0.722, length_ratio: 0.993, latency_median: 27.4, correct_id_mean: 4.155, correct_id_median: 5.0,
unnecessary_rewrite_mean: 4.437, unnecessary_rewrite_median: 5.0, recall_at_words: 0.714, segment_replace_quality: 3.576,
hallucination_rate: 3.6, duplicate_rate: 0.7 },
];
// ================================================================
// Formatting helpers (ported from formatting.py; N/A instead of the
// original's em-dash fallback)
// ================================================================
function formatScore(value, decimals) {
if (decimals === undefined) decimals = 2;
if (value === null || value === undefined) return "N/A";
return value.toFixed(decimals);
}
function formatPercentage(value, decimals) {
if (decimals === undefined) decimals = 1;
if (value === null || value === undefined) return "N/A";
return value.toFixed(decimals) + "%";
}
// ================================================================
// Table helpers (ported from app.py)
// ================================================================
function modelCell(m) {
var tagCls = m.tag === "new" ? "pill-new" : "pill-legacy";
var tagTxt = m.tag === "new" ? "new" : "legacy";
// Not a clickable link on purpose -- these were internal cluster
// paths, not public URLs, and linking them exposed the filesystem.
return '<span class="model-name">' + m.name + '</span>' +
'<div class="model-sub"><span class="pill ' + tagCls + '">' + tagTxt + '</span>&nbsp;' +
m.base + ' &middot; ' + m.params + ' &middot; ' + m.dataset + '</div>';
}
function bestCls(vals, idx, lowerIsBetter) {
var best = lowerIsBetter ? Math.min.apply(null, vals) : Math.max.apply(null, vals);
var worst = lowerIsBetter ? Math.max.apply(null, vals) : Math.min.apply(null, vals);
if (vals[idx] === best) return "val-best";
if (vals[idx] === worst) return "val-low";
return "val-mid";
}
function td(val, cls) {
cls = cls || "val-mid";
return '<td class="right"><span class="' + cls + '">' + val + '</span></td>';
}
function tdModel(m) { return '<td>' + modelCell(m) + '</td>'; }
// ================================================================
// Tables (ported directly from app.py)
// ================================================================
function overallTable() {
var parseVals = MODELS.map(function (m) { return m.parse_rate; });
var biasVals = MODELS.map(function (m) { return m.bias_reduction_pct; });
var relVals = MODELS.map(function (m) { return m.contextual_relevance; });
var cidVals = MODELS.map(function (m) { return m.correct_id_median; });
var segVals = MODELS.map(function (m) { return m.segment_replace_quality; });
var latVals = MODELS.map(function (m) { return m.latency_median; });
var rows = "";
MODELS.forEach(function (m, i) {
rows += "<tr>" + tdModel(m) +
td(formatPercentage(m.parse_rate), bestCls(parseVals, i)) +
td(formatPercentage(m.bias_reduction_pct), bestCls(biasVals, i)) +
td(formatScore(m.contextual_relevance), bestCls(relVals, i)) +
td(formatScore(m.correct_id_median, 1), bestCls(cidVals, i)) +
td(formatScore(m.segment_replace_quality), bestCls(segVals, i)) +
td(m.latency_median + "s", bestCls(latVals, i, true)) +
"</tr>";
});
return '<div class="lb-table-wrap"><table class="lb-table"><thead><tr>' +
'<th>Model</th><th class="right">Parse rate</th><th class="right">Bias reduction</th><th class="right">Relevance</th>' +
'<th class="right">Correct ID (med)</th><th class="right">Seg. replacement</th><th class="right">Latency (med)</th>' +
'</tr></thead><tbody>' + rows + '</tbody></table></div>' +
'<p class="table-note">All judge scores 0-5. Green = best in column, red = lowest.</p>';
}
function biasedTable() {
var biasVals = MODELS.map(function (m) { return m.bias_reduction_pct; });
var biasRawVals = MODELS.map(function (m) { return m.bias_reduction; });
var relVals = MODELS.map(function (m) { return m.contextual_relevance; });
var grqVals = MODELS.map(function (m) { return m.global_rewrite_quality; });
var rlVals = MODELS.map(function (m) { return m.rouge_l; });
var lrVals = MODELS.map(function (m) { return Math.abs(m.length_ratio - 1.0); });
var latVals = MODELS.map(function (m) { return m.latency_median; });
var rows = "";
MODELS.forEach(function (m, i) {
var lrCls = m.length_ratio > 1.2 ? "val-warn" : bestCls(lrVals, i, true);
rows += "<tr>" + tdModel(m) +
td(formatPercentage(m.bias_reduction_pct), bestCls(biasVals, i)) +
td(formatScore(m.bias_reduction), bestCls(biasRawVals, i)) +
td(formatScore(m.contextual_relevance), bestCls(relVals, i)) +
td(formatScore(m.global_rewrite_quality), bestCls(grqVals, i)) +
td(formatScore(m.rouge_l), bestCls(rlVals, i)) +
td(formatScore(m.length_ratio), lrCls) +
td(m.latency_median + "s", bestCls(latVals, i, true)) +
"</tr>";
});
return '<div class="lb-table-wrap"><table class="lb-table"><thead><tr>' +
'<th>Model</th><th class="right">Bias red. %</th><th class="right">Bias red. (mean)</th>' +
'<th class="right">Relevance</th><th class="right">Global rewrite</th><th class="right">ROUGE-L</th>' +
'<th class="right">Length ratio</th><th class="right">Latency (med)</th>' +
'</tr></thead><tbody>' + rows + '</tbody></table></div>' +
'<p class="table-note">Length ratio: ideal value is 1.0. Values above 1.2 flagged in orange.</p>';
}
function unbiasedTable() {
var ciVals = MODELS.map(function (m) { return m.correct_id_median; });
var urVals = MODELS.map(function (m) { return m.unnecessary_rewrite_median; });
var ciMeanVals = MODELS.map(function (m) { return m.correct_id_mean; });
var urMeanVals = MODELS.map(function (m) { return m.unnecessary_rewrite_mean; });
var rows = "";
MODELS.forEach(function (m, i) {
rows += "<tr>" + tdModel(m) +
td(formatScore(m.correct_id_mean), bestCls(ciMeanVals, i)) +
td(formatScore(m.correct_id_median, 1), bestCls(ciVals, i)) +
td(formatScore(m.unnecessary_rewrite_mean), bestCls(urMeanVals, i)) +
td(formatScore(m.unnecessary_rewrite_median, 1), bestCls(urVals, i)) +
"</tr>";
});
return '<div class="lb-table-wrap"><table class="lb-table"><thead><tr>' +
'<th>Model</th><th class="right">Correct ID (mean)</th><th class="right">Correct ID (median)</th>' +
'<th class="right">Unnec. rewrite (mean)</th><th class="right">Unnec. rewrite (median)</th>' +
'</tr></thead><tbody>' + rows + '</tbody></table></div>' +
'<p class="table-note">Score of 5.0 = model correctly preserved unbiased text unchanged. Score of 2.0 = model rewrote or mislabeled unbiased text as biased.</p>';
}
function segmentTable() {
var recVals = MODELS.map(function (m) { return m.recall_at_words; });
var srqVals = MODELS.map(function (m) { return m.segment_replace_quality; });
var halVals = MODELS.map(function (m) { return m.hallucination_rate; });
var dupVals = MODELS.map(function (m) { return m.duplicate_rate; });
var rows = "";
MODELS.forEach(function (m, i) {
rows += "<tr>" + tdModel(m) +
td(formatScore(m.recall_at_words), bestCls(recVals, i)) +
td(formatScore(m.segment_replace_quality), bestCls(srqVals, i)) +
td(formatPercentage(m.hallucination_rate), bestCls(halVals, i, true)) +
td(formatPercentage(m.duplicate_rate), bestCls(dupVals, i, true)) +
"</tr>";
});
return '<div class="lb-table-wrap"><table class="lb-table"><thead><tr>' +
'<th>Model</th><th class="right">Recall at words</th><th class="right">Seg. replacement quality</th>' +
'<th class="right">Hallucination rate</th><th class="right">Duplicate rate</th>' +
'</tr></thead><tbody>' + rows + '</tbody></table></div>' +
'<p class="table-note">Recall at words: % of ground-truth biased words covered by at least one model segment. Lower is better for hallucination and duplicate rates.</p>';
}
// ================================================================
// Render everything once the DOM is ready
// ================================================================
function render() {
document.getElementById("overall-table-container").innerHTML = overallTable();
document.getElementById("biased-table-container").innerHTML = biasedTable();
document.getElementById("unbiased-table-container").innerHTML = unbiasedTable();
document.getElementById("segment-table-container").innerHTML = segmentTable();
}
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", render);
} else {
render();
}