dkatz2391 commited on
Commit
696b9f6
·
verified ·
1 Parent(s): 9df9f29

REvert and just ocmment out

Browse files
Files changed (1) hide show
  1. app.py +78 -105
app.py CHANGED
@@ -1,16 +1,17 @@
1
- # Version: 1.1.3 - API State Fix + DEBUG (Video Disabled) + unload() Fix (2025-05-04)
2
  # Changes:
3
- # - FIXED TypeError in demo.unload() by removing incorrect 'inputs'/'outputs' arguments.
4
- # - ENSURED `import spaces` is present for the @spaces.GPU decorator.
5
- # - TEMPORARY DEBUGGING STEP: Commented out video rendering in `text_to_3d`
6
  # and return None for video_path to isolate the "Session not found" error.
7
- # - Modified `text_to_3d` to explicitly return the serializable `state_dict` from `pack_state`.
8
- # - Modified `extract_glb`/`extract_gaussian` to accept `state_dict: dict`.
9
- # - Kept Gradio UI bindings using `output_buf`.
10
- # - Added minor safety checks and logging.
11
 
12
  import gradio as gr
13
- import spaces # <<<--- ENSURE THIS IMPORT IS PRESENT
 
 
 
14
 
15
  import os
16
  import shutil
@@ -29,60 +30,49 @@ from trellis.utils import render_utils, postprocessing_utils
29
  import traceback
30
  import sys
31
 
32
-
33
  MAX_SEED = np.iinfo(np.int32).max
34
- # Use standard /tmp directory which is usually available in container environments
35
- TMP_DIR = '/tmp/gradio_sessions'
36
- print(f"Using temporary directory: {TMP_DIR}")
37
- # Ensure the base temp directory exists
38
  try:
39
  os.makedirs(TMP_DIR, exist_ok=True)
 
40
  except OSError as e:
41
- print(f"Warning: Could not create base temp directory {TMP_DIR}: {e}", file=sys.stderr)
42
- # Potentially fall back or exit if temp dir is critical
43
- TMP_DIR = '.' # Fallback to current directory (less ideal)
44
- print(f"Warning: Falling back to use current directory for temp files: {os.path.abspath(TMP_DIR)}")
45
-
46
 
47
  def start_session(req: gr.Request):
48
  """Creates a temporary directory for the user session."""
49
- user_dir = None # Initialize
50
  try:
51
  session_hash = req.session_hash
52
  if not session_hash:
53
- session_hash = f"no_session_{np.random.randint(10000, 99999)}"
54
- print(f"Warning: No session_hash in request, using temporary ID: {session_hash}")
55
-
56
- # Ensure TMP_DIR exists before joining path
57
- if not os.path.exists(TMP_DIR):
58
- os.makedirs(TMP_DIR, exist_ok=True)
59
-
60
  user_dir = os.path.join(TMP_DIR, str(session_hash))
61
  os.makedirs(user_dir, exist_ok=True)
62
  print(f"Started session, ensured directory exists: {user_dir}")
63
  except Exception as e:
64
  print(f"Error in start_session creating directory '{user_dir}': {e}", file=sys.stderr)
65
- traceback.print_exc()
66
-
67
 
68
  def end_session(req: gr.Request):
69
  """Removes the temporary directory for the user session."""
70
- user_dir = None # Initialize
71
  try:
72
  session_hash = req.session_hash
73
  if not session_hash:
74
- print("Warning: No session_hash in end_session request, cannot clean up.")
75
- return
76
-
77
  user_dir = os.path.join(TMP_DIR, str(session_hash))
78
- if os.path.exists(user_dir) and os.path.isdir(user_dir): # Extra check if it's a directory
79
  try:
80
  shutil.rmtree(user_dir)
81
  print(f"Ended session, removed directory: {user_dir}")
82
  except OSError as e:
83
  print(f"Error removing tmp directory {user_dir}: {e.strerror}", file=sys.stderr)
84
  else:
85
- print(f"Ended session, directory not found or not a directory: {user_dir}")
86
  except Exception as e:
87
  print(f"Error in end_session cleaning directory '{user_dir}': {e}", file=sys.stderr)
88
 
