Spaces:
Sleeping
Sleeping
| // ββ 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 = `<video id="previewThumb" src="${url}" muted></video>`; | |
| } else { | |
| if (previewThumb.tagName !== 'IMG') { | |
| document.getElementById('previewThumb').outerHTML = `<img id="previewThumb" src="${url}" />`; | |
| } 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 = '<div class="empty-state">No scans yet β run a detection to see results here.</div>'; | |
| } else { | |
| list.innerHTML = data.history.map(h => ` | |
| <div class="history-row"> | |
| <span class="name">${h.name}</span> | |
| <span class="badge ${h.verdict.toLowerCase()}">${h.verdict} Β· ${h.confidence}%</span> | |
| </div> | |
| `).join(''); | |
| } | |
| } catch (err) { | |
| console.error('Failed to load stats', err); | |
| } | |
| } | |