dkatz2391 commited on
Commit
94bae10
·
verified ·
1 Parent(s): e68e0ca

added logging

Browse files
Files changed (1) hide show
  1. app.py +211 -115
app.py CHANGED
@@ -4,9 +4,6 @@ import spaces
4
  import os
5
  import shutil
6
  import json
7
- os.environ['TOKENIZERS_PARALLELISM'] = 'true'
8
- os.environ['SPCONV_ALGO'] = 'native'
9
- from typing import *
10
  import torch
11
  import numpy as np
12
  import imageio
@@ -14,11 +11,22 @@ from easydict import EasyDict as edict
14
  from trellis.pipelines import TrellisTextTo3DPipeline
15
  from trellis.representations import Gaussian, MeshExtractResult
16
  from trellis.utils import render_utils, postprocessing_utils
17
-
18
  import traceback
19
  import sys
20
  import time
 
 
 
 
 
 
 
 
 
 
 
21
 
 
22
 
23
  # Add JSON encoder for NumPy arrays
24
  class NumpyEncoder(json.JSONEncoder):
@@ -259,24 +267,23 @@ def extract_gaussian(state: dict, req: gr.Request) -> Tuple[str, str]:
259
  return gaussian_path, gaussian_path
260
 
261
 
262
- # --- NEW COMBINED API FUNCTION ---
263
- @spaces.GPU(duration=120) # Allow more time for combined generation + extraction
264
  def generate_and_extract_glb(
265
- # Inputs mirror text_to_3d and extract_glb settings
266
  prompt: str,
267
  seed: int,
268
  ss_guidance_strength: float,
269
  ss_sampling_steps: int,
270
  slat_guidance_strength: float,
271
  slat_sampling_steps: int,
272
- mesh_simplify: float, # Added from extract_glb
273
- texture_size: int, # Added from extract_glb
274
- req: gr.Request, # Keep req for potential session info if needed
275
- ) -> Optional[str]: # MODIFIED: Explicitly show it can return None
276
  """
277
  Combines 3D model generation and GLB extraction into a single step
278
  for API usage, avoiding the need to transfer the state object.
279
-
280
  Args:
281
  prompt (str): Text prompt for generation.
282
  seed (int): Random seed.
@@ -286,37 +293,65 @@ def generate_and_extract_glb(
286
  slat_sampling_steps (int): Structured latent steps.
287
  mesh_simplify (float): Mesh simplification factor for GLB.
288
  texture_size (int): Texture resolution for GLB.
289
- req (gr.Request): Gradio request object.
290
-
291
  Returns:
292
- Optional[str]: The absolute path to the generated GLB file within the Space's filesystem,
293
- or None if any step fails.
294
  """
295
- session_hash = "API_CALL" # Use a generic identifier for API calls if req is None or lacks session
 
 
296
  if req and hasattr(req, 'session_hash') and req.session_hash:
297
- session_hash = req.session_hash
 
 
 
 
 
 
 
 
 
298
 
299
  user_dir = os.path.join(TMP_DIR, str(session_hash))
300
  try:
 
301
  os.makedirs(user_dir, exist_ok=True)
 
302
  except Exception as e:
303
- print(f"[{session_hash}] API: ERROR creating directory {user_dir}: {e}")
304
- return None # Cannot proceed without directory
 
 
305
 
306
- print(f"[{session_hash}] API: ===== generate_and_extract_glb START ====")
307
- print(f"[{session_hash}] API: Prompt: '{prompt}', Seed: {seed}, Simplify: {mesh_simplify}, Texture: {texture_size}")
308
 
 
 
 
 
 
 
 
 
309
  gs_output = None
310
  mesh_output = None
 
311
 
312
- # --- Step 1: Generate 3D Model (adapted from text_to_3d) ---
 
313
  try:
314
- print(f"[{session_hash}] API: Step 1 - Running generation pipeline...")
315
- t_start_gen = time.time() # Add timing
 
 
 
 
 
