nftnik commited on
Commit
5c1d384
·
verified ·
1 Parent(s): 1311abc

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +289 -165
app.py CHANGED
@@ -1,198 +1,321 @@
1
  import os
2
  import sys
3
  import random
 
 
4
  import torch
5
- from pathlib import Path
6
- from PIL import Image
7
  import gradio as gr
 
8
  from huggingface_hub import hf_hub_download
9
- import spaces
10
- from typing import Union, Sequence, Mapping, Any
11
-
12
- # 1. Configuração de Caminhos e Imports
13
- current_dir = os.path.dirname(os.path.abspath(__file__))
14
- comfyui_path = os.path.join(current_dir, "ComfyUI")
15
- sys.path.append(comfyui_path)
16
-
17
- # 2. Imports do ComfyUI
18
- import folder_paths
19
- from nodes import NODE_CLASS_MAPPINGS, init_extra_nodes
20
-
21
- # 3. Configuração de Diretórios
22
- BASE_DIR = os.path.dirname(os.path.realpath(__file__))
23
- output_dir = os.path.join(BASE_DIR, "output")
24
- models_dir = os.path.join(BASE_DIR, "models")
25
- os.makedirs(output_dir, exist_ok=True)
26
- os.makedirs(models_dir, exist_ok=True)
27
- folder_paths.set_output_directory(output_dir)
28
-
29
- # 4. Diagnóstico CUDA
30
- print("Python version:", sys.version)
31
- print("Torch version:", torch.__version__)
32
- print("CUDA disponível:", torch.cuda.is_available())
33
- print("Quantidade de GPUs:", torch.cuda.device_count())
34
- if torch.cuda.is_available():
35
- print("GPU atual:", torch.cuda.get_device_name(0))
36
-
37
- # 5. Inicialização do ComfyUI
38
- print("Inicializando ComfyUI...")
39
- init_extra_nodes()
40
-
41
- # 6. Helper Functions
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
42
  def get_value_at_index(obj: Union[Sequence, Mapping], index: int) -> Any:
 
43
  try:
44
  return obj[index]
45
  except KeyError:
46
  return obj["result"][index]
47
 
48
- # 7. Download de Modelos
49
- def download_models():
50
- print("Baixando modelos...")
51
- models = [
52
- ("black-forest-labs/FLUX.1-Redux-dev", "flux1-redux-dev.safetensors", "style_models"),
53
- ("comfyanonymous/flux_text_encoders", "t5xxl_fp16.safetensors", "text_encoders"),
54
- ("zer0int/CLIP-GmP-ViT-L-14", "ViT-L-14-TEXT-detail-improved-hiT-GmP-HF.safetensors", "text_encoders"),
55
- ("black-forest-labs/FLUX.1-dev", "ae.safetensors", "vae"),
56
- ("black-forest-labs/FLUX.1-dev", "flux1-dev.safetensors", "diffusion_models"),
57
- ("google/siglip-so400m-patch14-384", "model.safetensors", "clip_vision")
58
- ]
59
-
60
- for repo_id, filename, model_type in models:
61
- try:
62
- model_dir = os.path.join(models_dir, model_type)
63
- os.makedirs(model_dir, exist_ok=True)
64
- print(f"Baixando {filename} de {repo_id}...")
65
- hf_hub_download(repo_id=repo_id, filename=filename, local_dir=model_dir)
66
- # Adicionar o diretório ao folder_paths
67
- folder_paths.add_model_folder_path(model_type, model_dir)
68
- except Exception as e:
69
- print(f"Erro ao baixar {filename} de {repo_id}: {str(e)}")
70
- continue
71
-
72
- # 8. Download e Inicialização dos Modelos
73
- print("Baixando modelos...")
74
- download_models()
75
-
76
- print("Inicializando modelos...")
77
- with torch.inference_mode():
78
- # CLIP
79
- dualcliploader = NODE_CLASS_MAPPINGS["DualCLIPLoader"]()
80
- dualcliploader_357 = dualcliploader.load_clip(
81
- clip_name1="t5xxl_fp16.safetensors",
82
- clip_name2="ViT-L-14-TEXT-detail-improved-hiT-GmP-HF.safetensors",
83
- type="flux"
84
- )
85
 
