artificialguybr commited on
Commit
92ae147
·
1 Parent(s): 73f11f9

Redesign UI with modern studio-style interface

Browse files

- Add hero section with gradient title and feature pills
- Implement numbered sections (Prompt, Result, Settings)
- Add custom CSS with amber/gold theme for photorealistic aesthetic
- Add negative prompt as visible field with default value
- Add styled generate button with hover effects
- Add styled accordions for aspect ratio and metadata
- Improve overall layout with columns
- Add ZeroGPU badge and model info pills
- Use custom fonts (Outfit, Fira Code)
- Dark theme with gradient background effects

Files changed (1) hide show
  1. app.py +267 -90
app.py CHANGED
@@ -16,7 +16,7 @@ from diffusers import StableDiffusionXLPipeline, StableDiffusionXLImg2ImgPipelin
16
  logging.basicConfig(level=logging.INFO)
17
  logger = logging.getLogger(__name__)
18
 
19
- DESCRIPTION = "RealVis XL"
20
  if not torch.cuda.is_available():
21
  DESCRIPTION += "\n<p>Running on CPU 🥶 This demo does not work on CPU. </p>"
22
  IS_COLAB = utils.is_google_colab() or os.getenv("IS_COLAB") == "1"
@@ -28,6 +28,11 @@ USE_TORCH_COMPILE = os.getenv("USE_TORCH_COMPILE") == "1"
28
  ENABLE_CPU_OFFLOAD = os.getenv("ENABLE_CPU_OFFLOAD") == "1"
29
  OUTPUT_DIR = os.getenv("OUTPUT_DIR", "./outputs")
