weijielyu commited on
Commit
0704fd9
·
1 Parent(s): bee7b3f
Files changed (2) hide show
  1. VIEWER_DEBUG_GUIDE.md +209 -0
  2. app.py +36 -12
VIEWER_DEBUG_GUIDE.md ADDED
@@ -0,0 +1,209 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Viewer Debugging Guide
2
+
3
+ ## How to Check Where the PLY File Is
4
+
5
+ ### 1. Check the Debug Info Panel
6
+
7
+ After generating a 3D model, look at the **"🔍 Debug Info"** textbox which will show:
8
+
9
+ ```
10
+ PLY Path: /path/to/outputs/splats/xxxxx/gaussians.ply
11
+ PLY URL: /file=/path/to/outputs/splats/xxxxx/gaussians.ply
12
+ File exists: True
13
+ ```
14
+
15
+ This tells you:
16
+ - **PLY Path**: The actual file system path where the PLY was saved
17
+ - **PLY URL**: The URL the viewer is trying to fetch
18
+ - **File exists**: Whether the file actually exists on disk
19
+
20
+ ### 2. Check Browser Console
21
+
22
+ Open your browser's developer console (F12 or Cmd+Option+I) and look for:
23
+
24
+ ```
25
+ === PLY Loading Debug ===
26
+ PLY URL: /file=/path/to/outputs/splats/xxxxx/gaussians.ply
27
+ Current location: http://localhost:7860/
28
+ Worker exists: true/false
29
+ Fetch response status: 200 OK (or error)
30
+ Response headers: [...]
31
+ ✓ PLY loaded successfully!
32
+ Buffer size: 245678 bytes
33
+ ```
34
+
35
+ ### 3. Check Loading Indicator
36
+
37
+ The loading message in the viewer will update to show:
38
+ - `"Loading 3D model..."` → Initial state
39
+ - `"Fetching PLY from: /file=..."` → Fetch started
40
+ - `"Processing 245.6 KB..."` → File loaded, processing
41
+ - `"Error: [message]"` (in red) → Something went wrong
42
+
43
+ ## Common Issues and Fixes
44
+
45
+ ### Issue 1: File Not Found (404 Error)
46
+
47
+ **Symptoms:**
48
+ - Debug Info shows: `File exists: True`
49
+ - Console shows: `HTTP 404: Not Found`
50
+
51
+ **Problem:** Gradio's file serving path is incorrect
52
+
53
+ **Fix:** Update the PLY URL format in `_generate_and_filter_outputs()`:
54
+ ```python
55
+ # Try different URL formats:
56
+ ply_url = f"/file={ply_path}" # Current
57
+ # OR
58
+ ply_url = ply_path # Direct path
59
+ # OR
60
+ ply_url = f"/file/{Path(ply_path).name}" # Just filename
61
+ ```
62
+
63
+ ### Issue 2: Worker Not Initialized
64
+
65
+ **Symptoms:**
66
+ - Console shows: `Worker exists: false`
67
+ - Loading shows: `"Error: Viewer worker not ready"`
68
+
69
+ **Problem:** viewer.js didn't initialize properly
70
+
71
+ **Possible causes:**
72
+ 1. **viewer.js file is empty or corrupt**
73
+ - Check: `ls -lh viewer.js` should show ~51KB
74
+ - Fix: Re-download from GitHub
75
+
76
+ 2. **viewer.js has syntax errors**
77
+ - Check browser console for JavaScript errors
78
+ - Fix: Verify file integrity
79
+
80
+ 3. **Gradio HTML component limitations**
81
+ - The embedded script might be too large
82
+ - Fix: Serve viewer.js as a static file instead of embedding
83
+
84
+ ### Issue 3: Stuck on "Loading 3D model..."
85
+
86
+ **Symptoms:**
87
+ - No console logs appear
88
+ - Loading message never changes
89
+
90
+ **Problem:** JavaScript not executing
91
+
92
+ **Check:**
93
+ 1. Is the viewer HTML actually being rendered?
94
+ - Inspect the `out_viewer` component in browser DevTools
95
+ - Should see `<canvas id="canvas">`, scripts, etc.
96
+
97
+ 2. Are there Content Security Policy (CSP) errors?
98
+ - Check console for CSP violations
99
+ - Gradio might be blocking inline scripts
100
+
101
+ ### Issue 4: CORS Error
102
+
103
+ **Symptoms:**
104
+ - Console shows: `CORS policy: No 'Access-Control-Allow-Origin'`
105
+
106
+ **Problem:** Cross-origin resource sharing blocked
107
+
108
+ **Fix:** Ensure PLY file is served from the same origin as the app
109
+
110
+ ## Quick Diagnosis Checklist
111
+
112
+ Run through these checks in order:
113
+
114
+ - [ ] **Debug Info shows `File exists: True`**
115
+ - ✓ File was created successfully
116
+ - ✗ Check `generate_3d_head()` function
117
+
118
+ - [ ] **Console shows `Worker exists: true`**
119
+ - ✓ viewer.js loaded and initialized
120
+ - ✗ Check viewer.js file and embedding
121
+
122
+ - [ ] **Console shows fetch starting**
123
+ - ✓ Script is executing
124
+ - ✗ Check for JavaScript errors earlier in console
125
+
126
+ - [ ] **Console shows `200 OK` response**
127
+ - ✓ File is accessible
128
+ - ✗ Check PLY URL format and Gradio file serving
129
+
130
+ - [ ] **Console shows buffer size**
131
+ - ✓ File downloaded successfully
132
+ - ✗ Check fetch error message
133
+
134
+ - [ ] **Loading indicator disappears**
135
+ - ✓ Everything works!
136
+ - ✗ Check worker message passing
137
+
138
+ ## Alternative Approach: Static File Serving
139
+
140
+ If embedding doesn't work, serve files statically:
141
+
142
+ ```python
143
+ # In app.py, after imports:
144
+ import gradio as gr
145
+
146
+ # Setup static file serving
147
+ gr.set_static_paths(paths=["./outputs"])
148
+
149
+ # Then in create_splat_viewer_html():
150
+ def create_splat_viewer_html(ply_url: str) -> str:
151
+ # Use external script tag instead of embedding
152
+ return f"""
153
+ <div id="splat-viewer-container" style="...">
154
+ <canvas id="canvas"></canvas>
155
+ ...
156
+ </div>
157
+ <script src="/file/viewer.js"></script>
158
+ <script>
159
+ // Load PLY
160
+ fetch('{ply_url}')...
161
+ </script>
162
+ """
163
+ ```
164
+
165
+ ## Testing Locally
166
+
167
+ To test the viewer independently:
168
+
169
+ ```bash
170
+ # 1. Generate a PLY file
171
+ python app.py
172
+ # Upload image, click generate
173
+
174
+ # 2. Find the PLY path from Debug Info
175
+ # Example: outputs/splats/xxxxx/gaussians.ply
176
+
177
+ # 3. Test direct file access
178
+ curl http://localhost:7860/file=outputs/splats/xxxxx/gaussians.ply
179
+ # Should download the PLY file
180
+
181
+ # 4. Test viewer.js loading
182
+ curl http://localhost:7860/file/viewer.js
183
+ # Should return JavaScript code
184
+ ```
185
+
186
+ ## Getting Help
187
+
188
+ When reporting issues, provide:
189
+ 1. **Debug Info** textbox contents
190
+ 2. **Browser console** logs (full "=== PLY Loading Debug ===" section)
191
+ 3. **Browser** and version
192
+ 4. **File size** from `ls -lh outputs/splats/xxxxx/gaussians.ply`
193
+ 5. Any **error messages** shown in red
194
+
195
+ ## Next Steps
196
+
197
+ After identifying the issue:
198
+ 1. Fix the PLY URL format if it's a 404
199
+ 2. Re-download viewer.js if it's corrupt
200
+ 3. Switch to static file serving if embedding fails
201
+ 4. Check Gradio documentation for HTML component limitations
202
+
203
+ ---
204
+
205
+ **Current Status**: Debugging mode enabled ✓
206
+ **Debug Info**: Visible in UI
207
+ **Console Logging**: Verbose
208
+ **Error Display**: In viewer and console
209
+
app.py CHANGED
@@ -351,31 +351,51 @@ def create_splat_viewer_html(ply_url: str) -> str:
351
  // Auto-load the PLY file when viewer is ready
