Muhammad Uzair Khattak commited on
Commit
1f7ccca
·
1 Parent(s): 9b218f7

Make Generate always run live, never serve the precomputed cache

Browse files

Previously an exact spec match on the Generate button would replay the
cached result instead of running the model, including for the default
configuration each tab opens on. That's fine for passive browsing (still
handled by _sync_results/_fp_sync_results and the page-load prefill,
unchanged) but meant the one deliberate action a visitor takes -- pressing
Generate -- could be a replay rather than a real run, undermining
replicability. run_demo_stream and run_future_demo no longer check the
cache at all; only browsing stays free, the click itself always costs GPU
time now. Drops the now-dead _cached_arm_updates helper and
CACHE_HIT_DELAY constant, and updates both precompute scripts' docstrings
to stop claiming Generate is ever free.

Files changed (2) hide show
  1. app.py +15 -52
  2. scripts/upload_precomputed_to_hub.py +5 -2
app.py CHANGED
@@ -171,9 +171,6 @@ TEXT_OUTPUT_LINES = 6
171
  # default configuration of each tab ships pre-generated -- but a visitor must
172
  # always be able to tell which is which.
173
  CACHED_BADGE = "cached"
174
- # Cache hits are effectively instant; a beat of delay is what makes the click
175
- # read as "it did something" rather than "the button is broken".
176
- CACHE_HIT_DELAY = 0.35
177
 
178
 
179
  def _save_to_mp4(video_array):
@@ -542,23 +539,6 @@ def _cleared_frame_updates():
542
  return updates
543
 
544
 
545
- def _cached_arm_updates(seed_value):
546
- """Arming frame for a cache hit. Deliberately NOT _loading_state_html --
547
- its "Inference has started — the first run can take an extra 1-2 minutes
548
- while tokenizers load" copy would
549
- be a lie here. The pause that follows is a button-press acknowledgement,
550
- not a fake generation: an instantaneous flip reads as a dead button."""
551
- updates = _reset_frame_updates(seed_value)
552
- updates[IDX_STATUS] = gr.update(value=_status_html("loading precomputed result"))
553
- updates[IDX_EMPTY] = gr.update(visible=True, value=(
554
- '<div class="empty-state loading-state">'
555
- f'<p class="mono" style="margin-bottom:6px;color:var(--text-2)">precomputed · seed {seed_value}</p>'
556
- "<p>Loading a saved result — no GPU time used.</p></div>"
557
- ))
558
- updates[IDX_BTN] = gr.update(value="Loading…", interactive=False)
559
- return updates
560
-
561
-
562
  def _frame(updates):
563
  out = [gr.skip()] * N_STREAM_OUTPUTS
564
  for idx, upd in updates.items():
