Deepfake Authenticator commited on
Commit
cede9a4
Β·
1 Parent(s): 7f580a0

feat: make nav links functional (Dashboard/Agents/Logs/Network)

Browse files

- Dashboard: navigates to hero/upload section
- Agents: modal showing all 5 AI agents with descriptions and tech stack
- Logs: modal showing session history (last 20 analyses with verdict/confidence)
- Network: modal showing live health check, model status, API endpoint
- Escape key closes any open modal
- Click outside modal to dismiss
- Logs auto-populate after each analysis

Files changed (1) hide show
  1. frontend-vanilla/index.html +218 -5
frontend-vanilla/index.html CHANGED
@@ -273,12 +273,12 @@
273
  <nav class="fixed top-0 left-0 w-full z-50 flex justify-between items-center px-6 h-16 bg-emerald-950/20 backdrop-blur-xl border-b border-emerald-500/20 shadow-[0_4px_20px_rgba(0,0,0,0.5)] font-['Space_Grotesk'] tracking-wider uppercase text-xs">
274
  <!-- Brand -->
275
  <div class="flex items-center gap-8">
276
- <span class="text-2xl font-black tracking-tighter text-emerald-400 drop-shadow-[0_0_8px_rgba(0,255,156,0.5)]">AUTHRIX AI</span>
277
  <div class="hidden md:flex items-center gap-6">
278
- <a class="text-emerald-800/60 hover:text-emerald-400 transition-colors hover:bg-emerald-400/10 py-1 px-2 rounded-sm" href="#">Dashboard</a>
279
- <a class="text-emerald-800/60 hover:text-emerald-400 transition-colors hover:bg-emerald-400/10 py-1 px-2 rounded-sm" href="#">Agents</a>
280
- <a class="text-emerald-800/60 hover:text-emerald-400 transition-colors hover:bg-emerald-400/10 py-1 px-2 rounded-sm" href="#">Logs</a>
281
- <a class="text-emerald-800/60 hover:text-emerald-400 transition-colors hover:bg-emerald-400/10 py-1 px-2 rounded-sm" href="#">Network</a>
282
  </div>
283
  </div>
284
  <!-- Actions -->
@@ -736,6 +736,126 @@
736
  </div>
737
  </section>
738
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
739
  <!-- ═══════════════════════════════════════════════════════════
740
  FOOTER
741
  ════════════════════════════════════════════════════════════ -->
@@ -920,6 +1040,7 @@ async function analyzeVideo() {
920
  }
921
  const data = await res.json();
922
  stopPipelineAnimation();
 
923
  renderResults(data);
924
  showState('resultsSection');
