Spaces:
Running
on
Zero
Running
on
Zero
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],
|