FraudScore / templates /index.html
TheFrenchDemos's picture
+ 2 ic么nes inop茅rantes
eb9597a verified
raw
history blame
8.94 kB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Fraud Score</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" rel="stylesheet">
<style>
:root{
--apple-blue:#007aff;
--apple-gray:#f2f2f7;
--apple-border:#d1d1d6;
--apple-shadow:0 4px 12px rgba(0,0,0,.08);
}
body{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;background:var(--apple-gray);color:#1c1c1e;}
h1,h2,h5{font-weight:600;}
.preset-image-container{overflow:hidden;margin-bottom:12px}
.preset-image{width:100%;border-radius:12px;border:2px solid transparent;box-shadow:var(--apple-shadow);transition:transform .3s ease,border-color .3s ease;cursor:pointer}
.preset-image:hover{transform:scale(1.05)}
.preset-image.selected{border-color:var(--apple-blue)}
.dropzone{border:2px dashed var(--apple-border);border-radius:16px;background:#fff;padding:20px;text-align:center;box-shadow:var(--apple-shadow)}
.preview-image{max-width:220px;border-radius:16px;box-shadow:var(--apple-shadow);opacity:0;transition:opacity .4s ease}
.preview-image.visible{opacity:1}
.btn-primary{background:var(--apple-blue);border:none;font-weight:500}
.btn-primary:hover{background:#005ecb}
.jauge-container{display:none;align-items:center;gap:24px;margin-top:24px}
.jauge{width:24px;height:160px;border-radius:12px;background:#e5e5ea;position:relative;overflow:hidden;border:1px solid var(--apple-border)}
.jauge-level{position:absolute;bottom:0;width:100%;border-radius:12px;background:var(--apple-blue);transition:height .6s ease,background .3s ease}
.jauge-labels{font-size:.7rem;color:#636366;display:flex;flex-direction:column;justify-content:space-between;height:160px}
.icon-buttons { display: flex; flex-direction: column; gap: 16px; justify-content: center; align-items: center; margin-left: 12px; }
.icon-buttons button { background: none; border: none; color: var(--apple-blue); font-size: 24px; cursor: pointer; }
#compareSection{margin-top:40px;text-align:center;display:none}
</style>
</head>
<body>
<div class="container py-5">
<h1 class="text-center mb-1">Fraud Score</h1>
<p class="text-center text-muted mb-5 fs-5">Is my work used by generative AI ?</p>
<div class="row g-5">
<div class="col-md-6">
<h5 class="text-center mb-3">Select Original Image</h5>
<div class="row">
<div class="col-4"><div class="preset-image-container"><img id="preset-1-1" src="/static/marilyn_1.jpg" class="preset-image" onclick="selectPreset(1,1)" alt="Original 1"></div></div>
<div class="col-4"><div class="preset-image-container"><img id="preset-2-1" src="/static/star wars_1b.jpg" class="preset-image" onclick="selectPreset(2,1)" alt="Original 2"></div></div>
<div class="col-4"><div class="preset-image-container"><img id="preset-3-1" src="/static/muhammad ali_1.jpg" class="preset-image" onclick="selectPreset(3,1)" alt="Original 3"></div></div>
</div>
<div class="dropzone mt-3" id="dropzone1">
<p class="mb-2">Drag & Drop or Upload (.jpg/.png/.webp)</p>
<input type="file" id="fileInput1" accept="image/*" hidden>
<button class="btn btn-outline-secondary" onclick="document.getElementById('fileInput1').click()">Upload</button>
</div>
</div>
<div class="col-md-6">
<h5 class="text-center mb-3">Select AI Generated Image</h5>
<div class="row">
<div class="col-4"><div class="preset-image-container"><img id="preset-1-2" src="/static/marilyn_2.png" class="preset-image" onclick="selectPreset(1,2)" alt="AI 1"></div></div>
<div class="col-4"><div class="preset-image-container"><img id="preset-2-2" src="/static/star wars_2b.png" class="preset-image" onclick="selectPreset(2,2)" alt="AI 2"></div></div>
<div class="col-4"><div class="preset-image-container"><img id="preset-3-2" src="/static/muhammad ali_2.png" class="preset-image" onclick="selectPreset(3,2)" alt="AI 3"></div></div>
</div>
<div class="dropzone mt-3" id="dropzone2">
<p class="mb-2">Drag & Drop or Upload (.jpg/.png/.webp)</p>
<input type="file" id="fileInput2" accept="image/*" hidden>
<button class="btn btn-outline-secondary" onclick="document.getElementById('fileInput2').click()">Upload</button>
</div>
</div>
</div>
<div id="compareSection">
<div class="d-flex justify-content-center align-items-center gap-5 mt-5">
<img id="previewImage1" class="preview-image" alt="Original preview">
<div class="d-flex flex-column align-items-center">
<div id="compareButtonContainer" class="mb-3"></div>
<div id="scoreBlock" style="display:none;">
<h2 class="fw-semibold mb-3">Fraud Score <span id="euclidVal" class="text-muted"></span>%</h2>
<div class="d-flex align-items-center gap-4">
<div class="jauge-container mx-auto" id="gaugeWrapper">
<div class="jauge"><div class="jauge-level" id="jaugeLevel"></div></div>
<div class="jauge-labels text-start">
<span>most certainly</span><span>very probably</span><span>probably</span><span>possibly</span><span>probably not</span><span>definitely not</span>
</div>
</div>
<div class="icon-buttons">
<button title="Print"><i class="fas fa-print"></i></button>
<button title="Certificate"><i class="fas fa-certificate"></i></button>
</div>
</div>
</div>
</div>
<img id="previewImage2" class="preview-image" alt="AI preview">
</div>
<div id="results" class="mt-4"></div>
</div>
</div>
<script>
let file1=null, file2=null;
function resetSelection(target){
for(let i=1;i<=3;i++){
const thumb=document.getElementById(`preset-${i}-${target}`);
if(thumb)thumb.classList.remove('selected');
}
}
function selectPreset(n,target){
const imgEl=document.getElementById(`preset-${n}-${target}`);
const src=imgEl.src;
fetch(src).then(r=>r.blob()).then(blob=>{
const file=new File([blob],src.split('/').pop(),{type:blob.type});
if(target===1){file1=file;} else {file2=file;}
updatePreview(blob,target);
resetSelection(target);
imgEl.classList.add('selected');
checkReady();
});
}
function updatePreview(fileOrBlob,target){
const reader=new FileReader();
reader.onload=e=>{
const img=document.getElementById(`previewImage${target}`);
img.src=e.target.result;
img.classList.add('visible');
document.getElementById('compareSection').style.display='block';
};
reader.readAsDataURL(fileOrBlob);
}
document.getElementById('fileInput1').addEventListener('change',e=>{
if(e.target.files.length){file1=e.target.files[0];updatePreview(file1,1);resetSelection(1);checkReady();}
});
document.getElementById('fileInput2').addEventListener('change',e=>{
if(e.target.files.length){file2=e.target.files[0];updatePreview(file2,2);resetSelection(2);checkReady();}
});
function checkReady(){
const container=document.getElementById('compareButtonContainer');
if(file1&&file2){
container.innerHTML='<button class="btn btn-primary" onclick="processImages()">Calculate Fraud Score</button>';
}else{
container.innerHTML='';
}
}
async function processImages(){
const fd=new FormData();
fd.append('image1',file1);
fd.append('image2',file2);
const resDiv=document.getElementById('results');
resDiv.innerHTML='<div class="spinner-border text-primary"></div>';
try{
const res=await fetch('/process',{method:'POST',body:fd});
const data=await res.json();
const euclid=parseFloat(data.distance);
const fraud=Math.min(100,Math.max(2,185-2.73*euclid));
document.getElementById('euclidVal').textContent=fraud.toFixed(1);
document.getElementById('scoreBlock').style.display='block';
let color='#198754';
if(fraud>90)color='#dc3545';
else if(fraud>75)color='#fd7e14';
else if(fraud>60)color='#ffc107';
else if(fraud>45)color='#0dcaf0';
else if(fraud>30)color='#0d6efd';
const gaugeLevel=document.getElementById('jaugeLevel');
gaugeLevel.style.height=`${Math.min(100,fraud)}%`;
gaugeLevel.style.backgroundColor=color;
document.getElementById('gaugeWrapper').style.display='flex';
resDiv.innerHTML='';
}catch(err){
resDiv.innerHTML='<div class="text-danger">Error processing images.</div>';
}
}
</script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>