Spaces:
Running on Zero
Running on Zero
Update example preview meshes
Browse files- .gitattributes +14 -0
- app.py +176 -35
- examples/000.glb +2 -2
- examples/001.glb +3 -0
- examples/002.glb +3 -0
- examples/003.glb +3 -0
- examples/004.glb +3 -0
- examples/005.glb +3 -0
- examples/006.glb +3 -0
- examples/render/000.png +3 -0
- examples/render/001.png +3 -0
- examples/render/002.png +3 -0
- examples/render/003.png +3 -0
- examples/render/004.png +3 -0
- examples/render/005.png +3 -0
- examples/render/006.png +3 -0
- instruct_particulate_1m_warning_e22a80a.png +3 -0
.gitattributes
CHANGED
|
@@ -35,3 +35,17 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
| 36 |
examples/000.glb filter=lfs diff=lfs merge=lfs -text
|
| 37 |
examples/oven_blank.glb filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
| 36 |
examples/000.glb filter=lfs diff=lfs merge=lfs -text
|
| 37 |
examples/oven_blank.glb filter=lfs diff=lfs merge=lfs -text
|
| 38 |
+
examples/001.glb filter=lfs diff=lfs merge=lfs -text
|
| 39 |
+
examples/002.glb filter=lfs diff=lfs merge=lfs -text
|
| 40 |
+
examples/003.glb filter=lfs diff=lfs merge=lfs -text
|
| 41 |
+
examples/004.glb filter=lfs diff=lfs merge=lfs -text
|
| 42 |
+
examples/005.glb filter=lfs diff=lfs merge=lfs -text
|
| 43 |
+
examples/006.glb filter=lfs diff=lfs merge=lfs -text
|
| 44 |
+
examples/render/000.png filter=lfs diff=lfs merge=lfs -text
|
| 45 |
+
examples/render/001.png filter=lfs diff=lfs merge=lfs -text
|
| 46 |
+
examples/render/002.png filter=lfs diff=lfs merge=lfs -text
|
| 47 |
+
examples/render/003.png filter=lfs diff=lfs merge=lfs -text
|
| 48 |
+
examples/render/004.png filter=lfs diff=lfs merge=lfs -text
|
| 49 |
+
examples/render/005.png filter=lfs diff=lfs merge=lfs -text
|
| 50 |
+
examples/render/006.png filter=lfs diff=lfs merge=lfs -text
|
| 51 |
+
instruct_particulate_1m_warning_e22a80a.png filter=lfs diff=lfs merge=lfs -text
|
app.py
CHANGED
|
@@ -2,6 +2,7 @@ from __future__ import annotations
|
|
| 2 |
|
| 3 |
import asyncio
|
| 4 |
import hashlib
|
|
|
|
| 5 |
import json
|
| 6 |
import os
|
| 7 |
import shutil
|
|
@@ -379,16 +380,49 @@ DEMO_CSS = """
|
|
| 379 |
}
|
| 380 |
.mesh-examples {
|
| 381 |
flex: 0 0 auto;
|
| 382 |
-
|
| 383 |
-
overflow-y: auto;
|
| 384 |
border: 1px solid var(--demo-border);
|
| 385 |
border-radius: 6px;
|
| 386 |
-
padding:
|
| 387 |
background: var(--demo-panel-bg);
|
| 388 |
color: var(--demo-text) !important;
|
| 389 |
}
|
| 390 |
-
.
|
| 391 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 392 |
}
|
| 393 |
.kin-panel {
|
| 394 |
display: flex;
|
|
@@ -1467,6 +1501,34 @@ KINEMATIC_TREE_EDITOR_CSS = """
|
|
| 1467 |
}
|
| 1468 |
"""
|
| 1469 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1470 |
UPRIGHT_PICKER_JS = r"""
|
| 1471 |
() => {
|
| 1472 |
const choices = [
|
|
@@ -3033,6 +3095,14 @@ def _timestamped_mesh_output_dir(output_root: Path, mesh_hash: str, suffix: str
|
|
| 3033 |
return output_root / "_".join(name_parts)
|
| 3034 |
|
| 3035 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3036 |
def _upright_preview_cache_dir(mesh_hash: str) -> Path:
|
| 3037 |
return _mesh_cache_dir(mesh_hash) / "upright_previews"
|
| 3038 |
|
|
@@ -3934,6 +4004,17 @@ class InstructParticulateApp:
|
|
| 3934 |
gr.update(value=None, interactive=False),
|
| 3935 |
)
|
| 3936 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3937 |
def extract_kinematic_structure(
|
| 3938 |
self,
|
| 3939 |
mesh_path_value: Any,
|
|
@@ -3983,6 +4064,7 @@ class InstructParticulateApp:
|
|
| 3983 |
auto_output_dir = output_dir / "auto_kinematics"
|
| 3984 |
renders_dir = auto_output_dir / "renders"
|
| 3985 |
auto_output_dir.mkdir(parents=True, exist_ok=True)
|
|
|
|
| 3986 |
|
| 3987 |
mesh_geometry = self._prepare_geometry(mesh_path, canonical_up)
|
| 3988 |
|
|
@@ -4130,6 +4212,7 @@ class InstructParticulateApp:
|
|
| 4130 |
mesh_hash = str(mesh_hash_value or _mesh_file_sha256(mesh_path))
|
| 4131 |
output_dir = _timestamped_mesh_output_dir(self.output_root, mesh_hash)
|
| 4132 |
output_dir.mkdir(parents=True, exist_ok=True)
|
|
|
|
| 4133 |
num_query_points_value = int(num_query_points)
|
| 4134 |
num_query_points_per_face_for_seg_value = (
|
| 4135 |
None
|
|
@@ -4225,6 +4308,7 @@ class InstructParticulateApp:
|
|
| 4225 |
"joint_decoding_confidence_temperature": joint_decoding_confidence_temperature_value,
|
| 4226 |
},
|
| 4227 |
"mesh_path": str(mesh_path),
|
|
|
|
| 4228 |
"up_dir": str(canonical_up),
|
| 4229 |
"output_dir": str(output_dir),
|
| 4230 |
"batch": _to_cpu_payload(batch),
|
|
@@ -4364,6 +4448,7 @@ class InstructParticulateApp:
|
|
| 4364 |
output_payload = {
|
| 4365 |
"args": args_payload,
|
| 4366 |
"mesh_path": str(mesh_path),
|
|
|
|
| 4367 |
"up_dir": str(canonical_up),
|
| 4368 |
"output_dir": str(output_dir),
|
| 4369 |
"query_face_indices": np.asarray(
|
|
@@ -4401,6 +4486,7 @@ class InstructParticulateApp:
|
|
| 4401 |
|
| 4402 |
args_payload = dict(payload["args"])
|
| 4403 |
mesh_path = Path(str(payload["mesh_path"]))
|
|
|
|
| 4404 |
canonical_up = str(payload["up_dir"])
|
| 4405 |
output_dir = Path(str(payload["output_dir"]))
|
| 4406 |
visualization_path = Path(str(payload["visualization_path"]))
|
|
@@ -4435,6 +4521,7 @@ class InstructParticulateApp:
|
|
| 4435 |
joint_decoding_confidence_temperature=float(
|
| 4436 |
args_payload["joint_decoding_confidence_temperature"]
|
| 4437 |
),
|
|
|
|
| 4438 |
)
|
| 4439 |
return (
|
| 4440 |
str(output_dir / "animated_textured.glb"),
|
|
@@ -4608,6 +4695,7 @@ class InstructParticulateApp:
|
|
| 4608 |
animation_frames: int,
|
| 4609 |
enforce_connectivity_per_part: bool,
|
| 4610 |
joint_decoding_confidence_temperature: float,
|
|
|
|
| 4611 |
) -> None:
|
| 4612 |
motion_output = prediction["motion_output"]
|
| 4613 |
joint_refit_sampling = prediction["joint_refit_sampling"]
|
|
@@ -4737,6 +4825,7 @@ class InstructParticulateApp:
|
|
| 4737 |
visualization_path=visualization_path,
|
| 4738 |
overparam_visualization_path=overparam_visualization_path,
|
| 4739 |
optional_paths={
|
|
|
|
| 4740 |
"overparam_visualization_path": overparam_visualization_path,
|
| 4741 |
"urdf_export_payload_path": output_dir / "urdf_export_payload.npz",
|
| 4742 |
},
|
|
@@ -4835,11 +4924,53 @@ def prepare_inference_ui():
|
|
| 4835 |
)
|
| 4836 |
|
| 4837 |
|
| 4838 |
-
def _example_meshes() -> list[
|
| 4839 |
examples_dir = REPO_ROOT / "examples"
|
| 4840 |
-
|
|
|
|
| 4841 |
return []
|
| 4842 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4843 |
|
| 4844 |
|
| 4845 |
def _html_attr_json(value: dict[str, Any]) -> str:
|
|
@@ -4955,15 +5086,25 @@ def create_gradio_app(app: InstructParticulateApp) -> gr.Blocks:
|
|
| 4955 |
)
|
| 4956 |
latest_output_dir = gr.State(None)
|
| 4957 |
inference_payload = gr.State(None)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4958 |
|
| 4959 |
with gr.Row(equal_height=True, elem_classes=["demo-row", "demo-top-row"]):
|
| 4960 |
with gr.Column(scale=1, min_width=300, elem_classes=["demo-panel", "mesh-panel"]):
|
| 4961 |
input_mesh = gr.Model3D(label="Input Mesh", interactive=True, height=300)
|
| 4962 |
examples = _example_meshes()
|
| 4963 |
-
examples_container = None
|
| 4964 |
if examples:
|
| 4965 |
-
with gr.Column(elem_classes=["mesh-examples"])
|
| 4966 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4967 |
|
| 4968 |
with gr.Column(scale=1, min_width=300, elem_classes=["demo-panel", "kin-panel"]):
|
| 4969 |
extract_button = gr.Button("Extract Kinematic Structure")
|
|
@@ -5102,29 +5243,25 @@ def create_gradio_app(app: InstructParticulateApp) -> gr.Blocks:
|
|
| 5102 |
elem_classes=["compact-status"],
|
| 5103 |
)
|
| 5104 |
|
| 5105 |
-
if examples
|
| 5106 |
-
|
| 5107 |
-
|
| 5108 |
-
|
| 5109 |
-
|
| 5110 |
-
|
| 5111 |
-
|
| 5112 |
-
|
| 5113 |
-
|
| 5114 |
-
|
| 5115 |
-
|
| 5116 |
-
|
| 5117 |
-
|
| 5118 |
-
|
| 5119 |
-
|
| 5120 |
-
|
| 5121 |
-
|
| 5122 |
-
|
| 5123 |
-
|
| 5124 |
-
run_on_click=True,
|
| 5125 |
-
cache_examples=False,
|
| 5126 |
-
label="Examples",
|
| 5127 |
-
)
|
| 5128 |
|
| 5129 |
input_mesh.change(
|
| 5130 |
fn=app.register_mesh,
|
|
@@ -5237,6 +5374,7 @@ def create_gradio_app(app: InstructParticulateApp) -> gr.Blocks:
|
|
| 5237 |
inputs=[latest_output_dir],
|
| 5238 |
outputs=[urdf_zip, urdf_status],
|
| 5239 |
)
|
|
|
|
| 5240 |
demo.load(fn=None, js=UPRIGHT_PICKER_JS)
|
| 5241 |
demo.load(fn=None, js=KINEMATIC_TREE_EDITOR_JS)
|
| 5242 |
demo.queue()
|
|
@@ -5254,5 +5392,8 @@ if __name__ == "__main__":
|
|
| 5254 |
server_port=port,
|
| 5255 |
share=share,
|
| 5256 |
ssr_mode=False,
|
| 5257 |
-
allowed_paths=[
|
|
|
|
|
|
|
|
|
|
| 5258 |
)
|
|
|
|
| 2 |
|
| 3 |
import asyncio
|
| 4 |
import hashlib
|
| 5 |
+
import html
|
| 6 |
import json
|
| 7 |
import os
|
| 8 |
import shutil
|
|
|
|
| 380 |
}
|
| 381 |
.mesh-examples {
|
| 382 |
flex: 0 0 auto;
|
| 383 |
+
overflow: visible;
|
|
|
|
| 384 |
border: 1px solid var(--demo-border);
|
| 385 |
border-radius: 6px;
|
| 386 |
+
padding: 8px;
|
| 387 |
background: var(--demo-panel-bg);
|
| 388 |
color: var(--demo-text) !important;
|
| 389 |
}
|
| 390 |
+
.example-preview-grid {
|
| 391 |
+
display: grid;
|
| 392 |
+
grid-template-columns: repeat(auto-fit, minmax(68px, 1fr));
|
| 393 |
+
gap: 8px;
|
| 394 |
+
}
|
| 395 |
+
.example-preview-button {
|
| 396 |
+
display: flex;
|
| 397 |
+
flex-direction: column;
|
| 398 |
+
align-items: stretch;
|
| 399 |
+
gap: 4px;
|
| 400 |
+
min-width: 0;
|
| 401 |
+
padding: 0;
|
| 402 |
+
border: 1px solid var(--demo-border);
|
| 403 |
+
border-radius: 6px;
|
| 404 |
+
background: var(--demo-panel-bg);
|
| 405 |
+
color: var(--demo-text);
|
| 406 |
+
cursor: pointer;
|
| 407 |
+
overflow: hidden;
|
| 408 |
+
}
|
| 409 |
+
.example-preview-button:hover,
|
| 410 |
+
.example-preview-button:focus-visible {
|
| 411 |
+
border-color: var(--demo-focus);
|
| 412 |
+
outline: none;
|
| 413 |
+
}
|
| 414 |
+
.example-preview-button img {
|
| 415 |
+
display: block;
|
| 416 |
+
width: 100%;
|
| 417 |
+
aspect-ratio: 1 / 1;
|
| 418 |
+
object-fit: cover;
|
| 419 |
+
}
|
| 420 |
+
.example-preview-button span {
|
| 421 |
+
padding: 0 6px 6px;
|
| 422 |
+
color: var(--demo-muted);
|
| 423 |
+
font-size: 12px;
|
| 424 |
+
line-height: 1.2;
|
| 425 |
+
text-align: center;
|
| 426 |
}
|
| 427 |
.kin-panel {
|
| 428 |
display: flex;
|
|
|
|
| 1501 |
}
|
| 1502 |
"""
|
| 1503 |
|
| 1504 |
+
EXAMPLE_PICKER_JS = r"""
|
| 1505 |
+
() => {
|
| 1506 |
+
function wireExamplePicker() {
|
| 1507 |
+
const grid = document.getElementById("example-mesh-grid");
|
| 1508 |
+
const indexField = document.querySelector(
|
| 1509 |
+
"#example_mesh_index textarea, #example_mesh_index input"
|
| 1510 |
+
);
|
| 1511 |
+
if (!grid || !indexField) {
|
| 1512 |
+
window.setTimeout(wireExamplePicker, 100);
|
| 1513 |
+
return;
|
| 1514 |
+
}
|
| 1515 |
+
grid.querySelectorAll("[data-example-index]").forEach((button) => {
|
| 1516 |
+
if (button.dataset.examplePickerBound === "1") {
|
| 1517 |
+
return;
|
| 1518 |
+
}
|
| 1519 |
+
button.dataset.examplePickerBound = "1";
|
| 1520 |
+
button.addEventListener("click", () => {
|
| 1521 |
+
indexField.value = button.dataset.exampleIndex || "";
|
| 1522 |
+
indexField.dispatchEvent(new Event("input", { bubbles: true }));
|
| 1523 |
+
indexField.dispatchEvent(new Event("change", { bubbles: true }));
|
| 1524 |
+
});
|
| 1525 |
+
});
|
| 1526 |
+
}
|
| 1527 |
+
|
| 1528 |
+
wireExamplePicker();
|
| 1529 |
+
}
|
| 1530 |
+
"""
|
| 1531 |
+
|
| 1532 |
UPRIGHT_PICKER_JS = r"""
|
| 1533 |
() => {
|
| 1534 |
const choices = [
|
|
|
|
| 3095 |
return output_root / "_".join(name_parts)
|
| 3096 |
|
| 3097 |
|
| 3098 |
+
def _copy_original_input_mesh(mesh_path: Path, output_dir: Path) -> Path:
|
| 3099 |
+
suffix = mesh_path.suffix.lower() or ".mesh"
|
| 3100 |
+
output_path = output_dir / f"input_mesh_original{suffix}"
|
| 3101 |
+
output_path.parent.mkdir(parents=True, exist_ok=True)
|
| 3102 |
+
shutil.copy2(mesh_path, output_path)
|
| 3103 |
+
return output_path
|
| 3104 |
+
|
| 3105 |
+
|
| 3106 |
def _upright_preview_cache_dir(mesh_hash: str) -> Path:
|
| 3107 |
return _mesh_cache_dir(mesh_hash) / "upright_previews"
|
| 3108 |
|
|
|
|
| 4004 |
gr.update(value=None, interactive=False),
|
| 4005 |
)
|
| 4006 |
|
| 4007 |
+
def select_example_mesh(self, selected_index_value: Any):
|
| 4008 |
+
examples = _example_meshes()
|
| 4009 |
+
selected_index = int(str(selected_index_value).strip())
|
| 4010 |
+
if selected_index < 0 or selected_index >= len(examples):
|
| 4011 |
+
raise IndexError(
|
| 4012 |
+
f"Example index {selected_index} is outside the available examples."
|
| 4013 |
+
)
|
| 4014 |
+
mesh_path = examples[selected_index]["mesh_path"]
|
| 4015 |
+
for result in self.register_mesh(mesh_path):
|
| 4016 |
+
yield (mesh_path, *result)
|
| 4017 |
+
|
| 4018 |
def extract_kinematic_structure(
|
| 4019 |
self,
|
| 4020 |
mesh_path_value: Any,
|
|
|
|
| 4064 |
auto_output_dir = output_dir / "auto_kinematics"
|
| 4065 |
renders_dir = auto_output_dir / "renders"
|
| 4066 |
auto_output_dir.mkdir(parents=True, exist_ok=True)
|
| 4067 |
+
_copy_original_input_mesh(mesh_path, output_dir)
|
| 4068 |
|
| 4069 |
mesh_geometry = self._prepare_geometry(mesh_path, canonical_up)
|
| 4070 |
|
|
|
|
| 4212 |
mesh_hash = str(mesh_hash_value or _mesh_file_sha256(mesh_path))
|
| 4213 |
output_dir = _timestamped_mesh_output_dir(self.output_root, mesh_hash)
|
| 4214 |
output_dir.mkdir(parents=True, exist_ok=True)
|
| 4215 |
+
input_mesh_copy_path = _copy_original_input_mesh(mesh_path, output_dir)
|
| 4216 |
num_query_points_value = int(num_query_points)
|
| 4217 |
num_query_points_per_face_for_seg_value = (
|
| 4218 |
None
|
|
|
|
| 4308 |
"joint_decoding_confidence_temperature": joint_decoding_confidence_temperature_value,
|
| 4309 |
},
|
| 4310 |
"mesh_path": str(mesh_path),
|
| 4311 |
+
"input_mesh_copy_path": str(input_mesh_copy_path),
|
| 4312 |
"up_dir": str(canonical_up),
|
| 4313 |
"output_dir": str(output_dir),
|
| 4314 |
"batch": _to_cpu_payload(batch),
|
|
|
|
| 4448 |
output_payload = {
|
| 4449 |
"args": args_payload,
|
| 4450 |
"mesh_path": str(mesh_path),
|
| 4451 |
+
"input_mesh_copy_path": str(payload["input_mesh_copy_path"]),
|
| 4452 |
"up_dir": str(canonical_up),
|
| 4453 |
"output_dir": str(output_dir),
|
| 4454 |
"query_face_indices": np.asarray(
|
|
|
|
| 4486 |
|
| 4487 |
args_payload = dict(payload["args"])
|
| 4488 |
mesh_path = Path(str(payload["mesh_path"]))
|
| 4489 |
+
input_mesh_copy_path = Path(str(payload["input_mesh_copy_path"]))
|
| 4490 |
canonical_up = str(payload["up_dir"])
|
| 4491 |
output_dir = Path(str(payload["output_dir"]))
|
| 4492 |
visualization_path = Path(str(payload["visualization_path"]))
|
|
|
|
| 4521 |
joint_decoding_confidence_temperature=float(
|
| 4522 |
args_payload["joint_decoding_confidence_temperature"]
|
| 4523 |
),
|
| 4524 |
+
input_mesh_copy_path=input_mesh_copy_path,
|
| 4525 |
)
|
| 4526 |
return (
|
| 4527 |
str(output_dir / "animated_textured.glb"),
|
|
|
|
| 4695 |
animation_frames: int,
|
| 4696 |
enforce_connectivity_per_part: bool,
|
| 4697 |
joint_decoding_confidence_temperature: float,
|
| 4698 |
+
input_mesh_copy_path: Path,
|
| 4699 |
) -> None:
|
| 4700 |
motion_output = prediction["motion_output"]
|
| 4701 |
joint_refit_sampling = prediction["joint_refit_sampling"]
|
|
|
|
| 4825 |
visualization_path=visualization_path,
|
| 4826 |
overparam_visualization_path=overparam_visualization_path,
|
| 4827 |
optional_paths={
|
| 4828 |
+
"input_mesh_original_path": input_mesh_copy_path,
|
| 4829 |
"overparam_visualization_path": overparam_visualization_path,
|
| 4830 |
"urdf_export_payload_path": output_dir / "urdf_export_payload.npz",
|
| 4831 |
},
|
|
|
|
| 4924 |
)
|
| 4925 |
|
| 4926 |
|
| 4927 |
+
def _example_meshes() -> list[dict[str, str]]:
|
| 4928 |
examples_dir = REPO_ROOT / "examples"
|
| 4929 |
+
render_dir = examples_dir / "render"
|
| 4930 |
+
if not examples_dir.exists() or not render_dir.exists():
|
| 4931 |
return []
|
| 4932 |
+
image_suffixes = (".png", ".jpg", ".jpeg", ".webp")
|
| 4933 |
+
examples: list[dict[str, str]] = []
|
| 4934 |
+
for mesh_path in sorted(examples_dir.glob("*.glb")):
|
| 4935 |
+
preview_path = next(
|
| 4936 |
+
(
|
| 4937 |
+
render_dir / f"{mesh_path.stem}{suffix}"
|
| 4938 |
+
for suffix in image_suffixes
|
| 4939 |
+
if (render_dir / f"{mesh_path.stem}{suffix}").exists()
|
| 4940 |
+
),
|
| 4941 |
+
None,
|
| 4942 |
+
)
|
| 4943 |
+
if preview_path is None:
|
| 4944 |
+
continue
|
| 4945 |
+
examples.append(
|
| 4946 |
+
{
|
| 4947 |
+
"label": mesh_path.stem,
|
| 4948 |
+
"mesh_path": str(mesh_path),
|
| 4949 |
+
"preview_path": str(preview_path),
|
| 4950 |
+
}
|
| 4951 |
+
)
|
| 4952 |
+
return examples
|
| 4953 |
+
|
| 4954 |
+
|
| 4955 |
+
def _example_mesh_grid_html(examples: list[dict[str, str]]) -> str:
|
| 4956 |
+
buttons: list[str] = []
|
| 4957 |
+
for index, example in enumerate(examples):
|
| 4958 |
+
preview_path = Path(example["preview_path"]).resolve()
|
| 4959 |
+
label = html.escape(example["label"])
|
| 4960 |
+
src = html.escape(f"/file={preview_path}")
|
| 4961 |
+
buttons.append(
|
| 4962 |
+
f"""
|
| 4963 |
+
<button class="example-preview-button" type="button" data-example-index="{index}">
|
| 4964 |
+
<img src="{src}" alt="Example {label}" loading="lazy" />
|
| 4965 |
+
<span>{label}</span>
|
| 4966 |
+
</button>
|
| 4967 |
+
"""
|
| 4968 |
+
)
|
| 4969 |
+
return f"""
|
| 4970 |
+
<div id="example-mesh-grid" class="example-preview-grid">
|
| 4971 |
+
{''.join(buttons)}
|
| 4972 |
+
</div>
|
| 4973 |
+
"""
|
| 4974 |
|
| 4975 |
|
| 4976 |
def _html_attr_json(value: dict[str, Any]) -> str:
|
|
|
|
| 5086 |
)
|
| 5087 |
latest_output_dir = gr.State(None)
|
| 5088 |
inference_payload = gr.State(None)
|
| 5089 |
+
example_mesh_index = gr.Textbox(
|
| 5090 |
+
value="",
|
| 5091 |
+
label="Example Mesh Index",
|
| 5092 |
+
elem_id="example_mesh_index",
|
| 5093 |
+
elem_classes=["kinematic-json-sync"],
|
| 5094 |
+
)
|
| 5095 |
|
| 5096 |
with gr.Row(equal_height=True, elem_classes=["demo-row", "demo-top-row"]):
|
| 5097 |
with gr.Column(scale=1, min_width=300, elem_classes=["demo-panel", "mesh-panel"]):
|
| 5098 |
input_mesh = gr.Model3D(label="Input Mesh", interactive=True, height=300)
|
| 5099 |
examples = _example_meshes()
|
|
|
|
| 5100 |
if examples:
|
| 5101 |
+
with gr.Column(elem_classes=["mesh-examples"]):
|
| 5102 |
+
gr.Markdown("Examples")
|
| 5103 |
+
gr.HTML(
|
| 5104 |
+
_example_mesh_grid_html(examples),
|
| 5105 |
+
container=False,
|
| 5106 |
+
padding=False,
|
| 5107 |
+
)
|
| 5108 |
|
| 5109 |
with gr.Column(scale=1, min_width=300, elem_classes=["demo-panel", "kin-panel"]):
|
| 5110 |
extract_button = gr.Button("Extract Kinematic Structure")
|
|
|
|
| 5243 |
elem_classes=["compact-status"],
|
| 5244 |
)
|
| 5245 |
|
| 5246 |
+
if examples:
|
| 5247 |
+
example_mesh_index.change(
|
| 5248 |
+
fn=app.select_example_mesh,
|
| 5249 |
+
inputs=[example_mesh_index],
|
| 5250 |
+
outputs=[
|
| 5251 |
+
input_mesh,
|
| 5252 |
+
loaded_mesh_path,
|
| 5253 |
+
loaded_mesh_hash,
|
| 5254 |
+
mesh_face_warning,
|
| 5255 |
+
kinematic_tree,
|
| 5256 |
+
point_prompts,
|
| 5257 |
+
point_prompt_mesh_data,
|
| 5258 |
+
*upright_preview_images,
|
| 5259 |
+
selected_up_dir,
|
| 5260 |
+
latest_output_dir,
|
| 5261 |
+
export_urdf_button,
|
| 5262 |
+
urdf_zip,
|
| 5263 |
+
],
|
| 5264 |
+
)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 5265 |
|
| 5266 |
input_mesh.change(
|
| 5267 |
fn=app.register_mesh,
|
|
|
|
| 5374 |
inputs=[latest_output_dir],
|
| 5375 |
outputs=[urdf_zip, urdf_status],
|
| 5376 |
)
|
| 5377 |
+
demo.load(fn=None, js=EXAMPLE_PICKER_JS)
|
| 5378 |
demo.load(fn=None, js=UPRIGHT_PICKER_JS)
|
| 5379 |
demo.load(fn=None, js=KINEMATIC_TREE_EDITOR_JS)
|
| 5380 |
demo.queue()
|
|
|
|
| 5392 |
server_port=port,
|
| 5393 |
share=share,
|
| 5394 |
ssr_mode=False,
|
| 5395 |
+
allowed_paths=[
|
| 5396 |
+
str(demo_app.output_root.resolve()),
|
| 5397 |
+
str((REPO_ROOT / "examples").resolve()),
|
| 5398 |
+
],
|
| 5399 |
)
|
examples/000.glb
CHANGED
|
@@ -1,3 +1,3 @@
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
-
oid sha256:
|
| 3 |
-
size
|
|
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:a51d8e27b2a9d6efd4037ca9fc59928105bea0736faf3c0197a3e604fff4766c
|
| 3 |
+
size 27337420
|
examples/001.glb
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:1798e04c700bf8fc76473bce16ab947fa3ca9e0699d95c3d7983d3c8008ddf3d
|
| 3 |
+
size 20122296
|
examples/002.glb
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:3292f7f3df4e072842c6b39244f87068ed00c21af68e0f4bce2bd800f080a70f
|
| 3 |
+
size 27091456
|
examples/003.glb
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:fabba20d9ce4b9bc8b9169291a2acb028ddcfc7dc6d4b18cf7e5991b39682ab6
|
| 3 |
+
size 21317836
|
examples/004.glb
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:2f0f9aeedc00c829df3d00d3e90ab744283deb062b4a7809f7280e79c9712bc7
|
| 3 |
+
size 24409368
|
examples/005.glb
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:9c7229508031b80d9eb6106569938c6034030fdbaf2f0937a484aecad905d061
|
| 3 |
+
size 30834456
|
examples/006.glb
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:c2df757b9c5dea4cf0e6b08349754abe577075637daef745afa3a683a2ec44db
|
| 3 |
+
size 25199956
|
examples/render/000.png
ADDED
|
Git LFS Details
|
examples/render/001.png
ADDED
|
Git LFS Details
|
examples/render/002.png
ADDED
|
Git LFS Details
|
examples/render/003.png
ADDED
|
Git LFS Details
|
examples/render/004.png
ADDED
|
Git LFS Details
|
examples/render/005.png
ADDED
|
Git LFS Details
|
examples/render/006.png
ADDED
|
Git LFS Details
|
instruct_particulate_1m_warning_e22a80a.png
ADDED
|
Git LFS Details
|