tomiconic commited on
Commit
e6a4b4e
·
verified ·
1 Parent(s): e389efe

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +213 -155
app.py CHANGED
@@ -1,42 +1,43 @@
1
  import gradio as gr
2
  import torch
 
3
  from diffusers import StableDiffusionXLPipeline, DPMSolverMultistepScheduler
4
  from huggingface_hub import hf_hub_download
5
  import random
6
 
7
- # ── Device ────────────────────────────────────────────────────────────────────
8
- DEVICE = "cuda" if torch.cuda.is_available() else "cpu"
9
- DTYPE = torch.float16 if DEVICE == "cuda" else torch.float32
10
- print(f"Running on: {DEVICE.upper()}")
11
-
12
- # ── Model ─────────────────────────────────────────────────────────────────────
13
  MODEL_REPO = "cyberdelia/CyberRealisticPony"
14
  MODEL_FILE = "CyberRealisticPony_V16.0_FP16.safetensors"
15
  PONY_POS = "score_9, score_8_up, score_7_up, "
16
  PONY_NEG = "score_6, score_5, score_4, "
17
 
 
18
  print("Downloading model...")
19
  local_path = hf_hub_download(repo_id=MODEL_REPO, filename=MODEL_FILE)
20
- print(f"Loading from {local_path}...")
21
 
22
- pipe = StableDiffusionXLPipeline.from_single_file(local_path, torch_dtype=DTYPE)
 
 
 
23
  pipe.scheduler = DPMSolverMultistepScheduler.from_config(
24
- pipe.scheduler.config, use_karras_sigmas=True
 
25
  )
26
  pipe.enable_attention_slicing()
27
- if DEVICE == "cuda":
28
- pipe.enable_xformers_memory_efficient_attention()
29
- pipe = pipe.to(DEVICE)
30
- print("Ready.")
31
 
32
- # ── Generation ────────────────────────────────────────────────────────────────
 
33
  def generate(prompt, negative_prompt, width, height, steps, guidance, seed, randomize):
34
  if not prompt.strip():
35
  raise gr.Error("Please enter a prompt.")
36
  if randomize:
37
  seed = random.randint(0, 2**32 - 1)
38
  seed = int(seed)
