Raffael-Kultyshev commited on
Commit
abe51d3
·
1 Parent(s): 0ec8c92

Revert to working minimal version

Browse files
Files changed (1) hide show
  1. app.py +6 -414
app.py CHANGED
@@ -1,424 +1,16 @@
1
  """
2
- Dynamic Intelligence - Human Demo Visualizer
3
- Egocentric hand tracking dataset visualizer for robot training data
4
  """
5
-
6
  import gradio as gr
7
- import json
8
- import html
9
- import numpy as np
10
  from pathlib import Path
11
- import plotly.graph_objects as go
12
- import plotly.io as pio
13
- from typing import Dict, List
14
 
15
- # Load pipeline data
16
  DATA_DIR = Path(__file__).parent / "data"
17
-
18
- def load_json_safe(path):
19
- try:
20
- with open(path, 'r') as f:
21
- return json.load(f)
22
- except Exception as e:
23
- print(f"Error loading {path}: {e}")
24
- return {}
25
-
26
- # Load data at startup
27
- print("Loading data...")
28
- metadata = load_json_safe(DATA_DIR / "metadata.json")
29
- end_effector = load_json_safe(DATA_DIR / "end_effector.json")
30
- actions = load_json_safe(DATA_DIR / "actions.json")
31
- hands_2d = load_json_safe(DATA_DIR / "hands_2d.json")
32
- print(f"Loaded: metadata={len(metadata)}, ee={len(end_effector)}, actions={len(actions)}, hands={len(hands_2d)}")
33
-
34
- # Stats
35
- total_frames = max(1, len(metadata.get('poses', [])))
36
- fps = metadata.get('fps', 60)
37
- hand_detection_rate = len(hands_2d) / total_frames * 100
38
-
39
- # Count poses safely
40
- left_poses = 0
41
- right_poses = 0
42
- for frame_data in end_effector.values():
43
- if frame_data and isinstance(frame_data, dict):
44
- if frame_data.get('left_hand'):
45
- left_poses += 1
46
- if frame_data.get('right_hand'):
47
- right_poses += 1
48
-
49
- print(f"Stats: frames={total_frames}, left={left_poses}, right={right_poses}")
50
-
51
- # Video path
52
  video_path = DATA_DIR / "video.mp4"
53
 
