LovnishVerma commited on
Commit
db4a594
ยท
verified ยท
1 Parent(s): 1814306

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +225 -0
app.py ADDED
@@ -0,0 +1,225 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import pandas as pd
3
+ import plotly.express as px
4
+ import plotly.graph_objects as go
5
+ import numpy as np
6
+
7
+ # ==========================================
8
+ # 1. PAGE CONFIGURATION & THEME
9
+ # ==========================================
10
+ st.set_page_config(
11
+ page_title="Project Sentinel | UIDAI Dashboard",
12
+ page_icon="๐Ÿ›ก๏ธ",
13
+ layout="wide",
14
+ initial_sidebar_state="expanded"
15
+ )
16
+
17
+ # Custom CSS to mimic Government/Professional portals
18
+ st.markdown("""
19
+ <style>
20
+ .main {
21
+ background-color: #f8f9fa;
22
+ }
23
+ .stMetric {
24
+ background-color: #ffffff;
25
+ padding: 15px;
26
+ border-radius: 5px;
27
+ box-shadow: 0 2px 4px rgba(0,0,0,0.05);
28
+ }
29
+ h1, h2, h3 {
30
+ color: #2c3e50;
31
+ }
32
+ .high-risk {
33
+ color: #e74c3c;
34
+ font-weight: bold;
35
+ }
36
+ </style>
37
+ """, unsafe_allow_html=True)
38
+
39
+ # ==========================================
40
+ # 2. DATA LOADING
41
+ # ==========================================
42
+ @st.cache_data
43
+ def load_data():
44
+ # Load your exported CSV
45
+ try:
46
+ df = pd.read_csv('analyzed_aadhaar_data.csv')
47
+
48
+ # Ensure dates are datetime objects
49
+ if 'date' in df.columns:
50
+ df['date'] = pd.to_datetime(df['date'])
51
+
52
+ # --- HACKATHON TRICK FOR MAPS ---
53
+ # Real pincode-to-lat/lon APIs are slow. For the demo, we simulate
54
+ # coords centered on India to show the "Map Functionality" works.
55
+ # IN PRODUCTION: You would merge with a Pincode Master DB.
56
+ np.random.seed(42)
57
+ # Rough box for India: Lat 8-37, Lon 68-97.
58
+ # We generate random noise to spread points out for the visual.
59
+ df['lat'] = np.random.uniform(20.0, 28.0, size=len(df))
60
+ df['lon'] = np.random.uniform(77.0, 85.0, size=len(df))
61
+
62
+ return df
63
+ except FileNotFoundError:
64
+ st.error("โš ๏ธ File 'analyzed_aadhaar_data.csv' not found. Please run your Notebook first.")
65
+ return pd.DataFrame()
66
+
67
+ df = load_data()
68
+
69
+ if df.empty:
70
+ st.stop()
71
+
72
+ # ==========================================
73
+ # 3. SIDEBAR CONTROLS
74
+ # ==========================================
75
+ with st.sidebar:
76
+ st.image("https://upload.wikimedia.org/wikipedia/en/c/cf/Aadhaar_Logo.svg", width=150)
77
+ st.title("๐Ÿ›ก๏ธ Sentinel Control")
78
+ st.markdown("---")
79
+
80
+ # State Filter
81
+ state_list = ['All'] + sorted(df['state'].unique().tolist())
82
+ selected_state = st.selectbox("Select State", state_list)
83
+
84
+ # District Filter (Dynamic)
85
+ if selected_state != 'All':
86
+ district_list = ['All'] + sorted(df[df['state'] == selected_state]['district'].unique().tolist())
87
+ filtered_df = df[df['state'] == selected_state]
88
+ else:
89
+ district_list = ['All']
90
+ filtered_df = df
91
+
92
+ selected_district = st.selectbox("Select District", district_list)
93
+
94
+ if selected_district != 'All':
95
+ filtered_df = filtered_df[filtered_df['district'] == selected_district]
96
+
97
+ st.markdown("---")
98
+ st.markdown("**User:** Vigilance Officer (Level 1)\n\n**Session ID:** UIDAI_4571_SECURE")
99
+
100
+ # ==========================================
101
+ # 4. MAIN DASHBOARD
102
+ # ==========================================
103
+
104
+ # HEADER
105
+ col1, col2 = st.columns([3, 1])
106
+ with col1:
107
+ st.title("Project Sentinel: Fraud Detection Hub")
108
+ st.markdown("### Context-Aware Anomaly Detection System")
109
+ with col2:
110
+ st.markdown(f"**Data Date:** {pd.Timestamp.now().strftime('%d-%b-%Y')}")
111
+ st.markdown("**Status:** ๐ŸŸข System Online")
112
+
113
+ st.divider()
114
+
115
+ # KPI METRICS ROW
116
+ total_centers = len(filtered_df)
117
+ high_risk_centers = len(filtered_df[filtered_df['RISK_SCORE'] > 80])
118
+ avg_risk = filtered_df['RISK_SCORE'].mean()
119
+ weekend_anomalies = len(filtered_df[(filtered_df['is_weekend'] == 1) & (filtered_df['RISK_SCORE'] > 70)])
120
+
121
+ kpi1, kpi2, kpi3, kpi4 = st.columns(4)
122
+ kpi1.metric("Total Centers Monitored", f"{total_centers:,}", delta_color="off")
123
+ kpi2.metric("โš ๏ธ High Risk Alerts", f"{high_risk_centers}", f"+{int(high_risk_centers*0.15)} vs last week", delta_color="inverse")
124
+ kpi3.metric("Avg Risk Score", f"{avg_risk:.1f}/100", delta_color="inverse")
125
+ kpi4.metric("Weekend Spikes", f"{weekend_anomalies}", "Suspicious Activity Detected", delta_color="inverse")
126
+
127
+ # ==========================================
128
+ # 5. VISUALIZATION LAYER
129
+ # ==========================================
130
+
131
+ st.markdown("### ๐Ÿ—บ๏ธ Geographic Risk Heatmap")
132
+ st.info("Visualizing centers with high deviation from their local district baseline.")
133
+
134
+ # MAP (Simulated for Demo)
135
+ map_fig = px.scatter_mapbox(
136
+ filtered_df,
137
+ lat="lat",
138
+ lon="lon",
139
+ color="RISK_SCORE",
140
+ size="total_activity",
141
+ hover_name="pincode",
142
+ hover_data=["district", "enrol_adult", "ratio_deviation"],
143
+ color_continuous_scale=["green", "yellow", "red"],
144
+ zoom=4 if selected_state == 'All' else 6,
145
+ height=500,
146
+ mapbox_style="open-street-map" # Free style, no token needed
147
+ )
148
+ map_fig.update_layout(margin={"r":0,"t":0,"l":0,"b":0})
149
+ st.plotly_chart(map_fig, use_container_width=True)
150
+
151
+ # DRILL DOWN CHARTS
152
+ col_chart1, col_chart2 = st.columns(2)
153
+
154
+ with col_chart1:
155
+ st.subheader("๐Ÿ” The 'Ghost ID' Indicator")
156
+ st.markdown("*Deviation of Adult Enrolment Ratio vs District Avg*")
157
+
158
+ # Scatter plot showing outliers
159
+ scatter_fig = px.scatter(
160
+ filtered_df,
161
+ x="total_activity",
162
+ y="ratio_deviation",
163
+ color="RISK_SCORE",
164
+ size="RISK_SCORE",
165
+ hover_data=["pincode", "district"],
166
+ labels={"ratio_deviation": "Deviation from District Norm", "total_activity": "Daily Volume"},
167
+ color_continuous_scale="RdYlGn_r"
168
+ )
169
+ # Add a threshold line
170
+ scatter_fig.add_hline(y=0.2, line_dash="dot", annotation_text="Suspicious Threshold", annotation_position="bottom right")
171
+ st.plotly_chart(scatter_fig, use_container_width=True)
172
+
173
+ with col_chart2:
174
+ st.subheader("๐Ÿ“Š Top Risky Districts")
175
+ if selected_state == 'All':
176
+ group_col = 'state'
177
+ else:
178
+ group_col = 'district'
179
+
180
+ risk_by_loc = filtered_df.groupby(group_col)['RISK_SCORE'].mean().sort_values(ascending=False).head(10).reset_index()
181
+
182
+ bar_fig = px.bar(
183
+ risk_by_loc,
184
+ x=group_col,
185
+ y="RISK_SCORE",
186
+ color="RISK_SCORE",
187
+ color_continuous_scale="Reds",
188
+ title=f"Highest Average Risk by {group_col.title()}"
189
+ )
190
+ st.plotly_chart(bar_fig, use_container_width=True)
191
+
192
+ # ==========================================
193
+ # 6. ACTIONABLE REPORT
194
+ # ==========================================
195
+ st.divider()
196
+ st.subheader("๐Ÿ“‹ Priority Verification List (Action Items)")
197
+
198
+ # Filter for the table
199
+ high_risk_df = filtered_df[filtered_df['RISK_SCORE'] > 75].sort_values('RISK_SCORE', ascending=False)
200
+
201
+ # Styling the dataframe for display
202
+ st.dataframe(
203
+ high_risk_df[['date', 'state', 'district', 'pincode', 'total_activity', 'enrol_adult', 'RISK_SCORE']],
204
+ column_config={
205
+ "RISK_SCORE": st.column_config.ProgressColumn(
206
+ "Risk Score",
207
+ help="AI-calculated probability of anomaly",
208
+ format="%d",
209
+ min_value=0,
210
+ max_value=100,
211
+ ),
212
+ "total_activity": st.column_config.NumberColumn("Total Ops"),
213
+ },
214
+ use_container_width=True,
215
+ hide_index=True
216
+ )
217
+
218
+ # Download Button
219
+ csv = high_risk_df.to_csv(index=False).encode('utf-8')
220
+ st.download_button(
221
+ label="๐Ÿ“ฅ Download Priority List for Ground Squads",
222
+ data=csv,
223
+ file_name='uidai_priority_verification.csv',
224
+ mime='text/csv',
225
+ )