Raffael-Kultyshev commited on
Commit
ac90379
·
1 Parent(s): c253083

Test: minimal version

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