352
  setTimeout(function() {{
353
  const plyUrl = '{ply_url}';
354
- console.log('Loading PLY from:', plyUrl);
355
  const loadingDiv = document.getElementById('loading');
356
 
 
 
 
 
 
 
 
357
  fetch(plyUrl)
358
  .then(response => {{
359
- if (!response.ok) throw new Error('Failed to load PLY file');
 
 
 
 
 
 
360
  return response.arrayBuffer();
361
  }})
362
  .then(buffer => {{
363
- console.log('PLY loaded, size:', buffer.byteLength, 'bytes');
364
- if (loadingDiv) loadingDiv.textContent = 'Processing...';
 
365
 
366
  // Trigger the viewer to process the PLY
367
- const event = new MessageEvent('message', {{ data: {{ ply: buffer }} }});
368
  if (window.worker) {{
 
 
369
  window.worker.dispatchEvent(event);
370
- if (loadingDiv) loadingDiv.style.display = 'none';
 
 
371
  }} else {{
372
- console.error('Worker not initialized');
373
- if (loadingDiv) loadingDiv.textContent = 'Error: Viewer not ready';
 
 
374
  }}
375
  }})
376
  .catch(error => {{
377
- console.error('Error loading PLY:', error);
378
- if (loadingDiv) loadingDiv.textContent = 'Error loading model';
 
 
379
  }});
380
  }}, 1000);
