// ── Tab switching ───────────────────────────────────────────────── const tabBtns = document.querySelectorAll('.tab-btn'); const sections = document.querySelectorAll('section'); function showTab(name) { sections.forEach(s => s.classList.toggle('active', s.id === name)); tabBtns.forEach(b => b.classList.toggle('active', b.dataset.tab === name && !b.classList.contains('btn-launch'))); if (name === 'dashboard') refreshStats(); window.scrollTo({ top: 0, behavior: 'smooth' }); } tabBtns.forEach(btn => { btn.addEventListener('click', () => showTab(btn.dataset.tab)); }); // ── Upload handling ────────────────────────────────────────────── const uploadZone = document.getElementById('uploadZone'); const fileInput = document.getElementById('fileInput'); const previewRow = document.getElementById('previewRow'); const previewThumb = document.getElementById('previewThumb'); const previewName = document.getElementById('previewName'); const previewSize = document.getElementById('previewSize'); const clearBtn = document.getElementById('clearBtn'); const scanBtn = document.getElementById('scanBtn'); const verdictCard = document.getElementById('verdictCard'); let selectedFile = null; uploadZone.addEventListener('click', () => fileInput.click()); uploadZone.addEventListener('dragover', e => { e.preventDefault(); uploadZone.classList.add('dragover'); }); uploadZone.addEventListener('dragleave', () => uploadZone.classList.remove('dragover')); uploadZone.addEventListener('drop', e => { e.preventDefault(); uploadZone.classList.remove('dragover'); if (e.dataTransfer.files.length) handleFile(e.dataTransfer.files[0]); }); fileInput.addEventListener('change', () => { if (fileInput.files.length) handleFile(fileInput.files[0]); }); function handleFile(file) { selectedFile = file; previewName.textContent = file.name; previewSize.textContent = `${(file.size / (1024 * 1024)).toFixed(2)} MB · ${file.type.startsWith('video') ? 'Video' : 'Image'}`; const url = URL.createObjectURL(file); if (file.type.startsWith('video')) { previewThumb.outerHTML = ``; } else { if (previewThumb.tagName !== 'IMG') { document.getElementById('previewThumb').outerHTML = ``; } else { previewThumb.src = url; } } previewRow.style.display = 'flex'; scanBtn.disabled = false; verdictCard.classList.remove('show'); } clearBtn.addEventListener('click', () => { selectedFile = null; fileInput.value = ''; previewRow.style.display = 'none'; scanBtn.disabled = true; verdictCard.classList.remove('show'); }); // ── Run scan ───────────────────────────────────────────────────── scanBtn.addEventListener('click', async () => { if (!selectedFile) return; scanBtn.disabled = true; scanBtn.textContent = 'Scanning…'; const formData = new FormData(); formData.append('file', selectedFile); formData.append('sample_rate', document.getElementById('rateSelect').value); try { const res = await fetch('/api/analyze', { method: 'POST', body: formData }); const data = await res.json(); if (data.error) { alert(data.error); } else { renderVerdict(data); } } catch (err) { alert('Something went wrong while analyzing the file.'); console.error(err); } finally { scanBtn.disabled = false; scanBtn.textContent = 'Start Scan'; } }); function renderVerdict(data) { const isFake = data.verdict === 'FAKE'; const accent = isFake ? 'var(--red)' : 'var(--green)'; document.getElementById('verdictIcon').textContent = isFake ? '⚠' : '✓'; document.getElementById('verdictIcon').style.background = isFake ? 'rgba(244,63,94,0.14)' : 'rgba(52,211,153,0.14)'; document.getElementById('verdictIcon').style.color = accent; document.getElementById('verdictLabel').textContent = data.verdict; document.getElementById('verdictLabel').style.color = accent; document.getElementById('verdictConf').textContent = `${data.confidence}% confidence`; document.getElementById('fakeVal').textContent = `${data.fake_pct}%`; document.getElementById('realVal').textContent = `${data.real_pct}%`; document.getElementById('fakeBar').style.width = `${data.fake_pct}%`; document.getElementById('realBar').style.width = `${data.real_pct}%`; document.getElementById('metaType').textContent = data.file_type === 'video' ? '🎥 Video' : '🖼️ Image'; document.getElementById('metaElapsed').textContent = `${data.elapsed}s`; document.getElementById('metaFrames').textContent = data.frames; verdictCard.classList.add('show'); verdictCard.scrollIntoView({ behavior: 'smooth', block: 'nearest' }); } // ── Dashboard ──────────────────────────────────────────────────── async function refreshStats() { try { const res = await fetch('/api/stats'); const data = await res.json(); document.getElementById('statTotal').textContent = data.total_scans; document.getElementById('statFakes').textContent = data.fakes_detected; document.getElementById('statReal').textContent = data.authentic; document.getElementById('statAcc').textContent = `${data.model_accuracy}%`; document.getElementById('legendReal').textContent = data.authentic; document.getElementById('legendFake').textContent = data.fakes_detected; document.getElementById('donutPct').textContent = `${data.fake_rate}%`; const circumference = 2 * Math.PI * 70; // ~440 const fakeLen = (data.fake_rate / 100) * circumference; document.getElementById('donutFake').setAttribute('stroke-dasharray', `${fakeLen} ${circumference}`); const list = document.getElementById('historyList'); if (!data.history.length) { list.innerHTML = '
No scans yet — run a detection to see results here.
'; } else { list.innerHTML = data.history.map(h => `
${h.name} ${h.verdict} · ${h.confidence}%
`).join(''); } } catch (err) { console.error('Failed to load stats', err); } }