ivan-adaptemy commited on
Commit
b9375cd
·
1 Parent(s): 63b0c26

troubleshooting

Browse files
__pycache__/app.cpython-312.pyc CHANGED
Binary files a/__pycache__/app.cpython-312.pyc and b/__pycache__/app.cpython-312.pyc differ
 
__pycache__/app_full.cpython-312.pyc ADDED
Binary file (138 Bytes). View file
 
app.py CHANGED
@@ -1,405 +1,10 @@
1
- import uuid
2
- import json
3
- import os
4
- from pathlib import Path
5
  import gradio as gr
6
- from utils import (
7
- LEARN_ENDPOINT,
8
- xAPI_user_request,
9
- xr_experience_event_formatting,
10
- )
11
-
12
- BASE_DIR = Path(__file__).parent
13
- JSON_PATH = BASE_DIR / "content_objects.json"
14
-
15
-
16
- def get_gradio_auth():
17
- username = os.getenv("APP_USERNAME") or os.getenv("HF_APP_USERNAME")
18
- password = os.getenv("APP_PASSWORD") or os.getenv("HF_APP_PASSWORD")
19
-
20
- if username and password:
21
- return [(username, password)]
22
-
23
- return None
24
-
25
-
26
- def is_huggingface_space():
27
- return bool(os.getenv("SPACE_ID"))
28
-
29
-
30
- def load_content_objects():
31
- with open(JSON_PATH, "r", encoding="utf-8") as f:
32
- return json.load(f)
33
-
34
-
35
- def get_name_mapping():
36
- content_objects = load_content_objects()
37
- name_to_key = {obj["name"]: key for key, obj in content_objects.items()}
38
- object_names = list(name_to_key.keys())
39
- return content_objects, name_to_key, object_names
40
-
41
-
42
- def toggle_session(session_id, learner_name):
43
- # If no active session -> start one
44
- if not session_id:
45
- if not learner_name or not learner_name.strip():
46
- return (
47
- None, # session_state
48
- gr.update(value="Start Session"), # start/end button label
49
- gr.update(
50
- choices=[],
51
- value=None,
52
- interactive=False
53
- ), # object_selector
54
- "Start a session to load XR content inventory.", # details
55
- "⚠️ Please enter a learner name first.", # status
56
- 0, # duration_hours_input
57
- 0, # duration_minutes_input
58
- 0, # duration_seconds_input
59
- [], # records_table
60
- )
61
-
62
- new_session_id = str(uuid.uuid4())
63
- _, _, object_names = get_name_mapping()
64
-
65
- return (
66
- new_session_id, # session_state
67
- gr.update(value="End Session"), # start/end button label
68
- gr.update(
69
- choices=object_names,
70
- value=None,
71
- interactive=True
72
- ), # object_selector
73
- "Select XR content to view details.", # details
74
- "Session started. You can now select XR content.", # status
75
- 0, # duration_hours_input
76
- 0, # duration_minutes_input
77
- 0, # duration_seconds_input
78
- [], # records_table
79
- )
80
-
81
- # If session exists -> end it and reset everything
82
- return (
83
- None, # session_state
84
- gr.update(value="Start Session"), # start/end button label
85
- gr.update(
86
- choices=[],
87
- value=None,
88
- interactive=False
89
- ), # object_selector
90
- "Start a session to load XR content inventory.", # details
91
- "Session ended.", # status
92
- 0, # duration_hours_input
93
- 0, # duration_minutes_input
94
- 0, # duration_seconds_input
95
- [], # records_table
96
- )
97
-
98
-
99
- def show_details(selected_name, session_id):
100
- if not session_id:
101
- return "Start a session to load XR content inventory."
102
-
103
- if not selected_name:
104
- return "Select XR content to view details."
105
-
106
- content_objects, name_to_key, _ = get_name_mapping()
107
- key = name_to_key[selected_name]
108
- obj = content_objects[key]
109
-
110
- return f"""
111
- ### {obj["name"]}
112
-
113
- **Description:**
114
- {obj["description"]}
115
-
116
- **Scene:** {obj["scene"]}
117
- **Media Type:** {obj["media-type"]}
118
- **Device:** {obj["media-device"]}
119
- """
120
-
121
-
122
- def normalize_records(records):
123
- if records is None:
124
- return []
125
-
126
- if hasattr(records, "values") and hasattr(records.values, "tolist"):
127
- return records.values.tolist()
128
-
129
- if hasattr(records, "tolist"):
130
- converted_records = records.tolist()
131
- return converted_records if isinstance(converted_records, list) else []
132
-
133
- return list(records)
134
-
135
-
136
- def build_duration(hours, minutes, seconds):
137
- try:
138
- normalized_hours = int(hours or 0)
139
- normalized_minutes = int(minutes or 0)
140
- normalized_seconds = int(seconds or 0)
141
- except (TypeError, ValueError) as exc:
142
- raise ValueError("Duration must be numeric.") from exc
143
-
144
- if normalized_hours < 0 or normalized_minutes < 0 or normalized_seconds < 0:
145
- raise ValueError("Duration cannot be negative.")
146
-
147
- total_seconds = (normalized_hours * 3600) + (normalized_minutes * 60) + normalized_seconds
148
- if total_seconds <= 0:
149
- raise ValueError("Duration must be greater than zero.")
150
-
151
- display_hours, remainder = divmod(total_seconds, 3600)
152
- display_minutes, display_seconds = divmod(remainder, 60)
153
-
154
- iso_duration = "PT"
155
- if display_hours:
156
- iso_duration += f"{display_hours}H"
157
- if display_minutes:
158
- iso_duration += f"{display_minutes}M"
159
- if display_seconds or iso_duration == "PT":
160
- iso_duration += f"{display_seconds}S"
161
-
162
- return f"{display_hours:02d}h:{display_minutes:02d}m:{display_seconds:02d}s", iso_duration
163
-
164
-
165
- def add_record(session_id, selected_name, learner_name, duration_hours, duration_minutes, duration_seconds, records):
166
- existing_records = normalize_records(records)
167
-
168
- if not session_id:
169
- return existing_records, "⚠️ Please start a session first."
170
-
171
- if not selected_name:
172
- return existing_records, "⚠️ Please select a XR content."
173
-
174
- try:
175
- cleaned_duration, _ = build_duration(duration_hours, duration_minutes, duration_seconds)
176
- except ValueError as exc:
177
- return existing_records, f"⚠️ {exc}"
178
-
179
- updated_records = list(existing_records)
180
- updated_records.append([selected_name, cleaned_duration])
181
-
182
- return updated_records, f"Record ready. {len(updated_records)} record(s) queued for submission."
183
-
184
-
185
- def reset_duration():
186
- return (
187
- 0,
188
- 0,
189
- 0,
190
- "Duration reset.",
191
- )
192
-
193
-
194
- def submit_learner_experience(session_id, learner_name, records):
195
- if not session_id:
196
- return "⚠️ Please start a session first.", gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update()
197
-
198
- if not learner_name or not learner_name.strip():
199
- return "⚠️ Please enter a learner name.", gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update()
200
-
201
- cleaned_learner_name = learner_name.strip()
202
- cleaned_records = []
203
- for row in normalize_records(records):
204
- if not row or not any(str(cell).strip() for cell in row):
205
- continue
206
-
207
- normalized_row = [str(cell).strip() for cell in row[:2]]
208
- while len(normalized_row) < 2:
209
- normalized_row.append("")
210
- cleaned_records.append(normalized_row)
211
-
212
- if not cleaned_records:
213
- return "⚠️ Add at least one record before submitting.", gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update()
214
-
215
- content_objects, name_to_key, _ = get_name_mapping()
216
- payloads = []
217
-
218
- for index, (selected_name, duration) in enumerate(cleaned_records, start=1):
219
- if not selected_name:
220
- return f"⚠️ Record {index}: content is required.", gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update()
221
-
222
- if selected_name not in name_to_key:
223
- return f'⚠️ Record {index}: unknown content "{selected_name}".', gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update()
224
-
225
- if not duration:
226
- return f"⚠️ Record {index}: duration is required.", gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update()
227
-
228
- try:
229
- duration_text = duration.replace("s", "")
230
- hours_part, minute_second_text = duration_text.split("h:")
231
- minutes_part, seconds_part = minute_second_text.split("m:")
232
- _, cleaned_duration = build_duration(hours_part, minutes_part, seconds_part)
233
- except ValueError as exc:
234
- return f"⚠️ Record {index}: {exc}", gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update()
235
- except Exception:
236
- return f"⚠️ Record {index}: invalid duration format.", gr.update(), gr.update(), gr.update(), gr.update(), gr.update(), gr.update()
237
-
238
- key = name_to_key[selected_name]
239
- xr_content_object_id = content_objects[key]["id"]
240
- payloads.append(
241
- xr_experience_event_formatting(
242
- learner_name=cleaned_learner_name,
243
- duration=cleaned_duration,
244
- xr_content_object_id=xr_content_object_id,
245
- session_id=session_id,
246
- )
247
- )
248
-
249
- xAPI_user_request(LEARN_ENDPOINT, payloads)
250
-
251
- return (
252
- f"✅ Submitted **{len(payloads)}** learner experience record(s).\n\n"
253
- f"- Session ID: `{session_id}`\n"
254
- f"- Records sent: `{len(payloads)}`",
255
- gr.update(),
256
- gr.update(value=None),
257
- 0,
258
- 0,
259
- 0,
260
- [],
261
- )
262
 
