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,481 @@
1
+ """
2
+ Tutorial Gradio application for onboarding users to the Justice & Equity Challenge.
3
+
4
+ This app teaches:
5
+ 1. How to advance slideshow-style steps
6
+ 2. How to interact with sliders/buttons
7
+ 3. How model prediction output appears
8
+
9
+ Structure:
10
+ - Factory function `create_tutorial_app()` returns a Gradio Blocks object
11
+ - Convenience wrapper `launch_tutorial_app()` launches it inline (for notebooks)
12
+ """
13
+ import contextlib
14
+ import os
15
+
16
+
17
+ def _build_synthetic_model():
18
+ """Build a tiny linear regression model on synthetic study habit data."""
19
+ import numpy as np
20
+ from sklearn.linear_model import LinearRegression
21
+
22
+ rng = np.random.default_rng(7)
23
+ n = 200
24
+ hours_study = rng.uniform(0, 12, n)
25
+ hours_sleep = rng.uniform(4, 10, n)
26
+ attendance = rng.uniform(50, 100, n)
27
+ exam_score = (
28
+ 5 * hours_study
29
+ + 3 * hours_sleep
30
+ + 0.5 * attendance
31
+ + rng.normal(0, 10, n)
32
+ )
33
+
34
+ X = np.column_stack([hours_study, hours_sleep, attendance])
35
+ y = exam_score
36
+ lin_reg = LinearRegression().fit(X, y)
37
+
38
+ def predict_exam(sl, slp, att):
39
+ pred = float(lin_reg.predict([[sl, slp, att]])[0])
40
+ import numpy as np
41
+
42
+ pred = float(np.clip(pred, 0, 100))
43
+ return f"{round(pred, 1)}%"
44
+
45
+ return predict_exam
46
+
47
+
48
+ def create_tutorial_app(theme_primary_hue: str = "indigo") -> "gr.Blocks":
49
+ """Create the tutorial Gradio Blocks app (not launched yet)."""
50
+ try:
51
+ import gradio as gr
52
+
53
+ gr.close_all(verbose=False)
54
+
55
+ except ImportError as e:
56
+ raise ImportError(
57
+ "Gradio is required for the tutorial app. Install with `pip install gradio`."
58
+ ) from e
59
+
60
+ predict_exam = _build_synthetic_model()
61
+
62
+ # All custom colors use Gradio theme variables + dark-mode overrides.
63
+ css = """
64
+ /* ---------------------------------------------------- */
65
+ /* CORE TYPOGRAPHY / COMPONENT OVERRIDES */
66
+ /* ---------------------------------------------------- */
67
+
68
+ /* Prediction output styled with theme accent color */
69
+ #prediction_output_textbox textarea {
70
+ font-size: 2.5rem !important;
71
+ font-weight: bold !important;
72
+ text-align: center !important;
73
+ color: var(--color-accent) !important;
74
+ }
75
+
76
+ /* Tutorial intro container at top */
77
+ .tutorial-intro-box {
78
+ text-align: left;
79
+ font-size: 20px;
80
+ max-width: 800px;
81
+ margin: auto;
82
+ padding: 15px;
83
+ border-radius: 8px;
84
+
85
+ background-color: var(--block-background-fill);
86
+ color: var(--body-text-color);
87
+ border: 1px solid var(--border-color-primary);
88
+
89
+ box-shadow: 0 5px 15px rgba(0, 0, 0, 0.08);
90
+ }
91
+
92
+ /* Slide-style emphasis box (Step 1) */
93
+ .slide-box {
94
+ font-size: 28px;
95
+ text-align: center;
96
+ padding: 28px;
97
+ border-radius: 16px;
98
+ min-height: 150px;
99
+
100
+ background-color: var(--block-background-fill);
101
+ color: var(--body-text-color);
102
+ border: 1px solid var(--border-color-primary);
103
+
104
+ box-shadow: 0 5px 15px rgba(0, 0, 0, 0.08);
105
+ }
106
+
107
+ /* Step 2 explanation box */
108
+ .interactive-info-box {
109
+ font-size: 20px;
110
+ text-align: left;
111
+ padding: 20px;
112
+ border-radius: 16px;
113
+
114
+ background-color: var(--block-background-fill);
115
+ color: var(--body-text-color);
116
+ border: 1px solid var(--border-color-primary);
117
+
118
+ box-shadow: 0 5px 15px rgba(0, 0, 0, 0.08);
119
+ }
120
+
121
+ /* Completion message (Step 3) */
122
+ .complete-box {
123
+ font-size: 1.5rem;
124
+ padding: 28px;
125
+ border-radius: 16px;
126
+
127
+ background-color: var(--block-background-fill);
128
+ color: var(--body-text-color);
129
+ border: 2px solid var(--color-accent);
130
+
131
+ box-shadow: 0 5px 15px rgba(0, 0, 0, 0.08);
132
+ }
133
+
134
+ /* Loading title text */
135
+ .loading-title {
136
+ font-size: 2rem;
137
+ color: var(--secondary-text-color);
138
+ }
139
+
140
+ /* ---------------------------------------------------- */
141
+ /* NAVIGATION LOADING OVERLAY */
142
+ /* ---------------------------------------------------- */
143
+
144
+ #nav-loading-overlay {
145
+ position: fixed;
146
+ top: 0;
147
+ left: 0;
148
+ width: 100%;
149
+ height: 100%;
150
+
151
+ /* Use theme background, slightly blended with transparency */
152
+ background: color-mix(in srgb, var(--body-background-fill) 95%, transparent);
153
+
154
+ z-index: 9999;
155
+ display: none;
156
+ flex-direction: column;
157
+ align-items: center;
158
+ justify-content: center;
159
+ opacity: 0;
160
+ transition: opacity 0.3s ease;
161
+ }
162
+
163
+ .nav-spinner {
164
+ width: 50px;
165
+ height: 50px;
166
+ border: 5px solid var(--border-color-primary);
167
+ border-top: 5px solid var(--color-accent);
168
+ border-radius: 50%;
169
+ animation: nav-spin 1s linear infinite;
170
+ margin-bottom: 20px;
171
+ }
172
+
173
+ @keyframes nav-spin {
174
+ 0% { transform: rotate(0deg); }
175
+ 100% { transform: rotate(360deg); }
176
+ }
177
+
178
+ #nav-loading-text {
179
+ font-size: 1.3rem;
180
+ font-weight: 600;
181
+ color: var(--color-accent);
182
+ }
183
+
184
+ /* ---------------------------------------------------- */
185
+ /* DARK MODE OVERRIDES (HIGH-CONFIDENCE ZONE) */
186
+ /* ---------------------------------------------------- */
187
+
188
+ @media (prefers-color-scheme: dark) {
189
+ .tutorial-intro-box,
190
+ .slide-box,
191
+ .interactive-info-box,
192
+ .complete-box {
193
+ /* Explicit dark background for strong contrast */
194
+ background-color: #2D323E;
195
+ color: white;
196
+ border-color: #555555;
197
+ box-shadow: none;
198
+ }
199
+
200
+ #nav-loading-overlay {
201
+ background: rgba(15, 23, 42, 0.9);
202
+ }
203
+
204
+ .nav-spinner {
205
+ border-color: rgba(148, 163, 184, 0.4);
206
+ border-top-color: var(--color-accent);
207
+ }
208
+ }
209
+ """
210
+
211
+ with gr.Blocks(theme=gr.themes.Soft(primary_hue=theme_primary_hue), css=css) as demo:
212
+ # Persistent top anchor for scroll-to-top navigation
213
+ gr.HTML("<div id='app_top_anchor' style='height:0;'></div>")
214
+
215
+ # Navigation loading overlay with spinner and dynamic message
216
+ gr.HTML(
217
+ """
218
+ <div id='nav-loading-overlay'>
219
+ <div class='nav-spinner'></div>
220
+ <span id='nav-loading-text'>Loading...</span>
221
+ </div>
222
+ """
223
+ )
224
+
225
+ gr.Markdown("<h1 style='text-align:center;'>👋 How to Use an App (A Quick Tutorial)</h1>")
226
+ gr.Markdown(
227
+ """
228
+ <div class='tutorial-intro-box'>
229
+ This is a simple, 3-step tutorial.<br><br>
230
+ <b>Your Task:</b> Just read the instructions for each step and click the "Next" button to continue.
231
+ </div>
232
+ """
233
+ )
234
+ gr.HTML("<hr style='margin:24px 0;'>")
235
+
236
+ # --- Loading screen ---
237
+ with gr.Column(visible=False) as loading_screen:
238
+ gr.Markdown(
239
+ """
240
+ <div style='text-align:center; padding: 100px 0;'>
241
+ <h2 class='loading-title'>⏳ Loading...</h2>
242
+ </div>
243
+ """
244
+ )
245
+
246
+ # Step 1
247
+ with gr.Column(visible=True, elem_id="step-1") as step_1_container:
248
+ gr.Markdown("<h2 style='text-align:center;'>Step 1: How to Use \"Slideshows\"</h2>")
249
+ gr.Markdown(
250
+ """
251
+ <div class='slide-box'>
252
+ <b>This is a "Slideshow" step.</b><br><br>
253
+ Some apps are just for reading. Your only task is to click the "Next" button to move to the next step.
254
+ </div>
255
+ """
256
+ )
257
+ step_1_next = gr.Button("Next Step ▶️", variant="primary")
258
+
259
+ # Step 2
260
+ with gr.Column(visible=False, elem_id="step-2") as step_2_container:
261
+ gr.Markdown("<h2 style='text-align:center;'>Step 2: How to Use \"Interactive Demos\"</h2>")
262
+ gr.Markdown(
263
+ """
264
+ <div class='interactive-info-box'>
265
+ <b>This is an "Interactive Demo."</b><br><br>
266
+ Just follow the numbered steps below (from top to bottom) to see how it works!
267
+ </div>
268
+ """
269
+ )
270
+ gr.HTML("<br>")
271
+ gr.Markdown(
272
+ """
273
+ <div style="font-size: 24px; text-align:left; padding-left: 10px;">
274
+ <b>[ 1 ] Use these sliders to change the inputs.</b>
275
+ </div>
276
+ """
277
+ )
278
+ s_hours = gr.Slider(0, 12, step=0.5, value=6, label="Hours Studied per Week")
279
+ s_sleep = gr.Slider(4, 10, step=0.5, value=7, label="Hours of Sleep per Night")
280
+ s_att = gr.Slider(50, 100, step=1, value=90, label="Class Attendance %")
281
+
282
+ gr.HTML("<hr style='margin: 20px 0;'>")
283
+
284
+ gr.Markdown(
285
+ """
286
+ <div style="font-size: 24px; text-align:left; padding-left: 10px;">
287
+ <b>[ 2 ] Click this button to run.</b>
288
+ </div>
289
+ """
290
+ )
291
+ with gr.Row():
292
+ gr.HTML(visible=False)
293
+ go = gr.Button("🔮 Predict", variant="primary", scale=2)
294
+ gr.HTML(visible=False)
295
+
296
+ gr.HTML("<hr style='margin: 20px 0;'>")
297
+
298
+ gr.Markdown(
299
+ """
300
+ <div style="font-size: 24px; text-align:left; padding-left: 10px;">
301
+ <b>[ 3 ] See the result here!</b>
302
+ </div>
303
+ """
304
+ )
305
+ out = gr.Textbox(
306
+ label="🔮 Predicted Exam Score",
307
+ elem_id="prediction_output_textbox",
308
+ interactive=False,
309
+ )
310
+
311
+ # Added scroll_to_output so the page scrolls to the prediction result automatically.
312
+ go.click(
313
+ predict_exam,
314
+ [s_hours, s_sleep, s_att],
315
+ out,
316
+ scroll_to_output=True,
317
+ )
318
+
319
+ gr.HTML("<hr style='margin: 15px 0;'>")
320
+ with gr.Row():
321
+ step_2_back = gr.Button("◀️ Back")
322
+ step_2_next = gr.Button("Finish Tutorial ▶️", variant="primary")
323
+
324
+ # Step 3
325
+ with gr.Column(visible=False, elem_id="step-3") as step_3_container:
326
+ gr.Markdown(
327
+ """
328
+ <div style='text-align:center;'>
329
+ <h2 style='text-align:center; font-size: 2.5rem;'>✅ Tutorial Complete!</h2>
330
+ <div class='complete-box'>
331
+ You've mastered the basics!<br><br>
332
+ Your next step is <b>outside</b> this app window.<br><br>
333
+ <h1 style='margin:0; font-size: 3rem;'>👇 SCROLL DOWN 👇</h1><br>
334
+ Look below this app to find <b>Section 3</b> and begin the challenge!
335
+ </div>
336
+ </div>
337
+ """
338
+ )
339
+ with gr.Row():
340
+ step_3_back = gr.Button("◀️ Back")
341
+
342
+ # --- NAVIGATION LOGIC (GENERATOR-BASED) ---
343
+ all_steps = [step_1_container, step_2_container, step_3_container, loading_screen]
344
+
345
+ def create_nav_generator(current_step, next_step):
346
+ """A helper to create the generator functions to avoid repetitive code."""
347
+
348
+ def navigate():
349
+ updates = {loading_screen: gr.update(visible=True)}
350
+ for step in all_steps:
351
+ if step != loading_screen:
352
+ updates[step] = gr.update(visible=False)
353
+ yield updates
354
+
355
+ updates = {next_step: gr.update(visible=True)}
356
+ for step in all_steps:
357
+ if step != next_step:
358
+ updates[step] = gr.update(visible=False)
359
+ yield updates
360
+
361
+ return navigate
362
+
363
+ # Helper function to generate navigation JS with loading overlay
364
+ def nav_js(target_id: str, message: str, min_show_ms: int = 1200) -> str:
365
+ """
366
+ Generate JavaScript for enhanced slide navigation with loading overlay.
367
+
368
+ Args:
369
+ target_id: Element ID of the target slide (e.g., 'step-2')
370
+ message: Loading message to display during transition
371
+ min_show_ms: Minimum time to show overlay (prevents flicker)
372
+
373
+ Returns:
374
+ JavaScript arrow function string for Gradio's js parameter
375
+ """
376
+ return f"""
377
+ ()=>{{
378
+ try {{
379
+ const overlay = document.getElementById('nav-loading-overlay');
380
+ const messageEl = document.getElementById('nav-loading-text');
381
+ if(overlay && messageEl) {{
382
+ messageEl.textContent = '{message}';
383
+ overlay.style.display = 'flex';
384
+ setTimeout(() => {{ overlay.style.opacity = '1'; }}, 10);
385
+ }}
386
+
387
+ const startTime = Date.now();
388
+
389
+ setTimeout(() => {{
390
+ const anchor = document.getElementById('app_top_anchor');
391
+ const container = document.querySelector('.gradio-container') || document.scrollingElement || document.documentElement;
392
+
393
+ function doScroll() {{
394
+ if(anchor) {{ anchor.scrollIntoView({{behavior:'smooth', block:'start'}}); }}
395
+ else {{ container.scrollTo({{top:0, behavior:'smooth'}}); }}
396
+
397
+ try {{
398
+ if(window.parent && window.parent !== window && window.frameElement) {{
399
+ const top = window.frameElement.getBoundingClientRect().top + window.parent.scrollY;
400
+ window.parent.scrollTo({{top: Math.max(top - 10, 0), behavior:'smooth'}});
401
+ }}
402
+ }} catch(e2) {{}}
403
+ }}
404
+
405
+ doScroll();
406
+ let scrollAttempts = 0;
407
+ const scrollInterval = setInterval(() => {{
408
+ scrollAttempts++;
409
+ doScroll();
410
+ if(scrollAttempts >= 3) clearInterval(scrollInterval);
411
+ }}, 130);
412
+ }}, 40);
413
+
414
+ const targetId = '{target_id}';
415
+ const minShowMs = {min_show_ms};
416
+ let pollCount = 0;
417
+ const maxPolls = 77;
418
+
419
+ const pollInterval = setInterval(() => {{
420
+ pollCount++;
421
+ const elapsed = Date.now() - startTime;
422
+ const target = document.getElementById(targetId);
423
+ const isVisible = target && target.offsetParent !== null &&
424
+ window.getComputedStyle(target).display !== 'none';
425
+
426
+ if((isVisible && elapsed >= minShowMs) || pollCount >= maxPolls) {{
427
+ clearInterval(pollInterval);
428
+ if(overlay) {{
429
+ overlay.style.opacity = '0';
430
+ setTimeout(() => {{ overlay.style.display = 'none'; }}, 300);
431
+ }}
432
+ }}
433
+ }}, 90);
434
+
435
+ }} catch(e) {{ console.warn('nav-js error', e); }}
436
+ }}
437
+ """
438
+
439
+ step_1_next.click(
440
+ fn=create_nav_generator(step_1_container, step_2_container),
441
+ inputs=None,
442
+ outputs=all_steps,
443
+ show_progress="full",
444
+ js=nav_js("step-2", "Learning to interact..."),
445
+ )
446
+ step_2_back.click(
447
+ fn=create_nav_generator(step_2_container, step_1_container),
448
+ inputs=None,
449
+ outputs=all_steps,
450
+ show_progress="full",
451
+ js=nav_js("step-1", "Returning to start..."),
452
+ )
453
+ step_2_next.click(
454
+ fn=create_nav_generator(step_2_container, step_3_container),
455
+ inputs=None,
456
+ outputs=all_steps,
457
+ show_progress="full",
458
+ js=nav_js("step-3", "Completing tutorial..."),
459
+ )
460
+ step_3_back.click(
461
+ fn=create_nav_generator(step_3_container, step_2_container),
462
+ inputs=None,
463
+ outputs=all_steps,
464
+ show_progress="full",
465
+ js=nav_js("step-2", "Going back..."),
466
+ )
467
+
468
+ return demo
469
+
470
+
471
+ def launch_tutorial_app(height: int = 950, share: bool = False, debug: bool = False) -> None:
472
+ """Convenience wrapper to create and launch the tutorial app inline."""
473
+ demo = create_tutorial_app()
474
+ try:
475
+ import gradio as gr # noqa: F401
476
+ except ImportError as e:
477
+ raise ImportError("Gradio must be installed to launch the tutorial app.") from e
478
+ port = int(os.environ.get("PORT", 8080))
479
+ demo.launch(share=share, inline=True, debug=debug, height=height, server_port=port)
480
+
481
+