316
  outputs = pipeline.run(
317
  prompt,
318
  seed=seed,
319
- formats=["gaussian", "mesh"], # Need both for GLB extraction
320
  sparse_structure_sampler_params={
321
  "steps": ss_sampling_steps,
322
  "cfg_strength": ss_guidance_strength,
@@ -326,87 +361,167 @@ def generate_and_extract_glb(
326
  "cfg_strength": slat_guidance_strength,
327
  },
328
  )
 
329
  t_end_gen = time.time()
330
- print(f"[{session_hash}] API: Step 1 - Generation pipeline completed in {t_end_gen - t_start_gen:.2f}s.")
331
 
332
- # Validate outputs immediately
333
- if not outputs or 'gaussian' not in outputs or not outputs['gaussian'] or 'mesh' not in outputs or not outputs['mesh']:
334
- print(f"[{session_hash}] API: ERROR - Pipeline output is missing expected keys or values.")
335
- return None
 
 
 
 
 
 
 
 
 
336
 
337
  gs_output = outputs['gaussian'][0]
338
  mesh_output = outputs['mesh'][0]
339
 
340
- if gs_output is None or mesh_output is None:
341
- print(f"[{session_hash}] API: ERROR - Pipeline returned None for gs_output or mesh_output.")
342
- return None
343
 
344
- print(f"[{session_hash}] API: Step 1 - Outputs obtained (gs type: {type(gs_output)}, mesh type: {type(mesh_output)}).")
345
-
346
- except Exception as e:
347
- print(f"[{session_hash}] API: ERROR during generation pipeline step: {e}")
348
- # Print detailed traceback
349
- traceback.print_exc()
350
- # Clean up CUDA memory before returning
351
- try:
352
- torch.cuda.empty_cache()
353
- print(f"[{session_hash}] API: CUDA cache cleared after generation error.")
354
- except Exception as cache_e:
355
- print(f"[{session_hash}] API: Error clearing CUDA cache after generation error: {cache_e}")
356
- return None # Return None on failure
357
-
358
- # --- Step 2: Extract GLB (adapted from extract_glb) ---
359
- glb_path = None # Initialize glb_path
360
- try:
361
- print(f"[{session_hash}] API: Step 2 - Extracting GLB (simplify={mesh_simplify}, texture={texture_size})...")
362
- # Check if inputs from previous step are valid
363
- if gs_output is None or mesh_output is None:
364
- print(f"[{session_hash}] API: ERROR - Cannot proceed with GLB extraction, gs_output or mesh_output is None.")
365
- return None
366
 
367
- t_start_glb = time.time()
368
- # Directly use the outputs from the pipeline
369
- glb = postprocessing_utils.to_glb(gs_output, mesh_output, simplify=mesh_simplify, texture_size=texture_size, verbose=False)
370
- t_end_glb = time.time()
371
- print(f"[{session_hash}] API: Step 2 - GLB object created in {t_end_glb - t_start_glb:.2f}s.")
 
 
 
 
 
 
372
 
373
- if glb is None:
374
- print(f"[{session_hash}] API: ERROR - postprocessing_utils.to_glb returned None.")
375
- return None
376
 
377
- glb_path = os.path.join(user_dir, f'api_generated_{session_hash}.glb') # Use unique name
378
- print(f"[{session_hash}] API: Step 2 - Saving GLB to {glb_path}...")
379
- t_start_save = time.time()
380
- glb.export(glb_path)
381
- t_end_save = time.time()
382
- print(f"[{session_hash}] API: Step 2 - GLB saved in {t_end_save - t_start_save:.2f}s.")
383
- print(f"[{session_hash}] API: Step 2 - GLB extraction completed successfully.")
384
-
385
- except Exception as e:
386
- print(f"[{session_hash}] API: ERROR during GLB extraction step: {e}")
387
- # Print detailed traceback
388
  traceback.print_exc()
389
- # Clean up CUDA memory before returning
 
 
 
 
 
 
390
  try:
 
391
  torch.cuda.empty_cache()
392
- print(f"[{session_hash}] API: CUDA cache cleared after extraction error.")
393
- except Exception as cache_e:
394
- print(f"[{session_hash}] API: Error clearing CUDA cache after extraction error: {cache_e}")
395
- return None # Return None on failure
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
396
 
397
- # --- Final Cleanup and Return ---
 
 
398
  try:
 
399
  torch.cuda.empty_cache()
400
  print(f"[{session_hash}] API: Final CUDA cache cleared.")
401
- except Exception as cache_e:
402
- print(f"[{session_hash}] API: Error clearing final CUDA cache: {cache_e}")
403
 
 
 
 
 
 
 
404
  if glb_path and os.path.exists(glb_path):
405
- print(f"[{session_hash}] API: ===== generate_and_extract_glb END (Success) ===== Returning GLB path: {glb_path}")
406
- return glb_path # Return only the path to the generated GLB
 
407
  else:
408
- print(f"[{session_hash}] API: ===== generate_and_extract_glb END (Failure) ===== GLB path not generated or does not exist.")
409
- return None # Ensure None is returned if glb_path wasn't set or file doesn't exist
 
410
  # --- END NEW COMBINED API FUNCTION ---
411
 
412
 
@@ -535,40 +650,21 @@ with gr.Blocks(delete_cache=(600, 600)) as demo:
535
  outputs=[download_glb, download_gs], # Disable both download buttons
536
  )
