aaron-official commited on
Commit
2d6593a
·
verified ·
1 Parent(s): 0177267

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +88 -487
app.py CHANGED
@@ -47,376 +47,6 @@ BG_REMOVAL_SERVICES = {
47
  "Clipdrop": "clipdrop"
48
  }
49
 
50
- # Improved Custom CSS for better styling
51
- custom_css = """
52
- /* Root variables for consistent theming */
53
- :root {
54
- --primary-color: #2563eb;
55
- --primary-hover: #1d4ed8;
56
- --secondary-color: #64748b;
57
- --success-color: #10b981;
58
- --error-color: #ef4444;
59
- --warning-color: #f59e0b;
60
- --background-color: #ffffff;
61
- --surface-color: #f8fafc;
62
- --border-color: #e2e8f0;
63
- --text-primary: #0f172a;
64
- --text-secondary: #475569;
65
- --shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05);
66
- --shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
67
- --shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
68
- --border-radius: 8px;
69
- --border-radius-lg: 12px;
70
- }
71
-
72
- /* Main container styling */
73
- .gradio-container {
74
- font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
75
- background: var(--background-color);
76
- color: var(--text-primary);
77
- line-height: 1.5;
78
- }
79
-
80
- /* Header styling */
81
- .app-header {
82
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
83
- color: white;
84
- padding: 2rem;
85
- border-radius: var(--border-radius-lg);
86
- margin-bottom: 2rem;
87
- text-align: center;
88
- box-shadow: var(--shadow-lg);
89
- }
90
-
91
- .app-header h1 {
92
- margin: 0;
93
- font-size: 2.5rem;
94
- font-weight: 700;
95
- letter-spacing: -0.025em;
96
- }
97
-
98
- .app-header p {
99
- margin: 0.75rem 0 0 0;
100
- font-size: 1.125rem;
101
- opacity: 0.9;
102
- font-weight: 400;
103
- }
104
-
105
- /* Tab navigation */
106
- .tab-nav {
107
- background: var(--surface-color);
108
- border: 1px solid var(--border-color);
109
- border-radius: var(--border-radius);
110
- padding: 0.25rem;
111
- margin-bottom: 1.5rem;
112
- }
113
-
114
- .tab-nav button {
115
- background: transparent !important;
116
- border: none !important;
117
- color: var(--text-secondary) !important;
118
- font-weight: 500 !important;
119
- font-size: 0.95rem !important;
120
- padding: 0.75rem 1.5rem !important;
121
- border-radius: calc(var(--border-radius) - 2px) !important;
122
- transition: all 0.2s ease !important;
123
- }
124
-
125
- .tab-nav button:hover {
126
- background: var(--background-color) !important;
127
- color: var(--text-primary) !important;
128
- }
129
-
130
- .tab-nav button.selected {
131
- background: var(--primary-color) !important;
132
- color: white !important;
133
- font-weight: 600 !important;
134
- box-shadow: var(--shadow-sm);
135
- }
136
-
137
- /* Card styling */
138
- .feature-card {
139
- background: var(--background-color);
140
- border: 1px solid var(--border-color);
141
- border-radius: var(--border-radius-lg);
142
- padding: 1.5rem;
143
- margin: 1rem 0;
144
- box-shadow: var(--shadow-sm);
145
- }
146
-
147
- /* Upload areas */
148
- .upload-container {
149
- border: 2px dashed var(--border-color);
150
- border-radius: var(--border-radius);
151
- padding: 2rem;
152
- text-align: center;
153
- background: var(--surface-color);
154
- transition: all 0.3s ease;
155
- color: var(--text-secondary);
156
- }
157
-
158
- .upload-container:hover {
159
- border-color: var(--primary-color);
160
- background: var(--background-color);
161
- transform: translateY(-1px);
162
- box-shadow: var(--shadow-md);
163
- }
164
-
165
- /* Form elements */
166
- .gr-textbox label,
167
- .gr-dropdown label,
168
- .gr-slider label,
169
- .gr-number label,
170
- .gr-checkbox label,
171
- .gr-radio label {
172
- color: var(--text-primary) !important;
173
- font-weight: 500 !important;
174
- font-size: 0.875rem !important;
175
- margin-bottom: 0.5rem !important;
176
- }
177
-
178
- .gr-textbox input,
179
- .gr-dropdown select,
180
- .gr-slider input,
181
- .gr-number input {
182
- color: var(--text-primary) !important;
183
- background: var(--background-color) !important;
184
- border: 1px solid var(--border-color) !important;
185
- border-radius: var(--border-radius) !important;
186
- padding: 0.75rem !important;
187
- font-size: 0.875rem !important;
188
- transition: border-color 0.2s ease !important;
189
- }
190
-
191
- .gr-textbox input:focus,
192
- .gr-dropdown select:focus,
193
- .gr-number input:focus {
194
- outline: none !important;
195
- border-color: var(--primary-color) !important;
196
- box-shadow: 0 0 0 3px rgb(37 99 235 / 0.1) !important;
197
- }
198
-
199
- /* Buttons */
200
- .gr-button {
201
- font-size: 0.875rem !important;
202
- font-weight: 500 !important;
203
- padding: 0.75rem 1.5rem !important;
204
- border-radius: var(--border-radius) !important;
205
- transition: all 0.2s ease !important;
206
- border: 1px solid var(--border-color) !important;
207
- background: var(--background-color) !important;
208
- color: var(--text-primary) !important;
209
- }
210
-
211
- .gr-button:hover {
212
- background: var(--surface-color) !important;
213
- transform: translateY(-1px) !important;
214
- box-shadow: var(--shadow-md) !important;
215
- }
216
-
217
- .gr-button.primary {
218
- background: var(--primary-color) !important;
219
- color: white !important;
220
- border-color: var(--primary-color) !important;
221
- }
222
-
223
- .gr-button.primary:hover {
224
- background: var(--primary-hover) !important;
225
- border-color: var(--primary-hover) !important;
226
- }
227
-
228
- /* Status messages */
229
- .success-message {
230
- color: var(--success-color) !important;
231
- font-weight: 500 !important;
232
- padding: 0.75rem !important;
233
- background: rgb(16 185 129 / 0.1) !important;
234
- border: 1px solid rgb(16 185 129 / 0.2) !important;
235
- border-radius: var(--border-radius) !important;
236
- }
237
-
238
- .error-message {
239
- color: var(--error-color) !important;
240
- font-weight: 500 !important;
241
- padding: 0.75rem !important;
242
- background: rgb(239 68 68 / 0.1) !important;
243
- border: 1px solid rgb(239 68 68 / 0.2) !important;
244
- border-radius: var(--border-radius) !important;
245
- }
246
-
247
- /* Image components */
248
- .gr-image {
249
- border-radius: var(--border-radius) !important;
250
- overflow: hidden !important;
251
- border: 1px solid var(--border-color) !important;
252
- }
253
-
254
- /* Slider styling */
255
- .gr-slider {
256
- margin: 1rem 0 !important;
257
- }
258
-
259
- .gr-slider input[type="range"] {
260
- -webkit-appearance: none !important;
261
- appearance: none !important;
262
- background: var(--border-color) !important;
263
- height: 6px !important;
264
- border-radius: 3px !important;
265
- outline: none !important;
266
- }
267
-
268
- .gr-slider input[type="range"]::-webkit-slider-thumb {
269
- -webkit-appearance: none !important;
270
- appearance: none !important;
271
- width: 20px !important;
272
- height: 20px !important;
273
- background: var(--primary-color) !important;
274
- border-radius: 50% !important;
275
- cursor: pointer !important;
276
- box-shadow: var(--shadow-sm) !important;
277
- }
278
-
279
- .gr-slider input[type="range"]::-moz-range-thumb {
280
- width: 20px !important;
281
- height: 20px !important;
282
- background: var(--primary-color) !important;
283
- border-radius: 50% !important;
284
- cursor: pointer !important;
285
- border: none !important;
286
- box-shadow: var(--shadow-sm) !important;
287
- }
288
-
289
- /* Footer styling */
290
- .app-footer {
291
- margin-top: 3rem;
292
- padding: 2rem;
293
- background: var(--surface-color);
294
- border-radius: var(--border-radius-lg);
295
- border: 1px solid var(--border-color);
296
- text-align: center;
297
- }
298
-
299
- .app-footer h3 {
300
- color: var(--text-primary);
301
- margin-bottom: 1rem;
302
- font-size: 1.25rem;
303
- font-weight: 600;
304
- }
305
-
306
- .footer-grid {
307
- display: grid;
308
- grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
309
- gap: 2rem;
310
- margin-bottom: 1.5rem;
311
- }
312
-
313
- .footer-section {
314
- text-align: left;
315
- }
316
-
317
- .footer-section strong {
318
- color: var(--text-primary);
319
- font-weight: 600;
320
- }
321
-
322
- .footer-section {
323
- color: var(--text-secondary);
324
- font-size: 0.875rem;
325
- line-height: 1.6;
326
- }
327
-
328
- /* Responsive design */
329
- @media (max-width: 768px) {
330
- .app-header h1 {
331
- font-size: 2rem;
332
- }
333
-
334
- .app-header p {
335
- font-size: 1rem;
336
- }
337
-
338
- .footer-grid {
339
- grid-template-columns: 1fr;
340
- gap: 1rem;
341
- }
342
-
343
- .footer-section {
344
- text-align: center;
345
- }
346
- }
347
-
348
- /* Dark mode support */
349
- @media (prefers-color-scheme: dark) {
350
- :root {
351
- --background-color: #0f172a;
352
- --surface-color: #1e293b;
353
- --border-color: #334155;
354
- --text-primary: #f1f5f9;
355
- --text-secondary: #cbd5e1;
356
- }
357
- }
358
-
359
- /* Animation for smooth transitions */
360
- * {
361
- transition: background-color 0.2s ease, border-color 0.2s ease, color 0.2s ease;
362
- }
363
-
364
- /* Improved spacing and typography */
365
- .gr-row {
366
- gap: 1.5rem !important;
367
- }
368
-
369
- .gr-column {
370
- padding: 0 0.75rem !important;
371
- }
372
-
373
- /* JSON output styling */
374
- .gr-json {
375
- background: var(--surface-color) !important;
376
- border: 1px solid var(--border-color) !important;
377
- border-radius: var(--border-radius) !important;
378
- font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace !important;
379
- font-size: 0.875rem !important;
380
- }
381
-
382
- /* File upload styling */
383
- .gr-file {
384
- border: 1px solid var(--border-color) !important;
385
- border-radius: var(--border-radius) !important;
386
- background: var(--surface-color) !important;
387
- }
388
-
389
- /* Checkbox and radio styling */
390
- .gr-checkbox input[type="checkbox"],
391
- .gr-radio input[type="radio"] {
392
- accent-color: var(--primary-color) !important;
393
- }
394
-
395
- /* Loading states */
396
- .gr-button.loading {
397
- opacity: 0.7 !important;
398
- cursor: not-allowed !important;
399
- }
400
-
401
- /* Improved markdown styling */
402
- .gr-markdown {
403
- color: var(--text-primary) !important;
404
- }
405
-
406
- .gr-markdown h1,
407
- .gr-markdown h2,
408
- .gr-markdown h3,
409
- .gr-markdown h4 {
410
- color: var(--text-primary) !important;
411
- font-weight: 600 !important;
412
- }
413
-
414
- .gr-markdown p {
415
- color: var(--text-secondary) !important;
416
- line-height: 1.6 !important;
417
- }
418
- """
419
-
420
  # Android icon sizes (density: size in px)
