MySafeCode commited on
Commit
f096d25
·
verified ·
1 Parent(s): e0ce0b4

Upload app.py

Browse files
Files changed (1) hide show
  1. app.py +638 -30
app.py CHANGED
@@ -1,17 +1,28 @@
1
  import gradio as gr
2
  import requests
 
3
  import os
 
4
  from PIL import Image
5
  import io
6
  from datetime import datetime
7
 
 
8
  def get_api_key():
9
  return os.environ.get("PIXAZO_API_KEY")
10
 
11
- def generate_image(prompt):
 
 
 
12
  api_key = get_api_key()
 
13
  if not api_key:
14
- return None, "❌ API key not set"
 
 
 
 
15
 
16
  url = "https://gateway.pixazo.ai/flux-1-schnell/v1/getData"
17
 
@@ -21,15 +32,32 @@ def generate_image(prompt):
21
  'Ocp-Apim-Subscription-Key': api_key,
22
  }
23
 
 
24
  body = {
25
  "prompt": prompt,
26
- "num_steps": 4,
27
- "height": 512,
28
- "width": 512,
29
  }
30
 
 
 
 
 
 
 
 
31
  try:
32
- response = requests.post(url, headers=headers, json=body, timeout=60)
 
 
 
 
 
 
 
 
 
33
 
34
  if response.status_code == 200:
35
  result = response.json()
@@ -37,42 +65,622 @@ def generate_image(prompt):
37
  if "output" in result:
38
  image_url = result["output"]
39
 
40
- img_response = requests.get(image_url, timeout=30)
41
- if img_response.status_code == 200:
42
- image = Image.open(io.BytesIO(img_response.content))
43
- if image.mode in ('RGBA', 'LA', 'P'):
44
- image = image.convert('RGB')
45
- return image, "✅ Image generated successfully!"
46
- else:
47
- return None, f"❌ Failed to download image: HTTP {img_response.status_code}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
48
  else:
49
- return None, "❌ No image URL in response"
 
 
 
 
50
  else:
51
- return None, f"❌ API error: {response.status_code}"
 
 
 
 
52
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
53
  except Exception as e:
54
- return None, f"❌ Error: {str(e)}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
55
 
56
- # Simple interface
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
57
  with gr.Blocks(title="Pixazo Image Generator") as demo:
58
- gr.Markdown("# 🎨 Pixazo Image Generator")
59
 
 
 
 
 
 
 
 
 
 
 
 
 
 
60
  api_key = get_api_key()
61
  if api_key:
62
- gr.Markdown("✅ API Key: Configured")
 
 
 
 
63
  else:
64
- gr.Markdown("❌ API Key: Not configured. Set PIXAZO_API_KEY in secrets.")
 
 
 
 
 
65
 
66
- with gr.Row():
67
- with gr.Column():
68
- prompt = gr.Textbox(label="Prompt", lines=3)
69
- btn = gr.Button("Generate", variant="primary")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
70
 
71
- with gr.Column():
72
- image = gr.Image(label="Generated Image")
73
- status = gr.Textbox(label="Status", interactive=False)
 
 
 
 
 
74
 
75
- btn.click(generate_image, inputs=prompt, outputs=[image, status])
 
 
 
 
 
 
 
 
 
 
76
 
 
77
  if __name__ == "__main__":
78
- demo.launch(server_name="0.0.0.0", server_port=7860)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import gradio as gr
2
  import requests
3
+ import json
4
  import os
5
+ import time
6
  from PIL import Image
7
  import io
8
  from datetime import datetime
9
 
10
+ # Get API key from Hugging Face secrets
11
  def get_api_key():
12
  return os.environ.get("PIXAZO_API_KEY")
13
 
14
+ # Call Pixazo API
15
+ def call_pixazo_api(prompt, num_steps=4, seed=None, height=512, width=512,
16
+ style_preset=None, guidance_scale=None):
17
+
18
  api_key = get_api_key()
