euIaxs22 commited on
Commit
be0cee3
·
verified ·
1 Parent(s): 28eef4f

Update app_vince.py

Browse files
Files changed (1) hide show
  1. app_vince.py +220 -79
app_vince.py CHANGED
@@ -1,33 +1,39 @@
1
  import os
2
  import sys
 
 
 
3
  import torch
4
  import gradio as gr
5
  from PIL import Image
6
- from omegaconf import OmegaConf
7
 
8
- # --- ETAPA 1: CONFIGURAÇÃO DO AMBIENTE ---
9
 
 
10
  VINCIE_DIR = "/app/VINCIE"
11
  if VINCIE_DIR not in sys.path:
12
  sys.path.append(VINCIE_DIR)
13
 
14
  try:
15
  from generate import VINCIEGenerator
16
- from common.distributed import get_device
17
- from common.config import load_config
18
  except ImportError as e:
19
- print(f"FATAL: Não foi possível importar os módulos do VINCIE.")
20
- print(f"Verifique se o diretório '{VINCIE_DIR}' contém o código-fonte clonado.")
21
  raise e
22
 
23
- # --- ETAPA 2: INICIALIZAÇÃO DO MODELO (Simplificado para uma GPU) ---
24
 
25
- MODEL: VINCIEGenerator = None
26
- DEVICE: torch.device = None
 
27
 
28
  def setup_model():
29
  """
30
- Função de inicialização que carrega o modelo VINCIE em uma única GPU.
 
31
  """
32
  global MODEL, DEVICE
33
 
@@ -35,130 +41,265 @@ def setup_model():
35
  raise RuntimeError("FATAL: Nenhuma GPU compatível com CUDA foi encontrada.")
36
 
37
  num_gpus = torch.cuda.device_count()
38
- print(f"INFO: Detectadas {num_gpus} GPUs. Usando cuda:0 para a aplicação.")
39
  if num_gpus == 0:
40
- raise RuntimeError("FATAL: Nenhuma GPU foi alocada para este contêiner.")
41
-
 
42
  DEVICE = torch.device("cuda:0")
43
  torch.cuda.set_device(DEVICE)
44
 
45
- config_path = "configs/generate.yaml"
46
- print(f"INFO: Carregando e resolvendo configuração do modelo de '{config_path}'...")
47
  config = load_config(config_path, [])
48
 
49
  print("INFO: Instanciando VINCIEGenerator...")
50
  model_instance = VINCIEGenerator(config)
51
 
52
- print("INFO: Configurando a persistência (modo de inferência)...")
 
53
  model_instance.configure_persistence()
54
-
55
- print("INFO: Configurando os componentes do modelo (DiT, VAE, Text Encoder)...")
56
- # O método `configure_models` já move os modelos para o dispositivo CUDA definido
57
  model_instance.configure_models()
58
-
59
- print("INFO: Configurando os componentes de difusão...")
60
  model_instance.configure_diffusion()
61
 
62
  if not hasattr(model_instance, 'dit'):
63
- raise RuntimeError("FATAL: O modelo 'dit' não foi criado após a configuração.")
64
 
65
- # Opcional: garantir que tudo está no dispositivo correto (geralmente já feito)
66
  model_instance.dit.to(DEVICE)
67
  model_instance.vae.to(DEVICE)
68
  model_instance.text_encoder.to(DEVICE)
69
 
70
  MODEL = model_instance
71
- print(f"✅ SUCESSO: O modelo VINCIE está pronto na GPU {DEVICE}.")
72
 
 
73
 
74
- # --- ETAPA 3: LÓGICA DE INFERÊNCIA ---
 
 
 
 
 
 
 
 
 
75
 