86
- # CLIP Vision
87
- clipvisionloader = NODE_CLASS_MAPPINGS["CLIPVisionLoader"]()
88
- clip_vision = clipvisionloader.load_clip(
89
- clip_name="model.safetensors"
90
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
91
 
92
- # Style Model
93
- stylemodelloader = NODE_CLASS_MAPPINGS["StyleModelLoader"]()
94
- stylemodelloader_441 = stylemodelloader.load_style_model(
95
- style_model_name="flux1-redux-dev.safetensors"
96
- )
 
97
 
98
- # VAE
99
- vaeloader = NODE_CLASS_MAPPINGS["VAELoader"]()
100
- vaeloader_359 = vaeloader.load_vae(
101
- vae_name="ae.safetensors"
102
- )
103
 
104
- # 9. Função de Geração
105
- @spaces.GPU
106
- def generate_image(prompt, input_image, lora_weight, guidance, downsampling_factor, weight, seed, width, height, batch_size, steps, progress=gr.Progress(track_tqdm=True)):
107
- try:
108
- with torch.inference_mode():
109
- # Codificar texto
110
- cliptextencode = NODE_CLASS_MAPPINGS["CLIPTextEncode"]()
111
- encoded_text = cliptextencode.encode(
112
- text=prompt,
113
- clip=dualcliploader_357[0]
114
- )
115
 
116
- # Carregar e processar imagem
117
- loadimage = NODE_CLASS_MAPPINGS["LoadImage"]()
118
- loaded_image = loadimage.load_image(image=input_image)
 
 
 
 
 
 
 
 
 
119
 
120
- # Flux Guidance
121
- fluxguidance = NODE_CLASS_MAPPINGS["FluxGuidance"]()
122
- flux_guidance = fluxguidance.append(
123
- guidance=guidance,
124
- conditioning=encoded_text[0]
125
- )
 
126
 
127
- # Redux Advanced
128
- reduxadvanced = NODE_CLASS_MAPPINGS["ReduxAdvanced"]()
129
- redux_result = reduxadvanced.apply_stylemodel(
130
- downsampling_factor=downsampling_factor,
131
- downsampling_function="area",
132
- mode="keep aspect ratio",
133
- weight=weight,
134
- conditioning=flux_guidance[0],
135
- style_model=stylemodelloader_441[0],
136
- clip_vision=clip_vision[0],
137
- image=loaded_image[0]
138
- )
 
 
139
 
140
- # Empty Latent
141
- emptylatentimage = NODE_CLASS_MAPPINGS["EmptyLatentImage"]()
142
- empty_latent = emptylatentimage.generate(
143
- width=width,
144
- height=height,
145
- batch_size=batch_size
146
- )
147
 
148
- # KSampler
149
- ksampler = NODE_CLASS_MAPPINGS["KSampler"]()
150
- sampled = ksampler.sample(
151
- seed=seed,
152
- steps=steps,
153
- cfg=1,
154
- sampler_name="euler",
155
- scheduler="simple",
156
- denoise=1,
157
- model=stylemodelloader_441[0],
158
- positive=redux_result[0],
159
- negative=flux_guidance[0],
160
- latent_image=empty_latent[0]
161
- )
162
 
163
- # Decodificar VAE
164
- vaedecode = NODE_CLASS_MAPPINGS["VAEDecode"]()
165
- decoded = vaedecode.decode(
166
- samples=sampled[0],
167
- vae=vaeloader_359[0]
168
- )
 
 
 
 
 
 
 
169
 
170
- # Salvar imagem
171
- temp_filename = f"Flux_{random.randint(0, 99999)}.png"
172
- temp_path = os.path.join(output_dir, temp_filename)
173
- Image.fromarray((decoded[0] * 255).astype("uint8")).save(temp_path)
174
 
175
- return temp_path
176
  except Exception as e:
177
  print(f"Erro ao gerar imagem: {str(e)}")
178
  return None
179
 
180
- # 10. Interface Gradio
 
 
 
181
  with gr.Blocks() as app:
182
- gr.Markdown("# FLUX Redux Image Generator")
183
-
184
  with gr.Row():
185
  with gr.Column():
186
  prompt_input = gr.Textbox(
187
  label="Prompt",
188
- placeholder="Enter your prompt here...",
189
  lines=5
190
  )
191
  input_image = gr.Image(
192
- label="Input Image",
193
  type="filepath"
194
  )
195
-
196
  with gr.Row():
197
  with gr.Column():
198
  lora_weight = gr.Slider(
@@ -200,7 +323,7 @@ with gr.Blocks() as app:
200
  maximum=2,
201
  step=0.1,
202
  value=0.6,
203
- label="LoRA Weight"
204
  )
205
  guidance = gr.Slider(
206
  minimum=0,
@@ -221,7 +344,7 @@ with gr.Blocks() as app:
221
  maximum=2,
222
  step=0.1,
223
  value=1.0,
224
- label="Model Weight"
225
  )
226
  with gr.Column():
227
  seed = gr.Number(
@@ -230,12 +353,12 @@ with gr.Blocks() as app:
230
  precision=0
231
  )
232
  width = gr.Number(
233
- value=1024,
234
  label="Width",
235
  precision=0
236
  )
237
  height = gr.Number(
238
- value=1024,
239
  label="Height",
240
  precision=0
241
  )
@@ -249,12 +372,12 @@ with gr.Blocks() as app:
249
  label="Steps",
250
  precision=0
251
  )
