Raffael-Kultyshev commited on
Commit
715c080
·
1 Parent(s): 5aea41f

EXACT reference structure: sidebar left, video+plots right, Radio for hand selection

Browse files
Files changed (1) hide show
  1. app.py +131 -30
app.py CHANGED
@@ -7,6 +7,15 @@ import plotly.io as pio
7
  DATA_DIR = Path(__file__).parent / "data"
8
  video_path = DATA_DIR / "video.mp4"
9
 
 
 
 
 
 
 
 
 
 
10
  PLOT_GRID = [
11
  ["x_cm", "y_cm", "z_cm"],
12
  ["yaw_deg", "pitch_deg", "roll_deg"],
@@ -15,6 +24,55 @@ PLOT_GRID = [
15
  PLOT_ORDER = [metric for row in PLOT_GRID for metric in row]
16
 
17
  CUSTOM_CSS = """
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
18
  .plots-wrap {
19
  margin-top: 18px;
20
  }
@@ -105,44 +163,87 @@ def build_plot_html(metadata, end_effector, hand, metric):
105
  height=250,
106
  margin=dict(l=20, r=20, t=30, b=20),
107
  xaxis_title="Time (s)",
108
- yaxis_title=metric.replace("_", " ").title()
109
  )
110
  return pio.to_html(fig, include_plotlyjs="cdn", full_html=False)
111
  except Exception as e:
112
  return f"<p>Error: {str(e)}</p>"
113
 
114
- # Load data
115
- metadata, end_effector = load_data()
116
- total_frames = len(metadata.get('poses', []))
117
- fps = metadata.get('fps', 60)
118
-
119
- # Build plots - EXACTLY like reference app
120
- left_figs = {metric: build_plot_html(metadata, end_effector, "left", metric) for metric in PLOT_ORDER}
121
- right_figs = {metric: build_plot_html(metadata, end_effector, "right", metric) for metric in PLOT_ORDER}
122
-
123
- theme = gr.themes.Soft(primary_hue="cyan", secondary_hue="blue", neutral_hue="slate")
124
-
125
- with gr.Blocks(theme=theme, css=CUSTOM_CSS) as demo:
126
- gr.Markdown("# 🤖 Dynamic Intelligence - Human Demo Visualizer")
127
- gr.Markdown(f"**Frames:** {total_frames:,} | **FPS:** {fps}")
 
 
 
128
 
129
- gr.Video(value=str(video_path) if video_path.exists() else None, height=360)
 
 
 
 
 
 
 
 
 
 
130
 
131
- # Left hand - EXACT structure from reference
132
- gr.Markdown("### Left Hand Trajectories")
133
- with gr.Column(elem_classes=["plots-wrap"]):
134
- for row in PLOT_GRID:
135
- with gr.Row():
136
- for metric in row:
137
- gr.HTML(value=left_figs[metric], elem_classes=["plot-html"])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
138
 
139
- # Right hand - EXACT structure from reference
140
- gr.Markdown("### Right Hand Trajectories")
141
- with gr.Column(elem_classes=["plots-wrap"]):
142
- for row in PLOT_GRID:
143
- with gr.Row():
144
- for metric in row:
145
- gr.HTML(value=right_figs[metric], elem_classes=["plot-html"])
146
 
147
  if __name__ == "__main__":
148
  demo.launch()
 
7
  DATA_DIR = Path(__file__).parent / "data"
8
  video_path = DATA_DIR / "video.mp4"
9
 
10
+ METRIC_LABELS = {
11
+ "x_cm": "X (cm)",
12
+ "y_cm": "Y (cm)",
13
+ "z_cm": "Z (cm)",
14
+ "yaw_deg": "Yaw (°)",
15
+ "pitch_deg": "Pitch (°)",
16
+ "roll_deg": "Roll (°)",
17
+ }
18
+
19
  PLOT_GRID = [
20
  ["x_cm", "y_cm", "z_cm"],
21
  ["yaw_deg", "pitch_deg", "roll_deg"],
 
24
  PLOT_ORDER = [metric for row in PLOT_GRID for metric in row]
25
 
26
  CUSTOM_CSS = """
27
+ :root, .gradio-container, body {
28
+ background-color: #050a18 !important;
29
+ color: #f8fafc !important;
30
+ font-family: 'Inter', 'Segoe UI', system-ui, sans-serif;
31
+ }
32
+ .side-panel {
33
+ background: #0f172a;
34
+ padding: 20px;
35
+ border-radius: 18px;
36
+ border: 1px solid #1f2b47;
37
+ min-height: 100%;
38
+ }
39
+ .stats-card ul {
40
+ list-style: none;
41
+ padding: 0;
42
+ margin: 0;
43
+ font-size: 0.92rem;
44
+ }
45
+ .stats-card li {
46
+ margin-bottom: 10px;
47
+ color: #e2e8f0;
48
+ }
49
+ .stats-card span {
50
+ display: inline-block;
51
+ margin-right: 6px;
52
+ color: #7dd3fc;
53
+ }
54
+ .main-panel {
55
+ padding-top: 8px;
56
+ }
57
+ .video-card {
58
+ background: #0f172a;
59
+ border: 1px solid #1f2b47;
60
+ border-radius: 18px;
61
+ padding: 18px 20px;
62
+ margin-top: 18px;
63
+ }
64
+ .video-title {
65
+ font-size: 0.78rem;
66
+ text-transform: uppercase;
67
+ letter-spacing: 0.18em;
68
+ color: #94a3b8;
69
+ margin-bottom: 8px;
70
+ }
71
+ .video-panel video {
72
+ border-radius: 12px;
73
+ border: 1px solid #1f2b47;
74
+ background: #030712;
75
+ }
76
  .plots-wrap {
77
  margin-top: 18px;
78
  }
 
163
  height=250,
164
  margin=dict(l=20, r=20, t=30, b=20),
165
  xaxis_title="Time (s)",
166
+ yaxis_title=METRIC_LABELS[metric]
167
  )
168
  return pio.to_html(fig, include_plotlyjs="cdn", full_html=False)
169
  except Exception as e:
170
  return f"<p>Error: {str(e)}</p>"
171
 
172
+ def build_interface():
173
+ metadata, end_effector = load_data()
174
+ total_frames = len(metadata.get('poses', []))
175
+ fps = metadata.get('fps', 60)
176
+
177
+ # Build plots for left and right hands
178
+ left_figs = {metric: build_plot_html(metadata, end_effector, "left", metric) for metric in PLOT_ORDER}
179
+ right_figs = {metric: build_plot_html(metadata, end_effector, "right", metric) for metric in PLOT_ORDER}
180
+
181
+ stats_html = f"""
182
+ <div class="stats-card">
183
+ <ul>
184
+ <li><span>Number of samples/frames:</span> {total_frames:,}</li>
185
+ <li><span>Frames per second:</span> {fps:.1f}</li>
186
+ </ul>
187
+ </div>
188
+ """
189
 
190
+ theme = gr.themes.Soft(
191
+ primary_hue="cyan", secondary_hue="blue", neutral_hue="slate"
192
+ ).set(
193
+ body_background_fill="#0c1424",
194
+ body_text_color="#f8fafc",
195
+ block_background_fill="#111a2c",
196
+ block_title_text_color="#f8fafc",
197
+ input_background_fill="#151f33",
198
+ border_color_primary="#1f2b47",
199
+ shadow_drop="none",
200
+ )
201
 
202
+ with gr.Blocks(theme=theme, css=CUSTOM_CSS) as demo:
203
+ gr.Markdown("# 🤖 Dynamic Intelligence - Human Demo Visualizer")
204
+ gr.Markdown("Egocentric hand tracking dataset for humanoid robot training.")
205
+
206
+ with gr.Row(equal_height=True):
207
+ with gr.Column(scale=1, min_width=260, elem_classes=["side-panel"]):
208
+ gr.HTML(stats_html)
209
+ gr.HTML('<div class="episodes-title">Hands</div>')
210
+ hand_radio = gr.Radio(
211
+ choices=["Left Hand", "Right Hand"],
212
+ value="Left Hand",
213
+ label="Hand Selection",
214
+ )
215
+ with gr.Column(scale=2, min_width=640, elem_classes=["main-panel"]):
216
+ with gr.Column(elem_classes=["video-card"]):
217
+ gr.HTML('<div class="video-title">RGB Video</div>')
218
+ video = gr.Video(
219
+ height=360,
220
+ value=str(video_path) if video_path.exists() else None,
221
+ elem_classes=["video-panel"],
222
+ show_label=False,
223
+ show_download_button=False,
224
+ )
225
+
226
+ plot_outputs = []
227
+ gr.Markdown("### Hand Trajectories")
228
+ with gr.Column(elem_classes=["plots-wrap"]):
229
+ for row in PLOT_GRID:
230
+ with gr.Row():
231
+ for metric in row:
232
+ plot = gr.HTML(value=left_figs[metric], elem_classes=["plot-html"])
233
+ plot_outputs.append(plot)
234
+
235
+ def update_plots(hand_choice):
236
+ if hand_choice == "Left Hand":
237
+ figs = [left_figs[metric] for metric in PLOT_ORDER]
238
+ else:
239
+ figs = [right_figs[metric] for metric in PLOT_ORDER]
240
+ return figs
241
+
242
+ hand_radio.change(fn=update_plots, inputs=hand_radio, outputs=plot_outputs)
243
 
244
+ return demo
245
+
246
+ demo = build_interface()
 
 
 
 
247
 
248
  if __name__ == "__main__":
249
  demo.launch()