SadraCoding's picture
Upload index.html
64489ad verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Deepfake Detector</title>
<link href="https://fonts.googleapis.com/css2?family=Quicksand:wght@300;400;500;600;700&display=swap" rel="stylesheet">
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Quicksand', sans-serif;
}
body {
min-height: 100vh;
background: linear-gradient(135deg, #fce4ec 0%, #f8bbd0 25%, #e1bee7 50%, #f8bbd0 75%, #fce4ec 100%);
background-size: 400% 400%;
animation: bgFloat 15s ease infinite;
display: flex;
justify-content: center;
align-items: center;
padding: 20px;
}
@keyframes bgFloat {
0% { background-position: 0% 50%; }
50% { background-position: 100% 50%; }
100% { background-position: 0% 50%; }
}
.container {
background: rgba(255, 255, 255, 0.85);
backdrop-filter: blur(15px);
border: 3px solid #ffb6c1;
border-radius: 30px;
box-shadow: 0 10px 40px rgba(255, 182, 193, 0.4), 0 0 60px rgba(255, 192, 203, 0.2);
padding: 40px;
max-width: 850px;
width: 100%;
animation: fadeInUp 0.8s ease;
}
@keyframes fadeInUp {
from {
opacity: 0;
transform: translateY(30px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
h1 {
font-size: 2.5em;
font-weight: 700;
text-align: center;
background: linear-gradient(45deg, #ff69b4, #e91e63, #ff1493);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
margin-bottom: 15px;
letter-spacing: 1px;
}
.description {
color: #ad1457;
font-size: 1.1em;
font-weight: 400;
text-align: center;
background: rgba(255, 228, 235, 0.5);
border-radius: 20px;
padding: 18px;
border-left: 4px solid #ff69b4;
line-height: 1.8;
margin-bottom: 30px;
}
.upload-area {
background: rgba(255, 228, 235, 0.6);
border: 3px dashed #ffb6c1;
border-radius: 20px;
padding: 40px;
text-align: center;
cursor: pointer;
transition: all 0.4s ease;
margin-bottom: 25px;
position: relative;
}
.upload-area:hover {
background: rgba(255, 192, 203, 0.5);
border-color: #ff69b4;
box-shadow: 0 5px 25px rgba(255, 105, 180, 0.3);
transform: translateY(-3px);
}
.upload-area.dragover {
background: rgba(255, 192, 203, 0.7);
border-color: #ff1493;
box-shadow: 0 8px 35px rgba(255, 20, 147, 0.4);
}
.upload-icon {
font-size: 4em;
margin-bottom: 10px;
}
.upload-text {
color: #d81b60;
font-size: 1.2em;
font-weight: 600;
}
.upload-subtext {
color: #c2185b;
font-size: 0.9em;
margin-top: 5px;
font-weight: 400;
}
#fileInput {
display: none;
}
.preview-container {
display: none;
text-align: center;
margin-bottom: 25px;
animation: fadeInUp 0.5s ease;
}
.preview-container.show {
display: block;
}
#previewImage {
max-width: 100%;
max-height: 400px;
border: 4px solid #ffb6c1;
border-radius: 20px;
box-shadow: 0 8px 25px rgba(255, 105, 180, 0.3);
transition: all 0.4s ease;
}
#previewImage:hover {
border-color: #ff69b4;
box-shadow: 0 12px 35px rgba(255, 20, 147, 0.5);
transform: scale(1.02);
}
.btn {
display: block;
width: 100%;
background: linear-gradient(45deg, #ffb6c1, #ff69b4, #ff1493);
border: none;
color: white;
font-weight: 700;
font-size: 1.2em;
border-radius: 50px;
padding: 16px 40px;
letter-spacing: 1px;
box-shadow: 0 8px 25px rgba(255, 105, 180, 0.5);
transition: all 0.3s ease;
cursor: pointer;
text-transform: uppercase;
margin-bottom: 20px;
}
.btn:hover {
background: linear-gradient(45deg, #ff69b4, #ff1493, #c2185b);
box-shadow: 0 12px 35px rgba(255, 20, 147, 0.6);
transform: translateY(-4px) scale(1.02);
}
.btn:active {
transform: translateY(-1px) scale(0.98);
}
.btn:disabled {
opacity: 0.5;
cursor: not-allowed;
transform: none;
}
.result-container {
display: none;
background: linear-gradient(135deg, rgba(255, 182, 193, 0.15), rgba(255, 192, 203, 0.1));
border: 2px solid #ffb6c1;
border-radius: 25px;
padding: 25px;
text-align: center;
box-shadow: 0 5px 20px rgba(255, 182, 193, 0.3);
animation: fadeInUp 0.6s ease;
}
.result-container.show {
display: block;
}
.result-label {
color: #c2185b;
font-size: 1em;
font-weight: 500;
margin-bottom: 10px;
letter-spacing: 1px;
}
.result-value {
color: #c2185b;
font-size: 1.8em;
font-weight: 700;
letter-spacing: 1px;
text-transform: uppercase;
}
.examples {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(80px, 1fr));
gap: 10px;
margin-top: 25px;
padding: 15px;
background: rgba(255, 228, 235, 0.3);
border-radius: 20px;
}
.example-img {
width: 100%;
aspect-ratio: 1;
object-fit: cover;
border: 3px solid #ffb6c1;
border-radius: 15px;
cursor: pointer;
transition: all 0.3s ease;
}
.example-img:hover {
border-color: #ff69b4;
box-shadow: 0 5px 20px rgba(255, 105, 180, 0.4);
transform: scale(1.1);
}
.example-label {
color: #c2185b;
font-size: 0.8em;
text-align: center;
font-weight: 500;
margin-top: 5px;
}
.spinner {
display: inline-block;
width: 20px;
height: 20px;
border: 3px solid rgba(255, 255, 255, 0.3);
border-radius: 50%;
border-top-color: #fff;
animation: spin 0.8s linear infinite;
margin-right: 10px;
vertical-align: middle;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
.error-message {
color: #d32f2f;
background: rgba(211, 47, 47, 0.1);
border: 1px solid #d32f2f;
border-radius: 15px;
padding: 15px;
text-align: center;
margin-top: 15px;
display: none;
animation: fadeInUp 0.4s ease;
}
.error-message.show {
display: block;
}
footer {
color: #e91e63;
text-align: center;
font-size: 0.9em;
opacity: 0.8;
font-weight: 300;
margin-top: 25px;
}
</style>
</head>
<body>
<div class="container">
<h1>Deepfake Detector</h1>
<p class="description">Upload a face image to check if it's real or AI-generated. Your privacy is safe with us.</p>
<div class="upload-area" id="uploadArea">
<div class="upload-icon">📸</div>
<div class="upload-text">Click or drag your image here</div>
<div class="upload-subtext">Supports JPG, PNG, WEBP</div>
</div>
<input type="file" id="fileInput" accept="image/*">
<div class="preview-container" id="previewContainer">
<img id="previewImage" src="" alt="Preview">
</div>
<button class="btn" id="detectBtn" disabled>
<span id="btnText">Scan Image</span>
</button>
<div class="result-container" id="resultContainer">
<div class="result-label">Scan Result</div>
<div class="result-value" id="resultValue"></div>
</div>
<div class="error-message" id="errorMessage"></div>
<div class="examples">
<div>
<img class="example-img" src="https://via.placeholder.com/80/ffb6c1/ffffff?text=Fake1" alt="Example fake 1" onclick="loadExample('example_fake1.jpg')">
<div class="example-label">Fake</div>
</div>
<div>
<img class="example-img" src="https://via.placeholder.com/80/ffb6c1/ffffff?text=Fake2" alt="Example fake 2" onclick="loadExample('example_fake2.jpg')">
<div class="example-label">Fake</div>
</div>
<div>
<img class="example-img" src="https://via.placeholder.com/80/ffb6c1/ffffff?text=Fake3" alt="Example fake 3" onclick="loadExample('example_fake3.jpg')">
<div class="example-label">Fake</div>
</div>
<div>
<img class="example-img" src="https://via.placeholder.com/80/ffb6c1/ffffff?text=Fake4" alt="Example fake 4" onclick="loadExample('example_fake4.jpg')">
<div class="example-label">Fake</div>
</div>
<div>
<img class="example-img" src="https://via.placeholder.com/80/e1bee7/ffffff?text=Real1" alt="Example real 1" onclick="loadExample('example_real1.jpg')">
<div class="example-label">Real</div>
</div>
<div>
<img class="example-img" src="https://via.placeholder.com/80/e1bee7/ffffff?text=Real2" alt="Example real 2" onclick="loadExample('example_real2.jpg')">
<div class="example-label">Real</div>
</div>
<div>
<img class="example-img" src="https://via.placeholder.com/80/e1bee7/ffffff?text=Real3" alt="Example real 3" onclick="loadExample('example_real3.jpg')">
<div class="example-label">Real</div>
</div>
<div>
<img class="example-img" src="https://via.placeholder.com/80/e1bee7/ffffff?text=Real4" alt="Example real 4" onclick="loadExample('example_real4.jpg')">
<div class="example-label">Real</div>
</div>
<div>
<img class="example-img" src="https://via.placeholder.com/80/e1bee7/ffffff?text=Real5" alt="Example real 5" onclick="loadExample('example_real5.jpg')">
<div class="example-label">Real</div>
</div>
</div>
<footer>Made with love</footer>
</div>
<script>
const uploadArea = document.getElementById('uploadArea');
const fileInput = document.getElementById('fileInput');
const previewContainer = document.getElementById('previewContainer');
const previewImage = document.getElementById('previewImage');
const detectBtn = document.getElementById('detectBtn');
const btnText = document.getElementById('btnText');
const resultContainer = document.getElementById('resultContainer');
const resultValue = document.getElementById('resultValue');
const errorMessage = document.getElementById('errorMessage');
let selectedFile = null;
uploadArea.addEventListener('click', () => fileInput.click());
uploadArea.addEventListener('dragover', (e) => {
e.preventDefault();
uploadArea.classList.add('dragover');
});
uploadArea.addEventListener('dragleave', () => {
uploadArea.classList.remove('dragover');
});
uploadArea.addEventListener('drop', (e) => {
e.preventDefault();
uploadArea.classList.remove('dragover');
const file = e.dataTransfer.files[0];
if (file && file.type.startsWith('image/')) {
handleFile(file);
}
});
fileInput.addEventListener('change', (e) => {
const file = e.target.files[0];
if (file) {
handleFile(file);
}
});
function handleFile(file) {
selectedFile = file;
const reader = new FileReader();
reader.onload = (e) => {
previewImage.src = e.target.result;
previewContainer.classList.add('show');
detectBtn.disabled = false;
resultContainer.classList.remove('show');
errorMessage.classList.remove('show');
};
reader.readAsDataURL(file);
}
detectBtn.addEventListener('click', async () => {
if (!selectedFile) return;
detectBtn.disabled = true;
btnText.innerHTML = '<span class="spinner"></span> Scanning...';
resultContainer.classList.remove('show');
errorMessage.classList.remove('show');
const formData = new FormData();
formData.append('image', selectedFile);
try {
const response = await fetch('/predict', {
method: 'POST',
body: formData
});
const data = await response.json();
if (response.ok) {
resultValue.textContent = data.prediction;
resultContainer.classList.add('show');
} else {
errorMessage.textContent = data.error || 'Something went wrong. Please try again.';
errorMessage.classList.add('show');
}
} catch (error) {
errorMessage.textContent = 'Connection error. Please check your internet and try again.';
errorMessage.classList.add('show');
} finally {
detectBtn.disabled = false;
btnText.textContent = 'Scan Image';
}
});
function loadExample(filename) {
fetch(`/examples/${filename}`)
.then(response => response.blob())
.then(blob => {
const file = new File([blob], filename, { type: 'image/jpeg' });
handleFile(file);
})
.catch(() => {
errorMessage.textContent = 'Example image not available.';
errorMessage.classList.add('show');
});
}
</script>
</body>
</html>