Spaces:
Running
on
Zero
Running
on
Zero
Update demo
Browse files
app.py
CHANGED
|
@@ -376,24 +376,65 @@ GSPLAT_HEAD = """
|
|
| 376 |
function ensureViewer() {
|
| 377 |
if (renderer) return;
|
| 378 |
const container = document.getElementById("splat-container");
|
| 379 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 380 |
container.appendChild(renderer.canvas);
|
| 381 |
-
|
| 382 |
-
|
|
|
|
|
|
|
|
|
|
| 383 |
controls = new SPLAT.OrbitControls(camera, renderer.canvas);
|
| 384 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 385 |
requestAnimationFrame(loop);
|
|
|
|
| 386 |
}
|
| 387 |
|
| 388 |
async function loadSplat(url) {
|
|
|
|
| 389 |
ensureViewer();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 390 |
// clear previous
|
| 391 |
scene.children.length = 0;
|
| 392 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 393 |
}
|
| 394 |
|
| 395 |
// Expose callable function for Gradio
|
| 396 |
window.__load_splat__ = loadSplat;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 397 |
</script>
|
| 398 |
"""
|
| 399 |
|
|
@@ -416,10 +457,11 @@ def main():
|
|
| 416 |
return new_session_id()
|
| 417 |
|
| 418 |
# After generation: copy ply into per-session folder and return viewer URL
|
| 419 |
-
def _prep_viewer_url(ply_path: str, session_id: str)
|
| 420 |
if not ply_path or not os.path.exists(ply_path):
|
| 421 |
-
return ""
|
| 422 |
-
|
|
|
|
| 423 |
|
| 424 |
# Wrapper to return only the outputs we want to display
|
| 425 |
def _generate_and_filter_outputs(image_path, auto_crop, guidance_scale, random_seed, num_steps):
|
|
@@ -432,7 +474,7 @@ def main():
|
|
| 432 |
gr.Markdown("""
|
| 433 |
### 💡 Tips for Best Results
|
| 434 |
- **Works best with near-frontal portrait images**
|
| 435 |
-
- **
|
| 436 |
""")
|
| 437 |
|
| 438 |
with gr.Row():
|
|
@@ -455,7 +497,8 @@ def main():
|
|
| 455 |
with gr.Column(scale=1):
|
| 456 |
gr.Markdown("### Interactive Gaussian Splat Viewer")
|
| 457 |
viewer = gr.HTML("<div id='splat-container' style='width:100%;height:600px;background:#000;border:1px solid #ccc;border-radius:8px;'></div>")
|
| 458 |
-
|
|
|
|
| 459 |
reload_btn = gr.Button("Reload Viewer", size="sm")
|
| 460 |
|
| 461 |
out_recon = gr.Image(label="3D Reconstruction")
|
|
@@ -473,10 +516,10 @@ def main():
|
|
| 473 |
).then(
|
| 474 |
fn=_prep_viewer_url,
|
| 475 |
inputs=[out_ply, session],
|
| 476 |
-
outputs=url_box,
|
| 477 |
).then(
|
| 478 |
fn=None, inputs=url_box, outputs=None,
|
| 479 |
-
js="(url)=>window.__load_splat__(url)"
|
| 480 |
)
|
| 481 |
|
| 482 |
# Manual reload if needed
|
|
|
|
| 376 |
function ensureViewer() {
|
| 377 |
if (renderer) return;
|
| 378 |
const container = document.getElementById("splat-container");
|
| 379 |
+
if (!container) {
|
| 380 |
+
console.error("Container not found!");
|
| 381 |
+
return;
|
| 382 |
+
}
|
| 383 |
+
|
| 384 |
+
renderer = new SPLAT.WebGLRenderer();
|
| 385 |
+
renderer.canvas.style.width = '100%';
|
| 386 |
+
renderer.canvas.style.height = '100%';
|
| 387 |
container.appendChild(renderer.canvas);
|
| 388 |
+
|
| 389 |
+
scene = new SPLAT.Scene();
|
| 390 |
+
camera = new SPLAT.Camera();
|
| 391 |
+
camera.data.setPosition(0, 0, 2);
|
| 392 |
+
|
| 393 |
controls = new SPLAT.OrbitControls(camera, renderer.canvas);
|
| 394 |
+
|
| 395 |
+
const loop = () => {
|
| 396 |
+
controls.update();
|
| 397 |
+
renderer.render(scene, camera);
|
| 398 |
+
requestAnimationFrame(loop);
|
| 399 |
+
};
|
| 400 |
requestAnimationFrame(loop);
|
| 401 |
+
console.log("Viewer initialized");
|
| 402 |
}
|
| 403 |
|
| 404 |
async function loadSplat(url) {
|
| 405 |
+
console.log("Loading splat from:", url);
|
| 406 |
ensureViewer();
|
| 407 |
+
|
| 408 |
+
if (!scene) {
|
| 409 |
+
console.error("Scene not initialized!");
|
| 410 |
+
return;
|
| 411 |
+
}
|
| 412 |
+
|
| 413 |
// clear previous
|
| 414 |
scene.children.length = 0;
|
| 415 |
+
|
| 416 |
+
try {
|
| 417 |
+
await SPLAT.Loader.LoadAsync(url, scene, (progress) => {
|
| 418 |
+
console.log("Loading progress:", progress);
|
| 419 |
+
});
|
| 420 |
+
console.log("Splat loaded successfully!");
|
| 421 |
+
|
| 422 |
+
// Reset camera position after loading
|
| 423 |
+
camera.data.setPosition(0, 0, 2);
|
| 424 |
+
} catch (error) {
|
| 425 |
+
console.error("Error loading splat:", error);
|
| 426 |
+
}
|
| 427 |
}
|
| 428 |
|
| 429 |
// Expose callable function for Gradio
|
| 430 |
window.__load_splat__ = loadSplat;
|
| 431 |
+
|
| 432 |
+
// Initialize viewer when DOM is ready
|
| 433 |
+
if (document.readyState === 'loading') {
|
| 434 |
+
document.addEventListener('DOMContentLoaded', ensureViewer);
|
| 435 |
+
} else {
|
| 436 |
+
setTimeout(ensureViewer, 100);
|
| 437 |
+
}
|
| 438 |
</script>
|
| 439 |
"""
|
| 440 |
|
|
|
|
| 457 |
return new_session_id()
|
| 458 |
|
| 459 |
# After generation: copy ply into per-session folder and return viewer URL
|
| 460 |
+
def _prep_viewer_url(ply_path: str, session_id: str):
|
| 461 |
if not ply_path or not os.path.exists(ply_path):
|
| 462 |
+
return "Model file not found", ""
|
| 463 |
+
url = copy_to_session_and_get_url(ply_path, session_id)
|
| 464 |
+
return "Loading model into viewer...", url
|
| 465 |
|
| 466 |
# Wrapper to return only the outputs we want to display
|
| 467 |
def _generate_and_filter_outputs(image_path, auto_crop, guidance_scale, random_seed, num_steps):
|
|
|
|
| 474 |
gr.Markdown("""
|
| 475 |
### 💡 Tips for Best Results
|
| 476 |
- **Works best with near-frontal portrait images**
|
| 477 |
+
- **The provided checkpoints were not trained with accessories (glasses, hats, etc.). Portraits containing accessories may produce suboptimal results.**
|
| 478 |
""")
|
| 479 |
|
| 480 |
with gr.Row():
|
|
|
|
| 497 |
with gr.Column(scale=1):
|
| 498 |
gr.Markdown("### Interactive Gaussian Splat Viewer")
|
| 499 |
viewer = gr.HTML("<div id='splat-container' style='width:100%;height:600px;background:#000;border:1px solid #ccc;border-radius:8px;'></div>")
|
| 500 |
+
viewer_status = gr.Textbox(label="Viewer Status", value="Waiting for model...", interactive=False)
|
| 501 |
+
url_box = gr.Textbox(label="Model URL (for debugging)", interactive=False)
|
| 502 |
reload_btn = gr.Button("Reload Viewer", size="sm")
|
| 503 |
|
| 504 |
out_recon = gr.Image(label="3D Reconstruction")
|
|
|
|
| 516 |
).then(
|
| 517 |
fn=_prep_viewer_url,
|
| 518 |
inputs=[out_ply, session],
|
| 519 |
+
outputs=[viewer_status, url_box],
|
| 520 |
).then(
|
| 521 |
fn=None, inputs=url_box, outputs=None,
|
| 522 |
+
js="(url)=>{console.log('Calling __load_splat__ with:', url); return window.__load_splat__(url);}"
|
| 523 |
)
|
| 524 |
|
| 525 |
# Manual reload if needed
|