Cyber_Guider_AI / index.html
ba456jutt's picture
Upload 7 files
cb717fc verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Cyber Guider AI | Scam Protection</title>
<link href="https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;600;800&display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
:root {
--primary: #818cf8;
--primary-glow: rgba(129, 140, 248, 0.5);
--danger: #ef4444;
--success: #10b981;
--bg: #0f172a;
--glass: rgba(30, 41, 59, 0.7);
--glass-border: rgba(255, 255, 255, 0.1);
}
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: 'Outfit', sans-serif;
background: var(--bg);
color: white;
min-height: 100vh;
overflow-x: hidden;
background: radial-gradient(circle at top right, #1e1b4b, #0f172a);
}
.container { max-width: 1000px; margin: 0 auto; padding: 40px 20px; }
header { text-align: center; margin-bottom: 60px; animation: fadeInDown 0.8s ease-out; }
.logo { font-size: 4rem; font-weight: 800; letter-spacing: -2px; margin-bottom: 10px; background: linear-gradient(to right, #818cf8, #c084fc); -webkit-background-clip: text; -webkit-text-fill-color: transparent; filter: drop-shadow(0 0 10px var(--primary-glow)); }
.subtitle { color: #94a3b8; font-size: 1.1rem; }
.main-card {
background: var(--glass);
backdrop-filter: blur(12px);
border: 1px solid var(--glass-border);
border-radius: 24px;
padding: 30px;
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.5);
}
.tabs { display: flex; gap: 10px; margin-bottom: 30px; background: rgba(15, 23, 42, 0.5); padding: 5px; border-radius: 12px; }
.tab-btn {
flex: 1; padding: 12px; border: none; background: transparent; color: #94a3b8;
font-weight: 600; cursor: pointer; border-radius: 8px; transition: 0.3s;
}
.tab-btn.active { background: var(--primary); color: white; box-shadow: 0 4px 12px var(--primary-glow); }
.input-section { display: none; }
.input-section.active { display: block; animation: fadeIn 0.4s ease-out; }
textarea {
width: 100%; height: 150px; background: rgba(15, 23, 42, 0.8); border: 1px solid var(--glass-border);
border-radius: 16px; padding: 20px; color: white; font-size: 1rem; resize: none; margin-bottom: 20px;
transition: 0.3s;
}
textarea:focus { outline: none; border-color: var(--primary); box-shadow: 0 0 15px var(--primary-glow); }
.file-upload {
border: 2px dashed var(--glass-border); border-radius: 16px; padding: 40px; text-align: center;
cursor: pointer; transition: 0.3s;
}
.file-upload:hover { border-color: var(--primary); background: rgba(129, 140, 248, 0.05); }
.file-upload i { font-size: 3rem; color: var(--primary); margin-bottom: 15px; }
.btn-analyze {
width: 100%; padding: 18px; border: none; border-radius: 16px; background: var(--primary);
color: white; font-size: 1.1rem; font-weight: 700; cursor: pointer; transition: 0.3s;
box-shadow: 0 10px 20px -5px var(--primary-glow);
}
.btn-analyze:hover { transform: translateY(-2px); filter: brightness(1.1); }
.btn-analyze:active { transform: translateY(0); }
/* Results Area */
.results-container { margin-top: 40px; display: none; }
.loading { text-align: center; padding: 40px; }
.scanner {
width: 60px; height: 60px; border: 4px solid var(--primary); border-top-color: transparent;
border-radius: 50%; margin: 0 auto 20px; animation: spin 1s linear infinite;
}
.result-card {
background: rgba(15, 23, 42, 0.9); border-radius: 20px; padding: 30px;
border-left: 6px solid var(--primary); animation: slideUp 0.5s ease-out;
}
.result-card.danger { border-left-color: var(--danger); }
.result-card.success { border-left-color: var(--success); }
.status-badge {
display: inline-block; padding: 6px 16px; border-radius: 99px; font-weight: 700; font-size: 0.9rem;
margin-bottom: 15px; text-transform: uppercase;
}
.status-badge.scam { background: rgba(239, 68, 68, 0.2); color: var(--danger); }
.status-badge.safe { background: rgba(16, 185, 129, 0.2); color: var(--success); }
.grid-info { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; margin-bottom: 25px; }
.info-box { background: rgba(255, 255, 255, 0.03); padding: 15px; border-radius: 12px; }
.info-label { font-size: 0.8rem; color: #94a3b8; text-transform: uppercase; margin-bottom: 5px; }
.info-value { font-weight: 600; font-size: 1rem; }
/* Self-Learning Badge */
.learned-badge {
background: linear-gradient(135deg, #6366f1, #a855f7);
color: white;
padding: 4px 12px;
border-radius: 99px;
font-size: 0.75rem;
font-weight: 800;
display: inline-flex;
align-items: center;
gap: 5px;
margin-top: 5px;
box-shadow: 0 0 15px rgba(168, 85, 247, 0.4);
animation: pulse 2s infinite;
}
@keyframes pulse {
0% { box-shadow: 0 0 0 0 rgba(168, 85, 247, 0.4); }
70% { box-shadow: 0 0 0 10px rgba(168, 85, 247, 0); }
100% { box-shadow: 0 0 0 0 rgba(168, 85, 247, 0); }
}
.analysis-text { line-height: 1.6; color: #cbd5e1; margin-bottom: 20px; }
.action-plan { background: rgba(129, 140, 248, 0.05); padding: 20px; border-radius: 16px; }
.action-title { font-weight: 700; margin-bottom: 12px; display: flex; align-items: center; gap: 10px; color: var(--primary); }
.action-list { list-style: none; }
.action-list li { margin-bottom: 8px; display: flex; gap: 10px; align-items: flex-start; }
.action-list li::before { content: '✓'; color: var(--primary); font-weight: bold; }
/* New Action Buttons */
.action-btn-primary {
background: var(--primary); color: white; border: none; padding: 12px; border-radius: 12px;
font-weight: 700; cursor: pointer; transition: 0.3s; display: flex; align-items: center; justify-content: center; gap: 8px;
}
.action-btn-success {
background: var(--success); color: white; border: none; padding: 12px; border-radius: 12px;
font-weight: 700; cursor: pointer; transition: 0.3s; display: flex; align-items: center; justify-content: center; gap: 8px;
}
.secondary-btn {
background: transparent; border: 1px solid var(--danger); color: var(--danger); padding: 10px 20px;
border-radius: 12px; cursor: pointer; font-weight: 600; transition: 0.3s;
}
.action-btn-primary:hover, .action-btn-success:hover { transform: translateY(-2px); filter: brightness(1.1); box-shadow: 0 5px 15px rgba(0,0,0,0.3); }
/* Notification Toast */
#toast {
position: fixed; bottom: 30px; left: 50%; transform: translateX(-50%);
background: #1e293b; color: white; padding: 12px 24px; border-radius: 99px;
box-shadow: 0 10px 25px rgba(0,0,0,0.5); border: 1px solid var(--primary);
display: none; z-index: 1000; animation: slideUp 0.3s ease-out;
}
@keyframes spin { to { transform: rotate(360deg); } }
@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
@keyframes fadeInDown { from { opacity: 0; transform: translateY(-20px); } to { opacity: 1; transform: translateY(0); } }
@keyframes slideUp { from { opacity: 0; transform: translateY(20px); } to { opacity: 1; transform: translateY(0); } }
@media (max-width: 600px) {
.grid-info { grid-template-columns: 1fr; }
.logo { font-size: 2.5rem; }
}
</style>
</head>
<body>
<div class="container">
<header>
<div class="logo">CYBER GUIDER</div>
<p class="subtitle">Agentic Fraud Detection for Pakistani Citizens</p>
</header>
<main class="main-card">
<div class="tabs">
<button class="tab-btn active" onclick="switchTab('text')"><i class="fa-solid fa-message"></i> SMS</button>
<button class="tab-btn" onclick="switchTab('image')"><i class="fa-solid fa-image"></i> Screenshot</button>
<button class="tab-btn" onclick="switchTab('audio')"><i class="fa-solid fa-microphone"></i> Voice</button>
</div>
<div id="text-section" class="input-section active">
<textarea id="text-input" placeholder="Aapka 25000 ka inam nikla hai, is link par click karein..."></textarea>
</div>
<div id="image-section" class="input-section">
<div class="file-upload" onclick="document.getElementById('image-file').click()">
<i class="fa-solid fa-cloud-arrow-up"></i>
<h3>Upload Screenshot</h3>
<p id="image-status">Drop E-Challan or WhatsApp screenshot here</p>
<input type="file" id="image-file" hidden accept="image/*" onchange="updateFileStatus('image')">
</div>
</div>
<div id="audio-section" class="input-section">
<div class="file-upload" onclick="document.getElementById('audio-file').click()">
<i class="fa-solid fa-music"></i>
<h3>Upload Voice Note</h3>
<p id="audio-status">Upload WhatsApp .m4a or .opus voice note</p>
<input type="file" id="audio-file" hidden accept="audio/*" onchange="updateFileStatus('audio')">
</div>
</div>
<button class="btn-analyze" onclick="analyze()"><i class="fa-solid fa-shield-halved"></i> ANALYZE FOR THREATS</button>
<div id="results" class="results-container">
<div id="loading" class="loading">
<div class="scanner"></div>
<h3>Scanning for Scam Patterns...</h3>
<p>Agentic reasoning in progress</p>
</div>
<div id="result-content" style="display: none;">
<div id="result-card" class="result-card">
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px;">
<div id="status-badge" class="status-badge">SCAM DETECTED</div>
<div id="threat-meter" style="width: 100px; height: 10px; background: #334155; border-radius: 99px; overflow: hidden;">
<div id="meter-fill" style="width: 0%; height: 100%; background: var(--danger); transition: 1s ease-out;"></div>
</div>
</div>
<div class="grid-info">
<div class="info-box">
<div class="info-label">Risk Level</div>
<div id="risk-level" class="info-value">High</div>
</div>
<div class="info-box">
<div class="info-label">Detection Source</div>
<div id="source" class="info-value">Local Intelligence</div>
<div id="learned-tag" class="learned-badge" style="display:none;">
<i class="fa-solid fa-brain"></i> SELF-LEARNED
</div>
</div>
<div id="geo-box" class="info-box" style="display:none;">
<div class="info-label">Scammer Location</div>
<div id="geo-location" class="info-value">Unknown</div>
</div>
</div>
<div class="info-label">AI Forensic Analysis</div>
<p id="explanation" class="analysis-text"></p>
<div id="transcript-box" style="display:none; margin-bottom: 20px;">
<div class="info-label">Extracted Content</div>
<p id="transcript" style="font-style: italic; color: #94a3b8;"></p>
</div>
<div id="forensics-box" style="display:none; margin-bottom: 25px;">
<div class="info-label">Advanced Link Forensics</div>
<div id="forensics-details" style="background: rgba(0,0,0,0.3); padding: 15px; border-radius: 12px; font-size: 0.9rem; border-left: 3px solid var(--primary);"></div>
</div>
<div class="action-plan">
<div class="action-title"><i class="fa-solid fa-list-check"></i> Next Action Plan</div>
<ul id="next-steps" class="action-list"></ul>
</div>
<div id="chat-section" style="margin-top: 25px; border-top: 1px solid var(--glass-border); padding-top: 20px;">
<div class="action-title"><i class="fa-solid fa-comments"></i> Ask the Expert</div>
<div id="chat-history" style="max-height: 200px; overflow-y: auto; margin-bottom: 15px; font-size: 0.9rem; line-height: 1.5;"></div>
<div style="display: flex; gap: 10px;">
<input type="text" id="chat-input" placeholder="E.g. Kya main ne link khola to data chori ho gaya?" style="flex: 1; background: rgba(0,0,0,0.3); border: 1px solid var(--glass-border); padding: 10px; border-radius: 8px; color: white;">
<button onclick="sendChat()" style="background: var(--primary); border: none; color: white; padding: 10px 15px; border-radius: 8px; cursor: pointer;"><i class="fa-solid fa-paper-plane"></i></button>
</div>
</div>
<div id="report-section" style="margin-top: 25px; display: flex; flex-direction: column; gap: 15px;">
<div style="display: flex; gap: 10px; justify-content: center;">
<button id="btn-report" onclick="reportScam()" class="secondary-btn">
<i class="fa-solid fa-triangle-exclamation"></i> Blacklist Scam
</button>
</div>
<div id="action-buttons" style="display: grid; grid-template-columns: 1fr 1fr; gap: 10px;">
<button id="btn-copy-report" onclick="copyAndReport()" class="action-btn-primary">
<i class="fa-solid fa-copy"></i> Draft & Report FIA
</button>
<button id="btn-pdf" onclick="downloadLegalPDF()" class="action-btn-success">
<i class="fa-solid fa-file-pdf"></i> Download Legal PDF
</button>
</div>
</div>
<p id="report-msg" style="margin-top: 10px; font-size: 0.8rem; color: var(--success); text-align: center; display: none;">Reported successfully! Thank you for protecting others.</p>
</div>
</div>
</div>
</main>
</div>
<div id="toast">Draft copied to clipboard!</div>
<script>
let currentTab = 'text';
function switchTab(tab) {
currentTab = tab;
document.querySelectorAll('.tab-btn').forEach(b => b.classList.remove('active'));
document.querySelectorAll('.input-section').forEach(s => s.classList.remove('active'));
event.currentTarget.classList.add('active');
document.getElementById(tab + '-section').classList.add('active');
}
function updateFileStatus(type) {
const input = document.getElementById(type + '-file');
const status = document.getElementById(type + '-status');
if (input.files.length > 0) {
status.innerText = "Selected: " + input.files[0].name;
status.style.color = "#818cf8";
}
}
async function analyze() {
const results = document.getElementById('results');
const loading = document.getElementById('loading');
const content = document.getElementById('result-content');
results.style.display = 'block';
loading.style.display = 'block';
content.style.display = 'none';
results.scrollIntoView({ behavior: 'smooth' });
const formData = new FormData();
if (currentTab === 'text') {
const text = document.getElementById('text-input').value;
if (!text) { alert("Please enter some text"); return; }
formData.append('text_content', text);
} else if (currentTab === 'image') {
const file = document.getElementById('image-file').files[0];
if (!file) { alert("Please select an image"); return; }
formData.append('file', file);
} else if (currentTab === 'audio') {
const file = document.getElementById('audio-file').files[0];
if (!file) { alert("Please select an audio file"); return; }
formData.append('file', file);
}
try {
const response = await fetch('/analyze-media', {
method: 'POST',
body: formData
});
const data = await response.json();
displayResults(data);
} catch (error) {
console.error(error);
alert("Error connecting to backend. Make sure api.py is running on port 8000.");
} finally {
loading.style.display = 'none';
}
}
function displayResults(data) {
const content = document.getElementById('result-content');
const card = document.getElementById('result-card');
const badge = document.getElementById('status-badge');
content.style.display = 'block';
// Set styles based on scam status
if (data.is_scam) {
card.className = "result-card danger";
badge.className = "status-badge scam";
badge.innerText = "SCAM DETECTED";
} else {
card.className = "result-card success";
badge.className = "status-badge safe";
badge.innerText = "SAFE / SECURE";
}
document.getElementById('risk-level').innerText = data.risk_level;
document.getElementById('source').innerText = data.source;
const learnedTag = document.getElementById('learned-tag');
if (data.source.includes("Learned") || data.source.includes("Local")) {
learnedTag.style.display = 'inline-flex';
} else {
learnedTag.style.display = 'none';
}
document.getElementById('explanation').innerText = data.agent_explanation;
// Threat Meter
const meter = document.getElementById('meter-fill');
if (data.risk_level === 'High' || data.risk_level === 'Critical') {
meter.style.width = '100%';
meter.style.background = 'var(--danger)';
} else if (data.risk_level === 'Medium') {
meter.style.width = '60%';
meter.style.background = '#f59e0b';
} else {
meter.style.width = '20%';
meter.style.background = 'var(--success)';
}
if (data.transcription && data.transcription !== "Image content analysis requested.") {
document.getElementById('transcript-box').style.display = 'block';
document.getElementById('transcript').innerText = '"' + data.transcription + '"';
} else {
document.getElementById('transcript-box').style.display = 'none';
}
// Display Forensics
const forensicsBox = document.getElementById('forensics-box');
const geoBox = document.getElementById('geo-box');
if (data.forensics) {
forensicsBox.style.display = 'block';
geoBox.style.display = 'block';
const f = data.forensics;
document.getElementById('geo-location').innerText = (f.geolocation.country || 'Unknown') + ' (' + (f.geolocation.isp || '') + ')';
let html = `<div style="display:grid; grid-template-columns: 1fr 1fr; gap:10px;">
<div>📅 Age: <b>${f.age_days} days</b></div>
<div>🔒 SSL: <b>${f.ssl_info.valid ? 'Valid' : 'None'}</b></div>
<div>🌍 IP: <b>${f.geolocation.ip || 'Unknown'}</b></div>
<div>🛡️ VT: <b>${f.virustotal.risk || 'Unknown'}</b></div>
</div>`;
if (f.state_impersonation) {
html += `<div style="margin-top:10px; color:var(--danger); font-weight:bold;"><i class="fa-solid fa-triangle-exclamation"></i> CRITICAL: Impersonating Government Body!</div>`;
}
document.getElementById('forensics-details').innerHTML = html;
} else {
forensicsBox.style.display = 'none';
}
const stepsList = document.getElementById('next-steps');
stepsList.innerHTML = '';
data.next_steps.split('\n').forEach(step => {
if (step.trim()) {
const li = document.createElement('li');
li.innerText = step.replace(/^\d+\.\s*/, '');
stepsList.appendChild(li);
}
});
// Reset report button
document.getElementById('btn-report').style.display = data.is_scam ? 'inline-block' : 'none';
document.getElementById('report-msg').style.display = 'none';
// Store current data for reporting/downloading
window.currentReportText = data.transcription || document.getElementById('text-input').value;
window.currentComplaint = data.fia_complaint;
window.currentAgentExplanation = data.agent_explanation;
window.currentScamType = data.category || (data.is_scam ? "Cyber Fraud" : "General Inquiry");
window.currentEvidence = `Forensics: ${data.source}\nRisk: ${data.risk_level}\nExplanation: ${data.agent_explanation}`;
if (data.forensics) {
window.currentEvidence += `\nLink Details: Age ${data.forensics.age_days} days, SSL ${data.forensics.ssl_info.valid}`;
}
// Clear chat
document.getElementById('chat-history').innerHTML = '';
}
async function sendChat() {
const input = document.getElementById('chat-input');
const history = document.getElementById('chat-history');
const question = input.value;
if (!question) return;
history.innerHTML += `<div style="margin-bottom:10px; color:var(--primary);"><b>Aap:</b> ${question}</div>`;
input.value = '';
const formData = new FormData();
formData.append('question', question);
formData.append('context', window.currentAgentExplanation);
try {
const response = await fetch('/chat', {
method: 'POST',
body: formData
});
const data = await response.json();
history.innerHTML += `<div style="margin-bottom:15px; background:rgba(255,255,255,0.05); padding:10px; border-radius:8px;"><b>Expert:</b> ${data.response}</div>`;
history.scrollTop = history.scrollHeight;
} catch (error) {
console.error(error);
history.innerHTML += `<div style="color:var(--danger);">Error connecting to expert.</div>`;
}
}
async function reportScam() {
const btn = document.getElementById('btn-report');
const msg = document.getElementById('report-msg');
btn.innerText = "Reporting...";
btn.disabled = true;
const formData = new FormData();
formData.append('text_content', window.currentReportText);
try {
await fetch('/report-scam', {
method: 'POST',
body: formData
});
btn.style.display = 'none';
msg.style.display = 'block';
} catch (error) {
console.error(error);
alert("Error reporting scam.");
btn.innerText = "Report Scam";
btn.disabled = false;
}
}
function showToast(msg) {
const toast = document.getElementById('toast');
toast.innerText = msg;
toast.style.display = 'block';
setTimeout(() => { toast.style.display = 'none'; }, 3000);
}
async function copyAndReport() {
if (!window.currentComplaint) return;
try {
await navigator.clipboard.writeText(window.currentComplaint);
showToast("Legal draft copied! Opening FIA Portal...");
setTimeout(() => {
window.open('https://complaint.fia.gov.pk/', '_blank');
}, 1500);
} catch (err) {
console.error('Failed to copy: ', err);
}
}
async function downloadLegalPDF() {
if (!window.currentComplaint) return;
const btn = document.getElementById('btn-pdf');
const originalHtml = btn.innerHTML;
btn.innerHTML = '<i class="fa-solid fa-spinner fa-spin"></i> Generating...';
btn.disabled = true;
const formData = new FormData();
formData.append('complaint_text', window.currentComplaint);
formData.append('scam_type', window.currentScamType);
formData.append('evidence', window.currentEvidence);
try {
const response = await fetch('/generate-pdf', {
method: 'POST',
body: formData
});
if (!response.ok) throw new Error("PDF generation failed");
const blob = await response.blob();
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `FIA_Complaint_${new Date().getTime()}.pdf`;
document.body.appendChild(a);
a.click();
window.URL.revokeObjectURL(url);
showToast("PDF Downloaded Successfully!");
} catch (error) {
console.error(error);
alert("Error generating PDF.");
} finally {
btn.innerHTML = originalHtml;
btn.disabled = false;
}
}
function downloadComplaint() {
// Deprecated in favor of PDF
downloadLegalPDF();
}
</script>
</body>
</html>