537
 
538
- # --- NEW API ENDPOINT DEFINITION ---
539
- # Define the combined function as an API endpoint.
540
- # This is *separate* from the UI button clicks.
541
- # It directly calls the combined function.
542
- demo.load(
543
- None, # No function needed on load for this endpoint
544
- inputs=[
545
- text_prompt, # Map inputs from API request data based on order
546
- seed,
547
- ss_guidance_strength,
548
- ss_sampling_steps,
549
- slat_guidance_strength,
550
- slat_sampling_steps,
551
- mesh_simplify,
552
- texture_size
553
- ],
554
- outputs=None, # Output is handled by the function return for the API
555
- api_name="generate_and_extract_glb" # Assign the specific API name
556
- )
557
-
558
  # --- Launch the Gradio app ---
559
  if __name__ == "__main__":
560
- print("Loading Trellis pipeline...")
561
- # Consider adding error handling for pipeline loading
562
  try:
 
563
  pipeline = TrellisTextTo3DPipeline.from_pretrained("JeffreyXiang/TRELLIS-text-xlarge")
 
564
  pipeline.cuda()
565
- print("Pipeline loaded successfully.")
566
  except Exception as e:
567
- print(f"Error loading pipeline: {e}")
568
- # Optionally exit or provide a fallback UI
 
569
  sys.exit(1)
570
 
571
- print("Launching Gradio demo...")
572
- # Enable queue for handling multiple users/requests
573
- # Set share=True if you need a public link (requires login for private spaces)
574
  demo.queue().launch()
 
4
  import os
5
  import shutil
6
  import json
 
 
 
7
  import torch
8
  import numpy as np
9
  import imageio
 
11
  from trellis.pipelines import TrellisTextTo3DPipeline
12
  from trellis.representations import Gaussian, MeshExtractResult
13
  from trellis.utils import render_utils, postprocessing_utils
 
14
  import traceback
15
  import sys
16
  import time
17
+ # If psutil is available in the environment, we can use it for memory info
18
+ try:
19
+ import psutil
20
+ PSUTIL_AVAILABLE = True
21
+ except ImportError:
22
+ PSUTIL_AVAILABLE = False
23
+
24
+ # --- Environment Variables ---
25
+ os.environ['TOKENIZERS_PARALLELISM'] = 'true'
26
+ os.environ['SPCONV_ALGO'] = 'native'
27
+ # ---------------------------
28
 
29
+ from typing import *
30
 
31
  # Add JSON encoder for NumPy arrays
32
  class NumpyEncoder(json.JSONEncoder):
 
267
  return gaussian_path, gaussian_path
268
 
269
 