76
- def perform_inference(input_image: str, prompt: str):
77
- if MODEL is None:
78
- raise gr.Error("O modelo não está carregado. Verifique os logs de inicialização.")
79
- if input_image is None or not prompt.strip():
80
- raise gr.Error( necessário fornecer uma imagem de entrada e um prompt de edição.")
81
-
82
- print(f"INFO: Recebida nova requisição. Prompt: '{prompt}'")
83
- turn_1_prompt = [prompt]
84
- image_paths = [input_image]
 
 
 
 
 
 
 
 
 
85
 
86
  try:
87
- print("INFO: Preparando entradas com `model.prepare_input()`...")
88
 
89
- prompt_dict = {
90
- "index": 0, "img_paths": image_paths, "context": turn_1_prompt,
91
- }
92
- prompt_config = OmegaConf.create(prompt_dict)
 
 
 
 
93
 
 
94
  text_pos, condition, noise, _, _ = MODEL.prepare_input(
95
- prompt=prompt_config,
96
- repeat_idx=0,
97
- device=DEVICE # Usa o dispositivo único definido
98
  )
99
 
 
100
  with torch.no_grad():
101
- print("INFO: Executando `model.inference()`...")
102
  samples = MODEL.inference(
103
  noises=[noise],
104
  conditions=[condition],
105
  texts_pos=[text_pos],
106
  texts_neg=[MODEL.config.generation.negative_prompt],
 
107
  )
108
- print("INFO: Inferência concluída.")
109
 
110
  if not samples:
111
- raise RuntimeError("A inferência não retornou nenhum resultado.")
112
 
 
113
  output_tensor = samples[0][:, -1, :, :]
114
- output_image = output_tensor.clip(-1, 1).add(1).div(2).mul(255).byte()
115
- output_image = output_image.permute(1, 2, 0).cpu().numpy()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
116
 
117
- print("✅ SUCESSO: Imagem processada e retornada para a UI.")
118
- return output_image
119
 
120
- except Exception as e:
121
- print(f"ERRO: Falha durante a inferência: {e}")
122
- import traceback
123
- traceback.print_exc()
124
- raise gr.Error(f"Ocorreu um erro inesperado. Detalhes: {str(e)}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
125
 
126
 
127
- # --- ETAPA 4 e 5: UI e Lançamento (sem alterações) ---
128
 
129
  def create_ui():
130
- with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue"), title="VINCIE Image Editor") as demo:
131
- # ... (código da UI idêntico)
132
- gr.Markdown("# 🖼️ **VINCIE: Editor de Imagens por Contexto**\nFaça o upload de uma imagem e descreva a edição que você deseja realizar.")
133
- with gr.Row():
134
- with gr.Column(scale=1):
135
- image_input = gr.Image(type="filepath", label="Imagem de Entrada")
136
- prompt_input = gr.Textbox(lines=3, label="O que você quer mudar?", placeholder="Ex: 'mude o fundo para uma praia ensolarada'")
137
- submit_button = gr.Button(" Gerar Edição", variant="primary")
138
- with gr.Column(scale=1):
139
- image_output = gr.Image(label="Resultado da Edição", interactive=False, height=512)
140
- gr.Examples(
141
- examples=[
142
- ["/app/VINCIE/assets/woman_pineapple.png", "Adicione uma coroa na cabeça da mulher."],
143
- ["/app/VINCIE/assets/da_vinci.png", "Remova o chapéu da cabeça de Leonardo e mude seu casaco para um de cor azul."],
144
- ["/app/VINCIE/assets/dog1.png", "Transforme o cachorro em um filhote de leão."],
145
- ],
146
- inputs=[image_input, prompt_input],
147
- outputs=image_output,
148
- fn=perform_inference,
149
- cache_examples=False,
150
- )
151
- submit_button.click(fn=perform_inference, inputs=[image_input, prompt_input], outputs=[image_output])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
152
  return demo
153
 
 
 
154
  if __name__ == "__main__":
155
  setup_model()
156
  ui = create_ui()
157
- server_name = os.environ.get("GRADIO_SERVER_NAME", "127.0.0.1")
 
158
  server_port = int(os.environ.get("GRADIO_SERVER_PORT", 7860))
159
  enable_queue = os.environ.get("GRADIO_ENABLE_QUEUE", "True").lower() == "true"
 
160
  print(f"INFO: Lançando a interface Gradio em http://{server_name}:{server_port}")
161
  if enable_queue:
162
- print("INFO: Fila de requisições (queue) ativada.")
163
  ui.queue()
 
164
  ui.launch(server_name=server_name, server_port=server_port)
 
1
  import os
2
  import sys
3
+ import uuid
4
+ from typing import List, Dict, Any, Optional, Tuple
5
+
6
  import torch
7
  import gradio as gr
8
  from PIL import Image
9
+ from omegaconf import OmegaConf, DictConfig
10
 
11
+ # --- 1. CONFIGURAÇÃO E IMPORTS ---
12
 
13
+ # Adiciona o diretório do VINCIE ao path do Python para permitir a importação de seus módulos.
14
  VINCIE_DIR = "/app/VINCIE"
15
  if VINCIE_DIR not in sys.path:
16
  sys.path.append(VINCIE_DIR)
17
 
18
  try:
19
  from generate import VINCIEGenerator
20
+ from common.config import load_config
21
+ from common.seed import shift_seed
22
  except ImportError as e:
23
+ print(f"FATAL: Não foi possível importar os módulos do VINCIE. "
24
+ f"Verifique se o repositório está em '{VINCIE_DIR}'.")
25
  raise e
26
 
27
+ # --- 2. INICIALIZAÇÃO DO MODELO (SINGLETON) ---
28
 
29
+ # Variáveis globais para armazenar a instância única do modelo e o dispositivo.
30
+ MODEL: Optional[VINCIEGenerator] = None
31
+ DEVICE: Optional[torch.device] = None
32
 
33
  def setup_model():
34
  """
35
+ Inicializa e configura o modelo VINCIE.
36
+ Esta função é chamada uma vez no início da aplicação para carregar o modelo na GPU.
37
  """
38
  global MODEL, DEVICE
39
 
 
41
  raise RuntimeError("FATAL: Nenhuma GPU compatível com CUDA foi encontrada.")
42
 
43
  num_gpus = torch.cuda.device_count()
 
44
  if num_gpus == 0:
45
+ raise RuntimeError("FATAL: Nenhuma GPU foi detectada pelo PyTorch.")
46
+
47
+ print(f"INFO: Detectadas {num_gpus} GPUs. A aplicação usará 'cuda:0'.")
48
  DEVICE = torch.device("cuda:0")
49
  torch.cuda.set_device(DEVICE)
50
 
51
+ config_path = os.path.join(VINCIE_DIR, "configs/generate.yaml")
52
+ print(f"INFO: Carregando e resolvendo configuração de '{config_path}'...")
53
  config = load_config(config_path, [])
54
 
55
  print("INFO: Instanciando VINCIEGenerator...")
56
  model_instance = VINCIEGenerator(config)
57
 
58
+ # Executa a sequência de inicialização necessária do VINCIE
59
+ print("INFO: Configurando persistência, modelos e difusão...")
60
  model_instance.configure_persistence()
 
 
 
61
  model_instance.configure_models()
 
 
62
  model_instance.configure_diffusion()
63
 
64
  if not hasattr(model_instance, 'dit'):
65
+ raise RuntimeError("FATAL: Falha ao inicializar o componente DiT do modelo.")
66
 
67
+ # Move todos os componentes para o dispositivo principal
68
  model_instance.dit.to(DEVICE)
69
  model_instance.vae.to(DEVICE)
70
  model_instance.text_encoder.to(DEVICE)
71
 
72
  MODEL = model_instance
73
+ print(f"✅ SUCESSO: Modelo VINCIE pronto para uso na GPU {DEVICE}.")
74
 
75
+ # --- 3. LÓGICAS DE INFERÊNCIA ---
76
 
77
+ def _execute_vincie_logic(
78
+ prompt_config: DictConfig,
79
+ steps: int,
80
+ cfg_scale: float,
81
+ seed: int,
82
+ pad_img_placeholder: bool,
83
+ resolution: int
84
+ ) -> Image.Image:
85
+ """
86
+ Função central e reutilizável que executa a inferência do VINCIE.
87
 
88
+ Args:
89
+ prompt_config (DictConfig): Configuração do prompt para o modelo.
90
+ steps (int): Número de passos de difusão.
91
+ cfg_scale (float): Escala de orientação (Classifier-Free Guidance).
92
+ seed (int): Semente para reprodutibilidade.
93
+ pad_img_placeholder (bool): Se deve formatar o prompt com placeholders <IMG>.
94
+ resolution (int): Resolução do lado menor da imagem para processamento.
95
+
96
+ Returns:
97
+ Image.Image: A imagem gerada.
98
+ """
99
+ # Salva o estado original da configuração para restaurá-lo depois
100
+ original_config_state = {
101
+ "steps": MODEL.config.diffusion.timesteps.sampling.steps,
102
+ "seed": MODEL.config.generation.seed,
103
+ "pad": MODEL.config.generation.pad_img_placehoder,
104
+ "resolution": MODEL.config.generation.resolution,
105
+ }
106
 
107
  try:
108
+ OmegaConf.set_readonly(MODEL.config, False)
109
 
110
+ # 1. Aplica configurações dinâmicas
111
+ MODEL.config.diffusion.timesteps.sampling.steps = int(steps)
112
+ MODEL.configure_diffusion() # Recria o sampler com os novos passos
113
+
114
+ current_seed = seed if seed != -1 else torch.randint(0, 2**32 - 1, (1,)).item()
115
+ MODEL.config.generation.seed = shift_seed(current_seed, 0)
116
+ MODEL.config.generation.pad_img_placehoder = pad_img_placeholder
117
+ MODEL.config.generation.resolution = int(resolution)
118
 
119
+ # 2. Prepara as entradas
120
  text_pos, condition, noise, _, _ = MODEL.prepare_input(
121
+ prompt=prompt_config, repeat_idx=0, device=DEVICE
 
 
122
  )
123
 
124
+ # 3. Executa a inferência
125
  with torch.no_grad():
 
126
  samples = MODEL.inference(
127
  noises=[noise],
128
  conditions=[condition],
129
  texts_pos=[text_pos],
130
  texts_neg=[MODEL.config.generation.negative_prompt],
131
+ cfg_scale=cfg_scale
132
  )
 
133
 
134
  if not samples:
135
+ raise RuntimeError("A inferência do modelo não produziu resultados.")
136
 
137
+ # 4. Processa a saída para formato de imagem
138
  output_tensor = samples[0][:, -1, :, :]
139
+ output_image_np = output_tensor.clip(-1, 1).add(1).div(2).mul(255).byte().permute(1, 2, 0).cpu().numpy()
140
+ return Image.fromarray(output_image_np)
141
+
142
+ finally:
143
+ # 5. Restaura a configuração original para garantir consistência entre chamadas
144
+ OmegaConf.set_readonly(MODEL.config, False)
145
+ MODEL.config.diffusion.timesteps.sampling.steps = original_config_state["steps"]
146
+ MODEL.config.generation.seed = original_config_state["seed"]
147
+ MODEL.config.generation.pad_img_placehoder = original_config_state["pad"]
148
+ MODEL.config.generation.resolution = original_config_state["resolution"]
149
+ OmegaConf.set_readonly(MODEL.config, True)
150
+ MODEL.configure_diffusion() # Restaura o sampler padrão
151
+
152
+
153
+ def run_single_turn_inference(
154
+ input_image: str, prompt: str, aspect_ratio: str, resolution: int, steps: int, cfg_scale: float, seed: int
155
+ ) -> Image.Image:
156
+ """Handler para a aba 'Edição Simples'."""
157
+ if not all([input_image, prompt]):
158
+ raise gr.Error("É necessário fornecer uma imagem de entrada e um prompt.")
159
+
160
+ _print_params("Edição Simples", prompt=prompt, aspect_ratio=aspect_ratio, resolution=resolution, steps=steps, cfg_scale=cfg_scale, seed=seed)
161
+
162
+ prompt_config = OmegaConf.create({
163
+ "index": 0, "img_paths": [input_image], "context": [prompt], "aspect_ratio": aspect_ratio
164
+ })
165
+
166
+ return _execute_vincie_logic(prompt_config, steps, cfg_scale, seed, pad_img_placeholder=True, resolution=resolution)
167
+
168
+
169
+ def run_multi_turn_inference(
170
+ input_image: str, prompts_text: str, steps: int, cfg_scale: float, seed: int, progress=gr.Progress()
171
+ ) -> List[Image.Image]:
172
+ """Handler para a aba 'Edição em Múltiplos Turnos'."""
173
+ if not all([input_image, prompts_text]):
174
+ raise gr.Error("É necessário fornecer uma imagem de entrada e pelo menos um prompt.")
175
+
176
+ prompts = [p.strip() for p in prompts_text.splitlines() if p.strip()]
177
+ if not prompts:
178
+ raise gr.Error("Nenhum prompt válido fornecido.")
179
+
180
+ _print_params("Edição em Múltiplos Turnos", prompts=prompts, steps=steps, cfg_scale=cfg_scale, seed=seed)
181
+
182
+ output_images_with_paths = []
183
+
184
+ for i, prompt in enumerate(progress.tqdm(prompts, desc="Processando turnos")):
185
+ print(f"--- Turno {i+1}/{len(prompts)}: {prompt} ---")
186
 
187
+ image_paths = [input_image] + [path for _, path in output_images_with_paths]
188
+ context_prompts = prompts[:i+1]
189
 
190
+ prompt_config = OmegaConf.create({
191
+ "index": i, "img_paths": image_paths, "context": context_prompts, "aspect_ratio": "keep_ratio"
192
+ })
193
+
194
+ turn_seed = seed if seed == -1 else seed + i
195
+ result_image = _execute_vincie_logic(prompt_config, steps, cfg_scale, turn_seed, pad_img_placeholder=True, resolution=512)
196
+
197
+ temp_path = os.path.join("/tmp", f"{uuid.uuid4()}.png")
198
+ result_image.save(temp_path)
199
+ output_images_with_paths.append((result_image, temp_path))
200
+
201
+ return [img for img, _ in output_images_with_paths]
202
+
203
+
204
+ def run_multi_concept_inference(prompt: str, *images: str) -> Image.Image:
205
+ """Handler para a aba 'Composição de Conceitos'."""
206
+ image_paths = [img for img in images if img is not None]
207
+ if not image_paths or not prompt.strip():
208
+ raise gr.Error("É necessário um prompt e pelo menos uma imagem de entrada.")
209
+
210
+ _print_params("Composição de Conceitos", prompt=prompt, num_images=len(image_paths))
211
+
212
+ prefix_prompts = [f"<IMG{i+1}>: " for i in range(len(image_paths) - 1)]
213
+ all_prompts = prefix_prompts + [prompt]
214
+
215
+ prompt_config = OmegaConf.create({
216
+ "index": 0, "img_paths": image_paths, "context": all_prompts, "aspect_ratio": "1:1"
217
+ })
218
+
219
+ return _execute_vincie_logic(prompt_config, steps=50, cfg_scale=7.5, seed=1, pad_img_placeholder=False, resolution=512)
220
+
221
+
222
+ def _print_params(mode: str, **kwargs: Any):
223
+ """Função auxiliar para logging formatado das requisições."""
224
+ log_message = f"\n{'='*50}\nINFO: Nova requisição - Modo: {mode}\n"
225
+ for key, value in kwargs.items():
226
+ log_message += f" - {key.replace('_', ' ').title()}: {value}\n"
227
+ log_message += f"{'='*50}\n"
228
+ print(log_message)
229
 
230
 
231
+ # --- 4. CONSTRUÇÃO DA INTERFACE GRadio ---
232
 
233
  def create_ui():
234
+ """Cria e retorna a interface Gradio completa com todas as abas e controles."""
235
+ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue"), title="VINCIE Playground") as demo:
236
+ gr.Markdown("# 🖼️ **VINCIE Playground**\nExplore as diferentes capacidades do modelo VINCIE.")
237
+
238
+ with gr.Accordion("Opções Avançadas (para Abas 1 e 2)", open=False):
239
+ steps_input = gr.Slider(label="Passos de Inferência", minimum=10, maximum=100, step=1, value=50)
240
+ cfg_scale_input = gr.Slider(label="Escala de Orientação (CFG)", minimum=1.0, maximum=15.0, step=0.5, value=7.5)
241
+ seed_input = gr.Number(label="Semente (Seed)", value=-1, precision=0, info="Use -1 para aleatório.")
242
+
243
+ with gr.Tabs():
244
+ # Aba 1: Edição Simples
245
+ with gr.TabItem("Edição Simples"):
246
+ with gr.Row():
247
+ with gr.Column(scale=1):
248
+ single_turn_img_in = gr.Image(type="filepath", label="Imagem de Entrada")
249
+ single_turn_prompt = gr.Textbox(lines=2, label="Prompt de Edição")
250
+ with gr.Accordion("Opções de Imagem", open=True):
251
+ aspect_ratio_input = gr.Dropdown(label="Aspect Ratio", choices=["keep_ratio", "1:1", "16:9", "9:16", "4:3", "3:4"], value="keep_ratio")
252
+ resolution_input = gr.Slider(label="Resolução (lado menor)", minimum=256, maximum=1024, step=64, value=512)
253
+ single_turn_button = gr.Button("Gerar", variant="primary")
254
+ with gr.Column(scale=1):
255
+ single_turn_img_out = gr.Image(label="Resultado", interactive=False, height=512)
256
+ gr.Examples([["/app/VINCIE/assets/woman_pineapple.png", "Adicione uma coroa na cabeça da mulher."]], [single_turn_img_in, single_turn_prompt])
257
+
258
+ # Aba 2: Edição em Múltiplos Turnos
259
+ with gr.TabItem("Edição em Múltiplos Turnos"):
260
+ with gr.Row():
261
+ with gr.Column(scale=1):
262
+ multi_turn_img_in = gr.Image(type="filepath", label="Imagem de Entrada")
263
+ multi_turn_prompts = gr.Textbox(lines=5, label="Prompts (um por linha)", placeholder="Turno 1: faça isso\nTurno 2: agora mude aquilo...")
264
+ multi_turn_button = gr.Button("Gerar Sequência", variant="primary")
265
+ with gr.Column(scale=1):
266
+ multi_turn_gallery_out = gr.Gallery(label="Resultados dos Turnos", columns=3, height="auto")
267
+
268
+ # Aba 3: Composição de Conceitos
269
+ with gr.TabItem("Composição de Conceitos"):
270
+ gr.Markdown("Faça o upload de até 6 imagens (`<IMG0>` a `<IMG5>`) e escreva um prompt que as combine para gerar uma nova imagem (`<IMG6>`).")
271
+ with gr.Row():
272
+ concept_inputs = [gr.Image(type="filepath", label=f"Imagem {i} (<IMG{i}>)") for i in range(6)]
273
+ concept_prompt = gr.Textbox(lines=4, label="Prompt de Composição Final", value="Baseado em <IMG0>, <IMG1> e <IMG2>, crie um retrato de uma família com o pai de <IMG0>, a mãe de <IMG1> e o cachorro de <IMG2> em um parque. Saída <IMG6>:")
274
+ concept_button = gr.Button("Compor Imagem", variant="primary")
275
+ concept_img_out = gr.Image(label="Resultado da Composição", interactive=False, height=512)
276
+ gr.Examples(
277
+ [[
278
+ "Baseado em <IMG0>, <IMG1> e <IMG2>, crie um retrato de uma família com o pai de <IMG0>, a mãe de <IMG1> e o cachorro de <IMG2> em um parque. Saída <IMG6>:",
279
+ "/app/VINCIE/assets/father.png", "/app/VINCIE/assets/mother.png", "/app/VINCIE/assets/dog1.png"
280
+ ]],
281
+ [concept_prompt] + concept_inputs
282
+ )
283
+
284
+ # Conecta os botões às suas respectivas funções de backend
285
+ single_turn_button.click(fn=run_single_turn_inference, inputs=[single_turn_img_in, single_turn_prompt, aspect_ratio_input, resolution_input, steps_input, cfg_scale_input, seed_input], outputs=[single_turn_img_out])
286
+ multi_turn_button.click(fn=run_multi_turn_inference, inputs=[multi_turn_img_in, multi_turn_prompts, steps_input, cfg_scale_input, seed_input], outputs=[multi_turn_gallery_out])
287
+ concept_button.click(fn=run_multi_concept_inference, inputs=[concept_prompt] + concept_inputs, outputs=[concept_img_out])
288
+
289
  return demo
290
 
291
+ # --- 5. PONTO DE ENTRADA DA APLICAÇÃO ---
292
+
293
  if __name__ == "__main__":
294
  setup_model()
295
  ui = create_ui()
296
+
297
+ server_name = os.environ.get("GRADIO_SERVER_NAME", "0.0.0.0")
298
  server_port = int(os.environ.get("GRADIO_SERVER_PORT", 7860))
299
  enable_queue = os.environ.get("GRADIO_ENABLE_QUEUE", "True").lower() == "true"
300
+
301
  print(f"INFO: Lançando a interface Gradio em http://{server_name}:{server_port}")
302
  if enable_queue:
 
303
  ui.queue()
304
+
305
  ui.launch(server_name=server_name, server_port=server_port)