925
  } catch (err) {
@@ -1292,6 +1413,98 @@ function escHtml(str) {
1292
  .replace(/>/g, '&gt;')
1293
  .replace(/"/g, '&quot;');
1294
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1295
  </script>
1296
  </body>
1297
  </html>
 
273
  <nav class="fixed top-0 left-0 w-full z-50 flex justify-between items-center px-6 h-16 bg-emerald-950/20 backdrop-blur-xl border-b border-emerald-500/20 shadow-[0_4px_20px_rgba(0,0,0,0.5)] font-['Space_Grotesk'] tracking-wider uppercase text-xs">
274
  <!-- Brand -->
275
  <div class="flex items-center gap-8">
276
+ <span onclick="showState('heroSection')" class="text-2xl font-black tracking-tighter text-emerald-400 drop-shadow-[0_0_8px_rgba(0,255,156,0.5)] cursor-pointer">AUTHRIX AI</span>
277
  <div class="hidden md:flex items-center gap-6">
278
+ <a onclick="showState('heroSection')" class="text-emerald-800/60 hover:text-emerald-400 transition-colors hover:bg-emerald-400/10 py-1 px-2 rounded-sm cursor-pointer">Dashboard</a>
279
+ <a onclick="openModal('agentsModal')" class="text-emerald-800/60 hover:text-emerald-400 transition-colors hover:bg-emerald-400/10 py-1 px-2 rounded-sm cursor-pointer">Agents</a>
280
+ <a onclick="openModal('logsModal')" class="text-emerald-800/60 hover:text-emerald-400 transition-colors hover:bg-emerald-400/10 py-1 px-2 rounded-sm cursor-pointer">Logs</a>
281
+ <a onclick="openModal('networkModal')" class="text-emerald-800/60 hover:text-emerald-400 transition-colors hover:bg-emerald-400/10 py-1 px-2 rounded-sm cursor-pointer">Network</a>
282
  </div>
283
  </div>
284
  <!-- Actions -->
 
736
  </div>
737
  </section>
738
 
739
+ <!-- ═══════════════════════════════════════════════════════════
740
+ MODALS
741
+ ════════════════════════════════════════════════════════════ -->
742
+ <style>
743
+ .modal-backdrop {
744
+ position:fixed;inset:0;z-index:200;
745
+ background:rgba(0,0,0,0.8);backdrop-filter:blur(6px);
746
+ display:flex;align-items:center;justify-content:center;padding:24px;
747
+ animation:fadeIn 0.2s ease;
748
+ }
749
+ .modal-box {
750
+ background:#141e17;border:1px solid rgba(0,255,156,0.2);border-radius:12px;
751
+ width:100%;max-width:640px;max-height:80vh;overflow-y:auto;
752
+ box-shadow:0 0 60px rgba(0,255,156,0.1);animation:slideUp 0.25s ease;
753
+ }
754
+ @keyframes slideUp{from{opacity:0;transform:translateY(20px);}to{opacity:1;transform:none;}}
755
+ .modal-header{display:flex;align-items:center;justify-content:space-between;padding:20px 24px 16px;border-bottom:1px solid rgba(0,255,156,0.1);}
756
+ .modal-body{padding:20px 24px 24px;}
757
+ .modal-close{background:none;border:none;cursor:pointer;color:#849587;font-size:18px;padding:4px 8px;border-radius:4px;transition:color 0.2s;font-family:inherit;}
758
+ .modal-close:hover{color:#ffb4ab;}
759
+ .agent-row{display:flex;align-items:flex-start;gap:14px;padding:14px;border-radius:8px;background:rgba(35,44,37,0.3);border:1px solid rgba(0,255,156,0.08);margin-bottom:10px;}
760
+ .agent-icon{width:40px;height:40px;border-radius:8px;flex-shrink:0;background:rgba(0,255,156,0.08);border:1px solid rgba(0,255,156,0.2);display:flex;align-items:center;justify-content:center;font-size:18px;}
761
+ .log-row{display:flex;justify-content:space-between;align-items:center;padding:10px 0;border-bottom:1px solid rgba(255,255,255,0.05);font-family:'Space Grotesk',monospace;font-size:12px;gap:12px;}
762
+ .log-row:last-child{border-bottom:none;}
763
+ .net-row{display:flex;justify-content:space-between;align-items:center;padding:10px 14px;border-radius:6px;background:rgba(35,44,37,0.3);border:1px solid rgba(0,255,156,0.08);margin-bottom:8px;font-family:'Space Grotesk',monospace;font-size:12px;}
764
+ </style>
765
+
766
+ <!-- Agents Modal -->
767
+ <div id="agentsModal" style="display:none;" class="modal-backdrop" onclick="if(event.target===this)closeModal('agentsModal')">
768
+ <div class="modal-box">
769
+ <div class="modal-header">
770
+ <div>
771
+ <div style="font-size:11px;font-weight:700;letter-spacing:0.15em;color:#00ff9c;text-transform:uppercase;">AGENT PIPELINE</div>
772
+ <div style="font-size:12px;color:#849587;margin-top:4px;">5 specialized AI agents run in sequence</div>
773
+ </div>
774
+ <button class="modal-close" onclick="closeModal('agentsModal')">βœ•</button>
775
+ </div>
776
+ <div class="modal-body">
777
+ <div class="agent-row">
778
+ <div class="agent-icon">🎬</div>
779
+ <div>
780
+ <div style="font-size:14px;font-weight:600;color:#dae5da;">Frame Analyzer Agent</div>
781
+ <div style="font-size:12px;color:#849587;margin-top:4px;line-height:1.5;">Extracts 40 frames uniformly across the full video using OpenCV. Uniform temporal sampling ensures coverage regardless of video length.</div>
782
+ <div style="margin-top:6px;font-size:10px;font-weight:700;letter-spacing:0.1em;color:rgba(0,255,156,0.5);text-transform:uppercase;">OpenCV Β· Uniform sampling Β· Max 40 frames</div>
783
+ </div>
784
+ </div>
785
+ <div class="agent-row">
786
+ <div class="agent-icon">πŸ‘€</div>
787
+ <div>
788
+ <div style="font-size:14px;font-weight:600;color:#dae5da;">Face Detector Agent</div>
789
+ <div style="font-size:12px;color:#849587;margin-top:4px;line-height:1.5;">Detects and crops faces using MediaPipe. Applies a quality gate β€” blurry crops (blur &lt; 40) are discarded before model inference.</div>
790
+ <div style="margin-top:6px;font-size:10px;font-weight:700;letter-spacing:0.1em;color:rgba(0,255,156,0.5);text-transform:uppercase;">MediaPipe Β· Quality gate Β· 20% padding</div>
791
+ </div>
792
+ </div>
793
+ <div class="agent-row">
794
+ <div class="agent-icon">🧠</div>
795
+ <div>
796
+ <div style="font-size:14px;font-weight:600;color:#dae5da;">Decision Agent (ViT Ensemble)</div>
797
+ <div style="font-size:12px;color:#849587;margin-top:4px;line-height:1.5;">Runs two Vision Transformer models on each face crop. Scores aggregated with mean + median blend and adaptive thresholding based on frame consistency.</div>
798
+ <div style="margin-top:6px;font-size:10px;font-weight:700;letter-spacing:0.1em;color:rgba(0,255,156,0.5);text-transform:uppercase;">dima806 (99.3%) Β· prithivMLmods (92.1%) Β· Adaptive threshold</div>
799
+ </div>
800
+ </div>
801
+ <div class="agent-row">
802
+ <div class="agent-icon">πŸŽ™οΈ</div>
803
+ <div>
804
+ <div style="font-size:14px;font-weight:600;color:#dae5da;">Audio Analysis Agent</div>
805
+ <div style="font-size:12px;color:#849587;margin-top:4px;line-height:1.5;">Extracts audio via moviepy, runs librosa heuristics (pitch variance, MFCC delta, spectral flatness) and Wav2Vec2 ASVspoof model. Detects AI voices and audio-visual mismatch.</div>
806
+ <div style="margin-top:6px;font-size:10px;font-weight:700;letter-spacing:0.1em;color:rgba(0,227,253,0.5);text-transform:uppercase;">Wav2Vec2 (92.8%) Β· Librosa Β· AV mismatch detection</div>
807
+ </div>
808
+ </div>
809
+ <div class="agent-row">
810
+ <div class="agent-icon">πŸ“Š</div>
811
+ <div>
812
+ <div style="font-size:14px;font-weight:600;color:#dae5da;">Report Generator Agent</div>
813
+ <div style="font-size:12px;color:#849587;margin-top:4px;line-height:1.5;">Combines visual + audio scores into a final verdict. AV_MISMATCH (face-swap with dubbed audio) overrides visual REAL verdict. Generates insights and frame timeline.</div>
814
+ <div style="margin-top:6px;font-size:10px;font-weight:700;letter-spacing:0.1em;color:rgba(0,255,156,0.5);text-transform:uppercase;">AV mismatch Β· Confidence calibration Β· Insight generation</div>
815
+ </div>
816
+ </div>
817
+ </div>
818
+ </div>
819
+ </div>
820
+
821
+ <!-- Logs Modal -->
822
+ <div id="logsModal" style="display:none;" class="modal-backdrop" onclick="if(event.target===this)closeModal('logsModal')">
823
+ <div class="modal-box">
824
+ <div class="modal-header">
825
+ <div>
826
+ <div style="font-size:11px;font-weight:700;letter-spacing:0.15em;color:#00ff9c;text-transform:uppercase;">ANALYSIS LOGS</div>
827
+ <div style="font-size:12px;color:#849587;margin-top:4px;">Session history (last 20 analyses)</div>
828
+ </div>
829
+ <button class="modal-close" onclick="closeModal('logsModal')">βœ•</button>
830
+ </div>
831
+ <div class="modal-body">
832
+ <div id="logsContent">
833
+ <div style="font-size:12px;color:#849587;text-align:center;padding:32px 0;opacity:0.5;">
834
+ No analyses run this session.<br/>Upload a video to begin.
835
+ </div>
836
+ </div>
837
+ </div>
838
+ </div>
839
+ </div>
840
+
841
+ <!-- Network Modal -->
842
+ <div id="networkModal" style="display:none;" class="modal-backdrop" onclick="if(event.target===this)closeModal('networkModal')">
843
+ <div class="modal-box">
844
+ <div class="modal-header">
845
+ <div>
846
+ <div style="font-size:11px;font-weight:700;letter-spacing:0.15em;color:#00ff9c;text-transform:uppercase;">NETWORK STATUS</div>
847
+ <div style="font-size:12px;color:#849587;margin-top:4px;">Model endpoints and system health</div>
848
+ </div>
849
+ <button class="modal-close" onclick="closeModal('networkModal')">βœ•</button>
850
+ </div>
851
+ <div class="modal-body">
852
+ <div id="networkContent">
853
+ <div style="font-size:12px;color:#849587;text-align:center;padding:24px 0;opacity:0.5;">Checking...</div>
854
+ </div>
855
+ </div>
856
+ </div>
857
+ </div>
858
+
859
  <!-- ═══════════════════════════════════════════════════════════
860
  FOOTER
861
  ════════════════════════════════════════════════════════════ -->
 
1040
  }
1041
  const data = await res.json();
1042
  stopPipelineAnimation();
1043
+ logAnalysis(data, selectedFile?.name);
1044
  renderResults(data);
1045
  showState('resultsSection');
1046
  } catch (err) {
 
1413
  .replace(/>/g, '&gt;')
1414
  .replace(/"/g, '&quot;');
1415
  }
1416
+
1417
+ // ── Modal helpers ─────────────────────────────────────────────────────────────
1418
+ function openModal(id) {
1419
+ const el = document.getElementById(id);
1420
+ if (!el) return;
1421
+ el.style.display = 'flex';
1422
+ if (id === 'networkModal') refreshNetworkModal();
1423
+ if (id === 'logsModal') refreshLogsModal();
1424
+ }
1425
+ function closeModal(id) {
1426
+ const el = document.getElementById(id);
1427
+ if (el) el.style.display = 'none';
1428
+ }
1429
+ // Close on Escape
1430
+ document.addEventListener('keydown', e => {
1431
+ if (e.key === 'Escape') {
1432
+ ['agentsModal','logsModal','networkModal'].forEach(closeModal);
1433
+ }
1434
+ });
1435
+
1436
+ // ── Logs modal ────────────────────────────────────────────────────────────────
1437
+ const _sessionLogs = [];
1438
+
1439
+ function logAnalysis(data, filename) {
1440
+ _sessionLogs.unshift({
1441
+ ts: new Date().toLocaleTimeString(),
1442
+ file: filename || 'unknown',
1443
+ result: data.result,
1444
+ confidence: data.confidence,
1445
+ duration: data.metadata?.video_duration_sec ?? 'β€”',
1446
+ procTime: data.processing_time_sec ?? 'β€”',
1447
+ });
1448
+ if (_sessionLogs.length > 20) _sessionLogs.pop();
1449
+ }
1450
+
1451
+ function refreshLogsModal() {
1452
+ const el = document.getElementById('logsContent');
1453
+ if (!_sessionLogs.length) {
1454
+ el.innerHTML = `<div class="font-data-mono text-data-mono text-on-surface-variant text-xs text-center py-8 opacity-50">
1455
+ No analyses run this session.<br/>Upload a video to begin.</div>`;
1456
+ return;
1457
+ }
1458
+ el.innerHTML = _sessionLogs.map(log => {
1459
+ const isFake = log.result === 'FAKE';
1460
+ const color = isFake ? '#ffb4ab' : '#00ff9c';
1461
+ return `
1462
+ <div class="log-row">
1463
+ <div style="display:flex;align-items:center;gap:10px;flex:1;min-width:0;">
1464
+ <span class="material-symbols-outlined text-[14px]" style="color:${color};flex-shrink:0;">${isFake ? 'gpp_bad' : 'verified_user'}</span>
1465
+ <span style="color:#dae5da;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:200px;">${escHtml(log.file)}</span>
1466
+ </div>
1467
+ <div style="display:flex;align-items:center;gap:16px;flex-shrink:0;">
1468
+ <span style="color:${color};font-weight:700;">${log.result}</span>
1469
+ <span style="color:#849587;">${log.confidence}%</span>
1470
+ <span style="color:#849587;font-size:11px;">${log.ts}</span>
1471
+ </div>
1472
+ </div>`;
1473
+ }).join('');
1474
+ }
1475
+
1476
+ // ── Network modal ─────────────────────────────────────────────────────────────
1477
+ async function refreshNetworkModal() {
1478
+ const el = document.getElementById('networkContent');
1479
+ el.innerHTML = `<div class="font-data-mono text-data-mono text-on-surface-variant text-xs text-center py-6 opacity-50">Checking...</div>`;
1480
+
1481
+ let health = null;
1482
+ try {
1483
+ const r = await fetch(API_BASE + '/health');
1484
+ health = await r.json();
1485
+ } catch (_) {}
1486
+
1487
+ const rows = [
1488
+ { label: 'API Server', value: health ? 'ONLINE' : 'OFFLINE', ok: !!health },
1489
+ { label: 'Visual Models', value: health?.model ?? 'β€”', ok: health?.ready },
1490
+ { label: 'dima806 ViT (99.3%)', value: health?.ready ? 'LOADED' : 'PENDING', ok: health?.ready },
1491
+ { label: 'prithivMLmods ViT', value: health?.ready ? 'LOADED' : 'PENDING', ok: health?.ready },
1492
+ { label: 'Audio Wav2Vec2', value: health?.ready ? 'LOADED' : 'PENDING', ok: health?.ready },
1493
+ { label: 'Inference Mode', value: 'LOCAL (CPU)', ok: true },
1494
+ { label: 'Endpoint', value: API_BASE, ok: true },
1495
+ ];
1496
+
1497
+ el.innerHTML = rows.map(r => `
1498
+ <div class="net-row">
1499
+ <span style="color:#849587;letter-spacing:0.08em;">${r.label}</span>
1500
+ <span style="color:${r.ok ? '#00ff9c' : '#ffb4ab'};font-weight:700;">${escHtml(String(r.value))}</span>
1501
+ </div>`).join('') +
1502
+ `<div style="margin-top:14px;padding-top:12px;border-top:1px solid rgba(255,255,255,0.05);">
1503
+ <button onclick="refreshNetworkModal()" style="background:none;border:1px solid rgba(0,255,156,0.3);color:#00ff9c;padding:6px 14px;border-radius:4px;font-family:inherit;font-size:11px;letter-spacing:0.1em;cursor:pointer;transition:all 0.2s;" onmouseover="this.style.background='rgba(0,255,156,0.08)'" onmouseout="this.style.background='none'">
1504
+ ↻ REFRESH
1505
+ </button>
1506
+ </div>`;
1507
+ }
1508
  </script>
1509
  </body>
1510
  </html>