cavargas10 commited on
Commit
8d0e192
·
verified ·
1 Parent(s): d1e7f0a

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +60 -33
app.py CHANGED
@@ -9,38 +9,57 @@ import logging
9
  import random
10
  import uuid
11
 
12
- # Configuración del logging para depuración
13
  logging.basicConfig(level=logging.INFO, format='%(asctime)s - Step1X-3D - %(levelname)s - %(message)s')
14
 
 
15
  def install_dependencies():
16
- """Instala el toolkit de CUDA y compila las extensiones C++/CUDA necesarias."""
 
 
 
17
  logging.info("Iniciando la instalación de dependencias...")
18
 
19
- # Instalar CUDA Toolkit
20
  CUDA_TOOLKIT_URL = "https://developer.download.nvidia.com/compute/cuda/12.4.0/local_installers/cuda_12.4.0_550.54.14_linux.run"
21
  CUDA_TOOLKIT_FILE = f"/tmp/{os.path.basename(CUDA_TOOLKIT_URL)}"
22
  if not os.path.exists("/usr/local/cuda"):
23
  logging.info("Descargando e instalando CUDA Toolkit...")
24
- subprocess.call(["wget", "-q", CUDA_TOOLKIT_URL, "-O", CUDA_TOOLKIT_FILE])
25
- subprocess.call(["chmod", "+x", CUDA_TOOLKIT_FILE])
26
- subprocess.call([CUDA_TOOLKIT_FILE, "--silent", "--toolkit"])
27
  else:
28
  logging.info("CUDA Toolkit ya está instalado.")
29
 
 
30
  os.environ["CUDA_HOME"] = "/usr/local/cuda"
31
- os.environ["PATH"] = f"{os.environ['CUDA_HOME']}/bin:{os.environ['PATH']}"
32
- os.environ["LD_LIBRARY_PATH"] = f"{os.environ['CUDA_HOME']}/lib:{os.environ.get('LD_LIBRARY_PATH', '')}"
33
  os.environ["TORCH_CUDA_ARCH_LIST"] = "8.0;8.6"
34
 
35
- # Compilar extensiones personalizadas
36
- logging.info("Compilando extensiones de renderizado...")
37
  renderer_path = "/home/user/app/step1x3d_texture/differentiable_renderer/"
38
- subprocess.run(f"cd {renderer_path} && python setup.py install", shell=True, check=True)
39
- subprocess.run(shlex.split("pip install custom_rasterizer-0.1-cp310-cp310-linux_x86_64.whl"), check=True)
40
-
41
- logging.info("Instalación completada.")
42
- os.system('nvcc -V')
43
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
44
  install_dependencies()
45
 
46
  import torch
@@ -71,14 +90,13 @@ MAX_SEED = np.iinfo(np.int32).max
71
 
72
  logging.info("Cargando modelos... Este proceso puede tardar varios minutos.")
73
 
74
- # Carga de modelo de Texto a Imagen (FLUX)
75
  logging.info("Cargando pipeline de Texto a Imagen: FLUX.1-schnell")
76
  flux_pipeline = DiffusionPipeline.from_pretrained(
77
  "black-forest-labs/FLUX.1-schnell",
78
  torch_dtype=torch_dtype,
79
  use_safetensors=True
80
- )
81
- flux_pipeline.to(device)
82
  logging.info("Pipeline FLUX cargado.")
83
 
84
  # Carga de modelos de Step1X-3D
