aimodelshare 0.1.29__py3-none-any.whl → 0.1.64__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of aimodelshare might be problematic. Click here for more details.

Files changed (41) hide show
  1. aimodelshare/__init__.py +94 -14
  2. aimodelshare/aimsonnx.py +417 -262
  3. aimodelshare/api.py +13 -12
  4. aimodelshare/auth.py +163 -0
  5. aimodelshare/aws.py +4 -4
  6. aimodelshare/base_image.py +1 -1
  7. aimodelshare/containerisation.py +1 -1
  8. aimodelshare/data_sharing/download_data.py +103 -70
  9. aimodelshare/generatemodelapi.py +7 -6
  10. aimodelshare/main/authorization.txt +275 -275
  11. aimodelshare/main/eval_lambda.txt +81 -13
  12. aimodelshare/model.py +493 -197
  13. aimodelshare/modeluser.py +89 -1
  14. aimodelshare/moral_compass/README.md +408 -0
  15. aimodelshare/moral_compass/__init__.py +37 -0
  16. aimodelshare/moral_compass/_version.py +3 -0
  17. aimodelshare/moral_compass/api_client.py +601 -0
  18. aimodelshare/moral_compass/apps/__init__.py +26 -0
  19. aimodelshare/moral_compass/apps/ai_consequences.py +297 -0
  20. aimodelshare/moral_compass/apps/judge.py +299 -0
  21. aimodelshare/moral_compass/apps/tutorial.py +198 -0
  22. aimodelshare/moral_compass/apps/what_is_ai.py +426 -0
  23. aimodelshare/moral_compass/challenge.py +365 -0
  24. aimodelshare/moral_compass/config.py +187 -0
  25. aimodelshare/playground.py +26 -14
  26. aimodelshare/preprocessormodules.py +60 -6
  27. aimodelshare/pyspark/authorization.txt +258 -258
  28. aimodelshare/pyspark/eval_lambda.txt +1 -1
  29. aimodelshare/reproducibility.py +20 -5
  30. aimodelshare/utils/__init__.py +78 -0
  31. aimodelshare/utils/optional_deps.py +38 -0
  32. aimodelshare-0.1.64.dist-info/METADATA +298 -0
  33. {aimodelshare-0.1.29.dist-info → aimodelshare-0.1.64.dist-info}/RECORD +36 -25
  34. {aimodelshare-0.1.29.dist-info → aimodelshare-0.1.64.dist-info}/WHEEL +1 -1
  35. aimodelshare-0.1.64.dist-info/licenses/LICENSE +5 -0
  36. {aimodelshare-0.1.29.dist-info → aimodelshare-0.1.64.dist-info}/top_level.txt +0 -1
  37. aimodelshare-0.1.29.dist-info/METADATA +0 -78
  38. aimodelshare-0.1.29.dist-info/licenses/LICENSE +0 -22
  39. tests/__init__.py +0 -0
  40. tests/test_aimsonnx.py +0 -135
  41. tests/test_playground.py +0 -721
