someone-in-the-world Claude Sonnet 4.6 commited on
Commit
b36328a
·
1 Parent(s): c1f861c

Add user-adjustable GPU Duration slider to Advanced Settings

Browse files

Exposes the spaces.GPU duration as a UI slider (10–120s, step 5s) so
users can tune quota usage per request. Switching modes auto-resets the
slider to its default (fast=20s, high_detail=60s).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

app.py CHANGED
@@ -332,7 +332,7 @@ with open("templates/app.html") as _f:
332
 
333
  # ── Gradio blocks ──────────────────────────────────────────────────────────────
334
 
335
- def infer(images_b64_json, prompt, seed, randomize_seed, guidance_scale, steps, mode, progress=gr.Progress(track_tqdm=True)):
336
  # CPU-only preprocessing — GPU not yet allocated
337
  gc.collect()
338
  pil_images = b64_to_pil_list(images_b64_json)
@@ -341,7 +341,7 @@ def infer(images_b64_json, prompt, seed, randomize_seed, guidance_scale, steps,
341
  width, height = update_dimensions_on_upload(pil_images[0], max_dim_for_mode(mode))
342
  t0 = time.perf_counter()
343
  try:
344
- result_image, seed, duration = _infer_gpu(pil_images, prompt, seed, guidance_scale, steps, width, height, mode)
345
  # _spawn_log is called here (main process) so the thread survives after _infer_gpu's
346
  # @spaces.GPU subprocess exits — previously the daemon thread was killed on subprocess exit.
347
  _spawn_log(pil_images, result_image, prompt, seed, steps, guidance_scale, width, height, duration, True)
@@ -352,8 +352,8 @@ def infer(images_b64_json, prompt, seed, randomize_seed, guidance_scale, steps,
352
  raise
353
 
354
 
355
- @spaces.GPU(duration=lambda *a, **kw: 20 if (len(a) > 7 and a[7] == "fast") else 60)
356
- def _infer_gpu(pil_images, prompt, seed, guidance_scale, steps, width, height, mode):
357
  _cuda_ok = torch.cuda.is_available()
358
  timer = _InferTimer(_cuda_ok)
359
  t0 = time.perf_counter()
@@ -427,6 +427,7 @@ with gr.Blocks() as demo:
427
  guidance_scale = gr.Slider(minimum=1.0, maximum=10.0, step=0.1, value=1.0, elem_id="gradio-guidance", elem_classes="hidden-input", container=False)
428
  steps = gr.Slider(minimum=1, maximum=50, step=1, value=4, elem_id="gradio-steps", elem_classes="hidden-input", container=False)
429
  mode = gr.Textbox(value="fast", elem_id="gradio-mode", elem_classes="hidden-input", container=False)
 
430
  result = gr.Image(elem_id="gradio-result", elem_classes="hidden-input", container=False, format="png")
431
 
432
  example_idx = gr.Textbox(value="", elem_id="example-idx-input", elem_classes="hidden-input", container=False)
@@ -443,7 +444,7 @@ with gr.Blocks() as demo:
443
 
444
  run_btn.click(
445
  fn=infer,
446
- inputs=[hidden_images_b64, prompt, seed, randomize_seed, guidance_scale, steps, mode],
447
  outputs=[result, seed],
448
  js=run_preprocess_js,
449
  )
 
332
 
333
  # ── Gradio blocks ──────────────────────────────────────────────────────────────
334
 
335
+ def infer(images_b64_json, prompt, seed, randomize_seed, guidance_scale, steps, mode, gpu_duration=20, progress=gr.Progress(track_tqdm=True)):
336
  # CPU-only preprocessing — GPU not yet allocated
337
  gc.collect()
338
  pil_images = b64_to_pil_list(images_b64_json)
 
341
  width, height = update_dimensions_on_upload(pil_images[0], max_dim_for_mode(mode))
342
  t0 = time.perf_counter()
343
  try:
344
+ result_image, seed, duration = _infer_gpu(pil_images, prompt, seed, guidance_scale, steps, width, height, mode, int(gpu_duration))
345
  # _spawn_log is called here (main process) so the thread survives after _infer_gpu's
346
  # @spaces.GPU subprocess exits — previously the daemon thread was killed on subprocess exit.
347
  _spawn_log(pil_images, result_image, prompt, seed, steps, guidance_scale, width, height, duration, True)
 
352
  raise
353
 
354
 
355
+ @spaces.GPU(duration=lambda *a, **kw: int(a[8]) if len(a) > 8 else 60)
356
+ def _infer_gpu(pil_images, prompt, seed, guidance_scale, steps, width, height, mode, gpu_duration=20):
357
  _cuda_ok = torch.cuda.is_available()
358
  timer = _InferTimer(_cuda_ok)
359
  t0 = time.perf_counter()
 
427
  guidance_scale = gr.Slider(minimum=1.0, maximum=10.0, step=0.1, value=1.0, elem_id="gradio-guidance", elem_classes="hidden-input", container=False)
428
  steps = gr.Slider(minimum=1, maximum=50, step=1, value=4, elem_id="gradio-steps", elem_classes="hidden-input", container=False)
429
  mode = gr.Textbox(value="fast", elem_id="gradio-mode", elem_classes="hidden-input", container=False)
430
+ gpu_duration = gr.Slider(minimum=10, maximum=120, step=5, value=20, elem_id="gradio-gpu-duration", elem_classes="hidden-input", container=False)
431
  result = gr.Image(elem_id="gradio-result", elem_classes="hidden-input", container=False, format="png")
432
 
433
  example_idx = gr.Textbox(value="", elem_id="example-idx-input", elem_classes="hidden-input", container=False)
 
444
 
445
  run_btn.click(
446
  fn=infer,
447
+ inputs=[hidden_images_b64, prompt, seed, randomize_seed, guidance_scale, steps, mode, gpu_duration],
448
  outputs=[result, seed],
449
  js=run_preprocess_js,
450
  )
static/gallery.js CHANGED
@@ -234,6 +234,7 @@ function init() {
234
  syncSlider('custom-seed', 'gradio-seed');
235
  syncSlider('custom-guidance', 'gradio-guidance');
236
  syncSlider('custom-steps', 'gradio-steps');
 
237
 
238
  const randCheck = document.getElementById('custom-randomize');
239
  if (randCheck) {
 
234
  syncSlider('custom-seed', 'gradio-seed');
235
  syncSlider('custom-guidance', 'gradio-guidance');
236
  syncSlider('custom-steps', 'gradio-steps');
237
+ syncSlider('custom-gpu-duration', 'gradio-gpu-duration');
238
 
239
  const randCheck = document.getElementById('custom-randomize');
240
  if (randCheck) {
static/mode_toggle.js CHANGED
@@ -1,10 +1,18 @@
1
  () => {
2
  window.__selectedMode = 'fast';
 
3
  window.__setMode = function(m) {
4
  window.__selectedMode = m;
5
  var fast = document.getElementById('mode-btn-fast');
6
  var hd = document.getElementById('mode-btn-hd');
7
  if (fast) fast.classList.toggle('mode-btn-active', m === 'fast');
8
  if (hd) hd.classList.toggle('mode-btn-active', m === 'high_detail');
 
 
 
 
 
 
 
9
  };
10
  }
 
1
  () => {
2
  window.__selectedMode = 'fast';
3
+ var MODE_GPU_DURATION = { fast: 20, high_detail: 60 };
4
  window.__setMode = function(m) {
5
  window.__selectedMode = m;
6
  var fast = document.getElementById('mode-btn-fast');
7
  var hd = document.getElementById('mode-btn-hd');
8
  if (fast) fast.classList.toggle('mode-btn-active', m === 'fast');
9
  if (hd) hd.classList.toggle('mode-btn-active', m === 'high_detail');
10
+ var dur = MODE_GPU_DURATION[m];
11
+ if (dur !== undefined) {
12
+ var sl = document.getElementById('custom-gpu-duration');
13
+ var vl = document.getElementById('custom-gpu-duration-val');
14
+ if (sl) { sl.value = dur; sl.dispatchEvent(new Event('input', {bubbles: true})); }
15
+ if (vl) vl.textContent = dur;
16
+ }
17
  };
18
  }
static/run_preprocess.js CHANGED
@@ -1,9 +1,11 @@
1
- (imgs, p, s, rs, gs, st, m) => {
2
  const images = window.__uploadedImages || [];
3
  const b64Array = images.map(img => img.b64);
4
  const imgsJson = JSON.stringify(b64Array);
5
  const promptEl = document.getElementById('custom-prompt-input');
6
  const promptVal = promptEl ? promptEl.value : p;
7
  const mode = window.__selectedMode || 'fast';
8
- return [imgsJson, promptVal, s, rs, gs, st, mode];
 
 
9
  }
 
1
+ (imgs, p, s, rs, gs, st, m, gd) => {
2
  const images = window.__uploadedImages || [];
3
  const b64Array = images.map(img => img.b64);
4
  const imgsJson = JSON.stringify(b64Array);
5
  const promptEl = document.getElementById('custom-prompt-input');
6
  const promptVal = promptEl ? promptEl.value : p;
7
  const mode = window.__selectedMode || 'fast';
8
+ const gpuDurEl = document.getElementById('custom-gpu-duration');
9
+ const gpuDuration = gpuDurEl ? parseInt(gpuDurEl.value, 10) : gd;
10
+ return [imgsJson, promptVal, s, rs, gs, st, mode, gpuDuration];
11
  }
templates/app.html CHANGED
@@ -133,6 +133,11 @@
133
  <input type="range" id="custom-steps" min="1" max="50" step="1" value="4">
134
  <span class="slider-val" id="custom-steps-val">4</span>
135
  </div>
 
 
 
 
 
136
  </div>
137
  </div>
138
  </div>
 
133
  <input type="range" id="custom-steps" min="1" max="50" step="1" value="4">
134
  <span class="slider-val" id="custom-steps-val">4</span>
135
  </div>
136
+ <div class="slider-row">
137
+ <label>GPU Duration (s)</label>
138
+ <input type="range" id="custom-gpu-duration" min="10" max="120" step="5" value="20">
139
+ <span class="slider-val" id="custom-gpu-duration-val">20</span>
140
+ </div>
141
  </div>
142
  </div>
143
  </div>