| |
| |
| |
| |
| |
|
|
| |
| |
| |
| |
| const API_ENDPOINTS = { |
| engage: '/api/v1/honeypot/engage', |
| session: '/api/v1/honeypot/session', |
| health: '/api/v1/health', |
| batch: '/api/v1/honeypot/batch', |
| }; |
|
|
| |
| const EXAMPLE_MESSAGES = [ |
| "๐ฐ Congratulations! You have won 10 LAKH RUPEES in our lucky draw! Send OTP to claim your prize immediately!", |
| "๐ฆ ALERT: Your bank account will be blocked in 24 hours. Update KYC now by sending Rs 500 to processing@paytm", |
| "๐ฎ This is CBI calling. You are involved in money laundering case. Pay Rs 50000 immediately or face arrest. Call +919876543210", |
| "๐ฑ URGENT: Pay Rs 999 to receive your iPhone 15 Pro. UPI ID: scammer@ybl. Bank: 1234567890123 IFSC: HDFC0001234", |
| ]; |
|
|
| |
| |
| |
| let state = { |
| sessionId: null, |
| messages: [], |
| extractedIntel: { |
| upi_ids: [], |
| bank_accounts: [], |
| ifsc_codes: [], |
| phone_numbers: [], |
| phishing_links: [], |
| }, |
| lastResponse: null, |
| isLoading: false, |
| lastCallbackPayload: null, |
| }; |
|
|
| |
| |
| |
| document.addEventListener('DOMContentLoaded', () => { |
| console.log('Trinetra AI Dashboard initialized'); |
| checkHealth(); |
| |
| |
| setInterval(checkHealth, 30000); |
| }); |
|
|
| |
| |
| |
|
|
| |
| |
| |
| async function checkHealth() { |
| const statusDot = document.querySelector('.status-dot'); |
| const statusText = document.querySelector('.status-text'); |
| |
| try { |
| const response = await fetch(API_ENDPOINTS.health, { |
| headers: { |
| 'x-api-key': 'sVlunn0LMQZNAkRYqZB-f1-Ye7rgzjB_E3b1gNxnUV8', |
| }, |
| }); |
| const data = await response.json(); |
| |
| |
| statusDot.className = 'status-dot ' + data.status; |
| statusText.textContent = data.status.charAt(0).toUpperCase() + data.status.slice(1); |
| |
| |
| updateHealthStatus('healthGroq', data.dependencies?.groq_api); |
| updateHealthStatus('healthPostgres', data.dependencies?.postgres); |
| updateHealthStatus('healthRedis', data.dependencies?.redis); |
| updateHealthStatus('healthModels', data.dependencies?.models_loaded ? 'online' : 'offline'); |
| |
| console.log('โ
Health check:', data.status); |
| return data; |
| } catch (error) { |
| console.error('โ Health check failed:', error); |
| statusDot.className = 'status-dot offline'; |
| statusText.textContent = 'Offline'; |
| |
| updateHealthStatus('healthGroq', 'offline'); |
| updateHealthStatus('healthPostgres', 'offline'); |
| updateHealthStatus('healthRedis', 'offline'); |
| updateHealthStatus('healthModels', 'offline'); |
| |
| return null; |
| } |
| } |
|
|
| |
| |
| |
| async function sendMessage() { |
| const input = document.getElementById('messageInput'); |
| const message = input.value.trim(); |
| |
| if (!message || state.isLoading) return; |
| |
| |
| const welcome = document.querySelector('.chat-welcome'); |
| if (welcome) welcome.remove(); |
| |
| |
| setLoading(true); |
| input.value = ''; |
| |
| |
| addChatMessage(message, 'scammer'); |
| |
| try { |
| const startTime = Date.now(); |
| |
| const payload = { |
| message: message, |
| language: 'auto', |
| }; |
| |
| if (state.sessionId) { |
| payload.session_id = state.sessionId; |
| } |
| |
| const response = await fetch(API_ENDPOINTS.engage, { |
| method: 'POST', |
| headers: { |
| 'Content-Type': 'application/json', |
| 'x-api-key': 'sVlunn0LMQZNAkRYqZB-f1-Ye7rgzjB_E3b1gNxnUV8', |
| }, |
| body: JSON.stringify(payload), |
| }); |
| |
| const data = await response.json(); |
| const responseTime = Date.now() - startTime; |
| |
| |
| state.lastResponse = data; |
| state.sessionId = data.session_id; |
| |
| |
| document.getElementById('sessionId').textContent = |
| `Session: ${data.session_id.substring(0, 8)}...`; |
| |
| |
| document.getElementById('responseTime').textContent = |
| `Last response: ${responseTime}ms`; |
| |
| |
| updateDetectionResult(data); |
| |
| |
| updateAgentInfo(data); |
| |
| |
| if (data.scam_detected && data.engagement) { |
| addChatMessage(data.engagement.agent_response, 'agent', { |
| strategy: data.engagement.strategy, |
| persona: data.engagement.persona, |
| turn: data.engagement.turn_count, |
| }); |
| |
| |
| if (data.extracted_intelligence) { |
| updateIntelligence(data.extracted_intelligence); |
| } |
| } |
| |
| |
| if (data.guvi_callback) { |
| state.lastCallbackPayload = data.guvi_callback; |
| updateCallbackStatus(data.guvi_callback); |
| } |
| |
| console.log('๐จ API Response:', data); |
| |
| } catch (error) { |
| console.error('โ API Error:', error); |
| addSystemMessage('Error: Could not connect to API. Make sure the server is running.'); |
| } finally { |
| setLoading(false); |
| } |
| } |
|
|
| |
| |
| |
| function sendExample(index) { |
| const message = EXAMPLE_MESSAGES[index]; |
| document.getElementById('messageInput').value = message; |
| sendMessage(); |
| } |
|
|
| |
| |
| |
| function newSession() { |
| state.sessionId = null; |
| state.messages = []; |
| state.extractedIntel = { |
| upi_ids: [], |
| bank_accounts: [], |
| ifsc_codes: [], |
| phone_numbers: [], |
| phishing_links: [], |
| }; |
| state.lastResponse = null; |
| |
| |
| const chatContainer = document.getElementById('chatContainer'); |
| chatContainer.innerHTML = ` |
| <div class="chat-welcome"> |
| <div class="welcome-icon">๐ญ</div> |
| <h3>Test the Honeypot Agent</h3> |
| <p>Send a scam message to see how the AI agent responds and extracts intelligence.</p> |
| <div class="example-messages"> |
| <p><strong>Try these examples:</strong></p> |
| <button class="example-btn" onclick="sendExample(0)">๐ฐ Lottery Scam</button> |
| <button class="example-btn" onclick="sendExample(1)">๐ฆ Bank Fraud</button> |
| <button class="example-btn" onclick="sendExample(2)">๐ฎ Police Threat</button> |
| <button class="example-btn" onclick="sendExample(3)">๐ฑ UPI Scam</button> |
| </div> |
| </div> |
| `; |
| |
| |
| document.getElementById('sessionId').textContent = 'No active session'; |
| document.getElementById('detectionResult').innerHTML = |
| '<div class="no-data">Send a message to see detection results</div>'; |
| |
| |
| resetIntelligence(); |
| resetAgentInfo(); |
| resetCallbackStatus(); |
| |
| console.log('๐ New session started'); |
| } |
|
|
| |
| |
| |
|
|
| |
| |
| |
| function addChatMessage(text, sender, meta = {}) { |
| const chatContainer = document.getElementById('chatContainer'); |
| |
| const messageDiv = document.createElement('div'); |
| messageDiv.className = `chat-message ${sender}`; |
| |
| const avatar = sender === 'scammer' ? '๐ฆน' : '๐ค'; |
| const senderName = sender === 'scammer' ? 'Scammer' : 'Agent'; |
| |
| let metaHtml = ''; |
| if (meta.strategy) { |
| metaHtml = ` |
| <div class="message-meta"> |
| <span>Turn ${meta.turn}</span> |
| <span>Strategy: ${meta.strategy}</span> |
| <span>Persona: ${meta.persona}</span> |
| </div> |
| `; |
| } |
| |
| messageDiv.innerHTML = ` |
| <div class="message-avatar">${avatar}</div> |
| <div class="message-content"> |
| <div class="message-sender">${senderName}</div> |
| <div class="message-text">${escapeHtml(text)}</div> |
| ${metaHtml} |
| </div> |
| `; |
| |
| chatContainer.appendChild(messageDiv); |
| chatContainer.scrollTop = chatContainer.scrollHeight; |
| |
| state.messages.push({ sender, text, meta }); |
| } |
|
|
| |
| |
| |
| function addSystemMessage(text) { |
| const chatContainer = document.getElementById('chatContainer'); |
| |
| const messageDiv = document.createElement('div'); |
| messageDiv.className = 'system-message'; |
| messageDiv.style.cssText = 'text-align: center; padding: 10px; color: var(--warning);'; |
| messageDiv.textContent = text; |
| |
| chatContainer.appendChild(messageDiv); |
| } |
|
|
| |
| |
| |
| function updateDetectionResult(data) { |
| const container = document.getElementById('detectionResult'); |
| const isScam = data.scam_detected; |
| const confidence = (data.confidence * 100).toFixed(0); |
| |
| container.className = `detection-result ${isScam ? 'scam' : 'safe'}`; |
| container.innerHTML = ` |
| <div class="detection-label">Scam Detection</div> |
| <div class="detection-value">${isScam ? 'โ ๏ธ SCAM DETECTED' : 'โ SAFE'}</div> |
| <div class="confidence-bar"> |
| <div class="confidence-fill" style="width: ${confidence}%"></div> |
| </div> |
| <div style="margin-top: 8px; font-size: 0.8rem; color: var(--text-secondary);"> |
| Confidence: ${confidence}% | Language: ${data.language_detected} |
| </div> |
| `; |
| } |
|
|
| |
| |
| |
| function updateAgentInfo(data) { |
| if (data.engagement) { |
| document.getElementById('agentPersona').textContent = data.engagement.persona || '-'; |
| document.getElementById('agentStrategy').textContent = data.engagement.strategy || '-'; |
| document.getElementById('turnCount').textContent = `${data.engagement.turn_count} / 20`; |
| } |
| document.getElementById('detectedLanguage').textContent = data.language_detected || '-'; |
| } |
|
|
| |
| |
| |
| function resetAgentInfo() { |
| document.getElementById('agentPersona').textContent = '-'; |
| document.getElementById('agentStrategy').textContent = '-'; |
| document.getElementById('turnCount').textContent = '0 / 20'; |
| document.getElementById('detectedLanguage').textContent = '-'; |
| } |
|
|
| |
| |
| |
| function updateIntelligence(intel) { |
| |
| if (intel.upi_ids) { |
| state.extractedIntel.upi_ids = [...new Set([...state.extractedIntel.upi_ids, ...intel.upi_ids])]; |
| } |
| if (intel.bank_accounts) { |
| state.extractedIntel.bank_accounts = [...new Set([...state.extractedIntel.bank_accounts, ...intel.bank_accounts])]; |
| } |
| if (intel.ifsc_codes) { |
| state.extractedIntel.ifsc_codes = [...new Set([...state.extractedIntel.ifsc_codes, ...intel.ifsc_codes])]; |
| } |
| if (intel.phone_numbers) { |
| state.extractedIntel.phone_numbers = [...new Set([...state.extractedIntel.phone_numbers, ...intel.phone_numbers])]; |
| } |
| if (intel.phishing_links) { |
| state.extractedIntel.phishing_links = [...new Set([...state.extractedIntel.phishing_links, ...intel.phishing_links])]; |
| } |
| |
| |
| updateIntelValue('upiIds', state.extractedIntel.upi_ids); |
| updateIntelValue('bankAccounts', state.extractedIntel.bank_accounts); |
| updateIntelValue('ifscCodes', state.extractedIntel.ifsc_codes); |
| updateIntelValue('phoneNumbers', state.extractedIntel.phone_numbers); |
| updateIntelValue('phishingLinks', state.extractedIntel.phishing_links); |
| |
| |
| const confidence = intel.extraction_confidence || 0; |
| document.getElementById('extractionConfidence').textContent = `${(confidence * 100).toFixed(0)}%`; |
| document.getElementById('extractionConfidence').className = |
| `intel-value ${confidence > 0 ? 'has-data' : ''}`; |
| } |
|
|
| |
| |
| |
| function updateIntelValue(elementId, values) { |
| const element = document.getElementById(elementId); |
| if (values && values.length > 0) { |
| element.textContent = values.join(', '); |
| element.className = 'intel-value has-data'; |
| } else { |
| element.textContent = '-'; |
| element.className = 'intel-value'; |
| } |
| } |
|
|
| |
| |
| |
| function resetIntelligence() { |
| updateIntelValue('upiIds', []); |
| updateIntelValue('bankAccounts', []); |
| updateIntelValue('ifscCodes', []); |
| updateIntelValue('phoneNumbers', []); |
| updateIntelValue('phishingLinks', []); |
| document.getElementById('extractionConfidence').textContent = '-'; |
| } |
|
|
| |
| |
| |
| function updateHealthStatus(elementId, status) { |
| const element = document.getElementById(elementId); |
| let displayStatus = status || 'offline'; |
| |
| |
| if (displayStatus === 'not_configured') displayStatus = 'offline'; |
| if (displayStatus === true) displayStatus = 'online'; |
| if (displayStatus === false) displayStatus = 'offline'; |
| |
| element.textContent = displayStatus.charAt(0).toUpperCase() + displayStatus.slice(1); |
| element.className = `health-status ${displayStatus}`; |
| } |
|
|
| |
| |
| |
| function setLoading(loading) { |
| state.isLoading = loading; |
| const sendBtn = document.getElementById('sendBtn'); |
| sendBtn.disabled = loading; |
| sendBtn.innerHTML = loading |
| ? '<span>Sending...</span>' |
| : '<span>Send</span><svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M22 2L11 13M22 2l-7 20-4-9-9-4 20-7z"/></svg>'; |
| } |
|
|
| |
| |
| |
|
|
| |
| |
| |
| function exportReport() { |
| const modal = document.getElementById('reportModal'); |
| const content = document.getElementById('reportContent'); |
| |
| const report = generateReport(); |
| |
| content.innerHTML = ` |
| <div class="report-section"> |
| <h4>๐ Session Information</h4> |
| <div class="report-item"> |
| <span class="report-item-label">Session ID:</span> |
| <span class="report-item-value">${report.session_id || 'N/A'}</span> |
| </div> |
| <div class="report-item"> |
| <span class="report-item-label">Total Messages:</span> |
| <span class="report-item-value">${report.total_messages}</span> |
| </div> |
| <div class="report-item"> |
| <span class="report-item-label">Language:</span> |
| <span class="report-item-value">${report.language}</span> |
| </div> |
| <div class="report-item"> |
| <span class="report-item-label">Detection Status:</span> |
| <span class="report-item-value">${report.scam_detected ? 'โ ๏ธ SCAM DETECTED' : 'โ Safe'}</span> |
| </div> |
| <div class="report-item"> |
| <span class="report-item-label">Confidence:</span> |
| <span class="report-item-value">${report.confidence}%</span> |
| </div> |
| </div> |
| |
| <div class="report-section"> |
| <h4>๐ญ Agent Performance</h4> |
| <div class="report-item"> |
| <span class="report-item-label">Persona Used:</span> |
| <span class="report-item-value">${report.persona}</span> |
| </div> |
| <div class="report-item"> |
| <span class="report-item-label">Final Strategy:</span> |
| <span class="report-item-value">${report.strategy}</span> |
| </div> |
| <div class="report-item"> |
| <span class="report-item-label">Turns Completed:</span> |
| <span class="report-item-value">${report.turn_count}</span> |
| </div> |
| </div> |
| |
| <div class="report-section"> |
| <h4>๐ Extracted Intelligence</h4> |
| ${formatIntelList('UPI IDs', report.extracted_intelligence.upi_ids)} |
| ${formatIntelList('Bank Accounts', report.extracted_intelligence.bank_accounts)} |
| ${formatIntelList('IFSC Codes', report.extracted_intelligence.ifsc_codes)} |
| ${formatIntelList('Phone Numbers', report.extracted_intelligence.phone_numbers)} |
| ${formatIntelList('Phishing Links', report.extracted_intelligence.phishing_links)} |
| <div class="report-item"> |
| <span class="report-item-label">Extraction Confidence:</span> |
| <span class="report-item-value">${report.extraction_confidence}%</span> |
| </div> |
| </div> |
| |
| <div class="report-section"> |
| <h4>๐ฌ Conversation History</h4> |
| <div style="max-height: 200px; overflow-y: auto; background: var(--bg-card); padding: 12px; border-radius: 8px;"> |
| ${report.messages.map(m => ` |
| <div style="margin-bottom: 8px; padding: 8px; background: var(--bg-tertiary); border-radius: 4px;"> |
| <strong>${m.sender === 'scammer' ? '๐ฆน Scammer' : '๐ค Agent'}:</strong> |
| <span style="color: var(--text-secondary);">${escapeHtml(m.text)}</span> |
| </div> |
| `).join('')} |
| </div> |
| </div> |
| `; |
| |
| modal.classList.add('active'); |
| } |
|
|
| |
| |
| |
| function generateReport() { |
| const lastResp = state.lastResponse || {}; |
| |
| return { |
| session_id: state.sessionId, |
| timestamp: new Date().toISOString(), |
| total_messages: state.messages.length, |
| language: lastResp.language_detected || 'N/A', |
| scam_detected: lastResp.scam_detected || false, |
| confidence: ((lastResp.confidence || 0) * 100).toFixed(0), |
| persona: lastResp.engagement?.persona || 'N/A', |
| strategy: lastResp.engagement?.strategy || 'N/A', |
| turn_count: lastResp.engagement?.turn_count || 0, |
| extracted_intelligence: state.extractedIntel, |
| extraction_confidence: ((lastResp.extracted_intelligence?.extraction_confidence || 0) * 100).toFixed(0), |
| messages: state.messages, |
| }; |
| } |
|
|
| |
| |
| |
| function formatIntelList(label, items) { |
| if (!items || items.length === 0) { |
| return ` |
| <div class="report-item"> |
| <span class="report-item-label">${label}:</span> |
| <span class="report-item-value" style="color: var(--text-muted);">None found</span> |
| </div> |
| `; |
| } |
| |
| return ` |
| <div class="report-item"> |
| <span class="report-item-label">${label}:</span> |
| <ul class="report-list"> |
| ${items.map(item => `<li>${escapeHtml(item)}</li>`).join('')} |
| </ul> |
| </div> |
| `; |
| } |
|
|
| |
| |
| |
| function closeModal() { |
| document.getElementById('reportModal').classList.remove('active'); |
| } |
|
|
| |
| |
| |
| function downloadReport() { |
| const report = generateReport(); |
| const blob = new Blob([JSON.stringify(report, null, 2)], { type: 'application/json' }); |
| const url = URL.createObjectURL(blob); |
| |
| const a = document.createElement('a'); |
| a.href = url; |
| a.download = `trinetra-report-${state.sessionId || 'unknown'}.json`; |
| document.body.appendChild(a); |
| a.click(); |
| document.body.removeChild(a); |
| URL.revokeObjectURL(url); |
| } |
|
|
| |
| |
| |
|
|
| |
| |
| |
| function updateCallbackStatus(callbackData) { |
| const section = document.getElementById('callbackSection'); |
| const successEl = document.getElementById('callbackSuccess'); |
| const urlEl = document.getElementById('callbackUrl'); |
| |
| |
| section.style.display = 'block'; |
| |
| |
| if (callbackData.callback_success === true) { |
| successEl.textContent = 'โ
Sent Successfully'; |
| successEl.style.color = 'var(--success)'; |
| } else if (callbackData.callback_success === false) { |
| successEl.textContent = 'โ Failed'; |
| successEl.style.color = 'var(--danger)'; |
| } else { |
| successEl.textContent = 'โณ Pending'; |
| successEl.style.color = 'var(--warning)'; |
| } |
| |
| |
| if (callbackData.callback_url) { |
| urlEl.textContent = callbackData.callback_url; |
| } |
| |
| |
| addSystemMessage(`๐ GUVI Callback Triggered! Extraction confidence: ${((state.lastResponse?.extracted_intelligence?.extraction_confidence || 0) * 100).toFixed(0)}%`); |
| |
| console.log('๐ก GUVI Callback Triggered:', callbackData); |
| } |
|
|
| |
| |
| |
| function showCallbackPayload() { |
| if (!state.lastCallbackPayload) { |
| alert('No callback payload available'); |
| return; |
| } |
| |
| const modal = document.getElementById('callbackModal'); |
| const content = document.getElementById('callbackPayloadContent'); |
| const urlDisplay = document.getElementById('callbackUrlDisplay'); |
| |
| |
| const displayPayload = { |
| sessionId: state.lastCallbackPayload.sessionId, |
| scamDetected: state.lastCallbackPayload.scamDetected, |
| totalMessagesExchanged: state.lastCallbackPayload.totalMessagesExchanged, |
| extractedIntelligence: state.lastCallbackPayload.extractedIntelligence, |
| agentNotes: state.lastCallbackPayload.agentNotes, |
| }; |
| |
| |
| urlDisplay.textContent = `POST ${state.lastCallbackPayload.callback_url || 'https://hackathon.guvi.in/api/updateHoneyPotFinalResult'}`; |
| |
| |
| content.textContent = JSON.stringify(displayPayload, null, 2); |
| |
| modal.classList.add('active'); |
| } |
|
|
| |
| |
| |
| function closeCallbackModal() { |
| document.getElementById('callbackModal').classList.remove('active'); |
| } |
|
|
| |
| |
| |
| function copyCallbackPayload() { |
| if (!state.lastCallbackPayload) return; |
| |
| const displayPayload = { |
| sessionId: state.lastCallbackPayload.sessionId, |
| scamDetected: state.lastCallbackPayload.scamDetected, |
| totalMessagesExchanged: state.lastCallbackPayload.totalMessagesExchanged, |
| extractedIntelligence: state.lastCallbackPayload.extractedIntelligence, |
| agentNotes: state.lastCallbackPayload.agentNotes, |
| }; |
| |
| navigator.clipboard.writeText(JSON.stringify(displayPayload, null, 2)) |
| .then(() => { |
| alert('Callback payload copied to clipboard!'); |
| }) |
| .catch(err => { |
| console.error('Failed to copy:', err); |
| alert('Failed to copy to clipboard'); |
| }); |
| } |
|
|
| |
| |
| |
| function resetCallbackStatus() { |
| const section = document.getElementById('callbackSection'); |
| section.style.display = 'none'; |
| state.lastCallbackPayload = null; |
| } |
|
|
| |
| |
| |
|
|
| |
| |
| |
| function handleKeyDown(event) { |
| if (event.ctrlKey && event.key === 'Enter') { |
| event.preventDefault(); |
| sendMessage(); |
| } |
| } |
|
|
| |
| |
| |
| function escapeHtml(text) { |
| const div = document.createElement('div'); |
| div.textContent = text; |
| return div.innerHTML; |
| } |
|
|