inesbedar commited on
Commit
1d697ef
·
verified ·
1 Parent(s): 6970b1c

Upload app.py

Browse files
Files changed (1) hide show
  1. app.py +795 -0
app.py ADDED
@@ -0,0 +1,795 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+
3
+ # ─────────────────────────────────────────────
4
+ # REGMAP — AI System ID Card
5
+ # ─────────────────────────────────────────────
6
+
7
+ st.set_page_config(
8
+ page_title="RegMap — AI System ID Card",
9
+ page_icon="◈",
10
+ layout="centered",
11
+ )
12
+
13
+ # ── Visual Identity ──
14
+ st.markdown("""
15
+ <style>
16
+ @import url('https://fonts.googleapis.com/css2?family=DM+Sans:ital,opsz,wght@0,9..40,100..1000;1,9..40,100..1000&display=swap');
17
+ @import url('https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;600;700&display=swap');
18
+
19
+ html, body, [class*="css"] { font-family: 'DM Sans', sans-serif; }
20
+ .stApp { background-color: #F7F8FA; }
21
+
22
+ /* ── Dark text override for HF Spaces dark mode ──
23
+ Excludes .rmh (RegMap Header) elements */
24
+ .stApp p:not(.rmh-el), .stApp span:not(.rmh-el), .stApp label,
25
+ .stApp h1, .stApp h2, .stApp h3, .stApp h4,
26
+ .stApp li, .stApp strong:not(.rmh-el), .stApp em,
27
+ [data-testid="stMarkdownContainer"] p:not(.rmh-el),
28
+ [data-testid="stMarkdownContainer"] h4,
29
+ [data-testid="stMarkdownContainer"] strong:not(.rmh-el),
30
+ [data-testid="stMarkdownContainer"] li {
31
+ color: #1E293B !important;
32
+ }
33
+
34
+ /* ── Header ── */
35
+ .rmh {
36
+ background: linear-gradient(135deg, #0F2B46 0%, #143A5C 60%, #0F2B46 100%);
37
+ padding: 2rem 2.2rem 1.6rem 2.2rem;
38
+ border-radius: 14px;
39
+ margin-bottom: 1.8rem;
40
+ position: relative;
41
+ overflow: hidden;
42
+ border: 1px solid rgba(255,255,255,0.04);
43
+ }
44
+ .rmh::before {
45
+ content: '';
46
+ position: absolute;
47
+ top: -50%; right: -20%;
48
+ width: 60%; height: 200%;
49
+ background: radial-gradient(ellipse, rgba(13,148,136,0.15) 0%, transparent 70%);
50
+ pointer-events: none;
51
+ }
52
+ .rmh::after {
53
+ content: '';
54
+ position: absolute;
55
+ bottom: 0; left: 0;
56
+ width: 100%; height: 1px;
57
+ background: linear-gradient(90deg, transparent, rgba(45,212,191,0.3), transparent);
58
+ }
59
+ .rmh-logo {
60
+ font-family: 'Space Grotesk', sans-serif !important;
61
+ font-size: 1.7rem !important; font-weight: 700 !important;
62
+ letter-spacing: -0.02em !important;
63
+ color: #FFFFFF !important;
64
+ margin: 0 !important; position: relative; z-index: 1;
65
+ line-height: 1.2 !important;
66
+ }
67
+ .rmh-accent { color: #2DD4BF !important; }
68
+ .rmh-tagline {
69
+ font-family: 'DM Sans', sans-serif !important;
70
+ color: #8BA3BB !important;
71
+ font-size: 0.82rem !important;
72
+ font-weight: 400 !important;
73
+ letter-spacing: 0.03em !important;
74
+ margin: 0.35rem 0 0 0 !important;
75
+ position: relative; z-index: 1;
76
+ }
77
+ .rmh-badges {
78
+ display: flex; gap: 0.45rem;
79
+ margin-top: 0.9rem;
80
+ position: relative; z-index: 1;
81
+ }
82
+ .rmh-badge {
83
+ background: rgba(45,212,191,0.08) !important;
84
+ border: 1px solid rgba(45,212,191,0.2) !important;
85
+ border-radius: 5px !important;
86
+ padding: 0.18rem 0.55rem !important;
87
+ font-family: 'Space Grotesk', sans-serif !important;
88
+ font-size: 0.68rem !important;
89
+ font-weight: 600 !important;
90
+ color: #5EEAD4 !important;
91
+ letter-spacing: 0.06em !important;
92
+ text-transform: uppercase !important;
93
+ }
94
+
95
+ /* ── Progress ── */
96
+ .progress-container {
97
+ background: #E2E8F0; border-radius: 8px;
98
+ height: 5px; margin-bottom: 0.4rem;
99
+ }
100
+ .progress-fill {
101
+ background: linear-gradient(90deg, #0D9488, #2DD4BF);
102
+ height: 5px; border-radius: 8px;
103
+ transition: width 0.4s ease;
104
+ }
105
+ .progress-label {
106
+ color: #64748B !important; font-size: 0.78rem;
107
+ font-weight: 500; margin-bottom: 1.5rem;
108
+ }
109
+
110
+ /* ── Screen title ── */
111
+ .screen-title {
112
+ font-family: 'Space Grotesk', sans-serif;
113
+ color: #0F2B46 !important; font-size: 1.15rem;
114
+ font-weight: 700; letter-spacing: -0.01em;
115
+ margin-bottom: 0.2rem;
116
+ }
117
+ .screen-subtitle {
118
+ color: #64748B !important; font-size: 0.82rem;
119
+ font-weight: 400; margin-bottom: 1.5rem;
120
+ line-height: 1.4;
121
+ }
122
+
123
+ /* ── Buttons ── */
124
+ .stButton > button {
125
+ font-family: 'DM Sans', sans-serif;
126
+ font-weight: 600; font-size: 0.85rem;
127
+ border-radius: 8px; padding: 0.45rem 1.5rem;
128
+ color: #FFFFFF !important;
129
+ }
130
+
131
+ /* ── Summary cards ── */
132
+ .summary-section {
133
+ background: #F8FAFB;
134
+ border: 1px solid #E2E8F0;
135
+ border-left: 3px solid #0D9488;
136
+ border-radius: 8px;
137
+ padding: 1rem 1.3rem;
138
+ margin-bottom: 0.8rem;
139
+ }
140
+ .summary-section h4 {
141
+ color: #0F2B46 !important;
142
+ font-family: 'Space Grotesk', sans-serif;
143
+ font-size: 0.88rem; font-weight: 700;
144
+ margin: 0 0 0.5rem 0;
145
+ }
146
+ .summary-section p {
147
+ color: #334155 !important; font-size: 0.85rem;
148
+ margin: 0.15rem 0; line-height: 1.5;
149
+ }
150
+
151
+ /* ── Widget spacing ── */
152
+ .stSelectbox, .stMultiSelect, .stTextInput, .stTextArea { margin-bottom: 0.6rem; }
153
+
154
+ /* ── Widget labels (belt-and-suspenders) ── */
155
+ .stSelectbox label, .stMultiSelect label, .stTextInput label, .stTextArea label,
156
+ .stRadio label, .stCheckbox label, .stSlider label {
157
+ color: #1E293B !important;
158
+ }
159
+ .stSelectbox label p, .stMultiSelect label p, .stTextInput label p, .stTextArea label p,
160
+ .stRadio label p, .stCheckbox label p, .stSlider label p {
161
+ color: #1E293B !important;
162
+ }
163
+ .stRadio div[role="radiogroup"] label p,
164
+ .stRadio div[role="radiogroup"] label span,
165
+ .stRadio div[role="radiogroup"] label,
166
+ [data-testid="stRadio"] label p,
167
+ [data-testid="stRadio"] label span,
168
+ [data-testid="stRadio"] label,
169
+ [data-testid="stWidgetLabel"] p,
170
+ [data-testid="stWidgetLabel"] span {
171
+ color: #1E293B !important;
172
+ }
173
+ .stMarkdown h4, .stMarkdown p:not(.rmh-el), .stMarkdown strong:not(.rmh-el), .stMarkdown em,
174
+ .stMarkdown li, .stMarkdown span:not(.rmh-el),
175
+ [data-testid="stMarkdownContainer"] span:not(.rmh-el) {
176
+ color: #1E293B !important;
177
+ }
178
+ .stAlert p, .stAlert span,
179
+ [data-testid="stAlert"] p,
180
+ [data-testid="stAlert"] span {
181
+ color: #1E293B !important;
182
+ }
183
+ [data-testid="stCaptionContainer"] p,
184
+ [data-testid="stCaptionContainer"] span {
185
+ color: #64748B !important;
186
+ }
187
+
188
+ /* ── Beta disclaimer ── */
189
+ .beta-disclaimer {
190
+ background: #FEF3C7;
191
+ border: 1px solid #F59E0B;
192
+ border-radius: 8px;
193
+ padding: 0.8rem 1rem;
194
+ margin-bottom: 1rem;
195
+ color: #92400E !important;
196
+ font-size: 0.82rem;
197
+ line-height: 1.5;
198
+ }
199
+ .beta-disclaimer strong { color: #92400E !important; }
200
+
201
+ /* ── Hide branding ── */
202
+ #MainMenu {visibility: hidden;}
203
+ footer {visibility: hidden;}
204
+ header {visibility: hidden;}
205
+ </style>
206
+ """, unsafe_allow_html=True)
207
+
208
+
209
+ # ── Reference Data ──
210
+
211
+ INDUSTRY_SECTORS = [
212
+ "Agriculture & Food", "Automotive & Transportation",
213
+ "Banking & Financial Services", "Construction & Real Estate",
214
+ "Consulting & Professional Services", "Defence & Security",
215
+ "Education & Training", "Energy & Utilities",
216
+ "Entertainment & Media", "Environmental Services",
217
+ "Government & Public Administration", "Healthcare & Life Sciences",
218
+ "Hospitality & Tourism", "Human Resources & Recruitment",
219
+ "Insurance", "Legal Services", "Logistics & Supply Chain",
220
+ "Manufacturing", "Mining & Natural Resources", "Non-Profit & NGO",
221
+ "Pharmaceuticals", "Retail & E-commerce", "Telecommunications",
222
+ "Technology & Software", "Other",
223
+ ]
224
+
225
+ US_STATES = [
226
+ "Alabama", "Alaska", "Arizona", "Arkansas", "California", "Colorado",
227
+ "Connecticut", "Delaware", "Florida", "Georgia", "Hawaii", "Idaho",
228
+ "Illinois", "Indiana", "Iowa", "Kansas", "Kentucky", "Louisiana",
229
+ "Maine", "Maryland", "Massachusetts", "Michigan", "Minnesota",
230
+ "Mississippi", "Missouri", "Montana", "Nebraska", "Nevada",
231
+ "New Hampshire", "New Jersey", "New Mexico", "New York",
232
+ "North Carolina", "North Dakota", "Ohio", "Oklahoma", "Oregon",
233
+ "Pennsylvania", "Rhode Island", "South Carolina", "South Dakota",
234
+ "Tennessee", "Texas", "Utah", "Vermont", "Virginia", "Washington",
235
+ "West Virginia", "Wisconsin", "Wyoming", "District of Columbia",
236
+ ]
237
+
238
+ # States with specific AI regulation (for downstream analysis)
239
+ US_STATES_WITH_AI_REGULATION = [
240
+ "California", "Colorado", "Connecticut", "Illinois", "Texas", "Utah",
241
+ ]
242
+
243
+ EU_COUNTRIES = [
244
+ "Austria", "Belgium", "Bulgaria", "Croatia", "Cyprus", "Czechia",
245
+ "Denmark", "Estonia", "Finland", "France", "Germany", "Greece",
246
+ "Hungary", "Ireland", "Italy", "Latvia", "Lithuania", "Luxembourg",
247
+ "Malta", "Netherlands", "Poland", "Portugal", "Romania", "Slovakia",
248
+ "Slovenia", "Spain", "Sweden",
249
+ "Iceland (EEA)", "Liechtenstein (EEA)", "Norway (EEA)",
250
+ ]
251
+
252
+ UAE_EMIRATES = [
253
+ "Dubai", "Abu Dhabi", "Sharjah", "Ajman",
254
+ "Fujairah", "Ras Al Khaimah", "Umm Al Quwain",
255
+ ]
256
+
257
+ UAE_FREE_ZONES = {
258
+ "Dubai": ["DIFC", "DMCC", "JAFZA", "Dubai Internet City",
259
+ "Dubai Media City", "Dubai Silicon Oasis", "Dubai Healthcare City",
260
+ "Dubai Design District (d3)", "Dubai South", "Dubai Knowledge Park",
261
+ "DAFZA", "Dubai World Trade Centre", "Dubai Science Park",
262
+ "Dubai Textile City", "DUCAMZ", "Dubai Maritime City",
263
+ "Meydan Free Zone", "IFZA"],
264
+ "Abu Dhabi": ["ADGM", "KIZAD", "Masdar City", "ADAFZ",
265
+ "Khalifa Port Free Trade Zone", "Twofour54"],
266
+ "Sharjah": ["Sharjah Media City (Shams)", "SAIF Zone",
267
+ "Sharjah Publishing City", "Hamriyah Free Zone"],
268
+ "Ras Al Khaimah": ["RAKEZ", "RAK Maritime City", "RAK Media City"],
269
+ "Ajman": ["Ajman Free Zone"],
270
+ "Fujairah": ["Fujairah Free Zone", "Fujairah Creative City"],
271
+ "Umm Al Quwain": ["UAQ Free Trade Zone"],
272
+ }
273
+
274
+ ROLES = [
275
+ "Provider — You develop or commission the AI system",
276
+ "Deployer — You use an AI system in your operations (you did not build it)",
277
+ "Authorised Representative (EU) — You act on behalf of a non-EU provider to fulfill EU AI Act obligations",
278
+ "Importer (EU) — You place on the EU market an AI system from a non-EU provider",
279
+ "Distributor (EU) — You make an AI system available on the EU market (neither provider nor importer)",
280
+ ]
281
+
282
+ AI_TYPES = ["Machine Learning (ML)", "Generative AI (GenAI)", "Agentic AI", "Rule-based", "Hybrid"]
283
+
284
+ DATA_TYPE_OPTIONS = [
285
+ "Personal data (name, email, ID)",
286
+ "Sensitive/special category data (health, race, religion, political, sexual orientation)",
287
+ "Biometric data",
288
+ "Children's data (<18)",
289
+ "Financial/credit data",
290
+ "Employment/HR data",
291
+ "Copyrighted content (text, images, audio, video)",
292
+ "Publicly available data only",
293
+ "No personal data",
294
+ ]
295
+
296
+ TRAINING_SOURCES = ["Public web", "Licensed datasets", "Proprietary data", "User-generated content"]
297
+ INVOLVEMENT_LEVELS = ["Fully automated", "Human-assisted", "Human decides"]
298
+
299
+ ALL_COUNTRIES = [
300
+ "Afghanistan", "Albania", "Algeria", "Andorra", "Angola", "Argentina",
301
+ "Armenia", "Australia", "Austria", "Azerbaijan", "Bahrain", "Bangladesh",
302
+ "Belarus", "Belgium", "Bolivia", "Bosnia and Herzegovina", "Brazil",
303
+ "Brunei", "Bulgaria", "Cambodia", "Cameroon", "Canada", "Chile", "China",
304
+ "Colombia", "Costa Rica", "Croatia", "Cuba", "Cyprus", "Czechia",
305
+ "Denmark", "Dominican Republic", "Ecuador", "Egypt", "El Salvador",
306
+ "Estonia", "Ethiopia", "Finland", "France", "Georgia", "Germany",
307
+ "Ghana", "Greece", "Guatemala", "Honduras", "Hong Kong", "Hungary",
308
+ "Iceland", "India", "Indonesia", "Iran", "Iraq", "Ireland", "Israel",
309
+ "Italy", "Jamaica", "Japan", "Jordan", "Kazakhstan", "Kenya", "Kuwait",
310
+ "Latvia", "Lebanon", "Libya", "Liechtenstein", "Lithuania", "Luxembourg",
311
+ "Malaysia", "Malta", "Mexico", "Moldova", "Monaco", "Mongolia",
312
+ "Montenegro", "Morocco", "Mozambique", "Myanmar", "Nepal",
313
+ "Netherlands", "New Zealand", "Nicaragua", "Nigeria", "North Korea",
314
+ "North Macedonia", "Norway", "Oman", "Pakistan", "Panama",
315
+ "Paraguay", "Peru", "Philippines", "Poland", "Portugal", "Qatar",
316
+ "Romania", "Russia", "Rwanda", "Saudi Arabia", "Senegal", "Serbia",
317
+ "Singapore", "Slovakia", "Slovenia", "Somalia", "South Africa",
318
+ "South Korea", "Spain", "Sri Lanka", "Sudan", "Sweden", "Switzerland",
319
+ "Syria", "Taiwan", "Tanzania", "Thailand", "Tunisia", "Turkey",
320
+ "Uganda", "Ukraine", "United Arab Emirates", "United Kingdom",
321
+ "United States", "Uruguay", "Uzbekistan", "Venezuela", "Vietnam",
322
+ "Yemen", "Zambia", "Zimbabwe",
323
+ ]
324
+
325
+
326
+ # ── Session State ──
327
+
328
+ TOTAL_SCREENS = 7
329
+
330
+ if "screen" not in st.session_state:
331
+ st.session_state.screen = 1
332
+ if "data" not in st.session_state:
333
+ st.session_state.data = {}
334
+
335
+
336
+ def go_next():
337
+ if st.session_state.screen < TOTAL_SCREENS + 1:
338
+ st.session_state.screen += 1
339
+
340
+ def go_back():
341
+ if st.session_state.screen > 1:
342
+ st.session_state.screen -= 1
343
+
344
+ def go_to(n):
345
+ st.session_state.screen = n
346
+
347
+
348
+ # ── Header ──
349
+ st.markdown("""
350
+ <div class="rmh">
351
+ <p class="rmh-logo rmh-el">Reg<span class="rmh-accent rmh-el">Map</span></p>
352
+ <p class="rmh-tagline rmh-el">Navigate AI regulation across jurisdictions</p>
353
+ <div class="rmh-badges">
354
+ <span class="rmh-badge rmh-el">EU</span>
355
+ <span class="rmh-badge rmh-el">US</span>
356
+ <span class="rmh-badge rmh-el">UAE</span>
357
+ </div>
358
+ </div>
359
+ """, unsafe_allow_html=True)
360
+
361
+ # ── Progress ──
362
+ current = st.session_state.screen
363
+ progress_pct = min((current - 1) / TOTAL_SCREENS * 100, 100)
364
+ screen_labels = {
365
+ 1: "Screen 1/7 — AI System Identity",
366
+ 2: "Screen 2/7 — Application Domain",
367
+ 3: "Screen 3/7 — Company Location",
368
+ 4: "Screen 4/7 — Geographic Scope",
369
+ 5: "Screen 5/7 — Role in Value Chain",
370
+ 6: "Screen 6/7 — Technology Profile",
371
+ 7: "Screen 7/7 — Data Profile",
372
+ 8: "Summary",
373
+ }
374
+ label = screen_labels.get(current, "")
375
+
376
+ st.markdown(f"""
377
+ <div class="progress-container"><div class="progress-fill" style="width:{progress_pct}%"></div></div>
378
+ <div class="progress-label">{label}</div>
379
+ """, unsafe_allow_html=True)
380
+
381
+
382
+ # ═══════════════════════════════════════════════
383
+ # SCREEN 1: AI System Identity
384
+ # ═══════════════════════════════════════════════
385
+
386
+ if current == 1:
387
+ st.markdown('<p class="screen-title">AI System ID Card</p>', unsafe_allow_html=True)
388
+ st.markdown('<p class="screen-subtitle">Basic information about your AI system</p>', unsafe_allow_html=True)
389
+
390
+ st.markdown('<div class="beta-disclaimer"><strong>Beta version</strong> — This Space is public by default. We recommend not entering directly identifying data, especially in free text fields.</div>', unsafe_allow_html=True)
391
+
392
+ name = st.text_input(
393
+ "1.1 — AI system name",
394
+ value=st.session_state.data.get("name", ""),
395
+ placeholder="e.g. ResumeScreener, ChatAssist, FraudDetect",
396
+ )
397
+ description = st.text_area(
398
+ "1.2 — Brief description",
399
+ value=st.session_state.data.get("description", ""),
400
+ placeholder="Describe what your AI system does in 1-2 sentences",
401
+ height=100,
402
+ )
403
+
404
+ col1, col2 = st.columns([5, 1])
405
+ with col2:
406
+ if st.button("Next →", use_container_width=True, disabled=(not name.strip())):
407
+ st.session_state.data["name"] = name.strip()
408
+ st.session_state.data["description"] = description.strip()
409
+ go_next()
410
+ st.rerun()
411
+
412
+
413
+ # ═══════════════════════════════════════════════
414
+ # SCREEN 2: Application Domain
415
+ # ═══════════════════════════════════════════════
416
+
417
+ elif current == 2:
418
+ st.markdown('<p class="screen-title">Application Domain</p>', unsafe_allow_html=True)
419
+ st.markdown('<p class="screen-subtitle">Select all that apply</p>', unsafe_allow_html=True)
420
+
421
+ prev_sector = st.session_state.data.get("sector", [])
422
+ sector = st.multiselect(
423
+ "2.1 — Primary industry sector(s)",
424
+ INDUSTRY_SECTORS,
425
+ default=[s for s in prev_sector if s in INDUSTRY_SECTORS],
426
+ )
427
+
428
+ col1, col2, col3 = st.columns([1, 3, 1])
429
+ with col1:
430
+ if st.button("← Back", use_container_width=True):
431
+ go_back()
432
+ st.rerun()
433
+ with col3:
434
+ if st.button("Next →", use_container_width=True, disabled=(not sector)):
435
+ st.session_state.data["sector"] = sector
436
+ go_next()
437
+ st.rerun()
438
+
439
+
440
+ # ═══════════════════════════════════════════════
441
+ # SCREEN 3: Company Location
442
+ # ═══════════════════════════════════════════════
443
+
444
+ elif current == 3:
445
+ st.markdown('<p class="screen-title">Company Location</p>', unsafe_allow_html=True)
446
+ st.markdown('<p class="screen-subtitle">Where is your organization headquartered?</p>', unsafe_allow_html=True)
447
+
448
+ prev_base = st.session_state.data.get("company_base", None)
449
+ base_idx = ALL_COUNTRIES.index(prev_base) if prev_base in ALL_COUNTRIES else 0
450
+ company_base = st.selectbox(
451
+ "3.1 — Country where your company is legally established",
452
+ ALL_COUNTRIES,
453
+ index=base_idx,
454
+ key="q_company_base",
455
+ )
456
+
457
+ col1, col2, col3 = st.columns([1, 3, 1])
458
+ with col1:
459
+ if st.button("← Back", use_container_width=True):
460
+ go_back()
461
+ st.rerun()
462
+ with col3:
463
+ if st.button("Next →", use_container_width=True):
464
+ st.session_state.data["company_base"] = company_base
465
+ go_next()
466
+ st.rerun()
467
+
468
+
469
+ # ═══════════════════════════════════════════════
470
+ # SCREEN 4: Geographic Scope
471
+ # ═══════════════════════════════════════════════
472
+
473
+ elif current == 4:
474
+ st.markdown('<p class="screen-title">Geographic Scope</p>', unsafe_allow_html=True)
475
+ st.markdown('<p class="screen-subtitle">Select all that apply for each category</p>', unsafe_allow_html=True)
476
+
477
+ # 4.1 — Where the AI system operates
478
+ prev_ops = st.session_state.data.get("countries_operating", [])
479
+ countries_operating = st.multiselect(
480
+ "4.1 — Countries where the AI system operates",
481
+ ALL_COUNTRIES,
482
+ default=[c for c in prev_ops if c in ALL_COUNTRIES],
483
+ key="q_countries_operating",
484
+ )
485
+
486
+ # 4.2 — Where the AI system is distributed / made available
487
+ prev_dist = st.session_state.data.get("countries_distributed", [])
488
+ countries_distributed = st.multiselect(
489
+ "4.2 — Countries where the AI system is distributed or made available",
490
+ ALL_COUNTRIES,
491
+ default=[c for c in prev_dist if c in ALL_COUNTRIES],
492
+ key="q_countries_distributed",
493
+ )
494
+
495
+ # 4.3 — Where end users are located
496
+ prev_users = st.session_state.data.get("countries_end_users", [])
497
+ countries_end_users = st.multiselect(
498
+ "4.3 — Countries where end users are located",
499
+ ALL_COUNTRIES,
500
+ default=[c for c in prev_users if c in ALL_COUNTRIES],
501
+ key="q_countries_end_users",
502
+ )
503
+
504
+ # Combine all countries for detection
505
+ all_selected = list(set(countries_operating + countries_distributed + countries_end_users))
506
+
507
+ EU_COUNTRY_NAMES_CLEAN = [c.replace(" (EEA)", "") for c in EU_COUNTRIES]
508
+ selected_eu = [c for c in all_selected if c in EU_COUNTRY_NAMES_CLEAN or c in ["Iceland", "Liechtenstein", "Norway"]]
509
+ has_us = "United States" in all_selected
510
+ has_uae = "United Arab Emirates" in all_selected
511
+
512
+ # 4.4 — US states (if US in any dimension)
513
+ us_states = []
514
+ if has_us:
515
+ prev_states = st.session_state.data.get("us_states", [])
516
+ us_states = st.multiselect(
517
+ "4.4 — United States: which states?",
518
+ US_STATES,
519
+ default=[s for s in prev_states if s in US_STATES],
520
+ key="q_us_states",
521
+ )
522
+
523
+ # 4.5 — UAE emirates (if UAE in any dimension)
524
+ uae_emirates = []
525
+ if has_uae:
526
+ prev_emirates = st.session_state.data.get("uae_emirates", [])
527
+ uae_emirates = st.multiselect(
528
+ "4.5 — UAE: which emirates?",
529
+ UAE_EMIRATES,
530
+ default=[e for e in prev_emirates if e in UAE_EMIRATES],
531
+ key="q_uae_emirates",
532
+ )
533
+
534
+ # Validation — at least one country across any dimension
535
+ has_any_country = len(all_selected) > 0
536
+ can_proceed = has_any_country
537
+ if has_us and not us_states:
538
+ can_proceed = False
539
+ if has_uae and not uae_emirates:
540
+ can_proceed = False
541
+
542
+ col1, col2, col3 = st.columns([1, 3, 1])
543
+ with col1:
544
+ if st.button("← Back", use_container_width=True):
545
+ go_back()
546
+ st.rerun()
547
+ with col3:
548
+ if st.button("Next →", use_container_width=True, disabled=(not can_proceed)):
549
+ st.session_state.data["countries_operating"] = countries_operating
550
+ st.session_state.data["countries_distributed"] = countries_distributed
551
+ st.session_state.data["countries_end_users"] = countries_end_users
552
+ st.session_state.data["operating_countries"] = all_selected
553
+ st.session_state.data["us_states"] = us_states if has_us else []
554
+ st.session_state.data["us_states_with_regulation"] = [s for s in us_states if s in US_STATES_WITH_AI_REGULATION] if has_us else []
555
+ st.session_state.data["eu_countries"] = selected_eu
556
+ st.session_state.data["uae_emirates"] = uae_emirates if has_uae else []
557
+ regions = []
558
+ if has_us:
559
+ regions.append("United States")
560
+ if selected_eu:
561
+ regions.append("Europe")
562
+ if has_uae:
563
+ regions.append("UAE")
564
+ st.session_state.data["regions"] = regions
565
+ go_next()
566
+ st.rerun()
567
+
568
+
569
+ # ═══════════════════════════════════════════════
570
+ # SCREEN 5: Role in Value Chain
571
+ # ═══════════════════════════════════════════════
572
+
573
+ elif current == 5:
574
+ st.markdown('<p class="screen-title">Role in Value Chain</p>', unsafe_allow_html=True)
575
+ st.markdown('<p class="screen-subtitle">What is your current role?</p>', unsafe_allow_html=True)
576
+
577
+ prev_roles = st.session_state.data.get("roles", [])
578
+ roles = st.multiselect(
579
+ "5.1 — Your organization's role (select all that apply)",
580
+ ROLES,
581
+ default=[r for r in prev_roles if r in ROLES],
582
+ key="q_roles",
583
+ )
584
+
585
+ col1, col2, col3 = st.columns([1, 3, 1])
586
+ with col1:
587
+ if st.button("← Back", use_container_width=True):
588
+ go_back()
589
+ st.rerun()
590
+ with col3:
591
+ if st.button("Next →", use_container_width=True, disabled=(not roles)):
592
+ st.session_state.data["roles"] = roles
593
+ go_next()
594
+ st.rerun()
595
+
596
+
597
+ # ═══════════════════════════════════════════════
598
+ # SCREEN 6: Technology Profile
599
+ # ═══════════════════════════════════════════════
600
+
601
+ elif current == 6:
602
+ st.markdown('<p class="screen-title">Technology Profile</p>', unsafe_allow_html=True)
603
+ st.markdown('<p class="screen-subtitle">Describe your AI system\'s capabilities</p>', unsafe_allow_html=True)
604
+
605
+ # 6.1 AI type
606
+ prev_type = st.session_state.data.get("ai_type", AI_TYPES[0])
607
+ type_idx = AI_TYPES.index(prev_type) if prev_type in AI_TYPES else 0
608
+ ai_type = st.selectbox("6.1 — AI system type", AI_TYPES, index=type_idx, key="q_ai_type")
609
+
610
+ # 6.2 Model type
611
+ MODEL_TYPES = [
612
+ "Foundation model — general-purpose, trained on broad data (e.g. GPT, Claude, Llama)",
613
+ "Fine-tuned model — adapted from a foundation model for specific tasks",
614
+ "Task-specific model — built and trained for a single purpose",
615
+ ]
616
+ prev_model = st.session_state.data.get("model_type", MODEL_TYPES[2])
617
+ model_idx = MODEL_TYPES.index(prev_model) if prev_model in MODEL_TYPES else 2
618
+ model_type = st.selectbox("6.2 — How would you describe your AI model?", MODEL_TYPES, index=model_idx, key="q_model_type")
619
+
620
+ # 6.3 Capabilities
621
+ CAPABILITY_OPTIONS = [
622
+ "Interacts directly with end users",
623
+ "Makes or supports decisions that affect individuals",
624
+ "Profiles individuals (builds user profiles based on behavior, preferences, or characteristics)",
625
+ "Generates synthetic content (text, images, audio, video, code)",
626
+ "Performs emotion recognition",
627
+ ]
628
+ prev_caps = st.session_state.data.get("capabilities", [])
629
+ capabilities = st.multiselect(
630
+ "6.3 — What does your AI system do? (select all that apply)",
631
+ CAPABILITY_OPTIONS,
632
+ default=[c for c in prev_caps if c in CAPABILITY_OPTIONS],
633
+ key="q_capabilities",
634
+ )
635
+
636
+ # 6.4 Human involvement — always shown
637
+ prev_involvement = st.session_state.data.get("human_involvement", "N/A")
638
+ INVOLVEMENT_WITH_NA = ["N/A — no decisions affecting individuals", "Fully automated", "Human-assisted", "Human decides"]
639
+ if prev_involvement in INVOLVEMENT_LEVELS:
640
+ inv_idx = INVOLVEMENT_WITH_NA.index(prev_involvement)
641
+ else:
642
+ inv_idx = 0
643
+ human_involvement = st.selectbox(
644
+ "6.4 — Level of human involvement in decisions (if applicable)",
645
+ INVOLVEMENT_WITH_NA,
646
+ index=inv_idx,
647
+ key="q_involvement",
648
+ )
649
+
650
+ # 6.5 Synthetic content types — always shown
651
+ SYNTHETIC_TYPES = ["Text", "Images", "Audio", "Video", "Code"]
652
+ prev_content = st.session_state.data.get("synthetic_content", [])
653
+ synthetic_content = st.multiselect(
654
+ "6.5 — Types of synthetic content generated (if applicable, select all that apply)",
655
+ SYNTHETIC_TYPES,
656
+ default=[s for s in prev_content if s in SYNTHETIC_TYPES],
657
+ key="q_content",
658
+ )
659
+
660
+ col1, col2, col3 = st.columns([1, 3, 1])
661
+ with col1:
662
+ if st.button("← Back", use_container_width=True):
663
+ go_back()
664
+ st.rerun()
665
+ with col3:
666
+ if st.button("Next →", use_container_width=True):
667
+ st.session_state.data["ai_type"] = ai_type
668
+ st.session_state.data["model_type"] = model_type
669
+ st.session_state.data["gpai"] = model_type.startswith("Foundation model")
670
+ st.session_state.data["capabilities"] = capabilities
671
+ st.session_state.data["direct_interaction"] = "Interacts directly with end users" in capabilities
672
+ st.session_state.data["decision_making"] = "Makes or supports decisions that affect individuals" in capabilities
673
+ st.session_state.data["profiling"] = "Profiles individuals (builds user profiles based on behavior, preferences, or characteristics)" in capabilities
674
+ is_decision = "Makes or supports decisions that affect individuals" in capabilities
675
+ st.session_state.data["human_involvement"] = human_involvement if is_decision and not human_involvement.startswith("N/A") else "N/A"
676
+ is_synthetic = "Generates synthetic content (text, images, audio, video, code)" in capabilities
677
+ st.session_state.data["synthetic_content"] = synthetic_content if is_synthetic else []
678
+ st.session_state.data["emotion_recognition"] = "Performs emotion recognition" in capabilities
679
+ go_next()
680
+ st.rerun()
681
+
682
+
683
+ # ═══════════════════════════════════════════════
684
+ # SCREEN 7: Data Profile
685
+ # ═══════════════════════════════════════════════
686
+
687
+ elif current == 7:
688
+ st.markdown('<p class="screen-title">Data Profile</p>', unsafe_allow_html=True)
689
+ st.markdown('<p class="screen-subtitle">What data does your system process and where does it come from?</p>', unsafe_allow_html=True)
690
+
691
+ prev_data_types = st.session_state.data.get("data_types", [])
692
+ selected_data_types = st.multiselect(
693
+ "7.1 — What data types does your AI system process? (select all that apply)",
694
+ DATA_TYPE_OPTIONS,
695
+ default=[dt for dt in prev_data_types if dt in DATA_TYPE_OPTIONS],
696
+ )
697
+
698
+ st.divider()
699
+
700
+ prev_sources = st.session_state.data.get("training_sources", [])
701
+ training_sources = st.multiselect(
702
+ "7.2 — Training data sources (select all that apply)",
703
+ TRAINING_SOURCES,
704
+ default=[s for s in prev_sources if s in TRAINING_SOURCES],
705
+ )
706
+
707
+ col1, col2, col3 = st.columns([1, 3, 1])
708
+ with col1:
709
+ if st.button("← Back", use_container_width=True):
710
+ go_back()
711
+ st.rerun()
712
+ with col3:
713
+ if st.button("View Summary →", use_container_width=True, disabled=(not selected_data_types)):
714
+ st.session_state.data["data_types"] = selected_data_types
715
+ st.session_state.data["training_sources"] = training_sources
716
+ go_next()
717
+ st.rerun()
718
+
719
+
720
+ # ═══════════════════════════════════════════════
721
+ # SCREEN 8: Summary
722
+ # ═══════════════════════════════════════════════
723
+
724
+ elif current == 8:
725
+ d = st.session_state.data
726
+
727
+ st.markdown('<p class="screen-title">AI System ID Card — Summary</p>', unsafe_allow_html=True)
728
+ st.markdown(f'<p class="screen-subtitle">Review your inputs for <strong>{d.get("name", "")}</strong></p>', unsafe_allow_html=True)
729
+
730
+ # Identity
731
+ st.markdown(f'<div class="summary-section"><h4>AI System Identity</h4><p><strong>Name:</strong> {d.get("name", "—")}</p><p><strong>Description:</strong> {d.get("description", "—") or "—"}</p></div>', unsafe_allow_html=True)
732
+
733
+ # Domain
734
+ sectors = d.get("sector", [])
735
+ sectors_display = ", ".join(sectors) if sectors else "—"
736
+ st.markdown(f'<div class="summary-section"><h4>Application Domain</h4><p><strong>Sector(s):</strong> {sectors_display}</p></div>', unsafe_allow_html=True)
737
+
738
+ # Geography
739
+ geo_lines = f'<p><strong>Company base:</strong> {d.get("company_base", "—")}</p>'
740
+ ops = d.get("countries_operating", [])
741
+ dist = d.get("countries_distributed", [])
742
+ users = d.get("countries_end_users", [])
743
+ if ops:
744
+ geo_lines += f'<p><strong>Operates in:</strong> {", ".join(ops)}</p>'
745
+ if dist:
746
+ geo_lines += f'<p><strong>Distributed in:</strong> {", ".join(dist)}</p>'
747
+ if users:
748
+ geo_lines += f'<p><strong>End users in:</strong> {", ".join(users)}</p>'
749
+ if d.get("us_states"):
750
+ regulated = d.get("us_states_with_regulation", [])
751
+ non_regulated = [s for s in d["us_states"] if s not in regulated]
752
+ geo_lines += f'<p><strong>US states:</strong> {", ".join(d["us_states"])}</p>'
753
+ if regulated:
754
+ geo_lines += f'<p><strong>States with AI regulation:</strong> {", ".join(regulated)}</p>'
755
+ if non_regulated:
756
+ geo_lines += f'<p><strong>States without specific AI regulation:</strong> {", ".join(non_regulated)}</p>'
757
+ if d.get("eu_countries"):
758
+ geo_lines += f'<p><strong>EU/EEA countries detected:</strong> {", ".join(d["eu_countries"])}</p>'
759
+ if d.get("uae_emirates"):
760
+ geo_lines += f'<p><strong>UAE emirates:</strong> {", ".join(d["uae_emirates"])}</p>'
761
+ st.markdown(f'<div class="summary-section"><h4>Geographic Scope</h4>{geo_lines}</div>', unsafe_allow_html=True)
762
+
763
+ # Roles
764
+ roles_display = ", ".join(d.get("roles", ["—"]))
765
+ st.markdown(f'<div class="summary-section"><h4>Role in Value Chain</h4><p>{roles_display}</p></div>', unsafe_allow_html=True)
766
+
767
+ # Technology
768
+ model_type_display = d.get("model_type", "—")
769
+ caps = d.get("capabilities", [])
770
+ caps_display = ", ".join(caps) if caps else "None selected"
771
+ synthetic = ", ".join(d.get("synthetic_content", [])) or "None"
772
+ involvement = d.get("human_involvement", "N/A")
773
+
774
+ tech_lines = f'<p><strong>AI type:</strong> {d.get("ai_type", "—")}</p>'
775
+ tech_lines += f'<p><strong>Model:</strong> {model_type_display}</p>'
776
+ tech_lines += f'<p><strong>Capabilities:</strong> {caps_display}</p>'
777
+ if d.get("decision_making"):
778
+ tech_lines += f'<p><strong>Human involvement in decisions:</strong> {involvement}</p>'
779
+ if d.get("synthetic_content"):
780
+ tech_lines += f'<p><strong>Synthetic content types:</strong> {synthetic}</p>'
781
+ st.markdown(f'<div class="summary-section"><h4>Technology Profile</h4>{tech_lines}</div>', unsafe_allow_html=True)
782
+
783
+ # Data
784
+ data_types_display = ", ".join(d.get("data_types", ["—"]))
785
+ sources_display = ", ".join(d.get("training_sources", ["—"]))
786
+ st.markdown(f'<div class="summary-section"><h4>Data Profile</h4><p><strong>Data types:</strong> {data_types_display}</p><p><strong>Training sources:</strong> {sources_display}</p></div>', unsafe_allow_html=True)
787
+
788
+ # Navigation
789
+ col1, col2, col3 = st.columns([1, 2, 2])
790
+ with col1:
791
+ if st.button("← Edit", use_container_width=True):
792
+ go_to(1)
793
+ st.rerun()
794
+ with col3:
795
+ st.info("Regulation analysis coming in next version")