Daniel251 commited on
Commit
fd8b1b9
·
verified ·
1 Parent(s): bda20db

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +97 -258
app.py CHANGED
@@ -1,15 +1,13 @@
1
  """
2
  🎨 Basic Image Adjustments - App 2 do Photoshop AI Ecosystem
3
- Versão definitiva para Hugging Face Spaces com Gradio 6.2.0
4
  """
5
 
6
  import gradio as gr
7
  from PIL import Image, ImageEnhance, ImageOps
8
  import tempfile
9
  import numpy as np
10
- import traceback
11
  import sys
12
- import os
13
 
14
  print("=" * 50)
15
  print("🚀 INICIANDO APP BASIC ADJUSTMENTS")
@@ -20,84 +18,49 @@ print("=" * 50)
20
 
21
  # ========== FUNÇÕES DE PROCESSAMENTO ==========
22
 
23
- def log_function_call(func_name, *args):
24
- """Registra chamadas de função para debug"""
25
- print(f"📝 [{func_name}] Chamada com {len(args)} argumentos")
26
- return True
27
-
28
  def process_image(image, brightness=1.0, contrast=1.0, saturation=1.0, sharpness=1.0, auto_contrast=False):
29
  """Aplica ajustes básicos à imagem"""
30
- log_function_call("process_image", brightness, contrast, saturation, sharpness, auto_contrast)
31
-
32
  try:
33
  if image is None:
34
- print("⚠️ process_image: imagem é None")
35
  return None
36
 
37
- print(f"📊 process_image: tipo da entrada: {type(image)}")
38
-
39
  # Converter para PIL Image se necessário
40
  if isinstance(image, np.ndarray):
41
- print("🔧 Convertendo numpy array para PIL Image")
42
  img = Image.fromarray(image.astype('uint8'))
43
- elif isinstance(image, dict):
44
- # Gradio 6+ pode retornar dict
45
- print("🔧 Convertendo dict para PIL Image")
46
- if 'image' in image:
47
- img = Image.fromarray(image['image'])
48
- else:
49
- print("❌ Dict não contém 'image' key")
50
- return None
51
  else:
52
- print("🔧 Usando imagem como está")
53
  img = image
54
 
55
- print(f"📏 process_image: tamanho da imagem: {img.size}")
56
- print(f"🎨 process_image: modo da imagem: {img.mode}")
 
57
 
58
  # Aplicar contraste automático
59
  if auto_contrast:
60
- print("⚡ Aplicando contraste automático")
61
  img = ImageOps.autocontrast(img, cutoff=2)
62
 
63
- # Aplicar ajustes na ordem correta
64
- adjustments_applied = []
65
-
66
  if brightness != 1.0:
67
- print(f"☀️ Aplicando brilho: {brightness}")
68
  img = ImageEnhance.Brightness(img).enhance(brightness)
69
- adjustments_applied.append(f"brilho={brightness}")
70
 
71
  if contrast != 1.0:
72
- print(f"🎭 Aplicando contraste: {contrast}")
73
  img = ImageEnhance.Contrast(img).enhance(contrast)
74
- adjustments_applied.append(f"contraste={contrast}")
75
 
76
  if saturation != 1.0:
77
- print(f"🌈 Aplicando saturação: {saturation}")
78
  img = ImageEnhance.Color(img).enhance(saturation)
79
- adjustments_applied.append(f"saturação={saturation}")
80
 
81
  if sharpness != 1.0:
82
- print(f"🔍 Aplicando nitidez: {sharpness}")
83
  img = ImageEnhance.Sharpness(img).enhance(sharpness)
84
- adjustments_applied.append(f"nitidez={sharpness}")
85
-
86
- if adjustments_applied:
87
- print(f"✅ Ajustes aplicados: {', '.join(adjustments_applied)}")
88
- else:
89
- print("ℹ️ Nenhum ajuste aplicado (valores padrão)")
90
 
91
  return img
92
 
93
  except Exception as e:
94
  print(f"❌ ERRO em process_image: {str(e)}")
95
- print(traceback.format_exc())
96
  return None
97
 
98
  def get_preset(preset_name):
99
  """Retorna valores para os presets"""