19
+
20
  if not api_key:
21
+ return None, {
22
+ "error": "API key not configured",
23
+ "instructions": "Please set PIXAZO_API_KEY in Hugging Face Space secrets",
24
+ "timestamp": datetime.now().isoformat()
25
+ }
26
 
27
  url = "https://gateway.pixazo.ai/flux-1-schnell/v1/getData"
28
 
 
32
  'Ocp-Apim-Subscription-Key': api_key,
33
  }
34
 
35
+ # Prepare request body
36
  body = {
37
  "prompt": prompt,
38
+ "num_steps": num_steps,
39
+ "height": height,
40
+ "width": width,
41
  }
42
 
43
+ if seed and seed > 0:
44
+ body["seed"] = seed
45
+ if style_preset and style_preset != "none":
46
+ body["style_preset"] = style_preset
47
+ if guidance_scale:
48
+ body["guidance_scale"] = guidance_scale
49
+
50
  try:
51
+ print(f"🌐 Sending request to Pixazo API...")
52
+
53
+ response = requests.post(
54
+ url,
55
+ headers=headers,
56
+ json=body,
57
+ timeout=120
58
+ )
59
+
60
+ print(f"✅ Response status: {response.status_code}")
61
 
62
  if response.status_code == 200:
63
  result = response.json()
 
65
  if "output" in result:
66
  image_url = result["output"]
67
 
68
+ # Download the image from the URL
69
+ try:
70
+ print(f"⬇️ Downloading image from URL...")
71
+ img_response = requests.get(image_url, timeout=30, headers={
72
+ 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
73
+ })
74
+
75
+ if img_response.status_code == 200:
76
+ image = Image.open(io.BytesIO(img_response.content))
77
+
78
+ # Convert to RGB if necessary
79
+ if image.mode in ('RGBA', 'LA', 'P'):
80
+ image = image.convert('RGB')
81
+
82
+ return image, {
83
+ "success": True,
84
+ "status_code": 200,
85
+ "image_url_preview": image_url[:80] + "..." if len(image_url) > 80 else image_url,
86
+ "image_size": f"{image.size[0]}x{image.size[1]}",
87
+ "timestamp": datetime.now().isoformat()
88
+ }
89
+ else:
90
+ return None, {
91
+ "error": f"Failed to download image: HTTP {img_response.status_code}",
92
+ "image_url": image_url[:80] + "..." if len(image_url) > 80 else image_url,
93
+ "download_status": img_response.status_code,
94
+ "timestamp": datetime.now().isoformat()
95
+ }
96
+
97
+ except Exception as e:
98
+ return None, {
99
+ "error": f"Error downloading image: {str(e)}",
100
+ "image_url": image_url[:80] + "..." if len(image_url) > 80 else image_url,
101
+ "timestamp": datetime.now().isoformat()
102
+ }
103
  else:
104
+ return None, {
105
+ "error": "Response missing 'output' field",
106
+ "response_keys": list(result.keys()),
107
+ "timestamp": datetime.now().isoformat()
108
+ }
109
  else:
110
+ try:
111
+ error_data = response.json()
112
+ error_msg = error_data.get("error", str(error_data))
113
+ except:
114
+ error_msg = response.text[:200] if response.text else "No error message"
115
 
116
+ return None, {
117
+ "error": f"API returned status {response.status_code}: {error_msg}",
118
+ "status_code": response.status_code,
119
+ "timestamp": datetime.now().isoformat()
120
+ }
121
+
122
+ except requests.exceptions.Timeout:
123
+ return None, {
124
+ "error": "Request timed out after 120 seconds",
125
+ "suggestion": "Try reducing image size or number of steps",
126
+ "timestamp": datetime.now().isoformat()
127
+ }
128
+ except requests.exceptions.RequestException as e:
129
+ return None, {
130
+ "error": f"Network error: {str(e)}",
131
+ "timestamp": datetime.now().isoformat()
132
+ }
133
  except Exception as e:
134
+ return None, {
135
+ "error": f"Unexpected error: {str(e)}",
136
+ "timestamp": datetime.now().isoformat()
137
+ }
138
+
139
+ # Batch generate images
140
+ def generate_images(prompt, num_steps, seed, height, width, style_preset,
141
+ num_images, guidance_scale):
142
+
143
+ images = []
144
+ all_results = []
145
+
146
+ for i in range(num_images):
147
+ try:
148
+ current_seed = seed + i if seed > 0 else 0
149
+
150
+ image, result = call_pixazo_api(
151
+ prompt=prompt,
152
+ num_steps=num_steps,
153
+ seed=current_seed,
154
+ height=height,
155
+ width=width,
156
+ style_preset=style_preset,
157
+ guidance_scale=guidance_scale
158
+ )
159
+
160
+ if image:
161
+ images.append(image)
162
+
163
+ all_results.append(result)
164
+
165
+ status_text = f"Generated {i+1}/{num_images} images"
166
+ if "error" in result:
167
+ status_text = f"Image {i+1} error: {result['error'][:50]}..."
168
+
169
+ yield images if images else None, status_text, json.dumps(result, indent=2)
170
+
171
+ if i < num_images - 1:
172
+ time.sleep(1)
173
+
174
+ except Exception as e:
175
+ error_result = {"error": str(e), "image_index": i, "timestamp": datetime.now().isoformat()}
176
+ all_results.append(error_result)
177
+ yield images if images else None, f"Exception on image {i+1}: {str(e)[:50]}", json.dumps(error_result, indent=2)
178
+ break
179
+
180
+ # Final summary
181
+ success_count = len(images)
182
+
183
+ if success_count == 0:
184
+ final_status = f"❌ No images generated ({success_count}/{num_images} successful)"
185
+ gallery_val = None
186
+ elif success_count < num_images:
187
+ final_status = f"⚠️ Partial success: {success_count}/{num_images} images"
188
+ gallery_val = images
189
+ else:
190
+ final_status = f"🎉 Success! All {success_count} images generated"
191
+ gallery_val = images
192
+
193
+ summary = {
194
+ "summary": {
195
+ "total_attempts": num_images,
196
+ "successful": success_count,
197
+ "failed": num_images - success_count,
198
+ "timestamp": datetime.now().isoformat()
199
+ },
200
+ "parameters_used": {
201
+ "prompt_length": len(prompt),
202
+ "steps": num_steps,
203
+ "resolution": f"{width}x{height}",
204
+ "style": style_preset
205
+ }
206
+ }
207
+
208
+ yield gallery_val, final_status, json.dumps(summary, indent=2)
209
+
210
+ # Custom CSS for the beautiful UI
211
+ custom_css = """
212
+ :root {
213
+ --primary-gradient: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
214
+ --primary-color: #4f46e5;
215
+ --success-color: #10b981;
216
+ --error-color: #ef4444;
217
+ --warning-color: #f59e0b;
218
+ }
219
+
220
+ .gradio-container {
221
+ max-width: 1200px !important;
222
+ margin: 0 auto !important;
223
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;
224
+ }
225
+
226
+ .header-container {
227
+ background: var(--primary-gradient);
228
+ color: white;
229
+ padding: 40px 30px;
230
+ border-radius: 16px;
231
+ margin-bottom: 30px;
232
+ text-align: center;
233
+ box-shadow: 0 20px 60px rgba(102, 126, 234, 0.3);
234
+ }
235
+
236
+ .header-title {
237
+ font-size: 2.8em;
238
+ font-weight: 700;
239
+ margin-bottom: 10px;
240
+ display: flex;
241
+ align-items: center;
242
+ justify-content: center;
243
+ gap: 15px;
244
+ }
245
+
246
+ .header-subtitle {
247
+ font-size: 1.2em;
248
+ opacity: 0.9;
249
+ max-width: 600px;
250
+ margin: 0 auto;
251
+ }
252
+
253
+ .api-status {
254
+ padding: 16px 20px;
255
+ border-radius: 12px;
256
+ margin-bottom: 25px;
257
+ font-weight: 600;
258
+ font-size: 1.1em;
259
+ border-left: 6px solid;
260
+ }
261
+
262
+ .api-status-success {
263
+ background: linear-gradient(135deg, #d1fae5 0%, #a7f3d0 100%);
264
+ color: #065f46;
265
+ border-left-color: var(--success-color);
266
+ }
267
+
268
+ .api-status-error {
269
+ background: linear-gradient(135deg, #fee2e2 0%, #fecaca 100%);
270
+ color: #7f1d1d;
271
+ border-left-color: var(--error-color);
272
+ }
273
+
274
+ .input-section {
275
+ background: white;
276
+ padding: 30px;
277
+ border-radius: 16px;
278
+ border: 1px solid #e5e7eb;
279
+ box-shadow: 0 4px 20px rgba(0,0,0,0.05);
280
+ margin-bottom: 25px;
281
+ }
282
+
283
+ .section-title {
284
+ color: #333;
285
+ font-size: 1.4em;
286
+ font-weight: 600;
287
+ margin-bottom: 20px;
288
+ display: flex;
289
+ align-items: center;
290
+ gap: 10px;
291
+ }
292
+
293
+ .example-card {
294
+ background: #f8fafc;
295
+ padding: 20px;
296
+ border-radius: 12px;
297
+ border: 2px solid #e2e8f0;
298
+ margin: 12px 0;
299
+ cursor: pointer;
300
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
301
+ }
302
 
303
+ .example-card:hover {
304
+ background: #e2e8f0;
305
+ transform: translateY(-4px);
306
+ box-shadow: 0 10px 30px rgba(0,0,0,0.1);
307
+ border-color: var(--primary-color);
308
+ }
309
+
310
+ .example-title {
311
+ color: var(--primary-color);
312
+ font-weight: 600;
313
+ font-size: 1.1em;
314
+ margin-bottom: 8px;
315
+ }
316
+
317
+ .example-desc {
318
+ color: #666;
319
+ font-size: 0.95em;
320
+ line-height: 1.4;
321
+ }
322
+
323
+ .generate-btn {
324
+ background: var(--primary-gradient) !important;
325
+ color: white !important;
326
+ font-weight: 700 !important;
327
+ padding: 18px 40px !important;
328
+ font-size: 1.2em !important;
329
+ border-radius: 12px !important;
330
+ border: none !important;
331
+ transition: all 0.3s ease !important;
332
+ box-shadow: 0 8px 25px rgba(102, 126, 234, 0.4) !important;
333
+ }
334
+
335
+ .generate-btn:hover {
336
+ transform: translateY(-3px) !important;
337
+ box-shadow: 0 15px 35px rgba(102, 126, 234, 0.5) !important;
338
+ }
339
+
340
+ .secondary-btn {
341
+ background: #f1f5f9 !important;
342
+ color: #475569 !important;
343
+ border: 2px solid #e2e8f0 !important;
344
+ }
345
+
346
+ .param-group {
347
+ background: #f9fafb;
348
+ padding: 20px;
349
+ border-radius: 12px;
350
+ margin-bottom: 20px;
351
+ border: 1px solid #e5e7eb;
352
+ }
353
+
354
+ .gallery-container {
355
+ background: white;
356
+ padding: 25px;
357
+ border-radius: 16px;
358
+ border: 1px solid #e5e7eb;
359
+ box-shadow: 0 4px 20px rgba(0,0,0,0.05);
360
+ }
361
+
362
+ .status-box {
363
+ background: #f8fafc;
364
+ padding: 20px;
365
+ border-radius: 12px;
366
+ border-left: 5px solid var(--primary-color);
367
+ margin-bottom: 20px;
368
+ font-size: 1.1em;
369
+ }
370
+
371
+ .footer {
372
+ text-align: center;
373
+ color: #666;
374
+ font-size: 0.9em;
375
+ margin-top: 40px;
376
+ padding-top: 20px;
377
+ border-top: 1px solid #e5e7eb;
378
+ }
379
+
380
+ .tab-button {
381
+ font-weight: 600 !important;
382
+ padding: 12px 24px !important;
383
+ }
384
+ """
385
+
386
+ # Create the Gradio interface - FIXED: removed css from Blocks constructor
387
  with gr.Blocks(title="Pixazo Image Generator") as demo:
 
