|
|
<!DOCTYPE html>
|
|
|
<html lang="en">
|
|
|
<head>
|
|
|
<meta charset="UTF-8">
|
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
|
<title>FraudShield AI | Transaction Monitoring</title>
|
|
|
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
|
|
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700;800&display=swap" rel="stylesheet">
|
|
|
</head>
|
|
|
<body>
|
|
|
<div class="container">
|
|
|
<header>
|
|
|
<h1>FraudShield AI</h1>
|
|
|
<p>Advanced Real-time Credit Card Fraud Detection Pipeline</p>
|
|
|
</header>
|
|
|
|
|
|
<div class="main-layout">
|
|
|
<div class="card">
|
|
|
<div class="card-title">
|
|
|
<span>🔍</span> Sample Transactions
|
|
|
</div>
|
|
|
<div class="tabs">
|
|
|
<div class="tab active" id="tab-fraud">Fraud Cases</div>
|
|
|
<div class="tab" id="tab-normal">Legitimate</div>
|
|
|
</div>
|
|
|
<div class="samples-list" id="samples-container">
|
|
|
|
|
|
<p style="text-align: center; color: #64748b;">Loading samples...</p>
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
<div class="card">
|
|
|
<div class="card-title">
|
|
|
<span>⚙️</span> Analysis Engine
|
|
|
</div>
|
|
|
<form id="prediction-form">
|
|
|
<div class="form-group">
|
|
|
<div>
|
|
|
<label style="font-size: 0.8rem; color: #94a3b8;">Amount ($)</label>
|
|
|
<input type="number" id="Amount" class="input-field" step="0.01" required placeholder="89.99">
|
|
|
</div>
|
|
|
<div>
|
|
|
<label style="font-size: 0.8rem; color: #94a3b8;">Time (Seconds)</label>
|
|
|
<input type="number" id="Time" class="input-field" required placeholder="0">
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
<div style="margin-bottom: 0.5rem; font-size: 0.8rem; color: #94a3b8;">PCA Components (V1 - V28)</div>
|
|
|
<div style="max-height: 200px; overflow-y: auto; padding-right: 5px;" id="v-inputs">
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<button type="submit" class="btn">Analyze Transaction</button>
|
|
|
</form>
|
|
|
|
|
|
<div id="result-area">
|
|
|
<div class="result-title" id="res-title">SAFE</div>
|
|
|
<div class="result-conf" id="res-conf">Confidence: 99.8%</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
<script>
|
|
|
let samples = { fraud: [], normal: [] };
|
|
|
let activeTab = 'fraud';
|
|
|
|
|
|
|
|
|
const vContainer = document.getElementById('v-inputs');
|
|
|
for (let i = 1; i <= 28; i++) {
|
|
|
const div = document.createElement('div');
|
|
|
div.className = 'form-group';
|
|
|
div.style.marginBottom = '0.5rem';
|
|
|
div.innerHTML = `
|
|
|
<div style="grid-column: span 2">
|
|
|
<input type="number" step="0.000001" id="V${i}" class="input-field" placeholder="V${i} component" value="0">
|
|
|
</div>
|
|
|
`;
|
|
|
vContainer.appendChild(div);
|
|
|
}
|
|
|
|
|
|
|
|
|
fetch('/get_samples')
|
|
|
.then(res => res.json())
|
|
|
.then(data => {
|
|
|
samples = data;
|
|
|
renderSamples();
|
|
|
});
|
|
|
|
|
|
function renderSamples() {
|
|
|
const container = document.getElementById('samples-container');
|
|
|
container.innerHTML = '';
|
|
|
|
|
|
const list = activeTab === 'fraud' ? samples.fraud : samples.normal;
|
|
|
|
|
|
list.forEach(item => {
|
|
|
const el = document.createElement('div');
|
|
|
el.className = 'sample-item';
|
|
|
el.innerHTML = `
|
|
|
<div class="amount">$${item.Amount.toFixed(2)}</div>
|
|
|
<div class="meta">
|
|
|
<span>Time: ${Math.floor(item.Time)}s</span>
|
|
|
<span>PCA: Mixed</span>
|
|
|
</div>
|
|
|
`;
|
|
|
el.onclick = () => fillForm(item);
|
|
|
container.appendChild(el);
|
|
|
});
|
|
|
}
|
|
|
|
|
|
function fillForm(item) {
|
|
|
document.getElementById('Amount').value = item.Amount;
|
|
|
document.getElementById('Time').value = item.Time;
|
|
|
for (let i = 1; i <= 28; i++) {
|
|
|
document.getElementById(`V${i}`).value = item[`V${i}`];
|
|
|
}
|
|
|
|
|
|
const card = document.querySelectorAll('.card')[1];
|
|
|
card.style.borderColor = 'var(--primary)';
|
|
|
setTimeout(() => card.style.borderColor = 'var(--glass-border)', 500);
|
|
|
}
|
|
|
|
|
|
|
|
|
document.getElementById('tab-fraud').onclick = () => {
|
|
|
activeTab = 'fraud';
|
|
|
document.getElementById('tab-fraud').classList.add('active');
|
|
|
document.getElementById('tab-normal').classList.remove('active');
|
|
|
renderSamples();
|
|
|
};
|
|
|
document.getElementById('tab-normal').onclick = () => {
|
|
|
activeTab = 'normal';
|
|
|
document.getElementById('tab-normal').classList.add('active');
|
|
|
document.getElementById('tab-fraud').classList.remove('active');
|
|
|
renderSamples();
|
|
|
};
|
|
|
|
|
|
|
|
|
document.getElementById('prediction-form').onsubmit = async (e) => {
|
|
|
e.preventDefault();
|
|
|
const btn = e.target.querySelector('button');
|
|
|
btn.innerHTML = 'Processing...';
|
|
|
btn.disabled = true;
|
|
|
|
|
|
const data = {
|
|
|
Amount: document.getElementById('Amount').value,
|
|
|
Time: document.getElementById('Time').value
|
|
|
};
|
|
|
for (let i = 1; i <= 28; i++) {
|
|
|
data[`V${i}`] = document.getElementById(`V${i}`).value;
|
|
|
}
|
|
|
|
|
|
try {
|
|
|
const res = await fetch('/predict', {
|
|
|
method: 'POST',
|
|
|
headers: { 'Content-Type': 'application/json' },
|
|
|
body: JSON.stringify(data)
|
|
|
});
|
|
|
const result = await res.json();
|
|
|
|
|
|
const resArea = document.getElementById('result-area');
|
|
|
resArea.style.display = 'block';
|
|
|
resArea.className = result.is_fraud ? 'result-fraud' : 'result-safe';
|
|
|
|
|
|
document.getElementById('res-title').innerText = result.class;
|
|
|
document.getElementById('res-conf').innerText = `Confidence: ${result.confidence.toFixed(2)}%`;
|
|
|
|
|
|
} catch (err) {
|
|
|
alert('Analysis failed: ' + err.message);
|
|
|
} finally {
|
|
|
btn.innerHTML = 'Analyze Transaction';
|
|
|
btn.disabled = false;
|
|
|
}
|
|
|
};
|
|
|
</script>
|
|
|
</body>
|
|
|
</html>
|
|
|
|