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
|
@@ -5,6 +5,7 @@ Updated with i18n support for English (en), Spanish (es), and Catalan (ca).
|
|
|
5
5
|
import contextlib
|
|
6
6
|
import os
|
|
7
7
|
import gradio as gr
|
|
8
|
+
from functools import lru_cache
|
|
8
9
|
|
|
9
10
|
# -------------------------------------------------------------------------
|
|
10
11
|
# TRANSLATION CONFIGURATION
|
|
@@ -51,7 +52,7 @@ TRANSLATIONS = {
|
|
|
51
52
|
"s3_title": "🧠 How Does an AI Model Learn?",
|
|
52
53
|
"s3_h1": "1. It Learns from Examples",
|
|
53
54
|
"s3_p1": "An AI model isn't programmed with answers. Instead, it's trained on a huge number of examples, and it learns how to find the answers on its own.",
|
|
54
|
-
"s3_p2": "In our justice scenario, this means feeding the model thousands of past cases (<b>examples</b>) to teach it how to find the <b>patterns</b> that connect a person's details to their
|
|
55
|
+
"s3_p2": "In our justice scenario, this means feeding the model thousands of past cases (<b>examples</b>) to teach it how to find the <b>patterns</b> that connect a person's details to their risk of re-offending.",
|
|
55
56
|
"s3_h2": "2. The Training Process",
|
|
56
57
|
"s3_p3": "The AI \"trains\" by looping through historical data (past cases) millions of times:",
|
|
57
58
|
"flow_1": "1. INPUT<br>EXAMPLES",
|
|
@@ -65,7 +66,7 @@ TRANSLATIONS = {
|
|
|
65
66
|
"btn_next_try": "Next: Try It Yourself ▶️",
|
|
66
67
|
# Step 4 (Interactive)
|
|
67
68
|
"s4_title": "🎮 Try It Yourself!",
|
|
68
|
-
"s4_intro": "<b>Let's use a simple AI model to predict
|
|
69
|
+
"s4_intro": "<b>Let's use a simple AI model to predict risk of re-offending.</b><br>Adjust the inputs below and see how the model's prediction changes!",
|
|
69
70
|
"s4_sect1": "1️⃣ INPUT: Adjust the Data",
|
|
70
71
|
"lbl_age": "Age",
|
|
71
72
|
"info_age": "Defendant's age",
|
|
@@ -94,7 +95,7 @@ TRANSLATIONS = {
|
|
|
94
95
|
"s5_li1": "The <b>input data</b> might contain historical biases",
|
|
95
96
|
"s5_li2": "The <b>model</b> learns patterns from potentially unfair past decisions",
|
|
96
97
|
"s5_li3": "The <b>output predictions</b> can perpetuate discrimination",
|
|
97
|
-
"s5_final": "<b>Understanding how AI works is the first step to building fairer systems.</b><br><br>Now that you know
|
|
98
|
+
"s5_final": "<b>Understanding how AI works is the first step to building fairer systems.</b><br><br>Now that you know the basics of AI, you're ready to help design better models that are more ethical and less biased!",
|
|
98
99
|
"btn_complete": "Complete This Section ▶️",
|
|
99
100
|
# Step 6
|
|
100
101
|
"s6_title": "🎓 You Now Understand the Basics of AI!",
|
|
@@ -116,135 +117,135 @@ TRANSLATIONS = {
|
|
|
116
117
|
"risk_score": "Risk Score:"
|
|
117
118
|
},
|
|
118
119
|
"es": {
|
|
119
|
-
"title": "🤖 ¿
|
|
120
|
+
"title": "🤖 Pero, ¿qué es la IA, en realidad?",
|
|
120
121
|
"intro_box": "Antes de poder construir mejores sistemas de IA, necesitas entender qué es realmente la IA.<br>No te preocupes, ¡lo explicaremos en términos simples y cotidianos!",
|
|
121
122
|
"loading": "⏳ Cargando...",
|
|
122
123
|
# Step 1
|
|
123
|
-
"s1_title": "🎯 Una
|
|
124
|
+
"s1_title": "🎯 Una definición simple",
|
|
124
125
|
"s1_head": "Inteligencia Artificial (IA) es solo un nombre elegante para:",
|
|
125
126
|
"s1_big": "Un sistema que hace predicciones basadas en patrones",
|
|
126
127
|
"s1_sub": "¡Eso es todo! Desglosemos qué significa eso...",
|
|
127
128
|
"s1_list_title": "Piensa en cómo TÚ haces predicciones:",
|
|
128
|
-
"s1_li1": "<b>
|
|
129
|
-
"s1_li2": "<b>Tráfico:</b> Hora
|
|
130
|
-
"s1_li3": "<b>
|
|
129
|
+
"s1_li1": "<b>Tiempo:</b> Nubes oscuras → Predices lluvia → Llevas paraguas",
|
|
130
|
+
"s1_li2": "<b>Tráfico:</b> Hora punta → Predices congestión → Sales temprano",
|
|
131
|
+
"s1_li3": "<b>Película:</b> Actor que te gusta → Predices que te gustará → La ves",
|
|
131
132
|
"s1_highlight": "La IA hace lo mismo, pero usando datos y matemáticas en lugar de experiencia humana e intuición.",
|
|
132
|
-
"btn_next_formula": "Siguiente: La
|
|
133
|
+
"btn_next_formula": "Siguiente: La fórmula de la IA ▶️",
|
|
133
134
|
# Step 2
|
|
134
|
-
"s2_title": "📐
|
|
135
|
+
"s2_title": "📐 Las tres partes de la fórmula",
|
|
135
136
|
"s2_intro": "Todo sistema de IA funciona de la misma manera, siguiendo esta fórmula simple:",
|
|
136
137
|
"lbl_input": "ENTRADA",
|
|
137
138
|
"lbl_model": "MODELO",
|
|
138
139
|
"lbl_output": "SALIDA",
|
|
139
140
|
"desc_input": "Entran datos",
|
|
140
|
-
"desc_model": "IA procesa",
|
|
141
|
-
"desc_output": "Sale predicción",
|
|
142
|
-
"s2_ex_title": "Ejemplos del
|
|
141
|
+
"desc_model": "La IA los procesa",
|
|
142
|
+
"desc_output": "Sale la predicción",
|
|
143
|
+
"s2_ex_title": "Ejemplos del mundo real:",
|
|
143
144
|
"s2_ex1_in": "Foto de un perro",
|
|
144
|
-
"s2_ex1_mod": "IA de reconocimiento de
|
|
145
|
+
"s2_ex1_mod": "IA de reconocimiento de imágenes",
|
|
145
146
|
"s2_ex1_out": "\"Esto es un Golden Retriever\"",
|
|
146
|
-
"s2_ex2_in": "\"¿Qué
|
|
147
|
+
"s2_ex2_in": "\"¿Qué tiempo hace?\"",
|
|
147
148
|
"s2_ex2_mod": "IA de lenguaje (como ChatGPT)",
|
|
148
149
|
"s2_ex2_out": "Una respuesta útil",
|
|
149
150
|
"s2_ex3_in": "Historial criminal de una persona",
|
|
150
151
|
"s2_ex3_mod": "IA de evaluación de riesgos",
|
|
151
152
|
"s2_ex3_out": "\"Alto Riesgo\" o \"Bajo Riesgo\"",
|
|
152
153
|
"btn_back": "◀️ Atrás",
|
|
153
|
-
"btn_next_learn": "Siguiente: Cómo
|
|
154
|
+
"btn_next_learn": "Siguiente: Cómo aprenden los modelos ▶️",
|
|
154
155
|
# Step 3
|
|
155
|
-
"s3_title": "🧠 ¿Cómo
|
|
156
|
-
"s3_h1": "1. Aprende de
|
|
156
|
+
"s3_title": "🧠 ¿Cómo aprende un modelo de IA?",
|
|
157
|
+
"s3_h1": "1. Aprende de ejemplos",
|
|
157
158
|
"s3_p1": "Un modelo de IA no está programado con respuestas. En cambio, se entrena con una gran cantidad de ejemplos y aprende a encontrar las respuestas por sí mismo.",
|
|
158
159
|
"s3_p2": "En nuestro escenario de justicia, esto significa alimentar al modelo con miles de casos pasados (<b>ejemplos</b>) para enseñarle a encontrar los <b>patrones</b> que conectan los detalles de una persona con su riesgo criminal.",
|
|
159
|
-
"s3_h2": "2. El Proceso de
|
|
160
|
-
"s3_p3": "La IA \"entrena\"
|
|
160
|
+
"s3_h2": "2. El Proceso de entrenamiento",
|
|
161
|
+
"s3_p3": "La IA se \"entrena\" repitiendo el ciclo millones de veces a través de datos históricos (casos pasados):",
|
|
161
162
|
"flow_1": "1. EJEMPLOS<br>ENTRADA",
|
|
162
|
-
"flow_2": "2. MODELO<br>
|
|
163
|
+
"flow_2": "2. MODELO<br>ESTIMACIONES",
|
|
163
164
|
"flow_3": "3. REVISAR<br>RESPUESTA",
|
|
164
165
|
"flow_4": "4. AJUSTAR<br>PESOS",
|
|
165
166
|
"flow_5": "MODELO<br>APRENDIDO",
|
|
166
167
|
"s3_p4": "Durante el paso de <b>\"Ajustar\"</b>, el modelo cambia sus reglas internas (llamadas <b>\"pesos\"</b>) para acercarse a la respuesta correcta. Por ejemplo, aprende <b>cuánto</b> deben importar más los \"delitos previos\" que la \"edad\".",
|
|
167
|
-
"s3_eth_title": "⚠️ El
|
|
168
|
-
"s3_eth_p": "<b>Aquí
|
|
169
|
-
"btn_next_try": "Siguiente: Pruébalo
|
|
168
|
+
"s3_eth_title": "⚠️ El desafío ético",
|
|
169
|
+
"s3_eth_p": "<b>Aquí nos encontramos con un problema crítico:</b> El modelo *solo* aprende de los datos. Si los datos históricos están sesgados (por ejemplo, ciertos grupos de personas fueron arrestados con más frecuencia), el modelo aprenderá esos patrones sesgados.<br><br><b>El modelo no conoce de \"equidad\" o de \"justicia\", solo conoce patrones.</b>",
|
|
170
|
+
"btn_next_try": "Siguiente: Pruébalo tú mismo ▶️",
|
|
170
171
|
# Step 4
|
|
171
|
-
"s4_title": "🎮 ¡Pruébalo
|
|
172
|
-
"s4_intro": "<b>Usemos un modelo de IA simple para predecir el riesgo
|
|
173
|
-
"s4_sect1": "1️⃣ ENTRADA: Ajusta los
|
|
172
|
+
"s4_title": "🎮 ¡Pruébalo tú mismo!",
|
|
173
|
+
"s4_intro": "<b>Usemos un modelo de IA simple para predecir el riesgo de reincidencia.</b><br>¡A continuación, ajusta las entradas y observa cómo cambia la predicción del modelo!",
|
|
174
|
+
"s4_sect1": "1️⃣ ENTRADA: Ajusta los datos",
|
|
174
175
|
"lbl_age": "Edad",
|
|
175
176
|
"info_age": "Edad del acusado",
|
|
176
|
-
"lbl_priors": "Delitos
|
|
177
|
+
"lbl_priors": "Delitos previos",
|
|
177
178
|
"info_priors": "Número de crímenes anteriores",
|
|
178
|
-
"lbl_severity": "Gravedad del
|
|
179
|
+
"lbl_severity": "Gravedad del cargo actual",
|
|
179
180
|
"info_severity": "¿Qué tan grave es el cargo actual?",
|
|
180
181
|
"opt_minor": "Menor",
|
|
181
182
|
"opt_moderate": "Moderado",
|
|
182
183
|
"opt_serious": "Grave",
|
|
183
|
-
"s4_sect2": "2️⃣ MODELO: Procesa los
|
|
184
|
-
"btn_run": "🔮 Ejecutar
|
|
185
|
-
"s4_sect3": "3️⃣ SALIDA: Ver la
|
|
186
|
-
"res_placeholder": "Haz clic en \"Ejecutar
|
|
187
|
-
"s4_highlight": "<b>Lo
|
|
188
|
-
"btn_next_conn": "Siguiente: Conexión con la
|
|
184
|
+
"s4_sect2": "2️⃣ MODELO: Procesa los datos",
|
|
185
|
+
"btn_run": "🔮 Ejecutar predicción de la IA",
|
|
186
|
+
"s4_sect3": "3️⃣ SALIDA: Ver la predicción",
|
|
187
|
+
"res_placeholder": "Haz clic en \"Ejecutar predicción de la IA\" para ver el resultado",
|
|
188
|
+
"s4_highlight": "<b>Lo que acabas de hacer:</b><br><br>¡Usaste un modelo de IA muy simple! Proporcionaste <b style='color:#0369a1;'>datos de entrada</b> (edad, delitos, gravedad), el <b style='color:#92400e;'>modelo los procesó</b> usando reglas y patrones, y produjo una <b style='color:#15803d;'>predicción de salida</b>.<br><br>¡Los modelos de IA reales son más complejos, pero funcionan bajo el mismo principio!",
|
|
189
|
+
"btn_next_conn": "Siguiente: Conexión con la justicia ▶️",
|
|
189
190
|
# Step 5
|
|
190
|
-
"s5_title": "🔗
|
|
191
|
-
"s5_p1": "<b>¿Recuerdas la predicción de riesgo que usaste antes
|
|
191
|
+
"s5_title": "🔗 Connexión con el sistema de justicia penal",
|
|
192
|
+
"s5_p1": "<b>¿Recuerdas la predicción de riesgo que usaste antes en tu rol de juez?</b>",
|
|
192
193
|
"s5_p2": "Ese fue un ejemplo del mundo real de IA en acción:",
|
|
193
|
-
"s5_in_desc": "• Edad, raza, género, delitos previos, detalles del cargo",
|
|
194
|
-
"s5_mod_desc1": "•
|
|
195
|
-
"s5_mod_desc2": "• Busca patrones
|
|
194
|
+
"s5_in_desc": "• Edad, raza, género, delitos previos, detalles del cargo penal",
|
|
195
|
+
"s5_mod_desc1": "• Se entrena con datos históricos de la justicia penal",
|
|
196
|
+
"s5_mod_desc2": "• Busca patrones entre las personas que reincindieron en el pasado",
|
|
196
197
|
"s5_out_desc": "• \"Alto Riesgo\", \"Riesgo Medio\" o \"Bajo Riesgo\"",
|
|
197
|
-
"s5_h2": "Por
|
|
198
|
+
"s5_h2": "¿Por qué es esto importante para la ética?:",
|
|
198
199
|
"s5_li1": "Los <b>datos de entrada</b> pueden contener sesgos históricos",
|
|
199
200
|
"s5_li2": "El <b>modelo</b> aprende patrones de decisiones pasadas potencialmente injustas",
|
|
200
201
|
"s5_li3": "Las <b>predicciones de salida</b> pueden perpetuar la discriminación",
|
|
201
|
-
"s5_final": "<b>Entender cómo funciona la IA es el primer paso para construir sistemas más justos.</b><br><br>¡Ahora que sabes
|
|
202
|
-
"btn_complete": "Completar esta
|
|
202
|
+
"s5_final": "<b>Entender cómo funciona la IA es el primer paso para construir sistemas más justos.</b><br><br>¡Ahora que sabes los conceptos básicos de la IA, estás listo para ayudar a diseñar mejores modelos que sean más éticos y menos sesgados!",
|
|
203
|
+
"btn_complete": "Completar esta sección ▶️",
|
|
203
204
|
# Step 6
|
|
204
|
-
"s6_title": "🎓 ¡Ahora
|
|
205
|
+
"s6_title": "🎓 ¡Ahora entiendes los conceptos básicos de la IA!",
|
|
205
206
|
"s6_congrats": "<b>¡Felicidades!</b> Ahora sabes:",
|
|
206
207
|
"s6_li1": "Qué es la IA (un sistema de predicción)",
|
|
207
208
|
"s6_li2": "Cómo funciona (Entrada → Modelo → Salida)",
|
|
208
|
-
"s6_li3": "Cómo
|
|
209
|
-
"s6_li4": "Por qué importa para
|
|
210
|
-
"s6_li5": "Las implicaciones éticas de las decisiones de IA",
|
|
211
|
-
"s6_next": "<b>Próximos
|
|
209
|
+
"s6_li3": "Cómo los modelos de IA aprenden de los datos",
|
|
210
|
+
"s6_li4": "Por qué importa para el sistema de justicia penal",
|
|
211
|
+
"s6_li5": "Las implicaciones éticas de las decisiones de la IA",
|
|
212
|
+
"s6_next": "<b>Próximos pasos:</b>",
|
|
212
213
|
"s6_next_desc": "En las siguientes secciones, aprenderás cómo construir y mejorar modelos de IA para hacerlos más justos y éticos.",
|
|
213
214
|
"s6_scroll": "👇 DESPLÁZATE HACIA ABAJO 👇",
|
|
214
215
|
"s6_find": "Continúa en la siguiente sección abajo.",
|
|
215
|
-
"btn_review": "◀️ Volver a
|
|
216
|
+
"btn_review": "◀️ Volver a revisar",
|
|
216
217
|
"risk_high": "Alto Riesgo",
|
|
217
218
|
"risk_med": "Riesgo Medio",
|
|
218
219
|
"risk_low": "Bajo Riesgo",
|
|
219
220
|
"risk_score": "Puntaje de Riesgo:"
|
|
220
221
|
},
|
|
221
222
|
"ca": {
|
|
222
|
-
"title": "🤖
|
|
223
|
+
"title": "🤖 Però, què és la IA, realment?",
|
|
223
224
|
"intro_box": "Abans de poder construir millors sistemes d'IA, necessites entendre què és realment la IA.<br>No et preocupis, ho explicarem en termes simples i quotidians!",
|
|
224
225
|
"loading": "⏳ Carregant...",
|
|
225
226
|
# Step 1
|
|
226
|
-
"s1_title": "🎯 Una
|
|
227
|
+
"s1_title": "🎯 Una definició simple",
|
|
227
228
|
"s1_head": "Intel·ligència Artificial (IA) és només un nom elegant per a:",
|
|
228
229
|
"s1_big": "Un sistema que fa prediccions basades en patrons",
|
|
229
230
|
"s1_sub": "Això és tot! Desglossem què significa això...",
|
|
230
231
|
"s1_list_title": "Pensa en com TU fas prediccions:",
|
|
231
|
-
"s1_li1": "<b>Temps:</b> Núvols
|
|
232
|
+
"s1_li1": "<b>Temps:</b> Núvols negres → Predius pluja → Portes paraigua",
|
|
232
233
|
"s1_li2": "<b>Trànsit:</b> Hora punta → Predius congestió → Surts d'hora",
|
|
233
|
-
"s1_li3": "<b>
|
|
234
|
+
"s1_li3": "<b>Pel·lícula:</b> Actor que t'agrada → Predius que t'agradarà → La veus",
|
|
234
235
|
"s1_highlight": "La IA fa el mateix, però utilitzant dades i matemàtiques en lloc d'experiència humana i intuïció.",
|
|
235
|
-
"btn_next_formula": "Següent: La
|
|
236
|
+
"btn_next_formula": "Següent: La fórmula de la IA ▶️",
|
|
236
237
|
# Step 2
|
|
237
|
-
"s2_title": "📐
|
|
238
|
+
"s2_title": "📐 Les tres parts de la fórmula",
|
|
238
239
|
"s2_intro": "Tot sistema d'IA funciona de la mateixa manera, seguint aquesta fórmula simple:",
|
|
239
240
|
"lbl_input": "ENTRADA",
|
|
240
241
|
"lbl_model": "MODEL",
|
|
241
242
|
"lbl_output": "SORTIDA",
|
|
242
243
|
"desc_input": "Entren dades",
|
|
243
|
-
"desc_model": "IA processa",
|
|
244
|
-
"desc_output": "Surt predicció",
|
|
245
|
-
"s2_ex_title": "Exemples del
|
|
244
|
+
"desc_model": "La IA les processa",
|
|
245
|
+
"desc_output": "Surt la predicció",
|
|
246
|
+
"s2_ex_title": "Exemples del món real:",
|
|
246
247
|
"s2_ex1_in": "Foto d'un gos",
|
|
247
|
-
"s2_ex1_mod": "IA de reconeixement d'
|
|
248
|
+
"s2_ex1_mod": "IA de reconeixement d'imatges",
|
|
248
249
|
"s2_ex1_out": "\"Això és un Golden Retriever\"",
|
|
249
250
|
"s2_ex2_in": "\"Quin temps fa?\"",
|
|
250
251
|
"s2_ex2_mod": "IA de llenguatge (com ChatGPT)",
|
|
@@ -253,73 +254,73 @@ TRANSLATIONS = {
|
|
|
253
254
|
"s2_ex3_mod": "IA d'avaluació de riscos",
|
|
254
255
|
"s2_ex3_out": "\"Alt Risc\" o \"Baix Risc\"",
|
|
255
256
|
"btn_back": "◀️ Enrere",
|
|
256
|
-
"btn_next_learn": "Següent: Com
|
|
257
|
+
"btn_next_learn": "Següent: Com aprenen els models ▶️",
|
|
257
258
|
# Step 3
|
|
258
|
-
"s3_title": "🧠 Com
|
|
259
|
-
"s3_h1": "1. Aprèn d'
|
|
259
|
+
"s3_title": "🧠 Com aprèn un model d'IA?",
|
|
260
|
+
"s3_h1": "1. Aprèn d'exemples",
|
|
260
261
|
"s3_p1": "Un model d'IA no està programat amb respostes. En canvi, s'entrena amb una gran quantitat d'exemples i aprèn a trobar les respostes per si mateix.",
|
|
261
262
|
"s3_p2": "En el nostre escenari de justícia, això significa alimentar el model amb milers de casos passats (<b>exemples</b>) per ensenyar-li a trobar els <b>patrons</b> que connecten els detalls d'una persona amb el seu risc criminal.",
|
|
262
|
-
"s3_h2": "2. El
|
|
263
|
-
"s3_p3": "La IA \"entrena\"
|
|
263
|
+
"s3_h2": "2. El procés d'entrenament",
|
|
264
|
+
"s3_p3": "La IA \"s'entrena\" repetint el cicle milions de vegades a través de dades històriques (casos passats):",
|
|
264
265
|
"flow_1": "1. EXEMPLES<br>ENTRADA",
|
|
265
|
-
"flow_2": "2. MODEL<br>
|
|
266
|
+
"flow_2": "2. MODEL<br>ESTIMACIONS",
|
|
266
267
|
"flow_3": "3. REVISAR<br>RESPOSTA",
|
|
267
268
|
"flow_4": "4. AJUSTAR<br>PESOS",
|
|
268
269
|
"flow_5": "MODEL<br>APRÈS",
|
|
269
|
-
"s3_p4": "Durant el pas d'<b>\"
|
|
270
|
-
"s3_eth_title": "⚠️ El
|
|
271
|
-
"s3_eth_p": "<b>Aquí
|
|
272
|
-
"btn_next_try": "Següent: Prova-ho
|
|
270
|
+
"s3_p4": "Durant el pas d'<b>\"ajustar\"</b>, el model canvia les seves regles internes (anomenades <b>\"pesos\"</b>) per apropar-se a la resposta correcta. Per exemple, aprèn <b>quant</b> han d'importar més els \"delictes previs\" que l'\"edat\".",
|
|
271
|
+
"s3_eth_title": "⚠️ El desafiament ètic",
|
|
272
|
+
"s3_eth_p": "<b>Aquí ens trobem amb un problema crític:</b> El model *només* aprèn de les dades. Si les dades històriques estan esbiaixades (per exemple, certs grups de persones van ser detinguts amb més freqüència), el model aprendrà aquests patrons esbiaixats.<br><br><b>El model no coneix d'\"equitat\" o de \"justícia\", només coneix patrons.</b>",
|
|
273
|
+
"btn_next_try": "Següent: Prova-ho tu mateix ▶️",
|
|
273
274
|
# Step 4
|
|
274
|
-
"s4_title": "🎮 Prova-ho
|
|
275
|
-
"s4_intro": "<b>Utilitzem un model d'IA simple per predir el risc
|
|
276
|
-
"s4_sect1": "1️⃣ ENTRADA: Ajusta les
|
|
275
|
+
"s4_title": "🎮 Prova-ho tu mateix!",
|
|
276
|
+
"s4_intro": "<b>Utilitzem un model d'IA simple per predir el risc de reincidència.</b><br>A continuació, ajusta les entrades i observa com canvia la predicció del model!",
|
|
277
|
+
"s4_sect1": "1️⃣ ENTRADA: Ajusta les dades",
|
|
277
278
|
"lbl_age": "Edat",
|
|
278
|
-
"info_age": "Edat de
|
|
279
|
-
"lbl_priors": "Delictes
|
|
279
|
+
"info_age": "Edat de la persona presa",
|
|
280
|
+
"lbl_priors": "Delictes previs",
|
|
280
281
|
"info_priors": "Nombre de crims anteriors",
|
|
281
|
-
"lbl_severity": "Gravetat del
|
|
282
|
+
"lbl_severity": "Gravetat del càrrec actual",
|
|
282
283
|
"info_severity": "Què tan greu és el càrrec actual?",
|
|
283
284
|
"opt_minor": "Menor",
|
|
284
285
|
"opt_moderate": "Moderat",
|
|
285
286
|
"opt_serious": "Greu",
|
|
286
|
-
"s4_sect2": "2️⃣ MODEL: Processa les
|
|
287
|
-
"btn_run": "🔮 Executar
|
|
288
|
-
"s4_sect3": "3️⃣ SORTIDA: Veure la
|
|
289
|
-
"res_placeholder": "Fes clic a \"Executar
|
|
290
|
-
"s4_highlight": "<b>El
|
|
291
|
-
"btn_next_conn": "Següent: Connexió amb la
|
|
287
|
+
"s4_sect2": "2️⃣ MODEL: Processa les dades",
|
|
288
|
+
"btn_run": "🔮 Executar predicció de la IA",
|
|
289
|
+
"s4_sect3": "3️⃣ SORTIDA: Veure la predicció",
|
|
290
|
+
"res_placeholder": "Fes clic a \"Executar la predicció de la IA\" per veure el resultat",
|
|
291
|
+
"s4_highlight": "<b>El que acabes de fer:</b><br><br>Has utilitzat un model d'IA molt simple! Has proporcionat <b style='color:#0369a1;'>dades d'entrada</b> (edat, delictes, gravetat), el <b style='color:#92400e;'>model les ha processat</b> utilitzant regles i patrons, i ha produït una <b style='color:#15803d;'>predicció de sortida</b>.<br><br>Els models d'IA reals són més complexos, però funcionen sota el mateix principi!",
|
|
292
|
+
"btn_next_conn": "Següent: Connexió amb la justícia ▶️",
|
|
292
293
|
# Step 5
|
|
293
|
-
"s5_title": "🔗
|
|
294
|
-
"s5_p1": "<b>Recordes la predicció de risc que
|
|
295
|
-
"s5_p2": "Aquest
|
|
294
|
+
"s5_title": "🔗 Connexió amb el sistema de justícia penal",
|
|
295
|
+
"s5_p1": "<b>Recordes la predicció de risc que has utilitzat abans en el teu rol de jutge?</b>",
|
|
296
|
+
"s5_p2": "Aquest és un exemple real de l'aplicació de la IA:",
|
|
296
297
|
"s5_in_desc": "• Edat, raça, gènere, delictes previs, detalls del càrrec",
|
|
297
298
|
"s5_mod_desc1": "• Entrenat amb dades històriques de justícia penal",
|
|
298
|
-
"s5_mod_desc2": "• Busca patrons
|
|
299
|
+
"s5_mod_desc2": "• Busca patrons entre les persones que van reincidir en el passat",
|
|
299
300
|
"s5_out_desc": "• \"Alt Risc\", \"Risc Mitjà\" o \"Baix Risc\"",
|
|
300
|
-
"s5_h2": "Per
|
|
301
|
+
"s5_h2": "Per què això és important per a l'ètica?",
|
|
301
302
|
"s5_li1": "Les <b>dades d'entrada</b> poden contenir biaixos històrics",
|
|
302
303
|
"s5_li2": "El <b>model</b> aprèn patrons de decisions passades potencialment injustes",
|
|
303
304
|
"s5_li3": "Les <b>prediccions de sortida</b> poden perpetuar la discriminació",
|
|
304
|
-
"s5_final": "<b>Entendre com funciona la IA és el primer pas per construir sistemes més justos.</b><br><br>Ara que saps què és la IA, estàs llest per ajudar a dissenyar
|
|
305
|
-
"btn_complete": "Completar aquesta
|
|
305
|
+
"s5_final": "<b>Entendre com funciona la IA és el primer pas per construir sistemes més justos.</b><br><br>Ara que saps què és la IA, estàs llest per ajudar a dissenyar models que siguin més ètics i menys esbiaixats!",
|
|
306
|
+
"btn_complete": "Completar aquesta secció ▶️",
|
|
306
307
|
# Step 6
|
|
307
|
-
"s6_title": "🎓 Ara
|
|
308
|
+
"s6_title": "🎓 Ara ja entens els conceptes bàsics de la IA!",
|
|
308
309
|
"s6_congrats": "<b>Felicitats!</b> Ara saps:",
|
|
309
310
|
"s6_li1": "Què és la IA (un sistema de predicció)",
|
|
310
311
|
"s6_li2": "Com funciona (Entrada → Model → Sortida)",
|
|
311
|
-
"s6_li3": "Com
|
|
312
|
+
"s6_li3": "Com els models d'IA aprenen de les dades",
|
|
312
313
|
"s6_li4": "Per què importa per a la justícia penal",
|
|
313
|
-
"s6_li5": "Les implicacions ètiques de les decisions
|
|
314
|
+
"s6_li5": "Les implicacions ètiques de les decisions de la IA",
|
|
314
315
|
"s6_next": "<b>Propers Passos:</b>",
|
|
315
316
|
"s6_next_desc": "En les següents seccions, aprendràs com construir i millorar models d'IA per fer-los més justos i ètics.",
|
|
316
317
|
"s6_scroll": "👇 DESPLAÇA'T CAP AVALL 👇",
|
|
317
318
|
"s6_find": "Continua a la següent secció a sota.",
|
|
318
|
-
"btn_review": "◀️ Tornar a
|
|
319
|
+
"btn_review": "◀️ Tornar a revisar",
|
|
319
320
|
"risk_high": "Alt Risc",
|
|
320
321
|
"risk_med": "Risc Mitjà",
|
|
321
322
|
"risk_low": "Baix Risc",
|
|
322
|
-
"risk_score": "Puntuació de
|
|
323
|
+
"risk_score": "Puntuació de risc:"
|
|
323
324
|
}
|
|
324
325
|
}
|
|
325
326
|
|
|
@@ -688,12 +689,32 @@ def create_what_is_ai_app(theme_primary_hue: str = "indigo") -> "gr.Blocks":
|
|
|
688
689
|
|
|
689
690
|
# --- Update Logic ---
|
|
690
691
|
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
692
|
+
# --- CACHED UPDATE LOGIC ---
|
|
693
|
+
|
|
694
|
+
# List of outputs must match the return order exactly
|
|
695
|
+
update_targets = [
|
|
696
|
+
lang_state,
|
|
697
|
+
c_title, c_intro, c_load,
|
|
698
|
+
# S1
|
|
699
|
+
c_s1_title, c_s1_html, step_1_next,
|
|
700
|
+
# S2
|
|
701
|
+
c_s2_title, c_s2_html, step_2_back, step_2_next,
|
|
702
|
+
# S3
|
|
703
|
+
c_s3_title, c_s3_html, step_3_back, step_3_next,
|
|
704
|
+
# S4
|
|
705
|
+
c_s4_title, c_s4_intro, c_s4_sect1, age_slider, priors_slider, severity_dropdown,
|
|
706
|
+
c_s4_sect2, predict_btn, c_s4_sect3, prediction_output, c_s4_highlight, step_4_back, step_4_next,
|
|
707
|
+
# S5
|
|
708
|
+
c_s5_title, c_s5_html, step_5_back, step_5_next,
|
|
709
|
+
# S6
|
|
710
|
+
c_s6_html, back_to_connection_btn
|
|
711
|
+
]
|
|
712
|
+
|
|
713
|
+
@lru_cache(maxsize=16)
|
|
714
|
+
def get_cached_ui_updates(lang):
|
|
715
|
+
"""Cache the heavy UI generation."""
|
|
695
716
|
|
|
696
|
-
# Helper
|
|
717
|
+
# Helper must be defined here or available in scope
|
|
697
718
|
def get_opt(k): return t(lang, k)
|
|
698
719
|
|
|
699
720
|
return [
|
|
@@ -734,7 +755,7 @@ def create_what_is_ai_app(theme_primary_hue: str = "indigo") -> "gr.Blocks":
|
|
|
734
755
|
f"<h3 style='text-align:center; color:#92400e;'>{t(lang, 's4_sect2')}</h3>",
|
|
735
756
|
gr.Button(value=t(lang, 'btn_run')),
|
|
736
757
|
f"<h3 style='text-align:center; color:#15803d;'>{t(lang, 's4_sect3')}</h3>",
|
|
737
|
-
f"<div class='prediction-placeholder'><p style='font-size:18px; margin:0;'>{t(lang, 'res_placeholder')}</p></div>",
|
|
758
|
+
f"<div class='prediction-placeholder'><p style='font-size:18px; margin:0;'>{t(lang, 'res_placeholder')}</p></div>",
|
|
738
759
|
_get_step4_highlight_html(lang),
|
|
739
760
|
gr.Button(value=t(lang, 'btn_back')),
|
|
740
761
|
gr.Button(value=t(lang, 'btn_next_conn')),
|
|
@@ -750,24 +771,12 @@ def create_what_is_ai_app(theme_primary_hue: str = "indigo") -> "gr.Blocks":
|
|
|
750
771
|
gr.Button(value=t(lang, 'btn_review'))
|
|
751
772
|
]
|
|
752
773
|
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
# S2
|
|
760
|
-
c_s2_title, c_s2_html, step_2_back, step_2_next,
|
|
761
|
-
# S3
|
|
762
|
-
c_s3_title, c_s3_html, step_3_back, step_3_next,
|
|
763
|
-
# S4
|
|
764
|
-
c_s4_title, c_s4_intro, c_s4_sect1, age_slider, priors_slider, severity_dropdown,
|
|
765
|
-
c_s4_sect2, predict_btn, c_s4_sect3, prediction_output, c_s4_highlight, step_4_back, step_4_next,
|
|
766
|
-
# S5
|
|
767
|
-
c_s5_title, c_s5_html, step_5_back, step_5_next,
|
|
768
|
-
# S6
|
|
769
|
-
c_s6_html, back_to_connection_btn
|
|
770
|
-
]
|
|
774
|
+
def update_language(request: gr.Request):
|
|
775
|
+
params = request.query_params
|
|
776
|
+
lang = params.get("lang", "en")
|
|
777
|
+
if lang not in TRANSLATIONS: lang = "en"
|
|
778
|
+
|
|
779
|
+
return get_cached_ui_updates(lang)
|
|
771
780
|
|
|
772
781
|
demo.load(update_language, inputs=None, outputs=update_targets)
|
|
773
782
|
|
|
@@ -5,7 +5,7 @@ Provides a local state manager for tracking multi-metric progress
|
|
|
5
5
|
and syncing with the Moral Compass API.
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
|
-
from typing import Dict, Optional, List
|
|
8
|
+
from typing import Dict, Optional, List, Tuple
|
|
9
9
|
from dataclasses import dataclass
|
|
10
10
|
from .api_client import MoralcompassApiClient
|
|
11
11
|
|
|
@@ -173,7 +173,7 @@ class ChallengeManager:
|
|
|
173
173
|
"""
|
|
174
174
|
|
|
175
175
|
def __init__(self, table_id: str, username: str, api_client: Optional[MoralcompassApiClient] = None,
|
|
176
|
-
challenge: Optional[JusticeAndEquityChallenge] = None):
|
|
176
|
+
challenge: Optional[JusticeAndEquityChallenge] = None, team_name: Optional[str] = None):
|
|
177
177
|
"""
|
|
178
178
|
Initialize a challenge manager.
|
|
179
179
|
|
|
@@ -182,11 +182,13 @@ class ChallengeManager:
|
|
|
182
182
|
username: The username
|
|
183
183
|
api_client: Optional API client instance (creates new one if None)
|
|
184
184
|
challenge: Optional challenge instance (creates JusticeAndEquityChallenge if None)
|
|
185
|
+
team_name: Optional team name for the user
|
|
185
186
|
"""
|
|
186
187
|
self.table_id = table_id
|
|
187
188
|
self.username = username
|
|
188
189
|
self.api_client = api_client or MoralcompassApiClient()
|
|
189
190
|
self.challenge = challenge or JusticeAndEquityChallenge()
|
|
191
|
+
self.team_name = team_name
|
|
190
192
|
|
|
191
193
|
# Metrics state
|
|
192
194
|
self.metrics: Dict[str, float] = {}
|
|
@@ -216,34 +218,67 @@ class ChallengeManager:
|
|
|
216
218
|
if primary:
|
|
217
219
|
self.primary_metric = name
|
|
218
220
|
|
|
219
|
-
def set_progress(self, tasks_completed: int =
|
|
220
|
-
questions_correct: int =
|
|
221
|
+
def set_progress(self, tasks_completed: Optional[int] = None, total_tasks: Optional[int] = None,
|
|
222
|
+
questions_correct: Optional[int] = None, total_questions: Optional[int] = None) -> None:
|
|
221
223
|
"""
|
|
222
224
|
Set progress counters.
|
|
223
225
|
|
|
224
226
|
Args:
|
|
225
|
-
tasks_completed: Number of tasks completed
|
|
226
|
-
total_tasks: Total number of tasks
|
|
227
|
-
questions_correct: Number of questions answered correctly
|
|
228
|
-
total_questions: Total number of questions
|
|
227
|
+
tasks_completed: Number of tasks completed (None = keep current)
|
|
228
|
+
total_tasks: Total number of tasks (None = keep current)
|
|
229
|
+
questions_correct: Number of questions answered correctly (None = keep current)
|
|
230
|
+
total_questions: Total number of questions (None = keep current)
|
|
229
231
|
"""
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
232
|
+
if tasks_completed is not None:
|
|
233
|
+
self.tasks_completed = tasks_completed
|
|
234
|
+
if total_tasks is not None:
|
|
235
|
+
self.total_tasks = total_tasks
|
|
236
|
+
if questions_correct is not None:
|
|
237
|
+
self.questions_correct = questions_correct
|
|
238
|
+
if total_questions is not None:
|
|
239
|
+
self.total_questions = total_questions
|
|
234
240
|
|
|
235
|
-
def
|
|
241
|
+
def is_task_completed(self, task_id: str) -> bool:
|
|
242
|
+
"""
|
|
243
|
+
Check if a task has been completed.
|
|
244
|
+
|
|
245
|
+
Args:
|
|
246
|
+
task_id: The task identifier (e.g., 'A', 'B', 'C')
|
|
247
|
+
|
|
248
|
+
Returns:
|
|
249
|
+
True if the task has been completed, False otherwise
|
|
250
|
+
"""
|
|
251
|
+
return task_id in self._completed_task_ids
|
|
252
|
+
|
|
253
|
+
def complete_task(self, task_id: str) -> bool:
|
|
236
254
|
"""
|
|
237
255
|
Mark a task as completed.
|
|
238
256
|
|
|
239
257
|
Args:
|
|
240
258
|
task_id: The task identifier (e.g., 'A', 'B', 'C')
|
|
259
|
+
|
|
260
|
+
Returns:
|
|
261
|
+
True if the task was newly completed, False if already completed
|
|
241
262
|
"""
|
|
242
263
|
if task_id not in self._completed_task_ids:
|
|
243
264
|
self._completed_task_ids.add(task_id)
|
|
244
265
|
self.tasks_completed = len(self._completed_task_ids)
|
|
266
|
+
return True
|
|
267
|
+
return False
|
|
245
268
|
|
|
246
|
-
def
|
|
269
|
+
def is_question_answered(self, question_id: str) -> bool:
|
|
270
|
+
"""
|
|
271
|
+
Check if a question has been answered.
|
|
272
|
+
|
|
273
|
+
Args:
|
|
274
|
+
question_id: The question identifier
|
|
275
|
+
|
|
276
|
+
Returns:
|
|
277
|
+
True if the question has been answered, False otherwise
|
|
278
|
+
"""
|
|
279
|
+
return question_id in self._answered_questions
|
|
280
|
+
|
|
281
|
+
def answer_question(self, task_id: str, question_id: str, selected_index: int) -> Tuple[bool, bool]:
|
|
247
282
|
"""
|
|
248
283
|
Record an answer to a question.
|
|
249
284
|
|
|
@@ -253,8 +288,16 @@ class ChallengeManager:
|
|
|
253
288
|
selected_index: The index of the selected answer
|
|
254
289
|
|
|
255
290
|
Returns:
|
|
256
|
-
|
|
291
|
+
Tuple of (is_correct, is_new_answer):
|
|
292
|
+
- is_correct: True if the answer is correct, False otherwise
|
|
293
|
+
- is_new_answer: True if this is a new answer, False if already answered
|
|
257
294
|
"""
|
|
295
|
+
# Check if already answered
|
|
296
|
+
if question_id in self._answered_questions:
|
|
297
|
+
# Return the previous result and indicate it's not a new answer
|
|
298
|
+
is_correct = self._is_answer_correct(question_id, self._answered_questions[question_id])
|
|
299
|
+
return is_correct, False
|
|
300
|
+
|
|
258
301
|
# Find the question
|
|
259
302
|
question = None
|
|
260
303
|
for task in self.challenge.tasks:
|
|
@@ -280,7 +323,7 @@ class ChallengeManager:
|
|
|
280
323
|
if self._is_answer_correct(qid, idx)
|
|
281
324
|
)
|
|
282
325
|
|
|
283
|
-
return is_correct
|
|
326
|
+
return is_correct, True
|
|
284
327
|
|
|
285
328
|
def _is_answer_correct(self, question_id: str, selected_index: int) -> bool:
|
|
286
329
|
"""Check if an answer is correct"""
|
|
@@ -336,6 +379,42 @@ class ChallengeManager:
|
|
|
336
379
|
|
|
337
380
|
return primary_value * progress_ratio
|
|
338
381
|
|
|
382
|
+
def _build_completed_task_ids(self) -> List[str]:
|
|
383
|
+
"""
|
|
384
|
+
Build unified completedTaskIds list based on local state.
|
|
385
|
+
|
|
386
|
+
Maps completed tasks and answered questions to t1, t2, ..., tn format where:
|
|
387
|
+
- Tasks map to t1..tTotalTasks by their index order in self.challenge.tasks
|
|
388
|
+
- Questions map to tTotalTasks+1..tN by their index order across all tasks
|
|
389
|
+
|
|
390
|
+
Note: This mapping is deterministic for a given challenge definition.
|
|
391
|
+
Tasks and questions are indexed in their fixed order as defined in the
|
|
392
|
+
challenge structure, ensuring consistent t-numbers for the same items.
|
|
393
|
+
|
|
394
|
+
Returns:
|
|
395
|
+
List of completed task IDs in unified format, sorted
|
|
396
|
+
"""
|
|
397
|
+
result = []
|
|
398
|
+
|
|
399
|
+
# Map completed tasks to t1..tTotalTasks
|
|
400
|
+
# Uses enumerate to maintain consistent ordering based on challenge definition
|
|
401
|
+
for i, task in enumerate(self.challenge.tasks):
|
|
402
|
+
if task.id in self._completed_task_ids:
|
|
403
|
+
result.append(f"t{i + 1}")
|
|
404
|
+
|
|
405
|
+
# Map answered questions to tTotalTasks+1..tN
|
|
406
|
+
# Maintains consistent ordering across all questions in all tasks
|
|
407
|
+
question_offset = self.total_tasks
|
|
408
|
+
question_index = 0
|
|
409
|
+
for task in self.challenge.tasks:
|
|
410
|
+
for question in task.questions:
|
|
411
|
+
question_index += 1
|
|
412
|
+
if question.id in self._answered_questions:
|
|
413
|
+
result.append(f"t{question_offset + question_index}")
|
|
414
|
+
|
|
415
|
+
# Return sorted list for deterministic ordering
|
|
416
|
+
return sorted(result, key=lambda x: int(x[1:]))
|
|
417
|
+
|
|
339
418
|
def sync(self) -> Dict:
|
|
340
419
|
"""
|
|
341
420
|
Sync current state to the Moral Compass API.
|
|
@@ -354,7 +433,9 @@ class ChallengeManager:
|
|
|
354
433
|
total_tasks=self.total_tasks,
|
|
355
434
|
questions_correct=self.questions_correct,
|
|
356
435
|
total_questions=self.total_questions,
|
|
357
|
-
primary_metric=self.primary_metric
|
|
436
|
+
primary_metric=self.primary_metric,
|
|
437
|
+
team_name=self.team_name,
|
|
438
|
+
completed_task_ids=self._build_completed_task_ids()
|
|
358
439
|
)
|
|
359
440
|
|
|
360
441
|
def __repr__(self) -> str:
|