Jdp-08 commited on
Commit
1ee4266
·
verified ·
1 Parent(s): 65d00f9

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +281 -98
index.html CHANGED
@@ -19,11 +19,10 @@
19
  border-color: #3b82f6;
20
  background: rgba(59, 130, 246, 0.05);
21
  }
22
- .result-card {
23
- background: rgba(17, 24, 39, 0.95);
24
- backdrop-filter: blur(10px);
25
- }
26
  .progress-bar { transition: width 0.3s ease; }
 
 
27
  main { min-height: calc(100vh - 200px); }
28
  </style>
29
  </head>
@@ -46,49 +45,107 @@
46
 
47
  <!-- Main Content -->
48
  <main class="max-w-4xl mx-auto px-4 py-12 pb-24 flex-grow">
49
- <div class="text-center mb-16">
50
  <h2 class="text-3xl md:text-4xl font-bold mb-4 text-gray-100">Deepfake Detection</h2>
51
  <p class="text-lg text-gray-400 max-w-2xl mx-auto">
52
- Upload image or video for forensic analysis using advanced AI models.
53
  </p>
54
  </div>
55
 
56
- <!-- Upload Section -->
57
- <div id="uploadSection" class="result-card rounded-2xl p-8 md:p-12 mb-12 shadow-xl">
58
- <div id="uploadArea" class="upload-area rounded-xl p-12 text-center cursor-pointer mb-8 hover:border-gray-400 transition-colors"
59
- onclick="document.getElementById('fileInput').click()">
60
- <i class="fas fa-cloud-arrow-up text-4xl text-gray-500 mb-6"></i>
61
- <h3 class="text-xl font-semibold mb-3 text-gray-200">Drop file here or click to browse</h3>
62
- <p class="text-gray-500 mb-8">Supports JPG, PNG, MP4 (max 50MB)</p>
63
- <div class="flex justify-center space-x-6 text-sm text-gray-500">
64
- <span><i class="fas fa-image mr-1"></i> Image</span>
65
- <span><i class="fas fa-video mr-1"></i> Video</span>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
66
  </div>
 
 
 
 
67
  </div>
68
- <input type="file" id="fileInput" accept="image/*,video/*" class="hidden">
69
-
70
- <!-- Preview -->
71
- <div id="previewSection" class="hidden mb-8 p-6 bg-gray-900/50 rounded-xl">
72
- <div class="flex flex-col lg:flex-row gap-6 items-start">
73
- <!-- image preview -->
74
- <img id="previewImg" class="hidden flex-1 max-h-80 object-contain rounded-lg shadow-md mx-auto lg:mx-0" alt="Preview">
75
- <!-- video preview -->
76
- <video id="previewVideo" class="hidden flex-1 max-h-80 rounded-lg shadow-md mx-auto lg:mx-0" controls muted></video>
77
- <div id="fileInfo" class="flex-1 min-w-0"></div>
 
 
 
78
  </div>
 
 
 
79
  </div>
 
80
 
81
- <button id="analyzeBtn" class="hidden w-full bg-blue-600 hover:bg-blue-700 text-white font-medium py-4 px-8 rounded-xl text-lg transition-colors">
82
- Analyze for Deepfakes
83
- </button>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
84
  </div>
85
 
86
- <!-- Progress Section -->
87
  <div id="progressSection" class="hidden result-card rounded-2xl p-12 mb-12">
88
  <div class="text-center mb-8">
89
  <div class="w-12 h-12 border-4 border-blue-500/20 border-t-blue-500 rounded-full animate-spin mx-auto mb-6"></div>
90
- <p class="text-2xl font-semibold text-gray-100">Analyzing file</p>
91
- <p id="progressLabel" class="text-gray-500 mt-2 text-sm">Running forensic analysis with Groq Llama 4 Vision...</p>
92
  </div>
93
  <div class="w-full bg-gray-800 rounded-lg h-2.5 overflow-hidden">
94
  <div id="progressBar" class="progress-bar bg-blue-600 h-2.5 w-0"></div>
@@ -96,7 +153,7 @@
96
  <p id="progressText" class="text-center text-sm text-gray-500 mt-3">0%</p>
97
  </div>
98
 
99
- <!-- Results Section -->
100
  <div id="resultsSection" class="hidden">
101
  <div class="result-card rounded-2xl p-8 md:p-12">
102
 
@@ -112,7 +169,7 @@
112
  <!-- Confidence warning -->
113
  <div id="confidenceWarning" class="hidden mb-6 p-4 rounded-xl border text-sm font-medium"></div>
114
 
115
- <!-- Authenticity / Fake scores -->
116
  <div class="grid grid-cols-2 gap-4 mb-10">
117
  <div class="text-center p-5 bg-gray-900/50 rounded-xl border border-gray-700">
118
  <div id="scoreReal" class="text-3xl font-bold text-green-400 mb-1"></div>