@@ -0,0 +1,297 @@
1
+ """
2
+ AI Consequences - Gradio application for the Justice & Equity Challenge.
3
+
4
+ This app teaches:
5
+ 1. The consequences of wrong AI predictions in criminal justice
6
+ 2. Understanding false positives and false negatives
7
+ 3. The ethical stakes of relying on AI for high-stakes decisions
8
+
9
+ Structure:
10
+ - Factory function `create_ai_consequences_app()` returns a Gradio Blocks object
11
+ - Convenience wrapper `launch_ai_consequences_app()` launches it inline (for notebooks)
12
+ """
13
+ import contextlib
14
+ import os
15
+
16
+
17
+ def create_ai_consequences_app(theme_primary_hue: str = "indigo") -> "gr.Blocks":
18
+ """Create the AI Consequences Gradio Blocks app (not launched yet)."""
19
+ try:
20
+ import gradio as gr
21
+ except ImportError as e:
22
+ raise ImportError(
23
+ "Gradio is required for the AI consequences app. Install with `pip install gradio`."
24
+ ) from e
25
+
26
+ css = """
27
+ .large-text {
28
+ font-size: 20px !important;
29
+ }
30
+ .warning-box {
31
+ background: #fef2f2 !important;
32
+ border-left: 6px solid #dc2626 !important;
33
+ }
34
+ """
35
+
36
+ with gr.Blocks(theme=gr.themes.Soft(primary_hue=theme_primary_hue), css=css) as demo:
37
+ gr.Markdown("<h1 style='text-align:center;'>⚠️ What If the AI Was Wrong?</h1>")
38
+ gr.Markdown(
39
+ """
40
+ <div style='text-align:center; font-size:18px; max-width: 900px; margin: auto;
41
+ padding: 20px; background-color: #fef2f2; border-radius: 12px; border: 2px solid #dc2626;'>
42
+ You just made decisions based on an AI's predictions.<br>
43
+ But AI systems are not perfect. Let's explore what happens when they make mistakes.
44
+ </div>
45
+ """
46
+ )
47
+ gr.HTML("<hr style='margin:24px 0;'>")
48
+
49
+ # Step 1: Introduction
50
+ with gr.Column(visible=True) as step_1:
51
+ gr.Markdown("<h2 style='text-align:center;'>The Stakes of AI Predictions</h2>")
52
+ gr.Markdown(
53
+ """
54
+ <div style='font-size: 20px; background:#dbeafe; padding:28px; border-radius:16px;'>
55
+ <p>In the previous exercise, you relied on an AI system to predict which defendants
56
+ were at <b>High</b>, <b>Medium</b>, or <b>Low</b> risk of re-offending.</p>
57
+
58
+ <p style='margin-top:20px;'><b>But what if those predictions were incorrect?</b></p>
59
+
60
+ <p style='margin-top:20px;'>AI systems make two types of errors that have very different consequences:</p>
61
+
62
+ <ul style='font-size:18px; margin-top:12px;'>
63
+ <li><b>False Positives</b> - Incorrectly predicting HIGH risk</li>
64
+ <li><b>False Negatives</b> - Incorrectly predicting LOW risk</li>
65
+ </ul>
66
+
67
+ <p style='margin-top:20px;'>Let's examine each type of error and its real-world impact.</p>
68
+ </div>
69
+ """
70
+ )
71
+ step_1_next = gr.Button("Next: False Positives ▶️", variant="primary", size="lg")
72
+
73
+ # Step 2: False Positives
74
+ with gr.Column(visible=False) as step_2:
75
+ gr.Markdown("<h2 style='text-align:center;'>🔴 False Positives: Predicting Danger Where None Exists</h2>")
76
+ gr.Markdown(
77
+ """
78
+ <div style='font-size: 20px; background:#fef3c7; padding:28px; border-radius:16px; border: 3px solid #f59e0b;'>
79
+ <h3 style='color:#b45309; margin-top:0;'>What is a False Positive?</h3>
80
+
81
+ <p>A <b>false positive</b> occurs when the AI predicts someone is <b style='color:#dc2626;'>HIGH RISK</b>,
82
+ but they would NOT have actually re-offended if released.</p>
83
+
84
+ <div style='background:white; padding:20px; border-radius:8px; margin:20px 0;'>
85
+ <h4 style='margin-top:0;'>Example Scenario:</h4>
86
+ <p style='font-size:18px;'>
87
+ • Sarah was flagged as <b style='color:#dc2626;'>HIGH RISK</b><br>
88
+ • Based on this, the judge kept her in prison<br>
89
+ • In reality, Sarah would have rebuilt her life and never committed another crime
90
+ </p>
91
+ </div>
92
+
93
+ <h3 style='color:#b45309;'>The Human Cost:</h3>
94
+ <ul style='font-size:18px;'>
95
+ <li>Innocent people spend unnecessary time in prison</li>
96
+ <li>Families are separated for longer than needed</li>
97
+ <li>Job opportunities and rehabilitation are delayed</li>
98
+ <li>Trust in the justice system erodes</li>
99
+ <li>Disproportionate impact on marginalized communities</li>
100
+ </ul>
101
+
102
+ <div style='background:#fef2f2; padding:16px; border-radius:8px; margin-top:20px; border-left:6px solid #dc2626;'>
103
+ <p style='font-size:18px; margin:0;'><b>Key Point:</b> False positives mean the AI is being
104
+ <b>too cautious</b>, keeping people locked up who should be free.</p>
105
+ </div>
106
+ </div>
107
+ """
108
+ )
109
+ with gr.Row():
110
+ step_2_back = gr.Button("◀️ Back", size="lg")
111
+ step_2_next = gr.Button("Next: False Negatives ▶️", variant="primary", size="lg")
112
+
113
+ # Step 3: False Negatives
114
+ with gr.Column(visible=False) as step_3:
115
+ gr.Markdown("<h2 style='text-align:center;'>🔵 False Negatives: Missing Real Danger</h2>")
116
+ gr.Markdown(
117
+ """
118
+ <div style='font-size: 20px; background:#f0fdf4; padding:28px; border-radius:16px; border: 3px solid #16a34a;'>
119
+ <h3 style='color:#15803d; margin-top:0;'>What is a False Negative?</h3>
120
+
121
+ <p>A <b>false negative</b> occurs when the AI predicts someone is <b style='color:#16a34a;'>LOW RISK</b>,
122
+ but they DO actually re-offend after being released.</p>
123
+
124
+ <div style='background:white; padding:20px; border-radius:8px; margin:20px 0;'>
125
+ <h4 style='margin-top:0;'>Example Scenario:</h4>
126
+ <p style='font-size:18px;'>
127
+ • James was flagged as <b style='color:#16a34a;'>LOW RISK</b><br>
128
+ • Based on this, the judge released him<br>
129
+ • Unfortunately, James did commit another serious crime
130
+ </p>
131
+ </div>
132
+
133
+ <h3 style='color:#15803d;'>The Human Cost:</h3>
134
+ <ul style='font-size:18px;'>
135
+ <li>New victims of preventable crimes</li>
136
+ <li>Loss of public trust in the justice system</li>
137
+ <li>Media scrutiny and backlash against judges</li>
138
+ <li>Political pressure to be "tough on crime"</li>
139
+ <li>Potential harm to communities and families</li>
140
+ </ul>
141
+
142
+ <div style='background:#fef2f2; padding:16px; border-radius:8px; margin-top:20px; border-left:6px solid #dc2626;'>
143
+ <p style='font-size:18px; margin:0;'><b>Key Point:</b> False negatives mean the AI is being
144
+ <b>too lenient</b>, releasing people who pose a real danger to society.</p>
145
+ </div>
146
+ </div>
147
+ """
148
+ )
149
+ with gr.Row():
150
+ step_3_back = gr.Button("◀️ Back", size="lg")
151
+ step_3_next = gr.Button("Next: The Dilemma ▶️", variant="primary", size="lg")
152
+
153
+ # Step 4: The Dilemma
154
+ with gr.Column(visible=False) as step_4:
155
+ gr.Markdown("<h2 style='text-align:center;'>⚖️ The Impossible Balance</h2>")
156
+ gr.Markdown(
157
+ """
158
+ <div style='font-size: 20px; background:#faf5ff; padding:28px; border-radius:16px; border: 3px solid #9333ea;'>
159
+ <h3 style='color:#7e22ce; margin-top:0;'>Every AI System Makes Trade-offs</h3>
160
+
161
+ <p>Here's the harsh reality: <b>No AI system can eliminate both types of errors.</b></p>
162
+
163
+ <div style='background:white; padding:24px; border-radius:12px; margin:24px 0;'>
164
+ <p style='font-size:18px; margin-bottom:16px;'><b>If you make the AI more cautious:</b></p>
165
+ <ul style='font-size:18px;'>
166
+ <li>✓ Fewer false negatives (fewer dangerous people released)</li>
167
+ <li>✗ More false positives (more innocent people kept in prison)</li>
168
+ </ul>
169
+
170
+ <hr style='margin:20px 0;'>
171
+
172
+ <p style='font-size:18px; margin-bottom:16px;'><b>If you make the AI more lenient:</b></p>
173
+ <ul style='font-size:18px;'>
174
+ <li>✓ Fewer false positives (more innocent people freed)</li>
175
+ <li>✗ More false negatives (more dangerous people released)</li>
176
+ </ul>
177
+ </div>
178
+
179
+ <h3 style='color:#7e22ce;'>The Ethical Question:</h3>
180
+ <div style='background:#fef2f2; padding:20px; border-radius:8px; border-left:6px solid #dc2626;'>
181
+ <p style='font-size:20px; font-weight:bold; margin:0;'>
182
+ Which mistake is worse?
183
+ </p>
184
+ <p style='font-size:18px; margin-top:12px; margin-bottom:0;'>
185
+ • Keeping innocent people in prison?<br>
186
+ • Or releasing dangerous individuals?
187
+ </p>
188
+ </div>
189
+
190
+ <p style='margin-top:24px; font-size:18px;'><b>There is no universally "correct" answer.</b>
191
+ Different societies, legal systems, and ethical frameworks weigh these trade-offs differently.</p>
192
+
193
+ <div style='background:#dbeafe; padding:16px; border-radius:8px; margin-top:20px;'>
194
+ <p style='font-size:18px; margin:0;'><b>This is why understanding AI is crucial.</b>
195
+ We need to know how these systems work so we can make informed decisions about when
196
+ and how to use them.</p>
197
+ </div>
198
+ </div>
199
+ """
200
+ )
201
+ with gr.Row():
202
+ step_4_back = gr.Button("◀️ Back", size="lg")
203
+ step_4_next = gr.Button("Continue to Learn About AI ▶️", variant="primary", size="lg")
204
+
205
+ # Step 5: Completion
206
+ with gr.Column(visible=False) as step_5:
207
+ gr.Markdown(
208
+ """
209
+ <div style='text-align:center;'>
210
+ <h2 style='font-size: 2.5rem;'>✅ Section Complete!</h2>
211
+ <div style='font-size: 1.3rem; background:#e0f2fe; padding:28px; border-radius:16px;
212
+ border: 2px solid #0284c7;'>
213
+ <p>You now understand the consequences of AI errors in high-stakes decisions.</p>
214
+
215
+ <p style='margin-top:24px;'><b>Next up:</b> Learn what AI actually is and how these
216
+ prediction systems work.</p>
217
+
218
+ <p style='margin-top:24px;'>This knowledge will help you understand how to build
219
+ better, more ethical AI systems.</p>
220
+
221
+ <h1 style='margin:20px 0; font-size: 3rem;'>👇 SCROLL DOWN 👇</h1>
222
+ <p style='font-size:1.1rem;'>Find the next section below to continue your journey.</p>
223
+ </div>
224
+ </div>
225
+ """
226
+ )
227
+ back_to_dilemma_btn = gr.Button("◀️ Back to Review")
228
+
229
+ # Navigation logic
230
+ step_1_next.click(
231
+ lambda: (gr.update(visible=False), gr.update(visible=True), gr.update(visible=False),
232
+ gr.update(visible=False), gr.update(visible=False)),
233
+ inputs=None,
234
+ outputs=[step_1, step_2, step_3, step_4, step_5]
235
+ )
236
+
237
+ step_2_back.click(
238
+ lambda: (gr.update(visible=True), gr.update(visible=False), gr.update(visible=False),
239
+ gr.update(visible=False), gr.update(visible=False)),
240
+ inputs=None,
241
+ outputs=[step_1, step_2, step_3, step_4, step_5]
242
+ )
243
+
244
+ step_2_next.click(
245
+ lambda: (gr.update(visible=False), gr.update(visible=False), gr.update(visible=True),
246
+ gr.update(visible=False), gr.update(visible=False)),
247
+ inputs=None,
248
+ outputs=[step_1, step_2, step_3, step_4, step_5]
249
+ )
250
+
251
+ step_3_back.click(
252
+ lambda: (gr.update(visible=False), gr.update(visible=True), gr.update(visible=False),
253
+ gr.update(visible=False), gr.update(visible=False)),
254
+ inputs=None,
255
+ outputs=[step_1, step_2, step_3, step_4, step_5]
256
+ )
257
+
258
+ step_3_next.click(
259
+ lambda: (gr.update(visible=False), gr.update(visible=False), gr.update(visible=False),
260
+ gr.update(visible=True), gr.update(visible=False)),
261
+ inputs=None,
262
+ outputs=[step_1, step_2, step_3, step_4, step_5]
263
+ )
264
+
265
+ step_4_back.click(
266
+ lambda: (gr.update(visible=False), gr.update(visible=False), gr.update(visible=True),
267
+ gr.update(visible=False), gr.update(visible=False)),
268
+ inputs=None,
269
+ outputs=[step_1, step_2, step_3, step_4, step_5]
270
+ )
271
+
272
+ step_4_next.click(
273
+ lambda: (gr.update(visible=False), gr.update(visible=False), gr.update(visible=False),
274
+ gr.update(visible=False), gr.update(visible=True)),
275
+ inputs=None,
276
+ outputs=[step_1, step_2, step_3, step_4, step_5]
277
+ )
278
+
279
+ back_to_dilemma_btn.click(
280
+ lambda: (gr.update(visible=False), gr.update(visible=False), gr.update(visible=False),
281
+ gr.update(visible=True), gr.update(visible=False)),
282
+ inputs=None,
283
+ outputs=[step_1, step_2, step_3, step_4, step_5]
284
+ )
285
+
286
+ return demo
287
+
288
+
289
+ def launch_ai_consequences_app(height: int = 1000, share: bool = False, debug: bool = False) -> None:
290
+ """Convenience wrapper to create and launch the AI consequences app inline."""
291
+ demo = create_ai_consequences_app()
292
+ try:
293
+ import gradio as gr # noqa: F401
294
+ except ImportError as e:
295
+ raise ImportError("Gradio must be installed to launch the AI consequences app.") from e
296
+ with contextlib.redirect_stdout(open(os.devnull, 'w')), contextlib.redirect_stderr(open(os.devnull, 'w')):
297
+ demo.launch(share=share, inline=True, debug=debug, height=height)
@@ -0,0 +1,299 @@
1
+ """
2
+ You Be the Judge - Gradio application for the Justice & Equity Challenge.
3
+
4
+ This app teaches:
5
+ 1. How to make decisions based on AI predictions
6
+ 2. The stakes involved in using AI for criminal justice decisions
7
+ 3. The importance of understanding what AI gets wrong
8
+
9
+ Structure:
10
+ - Factory function `create_judge_app()` returns a Gradio Blocks object
11
+ - Convenience wrapper `launch_judge_app()` launches it inline (for notebooks)
12
+ """
13
+ import contextlib
14
+ import os
15
+
16
+
17
+ def _generate_defendant_profiles():
18
+ """Generate synthetic defendant profiles for the exercise."""
19
+ import random
20
+ random.seed(42) # For reproducibility
21
+
22
+ profiles = [
23
+ {
24
+ "id": 1,
25
+ "name": "Carlos M.",
26
+ "age": 23,
27
+ "gender": "Male",
28
+ "race": "Hispanic",
29
+ "prior_offenses": 2,
30
+ "current_charge": "Drug possession",
31
+ "ai_risk": "High",
32
+ "ai_confidence": "85%"
33
+ },
34
+ {
35
+ "id": 2,
36
+ "name": "Sarah J.",
37
+ "age": 34,
38
+ "gender": "Female",
39
+ "race": "White",
40
+ "prior_offenses": 0,
41
+ "current_charge": "Theft",
42
+ "ai_risk": "Low",
43
+ "ai_confidence": "72%"
44
+ },
45
+ {
46
+ "id": 3,
47
+ "name": "DeShawn W.",
48
+ "age": 19,
49
+ "gender": "Male",
50
+ "race": "Black",
51
+ "prior_offenses": 1,
52
+ "current_charge": "Assault",
53
+ "ai_risk": "Medium",
54
+ "ai_confidence": "68%"
55
+ },
56
+ {
57
+ "id": 4,
58
+ "name": "Maria R.",
59
+ "age": 41,
60
+ "gender": "Female",
61
+ "race": "Hispanic",
62
+ "prior_offenses": 3,
63
+ "current_charge": "Fraud",
64
+ "ai_risk": "Medium",
65
+ "ai_confidence": "70%"
66
+ },
67
+ {
68
+ "id": 5,
69
+ "name": "James K.",
70
+ "age": 28,
71
+ "gender": "Male",
72
+ "race": "White",
73
+ "prior_offenses": 5,
74
+ "current_charge": "Burglary",
75
+ "ai_risk": "High",
76
+ "ai_confidence": "91%"
77
+ }
78
+ ]
79
+
80
+ return profiles
81
+
82
+
83
+ def create_judge_app(theme_primary_hue: str = "indigo") -> "gr.Blocks":
84
+ """Create the You Be the Judge Gradio Blocks app (not launched yet)."""
85
+ try:
86
+ import gradio as gr
87
+ except ImportError as e:
88
+ raise ImportError(
89
+ "Gradio is required for the judge app. Install with `pip install gradio`."
90
+ ) from e
91
+
92
+ profiles = _generate_defendant_profiles()
93
+
94
+ # State to track decisions
95
+ decisions = {}
96
+
97
+ def format_profile(profile):
98
+ """Format a defendant profile for display."""
99
+ risk_color = {
100
+ "High": "#ef4444",
101
+ "Medium": "#f59e0b",
102
+ "Low": "#22c55e"
103
+ }
104
+
105
+ color = risk_color.get(profile["ai_risk"], "#6b7280")
106
+
107
+ return f"""
108
+ <div style='background:#f9fafb; padding:20px; border-radius:12px; border-left: 6px solid {color};'>
109
+ <h3 style='margin-top:0; color:#1f2937;'>Defendant #{profile['id']}: {profile['name']}</h3>
110
+ <div style='display: grid; grid-template-columns: 1fr 1fr; gap: 12px; font-size: 16px;'>
111
+ <div><b>Age:</b> {profile['age']}</div>
112
+ <div><b>Gender:</b> {profile['gender']}</div>
113
+ <div><b>Race:</b> {profile['race']}</div>
114
+ <div><b>Prior Offenses:</b> {profile['prior_offenses']}</div>
115
+ <div style='grid-column: span 2;'><b>Current Charge:</b> {profile['current_charge']}</div>
116
+ </div>
117
+ <div style='margin-top:16px; padding:12px; background:white; border-radius:8px;'>
118
+ <b>🤖 AI Risk Assessment:</b>
119
+ <span style='color:{color}; font-size:20px; font-weight:bold;'>{profile['ai_risk']} Risk</span>
120
+ <span style='color:#6b7280; margin-left:8px;'>(Confidence: {profile['ai_confidence']})</span>
121
+ </div>
122
+ </div>
123
+ """
124
+
125
+ def make_decision(defendant_id, decision):
126
+ """Record a decision for a defendant."""
127
+ decisions[defendant_id] = decision
128
+ return f"✓ Decision recorded: {decision}"
129
+
130
+ def get_summary():
131
+ """Get summary of all decisions made."""
132
+ if not decisions:
133
+ return "No decisions made yet."
134
+
135
+ released = sum(1 for d in decisions.values() if d == "Release")
136
+ kept = sum(1 for d in decisions.values() if d == "Keep in Prison")
137
+
138
+ summary = f"""
139
+ <div style='background:#dbeafe; padding:20px; border-radius:12px;'>
140
+ <h3 style='margin-top:0;'>📊 Your Decisions Summary</h3>
141
+ <div style='font-size:18px;'>
142
+ <p><b>Prisoners Released:</b> {released} of {len(decisions)}</p>
143
+ <p><b>Prisoners Kept in Prison:</b> {kept} of {len(decisions)}</p>
144
+ </div>
145
+ </div>
146
+ """
147
+ return summary
148
+
149
+ css = """
150
+ .decision-button {
151
+ font-size: 18px !important;
152
+ padding: 12px 24px !important;
153
+ }
154
+ """
155
+
156
+ with gr.Blocks(theme=gr.themes.Soft(primary_hue=theme_primary_hue), css=css) as demo:
157
+ gr.Markdown("<h1 style='text-align:center;'>⚖️ You Be the Judge</h1>")
158
+ gr.Markdown(
159
+ """
160
+ <div style='text-align:center; font-size:18px; max-width: 900px; margin: auto;
161
+ padding: 20px; background-color: #fef3c7; border-radius: 12px; border: 2px solid #f59e0b;'>
162
+ <b>Your Role:</b> You are a judge who must decide whether to release defendants from prison.<br>
163
+ An AI system has analyzed each case and provided a risk assessment.<br><br>
164
+ <b>Your Task:</b> Review each defendant's profile and the AI's prediction, then make your decision.
165
+ </div>
166
+ """
167
+ )
168
+ gr.HTML("<hr style='margin:24px 0;'>")
169
+
170
+ # Introduction
171
+ with gr.Column(visible=True) as intro_section:
172
+ gr.Markdown("<h2 style='text-align:center;'>📋 The Scenario</h2>")
173
+ gr.Markdown(
174
+ """
175
+ <div style='font-size: 18px; background:#e0f2fe; padding:24px; border-radius:12px;'>
176
+ You are a judge in a busy criminal court. Due to prison overcrowding, you must decide
177
+ which defendants can be safely released.<br><br>
178
+
179
+ To help you, the court has implemented an AI system that predicts the risk of each
180
+ defendant committing new crimes if released. The AI categorizes defendants as:<br><br>
181
+
182
+ <ul style='font-size:18px;'>
183
+ <li><span style='color:#ef4444; font-weight:bold;'>High Risk</span> - Likely to re-offend</li>
184
+ <li><span style='color:#f59e0b; font-weight:bold;'>Medium Risk</span> - Moderate chance of re-offending</li>
185
+ <li><span style='color:#22c55e; font-weight:bold;'>Low Risk</span> - Unlikely to re-offend</li>
186
+ </ul>
187
+
188
+ <b>Remember:</b> Your decisions affect real people's lives and public safety.
189
+ </div>
190
+ """
191
+ )
192
+ start_btn = gr.Button("Begin Making Decisions ▶️", variant="primary", size="lg")
193
+
194
+ # Defendant profiles section
195
+ with gr.Column(visible=False) as profiles_section:
196
+ gr.Markdown("<h2 style='text-align:center;'>👥 Defendant Profiles</h2>")
197
+ gr.Markdown(
198
+ """
199
+ <div style='text-align:center; font-size:16px; background:#f3f4f6; padding:12px; border-radius:8px;'>
200
+ Review each defendant's information and the AI's risk assessment, then make your decision.
201
+ </div>
202
+ """
203
+ )
204
+ gr.HTML("<br>")
205
+
206
+ # Create UI for each defendant
207
+ for profile in profiles:
208
+ with gr.Column():
209
+ gr.HTML(format_profile(profile))
210
+
211
+ with gr.Row():
212
+ release_btn = gr.Button(
213
+ "✓ Release Prisoner",
214
+ variant="primary",
215
+ elem_classes=["decision-button"]
216
+ )
217
+ keep_btn = gr.Button(
218
+ "✗ Keep in Prison",
219
+ variant="secondary",
220
+ elem_classes=["decision-button"]
221
+ )
222
+
223
+ decision_status = gr.Markdown("")
224
+
225
+ # Wire up buttons
226
+ release_btn.click(
227
+ lambda p_id=profile["id"]: make_decision(p_id, "Release"),
228
+ inputs=None,
229
+ outputs=decision_status
230
+ )
231
+ keep_btn.click(
232
+ lambda p_id=profile["id"]: make_decision(p_id, "Keep in Prison"),
233
+ inputs=None,
234
+ outputs=decision_status
235
+ )
236
+
237
+ gr.HTML("<hr style='margin:24px 0;'>")
238
+
239
+ # Summary section
240
+ summary_display = gr.HTML("")
241
+ show_summary_btn = gr.Button("📊 Show My Decisions Summary", variant="primary", size="lg")
242
+ show_summary_btn.click(get_summary, inputs=None, outputs=summary_display)
243
+
244
+ gr.HTML("<br>")
245
+ complete_btn = gr.Button("Complete This Section ▶️", variant="primary", size="lg")
246
+
247
+ # Completion section
248
+ with gr.Column(visible=False) as complete_section:
249
+ gr.Markdown(
250
+ """
251
+ <div style='text-align:center;'>
252
+ <h2 style='font-size: 2.5rem;'>✅ Decisions Complete!</h2>
253
+ <div style='font-size: 1.3rem; background:#e0f2fe; padding:28px; border-radius:16px;
254
+ border: 2px solid #0284c7;'>
255
+ You've made your decisions based on the AI's recommendations.<br><br>
256
+ But here's the critical question:<br><br>
257
+ <h2 style='color:#dc2626; margin:16px 0;'>What if the AI was wrong?</h2>
258
+ <p style='font-size:1.1rem;'>
259
+ Continue to the next section below to explore the consequences of
260
+ trusting AI predictions in high-stakes situations.
261
+ </p>
262
+ <h1 style='margin:20px 0; font-size: 3rem;'>👇 SCROLL DOWN 👇</h1>
263
+ </div>
264
+ </div>
265
+ """
266
+ )
267
+ back_to_profiles_btn = gr.Button("◀️ Back to Review Decisions")
268
+
269
+ # Navigation logic
270
+ start_btn.click(
271
+ lambda: (gr.update(visible=False), gr.update(visible=True), gr.update(visible=False)),
272
+ inputs=None,
273
+ outputs=[intro_section, profiles_section, complete_section]
274
+ )
275
+
276
+ complete_btn.click(
277
+ lambda: (gr.update(visible=False), gr.update(visible=False), gr.update(visible=True)),
278
+ inputs=None,
279
+ outputs=[intro_section, profiles_section, complete_section]
280
+ )
281
+
282
+ back_to_profiles_btn.click(
283
+ lambda: (gr.update(visible=False), gr.update(visible=True), gr.update(visible=False)),
284
+ inputs=None,
285
+ outputs=[intro_section, profiles_section, complete_section]
286
+ )
287
+
288
+ return demo
289
+
290
+
291
+ def launch_judge_app(height: int = 1200, share: bool = False, debug: bool = False) -> None:
292
+ """Convenience wrapper to create and launch the judge app inline."""
293
+ demo = create_judge_app()
294
+ try:
295
+ import gradio as gr # noqa: F401
296
+ except ImportError as e:
297
+ raise ImportError("Gradio must be installed to launch the judge app.") from e
298
+ with contextlib.redirect_stdout(open(os.devnull, 'w')), contextlib.redirect_stderr(open(os.devnull, 'w')):
299
+ demo.launch(share=share, inline=True, debug=debug, height=height)