252
-
253
  generate_btn = gr.Button("Generate Image")
254
-
255
  with gr.Column():
256
  output_image = gr.Image(label="Generated Image", type="filepath")
257
-
258
  generate_btn.click(
259
  fn=generate_image,
260
  inputs=[
@@ -274,4 +397,5 @@ with gr.Blocks() as app:
274
  )
275
 
276
  if __name__ == "__main__":
277
- app.launch()
 
 
1
  import os
2
  import sys
3
  import random
4
+ from typing import Sequence, Mapping, Any, Union
5
+
6
  import torch
 
 
7
  import gradio as gr
8
+ from PIL import Image
9
  from huggingface_hub import hf_hub_download
10
+
11
+ import spaces # Se estiver no Hugging Face Spaces. Se não, pode remover.
12
+
13
+ #####################################
14
+ # 1. Funções auxiliares de caminho e import
15
+ #####################################
16
+
17
+ def find_path(name: str, path: str = None) -> str:
18
+ """Busca recursivamente por uma pasta/arquivo 'name' a partir de 'path'."""
19
+ if path is None:
20
+ path = os.getcwd()
21
+ if name in os.listdir(path):
22
+ path_name = os.path.join(path, name)
23
+ print(f"{name} encontrado em: {path_name}")
24
+ return path_name
25
+ parent_directory = os.path.dirname(path)
26
+ if parent_directory == path:
27
+ return None
28
+ return find_path(name, parent_directory)
29
+
30
+ def add_comfyui_directory_to_sys_path() -> None:
31
+ """Adiciona o diretório ComfyUI ao sys.path, caso encontrado."""
32
+ comfyui_path = find_path("ComfyUI")
33
+ if comfyui_path is not None and os.path.isdir(comfyui_path):
34
+ sys.path.append(comfyui_path)
35
+ print(f"Diretório ComfyUI adicionado ao sys.path: {comfyui_path}")
36
+ else:
37
+ print("Não foi possível encontrar o diretório ComfyUI.")
38
+
39
+ def add_extra_model_paths() -> None:
40
+ """
41
+ Carrega configurações extras de caminhos de modelos, se existir
42
+ um arquivo 'extra_model_paths.yaml'.
43
+ """
44
+ try:
45
+ from main import load_extra_path_config
46
+ except ImportError:
47
+ # Dependendo da versão do ComfyUI, pode estar em 'utils.extra_config'
48
+ from utils.extra_config import load_extra_path_config
49
+
50
+ extra_model_paths = find_path("extra_model_paths.yaml")
51
+ if extra_model_paths is not None:
52
+ load_extra_path_config(extra_model_paths)
53
+ else:
54
+ print("Arquivo extra_model_paths.yaml não foi encontrado.")
55
+
56
+ def import_custom_nodes() -> None:
57
+ """
58
+ Executa a inicialização de nós extras e o servidor do ComfyUI (caso necessário),
59
+ similar ao que ocorre no segundo script.
60
+ """
61
+ import asyncio
62
+ import execution
63
+ from nodes import init_extra_nodes
64
+ import server
65
+
66
+ loop = asyncio.new_event_loop()
67
+ asyncio.set_event_loop(loop)
68
+ server_instance = server.PromptServer(loop)
69
+ execution.PromptQueue(server_instance)
70
+ init_extra_nodes()
71
+
72
+ #####################################
73
+ # 2. Ajustando o ambiente ComfyUI
74
+ #####################################
75
+
76
+ add_comfyui_directory_to_sys_path()
77
+ add_extra_model_paths()
78
+ import_custom_nodes()
79
+
80
+ #####################################
81
+ # 3. Importando nós do ComfyUI
82
+ #####################################
83
+ from comfy import model_management
84
+ from nodes import (
85
+ NODE_CLASS_MAPPINGS,
86
+ DualCLIPLoader,
87
+ CLIPVisionLoader,
88
+ StyleModelLoader,
89
+ VAELoader,
90
+ CLIPTextEncode,
91
+ LoadImage,
92
+ EmptyLatentImage,
93
+ VAEDecode
94
+ )
95
+
96
+ #####################################
97
+ # 4. Download de modelos (ajuste conforme sua necessidade)
98
+ #####################################
99
+
100
+ # Exemplo de downloads (ajuste conforme seus modelos):
101
+ os.makedirs("models/text_encoders", exist_ok=True)
102
+ os.makedirs("models/style_models", exist_ok=True)
103
+ os.makedirs("models/diffusion_models", exist_ok=True)
104
+ os.makedirs("models/vae", exist_ok=True)
105
+ os.makedirs("models/clip_vision", exist_ok=True)
106
+
107
+ try:
108
+ print("Baixando modelo Style (flux1-redux-dev.safetensors)...")
109
+ hf_hub_download(repo_id="black-forest-labs/FLUX.1-Redux-dev",
110
+ filename="flux1-redux-dev.safetensors",
111
+ local_dir="models/style_models")
112
+ print("Baixando T5 (t5xxl_fp16.safetensors)...")
113
+ hf_hub_download(repo_id="comfyanonymous/flux_text_encoders",
114
+ filename="t5xxl_fp16.safetensors",
115
+ local_dir="models/text_encoders")
116
+
117
+ print("Baixando CLIP L (ViT-L-14) ...")
118
+ hf_hub_download(repo_id="zer0int/CLIP-GmP-ViT-L-14",
119
+ filename="ViT-L-14-TEXT-detail-improved-hiT-GmP-HF.safetensors",
120
+ local_dir="models/text_encoders")
121
+ print("Baixando VAE (ae.safetensors)...")
122
+ hf_hub_download(repo_id="black-forest-labs/FLUX.1-dev",
123
+ filename="ae.safetensors",
124
+ local_dir="models/vae")
125
+ print("Baixando flux1-dev.safetensors (modelo difusão)...")
126
+ hf_hub_download(repo_id="black-forest-labs/FLUX.1-dev",
127
+ filename="flux1-dev.safetensors",
128
+ local_dir="models/diffusion_models")
129
+ print("Baixando CLIP Vision (model.safetensors)...")
130
+ hf_hub_download(repo_id="google/siglip-so400m-patch14-384",
131
+ filename="model.safetensors",
132
+ local_dir="models/clip_vision")
133
+ except Exception as e:
134
+ print("Algum download falhou:", e)
135
+
136
+ #####################################
137
+ # 5. Carregar modelos via ComfyUI
138
+ #####################################
139
+
140
+ # Carregando CLIP (DualCLIPLoader)
141
+ dualcliploader = DualCLIPLoader()
142
+ clip_model = dualcliploader.load_clip(
143
+ clip_name1="t5xxl_fp16.safetensors",
144
+ clip_name2="ViT-L-14-TEXT-detail-improved-hiT-GmP-HF.safetensors",
145
+ type="flux"
146
+ )
147
+
148
+ # Carregando CLIP Vision
149
+ clipvisionloader = CLIPVisionLoader()
150
+ clip_vision_model = clipvisionloader.load_clip(
151
+ clip_name="model.safetensors"
152
+ )
153
+
154
+ # Carregando Style Model
155
+ stylemodelloader = StyleModelLoader()
156
+ style_model = stylemodelloader.load_style_model(
157
+ style_model_name="flux1-redux-dev.safetensors"
158
+ )
159
+
160
+ # Carregando VAE
161
+ vaeloader = VAELoader()
162
+ vae_model = vaeloader.load_vae(
163
+ vae_name="ae.safetensors"
164
+ )
165
+
166
+ # (Opcional) Se tiver um model UNet, faça UNETLoader, etc.
167
+
168
+ # Opcional: Carregar para GPU
169
+ model_management.load_models_gpu([
170
+ loader[0] for loader in [clip_model, clip_vision_model, style_model, vae_model]
171
+ ])
172
+
173
+ #####################################
174
+ # 6. Funções auxiliares e placeholders
175
+ #####################################
176
+
177
  def get_value_at_index(obj: Union[Sequence, Mapping], index: int) -> Any:
178
+ """Retorna o 'index' de um objeto que pode ser um dict ou lista."""
179
  try:
180
  return obj[index]
181
  except KeyError:
182
  return obj["result"][index]
183
 
184
+ #####################################
185
+ # 7. Definir workflow simplificado
186
+ #####################################
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
187
 
188
+ @spaces.GPU # Se estiver no Hugging Face Spaces. Senão, remova.
189
+ def generate_image(
190
+ prompt: str,
191
+ input_image_path: str,
192
+ lora_weight: float,
193
+ guidance: float,
194
+ downsampling_factor: float,
195
+ weight: float,
196
+ seed: int,
197
+ width: int,
198
+ height: int,
199
+ batch_size: int,
200
+ steps: int,
201
+ progress=gr.Progress(track_tqdm=True)
202
+ ):
203
+ """
204
+ Gera imagem usando um fluxo simplificado, similar ao primeiro script.
205
+ """
206
+ try:
207
+ # Garantindo repetibilidade do seed
208
+ torch.manual_seed(seed)
209
+ random.seed(seed)
210
 
211
+ # 1) Encode Texto
212
+ cliptextencode = CLIPTextEncode()
213
+ encoded_text = cliptextencode.encode(
214
+ text=prompt,
215
+ clip=get_value_at_index(clip_model, 0)
216
+ )
217
 
218
+ # 2) Carregar imagem de entrada
219
+ loadimage = LoadImage()
220
+ loaded_image = loadimage.load_image(image=input_image_path)
 
 
221
 
222
+ # 3) Flux Guidance (se existir)
223
+ fluxguidance = NODE_CLASS_MAPPINGS["FluxGuidance"]()
224
+ flux_guided = fluxguidance.append(
225
+ guidance=guidance,
226
+ conditioning=get_value_at_index(encoded_text, 0)
227
+ )
 
 
 
 
 
228
 
229
+ # 4) Redux Advanced (aplicar style model)
230
+ reduxadvanced = NODE_CLASS_MAPPINGS["ReduxAdvanced"]()
231
+ redux_result = reduxadvanced.apply_stylemodel(
232
+ downsampling_factor=downsampling_factor,
233
+ downsampling_function="area",
234
+ mode="keep aspect ratio",
235
+ weight=weight,
236
+ conditioning=get_value_at_index(flux_guided, 0),
237
+ style_model=get_value_at_index(style_model, 0),
238
+ clip_vision=get_value_at_index(clip_vision_model, 0),
239
+ image=get_value_at_index(loaded_image, 0)
240
+ )
241
 
242
+ # 5) Empty Latent
243
+ emptylatent = EmptyLatentImage()
244
+ empty_latent = emptylatent.generate(
245
+ width=width,
246
+ height=height,
247
+ batch_size=batch_size
248
+ )
249
 
250
+ # 6) KSampler (no ComfyUI atual, há "KSamplerSelect" ou "KSampler")
251
+ ksampler = NODE_CLASS_MAPPINGS["KSampler"]()
252
+ sampled = ksampler.sample(
253
+ seed=seed,
254
+ steps=steps,
255
+ cfg=1, # Exemplo de CFG = 1
256
+ sampler_name="euler",
257
+ scheduler="simple",
258
+ denoise=1,
259
+ model=get_value_at_index(style_model, 0), # Usa o style model como UNet? (depende da config)
260
+ positive=get_value_at_index(redux_result, 0),
261
+ negative=get_value_at_index(flux_guided, 0),
262
+ latent_image=get_value_at_index(empty_latent, 0)
263
+ )
264
 
265
+ # 7) Decodificar VAE
266
+ vaedecode = VAEDecode()
267
+ decoded = vaedecode.decode(
268
+ samples=get_value_at_index(sampled, 0),
269
+ vae=get_value_at_index(vae_model, 0)
270
+ )
 
271
 
272
+ # 8) Salvar imagem
273
+ output_dir = "output"
274
+ os.makedirs(output_dir, exist_ok=True)
275
+ temp_filename = f"Flux_{random.randint(0, 99999)}.png"
276
+ temp_path = os.path.join(output_dir, temp_filename)
 
 
 
 
 
 
 
 
 
277
 
278
+ # No ComfyUI, 'decoded[0]' pode ser um tensor [C,H,W] normalizado
279
+ # ou algo no formato [N,C,H,W]. Precisamos converter para PIL:
280
+ # Se for um batch, pegue o primeiro item. Ajuste se quiser batch maior.
281
+ image_data = get_value_at_index(decoded, 0)
282
+ # Normalmente, se for "float [0,1]" em C,H,W:
283
+ # Precisamos mover pro CPU e converter em numpy
284
+ if isinstance(image_data, torch.Tensor):
285
+ image_data = image_data.cpu().numpy()
286
+
287
+ # Se a imagem estiver em [C,H,W], transpor para [H,W,C] e escalar 0..255
288
+ if len(image_data.shape) == 3:
289
+ image_data = image_data.transpose(1, 2, 0)
290
+ image_data = (image_data * 255).clip(0, 255).astype("uint8")
291
 
292
+ pil_image = Image.fromarray(image_data)
293
+ pil_image.save(temp_path)
 
 
294
 
295
+ return temp_path
296
  except Exception as e:
297
  print(f"Erro ao gerar imagem: {str(e)}")
298
  return None
299
 
300
+ #####################################
301
+ # 8. Interface Gradio (similar ao primeiro snippet)
302
+ #####################################
303
+
304
  with gr.Blocks() as app:
305
+ gr.Markdown("# FLUX Redux Image Generator (Simplificado)")
306
+
307
  with gr.Row():
308
  with gr.Column():
309
  prompt_input = gr.Textbox(
310
  label="Prompt",
311
+ placeholder="Escreva seu prompt...",
312
  lines=5
313
  )
314
  input_image = gr.Image(
315
+ label="Imagem de Entrada",
316
  type="filepath"
317
  )
318
+
319
  with gr.Row():
320
  with gr.Column():
321
  lora_weight = gr.Slider(
 
323
  maximum=2,
324
  step=0.1,
325
  value=0.6,
326
+ label="LoRA Weight (não usado nesse fluxo)"
327
  )
328
  guidance = gr.Slider(
329
  minimum=0,
 
344
  maximum=2,
345
  step=0.1,
346
  value=1.0,
347
+ label="Redux Model Weight"
348
  )
349
  with gr.Column():
350
  seed = gr.Number(
 
353
  precision=0
354
  )
355
  width = gr.Number(
356
+ value=512,
357
  label="Width",
358
  precision=0
359
  )
360
  height = gr.Number(
361
+ value=512,
362
  label="Height",
363
  precision=0
364
  )
 
372
  label="Steps",
373
  precision=0
374
  )
375
+
376
  generate_btn = gr.Button("Generate Image")
377
+
378
  with gr.Column():
379
  output_image = gr.Image(label="Generated Image", type="filepath")
380
+
381
  generate_btn.click(
382
  fn=generate_image,
383
  inputs=[
 
397
  )
398
 
399
  if __name__ == "__main__":
400
+ # Você pode usar app.launch(share=True) se quiser compartilhar via link.
401
+ app.launch()