421
  ANDROID_ICON_SIZES = {
422
  "mdpi": 48,
@@ -439,52 +69,47 @@ def make_android_icons_zip(image: Image.Image) -> str:
439
  return tmp.name # Return the file path for gr.File
440
 
441
  # Main Gradio Interface
442
- with gr.Blocks(css=custom_css, title="🎨 Advanced Image Processing Suite", theme=gr.themes.Default()) as demo:
443
 
444
- # Header
445
- gr.HTML("""
446
- <div class="app-header">
447
- <h1>🎨 Advanced Image Processing Suite</h1>
448
- <p>Professional-grade image processing, AI generation, and enhancement tools</p>
449
- </div>
450
- """)
451
 
452
  with gr.Tabs() as tabs:
453
  # Tab 1: Format
454
- with gr.Tab("🖼️ Format"):
455
  gr.Markdown("### Convert images between multiple formats with advanced options")
456
 
457
  with gr.Row():
458
- with gr.Column(scale=1):
459
- conv_input = gr.Image(label="📎 Upload Image", type="filepath")
460
  conv_format = gr.Dropdown(
461
  choices=SUPPORTED_FORMATS,
462
  value="PNG",
463
- label="🎯 Target Format"
464
  )
465
  conv_quality = gr.Slider(
466
  minimum=10, maximum=100, value=95,
467
- label="🎛️ Quality (for JPEG/WebP)", step=5
468
  )
469
- conv_btn = gr.Button("🚀 Convert Image", variant="primary")
470
 
471
- with gr.Column(scale=1):
472
- conv_output = gr.File(label="📥 Download Converted Image")
473
- conv_status = gr.Textbox(label="📊 Status", interactive=False)
474
 
475
  conv_btn.click(
476
- fn=lambda img, fmt, qual: processor.convert_image(img, fmt, qual) if img else (None, "Please upload an image"),
477
  inputs=[conv_input, conv_format, conv_quality],
478
  outputs=[conv_output, conv_status]
479
  )
480
 
481
  # Tab 2: AI Gen
482
- with gr.Tab("🤖 AI Gen"):
483
  gr.Markdown("### Generate stunning images using state-of-the-art AI models")
484
 
485
  with gr.Row():
486
  with gr.Column():
487
- gr.Markdown("#### 🔑 API Configuration")
488
  openai_key = gr.Textbox(
489
  label="OpenAI API Key",
490
  type="password",
@@ -501,32 +126,32 @@ with gr.Blocks(css=custom_css, title="🎨 Advanced Image Processing Suite", the
501
  placeholder="sk-..."
502
  )
503
 
504
- save_keys_btn = gr.Button("💾 Save API Keys", size="sm")
505
- key_status = gr.Textbox(label="🔐 Key Status", interactive=False)
506
 
507
  with gr.Row():
508
  with gr.Column():
509
  ai_prompt = gr.Textbox(
510
- label="🎨 Image Prompt",
511
  placeholder="A serene landscape with mountains and a lake at sunset...",
512
  lines=3
513
  )
514
  ai_model = gr.Dropdown(
515
  choices=list(AI_MODELS.keys()),
516
  value="OpenAI DALL-E 3",
517
- label="🧠 AI Model"
518
  )
519
  ai_size = gr.Dropdown(
520
  choices=["256x256", "512x512", "1024x1024", "1792x1024", "1024x1792"],
521
  value="1024x1024",
522
- label="📐 Image Size"
523
  )
524
 
525
- generate_btn = gr.Button("Generate Image", variant="primary")
526
 
527
  with gr.Column():
528
- ai_output = gr.Image(label="🖼️ Generated Image")
529
- ai_status = gr.Textbox(label="📊 Generation Status", interactive=False)
530
 
531
  # API key saving (refactored)
532
  def save_api_keys(openai, anthropic, deepseek):
@@ -541,8 +166,8 @@ with gr.Blocks(css=custom_css, title="🎨 Advanced Image Processing Suite", the
541
  if deepseek:
542
  saved_keys.append("DeepSeek")
543
  if saved_keys:
544
- return f"Saved keys for: {', '.join(saved_keys)}"
545
- return "No keys provided"
546
 
547
  save_keys_btn.click(
548
  fn=save_api_keys,
@@ -553,7 +178,7 @@ with gr.Blocks(css=custom_css, title="🎨 Advanced Image Processing Suite", the
553
  # Image generation (fixed: pass API keys directly)
554
  def generate_image(prompt, model, size, openai, anthropic):
555
  if not prompt:
556
- return None, "Please enter a prompt"
557
  if "OpenAI" in model:
558
  model_name = AI_MODELS[model]
559
  temp_gen = AIImageGenerator(openai_key=openai, anthropic_key=anthropic)
@@ -562,7 +187,7 @@ with gr.Blocks(css=custom_css, title="🎨 Advanced Image Processing Suite", the
562
  temp_gen = AIImageGenerator(openai_key=openai, anthropic_key=anthropic)
563
  return temp_gen.generate_image_anthropic(prompt)
564
  else:
565
- return None, f"{model} not yet implemented"
566
 
567
  generate_btn.click(
568
  fn=generate_image,
@@ -571,68 +196,68 @@ with gr.Blocks(css=custom_css, title="🎨 Advanced Image Processing Suite", the
571
  )
572
 
573
  # Tab 3: Enhance
574
- with gr.Tab("Enhance"):
575
  gr.Markdown("### Enhance your images with professional-grade filters and AI")
576
 
577
  with gr.Row():
578
  with gr.Column():
579
- enhance_input = gr.Image(label="📎 Upload Image to Enhance", type="filepath")
580
  enhance_type = gr.Dropdown(
581
  choices=ENHANCEMENT_OPTIONS,
582
  value="Color Enhancement",
583
- label="🎭 Enhancement Type"
584
  )
585
  enhance_intensity = gr.Slider(
586
  minimum=0.1, maximum=2.0, value=1.0, step=0.1,
587
- label="🎛️ Enhancement Intensity"
588
  )
589
- enhance_btn = gr.Button("🚀 Enhance Image", variant="primary")
590
 
591
  with gr.Column():
592
- enhance_output = gr.Image(label="Enhanced Image")
593
- enhance_status = gr.Textbox(label="📊 Enhancement Status", interactive=False)
594
 
595
  enhance_btn.click(
596
- fn=lambda img, enh_type, intensity: processor.enhance_image(img, enh_type, intensity) if img else (None, "Please upload an image"),
597
  inputs=[enhance_input, enhance_type, enhance_intensity],
598
  outputs=[enhance_output, enhance_status]
599
  )
600
 
601
  # Tab 4: BG Remove
602
- with gr.Tab("🎭 BG Remove"):
603
  gr.Markdown("### Remove backgrounds instantly with AI-powered tools")
604
 
605
  with gr.Row():
606
  with gr.Column():
607
- gr.Markdown("#### 🔑 API Keys for Premium Services")
608
  removebg_key = gr.Textbox(
609
  label="Remove.bg API Key",
610
  type="password",
611
  placeholder="Your Remove.bg API key"
612
  )
613
- save_bg_key_btn = gr.Button("💾 Save Remove.bg Key", size="sm")
614
- bg_key_status = gr.Textbox(label="🔐 API Status", interactive=False)
615
 
616
  with gr.Row():
617
  with gr.Column():
618
- bg_input = gr.Image(label="📎 Upload Image", type="filepath")
619
  bg_service = gr.Dropdown(
620
  choices=list(BG_REMOVAL_SERVICES.keys()),
621
  value="Local rembg",
622
- label="🛠️ Background Removal Service"
623
  )
624
- bg_btn = gr.Button("🎭 Remove Background", variant="primary")
625
 
626
  with gr.Column():
627
- bg_output = gr.Image(label="🖼️ Result (Transparent Background)")
628
- bg_status = gr.Textbox(label="📊 Processing Status", interactive=False)
629
 
630
  # Save background removal API key (refactored)
631
  def save_bg_api_key(key):
632
  bg_remover.removebg_key = key
633
  if key:
634
- return "Remove.bg API key saved"
635
- return "No key provided"
636
  save_bg_key_btn.click(
637
  fn=save_bg_api_key,
638
  inputs=removebg_key,
@@ -641,7 +266,7 @@ with gr.Blocks(css=custom_css, title="🎨 Advanced Image Processing Suite", the
641
  # Background removal (fixed: pass Remove.bg key directly)
642
  def remove_bg(img, service, removebg):
643
  if not img:
644
- return None, "Please upload an image"
645
  service_key = BG_REMOVAL_SERVICES.get(service, "local")
646
  if service_key == "local":
647
  return bg_remover.remove_local(img)
@@ -649,7 +274,7 @@ with gr.Blocks(css=custom_css, title="🎨 Advanced Image Processing Suite", the
649
  temp_remover = BackgroundRemover(removebg_key=removebg)
650
  return temp_remover.remove_with_removebg(img)
651
  else:
652
- return None, f"{service} not implemented"
653
  bg_btn.click(
654
  fn=remove_bg,
655
  inputs=[bg_input, bg_service, removebg_key],
@@ -657,27 +282,27 @@ with gr.Blocks(css=custom_css, title="🎨 Advanced Image Processing Suite", the
657
  )
658
 
659
  # Tab 5: Batch
660
- with gr.Tab("📦 Batch"):
661
  gr.Markdown("### Process multiple images simultaneously")
662
 
663
  with gr.Row():
664
  with gr.Column():
665
- batch_files = gr.Files(label="📎 Upload Multiple Images", file_types=["image"])
666
  batch_operation = gr.Dropdown(
667
  choices=["Format Conversion", "Enhancement", "Background Removal"],
668
  value="Format Conversion",
669
- label="🔧 Batch Operation"
670
  )
671
- batch_btn = gr.Button("🚀 Process Batch", variant="primary")
672
 
673
  with gr.Column():
674
- batch_output = gr.Files(label="📥 Download Processed Images")
675
- batch_status = gr.Textbox(label="📊 Batch Status", interactive=False, lines=5)
676
 
677
  # Batch processing (refactored)
678
  def process_batch(files, operation):
679
  if not files:
680
- return None, "Please upload images for batch processing"
681
  results = []
682
  status_messages = []
683
  for i, file in enumerate(files):
@@ -692,7 +317,7 @@ with gr.Blocks(css=custom_css, title="🎨 Advanced Image Processing Suite", the
692
  results.append(result)
693
  status_messages.append(f"File {i+1}: {msg}")
694
  except Exception as e:
695
- status_messages.append(f"File {i+1}: Error - {str(e)}")
696
  return results if results else None, "\n".join(status_messages)
697
  batch_btn.click(
698
  fn=process_batch,
@@ -701,18 +326,18 @@ with gr.Blocks(css=custom_css, title="🎨 Advanced Image Processing Suite", the
701
  )
702
 
703
  # Tab 6: Tools
704
- with gr.Tab("🔬 Tools"):
705
  gr.Markdown("### Professional image analysis and specialized processing")
706
 
707
  with gr.Tabs():
708
- with gr.Tab("🔍 Image Analysis"):
709
  with gr.Row():
710
  with gr.Column():
711
- analysis_input = gr.Image(label="📎 Upload Image for Analysis", type="filepath")
712
- analysis_btn = gr.Button("🔬 Analyze Image", variant="primary")
713
 
714
  with gr.Column():
715
- analysis_output = gr.JSON(label="📊 Image Analysis Results")
716
 
717
  # Advanced Tools: Image Analysis (refactored)
718
  def analyze_image(img_path):
@@ -723,22 +348,22 @@ with gr.Blocks(css=custom_css, title="🎨 Advanced Image Processing Suite", the
723
  outputs=analysis_output
724
  )
725
 
726
- with gr.Tab("🎨 Custom Filters"):
727
  with gr.Row():
728
  with gr.Column():
729
- filter_input = gr.Image(label="📎 Upload Image", type="filepath")
730
 
731
  # Custom filter controls
732
- brightness = gr.Slider(-100, 100, 0, label="☀️ Brightness")
733
- contrast = gr.Slider(-100, 100, 0, label="🌓 Contrast")
734
- saturation = gr.Slider(-100, 100, 0, label="🎨 Saturation")
735
- hue_shift = gr.Slider(-180, 180, 0, label="🌈 Hue Shift")
736
 
737
- apply_filter_btn = gr.Button("🎭 Apply Custom Filter", variant="primary")
738
 
739
  with gr.Column():
740
- filter_output = gr.Image(label="🖼️ Filtered Image")
741
- filter_status = gr.Textbox(label="📊 Filter Status", interactive=False)
742
 
743
  # Advanced Tools: Custom Filters (refactored)
744
  apply_filter_btn.click(
@@ -747,32 +372,32 @@ with gr.Blocks(css=custom_css, title="🎨 Advanced Image Processing Suite", the
747
  outputs=[filter_output, filter_status]
748
  )
749
 
750
- with gr.Tab("📏 Resize & Crop"):
751
  with gr.Row():
752
  with gr.Column():
753
- resize_input = gr.Image(label="📎 Upload Image", type="filepath")
754
 
755
  resize_mode = gr.Radio(
756
  choices=["Resize", "Crop", "Smart Crop", "Canvas Resize"],
757
  value="Resize",
758
- label="🔧 Operation Mode"
759
  )
760
 
761
- new_width = gr.Number(label="📐 Width", value=800)
762
- new_height = gr.Number(label="📐 Height", value=600)
763
 
764
- maintain_ratio = gr.Checkbox(label="🔒 Maintain Aspect Ratio", value=True)
765
  resize_quality = gr.Dropdown(
766
  choices=["NEAREST", "LANCZOS", "BILINEAR", "BICUBIC"],
767
  value="LANCZOS",
768
- label="🎯 Resize Quality"
769
  )
770
 
771
- resize_btn = gr.Button("📏 Process Image", variant="primary")
772
 
773
  with gr.Column():
774
- resize_output = gr.Image(label="🖼️ Processed Image")
775
- resize_status = gr.Textbox(label="📊 Processing Status", interactive=False)
776
 
777
  # Advanced Tools: Resize & Crop (refactored)
778
  resize_btn.click(
@@ -782,56 +407,32 @@ with gr.Blocks(css=custom_css, title="🎨 Advanced Image Processing Suite", the
782
  )
783
 
784
  # Tab 7: Android Icons
785
- with gr.Tab("📱 Android Icons"):
786
  gr.Markdown("### Generate all Android app icon sizes and download as a ZIP")
787
 
788
  with gr.Row():
789
  with gr.Column():
790
- android_icon_input = gr.Image(type="pil", label="📎 Upload Icon Source Image")
791
- android_icon_btn = gr.Button("🚀 Generate Android Icons", variant="primary")
792
 
793
  with gr.Column():
794
- android_icon_zip = gr.File(label="📥 Download Icons ZIP")
795
- android_status = gr.Textbox(label="📊 Generation Status", interactive=False)
796
 
797
  def handle_android_icon(image):
798
  if image is None:
799
- return None, "Please upload an image"
800
  try:
801
  zip_path = make_android_icons_zip(image)
802
- return zip_path, "Android icons generated successfully!"
803
  except Exception as e:
804
- return None, f"Error generating icons: {str(e)}"
805
 
806
  android_icon_btn.click(
807
  fn=handle_android_icon,
808
  inputs=android_icon_input,
809
  outputs=[android_icon_zip, android_status]
810
  )
811
-
812
- # Footer with additional information
813
- gr.HTML("""
814
- <div class="app-footer">
815
- <h3>🚀 Professional Image Processing Suite</h3>
816
- <div class="footer-grid">
817
- <div class="footer-section">
818
- <strong>📋 Supported Formats:</strong><br>
819
- JPEG, PNG, BMP, TIFF, WEBP, GIF, ICO, EPS, PDF, PSD, SVG, HEIC, AVIF, JXL
820
- </div>
821
- <div class="footer-section">
822
- <strong>🤖 AI Services:</strong><br>
823
- OpenAI DALL-E 2/3, Anthropic Claude, DeepSeek, Remove.bg, Clipdrop
824
- </div>
825
- <div class="footer-section">
826
- <strong>✨ Features:</strong><br>
827
- Format Conversion, AI Generation, Enhancement, Background Removal, Batch Processing
828
- </div>
829
- </div>
830
- <p style="margin-top: 1rem; color: var(--text-secondary); font-size: 0.875rem;">
831
- Made with ❤️ using Gradio — by Aaron 🚀
832
- </p>
833
- </div>
834
- """)
835
 
836
 
837
  # Launch configuration
 
47
  "Clipdrop": "clipdrop"
48
  }
49
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
50
  # Android icon sizes (density: size in px)
51
  ANDROID_ICON_SIZES = {
52
  "mdpi": 48,
 
69
  return tmp.name # Return the file path for gr.File
70
 
71
  # Main Gradio Interface
72
+ with gr.Blocks(title="Advanced Image Processing Suite") as demo:
73
 
74
+ gr.Markdown("# Advanced Image Processing Suite")
75
+ gr.Markdown("Professional-grade image processing, AI generation, and enhancement tools")
 
 
 
 
 
76
 
77
  with gr.Tabs() as tabs:
78
  # Tab 1: Format
79
+ with gr.Tab("Format"):
80
  gr.Markdown("### Convert images between multiple formats with advanced options")
81
 
82
  with gr.Row():
83
+ with gr.Column():
84
+ conv_input = gr.Image(label="Upload Image", type="filepath")
85
  conv_format = gr.Dropdown(
86
  choices=SUPPORTED_FORMATS,
87
  value="PNG",
88
+ label="Target Format"
89
  )
90
  conv_quality = gr.Slider(
91
  minimum=10, maximum=100, value=95,
92
+ label="Quality (for JPEG/WebP)", step=5
93
  )
94
+ conv_btn = gr.Button("Convert Image", variant="primary")
95
 
96
+ with gr.Column():
97
+ conv_output = gr.File(label="Download Converted Image")
98
+ conv_status = gr.Textbox(label="Status", interactive=False)
99
 
100
  conv_btn.click(
101
+ fn=lambda img, fmt, qual: processor.convert_image(img, fmt, qual) if img else (None, "Please upload an image"),
102
  inputs=[conv_input, conv_format, conv_quality],
103
  outputs=[conv_output, conv_status]
104
  )
105
 
106
  # Tab 2: AI Gen
107
+ with gr.Tab("AI Gen"):
108
  gr.Markdown("### Generate stunning images using state-of-the-art AI models")
109
 
110
  with gr.Row():
111
  with gr.Column():
112
+ gr.Markdown("#### API Configuration")
113
  openai_key = gr.Textbox(
114
  label="OpenAI API Key",
115
  type="password",
 
126
  placeholder="sk-..."
127
  )
128
 
129
+ save_keys_btn = gr.Button("Save API Keys")
130
+ key_status = gr.Textbox(label="Key Status", interactive=False)
131
 
132
  with gr.Row():
133
  with gr.Column():
134
  ai_prompt = gr.Textbox(
135
+ label="Image Prompt",
136
  placeholder="A serene landscape with mountains and a lake at sunset...",
137
  lines=3
138
  )
139
  ai_model = gr.Dropdown(
140
  choices=list(AI_MODELS.keys()),
141
  value="OpenAI DALL-E 3",
142
+ label="AI Model"
143
  )
144
  ai_size = gr.Dropdown(
145
  choices=["256x256", "512x512", "1024x1024", "1792x1024", "1024x1792"],
146
  value="1024x1024",
147
+ label="Image Size"
148
  )
149
 
150
+ generate_btn = gr.Button("Generate Image", variant="primary")
151
 
152
  with gr.Column():
153
+ ai_output = gr.Image(label="Generated Image")
154
+ ai_status = gr.Textbox(label="Generation Status", interactive=False)
155
 
156
  # API key saving (refactored)
157
  def save_api_keys(openai, anthropic, deepseek):
 
166
  if deepseek:
167
  saved_keys.append("DeepSeek")
168
  if saved_keys:
169
+ return f"Saved keys for: {', '.join(saved_keys)}"
170
+ return "No keys provided"
171
 
172
  save_keys_btn.click(
173
  fn=save_api_keys,
 
178
  # Image generation (fixed: pass API keys directly)
179
  def generate_image(prompt, model, size, openai, anthropic):
180
  if not prompt:
181
+ return None, "Please enter a prompt"
182
  if "OpenAI" in model:
183
  model_name = AI_MODELS[model]
184
  temp_gen = AIImageGenerator(openai_key=openai, anthropic_key=anthropic)
 
187
  temp_gen = AIImageGenerator(openai_key=openai, anthropic_key=anthropic)
188
  return temp_gen.generate_image_anthropic(prompt)
189
  else:
190
+ return None, f"{model} not yet implemented"
191
 
192
  generate_btn.click(
193
  fn=generate_image,
 
196
  )
197
 
198
  # Tab 3: Enhance
199
+ with gr.Tab("Enhance"):
200
  gr.Markdown("### Enhance your images with professional-grade filters and AI")
201
 
202
  with gr.Row():
203
  with gr.Column():
204
+ enhance_input = gr.Image(label="Upload Image to Enhance", type="filepath")
205
  enhance_type = gr.Dropdown(
206
  choices=ENHANCEMENT_OPTIONS,
207
  value="Color Enhancement",
208
+ label="Enhancement Type"
209
  )
210
  enhance_intensity = gr.Slider(
211
  minimum=0.1, maximum=2.0, value=1.0, step=0.1,
212
+ label="Enhancement Intensity"
213
  )
214
+ enhance_btn = gr.Button("Enhance Image", variant="primary")
215
 
216
  with gr.Column():
217
+ enhance_output = gr.Image(label="Enhanced Image")
218
+ enhance_status = gr.Textbox(label="Enhancement Status", interactive=False)
219
 
220
  enhance_btn.click(
221
+ fn=lambda img, enh_type, intensity: processor.enhance_image(img, enh_type, intensity) if img else (None, "Please upload an image"),
222
  inputs=[enhance_input, enhance_type, enhance_intensity],
223
  outputs=[enhance_output, enhance_status]
224
  )
225
 
226
  # Tab 4: BG Remove
227
+ with gr.Tab("BG Remove"):
228
  gr.Markdown("### Remove backgrounds instantly with AI-powered tools")
229
 
230
  with gr.Row():
231
  with gr.Column():
232
+ gr.Markdown("#### API Keys for Premium Services")
233
  removebg_key = gr.Textbox(
234
  label="Remove.bg API Key",
235
  type="password",
236
  placeholder="Your Remove.bg API key"
237
  )
238
+ save_bg_key_btn = gr.Button("Save Remove.bg Key")
239
+ bg_key_status = gr.Textbox(label="API Status", interactive=False)
240
 
241
  with gr.Row():
242
  with gr.Column():
243
+ bg_input = gr.Image(label="Upload Image", type="filepath")
244
  bg_service = gr.Dropdown(
245
  choices=list(BG_REMOVAL_SERVICES.keys()),
246
  value="Local rembg",
247
+ label="Background Removal Service"
248
  )
249
+ bg_btn = gr.Button("Remove Background", variant="primary")
250
 
251
  with gr.Column():
252
+ bg_output = gr.Image(label="Result (Transparent Background)")
253
+ bg_status = gr.Textbox(label="Processing Status", interactive=False)
254
 
255
  # Save background removal API key (refactored)
256
  def save_bg_api_key(key):
257
  bg_remover.removebg_key = key
258
  if key:
259
+ return "Remove.bg API key saved"
260
+ return "No key provided"
261
  save_bg_key_btn.click(
262
  fn=save_bg_api_key,
263
  inputs=removebg_key,
 
266
  # Background removal (fixed: pass Remove.bg key directly)
267
  def remove_bg(img, service, removebg):
268
  if not img:
269
+ return None, "Please upload an image"
270
  service_key = BG_REMOVAL_SERVICES.get(service, "local")
271
  if service_key == "local":
272
  return bg_remover.remove_local(img)
 
274
  temp_remover = BackgroundRemover(removebg_key=removebg)
275
  return temp_remover.remove_with_removebg(img)
276
  else:
277
+ return None, f"{service} not implemented"
278
  bg_btn.click(
279
  fn=remove_bg,
280
  inputs=[bg_input, bg_service, removebg_key],
 
282
  )
283
 
284
  # Tab 5: Batch
285
+ with gr.Tab("Batch"):
286
  gr.Markdown("### Process multiple images simultaneously")
287
 
288
  with gr.Row():
289
  with gr.Column():
290
+ batch_files = gr.Files(label="Upload Multiple Images", file_types=["image"])
291
  batch_operation = gr.Dropdown(
292
  choices=["Format Conversion", "Enhancement", "Background Removal"],
293
  value="Format Conversion",
294
+ label="Batch Operation"
295
  )
296
+ batch_btn = gr.Button("Process Batch", variant="primary")
297
 
298
  with gr.Column():
299
+ batch_output = gr.Files(label="Download Processed Images")
300
+ batch_status = gr.Textbox(label="Batch Status", interactive=False, lines=5)
301
 
302
  # Batch processing (refactored)
303
  def process_batch(files, operation):
304
  if not files:
305
+ return None, "Please upload images for batch processing"
306
  results = []
307
  status_messages = []
308
  for i, file in enumerate(files):
 
317
  results.append(result)
318
  status_messages.append(f"File {i+1}: {msg}")
319
  except Exception as e:
320
+ status_messages.append(f"File {i+1}: Error - {str(e)}")
321
  return results if results else None, "\n".join(status_messages)
322
  batch_btn.click(
323
  fn=process_batch,
 
326
  )
327
 
328
  # Tab 6: Tools
329
+ with gr.Tab("Tools"):
330
  gr.Markdown("### Professional image analysis and specialized processing")
331
 
332
  with gr.Tabs():
333
+ with gr.Tab("Image Analysis"):
334
  with gr.Row():
335
  with gr.Column():
336
+ analysis_input = gr.Image(label="Upload Image for Analysis", type="filepath")
337
+ analysis_btn = gr.Button("Analyze Image", variant="primary")
338
 
339
  with gr.Column():
340
+ analysis_output = gr.JSON(label="Image Analysis Results")
341
 
342
  # Advanced Tools: Image Analysis (refactored)
343
  def analyze_image(img_path):
 
348
  outputs=analysis_output
349
  )
350
 
351
+ with gr.Tab("Custom Filters"):
352
  with gr.Row():
353
  with gr.Column():
354
+ filter_input = gr.Image(label="Upload Image", type="filepath")
355
 
356
  # Custom filter controls
357
+ brightness = gr.Slider(-100, 100, 0, label="Brightness")
358
+ contrast = gr.Slider(-100, 100, 0, label="Contrast")
359
+ saturation = gr.Slider(-100, 100, 0, label="Saturation")
360
+ hue_shift = gr.Slider(-180, 180, 0, label="Hue Shift")
361
 
362
+ apply_filter_btn = gr.Button("Apply Custom Filter", variant="primary")
363
 
364
  with gr.Column():
365
+ filter_output = gr.Image(label="Filtered Image")
366
+ filter_status = gr.Textbox(label="Filter Status", interactive=False)
367
 
368
  # Advanced Tools: Custom Filters (refactored)
369
  apply_filter_btn.click(
 
372
  outputs=[filter_output, filter_status]
373
  )
374
 
375
+ with gr.Tab("Resize & Crop"):
376
  with gr.Row():
377
  with gr.Column():
378
+ resize_input = gr.Image(label="Upload Image", type="filepath")
379
 
380
  resize_mode = gr.Radio(
381
  choices=["Resize", "Crop", "Smart Crop", "Canvas Resize"],
382
  value="Resize",
383
+ label="Operation Mode"
384
  )
385
 
386
+ new_width = gr.Number(label="Width", value=800)
387
+ new_height = gr.Number(label="Height", value=600)
388
 
389
+ maintain_ratio = gr.Checkbox(label="Maintain Aspect Ratio", value=True)
390
  resize_quality = gr.Dropdown(
391
  choices=["NEAREST", "LANCZOS", "BILINEAR", "BICUBIC"],
392
  value="LANCZOS",
393
+ label="Resize Quality"
394
  )
395
 
396
+ resize_btn = gr.Button("Process Image", variant="primary")
397
 
398
  with gr.Column():
399
+ resize_output = gr.Image(label="Processed Image")
400
+ resize_status = gr.Textbox(label="Processing Status", interactive=False)
401
 
402
  # Advanced Tools: Resize & Crop (refactored)
403
  resize_btn.click(
 
407
  )
408
 
409
  # Tab 7: Android Icons
410
+ with gr.Tab("Android Icons"):
411
  gr.Markdown("### Generate all Android app icon sizes and download as a ZIP")
412
 
413
  with gr.Row():
414
  with gr.Column():
415
+ android_icon_input = gr.Image(type="pil", label="Upload Icon Source Image")
416
+ android_icon_btn = gr.Button("Generate Android Icons", variant="primary")
417
 
418
  with gr.Column():
419
+ android_icon_zip = gr.File(label="Download Icons ZIP")
420
+ android_status = gr.Textbox(label="Generation Status", interactive=False)
421
 
422
  def handle_android_icon(image):
423
  if image is None:
424
+ return None, "Please upload an image"
425
  try:
426
  zip_path = make_android_icons_zip(image)
427
+ return zip_path, "Android icons generated successfully!"
428
  except Exception as e:
429
+ return None, f"Error generating icons: {str(e)}"
430
 
431
  android_icon_btn.click(
432
  fn=handle_android_icon,
433
  inputs=android_icon_input,
434
  outputs=[android_icon_zip, android_status]
435
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
436
 
437
 
438
  # Launch configuration