MrTsp commited on
Commit
b15c9f4
·
1 Parent(s): ccfa4b0

Update static/script.js

Browse files
Files changed (1) hide show
  1. static/script.js +56 -161
static/script.js CHANGED
@@ -1,10 +1,8 @@
1
  /**
2
- * DeepShield AI — script.js (Full-Stack HF Space version)
3
- * API_URL = "" means: same server, same domain. No CORS needed!
4
  */
5
- const API_URL = ""; // Empty = same HF Space serves both UI and API
6
 
7
- // ── Server Status Ping ──
8
  async function checkServerStatus() {
9
  const statusMenu = document.getElementById("server-status");
10
  const statusText = document.getElementById("status-text");
@@ -22,56 +20,40 @@ async function checkServerStatus() {
22
  if (data.model_loaded === true) {
23
  statusMenu.classList.add("status-connected");
24
  statusText.textContent = "AI Ready ✓";
25
-
26
  dropZone.style.pointerEvents = "auto";
27
  dropZone.style.opacity = "1";
28
- document.querySelector(".drop-title").innerHTML = "Drop your video here";
29
- document.querySelector(".drop-sub").innerHTML = 'or <span class="link-text">browse files</span>';
30
  } else {
31
  statusMenu.classList.add("status-error");
32
  statusText.textContent = "Model Missing";
33
-
34
  dropZone.style.pointerEvents = "none";
35
  dropZone.style.opacity = "0.5";
36
  document.querySelector(".drop-title").innerHTML = "⚠️ Model Not Uploaded";
37
- document.querySelector(".drop-sub").textContent = "Admin: Upload best_model.pth to this HF Space.";
38
  }
39
  } catch (err) {
40
  statusMenu.className = "server-status status-error";
41
- statusText.textContent = "Server Waking Up...";
42
-
43
  dropZone.style.pointerEvents = "none";
44
  dropZone.style.opacity = "0.5";
45
- document.querySelector(".drop-title").innerHTML = "⚠️ Server is starting...";
46
- document.querySelector(".drop-sub").textContent = "Takes ~60 sec. Page will auto-refresh status.";
47
  }
48
  }
49
 
50
- // Check on load, then every 10 seconds (also keeps server alive!)
51
  checkServerStatus();
52
  setInterval(checkServerStatus, 10000);
53
 
54
  const MAX_FILE_MB = 30;
55
  const MAX_FILE_BYTES = MAX_FILE_MB * 1024 * 1024;
56
-
57
  let currentFile = null;
58
- let lastResult = null;
59
 
60
  function showSection(id) {
61
- const sections = ["upload-section", "loading-section", "results-section", "error-section"];
62
- sections.forEach(s => {
63
  document.getElementById(s).classList.toggle("hidden", s !== id);
64
  });
65
  }
66
 
67
- function onDragOver(e) {
68
- e.preventDefault();
69
- document.getElementById("drop-zone").classList.add("dragging");
70
- }
71
-
72
- function onDragLeave() {
73
- document.getElementById("drop-zone").classList.remove("dragging");
74
- }
75
 
76
  function onDrop(e) {
77
  e.preventDefault();
@@ -86,25 +68,46 @@ function onFileSelected(e) {
86
  }
87
 
88
  function processFile(file) {
89
- const allowedExt = [".mp4", ".mov", ".avi", ".mkv"];
90
  const ext = "." + file.name.split(".").pop().toLowerCase();
 
91
  if (!allowedExt.includes(ext)) {
92
- showError(`❌ Unsupported file type: "${ext}". Please upload MP4, MOV, AVI, or MKV.`);
93
  return;
94
  }
95
-
96
  if (file.size > MAX_FILE_BYTES) {
97
- const sizeMB = (file.size / 1024 / 1024).toFixed(1);
98
- showError(`❌ File too large (${sizeMB} MB). Maximum allowed: ${MAX_FILE_MB} MB.`);
99
  return;
100
  }
101
 
102
  currentFile = file;
103
  document.getElementById("file-name").textContent = file.name;
104
- document.getElementById("file-size").textContent = formatBytes(file.size);
105
 
106
  const url = URL.createObjectURL(file);
107
- document.getElementById("video-preview").src = url;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
108
 
109
  document.getElementById("drop-zone").classList.add("hidden");
110
  document.getElementById("file-preview").classList.remove("hidden");
@@ -112,123 +115,61 @@ function processFile(file) {
112
 
113
  function resetUpload() {
114
  currentFile = null;
115
- lastResult = null;
116
-
117
  document.getElementById("file-input").value = "";
118
-
119
- const video = document.getElementById("video-preview");
120
- if (video.src) URL.revokeObjectURL(video.src);
121
- video.src = "";
122
-
123
- document.getElementById("ring-fill").style.strokeDashoffset = "314";
124
- document.getElementById("frame-chart").innerHTML = "";
125
-
126
  document.getElementById("drop-zone").classList.remove("hidden");
127
  document.getElementById("file-preview").classList.add("hidden");
128
- showSection("upload-section");
129
-
130
- const btn = document.getElementById("analyze-btn");
131
- if (btn) {
132
- btn.disabled = false;
133
- btn.innerHTML = '<span class="btn-icon">🔍</span><span>Analyze for Deepfakes</span>';
134
- }
135
  }
136
 
137
  async function analyzeVideo() {
138
  if (!currentFile) return;
139
-
140
- const btn = document.getElementById("analyze-btn");
141
- btn.disabled = true;
142
- btn.innerHTML = '<span class="btn-icon">⏳</span><span>Uploading...</span>';
143
-
144
  showSection("loading-section");
145
- animateLoadingSteps();
146
 
147
  const formData = new FormData();
148
  formData.append("file", currentFile);
149
 
150
  try {
151
- const response = await fetch(`${API_URL}/predict`, {
152
- method: "POST",
153
- body: formData,
154
- });
155
-
156
- if (!response.ok) {
157
- const errData = await response.json().catch(() => ({ detail: "Unknown server error." }));
158
- throw new Error(errData.detail || `Server error: ${response.status}`);
159
- }
160
-
161
- const data = await response.json();
162
- lastResult = data;
163
  renderResults(data);
164
  showSection("results-section");
165
-
166
  } catch (err) {
167
- console.error("Analysis failed:", err);
168
- let msg = err.message || "Analysis failed.";
169
- if (msg.includes("fetch") || msg.includes("NetworkError") || msg.includes("Failed to fetch")) {
170
- msg = "⚠️ Cannot reach the AI server. The server might be waking up. Please wait ~60 sec and try again.";
171
- }
172
- showError(msg);
173
  }
174
  }
175
 
176
  function renderResults(data) {
177
  const isFake = data.verdict === "FAKE";
178
  const fakePct = data.fake_probability;
179
- const realPct = data.real_probability;
180
 
181
- const card = document.getElementById("verdict-card");
182
- card.classList.remove("is-fake", "is-real");
183
- card.classList.add(isFake ? "is-fake" : "is-real");
 
 
184
 
185
  const ring = document.getElementById("ring-fill");
186
- const circumference = 314;
187
  ring.style.stroke = isFake ? "#ef4444" : "#22c55e";
188
- setTimeout(() => {
189
- ring.style.strokeDashoffset = circumference - (fakePct / 100) * circumference;
190
- }, 100);
191
-
192
- document.getElementById("verdict-pct").textContent = `${fakePct}%`;
193
- const lbl = document.getElementById("verdict-label");
194
- lbl.textContent = data.verdict;
195
- lbl.style.color = isFake ? "#f87171" : "#4ade80";
196
-
197
- const badge = document.getElementById("verdict-badge");
198
- badge.textContent = isFake ? "⚠️ FAKE DETECTED" : "✅ REAL VIDEO";
199
- badge.className = "verdict-badge " + (isFake ? "fake" : "real");
200
 
201
  document.getElementById("stat-fake").textContent = `${fakePct}%`;
202
- document.getElementById("stat-real").textContent = `${realPct}%`;
203
- document.getElementById("stat-frames").textContent = `${data.frame_count} frames`;
204
- document.getElementById("stat-size").textContent = `${data.file_size_mb} MB`;
205
-
206
  renderFrameChart(data.per_frame_scores || []);
207
  }
208
 
209
  function renderFrameChart(scores) {
210
  const container = document.getElementById("frame-chart");
211
  container.innerHTML = "";
212
-
213
- if (!scores.length) {
214
- container.innerHTML = '<p style="color:var(--text-sub);font-size:13px;padding:20px 0;">No per-frame data.</p>';
215
- return;
216
- }
217
-
218
- scores.forEach((score, i) => {
219
- const isFakeBar = score > 50;
220
- const wrap = document.createElement("div");
221
- wrap.className = "bar-wrap";
222
-
223
  const bar = document.createElement("div");
224
- bar.className = `bar ${isFakeBar ? "bar-fake" : "bar-real"}`;
225
- bar.style.height = "0%";
226
- bar.setAttribute("data-tip", `Frame ${i + 1}: ${score}%`);
227
-
228
- wrap.appendChild(bar);
229
- container.appendChild(wrap);
230
-
231
- setTimeout(() => { bar.style.height = `${Math.max(4, score)}%`; }, 100 + i * 30);
232
  });
233
  }
234
 
@@ -236,49 +177,3 @@ function showError(msg) {
236
  document.getElementById("error-msg").textContent = msg;
237
  showSection("error-section");
238
  }
239
-
240
- function animateLoadingSteps() {
241
- const steps = ["step-1", "step-2", "step-3"];
242
- steps.forEach(s => {
243
- document.getElementById(s).classList.remove("active", "done");
244
- });
245
-
246
- let i = 0;
247
- function next() {
248
- if (i > 0) {
249
- document.getElementById(steps[i - 1]).classList.remove("active");
250
- document.getElementById(steps[i - 1]).classList.add("done");
251
- }
252
- if (i < steps.length) {
253
- document.getElementById(steps[i]).classList.add("active");
254
- i++;
255
- setTimeout(next, i < steps.length ? 4000 : 99999);
256
- }
257
- }
258
- next();
259
- }
260
-
261
- function copyResult() {
262
- if (!lastResult) return;
263
- const { verdict, fake_probability, real_probability, frame_count, filename } = lastResult;
264
- const text =
265
- `DeepShield AI — DINO-G50 Result\n` +
266
- `File: ${filename}\n` +
267
- `Verdict: ${verdict}\n` +
268
- `Fake: ${fake_probability}% | Real: ${real_probability}%\n` +
269
- `Frames Analyzed: ${frame_count}`;
270
-
271
- navigator.clipboard?.writeText(text).then(() => {
272
- const btn = document.querySelector(".action-secondary");
273
- if (btn) {
274
- const orig = btn.textContent;
275
- btn.textContent = "✅ Copied!";
276
- setTimeout(() => { btn.textContent = orig; }, 2000);
277
- }
278
- }).catch(() => alert(text));
279
- }
280
-
281
- function formatBytes(bytes) {
282
- if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + " KB";
283
- return (bytes / 1024 / 1024).toFixed(1) + " MB";
284
- }
 
1
  /**
2
+ * DeepShield AI — script.js (SupCon SOTA Version)
 
3
  */
4
+ const API_URL = "";
5
 
 
6
  async function checkServerStatus() {
7
  const statusMenu = document.getElementById("server-status");
8
  const statusText = document.getElementById("status-text");
 
20
  if (data.model_loaded === true) {
21
  statusMenu.classList.add("status-connected");
22
  statusText.textContent = "AI Ready ✓";
 
23
  dropZone.style.pointerEvents = "auto";
24
  dropZone.style.opacity = "1";
25
+ document.querySelector(".drop-title").innerHTML = "Drop your video or photo here";
 
26
  } else {
27
  statusMenu.classList.add("status-error");
28
  statusText.textContent = "Model Missing";
 
29
  dropZone.style.pointerEvents = "none";
30
  dropZone.style.opacity = "0.5";
31
  document.querySelector(".drop-title").innerHTML = "⚠️ Model Not Uploaded";
32
+ document.querySelector(".drop-sub").textContent = "Upload best_model.pth from scripts3.";
33
  }
34
  } catch (err) {
35
  statusMenu.className = "server-status status-error";
36
+ statusText.textContent = "Starting Server...";
 
37
  dropZone.style.pointerEvents = "none";
38
  dropZone.style.opacity = "0.5";
 
 
39
  }
40
  }
41
 
 
42
  checkServerStatus();
43
  setInterval(checkServerStatus, 10000);
44
 
45
  const MAX_FILE_MB = 30;
46
  const MAX_FILE_BYTES = MAX_FILE_MB * 1024 * 1024;
 
47
  let currentFile = null;
 
48
 
49
  function showSection(id) {
50
+ ["upload-section", "loading-section", "results-section", "error-section"].forEach(s => {
 
51
  document.getElementById(s).classList.toggle("hidden", s !== id);
52
  });
53
  }
54
 
55
+ function onDragOver(e) { e.preventDefault(); document.getElementById("drop-zone").classList.add("dragging"); }
56
+ function onDragLeave() { document.getElementById("drop-zone").classList.remove("dragging"); }
 
 
 
 
 
 
57
 
58
  function onDrop(e) {
59
  e.preventDefault();
 
68
  }
69
 
70
  function processFile(file) {
71
+ const allowedExt = [".mp4", ".mov", ".avi", ".mkv", ".jpg", ".jpeg", ".png", ".webp"];
72
  const ext = "." + file.name.split(".").pop().toLowerCase();
73
+
74
  if (!allowedExt.includes(ext)) {
75
+ showError(`❌ Unsupported file type. Use Video (MP4/MOV/AVI) or Photo (JPG/PNG).`);
76
  return;
77
  }
 
78
  if (file.size > MAX_FILE_BYTES) {
79
+ showError(`❌ File too large. Max: ${MAX_FILE_MB} MB.`);
 
80
  return;
81
  }
82
 
83
  currentFile = file;
84
  document.getElementById("file-name").textContent = file.name;
85
+ document.getElementById("file-size").textContent = (file.size / (1024*1024)).toFixed(1) + " MB";
86
 
87
  const url = URL.createObjectURL(file);
88
+ const isVideo = [".mp4", ".mov", ".avi", ".mkv"].includes(ext);
89
+
90
+ const videoPrev = document.getElementById("video-preview");
91
+ const videoCont = document.getElementById("video-container");
92
+
93
+ // Check if image-preview element exists, if not create it
94
+ let imgPrev = document.getElementById("image-preview");
95
+ if (!imgPrev) {
96
+ imgPrev = document.createElement("img");
97
+ imgPrev.id = "image-preview";
98
+ imgPrev.className = "video-preview"; // reuse styling
99
+ videoCont.appendChild(imgPrev);
100
+ }
101
+
102
+ if (isVideo) {
103
+ videoPrev.src = url;
104
+ videoPrev.style.display = "block";
105
+ imgPrev.style.display = "none";
106
+ } else {
107
+ videoPrev.style.display = "none";
108
+ imgPrev.src = url;
109
+ imgPrev.style.display = "block";
110
+ }
111
 
112
  document.getElementById("drop-zone").classList.add("hidden");
113
  document.getElementById("file-preview").classList.remove("hidden");
 
115
 
116
  function resetUpload() {
117
  currentFile = null;
 
 
118
  document.getElementById("file-input").value = "";
119
+ showSection("upload-section");
 
 
 
 
 
 
 
120
  document.getElementById("drop-zone").classList.remove("hidden");
121
  document.getElementById("file-preview").classList.add("hidden");
122
+ document.getElementById("ring-fill").style.strokeDashoffset = "314";
 
 
 
 
 
 
123
  }
124
 
125
  async function analyzeVideo() {
126
  if (!currentFile) return;
 
 
 
 
 
127
  showSection("loading-section");
 
128
 
129
  const formData = new FormData();
130
  formData.append("file", currentFile);
131
 
132
  try {
133
+ const res = await fetch(`${API_URL}/predict`, { method: "POST", body: formData });
134
+ if (!res.ok) throw new Error("Analysis failed on server.");
135
+ const data = await res.json();
 
 
 
 
 
 
 
 
 
136
  renderResults(data);
137
  showSection("results-section");
 
138
  } catch (err) {
139
+ showError(err.message);
 
 
 
 
 
140
  }
141
  }
142
 
143
  function renderResults(data) {
144
  const isFake = data.verdict === "FAKE";
145
  const fakePct = data.fake_probability;
 
146
 
147
+ document.getElementById("verdict-card").className = "verdict-card " + (isFake ? "is-fake" : "is-real");
148
+ document.getElementById("verdict-pct").textContent = `${fakePct}%`;
149
+ document.getElementById("verdict-label").textContent = data.verdict;
150
+ document.getElementById("verdict-badge").textContent = isFake ? "⚠ FAKE DETECTED" : "✅ REAL CONTENT";
151
+ document.getElementById("verdict-badge").className = "verdict-badge " + (isFake ? "fake" : "real");
152
 
153
  const ring = document.getElementById("ring-fill");
 
154
  ring.style.stroke = isFake ? "#ef4444" : "#22c55e";
155
+ ring.style.strokeDashoffset = 314 - (fakePct / 100) * 314;
 
 
 
 
 
 
 
 
 
 
 
156
 
157
  document.getElementById("stat-fake").textContent = `${fakePct}%`;
158
+ document.getElementById("stat-real").textContent = `${data.real_probability}%`;
159
+ document.getElementById("stat-frames").textContent = data.frame_count;
160
+ document.getElementById("stat-size").textContent = data.file_size_mb + " MB";
161
+
162
  renderFrameChart(data.per_frame_scores || []);
163
  }
164
 
165
  function renderFrameChart(scores) {
166
  const container = document.getElementById("frame-chart");
167
  container.innerHTML = "";
168
+ scores.forEach((s, i) => {
 
 
 
 
 
 
 
 
 
 
169
  const bar = document.createElement("div");
170
+ bar.className = "bar-wrap";
171
+ bar.innerHTML = `<div class="bar ${s > 50 ? 'bar-fake' : 'bar-real'}" style="height:${s}%"></div>`;
172
+ container.appendChild(bar);
 
 
 
 
 
173
  });
174
  }
175
 
 
177
  document.getElementById("error-msg").textContent = msg;
178
  showSection("error-section");
179
  }