FeilongTang commited on
Commit
bb0f4d9
Β·
1 Parent(s): 82a1045

Replace bottom Examples + top stats card with one demo button

Browse files

- Remove the 'Run summary' tile card at the top of the output
column; the four output panels (vis video, charts, canvas,
raw JSON accordion) are enough.
- Remove the bottom 'Demo video' card with three example rows;
sat awkwardly below the layout.
- Add a single 'Load demo video' button right under the upload
widget in the Input card. One click fills every control with
a curated preset (sbs Β· combined Β· log Β· GOP=dynamic Β· 1024
patches) and loads the bundled demo clip.
- Button is hidden when examples/demo_codec_heatmap.mp4 is
missing so the UI degrades cleanly on stripped checkouts.
- process() is back to its 4-output signature.

Files changed (1) hide show
  1. app.py +40 -113
app.py CHANGED
@@ -40,6 +40,26 @@ import numpy as np
40
 
41
  PATCH_CHOICES = [14, 16, 28]
42
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
43
 
44
  def smart_resize(frame: np.ndarray, max_pixels: int, factor: int) -> np.ndarray:
45
  """Resize so h,w are multiples of `factor` and h*w <= max_pixels."""
@@ -452,41 +472,6 @@ def pack_canvas(
452
  return canvas, n
453
 
454
 
455
- def render_stats_html(
456
- *, total_selected: int, n_groups: int, gop_label: str,
457
- n_sampled: int, total_frames: int, canvas_resolution: str,
458
- saliency_signal: str, score_log_scale: bool, elapsed_sec: float,
459
- grid_label: str, n_uniform: int, codec: str = "",
460
- ) -> str:
461
- """Format the run's headline numbers as a grid of brand-colored tiles."""
462
- sig = saliency_signal + (" Β· log" if score_log_scale else "")
463
- gop_disp = (
464
- gop_label if gop_label in ("global", "dynamic") else f"GOP={gop_label}"
465
- )
466
- cells = [
467
- ("selected patches", f"{total_selected:,}"),
468
- ("groups", f"{n_groups} Β· {gop_disp}"),
469
- ("sampled frames", f"{n_sampled} / {total_frames}"),
470
- ("canvas", canvas_resolution),
471
- ("uniform baseline", f"{n_uniform} frame{'s' if n_uniform != 1 else ''}"),
472
- ("saliency", sig),
473
- ("patch grid / frame", grid_label),
474
- ("elapsed", f"{elapsed_sec:.2f}s"),
475
- ]
476
- if codec:
477
- cells.insert(2, ("input codec", codec))
478
- parts = ['<div class="ovc-stats">']
479
- for label, value in cells:
480
- parts.append(
481
- f'<div class="ovc-stat">'
482
- f'<div class="value">{value}</div>'
483
- f'<div class="label">{label}</div>'
484
- f'</div>'
485
- )
486
- parts.append("</div>")
487
- return "".join(parts)
488
-
489
-
490
  def make_charts(
491
  grids: List[np.ndarray],
492
  masks: List[np.ndarray],
@@ -609,7 +594,7 @@ def process(
609
  progress=gr.Progress(track_tqdm=False),
610
  ):
611
  if not video_path:
612
- return None, None, "Please upload a video.", None, EMPTY_STATS
613
 
614
  t0 = time.time()
615
  progress(0.05, desc="Reading metadata")
@@ -619,7 +604,7 @@ def process(
619
  return None, None, json.dumps(
620
  {"error": "Could not read frame count.", "metadata": meta},
621
  indent=2, ensure_ascii=False,
622
- ), None, EMPTY_STATS
623
 
624
  progress(0.10, desc="Sampling frames")
625
  fps = float(meta.get("fps") or 0.0)
@@ -649,7 +634,7 @@ def process(
649
  return None, None, json.dumps(
650
  {"error": "Failed to decode frames.", "metadata": meta},
651
  indent=2, ensure_ascii=False,
652
- ), None, EMPTY_STATS
653
 
654
  progress(0.25, desc="smart_resize")
655
  resized = [smart_resize(f, int(max_pixels), int(patch_size)) for f in raw]
@@ -764,27 +749,11 @@ def process(
764
  groups=groups, gop_label=gop_resolved,
765
  )
766
 
767
- stats_html = render_stats_html(
768
- total_selected=int(actual_selected),
769
- n_groups=len(groups),
770
- gop_label=gop_resolved,
771
- n_sampled=len(fids),
772
- total_frames=int(total),
773
- canvas_resolution=f"{canvas.shape[1]}Γ—{canvas.shape[0]}",
774
- saliency_signal=saliency_signal,
775
- score_log_scale=bool(score_log_scale),
776
- elapsed_sec=round(time.time() - t0, 2),
777
- grid_label=f"{hb}Γ—{wb}",
778
- n_uniform=int(n_uniform),
779
- codec=str(meta.get("codec") or ""),
780
- )
781
-
782
  progress(1.0, desc="Done")
783
  return (
784
  vis_path, canvas_path,
785
  json.dumps(info, indent=2, ensure_ascii=False),
786
  chart_fig,
787
- stats_html,
788
  )
789
 
790
 
@@ -1203,20 +1172,6 @@ FLOW_HTML = """
1203
  </div>
1204
  """
1205
 
1206
- EMPTY_STATS = (
1207
- '<div class="ovc-stats">'
1208
- '<div class="ovc-stat" style="grid-column: 1 / -1; text-align:center; '
1209
- 'background: linear-gradient(135deg, rgba(79,70,229,0.04), rgba(6,182,212,0.03));">'
1210
- '<div class="value" style="font-size:1.05rem; font-weight:600; '
1211
- '-webkit-background-clip: initial; background-clip: initial; color: #64748b;">'
1212
- 'Hit <span style="background: var(--ovc-grad); -webkit-background-clip:text; '
1213
- 'background-clip:text; color:transparent;">Run pipeline</span>, '
1214
- 'or pick a row in <i>Demo video</i> below.'
1215
- '</div>'
1216
- '<div class="label" style="margin-top:6px;">key numbers will land here</div>'
1217
- '</div>'
1218
- '</div>'
1219
- )
1220
 
1221
 
1222
  with gr.Blocks(**_BLOCK_KW) as demo:
@@ -1229,6 +1184,11 @@ with gr.Blocks(**_BLOCK_KW) as demo:
1229
  with gr.Group(elem_classes="ovc-card"):
1230
  gr.Markdown("### Input")
1231
  video_in = gr.Video(label="Video", sources=["upload"], height=240)
 
 
 
 
 
1232
 
1233
  with gr.Group(elem_classes="ovc-card"):
1234
  gr.Markdown("### Pipeline")
@@ -1321,10 +1281,6 @@ with gr.Blocks(**_BLOCK_KW) as demo:
1321
 
1322
  # ─── Outputs (wide column) ───────────────────────────────────────
1323
  with gr.Column(scale=6, min_width=420):
1324
- with gr.Group(elem_classes="ovc-card ovc-card-primary"):
1325
- gr.Markdown("### Run summary")
1326
- stats_out = gr.HTML(value=EMPTY_STATS)
1327
-
1328
  with gr.Group(elem_classes="ovc-card ovc-card-primary"):
1329
  gr.Markdown("### Patch selection visualization")
1330
  vis_out = gr.Video(
@@ -1363,46 +1319,6 @@ with gr.Blocks(**_BLOCK_KW) as demo:
1363
  label="", language="json", lines=18,
1364
  )
1365
 
1366
- DEMO_VIDEO = os.path.join(
1367
- os.path.dirname(os.path.abspath(__file__)),
1368
- "examples", "demo_codec_heatmap.mp4",
1369
- )
1370
- if os.path.exists(DEMO_VIDEO):
1371
- with gr.Group(elem_classes="ovc-card"):
1372
- gr.Markdown("### Demo video")
1373
- gr.Markdown(
1374
- "<small>Click any row below to load the bundled clip with a "
1375
- "preset configuration. Or upload your own video at the top.</small>"
1376
- )
1377
- gr.Examples(
1378
- examples=[
1379
- [
1380
- DEMO_VIDEO, 16, 14, 1024, 150000,
1381
- "selection", 0.55, 0.0, 0.0,
1382
- "gradient", False, 99.0, 0.55, "global",
1383
- ],
1384
- [
1385
- DEMO_VIDEO, 16, 14, 1024, 150000,
1386
- "heatmap", 0.55, 0.0, 0.0,
1387
- "combined", True, 96.0, 0.55, "dynamic",
1388
- ],
1389
- [
1390
- DEMO_VIDEO, 24, 14, 2048, 150000,
1391
- "sbs", 0.55, 0.0, 0.0,
1392
- "combined", True, 95.0, 0.55, "8",
1393
- ],
1394
- ],
1395
- inputs=[
1396
- video_in, sample_frames, patch_size, top_k, max_pixels,
1397
- viz_mode, heatmap_alpha, start_sec, end_sec,
1398
- saliency_signal, score_log_scale, bitcost_pct,
1399
- fade_strength, gop,
1400
- ],
1401
- label="",
1402
- cache_examples=False,
1403
- examples_per_page=5,
1404
- )
1405
-
1406
  gr.HTML(
1407
  '<div id="ovc-footer">'
1408
  '<b>OneVision Encoder</b> Β· codec-style patch saliency demo Β· '
@@ -1432,7 +1348,18 @@ with gr.Blocks(**_BLOCK_KW) as demo:
1432
  saliency_signal, score_log_scale, bitcost_pct, fade_strength,
1433
  gop,
1434
  ],
1435
- outputs=[vis_out, canvas_out, info_out, chart_out, stats_out],
 
 
 
 
 
 
 
 
 
 
 
1436
  )
1437
 
1438
 
 
40
 
41
  PATCH_CHOICES = [14, 16, 28]
42
 
43
+ DEMO_VIDEO_PATH = os.path.join(
44
+ os.path.dirname(os.path.abspath(__file__)),
45
+ "examples", "demo_codec_heatmap.mp4",
46
+ )
47
+ DEMO_PRESET = (
48
+ DEMO_VIDEO_PATH, # video_in
49
+ 16, # sample_frames
50
+ 14, # patch_size
51
+ 1024, # total_patches
52
+ 150000, # max_pixels
53
+ "sbs", # viz_mode
54
+ 0.55, # heatmap_alpha
55
+ 0.0, 0.0, # start_sec, end_sec
56
+ "combined", # saliency_signal
57
+ True, # score_log_scale
58
+ 96.0, # bitcost_pct
59
+ 0.55, # fade_strength
60
+ "dynamic", # gop
61
+ )
62
+
63
 
64
  def smart_resize(frame: np.ndarray, max_pixels: int, factor: int) -> np.ndarray:
65
  """Resize so h,w are multiples of `factor` and h*w <= max_pixels."""
 
472
  return canvas, n
473
 
474
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
475
  def make_charts(
476
  grids: List[np.ndarray],
477
  masks: List[np.ndarray],
 
594
  progress=gr.Progress(track_tqdm=False),
595
  ):
596
  if not video_path:
597
+ return None, None, "Please upload a video.", None
598
 
599
  t0 = time.time()
600
  progress(0.05, desc="Reading metadata")
 
604
  return None, None, json.dumps(
605
  {"error": "Could not read frame count.", "metadata": meta},
606
  indent=2, ensure_ascii=False,
607
+ ), None
608
 
609
  progress(0.10, desc="Sampling frames")
610
  fps = float(meta.get("fps") or 0.0)
 
634
  return None, None, json.dumps(
635
  {"error": "Failed to decode frames.", "metadata": meta},
636
  indent=2, ensure_ascii=False,
637
+ ), None
638
 
639
  progress(0.25, desc="smart_resize")
640
  resized = [smart_resize(f, int(max_pixels), int(patch_size)) for f in raw]
 
749
  groups=groups, gop_label=gop_resolved,
750
  )
751
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
752
  progress(1.0, desc="Done")
753
  return (
754
  vis_path, canvas_path,
755
  json.dumps(info, indent=2, ensure_ascii=False),
756
  chart_fig,
 
757
  )
758
 
759
 
 
1172
  </div>
1173
  """
1174
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1175
 
1176
 
1177
  with gr.Blocks(**_BLOCK_KW) as demo:
 
1184
  with gr.Group(elem_classes="ovc-card"):
1185
  gr.Markdown("### Input")
1186
  video_in = gr.Video(label="Video", sources=["upload"], height=240)
1187
+ with gr.Row(elem_classes="ovc-preset"):
1188
+ btn_demo = gr.Button(
1189
+ "Load demo video", size="sm",
1190
+ visible=os.path.exists(DEMO_VIDEO_PATH),
1191
+ )
1192
 
1193
  with gr.Group(elem_classes="ovc-card"):
1194
  gr.Markdown("### Pipeline")
 
1281
 
1282
  # ─── Outputs (wide column) ───────────────────────────────────────
1283
  with gr.Column(scale=6, min_width=420):
 
 
 
 
1284
  with gr.Group(elem_classes="ovc-card ovc-card-primary"):
1285
  gr.Markdown("### Patch selection visualization")
1286
  vis_out = gr.Video(
 
1319
  label="", language="json", lines=18,
1320
  )
1321
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1322
  gr.HTML(
1323
  '<div id="ovc-footer">'
1324
  '<b>OneVision Encoder</b> Β· codec-style patch saliency demo Β· '
 
1348
  saliency_signal, score_log_scale, bitcost_pct, fade_strength,
1349
  gop,
1350
  ],
1351
+ outputs=[vis_out, canvas_out, info_out, chart_out],
1352
+ )
1353
+
1354
+ btn_demo.click(
1355
+ lambda: DEMO_PRESET,
1356
+ inputs=None,
1357
+ outputs=[
1358
+ video_in, sample_frames, patch_size, top_k, max_pixels,
1359
+ viz_mode, heatmap_alpha, start_sec, end_sec,
1360
+ saliency_signal, score_log_scale, bitcost_pct, fade_strength,
1361
+ gop,
1362
+ ],
1363
  )
1364
 
1365