100
- print(f"🎯 get_preset: {preset_name}")
101
  presets = {
102
  'vibrant': (1.2, 1.3, 1.4, 1.1, False),
103
  'soft': (1.05, 0.9, 0.8, 0.9, False),
@@ -106,128 +69,68 @@ def get_preset(preset_name):
106
  'bw': (1.0, 1.2, 0.0, 1.1, False),
107
  'reset': (1.0, 1.0, 1.0, 1.0, False)
108
  }
109
- result = presets.get(preset_name, presets['reset'])
110
- print(f"📋 Preset {preset_name}: {result}")
111
- return result
112
 
113
  def save_image(image):
114
  """Salva imagem para download"""
115
- log_function_call("save_image")
116
-
117
  try:
118
  if image is None:
119
- print("❌ save_image: imagem é None")
120
  return None
121
 
122
- print(f"💾 Salvando imagem para download")
123
  temp_file = tempfile.NamedTemporaryFile(delete=False, suffix=".png", prefix="adjusted_")
124
  image.save(temp_file.name, "PNG", optimize=True)
125
- print(f"✅ Imagem salva em: {temp_file.name}")
126
  return temp_file.name
127
 
128
  except Exception as e:
129
  print(f"❌ ERRO em save_image: {str(e)}")
130
- print(traceback.format_exc())
131
  return None
132
 
133
  def update_on_load(image):
134
  """Atualiza displays quando imagem é carregada"""
135
- print("🔄 update_on_load chamado")
136
- log_function_call("update_on_load")
137
-
138
- try:
139
- if image is None:
140
- print("⚠️ update_on_load: imagem é None")
141
- return None, None
142
-
143
- print(f"📥 Imagem carregada, tipo: {type(image)}")
144
- processed = process_image(image)
145
- print("✅ update_on_load concluído")
146
- return image, processed
147
-
148
- except Exception as e:
149
- print(f"❌ ERRO em update_on_load: {str(e)}")
150
  return None, None
 
 
 
151
 
152
  def update_on_change(image, b, c, s, sh, ac):
153
  """Atualiza imagem quando controles mudam"""
154
- log_function_call("update_on_change", b, c, s, sh, ac)
155
-
156
- try:
157
- if image is None:
158
- print("⚠️ update_on_change: imagem é None")
159
- return None
160
-
161
- print(f"🔄 Atualizando com parâmetros: brilho={b}, contraste={c}, saturação={s}, nitidez={sh}, auto={ac}")
162
- result = process_image(image, b, c, s, sh, ac)
163
- print("✅ update_on_change concluído")
164
- return result
165
-
166
- except Exception as e:
167
- print(f"❌ ERRO em update_on_change: {str(e)}")
168
  return None
 
 
169
 
170
- # ========== INTERFACE GRADIO ==========
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
171
 
172
- print("🎨 Criando interface Gradio...")
173
 
174
- # Criar interface SEM css no construtor (corrige warning do Gradio 6+)
175
- with gr.Blocks(title="🎨 Basic Image Adjustments") as demo:
176
-
177
- # Aplicar CSS depois
178
- demo.css = """
179
- .header-box {
180
- text-align: center;
181
- padding: 20px;
182
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
183
- border-radius: 10px;
184
- color: white;
185
- margin-bottom: 20px;
186
- }
187
- .control-box {
188
- padding: 15px;
189
- background: #f8f9fa;
190
- border-radius: 8px;
191
- margin-bottom: 10px;
192
- border: 1px solid #dee2e6;
193
- }
194
- .preset-btn {
195
- margin: 5px;
196
- transition: all 0.3s;
197
- }
198
- .preset-btn:hover {
199
- transform: translateY(-2px);
200
- box-shadow: 0 4px 8px rgba(0,0,0,0.1);
201
- }
202
- .image-box {
203
- border: 2px solid #e0e0e0;
204
- border-radius: 10px;
205
- padding: 10px;
206
- background: white;
207
- box-shadow: 0 2px 4px rgba(0,0,0,0.05);
208
- }
209
- .download-btn {
210
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
211
- color: white;
212
- border: none;
213
- padding: 12px 24px;
214
- border-radius: 8px;
215
- font-weight: bold;
216
- transition: all 0.3s;
217
- }
218
- .download-btn:hover {
219
- transform: translateY(-2px);
220
- box-shadow: 0 4px 12px rgba(102, 126, 234, 0.4);
221
- }
222
- .slider-label {
223
- font-weight: bold;
224
- color: #333;
225
- margin-bottom: 5px;
226
- display: block;
227
- }
228
- """
229
-
230
- print("✅ CSS aplicado")
231
 
