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.
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 +4399 -0
  22. aimodelshare/moral_compass/apps/model_building_app_ca_final.py +3899 -0
  23. aimodelshare/moral_compass/apps/model_building_app_en.py +4167 -0
  24. aimodelshare/moral_compass/apps/model_building_app_en_final.py +3869 -0
  25. aimodelshare/moral_compass/apps/model_building_app_es.py +4351 -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.3.94.dist-info}/METADATA +1 -1
  32. {aimodelshare-0.3.7.dist-info → aimodelshare-0.3.94.dist-info}/RECORD +35 -19
  33. aimodelshare/moral_compass/apps/bias_detective.py +0 -714
  34. {aimodelshare-0.3.7.dist-info → aimodelshare-0.3.94.dist-info}/WHEEL +0 -0
  35. {aimodelshare-0.3.7.dist-info → aimodelshare-0.3.94.dist-info}/licenses/LICENSE +0 -0
  36. {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 criminal risk.",
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 criminal risk.</b><br>Adjust the inputs below and see how the model's prediction changes!",
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 what AI is, you're ready to help design better models that are more ethical and less biased!",
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": "🤖 ¿Qué es la IA, en realidad?",
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 Definición Simple",
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>Clima:</b> Nubes oscuras → Predices lluvia → Llevas paraguas",
129
- "s1_li2": "<b>Tráfico:</b> Hora pico → Predices congestión → Sales temprano",
130
- "s1_li3": "<b>Cine:</b> Actor que te gusta → Predices que te gustará → La ves",
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 Fórmula de la IA ▶️",
133
+ "btn_next_formula": "Siguiente: La fórmula de la IA ▶️",
133
134
  # Step 2
134
- "s2_title": "📐 La Fórmula de Tres Partes",
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 Mundo Real:",
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 imagen",
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é tal el clima?\"",
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 Aprenden los Modelos ▶️",
154
+ "btn_next_learn": "Siguiente: Cómo aprenden los modelos ▶️",
154
155
  # Step 3
155
- "s3_title": "🧠 ¿Cómo Aprende un Modelo de IA?",
156
- "s3_h1": "1. Aprende de Ejemplos",
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 Entrenamiento",
160
- "s3_p3": "La IA \"entrena\" recorriendo datos históricos (casos pasados) millones de veces:",
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>ADIVINA",
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 Desafío Ético",
168
- "s3_eth_p": "<b>Aquí está el problema crítico:</b> El modelo *solo* aprende de los datos. Si los datos históricos están sesgados (por ejemplo, ciertos grupos fueron arrestados con más frecuencia), el modelo aprenderá esos patrones sesgados.<br><br><b>El modelo no conoce la \"equidad\" o la \"justicia\", solo conoce patrones.</b>",
169
- "btn_next_try": "Siguiente: Pruébalo Mismo ▶️",
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 mismo ▶️",
170
171
  # Step 4
171
- "s4_title": "🎮 ¡Pruébalo Mismo!",
172
- "s4_intro": "<b>Usemos un modelo de IA simple para predecir el riesgo criminal.</b><br>¡Ajusta las entradas a continuación y ve cómo cambia la predicción del modelo!",
173
- "s4_sect1": "1️⃣ ENTRADA: Ajusta los Datos",
172
+ "s4_title": "🎮 ¡Pruébalo 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 Previos",
177
+ "lbl_priors": "Delitos previos",
177
178
  "info_priors": "Número de crímenes anteriores",
178
- "lbl_severity": "Gravedad del Cargo Actual",
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 Datos",
184
- "btn_run": "🔮 Ejecutar Predicción IA",
185
- "s4_sect3": "3️⃣ SALIDA: Ver la Predicción",
186
- "res_placeholder": "Haz clic en \"Ejecutar Predicción IA\" arriba para ver el resultado",
187
- "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!",
188
- "btn_next_conn": "Siguiente: Conexión con la Justicia ▶️",
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": "🔗 Conectando con la Justicia Penal",
191
- "s5_p1": "<b>¿Recuerdas la predicción de riesgo que usaste antes como juez?</b>",
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": "• Entrenado con datos históricos de justicia penal",
195
- "s5_mod_desc2": "• Busca patrones en quién reincidió en el pasado",
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 Qué Esto Importa para la Ética:",
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 qué es la IA, estás listo para ayudar a diseñar mejores modelos que sean más éticos y menos sesgados!",
202
- "btn_complete": "Completar esta Sección ▶️",
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 Entiendes Los Conceptos Básicos de La IA!",
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 aprenden los modelos de IA de los datos",
209
- "s6_li4": "Por qué importa para la justicia penal",
210
- "s6_li5": "Las implicaciones éticas de las decisiones de IA",
211
- "s6_next": "<b>Próximos Pasos:</b>",
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 Revisar",
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": "🤖 Què és la IA, realment?",
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 Definició Simple",
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 foscos → Predius pluja → Portes paraigua",
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>Cinema:</b> Actor que t'agrada → Predius que t'agradarà → La veus",
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 Fórmula de la IA ▶️",
236
+ "btn_next_formula": "Següent: La fórmula de la IA ▶️",
236
237
  # Step 2
237
- "s2_title": "📐 La Fórmula de Tres Parts",
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 Món Real:",
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'imatge",
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 Aprenen els Models ▶️",
257
+ "btn_next_learn": "Següent: Com aprenen els models ▶️",
257
258
  # Step 3
258
- "s3_title": "🧠 Com Aprèn un Model d'IA?",
259
- "s3_h1": "1. Aprèn d'Exemples",
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 Procés d'Entrenament",
263
- "s3_p3": "La IA \"entrena\" recorrent dades històriques (casos passats) milions de vegades:",
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>ENDEVINA",
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>\"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\".",
270
- "s3_eth_title": "⚠️ El Desafiament Ètic",
271
- "s3_eth_p": "<b>Aquí hi ha el problema crític:</b> El model *només* aprèn de les dades. Si les dades històriques estan esbiaixades (per exemple, certs grups van ser arrestats amb més freqüència), el model aprendrà aquests patrons esbiaixats.<br><br><b>El model no coneix l'\"equitat\" o la \"justícia\", només coneix patrons.</b>",
272
- "btn_next_try": "Següent: Prova-ho Tu Mateix ▶️",
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 Tu Mateix!",
275
- "s4_intro": "<b>Utilitzem un model d'IA simple per predir el risc criminal.</b><br>Ajusta les entrades a continuació i veus com canvia la predicció del model!",
276
- "s4_sect1": "1️⃣ ENTRADA: Ajusta les Dades",
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 l'acusat",
279
- "lbl_priors": "Delictes Previs",
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 Càrrec Actual",
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 Dades",
287
- "btn_run": "🔮 Executar Predicció IA",
288
- "s4_sect3": "3️⃣ SORTIDA: Veure la Predicció",
289
- "res_placeholder": "Fes clic a \"Executar Predicció IA\" a dalt per veure el resultat",
290
- "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!",
291
- "btn_next_conn": "Següent: Connexió amb la Justícia ▶️",
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": "🔗 Connectant amb la Justícia Penal",
294
- "s5_p1": "<b>Recordes la predicció de risc que vas utilitzar abans com a jutge?</b>",
295
- "s5_p2": "Aquest va ser un exemple del món real d'IA en acció:",
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 en qui va reincidir en el passat",
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 Què Això Importa per a l'Ètica:",
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 millors models que siguin més ètics i menys esbiaixats!",
305
- "btn_complete": "Completar aquesta Secció ▶️",
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 Ja Entens els Conceptes Bàsics de La IA!",
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 aprenen els models d'IA de les dades",
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 d'IA",
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 Revisar",
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 Risc:"
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
- def update_language(request: gr.Request):
692
- params = request.query_params
693
- lang = params.get("lang", "en")
694
- if lang not in TRANSLATIONS: lang = "en"
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 to access options for Dropdown updates
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>", # Reset output on lang change
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
- # List of outputs must match the return order exactly
754
- update_targets = [
755
- lang_state,
756
- c_title, c_intro, c_load,
757
- # S1
758
- c_s1_title, c_s1_html, step_1_next,
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 = 0, total_tasks: int = 0,
220
- questions_correct: int = 0, total_questions: int = 0) -> None:
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
- self.tasks_completed = tasks_completed
231
- self.total_tasks = total_tasks
232
- self.questions_correct = questions_correct
233
- self.total_questions = total_questions
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 complete_task(self, task_id: str) -> None:
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 answer_question(self, task_id: str, question_id: str, selected_index: int) -> bool:
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
- True if the answer is correct, False otherwise
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:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: aimodelshare
3
- Version: 0.3.7
3
+ Version: 0.3.94
4
4
  Summary: Deploy locally saved machine learning models to a live REST API and integrated dashboard.
5
5
  Author-email: Michael Parrott <mikedparrott@modelshare.ai>
6
6
  License: