RealvsScreen / static /script.js
anakvyas's picture
Deploy: app, model, and frontend only (excludes training dataset)
e63d782
Raw
History Blame Contribute Delete
4.86 kB
const dropzone = document.getElementById('dropzone');
const fileInput = document.getElementById('fileInput');
const scanStage = document.getElementById('scanStage');
const previewImg = document.getElementById('previewImg');
const scanLabel = document.getElementById('scanLabel');
const rescanBtn = document.getElementById('rescanBtn');
const result = document.getElementById('result');
const errorBox = document.getElementById('errorBox');
const verdictIcon = document.getElementById('verdictIcon');
const verdictLabel = document.getElementById('verdictLabel');
const verdictSub = document.getElementById('verdictSub');
const realPct = document.getElementById('realPct');
const screenPct = document.getElementById('screenPct');
const meterFillReal = document.getElementById('meterFillReal');
const meterFillScreen = document.getElementById('meterFillScreen');
const MIN_SCAN_MS = 1700;
const SCAN_MESSAGES = ['Reading pixels…', 'Checking bezel shadows…', 'Measuring color temperature…', 'Scoring saturation profile…'];
dropzone.addEventListener('click', () => fileInput.click());
dropzone.addEventListener('dragover', (e) => { e.preventDefault(); dropzone.classList.add('drag-over'); });
dropzone.addEventListener('dragleave', () => dropzone.classList.remove('drag-over'));
dropzone.addEventListener('drop', (e) => {
e.preventDefault();
dropzone.classList.remove('drag-over');
if (e.dataTransfer.files.length) handleFile(e.dataTransfer.files[0]);
});
fileInput.addEventListener('change', () => {
if (fileInput.files.length) handleFile(fileInput.files[0]);
});
rescanBtn.addEventListener('click', resetUI);
function resetUI() {
fileInput.value = '';
dropzone.classList.remove('hidden');
scanStage.classList.add('hidden');
scanStage.classList.remove('scanning');
rescanBtn.classList.add('hidden');
result.classList.add('hidden');
errorBox.classList.add('hidden');
meterFillReal.style.width = '0%';
meterFillScreen.style.width = '0%';
}
function handleFile(file) {
if (!file.type.startsWith('image/')) {
showError('That file does not look like an image.');
return;
}
const url = URL.createObjectURL(file);
previewImg.src = url;
dropzone.classList.add('hidden');
scanStage.classList.remove('hidden');
scanStage.classList.add('scanning');
rescanBtn.classList.add('hidden');
result.classList.add('hidden');
errorBox.classList.add('hidden');
let msgIdx = 0;
scanLabel.textContent = SCAN_MESSAGES[0];
const msgTimer = setInterval(() => {
msgIdx = (msgIdx + 1) % SCAN_MESSAGES.length;
scanLabel.textContent = SCAN_MESSAGES[msgIdx];
}, 600);
const started = Date.now();
const formData = new FormData();
formData.append('file', file);
fetch('/api/predict', { method: 'POST', body: formData })
.then(async (res) => {
const body = await res.json().catch(() => ({}));
if (!res.ok) throw new Error(body.detail || 'Prediction failed.');
return body;
})
.then((data) => {
const elapsed = Date.now() - started;
const wait = Math.max(0, MIN_SCAN_MS - elapsed);
setTimeout(() => {
clearInterval(msgTimer);
finishScan();
showResult(data);
}, wait);
})
.catch((err) => {
clearInterval(msgTimer);
const elapsed = Date.now() - started;
const wait = Math.max(0, 600 - elapsed);
setTimeout(() => {
finishScan();
showError(err.message || 'Something went wrong while analyzing the image.');
}, wait);
});
}
function finishScan() {
scanStage.classList.remove('scanning');
rescanBtn.classList.remove('hidden');
}
function showResult(data) {
result.classList.remove('hidden');
const isScreen = data.label === 'screen_recapture';
verdictIcon.className = 'verdict-icon ' + (isScreen ? 'screen' : 'real');
verdictIcon.textContent = isScreen ? '⚠' : '✓';
verdictLabel.className = 'verdict-label ' + (isScreen ? 'screen' : 'real');
verdictLabel.textContent = isScreen ? 'Screen Recapture' : 'Real Photo';
verdictSub.textContent = `${data.confidence}% confidence`;
realPct.textContent = `${data.real_pct}%`;
screenPct.textContent = `${data.screen_pct}%`;
requestAnimationFrame(() => {
meterFillReal.style.width = `${data.real_pct}%`;
meterFillScreen.style.width = `${data.screen_pct}%`;
});
}
function showError(message) {
result.classList.remove('hidden');
errorBox.textContent = message;
errorBox.classList.remove('hidden');
verdictIcon.className = 'verdict-icon screen';
verdictIcon.textContent = '!';
verdictLabel.className = 'verdict-label screen';
verdictLabel.textContent = 'Could not analyze image';
verdictSub.textContent = '';
realPct.textContent = '0%';
screenPct.textContent = '0%';
meterFillReal.style.width = '0%';
meterFillScreen.style.width = '0%';
}