232
  # Cabeçalho
233
  gr.HTML("""
@@ -238,8 +141,6 @@ with gr.Blocks(title="🎨 Basic Image Adjustments") as demo:
238
  </div>
239
  """)
240
 
241
- print("✅ Cabeçalho criado")
242
-
243
  with gr.Row():
244
  # Coluna 1: Upload e Controles
245
  with gr.Column(scale=1):
@@ -248,22 +149,19 @@ with gr.Blocks(title="🎨 Basic Image Adjustments") as demo:
248
  image_input = gr.Image(
249
  type="pil",
250
  label="Clique ou arraste uma imagem aqui",
251
- height=180,
252
- elem_classes="image-box"
253
  )
254
 
255
- print("✅ Componente de upload criado")
256
-
257
  gr.Markdown("### ⚙️ Controles de Ajuste")
258
 
259
- with gr.Column(elem_classes="control-box"):
260
  brightness = gr.Slider(
261
  minimum=0.0,
262
  maximum=2.0,
263
  value=1.0,
264
  step=0.1,
265
  label="☀️ Brilho",
266
- info="Controla a luminosidade geral (0=escuro, 1=normal, 2=brilhante)"
267
  )
268
 
269
  contrast = gr.Slider(
@@ -272,7 +170,7 @@ with gr.Blocks(title="🎨 Basic Image Adjustments") as demo:
272
  value=1.0,
273
  step=0.1,
274
  label="🎭 Contraste",
275
- info="Controla a diferença entre cores claras e escuras"
276
  )
277
 
278
  saturation = gr.Slider(
@@ -281,7 +179,7 @@ with gr.Blocks(title="🎨 Basic Image Adjustments") as demo:
281
  value=1.0,
282
  step=0.1,
283
  label="🌈 Saturação",
284
- info="Controla a intensidade das cores (0=preto e branco)"
285
  )
286
 
287
  sharpness = gr.Slider(
@@ -296,28 +194,23 @@ with gr.Blocks(title="🎨 Basic Image Adjustments") as demo:
296
  auto_contrast = gr.Checkbox(
297
  label="⚡ Contraste Automático",
298
  value=False,
299
- info="Otimiza automaticamente o contraste da imagem"
300
  )
301
-
302
- print("✅ Controles criados")
303
 
304
  # Coluna 2: Presets e Visualização
305
  with gr.Column(scale=1):
306
  gr.Markdown("### 🎨 Presets Rápidos")
307
 
308
  with gr.Row():
309
- vibrant_btn = gr.Button("✨ Vibrante", variant="secondary", size="sm", elem_classes="preset-btn")
310
- soft_btn = gr.Button("🌸 Suave", variant="secondary", size="sm", elem_classes="preset-btn")
311
- dramatic_btn = gr.Button("🌑 Dramático", variant="secondary", size="sm", elem_classes="preset-btn")
312
 
313
  with gr.Row():
314
- retro_btn = gr.Button("📻 Retrô", variant="secondary", size="sm", elem_classes="preset-btn")
315
- bw_btn = gr.Button("⚫ Preto & Branco", variant="secondary", size="sm", elem_classes="preset-btn")
316
- reset_btn = gr.Button("🔄 Resetar", variant="stop", size="sm", elem_classes="preset-btn")
317
-
318
- print("✅ Botões de preset criados")
319
 
320
- # Visualização
321
  gr.Markdown("### 👁️ Visualização")
322
 
323
  with gr.Row():
@@ -327,7 +220,6 @@ with gr.Blocks(title="🎨 Basic Image Adjustments") as demo:
327
  type="pil",
328
  interactive=False,
329
  height=220,
330
- elem_classes="image-box",
331
  show_label=False
332
  )
333
 
@@ -337,11 +229,8 @@ with gr.Blocks(title="🎨 Basic Image Adjustments") as demo:
337
  type="pil",
338
  interactive=False,
339
  height=220,
340
- elem_classes="image-box",
341
  show_label=False
342
  )
343
-
344
- print("✅ Displays de imagem criados")
345
 
346
  # Download
347
  with gr.Row():
@@ -351,20 +240,15 @@ with gr.Blocks(title="🎨 Basic Image Adjustments") as demo:
351
  download_btn = gr.Button(
352
  "📥 Baixar Imagem Ajustada",
353
  variant="primary",
354
- size="lg",
355
- elem_classes="download-btn"
356
  )