263
 
264
  with gr.Blocks() as demo:
265
- gr.Markdown("# XREL Learning Tracker")
266
-
267
- session_state = gr.State(None)
268
-
269
- learner_name_input = gr.Textbox(
270
- label="Learner Name",
271
- placeholder="Enter learner name before starting a session",
272
- )
273
- session_btn = gr.Button("Start Session")
274
- gr.Markdown("## 1. Select XR content")
275
-
276
- object_selector = gr.Dropdown(
277
- choices=[],
278
- value=None,
279
- label="XR Content Inventory",
280
- interactive=False,
281
- elem_id="content-object-dropdown",
282
- )
283
-
284
- details = gr.Markdown("Start a session to load XR content inventory.")
285
- gr.Markdown("## 2. Record the experience")
286
- with gr.Row():
287
- with gr.Column(scale=0, min_width=110):
288
- gr.Markdown("**Duration:**")
289
- with gr.Column(scale=0, min_width=90):
290
- duration_hours_input = gr.Number(
291
- show_label=False,
292
- value=0,
293
- minimum=0,
294
- precision=0,
295
- container=False,
296
- )
297
- with gr.Column(scale=0, min_width=24):
298
- gr.Markdown("**H**")
299
- with gr.Column(scale=0, min_width=90):
300
- duration_minutes_input = gr.Number(
301
- show_label=False,
302
- value=0,
303
- minimum=0,
304
- precision=0,
305
- container=False,
306
- )
307
- with gr.Column(scale=0, min_width=24):
308
- gr.Markdown("**M**")
309
- with gr.Column(scale=0, min_width=90):
310
- duration_seconds_input = gr.Number(
311
- show_label=False,
312
- value=0,
313
- minimum=0,
314
- precision=0,
315
- container=False,
316
- )
317
- with gr.Column(scale=0, min_width=24):
318
- gr.Markdown("**S**")
319
- with gr.Column(scale=0, min_width=100):
320
- reset_duration_btn = gr.Button("Reset")
321
- with gr.Column():
322
- gr.Markdown("")
323
- add_record_btn = gr.Button("Add record")
324
- records_table = gr.Dataframe(
325
- headers=["XR Content", "Duration"],
326
- datatype=["str", "str"],
327
- value=[],
328
- row_count=(0, "dynamic"),
329
- column_count=(2, "fixed"),
330
- interactive=True,
331
- wrap=True,
332
- label="Learning Records",
333
- )
334
- submit_experience_btn = gr.Button("Submit records")
335
- experience_status = gr.Markdown()
336
-
337
- session_btn.click(
338
- fn=toggle_session,
339
- inputs=[session_state, learner_name_input],
340
- outputs=[
341
- session_state,
342
- session_btn,
343
- object_selector,
344
- details,
345
- experience_status,
346
- duration_hours_input,
347
- duration_minutes_input,
348
- duration_seconds_input,
349
- records_table,
350
- ]
351
- )
352
-
353
- object_selector.change(
354
- fn=show_details,
355
- inputs=[object_selector, session_state],
356
- outputs=details
357
- )
358
-
359
- reset_duration_btn.click(
360
- fn=reset_duration,
361
- outputs=[
362
- duration_hours_input,
363
- duration_minutes_input,
364
- duration_seconds_input,
365
- experience_status,
366
- ]
367
- )
368
-
369
- add_record_btn.click(
370
- fn=add_record,
371
- inputs=[
372
- session_state,
373
- object_selector,
374
- learner_name_input,
375
- duration_hours_input,
376
- duration_minutes_input,
377
- duration_seconds_input,
378
- records_table,
379
- ],
380
- outputs=[records_table, experience_status]
381
- )
382
-
383
- submit_experience_btn.click(
384
- fn=submit_learner_experience,
385
- inputs=[session_state, learner_name_input, records_table],
386
- outputs=[
387
- experience_status,
388
- learner_name_input,
389
- object_selector,
390
- duration_hours_input,
391
- duration_minutes_input,
392
- duration_seconds_input,
393
- records_table,
394
- ]
395
- )
396
 
397
 
398
  if __name__ == "__main__":
399
- demo.launch(
400
- server_name=os.getenv("GRADIO_SERVER_NAME", "0.0.0.0"),
401
- server_port=int(os.getenv("PORT", "7860")),
402
- auth=None if is_huggingface_space() else get_gradio_auth(),
403
- ssr_mode=False,
404
- show_error=True,
405
- )
 
 
 
 
 
1
  import gradio as gr
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
 
3
 
4
  with gr.Blocks() as demo:
5
+ gr.Markdown("# XREL Fallback")
6
+ gr.Markdown("If this page reaches Running on Hugging Face Spaces, the platform config is healthy.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7
 
8
 
9
  if __name__ == "__main__":
10
+ demo.launch()
 
 
 
 
 
 
app_full.py ADDED
File without changes