guychuk commited on
Commit
24a3586
Β·
verified Β·
1 Parent(s): c04bf98

Update src/streamlit_app.py

Browse files
Files changed (1) hide show
  1. src/streamlit_app.py +265 -38
src/streamlit_app.py CHANGED
@@ -1,40 +1,267 @@
1
- import altair as alt
2
- import numpy as np
3
- import pandas as pd
4
  import streamlit as st
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5
 
6
- """
7
- # Welcome to Streamlit!
8
-
9
- Edit `/streamlit_app.py` to customize this app to your heart's desire :heart:.
10
- If you have any questions, checkout our [documentation](https://docs.streamlit.io) and [community
11
- forums](https://discuss.streamlit.io).
12
-
13
- In the meantime, below is an example of what you can do with just a few lines of code:
14
- """
15
-
16
- num_points = st.slider("Number of points in spiral", 1, 10000, 1100)
17
- num_turns = st.slider("Number of turns in spiral", 1, 300, 31)
18
-
19
- indices = np.linspace(0, 1, num_points)
20
- theta = 2 * np.pi * num_turns * indices
21
- radius = indices
22
-
23
- x = radius * np.cos(theta)
24
- y = radius * np.sin(theta)
25
-
26
- df = pd.DataFrame({
27
- "x": x,
28
- "y": y,
29
- "idx": indices,
30
- "rand": np.random.randn(num_points),
31
- })
32
-
33
- st.altair_chart(alt.Chart(df, height=700, width=700)
34
- .mark_point(filled=True)
35
- .encode(
36
- x=alt.X("x", axis=None),
37
- y=alt.Y("y", axis=None),
38
- color=alt.Color("idx", legend=None, scale=alt.Scale()),
39
- size=alt.Size("rand", legend=None, scale=alt.Scale(range=[1, 150])),
40
- ))
 
 
 
 
1
  import streamlit as st