@@ -108,9 +98,9 @@ def pack_state(gs: Gaussian, mesh: MeshExtractResult) -> dict:
108
  print(f"[pack_state] Dictionary created. Keys: {list(packed_data.keys())}, Gaussian points: {len(packed_data['gaussian']['_xyz'])}, Mesh vertices: {len(packed_data['mesh']['vertices'])}")
109
  return packed_data
110
  except Exception as e:
111
- print(f"Error during pack_state: {e}", file=sys.stderr)
112
- traceback.print_exc()
113
- raise
114
 
115
 
116
  def unpack_state(state_dict: dict) -> Tuple[Gaussian, edict]:
@@ -161,6 +151,7 @@ def get_seed(randomize_seed: bool, seed: int) -> int:
161
  return int(new_seed)
162
 
163
 
 
164
  @spaces.GPU
165
  def text_to_3d(
166
  prompt: str,
@@ -170,22 +161,20 @@ def text_to_3d(
170
  slat_guidance_strength: float,
171
  slat_sampling_steps: int,
172
  req: gr.Request,
173
- ) -> Tuple[dict, Optional[str]]:
174
  """
175
  Generates a 3D model (Gaussian and Mesh) from text and returns a
176
  serializable state dictionary and potentially a video preview path.
177
  >>> TEMPORARILY DISABLED VIDEO RENDERING FOR DEBUGGING <<<
178
  """
179
  print(f"[text_to_3d - DEBUG MODE] Received prompt: '{prompt}', Seed: {seed}")
180
- user_dir = None # Initialize
181
- state_dict = None # Initialize
182
  try:
183
  session_hash = req.session_hash
184
  if not session_hash:
185
- session_hash = f"no_session_{np.random.randint(10000, 99999)}"
186
- print(f"Warning: No session_hash in text_to_3d request, using temporary ID: {session_hash}")
187
-
188
- # Ensure user directory exists
189
  user_dir = os.path.join(TMP_DIR, str(session_hash))
190
  os.makedirs(user_dir, exist_ok=True)
191
  print(f"[text_to_3d - DEBUG MODE] User directory: {user_dir}")
@@ -213,29 +202,40 @@ def text_to_3d(
213
  except Exception as e:
214
  print(f"❌ [text_to_3d - DEBUG MODE] Error during generation or packing: {e}", file=sys.stderr)
215
  traceback.print_exc()
216
- # Raise a Gradio error to send failure message back to client if possible
217
  raise gr.Error(f"Core generation failed: {e}")
218
 
219
  # --- Render Video Preview (TEMPORARILY DISABLED FOR DEBUGGING) ---
220
- video_path = None
221
  print("[text_to_3d - DEBUG MODE] Skipping video rendering.")
222
- # --- Original Video Code Block (Keep commented) ---
223
- # ... (video code commented out) ...
 
 
 
 
 
 
 
 
 
 
 
 
 
224
 
225
  # --- Cleanup and Return ---
226
  if torch.cuda.is_available():
227
  torch.cuda.empty_cache()
228
  print("[text_to_3d - DEBUG MODE] Cleared CUDA cache.")
229
 
230
- # --- Return Serializable Dictionary and None Video Path ---
231
  print("[text_to_3d - DEBUG MODE] Returning state dictionary and None video path.")
232
  if state_dict is None:
233
- # This case should ideally be caught by the exception handling above
234
  print("Error: state_dict is None before return, generation likely failed.", file=sys.stderr)
235
  raise gr.Error("State dictionary creation failed.")
236
  return state_dict, video_path
237
 
238
 
 
239
  @spaces.GPU(duration=120)
240
  def extract_glb(
241
  state_dict: dict,
@@ -247,13 +247,13 @@ def extract_glb(
247
  Extracts a GLB file from the provided 3D model state dictionary.
248
  """
249
  print(f"[extract_glb] Received request. Simplify: {mesh_simplify}, Texture Size: {texture_size}")
250
- user_dir = None # Initialize
251
- glb_path = None # Initialize
252
  try:
253
  session_hash = req.session_hash
254
  if not session_hash:
255
- session_hash = f"no_session_{np.random.randint(10000, 99999)}"
256
- print(f"Warning: No session_hash in extract_glb request, using temporary ID: {session_hash}")
257
 
258
  if not isinstance(state_dict, dict):
259
  print("❌ [extract_glb] Error: Invalid state_dict received (not a dictionary).")
@@ -279,7 +279,7 @@ def extract_glb(
279
  except Exception as e:
280
  print(f"❌ [extract_glb] Error during GLB extraction: {e}", file=sys.stderr)
281
  traceback.print_exc()
282
- raise gr.Error(f"Failed to extract GLB: {e}") # Propagate error
283
 
284
  # --- Cleanup and Return ---
285
  if torch.cuda.is_available():
@@ -293,6 +293,7 @@ def extract_glb(
293
  return glb_path, glb_path
294
 
295
 
 
296
  @spaces.GPU
297
  def extract_gaussian(
298
  state_dict: dict,
@@ -302,13 +303,13 @@ def extract_gaussian(
302
  Extracts a PLY (Gaussian) file from the provided 3D model state dictionary.
303
  """
304
  print("[extract_gaussian] Received request.")
305
- user_dir = None # Initialize
306
- gaussian_path = None # Initialize
307
  try:
308
  session_hash = req.session_hash
309
  if not session_hash:
310
- session_hash = f"no_session_{np.random.randint(10000, 99999)}"
311
- print(f"Warning: No session_hash in extract_gaussian request, using temporary ID: {session_hash}")
312
 
313
  if not isinstance(state_dict, dict):
314
  print("❌ [extract_gaussian] Error: Invalid state_dict received (not a dictionary).")
@@ -330,7 +331,7 @@ def extract_gaussian(
330
  except Exception as e:
331
  print(f"❌ [extract_gaussian] Error during Gaussian extraction: {e}", file=sys.stderr)
332
  traceback.print_exc()
333
- raise gr.Error(f"Failed to extract Gaussian PLY: {e}") # Propagate error
334
 
335
  # --- Cleanup and Return ---
336
  if torch.cuda.is_available():
@@ -355,13 +356,11 @@ with gr.Blocks(delete_cache=(600, 600), title="TRELLIS Text-to-3D") as demo:
355
  *(Note: Video preview is temporarily disabled for debugging)*
356
  """)
357
 
358
- # --- State Buffer ---
359
  output_buf = gr.State()
360
 
361
  with gr.Row():
362
- with gr.Column(scale=1): # Input column
363
  text_prompt = gr.Textbox(label="Text Prompt", lines=5, placeholder="e.g., a cute red dragon")
364
-
365
  with gr.Accordion(label="Generation Settings", open=False):
366
  seed = gr.Slider(0, MAX_SEED, label="Seed", value=0, step=1)
367
  randomize_seed = gr.Checkbox(label="Randomize Seed", value=True)
@@ -373,39 +372,28 @@ with gr.Blocks(delete_cache=(600, 600), title="TRELLIS Text-to-3D") as demo:
373
  with gr.Row():
374
  slat_guidance_strength = gr.Slider(0.0, 15.0, label="Guidance Strength", value=7.5, step=0.1)
375
  slat_sampling_steps = gr.Slider(10, 50, label="Sampling Steps", value=25, step=1)
376
-
377
  generate_btn = gr.Button("Generate 3D Preview", variant="primary")
378
-
379
  with gr.Accordion(label="GLB Extraction Settings", open=True):
380
  mesh_simplify = gr.Slider(0.9, 0.99, label="Simplify Factor", value=0.95, step=0.01, info="Higher value = less simplification (more polys)")
381
  texture_size = gr.Slider(512, 2048, label="Texture Size (pixels)", value=1024, step=512, info="Size of the generated texture map")
382
-
383
  with gr.Row():
384
  extract_glb_btn = gr.Button("Extract GLB", interactive=False)
385
  extract_gs_btn = gr.Button("Extract Gaussian (PLY)", interactive=False)
386
  gr.Markdown("""
387
  *NOTE: Gaussian file (.ply) can be very large (~50MB+) and may take time to process/download.*
388
  """)
389
-
390
- with gr.Column(scale=1): # Output column
391
- # Video component remains for layout but won't show anything in this debug version
392
  video_output = gr.Video(label="Generated 3D Preview (DISABLED FOR DEBUG)", autoplay=False, loop=False, value=None, height=350)
393
  model_output = gr.Model3D(label="Extracted Model Preview", height=350, clear_color=[0.95, 0.95, 0.95, 1.0])
394
-
395
  with gr.Row():
396
  download_glb = gr.DownloadButton(label="Download GLB", interactive=False)
397
  download_gs = gr.DownloadButton(label="Download Gaussian (PLY)", interactive=False)
398
 
399
  # --- Event Handlers ---
400
  print("Defining Gradio event handlers...")
 
 
401
 
402
- # Handle session start/end
403
- # demo.load() is valid with inputs=None, outputs=None (though default)
404
- demo.load(start_session, inputs=None, outputs=None)
405
- # >>> FIX: demo.unload() does NOT take inputs/outputs arguments <<<
406
- demo.unload(end_session) # Removed inputs/outputs kwargs
407
-
408
- # --- Generate Button Click Flow ---
409
  generate_event = generate_btn.click(
410
  get_seed,
411
  inputs=[randomize_seed, seed],
@@ -414,20 +402,17 @@ with gr.Blocks(delete_cache=(600, 600), title="TRELLIS Text-to-3D") as demo:
414
  ).then(
415
  text_to_3d,
416
  inputs=[text_prompt, seed, ss_guidance_strength, ss_sampling_steps, slat_guidance_strength, slat_sampling_steps],
417
- outputs=[output_buf, video_output], # state_dict -> output_buf, None -> video_output
418
  api_name="text_to_3d"
419
  ).then(
420
  lambda: (
421
- gr.Button(interactive=True),
422
- gr.Button(interactive=True),
423
- gr.DownloadButton(interactive=False),
424
- gr.DownloadButton(interactive=False)
425
  ),
426
  inputs=None,
427
  outputs=[extract_glb_btn, extract_gs_btn, download_glb, download_gs],
428
  )
429
 
430
- # --- Extract GLB Button Click Flow ---
431
  extract_glb_event = extract_glb_btn.click(
432
  extract_glb,
433
  inputs=[output_buf, mesh_simplify, texture_size],
@@ -439,7 +424,6 @@ with gr.Blocks(delete_cache=(600, 600), title="TRELLIS Text-to-3D") as demo:
439
  outputs=[download_glb],
440
  )
441
 
442
- # --- Extract Gaussian Button Click Flow ---
443
  extract_gs_event = extract_gs_btn.click(
444
  extract_gaussian,
445
  inputs=[output_buf],
@@ -451,7 +435,6 @@ with gr.Blocks(delete_cache=(600, 600), title="TRELLIS Text-to-3D") as demo:
451
  outputs=[download_gs],
452
  )
453
 
454
- # --- Clear Download Button Interactivity when model preview is cleared ---
455
  model_output.clear(
456
  lambda: (gr.DownloadButton(interactive=False), gr.DownloadButton(interactive=False)),
457
  inputs=None,
@@ -459,10 +442,8 @@ with gr.Blocks(delete_cache=(600, 600), title="TRELLIS Text-to-3D") as demo:
459
  )
460
  video_output.clear(
461
  lambda: (
462
- gr.Button(interactive=False),
463
- gr.Button(interactive=False),
464
- gr.DownloadButton(interactive=False),
465
- gr.DownloadButton(interactive=False)
466
  ),
467
  inputs=None,
468
  outputs=[extract_glb_btn, extract_gs_btn, download_glb, download_gs],
@@ -474,18 +455,19 @@ with gr.Blocks(delete_cache=(600, 600), title="TRELLIS Text-to-3D") as demo:
474
  # --- Launch the Gradio app ---
475
  if __name__ == "__main__":
476
  print("Loading Trellis pipeline...")
 
477
  pipeline_loaded = False
478
- pipeline = None # Initialize
479
  try:
 
480
  pipeline = TrellisTextTo3DPipeline.from_pretrained(
481
- "JeffreyXiang/TRELLIS-text-xlarge",
482
- torch_dtype=torch.float16 # Use float16 if GPU supports it
483
  )
484
  if torch.cuda.is_available():
485
  pipeline = pipeline.to("cuda")
486
  print("✅ Trellis pipeline loaded successfully to GPU.")
487
  else:
488
- print("⚠️ WARNING: CUDA not available, running on CPU (will be very slow).")
489
  print("✅ Trellis pipeline loaded successfully to CPU.")
490
  pipeline_loaded = True
491
  except Exception as e:
@@ -496,16 +478,7 @@ if __name__ == "__main__":
496
 
497
  if pipeline_loaded:
498
  print("Launching Gradio demo...")
499
- # Consider increasing queue timeout if tasks are long
500
- demo.queue(
501
- # default_concurrency_limit=2, # Limit concurrency if resource issues suspected
502
- # status_update_rate='auto'
503
- ).launch(
504
- # server_name="0.0.0.0", # Allows access from local network
505
- # share=False, # Set True for public link (careful with resources)
506
- debug=True, # Enable Gradio/FastAPI debug logs
507
- # prevent_thread_lock=True # Might help sometimes
508
- )
509
  print("Gradio demo launched.")
510
  else:
511
- print("Gradio demo not launched due to pipeline loading failure.")
 
1
+ # Version: 1.1.0 - API State Fix + DEBUG (Video Disabled - Corrected Baseline) (2025-05-04)
2
  # Changes:
3
+ # - Based *EXACTLY* on user-provided Version 1.1.0 code.
4
+ # - TEMPORARY DEBUGGING STEP: Commented out video rendering/saving in `text_to_3d`
 
5
  # and return None for video_path to isolate the "Session not found" error.
6
+ # - All other code (imports, functions, UI bindings, pipeline loading) is from Version 1.1.0.
7
+ # - Removed incorrect `torch_dtype` argument from pipeline loading.
8
+ # - Removed incorrect `inputs`/`outputs` arguments from `demo.unload()`.
 
9
 
10
  import gradio as gr
11
+ # NOTE: Ensuring 'spaces' is imported if decorators are used (was missing in user provided snippet but needed)
12
+ # If @spaces.GPU decorators are not used, this import is not needed.
13
+ # Assuming they ARE used based on previous context:
14
+ import spaces
15
 
16
  import os
17
  import shutil
 
30
  import traceback
31
  import sys
32
 
 
33
  MAX_SEED = np.iinfo(np.int32).max
34
+ # Using path relative to file as in original user provided code
35
+ TMP_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'tmp')
36
+ # Ensure base directory exists
 
37
  try:
38
  os.makedirs(TMP_DIR, exist_ok=True)
39
+ print(f"Using temporary directory: {TMP_DIR}")
40
  except OSError as e:
41
+ print(f"Warning: Could not create base temp directory {TMP_DIR}: {e}", file=sys.stderr)
42
+ TMP_DIR = '.' # Fallback
43
+ print(f"Warning: Falling back to use current directory for temp files: {os.path.abspath(TMP_DIR)}")
 
 
44
 
45
  def start_session(req: gr.Request):
46
  """Creates a temporary directory for the user session."""
47
+ user_dir = None
48
  try:
49
  session_hash = req.session_hash
50
  if not session_hash:
51
+ session_hash = f"no_session_{np.random.randint(10000, 99999)}"
52
+ print(f"Warning: No session_hash in request, using temporary ID: {session_hash}")
 
 
 
 
 
53
  user_dir = os.path.join(TMP_DIR, str(session_hash))
54
  os.makedirs(user_dir, exist_ok=True)
55
  print(f"Started session, ensured directory exists: {user_dir}")
56
  except Exception as e:
57
  print(f"Error in start_session creating directory '{user_dir}': {e}", file=sys.stderr)
 
 
58
 
59
  def end_session(req: gr.Request):
60
  """Removes the temporary directory for the user session."""
61
+ user_dir = None
62
  try:
63
  session_hash = req.session_hash
64
  if not session_hash:
65
+ print("Warning: No session_hash in end_session request, cannot clean up.")
66
+ return
 
67
  user_dir = os.path.join(TMP_DIR, str(session_hash))
68
+ if os.path.exists(user_dir) and os.path.isdir(user_dir):
69
  try:
70
  shutil.rmtree(user_dir)
71
  print(f"Ended session, removed directory: {user_dir}")
72
  except OSError as e:
73
  print(f"Error removing tmp directory {user_dir}: {e.strerror}", file=sys.stderr)
74
  else:
75
+ print(f"Ended session, directory not found or not a directory: {user_dir}")
76
  except Exception as e:
77
  print(f"Error in end_session cleaning directory '{user_dir}': {e}", file=sys.stderr)
78
 
 
98
  print(f"[pack_state] Dictionary created. Keys: {list(packed_data.keys())}, Gaussian points: {len(packed_data['gaussian']['_xyz'])}, Mesh vertices: {len(packed_data['mesh']['vertices'])}")
99
  return packed_data
100
  except Exception as e:
101
+ print(f"Error during pack_state: {e}", file=sys.stderr)
102
+ traceback.print_exc()
103
+ raise
104
 
105
 
106
  def unpack_state(state_dict: dict) -> Tuple[Gaussian, edict]:
 
151
  return int(new_seed)
152
 
153
 
154
+ # Decorator requires 'import spaces' at the top
155
  @spaces.GPU
156
  def text_to_3d(
157
  prompt: str,
 
161
  slat_guidance_strength: float,
162
  slat_sampling_steps: int,
163
  req: gr.Request,
164
+ ) -> Tuple[dict, Optional[str]]: # Return Optional[str] for video path
165
  """
166
  Generates a 3D model (Gaussian and Mesh) from text and returns a
167
  serializable state dictionary and potentially a video preview path.
168
  >>> TEMPORARILY DISABLED VIDEO RENDERING FOR DEBUGGING <<<
169
  """
170
  print(f"[text_to_3d - DEBUG MODE] Received prompt: '{prompt}', Seed: {seed}")
171
+ user_dir = None
172
+ state_dict = None
173
  try:
174
  session_hash = req.session_hash
175
  if not session_hash:
176
+ session_hash = f"no_session_{np.random.randint(10000, 99999)}"
177
+ print(f"Warning: No session_hash in text_to_3d request, using temporary ID: {session_hash}")
 
 
178
  user_dir = os.path.join(TMP_DIR, str(session_hash))
179
  os.makedirs(user_dir, exist_ok=True)
180
  print(f"[text_to_3d - DEBUG MODE] User directory: {user_dir}")
 
202
  except Exception as e:
203
  print(f"❌ [text_to_3d - DEBUG MODE] Error during generation or packing: {e}", file=sys.stderr)
204
  traceback.print_exc()
 
205
  raise gr.Error(f"Core generation failed: {e}")
206
 
207
  # --- Render Video Preview (TEMPORARILY DISABLED FOR DEBUGGING) ---
208
+ video_path = None # Explicitly set path to None for this debug version
209
  print("[text_to_3d - DEBUG MODE] Skipping video rendering.")
210
+ # --- Start Original Video Code Block (Commented Out) ---
211
+ # try:
212
+ # print("[text_to_3d] Rendering video preview...")
213
+ # video = render_utils.render_video(outputs['gaussian'][0], num_frames=120)['color']
214
+ # video_geo = render_utils.render_video(outputs['mesh'][0], num_frames=120)['normal']
215
+ # video = [np.concatenate([v.astype(np.uint8), vg.astype(np.uint8)], axis=1) for v, vg in zip(video, video_geo)]
216
+ # video_path_tmp = os.path.join(user_dir, 'sample.mp4')
217
+ # imageio.mimsave(video_path_tmp, video, fps=15, quality=8)
218
+ # print(f"[text_to_3d] Video saved to: {video_path_tmp}")
219
+ # video_path = video_path_tmp
220
+ # except Exception as e:
221
+ # print(f"❌ [text_to_3d] Video rendering/saving error: {e}", file=sys.stderr)
222
+ # traceback.print_exc()
223
+ # video_path = None # Indicate video failure
224
+ # --- End Original Video Code Block ---
225
 
226
  # --- Cleanup and Return ---
227
  if torch.cuda.is_available():
228
  torch.cuda.empty_cache()
229
  print("[text_to_3d - DEBUG MODE] Cleared CUDA cache.")
230
 
 
231
  print("[text_to_3d - DEBUG MODE] Returning state dictionary and None video path.")
232
  if state_dict is None:
 
233
  print("Error: state_dict is None before return, generation likely failed.", file=sys.stderr)
234
  raise gr.Error("State dictionary creation failed.")
235
  return state_dict, video_path
236
 
237
 
238
+ # Decorator requires 'import spaces' at the top
239
  @spaces.GPU(duration=120)
240
  def extract_glb(
241
  state_dict: dict,
 
247
  Extracts a GLB file from the provided 3D model state dictionary.
248
  """
249
  print(f"[extract_glb] Received request. Simplify: {mesh_simplify}, Texture Size: {texture_size}")
250
+ user_dir = None
251
+ glb_path = None
252
  try:
253
  session_hash = req.session_hash
254
  if not session_hash:
255
+ session_hash = f"no_session_{np.random.randint(10000, 99999)}"
256
+ print(f"Warning: No session_hash in extract_glb request, using temporary ID: {session_hash}")
257
 
258
  if not isinstance(state_dict, dict):
259
  print("❌ [extract_glb] Error: Invalid state_dict received (not a dictionary).")
 
279
  except Exception as e:
280
  print(f"❌ [extract_glb] Error during GLB extraction: {e}", file=sys.stderr)
281
  traceback.print_exc()
282
+ raise gr.Error(f"Failed to extract GLB: {e}")
283
 
284
  # --- Cleanup and Return ---
285
  if torch.cuda.is_available():
 
293
  return glb_path, glb_path
294
 
295
 
296
+ # Decorator requires 'import spaces' at the top
297
  @spaces.GPU
298
  def extract_gaussian(
299
  state_dict: dict,
 
303
  Extracts a PLY (Gaussian) file from the provided 3D model state dictionary.
304
  """
305
  print("[extract_gaussian] Received request.")
306
+ user_dir = None
307
+ gaussian_path = None
308
  try:
309
  session_hash = req.session_hash
310
  if not session_hash:
311
+ session_hash = f"no_session_{np.random.randint(10000, 99999)}"
312
+ print(f"Warning: No session_hash in extract_gaussian request, using temporary ID: {session_hash}")
313
 
314
  if not isinstance(state_dict, dict):
315
  print("❌ [extract_gaussian] Error: Invalid state_dict received (not a dictionary).")
 
331
  except Exception as e:
332
  print(f"❌ [extract_gaussian] Error during Gaussian extraction: {e}", file=sys.stderr)
333
  traceback.print_exc()
334
+ raise gr.Error(f"Failed to extract Gaussian PLY: {e}")
335
 
336
  # --- Cleanup and Return ---
337
  if torch.cuda.is_available():
 
356
  *(Note: Video preview is temporarily disabled for debugging)*
357
  """)
358
 
 
359
  output_buf = gr.State()
360
 
361
  with gr.Row():
362
+ with gr.Column(scale=1):
363
  text_prompt = gr.Textbox(label="Text Prompt", lines=5, placeholder="e.g., a cute red dragon")
 
364
  with gr.Accordion(label="Generation Settings", open=False):
365
  seed = gr.Slider(0, MAX_SEED, label="Seed", value=0, step=1)
366
  randomize_seed = gr.Checkbox(label="Randomize Seed", value=True)
 
372
  with gr.Row():
373
  slat_guidance_strength = gr.Slider(0.0, 15.0, label="Guidance Strength", value=7.5, step=0.1)
374
  slat_sampling_steps = gr.Slider(10, 50, label="Sampling Steps", value=25, step=1)
 
375
  generate_btn = gr.Button("Generate 3D Preview", variant="primary")
 
376
  with gr.Accordion(label="GLB Extraction Settings", open=True):
377
  mesh_simplify = gr.Slider(0.9, 0.99, label="Simplify Factor", value=0.95, step=0.01, info="Higher value = less simplification (more polys)")
378
  texture_size = gr.Slider(512, 2048, label="Texture Size (pixels)", value=1024, step=512, info="Size of the generated texture map")
 
379
  with gr.Row():
380
  extract_glb_btn = gr.Button("Extract GLB", interactive=False)
381
  extract_gs_btn = gr.Button("Extract Gaussian (PLY)", interactive=False)
382
  gr.Markdown("""
383
  *NOTE: Gaussian file (.ply) can be very large (~50MB+) and may take time to process/download.*
384
  """)
385
+ with gr.Column(scale=1):
 
 
386
  video_output = gr.Video(label="Generated 3D Preview (DISABLED FOR DEBUG)", autoplay=False, loop=False, value=None, height=350)
387
  model_output = gr.Model3D(label="Extracted Model Preview", height=350, clear_color=[0.95, 0.95, 0.95, 1.0])
 
388
  with gr.Row():
389
  download_glb = gr.DownloadButton(label="Download GLB", interactive=False)
390
  download_gs = gr.DownloadButton(label="Download Gaussian (PLY)", interactive=False)
391
 
392
  # --- Event Handlers ---
393
  print("Defining Gradio event handlers...")
394
+ demo.load(start_session) # Removed inputs/outputs kwargs, they are optional
395
+ demo.unload(end_session) # Removed incorrect inputs/outputs kwargs
396
 
 
 
 
 
 
 
 
397
  generate_event = generate_btn.click(
398
  get_seed,
399
  inputs=[randomize_seed, seed],
 
402
  ).then(
403
  text_to_3d,
404
  inputs=[text_prompt, seed, ss_guidance_strength, ss_sampling_steps, slat_guidance_strength, slat_sampling_steps],
405
+ outputs=[output_buf, video_output],
406
  api_name="text_to_3d"
407
  ).then(
408
  lambda: (
409
+ gr.Button(interactive=True), gr.Button(interactive=True),
410
+ gr.DownloadButton(interactive=False), gr.DownloadButton(interactive=False)
 
 
411
  ),
412
  inputs=None,
413
  outputs=[extract_glb_btn, extract_gs_btn, download_glb, download_gs],
414
  )
415
 
 
416
  extract_glb_event = extract_glb_btn.click(
417
  extract_glb,
418
  inputs=[output_buf, mesh_simplify, texture_size],
 
424
  outputs=[download_glb],
425
  )
426
 
 
427
  extract_gs_event = extract_gs_btn.click(
428
  extract_gaussian,
429
  inputs=[output_buf],
 
435
  outputs=[download_gs],
436
  )
437
 
 
438
  model_output.clear(
439
  lambda: (gr.DownloadButton(interactive=False), gr.DownloadButton(interactive=False)),
440
  inputs=None,
 
442
  )
443
  video_output.clear(
444
  lambda: (
445
+ gr.Button(interactive=False), gr.Button(interactive=False),
446
+ gr.DownloadButton(interactive=False), gr.DownloadButton(interactive=False)
 
 
447
  ),
448
  inputs=None,
449
  outputs=[extract_glb_btn, extract_gs_btn, download_glb, download_gs],
 
455
  # --- Launch the Gradio app ---
456
  if __name__ == "__main__":
457
  print("Loading Trellis pipeline...")
458
+ pipeline = None
459
  pipeline_loaded = False
 
460
  try:
461
+ # --- Load pipeline WITHOUT torch_dtype ---
462
  pipeline = TrellisTextTo3DPipeline.from_pretrained(
463
+ "JeffreyXiang/TRELLIS-text-xlarge"
464
+ # Removed: torch_dtype=torch.float16
465
  )
466
  if torch.cuda.is_available():
467
  pipeline = pipeline.to("cuda")
468
  print("✅ Trellis pipeline loaded successfully to GPU.")
469
  else:
470
+ print("⚠️ WARNING: CUDA not available, running on CPU.")
471
  print("✅ Trellis pipeline loaded successfully to CPU.")
472
  pipeline_loaded = True
473
  except Exception as e:
 
478
 
479
  if pipeline_loaded:
480
  print("Launching Gradio demo...")
481
+ demo.queue().launch(debug=True)
 
 
 
 
 
 
 
 
 
482
  print("Gradio demo launched.")
483
  else:
484
+ print("Gradio demo not launched.")