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

Add 2K/4K resolution selector to Advanced Settings

Browse files

- Add `_resolve_output_dimensions` helper to encapsulate max_dim parsing
- Wire `max_output_dim` hidden Gradio Textbox (defaults to MAX_OUTPUT_DIM) through infer
- Add res-btn toggle group in Advanced Settings panel (HTML + CSS)
- Track selection in `window.__setResolution` / `window.__selectedMaxDim` (gallery.js)
- Pass selected resolution through run_preprocess.js to the backend

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

app.py CHANGED
@@ -263,6 +263,11 @@ def _resolve_seed(seed: int, randomize_seed: bool) -> int:
263
  return random.randint(0, MAX_SEED) if randomize_seed else seed
264
 
265
 
 
 
 
 
 
266
  def _spawn_log(pil_images, result_image, prompt, seed, steps, guidance_scale,
267
  width, height, duration, success, error=""):
268
  threading.Thread(
@@ -298,7 +303,7 @@ with open("templates/app.html") as _f:
298
  # ── Gradio blocks ──────────────────────────────────────────────────────────────
299
 
300
  @spaces.GPU
301
- def infer(images_b64_json, prompt, seed, randomize_seed, guidance_scale, steps, progress=gr.Progress(track_tqdm=True)):
302
  _cuda_ok = torch.cuda.is_available()
303
  timer = _InferTimer(_cuda_ok)
304
  t0 = time.perf_counter()
@@ -327,7 +332,7 @@ def infer(images_b64_json, prompt, seed, randomize_seed, guidance_scale, steps,
327
 
328
  seed = _resolve_seed(seed, randomize_seed)
329
  generator = torch.Generator(device=device).manual_seed(seed)
330
- width, height = update_dimensions_on_upload(pil_images[0])
331
  print(f"[infer] input={pil_images[0].size}, output={width}x{height}, seed={seed}")
332
 
333
  # Per-step callback: syncs the GPU then records a CUDA event so elapsed_time()
@@ -387,6 +392,7 @@ with gr.Blocks() as demo:
387
  randomize_seed = gr.Checkbox(value=True, elem_id="gradio-randomize", elem_classes="hidden-input", container=False)
388
  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)
389
  steps = gr.Slider(minimum=1, maximum=50, step=1, value=4, elem_id="gradio-steps", elem_classes="hidden-input", container=False)
 
390
  result = gr.Image(elem_id="gradio-result", elem_classes="hidden-input", container=False, format="png")
391
 
392
  example_idx = gr.Textbox(value="", elem_id="example-idx-input", elem_classes="hidden-input", container=False)
@@ -402,7 +408,7 @@ with gr.Blocks() as demo:
402
 
403
  run_btn.click(
404
  fn=infer,
405
- inputs=[hidden_images_b64, prompt, seed, randomize_seed, guidance_scale, steps],
406
  outputs=[result, seed],
407
  js=run_preprocess_js,
408
  )
 
263
  return random.randint(0, MAX_SEED) if randomize_seed else seed
264
 
265
 
266
+ def _resolve_output_dimensions(image: Image.Image, max_output_dim) -> tuple:
267
+ max_dim = int(max_output_dim) if str(max_output_dim).strip() else MAX_OUTPUT_DIM
268
+ return compute_output_dimensions(*image.size, max_dim=max_dim)
269
+
270
+
271
  def _spawn_log(pil_images, result_image, prompt, seed, steps, guidance_scale,
272
  width, height, duration, success, error=""):
273
  threading.Thread(
 
303
  # ── Gradio blocks ──────────────────────────────────────────────────────────────
304
 
305
  @spaces.GPU
306
+ def infer(images_b64_json, prompt, seed, randomize_seed, guidance_scale, steps, max_output_dim, progress=gr.Progress(track_tqdm=True)):
307
  _cuda_ok = torch.cuda.is_available()
308
  timer = _InferTimer(_cuda_ok)
309
  t0 = time.perf_counter()
 
332
 
333
  seed = _resolve_seed(seed, randomize_seed)
334
  generator = torch.Generator(device=device).manual_seed(seed)
335
+ width, height = _resolve_output_dimensions(pil_images[0], max_output_dim)
336
  print(f"[infer] input={pil_images[0].size}, output={width}x{height}, seed={seed}")
337
 
338
  # Per-step callback: syncs the GPU then records a CUDA event so elapsed_time()
 
392
  randomize_seed = gr.Checkbox(value=True, elem_id="gradio-randomize", elem_classes="hidden-input", container=False)
393
  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)
394
  steps = gr.Slider(minimum=1, maximum=50, step=1, value=4, elem_id="gradio-steps", elem_classes="hidden-input", container=False)
395
+ max_output_dim = gr.Textbox(value=str(MAX_OUTPUT_DIM), elem_id="gradio-max-output-dim", elem_classes="hidden-input", container=False)
396
  result = gr.Image(elem_id="gradio-result", elem_classes="hidden-input", container=False, format="png")
397
 
398
  example_idx = gr.Textbox(value="", elem_id="example-idx-input", elem_classes="hidden-input", container=False)
 
408
 
409
  run_btn.click(
410
  fn=infer,
411
+ inputs=[hidden_images_b64, prompt, seed, randomize_seed, guidance_scale, steps, max_output_dim],
412
  outputs=[result, seed],
413
  js=run_preprocess_js,
414
  )
static/app.css CHANGED
@@ -301,6 +301,16 @@ body:not(.dark) #custom-run-btn *{color:#ffffff!important;-webkit-text-fill-colo
301
  .checkbox-row{display:flex;align-items:center;gap:8px;font-size:13px;color:#a1a1aa}
302
  .checkbox-row input[type="checkbox"]{accent-color:#ff0080;width:16px;height:16px;cursor:pointer}
303
  .checkbox-row label{color:#a1a1aa;font-size:13px;cursor:pointer}
 
 
 
 
 
 
 
 
 
 
304
 
305
  .app-statusbar{
306
  background:#280018;border-top:1px solid #4d0030;padding:6px 20px;
 
301
  .checkbox-row{display:flex;align-items:center;gap:8px;font-size:13px;color:#a1a1aa}
302
  .checkbox-row input[type="checkbox"]{accent-color:#ff0080;width:16px;height:16px;cursor:pointer}
303
  .checkbox-row label{color:#a1a1aa;font-size:13px;cursor:pointer}
304
+ .res-row{display:flex;align-items:center;gap:10px;min-height:28px}
305
+ .res-row label{font-size:13px;font-weight:500;color:#a1a1aa;min-width:72px;flex-shrink:0}
306
+ .res-btn-group{display:flex;gap:4px}
307
+ .res-btn{
308
+ padding:4px 16px;font-size:12px;font-weight:600;border-radius:6px;cursor:pointer;
309
+ border:1px solid #4d0030;background:transparent;color:#71717a;
310
+ font-family:'Inter',sans-serif;transition:all .15s;
311
+ }
312
+ .res-btn.active{background:rgba(255,0,128,.2);border-color:rgba(255,0,128,.5);color:#ff4da6}
313
+ .res-btn:hover:not(.active){background:rgba(255,0,128,.1);border-color:rgba(255,0,128,.3);color:#a1a1aa}
314
 
315
  .app-statusbar{
316
  background:#280018;border-top:1px solid #4d0030;padding:6px 20px;
static/gallery.js CHANGED
@@ -282,6 +282,13 @@ function init() {
282
 
283
  if (runBtnEl) runBtnEl.addEventListener('click', () => window.__clickGradioRunBtn());
284
 
 
 
 
 
 
 
 
285
  renderGallery();
286
  updateCounts();
287
  }
 
282
 
283
  if (runBtnEl) runBtnEl.addEventListener('click', () => window.__clickGradioRunBtn());
284
 
285
+ window.__selectedMaxDim = 2048;
286
+ window.__setResolution = function(dim, btn) {
287
+ window.__selectedMaxDim = dim;
288
+ document.querySelectorAll('.res-btn').forEach(b => b.classList.remove('active'));
289
+ if (btn) btn.classList.add('active');
290
+ };
291
+
292
  renderGallery();
293
  updateCounts();
294
  }
static/run_preprocess.js CHANGED
@@ -1,8 +1,9 @@
1
- (imgs, p, s, rs, gs, st) => {
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
- return [imgsJson, promptVal, s, rs, gs, st];
 
8
  }
 
1
+ (imgs, p, s, rs, gs, st, mod) => {
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 maxDim = String(window.__selectedMaxDim || 2048);
8
+ return [imgsJson, promptVal, s, rs, gs, st, maxDim];
9
  }
templates/app.html CHANGED
@@ -123,6 +123,13 @@
123
  <div class="settings-group">
124
  <div class="settings-group-title">Advanced Settings</div>
125
  <div class="settings-group-body">
 
 
 
 
 
 
 
126
  <div class="slider-row">
127
  <label>Seed</label>
128
  <input type="range" id="custom-seed" min="0" max="2147483647" step="1" value="0">
 
123
  <div class="settings-group">
124
  <div class="settings-group-title">Advanced Settings</div>
125
  <div class="settings-group-body">
126
+ <div class="res-row">
127
+ <label>Resolution</label>
128
+ <div class="res-btn-group">
129
+ <button type="button" class="res-btn active" onclick="window.__setResolution(2048, this)">2K</button>
130
+ <button type="button" class="res-btn" onclick="window.__setResolution(4096, this)">4K</button>
131
+ </div>
132
+ </div>
133
  <div class="slider-row">
134
  <label>Seed</label>
135
  <input type="range" id="custom-seed" min="0" max="2147483647" step="1" value="0">