30
 
 
 
 
 
 
31
  MODEL = os.getenv(
32
  "MODEL",
33
  "https://huggingface.co/SG161222/RealVisXL_V4.0/blob/main/RealVisXL_V4.0.safetensors",
@@ -176,52 +181,263 @@ if torch.cuda.is_available():
176
  else:
177
  pipe = None
178
 
179
- with gr.Blocks(css="style.css") as demo:
180
- title = gr.HTML(
181
- f"""<h1><span>{DESCRIPTION}</span></h1>""",
182
- elem_id="title",
183
- )
184
- gr.Markdown(
185
- f"""Gradio demo for ([RealVis XL]https://huggingface.co/SG161222/RealVisXL_V4.0/)""",
186
- elem_id="subtitle",
187
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
188
  gr.DuplicateButton(
189
  value="Duplicate Space for private use",
190
  elem_id="duplicate-button",
191
  visible=os.getenv("SHOW_DUPLICATE_BUTTON") == "1",
192
  )
193
- with gr.Group():
194
- with gr.Row():
195
- prompt = gr.Text(
196
- label="Prompt",
197
- show_label=False,
198
- max_lines=5,
199
- placeholder="Enter your prompt",
 
 
200
  container=False,
201
  )
202
- run_button = gr.Button(
203
- "Generate",
204
- variant="primary",
205
- scale=0
 
206
  )
207
- result = gr.Gallery(
208
- label="Result",
209
- columns=1,
210
- preview=True,
211
- show_label=False
212
- )
213
- with gr.Accordion(label="Advanced Settings", open=False):
214
- negative_prompt = gr.Text(
215
- label="Negative Prompt",
216
- max_lines=5,
217
- placeholder="Enter a negative prompt",
218
- value=""
219
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
220
  aspect_ratio_selector = gr.Radio(
221
- label="Aspect Ratio",
222
- choices=config.aspect_ratios,
223
- value="1024 x 1024",
224
- container=True,
225
  )
226
  with gr.Group(visible=False) as custom_resolution:
227
  with gr.Row():
@@ -239,68 +455,28 @@ with gr.Blocks(css="style.css") as demo:
239
  step=8,
240
  value=1024,
241
  )
242
- use_upscaler = gr.Checkbox(label="Use Upscaler", value=False)
243
- with gr.Row() as upscaler_row:
244
- upscaler_strength = gr.Slider(
245
- label="Strength",
246
- minimum=0,
247
- maximum=1,
248
- step=0.05,
249
- value=0.55,
250
- visible=False,
251
- )
252
- upscale_by = gr.Slider(
253
- label="Upscale by",
254
- minimum=1,
255
- maximum=1.5,
256
- step=0.1,
257
- value=1.5,
258
- visible=False,
259
- )
260
 
261
- sampler = gr.Dropdown(
262
- label="Sampler",
263
- choices=config.sampler_list,
264
- interactive=True,
265
- value="DPM++ 2M SDE Karras",
266
- )
267
- with gr.Row():
268
- seed = gr.Slider(
269
- label="Seed", minimum=0, maximum=utils.MAX_SEED, step=1, value=0
270
- )
271
- randomize_seed = gr.Checkbox(label="Randomize seed", value=True)
272
- with gr.Group():
273
- with gr.Row():
274
- guidance_scale = gr.Slider(
275
- label="Guidance scale",
276
- minimum=1,
277
- maximum=12,
278
- step=0.1,
279
- value=7.0,
280
- )
281
- num_inference_steps = gr.Slider(
282
- label="Number of inference steps",
283
- minimum=1,
284
- maximum=50,
285
- step=1,
286
- value=28,
287
- )
288
- with gr.Accordion(label="Generation Parameters", open=False):
289
- gr_metadata = gr.JSON(label="Metadata", show_label=False)
290
  gr.Examples(
291
  examples=config.examples,
292
  inputs=prompt,
293
  outputs=[result, gr_metadata],
294
- fn=lambda *args, **kwargs: generate(*args, use_upscaler=True, **kwargs),
295
  cache_examples=CACHE_EXAMPLES,
296
  )
 
297
  use_upscaler.change(
298
- fn=lambda x: [gr.update(visible=x), gr.update(visible=x)],
299
  inputs=use_upscaler,
300
- outputs=[upscaler_strength, upscale_by],
301
  queue=False,
302
  api_name=False,
303
  )
 
304
  aspect_ratio_selector.change(
305
  fn=lambda x: gr.update(visible=x == "Custom"),
306
  inputs=aspect_ratio_selector,
@@ -348,7 +524,7 @@ with gr.Blocks(css="style.css") as demo:
348
  outputs=result,
349
  api_name=False,
350
  )
351
- run_button.click(
352
  fn=utils.randomize_seed_fn,
353
  inputs=[seed, randomize_seed],
354
  outputs=seed,
@@ -360,4 +536,5 @@ with gr.Blocks(css="style.css") as demo:
360
  outputs=[result, gr_metadata],
361
  api_name=False,
362
  )
363
- demo.queue(max_size=20).launch(debug=IS_COLAB, share=IS_COLAB)
 
 
16
  logging.basicConfig(level=logging.INFO)
17
  logger = logging.getLogger(__name__)
18
 
19
+ DESCRIPTION = "RealVis Studio"
20
  if not torch.cuda.is_available():
21
  DESCRIPTION += "\n<p>Running on CPU 🥶 This demo does not work on CPU. </p>"
22
  IS_COLAB = utils.is_google_colab() or os.getenv("IS_COLAB") == "1"
 
28
  ENABLE_CPU_OFFLOAD = os.getenv("ENABLE_CPU_OFFLOAD") == "1"
29
  OUTPUT_DIR = os.getenv("OUTPUT_DIR", "./outputs")
30
 
31
+ DEFAULT_NEGATIVE = (
32
+ "(worst quality, low quality, normal quality, lowres, low details), "
33
+ "(watermark, signature, text, logo, words, letters), blurry, jpeg artifacts"
34
+ )
35
+
36
  MODEL = os.getenv(
37
  "MODEL",
38
  "https://huggingface.co/SG161222/RealVisXL_V4.0/blob/main/RealVisXL_V4.0.safetensors",
 
181
  else:
182
  pipe = None
183
 
184
+ CSS = """
185
+ @import url('https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;500;600;700;800&family=Fira+Code:wght@400;500&display=swap');
186
+
187
+ :root {
188
+ --bg: #080a0e;
189
+ --surf: #0d1017;
190
+ --card: #111520;
191
+ --border: #1c2133;
192
+ --border2: #252d45;
193
+ --amber: #f59e0b;
194
+ --gold: #fbbf24;
195
+ --cream: #fef3c7;
196
+ --text: #e2e8f0;
197
+ --muted: #4a5578;
198
+ --r: 14px;
199
+ --r-sm: 8px;
200
+ }
201
+
202
+ *, *::before, *::after { box-sizing: border-box; }
203
+
204
+ body, .gradio-container {
205
+ background: var(--bg) !important;
206
+ font-family: 'Outfit', sans-serif !important;
207
+ color: var(--text) !important;
208
+ }
209
+
210
+ .gradio-container::before {
211
+ content: '';
212
+ position: fixed; inset: 0; pointer-events: none; z-index: 0;
213
+ background:
214
+ radial-gradient(ellipse 70% 50% at 50% -10%, rgba(245,158,11,0.07) 0%, transparent 65%),
215
+ radial-gradient(ellipse 40% 30% at 90% 90%, rgba(251,191,36,0.04) 0%, transparent 60%);
216
+ }
217
+
218
+ .app-hero { padding: 52px 0 28px; text-align: center; }
219
+
220
+ .app-hero h1 {
221
+ font-size: 3rem; font-weight: 800; letter-spacing: -0.05em;
222
+ line-height: 1; margin: 0 0 12px;
223
+ background: linear-gradient(135deg, var(--cream) 0%, var(--gold) 40%, var(--amber) 100%);
224
+ -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text;
225
+ }
226
+
227
+ .app-hero .tagline {
228
+ color: var(--muted); font-size: 0.88rem; font-weight: 300;
229
+ letter-spacing: 0.06em; text-transform: uppercase; margin: 0 0 20px;
230
+ }
231
+
232
+ .app-hero .pills { display: flex; justify-content: center; gap: 8px; flex-wrap: wrap; }
233
+
234
+ .app-hero .pill {
235
+ background: var(--card); border: 1px solid var(--border2); border-radius: 100px;
236
+ padding: 4px 14px; font-size: 0.74rem; font-weight: 500; color: var(--muted);
237
+ font-family: 'Fira Code', monospace;
238
+ }
239
+
240
+ .app-hero .pill.gold { color: var(--amber); border-color: rgba(245,158,11,0.3); }
241
+
242
+ .sec-label {
243
+ font-size: 0.62rem !important; font-weight: 700 !important;
244
+ letter-spacing: 0.15em !important; text-transform: uppercase !important;
245
+ color: var(--amber) !important; margin: 0 0 8px !important; display: block;
246
+ }
247
+
248
+ label > span {
249
+ font-family: 'Outfit', sans-serif !important; font-size: 0.72rem !important;
250
+ font-weight: 500 !important; color: var(--muted) !important;
251
+ text-transform: uppercase; letter-spacing: 0.08em;
252
+ }
253
+
254
+ textarea, input[type="text"] {
255
+ background: var(--surf) !important; border: 1px solid var(--border) !important;
256
+ border-radius: var(--r-sm) !important; color: var(--text) !important;
257
+ font-family: 'Outfit', sans-serif !important; font-size: 0.95rem !important;
258
+ transition: border-color 0.2s, box-shadow 0.2s;
259
+ }
260
+
261
+ textarea:focus, input[type="text"]:focus {
262
+ border-color: var(--amber) !important;
263
+ box-shadow: 0 0 0 3px rgba(245,158,11,0.12) !important;
264
+ outline: none !important;
265
+ }
266
+
267
+ .gen-btn {
268
+ background: linear-gradient(135deg, var(--amber), #d97706) !important;
269
+ border: none !important; border-radius: var(--r) !important;
270
+ color: #000 !important; font-family: 'Outfit', sans-serif !important;
271
+ font-weight: 700 !important; font-size: 1rem !important;
272
+ height: 54px !important; width: 100% !important;
273
+ letter-spacing: 0.02em !important; cursor: pointer !important;
274
+ transition: opacity 0.18s, transform 0.15s, box-shadow 0.2s !important;
275
+ box-shadow: 0 4px 20px rgba(245,158,11,0.28) !important;
276
+ }
277
+
278
+ .gen-btn:hover {
279
+ opacity: 0.88 !important; transform: translateY(-1px) !important;
280
+ box-shadow: 0 8px 30px rgba(245,158,11,0.48) !important;
281
+ }
282
+
283
+ .gen-btn:active { transform: translateY(0) !important; }
284
+
285
+ .result-gallery .grid-wrap {
286
+ background: var(--surf) !important;
287
+ border: 1px solid var(--border) !important;
288
+ border-radius: var(--r) !important;
289
+ }
290
+
291
+ .result-gallery img { border-radius: 10px !important; }
292
+
293
+ .gr-accordion {
294
+ background: var(--card) !important; border: 1px solid var(--border) !important;
295
+ border-radius: var(--r) !important; margin-top: 10px !important;
296
+ }
297
+
298
+ .aspect-radio .wrap {
299
+ display: flex !important; flex-wrap: wrap !important; gap: 6px !important;
300
+ background: transparent !important; padding: 0 !important; border: none !important;
301
+ }
302
+
303
+ .aspect-radio label {
304
+ background: var(--surf) !important; border: 1px solid var(--border) !important;
305
+ border-radius: 100px !important; padding: 5px 12px !important;
306
+ font-size: 0.78rem !important; font-family: 'Fira Code', monospace !important;
307
+ color: var(--muted) !important; cursor: pointer !important;
308
+ transition: all 0.15s !important; white-space: nowrap !important;
309
+ }
310
+
311
+ .aspect-radio label:hover { border-color: var(--amber) !important; color: var(--text) !important; }
312
+
313
+ .aspect-radio label:has(input:checked) {
314
+ background: var(--amber) !important; border-color: var(--amber) !important;
315
+ color: #000 !important; font-weight: 600 !important;
316
+ }
317
+
318
+ .ghost-btn button {
319
+ background: transparent !important; border: 1px solid var(--border2) !important;
320
+ border-radius: var(--r-sm) !important; color: var(--muted) !important;
321
+ font-family: 'Outfit', sans-serif !important; font-size: 0.82rem !important;
322
+ height: 36px !important; transition: border-color 0.18s, color 0.18s !important;
323
+ }
324
+
325
+ .ghost-btn button:hover { border-color: var(--amber) !important; color: var(--text) !important; }
326
+
327
+ #duplicate-button {
328
+ margin: auto;
329
+ color: #fff;
330
+ background: linear-gradient(135deg, var(--amber), #d97706);
331
+ border-radius: 100vh;
332
+ font-family: 'Outfit', sans-serif;
333
+ }
334
+
335
+ ::-webkit-scrollbar { width: 5px; }
336
+ ::-webkit-scrollbar-track { background: var(--surf); }
337
+ ::-webkit-scrollbar-thumb { background: var(--border2); border-radius: 3px; }
338
+ ::-webkit-scrollbar-thumb:hover { background: var(--amber); }
339
+ """
340
+
341
+ with gr.Blocks(theme=gr.themes.Base(), css=CSS) as demo:
342
+
343
+ gr.HTML("""
344
+ <div class="app-hero">
345
+ <h1>RealVis Studio</h1>
346
+ <p class="tagline">Photorealistic · High-fidelity · Text-to-image</p>
347
+ <div class="pills">
348
+ <span class="pill gold">ZeroGPU ⚡</span>
349
+ <span class="pill">RealVisXL V4.0</span>
350
+ <span class="pill">SDXL · fp16</span>
351
+ <span class="pill">safetensors</span>
352
+ </div>
353
+ </div>
354
+ """)
355
+
356
  gr.DuplicateButton(
357
  value="Duplicate Space for private use",
358
  elem_id="duplicate-button",
359
  visible=os.getenv("SHOW_DUPLICATE_BUTTON") == "1",
360
  )
361
+
362
+ with gr.Row():
363
+
364
+ with gr.Column(scale=2):
365
+ gr.HTML('<span class="sec-label">① Prompt</span>')
366
+ prompt = gr.Textbox(
367
+ label="",
368
+ lines=4,
369
+ placeholder="high quality, portrait photo of 30 y.o woman, perfect detailed eyes, natural skin, cinematic shot...",
370
  container=False,
371
  )
372
+ gr.HTML('<div style="height:8px"></div>')
373
+ negative_prompt = gr.Textbox(
374
+ label="Negative prompt",
375
+ lines=2,
376
+ value=DEFAULT_NEGATIVE
377
  )
378
+
379
+ gr.HTML('<div style="height:10px"></div>')
380
+ run_btn = gr.Button("▶ Generate", variant="primary", elem_classes=["gen-btn"])
381
+
382
+ gr.HTML('<div style="height:14px"></div>')
383
+ gr.HTML('<span class="sec-label">② Result</span>')
384
+ result = gr.Gallery(
385
+ label="", columns=1, preview=True,
386
+ container=False, elem_classes=["result-gallery"], height=600,
387
+ )
388
+
389
+ with gr.Column(scale=1, min_width=280):
390
+ gr.HTML('<span class="sec-label">③ Settings</span>')
391
+
392
+ use_upscaler = gr.Checkbox(label="Use Upscaler", value=False)
393
+ with gr.Row(visible=False) as upscaler_row:
394
+ upscaler_strength = gr.Slider(
395
+ label="Strength",
396
+ minimum=0,
397
+ maximum=1,
398
+ step=0.05,
399
+ value=0.55,
400
+ )
401
+ upscale_by = gr.Slider(
402
+ label="Upscale by",
403
+ minimum=1,
404
+ maximum=1.5,
405
+ step=0.1,
406
+ value=1.5,
407
+ )
408
+
409
+ gr.HTML('<div style="height:8px"></div>')
410
+ sampler = gr.Dropdown(
411
+ label="Sampler",
412
+ choices=config.sampler_list,
413
+ value="DPM++ 2M SDE Karras",
414
+ )
415
+
416
+ with gr.Row():
417
+ guidance_scale = gr.Slider(
418
+ label="Guidance scale",
419
+ minimum=1,
420
+ maximum=12,
421
+ step=0.1,
422
+ value=7.0,
423
+ )
424
+ num_inference_steps = gr.Slider(
425
+ label="Steps",
426
+ minimum=1,
427
+ maximum=50,
428
+ step=1,
429
+ value=28,
430
+ )
431
+
432
+ seed = gr.Slider(
433
+ label="Seed", minimum=0, maximum=utils.MAX_SEED, step=1, value=0
434
+ )
435
+ randomize_seed = gr.Checkbox(label="Randomize seed", value=True)
436
+
437
+ with gr.Accordion("⚙ Aspect ratio", open=False):
438
  aspect_ratio_selector = gr.Radio(
439
+ label="", choices=config.aspect_ratios, value="1024 x 1024",
440
+ container=False, elem_classes=["aspect-radio"],
 
 
441
  )
442
  with gr.Group(visible=False) as custom_resolution:
443
  with gr.Row():
 
455
  step=8,
456
  value=1024,
457
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
458
 
459
+ with gr.Accordion("📋 Generation metadata", open=False):
460
+ gr_metadata = gr.JSON(label="", show_label=False)
461
+
462
+ gr.HTML('<div style="height:12px"></div>')
463
+ gr.HTML('<span class="sec-label">Examples</span>')
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
464
  gr.Examples(
465
  examples=config.examples,
466
  inputs=prompt,
467
  outputs=[result, gr_metadata],
468
+ fn=lambda *args, **kwargs: generate(*args, use_upscaler=False, **kwargs),
469
  cache_examples=CACHE_EXAMPLES,
470
  )
471
+
472
  use_upscaler.change(
473
+ fn=lambda x: gr.update(visible=x),
474
  inputs=use_upscaler,
475
+ outputs=upscaler_row,
476
  queue=False,
477
  api_name=False,
478
  )
479
+
480
  aspect_ratio_selector.change(
481
  fn=lambda x: gr.update(visible=x == "Custom"),
482
  inputs=aspect_ratio_selector,
 
524
  outputs=result,
525
  api_name=False,
526
  )
527
+ run_btn.click(
528
  fn=utils.randomize_seed_fn,
529
  inputs=[seed, randomize_seed],
530
  outputs=seed,
 
536
  outputs=[result, gr_metadata],
537
  api_name=False,
538
  )
539
+
540
+ demo.queue(max_size=20).launch(debug=IS_COLAB, share=IS_COLAB)