multimodalart HF Staff commited on
Commit
795963b
·
verified ·
1 Parent(s): 093adbd

Multi-user concurrency: compose outside the GPU queue, parallel assists/examples/videos

Browse files

Simple mode ran the composer LLM call inside the concurrency_id="gpu" (limit 1) event, so after clicking Generate the LLM request did not even START until every queued song from other users finished — the delay users are reporting. Also, Gradio's default concurrency limit is 1 per function, so one user's assist/example/video blocked everyone else's.

- Simple flow split: simple_compose (limit 8, starts immediately) -> .success -> studio_generate on the GPU queue. Status shows 'waiting for a GPU slot' between the two.
- compose_assist: limit 8. render_video: limit 4. load_example (cached files): unlimited.
- player.stop cancels the compose step too.

API note: the /simple_generate endpoint is replaced by /simple_compose + the chained sing step.

Files changed (1) hide show
  1. app.py +23 -16
app.py CHANGED
@@ -1533,19 +1533,21 @@ def compose_assist(raw_state, duration):
1533
  return state, "Lyrics & structured prompt ready — review and tweak them, then press Generate."
1534
 
1535
 
1536
- def simple_generate(state, duration, seed, randomize_seed, headroom, steps, guidance):
1537
- # One event so the output components engage (spinner) from the first click, through composing and singing.
 
1538
  state = _normalize_state(state)
1539
  description = _composed_description(state)
1540
  title = state["title"] or state["description"]
1541
- yield gr.skip(), "writing lyrics & structured prompt...", gr.skip(), gr.skip(), gr.skip(), title
1542
  lyr, gm, vd, arr = compose_song(description, duration)
1543
  state.update(lyrics=lyr, global_meta=gm, vocals=vd, arrangement=arr)
1544
- yield {"cmd": "status", "text": "Lyrics ready — acquiring ZeroGPU..."}, "lyrics ready — acquiring ZeroGPU...", gr.skip(), gr.skip(), state, gr.skip()
1545
- for audio, status, wav, used_seed in generate(
1546
- description, lyr, gm, vd, arr, duration, seed, randomize_seed, headroom, steps, guidance
1547
- ):
1548
- yield audio, status, wav, used_seed, gr.skip(), gr.skip()
 
1549
 
1550
 
1551
  def studio_generate(state, duration, seed, randomize_seed, headroom, steps, guidance):
@@ -1618,12 +1620,17 @@ with gr.Blocks(theme=gr.themes.Citrus(), css=CSS) as demo:
1618
 
1619
  _knobs = [duration, seed, randomize_seed, headroom, steps, guidance]
1620
 
1621
- ev_simple = composer.submit(lambda: ({"cmd": "reset", "loader": True, "status": "Writing lyrics & structured prompt with MiniMax-M3...", "nonce": random.random()}, None), None, [player, video_out]).then(
1622
- simple_generate, [composer] + _knobs,
1623
- [player, stats, wav_state, seed, composer, video_title],
 
 
 
 
 
1624
  concurrency_limit=1, concurrency_id="gpu", show_progress="minimal",
1625
  )
1626
- ev_simple.then(render_video, [wav_state, video_title], video_out).then(
1627
  lambda s: s.replace(" — rendering share video...", " — share video ready."), stats, stats
1628
  )
1629
 
@@ -1632,18 +1639,18 @@ with gr.Blocks(theme=gr.themes.Citrus(), css=CSS) as demo:
1632
  [player, stats, wav_state, seed, video_title],
1633
  concurrency_limit=1, concurrency_id="gpu", show_progress="minimal",
1634
  )
1635
- ev_studio.then(render_video, [wav_state, video_title], video_out).then(
1636
  lambda s: s.replace(" — rendering share video...", " — share video ready."), stats, stats
1637
  )
1638
 
1639
  player.stop(
1640
  lambda: "stopped — kept the part that was already streamed.", None, stats,
1641
- cancels=[ev_simple, ev_studio], show_progress="hidden",
1642
  )
1643
 
1644
- composer.edit(compose_assist, [composer, duration], [composer, stats], show_progress="minimal")
1645
 
1646
- composer.apply(load_example, [composer], [composer, player, stats, video_out, wav_state, video_title], show_progress="minimal")
1647
 
1648
  if __name__ == "__main__":
1649
  demo.launch()
 
1533
  return state, "Lyrics & structured prompt ready — review and tweak them, then press Generate."
1534
 
1535
 
1536
+ def simple_compose(state, duration):
1537
+ # Composing is a plain LLM API call, so it runs OUTSIDE the GPU queue: it starts the moment the user
1538
+ # clicks instead of waiting behind every queued song. The singing step chains after it on the GPU queue.
1539
  state = _normalize_state(state)
1540
  description = _composed_description(state)
1541
  title = state["title"] or state["description"]
1542
+ yield gr.skip(), "writing lyrics & structured prompt...", gr.skip(), title
1543
  lyr, gm, vd, arr = compose_song(description, duration)
1544
  state.update(lyrics=lyr, global_meta=gm, vocals=vd, arrangement=arr)
1545
+ yield (
1546
+ {"cmd": "status", "text": "Lyrics ready — waiting for a GPU slot..."},
1547
+ "lyrics ready waiting for a GPU slot...",
1548
+ state,
1549
+ gr.skip(),
1550
+ )
1551
 
1552
 
1553
  def studio_generate(state, duration, seed, randomize_seed, headroom, steps, guidance):
 
1620
 
1621
  _knobs = [duration, seed, randomize_seed, headroom, steps, guidance]
1622
 
1623
+ ev_compose = composer.submit(lambda: ({"cmd": "reset", "loader": True, "status": "Writing lyrics & structured prompt with MiniMax-M3...", "nonce": random.random()}, None), None, [player, video_out]).then(
1624
+ simple_compose, [composer, duration],
1625
+ [player, stats, composer, video_title],
1626
+ concurrency_limit=8, show_progress="minimal",
1627
+ )
1628
+ ev_simple = ev_compose.success(
1629
+ studio_generate, [composer] + _knobs,
1630
+ [player, stats, wav_state, seed, video_title],
1631
  concurrency_limit=1, concurrency_id="gpu", show_progress="minimal",
1632
  )
1633
+ ev_simple.then(render_video, [wav_state, video_title], video_out, concurrency_limit=4).then(
1634
  lambda s: s.replace(" — rendering share video...", " — share video ready."), stats, stats
1635
  )
1636
 
 
1639
  [player, stats, wav_state, seed, video_title],
1640
  concurrency_limit=1, concurrency_id="gpu", show_progress="minimal",
1641
  )
1642
+ ev_studio.then(render_video, [wav_state, video_title], video_out, concurrency_limit=4).then(
1643
  lambda s: s.replace(" — rendering share video...", " — share video ready."), stats, stats
1644
  )
1645
 
1646
  player.stop(
1647
  lambda: "stopped — kept the part that was already streamed.", None, stats,
1648
+ cancels=[ev_compose, ev_simple, ev_studio], show_progress="hidden",
1649
  )
1650
 
1651
+ composer.edit(compose_assist, [composer, duration], [composer, stats], concurrency_limit=8, show_progress="minimal")
1652
 
1653
+ composer.apply(load_example, [composer], [composer, player, stats, video_out, wav_state, video_title], concurrency_limit=None, show_progress="minimal")
1654
 
1655
  if __name__ == "__main__":
1656
  demo.launch()