@@ -136,18 +193,16 @@
136
  <div id="groqReasoning" class="p-4 bg-gray-900/50 rounded-xl border border-gray-700 text-sm text-gray-300 leading-relaxed"></div>
137
  </div>
138
 
139
- <!-- Forensic details -->
140
  <div class="p-5 bg-gray-900/50 rounded-xl border border-gray-700 mb-10 text-sm text-gray-400 space-y-2">
141
  <h4 class="text-sm font-semibold text-gray-400 uppercase tracking-wider mb-3">Forensic Details</h4>
142
  <p><span class="text-gray-500">SHA256:</span> <span id="hashValue" class="font-mono text-xs break-all"></span></p>
143
  <p id="metadataRiskRow"><span class="text-gray-500">Metadata Risk:</span> <span id="metadataRisk"></span></p>
144
- <!-- video only -->
145
  <p id="framesRow" class="hidden"><span class="text-gray-500">Frames Analyzed:</span> <span id="framesAnalyzed"></span></p>
146
  <p id="durationRow" class="hidden"><span class="text-gray-500">Video Duration:</span> <span id="videoDuration"></span></p>
147
  <p><span class="text-gray-500">Models Used:</span> <span id="modelsUsed"></span></p>
148
  </div>
149
 
150
- <!-- Buttons -->
151
  <div class="flex flex-col sm:flex-row gap-4">
152
  <button onclick="resetUI()" class="flex-1 bg-gray-700 hover:bg-gray-600 text-white font-medium py-3 px-6 rounded-xl border border-gray-600 transition-colors">
153
  <i class="fas fa-redo mr-2"></i> Analyze Another
@@ -157,12 +212,30 @@
157
  </div>
158
  </main>
159
 
160
- <!-- Footer -->
161
  <footer class="border-t border-gray-800 p-8 text-center text-xs text-gray-500 bg-gray-900/50">
162
  DeepTrust Forensics | Advanced AI Detection | 2026
163
  </footer>
164
 
165
  <script>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
166
  const uploadArea = document.getElementById('uploadArea');
167
  const fileInput = document.getElementById('fileInput');
168
  const analyzeBtn = document.getElementById('analyzeBtn');