39
- generator = torch.Generator(device=DEVICE).manual_seed(seed)
 
 
40
  result = pipe(
41
  prompt=PONY_POS + prompt.strip(),
42
  negative_prompt=PONY_NEG + negative_prompt.strip(),
@@ -51,186 +52,254 @@ def generate(prompt, negative_prompt, width, height, steps, guidance, seed, rand
51
 
52
  # ── CSS ───────────────────────────────────────────────────────────────────────
53
  css = """
54
- /* ── Base ── */
 
55
  body, .gradio-container {
56
- background: #0f0f13 !important;
57
- font-family: 'Inter', system-ui, sans-serif !important;
 
 
58
  }
59
 
60
- /* ── Header ── */
61
- .header-box {
62
- background: linear-gradient(135deg, #1a1a2e 0%, #16213e 50%, #0f3460 100%);
63
- border: 1px solid #e94560;
64
- border-radius: 16px;
65
- padding: 20px;
66
  text-align: center;
67
- margin-bottom: 8px;
 
 
 
 
 
 
 
 
 
68
  }
69
- .header-box h1 {
70
  color: #ffffff;
71
- font-size: 1.8em;
72
- font-weight: 800;
73
- margin: 0 0 6px 0;
74
- letter-spacing: -0.5px;
 
75
  }
76
- .header-box p {
77
- color: #a0a0b8;
78
- font-size: 0.85em;
79
- margin: 0;
 
 
 
80
  }
81
- .header-box .badge {
82
  display: inline-block;
83
- background: #e94560;
84
- color: white;
85
- font-size: 0.7em;
86
- font-weight: 700;
87
- padding: 2px 10px;
88
  border-radius: 20px;
89
- margin-top: 8px;
90
  text-transform: uppercase;
91
- letter-spacing: 1px;
 
92
  }
93
 
94
- /* ── Output image ── */
95
- .output-box {
96
- background: #1a1a2e;
97
- border: 2px dashed #2a2a4a;
98
- border-radius: 16px;
99
  overflow: hidden;
100
- min-height: 300px;
 
 
 
 
101
  }
102
- .output-box img {
103
- border-radius: 14px;
104
  width: 100%;
 
105
  }
106
 
107
- /* ── Panel cards ── */
108
- .panel-card {
109
- background: #1a1a2e;
110
- border: 1px solid #2a2a4a;
111
- border-radius: 14px;
112
- padding: 16px;
113
- margin-bottom: 10px;
 
 
114
  }
115
- .section-label {
116
- color: #e94560 !important;
117
- font-size: 0.75em !important;
118
- font-weight: 700 !important;
119
- text-transform: uppercase !important;
120
- letter-spacing: 1.5px !important;
121
- margin-bottom: 10px !important;
 
 
 
 
 
 
 
 
 
 
 
 
122
  }
123
 
124
- /* ── Inputs ── */
125
- textarea, input[type="number"] {
126
- background: #0f0f13 !important;
127
- border: 1px solid #2a2a4a !important;
128
- border-radius: 10px !important;
129
- color: #e0e0f0 !important;
130
  font-size: 15px !important;
 
 
 
131
  }
132
- textarea:focus, input[type="number"]:focus {
133
- border-color: #e94560 !important;
134
- box-shadow: 0 0 0 2px rgba(233, 69, 96, 0.2) !important;
 
135
  }
136
-
137
- /* ── Sliders ── */
138
- .gradio-slider input[type=range] {
139
- accent-color: #e94560;
140
  }
141
 
142
- /* ── Generate button ── */
143
- .generate-btn {
144
- background: linear-gradient(135deg, #e94560, #c23152) !important;
145
- border: none !important;
146
- border-radius: 14px !important;
147
- color: white !important;
148
- font-size: 1.1em !important;
149
- font-weight: 700 !important;
150
- padding: 16px !important;
151
- width: 100% !important;
152
- letter-spacing: 0.5px !important;
153
- box-shadow: 0 4px 20px rgba(233, 69, 96, 0.4) !important;
154
- transition: all 0.2s ease !important;
155
  }
156
- .generate-btn:active {
157
- transform: scale(0.98) !important;
158
- box-shadow: 0 2px 10px rgba(233, 69, 96, 0.3) !important;
 
 
 
159
  }
160
-
161
- /* ── Seed row ── */
162
- .seed-row {
163
- display: flex;
164
- align-items: center;
165
- gap: 10px;
166
  }
167
 
168
- /* ── Used seed display ── */
169
- .used-seed input {
170
- background: #0f0f13 !important;
171
- border: 1px solid #2a2a4a !important;
172
- color: #606080 !important;
173
- font-size: 0.85em !important;
174
- text-align: center !important;
 
175
  }
176
 
177
- /* ── Labels ── */
178
- label span, .gradio-label {
179
- color: #a0a0c0 !important;
 
 
 
 
 
 
 
 
 
 
 
180
  font-size: 0.82em !important;
181
  font-weight: 600 !important;
 
 
 
 
 
 
 
182
  text-transform: uppercase !important;
183
- letter-spacing: 0.8px !important;
184
  }
185
 
186
- /* ── Mobile: stack columns ── */
187
- @media (max-width: 768px) {
188
- .gr-row { flex-direction: column !important; }
189
- .gr-col { width: 100% !important; min-width: 100% !important; }
 
 
 
 
 
 
 
 
 
 
 
190
  }
 
 
 
 
 
 
 
 
 
 
 
 
191
  """
192
 
193
  # ── UI ────────────────────────────────────────────────────────────────────────
194
  with gr.Blocks(css=css, title="CyberRealistic Pony") as demo:
195
 
196
- # Header
197
  gr.HTML("""
198
- <div class="header-box">
199
  <h1>🐴 CyberRealistic Pony</h1>
200
- <p>SDXL · Pony Architecture · v16.0</p>
201
- <span class="badge"> CPU Mode — Slow</span>
202
  </div>
203
  """)
204
 
205
- # Output image — top on mobile so you see result first
206
- with gr.Group(elem_classes="output-box"):
207
  output_image = gr.Image(
208
- label="",
209
- type="pil",
210
  show_label=False,
211
- height=420,
 
212
  )
213
 
214
  used_seed = gr.Number(
215
- label="Seed used save to reproduce",
216
  interactive=False,
217
- elem_classes="used-seed",
218
  )
219
 
220
- # ── Prompt card ──
221
- gr.HTML('<div class="section-label" style="margin-top:14px;color:#e94560;font-size:0.75em;font-weight:700;text-transform:uppercase;letter-spacing:1.5px;">✏️ Prompt</div>')
222
-
223
  prompt = gr.Textbox(
224
- label="",
225
  placeholder="a woman in a futuristic city, cinematic lighting, highly detailed, photorealistic",
226
  lines=3,
227
- show_label=False,
228
  )
229
 
230
- gr.HTML('<div class="section-label" style="margin-top:10px;color:#e94560;font-size:0.75em;font-weight:700;text-transform:uppercase;letter-spacing:1.5px;">🚫 Negative Prompt</div>')
231
-
232
  negative_prompt = gr.Textbox(
233
- label="",
234
  value=(
235
  "(worst quality:1.2), (low quality:1.2), (normal quality:1.2), "
236
  "lowres, bad anatomy, bad hands, signature, watermarks, "
@@ -238,38 +307,27 @@ with gr.Blocks(css=css, title="CyberRealistic Pony") as demo:
238
  "unnatural body, error, extra limb, missing limbs"
239
  ),
240
  lines=2,
241
- show_label=False,
242
  )
243
 
244
- # ── Size card ──
245
- gr.HTML('<div class="section-label" style="margin-top:14px;color:#e94560;font-size:0.75em;font-weight:700;text-transform:uppercase;letter-spacing:1.5px;">📐 Size</div>')
246
-
247
  with gr.Row():
248
- width = gr.Slider(512, 896, value=768, step=64, label="Width")
249
- height = gr.Slider(512, 1152, value=896, step=64, label="Height")
250
 
251
- # ── Sampling card ──
252
- gr.HTML('<div class="section-label" style="margin-top:14px;color:#e94560;font-size:0.75em;font-weight:700;text-transform:uppercase;letter-spacing:1.5px;">⚙️ Sampling</div>')
253
-
254
- steps = gr.Slider(10, 30, value=20, step=1, label="Steps")
255
  guidance = gr.Slider(1.0, 12.0, value=5.0, step=0.5, label="CFG Scale")
256
 
257
- # ── Seed card ──
258
- gr.HTML('<div class="section-label" style="margin-top:14px;color:#e94560;font-size:0.75em;font-weight:700;text-transform:uppercase;letter-spacing:1.5px;">🎲 Seed</div>')
259
-
260
  with gr.Row():
261
- seed = gr.Number(label="Seed", value=42, precision=0, minimum=0, maximum=2**32-1, scale=2)
262
  randomize_seed = gr.Checkbox(label="Random", value=True, scale=1)
263
 
264
- # ── Generate button ──
265
- generate_btn = gr.Button(
266
- "✦ Generate Image",
267
- variant="primary",
268
- size="lg",
269
- elem_classes="generate-btn",
270
- )
271
 
272
- # ── Wire up ──
273
  generate_btn.click(
274
  fn=generate,
275
  inputs=[prompt, negative_prompt, width, height, steps, guidance, seed, randomize_seed],
 
1
  import gradio as gr
2
  import torch
3
+ import spaces
4
  from diffusers import StableDiffusionXLPipeline, DPMSolverMultistepScheduler
5
  from huggingface_hub import hf_hub_download
6
  import random
7
 
8
+ # ── Model config ──────────────────────────────────────────────────────────────
 
 
 
 
 
9
  MODEL_REPO = "cyberdelia/CyberRealisticPony"
10
  MODEL_FILE = "CyberRealisticPony_V16.0_FP16.safetensors"
11
  PONY_POS = "score_9, score_8_up, score_7_up, "
12
  PONY_NEG = "score_6, score_5, score_4, "
13
 
14
+ # ── Load model on CPU at startup, ZeroGPU moves it to GPU per request ─────────
15
  print("Downloading model...")
16
  local_path = hf_hub_download(repo_id=MODEL_REPO, filename=MODEL_FILE)
17
+ print("Loading pipeline...")
18
 
19
+ pipe = StableDiffusionXLPipeline.from_single_file(
20
+ local_path,
21
+ torch_dtype=torch.float16,
22
+ )
23
  pipe.scheduler = DPMSolverMultistepScheduler.from_config(
24
+ pipe.scheduler.config,
25
+ use_karras_sigmas=True,
26
  )
27
  pipe.enable_attention_slicing()
28
+ print("Pipeline ready.")
 
 
 
29
 
30
+ # ── Generation — @spaces.GPU gives this function a real GPU for its duration ──
31
+ @spaces.GPU(duration=120)
32
  def generate(prompt, negative_prompt, width, height, steps, guidance, seed, randomize):
33
  if not prompt.strip():
34
  raise gr.Error("Please enter a prompt.")
35
  if randomize:
36
  seed = random.randint(0, 2**32 - 1)
37
  seed = int(seed)
38
+
39
+ generator = torch.Generator(device="cuda").manual_seed(seed)
40
+
41
  result = pipe(
42
  prompt=PONY_POS + prompt.strip(),
43
  negative_prompt=PONY_NEG + negative_prompt.strip(),
 
52
 
53
  # ── CSS ───────────────────────────────────────────────────────────────────────
54
  css = """
55
+ * { box-sizing: border-box; }
56
+
57
  body, .gradio-container {
58
+ background: #0a0a0f !important;
59
+ font-family: 'Inter', system-ui, -apple-system, sans-serif !important;
60
+ max-width: 520px !important;
61
+ margin: 0 auto !important;
62
  }
63
 
64
+ /* Header */
65
+ .site-header {
66
+ background: linear-gradient(160deg, #12001a, #1e0033, #0d001a);
67
+ border: 1px solid #6f00ff44;
68
+ border-radius: 20px;
69
+ padding: 24px 20px 18px;
70
  text-align: center;
71
+ margin-bottom: 12px;
72
+ position: relative;
73
+ overflow: hidden;
74
+ }
75
+ .site-header::before {
76
+ content: '';
77
+ position: absolute;
78
+ top: -40px; left: -40px; right: -40px;
79
+ height: 120px;
80
+ background: radial-gradient(ellipse, #6f00ff22 0%, transparent 70%);
81
  }
82
+ .site-header h1 {
83
  color: #ffffff;
84
+ font-size: 1.7em;
85
+ font-weight: 900;
86
+ margin: 0 0 4px;
87
+ letter-spacing: -1px;
88
+ position: relative;
89
  }
90
+ .site-header .sub {
91
+ color: #9966cc;
92
+ font-size: 0.78em;
93
+ font-weight: 500;
94
+ letter-spacing: 2px;
95
+ text-transform: uppercase;
96
+ position: relative;
97
  }
98
+ .gpu-badge {
99
  display: inline-block;
100
+ background: linear-gradient(90deg, #00c853, #00e676);
101
+ color: #000;
102
+ font-size: 0.68em;
103
+ font-weight: 800;
104
+ padding: 3px 12px;
105
  border-radius: 20px;
106
+ margin-top: 10px;
107
  text-transform: uppercase;
108
+ letter-spacing: 1.5px;
109
+ position: relative;
110
  }
111
 
112
+ /* Output area */
113
+ .output-wrap {
114
+ background: #0f0f1a;
115
+ border: 1px solid #1e1e35;
116
+ border-radius: 18px;
117
  overflow: hidden;
118
+ margin-bottom: 10px;
119
+ min-height: 340px;
120
+ display: flex;
121
+ align-items: center;
122
+ justify-content: center;
123
  }
124
+ .output-wrap img {
 
125
  width: 100%;
126
+ border-radius: 18px;
127
  }
128
 
129
+ /* Seed display */
130
+ .seed-display input {
131
+ background: #0f0f1a !important;
132
+ border: 1px solid #1e1e35 !important;
133
+ border-radius: 10px !important;
134
+ color: #5544aa !important;
135
+ font-size: 0.8em !important;
136
+ text-align: center !important;
137
+ padding: 8px !important;
138
  }
139
+
140
+ /* Section headers */
141
+ .sec-head {
142
+ color: #7733cc;
143
+ font-size: 0.7em;
144
+ font-weight: 800;
145
+ text-transform: uppercase;
146
+ letter-spacing: 2px;
147
+ margin: 16px 0 8px;
148
+ padding-left: 2px;
149
+ display: flex;
150
+ align-items: center;
151
+ gap: 6px;
152
+ }
153
+ .sec-head::after {
154
+ content: '';
155
+ flex: 1;
156
+ height: 1px;
157
+ background: linear-gradient(90deg, #331155, transparent);
158
  }
159
 
160
+ /* Textareas */
161
+ textarea {
162
+ background: #0f0f1a !important;
163
+ border: 1px solid #221133 !important;
164
+ border-radius: 12px !important;
165
+ color: #d0c0ee !important;
166
  font-size: 15px !important;
167
+ line-height: 1.5 !important;
168
+ padding: 12px !important;
169
+ resize: none !important;
170
  }
171
+ textarea:focus {
172
+ border-color: #7733cc !important;
173
+ box-shadow: 0 0 0 3px #7733cc22 !important;
174
+ outline: none !important;
175
  }
176
+ textarea::placeholder {
177
+ color: #443355 !important;
 
 
178
  }
179
 
180
+ /* Sliders */
181
+ input[type=range] {
182
+ accent-color: #7733cc !important;
183
+ height: 4px;
 
 
 
 
 
 
 
 
 
184
  }
185
+ .gradio-slider {
186
+ background: #0f0f1a !important;
187
+ border: 1px solid #1e1e35 !important;
188
+ border-radius: 12px !important;
189
+ padding: 12px 14px !important;
190
+ margin-bottom: 8px !important;
191
  }
192
+ .gradio-slider label span {
193
+ color: #9966cc !important;
194
+ font-size: 0.78em !important;
195
+ font-weight: 600 !important;
196
+ text-transform: uppercase !important;
197
+ letter-spacing: 1px !important;
198
  }
199
 
200
+ /* Number inputs */
201
+ input[type=number] {
202
+ background: #0f0f1a !important;
203
+ border: 1px solid #221133 !important;
204
+ border-radius: 10px !important;
205
+ color: #d0c0ee !important;
206
+ font-size: 14px !important;
207
+ padding: 10px !important;
208
  }
209
 
210
+ /* Checkbox */
211
+ .gradio-checkbox {
212
+ background: #0f0f1a !important;
213
+ border: 1px solid #1e1e35 !important;
214
+ border-radius: 12px !important;
215
+ padding: 10px 14px !important;
216
+ }
217
+ input[type=checkbox] {
218
+ accent-color: #7733cc !important;
219
+ width: 18px !important;
220
+ height: 18px !important;
221
+ }
222
+ .gradio-checkbox label span {
223
+ color: #9966cc !important;
224
  font-size: 0.82em !important;
225
  font-weight: 600 !important;
226
+ }
227
+
228
+ /* Labels */
229
+ label span {
230
+ color: #8855bb !important;
231
+ font-size: 0.78em !important;
232
+ font-weight: 700 !important;
233
  text-transform: uppercase !important;
234
+ letter-spacing: 1px !important;
235
  }
236
 
237
+ /* Generate button */
238
+ button.lg.primary {
239
+ background: linear-gradient(135deg, #7733cc 0%, #5500aa 50%, #3d007a 100%) !important;
240
+ border: 1px solid #9944ee !important;
241
+ border-radius: 16px !important;
242
+ color: #ffffff !important;
243
+ font-size: 1.05em !important;
244
+ font-weight: 800 !important;
245
+ padding: 18px !important;
246
+ width: 100% !important;
247
+ letter-spacing: 1px !important;
248
+ text-transform: uppercase !important;
249
+ box-shadow: 0 4px 24px #7733cc55 !important;
250
+ transition: all 0.15s ease !important;
251
+ margin-top: 6px !important;
252
  }
253
+ button.lg.primary:hover {
254
+ box-shadow: 0 6px 32px #7733cc88 !important;
255
+ transform: translateY(-1px) !important;
256
+ }
257
+ button.lg.primary:active {
258
+ transform: scale(0.98) translateY(0) !important;
259
+ box-shadow: 0 2px 12px #7733cc44 !important;
260
+ }
261
+
262
+ /* Hide gradio footer */
263
+ footer { display: none !important; }
264
+ .built-with { display: none !important; }
265
  """
266
 
267
  # ── UI ────────────────────────────────────────────────────────────────────────
268
  with gr.Blocks(css=css, title="CyberRealistic Pony") as demo:
269
 
 
270
  gr.HTML("""
271
+ <div class="site-header">
272
  <h1>🐴 CyberRealistic Pony</h1>
273
+ <div class="sub">v16.0 · SDXL · Pony XL</div>
274
+ <div class="gpu-badge"> ZeroGPU</div>
275
  </div>
276
  """)
277
 
278
+ # Output — top of page so it's the first thing you see on mobile
279
+ with gr.Group(elem_classes="output-wrap"):
280
  output_image = gr.Image(
 
 
281
  show_label=False,
282
+ type="pil",
283
+ height=400,
284
  )
285
 
286
  used_seed = gr.Number(
287
+ label="Seed used note this down to recreate",
288
  interactive=False,
289
+ elem_classes="seed-display",
290
  )
291
 
292
+ # Prompt
293
+ gr.HTML('<div class="sec-head">✏️ Prompt</div>')
 
294
  prompt = gr.Textbox(
295
+ show_label=False,
296
  placeholder="a woman in a futuristic city, cinematic lighting, highly detailed, photorealistic",
297
  lines=3,
 
298
  )
299
 
300
+ gr.HTML('<div class="sec-head">🚫 Negative</div>')
 
301
  negative_prompt = gr.Textbox(
302
+ show_label=False,
303
  value=(
304
  "(worst quality:1.2), (low quality:1.2), (normal quality:1.2), "
305
  "lowres, bad anatomy, bad hands, signature, watermarks, "
 
307
  "unnatural body, error, extra limb, missing limbs"
308
  ),
309
  lines=2,
 
310
  )
311
 
312
+ # Size
313
+ gr.HTML('<div class="sec-head">📐 Size</div>')
 
314
  with gr.Row():
315
+ width = gr.Slider(512, 896, value=832, step=64, label="Width")
316
+ height = gr.Slider(512, 1152, value=1216, step=64, label="Height")
317
 
318
+ # Sampling
319
+ gr.HTML('<div class="sec-head">⚙️ Sampling</div>')
320
+ steps = gr.Slider(20, 60, value=30, step=1, label="Steps")
 
321
  guidance = gr.Slider(1.0, 12.0, value=5.0, step=0.5, label="CFG Scale")
322
 
323
+ # Seed
324
+ gr.HTML('<div class="sec-head">🎲 Seed</div>')
 
325
  with gr.Row():
326
+ seed = gr.Number(label="Seed", value=42, precision=0, minimum=0, maximum=2**32-1, scale=3)
327
  randomize_seed = gr.Checkbox(label="Random", value=True, scale=1)
328
 
329
+ generate_btn = gr.Button("⚡ Generate", variant="primary", size="lg")
 
 
 
 
 
 
330
 
 
331
  generate_btn.click(
332
  fn=generate,
333
  inputs=[prompt, negative_prompt, width, height, steps, guidance, seed, randomize_seed],