aimodelshare 0.3.7__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 (171) hide show
  1. aimodelshare/README.md +26 -0
  2. aimodelshare/__init__.py +100 -0
  3. aimodelshare/aimsonnx.py +2381 -0
  4. aimodelshare/api.py +836 -0
  5. aimodelshare/auth.py +163 -0
  6. aimodelshare/aws.py +511 -0
  7. aimodelshare/aws_client.py +173 -0
  8. aimodelshare/base_image.py +154 -0
  9. aimodelshare/bucketpolicy.py +106 -0
  10. aimodelshare/color_mappings/color_mapping_keras.csv +121 -0
  11. aimodelshare/color_mappings/color_mapping_pytorch.csv +117 -0
  12. aimodelshare/containerisation.py +244 -0
  13. aimodelshare/containerization.py +712 -0
  14. aimodelshare/containerization_templates/Dockerfile.txt +8 -0
  15. aimodelshare/containerization_templates/Dockerfile_PySpark.txt +23 -0
  16. aimodelshare/containerization_templates/buildspec.txt +14 -0
  17. aimodelshare/containerization_templates/lambda_function.txt +40 -0
  18. aimodelshare/custom_approach/__init__.py +1 -0
  19. aimodelshare/custom_approach/lambda_function.py +17 -0
  20. aimodelshare/custom_eval_metrics.py +103 -0
  21. aimodelshare/data_sharing/__init__.py +0 -0
  22. aimodelshare/data_sharing/data_sharing_templates/Dockerfile.txt +3 -0
  23. aimodelshare/data_sharing/data_sharing_templates/__init__.py +1 -0
  24. aimodelshare/data_sharing/data_sharing_templates/buildspec.txt +15 -0
  25. aimodelshare/data_sharing/data_sharing_templates/codebuild_policies.txt +129 -0
  26. aimodelshare/data_sharing/data_sharing_templates/codebuild_trust_relationship.txt +12 -0
  27. aimodelshare/data_sharing/download_data.py +620 -0
  28. aimodelshare/data_sharing/share_data.py +373 -0
  29. aimodelshare/data_sharing/utils.py +8 -0
  30. aimodelshare/deploy_custom_lambda.py +246 -0
  31. aimodelshare/documentation/Makefile +20 -0
  32. aimodelshare/documentation/karma_sphinx_theme/__init__.py +28 -0
  33. aimodelshare/documentation/karma_sphinx_theme/_version.py +2 -0
  34. aimodelshare/documentation/karma_sphinx_theme/breadcrumbs.html +70 -0
  35. aimodelshare/documentation/karma_sphinx_theme/layout.html +172 -0
  36. aimodelshare/documentation/karma_sphinx_theme/search.html +50 -0
  37. aimodelshare/documentation/karma_sphinx_theme/searchbox.html +14 -0
  38. aimodelshare/documentation/karma_sphinx_theme/static/css/custom.css +2 -0
  39. aimodelshare/documentation/karma_sphinx_theme/static/css/custom.css.map +1 -0
  40. aimodelshare/documentation/karma_sphinx_theme/static/css/theme.css +2751 -0
  41. aimodelshare/documentation/karma_sphinx_theme/static/css/theme.css.map +1 -0
  42. aimodelshare/documentation/karma_sphinx_theme/static/css/theme.min.css +2 -0
  43. aimodelshare/documentation/karma_sphinx_theme/static/css/theme.min.css.map +1 -0
  44. aimodelshare/documentation/karma_sphinx_theme/static/font/fontello.eot +0 -0
  45. aimodelshare/documentation/karma_sphinx_theme/static/font/fontello.svg +32 -0
  46. aimodelshare/documentation/karma_sphinx_theme/static/font/fontello.ttf +0 -0
  47. aimodelshare/documentation/karma_sphinx_theme/static/font/fontello.woff +0 -0
  48. aimodelshare/documentation/karma_sphinx_theme/static/font/fontello.woff2 +0 -0
  49. aimodelshare/documentation/karma_sphinx_theme/static/js/theme.js +68 -0
  50. aimodelshare/documentation/karma_sphinx_theme/theme.conf +9 -0
  51. aimodelshare/documentation/make.bat +35 -0
  52. aimodelshare/documentation/requirements.txt +2 -0
  53. aimodelshare/documentation/source/about.rst +18 -0
  54. aimodelshare/documentation/source/advanced_features.rst +137 -0
  55. aimodelshare/documentation/source/competition.rst +218 -0
  56. aimodelshare/documentation/source/conf.py +58 -0
  57. aimodelshare/documentation/source/create_credentials.rst +86 -0
  58. aimodelshare/documentation/source/example_notebooks.rst +132 -0
  59. aimodelshare/documentation/source/functions.rst +151 -0
  60. aimodelshare/documentation/source/gettingstarted.rst +390 -0
  61. aimodelshare/documentation/source/images/creds1.png +0 -0
  62. aimodelshare/documentation/source/images/creds2.png +0 -0
  63. aimodelshare/documentation/source/images/creds3.png +0 -0
  64. aimodelshare/documentation/source/images/creds4.png +0 -0
  65. aimodelshare/documentation/source/images/creds5.png +0 -0
  66. aimodelshare/documentation/source/images/creds_file_example.png +0 -0
  67. aimodelshare/documentation/source/images/predict_tab.png +0 -0
  68. aimodelshare/documentation/source/index.rst +110 -0
  69. aimodelshare/documentation/source/modelplayground.rst +132 -0
  70. aimodelshare/exceptions.py +11 -0
  71. aimodelshare/generatemodelapi.py +1270 -0
  72. aimodelshare/iam/codebuild_policy.txt +129 -0
  73. aimodelshare/iam/codebuild_trust_relationship.txt +12 -0
  74. aimodelshare/iam/lambda_policy.txt +15 -0
  75. aimodelshare/iam/lambda_trust_relationship.txt +12 -0
  76. aimodelshare/json_templates/__init__.py +1 -0
  77. aimodelshare/json_templates/api_json.txt +155 -0
  78. aimodelshare/json_templates/auth/policy.txt +1 -0
  79. aimodelshare/json_templates/auth/role.txt +1 -0
  80. aimodelshare/json_templates/eval/policy.txt +1 -0
  81. aimodelshare/json_templates/eval/role.txt +1 -0
  82. aimodelshare/json_templates/function/policy.txt +1 -0
  83. aimodelshare/json_templates/function/role.txt +1 -0
  84. aimodelshare/json_templates/integration_response.txt +5 -0
  85. aimodelshare/json_templates/lambda_policy_1.txt +15 -0
  86. aimodelshare/json_templates/lambda_policy_2.txt +8 -0
  87. aimodelshare/json_templates/lambda_role_1.txt +12 -0
  88. aimodelshare/json_templates/lambda_role_2.txt +16 -0
  89. aimodelshare/leaderboard.py +174 -0
  90. aimodelshare/main/1.txt +132 -0
  91. aimodelshare/main/1B.txt +112 -0
  92. aimodelshare/main/2.txt +153 -0
  93. aimodelshare/main/3.txt +134 -0
  94. aimodelshare/main/4.txt +128 -0
  95. aimodelshare/main/5.txt +109 -0
  96. aimodelshare/main/6.txt +105 -0
  97. aimodelshare/main/7.txt +144 -0
  98. aimodelshare/main/8.txt +142 -0
  99. aimodelshare/main/__init__.py +1 -0
  100. aimodelshare/main/authorization.txt +275 -0
  101. aimodelshare/main/eval_classification.txt +79 -0
  102. aimodelshare/main/eval_lambda.txt +1709 -0
  103. aimodelshare/main/eval_regression.txt +80 -0
  104. aimodelshare/main/lambda_function.txt +8 -0
  105. aimodelshare/main/nst.txt +149 -0
  106. aimodelshare/model.py +1543 -0
  107. aimodelshare/modeluser.py +215 -0
  108. aimodelshare/moral_compass/README.md +408 -0
  109. aimodelshare/moral_compass/__init__.py +65 -0
  110. aimodelshare/moral_compass/_version.py +3 -0
  111. aimodelshare/moral_compass/api_client.py +601 -0
  112. aimodelshare/moral_compass/apps/__init__.py +69 -0
  113. aimodelshare/moral_compass/apps/ai_consequences.py +540 -0
  114. aimodelshare/moral_compass/apps/bias_detective.py +714 -0
  115. aimodelshare/moral_compass/apps/ethical_revelation.py +898 -0
  116. aimodelshare/moral_compass/apps/fairness_fixer.py +889 -0
  117. aimodelshare/moral_compass/apps/judge.py +888 -0
  118. aimodelshare/moral_compass/apps/justice_equity_upgrade.py +853 -0
  119. aimodelshare/moral_compass/apps/mc_integration_helpers.py +820 -0
  120. aimodelshare/moral_compass/apps/model_building_game.py +1104 -0
  121. aimodelshare/moral_compass/apps/model_building_game_beginner.py +687 -0
  122. aimodelshare/moral_compass/apps/moral_compass_challenge.py +858 -0
  123. aimodelshare/moral_compass/apps/session_auth.py +254 -0
  124. aimodelshare/moral_compass/apps/shared_activity_styles.css +349 -0
  125. aimodelshare/moral_compass/apps/tutorial.py +481 -0
  126. aimodelshare/moral_compass/apps/what_is_ai.py +853 -0
  127. aimodelshare/moral_compass/challenge.py +365 -0
  128. aimodelshare/moral_compass/config.py +187 -0
  129. aimodelshare/placeholders/model.onnx +0 -0
  130. aimodelshare/placeholders/preprocessor.zip +0 -0
  131. aimodelshare/playground.py +1968 -0
  132. aimodelshare/postprocessormodules.py +157 -0
  133. aimodelshare/preprocessormodules.py +373 -0
  134. aimodelshare/pyspark/1.txt +195 -0
  135. aimodelshare/pyspark/1B.txt +181 -0
  136. aimodelshare/pyspark/2.txt +220 -0
  137. aimodelshare/pyspark/3.txt +204 -0
  138. aimodelshare/pyspark/4.txt +187 -0
  139. aimodelshare/pyspark/5.txt +178 -0
  140. aimodelshare/pyspark/6.txt +174 -0
  141. aimodelshare/pyspark/7.txt +211 -0
  142. aimodelshare/pyspark/8.txt +206 -0
  143. aimodelshare/pyspark/__init__.py +1 -0
  144. aimodelshare/pyspark/authorization.txt +258 -0
  145. aimodelshare/pyspark/eval_classification.txt +79 -0
  146. aimodelshare/pyspark/eval_lambda.txt +1441 -0
  147. aimodelshare/pyspark/eval_regression.txt +80 -0
  148. aimodelshare/pyspark/lambda_function.txt +8 -0
  149. aimodelshare/pyspark/nst.txt +213 -0
  150. aimodelshare/python/my_preprocessor.py +58 -0
  151. aimodelshare/readme.md +26 -0
  152. aimodelshare/reproducibility.py +181 -0
  153. aimodelshare/sam/Dockerfile.txt +8 -0
  154. aimodelshare/sam/Dockerfile_PySpark.txt +24 -0
  155. aimodelshare/sam/__init__.py +1 -0
  156. aimodelshare/sam/buildspec.txt +11 -0
  157. aimodelshare/sam/codebuild_policies.txt +129 -0
  158. aimodelshare/sam/codebuild_trust_relationship.txt +12 -0
  159. aimodelshare/sam/codepipeline_policies.txt +173 -0
  160. aimodelshare/sam/codepipeline_trust_relationship.txt +12 -0
  161. aimodelshare/sam/spark-class.txt +2 -0
  162. aimodelshare/sam/template.txt +54 -0
  163. aimodelshare/tools.py +103 -0
  164. aimodelshare/utils/__init__.py +78 -0
  165. aimodelshare/utils/optional_deps.py +38 -0
  166. aimodelshare/utils.py +57 -0
  167. aimodelshare-0.3.7.dist-info/METADATA +298 -0
  168. aimodelshare-0.3.7.dist-info/RECORD +171 -0
  169. aimodelshare-0.3.7.dist-info/WHEEL +5 -0
  170. aimodelshare-0.3.7.dist-info/licenses/LICENSE +5 -0
  171. aimodelshare-0.3.7.dist-info/top_level.txt +1 -0
@@ -0,0 +1,888 @@
1
+ """
2
+ You Be the Judge - Gradio application for the Justice & Equity Challenge.
3
+ Updated with i18n support and visual fixes (gr.HTML implementation).
4
+ """
5
+ import contextlib
6
+ import os
7
+ import gradio as gr
8
+
9
+ os.environ.setdefault("APP_NAME", "judge")
10
+
11
+ # -------------------------------------------------------------------------
12
+ # TRANSLATION CONFIGURATION
13
+ # -------------------------------------------------------------------------
14
+
15
+ TRANSLATIONS = {
16
+ "en": {
17
+ "title": "⚖️ You Be the Judge",
18
+ "intro_role": "<b>Your Role:</b> You are a judge who must decide whether to release defendants from prison.<br>An AI system has analyzed each case and provided a risk assessment.<br><br><b>Your Task:</b> Review each defendant's profile and the AI's prediction, then make your decision.",
19
+ "loading": "⏳ Loading...",
20
+ "scenario_title": "📋 The Scenario",
21
+ "scenario_box": """
22
+ You are a judge in a busy criminal court. Due to prison overcrowding, you must decide
23
+ which defendants can be safely released.<br><br>
24
+
25
+ To help you, the court has implemented an AI system that predicts the risk of each
26
+ defendant committing new crimes if released. The AI categorizes defendants as:<br><br>
27
+
28
+ <ul style='font-size:18px;'>
29
+ <li><span class='ai-risk-label risk-high'>High Risk</span> - Likely to re-offend</li>
30
+ <li><span class='ai-risk-label risk-medium'>Medium Risk</span> - Moderate chance of re-offending</li>
31
+ <li><span class='ai-risk-label risk-low'>Low Risk</span> - Unlikely to re-offend</li>
32
+ </ul>
33
+
34
+ <b>Remember:</b> Your decisions affect real people's lives and public safety.
35
+ """,
36
+ "btn_start": "Begin Making Decisions ▶️",
37
+ "profiles_title": "👥 Defendant Profiles",
38
+ "hint_box": "Review each defendant's information and the AI's risk assessment, then make your decision.",
39
+ "btn_release": "✓ Release Prisoner",
40
+ "btn_keep": "✗ Keep in Prison",
41
+ "btn_show_summary": "📊 Show My Decisions Summary",
42
+ "btn_complete": "Complete This Section ▶️",
43
+ "completion_title": "✅ Decisions Complete!",
44
+ "completion_box_pre": "You've made your decisions based on the AI's recommendations.<br><br>But here's the critical question:<br><br>",
45
+ "completion_question": "What if the AI was wrong?",
46
+ "completion_box_post": """
47
+ <p style='font-size:1.1rem;'>
48
+ Continue to the next section below to explore the consequences of
49
+ trusting AI predictions in high-stakes situations.
50
+ </p>
51
+ <h1 style='margin:20px 0; font-size: 3rem;'>👇 SCROLL DOWN 👇</h1>
52
+ <p style='font-size:1.1rem;'>
53
+ Find the next section below to continue your journey.
54
+ </p>
55
+ """,
56
+ "btn_back": "◀️ Back to Review Decisions",
57
+ "decision_release": "Release",
58
+ "decision_keep": "Keep in Prison",
59
+ "decision_recorded": "✓ Decision recorded:",
60
+ "summary_title": "📊 Your Decisions Summary",
61
+ "summary_released": "Prisoners Released:",
62
+ "summary_kept": "Prisoners Kept in Prison:",
63
+ "summary_empty": "No decisions made yet.",
64
+ "nav_loading_profiles": "Loading defendant profiles...",
65
+ "nav_reviewing": "Reviewing your decisions...",
66
+ "nav_returning": "Returning to profiles...",
67
+ # Profile Data Keys
68
+ "label_defendant": "Defendant",
69
+ "label_age": "Age",
70
+ "label_gender": "Gender",
71
+ "label_race": "Race",
72
+ "label_prior": "Prior Offenses",
73
+ "label_charge": "Current Charge",
74
+ "label_ai_risk": "🤖 AI Risk Assessment:",
75
+ "label_risk": "Risk",
76
+ "label_confidence": "Confidence:",
77
+ # Demographics Translations
78
+ "Male": "Male",
79
+ "Female": "Female",
80
+ "Hispanic": "Hispanic",
81
+ "White": "White",
82
+ "Black": "Black",
83
+ "High": "High",
84
+ "Medium": "Medium",
85
+ "Low": "Low",
86
+ "Drug possession": "Drug possession",
87
+ "Theft": "Theft",
88
+ "Assault": "Assault",
89
+ "Fraud": "Fraud",
90
+ "Burglary": "Burglary"
91
+ },
92
+ "es": {
93
+ "title": "⚖️ Tú Eres el Juez",
94
+ "intro_role": "<b>Tu Rol:</b> Eres un juez que debe decidir si liberar a los acusados de la prisión.<br>Un sistema de IA ha analizado cada caso y ha proporcionado una evaluación de riesgos.<br><br><b>Tu Tarea:</b> Revisa el perfil de cada acusado y la predicción de la IA, luego toma tu decisión.",
95
+ "loading": "⏳ Cargando...",
96
+ "scenario_title": "📋 El Escenario",
97
+ "scenario_box": """
98
+ Eres juez en un tribunal penal muy concurrido. Debido al hacinamiento en las cárceles, debes decidir
99
+ qué acusados pueden ser liberados de manera segura.<br><br>
100
+
101
+ Para ayudarte, el tribunal ha implementado un sistema de IA que predice el riesgo de que cada
102
+ acusado cometa nuevos delitos si es liberado. La IA clasifica a los acusados como:<br><br>
103
+
104
+ <ul style='font-size:18px;'>
105
+ <li><span class='ai-risk-label risk-high'>Alto Riesgo</span> - Probable reincidencia</li>
106
+ <li><span class='ai-risk-label risk-medium'>Riesgo Medio</span> - Probabilidad moderada de reincidencia</li>
107
+ <li><span class='ai-risk-label risk-low'>Bajo Riesgo</span> - Improbable reincidencia</li>
108
+ </ul>
109
+
110
+ <b>Recuerda:</b> Tus decisiones afectan la vida de personas reales y la seguridad pública.
111
+ """,
112
+ "btn_start": "Comenzar a Tomar Decisiones ▶️",
113
+ "profiles_title": "👥 Perfiles de Acusados",
114
+ "hint_box": "Revisa la información de cada acusado y la evaluación de riesgos de la IA, luego toma tu decisión.",
115
+ "btn_release": "✓ Liberar Prisionero",
116
+ "btn_keep": "✗ Mantener en Prisión",
117
+ "btn_show_summary": "📊 Mostrar Resumen de Decisiones",
118
+ "btn_complete": "Completar esta Sección ▶️",
119
+ "completion_title": "✅ ¡Decisiones Completadas!",
120
+ "completion_box_pre": "Has tomado tus decisiones basándote en las recomendaciones de la IA.<br><br>Pero aquí está la pregunta crítica:<br><br>",
121
+ "completion_question": "¿Y si la IA estuviera equivocada?",
122
+ "completion_box_post": """
123
+ <p style='font-size:1.1rem;'>
124
+ Continúa en la siguiente sección para explorar las consecuencias de
125
+ confiar en las predicciones de la IA en situaciones de alto riesgo.
126
+ </p>
127
+ <h1 style='margin:20px 0; font-size: 3rem;'>👇 DESPLÁZATE HACIA ABAJO 👇</h1>
128
+ <p style='font-size:1.1rem;'>
129
+ Encuentra la siguiente sección abajo para continuar tu viaje.
130
+ </p>
131
+ """,
132
+ "btn_back": "◀️ Volver a Revisar Decisiones",
133
+ "decision_release": "Liberar",
134
+ "decision_keep": "Mantener en Prisión",
135
+ "decision_recorded": "✓ Decisión registrada:",
136
+ "summary_title": "📊 Resumen de tus Decisiones",
137
+ "summary_released": "Prisioneros Liberados:",
138
+ "summary_kept": "Prisioneros Mantenidos en Prisión:",
139
+ "summary_empty": "Aún no se han tomado decisiones.",
140
+ "nav_loading_profiles": "Cargando perfiles...",
141
+ "nav_reviewing": "Revisando tus decisiones...",
142
+ "nav_returning": "Volviendo a perfiles...",
143
+ "label_defendant": "Acusado",
144
+ "label_age": "Edad",
145
+ "label_gender": "Género",
146
+ "label_race": "Raza",
147
+ "label_prior": "Delitos Previos",
148
+ "label_charge": "Cargo Actual",
149
+ "label_ai_risk": "🤖 Evaluación de Riesgo IA:",
150
+ "label_risk": "Riesgo",
151
+ "label_confidence": "Confianza:",
152
+ "Male": "Masculino",
153
+ "Female": "Femenino",
154
+ "Hispanic": "Hispano",
155
+ "White": "Blanco",
156
+ "Black": "Negro",
157
+ "High": "Alto",
158
+ "Medium": "Medio",
159
+ "Low": "Bajo",
160
+ "Drug possession": "Posesión de drogas",
161
+ "Theft": "Robo",
162
+ "Assault": "Asalto",
163
+ "Fraud": "Fraude",
164
+ "Burglary": "Robo con allanamiento"
165
+ },
166
+ "ca": {
167
+ "title": "⚖️ Tu Ets el Jutge",
168
+ "intro_role": "<b>El teu Rol:</b> Ets un jutge que ha de decidir si alliberar els acusats de la presó.<br>Un sistema d'IA ha analitzat cada cas i ha proporcionat una avaluació de riscos.<br><br><b>La teva Tasca:</b> Revisa el perfil de cada acusat i la predicció de la IA, després pren la teva decisió.",
169
+ "loading": "⏳ Carregant...",
170
+ "scenario_title": "📋 L'Escenari",
171
+ "scenario_box": """
172
+ Ets jutge en un tribunal penal molt concorregut. A causa de la massificació a les presons, has de decidir
173
+ quins acusats poden ser alliberats de manera segura.<br><br>
174
+
175
+ Per ajudar-te, el tribunal ha implementat un sistema d'IA que prediu el risc que cada
176
+ acusat cometi nous delictes si és alliberat. La IA classifica els acusats com:<br><br>
177
+
178
+ <ul style='font-size:18px;'>
179
+ <li><span class='ai-risk-label risk-high'>Alt Risc</span> - Probable reincidència</li>
180
+ <li><span class='ai-risk-label risk-medium'>Risc Mitjà</span> - Probabilitat moderada de reincidència</li>
181
+ <li><span class='ai-risk-label risk-low'>Baix Risc</span> - Improbable reincidència</li>
182
+ </ul>
183
+
184
+ <b>Recorda:</b> Les teves decisions afecten la vida de persones reals i la seguretat pública.
185
+ """,
186
+ "btn_start": "Començar a Prendre Decisions ▶️",
187
+ "profiles_title": "👥 Perfils d'Acusats",
188
+ "hint_box": "Revisa la informació de cada acusat i l'avaluació de riscos de la IA, després pren la teva decisió.",
189
+ "btn_release": "✓ Alliberar Presoner",
190
+ "btn_keep": "✗ Mantenir a la Presó",
191
+ "btn_show_summary": "📊 Mostrar Resum de Decisions",
192
+ "btn_complete": "Completar aquesta Secció ▶️",
193
+ "completion_title": "✅ Decisions Completades!",
194
+ "completion_box_pre": "Has pres les teves decisions basant-te en les recomanacions de la IA.<br><br>Però aquí està la pregunta crítica:<br><br>",
195
+ "completion_question": "I si la IA s'hagués equivocat?",
196
+ "completion_box_post": """
197
+ <p style='font-size:1.1rem;'>
198
+ Continua a la següent secció per explorar les conseqüències de
199
+ confiar en les prediccions de la IA en situacions d'alt risc.
200
+ </p>
201
+ <h1 style='margin:20px 0; font-size: 3rem;'>👇 DESPLAÇA'T CAP AVALL 👇</h1>
202
+ <p style='font-size:1.1rem;'>
203
+ Troba la següent secció a sota per continuar el teu viatge.
204
+ </p>
205
+ """,
206
+ "btn_back": "◀️ Tornar a Revisar Decisions",
207
+ "decision_release": "Alliberar",
208
+ "decision_keep": "Mantenir a la Presó",
209
+ "decision_recorded": "✓ Decisió registrada:",
210
+ "summary_title": "📊 Resum de les teves Decisions",
211
+ "summary_released": "Presoners Alliberats:",
212
+ "summary_kept": "Presoners Mantinguts a la Presó:",
213
+ "summary_empty": "Encara no s'han pres decisions.",
214
+ "nav_loading_profiles": "Carregant perfils...",
215
+ "nav_reviewing": "Revisant les teves decisions...",
216
+ "nav_returning": "Tornant a perfils...",
217
+ "label_defendant": "Acusat",
218
+ "label_age": "Edat",
219
+ "label_gender": "Gènere",
220
+ "label_race": "Raça",
221
+ "label_prior": "Delictes Previs",
222
+ "label_charge": "Càrrec Actual",
223
+ "label_ai_risk": "🤖 Avaluació de Risc IA:",
224
+ "label_risk": "Risc",
225
+ "label_confidence": "Confiança:",
226
+ "Male": "Masculí",
227
+ "Female": "Femení",
228
+ "Hispanic": "Hispà",
229
+ "White": "Blanc",
230
+ "Black": "Negre",
231
+ "High": "Alt",
232
+ "Medium": "Mitjà",
233
+ "Low": "Baix",
234
+ "Drug possession": "Possessió de drogues",
235
+ "Theft": "Robatori",
236
+ "Assault": "Assalt",
237
+ "Fraud": "Frau",
238
+ "Burglary": "Robatori amb violència"
239
+ }
240
+ }
241
+
242
+ def _generate_defendant_profiles():
243
+ """Generate synthetic defendant profiles for the exercise."""
244
+ import random
245
+ random.seed(42) # For reproducibility
246
+
247
+ profiles = [
248
+ {
249
+ "id": 1,
250
+ "name": "Carlos M.",
251
+ "age": 23,
252
+ "gender": "Male",
253
+ "race": "Hispanic",
254
+ "prior_offenses": 2,
255
+ "current_charge": "Drug possession",
256
+ "ai_risk": "High",
257
+ "ai_confidence": "85%",
258
+ },
259
+ {
260
+ "id": 2,
261
+ "name": "Sarah J.",
262
+ "age": 34,
263
+ "gender": "Female",
264
+ "race": "White",
265
+ "prior_offenses": 0,
266
+ "current_charge": "Theft",
267
+ "ai_risk": "Low",
268
+ "ai_confidence": "72%",
269
+ },
270
+ {
271
+ "id": 3,
272
+ "name": "DeShawn W.",
273
+ "age": 19,
274
+ "gender": "Male",
275
+ "race": "Black",
276
+ "prior_offenses": 1,
277
+ "current_charge": "Assault",
278
+ "ai_risk": "Medium",
279
+ "ai_confidence": "68%",
280
+ },
281
+ {
282
+ "id": 4,
283
+ "name": "Maria R.",
284
+ "age": 41,
285
+ "gender": "Female",
286
+ "race": "Hispanic",
287
+ "prior_offenses": 3,
288
+ "current_charge": "Fraud",
289
+ "ai_risk": "Medium",
290
+ "ai_confidence": "70%",
291
+ },
292
+ {
293
+ "id": 5,
294
+ "name": "James K.",
295
+ "age": 28,
296
+ "gender": "Male",
297
+ "race": "White",
298
+ "prior_offenses": 5,
299
+ "current_charge": "Burglary",
300
+ "ai_risk": "High",
301
+ "ai_confidence": "91%",
302
+ },
303
+ ]
304
+
305
+ return profiles
306
+
307
+
308
+ def create_judge_app(theme_primary_hue: str = "indigo") -> "gr.Blocks":
309
+ """Create the You Be the Judge Gradio Blocks app."""
310
+
311
+ gr.close_all(verbose=False)
312
+
313
+ profiles = _generate_defendant_profiles()
314
+
315
+ # Track decisions globally for simplicity in this factory context
316
+ decisions = {}
317
+
318
+ # Helpers
319
+ def t(lang, key):
320
+ """Translate helper."""
321
+ return TRANSLATIONS.get(lang, TRANSLATIONS["en"]).get(key, key)
322
+
323
+ def format_profile(profile, lang="en"):
324
+ """Format a defendant profile for display using theme-aware CSS classes and i18n."""
325
+ # Translate values
326
+ gender_t = t(lang, profile['gender'])
327
+ race_t = t(lang, profile['race'])
328
+ charge_t = t(lang, profile['current_charge'])
329
+ risk_val_t = t(lang, profile['ai_risk'])
330
+
331
+ risk_class = f"risk-{profile['ai_risk'].lower()}"
332
+
333
+ return f"""
334
+ <div class="profile-card {risk_class}">
335
+ <h3 class="profile-title">
336
+ {t(lang, 'label_defendant')} #{profile['id']}: {profile['name']}
337
+ </h3>
338
+ <div class="profile-grid">
339
+ <div><b>{t(lang, 'label_age')}:</b> {profile['age']}</div>
340
+ <div><b>{t(lang, 'label_gender')}:</b> {gender_t}</div>
341
+ <div><b>{t(lang, 'label_race')}:</b> {race_t}</div>
342
+ <div><b>{t(lang, 'label_prior')}:</b> {profile['prior_offenses']}</div>
343
+ <div class="profile-charge">
344
+ <b>{t(lang, 'label_charge')}:</b> {charge_t}
345
+ </div>
346
+ </div>
347
+ <div class="ai-risk-container">
348
+ <b>{t(lang, 'label_ai_risk')}</b>
349
+ <span class="ai-risk-label {risk_class}">
350
+ {risk_val_t} {t(lang, 'label_risk')}
351
+ </span>
352
+ <span class="ai-risk-confidence">
353
+ ({t(lang, 'label_confidence')} {profile['ai_confidence']})
354
+ </span>
355
+ </div>
356
+ </div>
357
+ """
358
+
359
+ def make_decision(defendant_id, decision_type, lang):
360
+ """Record a decision for a defendant."""
361
+ # Map generic decision type to display text
362
+ dec_text = t(lang, "decision_release" if decision_type == "Release" else "decision_keep")
363
+ decisions[defendant_id] = decision_type # Store raw type
364
+ return f"{t(lang, 'decision_recorded')} {dec_text}"
365
+
366
+ def get_summary(lang):
367
+ """Get summary of all decisions made."""
368
+ if not decisions:
369
+ return t(lang, "summary_empty")
370
+
371
+ released = sum(1 for d in decisions.values() if d == "Release")
372
+ kept = sum(1 for d in decisions.values() if d == "Keep in Prison")
373
+
374
+ summary = f"""
375
+ <div class="summary-box">
376
+ <h3 class="summary-title">{t(lang, 'summary_title')}</h3>
377
+ <div class="summary-body">
378
+ <p><b>{t(lang, 'summary_released')}</b> {released} of {len(decisions)}</p>
379
+ <p><b>{t(lang, 'summary_kept')}</b> {kept} of {len(decisions)}</p>
380
+ </div>
381
+ </div>
382
+ """
383
+ return summary
384
+
385
+ # --- CSS Definition (Kept Original) ---
386
+ css = """
387
+ /* -------------------------------------------- */
388
+ /* BUTTONS */
389
+ /* -------------------------------------------- */
390
+ .decision-button {
391
+ font-size: 18px !important;
392
+ padding: 12px 24px !important;
393
+ }
394
+
395
+ /* -------------------------------------------- */
396
+ /* TOP INTRO & CONTEXT BOXES */
397
+ /* -------------------------------------------- */
398
+
399
+ .judge-intro-box {
400
+ text-align: center;
401
+ font-size: 18px;
402
+ max-width: 900px;
403
+ margin: auto;
404
+ padding: 20px;
405
+ border-radius: 12px;
406
+ border: 2px solid var(--border-color-primary);
407
+
408
+ background-color: var(--block-background-fill);
409
+ color: var(--body-text-color);
410
+ box-shadow: 0 5px 15px rgba(0, 0, 0, 0.08);
411
+ }
412
+
413
+ .scenario-box {
414
+ font-size: 18px;
415
+ padding: 24px;
416
+ border-radius: 12px;
417
+
418
+ background-color: var(--block-background-fill);
419
+ color: var(--body-text-color);
420
+ border: 1px solid var(--border-color-primary);
421
+ box-shadow: 0 5px 15px rgba(0, 0, 0, 0.08);
422
+ }
423
+
424
+ .hint-box {
425
+ text-align: center;
426
+ font-size: 16px;
427
+ padding: 12px;
428
+ border-radius: 8px;
429
+
430
+ background-color: var(--block-background-fill);
431
+ color: var(--body-text-color);
432
+ border: 1px solid var(--border-color-primary);
433
+ }
434
+
435
+ .complete-box {
436
+ font-size: 1.3rem;
437
+ padding: 28px;
438
+ border-radius: 16px;
439
+
440
+ background-color: var(--block-background-fill);
441
+ color: var(--body-text-color);
442
+ border: 2px solid var(--color-accent);
443
+ box-shadow: 0 5px 15px rgba(0, 0, 0, 0.08);
444
+ }
445
+
446
+ .loading-title {
447
+ font-size: 2rem;
448
+ color: var(--secondary-text-color);
449
+ }
450
+
451
+ /* -------------------------------------------- */
452
+ /* DEFENDANT PROFILE CARD */
453
+ /* -------------------------------------------- */
454
+
455
+ .profile-card {
456
+ background-color: var(--block-background-fill);
457
+ color: var(--body-text-color);
458
+ padding: 20px;
459
+ border-radius: 12px;
460
+ border-left: 6px solid var(--border-color-primary);
461
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.06);
462
+ }
463
+
464
+ .profile-title {
465
+ margin-top: 0;
466
+ color: var(--body-text-color);
467
+ }
468
+
469
+ .profile-grid {
470
+ display: grid;
471
+ grid-template-columns: 1fr 1fr;
472
+ gap: 12px;
473
+ font-size: 16px;
474
+ }
475
+
476
+ .profile-charge {
477
+ grid-column: span 2;
478
+ }
479
+
480
+ .ai-risk-container {
481
+ margin-top: 16px;
482
+ padding: 12px;
483
+ background-color: var(--body-background-fill);
484
+ border-radius: 8px;
485
+ border: 1px solid var(--border-color-primary);
486
+ }
487
+
488
+ .ai-risk-label {
489
+ font-size: 20px;
490
+ font-weight: bold;
491
+ margin-left: 4px;
492
+ }
493
+
494
+ .ai-risk-confidence {
495
+ color: var(--secondary-text-color);
496
+ margin-left: 8px;
497
+ }
498
+
499
+ /* Semantic risk colors */
500
+ .risk-high { border-left-color: #ef4444; color: #ef4444; }
501
+ .profile-card.risk-high { border-left-color: #ef4444; }
502
+
503
+ .risk-medium { border-left-color: #f59e0b; color: #f59e0b; }
504
+ .profile-card.risk-medium { border-left-color: #f59e0b; }
505
+
506
+ .risk-low { border-left-color: #22c55e; color: #22c55e; }
507
+ .profile-card.risk-low { border-left-color: #22c55e; }
508
+
509
+ /* -------------------------------------------- */
510
+ /* SUMMARY BOX */
511
+ /* -------------------------------------------- */
512
+
513
+ .summary-box {
514
+ background-color: var(--block-background-fill);
515
+ color: var(--body-text-color);
516
+ padding: 20px;
517
+ border-radius: 12px;
518
+ border: 1px solid var(--border-color-primary);
519
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.06);
520
+ }
521
+
522
+ .summary-title { margin-top: 0; }
523
+ .summary-body { font-size: 18px; }
524
+
525
+ /* -------------------------------------------- */
526
+ /* NAVIGATION LOADING OVERLAY */
527
+ /* -------------------------------------------- */
528
+
529
+ #nav-loading-overlay {
530
+ position: fixed;
531
+ top: 0;
532
+ left: 0;
533
+ width: 100%;
534
+ height: 100%;
535
+ background: color-mix(in srgb, var(--body-background-fill) 95%, transparent);
536
+ z-index: 9999;
537
+ display: none;
538
+ flex-direction: column;
539
+ align-items: center;
540
+ justify-content: center;
541
+ opacity: 0;
542
+ transition: opacity 0.3s ease;
543
+ }
544
+
545
+ .nav-spinner {
546
+ width: 50px;
547
+ height: 50px;
548
+ border: 5px solid var(--border-color-primary);
549
+ border-top: 5px solid var(--color-accent);
550
+ border-radius: 50%;
551
+ animation: nav-spin 1s linear infinite;
552
+ margin-bottom: 20px;
553
+ }
554
+
555
+ @keyframes nav-spin {
556
+ 0% { transform: rotate(0deg); }
557
+ 100% { transform: rotate(360deg); }
558
+ }
559
+
560
+ #nav-loading-text {
561
+ font-size: 1.3rem;
562
+ font-weight: 600;
563
+ color: var(--color-accent);
564
+ }
565
+
566
+ @media (prefers-color-scheme: dark) {
567
+ .judge-intro-box, .scenario-box, .hint-box, .complete-box,
568
+ .profile-card, .summary-box {
569
+ background-color: #2D323E;
570
+ color: white;
571
+ border-color: #555555;
572
+ box-shadow: none;
573
+ }
574
+ .ai-risk-container {
575
+ background-color: #181B22;
576
+ border-color: #555555;
577
+ }
578
+ #nav-loading-overlay { background: rgba(15, 23, 42, 0.9); }
579
+ .nav-spinner {
580
+ border-color: rgba(148, 163, 184, 0.4);
581
+ border-top-color: var(--color-accent);
582
+ }
583
+ }
584
+ """
585
+
586
+ with gr.Blocks(theme=gr.themes.Soft(primary_hue=theme_primary_hue), css=css) as demo:
587
+ # State to hold current language (defaults to 'en')
588
+ lang_state = gr.State(value="en")
589
+
590
+ # --- UI COMPONENTS (Stored in variables for update) ---
591
+
592
+ gr.HTML("<div id='app_top_anchor' style='height:0;'></div>")
593
+
594
+ # Overlay
595
+ gr.HTML("""
596
+ <div id='nav-loading-overlay'>
597
+ <div class='nav-spinner'></div>
598
+ <span id='nav-loading-text'>Loading...</span>
599
+ </div>
600
+ """)
601
+
602
+ # Title
603
+ c_main_title = gr.Markdown("<h1 style='text-align:center;'>⚖️ You Be the Judge</h1>")
604
+
605
+ # Intro - CHANGED TO HTML to fix broken visuals
606
+ c_intro_html = gr.HTML(
607
+ f"""<div class="judge-intro-box">{t('en', 'intro_role')}</div>"""
608
+ )
609
+
610
+ gr.HTML("<hr style='margin:24px 0;'>")
611
+
612
+ # --- Loading screen ---
613
+ with gr.Column(visible=False) as loading_screen:
614
+ c_loading_title = gr.HTML(
615
+ f"""<div style='text-align:center; padding: 100px 0;'><h2 class='loading-title'>{t('en', 'loading')}</h2></div>"""
616
+ )
617
+
618
+ # --- Introduction Section ---
619
+ with gr.Column(visible=True, elem_id="intro") as intro_section:
620
+ c_scenario_title = gr.Markdown(f"<h2 style='text-align:center;'>{t('en', 'scenario_title')}</h2>")
621
+ # CHANGED TO HTML
622
+ c_scenario_box = gr.HTML(f"""<div class="scenario-box">{t('en', 'scenario_box')}</div>""")
623
+ start_btn = gr.Button(t('en', 'btn_start'), variant="primary", size="lg")
624
+
625
+ # --- Defendant profiles section ---
626
+ profile_ui_elements = [] # To store (html, btn_rel, btn_keep) tuples
627
+
628
+ with gr.Column(visible=False, elem_id="profiles") as profiles_section:
629
+ c_profiles_title = gr.Markdown(f"<h2 style='text-align:center;'>{t('en', 'profiles_title')}</h2>")
630
+ # CHANGED TO HTML
631
+ c_hint_box = gr.HTML(f"""<div class="hint-box">{t('en', 'hint_box')}</div>""")
632
+ gr.HTML("<br>")
633
+
634
+ # Create UI for each defendant
635
+ for profile in profiles:
636
+ with gr.Column():
637
+ # Profile Card HTML
638
+ p_html = gr.HTML(format_profile(profile, "en"))
639
+
640
+ with gr.Row():
641
+ p_rel_btn = gr.Button(
642
+ t('en', 'btn_release'),
643
+ variant="primary",
644
+ elem_classes=["decision-button"],
645
+ )
646
+ p_keep_btn = gr.Button(
647
+ t('en', 'btn_keep'),
648
+ variant="secondary",
649
+ elem_classes=["decision-button"],
650
+ )
651
+
652
+ decision_status = gr.Markdown("")
653
+
654
+ # Store for language updates
655
+ profile_ui_elements.append({
656
+ "id": profile["id"],
657
+ "profile_data": profile,
658
+ "html": p_html,
659
+ "btn_rel": p_rel_btn,
660
+ "btn_keep": p_keep_btn
661
+ })
662
+
663
+ # Wire up buttons (passing lang_state)
664
+ p_rel_btn.click(
665
+ lambda l, p_id=profile["id"]: make_decision(p_id, "Release", l),
666
+ inputs=[lang_state],
667
+ outputs=decision_status,
668
+ )
669
+ p_keep_btn.click(
670
+ lambda l, p_id=profile["id"]: make_decision(p_id, "Keep in Prison", l),
671
+ inputs=[lang_state],
672
+ outputs=decision_status,
673
+ )
674
+
675
+ gr.HTML("<hr style='margin:24px 0;'>")
676
+
677
+ # Summary section
678
+ summary_display = gr.HTML("")
679
+ show_summary_btn = gr.Button(t('en', 'btn_show_summary'), variant="primary", size="lg")
680
+
681
+ show_summary_btn.click(get_summary, inputs=[lang_state], outputs=summary_display)
682
+
683
+ gr.HTML("<br>")
684
+ complete_btn = gr.Button(t('en', 'btn_complete'), variant="primary", size="lg")
685
+
686
+ # --- Completion section ---
687
+ with gr.Column(visible=False, elem_id="complete") as complete_section:
688
+ # CHANGED TO HTML
689
+ c_completion_html = gr.HTML(
690
+ f"""
691
+ <div style='text-align:center;'>
692
+ <h2 style='font-size: 2.5rem;'>{t('en', 'completion_title')}</h2>
693
+ <div class="complete-box">
694
+ {t('en', 'completion_box_pre')}
695
+ <h2 style='margin:16px 0; color: var(--color-accent);'>{t('en', 'completion_question')}</h2>
696
+ {t('en', 'completion_box_post')}
697
+ </div>
698
+ </div>
699
+ """
700
+ )
701
+ back_to_profiles_btn = gr.Button(t('en', 'btn_back'))
702
+
703
+ # -------------------------------------------------------------------------
704
+ # I18N UPDATE LOGIC
705
+ # -------------------------------------------------------------------------
706
+
707
+ # List of all components that need text updates
708
+ # Order matters! Must match the return of update_language
709
+ update_targets = [
710
+ lang_state, # 0
711
+ c_main_title, # 1
712
+ c_intro_html, # 2
713
+ c_loading_title, # 3
714
+ c_scenario_title, # 4
715
+ c_scenario_box, # 5
716
+ start_btn, # 6
717
+ c_profiles_title, # 7
718
+ c_hint_box, # 8
719
+ show_summary_btn, # 9
720
+ complete_btn, # 10
721
+ c_completion_html, # 11
722
+ back_to_profiles_btn # 12
723
+ ]
724
+
725
+ # Add dynamic profile components
726
+ for p_ui in profile_ui_elements:
727
+ update_targets.append(p_ui["html"])
728
+ update_targets.append(p_ui["btn_rel"])
729
+ update_targets.append(p_ui["btn_keep"])
730
+
731
+ def update_language(request: gr.Request):
732
+ """Parse URL params and return updated content for all components."""
733
+ params = request.query_params
734
+ lang = params.get("lang", "en")
735
+ if lang not in TRANSLATIONS:
736
+ lang = "en"
737
+
738
+ # Prepare updates
739
+ updates = []
740
+
741
+ # 0. State
742
+ updates.append(lang)
743
+
744
+ # 1. Main Title
745
+ updates.append(f"<h1 style='text-align:center;'>{t(lang, 'title')}</h1>")
746
+
747
+ # 2. Intro
748
+ updates.append(f"""<div class="judge-intro-box">{t(lang, 'intro_role')}</div>""")
749
+
750
+ # 3. Loading
751
+ updates.append(f"""<div style='text-align:center; padding: 100px 0;'><h2 class='loading-title'>{t(lang, 'loading')}</h2></div>""")
752
+
753
+ # 4. Scenario Title
754
+ updates.append(f"<h2 style='text-align:center;'>{t(lang, 'scenario_title')}</h2>")
755
+
756
+ # 5. Scenario Box
757
+ updates.append(f"""<div class="scenario-box">{t(lang, 'scenario_box')}</div>""")
758
+
759
+ # 6. Start Button
760
+ updates.append(gr.Button(value=t(lang, 'btn_start')))
761
+
762
+ # 7. Profiles Title
763
+ updates.append(f"<h2 style='text-align:center;'>{t(lang, 'profiles_title')}</h2>")
764
+
765
+ # 8. Hint Box
766
+ updates.append(f"""<div class="hint-box">{t(lang, 'hint_box')}</div>""")
767
+
768
+ # 9. Summary Button
769
+ updates.append(gr.Button(value=t(lang, 'btn_show_summary')))
770
+
771
+ # 10. Complete Button
772
+ updates.append(gr.Button(value=t(lang, 'btn_complete')))
773
+
774
+ # 11. Completion HTML
775
+ updates.append(f"""
776
+ <div style='text-align:center;'>
777
+ <h2 style='font-size: 2.5rem;'>{t(lang, 'completion_title')}</h2>
778
+ <div class="complete-box">
779
+ {t(lang, 'completion_box_pre')}
780
+ <h2 style='margin:16px 0; color: var(--color-accent);'>{t(lang, 'completion_question')}</h2>
781
+ {t(lang, 'completion_box_post')}
782
+ </div>
783
+ </div>
784
+ """)
785
+
786
+ # 12. Back Button
787
+ updates.append(gr.Button(value=t(lang, 'btn_back')))
788
+
789
+ # Dynamic Profiles
790
+ for p_ui in profile_ui_elements:
791
+ # Update HTML card
792
+ updates.append(format_profile(p_ui["profile_data"], lang))
793
+ # Update Buttons
794
+ updates.append(gr.Button(value=t(lang, 'btn_release')))
795
+ updates.append(gr.Button(value=t(lang, 'btn_keep')))
796
+
797
+ return updates
798
+
799
+ # Trigger update on page load
800
+ demo.load(update_language, inputs=None, outputs=update_targets)
801
+
802
+ # -------------------------------------------------------------------------
803
+ # NAVIGATION GENERATORS
804
+ # -------------------------------------------------------------------------
805
+
806
+ all_steps = [intro_section, profiles_section, complete_section, loading_screen]
807
+
808
+ def create_nav_generator(current_step, next_step):
809
+ def navigate():
810
+ updates = {loading_screen: gr.update(visible=True)}
811
+ for step in all_steps:
812
+ if step != loading_screen:
813
+ updates[step] = gr.update(visible=False)
814
+ yield updates
815
+
816
+ updates = {next_step: gr.update(visible=True)}
817
+ for step in all_steps:
818
+ if step != next_step:
819
+ updates[step] = gr.update(visible=False)
820
+ yield updates
821
+ return navigate
822
+
823
+ # JS Helper
824
+ def nav_js(target_id: str, message: str) -> str:
825
+ return f"""
826
+ ()=>{{
827
+ try {{
828
+ const overlay = document.getElementById('nav-loading-overlay');
829
+ const messageEl = document.getElementById('nav-loading-text');
830
+ if(overlay && messageEl) {{
831
+ messageEl.textContent = '{message}';
832
+ overlay.style.display = 'flex';
833
+ setTimeout(() => {{ overlay.style.opacity = '1'; }}, 10);
834
+ }}
835
+
836
+ const startTime = Date.now();
837
+ setTimeout(() => {{
838
+ const anchor = document.getElementById('app_top_anchor');
839
+ if(anchor) anchor.scrollIntoView({{behavior:'smooth', block:'start'}});
840
+ }}, 40);
841
+
842
+ const targetId = '{target_id}';
843
+ const pollInterval = setInterval(() => {{
844
+ const elapsed = Date.now() - startTime;
845
+ const target = document.getElementById(targetId);
846
+ const isVisible = target && target.offsetParent !== null &&
847
+ window.getComputedStyle(target).display !== 'none';
848
+
849
+ if((isVisible && elapsed >= 1200) || elapsed > 7000) {{
850
+ clearInterval(pollInterval);
851
+ if(overlay) {{
852
+ overlay.style.opacity = '0';
853
+ setTimeout(() => {{ overlay.style.display = 'none'; }}, 300);
854
+ }}
855
+ }}
856
+ }}, 90);
857
+ }} catch(e) {{ console.warn('nav-js error', e); }}
858
+ }}
859
+ """
860
+
861
+ # Wire navigation
862
+ start_btn.click(
863
+ fn=create_nav_generator(intro_section, profiles_section),
864
+ outputs=all_steps,
865
+ js=nav_js("profiles", "Loading..."),
866
+ )
867
+ complete_btn.click(
868
+ fn=create_nav_generator(profiles_section, complete_section),
869
+ outputs=all_steps,
870
+ js=nav_js("complete", "Processing..."),
871
+ )
872
+ back_to_profiles_btn.click(
873
+ fn=create_nav_generator(complete_section, profiles_section),
874
+ outputs=all_steps,
875
+ js=nav_js("profiles", "Loading..."),
876
+ )
877
+
878
+ return demo
879
+
880
+
881
+ def launch_judge_app(height: int = 1200, share: bool = False, debug: bool = False) -> None:
882
+ demo = create_judge_app()
883
+ port = int(os.environ.get("PORT", 8080))
884
+ demo.launch(share=share, inline=True, debug=debug, height=height, server_port=port)
885
+
886
+ if __name__ == "__main__":
887
+ launch_judge_app()
888
+