import re with open(r"d:\ANTIGRAVITY\templates\index.html", "r", encoding="utf-8") as f: html = f.read() css_addition = """ /* New Forensic Report Styles */ .risk-badge { font-size: 0.75rem; font-weight: 700; padding: 4px 10px; border-radius: 20px; text-transform: uppercase; letter-spacing: 1px; margin-left: 10px; display: inline-block; } .risk-high { background: rgba(255, 42, 85, 0.2); color: var(--danger); border: 1px solid var(--danger-glow); animation: pulse-risk 2s infinite; } .risk-medium { background: rgba(255, 204, 0, 0.2); color: var(--warning); border: 1px solid rgba(255, 204, 0, 0.4); } .risk-low { background: rgba(0, 255, 170, 0.2); color: #00ffaa; border: 1px solid rgba(0, 255, 170, 0.4); } @keyframes pulse-risk { 0% { box-shadow: 0 0 0 0 var(--danger-glow); } 70% { box-shadow: 0 0 0 10px rgba(255, 42, 85, 0); } 100% { box-shadow: 0 0 0 0 rgba(255, 42, 85, 0); } } .report-section { background: rgba(255, 255, 255, 0.02); border: 1px solid rgba(255, 255, 255, 0.05); border-radius: 12px; padding: 20px; display: flex; flex-direction: column; gap: 15px; } .report-section-title { font-family: 'Space Grotesk', sans-serif; font-size: 1.1rem; font-weight: 600; color: var(--accent); display: flex; align-items: center; gap: 8px; border-bottom: 1px solid rgba(255,255,255,0.05); padding-bottom: 10px; } .evidence-list { list-style: none; display: flex; flex-direction: column; gap: 8px; } .evidence-list li { display: flex; align-items: flex-start; gap: 10px; font-size: 0.85rem; color: var(--text-main); } .evidence-list li i { margin-top: 3px; color: var(--accent); } .breakdown-table { display: flex; flex-direction: column; gap: 12px; } .breakdown-row { display: flex; flex-direction: column; gap: 5px; } .breakdown-meta { display: flex; justify-content: space-between; font-size: 0.85rem; } .breakdown-bar-bg { width: 100%; height: 6px; background: rgba(255,255,255,0.05); border-radius: 3px; overflow: hidden; } .breakdown-bar-fill { height: 100%; border-radius: 3px; transition: width 1s cubic-bezier(0.1, 0.8, 0.2, 1); width: 0%; } /* Tab Styles */ .tabs { display: flex; gap: 10px; border-bottom: 1px solid rgba(255,255,255,0.05); padding-bottom: 10px; flex-wrap: wrap; } .tab-btn { background: none; border: none; color: var(--text-muted); font-family: inherit; font-size: 0.9rem; cursor: pointer; padding: 5px 10px; transition: all 0.3s; border-radius: 4px; } .tab-btn:hover { color: var(--text-main); background: rgba(255,255,255,0.05); } .tab-btn.active { color: var(--accent); background: rgba(0, 240, 255, 0.1); } .tab-content { display: none; margin-top: 15px; } .tab-content.active { display: block; } .heatmap-img { width: 100%; border-radius: 8px; border: 1px solid var(--border-glow); } .meta-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 15px; } .meta-item { display: flex; flex-direction: column; gap: 5px; } .meta-label { font-size: 0.75rem; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.5px; } .meta-val { font-size: 0.9rem; font-weight: 500; } .pill-list { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 10px; } .pill { background: rgba(255,255,255,0.05); border: 1px solid rgba(255,255,255,0.1); padding: 4px 10px; border-radius: 12px; font-size: 0.75rem; color: var(--text-muted); } .collapsible-header { display: flex; justify-content: space-between; align-items: center; cursor: pointer; padding: 15px; background: rgba(255,255,255,0.02); border: 1px solid rgba(255,255,255,0.05); border-radius: 8px; margin-top: 15px; } .collapsible-header:hover { background: rgba(255,255,255,0.04); } .collapsible-content { display: none; padding: 15px; border: 1px solid rgba(255,255,255,0.05); border-top: none; border-radius: 0 0 8px 8px; margin-top: -8px; background: rgba(0,0,0,0.2); } .identity-table { width: 100%; border-collapse: collapse; font-size: 0.85rem; } .identity-table th, .identity-table td { padding: 8px; text-align: left; border-bottom: 1px solid rgba(255,255,255,0.05); } .identity-table th { color: var(--text-muted); font-weight: 500; } .identity-table tr.flagged td { color: var(--danger); } """ html = html.replace('/* Admin float link */', css_addition + '\n /* Admin float link */') html_structure = """

DEEPFAKE DETECTED HIGH RISK

High probability of synthetic rendering detected.

97%
Original Input
Aligned Crop
""" start_str = """ """ end_str = """
""" html = html.replace(html[html.find(start_str):html.find(end_str)+len(end_str)], html_structure) js_addition = """
""" html = html.replace("""
""", js_addition) js_logic = """ function toggleStats() { const content = document.getElementById('stats-content'); const chevron = document.getElementById('stats-chevron'); if (content.style.display === 'block') { content.style.display = 'none'; chevron.className = 'fa-solid fa-chevron-down'; } else { content.style.display = 'block'; chevron.className = 'fa-solid fa-chevron-up'; } } function renderForensicReport(data) { resultsEmpty.style.display = 'none'; resultsContainer.style.display = 'flex'; // Trigger animation frame setTimeout(() => { resultsContainer.classList.add('visible'); }, 50); // Populate media if (data.is_video) { resultImgOrig.style.display = 'none'; resultVideoOrig.style.display = 'block'; resultVideoOrig.src = data.image_url; resultImgAligned.style.display = 'none'; } else { resultVideoOrig.style.display = 'none'; resultImgOrig.style.display = 'block'; resultImgOrig.src = data.image_url; resultImgAligned.style.display = 'block'; resultImgAligned.src = data.aligned_url || data.image_url; } // Aligned crop scan animation toggle if (data.aligned_url) { alignedBox.classList.add('scan-line-active'); } else { alignedBox.classList.remove('scan-line-active'); } // --- 1. Verdict Banner --- let prediction = data.prediction; let confidence = data.confidence; let riskLevel = 'MEDIUM'; if (data.verdict) { prediction = data.verdict.final_prediction; confidence = data.verdict.final_confidence; riskLevel = data.verdict.risk_level || 'MEDIUM'; } const isFake = prediction === 'FAKE'; verdictBanner.className = 'verdict-banner ' + (isFake ? 'fake' : 'real'); const riskBadge = document.getElementById('risk-badge'); if (riskBadge) { riskBadge.textContent = riskLevel + " RISK"; riskBadge.className = 'risk-badge ' + (riskLevel === 'HIGH' ? 'risk-high' : (riskLevel === 'LOW' ? 'risk-low' : 'risk-medium')); } let verdictTitleText, verdictDescText; if (data.is_video) { verdictTitleText = isFake ? 'Verdict: AI Generated Video' : 'Verdict: Real Video'; verdictDescText = isFake ? 'Temporal frame analysis identifies high-confidence markers of video deepfake manipulation.' : 'Frame-by-frame forensic scan confirms temporal consistency consistent with organic footage.'; } else if (data.method === 'general_vit_detector') { verdictTitleText = isFake ? 'Verdict: AI Generated Image' : 'Verdict: Real Image'; verdictDescText = isFake ? 'General AI image detector (no face found) identifies AI-synthesis artefacts.' : 'General AI image analysis finds no synthetic generation markers.'; } else { verdictTitleText = isFake ? 'Verdict: AI Generated' : 'Verdict: Real Image'; verdictDescText = isFake ? 'Decomposition scan identifies high-confidence markers of synthetic rendering / deepfake.' : 'Microscopic texture analysis confirms organic, camera-sensor origins.'; } let riskBadgeHtml = `${riskLevel} RISK`; verdictTitle.innerHTML = `${verdictTitleText} ${riskBadgeHtml}`; verdictDescription.textContent = verdictDescText; verdictPercentage.innerHTML = `${Math.round(confidence)}%`; if (data.note) { verdictDescription.textContent += ' [' + data.note + ']'; } // Helper to render breakdown bars function createBreakdownBar(label, value, isSourceFake) { const color = isSourceFake ? 'var(--danger)' : 'var(--accent)'; return `
${label} ${value.toFixed(1)}%
`; } // --- 2. Evidence Summary Card --- if (data.evidence_summary && data.evidence_summary.length > 0) { document.getElementById('evidence-card').style.display = 'flex'; const ul = document.getElementById('evidence-list'); ul.innerHTML = ''; data.evidence_summary.forEach(ev => { ul.innerHTML += `
  • ${ev}
  • `; }); } else { document.getElementById('evidence-card').style.display = 'none'; } // --- 3. Confidence Breakdown Table --- if (data.confidence_breakdown) { document.getElementById('confidence-breakdown-card').style.display = 'flex'; const list = document.getElementById('confidence-breakdown-list'); let html = ''; const displayNames = { 'image_ensemble': 'Image Ensemble', 'frequency_analysis': 'Frequency Analysis', 'ela_analysis': 'Error Level Analysis', 'metadata_forensics': 'Metadata Forensics', 'temporal_consistency': 'Temporal Consistency', 'audio_analysis': 'Audio Analysis' }; for (const [key, val] of Object.entries(data.confidence_breakdown)) { const label = displayNames[key] || key; const isFakeSource = val > 50; html += createBreakdownBar(label, val, isFakeSource); } list.innerHTML = html; setTimeout(() => { document.querySelectorAll('#confidence-breakdown-list .breakdown-bar-fill').forEach(el => { el.style.width = el.style.width; // Trigger reflow is implicitly handled if we set it in HTML but let's animate }); }, 100); } else { document.getElementById('confidence-breakdown-card').style.display = 'none'; } // --- 4. Heatmap Carousel --- if (data.artifact_localization && (data.artifact_localization.ela_url || data.artifact_localization.freq_url || data.artifact_localization.attention_url)) { document.getElementById('heatmap-card').style.display = 'flex'; const tabs = document.getElementById('heatmap-tabs'); const contents = document.getElementById('heatmap-contents'); tabs.innerHTML = ''; contents.innerHTML = ''; const loc = data.artifact_localization; let first = true; function addTab(id, label, url) { if (!url) return; tabs.innerHTML += ``; contents.innerHTML += `
    `; first = false; } addTab('ela', 'Error Level Analysis', loc.ela_url); addTab('freq', 'Frequency Anomaly', loc.freq_url); addTab('attn', 'ViT Attention', loc.attention_url); window.switchTab = function(id) { document.querySelectorAll('.tab-btn').forEach(b => b.classList.remove('active')); document.querySelectorAll('.tab-content').forEach(c => c.classList.remove('active')); document.getElementById('btn-' + id).classList.add('active'); document.getElementById('content-' + id).classList.add('active'); }; } else { document.getElementById('heatmap-card').style.display = 'none'; } // --- 5. Ensemble Breakdown Card --- if (data.ensemble) { document.getElementById('ensemble-card').style.display = 'flex'; const list = document.getElementById('ensemble-breakdown-list'); let html = ''; if(data.ensemble.primary_score !== undefined) html += createBreakdownBar('Primary ViT (Face)', data.ensemble.primary_score, data.ensemble.primary_score > 50); if(data.ensemble.secondary_score !== undefined) html += createBreakdownBar('Secondary ViT (General)', data.ensemble.secondary_score, data.ensemble.secondary_score > 50); if(data.ensemble.fused_score !== undefined) html += createBreakdownBar('Fused Ensemble', data.ensemble.fused_score, data.ensemble.fused_score > 50); list.innerHTML = html; } else { document.getElementById('ensemble-card').style.display = 'none'; } // --- 6. Metadata Analysis Card --- if (data.metadata_analysis) { document.getElementById('metadata-card').style.display = 'flex'; const grid = document.getElementById('metadata-grid'); const m = data.metadata_analysis; grid.innerHTML = `
    Camera${m.camera_model || 'Unknown'}
    Lens${m.lens_info || 'Unknown'}
    Software${m.software_detected || 'None detected'}
    EXIF${m.has_exif ? 'Present' : 'Absent'}
    C2PA Status${m.c2pa_status || 'Absent'}
    `; const flags = document.getElementById('metadata-flags'); if (m.flags && m.flags.length > 0) { flags.innerHTML = m.flags.map(f => `
    ${f}
    `).join(''); } else { flags.innerHTML = `
    No anomalies
    `; } } else { document.getElementById('metadata-card').style.display = 'none'; } // --- 7. Audio Analysis Card --- if (data.audio_analysis) { document.getElementById('audio-card').style.display = 'flex'; const grid = document.getElementById('audio-grid'); const a = data.audio_analysis; const audioIsFake = a.audio_prediction === 'FAKE'; grid.innerHTML = `
    Audio Verdict${a.audio_prediction || 'N/A'}
    Confidence${a.audio_confidence ? a.audio_confidence.toFixed(1) + '%' : 'N/A'}
    Segments${a.segments_analyzed || 0}
    `; } else { document.getElementById('audio-card').style.display = 'none'; } // --- 8. Temporal Analysis Card --- if (data.temporal_analysis) { document.getElementById('temporal-card').style.display = 'flex'; const grid = document.getElementById('temporal-grid'); const t = data.temporal_analysis; grid.innerHTML = `
    Variance${t.confidence_variance !== undefined ? t.confidence_variance.toFixed(3) : 'N/A'}
    Drift${t.confidence_drift !== undefined ? t.confidence_drift.toFixed(3) : 'N/A'}
    Entropy${t.prediction_entropy !== undefined ? t.prediction_entropy.toFixed(3) : 'N/A'}
    Consistency${t.temporal_consistency_score !== undefined ? t.temporal_consistency_score.toFixed(3) : 'N/A'}
    `; const idTableContainer = document.getElementById('temporal-identities'); if (t.identities && t.identities.length > 0) { let idHtml = ``; t.identities.forEach(id => { const rowClass = id.flagged ? 'flagged' : ''; idHtml += ``; }); idHtml += `
    IDFramesFake ProbVerdict
    #${id.id || id.identity_id} ${id.frames || id.frames_seen} ${(id.mean_fake || id.mean_fake_prob).toFixed(1)}% ${id.prediction || (id.flagged ? 'FAKE' : 'REAL')}
    `; idTableContainer.innerHTML = idHtml; } else { idTableContainer.innerHTML = ''; } } else { document.getElementById('temporal-card').style.display = 'none'; } // --- 9. Processing Stats --- if (data.processing_stats) { document.getElementById('stats-card').style.display = 'block'; const grid = document.getElementById('stats-grid'); const s = data.processing_stats; grid.innerHTML = `
    Total Time${s.total_analysis_ms || 0} ms
    Inference${s.model_inference_ms || 0} ms
    Heatmaps${s.heatmap_generation_ms || 0} ms
    Peak RAM${s.peak_ram_mb || 0} MB
    `; } else { document.getElementById('stats-card').style.display = 'none'; } // Populate forensic metrics (safe with defaults if keys are missing) """ start_logic = """ function renderForensicReport(data) {""" end_logic = """ // Populate forensic metrics (safe with defaults if keys are missing)""" html = html.replace(html[html.find(start_logic):html.find(end_logic)+len(end_logic)], js_logic) with open(r"d:\ANTIGRAVITY\templates\index.html", "w", encoding="utf-8") as f: f.write(html)