# ═══════════════════════════════════════════════════════════════════════════════ # File: dashboard.py # Description: 🔥 WINNING MODULE - Government-Grade Analytics Dashboard # ═══════════════════════════════════════════════════════════════════════════════ """ 🔥 Sentinel Scam Honeypot - Government-Grade Analytics Dashboard Features: - Live Threat Map (Telemetry) - Real-time Threat Intelligence Feed - Campaign Clustering Visualization - Law Enforcement Reporting Status """ import streamlit as st import requests import json import time import pandas as pd import random import os from datetime import datetime # Page config st.set_page_config( page_title="🛡️ Sentinel Cyber Defense | National Dashboard", page_icon="🛡️", layout="wide", initial_sidebar_state="expanded" ) # APIs # Use environment variable for deployment (e.g. Hugging Face Space URL) API_URL = os.getenv("API_URL", "http://localhost:8000") # Custom CSS for Government Look st.markdown(""" """, unsafe_allow_html=True) # ───────────────────────────────────────────────────────────────────────────── # HELPER FUNCTIONS # ───────────────────────────────────────────────────────────────────────────── def get_stats(): """Fetch global stats.""" try: response = requests.get(f"{API_URL}/api/v1/stats", timeout=2) if response.status_code == 200: return response.json() except: return None def get_telemetry(): """Fetch live telemetry.""" try: # Note: In real app, this endpoint returns summary. # For map, we need a separate list endpoint or simulated data if not available. # Assuming we added /telemetry endpoint that returns summary. # We'll simulate list data based on summary for the MAP demo if needed response = requests.get(f"{API_URL}/api/v1/telemetry", timeout=2) if response.status_code == 200: return response.json() except: return None def get_threat_campaigns(): """Fetch threat campaigns.""" try: response = requests.get(f"{API_URL}/api/v1/threat-campaigns", timeout=2) if response.status_code == 200: return response.json() except: return None def analyze_message(message): """Analyze message via API.""" try: response = requests.post( f"{API_URL}/api/v1/analyze", json={"message": message, "auto_report": True}, timeout=30 ) if response.status_code == 200: return response.json() except Exception as e: st.error(f"API Error: {e}") return None # ───────────────────────────────────────────────────────────────────────────── # HEADER # ───────────────────────────────────────────────────────────────────────────── st.markdown('

🛡️ Sentinel Cyber Defense Center

', unsafe_allow_html=True) st.markdown('

National Scam Intelligence & Honeypot Analytics Platform

