document.addEventListener('DOMContentLoaded', async () => { await loadStats(); const biasForm = document.getElementById('biasForm'); biasForm.addEventListener('submit', async (e) => { e.preventDefault(); const data = { job: document.getElementById('job').value, years: document.getElementById('years').value, edu: document.getElementById('edu').value, skill: document.getElementById('skill').value }; const response = await fetch('/api/predict', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data) }); const result = await response.json(); const resultDiv = document.getElementById('predictionResult'); resultDiv.style.display = 'block'; if (result.decision === 1) { resultDiv.innerHTML = `SUGGESTED HIRE
Confidence: ${(result.probability * 100).toFixed(1)}%`; resultDiv.style.background = 'rgba(16, 185, 129, 0.1)'; } else { resultDiv.innerHTML = `REJECTION LIKELY
Confidence: ${((1 - result.probability) * 100).toFixed(1)}%`; resultDiv.style.background = 'rgba(239, 68, 68, 0.1)'; } }); }); async function loadStats() { try { const response = await fetch('/api/stats'); const data = await response.json(); // Update Header Stats document.getElementById('totalCandidates').innerText = data.overview.total_candidates.toLocaleString(); document.getElementById('aiApprovalRate').innerText = ((data.overview.ai_hired / data.overview.total_candidates) * 100).toFixed(1) + '%'; document.getElementById('humanApprovalRate').innerText = ((data.overview.human_hired / data.overview.total_candidates) * 100).toFixed(1) + '%'; document.getElementById('agreementRate').innerText = data.overview.agreement_rate.toFixed(1) + '%'; renderChart('genderChart', data.gender_bias.map(m => m.group), data.gender_bias.map(m => m.selection_rate), 'Selection Rate by Gender'); renderTable('genderTableBody', data.gender_bias); renderChart('raceChart', data.race_bias.map(m => m.group), data.race_bias.map(m => m.selection_rate), 'Selection Rate by Race'); renderTable('raceTableBody', data.race_bias); renderIntersectionalTable('intersectionalTableBody', data.intersectional); // Mitigation Button const mitigateBtn = document.getElementById('mitigateBtn'); mitigateBtn.addEventListener('click', async () => { mitigateBtn.innerText = 'Analyzing & Optimizing...'; mitigateBtn.disabled = true; const res = await fetch('/api/mitigate', { method: 'POST' }); const result = await res.json(); const statusDiv = document.getElementById('mitigationStatus'); statusDiv.style.display = 'block'; statusDiv.innerHTML = `
${result.status}
Strategy: ${result.strategy}
Result: ${result.improvement}
`; mitigateBtn.innerText = 'Mitigation Applied'; }); } catch (error) { console.error('Error loading stats:', error); } } function renderChart(id, labels, data, label) { const ctx = document.getElementById(id).getContext('2d'); new Chart(ctx, { type: 'bar', data: { labels: labels, datasets: [{ label: label, data: data, backgroundColor: 'rgba(99, 102, 241, 0.6)', borderColor: '#6366f1', borderWidth: 2, borderRadius: 5 }] }, options: { responsive: true, maintainAspectRatio: false, scales: { y: { beginAtZero: true, max: 1, grid: { color: 'rgba(255,255,255,0.05)' } }, x: { grid: { display: false } } }, plugins: { legend: { display: false } } } }); } function renderTable(bodyId, data) { const body = document.getElementById(bodyId); body.innerHTML = ''; data.forEach(item => { const di = item.disparate_impact; let status = 'Good'; let cls = 'impact-good'; if (di < 0.8) { status = 'Alert'; cls = 'impact-bad'; } else if (di < 0.9) { status = 'Warning'; cls = 'impact-warn'; } const row = ` ${item.group} ${(item.selection_rate * 100).toFixed(1)}% ${di.toFixed(2)} ${status} `; body.innerHTML += row; }); } function renderIntersectionalTable(bodyId, data) { const body = document.getElementById(bodyId); body.innerHTML = ''; data.sort((a, b) => b.rate - a.rate); data.forEach(item => { const row = ` ${item.group} ${(item.rate * 100).toFixed(1)}% `; body.innerHTML += row; }); }