357
 
358
  download_file = gr.File(
359
  label="Arquivo para download",
360
  interactive=False
361
  )
362
-
363
- print("✅ Botão de download criado")
364
-
365
- # ========== CONECTAR EVENTOS ==========
366
 
367
- print("🔗 Conectando eventos...")
368
 
369
  # Quando imagem é carregada
370
  image_input.change(
@@ -374,48 +258,44 @@ with gr.Blocks(title="🎨 Basic Image Adjustments") as demo:
374
  )
375
 
376
  # Quando controles mudam
377
- controls_list = [brightness, contrast, saturation, sharpness, auto_contrast]
378
 
379
- for control in controls_list:
380
  control.change(
381
  fn=update_on_change,
382
- inputs=[image_input, brightness, contrast, saturation, sharpness, auto_contrast],
383
  outputs=[processed_display]
384
  )
385
 
386
  # Presets
387
- def apply_preset_wrapper(preset_name):
388
- print(f"🎯 Aplicando preset: {preset_name}")
389
- return get_preset(preset_name)
390
-
391
  vibrant_btn.click(
392
- fn=lambda: apply_preset_wrapper('vibrant'),
393
- outputs=[brightness, contrast, saturation, sharpness, auto_contrast]
394
  )
395
 
396
  soft_btn.click(
397
- fn=lambda: apply_preset_wrapper('soft'),
398
- outputs=[brightness, contrast, saturation, sharpness, auto_contrast]
399
  )
400
 
401
  dramatic_btn.click(
402
- fn=lambda: apply_preset_wrapper('dramatic'),
403
- outputs=[brightness, contrast, saturation, sharpness, auto_contrast]
404
  )
405
 
406
  retro_btn.click(
407
- fn=lambda: apply_preset_wrapper('retro'),
408
- outputs=[brightness, contrast, saturation, sharpness, auto_contrast]
409
  )
410
 
411
  bw_btn.click(
412
- fn=lambda: apply_preset_wrapper('bw'),
413
- outputs=[brightness, contrast, saturation, sharpness, auto_contrast]
414
  )
415
 
416
  reset_btn.click(
417
- fn=lambda: apply_preset_wrapper('reset'),
418
- outputs=[brightness, contrast, saturation, sharpness, auto_contrast]
419
  )
420
 
421
  # Download
@@ -425,86 +305,45 @@ with gr.Blocks(title="🎨 Basic Image Adjustments") as demo:
425
  outputs=[download_file]
426
  )
427
 
428
- print("✅ Todos os eventos conectados")
429
-
430
- # Informações
431
  with gr.Accordion("📖 Guia de Uso & Dicas", open=False):
432
  gr.Markdown("""
433
- ## 🚀 Como usar este app:
434
-
435
- 1. **Faça upload** de uma imagem clicando na área acima
436
- 2. **Ajuste os controles** deslizantes para modificar a imagem
437
- 3. **Use presets** para efeitos rápidos e pré-definidos
438
- 4. **Compare** a imagem original com a ajustada
439
- 5. **Baixe** o resultado final
440
 
441
- ## 💡 Dicas de ajuste:
 
 
 
 
442
 
443
- ### Para **Retratos**:
444
- - Brilho: 1.05
445
- - Contraste: 1.1
446
- - Saturação: 0.9
447
- - Nitidez: 1.0
448
 
449
- ### Para **Paisagens**:
450
- - Brilho: 1.1
451
- - Contraste: 1.2
452
- - Saturação: 1.2
453
- - Nitidez: 1.1
454
 
455
- ### Para **Produtos**:
456
- - Brilho: 1.0
457
- - Contraste: 1.3
458
- - Saturação: 1.0
459
- - Nitidez: 1.2
460
 
461
- ## 🎨 Sobre os presets:
462
- - **Vibrante**: Realça cores para fotos de natureza e paisagens
463
- - **Suave**: Tons sutis e delicados, ideal para retratos
464
- - **Dramático**: Alto contraste para impacto visual
465
- - **Retrô**: Efeito vintage com cores desbotadas
466
- - **Preto & Branco**: Converte para escala de cinza
467
 
468
- ## ⚠️ Problemas comuns:
469
- - **Imagem não aparece**: Verifique se o formato é suportado (JPG, PNG, WEBP)
470
- - **Download não funciona**: Tente usar outra imagem
471
- - **Ajustes lentos**: Imagens muito grandes podem processar mais devagar
 
 
472
  """)
473
 
474
  # Rodapé
475
  gr.HTML(f"""
476
- <div style="
477
- text-align: center;
478
- margin-top: 30px;
479
- padding: 15px;
480
- background: #f8f9fa;
481
- border-radius: 8px;
482
- border-top: 3px solid #667eea;
483
- ">
484
- <p style="margin: 0; font-weight: bold; color: #333;">
485
- 🎨 Basic Image Adjustments - App 2 do Photoshop AI Ecosystem
486
- </p>
487
  <p style="margin: 5px 0 0 0; font-size: 0.9em; color: #666;">
488
- Gradio {gr.__version__} • Python {sys.version.split()[0]} • PIL {Image.__version__}
489
- </p>
490
- <p style="margin: 5px 0 0 0; font-size: 0.85em; color: #888;">
491
- Cada app tem uma função específica • Este app apenas ajusta brilho, contraste, saturação e nitidez
492
  </p>
493
  </div>
494
  """)
495
-
496
- print("✅ Interface completa criada")
497
-
498
- print("=" * 50)
499
- print("✅ APLICATIVO PRONTO PARA EXECUÇÃO")
500
- print("=" * 50)
501
 
502
- # ========== INICIALIZAÇÃO PARA HUGGING FACE ==========
503
- # O Hugging Face Spaces detecta automaticamente a variável 'demo'
504
- # e chama demo.launch() por conta própria
505
- # NÃO chame demo.launch() manualmente aqui
506
 
507
- # Para debug: verificar se o app está pronto
508
- print("🎯 App inicializado com sucesso!")
509
- print("📊 Estado da interface:", "OK" if demo else "ERRO")
510
- print("🏁 Aguardando conexões do Hugging Face Spaces...")
 
1
  """
2
  🎨 Basic Image Adjustments - App 2 do Photoshop AI Ecosystem
3
+ Versão otimizada para Hugging Face Spaces com Gradio 6.2.0
4
  """
5
 
6
  import gradio as gr
7
  from PIL import Image, ImageEnhance, ImageOps
8
  import tempfile
9
  import numpy as np
 
10
  import sys
 
11
 
12
  print("=" * 50)
13
  print("🚀 INICIANDO APP BASIC ADJUSTMENTS")
 
18
 
19
  # ========== FUNÇÕES DE PROCESSAMENTO ==========
20
 
 
 
 
 
 
21
  def process_image(image, brightness=1.0, contrast=1.0, saturation=1.0, sharpness=1.0, auto_contrast=False):
22
  """Aplica ajustes básicos à imagem"""
 
 
23
  try:
24
  if image is None:
 
25
  return None
26
 
 
 
27
  # Converter para PIL Image se necessário
28
  if isinstance(image, np.ndarray):
 
29
  img = Image.fromarray(image.astype('uint8'))
30
+ elif isinstance(image, dict) and 'image' in image:
31
+ img = Image.fromarray(image['image'])
 
 
 
 
 
 
32
  else:
 
33
  img = image
34
 
35
+ # Converter para RGB se necessário
36
+ if img.mode != 'RGB':
37
+ img = img.convert('RGB')
38
 
39
  # Aplicar contraste automático
40
  if auto_contrast:
 
41
  img = ImageOps.autocontrast(img, cutoff=2)
42
 
43
+ # Aplicar ajustes
 
 
44
  if brightness != 1.0:
 
45
  img = ImageEnhance.Brightness(img).enhance(brightness)
 
46
 
47
  if contrast != 1.0:
 
48
  img = ImageEnhance.Contrast(img).enhance(contrast)
 
49
 
50
  if saturation != 1.0:
 
51
  img = ImageEnhance.Color(img).enhance(saturation)
 
52
 
53
  if sharpness != 1.0:
 
54
  img = ImageEnhance.Sharpness(img).enhance(sharpness)
 
 
 
 
 
 
55
 
56
  return img
57
 
58
  except Exception as e:
59
  print(f"❌ ERRO em process_image: {str(e)}")
 
60
  return None
61
 
62
  def get_preset(preset_name):
63
  """Retorna valores para os presets"""
 
64
  presets = {
65
  'vibrant': (1.2, 1.3, 1.4, 1.1, False),
66
  'soft': (1.05, 0.9, 0.8, 0.9, False),
 
69
  'bw': (1.0, 1.2, 0.0, 1.1, False),
70
  'reset': (1.0, 1.0, 1.0, 1.0, False)
71
  }
72
+ return presets.get(preset_name, presets['reset'])
 
 
73
 
74
  def save_image(image):
75
  """Salva imagem para download"""
 
 
76
  try:
77
  if image is None:
 
78
  return None
79
 
 
80
  temp_file = tempfile.NamedTemporaryFile(delete=False, suffix=".png", prefix="adjusted_")
81
  image.save(temp_file.name, "PNG", optimize=True)
 
82
  return temp_file.name
83
 
84
  except Exception as e:
85
  print(f"❌ ERRO em save_image: {str(e)}")
 
86
  return None
87
 
88
  def update_on_load(image):
89
  """Atualiza displays quando imagem é carregada"""
90
+ if image is None:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
91
  return None, None
92
+
93
+ processed = process_image(image)
94
+ return image, processed
95
 
96
  def update_on_change(image, b, c, s, sh, ac):
97
  """Atualiza imagem quando controles mudam"""
98
+ if image is None:
 
 
 
 
 
 
 
 
 
 
 
 
 
99
  return None
100
+
101
+ return process_image(image, b, c, s, sh, ac)
102
 
103
+ # ========== CSS ==========
104
+ css = """
105
+ .header-box {
106
+ text-align: center;
107
+ padding: 20px;
108
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
109
+ border-radius: 10px;
110
+ color: white;
111
+ margin-bottom: 20px;
112
+ }
113
+ .control-box {
114
+ padding: 15px;
115
+ background: #f8f9fa;
116
+ border-radius: 8px;
117
+ margin-bottom: 10px;
118
+ border: 1px solid #dee2e6;
119
+ }
120
+ .preset-btn {
121
+ margin: 5px;
122
+ }
123
+ .image-box {
124
+ border: 2px solid #e0e0e0;
125
+ border-radius: 10px;
126
+ padding: 10px;
127
+ background: white;
128
+ }
129
+ """
130
 
131
+ # ========== INTERFACE GRADIO ==========
132
 
133
+ with gr.Blocks(css=css, title="🎨 Basic Image Adjustments") as demo:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
134
 
135
  # Cabeçalho
136
  gr.HTML("""
 
141
  </div>
142
  """)
143
 
 
 
144
  with gr.Row():
145
  # Coluna 1: Upload e Controles
146
  with gr.Column(scale=1):
 
149
  image_input = gr.Image(
150
  type="pil",
151
  label="Clique ou arraste uma imagem aqui",
152
+ height=180
 
153
  )
154
 
 
 
155
  gr.Markdown("### ⚙️ Controles de Ajuste")
156
 
157
+ with gr.Group():
158
  brightness = gr.Slider(
159
  minimum=0.0,
160
  maximum=2.0,
161
  value=1.0,
162
  step=0.1,
163
  label="☀️ Brilho",
164
+ info="Controla a luminosidade geral"
165
  )
166
 
167
  contrast = gr.Slider(
 
170
  value=1.0,
171
  step=0.1,
172
  label="🎭 Contraste",
173
+ info="Controla a diferença entre cores"
174
  )
175
 
176
  saturation = gr.Slider(
 
179
  value=1.0,
180
  step=0.1,
181
  label="🌈 Saturação",
182
+ info="Controla a intensidade das cores"
183
  )
184
 
185
  sharpness = gr.Slider(
 
194
  auto_contrast = gr.Checkbox(
195
  label="⚡ Contraste Automático",
196
  value=False,
197
+ info="Otimiza automaticamente o contraste"
198
  )
 
 
199
 
200
  # Coluna 2: Presets e Visualização
201
  with gr.Column(scale=1):
202
  gr.Markdown("### 🎨 Presets Rápidos")
203
 
204
  with gr.Row():
205
+ vibrant_btn = gr.Button("✨ Vibrante", size="sm")
206
+ soft_btn = gr.Button("🌸 Suave", size="sm")
207
+ dramatic_btn = gr.Button("🌑 Dramático", size="sm")
208
 
209
  with gr.Row():
210
+ retro_btn = gr.Button("📻 Retrô", size="sm")
211
+ bw_btn = gr.Button("⚫ P&B", size="sm")
212
+ reset_btn = gr.Button("🔄 Resetar", size="sm")
 
 
213
 
 
214
  gr.Markdown("### 👁️ Visualização")
215
 
216
  with gr.Row():
 
220
  type="pil",
221
  interactive=False,
222
  height=220,
 
223
  show_label=False
224
  )
