Spaces:
Sleeping
Sleeping
| /** | |
| * DeepShield AI — script.js (SupCon SOTA Version) | |
| */ | |
| const API_URL = ""; | |
| async function checkServerStatus() { | |
| const statusMenu = document.getElementById("server-status"); | |
| const statusText = document.getElementById("status-text"); | |
| const dropZone = document.getElementById("drop-zone"); | |
| if (!statusMenu) return; | |
| try { | |
| const res = await fetch(`${API_URL}/health`); | |
| if (!res.ok) throw new Error("Server not OK"); | |
| const data = await res.json(); | |
| statusMenu.className = "server-status"; | |
| if (data.model_loaded === true) { | |
| statusMenu.classList.add("status-connected"); | |
| statusText.textContent = "AI Ready ✓"; | |
| dropZone.style.pointerEvents = "auto"; | |
| dropZone.style.opacity = "1"; | |
| document.querySelector(".drop-title").innerHTML = "Drop your video or photo here"; | |
| } else { | |
| statusMenu.classList.add("status-error"); | |
| statusText.textContent = "Model Missing"; | |
| dropZone.style.pointerEvents = "none"; | |
| dropZone.style.opacity = "0.5"; | |
| document.querySelector(".drop-title").innerHTML = "⚠️ Model Not Uploaded"; | |
| document.querySelector(".drop-sub").textContent = "Upload best_model.pth from scripts3."; | |
| } | |
| } catch (err) { | |
| statusMenu.className = "server-status status-error"; | |
| statusText.textContent = "Starting Server..."; | |
| dropZone.style.pointerEvents = "none"; | |
| dropZone.style.opacity = "0.5"; | |
| } | |
| } | |
| checkServerStatus(); | |
| setInterval(checkServerStatus, 10000); | |
| const MAX_FILE_MB = 30; | |
| const MAX_FILE_BYTES = MAX_FILE_MB * 1024 * 1024; | |
| let currentFile = null; | |
| function showSection(id) { | |
| ["upload-section", "loading-section", "results-section", "error-section"].forEach(s => { | |
| document.getElementById(s).classList.toggle("hidden", s !== id); | |
| }); | |
| } | |
| function onDragOver(e) { e.preventDefault(); document.getElementById("drop-zone").classList.add("dragging"); } | |
| function onDragLeave() { document.getElementById("drop-zone").classList.remove("dragging"); } | |
| function onDrop(e) { | |
| e.preventDefault(); | |
| document.getElementById("drop-zone").classList.remove("dragging"); | |
| const file = e.dataTransfer?.files?.[0]; | |
| if (file) processFile(file); | |
| } | |
| function onFileSelected(e) { | |
| const file = e.target.files?.[0]; | |
| if (file) processFile(file); | |
| } | |
| function processFile(file) { | |
| const allowedExt = [".mp4", ".mov", ".avi", ".mkv", ".jpg", ".jpeg", ".png", ".webp"]; | |
| const ext = "." + file.name.split(".").pop().toLowerCase(); | |
| if (!allowedExt.includes(ext)) { | |
| showError(`❌ Unsupported file type. Use Video (MP4/MOV/AVI) or Photo (JPG/PNG).`); | |
| return; | |
| } | |
| if (file.size > MAX_FILE_BYTES) { | |
| showError(`❌ File too large. Max: ${MAX_FILE_MB} MB.`); | |
| return; | |
| } | |
| currentFile = file; | |
| document.getElementById("file-name").textContent = file.name; | |
| document.getElementById("file-size").textContent = (file.size / (1024*1024)).toFixed(1) + " MB"; | |
| const url = URL.createObjectURL(file); | |
| const isVideo = [".mp4", ".mov", ".avi", ".mkv"].includes(ext); | |
| const videoPrev = document.getElementById("video-preview"); | |
| const videoCont = document.getElementById("video-container"); | |
| // Check if image-preview element exists, if not create it | |
| let imgPrev = document.getElementById("image-preview"); | |
| if (!imgPrev) { | |
| imgPrev = document.createElement("img"); | |
| imgPrev.id = "image-preview"; | |
| imgPrev.className = "video-preview"; // reuse styling | |
| videoCont.appendChild(imgPrev); | |
| } | |
| if (isVideo) { | |
| videoPrev.src = url; | |
| videoPrev.style.display = "block"; | |
| imgPrev.style.display = "none"; | |
| } else { | |
| videoPrev.style.display = "none"; | |
| imgPrev.src = url; | |
| imgPrev.style.display = "block"; | |
| } | |
| document.getElementById("drop-zone").classList.add("hidden"); | |
| document.getElementById("file-preview").classList.remove("hidden"); | |
| } | |
| function resetUpload() { | |
| currentFile = null; | |
| document.getElementById("file-input").value = ""; | |
| showSection("upload-section"); | |
| document.getElementById("drop-zone").classList.remove("hidden"); | |
| document.getElementById("file-preview").classList.add("hidden"); | |
| document.getElementById("ring-fill").style.strokeDashoffset = "314"; | |
| } | |
| async function analyzeVideo() { | |
| if (!currentFile) return; | |
| showSection("loading-section"); | |
| const formData = new FormData(); | |
| formData.append("file", currentFile); | |
| try { | |
| const res = await fetch(`${API_URL}/predict`, { method: "POST", body: formData }); | |
| if (!res.ok) throw new Error("Analysis failed on server."); | |
| const data = await res.json(); | |
| renderResults(data); | |
| showSection("results-section"); | |
| } catch (err) { | |
| showError(err.message); | |
| } | |
| } | |
| function renderResults(data) { | |
| const isFake = data.verdict === "FAKE"; | |
| const fakePct = data.fake_probability; | |
| document.getElementById("verdict-card").className = "verdict-card " + (isFake ? "is-fake" : "is-real"); | |
| document.getElementById("verdict-pct").textContent = `${fakePct}%`; | |
| document.getElementById("verdict-label").textContent = data.verdict; | |
| document.getElementById("verdict-badge").textContent = isFake ? "⚠ FAKE DETECTED" : "✅ REAL CONTENT"; | |
| document.getElementById("verdict-badge").className = "verdict-badge " + (isFake ? "fake" : "real"); | |
| const ring = document.getElementById("ring-fill"); | |
| ring.style.stroke = isFake ? "#ef4444" : "#22c55e"; | |
| ring.style.strokeDashoffset = 314 - (fakePct / 100) * 314; | |
| document.getElementById("stat-fake").textContent = `${fakePct}%`; | |
| document.getElementById("stat-real").textContent = `${data.real_probability}%`; | |
| document.getElementById("stat-frames").textContent = data.frame_count; | |
| document.getElementById("stat-size").textContent = data.file_size_mb + " MB"; | |
| renderFrameChart(data.per_frame_scores || []); | |
| } | |
| function renderFrameChart(scores) { | |
| const container = document.getElementById("frame-chart"); | |
| container.innerHTML = ""; | |
| scores.forEach((s, i) => { | |
| const bar = document.createElement("div"); | |
| bar.className = "bar-wrap"; | |
| bar.innerHTML = `<div class="bar ${s > 50 ? 'bar-fake' : 'bar-real'}" style="height:${s}%"></div>`; | |
| container.appendChild(bar); | |
| }); | |
| } | |
| function showError(msg) { | |
| document.getElementById("error-msg").textContent = msg; | |
| showSection("error-section"); | |
| } | |