dcata004 commited on
Commit
1fbcb49
Β·
verified Β·
1 Parent(s): 0d6eac3

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +321 -62
app.py CHANGED
@@ -1,68 +1,327 @@
 
 
 
 
 
1
  import streamlit as st
2
- import pandas as pd
3
- import numpy as np
4
- import plotly.graph_objects as go
5
- import time
6
-
7
- # --- CONFIGURATION ---
8
- st.set_page_config(page_title="Veritas SCADA Simulator", layout="wide")
9
-
10
- # --- SIDEBAR (Compliance) ---
11
- st.sidebar.image("https://img.icons8.com/color/96/000000/shield.png", width=50)
12
- st.sidebar.header("πŸ›‘οΈ Veritas Sentinel")
13
- st.sidebar.markdown("**System Status:** βœ… ONLINE")
14
- st.sidebar.markdown("---")
15
- st.sidebar.subheader("NIST AI RMF Controls")
16
- st.sidebar.checkbox("Map-1.3: Asset Inventory", value=True)
17
- st.sidebar.checkbox("Manage-2.4: Incident Response", value=True)
18
- st.sidebar.checkbox("Gov-3.1: Human Oversight", value=True)
19
-
20
- # --- MAIN DASHBOARD ---
21
- st.title("🌊 Water Treatment Plant #4 - SCADA Monitor")
22
- st.markdown("Real-time telemetry monitoring for **Cyber-Physical Anomalies**.")
23
-
24
- # --- SIMULATION LOGIC ---
25
- # Create placeholders for the live graph
26
- placeholder = st.empty()
27
- alert_box = st.empty()
28
-
29
- # Button to trigger "Attack"
30
- if st.button('⚠️ SIMULATE RANSOMWARE ATTACK'):
31
- attack_mode = True
32
- else:
33
- attack_mode = False
34
-
35
- # Generate Data
36
- seconds = 0
37
- data = []
38
-
39
- # --- LIVE LOOP (Simulated) ---
40
- # In a real app, this would run indefinitely. For the demo, we show a snapshot.
41
- for i in range(50):
42
- seconds += 1
43
 
