aimodelshare 0.3.7__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.
- aimodelshare/README.md +26 -0
- aimodelshare/__init__.py +100 -0
- aimodelshare/aimsonnx.py +2381 -0
- aimodelshare/api.py +836 -0
- aimodelshare/auth.py +163 -0
- aimodelshare/aws.py +511 -0
- aimodelshare/aws_client.py +173 -0
- aimodelshare/base_image.py +154 -0
- aimodelshare/bucketpolicy.py +106 -0
- aimodelshare/color_mappings/color_mapping_keras.csv +121 -0
- aimodelshare/color_mappings/color_mapping_pytorch.csv +117 -0
- aimodelshare/containerisation.py +244 -0
- aimodelshare/containerization.py +712 -0
- aimodelshare/containerization_templates/Dockerfile.txt +8 -0
- aimodelshare/containerization_templates/Dockerfile_PySpark.txt +23 -0
- aimodelshare/containerization_templates/buildspec.txt +14 -0
- aimodelshare/containerization_templates/lambda_function.txt +40 -0
- aimodelshare/custom_approach/__init__.py +1 -0
- aimodelshare/custom_approach/lambda_function.py +17 -0
- aimodelshare/custom_eval_metrics.py +103 -0
- aimodelshare/data_sharing/__init__.py +0 -0
- aimodelshare/data_sharing/data_sharing_templates/Dockerfile.txt +3 -0
- aimodelshare/data_sharing/data_sharing_templates/__init__.py +1 -0
- aimodelshare/data_sharing/data_sharing_templates/buildspec.txt +15 -0
- aimodelshare/data_sharing/data_sharing_templates/codebuild_policies.txt +129 -0
- aimodelshare/data_sharing/data_sharing_templates/codebuild_trust_relationship.txt +12 -0
- aimodelshare/data_sharing/download_data.py +620 -0
- aimodelshare/data_sharing/share_data.py +373 -0
- aimodelshare/data_sharing/utils.py +8 -0
- aimodelshare/deploy_custom_lambda.py +246 -0
- aimodelshare/documentation/Makefile +20 -0
- aimodelshare/documentation/karma_sphinx_theme/__init__.py +28 -0
- aimodelshare/documentation/karma_sphinx_theme/_version.py +2 -0
- aimodelshare/documentation/karma_sphinx_theme/breadcrumbs.html +70 -0
- aimodelshare/documentation/karma_sphinx_theme/layout.html +172 -0
- aimodelshare/documentation/karma_sphinx_theme/search.html +50 -0
- aimodelshare/documentation/karma_sphinx_theme/searchbox.html +14 -0
- aimodelshare/documentation/karma_sphinx_theme/static/css/custom.css +2 -0
- aimodelshare/documentation/karma_sphinx_theme/static/css/custom.css.map +1 -0
- aimodelshare/documentation/karma_sphinx_theme/static/css/theme.css +2751 -0
- aimodelshare/documentation/karma_sphinx_theme/static/css/theme.css.map +1 -0
- aimodelshare/documentation/karma_sphinx_theme/static/css/theme.min.css +2 -0
- aimodelshare/documentation/karma_sphinx_theme/static/css/theme.min.css.map +1 -0
- aimodelshare/documentation/karma_sphinx_theme/static/font/fontello.eot +0 -0
- aimodelshare/documentation/karma_sphinx_theme/static/font/fontello.svg +32 -0
- aimodelshare/documentation/karma_sphinx_theme/static/font/fontello.ttf +0 -0
- aimodelshare/documentation/karma_sphinx_theme/static/font/fontello.woff +0 -0
- aimodelshare/documentation/karma_sphinx_theme/static/font/fontello.woff2 +0 -0
- aimodelshare/documentation/karma_sphinx_theme/static/js/theme.js +68 -0
- aimodelshare/documentation/karma_sphinx_theme/theme.conf +9 -0
- aimodelshare/documentation/make.bat +35 -0
- aimodelshare/documentation/requirements.txt +2 -0
- aimodelshare/documentation/source/about.rst +18 -0
- aimodelshare/documentation/source/advanced_features.rst +137 -0
- aimodelshare/documentation/source/competition.rst +218 -0
- aimodelshare/documentation/source/conf.py +58 -0
- aimodelshare/documentation/source/create_credentials.rst +86 -0
- aimodelshare/documentation/source/example_notebooks.rst +132 -0
- aimodelshare/documentation/source/functions.rst +151 -0
- aimodelshare/documentation/source/gettingstarted.rst +390 -0
- aimodelshare/documentation/source/images/creds1.png +0 -0
- aimodelshare/documentation/source/images/creds2.png +0 -0
- aimodelshare/documentation/source/images/creds3.png +0 -0
- aimodelshare/documentation/source/images/creds4.png +0 -0
- aimodelshare/documentation/source/images/creds5.png +0 -0
- aimodelshare/documentation/source/images/creds_file_example.png +0 -0
- aimodelshare/documentation/source/images/predict_tab.png +0 -0
- aimodelshare/documentation/source/index.rst +110 -0
- aimodelshare/documentation/source/modelplayground.rst +132 -0
- aimodelshare/exceptions.py +11 -0
- aimodelshare/generatemodelapi.py +1270 -0
- aimodelshare/iam/codebuild_policy.txt +129 -0
- aimodelshare/iam/codebuild_trust_relationship.txt +12 -0
- aimodelshare/iam/lambda_policy.txt +15 -0
- aimodelshare/iam/lambda_trust_relationship.txt +12 -0
- aimodelshare/json_templates/__init__.py +1 -0
- aimodelshare/json_templates/api_json.txt +155 -0
- aimodelshare/json_templates/auth/policy.txt +1 -0
- aimodelshare/json_templates/auth/role.txt +1 -0
- aimodelshare/json_templates/eval/policy.txt +1 -0
- aimodelshare/json_templates/eval/role.txt +1 -0
- aimodelshare/json_templates/function/policy.txt +1 -0
- aimodelshare/json_templates/function/role.txt +1 -0
- aimodelshare/json_templates/integration_response.txt +5 -0
- aimodelshare/json_templates/lambda_policy_1.txt +15 -0
- aimodelshare/json_templates/lambda_policy_2.txt +8 -0
- aimodelshare/json_templates/lambda_role_1.txt +12 -0
- aimodelshare/json_templates/lambda_role_2.txt +16 -0
- aimodelshare/leaderboard.py +174 -0
- aimodelshare/main/1.txt +132 -0
- aimodelshare/main/1B.txt +112 -0
- aimodelshare/main/2.txt +153 -0
- aimodelshare/main/3.txt +134 -0
- aimodelshare/main/4.txt +128 -0
- aimodelshare/main/5.txt +109 -0
- aimodelshare/main/6.txt +105 -0
- aimodelshare/main/7.txt +144 -0
- aimodelshare/main/8.txt +142 -0
- aimodelshare/main/__init__.py +1 -0
- aimodelshare/main/authorization.txt +275 -0
- aimodelshare/main/eval_classification.txt +79 -0
- aimodelshare/main/eval_lambda.txt +1709 -0
- aimodelshare/main/eval_regression.txt +80 -0
- aimodelshare/main/lambda_function.txt +8 -0
- aimodelshare/main/nst.txt +149 -0
- aimodelshare/model.py +1543 -0
- aimodelshare/modeluser.py +215 -0
- aimodelshare/moral_compass/README.md +408 -0
- aimodelshare/moral_compass/__init__.py +65 -0
- aimodelshare/moral_compass/_version.py +3 -0
- aimodelshare/moral_compass/api_client.py +601 -0
- aimodelshare/moral_compass/apps/__init__.py +69 -0
- aimodelshare/moral_compass/apps/ai_consequences.py +540 -0
- aimodelshare/moral_compass/apps/bias_detective.py +714 -0
- aimodelshare/moral_compass/apps/ethical_revelation.py +898 -0
- aimodelshare/moral_compass/apps/fairness_fixer.py +889 -0
- aimodelshare/moral_compass/apps/judge.py +888 -0
- aimodelshare/moral_compass/apps/justice_equity_upgrade.py +853 -0
- aimodelshare/moral_compass/apps/mc_integration_helpers.py +820 -0
- aimodelshare/moral_compass/apps/model_building_game.py +1104 -0
- aimodelshare/moral_compass/apps/model_building_game_beginner.py +687 -0
- aimodelshare/moral_compass/apps/moral_compass_challenge.py +858 -0
- aimodelshare/moral_compass/apps/session_auth.py +254 -0
- aimodelshare/moral_compass/apps/shared_activity_styles.css +349 -0
- aimodelshare/moral_compass/apps/tutorial.py +481 -0
- aimodelshare/moral_compass/apps/what_is_ai.py +853 -0
- aimodelshare/moral_compass/challenge.py +365 -0
- aimodelshare/moral_compass/config.py +187 -0
- aimodelshare/placeholders/model.onnx +0 -0
- aimodelshare/placeholders/preprocessor.zip +0 -0
- aimodelshare/playground.py +1968 -0
- aimodelshare/postprocessormodules.py +157 -0
- aimodelshare/preprocessormodules.py +373 -0
- aimodelshare/pyspark/1.txt +195 -0
- aimodelshare/pyspark/1B.txt +181 -0
- aimodelshare/pyspark/2.txt +220 -0
- aimodelshare/pyspark/3.txt +204 -0
- aimodelshare/pyspark/4.txt +187 -0
- aimodelshare/pyspark/5.txt +178 -0
- aimodelshare/pyspark/6.txt +174 -0
- aimodelshare/pyspark/7.txt +211 -0
- aimodelshare/pyspark/8.txt +206 -0
- aimodelshare/pyspark/__init__.py +1 -0
- aimodelshare/pyspark/authorization.txt +258 -0
- aimodelshare/pyspark/eval_classification.txt +79 -0
- aimodelshare/pyspark/eval_lambda.txt +1441 -0
- aimodelshare/pyspark/eval_regression.txt +80 -0
- aimodelshare/pyspark/lambda_function.txt +8 -0
- aimodelshare/pyspark/nst.txt +213 -0
- aimodelshare/python/my_preprocessor.py +58 -0
- aimodelshare/readme.md +26 -0
- aimodelshare/reproducibility.py +181 -0
- aimodelshare/sam/Dockerfile.txt +8 -0
- aimodelshare/sam/Dockerfile_PySpark.txt +24 -0
- aimodelshare/sam/__init__.py +1 -0
- aimodelshare/sam/buildspec.txt +11 -0
- aimodelshare/sam/codebuild_policies.txt +129 -0
- aimodelshare/sam/codebuild_trust_relationship.txt +12 -0
- aimodelshare/sam/codepipeline_policies.txt +173 -0
- aimodelshare/sam/codepipeline_trust_relationship.txt +12 -0
- aimodelshare/sam/spark-class.txt +2 -0
- aimodelshare/sam/template.txt +54 -0
- aimodelshare/tools.py +103 -0
- aimodelshare/utils/__init__.py +78 -0
- aimodelshare/utils/optional_deps.py +38 -0
- aimodelshare/utils.py +57 -0
- aimodelshare-0.3.7.dist-info/METADATA +298 -0
- aimodelshare-0.3.7.dist-info/RECORD +171 -0
- aimodelshare-0.3.7.dist-info/WHEEL +5 -0
- aimodelshare-0.3.7.dist-info/licenses/LICENSE +5 -0
- aimodelshare-0.3.7.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,853 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Activity 9: Justice & Equity Upgrade - Gradio application for the Justice & Equity Challenge.
|
|
3
|
+
|
|
4
|
+
This app teaches:
|
|
5
|
+
1. Elevating fairness through accessibility and inclusion
|
|
6
|
+
2. Stakeholder engagement and community participation
|
|
7
|
+
3. Final Moral Compass score reveal and team leaderboard
|
|
8
|
+
4. Certificate unlock and challenge completion
|
|
9
|
+
|
|
10
|
+
Structure:
|
|
11
|
+
- Factory function `create_justice_equity_upgrade_app()` returns a Gradio Blocks object
|
|
12
|
+
- Convenience wrapper `launch_justice_equity_upgrade_app()` launches it inline (for notebooks)
|
|
13
|
+
|
|
14
|
+
Moral Compass Integration:
|
|
15
|
+
- Uses ChallengeManager for progress tracking (tasks A-F)
|
|
16
|
+
- Debounced sync prevents excessive API calls
|
|
17
|
+
- Team aggregation via synthetic team: username
|
|
18
|
+
- Force Sync button for manual refresh
|
|
19
|
+
"""
|
|
20
|
+
import contextlib
|
|
21
|
+
import os
|
|
22
|
+
import logging
|
|
23
|
+
|
|
24
|
+
# Import moral compass integration helpers
|
|
25
|
+
from .mc_integration_helpers import (
|
|
26
|
+
get_challenge_manager,
|
|
27
|
+
sync_user_moral_state,
|
|
28
|
+
sync_team_state,
|
|
29
|
+
build_moral_leaderboard_html,
|
|
30
|
+
get_moral_compass_widget_html,
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
logger = logging.getLogger("aimodelshare.moral_compass.apps.justice_equity_upgrade")
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def _get_user_stats():
|
|
37
|
+
"""Get user statistics for final score reveal."""
|
|
38
|
+
try:
|
|
39
|
+
username = os.environ.get("username")
|
|
40
|
+
team_name = os.environ.get("TEAM_NAME", "Unknown Team")
|
|
41
|
+
|
|
42
|
+
return {
|
|
43
|
+
"username": username or "Guest",
|
|
44
|
+
"team_name": team_name,
|
|
45
|
+
"is_signed_in": bool(username)
|
|
46
|
+
}
|
|
47
|
+
except Exception:
|
|
48
|
+
return {
|
|
49
|
+
"username": "Guest",
|
|
50
|
+
"team_name": "Unknown Team",
|
|
51
|
+
"is_signed_in": False
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def create_justice_equity_upgrade_app(theme_primary_hue: str = "indigo") -> "gr.Blocks":
|
|
56
|
+
"""Create the Justice & Equity Upgrade Gradio Blocks app (not launched yet)."""
|
|
57
|
+
try:
|
|
58
|
+
import gradio as gr
|
|
59
|
+
gr.close_all(verbose=False)
|
|
60
|
+
except ImportError as e:
|
|
61
|
+
raise ImportError(
|
|
62
|
+
"Gradio is required for the justice & equity upgrade app. Install with `pip install gradio`."
|
|
63
|
+
) from e
|
|
64
|
+
|
|
65
|
+
# Get user stats and initialize challenge manager
|
|
66
|
+
user_stats = _get_user_stats()
|
|
67
|
+
challenge_manager = None
|
|
68
|
+
if user_stats["is_signed_in"]:
|
|
69
|
+
challenge_manager = get_challenge_manager(user_stats["username"])
|
|
70
|
+
|
|
71
|
+
# Track state
|
|
72
|
+
moral_compass_points = {"value": 0}
|
|
73
|
+
server_moral_score = {"value": None}
|
|
74
|
+
is_synced = {"value": False}
|
|
75
|
+
accessibility_features = []
|
|
76
|
+
diversity_improvements = []
|
|
77
|
+
stakeholder_priorities = []
|
|
78
|
+
|
|
79
|
+
def sync_moral_state(override=False):
|
|
80
|
+
"""Sync moral state to server (debounced unless override)."""
|
|
81
|
+
if not challenge_manager:
|
|
82
|
+
return {
|
|
83
|
+
'widget_html': get_moral_compass_widget_html(
|
|
84
|
+
local_points=moral_compass_points["value"],
|
|
85
|
+
server_score=None,
|
|
86
|
+
is_synced=False
|
|
87
|
+
),
|
|
88
|
+
'status': 'Guest mode - sign in to sync'
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
# Mark task E (Accessibility) as completed
|
|
92
|
+
challenge_manager.complete_task('E')
|
|
93
|
+
|
|
94
|
+
# Sync to server
|
|
95
|
+
sync_result = sync_user_moral_state(
|
|
96
|
+
cm=challenge_manager,
|
|
97
|
+
moral_points=moral_compass_points["value"],
|
|
98
|
+
override=override
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
# Update state
|
|
102
|
+
if sync_result['synced']:
|
|
103
|
+
server_moral_score["value"] = sync_result.get('server_score')
|
|
104
|
+
is_synced["value"] = True
|
|
105
|
+
|
|
106
|
+
# Trigger team sync if user sync succeeded
|
|
107
|
+
if user_stats.get("team_name"):
|
|
108
|
+
sync_team_state(user_stats["team_name"])
|
|
109
|
+
|
|
110
|
+
# Generate widget HTML
|
|
111
|
+
widget_html = get_moral_compass_widget_html(
|
|
112
|
+
local_points=moral_compass_points["value"],
|
|
113
|
+
server_score=server_moral_score["value"],
|
|
114
|
+
is_synced=is_synced["value"]
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
return {
|
|
118
|
+
'widget_html': widget_html,
|
|
119
|
+
'status': sync_result['message']
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
def apply_accessibility_features(multilang, plaintext, screenreader):
|
|
123
|
+
"""Apply accessibility features."""
|
|
124
|
+
features_added = []
|
|
125
|
+
|
|
126
|
+
if multilang:
|
|
127
|
+
features_added.append("Multi-language support (Catalan, Spanish, English)")
|
|
128
|
+
accessibility_features.append("multilang")
|
|
129
|
+
|
|
130
|
+
if plaintext:
|
|
131
|
+
features_added.append("Plain text summaries for non-technical users")
|
|
132
|
+
accessibility_features.append("plaintext")
|
|
133
|
+
|
|
134
|
+
if screenreader:
|
|
135
|
+
features_added.append("Screen reader compatibility")
|
|
136
|
+
accessibility_features.append("screenreader")
|
|
137
|
+
|
|
138
|
+
if features_added:
|
|
139
|
+
moral_compass_points["value"] += 75
|
|
140
|
+
|
|
141
|
+
# Update ChallengeManager if available
|
|
142
|
+
if challenge_manager:
|
|
143
|
+
challenge_manager.answer_question('E', 'E1', 1) # Correct answer for accessibility task
|
|
144
|
+
|
|
145
|
+
report = "## Accessibility Features Applied\n\n"
|
|
146
|
+
for feature in features_added:
|
|
147
|
+
report += f"- ✓ {feature}\n"
|
|
148
|
+
report += f"\n**Impact:** These features ensure **equal opportunity of access** for all users, "
|
|
149
|
+
report += "regardless of language, technical background, or disability.\n\n"
|
|
150
|
+
report += "🏆 +75 Moral Compass points for improving accessibility!"
|
|
151
|
+
|
|
152
|
+
# Trigger sync
|
|
153
|
+
sync_result = sync_moral_state()
|
|
154
|
+
report += f"\n\n{sync_result['status']}"
|
|
155
|
+
else:
|
|
156
|
+
report = "Select accessibility features to apply."
|
|
157
|
+
|
|
158
|
+
return report
|
|
159
|
+
|
|
160
|
+
def apply_diversity_improvements(team_diversity, community_voices, diverse_review):
|
|
161
|
+
"""Apply diversity improvements."""
|
|
162
|
+
improvements = []
|
|
163
|
+
|
|
164
|
+
if team_diversity:
|
|
165
|
+
improvements.append("Diverse team composition (gender, ethnicity, background)")
|
|
166
|
+
diversity_improvements.append("team_diversity")
|
|
167
|
+
|
|
168
|
+
if community_voices:
|
|
169
|
+
improvements.append("Community advisory board with affected population representatives")
|
|
170
|
+
diversity_improvements.append("community_voices")
|
|
171
|
+
|
|
172
|
+
if diverse_review:
|
|
173
|
+
improvements.append("Diverse review panel for model evaluation")
|
|
174
|
+
diversity_improvements.append("diverse_review")
|
|
175
|
+
|
|
176
|
+
if improvements:
|
|
177
|
+
moral_compass_points["value"] += 100
|
|
178
|
+
|
|
179
|
+
# Update ChallengeManager if available
|
|
180
|
+
if challenge_manager:
|
|
181
|
+
challenge_manager.complete_task('F') # Diversity task
|
|
182
|
+
|
|
183
|
+
report = "## Diversity & Inclusion Improvements\n\n"
|
|
184
|
+
for improvement in improvements:
|
|
185
|
+
report += f"- ✓ {improvement}\n"
|
|
186
|
+
report += f"\n**Impact:** Diverse perspectives help identify blind spots and ensure the "
|
|
187
|
+
report += "system serves all communities fairly.\n\n"
|
|
188
|
+
report += "🏆 +100 Moral Compass points for advancing inclusion!"
|
|
189
|
+
|
|
190
|
+
# Trigger sync
|
|
191
|
+
sync_result = sync_moral_state()
|
|
192
|
+
report += f"\n\n{sync_result['status']}"
|
|
193
|
+
else:
|
|
194
|
+
report = "Select diversity improvements to apply."
|
|
195
|
+
|
|
196
|
+
return report
|
|
197
|
+
|
|
198
|
+
def visualize_improvements():
|
|
199
|
+
"""Show before/after comparison."""
|
|
200
|
+
report = """
|
|
201
|
+
## Before/After: System-Level Transformation
|
|
202
|
+
|
|
203
|
+
### Before (Original System)
|
|
204
|
+
- ❌ English-only interface
|
|
205
|
+
- ❌ Technical jargon throughout
|
|
206
|
+
- ❌ No accessibility accommodations
|
|
207
|
+
- ❌ Homogeneous development team
|
|
208
|
+
- ❌ No community input
|
|
209
|
+
- ❌ Decisions made in isolation
|
|
210
|
+
|
|
211
|
+
### After (Justice & Equity Upgrade)
|
|
212
|
+
"""
|
|
213
|
+
|
|
214
|
+
if "multilang" in accessibility_features:
|
|
215
|
+
report += "- ✅ Multi-language support\n"
|
|
216
|
+
if "plaintext" in accessibility_features:
|
|
217
|
+
report += "- ✅ Plain language explanations\n"
|
|
218
|
+
if "screenreader" in accessibility_features:
|
|
219
|
+
report += "- ✅ Screen reader compatibility\n"
|
|
220
|
+
if "team_diversity" in diversity_improvements:
|
|
221
|
+
report += "- ✅ Diverse development team\n"
|
|
222
|
+
if "community_voices" in diversity_improvements:
|
|
223
|
+
report += "- ✅ Community advisory board\n"
|
|
224
|
+
if "diverse_review" in diversity_improvements:
|
|
225
|
+
report += "- ✅ Inclusive review process\n"
|
|
226
|
+
|
|
227
|
+
if accessibility_features or diversity_improvements:
|
|
228
|
+
report += "\n**Result:** A more **inclusive, accessible, and just** AI system.\n"
|
|
229
|
+
else:
|
|
230
|
+
report += "\n*Apply accessibility and diversity improvements to see the transformation.*\n"
|
|
231
|
+
|
|
232
|
+
return report
|
|
233
|
+
|
|
234
|
+
def prioritize_stakeholders(judges_pri, defendants_pri, families_pri, community_pri, ngos_pri):
|
|
235
|
+
"""Check stakeholder prioritization."""
|
|
236
|
+
scoring = {
|
|
237
|
+
"Defendants": defendants_pri == "Critical",
|
|
238
|
+
"Community Advocates": community_pri == "Critical",
|
|
239
|
+
"Families": families_pri == "High",
|
|
240
|
+
"Judges": judges_pri == "High",
|
|
241
|
+
"NGOs": ngos_pri in ["High", "Medium"]
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
score = sum(scoring.values())
|
|
245
|
+
feedback = []
|
|
246
|
+
|
|
247
|
+
if scoring["Defendants"]:
|
|
248
|
+
feedback.append("✓ Defendants are critical - they're directly affected by decisions.")
|
|
249
|
+
else:
|
|
250
|
+
feedback.append("⚠️ Defendants should be 'Critical' - they're most impacted.")
|
|
251
|
+
|
|
252
|
+
if scoring["Community Advocates"]:
|
|
253
|
+
feedback.append("✓ Community Advocates are critical - they represent affected populations.")
|
|
254
|
+
else:
|
|
255
|
+
feedback.append("⚠️ Community Advocates should be 'Critical' - they ensure community voice.")
|
|
256
|
+
|
|
257
|
+
if scoring["Families"]:
|
|
258
|
+
feedback.append("✓ Families are highly important - they're indirectly affected.")
|
|
259
|
+
else:
|
|
260
|
+
feedback.append("⚠️ Families should be 'High' importance - they suffer consequences too.")
|
|
261
|
+
|
|
262
|
+
if scoring["Judges"]:
|
|
263
|
+
feedback.append("✓ Judges are highly important - they make final decisions.")
|
|
264
|
+
else:
|
|
265
|
+
feedback.append("⚠️ Judges should be 'High' importance - they're key decision makers.")
|
|
266
|
+
|
|
267
|
+
points = 0
|
|
268
|
+
if score >= 4:
|
|
269
|
+
points = 100
|
|
270
|
+
moral_compass_points["value"] += points
|
|
271
|
+
feedback.append(f"\n🎉 Excellent stakeholder prioritization!\n🏆 +{points} Moral Compass points!")
|
|
272
|
+
elif score >= 3:
|
|
273
|
+
points = 50
|
|
274
|
+
moral_compass_points["value"] += points
|
|
275
|
+
feedback.append(f"\n🏆 +{points} Moral Compass points!")
|
|
276
|
+
|
|
277
|
+
# Store prioritization
|
|
278
|
+
for stakeholder in ["Defendants", "Families", "Judges", "Community Advocates", "NGOs"]:
|
|
279
|
+
stakeholder_priorities.append(stakeholder)
|
|
280
|
+
|
|
281
|
+
# Update ChallengeManager if available (stakeholder engagement = task F)
|
|
282
|
+
if challenge_manager and score >= 3:
|
|
283
|
+
challenge_manager.answer_question('F', 'F1', 1)
|
|
284
|
+
|
|
285
|
+
explanation = "\n\n**Why certain groups are critical:**\n"
|
|
286
|
+
explanation += "- **Defendants & Community Advocates:** Directly affected by AI decisions\n"
|
|
287
|
+
explanation += "- **Families:** Bear consequences of incorrect predictions\n"
|
|
288
|
+
explanation += "- **Judges:** Need to trust the system they're using\n"
|
|
289
|
+
explanation += "- **NGOs:** Provide oversight and advocacy\n"
|
|
290
|
+
|
|
291
|
+
result = "\n".join(feedback) + explanation
|
|
292
|
+
|
|
293
|
+
# Trigger sync if points were awarded
|
|
294
|
+
if points > 0:
|
|
295
|
+
sync_result = sync_moral_state()
|
|
296
|
+
result += f"\n\n{sync_result['status']}"
|
|
297
|
+
|
|
298
|
+
return result
|
|
299
|
+
|
|
300
|
+
def check_stakeholder_question(answer):
|
|
301
|
+
"""Check stakeholder identification question."""
|
|
302
|
+
if answer == "Defendants and community members directly affected by the system":
|
|
303
|
+
moral_compass_points["value"] += 50
|
|
304
|
+
return "✓ Correct! Those directly affected by AI decisions must have a voice in system design and oversight.\n\n🏆 +50 Moral Compass points!"
|
|
305
|
+
else:
|
|
306
|
+
return "✗ Not quite. Think about who faces the real-world consequences of AI predictions."
|
|
307
|
+
|
|
308
|
+
def check_inclusion_question(answer):
|
|
309
|
+
"""Check inclusion definition question."""
|
|
310
|
+
if answer == "Actively involving diverse stakeholders in design, development, and oversight":
|
|
311
|
+
moral_compass_points["value"] += 50
|
|
312
|
+
return "✓ Correct! Inclusion means bringing diverse voices into the process, not just serving diverse populations.\n\n🏆 +50 Moral Compass points!"
|
|
313
|
+
else:
|
|
314
|
+
return "✗ Not quite. Inclusion is about participation and voice, not just access."
|
|
315
|
+
|
|
316
|
+
def reveal_final_score():
|
|
317
|
+
"""Reveal final Moral Compass score with growth visualization."""
|
|
318
|
+
user_stats = _get_user_stats()
|
|
319
|
+
total_score = moral_compass_points["value"]
|
|
320
|
+
|
|
321
|
+
# Simulated score progression through activities
|
|
322
|
+
activity7_score = min(400, int(total_score * 0.3))
|
|
323
|
+
activity8_score = min(800, int(total_score * 0.6))
|
|
324
|
+
activity9_score = total_score
|
|
325
|
+
|
|
326
|
+
report = f"""
|
|
327
|
+
# 🎊 Final Moral Compass Score Reveal
|
|
328
|
+
|
|
329
|
+
## Your Justice & Equity Journey
|
|
330
|
+
|
|
331
|
+
### Score Progression
|
|
332
|
+
- **Activity 7 (Bias Detective):** {activity7_score} points
|
|
333
|
+
- **Activity 8 (Fairness Fixer):** {activity8_score} points
|
|
334
|
+
- **Activity 9 (Justice & Equity Upgrade):** {activity9_score} points
|
|
335
|
+
|
|
336
|
+
### Total Moral Compass Score: {total_score} points
|
|
337
|
+
|
|
338
|
+
---
|
|
339
|
+
|
|
340
|
+
## 🏆 Achievement Unlocked: **Justice & Equity Champion**
|
|
341
|
+
|
|
342
|
+
You've demonstrated mastery of:
|
|
343
|
+
- ✅ Expert fairness frameworks (OEIAC)
|
|
344
|
+
- ✅ Bias detection and diagnosis
|
|
345
|
+
- ✅ Technical fairness interventions
|
|
346
|
+
- ✅ Representative data strategies
|
|
347
|
+
- ✅ Accessibility and inclusion
|
|
348
|
+
- ✅ Stakeholder engagement
|
|
349
|
+
|
|
350
|
+
---
|
|
351
|
+
|
|
352
|
+
## Team Leaderboard
|
|
353
|
+
"""
|
|
354
|
+
|
|
355
|
+
if user_stats["is_signed_in"]:
|
|
356
|
+
report += f"""
|
|
357
|
+
**Your Team:** {user_stats["team_name"]}
|
|
358
|
+
**Username:** {user_stats["username"]}
|
|
359
|
+
**Your Score:** {total_score} points
|
|
360
|
+
|
|
361
|
+
*Check the full leaderboard in the Model Building Game app to see team rankings!*
|
|
362
|
+
"""
|
|
363
|
+
else:
|
|
364
|
+
report += """
|
|
365
|
+
*Sign in to see your team ranking and compete on the leaderboard!*
|
|
366
|
+
"""
|
|
367
|
+
|
|
368
|
+
report += """
|
|
369
|
+
---
|
|
370
|
+
|
|
371
|
+
## 🎖️ Badge Earned
|
|
372
|
+
|
|
373
|
+
**Justice & Equity Champion**
|
|
374
|
+
|
|
375
|
+
*Awarded for completing Activities 7, 8, and 9 with demonstrated understanding
|
|
376
|
+
of fairness principles, technical fixes, and systemic improvements.*
|
|
377
|
+
"""
|
|
378
|
+
|
|
379
|
+
return report
|
|
380
|
+
|
|
381
|
+
def generate_completion_certificate():
|
|
382
|
+
"""Generate completion message with certificate unlock."""
|
|
383
|
+
user_stats = _get_user_stats()
|
|
384
|
+
|
|
385
|
+
certificate = f"""
|
|
386
|
+
# 🎓 Certificate of Completion
|
|
387
|
+
|
|
388
|
+
## Ethics at Play: Justice & Equity Challenge
|
|
389
|
+
|
|
390
|
+
**This certifies that**
|
|
391
|
+
|
|
392
|
+
### {user_stats["username"]}
|
|
393
|
+
|
|
394
|
+
**has successfully completed Activities 7, 8, and 9:**
|
|
395
|
+
|
|
396
|
+
- 🕵️ **Bias Detective:** Diagnosed bias in AI systems using expert frameworks
|
|
397
|
+
- 🔧 **Fairness Fixer:** Applied technical fairness interventions
|
|
398
|
+
- 🌟 **Justice & Equity Upgrade:** Elevated the system through inclusion and accessibility
|
|
399
|
+
|
|
400
|
+
**Final Moral Compass Score:** {moral_compass_points["value"]} points
|
|
401
|
+
|
|
402
|
+
**Team:** {user_stats["team_name"]}
|
|
403
|
+
|
|
404
|
+
---
|
|
405
|
+
|
|
406
|
+
### Skills Demonstrated:
|
|
407
|
+
- Expert fairness evaluation (OEIAC framework)
|
|
408
|
+
- Demographic bias identification
|
|
409
|
+
- Group-level disparity analysis
|
|
410
|
+
- Feature and proxy removal
|
|
411
|
+
- Representative data strategy
|
|
412
|
+
- Continuous improvement planning
|
|
413
|
+
- Accessibility enhancement
|
|
414
|
+
- Stakeholder engagement
|
|
415
|
+
|
|
416
|
+
**Date Completed:** [Auto-generated in production]
|
|
417
|
+
|
|
418
|
+
---
|
|
419
|
+
|
|
420
|
+
### Next Steps:
|
|
421
|
+
Proceed to **Section 10** to continue your Ethics at Play journey!
|
|
422
|
+
"""
|
|
423
|
+
|
|
424
|
+
return certificate
|
|
425
|
+
|
|
426
|
+
# Create the Gradio app
|
|
427
|
+
with gr.Blocks(
|
|
428
|
+
title="Activity 9: Justice & Equity Upgrade",
|
|
429
|
+
theme=gr.themes.Soft(primary_hue=theme_primary_hue)
|
|
430
|
+
) as app:
|
|
431
|
+
gr.Markdown("# 🌟 Activity 9: Justice & Equity Upgrade")
|
|
432
|
+
gr.Markdown(
|
|
433
|
+
"""
|
|
434
|
+
**Objective:** Elevate fairness improvements by addressing inclusion, accessibility,
|
|
435
|
+
stakeholder engagement, and structural justice.
|
|
436
|
+
|
|
437
|
+
**Your Role:** You're now a **Justice Architect**.
|
|
438
|
+
|
|
439
|
+
**Progress:** Activity 9 of 10 — Elevate the System
|
|
440
|
+
|
|
441
|
+
**Estimated Time:** 8–10 minutes
|
|
442
|
+
"""
|
|
443
|
+
)
|
|
444
|
+
|
|
445
|
+
# Moral Compass widget with Force Sync
|
|
446
|
+
with gr.Row():
|
|
447
|
+
with gr.Column(scale=3):
|
|
448
|
+
moral_compass_display = gr.HTML(
|
|
449
|
+
get_moral_compass_widget_html(
|
|
450
|
+
local_points=0,
|
|
451
|
+
server_score=None,
|
|
452
|
+
is_synced=False
|
|
453
|
+
)
|
|
454
|
+
)
|
|
455
|
+
with gr.Column(scale=1):
|
|
456
|
+
force_sync_btn = gr.Button("Force Sync", variant="secondary", size="sm")
|
|
457
|
+
sync_status = gr.Markdown("")
|
|
458
|
+
|
|
459
|
+
# Force Sync handler
|
|
460
|
+
def handle_force_sync():
|
|
461
|
+
sync_result = sync_moral_state(override=True)
|
|
462
|
+
return sync_result['widget_html'], sync_result['status']
|
|
463
|
+
|
|
464
|
+
force_sync_btn.click(
|
|
465
|
+
fn=handle_force_sync,
|
|
466
|
+
outputs=[moral_compass_display, sync_status]
|
|
467
|
+
)
|
|
468
|
+
|
|
469
|
+
gr.Markdown(
|
|
470
|
+
"""
|
|
471
|
+
### Quick Recap
|
|
472
|
+
|
|
473
|
+
In Activities 7 & 8, you addressed **technical fairness**:
|
|
474
|
+
- Removed biased features
|
|
475
|
+
- Eliminated proxy variables
|
|
476
|
+
- Created representative data guidelines
|
|
477
|
+
|
|
478
|
+
Now, let's elevate to **systemic justice** through inclusion and accessibility.
|
|
479
|
+
"""
|
|
480
|
+
)
|
|
481
|
+
|
|
482
|
+
# Section 9.2: Access & Inclusion Makeover
|
|
483
|
+
with gr.Tab("9.2 Access & Inclusion"):
|
|
484
|
+
gr.Markdown(
|
|
485
|
+
"""
|
|
486
|
+
## Access & Inclusion Makeover
|
|
487
|
+
|
|
488
|
+
**Principles:**
|
|
489
|
+
- **Equal Opportunity of Access:** Everyone can use the system
|
|
490
|
+
- **Inclusion and Diversity:** Diverse voices shape the system
|
|
491
|
+
|
|
492
|
+
### 📚 Real-World Example: Court Interface Multilanguage Support
|
|
493
|
+
|
|
494
|
+
<details>
|
|
495
|
+
<summary><b>Click to expand: Barcelona Court System Case Study</b></summary>
|
|
496
|
+
|
|
497
|
+
**Scenario:** A court in Barcelona implemented an AI risk assessment tool but provided
|
|
498
|
+
the interface only in Spanish.
|
|
499
|
+
|
|
500
|
+
**Problem:**
|
|
501
|
+
- Many defendants spoke primarily Catalan or were immigrants with limited Spanish
|
|
502
|
+
- Unable to understand the AI's reasoning or contest decisions
|
|
503
|
+
- Violated equal access principles
|
|
504
|
+
|
|
505
|
+
**Solution:**
|
|
506
|
+
- Added Catalan, Spanish, and English interfaces
|
|
507
|
+
- Included plain-language summaries of technical terms
|
|
508
|
+
- Provided audio explanations for low-literacy users
|
|
509
|
+
|
|
510
|
+
**Outcome:**
|
|
511
|
+
- 40% increase in defendants able to understand their risk scores
|
|
512
|
+
- Reduced appeals due to miscommunication
|
|
513
|
+
- Improved trust in the justice system
|
|
514
|
+
|
|
515
|
+
</details>
|
|
516
|
+
|
|
517
|
+
---
|
|
518
|
+
|
|
519
|
+
### Accessibility Features
|
|
520
|
+
|
|
521
|
+
Select features to add:
|
|
522
|
+
"""
|
|
523
|
+
)
|
|
524
|
+
|
|
525
|
+
multilang_toggle = gr.Checkbox(label="Multi-language support (Catalan, Spanish, English)", value=False)
|
|
526
|
+
plaintext_toggle = gr.Checkbox(label="Plain text summaries (non-technical language)", value=False)
|
|
527
|
+
screenreader_toggle = gr.Checkbox(label="Screen reader compatibility", value=False)
|
|
528
|
+
|
|
529
|
+
accessibility_btn = gr.Button("Apply Accessibility Features", variant="primary")
|
|
530
|
+
accessibility_output = gr.Markdown("")
|
|
531
|
+
|
|
532
|
+
def update_widget_after_accessibility(multilang, plaintext, screenreader):
|
|
533
|
+
result = apply_accessibility_features(multilang, plaintext, screenreader)
|
|
534
|
+
widget_html = get_moral_compass_widget_html(
|
|
535
|
+
local_points=moral_compass_points["value"],
|
|
536
|
+
server_score=server_moral_score["value"],
|
|
537
|
+
is_synced=is_synced["value"]
|
|
538
|
+
)
|
|
539
|
+
return result, widget_html
|
|
540
|
+
|
|
541
|
+
accessibility_btn.click(
|
|
542
|
+
fn=update_widget_after_accessibility,
|
|
543
|
+
inputs=[multilang_toggle, plaintext_toggle, screenreader_toggle],
|
|
544
|
+
outputs=[accessibility_output, moral_compass_display]
|
|
545
|
+
)
|
|
546
|
+
|
|
547
|
+
gr.Markdown(
|
|
548
|
+
"""
|
|
549
|
+
### Diversity & Inclusion
|
|
550
|
+
|
|
551
|
+
### 📚 Case Study: Homogeneous vs Diverse Design Reviews
|
|
552
|
+
|
|
553
|
+
<details>
|
|
554
|
+
<summary><b>Click to expand: Impact of Team Diversity</b></summary>
|
|
555
|
+
|
|
556
|
+
**Scenario A - Homogeneous Team:**
|
|
557
|
+
- 5 data scientists, all from same demographic background
|
|
558
|
+
- Reviewed pretrial risk model
|
|
559
|
+
- Found model "looks good" - high accuracy on test set
|
|
560
|
+
- Deployed to production
|
|
561
|
+
|
|
562
|
+
**Result:**
|
|
563
|
+
- Within 3 months, community advocates identified severe racial bias
|
|
564
|
+
- Model was over-predicting risk for minority defendants
|
|
565
|
+
- Legal challenges filed; model withdrawn
|
|
566
|
+
|
|
567
|
+
**Scenario B - Diverse Team:**
|
|
568
|
+
- Same 5 data scientists + 3 community advocates + 2 affected individuals + 1 civil rights lawyer
|
|
569
|
+
- Reviewed same pretrial risk model
|
|
570
|
+
- Identified 7 potential fairness issues before deployment
|
|
571
|
+
|
|
572
|
+
**Result:**
|
|
573
|
+
- Addressed bias in training data
|
|
574
|
+
- Removed problematic proxy features
|
|
575
|
+
- Added fairness constraints
|
|
576
|
+
- Successful deployment with ongoing monitoring
|
|
577
|
+
|
|
578
|
+
**Lesson:** Diverse perspectives catch blind spots that homogeneous teams miss.
|
|
579
|
+
|
|
580
|
+
</details>
|
|
581
|
+
|
|
582
|
+
---
|
|
583
|
+
"""
|
|
584
|
+
)
|
|
585
|
+
|
|
586
|
+
team_diversity_toggle = gr.Checkbox(label="Diverse team composition (gender, ethnicity, expertise)", value=False)
|
|
587
|
+
community_toggle = gr.Checkbox(label="Community advisory board", value=False)
|
|
588
|
+
review_diversity_toggle = gr.Checkbox(label="Diverse review panel", value=False)
|
|
589
|
+
|
|
590
|
+
diversity_btn = gr.Button("Apply Diversity Improvements", variant="primary")
|
|
591
|
+
diversity_output = gr.Markdown("")
|
|
592
|
+
|
|
593
|
+
def update_widget_after_diversity(team_diversity, community_voices, diverse_review):
|
|
594
|
+
result = apply_diversity_improvements(team_diversity, community_voices, diverse_review)
|
|
595
|
+
widget_html = get_moral_compass_widget_html(
|
|
596
|
+
local_points=moral_compass_points["value"],
|
|
597
|
+
server_score=server_moral_score["value"],
|
|
598
|
+
is_synced=is_synced["value"]
|
|
599
|
+
)
|
|
600
|
+
return result, widget_html
|
|
601
|
+
|
|
602
|
+
diversity_btn.click(
|
|
603
|
+
fn=update_widget_after_diversity,
|
|
604
|
+
inputs=[team_diversity_toggle, community_toggle, review_diversity_toggle],
|
|
605
|
+
outputs=[diversity_output, moral_compass_display]
|
|
606
|
+
)
|
|
607
|
+
|
|
608
|
+
gr.Markdown("### Before/After Comparison")
|
|
609
|
+
|
|
610
|
+
compare_btn = gr.Button("Show System Transformation", variant="secondary")
|
|
611
|
+
compare_output = gr.Markdown("")
|
|
612
|
+
|
|
613
|
+
compare_btn.click(
|
|
614
|
+
fn=visualize_improvements,
|
|
615
|
+
outputs=compare_output
|
|
616
|
+
)
|
|
617
|
+
|
|
618
|
+
# Section 9.3: Stakeholder Mapping
|
|
619
|
+
with gr.Tab("9.3 Stakeholder Mapping"):
|
|
620
|
+
gr.Markdown(
|
|
621
|
+
"""
|
|
622
|
+
## Stakeholder Prioritization Map
|
|
623
|
+
|
|
624
|
+
**Principle:** Affected community members must have a voice.
|
|
625
|
+
|
|
626
|
+
### 📊 Stakeholder Analysis Framework
|
|
627
|
+
|
|
628
|
+
<details>
|
|
629
|
+
<summary><b>Click to expand: Power vs Impact vs Voice Matrix</b></summary>
|
|
630
|
+
|
|
631
|
+
| Stakeholder Group | Power* | Impact** | Voice*** | Priority |
|
|
632
|
+
|-------------------|--------|----------|----------|----------|
|
|
633
|
+
| **Defendants** | Low | High | Low | **CRITICAL** |
|
|
634
|
+
| **Community Advocates** | Medium | High | Medium | **CRITICAL** |
|
|
635
|
+
| **Families** | Low | High | Low | **HIGH** |
|
|
636
|
+
| **Judges** | High | Medium | High | **HIGH** |
|
|
637
|
+
| **Data Scientists** | Medium | Low | High | **MEDIUM** |
|
|
638
|
+
| **NGOs** | Medium | Medium | Medium | **HIGH** |
|
|
639
|
+
| **System Administrators** | Medium | Low | Medium | **MEDIUM** |
|
|
640
|
+
|
|
641
|
+
*Power = ability to influence system design
|
|
642
|
+
**Impact = how much they're affected by system decisions
|
|
643
|
+
***Voice = current representation in decision-making
|
|
644
|
+
|
|
645
|
+
**Key Insight:** Those with **high impact but low voice** (defendants, families)
|
|
646
|
+
must be prioritized to achieve justice.
|
|
647
|
+
|
|
648
|
+
</details>
|
|
649
|
+
|
|
650
|
+
---
|
|
651
|
+
|
|
652
|
+
### Exercise: Prioritize Stakeholders
|
|
653
|
+
|
|
654
|
+
Assign each stakeholder to the appropriate priority level:
|
|
655
|
+
- **Critical:** Must be involved in all decisions
|
|
656
|
+
- **High:** Important voice in major decisions
|
|
657
|
+
- **Medium:** Should be consulted periodically
|
|
658
|
+
"""
|
|
659
|
+
)
|
|
660
|
+
|
|
661
|
+
judges_priority = gr.Radio(
|
|
662
|
+
choices=["Critical", "High", "Medium"],
|
|
663
|
+
label="Judges (use the system to make decisions):",
|
|
664
|
+
value=None
|
|
665
|
+
)
|
|
666
|
+
defendants_priority = gr.Radio(
|
|
667
|
+
choices=["Critical", "High", "Medium"],
|
|
668
|
+
label="Defendants (directly affected by predictions):",
|
|
669
|
+
value=None
|
|
670
|
+
)
|
|
671
|
+
families_priority = gr.Radio(
|
|
672
|
+
choices=["Critical", "High", "Medium"],
|
|
673
|
+
label="Families (indirectly affected):",
|
|
674
|
+
value=None
|
|
675
|
+
)
|
|
676
|
+
community_priority = gr.Radio(
|
|
677
|
+
choices=["Critical", "High", "Medium"],
|
|
678
|
+
label="Community Advocates (represent affected populations):",
|
|
679
|
+
value=None
|
|
680
|
+
)
|
|
681
|
+
ngos_priority = gr.Radio(
|
|
682
|
+
choices=["Critical", "High", "Medium"],
|
|
683
|
+
label="NGOs (provide oversight):",
|
|
684
|
+
value=None
|
|
685
|
+
)
|
|
686
|
+
|
|
687
|
+
stakeholder_btn = gr.Button("Submit Prioritization", variant="primary")
|
|
688
|
+
stakeholder_output = gr.Markdown("")
|
|
689
|
+
|
|
690
|
+
stakeholder_btn.click(
|
|
691
|
+
fn=prioritize_stakeholders,
|
|
692
|
+
inputs=[judges_priority, defendants_priority, families_priority, community_priority, ngos_priority],
|
|
693
|
+
outputs=stakeholder_output
|
|
694
|
+
).then(
|
|
695
|
+
fn=lambda: f"## 🧭 Moral Compass Score: {moral_compass_points['value']} points",
|
|
696
|
+
outputs=moral_compass_display
|
|
697
|
+
)
|
|
698
|
+
|
|
699
|
+
gr.Markdown("### Check-In Questions")
|
|
700
|
+
|
|
701
|
+
stakeholder_question = gr.Radio(
|
|
702
|
+
choices=[
|
|
703
|
+
"Technical experts and data scientists",
|
|
704
|
+
"Government officials and administrators",
|
|
705
|
+
"Defendants and community members directly affected by the system",
|
|
706
|
+
"Only judges who use the system"
|
|
707
|
+
],
|
|
708
|
+
label="Who should have the strongest voice in AI criminal justice systems?",
|
|
709
|
+
value=None
|
|
710
|
+
)
|
|
711
|
+
stakeholder_check_btn = gr.Button("Check Answer")
|
|
712
|
+
stakeholder_feedback = gr.Markdown("")
|
|
713
|
+
|
|
714
|
+
stakeholder_check_btn.click(
|
|
715
|
+
fn=check_stakeholder_question,
|
|
716
|
+
inputs=stakeholder_question,
|
|
717
|
+
outputs=stakeholder_feedback
|
|
718
|
+
).then(
|
|
719
|
+
fn=lambda: f"## 🧭 Moral Compass Score: {moral_compass_points['value']} points",
|
|
720
|
+
outputs=moral_compass_display
|
|
721
|
+
)
|
|
722
|
+
|
|
723
|
+
inclusion_question = gr.Radio(
|
|
724
|
+
choices=[
|
|
725
|
+
"Making sure the system works for everyone",
|
|
726
|
+
"Hiring diverse employees",
|
|
727
|
+
"Actively involving diverse stakeholders in design, development, and oversight",
|
|
728
|
+
"Translating the interface into multiple languages"
|
|
729
|
+
],
|
|
730
|
+
label="What does 'Inclusion' mean in the context of AI ethics?",
|
|
731
|
+
value=None
|
|
732
|
+
)
|
|
733
|
+
inclusion_check_btn = gr.Button("Check Answer")
|
|
734
|
+
inclusion_feedback = gr.Markdown("")
|
|
735
|
+
|
|
736
|
+
inclusion_check_btn.click(
|
|
737
|
+
fn=check_inclusion_question,
|
|
738
|
+
inputs=inclusion_question,
|
|
739
|
+
outputs=inclusion_feedback
|
|
740
|
+
).then(
|
|
741
|
+
fn=lambda: f"## 🧭 Moral Compass Score: {moral_compass_points['value']} points",
|
|
742
|
+
outputs=moral_compass_display
|
|
743
|
+
)
|
|
744
|
+
|
|
745
|
+
# Section 9.4: Final Score Reveal
|
|
746
|
+
with gr.Tab("9.4 Final Score"):
|
|
747
|
+
gr.Markdown(
|
|
748
|
+
"""
|
|
749
|
+
## 🎊 Final Moral Compass Score Reveal
|
|
750
|
+
|
|
751
|
+
See how you've grown from the start of Section 7 to now!
|
|
752
|
+
"""
|
|
753
|
+
)
|
|
754
|
+
|
|
755
|
+
reveal_btn = gr.Button("Reveal My Final Score", variant="primary", size="lg")
|
|
756
|
+
score_output = gr.Markdown("")
|
|
757
|
+
|
|
758
|
+
reveal_btn.click(
|
|
759
|
+
fn=reveal_final_score,
|
|
760
|
+
outputs=score_output
|
|
761
|
+
)
|
|
762
|
+
|
|
763
|
+
# Ethics Leaderboard Tab
|
|
764
|
+
with gr.Tab("Ethics Leaderboard"):
|
|
765
|
+
gr.Markdown(
|
|
766
|
+
"""
|
|
767
|
+
## 🏆 Ethics Leaderboard
|
|
768
|
+
|
|
769
|
+
This leaderboard shows **combined ethical engagement + performance scores**,
|
|
770
|
+
different from the Model Building Game's accuracy-only leaderboard.
|
|
771
|
+
|
|
772
|
+
**What's measured:**
|
|
773
|
+
- Your moral compass points (ethical decision-making)
|
|
774
|
+
- Your model accuracy (technical performance)
|
|
775
|
+
- Combined score = accuracy × normalized_moral_points
|
|
776
|
+
|
|
777
|
+
**Difference from Model Game Leaderboard:**
|
|
778
|
+
- Model Game: Pure accuracy/performance
|
|
779
|
+
- Ethics Leaderboard: Holistic score (ethics + accuracy)
|
|
780
|
+
"""
|
|
781
|
+
)
|
|
782
|
+
|
|
783
|
+
leaderboard_display = gr.HTML("")
|
|
784
|
+
refresh_leaderboard_btn = gr.Button("Refresh Leaderboard", variant="secondary")
|
|
785
|
+
|
|
786
|
+
def load_leaderboard():
|
|
787
|
+
return build_moral_leaderboard_html(
|
|
788
|
+
highlight_username=user_stats.get("username"),
|
|
789
|
+
include_teams=True
|
|
790
|
+
)
|
|
791
|
+
|
|
792
|
+
# Load on tab open
|
|
793
|
+
refresh_leaderboard_btn.click(
|
|
794
|
+
fn=load_leaderboard,
|
|
795
|
+
outputs=leaderboard_display
|
|
796
|
+
)
|
|
797
|
+
|
|
798
|
+
# Also load initially
|
|
799
|
+
app.load(fn=load_leaderboard, outputs=leaderboard_display)
|
|
800
|
+
|
|
801
|
+
# Section 9.5: Completion
|
|
802
|
+
with gr.Tab("9.5 Completion"):
|
|
803
|
+
gr.Markdown(
|
|
804
|
+
"""
|
|
805
|
+
## 🎓 Activity 9 Complete!
|
|
806
|
+
|
|
807
|
+
Generate your completion certificate and unlock the next section.
|
|
808
|
+
"""
|
|
809
|
+
)
|
|
810
|
+
|
|
811
|
+
certificate_btn = gr.Button("Generate Certificate", variant="primary", size="lg")
|
|
812
|
+
certificate_output = gr.Markdown("")
|
|
813
|
+
|
|
814
|
+
certificate_btn.click(
|
|
815
|
+
fn=generate_completion_certificate,
|
|
816
|
+
outputs=certificate_output
|
|
817
|
+
)
|
|
818
|
+
|
|
819
|
+
gr.Markdown(
|
|
820
|
+
"""
|
|
821
|
+
---
|
|
822
|
+
|
|
823
|
+
### 🎉 Congratulations!
|
|
824
|
+
|
|
825
|
+
You've completed the **Justice & Equity Challenge** (Activities 7, 8, and 9).
|
|
826
|
+
|
|
827
|
+
**What you've learned:**
|
|
828
|
+
- How to diagnose bias using expert frameworks
|
|
829
|
+
- Technical fairness interventions
|
|
830
|
+
- Representative data strategies
|
|
831
|
+
- Accessibility and inclusion principles
|
|
832
|
+
- Stakeholder engagement best practices
|
|
833
|
+
|
|
834
|
+
**Next:** Continue to **Section 10** to complete your Ethics at Play journey!
|
|
835
|
+
"""
|
|
836
|
+
)
|
|
837
|
+
|
|
838
|
+
return app
|
|
839
|
+
|
|
840
|
+
|
|
841
|
+
def launch_justice_equity_upgrade_app(
|
|
842
|
+
share: bool = False,
|
|
843
|
+
server_name: str = None,
|
|
844
|
+
server_port: int = None,
|
|
845
|
+
theme_primary_hue: str = "indigo"
|
|
846
|
+
) -> None:
|
|
847
|
+
"""Convenience wrapper to create and launch the justice & equity upgrade app inline."""
|
|
848
|
+
app = create_justice_equity_upgrade_app(theme_primary_hue=theme_primary_hue)
|
|
849
|
+
# Use provided values or fall back to PORT env var and 0.0.0.0
|
|
850
|
+
|
|
851
|
+
if server_port is None:
|
|
852
|
+
server_port = int(os.environ.get("PORT", 8080))
|
|
853
|
+
app.launch(share=share, server_port=server_port)
|