| <!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>
|
|
|