54
- # Prepare time-series data
55
- def prepare_data():
56
- """Prepare time-series data for plots."""
57
- times = []
58
- left_pos = {'x': [], 'y': [], 'z': []}
59
- left_rot = {'yaw': [], 'pitch': [], 'roll': []}
60
- right_pos = {'x': [], 'y': [], 'z': []}
61
- right_rot = {'yaw': [], 'pitch': [], 'roll': []}
62
-
63
- if not end_effector:
64
- return {
65
- 'times': times,
66
- 'left_pos': left_pos,
67
- 'left_rot': left_rot,
68
- 'right_pos': right_pos,
69
- 'right_rot': right_rot
70
- }
71
-
72
- try:
73
- frame_keys = sorted([int(k) for k in end_effector.keys() if str(k).isdigit()])
74
- except:
75
- frame_keys = []
76
-
77
- for frame_idx in frame_keys:
78
- frame_key = str(frame_idx)
79
- t = frame_idx / fps
80
- times.append(t)
81
-
82
- ee_data = end_effector.get(frame_key, {}) or {}
83
-
84
- # Left hand
85
- left_hand_data = ee_data.get('left_hand')
86
- if left_hand_data and isinstance(left_hand_data, dict):
87
- pose = left_hand_data.get('pose_6dof')
88
- if pose and len(pose) >= 6:
89
- left_pos['x'].append(pose[0] * 100) # m to cm
90
- left_pos['y'].append(pose[1] * 100)
91
- left_pos['z'].append(pose[2] * 100)
92
- left_rot['roll'].append(pose[3] * 57.3) # rad to deg
93
- left_rot['pitch'].append(pose[4] * 57.3)
94
- left_rot['yaw'].append(pose[5] * 57.3)
95
- else:
96
- for k in left_pos: left_pos[k].append(None)
97
- for k in left_rot: left_rot[k].append(None)
98
- else:
99
- for k in left_pos: left_pos[k].append(None)
100
- for k in left_rot: left_rot[k].append(None)
101
-
102
- # Right hand
103
- right_hand_data = ee_data.get('right_hand')
104
- if right_hand_data and isinstance(right_hand_data, dict):
105
- pose = right_hand_data.get('pose_6dof')
106
- if pose and len(pose) >= 6:
107
- right_pos['x'].append(pose[0] * 100)
108
- right_pos['y'].append(pose[1] * 100)
109
- right_pos['z'].append(pose[2] * 100)
110
- right_rot['roll'].append(pose[3] * 57.3)
111
- right_rot['pitch'].append(pose[4] * 57.3)
112
- right_rot['yaw'].append(pose[5] * 57.3)
113
- else:
114
- for k in right_pos: right_pos[k].append(None)
115
- for k in right_rot: right_rot[k].append(None)
116
- else:
117
- for k in right_pos: right_pos[k].append(None)
118
- for k in right_rot: right_rot[k].append(None)
119
-
120
- return {
121
- 'times': times,
122
- 'left_pos': left_pos,
123
- 'left_rot': left_rot,
124
- 'right_pos': right_pos,
125
- 'right_rot': right_rot
126
- }
127
-
128
- # Lazy load plot data
129
- plot_data = None
130
-
131
- def get_plot_data():
132
- """Lazy load plot data."""
133
- global plot_data
134
- if plot_data is None:
135
- try:
136
- plot_data = prepare_data()
137
- except Exception as e:
138
- print(f"Error preparing plot data: {e}")
139
- plot_data = {
140
- 'times': [],
141
- 'left_pos': {'x': [], 'y': [], 'z': []},
142
- 'left_rot': {'yaw': [], 'pitch': [], 'roll': []},
143
- 'right_pos': {'x': [], 'y': [], 'z': []},
144
- 'right_rot': {'yaw': [], 'pitch': [], 'roll': []}
145
- }
146
- return plot_data
147
-
148
- METRIC_LABELS = {
149
- "x_cm": "X (cm)",
150
- "y_cm": "Y (cm)",
151
- "z_cm": "Z (cm)",
152
- "yaw_deg": "Yaw (°)",
153
- "pitch_deg": "Pitch (°)",
154
- "roll_deg": "Roll (°)",
155
- }
156
-
157
- PLOT_GRID = [
158
- ["x_cm", "y_cm", "z_cm"],
159
- ["yaw_deg", "pitch_deg", "roll_deg"],
160
- ]
161
-
162
- PLOT_ORDER = [metric for row in PLOT_GRID for metric in row]
163
-
164
- CUSTOM_CSS = """
165
- :root, .gradio-container, body {
166
- background-color: #050a18 !important;
167
- color: #f8fafc !important;
168
- font-family: 'Inter', 'Segoe UI', system-ui, sans-serif;
169
- }
170
- .side-panel {
171
- background: #0f172a;
172
- padding: 20px;
173
- border-radius: 18px;
174
- border: 1px solid #1f2b47;
175
- min-height: 100%;
176
- }
177
- .stats-card ul {
178
- list-style: none;
179
- padding: 0;
180
- margin: 0;
181
- font-size: 0.92rem;
182
- }
183
- .stats-card li {
184
- margin-bottom: 10px;
185
- color: #e2e8f0;
186
- }
187
- .stats-card span {
188
- display: inline-block;
189
- margin-right: 6px;
190
- color: #7dd3fc;
191
- }
192
- .main-panel {
193
- padding-top: 8px;
194
- }
195
- .instruction-card {
196
- background: #0f172a;
197
- padding: 18px 20px;
198
- border-radius: 18px;
199
- border: 1px solid #1f2b47;
200
- }
201
- .instruction-label {
202
- font-size: 0.75rem;
203
- letter-spacing: 0.12em;
204
- text-transform: uppercase;
205
- color: #94a3b8;
206
- margin-bottom: 10px;
207
- }
208
- .instruction-text {
209
- font-size: 1.1rem;
210
- line-height: 1.5;
211
- }
212
- .video-card {
213
- background: #0f172a;
214
- border: 1px solid #1f2b47;
215
- border-radius: 18px;
216
- padding: 18px 20px;
217
- margin-top: 18px;
218
- }
219
- .video-title {
220
- font-size: 0.78rem;
221
- text-transform: uppercase;
222
- letter-spacing: 0.18em;
223
- color: #94a3b8;
224
- margin-bottom: 8px;
225
- }
226
- .video-panel video {
227
- border-radius: 12px;
228
- border: 1px solid #1f2b47;
229
- background: #030712;
230
- }
231
- .download-button button {
232
- border-radius: 999px;
233
- border: 1px solid #334155;
234
- background: #1e293b;
235
- color: #f8fafc;
236
- font-size: 0.85rem;
237
- padding: 8px 24px;
238
- }
239
- .download-button button:hover {
240
- border-color: #67e8f9;
241
- color: #67e8f9;
242
- }
243
- .plots-wrap {
244
- margin-top: 18px;
245
- }
246
- .plots-wrap .gr-row {
247
- gap: 16px;
248
- }
249
- .plot-html {
250
- background: #111a2c;
251
- border-radius: 12px;
252
- padding: 10px;
253
- border: 1px solid #1f2b47;
254
- min-height: 320px;
255
- }
256
- .plot-html iframe {
257
- width: 100%;
258
- height: 300px;
259
- border: none;
260
- }
261
- """
262
-
263
- def build_plot_fig(metric: str, hand: str = "left") -> go.Figure:
264
- """Build Plotly figure for a metric."""
265
- try:
266
- data = get_plot_data()
267
- times = data.get('times', [])
268
-
269
- if hand == "left":
270
- if "cm" in metric:
271
- key = metric.replace('_cm', '')
272
- plot_values = data.get('left_pos', {}).get(key, [])
273
- else:
274
- key = metric.replace('_deg', '')
275
- plot_values = data.get('left_rot', {}).get(key, [])
276
- name = "Left Hand"
277
- else:
278
- if "cm" in metric:
279
- key = metric.replace('_cm', '')
280
- plot_values = data.get('right_pos', {}).get(key, [])
281
- else:
282
- key = metric.replace('_deg', '')
283
- plot_values = data.get('right_rot', {}).get(key, [])
284
- name = "Right Hand"
285
-
286
- if not times or not plot_values:
287
- # Return empty plot
288
- times = [0]
289
- plot_values = [0]
290
- except Exception as e:
291
- print(f"Error in build_plot_fig: {e}")
292
- times = [0]
293
- plot_values = [0]
294
- name = "Error"
295
-
296
- fig = go.Figure()
297
- fig.add_trace(
298
- go.Scatter(
299
- x=times,
300
- y=plot_values,
301
- mode="lines",
302
- name=name,
303
- line=dict(color="#67e8f9", width=2)
304
- )
305
- )
306
- fig.update_layout(
307
- margin=dict(l=20, r=20, t=30, b=20),
308
- height=250,
309
- template="plotly_dark",
310
- legend=dict(orientation="h", yanchor="bottom", y=1.02, xanchor="right", x=1),
311
- xaxis_title="Time (s)",
312
- yaxis_title=METRIC_LABELS[metric],
313
- )
314
- fig.update_xaxes(showgrid=True, gridwidth=0.5, gridcolor="rgba(255,255,255,0.1)")
315
- fig.update_yaxes(showgrid=True, gridwidth=0.5, gridcolor="rgba(255,255,255,0.1)")
316
- return fig
317
-
318
- def build_plot_html(metric: str, hand: str = "left") -> str:
319
- """Build Plotly HTML for a metric."""
320
- fig = build_plot_fig(metric, hand)
321
- return pio.to_html(fig, include_plotlyjs="cdn", full_html=False)
322
-
323
- # Build interface
324
- stats_html = f"""
325
- <div class="stats-card">
326
- <ul>
327
- <li><span>Number of samples/frames:</span> {total_frames:,}</li>
328
- <li><span>Hand detection rate:</span> {hand_detection_rate:.1f}%</li>
329
- <li><span>Left hand poses:</span> {left_poses}</li>
330
- <li><span>Right hand poses:</span> {right_poses}</li>
331
- <li><span>Frames per second:</span> {fps:.1f}</li>
332
- </ul>
333
- </div>
334
- """
335
-
336
- instruction_text = "LiDAR-based egocentric hand tracking for robot training data"
337
-
338
- theme = gr.themes.Soft(
339
- primary_hue="cyan", secondary_hue="blue", neutral_hue="slate"
340
- ).set(
341
- body_background_fill="#0c1424",
342
- body_text_color="#f8fafc",
343
- block_background_fill="#111a2c",
344
- block_title_text_color="#f8fafc",
345
- input_background_fill="#151f33",
346
- border_color_primary="#1f2b47",
347
- shadow_drop="none",
348
- )
349
-
350
- def format_instruction_html(text: str) -> str:
351
- safe_text = html.escape(text)
352
- return (
353
- '<div class="instruction-card">'
354
- '<p class="instruction-label">Language Instruction</p>'
355
- f'<p class="instruction-text">{safe_text}</p>'
356
- "</div>"
357
- )
358
-
359
- with gr.Blocks(theme=theme, css=CUSTOM_CSS) as demo:
360
- gr.Markdown("# 🤖 Dynamic Intelligence - Human Demo Visualizer")
361
- gr.Markdown(
362
- "Egocentric hand tracking dataset for humanoid robot training. "
363
- "Pipeline: iPhone LiDAR → MediaPipe → 6DoF End-Effector → Robot Training Data"
364
- )
365
-
366
- with gr.Row(equal_height=True):
367
- with gr.Column(scale=1, min_width=260, elem_classes=["side-panel"]):
368
- gr.HTML(stats_html)
369
- with gr.Column(scale=2, min_width=640, elem_classes=["main-panel"]):
370
- instruction_box = gr.HTML(
371
- format_instruction_html(instruction_text),
372
- label="Language Instruction",
373
- )
374
- with gr.Column(elem_classes=["video-card"]):
375
- gr.HTML('<div class="video-title">RGB Video</div>')
376
- video = gr.Video(
377
- height=360,
378
- value=str(video_path) if video_path.exists() else None,
379
- elem_classes=["video-panel"],
380
- show_label=False,
381
- show_download_button=False,
382
- )
383
- download_button = gr.DownloadButton(
384
- label="Download",
385
- value=str(video_path) if video_path.exists() else None,
386
- elem_classes=["download-button"],
387
- )
388
-
389
- try:
390
- gr.Markdown("### Left Hand Trajectories", elem_classes=["plots-title"])
391
- plot_outputs_left = []
392
- with gr.Column(elem_classes=["plots-wrap"]):
393
- for row in PLOT_GRID:
394
- with gr.Row():
395
- for metric in row:
396
- try:
397
- plot_html = build_plot_html(metric, "left")
398
- plot = gr.HTML(value=plot_html, elem_classes=["plot-html"])
399
- plot_outputs_left.append(plot)
400
- except Exception as e:
401
- print(f"Error creating plot {metric} for left hand: {e}")
402
- plot = gr.HTML(value="<p>Plot unavailable</p>", elem_classes=["plot-html"])
403
- plot_outputs_left.append(plot)
404
-
405
- gr.Markdown("### Right Hand Trajectories", elem_classes=["plots-title"])
406
- plot_outputs_right = []
407
- with gr.Column(elem_classes=["plots-wrap"]):
408
- for row in PLOT_GRID:
409
- with gr.Row():
410
- for metric in row:
411
- try:
412
- plot_html = build_plot_html(metric, "right")
413
- plot = gr.HTML(value=plot_html, elem_classes=["plot-html"])
414
- plot_outputs_right.append(plot)
415
- except Exception as e:
416
- print(f"Error creating plot {metric} for right hand: {e}")
417
- plot = gr.HTML(value="<p>Plot unavailable</p>", elem_classes=["plot-html"])
418
- plot_outputs_right.append(plot)
419
- except Exception as e:
420
- print(f"Error creating plots section: {e}")
421
- gr.Markdown("### Plots unavailable")
422
 
423
  if __name__ == "__main__":
424
- demo.queue().launch(show_api=False)
 
 
1
  """
2
+ Minimal test version
 
3
  """
 
4
  import gradio as gr
 
 
 
5
  from pathlib import Path
 
 
 
6
 
 
7
  DATA_DIR = Path(__file__).parent / "data"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8
  video_path = DATA_DIR / "video.mp4"
9
 
10
+ with gr.Blocks() as demo:
11
+ gr.Markdown("# Test")
12
+ gr.Video(value=str(video_path) if video_path.exists() else None)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13
 
14
  if __name__ == "__main__":
15
+ demo.launch()
16
+