aimodelshare 0.3.7__py3-none-any.whl → 0.4.71__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/moral_compass/__init__.py +51 -2
- aimodelshare/moral_compass/api_client.py +92 -4
- aimodelshare/moral_compass/apps/__init__.py +36 -16
- aimodelshare/moral_compass/apps/ai_consequences.py +98 -88
- aimodelshare/moral_compass/apps/bias_detective_ca.py +2722 -0
- aimodelshare/moral_compass/apps/bias_detective_en.py +2722 -0
- aimodelshare/moral_compass/apps/bias_detective_part1.py +2722 -0
- aimodelshare/moral_compass/apps/bias_detective_part2.py +2465 -0
- aimodelshare/moral_compass/apps/bias_detective_part_es.py +2722 -0
- aimodelshare/moral_compass/apps/ethical_revelation.py +237 -147
- aimodelshare/moral_compass/apps/fairness_fixer.py +1839 -859
- aimodelshare/moral_compass/apps/fairness_fixer_ca.py +1869 -0
- aimodelshare/moral_compass/apps/fairness_fixer_en.py +1869 -0
- aimodelshare/moral_compass/apps/fairness_fixer_es.py +1869 -0
- aimodelshare/moral_compass/apps/judge.py +130 -143
- aimodelshare/moral_compass/apps/justice_equity_upgrade.py +793 -831
- aimodelshare/moral_compass/apps/justice_equity_upgrade_ca.py +815 -0
- aimodelshare/moral_compass/apps/justice_equity_upgrade_en.py +815 -0
- aimodelshare/moral_compass/apps/justice_equity_upgrade_es.py +815 -0
- aimodelshare/moral_compass/apps/mc_integration_helpers.py +227 -745
- aimodelshare/moral_compass/apps/model_building_app_ca.py +4544 -0
- aimodelshare/moral_compass/apps/model_building_app_ca_final.py +3899 -0
- aimodelshare/moral_compass/apps/model_building_app_en.py +4290 -0
- aimodelshare/moral_compass/apps/model_building_app_en_final.py +3869 -0
- aimodelshare/moral_compass/apps/model_building_app_es.py +4362 -0
- aimodelshare/moral_compass/apps/model_building_app_es_final.py +3899 -0
- aimodelshare/moral_compass/apps/model_building_game.py +4211 -935
- aimodelshare/moral_compass/apps/moral_compass_challenge.py +195 -95
- aimodelshare/moral_compass/apps/what_is_ai.py +126 -117
- aimodelshare/moral_compass/challenge.py +98 -17
- {aimodelshare-0.3.7.dist-info → aimodelshare-0.4.71.dist-info}/METADATA +1 -1
- {aimodelshare-0.3.7.dist-info → aimodelshare-0.4.71.dist-info}/RECORD +35 -19
- aimodelshare/moral_compass/apps/bias_detective.py +0 -714
- {aimodelshare-0.3.7.dist-info → aimodelshare-0.4.71.dist-info}/WHEEL +0 -0
- {aimodelshare-0.3.7.dist-info → aimodelshare-0.4.71.dist-info}/licenses/LICENSE +0 -0
- {aimodelshare-0.3.7.dist-info → aimodelshare-0.4.71.dist-info}/top_level.txt +0 -0
|
@@ -8,7 +8,7 @@ import random
|
|
|
8
8
|
import time
|
|
9
9
|
import threading
|
|
10
10
|
from typing import Optional, Dict, Any, Tuple
|
|
11
|
-
|
|
11
|
+
from functools import lru_cache
|
|
12
12
|
import gradio as gr
|
|
13
13
|
import pandas as pd
|
|
14
14
|
|
|
@@ -32,6 +32,35 @@ TEAM_NAMES = [
|
|
|
32
32
|
"The Ethical Explorers", "The Fairness Finders", "The Accuracy Avengers"
|
|
33
33
|
]
|
|
34
34
|
|
|
35
|
+
# NEW: Team name translations for UI display only
|
|
36
|
+
# Internal logic (ranking, caching, grouping) always uses canonical English names
|
|
37
|
+
TEAM_NAME_TRANSLATIONS = {
|
|
38
|
+
"en": {
|
|
39
|
+
"The Justice League": "The Justice League",
|
|
40
|
+
"The Moral Champions": "The Moral Champions",
|
|
41
|
+
"The Data Detectives": "The Data Detectives",
|
|
42
|
+
"The Ethical Explorers": "The Ethical Explorers",
|
|
43
|
+
"The Fairness Finders": "The Fairness Finders",
|
|
44
|
+
"The Accuracy Avengers": "The Accuracy Avengers"
|
|
45
|
+
},
|
|
46
|
+
"es": {
|
|
47
|
+
"The Justice League": "La Liga de la Justicia",
|
|
48
|
+
"The Moral Champions": "Los Campeones Morales",
|
|
49
|
+
"The Data Detectives": "Los Detectives de Datos",
|
|
50
|
+
"The Ethical Explorers": "Los Exploradores Éticos",
|
|
51
|
+
"The Fairness Finders": "Los Buscadores de Equidad",
|
|
52
|
+
"The Accuracy Avengers": "Los Vengadores de Precisión"
|
|
53
|
+
},
|
|
54
|
+
"ca": {
|
|
55
|
+
"The Justice League": "La Lliga de la Justícia",
|
|
56
|
+
"The Moral Champions": "Els Campions Morals",
|
|
57
|
+
"The Data Detectives": "Els Detectives de Dades",
|
|
58
|
+
"The Ethical Explorers": "Els Exploradors Ètics",
|
|
59
|
+
"The Fairness Finders": "Els Cercadors d'Equitat",
|
|
60
|
+
"The Accuracy Avengers": "Els Venjadors de Precisió"
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
35
64
|
# ---------------------------------------------------------------------------
|
|
36
65
|
# In-memory caches
|
|
37
66
|
# ---------------------------------------------------------------------------
|
|
@@ -51,7 +80,7 @@ TRANSLATIONS = {
|
|
|
51
80
|
"loading_session": "🔒 Loading your session...",
|
|
52
81
|
# Step 1 (Standing)
|
|
53
82
|
"s1_title_auth": "You've Built an Accurate Model",
|
|
54
|
-
"s1_sub_auth": "
|
|
83
|
+
"s1_sub_auth": "By experimenting and refining your model, you've achieved impressive results:",
|
|
55
84
|
"lbl_best_acc": "Your Best Accuracy",
|
|
56
85
|
"lbl_ind_rank": "Your Individual Rank",
|
|
57
86
|
"lbl_team": "Your Team",
|
|
@@ -78,7 +107,7 @@ TRANSLATIONS = {
|
|
|
78
107
|
"s2_box_emph_head": "This score measures only <strong>one dimension</strong> of success.",
|
|
79
108
|
"s2_box_emph_text": "It's time to add a second, equally important dimension: <strong class='emph-fairness'>Ethics</strong>.",
|
|
80
109
|
"btn_back": "◀️ Back",
|
|
81
|
-
"btn_reset": "Reset and
|
|
110
|
+
"btn_reset": "Reset and Improve ▶️",
|
|
82
111
|
# Step 3 (Reset)
|
|
83
112
|
"s3_title": "Your Accuracy Score Is Being Reset",
|
|
84
113
|
"lbl_score_reset": "Score Reset",
|
|
@@ -117,62 +146,62 @@ TRANSLATIONS = {
|
|
|
117
146
|
"s6_proceed": "Proceed to ethical tooling & evaluation modules."
|
|
118
147
|
},
|
|
119
148
|
"es": {
|
|
120
|
-
"title": "⚖️ El
|
|
149
|
+
"title": "⚖️ El reto de la Brújula Moral",
|
|
121
150
|
"loading": "⏳ Cargando...",
|
|
122
151
|
"loading_session": "🔒 Cargando tu sesión...",
|
|
123
|
-
"s1_title_auth": "Has
|
|
124
|
-
"s1_sub_auth": "
|
|
125
|
-
"lbl_best_acc": "Tu
|
|
126
|
-
"lbl_ind_rank": "Tu
|
|
127
|
-
"lbl_team": "Tu
|
|
152
|
+
"s1_title_auth": "Has construido un modelo preciso",
|
|
153
|
+
"s1_sub_auth": "Con experimentación y ajustes continuos, has logrado resultados impresionantes:",
|
|
154
|
+
"lbl_best_acc": "Tu mejor precisión",
|
|
155
|
+
"lbl_ind_rank": "Tu rango individual",
|
|
156
|
+
"lbl_team": "Tu equipo",
|
|
128
157
|
"lbl_team_rank": "Rango de Equipo:",
|
|
129
158
|
"s1_li1": "✅ Dominaste el proceso de construcción de modelos",
|
|
130
159
|
"s1_li2": "✅ Escalaste en la tabla de clasificación de precisión",
|
|
131
|
-
"s1_li3": "✅ Competiste con otros ingenieros",
|
|
160
|
+
"s1_li3": "✅ Competiste con otros ingenieros e ingenieras",
|
|
132
161
|
"s1_li4": "✅ Ganaste promociones y desbloqueaste herramientas",
|
|
133
162
|
"s1_congrats": "🏆 ¡Felicidades por tu logro técnico!",
|
|
134
163
|
"s1_box_title": "Pero ahora conoces la historia completa...",
|
|
135
164
|
"s1_box_text": "La alta precisión no es suficiente. Los sistemas de IA del mundo real también deben ser <strong>justos, equitativos y <span class='emph-harm'>minimizar el daño</span></strong> para todos los grupos de personas.",
|
|
136
|
-
"s1_title_guest": "Listo para
|
|
137
|
-
"s1_sub_guest": "
|
|
165
|
+
"s1_title_guest": "Listo para comenzar tu viaje",
|
|
166
|
+
"s1_sub_guest": "Ya conoces cómo se construye un modelo de IA y estás listo para aceptar el desafío:",
|
|
138
167
|
"s1_li1_guest": "✅ Entendiste el proceso de construcción de modelos de IA",
|
|
139
168
|
"s1_li2_guest": "✅ Aprendiste sobre precisión y rendimiento",
|
|
140
|
-
"s1_li3_guest": "✅ Descubriste el sesgo
|
|
169
|
+
"s1_li3_guest": "✅ Descubriste cómo aparece el sesgo en sistemas reales",
|
|
141
170
|
"s1_ready": "🎯 ¡Listo para aprender sobre IA ética!",
|
|
142
|
-
"btn_new_std": "Introducir el
|
|
143
|
-
"s2_title": "Necesitamos un
|
|
144
|
-
"s2_sub": "
|
|
145
|
-
"s2_box_head": "Observa tu
|
|
146
|
-
"lbl_acc_score": "Puntuación de
|
|
171
|
+
"btn_new_std": "Introducir el nuevo estándar ▶️",
|
|
172
|
+
"s2_title": "Necesitamos un estándar más alto",
|
|
173
|
+
"s2_sub": "Si bien tu modelo es preciso, se necesita un estándar más alto para prevenir <span class='emph-harm'>daños reales</span>. Para incentivar este nuevo enfoque, introducimos una nueva puntuación.",
|
|
174
|
+
"s2_box_head": "Observa tu puntuación",
|
|
175
|
+
"lbl_acc_score": "Puntuación de precisión",
|
|
147
176
|
"s2_box_emph_head": "Esta puntuación mide solo <strong>una dimensión</strong> del éxito.",
|
|
148
177
|
"s2_box_emph_text": "Es hora de agregar una segunda dimensión igualmente importante: <strong class='emph-fairness'>Ética</strong>.",
|
|
149
178
|
"btn_back": "◀️ Atrás",
|
|
150
|
-
"btn_reset": "
|
|
151
|
-
"s3_title": "
|
|
152
|
-
"lbl_score_reset": "Puntuación
|
|
153
|
-
"s3_why_head": "⚠️ ¿Por
|
|
154
|
-
"s3_why_text": "
|
|
155
|
-
"s3_worry_head": "✅ ¡No
|
|
156
|
-
"s3_worry_text": "A medida que hagas que tu IA sea más ética a través de las próximas lecciones y desafíos, <strong>tu puntuación
|
|
179
|
+
"btn_reset": "Reiniciar y mejorar ▶️",
|
|
180
|
+
"s3_title": "Vamos a reiniciar tu puntuación de precisión",
|
|
181
|
+
"lbl_score_reset": "Puntuación reiniciada",
|
|
182
|
+
"s3_why_head": "⚠️ ¿Por qué este reinicio?",
|
|
183
|
+
"s3_why_text": "Hemos reiniciado tu puntuación para subrayar una verdad importante: tu éxito anterior solo medía <strong>una dimensión</strong> — precisión de predicción. Todavía, <strong>no has demostrado</strong> que sabes cómo diseñar un sistema de IA que sea <span class='emph-fairness'>seguro para la sociedad</span>. Tampoco sabes si el modelo que construiste está <strong class='emph-harm'>tan sesgado</strong> como los ejemplos dañinos que estudiamos en la actividad anterior. A partir de ahora, tendrás que destacar en <strong>dos frentes</strong>: rendimiento técnico <em>y</em> responsabilidad ética.",
|
|
184
|
+
"s3_worry_head": "✅ ¡No te preocupes!",
|
|
185
|
+
"s3_worry_text": "A medida que hagas que tu IA sea más ética a través de las próximas lecciones y desafíos, <strong>recuperarás tu puntuación</strong>—y podría llegar a ser incluso más alta que antes.",
|
|
157
186
|
"btn_intro_mc": "Introducir Brújula Moral ▶️",
|
|
158
|
-
"s4_title": "Una
|
|
159
|
-
"s4_sub": "Tu nuevo objetivo es escalar en la clasificación
|
|
160
|
-
"s4_formula_head": "📐 La
|
|
187
|
+
"s4_title": "Una nueva forma de ganar",
|
|
188
|
+
"s4_sub": "Tu nuevo objetivo es escalar en la clasificación gracias a tu <strong>Puntuación de Brújula Moral</strong>.",
|
|
189
|
+
"s4_formula_head": "📐 La fórmula de puntuación",
|
|
161
190
|
"s4_formula_text": "<strong>Puntuación de Brújula Moral</strong> =<br><br>[ Precisión del Modelo Actual ] × [ Progreso Ético % ]",
|
|
162
191
|
"s4_where": "Donde:",
|
|
163
192
|
"s4_li1": "<strong>Precisión del Modelo Actual:</strong> Tu rendimiento técnico",
|
|
164
193
|
"s4_li2": "<strong>Progreso Ético %:</strong> Porcentaje de:",
|
|
165
194
|
"s4_li2_sub1": "✅ Tareas de aprendizaje ético completadas",
|
|
166
195
|
"s4_li2_sub2": "✅ Preguntas de control respondidas correctamente",
|
|
167
|
-
"s4_mean_head": "💡 Qué
|
|
168
|
-
"s4_mean_text": "<strong>No puedes</strong> ganar solo con precisión—también debes demostrar <strong class='emph-fairness'>comprensión ética</strong>. Y <strong>no puedes</strong> ganar solo completando lecciones—necesitas un modelo
|
|
169
|
-
"btn_see_chal": "Ver el
|
|
170
|
-
"s6_title": "📍 Tu
|
|
171
|
-
"s6_pos_auth": "
|
|
196
|
+
"s4_mean_head": "💡 Qué significa esto:",
|
|
197
|
+
"s4_mean_text": "<strong>No puedes</strong> ganar solo con precisión—también debes demostrar <strong class='emph-fairness'>comprensión ética</strong>. Y <strong>no puedes</strong> ganar solo completando lecciones—también necesitas un modelo que funcione. <strong class='emph-risk'>Ambas dimensiones importan</strong>.",
|
|
198
|
+
"btn_see_chal": "Ver el desafío ▶️",
|
|
199
|
+
"s6_title": "📍 Tu nuevo punto de partida",
|
|
200
|
+
"s6_pos_auth": "Antes ocupabas el puesto #{rank} en la tabla de clasificación de precisión.",
|
|
172
201
|
"s6_pos_guest": "Establecerás tu posición a medida que construyas modelos éticamente conscientes.",
|
|
173
|
-
"s6_mc_rank": "Rango
|
|
202
|
+
"s6_mc_rank": "Rango actual de Brújula Moral: <span style='color:#b91c1c;'>Aún no establecido</span>",
|
|
174
203
|
"s6_mc_score": "(Puntuación de Brújula Moral = 0 inicialmente)",
|
|
175
|
-
"s6_path_head": "🛤️ Camino a
|
|
204
|
+
"s6_path_head": "🛤️ Camino a seguir",
|
|
176
205
|
"s6_li1": "🔍 Detectar y medir sesgos",
|
|
177
206
|
"s6_li2": "⚖️ Aplicar métricas de equidad",
|
|
178
207
|
"s6_li3": "🔧 Rediseñar modelos para minimizar daños",
|
|
@@ -183,62 +212,62 @@ TRANSLATIONS = {
|
|
|
183
212
|
"s6_proceed": "Proceder a herramientas y evaluación ética."
|
|
184
213
|
},
|
|
185
214
|
"ca": {
|
|
186
|
-
"title": "⚖️ El
|
|
215
|
+
"title": "⚖️ El repte de la Brúixola Moral",
|
|
187
216
|
"loading": "⏳ Carregant...",
|
|
188
217
|
"loading_session": "🔒 Carregant la teva sessió...",
|
|
189
|
-
"s1_title_auth": "Has
|
|
190
|
-
"s1_sub_auth": "
|
|
191
|
-
"lbl_best_acc": "La
|
|
192
|
-
"lbl_ind_rank": "El
|
|
193
|
-
"lbl_team": "El
|
|
194
|
-
"lbl_team_rank": "Rang d'
|
|
218
|
+
"s1_title_auth": "Has construït un model precís",
|
|
219
|
+
"s1_sub_auth": "Amb experimentació i ajustos constants, has aconseguit resultats impressionants:",
|
|
220
|
+
"lbl_best_acc": "La teva millor precisió",
|
|
221
|
+
"lbl_ind_rank": "El teu rang individual",
|
|
222
|
+
"lbl_team": "El teu equip",
|
|
223
|
+
"lbl_team_rank": "Rang d'equip:",
|
|
195
224
|
"s1_li1": "✅ Has dominat el procés de construcció de models",
|
|
196
225
|
"s1_li2": "✅ Has escalat a la taula de classificació de precisió",
|
|
197
|
-
"s1_li3": "✅ Has competit amb altres enginyers",
|
|
226
|
+
"s1_li3": "✅ Has competit amb altres enginyers i enginyeres",
|
|
198
227
|
"s1_li4": "✅ Has guanyat promocions i desbloquejat eines",
|
|
199
228
|
"s1_congrats": "🏆 Felicitats pel teu èxit tècnic!",
|
|
200
|
-
"s1_box_title": "Però ara coneixes la història
|
|
229
|
+
"s1_box_title": "Però ara ja coneixes tota la història...",
|
|
201
230
|
"s1_box_text": "L'alta precisió no és suficient. Els sistemes d'IA del món real també han de ser <strong>justos, equitatius i <span class='emph-harm'>minimitzar el dany</span></strong> per a tots els grups de persones.",
|
|
202
|
-
"s1_title_guest": "A
|
|
203
|
-
"s1_sub_guest": "
|
|
231
|
+
"s1_title_guest": "A punt per començar el teu viatge",
|
|
232
|
+
"s1_sub_guest": "Ja saps com es construeix un model d’IA i estàs preparat/ada per afrontar el repte:",
|
|
204
233
|
"s1_li1_guest": "✅ Has entès el procés de construcció de models d'IA",
|
|
205
234
|
"s1_li2_guest": "✅ Has après sobre precisió i rendiment",
|
|
206
|
-
"s1_li3_guest": "✅ Has descobert el biaix
|
|
235
|
+
"s1_li3_guest": "✅ Has descobert com apareix el biaix en sistemes reals",
|
|
207
236
|
"s1_ready": "🎯 A punt per aprendre sobre IA ètica!",
|
|
208
|
-
"btn_new_std": "Introduir el
|
|
209
|
-
"s2_title": "Necessitem un
|
|
210
|
-
"s2_sub": "Tot i que el teu model és precís,
|
|
211
|
-
"s2_box_head": "Observa la teva
|
|
212
|
-
"lbl_acc_score": "Puntuació de
|
|
237
|
+
"btn_new_std": "Introduir el nou estàndard ▶️",
|
|
238
|
+
"s2_title": "Necessitem un estàndard més alt",
|
|
239
|
+
"s2_sub": "Tot i que el teu model és precís, cal un estàndard més alt per prevenir <span class='emph-harm'>danys reals</span>. Per impulsar aquest nou enfocament, introduïm una nova puntuació.",
|
|
240
|
+
"s2_box_head": "Observa la teva puntuació",
|
|
241
|
+
"lbl_acc_score": "Puntuació de precisió",
|
|
213
242
|
"s2_box_emph_head": "Aquesta puntuació mesura només <strong>una dimensió</strong> de l'èxit.",
|
|
214
243
|
"s2_box_emph_text": "És hora d'afegir una segona dimensió igualment important: <strong class='emph-fairness'>Ètica</strong>.",
|
|
215
244
|
"btn_back": "◀️ Enrere",
|
|
216
|
-
"btn_reset": "
|
|
217
|
-
"s3_title": "
|
|
218
|
-
"lbl_score_reset": "Puntuació
|
|
219
|
-
"s3_why_head": "⚠️ Per
|
|
220
|
-
"s3_why_text": "
|
|
221
|
-
"s3_worry_head": "✅ No
|
|
222
|
-
"s3_worry_text": "A mesura que facis que la teva IA sigui més ètica a través de les properes lliçons i reptes, <strong>la teva
|
|
245
|
+
"btn_reset": "Reiniciar i millorar ▶️",
|
|
246
|
+
"s3_title": "Reiniciarem la teva puntuació de precisió",
|
|
247
|
+
"lbl_score_reset": "Puntuació reiniciada",
|
|
248
|
+
"s3_why_head": "⚠️ Per què aquest reinici?",
|
|
249
|
+
"s3_why_text": "Hem reiniciat la teva puntuació per subratllar una veritat important: el teu èxit anterior només mesurava <strong>una dimensió</strong> — precisió de predicció. Encara <strong>no has demostrat</strong> que saps com dissenyar un sistema d’IA <span class='emph-fairness'>segur per a la societat</span>. Tampoc saps si el model que has construït és <strong class='emph-harm'>tan esbiaixat</strong> com els exemples perjudicials que hem estudiat en l'activitat anterior. D'ara endavant, hauràs de destacar en <strong>dos fronts</strong>: rendiment tècnic <em>i</em> responsabilitat ètica.",
|
|
250
|
+
"s3_worry_head": "✅ No et preocupis!",
|
|
251
|
+
"s3_worry_text": "A mesura que facis que la teva IA sigui més ètica a través de les properes lliçons i reptes, <strong>recuperaràs la teva puntuació</strong>—i fins i tot podria arribar a ser més alta que abans.",
|
|
223
252
|
"btn_intro_mc": "Introduir Brúixola Moral ▶️",
|
|
224
|
-
"s4_title": "Una
|
|
225
|
-
"s4_sub": "El teu nou objectiu és
|
|
226
|
-
"s4_formula_head": "📐 La
|
|
253
|
+
"s4_title": "Una nova manera de guanyar",
|
|
254
|
+
"s4_sub": "El teu nou objectiu és pujar en la classificació gràcies a la teva <strong>Puntuació de Brúixola Moral</strong>.",
|
|
255
|
+
"s4_formula_head": "📐 La fórmula de puntuació",
|
|
227
256
|
"s4_formula_text": "<strong>Puntuació de Brúixola Moral</strong> =<br><br>[ Precisió del Model Actual ] × [ Progrés Ètic % ]",
|
|
228
257
|
"s4_where": "On:",
|
|
229
258
|
"s4_li1": "<strong>Precisió del Model Actual:</strong> El teu rendiment tècnic",
|
|
230
259
|
"s4_li2": "<strong>Progrés Ètic %:</strong> Percentatge de:",
|
|
231
260
|
"s4_li2_sub1": "✅ Tasques d'aprenentatge ètic completades",
|
|
232
261
|
"s4_li2_sub2": "✅ Preguntes de control respostes correctament",
|
|
233
|
-
"s4_mean_head": "💡 Què
|
|
234
|
-
"s4_mean_text": "<strong>No pots</strong> guanyar només amb precisió—també has de demostrar <strong class='emph-fairness'>comprensió ètica</strong>. I <strong>no pots</strong> guanyar només completant lliçons—necessites un model
|
|
235
|
-
"btn_see_chal": "Veure el
|
|
236
|
-
"s6_title": "📍 El
|
|
237
|
-
"s6_pos_auth": "
|
|
262
|
+
"s4_mean_head": "💡 Què significa això:",
|
|
263
|
+
"s4_mean_text": "<strong>No pots</strong> guanyar només amb precisió—també has de demostrar <strong class='emph-fairness'>comprensió ètica</strong>. I <strong>no pots</strong> guanyar només completant lliçons—també necessites un model que funcioni. <strong class='emph-risk'>Les dues dimensions són importants</strong>.",
|
|
264
|
+
"btn_see_chal": "Veure el repte ▶️",
|
|
265
|
+
"s6_title": "📍 El teu nou punt de partida",
|
|
266
|
+
"s6_pos_auth": "Abans ocupaves la posició #{rank} a la taula de classificació de precisió.",
|
|
238
267
|
"s6_pos_guest": "Establiràs la teva posició a mesura que construeixis models èticament conscients.",
|
|
239
|
-
"s6_mc_rank": "Rang
|
|
268
|
+
"s6_mc_rank": "Rang actual de Brúixola Moral: <span style='color:#b91c1c;'>Encara no establert</span>",
|
|
240
269
|
"s6_mc_score": "(Puntuació de Brúixola Moral = 0 inicialment)",
|
|
241
|
-
"s6_path_head": "🛤️ Camí a
|
|
270
|
+
"s6_path_head": "🛤️ Camí a seguir",
|
|
242
271
|
"s6_li1": "🔍 Detectar i mesurar biaixos",
|
|
243
272
|
"s6_li2": "⚖️ Aplicar mètriques d'equitat",
|
|
244
273
|
"s6_li3": "🔧 Redissenyar models per minimitzar danys",
|
|
@@ -263,6 +292,48 @@ def _normalize_team_name(name: str) -> str:
|
|
|
263
292
|
return ""
|
|
264
293
|
return " ".join(str(name).strip().split())
|
|
265
294
|
|
|
295
|
+
# NEW: Team name translation helpers for UI display
|
|
296
|
+
def translate_team_name_for_display(team_en: str, lang: str = "en") -> str:
|
|
297
|
+
"""
|
|
298
|
+
Translate a canonical English team name to the specified language for UI display.
|
|
299
|
+
Fallback to English if translation not found.
|
|
300
|
+
"""
|
|
301
|
+
if lang not in TEAM_NAME_TRANSLATIONS:
|
|
302
|
+
lang = "en"
|
|
303
|
+
return TEAM_NAME_TRANSLATIONS[lang].get(team_en, team_en)
|
|
304
|
+
|
|
305
|
+
# NEW: Reverse lookup for future use (e.g., if user input needs to be normalized back to English)
|
|
306
|
+
def translate_team_name_to_english(display_name: str, lang: str = "en") -> str:
|
|
307
|
+
"""
|
|
308
|
+
Reverse lookup: given a localized team name, return the canonical English name.
|
|
309
|
+
Returns the original display_name if not found.
|
|
310
|
+
"""
|
|
311
|
+
if lang not in TEAM_NAME_TRANSLATIONS:
|
|
312
|
+
return display_name # Already English or unknown
|
|
313
|
+
|
|
314
|
+
translations = TEAM_NAME_TRANSLATIONS[lang]
|
|
315
|
+
for english_name, localized_name in translations.items():
|
|
316
|
+
if localized_name == display_name:
|
|
317
|
+
return english_name
|
|
318
|
+
return display_name # UPDATED: Return display_name instead of None for consistency
|
|
319
|
+
|
|
320
|
+
# NEW: Format leaderboard DataFrame with localized team names (non-destructive copy)
|
|
321
|
+
def _format_leaderboard_for_display(df: Optional[pd.DataFrame], lang: str = "en") -> Optional[pd.DataFrame]:
|
|
322
|
+
"""
|
|
323
|
+
Create a copy of the leaderboard DataFrame with team names translated for display.
|
|
324
|
+
Does not mutate the original DataFrame.
|
|
325
|
+
For potential future use when displaying full leaderboard.
|
|
326
|
+
"""
|
|
327
|
+
if df is None:
|
|
328
|
+
return None # UPDATED: Handle None explicitly
|
|
329
|
+
|
|
330
|
+
if df.empty or "Team" not in df.columns:
|
|
331
|
+
return df.copy() # UPDATED: Return copy for empty or missing Team column
|
|
332
|
+
|
|
333
|
+
df_display = df.copy()
|
|
334
|
+
df_display["Team"] = df_display["Team"].apply(lambda t: translate_team_name_for_display(t, lang))
|
|
335
|
+
return df_display
|
|
336
|
+
|
|
266
337
|
def _fetch_leaderboard(token: str) -> Optional[pd.DataFrame]:
|
|
267
338
|
now = time.time()
|
|
268
339
|
with _cache_lock:
|
|
@@ -393,7 +464,8 @@ def build_standing_html(user_stats, lang="en"):
|
|
|
393
464
|
if user_stats["is_signed_in"] and user_stats["best_score"] is not None:
|
|
394
465
|
best_score_pct = f"{(user_stats['best_score'] * 100):.1f}%"
|
|
395
466
|
rank_text = f"#{user_stats['rank']}" if user_stats["rank"] else "N/A"
|
|
396
|
-
|
|
467
|
+
# UPDATED: Translate team name for display based on selected language
|
|
468
|
+
team_text = translate_team_name_for_display(user_stats["team_name"], lang) if user_stats["team_name"] else "N/A"
|
|
397
469
|
team_rank_text = f"#{user_stats['team_rank']}" if user_stats["team_rank"] else "N/A"
|
|
398
470
|
return f"""
|
|
399
471
|
<div class='slide-shell slide-shell--info'>
|
|
@@ -762,21 +834,65 @@ def create_moral_compass_challenge_app(theme_primary_hue: str = "indigo") -> "gr
|
|
|
762
834
|
loading_screen = gr.Column(visible=False)
|
|
763
835
|
all_steps = [step_1, step_2, step_3, step_4, step_6, loading_screen, initial_loading]
|
|
764
836
|
|
|
765
|
-
#
|
|
837
|
+
# -------------------------------------------------------------------------
|
|
838
|
+
# HYBRID CACHING LOGIC (OPTIMIZED)
|
|
839
|
+
# -------------------------------------------------------------------------
|
|
840
|
+
|
|
841
|
+
# 1. Define update targets (Order must match the return list below)
|
|
842
|
+
update_targets = [
|
|
843
|
+
initial_loading, step_1,
|
|
844
|
+
c_title, c_loading,
|
|
845
|
+
stats_display, step_2_html_comp, step_6_html_comp, # Dynamic HTML
|
|
846
|
+
step_3_html_comp, step_4_html_comp, # Static HTML
|
|
847
|
+
step_1_next, step_2_back, step_2_next, step_3_back, step_3_next, step_4_back, step_4_next, step_6_back
|
|
848
|
+
]
|
|
849
|
+
|
|
850
|
+
# 2. Cached Generator for Static Content (Steps 3 & 4 + Buttons)
|
|
851
|
+
@lru_cache(maxsize=16)
|
|
852
|
+
def get_cached_static_content(lang):
|
|
853
|
+
"""
|
|
854
|
+
Generates the heavy static HTML for Steps 3 & 4 and all buttons once per language.
|
|
855
|
+
"""
|
|
856
|
+
return [
|
|
857
|
+
# Static HTML Steps
|
|
858
|
+
_get_step3_html(lang),
|
|
859
|
+
_get_step4_html(lang),
|
|
860
|
+
|
|
861
|
+
# All Buttons
|
|
862
|
+
gr.Button(value=t(lang, 'btn_new_std')), # step_1_next
|
|
863
|
+
gr.Button(value=t(lang, 'btn_back')), # step_2_back
|
|
864
|
+
gr.Button(value=t(lang, 'btn_reset')), # step_2_next
|
|
865
|
+
gr.Button(value=t(lang, 'btn_back')), # step_3_back
|
|
866
|
+
gr.Button(value=t(lang, 'btn_intro_mc')),# step_3_next
|
|
867
|
+
gr.Button(value=t(lang, 'btn_back')), # step_4_back
|
|
868
|
+
gr.Button(value=t(lang, 'btn_see_chal')),# step_4_next
|
|
869
|
+
gr.Button(value=t(lang, 'btn_back')) # step_6_back
|
|
870
|
+
]
|
|
871
|
+
|
|
872
|
+
# 3. Hybrid Load Function
|
|
766
873
|
def initial_load(request: gr.Request):
|
|
767
874
|
# 1. Language
|
|
768
875
|
params = request.query_params
|
|
769
876
|
lang = params.get("lang", "en")
|
|
770
877
|
if lang not in TRANSLATIONS: lang = "en"
|
|
771
878
|
|
|
772
|
-
# 2. Auth
|
|
879
|
+
# 2. Auth (Dynamic)
|
|
773
880
|
success, username, token = _try_session_based_auth(request)
|
|
774
881
|
|
|
775
|
-
# 3. Stats
|
|
882
|
+
# 3. Stats (Dynamic)
|
|
776
883
|
stats = {"is_signed_in": False, "best_score": None}
|
|
777
884
|
if success and username:
|
|
778
885
|
stats = _compute_user_stats(username, token)
|
|
779
886
|
|
|
887
|
+
# 4. Build Dynamic HTML
|
|
888
|
+
html_standing = build_standing_html(stats, lang)
|
|
889
|
+
html_step2 = build_step2_html(stats, lang)
|
|
890
|
+
html_step6 = build_step6_html(stats, lang)
|
|
891
|
+
|
|
892
|
+
# 5. Fetch Static Content from Cache
|
|
893
|
+
static_content = get_cached_static_content(lang)
|
|
894
|
+
|
|
895
|
+
# 6. Combine
|
|
780
896
|
return [
|
|
781
897
|
gr.update(visible=False), # initial_loading
|
|
782
898
|
gr.update(visible=True), # step_1
|
|
@@ -785,31 +901,15 @@ def create_moral_compass_challenge_app(theme_primary_hue: str = "indigo") -> "gr
|
|
|
785
901
|
f"<h1 style='text-align:center;'>{t(lang, 'title')}</h1>",
|
|
786
902
|
f"<div style='text-align:center; padding:80px 0;'><h2>{t(lang, 'loading')}</h2></div>",
|
|
787
903
|
|
|
788
|
-
# HTML
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
_get_step4_html(lang),
|
|
793
|
-
build_step6_html(stats, lang),
|
|
904
|
+
# Dynamic HTML
|
|
905
|
+
html_standing,
|
|
906
|
+
html_step2,
|
|
907
|
+
html_step6,
|
|
794
908
|
|
|
795
|
-
# Buttons
|
|
796
|
-
|
|
797
|
-
gr.Button(value=t(lang, 'btn_back')), # s2 back
|
|
798
|
-
gr.Button(value=t(lang, 'btn_reset')), # s2 next
|
|
799
|
-
gr.Button(value=t(lang, 'btn_back')), # s3 back
|
|
800
|
-
gr.Button(value=t(lang, 'btn_intro_mc')), # s3 next
|
|
801
|
-
gr.Button(value=t(lang, 'btn_back')), # s4 back
|
|
802
|
-
gr.Button(value=t(lang, 'btn_see_chal')), # s4 next
|
|
803
|
-
gr.Button(value=t(lang, 'btn_back')), # s6 back
|
|
909
|
+
# Static HTML & Buttons (Unpacked from cache)
|
|
910
|
+
*static_content
|
|
804
911
|
]
|
|
805
912
|
|
|
806
|
-
update_targets = [
|
|
807
|
-
initial_loading, step_1,
|
|
808
|
-
c_title, c_loading,
|
|
809
|
-
stats_display, step_2_html_comp, step_3_html_comp, step_4_html_comp, step_6_html_comp,
|
|
810
|
-
step_1_next, step_2_back, step_2_next, step_3_back, step_3_next, step_4_back, step_4_next, step_6_back
|
|
811
|
-
]
|
|
812
|
-
|
|
813
913
|
demo.load(fn=initial_load, inputs=None, outputs=update_targets)
|
|
814
914
|
|
|
815
915
|
# --- Navigation ---
|