Spaces:
Runtime error
Runtime error
Update app.py
Browse files
app.py
CHANGED
|
@@ -47,6 +47,7 @@ import random
|
|
| 47 |
import numpy as np
|
| 48 |
import gradio as gr
|
| 49 |
from PIL import Image
|
|
|
|
| 50 |
from diffusers import FluxPipeline, FluxTransformer2DModel, GGUFQuantizationConfig
|
| 51 |
from transformers import T5EncoderModel, BitsAndBytesConfig as BitsAndBytesConfigTF
|
| 52 |
from step1x3d_geometry.models.pipelines.pipeline import Step1X3DGeometryPipeline
|
|
@@ -82,17 +83,28 @@ texture_model = Step1X3DTexturePipeline.from_pretrained("stepfun-ai/Step1X-3D",
|
|
| 82 |
# --- Carga de Modelo FLUX para Texto-a-Imagen ---
|
| 83 |
logging.info("Cargando modelo FLUX para Texto-a-Imagen...")
|
| 84 |
single_file_base_model = "camenduru/FLUX.1-dev-diffusers"
|
| 85 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 86 |
|
| 87 |
quantization_config_tf = BitsAndBytesConfigTF(load_in_8bit=True, bnb_8bit_compute_dtype=torch_dtype)
|
| 88 |
text_encoder_2 = T5EncoderModel.from_pretrained(single_file_base_model, subfolder="text_encoder_2", torch_dtype=torch_dtype, quantization_config=quantization_config_tf)
|
| 89 |
-
|
|
|
|
|
|
|
| 90 |
flux_pipeline = FluxPipeline.from_pretrained(single_file_base_model, transformer=transformer, text_encoder_2=text_encoder_2, torch_dtype=torch_dtype)
|
| 91 |
flux_pipeline.to(device)
|
| 92 |
logging.info("Todos los modelos han sido cargados correctamente.")
|
| 93 |
|
|
|
|
| 94 |
# ==============================================================================
|
| 95 |
-
# 3. FUNCIONES DE GENERACIÓN POR PASOS
|
| 96 |
# ==============================================================================
|
| 97 |
|
| 98 |
@spaces.GPU(duration=60)
|
|
@@ -107,7 +119,6 @@ def generate_image_from_text(prompt, seed, randomize_seed, guidance_scale, num_s
|
|
| 107 |
logging.info(f"Generando imagen con prompt: '{prompt}' y seed: {seed}")
|
| 108 |
generator = torch.Generator(device=device).manual_seed(seed)
|
| 109 |
|
| 110 |
-
# Prompting específico que funciona bien con el modelo FLUX para objetos
|
| 111 |
full_prompt = f"professional 3d model {prompt}. octane render, highly detailed, volumetric, dramatic lighting, on a white background"
|
| 112 |
negative_prompt = "ugly, deformed, noisy, low poly, blurry, painting, photo, text, watermark"
|
| 113 |
|
|
@@ -136,7 +147,6 @@ def generate_geometry(input_image_path, guidance_scale, inference_steps, max_fac
|
|
| 136 |
|
| 137 |
logging.info(f"Iniciando generación de geometría desde: {os.path.basename(input_image_path)}")
|
| 138 |
|
| 139 |
-
# ... (El resto de esta función es idéntico al de la respuesta anterior)
|
| 140 |
if "Label" in args.geometry_model:
|
| 141 |
symmetry_values = ["x", "asymmetry"]
|
| 142 |
out = geometry_model(
|
|
@@ -174,11 +184,11 @@ def generate_texture(input_image_path, geometry_path):
|
|
| 174 |
|
| 175 |
logging.info(f"Iniciando texturizado para la malla: {os.path.basename(geometry_path)}")
|
| 176 |
|
| 177 |
-
# ... (El resto de esta función es idéntico al de la respuesta anterior)
|
| 178 |
geometry_mesh = trimesh.load(geometry_path)
|
| 179 |
geometry_mesh = remove_degenerate_face(geometry_mesh)
|
| 180 |
geometry_mesh = reduce_face(geometry_mesh)
|
| 181 |
textured_mesh = texture_model(input_image_path, geometry_mesh)
|
|
|
|
| 182 |
save_name = os.path.basename(geometry_path).replace("_geometry.glb", "")
|
| 183 |
textured_save_path = f"{args.cache_dir}/{save_name}_textured.glb"
|
| 184 |
textured_mesh.export(textured_save_path)
|
|
@@ -188,20 +198,18 @@ def generate_texture(input_image_path, geometry_path):
|
|
| 188 |
return textured_save_path
|
| 189 |
|
| 190 |
# ==============================================================================
|
| 191 |
-
# 4. INTERFAZ DE GRADIO
|
| 192 |
# ==============================================================================
|
| 193 |
|
| 194 |
with gr.Blocks(title="Step1X-3D", css="footer {display: none !important;} a {text-decoration: none !important;}") as demo:
|
| 195 |
gr.Markdown("# Step1X-3D: Flujo de Texto a Malla 3D Texturizada")
|
| 196 |
gr.Markdown("Flujo de trabajo en 3 pasos: **0. Generar Imagen → 1. Generar Geometría → 2. Generar Textura**")
|
| 197 |
|
| 198 |
-
# Estados para mantener las rutas de los archivos entre pasos
|
| 199 |
generated_image_path_state = gr.State()
|
| 200 |
geometry_path_state = gr.State()
|
| 201 |
|
| 202 |
with gr.Row():
|
| 203 |
with gr.Column(scale=2):
|
| 204 |
-
# --- Panel de Entradas ---
|
| 205 |
prompt = gr.Textbox(label="Paso 0: Describe tu objeto", placeholder="Ej: a treasure chest, a sci-fi helmet, a cute dog")
|
| 206 |
|
| 207 |
with gr.Accordion("Opciones de Generación de Imagen (Paso 0)", open=True):
|
|
@@ -224,15 +232,11 @@ with gr.Blocks(title="Step1X-3D", css="footer {display: none !important;} a {tex
|
|
| 224 |
btn_tex = gr.Button("2. Generate Texture", interactive=False)
|
| 225 |
|
| 226 |
with gr.Column(scale=3):
|
| 227 |
-
# --- Panel de Salidas ---
|
| 228 |
generated_image_preview = gr.Image(label="Imagen Generada", type="filepath", interactive=False, height=400)
|
| 229 |
geometry_preview = gr.Model3D(label="Vista Previa de la Geometría", height=400, clear_color=[0.0, 0.0, 0.0, 0.0])
|
| 230 |
textured_preview = gr.Model3D(label="Vista Previa del Modelo Texturizado", height=400, clear_color=[0.0, 0.0, 0.0, 0.0])
|
| 231 |
|
| 232 |
-
# --- Lógica de la Interfaz ---
|
| 233 |
-
|
| 234 |
def on_image_generated(path):
|
| 235 |
-
"""Callback para actualizar la UI después de generar la imagen."""
|
| 236 |
return {
|
| 237 |
generated_image_path_state: path,
|
| 238 |
btn_geo: gr.update(interactive=True, variant="primary"),
|
|
@@ -242,13 +246,11 @@ with gr.Blocks(title="Step1X-3D", css="footer {display: none !important;} a {tex
|
|
| 242 |
}
|
| 243 |
|
| 244 |
def on_geometry_generated(path):
|
| 245 |
-
"""Callback para actualizar la UI después de generar la geometría."""
|
| 246 |
return {
|
| 247 |
geometry_path_state: path,
|
| 248 |
btn_tex: gr.update(interactive=True, variant="primary"),
|
| 249 |
}
|
| 250 |
|
| 251 |
-
# Cadena de eventos
|
| 252 |
btn_t2i.click(
|
| 253 |
fn=generate_image_from_text,
|
| 254 |
inputs=[prompt, seed, randomize_seed, guidance_t2i, steps_t2i],
|
|
|
|
| 47 |
import numpy as np
|
| 48 |
import gradio as gr
|
| 49 |
from PIL import Image
|
| 50 |
+
from huggingface_hub import hf_hub_download
|
| 51 |
from diffusers import FluxPipeline, FluxTransformer2DModel, GGUFQuantizationConfig
|
| 52 |
from transformers import T5EncoderModel, BitsAndBytesConfig as BitsAndBytesConfigTF
|
| 53 |
from step1x3d_geometry.models.pipelines.pipeline import Step1X3DGeometryPipeline
|
|
|
|
| 83 |
# --- Carga de Modelo FLUX para Texto-a-Imagen ---
|
| 84 |
logging.info("Cargando modelo FLUX para Texto-a-Imagen...")
|
| 85 |
single_file_base_model = "camenduru/FLUX.1-dev-diffusers"
|
| 86 |
+
|
| 87 |
+
# --- CORRECCIÓN AQUÍ ---
|
| 88 |
+
# Descargar el archivo GGUF explícitamente usando hf_hub_download
|
| 89 |
+
flux_repo_id = "gokaygokay/flux-game"
|
| 90 |
+
flux_filename = "hyperflux_00001_.q8_0.gguf"
|
| 91 |
+
logging.info(f"Descargando {flux_filename} desde {flux_repo_id}...")
|
| 92 |
+
downloaded_flux_path = hf_hub_download(repo_id=flux_repo_id, filename=flux_filename)
|
| 93 |
+
logging.info(f"Archivo GGUF descargado en: {downloaded_flux_path}")
|
| 94 |
+
# --- FIN DE LA CORRECCIÓN ---
|
| 95 |
|
| 96 |
quantization_config_tf = BitsAndBytesConfigTF(load_in_8bit=True, bnb_8bit_compute_dtype=torch_dtype)
|
| 97 |
text_encoder_2 = T5EncoderModel.from_pretrained(single_file_base_model, subfolder="text_encoder_2", torch_dtype=torch_dtype, quantization_config=quantization_config_tf)
|
| 98 |
+
|
| 99 |
+
# Usar la ruta local descargada
|
| 100 |
+
transformer = FluxTransformer2DModel.from_single_file(downloaded_flux_path, subfolder="transformer", quantization_config=GGUFQuantizationConfig(compute_dtype=torch_dtype), torch_dtype=torch_dtype, config=single_file_base_model)
|
| 101 |
flux_pipeline = FluxPipeline.from_pretrained(single_file_base_model, transformer=transformer, text_encoder_2=text_encoder_2, torch_dtype=torch_dtype)
|
| 102 |
flux_pipeline.to(device)
|
| 103 |
logging.info("Todos los modelos han sido cargados correctamente.")
|
| 104 |
|
| 105 |
+
|
| 106 |
# ==============================================================================
|
| 107 |
+
# 3. FUNCIONES DE GENERACIÓN POR PASOS (Sin cambios)
|
| 108 |
# ==============================================================================
|
| 109 |
|
| 110 |
@spaces.GPU(duration=60)
|
|
|
|
| 119 |
logging.info(f"Generando imagen con prompt: '{prompt}' y seed: {seed}")
|
| 120 |
generator = torch.Generator(device=device).manual_seed(seed)
|
| 121 |
|
|
|
|
| 122 |
full_prompt = f"professional 3d model {prompt}. octane render, highly detailed, volumetric, dramatic lighting, on a white background"
|
| 123 |
negative_prompt = "ugly, deformed, noisy, low poly, blurry, painting, photo, text, watermark"
|
| 124 |
|
|
|
|
| 147 |
|
| 148 |
logging.info(f"Iniciando generación de geometría desde: {os.path.basename(input_image_path)}")
|
| 149 |
|
|
|
|
| 150 |
if "Label" in args.geometry_model:
|
| 151 |
symmetry_values = ["x", "asymmetry"]
|
| 152 |
out = geometry_model(
|
|
|
|
| 184 |
|
| 185 |
logging.info(f"Iniciando texturizado para la malla: {os.path.basename(geometry_path)}")
|
| 186 |
|
|
|
|
| 187 |
geometry_mesh = trimesh.load(geometry_path)
|
| 188 |
geometry_mesh = remove_degenerate_face(geometry_mesh)
|
| 189 |
geometry_mesh = reduce_face(geometry_mesh)
|
| 190 |
textured_mesh = texture_model(input_image_path, geometry_mesh)
|
| 191 |
+
|
| 192 |
save_name = os.path.basename(geometry_path).replace("_geometry.glb", "")
|
| 193 |
textured_save_path = f"{args.cache_dir}/{save_name}_textured.glb"
|
| 194 |
textured_mesh.export(textured_save_path)
|
|
|
|
| 198 |
return textured_save_path
|
| 199 |
|
| 200 |
# ==============================================================================
|
| 201 |
+
# 4. INTERFAZ DE GRADIO (Sin cambios)
|
| 202 |
# ==============================================================================
|
| 203 |
|
| 204 |
with gr.Blocks(title="Step1X-3D", css="footer {display: none !important;} a {text-decoration: none !important;}") as demo:
|
| 205 |
gr.Markdown("# Step1X-3D: Flujo de Texto a Malla 3D Texturizada")
|
| 206 |
gr.Markdown("Flujo de trabajo en 3 pasos: **0. Generar Imagen → 1. Generar Geometría → 2. Generar Textura**")
|
| 207 |
|
|
|
|
| 208 |
generated_image_path_state = gr.State()
|
| 209 |
geometry_path_state = gr.State()
|
| 210 |
|
| 211 |
with gr.Row():
|
| 212 |
with gr.Column(scale=2):
|
|
|
|
| 213 |
prompt = gr.Textbox(label="Paso 0: Describe tu objeto", placeholder="Ej: a treasure chest, a sci-fi helmet, a cute dog")
|
| 214 |
|
| 215 |
with gr.Accordion("Opciones de Generación de Imagen (Paso 0)", open=True):
|
|
|
|
| 232 |
btn_tex = gr.Button("2. Generate Texture", interactive=False)
|
| 233 |
|
| 234 |
with gr.Column(scale=3):
|
|
|
|
| 235 |
generated_image_preview = gr.Image(label="Imagen Generada", type="filepath", interactive=False, height=400)
|
| 236 |
geometry_preview = gr.Model3D(label="Vista Previa de la Geometría", height=400, clear_color=[0.0, 0.0, 0.0, 0.0])
|
| 237 |
textured_preview = gr.Model3D(label="Vista Previa del Modelo Texturizado", height=400, clear_color=[0.0, 0.0, 0.0, 0.0])
|
| 238 |
|
|
|
|
|
|
|
| 239 |
def on_image_generated(path):
|
|
|
|
| 240 |
return {
|
| 241 |
generated_image_path_state: path,
|
| 242 |
btn_geo: gr.update(interactive=True, variant="primary"),
|
|
|
|
| 246 |
}
|
| 247 |
|
| 248 |
def on_geometry_generated(path):
|
|
|
|
| 249 |
return {
|
| 250 |
geometry_path_state: path,
|
| 251 |
btn_tex: gr.update(interactive=True, variant="primary"),
|
| 252 |
}
|
| 253 |
|
|
|
|
| 254 |
btn_t2i.click(
|
| 255 |
fn=generate_image_from_text,
|
| 256 |
inputs=[prompt, seed, randomize_seed, guidance_t2i, steps_t2i],
|