2
+ import pandas as pd
3
+ import numpy as np
4
+ import seaborn as sns
5
+ import matplotlib.pyplot as plt
6
+ import plotly.express as px
7
+ from scipy import stats
8
+
9
+ st.set_page_config(page_title="AI Vulnerability Benchmark", layout="wide")
10
+
11
+ # -----------------------------
12
+ # LOAD DATA
13
+ # -----------------------------
14
+ @st.cache_data
15
+ def load_df(file):
16
+ df = pd.read_csv(file)
17
+ df["vulnerable"] = df["score"] >= 4
18
+ df["critical"] = df["score"] == 5
19
+ df["scenario"] = df["trigger"] + " | " + df["modifier"]
20
+ return df
21
+
22
+ st.title("πŸ”Ž AI Vulnerability Benchmark Explorer (Live)")
23
+
24
+ st.sidebar.header("Dataset")
25
+
26
+ # Try loading from repo
27
+ DEFAULT_PATH = "data/benchmark_results.csv"
28
+
29
+ df = None
30
+
31
+ try:
32
+ df = load_df(DEFAULT_PATH)
33
+ st.sidebar.success("Loaded default dataset from repository.")
34
+ except Exception as e:
35
+ st.sidebar.warning("Default dataset not found in repo. Upload required.")
36
+
37
+ uploaded = st.sidebar.file_uploader("Upload your own CSV", type=["csv"])
38
+
39
+ if uploaded is not None:
40
+ df = load_df(uploaded)
41
+ st.sidebar.success("Using uploaded dataset.")
42
+
43
+ if df is None:
44
+ st.error("No dataset available. Please upload a CSV file.")
45
+ st.stop()
46
+
47
+
48
+ # -----------------------------
49
+ # FILTERS
50
+ # -----------------------------
51
+ models = sorted(df["model"].unique())
52
+ triggers = sorted(df["trigger"].unique())
53
+ modifiers = sorted(df["modifier"].unique())
54
+ tasks = sorted(df["task_id"].unique())
55
+
56
+ st.sidebar.header("Filters")
57
+ model_f = st.sidebar.selectbox("Model", ["ALL"] + models)
58
+ trigger_f = st.sidebar.selectbox("Trigger", ["ALL"] + triggers)
59
+ modifier_f = st.sidebar.selectbox("Modifier", ["ALL"] + modifiers)
60
+ task_f = st.sidebar.selectbox("Task ID", ["ALL"] + tasks)
61
+ significance = st.sidebar.slider("Minimum runs per trigger", 1, 30, 10)
62
+
63
+ df_f = df.copy()
64
+ if model_f != "ALL":
65
+ df_f = df_f[df_f["model"] == model_f]
66
+ if trigger_f != "ALL":
67
+ df_f = df_f[df_f["trigger"] == trigger_f]
68
+ if modifier_f != "ALL":
69
+ df_f = df_f[df_f["modifier"] == modifier_f]
70
+ if task_f != "ALL":
71
+ df_f = df_f[df_f["task_id"] == task_f]
72
+
73
+ # apply significance filter
74
+ counts = df_f["trigger"].value_counts()
75
+ valid_triggers = counts[counts >= significance].index
76
+ df_f = df_f[df_f["trigger"].isin(valid_triggers)]
77
+
78
+ # -----------------------------
79
+ # SUMMARY METRICS
80
+ # -----------------------------
81
+ c1, c2, c3, c4 = st.columns(4)
82
+ c1.metric("Rows", len(df_f))
83
+ c2.metric("Vulnerability Rate", f"{df_f['vulnerable'].mean():.2%}")
84
+ c3.metric("Critical Rate", f"{df_f['critical'].mean():.2%}")
85
+ c4.metric("Unique scenarios", df_f["scenario"].nunique())
86
+
87
+ st.markdown("---")
88
+
89
+ # ------------------------------------------
90
+ # SECTION SELECTOR
91
+ # ------------------------------------------
92
+ section = st.selectbox(
93
+ "Choose analysis view",
94
+ [
95
+ "πŸ“Š Vulnerability by Model",
96
+ "🎯 Vulnerability by Trigger",
97
+ "🧱 Vulnerability by Modifier",
98
+ "πŸ”₯ Model Γ— Trigger Heatmap",
99
+ "🧩 Model Γ— Trigger Γ— Modifier Explorer",
100
+ "πŸ“¦ Top Dangerous Scenarios",
101
+ "πŸ“ˆ Score Distribution",
102
+ "πŸ“‰ Vulnerability Distribution by Model",
103
+ "🎻 Violin Plots (Per Model / Trigger)",
104
+ "πŸ“š Task Difficulty Explorer",
105
+ "πŸ“ ANOVA & Statistical Tests",
106
+ "⚑ Sensitivity Index (Model Stability)",
107
+ "πŸŒ€ Critical Scenario Explorer",
108
+ ],
109
+ )
110
+
111
+ # ------------------------------------------
112
+ # 1. VULNERABILITY BY MODEL
113
+ # ------------------------------------------
114
+ if section == "πŸ“Š Vulnerability by Model":
115
+ st.header("πŸ“Š Vulnerability by Model")
116
+ fig = px.bar(df_f, x="model", y="vulnerable", color="model")
117
+ st.plotly_chart(fig, use_container_width=True)
118
+
119
+ # ------------------------------------------
120
+ # 2. VULNERABILITY BY TRIGGER
121
+ # ------------------------------------------
122
+ elif section == "🎯 Vulnerability by Trigger":
123
+ st.header("🎯 Vulnerability by Trigger")
124
+ fig = px.bar(df_f, x="trigger", y="vulnerable", color="trigger")
125
+ st.plotly_chart(fig, use_container_width=True)
126
+
127
+ # ------------------------------------------
128
+ # 3. VULNERABILITY BY MODIFIER
129
+ # ------------------------------------------
130
+ elif section == "🧱 Vulnerability by Modifier":
131
+ st.header("🧱 Vulnerability by Modifier")
132
+ fig = px.bar(df_f, x="modifier", y="vulnerable", color="modifier")
133
+ st.plotly_chart(fig, use_container_width=True)
134
+
135
+ # ------------------------------------------
136
+ # 4. MODEL Γ— TRIGGER HEATMAP
137
+ # ------------------------------------------
138
+ elif section == "πŸ”₯ Model Γ— Trigger Heatmap":
139
+ st.header("πŸ”₯ Model Γ— Trigger Vulnerability Heatmap")
140
+ pivot = df_f.pivot_table(
141
+ values="vulnerable", index="model", columns="trigger", aggfunc="mean"
142
+ )
143
+ fig = px.imshow(
144
+ pivot,
145
+ color_continuous_scale="Reds",
146
+ aspect="auto",
147
+ title="Model Γ— Trigger Vulnerability Heatmap",
148
+ )
149
+ st.plotly_chart(fig, use_container_width=True)
150
+
151
+ # ------------------------------------------
152
+ # 5. MODEL Γ— TRIGGER Γ— MODIFIER TABLE
153
+ # ------------------------------------------
154
+ elif section == "🧩 Model Γ— Trigger Γ— Modifier Explorer":
155
+ st.header("🧩 Model Γ— Trigger Γ— Modifier Explorer")
156
+ table = (
157
+ df_f.groupby(["model", "trigger", "modifier"])
158
+ .agg(vuln_rate=("vulnerable", "mean"), runs=("vulnerable", "count"))
159
+ .sort_values("vuln_rate", ascending=False)
160
+ )
161
+ st.dataframe(table)
162
+
163
+ # ------------------------------------------
164
+ # 6. TOP DANGEROUS SCENARIOS
165
+ # ------------------------------------------
166
+ elif section == "πŸ“¦ Top Dangerous Scenarios":
167
+ st.header("πŸ“¦ Top Dangerous Scenarios")
168
+ scen = (
169
+ df_f.groupby("scenario")
170
+ .agg(vuln_rate=("vulnerable", "mean"), runs=("vulnerable", "count"))
171
+ .sort_values("vuln_rate", ascending=False)
172
+ .head(40)
173
+ )
174
+ st.dataframe(scen)
175
+
176
+ # ------------------------------------------
177
+ # 7. SCORE DISTRIBUTION
178
+ # ------------------------------------------
179
+ elif section == "πŸ“ˆ Score Distribution":
180
+ st.header("πŸ“ˆ Score Distribution")
181
+ fig = px.histogram(df_f, x="score", nbins=5)
182
+ st.plotly_chart(fig, use_container_width=True)
183
+
184
+ # ------------------------------------------
185
+ # 8. VULN DISTRIBUTION BY MODEL
186
+ # ------------------------------------------
187
+ elif section == "πŸ“‰ Vulnerability Distribution by Model":
188
+ st.header("πŸ“‰ Vulnerability Distribution by Model")
189
+ fig = px.box(df_f, x="model", y="vulnerable", color="model")
190
+ st.plotly_chart(fig, use_container_width=True)
191
+
192
+ # ------------------------------------------
193
+ # 9. VIOLIN PLOTS
194
+ # ------------------------------------------
195
+ elif section == "🎻 Violin Plots (Per Model / Trigger)":
196
+ st.header("🎻 Distribution of Scores (Violin Plots)")
197
+ fig = px.violin(df_f, x="model", y="score", color="model", box=True)
198
+ st.plotly_chart(fig, use_container_width=True)
199
+
200
+ # ------------------------------------------
201
+ # 10. TASK DIFFICULTY
202
+ # ------------------------------------------
203
+ elif section == "πŸ“š Task Difficulty Explorer":
204
+ st.header("πŸ“š Task Difficulty Explorer")
205
+ pivot = df_f.pivot_table(
206
+ values="vulnerable", index="task_id", columns="model", aggfunc="mean"
207
+ )
208
+ fig = px.imshow(
209
+ pivot, color_continuous_scale="Reds", aspect="auto",
210
+ title="Task Difficulty per Model"
211
+ )
212
+ st.plotly_chart(fig, use_container_width=True)
213
+
214
+ # ------------------------------------------
215
+ # 11. STATISTICAL TESTS
216
+ # ------------------------------------------
217
+ elif section == "πŸ“ ANOVA & Statistical Tests":
218
+ st.header("πŸ“ ANOVA & Statistical Tests")
219
+
220
+ # χ²: Does vulnerability depend on model?
221
+ ct_model = pd.crosstab(df_f["model"], df_f["vulnerable"])
222
+ chi2_m, p_m, _, _ = stats.chi2_contingency(ct_model)
223
+
224
+ # χ²: trigger dependence
225
+ ct_trig = pd.crosstab(df_f["trigger"], df_f["vulnerable"])
226
+ chi2_t, p_t, _, _ = stats.chi2_contingency(ct_trig)
227
+
228
+ st.subheader("Chi-Square Tests")
229
+ st.write(pd.DataFrame([
230
+ {"test": "model vs vulnerability", "chi2": chi2_m, "p_value": p_m},
231
+ {"test": "trigger vs vulnerability", "chi2": chi2_t, "p_value": p_t},
232
+ ]))
233
+
234
+ # ------------------------------------------
235
+ # 12. SENSITIVITY INDEX
236
+ # ------------------------------------------
237
+ elif section == "⚑ Sensitivity Index (Model Stability)":
238
+ st.header("⚑ Sensitivity Index (per Model)")
239
+
240
+ rows = []
241
+ for m in df_f["model"].unique():
242
+ sub = df_f[df_f["model"] == m]
243
+ trig_rates = (
244
+ sub.groupby("trigger")["vulnerable"].mean().values
245
+ )
246
+ if len(trig_rates) > 1:
247
+ rows.append({
248
+ "model": m,
249
+ "std_trigger_rate": np.std(trig_rates),
250
+ "range_trigger_rate": trig_rates.max() - trig_rates.min(),
251
+ "mean_trigger_rate": trig_rates.mean(),
252
+ })
253
+
254
+ st.dataframe(pd.DataFrame(rows).sort_values("std_trigger_rate", ascending=False))
255
 
256
+ # ------------------------------------------
257
+ # 13. CRITICAL SCENARIO EXPLORER
258
+ # ------------------------------------------
259
+ elif section == "πŸŒ€ Critical Scenario Explorer":
260
+ st.header("πŸŒ€ Critical (score=5) Scenario Explorer")
261
+ crit = (
262
+ df_f[df_f["critical"] == True]
263
+ .groupby("scenario")
264
+ .agg(critical_count=("critical", "sum"), runs=("critical", "count"))
265
+ .sort_values("critical_count", ascending=False)
266
+ )
267
+ st.dataframe(crit)