388
 
389
+ # Custom header
390
+ gr.HTML("""
391
+ <div class="header-container">
392
+ <div class="header-title">
393
+ 🎨 Pixazo Image Generator
394
+ </div>
395
+ <div class="header-subtitle">
396
+ Generate stunning AI images with FLUX-1 Schnell model
397
+ </div>
398
+ </div>
399
+ """)
400
+
401
+ # API Status
402
  api_key = get_api_key()
403
  if api_key:
404
+ gr.HTML(f"""
405
+ <div class="api-status api-status-success">
406
+ ✅ API Status: Connected • Key length: {len(api_key)} characters
407
+ </div>
408
+ """)
409
  else:
410
+ gr.HTML("""
411
+ <div class="api-status api-status-error">
412
+ ❌ API Status: Not Configured
413
+ <br><small>Go to Space Settings → Repository secrets → Add: <code>PIXAZO_API_KEY</code> = your API key</small>
414
+ </div>
415
+ """)
416
 
417
+ with gr.Row(equal_height=False):
418
+ # Left Column - Inputs
419
+ with gr.Column(scale=1, min_width=450):
420
+ # Prompt Section
421
+ with gr.Group(elem_classes="input-section"):
422
+ gr.Markdown("""
423
+ <div class="section-title">
424
+ ✨ Image Description
425
+ </div>
426
+ """)
427
+ prompt = gr.Textbox(
428
+ label="",
429
+ placeholder="Describe the image you want to generate in detail...",
430
+ lines=4,
431
+ show_label=False,
432
+ container=False
433
+ )
434
+
435
+ # Parameters Section
436
+ with gr.Group(elem_classes="input-section"):
437
+ gr.Markdown("""
438
+ <div class="section-title">
439
+ ⚙️ Generation Parameters
440
+ </div>
441
+ """)
442
+
443
+ with gr.Row():
444
+ style_preset = gr.Dropdown(
445
+ label="🎭 Style Preset",
446
+ choices=[
447
+ "none", "cyberpunk", "fantasy", "anime", "photographic",
448
+ "digital-art", "comic", "3d-model", "pixel-art",
449
+ "isometric", "watercolor", "oil-painting", "sketch",
450
+ "cinematic", "sci-fi", "renaissance", "impressionist"
451
+ ],
452
+ value="none",
453
+ info="Select an art style"
454
+ )
455
+
456
+ with gr.Row():
457
+ guidance_scale = gr.Slider(
458
+ label="🎯 Guidance Scale",
459
+ minimum=1.0,
460
+ maximum=20.0,
461
+ value=7.5,
462
+ step=0.5,
463
+ info="Higher values = more prompt adherence"
464
+ )
465
+
466
+ with gr.Row():
467
+ num_steps = gr.Slider(
468
+ label="⚡ Inference Steps",
469
+ minimum=1,
470
+ maximum=100,
471
+ value=4,
472
+ step=1,
473
+ info="More steps = better quality but slower"
474
+ )
475
+
476
+ seed = gr.Number(
477
+ label="🌱 Seed",
478
+ value=42,
479
+ minimum=0,
480
+ maximum=999999,
481
+ info="0 for random, fixed for reproducible results"
482
+ )
483
+
484
+ with gr.Row():
485
+ width = gr.Slider(
486
+ label="📏 Width",
487
+ minimum=256,
488
+ maximum=2048,
489
+ value=512,
490
+ step=64,
491
+ info="Image width in pixels"
492
+ )
493
+
494
+ height = gr.Slider(
495
+ label="📐 Height",
496
+ minimum=256,
497
+ maximum=2048,
498
+ value=512,
499
+ step=64,
500
+ info="Image height in pixels"
501
+ )
502
+
503
+ num_images = gr.Slider(
504
+ label="🖼️ Number of Images",
505
+ minimum=1,
506
+ maximum=8,
507
+ value=1,
508
+ step=1,
509
+ info="Generate multiple variations"
510
+ )
511
+
512
+ # Action Buttons
513
+ with gr.Row():
514
+ generate_btn = gr.Button(
515
+ "✨ Generate Images",
516
+ variant="primary",
517
+ scale=3,
518
+ elem_classes="generate-btn"
519
+ )
520
+ clear_btn = gr.Button(
521
+ "🗑️ Clear",
522
+ variant="secondary",
523
+ scale=1,
524
+ elem_classes="secondary-btn"
525
+ )
526
+
527
+ # Examples Section
528
+ with gr.Group(elem_classes="input-section"):
529
+ gr.Markdown("""
530
+ <div class="section-title">
531
+ 💡 Example Prompts
532
+ </div>
533
+ <p style="color: #666; margin-bottom: 15px;">Click any example to try it:</p>
534
+ """)
535
+
536
+ examples = [
537
+ ("Cyberpunk Cityscape", "A futuristic cyberpunk city at night with neon signs, flying cars, and rain reflections", "cyberpunk"),
538
+ ("Fantasy Dragon", "A majestic dragon perched on a mountain peak overlooking a magical kingdom at sunset", "fantasy"),
539
+ ("Anime Character", "A cute anime girl with magical powers in a cherry blossom garden, studio ghibli style", "anime"),
540
+ ("Space Explorer", "An astronaut on Mars with detailed reflection in visor, photorealistic", "photographic"),
541
+ ("Isometric Office", "Cozy isometric bedroom with plants, books, and warm lighting, detailed 3d render", "isometric")
542
+ ]
543
+
544
+ for title, desc, style in examples:
545
+ # Create a clickable example card using a Button with custom styling
546
+ example_btn = gr.Button(
547
+ value=f"{title}: {desc[:50]}...",
548
+ size="sm",
549
+ variant="secondary",
550
+ elem_classes="example-card"
551
+ )
552
+
553
+ def use_example(p=desc, s=style):
554
+ return p, s
555
+
556
+ example_btn.click(
557
+ use_example,
558
+ outputs=[prompt, style_preset]
559
+ )
560
+
561
+ # Right Column - Outputs
562
+ with gr.Column(scale=2, min_width=650):
563
+ # Status Display
564
+ gr.HTML("""
565
+ <div class="section-title">
566
+ 📊 Generation Results
567
+ </div>
568
+ """)
569
+
570
+ status = gr.Textbox(
571
+ label="",
572
+ value="🎯 Ready to generate images. Enter a prompt above and click Generate!",
573
+ interactive=False,
574
+ lines=2,
575
+ container=False,
576
+ elem_classes="status-box"
577
+ )
578
+
579
+ # Gallery
580
+ with gr.Group(elem_classes="gallery-container"):
581
+ gallery = gr.Gallery(
582
+ label="🎨 Generated Images",
583
+ columns=3,
584
+ height="auto",
585
+ object_fit="contain",
586
+ show_label=True,
587
+ preview=True
588
+ )
589
+
590
+ # Tabs for additional info
591
+ with gr.Tabs():
592
+ with gr.TabItem("📈 Generation Details"):
593
+ json_output = gr.JSON(
594
+ label="API Response & Metrics",
595
+ container=True
596
+ )
597
+
598
+ with gr.TabItem("🛠️ Quick Actions"):
599
+ with gr.Column():
600
+ gr.Markdown("""
601
+ ### Quick Actions
602
+
603
+ **Download Options:**
604
+ - Right-click any image to save it
605
+ - Use browser's "Save image as" option
606
+
607
+ **Tips for Better Results:**
608
+ 1. **Be descriptive** - Include details about lighting, style, mood
609
+ 2. **Use specific styles** - Try different style presets
610
+ 3. **Adjust guidance** - Higher values follow prompt more closely
611
+ 4. **Experiment with seeds** - Same seed + same prompt = same image
612
+ """)
613
+
614
+ with gr.TabItem("ℹ️ About"):
615
+ gr.Markdown(f"""
616
+ ### About This Application
617
+
618
+ **Version:** 1.0.0
619
+ **Gradio:** {gr.__version__}
620
+ **API Format:** `{"output": "IMAGE_URL"}`
621
+
622
+ **How It Works:**
623
+ 1. Your prompt is sent to Pixazo's FLUX-1 Schnell API
624
+ 2. API returns a JSON response with an image URL
625
+ 3. App downloads and displays the image
626
+ 4. All metadata is shown for transparency
627
+
628
+ **Credits:**
629
+ - Powered by [Pixazo AI](https://pixazo.ai)
630
+ - Built with [Gradio](https://gradio.app)
631
+ - Hosted on [Hugging Face Spaces](https://huggingface.co/spaces)
632
+
633
+ **Note:** API key must be set in Space secrets for this to work.
634
+ """)
635
+
636
+ # Footer
637
+ gr.HTML("""
638
+ <div class="footer">
639
+ <p>Built with ❤️ using Gradio • Powered by Pixazo FLUX-1 Schnell</p>
640
+ <p>Model: flux-1-schnell • Response Format: <code>{"output": "IMAGE_URL"}</code></p>
641
+ </div>
642
+ """)
643
+
644
+ # Event Handlers
645
+ def on_generate(prompt, num_steps, seed, height, width, style_preset, num_images, guidance_scale):
646
+ if not prompt.strip():
647
+ yield None, "❌ Please enter a prompt first", {"error": "No prompt provided"}
648
+ return
649
 
650
+ # Generator function that yields progress
651
+ for gallery_val, status_val, json_val in generate_images(
652
+ prompt, num_steps, seed, height, width, style_preset, num_images, guidance_scale
653
+ ):
654
+ yield gallery_val, status_val, json_val
655
+
656
+ def on_clear():
657
+ return None, "🎯 Ready to generate images. Enter a prompt above and click Generate!", None
658
 
659
+ # Connect buttons
660
+ generate_btn.click(
661
+ fn=on_generate,
662
+ inputs=[prompt, num_steps, seed, height, width, style_preset, num_images, guidance_scale],
663
+ outputs=[gallery, status, json_output]
664
+ )
665
+
666
+ clear_btn.click(
667
+ fn=on_clear,
668
+ outputs=[gallery, status, json_output]
669
+ )
670
 
671
+ # Launch the app
672
  if __name__ == "__main__":
673
+ print("=" * 60)
674
+ print("🚀 Pixazo Image Generator")
675
+ print("🎨 Beautiful UI with Gradio 6.2.0 - FIXED VERSION")
676
+ print(f"📦 Gradio Version: {gr.__version__}")
677
+ print(f"🔑 API Key Configured: {'Yes' if get_api_key() else 'No'}")
678
+ print("=" * 60)
679
+
680
+ # Launch with css parameter in launch() method for Gradio 6.x
681
+ demo.launch(
682
+ server_name="0.0.0.0",
683
+ server_port=7860,
684
+ share=False,
685
+ css=custom_css
686
+ )