Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Full Fraud Detection - Janus Scanner Pro</title> | |
| <link rel="icon" type="image/x-icon" href="/static/favicon.ico"> | |
| <link rel="stylesheet" href="style.css"> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| <script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script> | |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.18.5/xlsx.full.min.js"></script> | |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.11.338/pdf.min.js"></script> | |
| </head> | |
| <body class="bg-black text-terminal-green"> | |
| <div class="scanline"></div> | |
| <header class="bg-primary border-b-2 border-accent py-4 px-6 flex justify-between items-center"> | |
| <div class="flex items-center space-x-2"> | |
| <i data-feather="eye" class="text-accent pulse"></i> | |
| <h1 class="text-2xl font-bold text-accent">JANUS SCANNER</h1> | |
| <span class="version-tag">v2.1 - "Opération Foudre Silencieuse"</span> | |
| </div> | |
| <nav class="flex space-x-6"> | |
| <a href="index.html" class="hover:text-accent text-gray-300">[DASHBOARD]</a> | |
| <a href="full-fraud-detection.html" class="hover:text-accent text-accent text-bold">[FULL DETECTION]</a> | |
| <a href="reports.html" class="hover:text-accent text-gray-300">[RAPPORTS]</a> | |
| <a href="settings.html" class="hover:text-accent text-gray-300">[CONFIG]</a> | |
| <a href="https://github.com/janus-scanner-pro" target="_blank" class="hover:text-accent text-gray-300">[GITHUB]</a> | |
| </nav> | |
| </header> | |
| <main class="container mx-auto px-4 py-8"> | |
| <!-- Unified Threat Dashboard --> | |
| <section class="mb-12"> | |
| <h2 class="text-3xl font-bold text-accent mb-4">SYSTEME DE DETECTION GLOBALE</h2> | |
| <p class="text-gray-400 max-w-2xl mx-auto"> | |
| Analyse omnidirectionnelle: FEC, Bilans, Comptes Bancaires, Crypto, Sociétés Offshore. | |
| </p> | |
| </section> | |
| <!-- Master Risk Score --> | |
| <div class="bg-secondary border-2 border-accent rounded-lg p-8 mb-8"> | |
| <h3 class="card-title text-center mb-4">SCORE DE RISQUE GLOBAL</h3> | |
| <div class="text-center"> | |
| <div class="text-6xl font-bold text-accent" id="masterRiskScore">0%</div> | |
| <div class="mt-4 w-full bg-gray-800 rounded-full h-4"> | |
| <div id="masterRiskBar" class="bg-accent h-4 rounded-full transition-all duration-1000" style="width: 0%"></div> | |
| </div> | |
| <p class="text-gray-400 mt-2" id="threatLevel">En attente d'analyse...</p> | |
| </div> | |
| </div> | |
| <!-- Multi-Module Grid --> | |
| <div class="grid grid-cols-1 lg:grid-cols-3 gap-8 mb-12"> | |
| <!-- Crypto Analysis --> | |
| <div class="bg-secondary border border-gray-700 rounded-lg p-6 hover:border-accent transition-colors"> | |
| <h3 class="card-title">[ANALYSE CRYPTO]</h3> | |
| <div class="space-y-4"> | |
| <input type="text" id="cryptoWallet" placeholder="Adresse wallet (ex: 1A1zP...)" | |
| class="w-full bg-gray-800 px-4 py-2 rounded border border-gray-600 focus:border-accent focus:outline-none"> | |
| <button id="analyzeCryptoBtn" class="btn w-full"> | |
| [SCANNER WALLET] | |
| </button> | |
| <div id="cryptoResults" class="space-y-2"> | |
| <div class="text-center py-4 text-gray-500"> | |
| <i data-feather="dollar-sign" class="mx-auto mb-2"></i> | |
| <p class="text-sm">Enter wallet address and click scan</p> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Offshore Entity Detection --> | |
| <div class="bg-secondary border border-gray-700 rounded-lg p-6 hover:border-accent transition-colors"> | |
| <h3 class="card-title">[SOCIÉTÉS OFFSHORE]</h3> | |
| <div class="space-y-4"> | |
| <textarea id="offshoreText" rows="4" placeholder="Coller texte à analyser (contrats, noms de sociétés...)" | |
| class="w-full bg-gray-800 px-4 py-2 rounded border border-gray-600 focus:border-accent focus:outline-none"></textarea> | |
| <button id="detectOffshoreBtn" class="btn w-full"> | |
| [DÉTECTER ENTITÉS] | |
| </button> | |
| <div id="offshoreResults" class="space-y-2"> | |
| <div class="text-center py-4 text-gray-500"> | |
| <i data-feather="globe" class="mx-auto mb-2"></i> | |
| <p class="text-sm">Paste text to analyze</p> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Bank Account Analysis --> | |
| <div class="bg-secondary border border-gray-700 rounded-lg p-6 hover:border-accent transition-colors"> | |
| <h3 class="card-title">[COMPTES BANCAIRES]</h3> | |
| <div class="space-y-4"> | |
| <div class="border-2 border-dashed border-gray-600 rounded-lg p-6 text-center"> | |
| <i data-feather="credit-card" class="mx-auto mb-2 text-gray-400"></i> | |
| <p class="text-gray-400 text-sm">Format: CSV (Date, Montant, Description, Solde)</p> | |
| <input type="file" id="bankFile" class="hidden" accept=".csv,.xlsx"> | |
| <label for="bankFile" class="btn mt-2 cursor-pointer text-xs"> | |
| [CHOISIR FICHIER] | |
| </label> | |
| </div> | |
| <button id="analyzeBankBtn" class="btn w-full"> | |
| [ANALYSER COMPTES] | |
| </button> | |
| <div id="bankResults" class="space-y-2"> | |
| <div class="text-center py-4 text-gray-500"> | |
| <i data-feather="activity" class="mx-auto mb-2"></i> | |
| <p class="text-sm">Upload bank transaction file</p> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- All-in-One File Analysis --> | |
| <div class="bg-secondary border border-gray-700 rounded-lg p-8 mb-8"> | |
| <h3 class="card-title text-center mb-6">[ANALYSE OMNIDIRECTIONNELLE]</h3> | |
| <div class="grid grid-cols-1 md:grid-cols-4 gap-4"> | |
| <div class="text-center"> | |
| <div class="border-2 border-dashed border-gray-600 rounded-lg p-4"> | |
| <i data-feather="upload" class="mx-auto mb-2 text-gray-400"></i> | |
| <input type="file" id="omniFile" class="hidden" accept=".pdf,.xls,.xlsx,.csv"> | |
| <label for="omniFile" class="btn cursor-pointer text-sm"> | |
| [FEC/BILAN] | |
| </label> | |
| </div> | |
| </div> | |
| <div class="text-center"> | |
| <div class="border-2 border-dashed border-gray-600 rounded-lg p-4"> | |
| <i data-feather="file-text" class="mx-auto mb-2 text-gray-400"></i> | |
| <input type="file" id="contractFile" class="hidden" accept=".pdf,.txt"> | |
| <label for="contractFile" class="btn cursor-pointer text-sm"> | |
| [CONTRATS] | |
| </label> | |
| </div> | |
| </div> | |
| <div class="text-center"> | |
| <div class="border-2 border-dashed border-gray-600 rounded-lg p-4"> | |
| <i data-feather="database" class="mx-auto mb-2 text-gray-400"></i> | |
| <input type="file" id="transactionFile" class="hidden" accept=".csv,.xlsx"> | |
| <label for="transactionFile" class="btn cursor-pointer text-sm"> | |
| [TRANSACTIONS] | |
| </label> | |
| </div> | |
| </div> | |
| <div class="flex items-center"> | |
| <button id="omniAnalyzeBtn" class="btn w-full"> | |
| [LANCER ANALYSE TOTALE] | |
| </button> | |
| </div> | |
| </div> | |
| <div id="omniResults" class="mt-6 hidden"> | |
| <div class="bg-gray-900 p-4 rounded border border-red-800"> | |
| <div id="omniResultsContent"></div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Real-time Threat Feed --> | |
| <div class="bg-secondary border border-accent rounded-lg p-6 mb-8"> | |
| <h3 class="card-title">[FIL D'ALERTES TEMPS RÉEL]</h3> | |
| <div id="threatFeed" class="terminal-content max-h-64 overflow-y-auto"> | |
| <div class="text-gray-400"># Initialisation du système de surveillance...</div> | |
| <div class="text-gray-400"># API Status: <span id="apiConnectionStatus">Checking...</span></div> | |
| </div> | |
| </div> | |
| <!-- Strike Configuration --> | |
| <div class="section"> | |
| <h3 class="section-title">[CONFIGURATION AUTOMATIQUE]</h3> | |
| <div class="grid grid-cols-1 md:grid-cols-2 gap-6"> | |
| <div class="bg-gray-900 p-4 rounded border border-gray-700"> | |
| <h4 class="font-semibold text-accent mb-2">Alertes Automatisées</h4> | |
| <div class="space-y-2 text-sm"> | |
| <label class="flex items-center justify-between"> | |
| <span>Procureur de Paris</span> | |
| <input type="checkbox" id="alertProcureur" checked class="w-4 h-4"> | |
| </label> | |
| <label class="flex items-center justify-between"> | |
| <span>TRACFIN</span> | |
| <input type="checkbox" id="alertTracfin" checked class="w-4 h-4"> | |
| </label> | |
| <label class="flex items-center justify-between"> | |
| <span>Douanes</span> | |
| <input type="checkbox" id="alertDouane" checked class="w-4 h-4"> | |
| </label> | |
| <label class="flex items-center justify-between"> | |
| <span>Mediapart</span> | |
| <input type="checkbox" id="alertMedia" class="w-4 h-4"> | |
| </label> | |
| </div> | |
| </div> | |
| <div class="bg-gray-900 p-4 rounded border border-gray-700"> | |
| <h4 class="font-semibold text-accent mb-2">Paramètres de Frappe</h4> | |
| <div class="space-y-2 text-sm"> | |
| <label class="flex items-center justify-between"> | |
| <span>Mode Furtif</span> | |
| <input type="checkbox" id="stealthMode" checked class="w-4 h-4"> | |
| </label> | |
| <label class="flex items-center justify-between"> | |
| <span>Proxy TOR</span> | |
| <input type="checkbox" id="torProxy" checked class="w-4 h-4"> | |
| </label> | |
| <label class="flex items-center justify-between"> | |
| <span>Zero Trace</span> | |
| <input type="checkbox" id="zeroTrace" checked class="w-4 h-4"> | |
| </label> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </main> | |
| <custom-footer></custom-footer> | |
| <script src="components/navbar.js"></script> | |
| <script src="components/footer.js"></script> | |
| <script src="components/api-status.js"></script> | |
| <script src="components/real-time-feed.js"></script> | |
| <script src="script.js"></script> | |
| <script>feather.replace();</script> | |
| <script> | |
| // API Configuration | |
| const API_CONFIG = { | |
| baseUrl: 'https://openrouter.ai/api/v1', | |
| models: { | |
| analysis: 'deepseek/deepseek-chat-v3.1:free', | |
| fast: 'meituan/longcat-flash-chat:free', | |
| complex: 'nousresearch/hermes-3-llama-3.1-405b:free' | |
| } | |
| }; | |
| // Global state | |
| let globalRiskScore = 0; | |
| let riskComponents = []; | |
| let scanHistory = []; | |
| // Full Fraud Detection specific functionality | |
| document.addEventListener('DOMContentLoaded', function() { | |
| // Load API key from settings | |
| const settings = JSON.parse(localStorage.getItem('janusSettings')) || {}; | |
| API_CONFIG.apiKey = settings.apiKey || ''; | |
| // Check API status on load | |
| checkApiStatus(); | |
| // Elements | |
| const cryptoWallet = document.getElementById('cryptoWallet'); | |
| const analyzeCryptoBtn = document.getElementById('analyzeCryptoBtn'); | |
| const cryptoResults = document.getElementById('cryptoResults'); | |
| const offshoreText = document.getElementById('offshoreText'); | |
| const detectOffshoreBtn = document.getElementById('detectOffshoreBtn'); | |
| const offshoreResults = document.getElementById('offshoreResults'); | |
| const bankFile = document.getElementById('bankFile'); | |
| const analyzeBankBtn = document.getElementById('analyzeBankBtn'); | |
| const bankResults = document.getElementById('bankResults'); | |
| const omniFile = document.getElementById('omniFile'); | |
| const contractFile = document.getElementById('contractFile'); | |
| const transactionFile = document.getElementById('transactionFile'); | |
| const omniAnalyzeBtn = document.getElementById('omniAnalyzeBtn'); | |
| const omniResults = document.getElementById('omniResults'); | |
| const omniResultsContent = document.getElementById('omniResultsContent'); | |
| const threatFeed = document.getElementById('threatFeed'); | |
| const masterRiskScore = document.getElementById('masterRiskScore'); | |
| const masterRiskBar = document.getElementById('masterRiskBar'); | |
| const threatLevel = document.getElementById('threatLevel'); | |
| const apiConnectionStatus = document.getElementById('apiConnectionStatus'); | |
| let globalRiskScore = 0; | |
| let riskComponents = []; | |
| // Threat feed simulation | |
| const threatMessages = [ | |
| { type: 'info', text: 'Système de surveillance activé' }, | |
| { type: 'warning', text: 'Analyse du FEC en cours...' }, | |
| { type: 'danger', text: 'Transaction suspecte détectée!' }, | |
| { type: 'info', text: 'Vérification des comptes divers...' }, | |
| { type: 'warning', text: "Pattern offshore identifié" }, | |
| { type: 'danger', text: 'ALERTE: Montants > €10k en cash' }, | |
| { type: 'info', text: 'Scan complet terminé' } | |
| ]; | |
| function addThreatMessage(message, type = 'info') { | |
| const div = document.createElement('div'); | |
| div.className = type === 'danger' ? 'text-red-500' : type === 'warning' ? 'text-yellow-500' : 'text-terminal-green'; | |
| div.textContent = `[${new Date().toLocaleTimeString()}] ${message}`; | |
| threatFeed.appendChild(div); | |
| threatFeed.scrollTop = threatFeed.scrollHeight; | |
| } | |
| // Crypto Analysis | |
| analyzeCryptoBtn.addEventListener('click', async function() { | |
| const wallet = cryptoWallet.value.trim(); | |
| if (!wallet) { | |
| alert('Entrez une adresse wallet'); | |
| return; | |
| } | |
| analyzeCryptoBtn.disabled = true; | |
| analyzeCryptoBtn.innerHTML = '<i data-feather="loader" class="animate-spin inline mr-2"></i>Scanning...'; | |
| feather.replace(); | |
| try { | |
| addThreatMessage(`Scan wallet: ${wallet.substring(0, 20)}...`, 'warning'); | |
| // Utiliser la fonction du script.js | |
| const result = await window.JanusFraudDetector.analyzeCryptoTransactions(wallet); | |
| if (result) { | |
| cryptoResults.innerHTML = ` | |
| <div class="bg-gray-700 p-3 rounded border ${result.riskScore > 70 ? 'border-red-500' : 'border-yellow-500'}"> | |
| <div class="flex justify-between items-center mb-2"> | |
| <span class="font-medium">Wallet Risk</span> | |
| <span class="font-bold ${result.riskScore > 70 ? 'text-red-500' : 'text-yellow-500'}">${result.riskScore}%</span> | |
| </div> | |
| <div class="text-sm text-gray-300"> | |
| <p>Value: $${result.totalValue.toFixed(2)}</p> | |
| <p>Anomalies: ${result.anomalies.length}</p> | |
| </div> | |
| </div> | |
| `; | |
| updateMasterRisk('Crypto Wallet', result.riskScore); | |
| addThreatMessage(`Risque crypto: ${result.riskScore}%`, result.riskScore > 70 ? 'danger' : 'warning'); | |
| } | |
| } catch (error) { | |
| cryptoResults.innerHTML = `<div class="text-red-500">Erreur: ${error.message}</div>`; | |
| } finally { | |
| analyzeCryptoBtn.disabled = false; | |
| analyzeCryptoBtn.innerHTML = '[SCANNER WALLET]'; | |
| feather.replace(); | |
| } | |
| }); | |
| // Offshore Detection | |
| detectOffshoreBtn.addEventListener('click', function() { | |
| const text = offshoreText.value.trim(); | |
| if (!text) { | |
| alert('Collez du texte à analyser'); | |
| return; | |
| } | |
| const detections = window.JanusFraudDetector.detectOffshoreEntities(text); | |
| if (detections.length === 0) { | |
| offshoreResults.innerHTML = ` | |
| <div class="text-center py-4 text-green-500"> | |
| <i data-feather="check-circle" class="mx-auto mb-2"></i> | |
| Aucune entité offshore détectée | |
| </div> | |
| `; | |
| } else { | |
| offshoreResults.innerHTML = detections.map(d => ` | |
| <div class="bg-red-900 bg-opacity-50 p-3 rounded border border-red-500"> | |
| <div class="flex justify-between items-center"> | |
| <span class="font-medium">${d.entity || d.pattern}</span> | |
| <span class="text-red-500 text-sm">${d.severity}</span> | |
| </div> | |
| <div class="text-sm text-gray-400">${d.type}</div> | |
| </div> | |
| `).join(''); | |
| const offshoreRisk = Math.min(100, detections.length * 25); | |
| updateMasterRisk('Offshore Entities', offshoreRisk); | |
| addThreatMessage(`${detections.length} entités offshore détectées!`, 'danger'); | |
| } | |
| feather.replace(); | |
| }); | |
| // Bank Account Analysis | |
| analyzeBankBtn.addEventListener('click', async function() { | |
| const file = bankFile.files[0]; | |
| if (!file) { | |
| alert('Sélectionnez un fichier de transactions bancaires'); | |
| return; | |
| } | |
| analyzeBankBtn.disabled = true; | |
| analyzeBankBtn.innerHTML = '<i data-feather="loader" class="animate-spin inline mr-2"></i>Analyzing...'; | |
| feather.replace(); | |
| try { | |
| const data = await processExcelFile(file); | |
| const analysis = performBankAnalysis(data); | |
| bankResults.innerHTML = ` | |
| <div class="bg-gray-700 p-3 rounded border ${analysis.riskScore > 70 ? 'border-red-500' : analysis.riskScore > 40 ? 'border-yellow-500' : 'border-green-500'}"> | |
| <div class="flex justify-between items-center mb-2"> | |
| <span class="font-medium">Account Risk</span> | |
| <span class="font-bold ${analysis.riskScore > 70 ? 'text-red-500' : analysis.riskScore > 40 ? 'text-yellow-500' : 'text-green-500'}">${analysis.riskScore}%</span> | |
| </div> | |
| <div class="text-sm text-gray-300"> | |
| <p>Suspicious Transactions: ${analysis.suspiciousCount}</p> | |
| <p>Total Analyzed: ${data.length}</p> | |
| </div> | |
| </div> | |
| `; | |
| updateMasterRisk('Bank Accounts', analysis.riskScore); | |
| addThreatMessage(`${analysis.suspiciousCount} transactions bancaires suspectes`, analysis.riskScore > 70 ? 'danger' : 'warning'); | |
| } catch (error) { | |
| bankResults.innerHTML = `<div class="text-red-500">Erreur: ${error.message}</div>`; | |
| } finally { | |
| analyzeBankBtn.disabled = false; | |
| analyzeBankBtn.innerHTML = '[ANALYSER COMPTES]'; | |
| feather.replace(); | |
| } | |
| }); | |
| function performBankAnalysis(data) { | |
| const suspiciousPatterns = [ | |
| 'cash', 'bitcoin', 'crypto', 'anonymous', 'instant transfer', | |
| 'urgent', 'confidential', 'personal', 'gift', 'loan' | |
| ]; | |
| let suspiciousCount = 0; | |
| const anomalies = []; | |
| data.forEach((entry, index) => { | |
| const text = JSON.stringify(entry).toLowerCase(); | |
| const amount = extractAmount(text); | |
| // Détection de transactions suspectes | |
| suspiciousPatterns.forEach(pattern => { | |
| if (text.includes(pattern) && amount > 5000) { | |
| suspiciousCount++; | |
| anomalies.push({ | |
| pattern, | |
| amount, | |
| line: index | |
| }); | |
| } | |
| }); | |
| // Détection de structuring (smurfing) | |
| if (amount >= 9000 && amount <= 9999) { | |
| suspiciousCount++; | |
| anomalies.push({ | |
| pattern: 'Potential Structuring', | |
| amount, | |
| line: index | |
| }); | |
| } | |
| }); | |
| const riskScore = Math.min(100, suspiciousCount * 10); | |
| return { riskScore, suspiciousCount, anomalies }; | |
| } | |
| // Omni Analyzer | |
| omniAnalyzeBtn.addEventListener('click', async function() { | |
| const files = { | |
| omni: omniFile.files[0], | |
| contract: contractFile.files[0], | |
| transaction: transactionFile.files[0] | |
| }; | |
| if (!files.omni && !files.contract && !files.transaction) { | |
| alert('Sélectionnez au moins un fichier à analyser'); | |
| return; | |
| } | |
| omniAnalyzeBtn.disabled = true; | |
| omniAnalyzeBtn.innerHTML = '<i data-feather="loader" class="animate-spin inline mr-2"></i>Analyse totale en cours...'; | |
| feather.replace(); | |
| try { | |
| addThreatMessage('Lancement analyse omnidirectionnelle', 'info'); | |
| const results = await performOmniAnalysis(files); | |
| displayOmniResults(results); | |
| addThreatMessage(`Analyse terminée. Risque global: ${results.globalRisk}%`, results.globalRisk > 70 ? 'danger' : 'warning'); | |
| } catch (error) { | |
| omniResultsContent.innerHTML = `<div class="text-red-500">Erreur critique: ${error.message}</div>`; | |
| omniResults.classList.remove('hidden'); | |
| } finally { | |
| omniAnalyzeBtn.disabled = false; | |
| omniAnalyzeBtn.innerHTML = '[LANCER ANALYSE TOTALE]'; | |
| feather.replace(); | |
| } | |
| }); | |
| async function performOmniAnalysis(files) { | |
| const results = { components: [], globalRisk: 0 }; | |
| let totalWeight = 0; | |
| if (files.omni) { | |
| addThreatMessage(`Analyse du FEC/Bilan: ${files.omni.name}`, 'warning'); | |
| const fecResult = await performAnalysis(files.omni); | |
| results.components.push({ | |
| type: 'FEC/BILAN', | |
| risk: fecResult.riskScore, | |
| weight: 0.4 | |
| }); | |
| totalWeight += 0.4; | |
| } | |
| if (files.contract) { | |
| addThreatMessage(`Analyse des contrats: ${files.contract.name}`, 'warning'); | |
| const contractText = files.contract.type === 'application/pdf' ? | |
| await extractTextFromPDF(files.contract) : | |
| await files.contract.text(); | |
| const offshoreDetections = detectOffshoreEntities(contractText); | |
| const contractRisk = Math.min(100, offshoreDetections.length * 20); | |
| results.components.push({ | |
| type: 'CONTRACTS', | |
| risk: contractRisk, | |
| weight: 0.3 | |
| }); | |
| totalWeight += 0.3; | |
| } | |
| if (files.transaction) { | |
| addThreatMessage(`Analyse transactions: ${files.transaction.name}`, 'warning'); | |
| const data = await processExcelFile(files.transaction); | |
| const bankResult = performBankAnalysis(data); | |
| results.components.push({ | |
| type: 'TRANSACTIONS', | |
| risk: bankResult.riskScore, | |
| weight: 0.3 | |
| }); | |
| totalWeight += 0.3; | |
| } | |
| // Calcul du risque global pondéré | |
| results.globalRisk = Math.round( | |
| results.components.reduce((sum, comp) => sum + (comp.risk * comp.weight), 0) / totalWeight | |
| ); | |
| return results; | |
| } | |
| function displayOmniResults(results) { | |
| let content = `<h4 class="text-xl font-bold mb-4">Résultats Omnidirectionnels</h4>`; | |
| content += `<div class="mb-4"><span class="text-2xl font-bold text-accent">Risque Global: ${results.globalRisk}%</span></div>`; | |
| results.components.forEach(comp => { | |
| content += ` | |
| <div class="mb-3 p-3 bg-gray-800 rounded border ${comp.risk > 70 ? 'border-red-500' : comp.risk > 40 ? 'border-yellow-500' : 'border-green-500'}"> | |
| <div class="flex justify-between"> | |
| <span class="font-medium">${comp.type}</span> | |
| <span class="font-bold ${comp.risk > 70 ? 'text-red-500' : comp.risk > 40 ? 'text-yellow-500' : 'text-green-500'}">${comp.risk}%</span> | |
| </div> | |
| </div> | |
| `; | |
| }); | |
| omniResultsContent.innerHTML = content; | |
| omniResults.classList.remove('hidden'); | |
| updateMasterRisk('Omni Analysis', results.globalRisk); | |
| } | |
| function updateMasterRisk(component, risk) { | |
| riskComponents.push({ component, risk }); | |
| // Calcul moyenne des risques | |
| const avgRisk = Math.round( | |
| riskComponents.reduce((sum, comp) => sum + comp.risk, 0) / riskComponents.length | |
| ); | |
| globalRiskScore = avgRisk; | |
| masterRiskScore.textContent = globalRiskScore + '%'; | |
| masterRiskBar.style.width = globalRiskScore + '%'; | |
| // Mise à jour du niveau de menace | |
| if (globalRiskScore > 70) { | |
| threatLevel.textContent = 'CRITIQUE - Action immédiate requise'; | |
| threatLevel.className = 'text-red-500 mt-2 font-bold'; | |
| } else if (globalRiskScore > 40) { | |
| threatLevel.textContent = 'ÉLEVÉ - Investigation nécessaire'; | |
| threatLevel.className = 'text-yellow-500 mt-2 font-bold'; | |
| } else { | |
| threatLevel.textContent = 'MODÉRÉ - Surveillance continue'; | |
| threatLevel.className = 'text-green-500 mt-2 font-bold'; | |
| } | |
| // Animation de la barre | |
| masterRiskBar.classList.add('animate-risk'); | |
| } | |
| // File upload handlers | |
| bankFile.addEventListener('change', (e) => { | |
| if (e.target.files[0]) { | |
| bankResults.innerHTML = `<div class="text-green-500">Fichier chargé: ${e.target.files[0].name}</div>`; | |
| } | |
| }); | |
| // Initialiser le fil d'alertes | |
| threatMessages.forEach((msg, index) => { | |
| // Check API status | |
| async function checkApiStatus() { | |
| if (!API_CONFIG.apiKey) { | |
| apiConnectionStatus.innerHTML = '<span class="text-yellow-500">No API Key Configured</span>'; | |
| return; | |
| } | |
| try { | |
| const response = await fetch(`${API_CONFIG.baseUrl}/models`, { | |
| headers: { | |
| 'Authorization': `Bearer ${API_CONFIG.apiKey}`, | |
| 'HTTP-Referer': window.location.href, | |
| 'X-Title': 'Janus Scanner Pro' | |
| } | |
| }); | |
| if (response.ok) { | |
| apiConnectionStatus.innerHTML = '<span class="text-green-500">Connected</span>'; | |
| } else { | |
| apiConnectionStatus.innerHTML = '<span class="text-red-500">Connection Failed</span>'; | |
| } | |
| } catch (error) { | |
| apiConnectionStatus.innerHTML = '<span class="text-red-500">Offline</span>'; | |
| } | |
| } | |
| // AI Analysis function | |
| async function performAIAnalysis(data, analysisType = 'fraud') { | |
| if (!API_CONFIG.apiKey) { | |
| throw new Error('OpenRouter API key not configured. Go to Settings to add your API key.'); | |
| } | |
| const models = { | |
| fraud: API_CONFIG.models.analysis, | |
| fast: API_CONFIG.models.fast, | |
| complex: API_CONFIG.models.complex | |
| }; | |
| const prompt = analysisType === 'fraud' | |
| ? `Analyze this financial data for fraud patterns, anomalies, and suspicious activities. Return a JSON with: {riskScore: 0-100, anomalies: [{type, severity, description}], summary: string}` | |
| : `Analyze this crypto/blockchain data. Return JSON: {riskScore: 0-100, anomalies: [], totalValue: number, summary: string}`; | |
| const response = await fetch(`${API_CONFIG.baseUrl}/chat/completions`, { | |
| method: 'POST', | |
| headers: { | |
| 'Authorization': `Bearer ${API_CONFIG.apiKey}`, | |
| 'Content-Type': 'application/json', | |
| 'HTTP-Referer': window.location.href, | |
| 'X-Title': 'Janus Scanner Pro' | |
| }, | |
| body: JSON.stringify({ | |
| model: models[analysisType] || models.fraud, | |
| messages: [ | |
| { | |
| role: 'system', | |
| content: prompt | |
| }, | |
| { | |
| role: 'user', | |
| content: JSON.stringify(data) | |
| } | |
| ], | |
| temperature: 0.3 | |
| }) | |
| }); | |
| if (!response.ok) { | |
| throw new Error(`API Error: ${response.status} - ${await response.text()}`); | |
| } | |
| const result = await response.json(); | |
| return JSON.parse(result.choices[0].message.content); | |
| } | |
| // Enhanced crypto analysis with AI | |
| analyzeCryptoBtn.addEventListener('click', async function() { | |
| const wallet = cryptoWallet.value.trim(); | |
| if (!wallet) { | |
| alert('Entrez une adresse wallet'); | |
| return; | |
| } | |
| analyzeCryptoBtn.disabled = true; | |
| analyzeCryptoBtn.innerHTML = '<i data-feather="loader" class="animate-spin inline mr-2"></i>Scanning blockchain...'; | |
| feather.replace(); | |
| try { | |
| addThreatMessage(`Scan wallet: ${wallet.substring(0, 20)}...`, 'warning'); | |
| // Get real crypto data | |
| const pricesResponse = await fetch(`https://api.coingecko.com/api/v3/simple/price?ids=bitcoin,ethereum&vs_currencies=usd`); | |
| const prices = await pricesResponse.json(); | |
| // Simulate transaction data for AI analysis | |
| const mockData = { | |
| wallet: wallet, | |
| transactions: Array.from({length: 10}, (_, i) => ({ | |
| amount: Math.random() * 50000 + 1000, | |
| type: ['withdrawal', 'deposit', 'transfer'][Math.floor(Math.random() * 3)], | |
| timestamp: Date.now() - (i * 3600000), | |
| counterparty: `0x${Math.random().toString(16).substr(2, 40)}` | |
| })), | |
| currentPrices: prices | |
| }; | |
| // AI Analysis | |
| const aiResult = await performAIAnalysis(mockData, 'crypto'); | |
| if (aiResult) { | |
| cryptoResults.innerHTML = ` | |
| <div class="bg-gray-700 p-3 rounded border ${aiResult.riskScore > 70 ? 'border-red-500' : aiResult.riskScore > 40 ? 'border-yellow-500' : 'border-green-500'}"> | |
| <div class="flex justify-between items-center mb-2"> | |
| <span class="font-medium">AI Risk Assessment</span> | |
| <span class="font-bold ${aiResult.riskScore > 70 ? 'text-red-500' : aiResult.riskScore > 40 ? 'text-yellow-500' : 'text-green-500'}">${aiResult.riskScore}%</span> | |
| </div> | |
| <div class="text-sm text-gray-300"> | |
| <p>Est. Value: ${aiResult.totalValue ? aiResult.totalValue.toFixed(2) : 'N/A'}</p> | |
| <p>AI Detected: ${aiResult.anomalies ? aiResult.anomalies.length : 0} anomalies</p> | |
| <p class="mt-2 text-xs">${aiResult.summary || 'Analysis complete'}</p> | |
| </div> | |
| </div> | |
| `; | |
| updateMasterRisk('Crypto Wallet', aiResult.riskScore); | |
| addThreatMessage(`Risque crypto: ${aiResult.riskScore}%`, aiResult.riskScore > 70 ? 'danger' : 'warning'); | |
| // Save to history | |
| addToScanHistory({ | |
| fileName: `Crypto Wallet ${wallet.substring(0, 10)}...`, | |
| date: new Date().toISOString(), | |
| riskScore: aiResult.riskScore, | |
| anomalies: aiResult.anomalies ? aiResult.anomalies.length : 0, | |
| status: aiResult.riskScore > 70 ? 'HIGH RISK' : aiResult.riskScore > 40 ? 'MEDIUM RISK' : 'LOW RISK' | |
| }); | |
| } | |
| } catch (error) { | |
| cryptoResults.innerHTML = `<div class="text-red-500">Erreur: ${error.message}</div>`; | |
| addThreatMessage(`Crypto scan failed: ${error.message}`, 'danger'); | |
| } finally { | |
| analyzeCryptoBtn.disabled = false; | |
| analyzeCryptoBtn.innerHTML = '[SCANNER WALLET]'; | |
| feather.replace(); | |
| } | |
| }); | |
| // Enhanced offshore detection with AI | |
| detectOffshoreBtn.addEventListener('click', async function() { | |
| const text = offshoreText.value.trim(); | |
| if (!text) { | |
| alert('Collez du texte à analyser'); | |
| return; | |
| } | |
| detectOffshoreBtn.disabled = true; | |
| detectOffshoreBtn.innerHTML = '<i data-feather="loader" class="animate-spin inline mr-2"></i>Analyzing...'; | |
| feather.replace(); | |
| try { | |
| addThreatMessage('Analyse IA des entités offshore...', 'warning'); | |
| const aiResult = await performAIAnalysis({ | |
| text: text, | |
| context: 'offshore_entity_detection' | |
| }, 'complex'); | |
| if (aiResult && aiResult.anomalies) { | |
| if (aiResult.anomalies.length === 0) { | |
| offshoreResults.innerHTML = ` | |
| <div class="text-center py-4 text-green-500"> | |
| <i data-feather="check-circle" class="mx-auto mb-2"></i> | |
| Aucune entité suspecte détectée par IA | |
| </div> | |
| `; | |
| } else { | |
| offshoreResults.innerHTML = aiResult.anomalies.map(a => ` | |
| <div class="bg-red-900 bg-opacity-50 p-3 rounded border border-red-500"> | |
| <div class="flex justify-between items-center"> | |
| <span class="font-medium">${a.type || 'Suspicious Entity'}</span> | |
| <span class="text-red-500 text-sm">${a.severity || 'HIGH'}</span> | |
| </div> | |
| <div class="text-sm text-gray-400 mt-1">${a.description}</div> | |
| </div> | |
| `).join(''); | |
| const offshoreRisk = aiResult.riskScore || Math.min(100, aiResult.anomalies.length * 25); | |
| updateMasterRisk('Offshore Entities', offshoreRisk); | |
| addThreatMessage(`${aiResult.anomalies.length} entités suspectes détectées!`, 'danger'); | |
| } | |
| // Update with AI summary | |
| if (aiResult.summary) { | |
| offshoreResults.innerHTML += `<div class="mt-3 p-2 bg-blue-900 bg-opacity-30 rounded text-xs text-blue-300">${aiResult.summary}</div>`; | |
| } | |
| } else { | |
| // Fallback to regex detection | |
| const detections = window.JanusFraudDetector.detectOffshoreEntities(text); | |
| if (detections.length === 0) { | |
| offshoreResults.innerHTML = ` | |
| <div class="text-center py-4 text-green-500"> | |
| <i data-feather="check-circle" class="mx-auto mb-2"></i> | |
| Aucune entité offshore détectée | |
| </div> | |
| `; | |
| } else { | |
| offshoreResults.innerHTML = detections.map(d => ` | |
| <div class="bg-red-900 bg-opacity-50 p-3 rounded border border-red-500"> | |
| <div class="flex justify-between items-center"> | |
| <span class="font-medium">${d.entity || d.pattern}</span> | |
| <span class="text-red-500 text-sm">${d.severity}</span> | |
| </div> | |
| <div class="text-sm text-gray-400">${d.type}</div> | |
| </div> | |
| `).join(''); | |
| const offshoreRisk = Math.min(100, detections.length * 25); | |
| updateMasterRisk('Offshore Entities', offshoreRisk); | |
| addThreatMessage(`${detections.length} entités offshore détectées!`, 'danger'); | |
| } | |
| } | |
| } catch (error) { | |
| offshoreResults.innerHTML = `<div class="text-red-500">Erreur IA: ${error.message}</div>`; | |
| addThreatMessage(`Offshore detection failed: ${error.message}`, 'danger'); | |
| } finally { | |
| detectOffshoreBtn.disabled = false; | |
| detectOffshoreBtn.innerHTML = '[DÉTECTER ENTITÉS]'; | |
| feather.replace(); | |
| } | |
| }); | |
| // Bank analysis with AI | |
| analyzeBankBtn.addEventListener('click', async function() { | |
| const file = bankFile.files[0]; | |
| if (!file) { | |
| alert('Sélectionnez un fichier de transactions bancaires'); | |
| return; | |
| } | |
| analyzeBankBtn.disabled = true; | |
| analyzeBankBtn.innerHTML = '<i data-feather="loader" class="animate-spin inline mr-2"></i>AI Analyzing...'; | |
| feather.replace(); | |
| try { | |
| addThreatMessage(`Analyse bancaire IA: ${file.name}`, 'warning'); | |
| const data = await processExcelFile(file); | |
| const aiResult = await performAIAnalysis({ | |
| transactions: data.slice(0, 50), // Limit for API | |
| accountPatterns: ['cash', 'anonymous', 'urgent', 'personal'] | |
| }, 'fraud'); | |
| if (aiResult) { | |
| bankResults.innerHTML = ` | |
| <div class="bg-gray-700 p-3 rounded border ${aiResult.riskScore > 70 ? 'border-red-500' : aiResult.riskScore > 40 ? 'border-yellow-500' : 'border-green-500'}"> | |
| <div class="flex justify-between items-center mb-2"> | |
| <span class="font-medium">AI Risk Assessment</span> | |
| <span class="font-bold ${aiResult.riskScore > 70 ? 'text-red-500' : aiResult.riskScore > 40 ? 'text-yellow-500' : 'text-green-500'}">${aiResult.riskScore}%</span> | |
| </div> | |
| <div class="text-sm text-gray-300"> | |
| <p>AI Detected: ${aiResult.anomalies ? aiResult.anomalies.length : 0} anomalies</p> | |
| <p>Transactions: ${data.length}</p> | |
| <p class="mt-2 text-xs">${aiResult.summary || 'Bank analysis complete'}</p> | |
| </div> | |
| </div> | |
| `; | |
| updateMasterRisk('Bank Accounts', aiResult.riskScore); | |
| addThreatMessage(`${aiResult.anomalies ? aiResult.anomalies.length : 0} anomalies bancaires`, aiResult.riskScore > 70 ? 'danger' : 'warning'); | |
| // Save to history | |
| addToScanHistory({ | |
| fileName: file.name, | |
| date: new Date().toISOString(), | |
| riskScore: aiResult.riskScore, | |
| anomalies: aiResult.anomalies ? aiResult.anomalies.length : 0, | |
| status: aiResult.riskScore > 70 ? 'HIGH RISK' : aiResult.riskScore > 40 ? 'MEDIUM RISK' : 'LOW RISK' | |
| }); | |
| } | |
| } catch (error) { | |
| bankResults.innerHTML = `<div class="text-red-500">Erreur IA: ${error.message}</div>`; | |
| addThreatMessage(`Bank analysis failed: ${error.message}`, 'danger'); | |
| } finally { | |
| analyzeBankBtn.disabled = false; | |
| analyzeBankBtn.innerHTML = '[ANALYSER COMPTES]'; | |
| feather.replace(); | |
| } | |
| }); | |
| // File processing helper | |
| // Helper functions for file processing | |
| async function processExcelFile(file) { | |
| return new Promise((resolve, reject) => { | |
| const reader = new FileReader(); | |
| reader.onload = function(e) { | |
| try { | |
| const data = new Uint8Array(e.target.result); | |
| const workbook = XLSX.read(data, { type: 'array' }); | |
| const firstSheet = workbook.Sheets[workbook.SheetNames[0]]; | |
| const jsonData = XLSX.utils.sheet_to_json(firstSheet); | |
| resolve(jsonData); | |
| } catch (error) { | |
| reject(new Error('Failed to process Excel file')); | |
| } | |
| }; | |
| reader.onerror = () => reject(new Error('Failed to read file')); | |
| reader.readAsArrayBuffer(file); | |
| }); | |
| } | |
| function extractAmount(text) { | |
| const amountMatch = text.match(/(\d{1,3}(?:,\d{3})*(?:\.\d{2})?)/g); | |
| if (amountMatch) { | |
| return parseFloat(amountMatch[0].replace(/,/g, '')) || 0; | |
| } | |
| return 0; | |
| } | |
| async function extractTextFromPDF(file) { | |
| return new Promise((resolve, reject) => { | |
| const reader = new FileReader(); | |
| reader.onload = async function(e) { | |
| try { | |
| const pdfData = new Uint8Array(e.target.result); | |
| const pdf = await pdfjsLib.getDocument({ data: pdfData }).promise; | |
| let fullText = ''; | |
| for (let i = 1; i <= pdf.numPages; i++) { | |
| const page = await pdf.getPage(i); | |
| const textContent = await page.getTextContent(); | |
| const pageText = textContent.items.map(item => item.str).join(' '); | |
| fullText += pageText + '\n'; | |
| } | |
| resolve(fullText); | |
| } catch (error) { | |
| reject(new Error('Failed to extract text from PDF')); | |
| } | |
| }; | |
| reader.onerror = () => reject(new Error('Failed to read file')); | |
| reader.readAsArrayBuffer(file); | |
| }); | |
| } | |
| // Add to scan history | |
| function addToScanHistory(scanData) { | |
| scanHistory.unshift({ | |
| ...scanData, | |
| id: Date.now() | |
| }); | |
| scanHistory = scanHistory.slice(0, 50); | |
| localStorage.setItem('scanHistory', JSON.stringify(scanHistory)); | |
| } | |
| // Initialize threat feed | |
| threatMessages.forEach((msg, index) => { | |
| setTimeout(() => addThreatMessage(msg.text, msg.type), index * 1500); | |
| }); | |
| }); | |
| </script> | |
| </body> | |
| </html> |