381
  </script>
@@ -402,7 +422,10 @@ def main():
402
  ply_url = f"/file={ply_path}"
403
  viewer_html = create_splat_viewer_html(ply_url)
404
 
405
- return viewer_html, output_path, turntable_path, ply_path
 
 
 
406
 
407
  gr.Markdown("## FaceLift: Single Image 3D Face Reconstruction.")
408
 
@@ -431,6 +454,7 @@ def main():
431
 
432
  with gr.Column(scale=1):
433
  out_viewer = gr.HTML(label="🎮 Interactive 3D Viewer")
 
434
  out_recon = gr.Image(label="3D Reconstruction Views")
435
  out_video = gr.PlayableVideo(label="Turntable Animation (360° View)", height=400)
436
  out_ply = gr.File(label="Download 3D Model (.ply)")
@@ -444,7 +468,7 @@ def main():
444
  run_btn.click(
445
  fn=_generate_and_filter_outputs,
446
  inputs=[in_image, auto_crop, guidance, seed, steps],
447
- outputs=[out_viewer, out_recon, out_video, out_ply],
448
  )
449
 
450
  demo.queue(max_size=10)
 
351
  // Auto-load the PLY file when viewer is ready
352
  setTimeout(function() {{
353
  const plyUrl = '{ply_url}';
 
354
  const loadingDiv = document.getElementById('loading');
355
 
356
+ console.log('=== PLY Loading Debug ===');
357
+ console.log('PLY URL:', plyUrl);
358
+ console.log('Current location:', window.location.href);
359
+ console.log('Worker exists:', !!window.worker);
360
+
361
+ loadingDiv.textContent = 'Fetching PLY from: ' + plyUrl;
362
+
363
  fetch(plyUrl)
364
  .then(response => {{
365
+ console.log('Fetch response status:', response.status, response.statusText);
366
+ console.log('Response headers:', Array.from(response.headers.entries()));
367
+ console.log('Response OK:', response.ok);
368
+
369
+ if (!response.ok) {{
370
+ throw new Error(`HTTP ${{response.status}}: ${{response.statusText}}`);
371
+ }}
372
  return response.arrayBuffer();
373
  }})
374
  .then(buffer => {{
375
+ console.log('PLY loaded successfully!');
376
+ console.log('Buffer size:', buffer.byteLength, 'bytes');
377
+ loadingDiv.textContent = 'Processing ' + (buffer.byteLength / 1024).toFixed(1) + ' KB...';
378
 
379
  // Trigger the viewer to process the PLY
 
380
  if (window.worker) {{
381
+ console.log('Dispatching to worker...');
382
+ const event = new MessageEvent('message', {{ data: {{ ply: buffer }} }});
383
  window.worker.dispatchEvent(event);
384
+ setTimeout(() => {{
385
+ if (loadingDiv) loadingDiv.style.display = 'none';
386
+ }}, 2000);
387
  }} else {{
388
+ console.error('Worker not initialized!');
389
+ console.log('Window keys:', Object.keys(window).filter(k => k.includes('work')));
390
+ loadingDiv.textContent = 'Error: Viewer worker not ready';
391
+ loadingDiv.style.color = '#ff4444';
392
  }}
393
  }})
394
  .catch(error => {{
395
+ console.error('Error loading PLY:', error);
396
+ console.error('Error stack:', error.stack);
397
+ loadingDiv.textContent = 'Error: ' + error.message;
398
+ loadingDiv.style.color = '#ff4444';
399
  }});
400
  }}, 1000);
401
  </script>
 
422
  ply_url = f"/file={ply_path}"
423
  viewer_html = create_splat_viewer_html(ply_url)
424
 
425
+ # Debug info showing the paths
426
+ debug_info = f"PLY Path: {ply_path}\nPLY URL: {ply_url}\nFile exists: {Path(ply_path).exists()}"
427
+
428
+ return viewer_html, output_path, turntable_path, ply_path, debug_info
429
 
430
  gr.Markdown("## FaceLift: Single Image 3D Face Reconstruction.")
431
 
 
454
 
455
  with gr.Column(scale=1):
456
  out_viewer = gr.HTML(label="🎮 Interactive 3D Viewer")
457
+ out_debug = gr.Textbox(label="🔍 Debug Info", lines=3, visible=True)
458
  out_recon = gr.Image(label="3D Reconstruction Views")
459
  out_video = gr.PlayableVideo(label="Turntable Animation (360° View)", height=400)
460
  out_ply = gr.File(label="Download 3D Model (.ply)")
 
468
  run_btn.click(
469
  fn=_generate_and_filter_outputs,
470
  inputs=[in_image, auto_crop, guidance, seed, steps],
471
+ outputs=[out_viewer, out_recon, out_video, out_ply, out_debug],
472
  )
473
 
474
  demo.queue(max_size=10)