Spaces:
Paused
Paused
Update app_vince.py
Browse files- app_vince.py +45 -60
app_vince.py
CHANGED
|
@@ -3,7 +3,7 @@ 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 |
|
|
@@ -20,46 +20,55 @@ except ImportError as e:
|
|
| 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
|
| 24 |
-
# (Esta seção permanece inalterada)
|
| 25 |
|
| 26 |
MODEL: VINCIEGenerator = None
|
| 27 |
-
|
| 28 |
|
| 29 |
def setup_model():
|
| 30 |
-
|
| 31 |
-
|
|
|
|
|
|
|
|
|
|
| 32 |
if not torch.cuda.is_available():
|
| 33 |
raise RuntimeError("FATAL: Nenhuma GPU compatível com CUDA foi encontrada.")
|
|
|
|
| 34 |
num_gpus = torch.cuda.device_count()
|
| 35 |
-
print(f"INFO: Detectadas {num_gpus} GPUs.")
|
| 36 |
if num_gpus == 0:
|
| 37 |
raise RuntimeError("FATAL: Nenhuma GPU foi alocada para este contêiner.")
|
| 38 |
-
|
| 39 |
-
torch.cuda
|
|
|
|
|
|
|
| 40 |
config_path = "configs/generate.yaml"
|
| 41 |
print(f"INFO: Carregando e resolvendo configuração do modelo de '{config_path}'...")
|
| 42 |
config = load_config(config_path, [])
|
|
|
|
| 43 |
print("INFO: Instanciando VINCIEGenerator...")
|
| 44 |
model_instance = VINCIEGenerator(config)
|
|
|
|
| 45 |
print("INFO: Configurando a persistência (modo de inferência)...")
|
| 46 |
model_instance.configure_persistence()
|
| 47 |
-
|
|
|
|
|
|
|
| 48 |
model_instance.configure_models()
|
|
|
|
| 49 |
print("INFO: Configurando os componentes de difusão...")
|
| 50 |
model_instance.configure_diffusion()
|
|
|
|
| 51 |
if not hasattr(model_instance, 'dit'):
|
| 52 |
raise RuntimeError("FATAL: O modelo 'dit' não foi criado após a configuração.")
|
| 53 |
-
|
| 54 |
-
|
| 55 |
-
model_instance.
|
| 56 |
-
|
| 57 |
-
|
| 58 |
-
|
| 59 |
-
model_instance.dit = torch.nn.DataParallel(model_instance.dit)
|
| 60 |
-
print("INFO: DataParallel ativado no modelo DiT.")
|
| 61 |
MODEL = model_instance
|
| 62 |
-
print("✅ SUCESSO: O modelo VINCIE está pronto
|
| 63 |
|
| 64 |
|
| 65 |
# --- ETAPA 3: LÓGICA DE INFERÊNCIA ---
|
|
@@ -69,26 +78,23 @@ def perform_inference(input_image: str, prompt: str):
|
|
| 69 |
raise gr.Error("O modelo não está carregado. Verifique os logs de inicialização.")
|
| 70 |
if input_image is None or not prompt.strip():
|
| 71 |
raise gr.Error("É necessário fornecer uma imagem de entrada e um prompt de edição.")
|
|
|
|
| 72 |
print(f"INFO: Recebida nova requisição. Prompt: '{prompt}'")
|
| 73 |
turn_1_prompt = [prompt]
|
| 74 |
image_paths = [input_image]
|
|
|
|
| 75 |
try:
|
| 76 |
print("INFO: Preparando entradas com `model.prepare_input()`...")
|
| 77 |
-
|
| 78 |
-
# --- CORREÇÃO PRINCIPAL ---
|
| 79 |
-
# Cria um dicionário Python padrão
|
| 80 |
prompt_dict = {
|
| 81 |
-
"index": 0,
|
| 82 |
-
"img_paths": image_paths,
|
| 83 |
-
"context": turn_1_prompt,
|
| 84 |
}
|
| 85 |
-
# Converte o dicionário para um OmegaConf DictConfig antes de passar para a função
|
| 86 |
prompt_config = OmegaConf.create(prompt_dict)
|
| 87 |
|
| 88 |
text_pos, condition, noise, _, _ = MODEL.prepare_input(
|
| 89 |
-
prompt=prompt_config,
|
| 90 |
repeat_idx=0,
|
| 91 |
-
device=
|
| 92 |
)
|
| 93 |
|
| 94 |
with torch.no_grad():
|
|
@@ -100,41 +106,34 @@ def perform_inference(input_image: str, prompt: str):
|
|
| 100 |
texts_neg=[MODEL.config.generation.negative_prompt],
|
| 101 |
)
|
| 102 |
print("INFO: Inferência concluída.")
|
|
|
|
| 103 |
if not samples:
|
| 104 |
raise RuntimeError("A inferência não retornou nenhum resultado.")
|
|
|
|
| 105 |
output_tensor = samples[0][:, -1, :, :]
|
| 106 |
output_image = output_tensor.clip(-1, 1).add(1).div(2).mul(255).byte()
|
| 107 |
output_image = output_image.permute(1, 2, 0).cpu().numpy()
|
|
|
|
| 108 |
print("✅ SUCESSO: Imagem processada e retornada para a UI.")
|
| 109 |
return output_image
|
|
|
|
| 110 |
except Exception as e:
|
| 111 |
print(f"ERRO: Falha durante a inferência: {e}")
|
| 112 |
import traceback
|
| 113 |
traceback.print_exc()
|
| 114 |
-
raise gr.Error(f"Ocorreu um erro inesperado
|
| 115 |
|
| 116 |
|
| 117 |
-
# --- ETAPA 4:
|
| 118 |
-
# (Esta seção permanece inalterada)
|
| 119 |
|
| 120 |
def create_ui():
|
| 121 |
-
# ... (código de create_ui idêntico à versão anterior)
|
| 122 |
with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue"), title="VINCIE Image Editor") as demo:
|
| 123 |
-
|
| 124 |
-
|
| 125 |
-
# 🖼️ **VINCIE: Editor de Imagens por Contexto**
|
| 126 |
-
Faça o upload de uma imagem e descreva a edição que você deseja realizar.
|
| 127 |
-
O modelo processará sua requisição usando múltiplas GPUs.
|
| 128 |
-
"""
|
| 129 |
-
)
|
| 130 |
with gr.Row():
|
| 131 |
with gr.Column(scale=1):
|
| 132 |
image_input = gr.Image(type="filepath", label="Imagem de Entrada")
|
| 133 |
-
prompt_input = gr.Textbox(
|
| 134 |
-
lines=3,
|
| 135 |
-
label="O que você quer mudar?",
|
| 136 |
-
placeholder="Exemplo: 'mude o fundo para uma praia ensolarada e adicione óculos de sol na pessoa'"
|
| 137 |
-
)
|
| 138 |
submit_button = gr.Button("✨ Gerar Edição", variant="primary")
|
| 139 |
with gr.Column(scale=1):
|
| 140 |
image_output = gr.Image(label="Resultado da Edição", interactive=False, height=512)
|
|
@@ -149,31 +148,17 @@ def create_ui():
|
|
| 149 |
fn=perform_inference,
|
| 150 |
cache_examples=False,
|
| 151 |
)
|
| 152 |
-
submit_button.click(
|
| 153 |
-
fn=perform_inference,
|
| 154 |
-
inputs=[image_input, prompt_input],
|
| 155 |
-
outputs=[image_output]
|
| 156 |
-
)
|
| 157 |
return demo
|
| 158 |
|
| 159 |
-
|
| 160 |
-
# --- ETAPA 5: PONTO DE ENTRADA DA APLICAÇÃO ---
|
| 161 |
-
|
| 162 |
if __name__ == "__main__":
|
| 163 |
setup_model()
|
| 164 |
ui = create_ui()
|
| 165 |
-
|
| 166 |
server_name = os.environ.get("GRADIO_SERVER_NAME", "127.0.0.1")
|
| 167 |
server_port = int(os.environ.get("GRADIO_SERVER_PORT", 7860))
|
| 168 |
enable_queue = os.environ.get("GRADIO_ENABLE_QUEUE", "True").lower() == "true"
|
| 169 |
-
|
| 170 |
print(f"INFO: Lançando a interface Gradio em http://{server_name}:{server_port}")
|
| 171 |
-
|
| 172 |
if enable_queue:
|
| 173 |
print("INFO: Fila de requisições (queue) ativada.")
|
| 174 |
ui.queue()
|
| 175 |
-
|
| 176 |
-
ui.launch(
|
| 177 |
-
server_name=server_name,
|
| 178 |
-
server_port=server_port
|
| 179 |
-
)
|
|
|
|
| 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 |
|
|
|
|
| 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 |
+
|
| 34 |
if not torch.cuda.is_available():
|
| 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 ---
|
|
|
|
| 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():
|
|
|
|
| 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)
|
|
|
|
| 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)
|
|
|
|
|
|
|
|
|
|
|
|