@@ -185,7 +258,6 @@ function handleFiles(files) {
185
  function showPreview(file) {
186
  const url = URL.createObjectURL(file);
187
  const isVideo = file.type.startsWith('video/');
188
-
189
  const imgEl = document.getElementById('previewImg');
190
  const videoEl = document.getElementById('previewVideo');
191
 
@@ -211,50 +283,115 @@ function showPreview(file) {
211
 
212
  document.getElementById('previewSection').classList.remove('hidden');
213
  analyzeBtn.classList.remove('hidden');
214
-
215
- // update progress label for video
216
- if (isVideo) {
217
- document.getElementById('progressLabel').textContent = 'Analyzing 5 key frames with Groq Llama 4 Vision...';
218
- } else {
219
- document.getElementById('progressLabel').textContent = 'Running forensic analysis with Groq Llama 4 Vision...';
220
- }
221
- }
222
-
223
- function formatBytes(bytes) {
224
- if (bytes === 0) return '0 B';
225
- const sizes = ['B', 'KB', 'MB'];
226
- const i = Math.floor(Math.log(bytes) / Math.log(1024));
227
- return (bytes / Math.pow(1024, i)).toFixed(1) + ' ' + sizes[i];
228
  }
229
 
230
  analyzeBtn.addEventListener('click', async () => {
231
  const file = fileInput.files[0];
232
  if (!file) return;
 
233
 
234
  document.getElementById('uploadArea').style.display = 'none';
235
  document.getElementById('previewSection').style.display = 'none';
236
  analyzeBtn.style.display = 'none';
237
- document.getElementById('progressSection').classList.remove('hidden');
238
 
239
- // video takes longer so slower progress
240
- const isVideo = file.type.startsWith('video/');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
241
  let progress = 0;
242
- const interval = setInterval(() => {
243
- progress += isVideo ? 1 : 3;
244
  if (progress > 90) progress = 90;
245
  document.getElementById('progressBar').style.width = progress + '%';
246
  document.getElementById('progressText').textContent = progress + '%';
247
  }, 400);
 
248
 
249
- const formData = new FormData();
250
- formData.append("file", file);
251
-
252
  try {
253
  const response = await fetch("/analyze", { method: "POST", body: formData });
254
  if (!response.ok) throw new Error("Server error");
255
  const data = await response.json();
256
 
257
- clearInterval(interval);
258
  document.getElementById('progressBar').style.width = '100%';
259
  document.getElementById('progressText').textContent = '100%';
260
 
@@ -264,20 +401,21 @@ analyzeBtn.addEventListener('click', async () => {
264
  }, 400);
265
 
266
  } catch (error) {
267
- clearInterval(interval);
268
  document.getElementById('progressSection').classList.add('hidden');
269
  console.error(error);
270
  alert("Analysis failed. Check backend.");
271
  }
272
- });
273
 
 
274
  function showResults(data) {
275
  const section = document.getElementById('resultsSection');
276
  section.classList.remove('hidden');
277
  section.scrollIntoView({ behavior: 'smooth' });
278
 
279
  const isAuthentic = data.authenticity > 50;
280
- const isVideo = data.type === 'video';
281
  const iconEl = document.getElementById('resultIcon');
282
 
283
  // confidence warning
@@ -294,15 +432,22 @@ function showResults(data) {
294
  warningEl.classList.add('hidden');
295
  }
296
 
297
- // verdict
 
 
 
 
 
 
 
298
  if (isAuthentic) {
299
  iconEl.innerHTML = '<i class="fas fa-check text-green-500 text-2xl"></i>';
300
- document.getElementById('resultTitle').textContent = isVideo ? 'Authentic Video Detected' : 'Authentic Media Detected';
301
- document.getElementById('resultSubtitle').textContent = 'No synthetic manipulation found.';
302
  } else {
303
  iconEl.innerHTML = '<i class="fas fa-triangle-exclamation text-orange-500 text-2xl"></i>';
304
- document.getElementById('resultTitle').textContent = isVideo ? 'Potential Deepfake Video Detected' : 'Potential Deepfake Detected';
305
- document.getElementById('resultSubtitle').textContent = 'Signs of fabrication detected.';
306
  }
307
 
308
  document.getElementById('scoreReal').textContent = Math.round(data.authenticity) + '%';
@@ -310,8 +455,8 @@ function showResults(data) {
310
  document.getElementById('hashValue').textContent = data.sha256;
311
  document.getElementById('modelsUsed').textContent = (data.models_used || []).join(', ');
312
 
313
- // forensic details — different for video vs image
314
- if (isVideo) {
315
  document.getElementById('metadataRiskRow').classList.add('hidden');
316
  document.getElementById('framesRow').classList.remove('hidden');
317
  document.getElementById('durationRow').classList.remove('hidden');
@@ -327,26 +472,41 @@ function showResults(data) {
327
  // model breakdown
328
  const modelDiv = document.getElementById('modelBreakdown');
329
  modelDiv.innerHTML = '';
330
- const score = data.details.groq_score;
331
- const isUnavailable = score === 'unavailable' || score === null;
332
- const pct = isUnavailable ? 0 : Math.round(score * 100);
333
- const color = isUnavailable ? 'bg-gray-600' : score > 0.5 ? 'bg-red-500' : 'bg-green-500';
334
- const textColor = isUnavailable ? 'text-gray-500' : score > 0.5 ? 'text-red-400' : 'text-green-400';
335
- modelDiv.innerHTML = `
336
- <div class="p-4 bg-gray-900/50 rounded-xl border border-gray-700">
337
- <div class="flex justify-between items-center mb-2">
338
- <span class="text-sm text-gray-300 font-medium">
339
- <i class="fas fa-brain mr-2 text-orange-400"></i>Groq Llama 4 Vision
340
- ${isVideo ? '<span class="ml-2 text-xs text-gray-500">(avg of 5 frames)</span>' : ''}
341
- </span>
342
- <span class="text-sm font-bold ${textColor}">
343
- ${isUnavailable ? 'Unavailable' : pct + '% fake'}
344
- </span>
345
- </div>
346
- <div class="w-full bg-gray-800 rounded-full h-2">
347
- <div class="${color} h-2 rounded-full transition-all" style="width: ${pct}%"></div>
348
- </div>
349
- </div>`;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
350
 
351
  // AI reasoning
352
  if (data.details.groq_reasoning) {
@@ -357,20 +517,43 @@ function showResults(data) {
357
  }
358
  }
359
 
 
 
 
 
 
 
 
 
360
  function resetUI() {
361
  document.getElementById('resultsSection').classList.add('hidden');
 
 
 
 
 
 
362
  document.getElementById('uploadArea').style.display = 'block';
363
  document.getElementById('previewSection').classList.add('hidden');
364
  document.getElementById('previewSection').style.display = '';
365
- analyzeBtn.classList.remove('hidden');
366
- analyzeBtn.style.display = '';
367
- document.getElementById('progressBar').style.width = '0%';
368
- document.getElementById('progressText').textContent = '0%';
369
- document.getElementById('confidenceWarning').classList.add('hidden');
370
- document.getElementById('groqReasoningSection').classList.add('hidden');
371
  document.getElementById('previewImg').classList.add('hidden');
372
  document.getElementById('previewVideo').classList.add('hidden');
373
  fileInput.value = '';
 
 
 
 
 
 
 
 
 
 
 
 
 
374
  }
375
  </script>
376
  </body>
 
19
  border-color: #3b82f6;
20
  background: rgba(59, 130, 246, 0.05);
21
  }
22
+ .result-card { background: rgba(17, 24, 39, 0.95); backdrop-filter: blur(10px); }
 
 
 
23
  .progress-bar { transition: width 0.3s ease; }
24
+ .tab-btn { transition: all 0.2s ease; }
25
+ .tab-btn.active { background: #2563eb; color: white; }
26
  main { min-height: calc(100vh - 200px); }
27
  </style>
28
  </head>
 
45
 
46
  <!-- Main Content -->
47
  <main class="max-w-4xl mx-auto px-4 py-12 pb-24 flex-grow">
48
+ <div class="text-center mb-12">
49
  <h2 class="text-3xl md:text-4xl font-bold mb-4 text-gray-100">Deepfake Detection</h2>
50
  <p class="text-lg text-gray-400 max-w-2xl mx-auto">
51
+ Forensic analysis of images, videos, text, and documents using advanced AI models.
52
  </p>
53
  </div>
54
 
55
+ <!-- Tabs -->
56
+ <div class="flex gap-2 mb-8 p-1 bg-gray-900/50 rounded-xl border border-gray-800">
57
+ <button onclick="switchTab('media')" id="tab-media" class="tab-btn active flex-1 py-3 px-4 rounded-lg text-sm font-medium">
58
+ <i class="fas fa-photo-film mr-2"></i>Image / Video
59
+ </button>
60
+ <button onclick="switchTab('text')" id="tab-text" class="tab-btn flex-1 py-3 px-4 rounded-lg text-sm font-medium text-gray-400">
61
+ <i class="fas fa-align-left mr-2"></i>Text
62
+ </button>
63
+ <button onclick="switchTab('pdf')" id="tab-pdf" class="tab-btn flex-1 py-3 px-4 rounded-lg text-sm font-medium text-gray-400">
64
+ <i class="fas fa-file-pdf mr-2"></i>PDF / Document
65
+ </button>
66
+ </div>
67
+
68
+ <!-- ======= MEDIA TAB ======= -->
69
+ <div id="panel-media">
70
+ <div id="uploadSection" class="result-card rounded-2xl p-8 md:p-12 mb-12 shadow-xl">
71
+ <div id="uploadArea" class="upload-area rounded-xl p-12 text-center cursor-pointer mb-8 hover:border-gray-400 transition-colors"
72
+ onclick="document.getElementById('fileInput').click()">
73
+ <i class="fas fa-cloud-arrow-up text-4xl text-gray-500 mb-6"></i>
74
+ <h3 class="text-xl font-semibold mb-3 text-gray-200">Drop file here or click to browse</h3>
75
+ <p class="text-gray-500 mb-8">Supports JPG, PNG, MP4 (max 50MB)</p>
76
+ <div class="flex justify-center space-x-6 text-sm text-gray-500">
77
+ <span><i class="fas fa-image mr-1"></i> Image</span>
78
+ <span><i class="fas fa-video mr-1"></i> Video</span>
79
+ </div>
80
+ </div>
81
+ <input type="file" id="fileInput" accept="image/*,video/*" class="hidden">
82
+
83
+ <div id="previewSection" class="hidden mb-8 p-6 bg-gray-900/50 rounded-xl">
84
+ <div class="flex flex-col lg:flex-row gap-6 items-start">
85
+ <img id="previewImg" class="hidden flex-1 max-h-80 object-contain rounded-lg shadow-md mx-auto lg:mx-0" alt="Preview">
86
+ <video id="previewVideo" class="hidden flex-1 max-h-80 rounded-lg shadow-md mx-auto lg:mx-0" controls muted></video>
87
+ <div id="fileInfo" class="flex-1 min-w-0"></div>
88
+ </div>
89
  </div>
90
+
91
+ <button id="analyzeBtn" class="hidden w-full bg-blue-600 hover:bg-blue-700 text-white font-medium py-4 px-8 rounded-xl text-lg transition-colors">
92
+ <i class="fas fa-magnifying-glass mr-2"></i>Analyze for Deepfakes
93
+ </button>
94
  </div>
95
+ </div>
96
+
97
+ <!-- ======= TEXT TAB ======= -->
98
+ <div id="panel-text" class="hidden">
99
+ <div class="result-card rounded-2xl p-8 md:p-12 mb-12 shadow-xl">
100
+ <h3 class="text-lg font-semibold text-gray-200 mb-2">Paste Text to Analyze</h3>
101
+ <p class="text-gray-500 text-sm mb-6">Works for news articles, social media posts, government notices, or any written content.</p>
102
+ <textarea id="textInput" rows="10"
103
+ class="w-full bg-gray-900 border border-gray-700 rounded-xl p-4 text-gray-200 text-sm resize-none focus:outline-none focus:border-blue-500 transition-colors"
104
+ placeholder="Paste your text here... (news article, government document, social media post, etc.)"></textarea>
105
+ <div class="flex justify-between items-center mt-3 mb-6">
106
+ <span id="charCount" class="text-xs text-gray-500">0 characters</span>
107
+ <span class="text-xs text-gray-500">Max 4000 characters analyzed</span>
108
  </div>
109
+ <button id="analyzeTextBtn" class="w-full bg-blue-600 hover:bg-blue-700 text-white font-medium py-4 px-8 rounded-xl text-lg transition-colors disabled:opacity-50 disabled:cursor-not-allowed">
110
+ <i class="fas fa-magnifying-glass mr-2"></i>Analyze Text
111
+ </button>
112
  </div>
113
+ </div>
114
 
115
+ <!-- ======= PDF TAB ======= -->
116
+ <div id="panel-pdf" class="hidden">
117
+ <div class="result-card rounded-2xl p-8 md:p-12 mb-12 shadow-xl">
118
+ <div id="pdfUploadArea" class="upload-area rounded-xl p-12 text-center cursor-pointer mb-8 hover:border-gray-400 transition-colors"
119
+ onclick="document.getElementById('pdfInput').click()">
120
+ <i class="fas fa-file-pdf text-4xl text-red-400 mb-6"></i>
121
+ <h3 class="text-xl font-semibold mb-3 text-gray-200">Upload PDF Document</h3>
122
+ <p class="text-gray-500 mb-4">Government docs, news articles, official notices (max 50MB)</p>
123
+ <p class="text-xs text-yellow-400"><i class="fas fa-clock mr-1"></i>PDF analysis takes ~30-60s (text + images analyzed)</p>
124
+ </div>
125
+ <input type="file" id="pdfInput" accept=".pdf,application/pdf" class="hidden">
126
+
127
+ <div id="pdfPreview" class="hidden mb-8 p-4 bg-gray-900/50 rounded-xl border border-gray-700">
128
+ <div class="flex items-center gap-3">
129
+ <i class="fas fa-file-pdf text-red-400 text-2xl"></i>
130
+ <div>
131
+ <p id="pdfFileName" class="text-gray-200 font-medium text-sm"></p>
132
+ <p id="pdfFileSize" class="text-gray-500 text-xs"></p>
133
+ </div>
134
+ </div>
135
+ </div>
136
+
137
+ <button id="analyzePdfBtn" class="hidden w-full bg-blue-600 hover:bg-blue-700 text-white font-medium py-4 px-8 rounded-xl text-lg transition-colors">
138
+ <i class="fas fa-magnifying-glass mr-2"></i>Analyze Document
139
+ </button>
140
+ </div>
141
  </div>
142
 
143
+ <!-- Progress Section (shared) -->
144
  <div id="progressSection" class="hidden result-card rounded-2xl p-12 mb-12">
145
  <div class="text-center mb-8">
146
  <div class="w-12 h-12 border-4 border-blue-500/20 border-t-blue-500 rounded-full animate-spin mx-auto mb-6"></div>
147
+ <p class="text-2xl font-semibold text-gray-100">Analyzing</p>
148
+ <p id="progressLabel" class="text-gray-500 mt-2 text-sm"></p>
149
  </div>
150
  <div class="w-full bg-gray-800 rounded-lg h-2.5 overflow-hidden">
151
  <div id="progressBar" class="progress-bar bg-blue-600 h-2.5 w-0"></div>
 
153
  <p id="progressText" class="text-center text-sm text-gray-500 mt-3">0%</p>
154
  </div>
155
 
156
+ <!-- Results Section (shared) -->
157
  <div id="resultsSection" class="hidden">
158
  <div class="result-card rounded-2xl p-8 md:p-12">
159
 
 
169
  <!-- Confidence warning -->
170
  <div id="confidenceWarning" class="hidden mb-6 p-4 rounded-xl border text-sm font-medium"></div>
171
 
172
+ <!-- Scores -->
173
  <div class="grid grid-cols-2 gap-4 mb-10">
174
  <div class="text-center p-5 bg-gray-900/50 rounded-xl border border-gray-700">
175
  <div id="scoreReal" class="text-3xl font-bold text-green-400 mb-1"></div>
 
193
  <div id="groqReasoning" class="p-4 bg-gray-900/50 rounded-xl border border-gray-700 text-sm text-gray-300 leading-relaxed"></div>
194
  </div>
195
 
196
+ <!-- Forensic Details -->
197
  <div class="p-5 bg-gray-900/50 rounded-xl border border-gray-700 mb-10 text-sm text-gray-400 space-y-2">
198
  <h4 class="text-sm font-semibold text-gray-400 uppercase tracking-wider mb-3">Forensic Details</h4>
199
  <p><span class="text-gray-500">SHA256:</span> <span id="hashValue" class="font-mono text-xs break-all"></span></p>
200
  <p id="metadataRiskRow"><span class="text-gray-500">Metadata Risk:</span> <span id="metadataRisk"></span></p>
 
201
  <p id="framesRow" class="hidden"><span class="text-gray-500">Frames Analyzed:</span> <span id="framesAnalyzed"></span></p>
202
  <p id="durationRow" class="hidden"><span class="text-gray-500">Video Duration:</span> <span id="videoDuration"></span></p>
203
  <p><span class="text-gray-500">Models Used:</span> <span id="modelsUsed"></span></p>
204
  </div>
205
 
 
206
  <div class="flex flex-col sm:flex-row gap-4">
207
  <button onclick="resetUI()" class="flex-1 bg-gray-700 hover:bg-gray-600 text-white font-medium py-3 px-6 rounded-xl border border-gray-600 transition-colors">
208
  <i class="fas fa-redo mr-2"></i> Analyze Another
 
212
  </div>
213
  </main>
214
 
 
215
  <footer class="border-t border-gray-800 p-8 text-center text-xs text-gray-500 bg-gray-900/50">
216
  DeepTrust Forensics | Advanced AI Detection | 2026
217
  </footer>
218
 
219
  <script>
220
+ // ===================== TABS =====================
221
+ let currentTab = 'media';
222
+
223
+ function switchTab(tab) {
224
+ ['media', 'text', 'pdf'].forEach(t => {
225
+ document.getElementById(`panel-${t}`).classList.add('hidden');
226
+ const btn = document.getElementById(`tab-${t}`);
227
+ btn.classList.remove('active');
228
+ btn.classList.add('text-gray-400');
229
+ });
230
+ document.getElementById(`panel-${tab}`).classList.remove('hidden');
231
+ const activeBtn = document.getElementById(`tab-${tab}`);
232
+ activeBtn.classList.add('active');
233
+ activeBtn.classList.remove('text-gray-400');
234
+ currentTab = tab;
235
+ document.getElementById('resultsSection').classList.add('hidden');
236
+ }
237
+
238
+ // ===================== MEDIA TAB =====================
239
  const uploadArea = document.getElementById('uploadArea');
240
  const fileInput = document.getElementById('fileInput');
241
  const analyzeBtn = document.getElementById('analyzeBtn');
 
258
  function showPreview(file) {
259
  const url = URL.createObjectURL(file);
260
  const isVideo = file.type.startsWith('video/');
 
261
  const imgEl = document.getElementById('previewImg');
262
  const videoEl = document.getElementById('previewVideo');
263
 
 
283
 
284
  document.getElementById('previewSection').classList.remove('hidden');
285
  analyzeBtn.classList.remove('hidden');
286
+ document.getElementById('progressLabel').textContent = isVideo
287
+ ? 'Analyzing 5 key frames with Groq Llama 4 Vision...'
288
+ : 'Running forensic analysis with Groq Llama 4 Vision...';
 
 
 
 
 
 
 
 
 
 
 
289
  }
290
 
291
  analyzeBtn.addEventListener('click', async () => {
292
  const file = fileInput.files[0];
293
  if (!file) return;
294
+ const isVideo = file.type.startsWith('video/');
295
 
296
  document.getElementById('uploadArea').style.display = 'none';
297
  document.getElementById('previewSection').style.display = 'none';
298
  analyzeBtn.style.display = 'none';
299
+ startProgress(isVideo ? 1 : 3);
300
 
301
+ const formData = new FormData();
302
+ formData.append("file", file);
303
+ await submitAndShow(formData);
304
+ });
305
+
306
+ // ===================== TEXT TAB =====================
307
+ const textInput = document.getElementById('textInput');
308
+ const charCount = document.getElementById('charCount');
309
+
310
+ textInput.addEventListener('input', () => {
311
+ charCount.textContent = textInput.value.length + ' characters';
312
+ });
313
+
314
+ document.getElementById('analyzeTextBtn').addEventListener('click', async () => {
315
+ const text = textInput.value.trim();
316
+ if (!text) { alert('Please paste some text first.'); return; }
317
+ if (text.length < 50) { alert('Text is too short for analysis. Please paste at least 50 characters.'); return; }
318
+
319
+ document.getElementById('panel-text').style.display = 'none';
320
+ document.getElementById('progressLabel').textContent = 'Analyzing text with RoBERTa + Groq Llama 3...';
321
+ startProgress(2);
322
+
323
+ const formData = new FormData();
324
+ formData.append("text", text);
325
+ await submitAndShow(formData);
326
+ });
327
+
328
+ // ===================== PDF TAB =====================
329
+ const pdfInput = document.getElementById('pdfInput');
330
+
331
+ pdfInput.addEventListener('change', e => {
332
+ const file = e.target.files[0];
333
+ if (!file) return;
334
+ if (file.size > 50 * 1024 * 1024) { alert('File exceeds 50MB limit.'); return; }
335
+ document.getElementById('pdfFileName').textContent = file.name;
336
+ document.getElementById('pdfFileSize').textContent = formatBytes(file.size);
337
+ document.getElementById('pdfPreview').classList.remove('hidden');
338
+ document.getElementById('analyzePdfBtn').classList.remove('hidden');
339
+ });
340
+
341
+ const pdfUploadArea = document.getElementById('pdfUploadArea');
342
+ ['dragenter', 'dragover', 'dragleave', 'drop'].forEach(e => {
343
+ pdfUploadArea.addEventListener(e, ev => { ev.preventDefault(); ev.stopPropagation(); });
344
+ });
345
+ ['dragenter', 'dragover'].forEach(e => pdfUploadArea.addEventListener(e, () => pdfUploadArea.classList.add('dragover')));
346
+ ['dragleave', 'drop'].forEach(e => pdfUploadArea.addEventListener(e, () => pdfUploadArea.classList.remove('dragover')));
347
+ pdfUploadArea.addEventListener('drop', e => {
348
+ const file = e.dataTransfer.files[0];
349
+ if (file && file.type === 'application/pdf') {
350
+ pdfInput.files = e.dataTransfer.files;
351
+ document.getElementById('pdfFileName').textContent = file.name;
352
+ document.getElementById('pdfFileSize').textContent = formatBytes(file.size);
353
+ document.getElementById('pdfPreview').classList.remove('hidden');
354
+ document.getElementById('analyzePdfBtn').classList.remove('hidden');
355
+ }
356
+ });
357
+
358
+ document.getElementById('analyzePdfBtn').addEventListener('click', async () => {
359
+ const file = pdfInput.files[0];
360
+ if (!file) return;
361
+
362
+ document.getElementById('pdfUploadArea').style.display = 'none';
363
+ document.getElementById('pdfPreview').style.display = 'none';
364
+ document.getElementById('analyzePdfBtn').style.display = 'none';
365
+ document.getElementById('progressLabel').textContent = 'Extracting text & images from PDF, analyzing with RoBERTa + Groq...';
366
+ startProgress(1);
367
+
368
+ const formData = new FormData();
369
+ formData.append("file", file);
370
+ await submitAndShow(formData);
371
+ });
372
+
373
+ // ===================== SHARED SUBMIT =====================
374
+ let progressInterval = null;
375
+
376
+ function startProgress(increment) {
377
+ document.getElementById('resultsSection').classList.add('hidden');
378
+ document.getElementById('progressSection').classList.remove('hidden');
379
  let progress = 0;
380
+ progressInterval = setInterval(() => {
381
+ progress += increment;
382
  if (progress > 90) progress = 90;
383
  document.getElementById('progressBar').style.width = progress + '%';
384
  document.getElementById('progressText').textContent = progress + '%';
385
  }, 400);
386
+ }
387
 
388
+ async function submitAndShow(formData) {
 
 
389
  try {
390
  const response = await fetch("/analyze", { method: "POST", body: formData });
391
  if (!response.ok) throw new Error("Server error");
392
  const data = await response.json();
393
 
394
+ clearInterval(progressInterval);
395
  document.getElementById('progressBar').style.width = '100%';
396
  document.getElementById('progressText').textContent = '100%';
397
 
 
401
  }, 400);
402
 
403
  } catch (error) {
404
+ clearInterval(progressInterval);
405
  document.getElementById('progressSection').classList.add('hidden');
406
  console.error(error);
407
  alert("Analysis failed. Check backend.");
408
  }
409
+ }
410
 
411
+ // ===================== SHOW RESULTS =====================
412
  function showResults(data) {
413
  const section = document.getElementById('resultsSection');
414
  section.classList.remove('hidden');
415
  section.scrollIntoView({ behavior: 'smooth' });
416
 
417
  const isAuthentic = data.authenticity > 50;
418
+ const type = data.type;
419
  const iconEl = document.getElementById('resultIcon');
420
 
421
  // confidence warning
 
432
  warningEl.classList.add('hidden');
433
  }
434
 
435
+ // verdict titles based on type
436
+ const titles = {
437
+ image: ['Authentic Media Detected', 'Potential Deepfake Detected'],
438
+ video: ['Authentic Video Detected', 'Potential Deepfake Video Detected'],
439
+ text: ['Authentic Text Detected', 'Potentially Fake / AI-Generated Text'],
440
+ pdf: ['Authentic Document Detected', 'Potentially Forged / AI-Generated Document'],
441
+ };
442
+
443
  if (isAuthentic) {
444
  iconEl.innerHTML = '<i class="fas fa-check text-green-500 text-2xl"></i>';
445
+ document.getElementById('resultTitle').textContent = titles[type]?.[0] || 'Authentic';
446
+ document.getElementById('resultSubtitle').textContent = 'No signs of manipulation or AI generation found.';
447
  } else {
448
  iconEl.innerHTML = '<i class="fas fa-triangle-exclamation text-orange-500 text-2xl"></i>';
449
+ document.getElementById('resultTitle').textContent = titles[type]?.[1] || 'Suspicious';
450
+ document.getElementById('resultSubtitle').textContent = 'Signs of fabrication or AI generation detected.';
451
  }
452
 
453
  document.getElementById('scoreReal').textContent = Math.round(data.authenticity) + '%';
 
455
  document.getElementById('hashValue').textContent = data.sha256;
456
  document.getElementById('modelsUsed').textContent = (data.models_used || []).join(', ');
457
 
458
+ // forensic details
459
+ if (type === 'video') {
460
  document.getElementById('metadataRiskRow').classList.add('hidden');
461
  document.getElementById('framesRow').classList.remove('hidden');
462
  document.getElementById('durationRow').classList.remove('hidden');
 
472
  // model breakdown
473
  const modelDiv = document.getElementById('modelBreakdown');
474
  modelDiv.innerHTML = '';
475
+
476
+ // build model list based on type
477
+ let models = [];
478
+ if (type === 'text' || type === 'pdf') {
479
+ models = [
480
+ { name: 'RoBERTa Fake News', icon: 'fa-newspaper', color: 'text-purple-400', score: data.details.roberta_fakenews_score },
481
+ { name: 'RoBERTa AI Detector', icon: 'fa-robot', color: 'text-blue-400', score: data.details.roberta_aidetector_score },
482
+ { name: 'Groq Llama 3 (Text)', icon: 'fa-brain', color: 'text-orange-400', score: data.details.groq_score === 'see breakdown' ? 'unavailable' : data.details.groq_score },
483
+ ];
484
+ } else {
485
+ models = [
486
+ { name: `Groq Llama 4 Vision${type === 'video' ? ' (avg 5 frames)' : ''}`, icon: 'fa-brain', color: 'text-orange-400', score: data.details.groq_score },
487
+ ];
488
+ }
489
+
490
+ models.forEach(({ name, icon, color, score }) => {
491
+ const isUnavailable = score === 'unavailable' || score === null;
492
+ const pct = isUnavailable ? 0 : Math.round(score * 100);
493
+ const barColor = isUnavailable ? 'bg-gray-600' : score > 0.5 ? 'bg-red-500' : 'bg-green-500';
494
+ const textColor = isUnavailable ? 'text-gray-500' : score > 0.5 ? 'text-red-400' : 'text-green-400';
495
+ modelDiv.innerHTML += `
496
+ <div class="p-4 bg-gray-900/50 rounded-xl border border-gray-700">
497
+ <div class="flex justify-between items-center mb-2">
498
+ <span class="text-sm text-gray-300 font-medium">
499
+ <i class="fas ${icon} mr-2 ${color}"></i>${name}
500
+ </span>
501
+ <span class="text-sm font-bold ${textColor}">
502
+ ${isUnavailable ? 'Unavailable' : pct + '% fake'}
503
+ </span>
504
+ </div>
505
+ <div class="w-full bg-gray-800 rounded-full h-2">
506
+ <div class="${barColor} h-2 rounded-full" style="width: ${pct}%"></div>
507
+ </div>
508
+ </div>`;
509
+ });
510
 
511
  // AI reasoning
512
  if (data.details.groq_reasoning) {
 
517
  }
518
  }
519
 
520
+ // ===================== UTILS =====================
521
+ function formatBytes(bytes) {
522
+ if (bytes === 0) return '0 B';
523
+ const sizes = ['B', 'KB', 'MB'];
524
+ const i = Math.floor(Math.log(bytes) / Math.log(1024));
525
+ return (bytes / Math.pow(1024, i)).toFixed(1) + ' ' + sizes[i];
526
+ }
527
+
528
  function resetUI() {
529
  document.getElementById('resultsSection').classList.add('hidden');
530
+ document.getElementById('confidenceWarning').classList.add('hidden');
531
+ document.getElementById('groqReasoningSection').classList.add('hidden');
532
+ document.getElementById('progressBar').style.width = '0%';
533
+ document.getElementById('progressText').textContent = '0%';
534
+
535
+ // reset media
536
  document.getElementById('uploadArea').style.display = 'block';
537
  document.getElementById('previewSection').classList.add('hidden');
538
  document.getElementById('previewSection').style.display = '';
539
+ document.getElementById('analyzeBtn').classList.add('hidden');
540
+ document.getElementById('analyzeBtn').style.display = '';
 
 
 
 
541
  document.getElementById('previewImg').classList.add('hidden');
542
  document.getElementById('previewVideo').classList.add('hidden');
543
  fileInput.value = '';
544
+
545
+ // reset text
546
+ document.getElementById('panel-text').style.display = '';
547
+ textInput.value = '';
548
+ charCount.textContent = '0 characters';
549
+
550
+ // reset pdf
551
+ document.getElementById('pdfUploadArea').style.display = 'block';
552
+ document.getElementById('pdfPreview').classList.add('hidden');
553
+ document.getElementById('pdfPreview').style.display = '';
554
+ document.getElementById('analyzePdfBtn').classList.add('hidden');
555
+ document.getElementById('analyzePdfBtn').style.display = '';
556
+ pdfInput.value = '';
557
  }
558
  </script>
559
  </body>