225
 
 
229
  type="pil",
230
  interactive=False,
231
  height=220,
 
232
  show_label=False
233
  )
 
 
234
 
235
  # Download
236
  with gr.Row():
 
240
  download_btn = gr.Button(
241
  "📥 Baixar Imagem Ajustada",
242
  variant="primary",
243
+ size="lg"
 
244
  )
245
 
246
  download_file = gr.File(
247
  label="Arquivo para download",
248
  interactive=False
249
  )
 
 
 
 
250
 
251
+ # ========== EVENTOS ==========
252
 
253
  # Quando imagem é carregada
254
  image_input.change(
 
258
  )
259
 
260
  # Quando controles mudam
261
+ controls = [brightness, contrast, saturation, sharpness, auto_contrast]
262
 
263
+ for control in controls:
264
  control.change(
265
  fn=update_on_change,
266
+ inputs=[image_input] + controls,
267
  outputs=[processed_display]
268
  )
269
 
270
  # Presets
 
 
 
 
271
  vibrant_btn.click(
272
+ fn=lambda: get_preset('vibrant'),
273
+ outputs=controls
274
  )
275
 
276
  soft_btn.click(
277
+ fn=lambda: get_preset('soft'),
278
+ outputs=controls
279
  )
280
 
281
  dramatic_btn.click(
282
+ fn=lambda: get_preset('dramatic'),
283
+ outputs=controls
284
  )
285
 
286
  retro_btn.click(
287
+ fn=lambda: get_preset('retro'),
288
+ outputs=controls
289
  )
290
 
291
  bw_btn.click(
292
+ fn=lambda: get_preset('bw'),
293
+ outputs=controls
294
  )
295
 
296
  reset_btn.click(
297
+ fn=lambda: get_preset('reset'),
298
+ outputs=controls
299
  )
300
 
301
  # Download
 
305
  outputs=[download_file]
306
  )
307
 
308
+ # Guia de uso
 
 
309
  with gr.Accordion("📖 Guia de Uso & Dicas", open=False):
310
  gr.Markdown("""
311
+ ## 🚀 Como usar:
 
 
 
 
 
 
312
 
313
+ 1. **Upload** da imagem
314
+ 2. **Ajuste** os controles deslizantes
315
+ 3. **Use presets** para efeitos rápidos
316
+ 4. **Compare** original vs ajustada
317
+ 5. **Baixe** o resultado
318
 
319
+ ## 💡 Dicas por tipo de foto:
 
 
 
 
320
 
321
+ **Retratos**: Brilho 1.05, Contraste 1.1, Saturação 0.9
 
 
 
 
322
 
323
+ **Paisagens**: Brilho 1.1, Contraste 1.2, Saturação 1.2
 
 
 
 
324
 
325
+ **Produtos**: Brilho 1.0, Contraste 1.3, Nitidez 1.2
 
 
 
 
 
326
 
327
+ ## 🎨 Presets:
328
+ - **Vibrante**: Cores intensas para natureza
329
+ - **Suave**: Tons delicados para retratos
330
+ - **Dramático**: Alto contraste
331
+ - **Retrô**: Efeito vintage
332
+ - **P&B**: Preto e branco
333
  """)
334
 
335
  # Rodapé
336
  gr.HTML(f"""
337
+ <div style="text-align: center; margin-top: 30px; padding: 15px; background: #f8f9fa; border-radius: 8px;">
338
+ <p style="margin: 0; font-weight: bold;">🎨 Basic Image Adjustments - Photoshop AI Ecosystem</p>
 
 
 
 
 
 
 
 
 
339
  <p style="margin: 5px 0 0 0; font-size: 0.9em; color: #666;">
340
+ Gradio {gr.__version__} • Python {sys.version.split()[0]}
 
 
 
341
  </p>
342
  </div>
343
  """)
 
 
 
 
 
 
344
 
345
+ print("✅ Interface criada com sucesso")
346
+ print("🏁 App pronto para Hugging Face Spaces")
 
 
347
 
348
+ # O Hugging Face detecta automaticamente a variável 'demo'
349
+ # NÃO adicione demo.launch() aqui