44
- # Normal Pressure is 60-80 PSI. Attack spikes to 150 PSI.
45
- if attack_mode and i > 25:
46
- pressure = np.random.randint(140, 160)
47
- status_color = "red"
48
- alert_box.error("🚨 CRITICAL ALERT: PLC CONTROL FAILURE DETECTED. MANUAL OVERRIDE REQUIRED.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
49
  else:
50
- pressure = np.random.randint(60, 80)
51
- status_color = "#00ff00" # Neon Green
52
- if not attack_mode:
53
- alert_box.success("System Normal. AI Governance Active.")
54
 
55
- data.append(pressure)
56
-
57
- # Draw Graph
58
- fig = go.Figure()
59
- fig.add_trace(go.Scatter(y=data, mode='lines+markers', line=dict(color=status_color, width=3)))
60
- fig.update_layout(
61
- title="Main Pump Discharge Pressure (PSI)",
62
- yaxis_range=[0, 200],
63
- template="plotly_dark",
64
- height=400
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
65
  )
66
 
67
- placeholder.plotly_chart(fig, use_container_width=True)
68
- time.sleep(0.1)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Cata Risk Lab: Policy Auditor
3
+ A Streamlit tool for auditing AI Use Policies
4
+ """
5
+
6
  import streamlit as st
7
+ import re
8
+ from dataclasses import dataclass
9
+
10
+
11
+ @dataclass
12
+ class KeywordCheck:
13
+ keyword: str
14
+ found: bool
15
+ weight: int
16
+ category: str
17
+
18
+
19
+ def analyze_policy(text: str) -> dict:
20
+ """Analyze the AI Use Policy text and return findings."""
21
+
22
+ text_lower = text.lower()
23
+
24
+ # Define keywords to check with their weights and categories
25
+ keywords_config = [
26
+ ("liability", 15, "Legal Protection"),
27
+ ("human review", 15, "Oversight"),
28
+ ("data training", 10, "Data Governance"),
29
+ ("human-in-the-loop", 20, "Critical Safety"),
30
+ ("accountability", 10, "Legal Protection"),
31
+ ("transparency", 10, "Ethics"),
32
+ ("bias", 8, "Fairness"),
33
+ ("audit", 8, "Compliance"),
34
+ ("consent", 7, "Privacy"),
35
+ ("privacy", 7, "Privacy"),
36
+ ("security", 5, "Security"),
37
+ ("compliance", 5, "Compliance"),
38
+ ]
39
+
40
+ results = []
41
+ total_possible = sum(k[1] for k in keywords_config)
42
+ earned_points = 0
 
 
 
 
 
43
 
44
+ for keyword, weight, category in keywords_config:
45
+ # Check for keyword (allowing for variations)
46
+ pattern = re.compile(re.escape(keyword), re.IGNORECASE)
47
+ found = bool(pattern.search(text))
48
+
49
+ if found:
50
+ earned_points += weight
51
+
52
+ results.append(KeywordCheck(
53
+ keyword=keyword,
54
+ found=found,
55
+ weight=weight,
56
+ category=category
57
+ ))
58
+
59
+ # Calculate base score (normalized to 100)
60
+ base_score = (earned_points / total_possible) * 100
61
+
62
+ # Special penalty: Deduct additional points if 'Human-in-the-Loop' is missing
63
+ human_in_loop_check = next((r for r in results if r.keyword == "human-in-the-loop"), None)
64
+ penalty = 0
65
+ if human_in_loop_check and not human_in_loop_check.found:
66
+ penalty = 15 # Additional penalty beyond the missed weight
67
+
68
+ final_score = max(0, base_score - penalty)
69
+
70
+ return {
71
+ "results": results,
72
+ "base_score": base_score,
73
+ "penalty": penalty,
74
+ "final_score": round(final_score, 1),
75
+ "earned_points": earned_points,
76
+ "total_possible": total_possible
77
+ }
78
+
79
+
80
+ def get_score_color(score: float) -> str:
81
+ """Return color based on score."""
82
+ if score >= 80:
83
+ return "#28a745" # Green
84
+ elif score >= 60:
85
+ return "#ffc107" # Yellow
86
+ elif score >= 40:
87
+ return "#fd7e14" # Orange
88
  else:
89
+ return "#dc3545" # Red
 
 
 
90
 
91
+
92
+ def get_score_label(score: float) -> str:
93
+ """Return label based on score."""
94
+ if score >= 80:
95
+ return "Excellent"
96
+ elif score >= 60:
97
+ return "Good"
98
+ elif score >= 40:
99
+ return "Needs Improvement"
100
+ else:
101
+ return "High Risk"
102
+
103
+
104
+ def render_badge():
105
+ """Render the certification badge."""
106
+ badge_html = """
107
+ <div style="
108
+ display: flex;
109
+ justify-content: center;
110
+ margin: 20px 0;
111
+ ">
112
+ <div style="
113
+ background: linear-gradient(135deg, #1a5f2a 0%, #28a745 50%, #1a5f2a 100%);
114
+ border: 3px solid #ffd700;
115
+ border-radius: 15px;
116
+ padding: 20px 40px;
117
+ text-align: center;
118
+ box-shadow: 0 4px 15px rgba(0,0,0,0.3);
119
+ ">
120
+ <div style="font-size: 40px; margin-bottom: 5px;">πŸ›‘οΈ</div>
121
+ <div style="
122
+ color: #ffd700;
123
+ font-size: 14px;
124
+ font-weight: bold;
125
+ letter-spacing: 2px;
126
+ margin-bottom: 5px;
127
+ ">βœ“ CERTIFIED</div>
128
+ <div style="
129
+ color: white;
130
+ font-size: 18px;
131
+ font-weight: bold;
132
+ ">Cata Risk Lab</div>
133
+ <div style="
134
+ color: #90EE90;
135
+ font-size: 12px;
136
+ margin-top: 5px;
137
+ ">AI Policy Approved</div>
138
+ </div>
139
+ </div>
140
+ """
141
+ st.markdown(badge_html, unsafe_allow_html=True)
142
+
143
+
144
+ def main():
145
+ st.set_page_config(
146
+ page_title="Cata Risk Lab: Policy Auditor",
147
+ page_icon="πŸ”",
148
+ layout="wide"
149
  )
150
 
151
+ # Custom CSS
152
+ st.markdown("""
153
+ <style>
154
+ .main-header {
155
+ text-align: center;
156
+ padding: 20px;
157
+ background: linear-gradient(90deg, #1e3a5f, #2d5a87);
158
+ border-radius: 10px;
159
+ margin-bottom: 30px;
160
+ }
161
+ .main-header h1 {
162
+ color: white;
163
+ margin: 0;
164
+ }
165
+ .main-header p {
166
+ color: #a0c4e8;
167
+ margin: 5px 0 0 0;
168
+ }
169
+ .keyword-found {
170
+ background-color: #d4edda;
171
+ border-left: 4px solid #28a745;
172
+ padding: 10px;
173
+ margin: 5px 0;
174
+ border-radius: 0 5px 5px 0;
175
+ }
176
+ .keyword-missing {
177
+ background-color: #f8d7da;
178
+ border-left: 4px solid #dc3545;
179
+ padding: 10px;
180
+ margin: 5px 0;
181
+ border-radius: 0 5px 5px 0;
182
+ }
183
+ .score-card {
184
+ text-align: center;
185
+ padding: 30px;
186
+ border-radius: 15px;
187
+ margin: 20px 0;
188
+ }
189
+ </style>
190
+ """, unsafe_allow_html=True)
191
+
192
+ # Header
193
+ st.markdown("""
194
+ <div class="main-header">
195
+ <h1>πŸ” Cata Risk Lab: Policy Auditor</h1>
196
+ <p>Analyze your AI Use Policy for safety and compliance</p>
197
+ </div>
198
+ """, unsafe_allow_html=True)
199
+
200
+ # Main layout
201
+ col1, col2 = st.columns([1, 1])
202
+
203
+ with col1:
204
+ st.subheader("πŸ“„ Paste Your AI Use Policy")
205
+
206
+ policy_text = st.text_area(
207
+ "Enter your company's AI Use Policy below:",
208
+ height=400,
209
+ placeholder="""Paste your AI Use Policy here...
210
+
211
+ Example content might include:
212
+ - Data handling procedures
213
+ - Human oversight requirements
214
+ - Liability clauses
215
+ - Training data policies
216
+ - Compliance frameworks"""
217
+ )
218
+
219
+ analyze_button = st.button("πŸ” Analyze Policy", type="primary", use_container_width=True)
220
+
221
+ with col2:
222
+ st.subheader("πŸ“Š Analysis Results")
223
+
224
+ if analyze_button and policy_text.strip():
225
+ analysis = analyze_policy(policy_text)
226
+
227
+ # Score display
228
+ score = analysis["final_score"]
229
+ score_color = get_score_color(score)
230
+ score_label = get_score_label(score)
231
+
232
+ st.markdown(f"""
233
+ <div class="score-card" style="background: linear-gradient(135deg, {score_color}22, {score_color}44); border: 2px solid {score_color};">
234
+ <div style="font-size: 60px; font-weight: bold; color: {score_color};">{score}</div>
235
+ <div style="font-size: 20px; color: {score_color};">Safety Score / 100</div>
236
+ <div style="font-size: 16px; color: #666; margin-top: 10px;">{score_label}</div>
237
+ </div>
238
+ """, unsafe_allow_html=True)
239
+
240
+ # Certification badge
241
+ if score > 80:
242
+ render_badge()
243
+ else:
244
+ st.warning("⚠️ Score must be above 80 to receive certification.")
245
+
246
+ # Penalty notice
247
+ if analysis["penalty"] > 0:
248
+ st.error(f"🚨 **Penalty Applied:** -{analysis['penalty']} points for missing 'Human-in-the-Loop' provision")
249
+
250
+ # Detailed results
251
+ st.markdown("---")
252
+ st.subheader("πŸ”Ž Detailed Findings")
253
+
254
+ # Group by category
255
+ categories = {}
256
+ for result in analysis["results"]:
257
+ if result.category not in categories:
258
+ categories[result.category] = []
259
+ categories[result.category].append(result)
260
+
261
+ for category, items in categories.items():
262
+ with st.expander(f"πŸ“ {category}", expanded=True):
263
+ for item in items:
264
+ if item.found:
265
+ st.markdown(f"""
266
+ <div class="keyword-found">
267
+ βœ… <strong>{item.keyword.title()}</strong>
268
+ <span style="float: right; color: #28a745;">+{item.weight} pts</span>
269
+ </div>
270
+ """, unsafe_allow_html=True)
271
+ else:
272
+ st.markdown(f"""
273
+ <div class="keyword-missing">
274
+ ❌ <strong>{item.keyword.title()}</strong> - Not found
275
+ <span style="float: right; color: #dc3545;">0/{item.weight} pts</span>
276
+ </div>
277
+ """, unsafe_allow_html=True)
278
+
279
+ # Summary stats
280
+ st.markdown("---")
281
+ found_count = sum(1 for r in analysis["results"] if r.found)
282
+ total_count = len(analysis["results"])
283
+
284
+ col_a, col_b, col_c = st.columns(3)
285
+ with col_a:
286
+ st.metric("Keywords Found", f"{found_count}/{total_count}")
287
+ with col_b:
288
+ st.metric("Points Earned", f"{analysis['earned_points']}/{analysis['total_possible']}")
289
+ with col_c:
290
+ st.metric("Penalties", f"-{analysis['penalty']}" if analysis['penalty'] > 0 else "None")
291
+
292
+ elif analyze_button:
293
+ st.warning("Please paste your AI Use Policy text to analyze.")
294
+ else:
295
+ st.info("πŸ‘ˆ Paste your policy text and click 'Analyze Policy' to begin.")
296
+
297
+ # Show what we check for
298
+ st.markdown("---")
299
+ st.subheader("🎯 What We Check For")
300
+
301
+ checks = [
302
+ ("Liability", "Legal protection clauses"),
303
+ ("Human Review", "Manual oversight processes"),
304
+ ("Data Training", "Training data governance"),
305
+ ("Human-in-the-Loop", "Critical safety requirement"),
306
+ ("Accountability", "Responsibility frameworks"),
307
+ ("Transparency", "Disclosure practices"),
308
+ ("Bias", "Fairness considerations"),
309
+ ("Audit", "Review mechanisms"),
310
+ ("Consent", "User permission protocols"),
311
+ ("Privacy", "Data protection measures"),
312
+ ]
313
+
314
+ for keyword, description in checks:
315
+ st.markdown(f"β€’ **{keyword}**: {description}")
316
+
317
+ # Footer
318
+ st.markdown("---")
319
+ st.markdown("""
320
+ <div style="text-align: center; color: #666; padding: 20px;">
321
+ <p>πŸ”’ Cata Risk Lab Policy Auditor | Helping organizations build safer AI practices</p>
322
+ </div>
323
+ """, unsafe_allow_html=True)
324
+
325
+
326
+ if __name__ == "__main__":
327
+ main()