270
+ # --- NEW COMBINED API FUNCTION (with HEAVY logging) ---
271
+ @spaces.GPU(duration=120)
272
  def generate_and_extract_glb(
 
273
  prompt: str,
274
  seed: int,
275
  ss_guidance_strength: float,
276
  ss_sampling_steps: int,
277
  slat_guidance_strength: float,
278
  slat_sampling_steps: int,
279
+ mesh_simplify: float,
280
+ texture_size: int,
281
+ req: Optional[gr.Request] = None, # Make req optional for robustness
282
+ ) -> Optional[str]:
283
  """
284
  Combines 3D model generation and GLB extraction into a single step
285
  for API usage, avoiding the need to transfer the state object.
286
+ Includes extensive logging.
287
  Args:
288
  prompt (str): Text prompt for generation.
289
  seed (int): Random seed.
 
293
  slat_sampling_steps (int): Structured latent steps.
294
  mesh_simplify (float): Mesh simplification factor for GLB.
295
  texture_size (int): Texture resolution for GLB.
296
+ req (Optional[gr.Request]): Gradio request object.
 
297
  Returns:
298
+ Optional[str]: Path to the generated GLB file or None on failure.
 
299
  """
300
+ # --- Setup & Initial Logging ---
301
+ pid = os.getpid()
302
+ session_hash = f"API_CALL_{pid}_{int(time.time()*1000)}" # More unique ID for API calls
303
  if req and hasattr(req, 'session_hash') and req.session_hash:
304
+ session_hash = req.session_hash # Use session hash if available from UI call
305
+
306
+ print(f"\n[{session_hash}] ========= generate_and_extract_glb INVOKED =========")
307
+ print(f"[{session_hash}] API: PID: {pid}")
308
+ if PSUTIL_AVAILABLE:
309
+ process = psutil.Process(pid)
310
+ mem_info_start = process.memory_info()
311
+ print(f"[{session_hash}] API: Initial Memory: RSS={mem_info_start.rss / (1024**2):.2f} MB, VMS={mem_info_start.vms / (1024**2):.2f} MB")
312
+ else:
313
+ print(f"[{session_hash}] API: psutil not available, cannot log memory usage.")
314
 
315
  user_dir = os.path.join(TMP_DIR, str(session_hash))
316
  try:
317
+ print(f"[{session_hash}] API: Ensuring directory exists: {user_dir}")
318
  os.makedirs(user_dir, exist_ok=True)
319
+ print(f"[{session_hash}] API: Directory ensured.")
320
  except Exception as e:
321
+ print(f"[{session_hash}] API: FATAL ERROR creating directory {user_dir}: {e}")
322
+ traceback.print_exc()
323
+ print(f"[{session_hash}] ========= generate_and_extract_glb FAILED (Directory Creation) =========")
324
+ return None
325
 
326
+ print(f"[{session_hash}] API: Input Params: Prompt='{prompt}', Seed={seed}, Simplify={mesh_simplify}, Texture={texture_size}")
327
+ print(f"[{session_hash}] API: Input Params: SS Steps={ss_sampling_steps}, SS Cfg={ss_guidance_strength}, Slat Steps={slat_sampling_steps}, Slat Cfg={slat_guidance_strength}")
328
 
329
+ # Check CUDA availability
330
+ cuda_available = torch.cuda.is_available()
331
+ print(f"[{session_hash}] API: torch.cuda.is_available(): {cuda_available}")
332
+ if not cuda_available:
333
+ print(f"[{session_hash}] API: FATAL ERROR - CUDA not available!")
334
+ print(f"[{session_hash}] ========= generate_and_extract_glb FAILED (CUDA Unavailable) =========")
335
+ return None
336
+
337
  gs_output = None
338
  mesh_output = None
339
+ glb_path = None
340
 
341
+ # --- Step 1: Generate 3D Model ---
342
+ print(f"\n[{session_hash}] API: --- Starting Step 1: Generation Pipeline --- ")
343
  try:
344
+ if pipeline is None:
345
+ print(f"[{session_hash}] API: FATAL ERROR - `pipeline` object is None!")
346
+ raise ValueError("Trellis pipeline is not loaded.")
347
+
348
+ print(f"[{session_hash}] API: Step 1 - Calling pipeline.run()...")
349
+ t_start_gen = time.time()
350
+ # --- The actual pipeline call ---
351
  outputs = pipeline.run(
352
  prompt,
353
  seed=seed,
354
+ formats=["gaussian", "mesh"],
355
  sparse_structure_sampler_params={
356
  "steps": ss_sampling_steps,
357
  "cfg_strength": ss_guidance_strength,
 
361
  "cfg_strength": slat_guidance_strength,
362
  },
363
  )
364
+ # --- End pipeline call ---
365
  t_end_gen = time.time()
366
+ print(f"[{session_hash}] API: Step 1 - pipeline.run() completed in {t_end_gen - t_start_gen:.2f}s.")
367
 
368
+ # === Validate pipeline outputs ===
369
+ print(f"[{session_hash}] API: Step 1 - Validating pipeline outputs...")
370
+ if not outputs:
371
+ print(f"[{session_hash}] API: ERROR - Pipeline output dictionary is None or empty.")
372
+ raise ValueError("Pipeline returned empty output.")
373
+
374
+ if 'gaussian' not in outputs or not outputs['gaussian']:
375
+ print(f"[{session_hash}] API: ERROR - Pipeline output missing 'gaussian' key or value is empty.")
376
+ raise ValueError("Pipeline output missing Gaussian result.")
377
+
378
+ if 'mesh' not in outputs or not outputs['mesh']:
379
+ print(f"[{session_hash}] API: ERROR - Pipeline output missing 'mesh' key or value is empty.")
380
+ raise ValueError("Pipeline output missing Mesh result.")
381
 
382
  gs_output = outputs['gaussian'][0]
383
  mesh_output = outputs['mesh'][0]
384
 
385
+ if gs_output is None:
386
+ print(f"[{session_hash}] API: ERROR - Pipeline returned gs_output as None.")
387
+ raise ValueError("Pipeline returned None for Gaussian output.")
388
 