@@ -90,7 +108,7 @@ geometry_model = Step1X3DGeometryPipeline.from_pretrained(
90
  logging.info(f"Cargando modelo de textura: {args.texture_model}")
91
  texture_model = Step1X3DTexturePipeline.from_pretrained("stepfun-ai/Step1X-3D", subfolder=args.texture_model)
92
 
93
- logging.info("Todos los modelos han sido cargados correctamente.")
94
 
95
 
96
  # ==============================================================================
@@ -108,16 +126,15 @@ def generate_image(prompt: str, randomize_seed: bool, seed: int):
108
 
109
  generator = torch.Generator(device=device).manual_seed(int(seed))
110
 
111
- # Prompt optimizado para obtener buenos resultados para 3D
112
  final_prompt = f"wbgmsst, professional 3d model {prompt}, octane render, highly detailed, volumetric, dramatic lighting, white background"
113
- negative_prompt = "ugly, deformed, noisy, low poly, blurry, painting, text, watermark, signature"
114
 
115
  logging.info(f"Generando imagen con FLUX. Seed: {seed}, Prompt: '{final_prompt}'")
116
 
117
  image = flux_pipeline(
118
  prompt=final_prompt,
119
  negative_prompt=negative_prompt,
120
- num_inference_steps=28, # Valor óptimo para FLUX.1-schnell
121
  guidance_scale=7.5,
122
  generator=generator,
123
  ).images[0]
@@ -137,7 +154,6 @@ def generate_geometry(input_image_path, guidance_scale, inference_steps, max_fac
137
 
138
  logging.info(f"Iniciando generación de geometría desde: {os.path.basename(input_image_path)}")
139
 
140
- # La lógica de generación de geometría permanece igual
141
  if "Label" in args.geometry_model:
142
  symmetry_values = ["x", "asymmetry"]
143
  out = geometry_model(
@@ -197,14 +213,12 @@ with gr.Blocks(title="Step1X-3D", css="footer {display: none !important;} a {tex
197
  gr.Markdown("# Step1X-3D: Flujo de Texto a 3D")
198
  gr.Markdown("Flujo de trabajo en 3 pasos: **0. Generar Imagen → 1. Generar Geometría → 2. Generar Textura**")
199
 
200
- # Estados para mantener las rutas de los archivos entre pasos
201
  image_path_state = gr.State()
202
  geometry_path_state = gr.State()
203
 
204
  with gr.Row():
205
  with gr.Column(scale=2):
206
- # --- Panel de Entradas ---
207
- prompt = gr.Textbox(label="Paso 0: Describe el objeto que quieres crear", value="a cute pokemon, pikachu")
208
 
209
  with gr.Accordion(label="Opciones Avanzadas", open=False):
210
  seed = gr.Slider(0, MAX_SEED, label="Seed (para Imagen 2D)", value=42, step=1)
@@ -224,7 +238,6 @@ 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
  image_preview = gr.Image(label="Resultado de la 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])
@@ -243,12 +256,11 @@ with gr.Blocks(title="Step1X-3D", css="footer {display: none !important;} a {tex
243
  current_seed = gr.Textbox(label="Seed Usada", interactive=False)
244
 
245
  # --- Lógica de la Interfaz ---
246
-
247
  def on_image_generated(path, used_seed):
248
- """Callback que se ejecuta cuando la imagen 2D ha sido generada."""
249
  return {
250
  image_path_state: path,
251
  current_seed: used_seed,
 
252
  btn_geo: gr.update(interactive=True, variant="primary"),
253
  btn_tex: gr.update(interactive=False),
254
  geometry_preview: gr.update(value=None),
@@ -256,36 +268,51 @@ with gr.Blocks(title="Step1X-3D", css="footer {display: none !important;} a {tex
256
  }
257
 
258
  def on_geometry_generated(path):
259
- """Callback que se ejecuta cuando la geometría se ha generado."""
260
  return {
261
  geometry_path_state: path,
 
262
  btn_tex: gr.update(interactive=True, variant="primary"),
263
  }
 
 
 
 
 
264
 
265
  btn_image.click(
 
 
266
  fn=generate_image,
267
  inputs=[prompt, randomize_seed, seed],
268
  outputs=[image_preview, current_seed]
269
  ).then(
270
  fn=on_image_generated,
271
  inputs=[image_preview, current_seed],
272
- outputs=[image_path_state, current_seed, btn_geo, btn_tex, geometry_preview, textured_preview]
273
  )
274
 
275
  btn_geo.click(
 
 
 
276
  fn=generate_geometry,
277
  inputs=[image_path_state, guidance_3d, steps_3d, max_facenum, symmetry, edge_type],
278
  outputs=[geometry_preview]
279
  ).then(
280
  fn=on_geometry_generated,
281
  inputs=[geometry_preview],
282
- outputs=[geometry_path_state, btn_tex]
283
  )
284
 
285
  btn_tex.click(
 
 
286
  fn=generate_texture,
287
  inputs=[image_path_state, geometry_path_state],
288
  outputs=[textured_preview],
 
 
 
289
  )
290
 
291
  demo.launch(ssr_mode=False)
 
9
  import random
10
  import uuid
11
 
12
+ # Configuración del logging para una mejor depuración
13
  logging.basicConfig(level=logging.INFO, format='%(asctime)s - Step1X-3D - %(levelname)s - %(message)s')
14
 
15
+ @spaces.GPU
16
  def install_dependencies():
17
+ """
18
+ Instala de forma robusta el toolkit de CUDA y compila las extensiones C++/CUDA.
19
+ Usa subprocess.run para capturar errores.
20
+ """
21
  logging.info("Iniciando la instalación de dependencias...")
22
 
23
+ # Instalar CUDA Toolkit si no está presente
24
  CUDA_TOOLKIT_URL = "https://developer.download.nvidia.com/compute/cuda/12.4.0/local_installers/cuda_12.4.0_550.54.14_linux.run"
25
  CUDA_TOOLKIT_FILE = f"/tmp/{os.path.basename(CUDA_TOOLKIT_URL)}"
26
  if not os.path.exists("/usr/local/cuda"):
27
  logging.info("Descargando e instalando CUDA Toolkit...")
28
+ subprocess.run(["wget", "-q", CUDA_TOOLKIT_URL, "-O", CUDA_TOOLKIT_FILE], check=True)
29
+ subprocess.run(["chmod", "+x", CUDA_TOOLKIT_FILE], check=True)
30
+ subprocess.run([CUDA_TOOLKIT_FILE, "--silent", "--toolkit"], check=True)
31
  else:
32
  logging.info("CUDA Toolkit ya está instalado.")
33
 
34
+ # Configurar variables de entorno para la compilación
35
  os.environ["CUDA_HOME"] = "/usr/local/cuda"
36
+ os.environ["PATH"] = f"{os.environ.get('CUDA_HOME', '')}/bin:{os.environ.get('PATH', '')}"
37
+ os.environ["LD_LIBRARY_PATH"] = f"{os.environ.get('CUDA_HOME', '')}/lib:{os.environ.get('LD_LIBRARY_PATH', '')}"
38
  os.environ["TORCH_CUDA_ARCH_LIST"] = "8.0;8.6"
39
 
40
+ # Compilar extensiones personalizadas con manejo de errores
41
+ logging.info("Compilando extensión 'differentiable_renderer'...")
42
  renderer_path = "/home/user/app/step1x3d_texture/differentiable_renderer/"
43
+ try:
44
+ subprocess.run(f"cd {renderer_path} && python setup.py install", shell=True, check=True, capture_output=True, text=True)
45
+ logging.info("Extensión 'differentiable_renderer' compilada con éxito.")
46
+ except subprocess.CalledProcessError as e:
47
+ logging.error("¡FALLÓ LA COMPILACIÓN de 'differentiable_renderer'!")
48
+ logging.error(f"STDOUT: {e.stdout}")
49
+ logging.error(f"STDERR: {e.stderr}")
50
+ raise # Detiene la aplicación si la compilación falla
51
+
52
+ try:
53
+ subprocess.run(shlex.split("pip install custom_rasterizer-0.1-cp310-cp310-linux_x86_64.whl"), check=True)
54
+ logging.info("Extensión 'custom_rasterizer' instalada con éxito.")
55
+ except subprocess.CalledProcessError as e:
56
+ logging.error("¡FALLÓ LA INSTALACIÓN de 'custom_rasterizer'!")
57
+ raise
58
+
59
+ logging.info("Instalación de dependencias completada.")
60
+ subprocess.run(['nvcc', '--version'], check=True)
61
+
62
+ # Llama a la función de instalación solo una vez al iniciar
63
  install_dependencies()
64
 
65
  import torch
 
90
 
91
  logging.info("Cargando modelos... Este proceso puede tardar varios minutos.")
92
 
93
+ # Carga de modelo de Texto a Imagen (FLUX - versión rápida)
94
  logging.info("Cargando pipeline de Texto a Imagen: FLUX.1-schnell")
95
  flux_pipeline = DiffusionPipeline.from_pretrained(
96
  "black-forest-labs/FLUX.1-schnell",
97
  torch_dtype=torch_dtype,
98
  use_safetensors=True
99
+ ).to(device)
 
100
  logging.info("Pipeline FLUX cargado.")
101
 
102
  # Carga de modelos de Step1X-3D
 
108
  logging.info(f"Cargando modelo de textura: {args.texture_model}")
109
  texture_model = Step1X3DTexturePipeline.from_pretrained("stepfun-ai/Step1X-3D", subfolder=args.texture_model)
110
 
111
+ logging.info("Todos los modelos han sido cargados correctamente y están listos.")
112
 
113
 
114
  # ==============================================================================
 
126
 
127
  generator = torch.Generator(device=device).manual_seed(int(seed))
128
 
 
129
  final_prompt = f"wbgmsst, professional 3d model {prompt}, octane render, highly detailed, volumetric, dramatic lighting, white background"
130
+ negative_prompt = "ugly, deformed, noisy, low poly, blurry, painting, text, watermark, signature, jpeg artifacts"
131
 
132
  logging.info(f"Generando imagen con FLUX. Seed: {seed}, Prompt: '{final_prompt}'")
133
 
134
  image = flux_pipeline(
135
  prompt=final_prompt,
136
  negative_prompt=negative_prompt,
137
+ num_inference_steps=28,
138
  guidance_scale=7.5,
139
  generator=generator,
140
  ).images[0]
 
154
 
155
  logging.info(f"Iniciando generación de geometría desde: {os.path.basename(input_image_path)}")
156
 
 
157
  if "Label" in args.geometry_model:
158
  symmetry_values = ["x", "asymmetry"]
159
  out = geometry_model(
 
213
  gr.Markdown("# Step1X-3D: Flujo de Texto a 3D")
214
  gr.Markdown("Flujo de trabajo en 3 pasos: **0. Generar Imagen → 1. Generar Geometría → 2. Generar Textura**")
215
 
 
216
  image_path_state = gr.State()
217
  geometry_path_state = gr.State()
218
 
219
  with gr.Row():
220
  with gr.Column(scale=2):
221
+ prompt = gr.Textbox(label="Paso 0: Describe el objeto", value="a comfortable armchair")
 
222
 
223
  with gr.Accordion(label="Opciones Avanzadas", open=False):
224
  seed = gr.Slider(0, MAX_SEED, label="Seed (para Imagen 2D)", value=42, step=1)
 
238
  btn_tex = gr.Button("2. Generate Texture", interactive=False)
239
 
240
  with gr.Column(scale=3):
 
241
  image_preview = gr.Image(label="Resultado de la Imagen Generada", type="filepath", interactive=False, height=400)
242
  geometry_preview = gr.Model3D(label="Vista Previa de la Geometría", height=400, clear_color=[0.0, 0.0, 0.0, 0.0])
243
  textured_preview = gr.Model3D(label="Vista Previa del Modelo Texturizado", height=400, clear_color=[0.0, 0.0, 0.0, 0.0])
 
256
  current_seed = gr.Textbox(label="Seed Usada", interactive=False)
257
 
258
  # --- Lógica de la Interfaz ---
 
259
  def on_image_generated(path, used_seed):
 
260
  return {
261
  image_path_state: path,
262
  current_seed: used_seed,
263
+ btn_image: gr.update(interactive=True),
264
  btn_geo: gr.update(interactive=True, variant="primary"),
265
  btn_tex: gr.update(interactive=False),
266
  geometry_preview: gr.update(value=None),
 
268
  }
269
 
270
  def on_geometry_generated(path):
 
271
  return {
272
  geometry_path_state: path,
273
+ btn_geo: gr.update(interactive=True, variant="secondary"),
274
  btn_tex: gr.update(interactive=True, variant="primary"),
275
  }
276
+
277
+ def on_texture_generated():
278
+ return {
279
+ btn_tex: gr.update(interactive=True, variant="secondary")
280
+ }
281
 
282
  btn_image.click(
283
+ fn=lambda: gr.update(interactive=False), outputs=[btn_image]
284
+ ).then(
285
  fn=generate_image,
286
  inputs=[prompt, randomize_seed, seed],
287
  outputs=[image_preview, current_seed]
288
  ).then(
289
  fn=on_image_generated,
290
  inputs=[image_preview, current_seed],
291
+ outputs=[image_path_state, current_seed, btn_image, btn_geo, btn_tex, geometry_preview, textured_preview]
292
  )
293
 
294
  btn_geo.click(
295
+ fn=lambda: (gr.update(interactive=False), gr.update(interactive=False)),
296
+ outputs=[btn_geo, btn_tex]
297
+ ).then(
298
  fn=generate_geometry,
299
  inputs=[image_path_state, guidance_3d, steps_3d, max_facenum, symmetry, edge_type],
300
  outputs=[geometry_preview]
301
  ).then(
302
  fn=on_geometry_generated,
303
  inputs=[geometry_preview],
304
+ outputs=[geometry_path_state, btn_geo, btn_tex]
305
  )
306
 
307
  btn_tex.click(
308
+ fn=lambda: gr.update(interactive=False), outputs=[btn_tex]
309
+ ).then(
310
  fn=generate_texture,
311
  inputs=[image_path_state, geometry_path_state],
312
  outputs=[textured_preview],
313
+ ).then(
314
+ fn=on_texture_generated,
315
+ outputs=[btn_tex]
316
  )
317
 
318
  demo.launch(ssr_mode=False)