AI-hiring / static /js /app.js
d-e-e-k-11's picture
Upload folder using huggingface_hub
c9f05a2 verified
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 = `<span style="color: #10b981; font-weight:700">SUGGESTED HIRE</span><br><small>Confidence: ${(result.probability * 100).toFixed(1)}%</small>`;
resultDiv.style.background = 'rgba(16, 185, 129, 0.1)';
} else {
resultDiv.innerHTML = `<span style="color: #ef4444; font-weight:700">REJECTION LIKELY</span><br><small>Confidence: ${((1 - result.probability) * 100).toFixed(1)}%</small>`;
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 = `
<div style="color: var(--success); font-weight:600">${result.status}</div>
<div style="color: var(--text-muted)">Strategy: ${result.strategy}</div>
<div style="color: var(--primary)">Result: ${result.improvement}</div>
`;
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 = `
<tr>
<td>${item.group}</td>
<td>${(item.selection_rate * 100).toFixed(1)}%</td>
<td>${di.toFixed(2)}</td>
<td><span class="impact-badge ${cls}">${status}</span></td>
</tr>
`;
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 = `
<tr>
<td style="font-size: 0.8rem">${item.group}</td>
<td>${(item.rate * 100).toFixed(1)}%</td>
</tr>
`;
body.innerHTML += row;
});
}