@@ -1803,11 +1783,17 @@ with gr.Blocks(title="A2A-Video: Any-to-All Video Generation", theme=_THEME, css
1803
 
1804
  def run_demo_stream(src_mode, example_stem, upload_path, caption_text, abs_mod,
1805
  chain, seed_value, top_p, top_k, *hyperparam_values):
1806
- """Undecorated on purpose. Validation and the cache lookup run
1807
- here, on CPU; only a genuine miss reaches the GPU. That also
1808
- means a validation error surfaces with its real message --
1809
- spaces' worker wrapper replaces exception messages with a bare
1810
- "ZeroGPU worker error"."""
 
 
 
 
 
 
1811
  try:
1812
  req = resolve_a2a(src_mode, example_stem, upload_path, caption_text,
1813
  abs_mod, chain, seed_value, top_p, top_k,
@@ -1815,14 +1801,7 @@ with gr.Blocks(title="A2A-Video: Any-to-All Video Generation", theme=_THEME, css
1815
  except ValueError as e:
1816
  raise gr.Error(str(e))
1817
 
1818
- entry = _CACHE.lookup(req.spec)
1819
- if entry is not None:
1820
- yield _frame(_cached_arm_updates(req.seed))
1821
- time.sleep(CACHE_HIT_DELAY)
1822
- yield _cached_a2a_frames(req, entry)
1823
- return
1824
-
1825
- # Miss. Arm the UI before asking for a GPU, so the spinner is
1826
  # already up during the ZeroGPU queue wait.
1827
  yield _frame(_reset_frame_updates(req.seed))
1828
  yield from _run_demo_stream_gpu(req.input_modality, req.chain, req.gen_kwargs,
@@ -2300,8 +2279,9 @@ with gr.Blocks(title="A2A-Video: Any-to-All Video Generation", theme=_THEME, css
2300
 
2301
  def run_future_demo(example_stem, obs_mod, seed_tokens, cond_mode, cond_mod, steer_text, targets,
2302
  seed_value, top_p, top_k, complete_seed, *hyperparam_values):
2303
- """Undecorated: validation and cache lookup on CPU, GPU only on
2304
- a miss (see run_demo_stream)."""
 
2305
  try:
2306
  req = resolve_fp(example_stem, obs_mod, seed_tokens, cond_mode, cond_mod,
2307
  steer_text, targets, seed_value, top_p, top_k,
@@ -2310,23 +2290,6 @@ with gr.Blocks(title="A2A-Video: Any-to-All Video Generation", theme=_THEME, css
2310
  except ValueError as e:
2311
  raise gr.Error(str(e))
2312
 
2313
- entry = _CACHE.lookup(req.spec)
2314
- if entry is not None:
2315
- yield _fp_frame(_fp_arm_updates(
2316
- req.seed, "loading precomputed result",
2317
- '<div class="empty-state loading-state">'
2318
- f'<p class="mono" style="margin-bottom:6px;color:var(--text-2)">precomputed · seed {req.seed}</p>'
2319
- "<p>Loading a saved result — no GPU time used.</p></div>",
2320
- "Loading…",
2321
- ))
2322
- time.sleep(CACHE_HIT_DELAY)
2323
- results = _CACHE.resolve_results(entry)
2324
- cards = _fp_cards(req.obs_mod, req.extra, req.chain, req.seed_tokens,
2325
- results, req.steer_text, complete_seed=req.complete_seed)
2326
- yield _fp_frame(_fp_final_updates(
2327
- cards, f"precomputed · seed {req.seed}", "Predict again", CACHED_BADGE))
2328
- return
2329
-
2330
  yield _fp_frame(_fp_arm_updates(
2331
  req.seed, f"warming up · seed {req.seed}",
2332
  _loading_state_html(req.seed), "Predicting…"))
 
171
  # default configuration of each tab ships pre-generated -- but a visitor must
172
  # always be able to tell which is which.
173
  CACHED_BADGE = "cached"
 
 
 
174
 
175
 
176
  def _save_to_mp4(video_array):
 
539
  return updates
540
 
541
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
542
  def _frame(updates):
543
  out = [gr.skip()] * N_STREAM_OUTPUTS
544
  for idx, upd in updates.items():
 
1783
 
1784
  def run_demo_stream(src_mode, example_stem, upload_path, caption_text, abs_mod,
1785
  chain, seed_value, top_p, top_k, *hyperparam_values):
1786
+ """Undecorated on purpose. Validation runs here, on CPU. That
1787
+ also means a validation error surfaces with its real message
1788
+ -- spaces' worker wrapper replaces exception messages with a
1789
+ bare "ZeroGPU worker error".
1790
+
1791
+ Deliberately does NOT serve the precomputed cache, even on an
1792
+ exact spec match: pressing Generate is the one action that
1793
+ should always be a real, replicable run of the model, not a
1794
+ replay -- the cache still fronts every other configuration
1795
+ (see _sync_results/the page-load prefill), so browsing stays
1796
+ free; only the click itself always costs GPU time."""
1797
  try:
1798
  req = resolve_a2a(src_mode, example_stem, upload_path, caption_text,
1799
  abs_mod, chain, seed_value, top_p, top_k,
 
1801
  except ValueError as e:
1802
  raise gr.Error(str(e))
1803
 
1804
+ # Arm the UI before asking for a GPU, so the spinner is
 
 
 
 
 
 
 
1805
  # already up during the ZeroGPU queue wait.
1806
  yield _frame(_reset_frame_updates(req.seed))
1807
  yield from _run_demo_stream_gpu(req.input_modality, req.chain, req.gen_kwargs,
 
2279
 
2280
  def run_future_demo(example_stem, obs_mod, seed_tokens, cond_mode, cond_mod, steer_text, targets,
2281
  seed_value, top_p, top_k, complete_seed, *hyperparam_values):
2282
+ """Undecorated: validation on CPU, GPU always follows (see
2283
+ run_demo_stream -- pressing Generate never serves the cache,
2284
+ on purpose)."""
2285
  try:
2286
  req = resolve_fp(example_stem, obs_mod, seed_tokens, cond_mode, cond_mod,
2287
  steer_text, targets, seed_value, top_p, top_k,
 
2290
  except ValueError as e:
2291
  raise gr.Error(str(e))
2292
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2293
  yield _fp_frame(_fp_arm_updates(
2294
  req.seed, f"warming up · seed {req.seed}",
2295
  _loading_state_html(req.seed), "Predicting…"))
scripts/upload_precomputed_to_hub.py CHANGED
@@ -6,8 +6,11 @@ scripts/precompute_demo_outputs.py, which produces the folder this uploads).
6
  Why precompute at all: ZeroGPU gives free-tier Space visitors a few minutes of
7
  GPU per day, and load_pipeline's ~37.5 GB of checkpoints is loaded from inside
8
  that allocation. Shipping the default configuration of each tab pre-generated
9
- means the demo shows real predictions the moment it opens, and clicking
10
- Generate without changing anything costs no quota.
 
 
 
11
 
12
  The folder is uploaded VERBATIM under the `precomputed/` prefix of the same
13
  dataset repo that already holds the example tokens and previews:
 
6
  Why precompute at all: ZeroGPU gives free-tier Space visitors a few minutes of
7
  GPU per day, and load_pipeline's ~37.5 GB of checkpoints is loaded from inside
8
  that allocation. Shipping the default configuration of each tab pre-generated
9
+ means the demo shows real predictions the moment it opens, and browsing any
10
+ other precomputed clip/chain/modality shows its result instantly too, at no
11
+ GPU cost. Pressing Generate always runs live regardless -- the app never
12
+ serves this cache from the Generate button itself, only from passively
13
+ switching between configurations.
14
 
15
  The folder is uploaded VERBATIM under the `precomputed/` prefix of the same
16
  dataset repo that already holds the example tokens and previews: