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.
- aimodelshare/README.md +26 -0
- aimodelshare/__init__.py +100 -0
- aimodelshare/aimsonnx.py +2381 -0
- aimodelshare/api.py +836 -0
- aimodelshare/auth.py +163 -0
- aimodelshare/aws.py +511 -0
- aimodelshare/aws_client.py +173 -0
- aimodelshare/base_image.py +154 -0
- aimodelshare/bucketpolicy.py +106 -0
- aimodelshare/color_mappings/color_mapping_keras.csv +121 -0
- aimodelshare/color_mappings/color_mapping_pytorch.csv +117 -0
- aimodelshare/containerisation.py +244 -0
- aimodelshare/containerization.py +712 -0
- aimodelshare/containerization_templates/Dockerfile.txt +8 -0
- aimodelshare/containerization_templates/Dockerfile_PySpark.txt +23 -0
- aimodelshare/containerization_templates/buildspec.txt +14 -0
- aimodelshare/containerization_templates/lambda_function.txt +40 -0
- aimodelshare/custom_approach/__init__.py +1 -0
- aimodelshare/custom_approach/lambda_function.py +17 -0
- aimodelshare/custom_eval_metrics.py +103 -0
- aimodelshare/data_sharing/__init__.py +0 -0
- aimodelshare/data_sharing/data_sharing_templates/Dockerfile.txt +3 -0
- aimodelshare/data_sharing/data_sharing_templates/__init__.py +1 -0
- aimodelshare/data_sharing/data_sharing_templates/buildspec.txt +15 -0
- aimodelshare/data_sharing/data_sharing_templates/codebuild_policies.txt +129 -0
- aimodelshare/data_sharing/data_sharing_templates/codebuild_trust_relationship.txt +12 -0
- aimodelshare/data_sharing/download_data.py +620 -0
- aimodelshare/data_sharing/share_data.py +373 -0
- aimodelshare/data_sharing/utils.py +8 -0
- aimodelshare/deploy_custom_lambda.py +246 -0
- aimodelshare/documentation/Makefile +20 -0
- aimodelshare/documentation/karma_sphinx_theme/__init__.py +28 -0
- aimodelshare/documentation/karma_sphinx_theme/_version.py +2 -0
- aimodelshare/documentation/karma_sphinx_theme/breadcrumbs.html +70 -0
- aimodelshare/documentation/karma_sphinx_theme/layout.html +172 -0
- aimodelshare/documentation/karma_sphinx_theme/search.html +50 -0
- aimodelshare/documentation/karma_sphinx_theme/searchbox.html +14 -0
- aimodelshare/documentation/karma_sphinx_theme/static/css/custom.css +2 -0
- aimodelshare/documentation/karma_sphinx_theme/static/css/custom.css.map +1 -0
- aimodelshare/documentation/karma_sphinx_theme/static/css/theme.css +2751 -0
- aimodelshare/documentation/karma_sphinx_theme/static/css/theme.css.map +1 -0
- aimodelshare/documentation/karma_sphinx_theme/static/css/theme.min.css +2 -0
- aimodelshare/documentation/karma_sphinx_theme/static/css/theme.min.css.map +1 -0
- aimodelshare/documentation/karma_sphinx_theme/static/font/fontello.eot +0 -0
- aimodelshare/documentation/karma_sphinx_theme/static/font/fontello.svg +32 -0
- aimodelshare/documentation/karma_sphinx_theme/static/font/fontello.ttf +0 -0
- aimodelshare/documentation/karma_sphinx_theme/static/font/fontello.woff +0 -0
- aimodelshare/documentation/karma_sphinx_theme/static/font/fontello.woff2 +0 -0
- aimodelshare/documentation/karma_sphinx_theme/static/js/theme.js +68 -0
- aimodelshare/documentation/karma_sphinx_theme/theme.conf +9 -0
- aimodelshare/documentation/make.bat +35 -0
- aimodelshare/documentation/requirements.txt +2 -0
- aimodelshare/documentation/source/about.rst +18 -0
- aimodelshare/documentation/source/advanced_features.rst +137 -0
- aimodelshare/documentation/source/competition.rst +218 -0
- aimodelshare/documentation/source/conf.py +58 -0
- aimodelshare/documentation/source/create_credentials.rst +86 -0
- aimodelshare/documentation/source/example_notebooks.rst +132 -0
- aimodelshare/documentation/source/functions.rst +151 -0
- aimodelshare/documentation/source/gettingstarted.rst +390 -0
- aimodelshare/documentation/source/images/creds1.png +0 -0
- aimodelshare/documentation/source/images/creds2.png +0 -0
- aimodelshare/documentation/source/images/creds3.png +0 -0
- aimodelshare/documentation/source/images/creds4.png +0 -0
- aimodelshare/documentation/source/images/creds5.png +0 -0
- aimodelshare/documentation/source/images/creds_file_example.png +0 -0
- aimodelshare/documentation/source/images/predict_tab.png +0 -0
- aimodelshare/documentation/source/index.rst +110 -0
- aimodelshare/documentation/source/modelplayground.rst +132 -0
- aimodelshare/exceptions.py +11 -0
- aimodelshare/generatemodelapi.py +1270 -0
- aimodelshare/iam/codebuild_policy.txt +129 -0
- aimodelshare/iam/codebuild_trust_relationship.txt +12 -0
- aimodelshare/iam/lambda_policy.txt +15 -0
- aimodelshare/iam/lambda_trust_relationship.txt +12 -0
- aimodelshare/json_templates/__init__.py +1 -0
- aimodelshare/json_templates/api_json.txt +155 -0
- aimodelshare/json_templates/auth/policy.txt +1 -0
- aimodelshare/json_templates/auth/role.txt +1 -0
- aimodelshare/json_templates/eval/policy.txt +1 -0
- aimodelshare/json_templates/eval/role.txt +1 -0
- aimodelshare/json_templates/function/policy.txt +1 -0
- aimodelshare/json_templates/function/role.txt +1 -0
- aimodelshare/json_templates/integration_response.txt +5 -0
- aimodelshare/json_templates/lambda_policy_1.txt +15 -0
- aimodelshare/json_templates/lambda_policy_2.txt +8 -0
- aimodelshare/json_templates/lambda_role_1.txt +12 -0
- aimodelshare/json_templates/lambda_role_2.txt +16 -0
- aimodelshare/leaderboard.py +174 -0
- aimodelshare/main/1.txt +132 -0
- aimodelshare/main/1B.txt +112 -0
- aimodelshare/main/2.txt +153 -0
- aimodelshare/main/3.txt +134 -0
- aimodelshare/main/4.txt +128 -0
- aimodelshare/main/5.txt +109 -0
- aimodelshare/main/6.txt +105 -0
- aimodelshare/main/7.txt +144 -0
- aimodelshare/main/8.txt +142 -0
- aimodelshare/main/__init__.py +1 -0
- aimodelshare/main/authorization.txt +275 -0
- aimodelshare/main/eval_classification.txt +79 -0
- aimodelshare/main/eval_lambda.txt +1709 -0
- aimodelshare/main/eval_regression.txt +80 -0
- aimodelshare/main/lambda_function.txt +8 -0
- aimodelshare/main/nst.txt +149 -0
- aimodelshare/model.py +1543 -0
- aimodelshare/modeluser.py +215 -0
- aimodelshare/moral_compass/README.md +408 -0
- aimodelshare/moral_compass/__init__.py +65 -0
- aimodelshare/moral_compass/_version.py +3 -0
- aimodelshare/moral_compass/api_client.py +601 -0
- aimodelshare/moral_compass/apps/__init__.py +69 -0
- aimodelshare/moral_compass/apps/ai_consequences.py +540 -0
- aimodelshare/moral_compass/apps/bias_detective.py +714 -0
- aimodelshare/moral_compass/apps/ethical_revelation.py +898 -0
- aimodelshare/moral_compass/apps/fairness_fixer.py +889 -0
- aimodelshare/moral_compass/apps/judge.py +888 -0
- aimodelshare/moral_compass/apps/justice_equity_upgrade.py +853 -0
- aimodelshare/moral_compass/apps/mc_integration_helpers.py +820 -0
- aimodelshare/moral_compass/apps/model_building_game.py +1104 -0
- aimodelshare/moral_compass/apps/model_building_game_beginner.py +687 -0
- aimodelshare/moral_compass/apps/moral_compass_challenge.py +858 -0
- aimodelshare/moral_compass/apps/session_auth.py +254 -0
- aimodelshare/moral_compass/apps/shared_activity_styles.css +349 -0
- aimodelshare/moral_compass/apps/tutorial.py +481 -0
- aimodelshare/moral_compass/apps/what_is_ai.py +853 -0
- aimodelshare/moral_compass/challenge.py +365 -0
- aimodelshare/moral_compass/config.py +187 -0
- aimodelshare/placeholders/model.onnx +0 -0
- aimodelshare/placeholders/preprocessor.zip +0 -0
- aimodelshare/playground.py +1968 -0
- aimodelshare/postprocessormodules.py +157 -0
- aimodelshare/preprocessormodules.py +373 -0
- aimodelshare/pyspark/1.txt +195 -0
- aimodelshare/pyspark/1B.txt +181 -0
- aimodelshare/pyspark/2.txt +220 -0
- aimodelshare/pyspark/3.txt +204 -0
- aimodelshare/pyspark/4.txt +187 -0
- aimodelshare/pyspark/5.txt +178 -0
- aimodelshare/pyspark/6.txt +174 -0
- aimodelshare/pyspark/7.txt +211 -0
- aimodelshare/pyspark/8.txt +206 -0
- aimodelshare/pyspark/__init__.py +1 -0
- aimodelshare/pyspark/authorization.txt +258 -0
- aimodelshare/pyspark/eval_classification.txt +79 -0
- aimodelshare/pyspark/eval_lambda.txt +1441 -0
- aimodelshare/pyspark/eval_regression.txt +80 -0
- aimodelshare/pyspark/lambda_function.txt +8 -0
- aimodelshare/pyspark/nst.txt +213 -0
- aimodelshare/python/my_preprocessor.py +58 -0
- aimodelshare/readme.md +26 -0
- aimodelshare/reproducibility.py +181 -0
- aimodelshare/sam/Dockerfile.txt +8 -0
- aimodelshare/sam/Dockerfile_PySpark.txt +24 -0
- aimodelshare/sam/__init__.py +1 -0
- aimodelshare/sam/buildspec.txt +11 -0
- aimodelshare/sam/codebuild_policies.txt +129 -0
- aimodelshare/sam/codebuild_trust_relationship.txt +12 -0
- aimodelshare/sam/codepipeline_policies.txt +173 -0
- aimodelshare/sam/codepipeline_trust_relationship.txt +12 -0
- aimodelshare/sam/spark-class.txt +2 -0
- aimodelshare/sam/template.txt +54 -0
- aimodelshare/tools.py +103 -0
- aimodelshare/utils/__init__.py +78 -0
- aimodelshare/utils/optional_deps.py +38 -0
- aimodelshare/utils.py +57 -0
- aimodelshare-0.3.7.dist-info/METADATA +298 -0
- aimodelshare-0.3.7.dist-info/RECORD +171 -0
- aimodelshare-0.3.7.dist-info/WHEEL +5 -0
- aimodelshare-0.3.7.dist-info/licenses/LICENSE +5 -0
- aimodelshare-0.3.7.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,540 @@
|
|
|
1
|
+
"""
|
|
2
|
+
AI Consequences - Gradio application for the Justice & Equity Challenge.
|
|
3
|
+
Updated with i18n support for English (en), Spanish (es), and Catalan (ca).
|
|
4
|
+
"""
|
|
5
|
+
import contextlib
|
|
6
|
+
import os
|
|
7
|
+
import gradio as gr
|
|
8
|
+
|
|
9
|
+
# -------------------------------------------------------------------------
|
|
10
|
+
# TRANSLATION CONFIGURATION
|
|
11
|
+
# -------------------------------------------------------------------------
|
|
12
|
+
|
|
13
|
+
TRANSLATIONS = {
|
|
14
|
+
"en": {
|
|
15
|
+
"title": "⚠️ What If the AI Was Wrong?",
|
|
16
|
+
"intro_box": "You just made decisions based on an AI's predictions.<br>But AI systems are not perfect. Let's explore what happens when they make mistakes.",
|
|
17
|
+
"loading": "⏳ Loading...",
|
|
18
|
+
# Step 1
|
|
19
|
+
"s1_title": "The Stakes of AI Predictions",
|
|
20
|
+
"s1_p1": "In the previous exercise, you relied on an AI system to predict which defendants were at <b>High</b>, <b>Medium</b>, or <b>Low</b> risk of re-offending.",
|
|
21
|
+
"s1_p2": "<b>But what if those predictions were incorrect?</b>",
|
|
22
|
+
"s1_p3": "AI systems make two types of errors that have very different consequences:",
|
|
23
|
+
"s1_li1": "<b>False Positives</b> - Incorrectly predicting HIGH risk",
|
|
24
|
+
"s1_li2": "<b>False Negatives</b> - Incorrectly predicting LOW risk",
|
|
25
|
+
"s1_p4": "Let's examine each type of error and its real-world impact.",
|
|
26
|
+
"btn_next_fp": "Next: False Positives ▶️",
|
|
27
|
+
# Step 2 (False Positives)
|
|
28
|
+
"s2_title": "🔴 False Positives: Predicting Danger Where None Exists",
|
|
29
|
+
"s2_card_title": "What is a False Positive?",
|
|
30
|
+
"s2_def": "A <b>false positive</b> occurs when the AI predicts someone is <b style='color:#dc2626;'>HIGH RISK</b>, but they would NOT have actually re-offended if released.",
|
|
31
|
+
"s2_ex_title": "Example Scenario:",
|
|
32
|
+
"s2_ex_li1": "• Sarah was flagged as <b style='color:#dc2626;'>HIGH RISK</b>",
|
|
33
|
+
"s2_ex_li2": "• Based on this, the judge kept her in prison",
|
|
34
|
+
"s2_ex_li3": "• In reality, Sarah would have rebuilt her life and never committed another crime",
|
|
35
|
+
"s2_cost_title": "The Human Cost:",
|
|
36
|
+
"s2_cost_li1": "Innocent people spend unnecessary time in prison",
|
|
37
|
+
"s2_cost_li2": "Families are separated for longer than needed",
|
|
38
|
+
"s2_cost_li3": "Job opportunities and rehabilitation are delayed",
|
|
39
|
+
"s2_cost_li4": "Trust in the justice system erodes",
|
|
40
|
+
"s2_cost_li5": "Disproportionate impact on marginalized communities",
|
|
41
|
+
"s2_key": "<b>Key Point:</b> False positives mean the AI is being <b>too cautious</b>, keeping people locked up who should be free.",
|
|
42
|
+
"btn_back": "◀️ Back",
|
|
43
|
+
"btn_next_fn": "Next: False Negatives ▶️",
|
|
44
|
+
# Step 3 (False Negatives)
|
|
45
|
+
"s3_title": "🔵 False Negatives: Missing Real Danger",
|
|
46
|
+
"s3_card_title": "What is a False Negative?",
|
|
47
|
+
"s3_def": "A <b>false negative</b> occurs when the AI predicts someone is <b style='color:#16a34a;'>LOW RISK</b>, but they DO actually re-offend after being released.",
|
|
48
|
+
"s3_ex_title": "Example Scenario:",
|
|
49
|
+
"s3_ex_li1": "• James was flagged as <b style='color:#16a34a;'>LOW RISK</b>",
|
|
50
|
+
"s3_ex_li2": "• Based on this, the judge released him",
|
|
51
|
+
"s3_ex_li3": "• Unfortunately, James did commit another serious crime",
|
|
52
|
+
"s3_cost_title": "The Human Cost:",
|
|
53
|
+
"s3_cost_li1": "New victims of preventable crimes",
|
|
54
|
+
"s3_cost_li2": "Loss of public trust in the justice system",
|
|
55
|
+
"s3_cost_li3": "Media scrutiny and backlash against judges",
|
|
56
|
+
"s3_cost_li4": "Political pressure to be 'tough on crime'",
|
|
57
|
+
"s3_cost_li5": "Potential harm to communities and families",
|
|
58
|
+
"s3_key": "<b>Key Point:</b> False negatives mean the AI is being <b>too lenient</b>, releasing people who pose a real danger to society.",
|
|
59
|
+
"btn_next_dil": "Next: The Dilemma ▶️",
|
|
60
|
+
# Step 4 (Dilemma)
|
|
61
|
+
"s4_title": "⚖️ The Impossible Balance",
|
|
62
|
+
"s4_card_title": "Every AI System Makes Trade-offs",
|
|
63
|
+
"s4_p1": "Here's the harsh reality: <b>No AI system can eliminate both types of errors.</b>",
|
|
64
|
+
"s4_sub1": "<b>If you make the AI more cautious:</b>",
|
|
65
|
+
"s4_sub1_li1": "✓ Fewer false negatives (fewer dangerous people released)",
|
|
66
|
+
"s4_sub1_li2": "✗ More false positives (more innocent people kept in prison)",
|
|
67
|
+
"s4_sub2": "<b>If you make the AI more lenient:</b>",
|
|
68
|
+
"s4_sub2_li1": "✓ Fewer false positives (more innocent people freed)",
|
|
69
|
+
"s4_sub2_li2": "✗ More false negatives (more dangerous people released)",
|
|
70
|
+
"s4_eth_title": "The Ethical Question:",
|
|
71
|
+
"s4_q1": "Which mistake is worse?",
|
|
72
|
+
"s4_q2": "• Keeping innocent people in prison?<br>• Or releasing dangerous individuals?",
|
|
73
|
+
"s4_conc": "<b>There is no universally 'correct' answer.</b> Different societies, legal systems, and ethical frameworks weigh these trade-offs differently.",
|
|
74
|
+
"s4_final": "<b>This is why understanding AI is crucial.</b> We need to know how these systems work so we can make informed decisions about when and how to use them.",
|
|
75
|
+
"btn_cont": "Continue to Learn About AI ▶️",
|
|
76
|
+
# Step 5 (Completion)
|
|
77
|
+
"s5_title": "✅ Section Complete!",
|
|
78
|
+
"s5_p1": "You now understand the consequences of AI errors in high-stakes decisions.",
|
|
79
|
+
"s5_p2": "<b>Next up:</b> Learn what AI actually is and how these prediction systems work.",
|
|
80
|
+
"s5_p3": "This knowledge will help you understand how to build better, more ethical AI systems.",
|
|
81
|
+
"s5_scroll": "👇 SCROLL DOWN 👇",
|
|
82
|
+
"s5_find": "Find the next section below to continue your journey.",
|
|
83
|
+
"btn_review": "◀️ Back to Review"
|
|
84
|
+
},
|
|
85
|
+
"es": {
|
|
86
|
+
"title": "⚠️ ¿Y si la IA estuviera equivocada?",
|
|
87
|
+
"intro_box": "Acabas de tomar decisiones basadas en las predicciones de una IA.<br>Pero los sistemas de IA no son perfectos. Exploremos qué sucede cuando cometen errores.",
|
|
88
|
+
"loading": "⏳ Cargando...",
|
|
89
|
+
# Step 1
|
|
90
|
+
"s1_title": "Las Apuestas de las Predicciones de IA",
|
|
91
|
+
"s1_p1": "En el ejercicio anterior, confiaste en un sistema de IA para predecir qué acusados tenían un riesgo <b>Alto</b>, <b>Medio</b> o <b>Bajo</b> de reincidir.",
|
|
92
|
+
"s1_p2": "<b>¿Pero qué pasa si esas predicciones eran incorrectas?</b>",
|
|
93
|
+
"s1_p3": "Los sistemas de IA cometen dos tipos de errores que tienen consecuencias muy diferentes:",
|
|
94
|
+
"s1_li1": "<b>Falsos Positivos</b> - Predecir incorrectamente ALTO riesgo",
|
|
95
|
+
"s1_li2": "<b>Falsos Negativos</b> - Predecir incorrectamente BAJO riesgo",
|
|
96
|
+
"s1_p4": "Examinemos cada tipo de error y su impacto en el mundo real.",
|
|
97
|
+
"btn_next_fp": "Siguiente: Falsos Positivos ▶️",
|
|
98
|
+
# Step 2
|
|
99
|
+
"s2_title": "🔴 Falsos Positivos: Prediciendo Peligro Donde No Lo Hay",
|
|
100
|
+
"s2_card_title": "¿Qué es un Falso Positivo?",
|
|
101
|
+
"s2_def": "Un <b>falso positivo</b> ocurre cuando la IA predice que alguien es de <b style='color:#dc2626;'>ALTO RIESGO</b>, pero en realidad NO habría reincidido si fuera liberado.",
|
|
102
|
+
"s2_ex_title": "Escenario de Ejemplo:",
|
|
103
|
+
"s2_ex_li1": "• Sarah fue marcada como <b style='color:#dc2626;'>ALTO RIESGO</b>",
|
|
104
|
+
"s2_ex_li2": "• Basado en esto, el juez la mantuvo en prisión",
|
|
105
|
+
"s2_ex_li3": "• En realidad, Sarah habría rehecho su vida y nunca habría cometido otro delito",
|
|
106
|
+
"s2_cost_title": "El Costo Humano:",
|
|
107
|
+
"s2_cost_li1": "Personas inocentes pasan tiempo innecesario en prisión",
|
|
108
|
+
"s2_cost_li2": "Las familias son separadas por más tiempo del necesario",
|
|
109
|
+
"s2_cost_li3": "Las oportunidades laborales y la rehabilitación se retrasan",
|
|
110
|
+
"s2_cost_li4": "La confianza en el sistema judicial se erosiona",
|
|
111
|
+
"s2_cost_li5": "Impacto desproporcionado en comunidades marginadas",
|
|
112
|
+
"s2_key": "<b>Punto Clave:</b> Los falsos positivos significan que la IA está siendo <b>demasiado cautelosa</b>, manteniendo encerradas a personas que deberían estar libres.",
|
|
113
|
+
"btn_back": "◀️ Atrás",
|
|
114
|
+
"btn_next_fn": "Siguiente: Falsos Negativos ▶️",
|
|
115
|
+
# Step 3
|
|
116
|
+
"s3_title": "🔵 Falsos Negativos: No Detectando Peligro Real",
|
|
117
|
+
"s3_card_title": "¿Qué es un Falso Negativo?",
|
|
118
|
+
"s3_def": "Un <b>falso negativo</b> ocurre cuando la IA predice que alguien es de <b style='color:#16a34a;'>BAJO RIESGO</b>, pero SÍ reincide después de ser liberado.",
|
|
119
|
+
"s3_ex_title": "Escenario de Ejemplo:",
|
|
120
|
+
"s3_ex_li1": "• James fue marcado como <b style='color:#16a34a;'>BAJO RIESGO</b>",
|
|
121
|
+
"s3_ex_li2": "• Basado en esto, el juez lo liberó",
|
|
122
|
+
"s3_ex_li3": "• Desafortunadamente, James cometió otro delito grave",
|
|
123
|
+
"s3_cost_title": "El Costo Humano:",
|
|
124
|
+
"s3_cost_li1": "Nuevas víctimas de delitos prevenibles",
|
|
125
|
+
"s3_cost_li2": "Pérdida de confianza pública en el sistema judicial",
|
|
126
|
+
"s3_cost_li3": "Escrutinio mediático y reacciones contra los jueces",
|
|
127
|
+
"s3_cost_li4": "Presión política para ser 'duro con el crimen'",
|
|
128
|
+
"s3_cost_li5": "Daño potencial a comunidades y familias",
|
|
129
|
+
"s3_key": "<b>Punto Clave:</b> Los falsos negativos significan que la IA está siendo <b>demasiado indulgente</b>, liberando a personas que representan un peligro real para la sociedad.",
|
|
130
|
+
"btn_next_dil": "Siguiente: El Dilema ▶️",
|
|
131
|
+
# Step 4
|
|
132
|
+
"s4_title": "⚖️ El Equilibrio Imposible",
|
|
133
|
+
"s4_card_title": "Todo Sistema de IA Hace Concesiones",
|
|
134
|
+
"s4_p1": "Aquí está la dura realidad: <b>Ningún sistema de IA puede eliminar ambos tipos de errores.</b>",
|
|
135
|
+
"s4_sub1": "<b>Si haces que la IA sea más cautelosa:</b>",
|
|
136
|
+
"s4_sub1_li1": "✓ Menos falsos negativos (menos personas peligrosas liberadas)",
|
|
137
|
+
"s4_sub1_li2": "✗ Más falsos positivos (más personas inocentes en prisión)",
|
|
138
|
+
"s4_sub2": "<b>Si haces que la IA sea más indulgente:</b>",
|
|
139
|
+
"s4_sub2_li1": "✓ Menos falsos positivos (más personas inocentes liberadas)",
|
|
140
|
+
"s4_sub2_li2": "✗ Más falsos negativos (más personas peligrosas liberadas)",
|
|
141
|
+
"s4_eth_title": "La Pregunta Ética:",
|
|
142
|
+
"s4_q1": "¿Qué error es peor?",
|
|
143
|
+
"s4_q2": "• ¿Mantener a personas inocentes en prisión?<br>• ¿O liberar a individuos peligrosos?",
|
|
144
|
+
"s4_conc": "<b>No hay una respuesta universalmente 'correcta'.</b> Diferentes sociedades, sistemas legales y marcos éticos sopesan estas concesiones de manera diferente.",
|
|
145
|
+
"s4_final": "<b>Por eso es crucial entender la IA.</b> Necesitamos saber cómo funcionan estos sistemas para tomar decisiones informadas sobre cuándo y cómo usarlos.",
|
|
146
|
+
"btn_cont": "Continuar Aprendiendo Sobre IA ▶️",
|
|
147
|
+
# Step 5
|
|
148
|
+
"s5_title": "✅ Sección Completada",
|
|
149
|
+
"s5_p1": "Ahora entiendes las consecuencias de los errores de la IA en decisiones de alto riesgo.",
|
|
150
|
+
"s5_p2": "<b>A continuación:</b> Aprende qué es realmente la IA y cómo funcionan estos sistemas de predicción.",
|
|
151
|
+
"s5_p3": "Este conocimiento te ayudará a entender cómo construir sistemas de IA mejores y más éticos.",
|
|
152
|
+
"s5_scroll": "👇 DESPLÁZATE HACIA ABAJO 👇",
|
|
153
|
+
"s5_find": "Encuentra la siguiente sección abajo para continuar tu viaje.",
|
|
154
|
+
"btn_review": "◀️ Volver a Revisar"
|
|
155
|
+
},
|
|
156
|
+
"ca": {
|
|
157
|
+
"title": "⚠️ I si la IA s'hagués equivocat?",
|
|
158
|
+
"intro_box": "Acabes de prendre decisions basades en les prediccions d'una IA.<br>Però els sistemes d'IA no són perfectes. Explorem què passa quan cometen errors.",
|
|
159
|
+
"loading": "⏳ Carregant...",
|
|
160
|
+
# Step 1
|
|
161
|
+
"s1_title": "Les Apostes de les Prediccions d'IA",
|
|
162
|
+
"s1_p1": "En l'exercici anterior, vas confiar en un sistema d'IA per predir quins acusats tenien un risc <b>Alt</b>, <b>Mitjà</b> o <b>Baix</b> de reincidir.",
|
|
163
|
+
"s1_p2": "<b>Però què passa si aquestes prediccions eren incorrectes?</b>",
|
|
164
|
+
"s1_p3": "Els sistemes d'IA cometen dos tipus d'errors que tenen conseqüències molt diferents:",
|
|
165
|
+
"s1_li1": "<b>Falsos Positius</b> - Predir incorrectament ALT risc",
|
|
166
|
+
"s1_li2": "<b>Falsos Negatius</b> - Predir incorrectament BAIX risc",
|
|
167
|
+
"s1_p4": "Examinem cada tipus d'error i el seu impacte en el món real.",
|
|
168
|
+
"btn_next_fp": "Següent: Falsos Positius ▶️",
|
|
169
|
+
# Step 2
|
|
170
|
+
"s2_title": "🔴 Falsos Positius: Predint Perill On No N'hi Ha",
|
|
171
|
+
"s2_card_title": "Què és un Fals Positiu?",
|
|
172
|
+
"s2_def": "Un <b>fals positiu</b> es produeix quan la IA prediu que algú és d'<b style='color:#dc2626;'>ALT RISC</b>, però en realitat NO hauria reincidit si fos alliberat.",
|
|
173
|
+
"s2_ex_title": "Escenari d'Exemple:",
|
|
174
|
+
"s2_ex_li1": "• La Sarah va ser marcada com a <b style='color:#dc2626;'>ALT RISC</b>",
|
|
175
|
+
"s2_ex_li2": "• Basat en això, el jutge la va mantenir a la presó",
|
|
176
|
+
"s2_ex_li3": "• En realitat, la Sarah hauria refet la seva vida i mai hauria comès un altre delicte",
|
|
177
|
+
"s2_cost_title": "El Cost Humà:",
|
|
178
|
+
"s2_cost_li1": "Persones innocents passen temps innecessari a la presó",
|
|
179
|
+
"s2_cost_li2": "Les famílies són separades per més temps del necessari",
|
|
180
|
+
"s2_cost_li3": "Les oportunitats laborals i la rehabilitació es retarden",
|
|
181
|
+
"s2_cost_li4": "La confiança en el sistema judicial s'erosiona",
|
|
182
|
+
"s2_cost_li5": "Impacte desproporcionat en comunitats marginades",
|
|
183
|
+
"s2_key": "<b>Punt Clau:</b> Els falsos positius signifiquen que la IA està sent <b>massa cautelosa</b>, mantenint tancades a persones que haurien d'estar lliures.",
|
|
184
|
+
"btn_back": "◀️ Enrere",
|
|
185
|
+
"btn_next_fn": "Següent: Falsos Negatius ▶️",
|
|
186
|
+
# Step 3
|
|
187
|
+
"s3_title": "🔵 Falsos Negatius: No Detectant Perill Real",
|
|
188
|
+
"s3_card_title": "Què és un Fals Negatiu?",
|
|
189
|
+
"s3_def": "Un <b>fals negatiu</b> es produeix quan la IA prediu que algú és de <b style='color:#16a34a;'>BAIX RISC</b>, però SÍ reincideix després de ser alliberat.",
|
|
190
|
+
"s3_ex_title": "Escenari d'Exemple:",
|
|
191
|
+
"s3_ex_li1": "• En James va ser marcat com a <b style='color:#16a34a;'>BAIX RISC</b>",
|
|
192
|
+
"s3_ex_li2": "• Basat en això, el jutge el va alliberar",
|
|
193
|
+
"s3_ex_li3": "• Malauradament, en James va cometre un altre delicte greu",
|
|
194
|
+
"s3_cost_title": "El Cost Humà:",
|
|
195
|
+
"s3_cost_li1": "Noves víctimes de delictes prevenibles",
|
|
196
|
+
"s3_cost_li2": "Pèrdua de confiança pública en el sistema judicial",
|
|
197
|
+
"s3_cost_li3": "Escrutini mediàtic i reaccions contra els jutges",
|
|
198
|
+
"s3_cost_li4": "Pressió política per ser 'dur amb el crim'",
|
|
199
|
+
"s3_cost_li5": "Dany potencial a comunitats i famílies",
|
|
200
|
+
"s3_key": "<b>Punt Clau:</b> Els falsos negatius signifiquen que la IA està sent <b>massa indulgent</b>, alliberant persones que representen un perill real per a la societat.",
|
|
201
|
+
"btn_next_dil": "Següent: El Dilema ▶️",
|
|
202
|
+
# Step 4
|
|
203
|
+
"s4_title": "⚖️ L'Equilibri Impossible",
|
|
204
|
+
"s4_card_title": "Tot Sistema d'IA Fa Concessions",
|
|
205
|
+
"s4_p1": "Aquí està la dura realitat: <b>Cap sistema d'IA pot eliminar els dos tipus d'errors.</b>",
|
|
206
|
+
"s4_sub1": "<b>Si fas que la IA sigui més cautelosa:</b>",
|
|
207
|
+
"s4_sub1_li1": "✓ Menys falsos negatius (menys persones perilloses alliberades)",
|
|
208
|
+
"s4_sub1_li2": "✗ Més falsos positius (més persones innocents a la presó)",
|
|
209
|
+
"s4_sub2": "<b>Si fas que la IA sigui més indulgent:</b>",
|
|
210
|
+
"s4_sub2_li1": "✓ Menys falsos positius (més persones innocents alliberades)",
|
|
211
|
+
"s4_sub2_li2": "✗ Més falsos negatius (més persones perilloses alliberades)",
|
|
212
|
+
"s4_eth_title": "La Pregunta Ètica:",
|
|
213
|
+
"s4_q1": "Quin error és pitjor?",
|
|
214
|
+
"s4_q2": "• Mantenir persones innocents a la presó?<br>• O alliberar individus perillosos?",
|
|
215
|
+
"s4_conc": "<b>No hi ha una resposta universalment 'correcta'.</b> Diferents societats, sistemes legals i marcs ètics sospesen aquestes concessions de manera diferent.",
|
|
216
|
+
"s4_final": "<b>Per això és crucial entendre la IA.</b> Necessitem saber com funcionen aquests sistemes per prendre decisions informades sobre quan i com utilitzar-los.",
|
|
217
|
+
"btn_cont": "Continuar Aprenent Sobre IA ▶️",
|
|
218
|
+
# Step 5
|
|
219
|
+
"s5_title": "✅ Secció Completada",
|
|
220
|
+
"s5_p1": "Ara entens les conseqüències dels errors de la IA en decisions d'alt risc.",
|
|
221
|
+
"s5_p2": "<b>A continuació:</b> Aprèn què és realment la IA i com funcionen aquests sistemes de predicció.",
|
|
222
|
+
"s5_p3": "Aquest coneixement t'ajudarà a entendre com construir sistemes d'IA millors i més ètics.",
|
|
223
|
+
"s5_scroll": "👇 DESPLAÇA'T CAP AVALL 👇",
|
|
224
|
+
"s5_find": "Troba la següent secció a sota per continuar el teu viatge.",
|
|
225
|
+
"btn_review": "◀️ Tornar a Revisar"
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
def create_ai_consequences_app(theme_primary_hue: str = "indigo") -> "gr.Blocks":
|
|
230
|
+
"""Create the AI Consequences Gradio Blocks app."""
|
|
231
|
+
try:
|
|
232
|
+
import gradio as gr
|
|
233
|
+
gr.close_all(verbose=False)
|
|
234
|
+
except ImportError as e:
|
|
235
|
+
raise ImportError("Gradio is required.") from e
|
|
236
|
+
|
|
237
|
+
# --- HTML Generator Helpers for i18n ---
|
|
238
|
+
def t(lang, key):
|
|
239
|
+
return TRANSLATIONS.get(lang, TRANSLATIONS["en"]).get(key, key)
|
|
240
|
+
|
|
241
|
+
def _get_step1_html(lang):
|
|
242
|
+
return f"""
|
|
243
|
+
<div class='step-card'>
|
|
244
|
+
<p>{t(lang, 's1_p1')}</p>
|
|
245
|
+
<p style='margin-top:20px;'>{t(lang, 's1_p2')}</p>
|
|
246
|
+
<p style='margin-top:20px;'>{t(lang, 's1_p3')}</p>
|
|
247
|
+
<ul style='font-size:18px; margin-top:12px;'>
|
|
248
|
+
<li>{t(lang, 's1_li1')}</li>
|
|
249
|
+
<li>{t(lang, 's1_li2')}</li>
|
|
250
|
+
</ul>
|
|
251
|
+
<p style='margin-top:20px;'>{t(lang, 's1_p4')}</p>
|
|
252
|
+
</div>
|
|
253
|
+
"""
|
|
254
|
+
|
|
255
|
+
def _get_step2_html(lang):
|
|
256
|
+
return f"""
|
|
257
|
+
<div class='step-card step-card-warning'>
|
|
258
|
+
<h3 style='color:#b45309; margin-top:0;'>{t(lang, 's2_card_title')}</h3>
|
|
259
|
+
<p>{t(lang, 's2_def')}</p>
|
|
260
|
+
<div class='inner-card'>
|
|
261
|
+
<h4 style='margin-top:0;'>{t(lang, 's2_ex_title')}</h4>
|
|
262
|
+
<p style='font-size:18px;'>
|
|
263
|
+
{t(lang, 's2_ex_li1')}<br>
|
|
264
|
+
{t(lang, 's2_ex_li2')}<br>
|
|
265
|
+
{t(lang, 's2_ex_li3')}
|
|
266
|
+
</p>
|
|
267
|
+
</div>
|
|
268
|
+
<h3 style='color:#b45309;'>{t(lang, 's2_cost_title')}</h3>
|
|
269
|
+
<ul style='font-size:18px;'>
|
|
270
|
+
<li>{t(lang, 's2_cost_li1')}</li>
|
|
271
|
+
<li>{t(lang, 's2_cost_li2')}</li>
|
|
272
|
+
<li>{t(lang, 's2_cost_li3')}</li>
|
|
273
|
+
<li>{t(lang, 's2_cost_li4')}</li>
|
|
274
|
+
<li>{t(lang, 's2_cost_li5')}</li>
|
|
275
|
+
</ul>
|
|
276
|
+
<div class='keypoint-box'>
|
|
277
|
+
<p style='font-size:18px; margin:0;'>{t(lang, 's2_key')}</p>
|
|
278
|
+
</div>
|
|
279
|
+
</div>
|
|
280
|
+
"""
|
|
281
|
+
|
|
282
|
+
def _get_step3_html(lang):
|
|
283
|
+
return f"""
|
|
284
|
+
<div class='step-card step-card-success'>
|
|
285
|
+
<h3 style='color:#15803d; margin-top:0;'>{t(lang, 's3_card_title')}</h3>
|
|
286
|
+
<p>{t(lang, 's3_def')}</p>
|
|
287
|
+
<div class='inner-card'>
|
|
288
|
+
<h4 style='margin-top:0;'>{t(lang, 's3_ex_title')}</h4>
|
|
289
|
+
<p style='font-size:18px;'>
|
|
290
|
+
{t(lang, 's3_ex_li1')}<br>
|
|
291
|
+
{t(lang, 's3_ex_li2')}<br>
|
|
292
|
+
{t(lang, 's3_ex_li3')}
|
|
293
|
+
</p>
|
|
294
|
+
</div>
|
|
295
|
+
<h3 style='color:#15803d;'>{t(lang, 's3_cost_title')}</h3>
|
|
296
|
+
<ul style='font-size:18px;'>
|
|
297
|
+
<li>{t(lang, 's3_cost_li1')}</li>
|
|
298
|
+
<li>{t(lang, 's3_cost_li2')}</li>
|
|
299
|
+
<li>{t(lang, 's3_cost_li3')}</li>
|
|
300
|
+
<li>{t(lang, 's3_cost_li4')}</li>
|
|
301
|
+
<li>{t(lang, 's3_cost_li5')}</li>
|
|
302
|
+
</ul>
|
|
303
|
+
<div class='keypoint-box'>
|
|
304
|
+
<p style='font-size:18px; margin:0;'>{t(lang, 's3_key')}</p>
|
|
305
|
+
</div>
|
|
306
|
+
</div>
|
|
307
|
+
"""
|
|
308
|
+
|
|
309
|
+
def _get_step4_html(lang):
|
|
310
|
+
return f"""
|
|
311
|
+
<div class='step-card step-card-balance'>
|
|
312
|
+
<h3 style='color:#7e22ce; margin-top:0;'>{t(lang, 's4_card_title')}</h3>
|
|
313
|
+
<p>{t(lang, 's4_p1')}</p>
|
|
314
|
+
<div class='inner-card-wide'>
|
|
315
|
+
<p style='font-size:18px; margin-bottom:16px;'>{t(lang, 's4_sub1')}</p>
|
|
316
|
+
<ul style='font-size:18px;'>
|
|
317
|
+
<li>{t(lang, 's4_sub1_li1')}</li>
|
|
318
|
+
<li>{t(lang, 's4_sub1_li2')}</li>
|
|
319
|
+
</ul>
|
|
320
|
+
<hr style='margin:20px 0;'>
|
|
321
|
+
<p style='font-size:18px; margin-bottom:16px;'>{t(lang, 's4_sub2')}</p>
|
|
322
|
+
<ul style='font-size:18px;'>
|
|
323
|
+
<li>{t(lang, 's4_sub2_li1')}</li>
|
|
324
|
+
<li>{t(lang, 's4_sub2_li2')}</li>
|
|
325
|
+
</ul>
|
|
326
|
+
</div>
|
|
327
|
+
<h3 style='color:#7e22ce;'>{t(lang, 's4_eth_title')}</h3>
|
|
328
|
+
<div class='keypoint-box'>
|
|
329
|
+
<p style='font-size:20px; font-weight:bold; margin:0;'>{t(lang, 's4_q1')}</p>
|
|
330
|
+
<p style='font-size:18px; margin-top:12px; margin-bottom:0;'>{t(lang, 's4_q2')}</p>
|
|
331
|
+
</div>
|
|
332
|
+
<p style='margin-top:24px; font-size:18px;'>{t(lang, 's4_conc')}</p>
|
|
333
|
+
<div class='highlight-soft'>
|
|
334
|
+
<p style='font-size:18px; margin:0;'>{t(lang, 's4_final')}</p>
|
|
335
|
+
</div>
|
|
336
|
+
</div>
|
|
337
|
+
"""
|
|
338
|
+
|
|
339
|
+
def _get_step5_html(lang):
|
|
340
|
+
return f"""
|
|
341
|
+
<div style='text-align:center;'>
|
|
342
|
+
<h2 style='font-size: 2.5rem;'>{t(lang, 's5_title')}</h2>
|
|
343
|
+
<div class='completion-box'>
|
|
344
|
+
<p>{t(lang, 's5_p1')}</p>
|
|
345
|
+
<p style='margin-top:24px;'>{t(lang, 's5_p2')}</p>
|
|
346
|
+
<p style='margin-top:24px;'>{t(lang, 's5_p3')}</p>
|
|
347
|
+
<h1 style='margin:20px 0; font-size: 3rem;'>{t(lang, 's5_scroll')}</h1>
|
|
348
|
+
<p style='font-size:1.1rem;'>{t(lang, 's5_find')}</p>
|
|
349
|
+
</div>
|
|
350
|
+
</div>
|
|
351
|
+
"""
|
|
352
|
+
|
|
353
|
+
css = """
|
|
354
|
+
/* (CSS remains exactly as provided in the previous snippet) */
|
|
355
|
+
.large-text { font-size: 20px !important; }
|
|
356
|
+
.loading-title { font-size: 2rem; color: var(--secondary-text-color); }
|
|
357
|
+
.warning-box { background-color: var(--block-background-fill) !important; border-left: 6px solid #dc2626 !important; color: var(--body-text-color); }
|
|
358
|
+
.consequences-intro-box { text-align: center; font-size: 18px; max-width: 900px; margin: auto; padding: 20px; border-radius: 12px; background-color: var(--block-background-fill); color: var(--body-text-color); border: 2px solid #dc2626; box-shadow: 0 5px 15px rgba(0, 0, 0, 0.08); }
|
|
359
|
+
.step-card { font-size: 20px; padding: 28px; border-radius: 16px; background-color: var(--block-background-fill); color: var(--body-text-color); border: 1px solid var(--border-color-primary); box-shadow: 0 4px 12px rgba(0, 0, 0, 0.06); }
|
|
360
|
+
.step-card-warning { border-width: 3px; border-color: #f59e0b; }
|
|
361
|
+
.step-card-success { border-width: 3px; border-color: #16a34a; }
|
|
362
|
+
.step-card-balance { border-width: 3px; border-color: #9333ea; }
|
|
363
|
+
.inner-card { background-color: var(--body-background-fill); color: var(--body-text-color); padding: 20px; border-radius: 8px; margin: 20px 0; border: 1px solid var(--border-color-primary); }
|
|
364
|
+
.inner-card-wide { background-color: var(--body-background-fill); color: var(--body-text-color); padding: 24px; border-radius: 12px; margin: 24px 0; border: 1px solid var(--border-color-primary); }
|
|
365
|
+
.keypoint-box { background-color: var(--block-background-fill); color: var(--body-text-color); padding: 16px; border-radius: 8px; margin-top: 20px; border-left: 6px solid #dc2626; }
|
|
366
|
+
.highlight-soft { background-color: var(--block-background-fill); color: var(--body-text-color); padding: 16px; border-radius: 8px; margin-top: 20px; border: 1px solid var(--border-color-primary); }
|
|
367
|
+
.completion-box { font-size: 1.3rem; padding: 28px; border-radius: 16px; background-color: var(--block-background-fill); color: var(--body-text-color); border: 2px solid var(--color-accent); box-shadow: 0 5px 15px rgba(0, 0, 0, 0.08); }
|
|
368
|
+
#nav-loading-overlay { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: color-mix(in srgb, var(--body-background-fill) 95%, transparent); z-index: 9999; display: none; flex-direction: column; align-items: center; justify-content: center; opacity: 0; transition: opacity 0.3s ease; }
|
|
369
|
+
.nav-spinner { width: 50px; height: 50px; border: 5px solid var(--border-color-primary); border-top: 5px solid var(--color-accent); border-radius: 50%; animation: nav-spin 1s linear infinite; margin-bottom: 20px; }
|
|
370
|
+
@keyframes nav-spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }
|
|
371
|
+
#nav-loading-text { font-size: 1.3rem; font-weight: 600; color: var(--color-accent); }
|
|
372
|
+
@media (prefers-color-scheme: dark) { .consequences-intro-box, .step-card, .inner-card, .inner-card-wide, .keypoint-box, .highlight-soft, .completion-box { background-color: #2D323E; color: white; border-color: #555555; box-shadow: none; } .inner-card, .inner-card-wide { background-color: #181B22; } #nav-loading-overlay { background: rgba(15, 23, 42, 0.9); } .nav-spinner { border-color: rgba(148, 163, 184, 0.4); border-top-color: var(--color-accent); } }
|
|
373
|
+
"""
|
|
374
|
+
|
|
375
|
+
with gr.Blocks(theme=gr.themes.Soft(primary_hue=theme_primary_hue), css=css) as demo:
|
|
376
|
+
gr.HTML("<div id='app_top_anchor' style='height:0;'></div>")
|
|
377
|
+
gr.HTML("<div id='nav-loading-overlay'><div class='nav-spinner'></div><span id='nav-loading-text'>Loading...</span></div>")
|
|
378
|
+
|
|
379
|
+
# --- Dynamic Text Components ---
|
|
380
|
+
# We assign them to variables so we can return them in the update function
|
|
381
|
+
|
|
382
|
+
c_main_title = gr.Markdown("<h1 style='text-align:center;'>⚠️ What If the AI Was Wrong?</h1>")
|
|
383
|
+
c_intro_box = gr.Markdown(f"<div class='consequences-intro-box'>{t('en', 'intro_box')}</div>")
|
|
384
|
+
gr.HTML("<hr style='margin:24px 0;'>")
|
|
385
|
+
|
|
386
|
+
with gr.Column(visible=False) as loading_screen:
|
|
387
|
+
c_loading_title = gr.Markdown(f"<div style='text-align:center; padding: 100px 0;'><h2 class='loading-title'>{t('en', 'loading')}</h2></div>")
|
|
388
|
+
|
|
389
|
+
# Step 1
|
|
390
|
+
with gr.Column(visible=True, elem_id="step-1") as step_1:
|
|
391
|
+
c_s1_title = gr.Markdown(f"<h2 style='text-align:center;'>{t('en', 's1_title')}</h2>")
|
|
392
|
+
c_s1_html = gr.HTML(_get_step1_html("en"))
|
|
393
|
+
step_1_next = gr.Button(t('en', 'btn_next_fp'), variant="primary", size="lg")
|
|
394
|
+
|
|
395
|
+
# Step 2
|
|
396
|
+
with gr.Column(visible=False, elem_id="step-2") as step_2:
|
|
397
|
+
c_s2_title = gr.Markdown(f"<h2 style='text-align:center;'>{t('en', 's2_title')}</h2>")
|
|
398
|
+
c_s2_html = gr.HTML(_get_step2_html("en"))
|
|
399
|
+
with gr.Row():
|
|
400
|
+
step_2_back = gr.Button(t('en', 'btn_back'), size="lg")
|
|
401
|
+
step_2_next = gr.Button(t('en', 'btn_next_fn'), variant="primary", size="lg")
|
|
402
|
+
|
|
403
|
+
# Step 3
|
|
404
|
+
with gr.Column(visible=False, elem_id="step-3") as step_3:
|
|
405
|
+
c_s3_title = gr.Markdown(f"<h2 style='text-align:center;'>{t('en', 's3_title')}</h2>")
|
|
406
|
+
c_s3_html = gr.HTML(_get_step3_html("en"))
|
|
407
|
+
with gr.Row():
|
|
408
|
+
step_3_back = gr.Button(t('en', 'btn_back'), size="lg")
|
|
409
|
+
step_3_next = gr.Button(t('en', 'btn_next_dil'), variant="primary", size="lg")
|
|
410
|
+
|
|
411
|
+
# Step 4
|
|
412
|
+
with gr.Column(visible=False, elem_id="step-4") as step_4:
|
|
413
|
+
c_s4_title = gr.Markdown(f"<h2 style='text-align:center;'>{t('en', 's4_title')}</h2>")
|
|
414
|
+
c_s4_html = gr.HTML(_get_step4_html("en"))
|
|
415
|
+
with gr.Row():
|
|
416
|
+
step_4_back = gr.Button(t('en', 'btn_back'), size="lg")
|
|
417
|
+
step_4_next = gr.Button(t('en', 'btn_cont'), variant="primary", size="lg")
|
|
418
|
+
|
|
419
|
+
# Step 5
|
|
420
|
+
with gr.Column(visible=False, elem_id="step-5") as step_5:
|
|
421
|
+
c_s5_html = gr.HTML(_get_step5_html("en"))
|
|
422
|
+
back_to_dilemma_btn = gr.Button(t('en', 'btn_review'))
|
|
423
|
+
|
|
424
|
+
# --- I18N UPDATE LOGIC ---
|
|
425
|
+
|
|
426
|
+
update_targets = [
|
|
427
|
+
c_main_title, c_intro_box, c_loading_title,
|
|
428
|
+
c_s1_title, c_s1_html, step_1_next,
|
|
429
|
+
c_s2_title, c_s2_html, step_2_back, step_2_next,
|
|
430
|
+
c_s3_title, c_s3_html, step_3_back, step_3_next,
|
|
431
|
+
c_s4_title, c_s4_html, step_4_back, step_4_next,
|
|
432
|
+
c_s5_html, back_to_dilemma_btn
|
|
433
|
+
]
|
|
434
|
+
|
|
435
|
+
def update_language(request: gr.Request):
|
|
436
|
+
params = request.query_params
|
|
437
|
+
lang = params.get("lang", "en")
|
|
438
|
+
if lang not in TRANSLATIONS:
|
|
439
|
+
lang = "en"
|
|
440
|
+
|
|
441
|
+
return [
|
|
442
|
+
f"<h1 style='text-align:center;'>{t(lang, 'title')}</h1>",
|
|
443
|
+
f"<div class='consequences-intro-box'>{t(lang, 'intro_box')}</div>",
|
|
444
|
+
f"<div style='text-align:center; padding: 100px 0;'><h2 class='loading-title'>{t(lang, 'loading')}</h2></div>",
|
|
445
|
+
# Step 1
|
|
446
|
+
f"<h2 style='text-align:center;'>{t(lang, 's1_title')}</h2>",
|
|
447
|
+
_get_step1_html(lang),
|
|
448
|
+
gr.Button(value=t(lang, 'btn_next_fp')),
|
|
449
|
+
# Step 2
|
|
450
|
+
f"<h2 style='text-align:center;'>{t(lang, 's2_title')}</h2>",
|
|
451
|
+
_get_step2_html(lang),
|
|
452
|
+
gr.Button(value=t(lang, 'btn_back')),
|
|
453
|
+
gr.Button(value=t(lang, 'btn_next_fn')),
|
|
454
|
+
# Step 3
|
|
455
|
+
f"<h2 style='text-align:center;'>{t(lang, 's3_title')}</h2>",
|
|
456
|
+
_get_step3_html(lang),
|
|
457
|
+
gr.Button(value=t(lang, 'btn_back')),
|
|
458
|
+
gr.Button(value=t(lang, 'btn_next_dil')),
|
|
459
|
+
# Step 4
|
|
460
|
+
f"<h2 style='text-align:center;'>{t(lang, 's4_title')}</h2>",
|
|
461
|
+
_get_step4_html(lang),
|
|
462
|
+
gr.Button(value=t(lang, 'btn_back')),
|
|
463
|
+
gr.Button(value=t(lang, 'btn_cont')),
|
|
464
|
+
# Step 5
|
|
465
|
+
_get_step5_html(lang),
|
|
466
|
+
gr.Button(value=t(lang, 'btn_review')),
|
|
467
|
+
]
|
|
468
|
+
|
|
469
|
+
demo.load(update_language, inputs=None, outputs=update_targets)
|
|
470
|
+
|
|
471
|
+
# --- NAVIGATION LOGIC ---
|
|
472
|
+
|
|
473
|
+
all_steps = [step_1, step_2, step_3, step_4, step_5, loading_screen]
|
|
474
|
+
|
|
475
|
+
def create_nav_generator(current_step, next_step):
|
|
476
|
+
def navigate():
|
|
477
|
+
updates = {loading_screen: gr.update(visible=True)}
|
|
478
|
+
for step in all_steps:
|
|
479
|
+
if step != loading_screen:
|
|
480
|
+
updates[step] = gr.update(visible=False)
|
|
481
|
+
yield updates
|
|
482
|
+
|
|
483
|
+
updates = {next_step: gr.update(visible=True)}
|
|
484
|
+
for step in all_steps:
|
|
485
|
+
if step != next_step:
|
|
486
|
+
updates[step] = gr.update(visible=False)
|
|
487
|
+
yield updates
|
|
488
|
+
return navigate
|
|
489
|
+
|
|
490
|
+
def nav_js(target_id: str, message: str) -> str:
|
|
491
|
+
return f"""
|
|
492
|
+
()=>{{
|
|
493
|
+
try {{
|
|
494
|
+
const overlay = document.getElementById('nav-loading-overlay');
|
|
495
|
+
const messageEl = document.getElementById('nav-loading-text');
|
|
496
|
+
if(overlay && messageEl) {{
|
|
497
|
+
messageEl.textContent = '{message}';
|
|
498
|
+
overlay.style.display = 'flex';
|
|
499
|
+
setTimeout(() => {{ overlay.style.opacity = '1'; }}, 10);
|
|
500
|
+
}}
|
|
501
|
+
const startTime = Date.now();
|
|
502
|
+
setTimeout(() => {{
|
|
503
|
+
const anchor = document.getElementById('app_top_anchor');
|
|
504
|
+
if(anchor) anchor.scrollIntoView({{behavior:'smooth', block:'start'}});
|
|
505
|
+
}}, 40);
|
|
506
|
+
const targetId = '{target_id}';
|
|
507
|
+
const pollInterval = setInterval(() => {{
|
|
508
|
+
const elapsed = Date.now() - startTime;
|
|
509
|
+
const target = document.getElementById(targetId);
|
|
510
|
+
const isVisible = target && target.offsetParent !== null &&
|
|
511
|
+
window.getComputedStyle(target).display !== 'none';
|
|
512
|
+
if((isVisible && elapsed >= 1200) || elapsed > 7000) {{
|
|
513
|
+
clearInterval(pollInterval);
|
|
514
|
+
if(overlay) {{
|
|
515
|
+
overlay.style.opacity = '0';
|
|
516
|
+
setTimeout(() => {{ overlay.style.display = 'none'; }}, 300);
|
|
517
|
+
}}
|
|
518
|
+
}}
|
|
519
|
+
}}, 90);
|
|
520
|
+
}} catch(e) {{ console.warn('nav-js error', e); }}
|
|
521
|
+
}}
|
|
522
|
+
"""
|
|
523
|
+
|
|
524
|
+
step_1_next.click(fn=create_nav_generator(step_1, step_2), outputs=all_steps, js=nav_js("step-2", "Loading..."))
|
|
525
|
+
step_2_back.click(fn=create_nav_generator(step_2, step_1), outputs=all_steps, js=nav_js("step-1", "Loading..."))
|
|
526
|
+
step_2_next.click(fn=create_nav_generator(step_2, step_3), outputs=all_steps, js=nav_js("step-3", "Loading..."))
|
|
527
|
+
step_3_back.click(fn=create_nav_generator(step_3, step_2), outputs=all_steps, js=nav_js("step-2", "Loading..."))
|
|
528
|
+
step_3_next.click(fn=create_nav_generator(step_3, step_4), outputs=all_steps, js=nav_js("step-4", "Loading..."))
|
|
529
|
+
step_4_back.click(fn=create_nav_generator(step_4, step_3), outputs=all_steps, js=nav_js("step-3", "Loading..."))
|
|
530
|
+
step_4_next.click(fn=create_nav_generator(step_4, step_5), outputs=all_steps, js=nav_js("step-5", "Loading..."))
|
|
531
|
+
back_to_dilemma_btn.click(fn=create_nav_generator(step_5, step_4), outputs=all_steps, js=nav_js("step-4", "Loading..."))
|
|
532
|
+
|
|
533
|
+
return demo
|
|
534
|
+
|
|
535
|
+
def launch_ai_consequences_app(height: int = 1000, share: bool = False, debug: bool = False) -> None:
|
|
536
|
+
demo = create_ai_consequences_app()
|
|
537
|
+
port = int(os.environ.get("PORT", 8080))
|
|
538
|
+
demo.launch(share=share, inline=True, debug=debug, height=height, server_port=port)
|
|
539
|
+
|
|
540
|
+
|