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.
Files changed (36) hide show
  1. aimodelshare/moral_compass/__init__.py +51 -2
  2. aimodelshare/moral_compass/api_client.py +92 -4
  3. aimodelshare/moral_compass/apps/__init__.py +36 -16
  4. aimodelshare/moral_compass/apps/ai_consequences.py +98 -88
  5. aimodelshare/moral_compass/apps/bias_detective_ca.py +2722 -0
  6. aimodelshare/moral_compass/apps/bias_detective_en.py +2722 -0
  7. aimodelshare/moral_compass/apps/bias_detective_part1.py +2722 -0
  8. aimodelshare/moral_compass/apps/bias_detective_part2.py +2465 -0
  9. aimodelshare/moral_compass/apps/bias_detective_part_es.py +2722 -0
  10. aimodelshare/moral_compass/apps/ethical_revelation.py +237 -147
  11. aimodelshare/moral_compass/apps/fairness_fixer.py +1839 -859
  12. aimodelshare/moral_compass/apps/fairness_fixer_ca.py +1869 -0
  13. aimodelshare/moral_compass/apps/fairness_fixer_en.py +1869 -0
  14. aimodelshare/moral_compass/apps/fairness_fixer_es.py +1869 -0
  15. aimodelshare/moral_compass/apps/judge.py +130 -143
  16. aimodelshare/moral_compass/apps/justice_equity_upgrade.py +793 -831
  17. aimodelshare/moral_compass/apps/justice_equity_upgrade_ca.py +815 -0
  18. aimodelshare/moral_compass/apps/justice_equity_upgrade_en.py +815 -0
  19. aimodelshare/moral_compass/apps/justice_equity_upgrade_es.py +815 -0
  20. aimodelshare/moral_compass/apps/mc_integration_helpers.py +227 -745
  21. aimodelshare/moral_compass/apps/model_building_app_ca.py +4544 -0
  22. aimodelshare/moral_compass/apps/model_building_app_ca_final.py +3899 -0
  23. aimodelshare/moral_compass/apps/model_building_app_en.py +4290 -0
  24. aimodelshare/moral_compass/apps/model_building_app_en_final.py +3869 -0
  25. aimodelshare/moral_compass/apps/model_building_app_es.py +4362 -0
  26. aimodelshare/moral_compass/apps/model_building_app_es_final.py +3899 -0
  27. aimodelshare/moral_compass/apps/model_building_game.py +4211 -935
  28. aimodelshare/moral_compass/apps/moral_compass_challenge.py +195 -95
  29. aimodelshare/moral_compass/apps/what_is_ai.py +126 -117
  30. aimodelshare/moral_compass/challenge.py +98 -17
  31. {aimodelshare-0.3.7.dist-info → aimodelshare-0.4.71.dist-info}/METADATA +1 -1
  32. {aimodelshare-0.3.7.dist-info → aimodelshare-0.4.71.dist-info}/RECORD +35 -19
  33. aimodelshare/moral_compass/apps/bias_detective.py +0 -714
  34. {aimodelshare-0.3.7.dist-info → aimodelshare-0.4.71.dist-info}/WHEEL +0 -0
  35. {aimodelshare-0.3.7.dist-info → aimodelshare-0.4.71.dist-info}/licenses/LICENSE +0 -0
  36. {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": "Through experimentation and iteration, you've achieved impressive results:",
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 Transform ▶️",
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 Desafío de la Brújula Moral",
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 Construido un Modelo Preciso",
124
- "s1_sub_auth": "A través de la experimentación e iteración, has logrado resultados impresionantes:",
125
- "lbl_best_acc": "Tu Mejor Precisión",
126
- "lbl_ind_rank": "Tu Rango Individual",
127
- "lbl_team": "Tu Equipo",
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 Comenzar tu Viaje",
137
- "s1_sub_guest": "Has aprendido sobre el proceso de construcción de modelos y estás listo para aceptar el desafío:",
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 del mundo real en los sistemas de IA",
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 Nuevo Estándar ▶️",
143
- "s2_title": "Necesitamos un Estándar Más Alto",
144
- "s2_sub": "Aunque tu modelo es preciso, se necesita un estándar más alto para prevenir <span class='emph-harm'>daños en el mundo real</span>. Para incentivar este nuevo enfoque, introducimos una nueva puntuación.",
145
- "s2_box_head": "Observa tu Puntuación",
146
- "lbl_acc_score": "Puntuación de Precisión",
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": "Restablecer y Transformar ▶️",
151
- "s3_title": "Tu Puntuación de Precisión Se Está Restableciendo",
152
- "lbl_score_reset": "Puntuación Restablecida",
153
- "s3_why_head": "⚠️ ¿Por Qué Este Restablecimiento?",
154
- "s3_why_text": "Restablecemos tu puntuación para enfatizar una verdad crítica: tu éxito anterior se midió por solo <strong>una dimensión</strong> — precisión de predicción. Hasta ahora, <strong>no has demostrado</strong> que sabes cómo hacer que tu sistema de IA sea <span class='emph-fairness'>seguro para la sociedad</span>. Aún no 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. De ahora en adelante, necesitarás sobresalir en <strong>dos frentes</strong>: rendimiento técnico <em>y</em> responsabilidad ética.",
155
- "s3_worry_head": "✅ ¡No Te Preocupes!",
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 será restaurada</strong>—y podría subir aún más que antes.",
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 Nueva Forma de Ganar",
159
- "s4_sub": "Tu nuevo objetivo es escalar en la clasificación aumentando tu <strong>Puntuación de Brújula Moral</strong>.",
160
- "s4_formula_head": "📐 La Fórmula de Puntuación",
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é Significa Esto:",
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 funcional también. <strong class='emph-risk'>Ambas dimensiones importan</strong>.",
169
- "btn_see_chal": "Ver el Desafío por Delante ▶️",
170
- "s6_title": "📍 Tu Nuevo Punto de Partida",
171
- "s6_pos_auth": "Anteriormente estabas clasificado #{rank} en la tabla de precisión.",
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 Actual de Brújula Moral: <span style='color:#b91c1c;'>Aún No Establecido</span>",
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 Seguir",
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 Repte de la Brúixola Moral",
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 Construït un Model Precís",
190
- "s1_sub_auth": "A través de l'experimentació i iteració, has aconseguit resultats impressionants:",
191
- "lbl_best_acc": "La Teva Millor Precisió",
192
- "lbl_ind_rank": "El Teu Rang Individual",
193
- "lbl_team": "El Teu Equip",
194
- "lbl_team_rank": "Rang d'Equip:",
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 completa...",
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 Punt per Començar el Teu Viatge",
203
- "s1_sub_guest": "Has après sobre el procés de construcció de models i estàs a punt per acceptar el repte:",
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 del món real en els sistemes d'IA",
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 Nou Estàndard ▶️",
209
- "s2_title": "Necessitem un Estàndard Més Alt",
210
- "s2_sub": "Tot i que el teu model és precís, es necessita un estàndard més alt per prevenir <span class='emph-harm'>danys al món real</span>. Per incentivar aquest nou enfocament, introduïm una nova puntuació.",
211
- "s2_box_head": "Observa la teva Puntuació",
212
- "lbl_acc_score": "Puntuació de Precisió",
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": "Restablir i Transformar ▶️",
217
- "s3_title": "La Teva Puntuació de Precisió S'està Restablint",
218
- "lbl_score_reset": "Puntuació Restablerta",
219
- "s3_why_head": "⚠️ Per Què Aquest Restabliment?",
220
- "s3_why_text": "Restablim la teva puntuació per emfatitzar una veritat crítica: el teu èxit anterior es va mesurar per només <strong>una dimensió</strong> — precisió de predicció. Fins ara, <strong>no has demostrat</strong> que saps com fer que el teu sistema d'IA sigui <span class='emph-fairness'>segur per a la societat</span>. Encara no saps si el model que has construït està <strong class='emph-harm'>tan esbiaixat</strong> com els exemples nocius que vam estudiar en l'activitat anterior. D'ara endavant, necessitaràs sobresortir en <strong>dos fronts</strong>: rendiment tècnic <em>i</em> responsabilitat ètica.",
221
- "s3_worry_head": "✅ No Et Preocupis!",
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 puntuació serà restaurada</strong>—i podria pujar encara més que abans.",
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 dIA <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 Nova Manera de Guanyar",
225
- "s4_sub": "El teu nou objectiu és escalar a la classificació augmentant la teva <strong>Puntuació de Brúixola Moral</strong>.",
226
- "s4_formula_head": "📐 La Fórmula de Puntuació",
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è Significa Això:",
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 funcional també. <strong class='emph-risk'>Les dues dimensions importen</strong>.",
235
- "btn_see_chal": "Veure el Repte per Endavant ▶️",
236
- "s6_title": "📍 El Teu Nou Punt de Partida",
237
- "s6_pos_auth": "Anteriorment estaves classificat #{rank} a la taula de precisió.",
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 Actual de Brúixola Moral: <span style='color:#b91c1c;'>Encara No Establert</span>",
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 Seguir",
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
- team_text = user_stats["team_name"] if user_stats["team_name"] else "N/A"
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
- # --- Initial Load Handler ---
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 Components
789
- build_standing_html(stats, lang),
790
- build_step2_html(stats, lang),
791
- _get_step3_html(lang),
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
- gr.Button(value=t(lang, 'btn_new_std')), # s1 next
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 ---