document.addEventListener('DOMContentLoaded', () => {
const configSelect = document.getElementById('config-select');
const tbody = document.getElementById('metrics-tbody');
const tfoot = document.getElementById('metrics-tfoot');
const instancesList = document.getElementById('instances-list');
const instancesTitle = document.getElementById('instances-title');
let currentConfig = null;
let selectedCell = null;
// Initialize
fetchConfigs();
configSelect.addEventListener('change', (e) => {
currentConfig = e.target.value;
loadMetrics(currentConfig);
clearInstances();
});
async function fetchConfigs() {
try {
const res = await fetch('/api/configs');
const data = await res.json();
configSelect.innerHTML = '';
if (data.configs.length === 0) {
const opt = document.createElement('option');
opt.text = 'Aucune configuration trouvée';
opt.disabled = true;
configSelect.appendChild(opt);
return;
}
data.configs.forEach((conf, idx) => {
const opt = document.createElement('option');
opt.value = conf;
opt.text = conf;
if (idx === 0) {
opt.selected = true;
currentConfig = conf;
}
configSelect.appendChild(opt);
});
if (currentConfig) {
loadMetrics(currentConfig);
}
} catch (err) {
console.error('Failed to fetch configs', err);
configSelect.innerHTML = '';
}
}
async function loadMetrics(configName) {
try {
const res = await fetch(`/api/configs/${encodeURIComponent(configName)}/metrics`);
const data = await res.json();
renderTable(data.metrics, data.macro_f1);
} catch (err) {
console.error('Failed to load metrics', err);
tbody.innerHTML = '
| Erreur lors du chargement des données. |
';
}
}
function getMetricColor(value) {
if (value >= 0.8) return 'var(--metric-good)';
if (value >= 0.5) return 'var(--metric-ok)';
return 'var(--metric-bad)';
}
function renderTable(metrics, macroF1) {
tbody.innerHTML = '';
metrics.forEach(m => {
const tr = document.createElement('tr');
const f1Color = getMetricColor(m.f1);
const precColor = getMetricColor(m.precision);
const recColor = getMetricColor(m.recall);
tr.innerHTML = `
${escapeHtml(m.display_name)} |
${m.f1.toFixed(3)} |
${m.precision.toFixed(3)} |
${m.recall.toFixed(3)} |
${m.fn} |
${m.fp} |
${m.tn} |
${m.tp} |
`;
tbody.appendChild(tr);
});
const macroColor = getMetricColor(macroF1);
tfoot.innerHTML = `
| Macro avg |
${macroF1.toFixed(3)} |
|
|
|
|
|
|
`;
// Attach event listeners to clickable cells
const clickableCells = tbody.querySelectorAll('.cell-clickable');
clickableCells.forEach(cell => {
cell.addEventListener('click', onCellClick);
});
}
async function onCellClick(e) {
if (!currentConfig) return;
const cell = e.currentTarget;
const label = cell.getAttribute('data-label');
const outcome = cell.getAttribute('data-outcome');
// Manage selection state
if (selectedCell) {
selectedCell.classList.remove('cell-selected');
}
selectedCell = cell;
selectedCell.classList.add('cell-selected');
try {
const res = await fetch(`/api/configs/${encodeURIComponent(currentConfig)}/instances?label=${encodeURIComponent(label)}&outcome=${encodeURIComponent(outcome)}`);
const data = await res.json();
instancesTitle.textContent = data.title;
instancesList.innerHTML = '';
if (data.texts && data.texts.length > 0) {
data.texts.forEach(text => {
const div = document.createElement('div');
div.className = 'instance-item';
div.textContent = text;
instancesList.appendChild(div);
});
} else {
instancesList.innerHTML = 'Aucune phrase à afficher.
';
}
} catch (err) {
console.error('Failed to load instances', err);
instancesTitle.textContent = "Erreur de chargement";
instancesList.innerHTML = 'Impossible de charger les instances.
';
}
}
function clearInstances() {
instancesTitle.textContent = "Cliquez sur une cellule pour voir les instances";
instancesList.innerHTML = 'Aucune phrase à afficher.
';
if (selectedCell) {
selectedCell.classList.remove('cell-selected');
selectedCell = null;
}
}
function escapeHtml(unsafe) {
return (unsafe || '').toString()
.replace(/&/g, "&")
.replace(//g, ">")
.replace(/"/g, """)
.replace(/'/g, "'");
}
});