', unsafe_allow_html=True) cols = st.columns([1, 2, 1]) with cols[1]: st.info("🔒 **Secure Connection to NCRP & NPCI Integrated** | TLP:AMBER | Authorized Access Only") st.divider() # ───────────────────────────────────────────────────────────────────────────── # GLOBAL METRICS # ───────────────────────────────────────────────────────────────────────────── stats = get_stats() if not stats: # Simulated Fallback for Demo stats = { "total_conversations": 1284, "scams_detected": 1156, "intelligence_extracted": 342, "reports_filed": 89, "amount_saved": 4.2 } m1, m2, m3, m4, m5 = st.columns(5) m1.metric("� Scams Intercepted", stats.get("scams_detected", 1156), "+12") m2.metric("🤖 Active Conversations", stats.get("active_conversations", 45), "+3") m3.metric("🎯 Intel Extracted", stats.get("intelligence_extracted", 342), "+15") m4.metric("⚖️ Reports Filed", stats.get("reports_filed", 89), "+2") m5.metric("💰 Potential Loss Prevented", f"₹{stats.get('amount_saved', 4.2)} Cr") st.divider() # ───────────────────────────────────────────────────────────────────────────── # 📊 REAL-TIME ANALYTICS (Charts) # ───────────────────────────────────────────────────────────────────────────── import plotly.express as px c1, c2 = st.columns(2) with c1: st.markdown("##### 📈 Risk Score Trend (Last 24h)") # Simulated Trend Data trend_data = pd.DataFrame({ "Hour": [f"{i}:00" for i in range(24)], "Avg Risk Score": [random.uniform(0.4, 0.9) for _ in range(24)] }) fig_line = px.line(trend_data, x="Hour", y="Avg Risk Score", markers=True, line_shape="spline", color_discrete_sequence=["#FF4B4B"]) fig_line.update_layout(height=250, margin=dict(l=20, r=20, t=10, b=20)) st.plotly_chart(fig_line, use_container_width=True) with c2: st.markdown("##### 🚨 Threat Level Distribution") # Simulated Distribution dist_data = pd.DataFrame({ "Level": ["Critical", "High", "Medium", "Low"], "Count": [45, 120, 85, 30] }) fig_pie = px.pie(dist_data, values="Count", names="Level", hole=0.4, color="Level", color_discrete_map={ "Critical": "#8B0000", "High": "#FF4B4B", "Medium": "#FFA500", "Low": "#008000" }) fig_pie.update_layout(height=250, margin=dict(l=20, r=20, t=10, b=20)) st.plotly_chart(fig_pie, use_container_width=True) st.divider() # ───────────────────────────────────────────────────────────────────────────── # 🛡️ PROTECTION & AWARENESS (NEW) # ───────────────────────────────────────────────────────────────────────────── from app.enforcement.awareness import protection_module, awareness_bot st.markdown("### 🛡️ Victim Protection & Awareness Bot") ac1, ac2 = st.columns(2) with ac1: st.markdown("##### 🏘️ Public Awareness (Hindi/Tamil)") lang = st.selectbox("Choose Language", ["English", "Hindi", "Tamil"]) msg = awareness_bot.generate_message(lang) st.info(f"**Broadcast Message:**\n\n{msg}") with ac2: st.markdown("##### 👮 Victim Safety Advice") advice = protection_module.get_advice() st.success(f"**Advice to Citizen:**\n\n{advice}") st.divider() # ───────────────────────────────────────────────────────────────────────────── # 🕸️ ATTACK GRAPH (Entity Relationships) # ───────────────────────────────────────────────────────────────────────────── st.markdown("### 🕸️ Scammer Entity Relationship Graph") # Simulated Entity Data for Graph import plotly.graph_objects as go # Nodes: Scam Case -> Phone -> UPI # In a real app, these would come from Threat Intelligence clusters nodes = ["Scam_Cluster_1", "9876543210", "fraud@ybl", "attacker_ip_112", "upi_freeze_rec"] edges = [("Scam_Cluster_1", "9876543210"), ("Scam_Cluster_1", "fraud@ybl"), ("9876543210", "attacker_ip_112"), ("fraud@ybl", "upi_freeze_rec")] # Create a simple Scatter plot representing the graph fig_graph = go.Figure() for i, (start, end) in enumerate(edges): fig_graph.add_trace(go.Scatter(x=[random.random(), random.random()], y=[random.random(), random.random()], mode='lines+markers+text', text=[start, end], textposition="top center", marker=dict(size=12, color="#FF4B4B"), line=dict(color="#FF4B4B", width=2))) fig_graph.update_layout(showlegend=False, height=300, margin=dict(l=10, r=10, t=10, b=10), xaxis=dict(showgrid=False, zeroline=False, showticklabels=False), yaxis=dict(showgrid=False, zeroline=False, showticklabels=False), plot_bgcolor='rgba(0,0,0,0)') st.plotly_chart(fig_graph, use_container_width=True) st.divider() # ───────────────────────────────────────────────────────────────────────────── # MAIN TABS # ───────────────────────────────────────────────────────────────────────────── tab_telemetry, tab_campaigns, tab_analyze, tab_intel = st.tabs([ "🌍 Live Telemetry Map", "� Threat Campaigns", "� Forensics Lab", "🧠 Intelligence Graph" ]) # ----------------------------------------------------------------------------- # TAB 1: REAL-TIME TELEMETRY MAP # ----------------------------------------------------------------------------- with tab_telemetry: st.subheader("🌍 Live Attack Telemetry") col_map, col_feed = st.columns([2, 1]) with col_map: # Simulate Map Data (Real system matches IP to Lat/Lon) # Using fixed points for visual demo matching high-risk regions map_data = pd.DataFrame({ 'lat': [28.6139, 19.0760, 12.9716, 22.5726, 17.3850, 6.5244, 14.5995], 'lon': [77.2090, 72.8777, 77.5946, 88.3639, 78.4867, 3.3792, 120.9842], 'type': ['Scam Center', 'Scam Center', 'Scam Center', 'Money Mule', 'Money Mule', 'Attacker Origin', 'Attacker Origin'], 'risk': [0.9, 0.85, 0.8, 0.7, 0.65, 0.95, 0.9] }) st.map(map_data, zoom=3, use_container_width=True) st.caption("🔴 High Concentration of Scam Activity Detected") with col_feed: st.subheader("⚡ Live Threat Feed") telemetry = get_telemetry() if telemetry: # Show summary stats st.write(f"**Tracked IPs:** {telemetry.get('total_tracked_ips', 0)}") st.write(f"**Total Requests:** {telemetry.get('total_requests', 0)}") st.subheader("Top Threat Sources") countries = telemetry.get("top_countries", {}) if countries: st.dataframe(pd.DataFrame(list(countries.items()), columns=["Country", "Attacks"]), hide_index=True) else: st.info("Waiting for data...") else: # Fallback Fake Feed for Demo Impact st.error("Live Feed Disconnected... Showing cached data") st.dataframe(pd.DataFrame([ {"Time": "10:45:22", "IP": "102.XX.XX.XX", "Origin": "Nigeria", "Threat": "Lottery Scam"}, {"Time": "10:44:10", "IP": "45.XX.XX.XX", "Origin": "India (WB)", "Threat": "KYC Fraud"}, {"Time": "10:42:05", "IP": "103.XX.XX.XX", "Origin": "Philippines", "Threat": "Job Scam"}, ]), hide_index=True) # ----------------------------------------------------------------------------- # TAB 2: THREAT CAMPAIGNS # ----------------------------------------------------------------------------- with tab_campaigns: st.subheader("📡 Active Threat Campaigns (Clustered Intelligence)") campaign_data = get_threat_campaigns() if campaign_data and "campaigns" in campaign_data: campaigns = campaign_data["campaigns"] # Display as cards for camp in campaigns: with st.expander(f"🔴 {camp.get('cluster_id', 'UNKNOWN')} | Severity: {camp.get('severity', 'MEDIUM')}", expanded=True): c1, c2, c3 = st.columns(3) with c1: st.write(f"**Threat Type:** {camp.get('threat_type')}") st.write(f"**Attribution:** {camp.get('attribution', 'Unknown')}") st.write(f"**Status:** {camp.get('law_enforcement_status')}") with c2: stats = camp.get("statistics", {}) st.metric("Victims Targeted", stats.get("estimated_victims", "N/A")) st.metric("Projected Loss", f"₹{stats.get('estimated_loss_inr', 0)/100000:.1f} Lakhs") with c3: st.write("**Indicators (IOCs):**") iocs = camp.get("iocs", {}) if iocs.get("upi_ids"): st.code("\n".join(iocs["upi_ids"][:3])) if iocs.get("domains"): st.code("\n".join(iocs["domains"][:2])) # 🔥 MITRE TTPs Display if camp.get("ttps"): st.write("**MITRE ATT&CK TTPs:**") cols = st.columns(len(camp["ttps"])) for idx, ttp in enumerate(camp["ttps"]): cols[idx].caption(f"🛡️ {ttp}") # ----------------------------------------------------------------------------- # TAB 3: FORENSICS LAB (Analyze) # ----------------------------------------------------------------------------- with tab_analyze: st.subheader("🔬 Message Forensics Lab") msg_input = st.text_area("Input Suspicious Message / SMS / WhatsApp:", height=100, placeholder="e.g. Dear customer, your KYC is pending...") if st.button("🚀 Analyze Threat", type="primary"): with st.spinner("Running Agentic Analysis..."): result = analyze_message(msg_input) if result: st.success("Analysis Complete") # Show key results c1, c2, c3 = st.columns(3) c1.metric("Risk Score", f"{result.get('risk_score', 0):.0%}", delta="High Risk", delta_color="inverse") c2.metric("Confidence", f"{result.get('confidence', 0):.0%}") c3.metric("Scam Type", result.get("scam_type", "Unknown")) # Agent Steps Visualization with st.expander("🧠 Agent Reasoning Steps (Explainability)", expanded=True): if result.get("agent_steps"): for step in result["agent_steps"]: st.write(f"✅ {step}") else: st.info("Agent steps not available in response.") # Telemetry if available if result.get("telemetry"): st.subheader("� Attacker Telemetry") st.json(result["telemetry"]) # ----------------------------------------------------------------------------- # SIDEBAR CONTROLS # ----------------------------------------------------------------------------- with st.sidebar: st.header("⚙️ Configuration") st.checkbox("Enable Threat Feed", value=True) st.checkbox("Auto-Report to Cyber Cell", value=True) st.checkbox("Active Honeypot Mode", value=True) st.divider() st.markdown("### System Status") st.markdown("🟢 **API Gateway:** Online") st.markdown("🟢 **Agents:** Active (6/6)") st.markdown("🟢 **NPCI Link:** Connected") st.divider() if st.button("🔄 Refresh Data"): st.rerun()