Spaces:
Running on Zero
Running on Zero
Commit Β·
f333d01
1
Parent(s): 0ce14db
Add Fast / High-Detail mode toggle (768px vs 2048px output)
Browse filesCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- app.py +9 -7
- dimensions.py +1 -0
- static/app.css +13 -0
- static/run_preprocess.js +3 -2
- templates/app.html +14 -0
app.py
CHANGED
|
@@ -33,7 +33,7 @@ torch.backends.cudnn.allow_tf32 = True
|
|
| 33 |
print("[startup] TF32 enabled", flush=True)
|
| 34 |
|
| 35 |
print("[startup] importing dimensions...", flush=True)
|
| 36 |
-
from dimensions import compute_output_dimensions
|
| 37 |
print("[startup] importing diffusers...", flush=True)
|
| 38 |
from diffusers import FlowMatchEulerDiscreteScheduler
|
| 39 |
print("[startup] importing QwenImageEditPlusPipeline...", flush=True)
|
|
@@ -207,11 +207,11 @@ def b64_to_pil_list(b64_json_str):
|
|
| 207 |
return pil_images
|
| 208 |
|
| 209 |
|
| 210 |
-
def update_dimensions_on_upload(image):
|
| 211 |
if image is None:
|
| 212 |
-
return
|
| 213 |
w, h = image.size
|
| 214 |
-
return compute_output_dimensions(w, h)
|
| 215 |
|
| 216 |
|
| 217 |
class _InferTimer:
|
|
@@ -330,7 +330,7 @@ with open("templates/app.html") as _f:
|
|
| 330 |
# ββ Gradio blocks ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 331 |
|
| 332 |
@spaces.GPU
|
| 333 |
-
def infer(images_b64_json, prompt, seed, randomize_seed, guidance_scale, steps, progress=gr.Progress(track_tqdm=True)):
|
| 334 |
_cuda_ok = torch.cuda.is_available()
|
| 335 |
timer = _InferTimer(_cuda_ok)
|
| 336 |
t0 = time.perf_counter()
|
|
@@ -359,7 +359,8 @@ def infer(images_b64_json, prompt, seed, randomize_seed, guidance_scale, steps,
|
|
| 359 |
|
| 360 |
seed = _resolve_seed(seed, randomize_seed)
|
| 361 |
generator = torch.Generator(device=device).manual_seed(seed)
|
| 362 |
-
|
|
|
|
| 363 |
print(f"[infer] input={pil_images[0].size}, output={width}x{height}, seed={seed}")
|
| 364 |
|
| 365 |
# Per-step callback: syncs the GPU then records a CUDA event so elapsed_time()
|
|
@@ -419,6 +420,7 @@ with gr.Blocks() as demo:
|
|
| 419 |
randomize_seed = gr.Checkbox(value=True, elem_id="gradio-randomize", elem_classes="hidden-input", container=False)
|
| 420 |
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)
|
| 421 |
steps = gr.Slider(minimum=1, maximum=50, step=1, value=4, elem_id="gradio-steps", elem_classes="hidden-input", container=False)
|
|
|
|
| 422 |
result = gr.Image(elem_id="gradio-result", elem_classes="hidden-input", container=False, format="png")
|
| 423 |
|
| 424 |
example_idx = gr.Textbox(value="", elem_id="example-idx-input", elem_classes="hidden-input", container=False)
|
|
@@ -434,7 +436,7 @@ with gr.Blocks() as demo:
|
|
| 434 |
|
| 435 |
run_btn.click(
|
| 436 |
fn=infer,
|
| 437 |
-
inputs=[hidden_images_b64, prompt, seed, randomize_seed, guidance_scale, steps],
|
| 438 |
outputs=[result, seed],
|
| 439 |
js=run_preprocess_js,
|
| 440 |
)
|
|
|
|
| 33 |
print("[startup] TF32 enabled", flush=True)
|
| 34 |
|
| 35 |
print("[startup] importing dimensions...", flush=True)
|
| 36 |
+
from dimensions import compute_output_dimensions, MAX_OUTPUT_DIM_FAST
|
| 37 |
print("[startup] importing diffusers...", flush=True)
|
| 38 |
from diffusers import FlowMatchEulerDiscreteScheduler
|
| 39 |
print("[startup] importing QwenImageEditPlusPipeline...", flush=True)
|
|
|
|
| 207 |
return pil_images
|
| 208 |
|
| 209 |
|
| 210 |
+
def update_dimensions_on_upload(image, max_dim):
|
| 211 |
if image is None:
|
| 212 |
+
return max_dim, max_dim
|
| 213 |
w, h = image.size
|
| 214 |
+
return compute_output_dimensions(w, h, max_dim)
|
| 215 |
|
| 216 |
|
| 217 |
class _InferTimer:
|
|
|
|
| 330 |
# ββ Gradio blocks ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 331 |
|
| 332 |
@spaces.GPU
|
| 333 |
+
def infer(images_b64_json, prompt, seed, randomize_seed, guidance_scale, steps, mode="fast", progress=gr.Progress(track_tqdm=True)):
|
| 334 |
_cuda_ok = torch.cuda.is_available()
|
| 335 |
timer = _InferTimer(_cuda_ok)
|
| 336 |
t0 = time.perf_counter()
|
|
|
|
| 359 |
|
| 360 |
seed = _resolve_seed(seed, randomize_seed)
|
| 361 |
generator = torch.Generator(device=device).manual_seed(seed)
|
| 362 |
+
max_dim = MAX_OUTPUT_DIM_FAST if mode == "fast" else MAX_OUTPUT_DIM
|
| 363 |
+
width, height = update_dimensions_on_upload(pil_images[0], max_dim)
|
| 364 |
print(f"[infer] input={pil_images[0].size}, output={width}x{height}, seed={seed}")
|
| 365 |
|
| 366 |
# Per-step callback: syncs the GPU then records a CUDA event so elapsed_time()
|
|
|
|
| 420 |
randomize_seed = gr.Checkbox(value=True, elem_id="gradio-randomize", elem_classes="hidden-input", container=False)
|
| 421 |
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)
|
| 422 |
steps = gr.Slider(minimum=1, maximum=50, step=1, value=4, elem_id="gradio-steps", elem_classes="hidden-input", container=False)
|
| 423 |
+
mode = gr.Textbox(value="fast", elem_id="gradio-mode", elem_classes="hidden-input", container=False)
|
| 424 |
result = gr.Image(elem_id="gradio-result", elem_classes="hidden-input", container=False, format="png")
|
| 425 |
|
| 426 |
example_idx = gr.Textbox(value="", elem_id="example-idx-input", elem_classes="hidden-input", container=False)
|
|
|
|
| 436 |
|
| 437 |
run_btn.click(
|
| 438 |
fn=infer,
|
| 439 |
+
inputs=[hidden_images_b64, prompt, seed, randomize_seed, guidance_scale, steps, mode],
|
| 440 |
outputs=[result, seed],
|
| 441 |
js=run_preprocess_js,
|
| 442 |
)
|
dimensions.py
CHANGED
|
@@ -1,4 +1,5 @@
|
|
| 1 |
MAX_OUTPUT_DIM = 2048
|
|
|
|
| 2 |
|
| 3 |
|
| 4 |
def compute_output_dimensions(w, h, max_dim=MAX_OUTPUT_DIM):
|
|
|
|
| 1 |
MAX_OUTPUT_DIM = 2048
|
| 2 |
+
MAX_OUTPUT_DIM_FAST = 768
|
| 3 |
|
| 4 |
|
| 5 |
def compute_output_dimensions(w, h, max_dim=MAX_OUTPUT_DIM):
|
static/app.css
CHANGED
|
@@ -206,6 +206,19 @@ body:not(.dark) .modern-tb-btn .tb-svg,body:not(.dark) .modern-tb-btn .tb-svg *{
|
|
| 206 |
.toast-notification .toast-icon{font-size:16px;line-height:1}
|
| 207 |
.toast-notification .toast-text{line-height:1.3}
|
| 208 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 209 |
.btn-run{
|
| 210 |
display:flex;align-items:center;justify-content:center;gap:8px;width:100%;
|
| 211 |
background:linear-gradient(135deg,#ff0080,#cc0066);border:none;border-radius:10px;
|
|
|
|
| 206 |
.toast-notification .toast-icon{font-size:16px;line-height:1}
|
| 207 |
.toast-notification .toast-text{line-height:1.3}
|
| 208 |
|
| 209 |
+
.mode-toggle-wrap{display:flex;gap:8px;padding:8px 20px 0}
|
| 210 |
+
.mode-btn{
|
| 211 |
+
flex:1;padding:8px 12px;border-radius:8px;border:1px solid #4d0030;background:transparent;
|
| 212 |
+
cursor:pointer;font-size:13px;font-weight:600;font-family:'Inter',sans-serif;
|
| 213 |
+
color:#a1a1aa;transition:all .2s ease;
|
| 214 |
+
}
|
| 215 |
+
.mode-btn-active{
|
| 216 |
+
background:linear-gradient(135deg,#ff0080,#cc0066);border-color:transparent;
|
| 217 |
+
color:#ffffff!important;-webkit-text-fill-color:#ffffff!important;
|
| 218 |
+
box-shadow:0 2px 8px rgba(255,0,128,.35);
|
| 219 |
+
}
|
| 220 |
+
.mode-btn:not(.mode-btn-active):hover{border-color:#ff0080;color:#ff0080}
|
| 221 |
+
|
| 222 |
.btn-run{
|
| 223 |
display:flex;align-items:center;justify-content:center;gap:8px;width:100%;
|
| 224 |
background:linear-gradient(135deg,#ff0080,#cc0066);border:none;border-radius:10px;
|
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 |
-
|
|
|
|
| 8 |
}
|
|
|
|
| 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 |
}
|
templates/app.html
CHANGED
|
@@ -82,6 +82,11 @@
|
|
| 82 |
</div>
|
| 83 |
</div>
|
| 84 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 85 |
<div style="padding:12px 20px;">
|
| 86 |
<button id="custom-run-btn" class="btn-run">
|
| 87 |
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M12 23c-3.6 0-8-2.69-8-7.5 0-3.5 3-6.5 4.5-8 .27-.27.75-.08.75.28v2.44c0 .42.5.63.72.28C12.28 7.5 13 3 13 1c0-.42.48-.64.8-.35C18 4.5 20 9 20 12c0 5.5-3.5 11-8 11z"/></svg>
|
|
@@ -174,3 +179,12 @@
|
|
| 174 |
</details>
|
| 175 |
|
| 176 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 82 |
</div>
|
| 83 |
</div>
|
| 84 |
|
| 85 |
+
<div class="mode-toggle-wrap">
|
| 86 |
+
<button id="mode-btn-fast" class="mode-btn mode-btn-active" onclick="window.__setMode('fast')">Fast</button>
|
| 87 |
+
<button id="mode-btn-hd" class="mode-btn" onclick="window.__setMode('high_detail')">High-Detail</button>
|
| 88 |
+
</div>
|
| 89 |
+
|
| 90 |
<div style="padding:12px 20px;">
|
| 91 |
<button id="custom-run-btn" class="btn-run">
|
| 92 |
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M12 23c-3.6 0-8-2.69-8-7.5 0-3.5 3-6.5 4.5-8 .27-.27.75-.08.75.28v2.44c0 .42.5.63.72.28C12.28 7.5 13 3 13 1c0-.42.48-.64.8-.35C18 4.5 20 9 20 12c0 5.5-3.5 11-8 11z"/></svg>
|
|
|
|
| 179 |
</details>
|
| 180 |
|
| 181 |
</div>
|
| 182 |
+
|
| 183 |
+
<script>
|
| 184 |
+
window.__selectedMode = 'fast';
|
| 185 |
+
window.__setMode = function(m) {
|
| 186 |
+
window.__selectedMode = m;
|
| 187 |
+
document.getElementById('mode-btn-fast').classList.toggle('mode-btn-active', m === 'fast');
|
| 188 |
+
document.getElementById('mode-btn-hd').classList.toggle('mode-btn-active', m === 'high_detail');
|
| 189 |
+
};
|
| 190 |
+
</script>
|