aimodelshare 0.3.7__py3-none-any.whl → 0.3.94__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 +4399 -0
- aimodelshare/moral_compass/apps/model_building_app_ca_final.py +3899 -0
- aimodelshare/moral_compass/apps/model_building_app_en.py +4167 -0
- aimodelshare/moral_compass/apps/model_building_app_en_final.py +3869 -0
- aimodelshare/moral_compass/apps/model_building_app_es.py +4351 -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.3.94.dist-info}/METADATA +1 -1
- {aimodelshare-0.3.7.dist-info → aimodelshare-0.3.94.dist-info}/RECORD +35 -19
- aimodelshare/moral_compass/apps/bias_detective.py +0 -714
- {aimodelshare-0.3.7.dist-info → aimodelshare-0.3.94.dist-info}/WHEEL +0 -0
- {aimodelshare-0.3.7.dist-info → aimodelshare-0.3.94.dist-info}/licenses/LICENSE +0 -0
- {aimodelshare-0.3.7.dist-info → aimodelshare-0.3.94.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 pandas as pd
|
|
13
13
|
import gradio as gr
|
|
14
14
|
|
|
@@ -34,6 +34,35 @@ TEAM_NAMES = [
|
|
|
34
34
|
"The Ethical Explorers", "The Fairness Finders", "The Accuracy Avengers"
|
|
35
35
|
]
|
|
36
36
|
|
|
37
|
+
# NEW: Team name translations for UI display only
|
|
38
|
+
# Internal logic (ranking, caching, grouping) always uses canonical English names
|
|
39
|
+
TEAM_NAME_TRANSLATIONS = {
|
|
40
|
+
"en": {
|
|
41
|
+
"The Justice League": "The Justice League",
|
|
42
|
+
"The Moral Champions": "The Moral Champions",
|
|
43
|
+
"The Data Detectives": "The Data Detectives",
|
|
44
|
+
"The Ethical Explorers": "The Ethical Explorers",
|
|
45
|
+
"The Fairness Finders": "The Fairness Finders",
|
|
46
|
+
"The Accuracy Avengers": "The Accuracy Avengers"
|
|
47
|
+
},
|
|
48
|
+
"es": {
|
|
49
|
+
"The Justice League": "La Liga de la Justicia",
|
|
50
|
+
"The Moral Champions": "Los Campeones Morales",
|
|
51
|
+
"The Data Detectives": "Los Detectives de Datos",
|
|
52
|
+
"The Ethical Explorers": "Los Exploradores Éticos",
|
|
53
|
+
"The Fairness Finders": "Los Buscadores de Equidad",
|
|
54
|
+
"The Accuracy Avengers": "Los Vengadores de Precisión"
|
|
55
|
+
},
|
|
56
|
+
"ca": {
|
|
57
|
+
"The Justice League": "La Lliga de la Justícia",
|
|
58
|
+
"The Moral Champions": "Els Campions Morals",
|
|
59
|
+
"The Data Detectives": "Els Detectives de Dades",
|
|
60
|
+
"The Ethical Explorers": "Els Exploradors Ètics",
|
|
61
|
+
"The Fairness Finders": "Els Cercadors d'Equitat",
|
|
62
|
+
"The Accuracy Avengers": "Els Venjadors de Precisió"
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
37
66
|
_cache_lock = threading.Lock()
|
|
38
67
|
_leaderboard_cache: Dict[str, Any] = {"data": None, "timestamp": 0.0}
|
|
39
68
|
_user_stats_cache: Dict[str, Dict[str, Any]] = {}
|
|
@@ -65,8 +94,8 @@ TRANSLATIONS = {
|
|
|
65
94
|
"s2_title": "⚠️ But Wait...",
|
|
66
95
|
"s2_intro": "Before we share the model, there's something you need to know...",
|
|
67
96
|
"s2_box_title": "A Real-World Story",
|
|
68
|
-
"s2_p1": "A model similar to yours was actually used in the real world. It was used by judges across the United States to
|
|
69
|
-
"s2_p2": "Like yours, it had impressive accuracy scores. Like yours, it was built on data about past criminal cases. Like yours, it aimed to predict who
|
|
97
|
+
"s2_p1": "A model similar to yours was actually used in the real world. It was used by judges across the United States to determine whether to grant parole to people in prison.",
|
|
98
|
+
"s2_p2": "Like yours, it had impressive accuracy scores. Like yours, it was built on data about past criminal cases. Like yours, it aimed to predict who might re-offend.",
|
|
70
99
|
"s2_p3": "But something was terribly wrong...",
|
|
71
100
|
"btn_back": "◀️ Back",
|
|
72
101
|
"btn_reveal": "Reveal the Truth ▶️",
|
|
@@ -77,7 +106,7 @@ TRANSLATIONS = {
|
|
|
77
106
|
"s3_box_title": "Their Shocking Findings:",
|
|
78
107
|
"s3_alert": "⚠️ Black defendants were labeled \"high-risk\" at nearly <u>TWICE</u> the rate of white defendants.",
|
|
79
108
|
"s3_spec": "<strong>Specifically:</strong>",
|
|
80
|
-
"s3_li1_pre": "defendants who <em>did NOT re-offend</em
|
|
109
|
+
"s3_li1_pre": "<strong>Black defendants</strong> who <em>did NOT re-offend</em>, were incorrectly labeled as <strong>\"high-risk\"</strong> at a rate of about <strong>45%</strong>",
|
|
81
110
|
"s3_li2_pre": "<strong>White defendants</strong> who <em>did NOT re-offend</em> were incorrectly labeled as <strong>\"high-risk\"</strong> at a rate of only <strong>24%</strong>",
|
|
82
111
|
"s3_li3": "Meanwhile, <strong>white defendants</strong> who <em>DID re-offend</em> were <strong>more likely to be labeled \"low-risk\"</strong> compared to Black defendants",
|
|
83
112
|
"s3_box2_title": "What Does This Mean?",
|
|
@@ -87,8 +116,8 @@ TRANSLATIONS = {
|
|
|
87
116
|
"lbl_black": "Black", # Used in dynamic construction if needed
|
|
88
117
|
# Step 4 EU
|
|
89
118
|
"s4eu_title": "🇪🇺 This Isn’t Just a US Problem",
|
|
90
|
-
"s4eu_head": "
|
|
91
|
-
"s4eu_intro": "The COMPAS story is not just an American warning. Across Europe, public authorities have experimented with <strong>very similar tools</strong>
|
|
119
|
+
"s4eu_head": "Europe Is Already Using AI to Predict Reoffending Risk",
|
|
120
|
+
"s4eu_intro": "The COMPAS story is not just an American warning. Across Europe, public authorities have experimented with <strong>very similar tools</strong> designed to predict who might reoffend or which areas are considered “high risk”.",
|
|
92
121
|
"s4eu_li1_title": "United Kingdom – HART (Harm Assessment Risk Tool)",
|
|
93
122
|
"s4eu_li1_body": "A machine-learning model used by Durham Police to predict who will reoffend within two years. It uses variables like age, gender, <em>postcode</em>, housing and job instability – socio-economic proxies that can reproduce the same kinds of biased patterns exposed in COMPAS.",
|
|
94
123
|
"s4eu_li2_title": "Spain – VioGén",
|
|
@@ -103,7 +132,7 @@ TRANSLATIONS = {
|
|
|
103
132
|
# Step 4 Lesson
|
|
104
133
|
"s4_title": "💡 The Critical Lesson",
|
|
105
134
|
"s4_box_title": "Why This Matters:",
|
|
106
|
-
"s4_li1_title": "
|
|
135
|
+
"s4_li1_title": "A model’s overall accuracy can hide group-specific harm",
|
|
107
136
|
"s4_li1_body": "A model might be 70% accurate overall — but the remaining 30% of errors can fall disproportionately on <span class='emph-harm'>specific groups</span>, resulting in real harm even when the total accuracy appears “good”.",
|
|
108
137
|
"s4_li2_title": "Historical bias in training data gets amplified",
|
|
109
138
|
"s4_li2_body": "If past policing or judicial decisions were biased, the AI system will <span class='emph-harm'>learn and reinforce</span> those inequities — often making them worse at scale.",
|
|
@@ -127,155 +156,155 @@ TRANSLATIONS = {
|
|
|
127
156
|
"btn_review": "◀️ Review the Investigation"
|
|
128
157
|
},
|
|
129
158
|
"es": {
|
|
130
|
-
"title": "🚀 La
|
|
159
|
+
"title": "🚀 La revelación ética: impacto real",
|
|
131
160
|
"loading_personal": "⏳ Cargando tu experiencia personalizada...",
|
|
132
|
-
"stats_title": "🏆 ¡Gran
|
|
133
|
-
"stats_subtitle": "Aquí
|
|
134
|
-
"stats_heading": "Tus
|
|
135
|
-
"lbl_accuracy": "Mejor
|
|
136
|
-
"lbl_rank": "Tu
|
|
161
|
+
"stats_title": "🏆 ¡Gran trabajo, ingeniero/a! 🏆",
|
|
162
|
+
"stats_subtitle": "Aquí tienes el resumen de tu rendimiento.",
|
|
163
|
+
"stats_heading": "Tus estadísticas",
|
|
164
|
+
"lbl_accuracy": "Mejor precisión",
|
|
165
|
+
"lbl_rank": "Tu rango",
|
|
137
166
|
"lbl_team": "Equipo",
|
|
138
167
|
"stats_footer": "¿Listo para compartir tu modelo y explorar su impacto en el mundo real?",
|
|
139
|
-
"btn_deploy": "🌍 Compartir tu
|
|
140
|
-
"guest_title": "🚀 ¡Has
|
|
168
|
+
"btn_deploy": "🌍 Compartir tu modelo de IA (simulación)",
|
|
169
|
+
"guest_title": "🚀 ¡Has iniciado sesión!",
|
|
141
170
|
"guest_subtitle": "Aún no has enviado un modelo, pero estás listo para seguir aprendiendo.",
|
|
142
171
|
"guest_body": "Una vez que envíes un modelo en el Juego de Construcción de Modelos, tu precisión y clasificación aparecerán aquí.",
|
|
143
172
|
"guest_footer": "Continúa a la siguiente sección cuando estés listo.",
|
|
144
173
|
"loading_session": "🔒 Cargando tu sesión...",
|
|
145
|
-
"s2_title": "⚠️ Pero
|
|
174
|
+
"s2_title": "⚠️ Pero espera...",
|
|
146
175
|
"s2_intro": "Antes de compartir el modelo, hay algo que necesitas saber...",
|
|
147
|
-
"s2_box_title": "Una
|
|
148
|
-
"s2_p1": "Un modelo similar al tuyo se
|
|
149
|
-
"s2_p2": "Como el tuyo, tenía puntuaciones de precisión impresionantes. Como el tuyo, se construyó con datos de casos criminales pasados. Como el tuyo, su objetivo era predecir
|
|
150
|
-
"s2_p3": "Pero algo
|
|
176
|
+
"s2_box_title": "Una historia del mundo real",
|
|
177
|
+
"s2_p1": "Un modelo similar al tuyo se empleó en situaciones reales. Jueces de todo Estados Unidos lo usaron para determinar si conceder la libertad condicional a personas presas.",
|
|
178
|
+
"s2_p2": "Como el tuyo, tenía puntuaciones de precisión impresionantes. Como el tuyo, se construyó con datos de casos criminales pasados. Como el tuyo, su objetivo era predecir quíen podría volver a cometer un delito..",
|
|
179
|
+
"s2_p3": "Pero algo iba muy mal...",
|
|
151
180
|
"btn_back": "◀️ Atrás",
|
|
152
|
-
"btn_reveal": "Revelar la
|
|
153
|
-
"s3_title": "📰 La
|
|
154
|
-
"s3_head": "\"
|
|
181
|
+
"btn_reveal": "Revelar la verdad ▶️",
|
|
182
|
+
"s3_title": "📰 La investigación de ProPublica",
|
|
183
|
+
"s3_head": "\"Machine Bias\" - Una investigación de referencia sobre los sesgos algorítmicos",
|
|
155
184
|
"s3_p1": "En 2016, periodistas de <strong>ProPublica</strong> investigaron un algoritmo de evaluación de riesgo criminal ampliamente utilizado llamado <strong>COMPAS</strong>. Analizaron más de <strong>7,000 casos reales</strong> para ver si las predicciones de la IA se cumplían.",
|
|
156
|
-
"s3_box_title": "Sus
|
|
157
|
-
"s3_alert": "⚠️
|
|
185
|
+
"s3_box_title": "Sus hallazgos impactantes:",
|
|
186
|
+
"s3_alert": "⚠️ Las personas negras presas fueron clasificadas como \"alto riesgo\" casi el <u>DOBLE</u> que las personas blancas presas.",
|
|
158
187
|
"s3_spec": "<strong>Específicamente:</strong>",
|
|
159
|
-
"s3_li1_pre": "
|
|
160
|
-
"s3_li2_pre": "
|
|
161
|
-
"s3_li3": "
|
|
162
|
-
"s3_box2_title": "¿Qué
|
|
163
|
-
"s3_mean_p1": "El sistema de IA
|
|
164
|
-
"s3_mean_p2": "
|
|
165
|
-
"btn_eu": "Ver
|
|
188
|
+
"s3_li1_pre": "Las <span class='emph-danger'>personas negras presas</span> que <em>NO volvieron a cometer un delito</em> fueron clasificadas incorrectamente como <strong>\"alto riesgo\"</strong> en aproximadamente un <strong>45%</strong> de los casos",
|
|
189
|
+
"s3_li2_pre": "Las <strong>personas blancas presas</strong> que <em>NO reincidieron</em> fueron clasificadas incorrectamente como <strong>\"alto riesgo\"</strong> solo en un <strong>24%</strong> de los casos",
|
|
190
|
+
"s3_li3": "En cambio, las <strong>personas blancas presas</strong> que <em>SÍ reincidieron</em> tenían <strong>más probabilidades de ser clasificadas como de \"bajo riesgo\"</strong> en comparación con las personas negras presas",
|
|
191
|
+
"s3_box2_title": "¿Qué significa esto?",
|
|
192
|
+
"s3_mean_p1": "El sistema de IA mostraba <strong class='emph-danger'>un sesgo sistemático</strong>. No solo cometía errores al azar; también hacía <strong>errores distintos según el grupo de personas</strong>.",
|
|
193
|
+
"s3_mean_p2": "Las personas negras presas enfrentaban un riesgo mucho mayor de ser <strong class='emph-danger'>injustamente classificadas como peligrosas</strong>, lo que potencialmente conducía a sentencias de prisión más largas o libertad condicional denegada, incluso cuando no habrían vuelto a cometer un delito.",
|
|
194
|
+
"btn_eu": "Ver esto en Europa ▶️",
|
|
166
195
|
"lbl_black": "Negros",
|
|
167
|
-
"s4eu_title": "🇪🇺 Esto
|
|
168
|
-
"s4eu_head": "
|
|
196
|
+
"s4eu_title": "🇪🇺 Esto no es solo un problema de EE. UU.",
|
|
197
|
+
"s4eu_head": "Europa ya utiliza IA para evaluar el riesgo de reincidencia",
|
|
169
198
|
"s4eu_intro": "La historia de COMPAS no es solo una advertencia estadounidense. En toda Europa, las autoridades públicas han experimentado con <strong>herramientas muy similares</strong> que pretenden predecir quién reincidirá o qué áreas son de \"alto riesgo\".",
|
|
170
199
|
"s4eu_li1_title": "Reino Unido – HART (Harm Assessment Risk Tool)",
|
|
171
200
|
"s4eu_li1_body": "Un modelo de aprendizaje automático utilizado por la Policía de Durham para predecir quién reincidirá en dos años. Utiliza variables como edad, género, <em>código postal</em>, vivienda e inestabilidad laboral: indicadores socioeconómicos que pueden reproducir los mismos tipos de patrones sesgados expuestos en COMPAS.",
|
|
172
201
|
"s4eu_li2_title": "España – VioGén",
|
|
173
|
-
"s4eu_li2_body": "Una herramienta de riesgo para casos de violencia de género cuyo funcionamiento interno es en gran medida una <em>\"caja negra\"</em>. Los oficiales dependen en gran medida de sus puntuaciones para decidir medidas de protección, aunque
|
|
202
|
+
"s4eu_li2_body": "Una herramienta de riesgo para casos de violencia de género cuyo funcionamiento interno es en gran medida una <em>\"caja negra\"</em>. Los oficiales dependen en gran medida de sus puntuaciones para decidir medidas de protección, aunque no se puede auditar fácilmente el algoritmo en busca de sesgos o errores.",
|
|
174
203
|
"s4eu_li3_title": "Países Bajos y Dinamarca – Perfiles predictivos",
|
|
175
|
-
"s4eu_li3_body": "Sistemas como el <em>
|
|
176
|
-
"s4eu_box_title": "Debate
|
|
204
|
+
"s4eu_li3_body": "Sistemas como el <em>Crime Anticipation System (CAS)</em> holandés y las clasificaciones algorítmicas de <em>\"guetos\"</em> de Dinamarca utilizan datos demográficos y socioeconómicos para orientar la vigilancia i las sanciones, con el riesgo de generar bucles de retroalimentación que señalen una y otra vez a las mismas comunidades.",
|
|
205
|
+
"s4eu_box_title": "Debate europeo en curso",
|
|
177
206
|
"s4eu_box_body": "La Fiscalía de Barcelona ha propuesto una \"calculadora electrónica de reincidencia\". Tribunales, reguladores e investigadores están examinando activamente cómo estas herramientas afectan los derechos fundamentales como la no discriminación, el juicio justo y la protección de datos.",
|
|
178
|
-
"s4eu_note": "<strong>
|
|
179
|
-
"btn_back_invest": "◀️ Volver a la
|
|
180
|
-
"btn_zoom": "
|
|
181
|
-
"s4_title": "💡 La
|
|
182
|
-
"s4_box_title": "Por
|
|
183
|
-
"s4_li1_title": "La precisión
|
|
184
|
-
"s4_li1_body": "Un modelo puede tener un 70% de precisión
|
|
207
|
+
"s4eu_note": "<strong>Idea clave:</strong> Los riesgos que viste con COMPAS no están lejos ni son ajenos. <strong class='emph-key'>Son cuestiones pleanmente actuales tanto en Europa como en los EE. UU.</strong>",
|
|
208
|
+
"btn_back_invest": "◀️ Volver a la investigación",
|
|
209
|
+
"btn_zoom": "Vista general de la lección ▶️",
|
|
210
|
+
"s4_title": "💡 La lección fundamental",
|
|
211
|
+
"s4_box_title": "Por qué importa esto:",
|
|
212
|
+
"s4_li1_title": "La precisión global de un modelo puede ocultar daños específicos por grupo",
|
|
213
|
+
"s4_li1_body": "Un modelo puede tener un 70% de precisión global, pero el 30% restante de errores puede concentrarse de manera desproporcionada en <span class='emph-harm'>grupos concretos</span>, causando daños reales incluso cuando la precisión global parece \"buena\".",
|
|
185
214
|
"s4_li2_title": "El sesgo histórico en los datos de entrenamiento se amplifica",
|
|
186
|
-
"s4_li2_body": "Si las decisiones policiales o judiciales pasadas fueron sesgadas, el sistema de IA <span class='emph-harm'>aprenderá y reforzará</span> esas desigualdades, a menudo
|
|
215
|
+
"s4_li2_body": "Si las decisiones policiales o judiciales pasadas fueron sesgadas, el sistema de IA <span class='emph-harm'>aprenderá y reforzará</span> esas desigualdades, y a menudo las amplificará a gran escala.",
|
|
187
216
|
"s4_li3_title": "Las vidas de personas reales se ven afectadas",
|
|
188
|
-
"s4_li3_body": "Cada <strong class='emph-harm'>\"falso positivo\"</strong> representa a una persona que puede perder años de libertad, empleo, vivienda o conexión familiar, todo
|
|
217
|
+
"s4_li3_body": "Cada <strong class='emph-harm'>\"falso positivo\"</strong> representa a una persona que puede perder años de libertad, empleo, vivienda o conexión familiar, todo a causa de una sola <strong class='emph-harm'>predicción sesgada</strong>.",
|
|
189
218
|
"btn_back_eu": "◀️ Atrás",
|
|
190
|
-
"btn_what_do": "¿Qué
|
|
191
|
-
"s5_title": "🛤️ El
|
|
192
|
-
"s5_head": "De la
|
|
193
|
-
"s5_intro": "
|
|
194
|
-
"s5_li1": "✅
|
|
195
|
-
"s5_li2": "⚠️
|
|
219
|
+
"btn_what_do": "¿Qué podemos hacer? ▶️",
|
|
220
|
+
"s5_title": "🛤️ El camino a seguir",
|
|
221
|
+
"s5_head": "De la precisión a la ética",
|
|
222
|
+
"s5_intro": "Ya has visto los dos lados de la IA:",
|
|
223
|
+
"s5_li1": "✅ Has construido modelos con altos niveles de precisión",
|
|
224
|
+
"s5_li2": "⚠️ Has aprendido cómo modelos similares han causado daños reales",
|
|
196
225
|
"s5_li3": "🤔 Entiendes que la precisión por sí sola no es suficiente",
|
|
197
|
-
"s5_box_title": "Lo
|
|
226
|
+
"s5_box_title": "Lo que harás a continuación:",
|
|
198
227
|
"s5_p1": "En la siguiente sección, se te presentará una <strong class='emph-key'>nueva forma de medir el éxito</strong>, una que equilibra el rendimiento con la equidad y la ética.",
|
|
199
228
|
"s5_p2": "Aprenderás técnicas para <strong class='emph-key'>detectar sesgos</strong> en tus modelos, <strong class='emph-key'>medir la equidad</strong> en diferentes grupos y <strong class='emph-key'>rediseñar tu IA</strong> para minimizar el daño.",
|
|
200
|
-
"s5_mission": "🎯 Tu nueva misión: Construir IA que no solo sea precisa, sino también <strong class='emph-key'>justa, equitativa y éticamente sólida</strong>.",
|
|
229
|
+
"s5_mission": "🎯 Tu nueva misión: Construir una IA que no solo sea precisa, sino también <strong class='emph-key'>justa, equitativa y éticamente sólida</strong>.",
|
|
201
230
|
"s5_scroll": "👇 DESPLÁZATE HACIA ABAJO 👇",
|
|
202
|
-
"s5_continue": "Continúa en la siguiente sección
|
|
231
|
+
"s5_continue": "Continúa en la siguiente sección para comenzar tu viaje de IA ética.",
|
|
203
232
|
"btn_review": "◀️ Revisar la Investigación"
|
|
204
233
|
},
|
|
205
234
|
"ca": {
|
|
206
|
-
"title": "🚀 La
|
|
235
|
+
"title": "🚀 La revelació ètica: impacte real",
|
|
207
236
|
"loading_personal": "⏳ Carregant la teva experiència personalitzada...",
|
|
208
|
-
"stats_title": "🏆 Bona
|
|
237
|
+
"stats_title": "🏆 Bona feina, enginyer/a! 🏆",
|
|
209
238
|
"stats_subtitle": "Aquí tens el teu resum de rendiment.",
|
|
210
|
-
"stats_heading": "Les
|
|
211
|
-
"lbl_accuracy": "Millor
|
|
212
|
-
"lbl_rank": "El
|
|
239
|
+
"stats_heading": "Les teves estadístiques",
|
|
240
|
+
"lbl_accuracy": "Millor precisió",
|
|
241
|
+
"lbl_rank": "El teu rang",
|
|
213
242
|
"lbl_team": "Equip",
|
|
214
243
|
"stats_footer": "A punt per compartir el teu model i explorar el seu impacte al món real?",
|
|
215
|
-
"btn_deploy": "🌍 Compartir el
|
|
216
|
-
"guest_title": "🚀 Has
|
|
244
|
+
"btn_deploy": "🌍 Compartir el teu model d'IA (simulació)",
|
|
245
|
+
"guest_title": "🚀 Has iniciat sessió!",
|
|
217
246
|
"guest_subtitle": "Encara no has enviat un model, però estàs a punt per continuar aprenent.",
|
|
218
247
|
"guest_body": "Un cop enviïs un model al Joc de Construcció de Models, la teva precisió i classificació apareixeran aquí.",
|
|
219
248
|
"guest_footer": "Continua a la següent secció quan estiguis a punt.",
|
|
220
249
|
"loading_session": "🔒 Carregant la teva sessió...",
|
|
221
|
-
"s2_title": "⚠️ Però
|
|
222
|
-
"s2_intro": "Abans de compartir el model, hi ha una cosa que
|
|
223
|
-
"s2_box_title": "Una
|
|
224
|
-
"s2_p1": "Un model similar al teu es va utilitzar
|
|
225
|
-
"s2_p2": "Com el teu, tenia puntuacions de precisió impressionants. Com el teu, es va construir amb dades de casos criminals passats. Com el teu, el seu objectiu era predir qui
|
|
226
|
-
"s2_p3": "Però alguna cosa
|
|
250
|
+
"s2_title": "⚠️ Però espera...",
|
|
251
|
+
"s2_intro": "Abans de compartir el model, hi ha una cosa que hauries de saber...",
|
|
252
|
+
"s2_box_title": "Una història del món real",
|
|
253
|
+
"s2_p1": "Un model similar al teu es va utilitzar en situacions reals. Jutges d’arreu dels Estats Units el van fer servir per determinar si concedir la llibertat condicional a persones preses.",
|
|
254
|
+
"s2_p2": "Com el teu, tenia puntuacions de precisió impressionants. Com el teu, es va construir amb dades de casos criminals passats. Com el teu, el seu objectiu era predir qui podria tornar a cometre un delicte.",
|
|
255
|
+
"s2_p3": "Però alguna cosa no anava bé...",
|
|
227
256
|
"btn_back": "◀️ Enrere",
|
|
228
|
-
"btn_reveal": "Revelar la
|
|
229
|
-
"s3_title": "📰 La
|
|
230
|
-
"s3_head": "\"
|
|
231
|
-
"s3_p1": "El 2016, periodistes de <strong>ProPublica</strong> van
|
|
232
|
-
"s3_box_title": "Les
|
|
233
|
-
"s3_alert": "⚠️
|
|
234
|
-
"s3_spec": "<strong>
|
|
235
|
-
"s3_li1_pre": "
|
|
236
|
-
"s3_li2_pre": "
|
|
237
|
-
"s3_li3": "
|
|
238
|
-
"s3_box2_title": "Què
|
|
239
|
-
"s3_mean_p1": "El sistema d'IA estava <strong class='emph-danger'>sistemàticament esbiaixat</strong>. No només cometia errors aleatoris, cometia <strong>diferents tipus d'errors
|
|
240
|
-
"s3_mean_p2": "
|
|
241
|
-
"btn_eu": "Veure
|
|
257
|
+
"btn_reveal": "Revelar la veritat ▶️",
|
|
258
|
+
"s3_title": "📰 La investigació de ProPublica",
|
|
259
|
+
"s3_head": "\"Machine Bias\" - Una investigació de referència sobre els biaixos algorítmics",
|
|
260
|
+
"s3_p1": "El 2016, periodistes de <strong>ProPublica</strong> van analitzar un algoritme d’avaluació del risc penal molt estès anomenat <strong>COMPAS</strong>. Van estudiar més de <strong>7.000 casos reals</strong> per veure si les prediccions de la IA es complien.",
|
|
261
|
+
"s3_box_title": "Les seves troballes més impactants:",
|
|
262
|
+
"s3_alert": "⚠️ Les persones negres preses eren classificades com a \"alt risc\" gairebé el <u>DOBLE</u> que les persones blanques preses.",
|
|
263
|
+
"s3_spec": "<strong>En concret:</strong>",
|
|
264
|
+
"s3_li1_pre": "Les <span class='emph-danger'>persones negres preses</span> que <em>NO van tornar a cometre un delicte</em> van ser classificades incorrectament com a <strong>\"alt risc\"</strong> en aproximadament el <strong>45%</strong> dels casos.",
|
|
265
|
+
"s3_li2_pre": "Les <strong>persones blanques preses</strong> que <em>NO van reincidir</em> van ser classificades incorrectament com a <strong>\"alt risc\"</strong> en només el <strong>24%</strong> dels casos.",
|
|
266
|
+
"s3_li3": "En canvi, les <strong>persones blanques preses</strong> que <em>SÍ van reincidir</em> tenien <strong>més probabilitats de ser classificades com a \"baix risc\"</strong> en comparació amb les persones negres preses.",
|
|
267
|
+
"s3_box2_title": "Què significa això?",
|
|
268
|
+
"s3_mean_p1": "El sistema d'IA estava <strong class='emph-danger'>sistemàticament esbiaixat</strong>. No només cometia errors aleatoris, cometia <strong>diferents tipus d'errors segons el grup de persones</strong>.",
|
|
269
|
+
"s3_mean_p2": "Les persones negres preses s'enfrontaven a un risc molt més gran de ser <strong class='emph-danger'>injustament classificats com a perillosos</strong>, la qual cosa que podia comportar penes de presó més llargues o que se’ls denegués la llibertat condicional, fins i tot quan no haurien tornat a cometre un delicte.",
|
|
270
|
+
"btn_eu": "Veure això a Europa ▶️",
|
|
242
271
|
"lbl_black": "Negres",
|
|
243
|
-
"s4eu_title": "🇪🇺 Això
|
|
244
|
-
"s4eu_head": "
|
|
272
|
+
"s4eu_title": "🇪🇺 Això no és només un problema dels EUA",
|
|
273
|
+
"s4eu_head": "Europa ja utilitza IA per avaluar el risc de reincidència",
|
|
245
274
|
"s4eu_intro": "La història de COMPAS no és només una advertència nord-americana. A tota Europa, les autoritats públiques han experimentat amb <strong>eines molt similars</strong> que pretenen predir qui reincidirà o quines àrees són d'\"alt risc\".",
|
|
246
275
|
"s4eu_li1_title": "Regne Unit – HART (Harm Assessment Risk Tool)",
|
|
247
276
|
"s4eu_li1_body": "Un model d'aprenentatge automàtic utilitzat per la Policia de Durham per predir qui reincidirà en dos anys. Utilitza variables com edat, gènere, <em>codi postal</em>, habitatge i inestabilitat laboral: indicadors socioeconòmics que poden reproduir els mateixos tipus de patrons esbiaixats exposats a COMPAS.",
|
|
248
277
|
"s4eu_li2_title": "Espanya – VioGén",
|
|
249
|
-
"s4eu_li2_body": "Una eina de risc per a casos de violència de gènere
|
|
278
|
+
"s4eu_li2_body": "Una eina de risc per a casos de violència de gènere, amb processos interns que són, en gran part, una <em>\"caixa negra\"</em>. Les autoritats depenen àmpliament de les seves puntuacions per decidir mesures de protecció, tot i que l’algoritme no es pot auditar fàcilment per detectar biaixos o errors.",
|
|
250
279
|
"s4eu_li3_title": "Països Baixos i Dinamarca – Perfils predictius",
|
|
251
|
-
"s4eu_li3_body": "Sistemes com el <em>
|
|
252
|
-
"s4eu_box_title": "Debat
|
|
280
|
+
"s4eu_li3_body": "Sistemes com el <em>Crime Anticipation System (CAS)</em> holandès i les classificacions algorítmiques de <em>\"guetos\"</em> de Dinamarca utilitzen dades demogràfiques i socioeconòmiques per orientar la vigilància i les sancions, amb el risc de generar bucles de retroalimentació que assenyalen una i altra vegada les mateixes comunitats.",
|
|
281
|
+
"s4eu_box_title": "Debat europeu en curs",
|
|
253
282
|
"s4eu_box_body": "La Fiscalia de Barcelona ha proposat una \"calculadora electrònica de reincidència\". Tribunals, reguladors i investigadors estan examinant activament com aquestes eines afecten els drets fonamentals com la no discriminació, el judici just i la protecció de dades.",
|
|
254
|
-
"s4eu_note": "<strong>Punt clau:</strong> Els riscos que vas veure amb COMPAS no són lluny
|
|
255
|
-
"btn_back_invest": "◀️ Tornar a la
|
|
256
|
-
"btn_zoom": "
|
|
257
|
-
"s4_title": "💡 La
|
|
258
|
-
"s4_box_title": "Per
|
|
259
|
-
"s4_li1_title": "La precisió
|
|
260
|
-
"s4_li1_body": "Un model pot tenir un 70% de precisió
|
|
283
|
+
"s4eu_note": "<strong>Punt clau:</strong> Els riscos que vas veure amb COMPAS no són lluny ni aliens. <strong class='emph-key'>Són qüestions plenament actuals tant a Europa com als EUA.</strong>",
|
|
284
|
+
"btn_back_invest": "◀️ Tornar a la investigació",
|
|
285
|
+
"btn_zoom": "Vista general de la Lliçó ▶️",
|
|
286
|
+
"s4_title": "💡 La lliçó crítica",
|
|
287
|
+
"s4_box_title": "Per què és important això:",
|
|
288
|
+
"s4_li1_title": "La precisió global d'un model pot amagar danys específics a grups concrets",
|
|
289
|
+
"s4_li1_body": "Un model pot tenir un 70% de precisió global, però el 30% restant d'errors pot recaure desproporcionadament en <span class='emph-harm'>determinats grups</span>, provocant danys reals fins i tot quan la precisió global sembla \"bona\".",
|
|
261
290
|
"s4_li2_title": "El biaix històric en les dades d'entrenament s'amplifica",
|
|
262
|
-
"s4_li2_body": "Si les decisions policials o judicials passades van ser esbiaixades, el sistema d'IA <span class='emph-harm'>aprendrà i reforçarà</span> aquestes desigualtats, sovint
|
|
291
|
+
"s4_li2_body": "Si les decisions policials o judicials passades van ser esbiaixades, el sistema d'IA <span class='emph-harm'>aprendrà i reforçarà</span> aquestes desigualtats, i sovint les amplificarà.",
|
|
263
292
|
"s4_li3_title": "Les vides de persones reals es veuen afectades",
|
|
264
|
-
"s4_li3_body": "Cada <strong class='emph-harm'>\"fals positiu\"</strong> representa una persona que pot perdre anys de llibertat, feina, habitatge o connexió familiar, tot
|
|
293
|
+
"s4_li3_body": "Cada <strong class='emph-harm'>\"fals positiu\"</strong> representa una persona que pot perdre anys de llibertat, feina, habitatge o connexió familiar, tot per una única <strong class='emph-harm'>predicció esbiaixada</strong>.",
|
|
265
294
|
"btn_back_eu": "◀️ Enrere",
|
|
266
|
-
"btn_what_do": "Què
|
|
267
|
-
"s5_title": "🛤️ El
|
|
268
|
-
"s5_head": "De la
|
|
269
|
-
"s5_intro": "Ara has vist els dos costats de la
|
|
270
|
-
"s5_li1": "✅
|
|
271
|
-
"s5_li2": "⚠️
|
|
295
|
+
"btn_what_do": "Què podem fer? ▶️",
|
|
296
|
+
"s5_title": "🛤️ El camí a seguir",
|
|
297
|
+
"s5_head": "De la precisió a l'ètica",
|
|
298
|
+
"s5_intro": "Ara ja has vist els dos costats de la IA:",
|
|
299
|
+
"s5_li1": "✅ Has construït models amb alts nivells de precisió",
|
|
300
|
+
"s5_li2": "⚠️ Has après com models similars han causat danys reals",
|
|
272
301
|
"s5_li3": "🤔 Entens que la precisió per si sola no és suficient",
|
|
273
|
-
"s5_box_title": "
|
|
302
|
+
"s5_box_title": "Què faràs a continuació:",
|
|
274
303
|
"s5_p1": "En la següent secció, se't presentarà una <strong class='emph-key'>nova manera de mesurar l'èxit</strong>, una que equilibra el rendiment amb l'equitat i l'ètica.",
|
|
275
304
|
"s5_p2": "Aprendràs tècniques per <strong class='emph-key'>detectar biaixos</strong> en els teus models, <strong class='emph-key'>mesurar l'equitat</strong> en diferents grups i <strong class='emph-key'>redissenyar la teva IA</strong> per minimitzar el dany.",
|
|
276
|
-
"s5_mission": "🎯 La teva nova missió: Construir IA que no només sigui precisa, sinó també <strong class='emph-key'>justa, equitativa i èticament sòlida</strong>.",
|
|
305
|
+
"s5_mission": "🎯 La teva nova missió: Construir una IA que no només sigui precisa, sinó també <strong class='emph-key'>justa, equitativa i èticament sòlida</strong>.",
|
|
277
306
|
"s5_scroll": "👇 DESPLAÇA'T CAP AVALL 👇",
|
|
278
|
-
"s5_continue": "Continua
|
|
307
|
+
"s5_continue": "Continua amb la següent secció per iniciar el teu recorregut cap a una IA ètica.",
|
|
279
308
|
"btn_review": "◀️ Revisar la Investigació"
|
|
280
309
|
}
|
|
281
310
|
}
|
|
@@ -293,6 +322,48 @@ def _normalize_team_name(name: str) -> str:
|
|
|
293
322
|
return ""
|
|
294
323
|
return " ".join(str(name).strip().split())
|
|
295
324
|
|
|
325
|
+
# NEW: Team name translation helpers for UI display
|
|
326
|
+
def translate_team_name_for_display(team_en: str, lang: str = "en") -> str:
|
|
327
|
+
"""
|
|
328
|
+
Translate a canonical English team name to the specified language for UI display.
|
|
329
|
+
Fallback to English if translation not found.
|
|
330
|
+
"""
|
|
331
|
+
if lang not in TEAM_NAME_TRANSLATIONS:
|
|
332
|
+
lang = "en"
|
|
333
|
+
return TEAM_NAME_TRANSLATIONS[lang].get(team_en, team_en)
|
|
334
|
+
|
|
335
|
+
# NEW: Reverse lookup for future use (e.g., if user input needs to be normalized back to English)
|
|
336
|
+
def translate_team_name_to_english(display_name: str, lang: str = "en") -> str:
|
|
337
|
+
"""
|
|
338
|
+
Reverse lookup: given a localized team name, return the canonical English name.
|
|
339
|
+
Returns the original display_name if not found.
|
|
340
|
+
"""
|
|
341
|
+
if lang not in TEAM_NAME_TRANSLATIONS:
|
|
342
|
+
return display_name # Already English or unknown
|
|
343
|
+
|
|
344
|
+
translations = TEAM_NAME_TRANSLATIONS[lang]
|
|
345
|
+
for english_name, localized_name in translations.items():
|
|
346
|
+
if localized_name == display_name:
|
|
347
|
+
return english_name
|
|
348
|
+
return display_name # UPDATED: Return display_name instead of None for consistency
|
|
349
|
+
|
|
350
|
+
# NEW: Format leaderboard DataFrame with localized team names (non-destructive copy)
|
|
351
|
+
def _format_leaderboard_for_display(df: Optional[pd.DataFrame], lang: str = "en") -> Optional[pd.DataFrame]:
|
|
352
|
+
"""
|
|
353
|
+
Create a copy of the leaderboard DataFrame with team names translated for display.
|
|
354
|
+
Does not mutate the original DataFrame.
|
|
355
|
+
For potential future use when displaying full leaderboard.
|
|
356
|
+
"""
|
|
357
|
+
if df is None:
|
|
358
|
+
return None # UPDATED: Handle None explicitly
|
|
359
|
+
|
|
360
|
+
if df.empty or "Team" not in df.columns:
|
|
361
|
+
return df.copy() # UPDATED: Return copy for empty or missing Team column
|
|
362
|
+
|
|
363
|
+
df_display = df.copy()
|
|
364
|
+
df_display["Team"] = df_display["Team"].apply(lambda t: translate_team_name_for_display(t, lang))
|
|
365
|
+
return df_display
|
|
366
|
+
|
|
296
367
|
def _fetch_leaderboard(token: str) -> Optional[pd.DataFrame]:
|
|
297
368
|
now = time.time()
|
|
298
369
|
with _cache_lock:
|
|
@@ -423,7 +494,8 @@ def build_stats_html(user_stats: Dict[str, Any], lang="en") -> str:
|
|
|
423
494
|
if user_stats.get("best_score") is not None:
|
|
424
495
|
best_score_pct = f"{(user_stats['best_score'] * 100):.1f}%"
|
|
425
496
|
rank_text = f"#{user_stats['rank']}" if user_stats['rank'] else "N/A"
|
|
426
|
-
|
|
497
|
+
# UPDATED: Translate team name for display based on selected language
|
|
498
|
+
team_text = translate_team_name_for_display(user_stats['team_name'], lang) if user_stats['team_name'] else "N/A"
|
|
427
499
|
return f"""
|
|
428
500
|
<div class='slide-shell slide-shell--primary'>
|
|
429
501
|
<div style='text-align:center;'>
|
|
@@ -536,7 +608,6 @@ def _get_step3_html(lang):
|
|
|
536
608
|
<ul style='font-size:1.05rem; line-height:1.8;'>
|
|
537
609
|
<li>
|
|
538
610
|
{t(lang, 's3_li1_pre')}
|
|
539
|
-
<span class='emph-danger'> 45%</span>
|
|
540
611
|
</li>
|
|
541
612
|
<li>
|
|
542
613
|
{t(lang, 's3_li2_pre')}
|
|
@@ -773,74 +844,93 @@ def create_ethical_revelation_app(theme_primary_hue: str = "indigo") -> "gr.Bloc
|
|
|
773
844
|
loading_screen = gr.Column(visible=False)
|
|
774
845
|
all_steps = [step_1, step_2, step_3, step_4_eu, step_4, step_5, loading_screen, initial_loading]
|
|
775
846
|
|
|
776
|
-
#
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
# Return all UI updates
|
|
847
|
+
# -------------------------------------------------------------------------
|
|
848
|
+
# HYBRID CACHING LOGIC
|
|
849
|
+
# -------------------------------------------------------------------------
|
|
850
|
+
|
|
851
|
+
# 1. Define all targets that need updating
|
|
852
|
+
update_targets = [
|
|
853
|
+
initial_loading, step_1, stats_display, c_title, c_loading_text,
|
|
854
|
+
deploy_button,
|
|
855
|
+
c_s2_title, c_s2_html, step_2_back, step_2_next,
|
|
856
|
+
c_s3_title, c_s3_html, step_3_back, step_3_next,
|
|
857
|
+
c_s4eu_title, c_s4eu_html, step_4_eu_back, step_4_eu_next,
|
|
858
|
+
c_s4_title, c_s4_html, step_4_back, step_4_next,
|
|
859
|
+
c_s5_title, c_s5_html, back_to_lesson_btn
|
|
860
|
+
]
|
|
861
|
+
|
|
862
|
+
# 2. Cached Generator for Static Content (Steps 2-5)
|
|
863
|
+
@lru_cache(maxsize=16)
|
|
864
|
+
def get_cached_static_content(lang):
|
|
865
|
+
"""
|
|
866
|
+
Generates the heavy HTML for Steps 2, 3, 4, and 5 once per language.
|
|
867
|
+
"""
|
|
798
868
|
return [
|
|
799
|
-
|
|
800
|
-
gr.update(visible=True), # step_1
|
|
801
|
-
gr.update(value=stats_html), # stats_display
|
|
802
|
-
# Title
|
|
803
|
-
f"<h1 style='text-align:center;'>{t(lang, 'title')}</h1>",
|
|
804
|
-
# Loading Text
|
|
805
|
-
f"<div style='text-align:center; padding:80px 0;'><h2>{t(lang, 'loading_personal')}</h2></div>",
|
|
806
|
-
# Step 1 Button
|
|
869
|
+
# Step 1 Button (Static Text)
|
|
807
870
|
gr.Button(value=t(lang, 'btn_deploy')),
|
|
871
|
+
|
|
808
872
|
# Step 2
|
|
809
873
|
f"<h2 style='text-align:center;'>{t(lang, 's2_title')}</h2>",
|
|
810
874
|
_get_step2_html(lang),
|
|
811
875
|
gr.Button(value=t(lang, 'btn_back')),
|
|
812
876
|
gr.Button(value=t(lang, 'btn_reveal')),
|
|
877
|
+
|
|
813
878
|
# Step 3
|
|
814
879
|
f"<h2 style='text-align:center;'>{t(lang, 's3_title')}</h2>",
|
|
815
880
|
_get_step3_html(lang),
|
|
816
881
|
gr.Button(value=t(lang, 'btn_back')),
|
|
817
882
|
gr.Button(value=t(lang, 'btn_eu')),
|
|
883
|
+
|
|
818
884
|
# Step 4 EU
|
|
819
885
|
f"<h2 style='text-align:center;'>{t(lang, 's4eu_title')}</h2>",
|
|
820
886
|
_get_step4_eu_html(lang),
|
|
821
887
|
gr.Button(value=t(lang, 'btn_back_invest')),
|
|
822
888
|
gr.Button(value=t(lang, 'btn_zoom')),
|
|
889
|
+
|
|
823
890
|
# Step 4 Lesson
|
|
824
891
|
f"<h2 style='text-align:center;'>{t(lang, 's4_title')}</h2>",
|
|
825
892
|
_get_step4_lesson_html(lang),
|
|
826
893
|
gr.Button(value=t(lang, 'btn_back_eu')),
|
|
827
894
|
gr.Button(value=t(lang, 'btn_what_do')),
|
|
895
|
+
|
|
828
896
|
# Step 5
|
|
829
897
|
f"<h2 style='text-align:center;'>{t(lang, 's5_title')}</h2>",
|
|
830
898
|
_get_step5_html(lang),
|
|
831
899
|
gr.Button(value=t(lang, 'btn_review'))
|
|
832
900
|
]
|
|
833
901
|
|
|
834
|
-
# Load
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
902
|
+
# 3. Hybrid Load Function
|
|
903
|
+
def initial_load(request: gr.Request):
|
|
904
|
+
params = request.query_params
|
|
905
|
+
lang = params.get("lang", "en")
|
|
906
|
+
if lang not in TRANSLATIONS: lang = "en"
|
|
907
|
+
|
|
908
|
+
# --- DYNAMIC PART (Runs every time) ---
|
|
909
|
+
success, username, token = _try_session_based_auth(request)
|
|
910
|
+
|
|
911
|
+
stats_html = ""
|
|
912
|
+
if success and username:
|
|
913
|
+
stats = _compute_user_stats(username, token)
|
|
914
|
+
stats_html = build_stats_html(stats, lang)
|
|
915
|
+
else:
|
|
916
|
+
stats_html = f"""
|
|
917
|
+
<div class='slide-shell slide-shell--primary' style='text-align:center;'>
|
|
918
|
+
<h2 class='slide-shell__title'>{t(lang, 'loading_session')}</h2>
|
|
919
|
+
</div>
|
|
920
|
+
"""
|
|
921
|
+
|
|
922
|
+
# --- STATIC PART (Fetched from Cache) ---
|
|
923
|
+
static_updates = get_cached_static_content(lang)
|
|
924
|
+
|
|
925
|
+
# Combine: Dynamic + Static
|
|
926
|
+
return [
|
|
927
|
+
gr.update(visible=False), # initial_loading
|
|
928
|
+
gr.update(visible=True), # step_1
|
|
929
|
+
gr.update(value=stats_html), # stats_display (DYNAMIC)
|
|
930
|
+
f"<h1 style='text-align:center;'>{t(lang, 'title')}</h1>", # Title
|
|
931
|
+
f"<div style='text-align:center; padding:80px 0;'><h2>{t(lang, 'loading_personal')}</h2></div>", # Loading Text
|
|
932
|
+
] + static_updates
|
|
933
|
+
|
|
844
934
|
demo.load(fn=initial_load, inputs=None, outputs=update_targets)
|
|
845
935
|
|
|
846
936
|
# --- Navigation Logic ---
|