389
+ if mesh_output is None:
390
+ print(f"[{session_hash}] API: ERROR - Pipeline returned mesh_output as None.")
391
+ raise ValueError("Pipeline returned None for Mesh output.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
392
 
393
+ print(f"[{session_hash}] API: Step 1 - Outputs validated successfully.")
394
+ print(f"[{session_hash}] API: Step 1 - gs_output type: {type(gs_output)}")
395
+ # Add more details if useful, e.g., number of Gaussians
396
+ if hasattr(gs_output, '_xyz'):
397
+ print(f"[{session_hash}] API: Step 1 - gs_output num points: {len(gs_output._xyz)}")
398
+
399
+ print(f"[{session_hash}] API: Step 1 - mesh_output type: {type(mesh_output)}")
400
+ # Add more details if useful, e.g., number of vertices/faces
401
+ if hasattr(mesh_output, 'vertices') and hasattr(mesh_output, 'faces'):
402
+ print(f"[{session_hash}] API: Step 1 - mesh_output verts: {len(mesh_output.vertices)}, faces: {len(mesh_output.faces)}")
403
+ # =================================
404
 
405
+ if PSUTIL_AVAILABLE:
406
+ mem_info_after_gen = process.memory_info()
407
+ print(f"[{session_hash}] API: Memory After Gen: RSS={mem_info_after_gen.rss / (1024**2):.2f} MB, VMS={mem_info_after_gen.vms / (1024**2):.2f} MB")
408
 
409
+ except Exception as e_gen:
410
+ print(f"\n[{session_hash}] API: ******** ERROR IN STEP 1: Generation Pipeline ********")
411
+ print(f"[{session_hash}] API: Error Type: {type(e_gen).__name__}, Message: {e_gen}")
412
+ print(f"[{session_hash}] API: Printing traceback...")
 
 
 
 
 
 
 
413
  traceback.print_exc()
414
+ print(f"[{session_hash}] API: ********************************************************")
415
+ gs_output = None # Ensure reset on error
416
+ mesh_output = None
417
+ # Fall through to finally block for cleanup
418
+ finally:
419
+ # Attempt cleanup regardless of success/failure in try block
420
+ print(f"[{session_hash}] API: Step 1 - Entering finally block for potential cleanup.")
421
  try:
422
+ print(f"[{session_hash}] API: Step 1 - Attempting CUDA cache clear (finally)...")
423
  torch.cuda.empty_cache()
424
+ print(f"[{session_hash}] API: Step 1 - CUDA cache cleared (finally).")
425
+ except Exception as cache_e_gen:
426
+ print(f"[{session_hash}] API: WARNING - Error clearing CUDA cache in Step 1 finally block: {cache_e_gen}")
427
+ print(f"[{session_hash}] API: --- Finished Step 1: Generation Pipeline (gs valid: {gs_output is not None}, mesh valid: {mesh_output is not None}) --- \n")
428
+
429
+ # --- Step 2: Extract GLB ---
430
+ # Proceed only if Step 1 was successful
431
+ if gs_output is not None and mesh_output is not None:
432
+ print(f"\n[{session_hash}] API: --- Starting Step 2: GLB Extraction --- ")
433
+ try:
434
+ print(f"[{session_hash}] API: Step 2 - Inputs: gs type {type(gs_output)}, mesh type {type(mesh_output)}")
435
+ print(f"[{session_hash}] API: Step 2 - Params: Simplify={mesh_simplify}, Texture Size={texture_size}")
436
+ print(f"[{session_hash}] API: Step 2 - Calling postprocessing_utils.to_glb()...")
437
+ t_start_glb = time.time()
438
+ # --- The actual GLB conversion call ---
439
+ glb = postprocessing_utils.to_glb(gs_output, mesh_output, simplify=mesh_simplify, texture_size=texture_size, verbose=False)
440
+ # --- End GLB conversion call ---
441
+ t_end_glb = time.time()
442
+ print(f"[{session_hash}] API: Step 2 - postprocessing_utils.to_glb() completed in {t_end_glb - t_start_glb:.2f}s.")
443
+
444
+ # === Validate GLB output ===
445
+ print(f"[{session_hash}] API: Step 2 - Validating GLB object...")
446
+ if glb is None:
447
+ print(f"[{session_hash}] API: ERROR - postprocessing_utils.to_glb returned None.")
448
+ raise ValueError("GLB conversion returned None.")
449
+ print(f"[{session_hash}] API: Step 2 - GLB object validated successfully (type: {type(glb)})...")
450
+ # ==========================
451
+
452
+ # === Save GLB ===
453
+ glb_path = os.path.join(user_dir, f'api_generated_{session_hash}_{int(time.time()*1000)}.glb') # More unique name
454
+ print(f"[{session_hash}] API: Step 2 - Saving GLB to path: {glb_path}...")
455
+ t_start_save = time.time()
456
+ # --- The actual GLB export call ---
457
+ glb.export(glb_path)
458
+ # --- End GLB export call ---
459
+ t_end_save = time.time()
460
+ print(f"[{session_hash}] API: Step 2 - glb.export() completed in {t_end_save - t_start_save:.2f}s.")
461
+ # =================
462
+
463
+ # === Verify File Exists ===
464
+ print(f"[{session_hash}] API: Step 2 - Verifying saved file exists at {glb_path}...")
465
+ if not os.path.exists(glb_path):
466
+ print(f"[{session_hash}] API: ERROR - GLB file was not found after export at {glb_path}.")
467
+ raise IOError(f"GLB export failed, file not found: {glb_path}")
468
+ print(f"[{session_hash}] API: Step 2 - Saved file verified.")
469
+ # =========================
470
+
471
+ print(f"[{session_hash}] API: Step 2 - GLB extraction and saving completed successfully.")
472
+ if PSUTIL_AVAILABLE:
473
+ mem_info_after_glb = process.memory_info()
474
+ print(f"[{session_hash}] API: Memory After GLB: RSS={mem_info_after_glb.rss / (1024**2):.2f} MB, VMS={mem_info_after_glb.vms / (1024**2):.2f} MB")
475
+
476
+ except Exception as e_glb:
477
+ print(f"\n[{session_hash}] API: ******** ERROR IN STEP 2: GLB Extraction ********")
478
+ print(f"[{session_hash}] API: Error Type: {type(e_glb).__name__}, Message: {e_glb}")
479
+ print(f"[{session_hash}] API: Printing traceback...")
480
+ traceback.print_exc()
481
+ print(f"[{session_hash}] API: *****************************************************")
482
+ glb_path = None # Ensure reset on error
483
+ # Fall through to finally block for cleanup
484
+ finally:
485
+ # Attempt cleanup regardless of success/failure in try block
486
+ print(f"[{session_hash}] API: Step 2 - Entering finally block for potential cleanup.")
487
+ # Explicitly delete large objects if possible (might help memory)
488
+ del glb
489
+ print(f"[{session_hash}] API: Step 2 - Deleted intermediate 'glb' object.")
490
+ try:
491
+ print(f"[{session_hash}] API: Step 2 - Attempting CUDA cache clear (finally)...")
492
+ torch.cuda.empty_cache()
493
+ print(f"[{session_hash}] API: Step 2 - CUDA cache cleared (finally).")
494
+ except Exception as cache_e_glb:
495
+ print(f"[{session_hash}] API: WARNING - Error clearing CUDA cache in Step 2 finally block: {cache_e_glb}")
496
+ print(f"[{session_hash}] API: --- Finished Step 2: GLB Extraction (path valid: {glb_path is not None}) --- \n")
497
+ else:
498
+ print(f"[{session_hash}] API: Skipping Step 2 (GLB Extraction) because Step 1 failed or produced invalid outputs.")
499
+ glb_path = None # Ensure glb_path is None if Step 1 failed
500
 
501
+ # --- Final Cleanup and Return ---
502
+ print(f"[{session_hash}] API: --- Entering Final Cleanup and Return --- ")
503
+ # Final attempt to clear CUDA cache
504
  try:
505
+ print(f"[{session_hash}] API: Final CUDA cache clear attempt...")
506
  torch.cuda.empty_cache()
507
  print(f"[{session_hash}] API: Final CUDA cache cleared.")
508
+ except Exception as cache_e_final:
509
+ print(f"[{session_hash}] API: WARNING - Error clearing final CUDA cache: {cache_e_final}")
510
 
511
+ # Explicitly delete pipeline outputs if they exist
512
+ del gs_output
513
+ del mesh_output
514
+ print(f"[{session_hash}] API: Deleted intermediate 'gs_output' and 'mesh_output' objects.")
515
+
516
+ # Final decision based on glb_path status
517
  if glb_path and os.path.exists(glb_path):
518
+ print(f"[{session_hash}] API: Final Result: SUCCESS. GLB Path: {glb_path}")
519
+ print(f"[{session_hash}] ========= generate_and_extract_glb END (Success) =========")
520
+ return glb_path
521
  else:
522
+ print(f"[{session_hash}] API: Final Result: FAILURE. GLB Path: {glb_path} (Exists: {os.path.exists(glb_path) if glb_path else 'N/A'})")
523
+ print(f"[{session_hash}] ========= generate_and_extract_glb END (Failure) =========")
524
+ return None
525
  # --- END NEW COMBINED API FUNCTION ---
526
 
527
 
 
650
  outputs=[download_glb, download_gs], # Disable both download buttons
651
  )
652
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
653
  # --- Launch the Gradio app ---
654
  if __name__ == "__main__":
655
+ print("Initializing pipeline...")
656
+ pipeline = None # Initialize pipeline variable
657
  try:
658
+ # Load the pipeline
659
  pipeline = TrellisTextTo3DPipeline.from_pretrained("JeffreyXiang/TRELLIS-text-xlarge")
660
+ # Move pipeline to CUDA device
661
  pipeline.cuda()
662
+ print("Pipeline loaded and moved to CUDA successfully.")
663
  except Exception as e:
664
+ print(f"FATAL ERROR initializing pipeline: {e}")
665
+ traceback.print_exc()
666
+ # Optionally exit if pipeline loading fails
667
  sys.exit(1)
668
 
669
+ print("Launching Gradio demo with queue enabled...")
 
 
670
  demo.queue().launch()