Spaces:
Sleeping
Sleeping
Deploy Space app files
Browse files
app.py
CHANGED
|
@@ -36,6 +36,14 @@ DATASET_REPO = os.environ.get("DATASET_REPO", "3DReflecNet/3DReflecNet")
|
|
| 36 |
HF_TOKEN = os.environ.get("HF_TOKEN", None)
|
| 37 |
MAX_RESULTS = 300
|
| 38 |
BOOL_COLUMNS = ["hasGlass", "isGenerated", "transparent", "near_light"]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 39 |
|
| 40 |
_GLB_CACHE_DIR = Path(tempfile.mkdtemp(prefix="glb_cache_"))
|
| 41 |
atexit.register(shutil.rmtree, str(_GLB_CACHE_DIR), True)
|
|
@@ -53,6 +61,10 @@ def load_preview_dataframe() -> pd.DataFrame:
|
|
| 53 |
"main_category", "sub_category", "model_name",
|
| 54 |
"material_name", "env_name", "glb_path",
|
| 55 |
"hasGlass", "isGenerated", "transparent", "near_light",
|
|
|
|
|
|
|
|
|
|
|
|
|
| 56 |
]
|
| 57 |
ds = load_dataset(
|
| 58 |
DATASET_REPO,
|
|
@@ -68,10 +80,13 @@ def load_preview_dataframe() -> pd.DataFrame:
|
|
| 68 |
[
|
| 69 |
"instance_id", "split", "main_category", "sub_category",
|
| 70 |
"model_name", "material_name", "env_name", "glb_path",
|
|
|
|
| 71 |
],
|
| 72 |
"preview parquet",
|
| 73 |
)
|
| 74 |
require_bool_columns(df, BOOL_COLUMNS, "preview parquet")
|
|
|
|
|
|
|
| 75 |
if df["frame_id"].isna().any() or not pd.api.types.is_integer_dtype(df["frame_id"]):
|
| 76 |
raise TypeError(f"Expected integer dtype for column 'frame_id' in preview parquet, got {df['frame_id'].dtype}.")
|
| 77 |
for col in ["rgb", "mask", "depth_preview", "normal_preview"]:
|
|
@@ -93,7 +108,7 @@ def build_preview_instance_dataframe(preview_df: pd.DataFrame) -> pd.DataFrame:
|
|
| 93 |
instance_cols = [
|
| 94 |
"instance_id", "main_category", "sub_category", "model_name",
|
| 95 |
"material_name", "env_name", "hasGlass", "isGenerated",
|
| 96 |
-
"transparent", "near_light", "glb_path",
|
| 97 |
]
|
| 98 |
require_columns(preview_df, instance_cols, "preview parquet")
|
| 99 |
|
|
@@ -113,10 +128,15 @@ def build_preview_instance_dataframe(preview_df: pd.DataFrame) -> pd.DataFrame:
|
|
| 113 |
[
|
| 114 |
"instance_id", "main_category", "sub_category",
|
| 115 |
"model_name", "material_name", "env_name", "glb_path",
|
|
|
|
| 116 |
],
|
| 117 |
"preview instance dataframe",
|
| 118 |
)
|
| 119 |
require_bool_columns(df, BOOL_COLUMNS, "preview instance dataframe")
|
|
|
|
|
|
|
|
|
|
|
|
|
| 120 |
if df["glb_path"].map(lambda value: not value.strip()).any():
|
| 121 |
raise ValueError("Preview instance dataframe contains empty GLB paths.")
|
| 122 |
return df
|
|
@@ -144,6 +164,37 @@ def instance_caption(row: dict[str, Any]) -> str:
|
|
| 144 |
return f"{row['model_name']} | {row['material_name']} | {row['env_name']}"
|
| 145 |
|
| 146 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 147 |
def build_instance_gallery_items(
|
| 148 |
rows: list[dict[str, Any]],
|
| 149 |
preview_df: pd.DataFrame,
|
|
@@ -218,60 +269,139 @@ def download_glb(glb_path: str) -> str:
|
|
| 218 |
# ---------------------------------------------------------------------------
|
| 219 |
|
| 220 |
def build_app(instance_df: pd.DataFrame, preview_df: pd.DataFrame) -> gr.Blocks:
|
| 221 |
-
|
| 222 |
material_name_choices = get_distinct_text_choices(instance_df, "material_name")
|
| 223 |
env_name_choices = get_distinct_text_choices(instance_df, "env_name")
|
| 224 |
|
| 225 |
-
def
|
| 226 |
-
|
| 227 |
-
|
| 228 |
-
|
| 229 |
-
|
| 230 |
-
|
| 231 |
-
|
| 232 |
-
near_light: str,
|
| 233 |
-
) -> tuple[pd.DataFrame, list[dict[str, Any]]]:
|
| 234 |
-
filtered = filter_dataframe_advanced(
|
| 235 |
instance_df,
|
| 236 |
-
|
| 237 |
-
material_name=material_name,
|
| 238 |
-
env_name=env_name,
|
| 239 |
-
has_glass=has_glass,
|
| 240 |
-
is_generated=is_generated,
|
| 241 |
-
transparent=transparent,
|
| 242 |
-
near_light=near_light,
|
| 243 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 244 |
shown = filtered.head(MAX_RESULTS).copy()
|
| 245 |
rows = shown.to_dict(orient="records")
|
| 246 |
return filtered, rows
|
| 247 |
|
| 248 |
def filter_gallery(
|
| 249 |
-
|
| 250 |
material_name: str,
|
| 251 |
env_name: str,
|
| 252 |
has_glass: str,
|
| 253 |
is_generated: str,
|
| 254 |
transparent: str,
|
| 255 |
near_light: str,
|
|
|
|
| 256 |
):
|
| 257 |
-
|
| 258 |
-
|
| 259 |
-
|
| 260 |
-
|
| 261 |
-
|
| 262 |
-
|
| 263 |
-
|
| 264 |
-
|
|
|
|
|
|
|
|
|
|
| 265 |
)
|
|
|
|
| 266 |
summary = f"Matched **{len(filtered)}** preview instances, showing **{len(rows)}**."
|
| 267 |
gallery_items = build_instance_gallery_items(rows, preview_df)
|
| 268 |
slider_empty = gr.update(minimum=1, maximum=1, step=1, value=1, interactive=False)
|
| 269 |
-
return
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 270 |
|
| 271 |
def on_instance_select(rows: list[dict[str, Any]], evt: gr.SelectData):
|
| 272 |
if not rows:
|
| 273 |
slider_empty = gr.update(minimum=1, maximum=1, step=1, value=1, interactive=False)
|
| 274 |
-
return {}, None, None, None, None, None, slider_empty, []
|
| 275 |
idx = evt.index[0] if isinstance(evt.index, tuple) else evt.index
|
| 276 |
if not isinstance(idx, int) or idx < 0 or idx >= len(rows):
|
| 277 |
raise IndexError(f"Selected gallery index is out of range: {evt.index!r}")
|
|
@@ -289,7 +419,14 @@ def build_app(instance_df: pd.DataFrame, preview_df: pd.DataFrame) -> gr.Blocks:
|
|
| 289 |
value=1,
|
| 290 |
interactive=True,
|
| 291 |
)
|
| 292 |
-
return
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 293 |
|
| 294 |
def on_frame_change(frame_idx: float, frame_items: list[dict[str, Any]]):
|
| 295 |
return render_frame_images(frame_items, frame_idx)
|
|
@@ -305,7 +442,7 @@ def build_app(instance_df: pd.DataFrame, preview_df: pd.DataFrame) -> gr.Blocks:
|
|
| 305 |
)
|
| 306 |
|
| 307 |
with gr.Row():
|
| 308 |
-
|
| 309 |
material_name = gr.Dropdown(label="material_name", choices=material_name_choices, value=FILTER_ALL)
|
| 310 |
env_name = gr.Dropdown(label="env_name", choices=env_name_choices, value=FILTER_ALL)
|
| 311 |
with gr.Row():
|
|
@@ -325,6 +462,7 @@ def build_app(instance_df: pd.DataFrame, preview_df: pd.DataFrame) -> gr.Blocks:
|
|
| 325 |
|
| 326 |
with gr.Row():
|
| 327 |
instance_meta = gr.JSON(label="Instance Metadata")
|
|
|
|
| 328 |
model_viewer = gr.Model3D(
|
| 329 |
label="3D Preview (GLB)",
|
| 330 |
clear_color=(0.35, 0.35, 0.38, 1.0),
|
|
@@ -349,7 +487,7 @@ def build_app(instance_df: pd.DataFrame, preview_df: pd.DataFrame) -> gr.Blocks:
|
|
| 349 |
frame_state = gr.State([])
|
| 350 |
|
| 351 |
filter_inputs = [
|
| 352 |
-
|
| 353 |
material_name,
|
| 354 |
env_name,
|
| 355 |
has_glass,
|
|
@@ -358,10 +496,14 @@ def build_app(instance_df: pd.DataFrame, preview_df: pd.DataFrame) -> gr.Blocks:
|
|
| 358 |
near_light,
|
| 359 |
]
|
| 360 |
filter_outputs = [
|
|
|
|
|
|
|
|
|
|
| 361 |
summary,
|
| 362 |
instance_gallery,
|
| 363 |
instance_state,
|
| 364 |
instance_meta,
|
|
|
|
| 365 |
model_viewer,
|
| 366 |
rgb_image,
|
| 367 |
mask_image,
|
|
@@ -370,9 +512,17 @@ def build_app(instance_df: pd.DataFrame, preview_df: pd.DataFrame) -> gr.Blocks:
|
|
| 370 |
frame_slider,
|
| 371 |
frame_state,
|
| 372 |
]
|
| 373 |
-
for filter_component in
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 374 |
filter_component.change(
|
| 375 |
-
fn=
|
| 376 |
inputs=filter_inputs,
|
| 377 |
outputs=filter_outputs,
|
| 378 |
)
|
|
@@ -381,6 +531,7 @@ def build_app(instance_df: pd.DataFrame, preview_df: pd.DataFrame) -> gr.Blocks:
|
|
| 381 |
inputs=[instance_state],
|
| 382 |
outputs=[
|
| 383 |
instance_meta,
|
|
|
|
| 384 |
model_viewer,
|
| 385 |
rgb_image,
|
| 386 |
mask_image,
|
|
|
|
| 36 |
HF_TOKEN = os.environ.get("HF_TOKEN", None)
|
| 37 |
MAX_RESULTS = 300
|
| 38 |
BOOL_COLUMNS = ["hasGlass", "isGenerated", "transparent", "near_light"]
|
| 39 |
+
TAG_TEXT_COLUMNS = [
|
| 40 |
+
"indoor_outdoor", "glossiness", "reflectivity", "texture_scale",
|
| 41 |
+
"anisotropy", "metallic_hint", "light_type", "light_intensity",
|
| 42 |
+
"key_light_direction", "shadow_hardness", "description",
|
| 43 |
+
]
|
| 44 |
+
TAG_NUMERIC_COLUMNS = ["roughness"]
|
| 45 |
+
TAG_COLUMNS = TAG_TEXT_COLUMNS + TAG_NUMERIC_COLUMNS
|
| 46 |
+
TEXT_FILTER_COLUMNS = ["main_category", "material_name", "env_name"]
|
| 47 |
|
| 48 |
_GLB_CACHE_DIR = Path(tempfile.mkdtemp(prefix="glb_cache_"))
|
| 49 |
atexit.register(shutil.rmtree, str(_GLB_CACHE_DIR), True)
|
|
|
|
| 61 |
"main_category", "sub_category", "model_name",
|
| 62 |
"material_name", "env_name", "glb_path",
|
| 63 |
"hasGlass", "isGenerated", "transparent", "near_light",
|
| 64 |
+
"indoor_outdoor", "glossiness", "roughness", "reflectivity",
|
| 65 |
+
"texture_scale", "anisotropy", "metallic_hint", "light_type",
|
| 66 |
+
"light_intensity", "key_light_direction", "shadow_hardness",
|
| 67 |
+
"description",
|
| 68 |
]
|
| 69 |
ds = load_dataset(
|
| 70 |
DATASET_REPO,
|
|
|
|
| 80 |
[
|
| 81 |
"instance_id", "split", "main_category", "sub_category",
|
| 82 |
"model_name", "material_name", "env_name", "glb_path",
|
| 83 |
+
*TAG_TEXT_COLUMNS,
|
| 84 |
],
|
| 85 |
"preview parquet",
|
| 86 |
)
|
| 87 |
require_bool_columns(df, BOOL_COLUMNS, "preview parquet")
|
| 88 |
+
if df["roughness"].isna().any() or not pd.api.types.is_numeric_dtype(df["roughness"]):
|
| 89 |
+
raise TypeError(f"Expected numeric dtype for column 'roughness' in preview parquet, got {df['roughness'].dtype}.")
|
| 90 |
if df["frame_id"].isna().any() or not pd.api.types.is_integer_dtype(df["frame_id"]):
|
| 91 |
raise TypeError(f"Expected integer dtype for column 'frame_id' in preview parquet, got {df['frame_id'].dtype}.")
|
| 92 |
for col in ["rgb", "mask", "depth_preview", "normal_preview"]:
|
|
|
|
| 108 |
instance_cols = [
|
| 109 |
"instance_id", "main_category", "sub_category", "model_name",
|
| 110 |
"material_name", "env_name", "hasGlass", "isGenerated",
|
| 111 |
+
"transparent", "near_light", "glb_path", *TAG_COLUMNS,
|
| 112 |
]
|
| 113 |
require_columns(preview_df, instance_cols, "preview parquet")
|
| 114 |
|
|
|
|
| 128 |
[
|
| 129 |
"instance_id", "main_category", "sub_category",
|
| 130 |
"model_name", "material_name", "env_name", "glb_path",
|
| 131 |
+
*TAG_TEXT_COLUMNS,
|
| 132 |
],
|
| 133 |
"preview instance dataframe",
|
| 134 |
)
|
| 135 |
require_bool_columns(df, BOOL_COLUMNS, "preview instance dataframe")
|
| 136 |
+
if df["roughness"].isna().any() or not pd.api.types.is_numeric_dtype(df["roughness"]):
|
| 137 |
+
raise TypeError(
|
| 138 |
+
f"Expected numeric dtype for column 'roughness' in preview instance dataframe, got {df['roughness'].dtype}."
|
| 139 |
+
)
|
| 140 |
if df["glb_path"].map(lambda value: not value.strip()).any():
|
| 141 |
raise ValueError("Preview instance dataframe contains empty GLB paths.")
|
| 142 |
return df
|
|
|
|
| 164 |
return f"{row['model_name']} | {row['material_name']} | {row['env_name']}"
|
| 165 |
|
| 166 |
|
| 167 |
+
def build_llm_tags(row: dict[str, Any]) -> dict[str, Any]:
|
| 168 |
+
"""Reconstruct the tags.json shape from preview parquet columns."""
|
| 169 |
+
return {
|
| 170 |
+
"instance_id": row["instance_id"],
|
| 171 |
+
"category": {
|
| 172 |
+
"main": row["main_category"],
|
| 173 |
+
"sub": row["sub_category"],
|
| 174 |
+
},
|
| 175 |
+
"material_properties": {
|
| 176 |
+
"glossiness": row["glossiness"],
|
| 177 |
+
"roughness": float(row["roughness"]),
|
| 178 |
+
"reflectivity": row["reflectivity"],
|
| 179 |
+
"texture_scale": row["texture_scale"],
|
| 180 |
+
"anisotropy": row["anisotropy"],
|
| 181 |
+
"metallic_hint": row["metallic_hint"],
|
| 182 |
+
},
|
| 183 |
+
"environment": {
|
| 184 |
+
"indoor_outdoor": row["indoor_outdoor"],
|
| 185 |
+
"light_type": row["light_type"],
|
| 186 |
+
"light_intensity": row["light_intensity"],
|
| 187 |
+
"key_light_direction": row["key_light_direction"],
|
| 188 |
+
"shadow_hardness": row["shadow_hardness"],
|
| 189 |
+
},
|
| 190 |
+
"description": row["description"],
|
| 191 |
+
}
|
| 192 |
+
|
| 193 |
+
|
| 194 |
+
def build_instance_metadata(row: dict[str, Any]) -> dict[str, Any]:
|
| 195 |
+
return {key: value for key, value in row.items() if key not in TAG_COLUMNS}
|
| 196 |
+
|
| 197 |
+
|
| 198 |
def build_instance_gallery_items(
|
| 199 |
rows: list[dict[str, Any]],
|
| 200 |
preview_df: pd.DataFrame,
|
|
|
|
| 269 |
# ---------------------------------------------------------------------------
|
| 270 |
|
| 271 |
def build_app(instance_df: pd.DataFrame, preview_df: pd.DataFrame) -> gr.Blocks:
|
| 272 |
+
main_category_choices = get_distinct_text_choices(instance_df, "main_category")
|
| 273 |
material_name_choices = get_distinct_text_choices(instance_df, "material_name")
|
| 274 |
env_name_choices = get_distinct_text_choices(instance_df, "env_name")
|
| 275 |
|
| 276 |
+
def text_choices_for(df: pd.DataFrame, column: str) -> list[str]:
|
| 277 |
+
if df.empty:
|
| 278 |
+
return [FILTER_ALL]
|
| 279 |
+
return get_distinct_text_choices(df, column)
|
| 280 |
+
|
| 281 |
+
def filter_with_values(values: dict[str, str], skip_text_column: str | None = None) -> pd.DataFrame:
|
| 282 |
+
return filter_dataframe_advanced(
|
|
|
|
|
|
|
|
|
|
| 283 |
instance_df,
|
| 284 |
+
main_category=FILTER_ALL if skip_text_column == "main_category" else values["main_category"],
|
| 285 |
+
material_name=FILTER_ALL if skip_text_column == "material_name" else values["material_name"],
|
| 286 |
+
env_name=FILTER_ALL if skip_text_column == "env_name" else values["env_name"],
|
| 287 |
+
has_glass=values["has_glass"],
|
| 288 |
+
is_generated=values["is_generated"],
|
| 289 |
+
transparent=values["transparent"],
|
| 290 |
+
near_light=values["near_light"],
|
| 291 |
)
|
| 292 |
+
|
| 293 |
+
def normalize_filter_values(values: dict[str, str], changed_column: str | None) -> dict[str, str]:
|
| 294 |
+
normalized = values.copy()
|
| 295 |
+
for column in TEXT_FILTER_COLUMNS:
|
| 296 |
+
value = (normalized[column] or "").strip()
|
| 297 |
+
normalized[column] = value if value else FILTER_ALL
|
| 298 |
+
for column in ["has_glass", "is_generated", "transparent", "near_light"]:
|
| 299 |
+
value = (normalized[column] or "").strip()
|
| 300 |
+
normalized[column] = value if value else FILTER_ALL
|
| 301 |
+
|
| 302 |
+
protected = {changed_column} if changed_column in TEXT_FILTER_COLUMNS else set()
|
| 303 |
+
for _ in TEXT_FILTER_COLUMNS:
|
| 304 |
+
changed = False
|
| 305 |
+
for column in TEXT_FILTER_COLUMNS:
|
| 306 |
+
if column in protected:
|
| 307 |
+
continue
|
| 308 |
+
choices = text_choices_for(filter_with_values(normalized, skip_text_column=column), column)
|
| 309 |
+
if normalized[column] not in choices:
|
| 310 |
+
normalized[column] = FILTER_ALL
|
| 311 |
+
changed = True
|
| 312 |
+
if not changed:
|
| 313 |
+
break
|
| 314 |
+
|
| 315 |
+
for column in protected:
|
| 316 |
+
choices = text_choices_for(filter_with_values(normalized, skip_text_column=column), column)
|
| 317 |
+
if normalized[column] not in choices:
|
| 318 |
+
normalized[column] = FILTER_ALL
|
| 319 |
+
return normalized
|
| 320 |
+
|
| 321 |
+
def text_filter_updates(values: dict[str, str]) -> list[Any]:
|
| 322 |
+
return [
|
| 323 |
+
gr.update(
|
| 324 |
+
choices=text_choices_for(filter_with_values(values, skip_text_column=column), column),
|
| 325 |
+
value=values[column],
|
| 326 |
+
)
|
| 327 |
+
for column in TEXT_FILTER_COLUMNS
|
| 328 |
+
]
|
| 329 |
+
|
| 330 |
+
def filtered_instance_rows(values: dict[str, str]) -> tuple[pd.DataFrame, list[dict[str, Any]]]:
|
| 331 |
+
filtered = filter_with_values(values)
|
| 332 |
shown = filtered.head(MAX_RESULTS).copy()
|
| 333 |
rows = shown.to_dict(orient="records")
|
| 334 |
return filtered, rows
|
| 335 |
|
| 336 |
def filter_gallery(
|
| 337 |
+
main_category: str,
|
| 338 |
material_name: str,
|
| 339 |
env_name: str,
|
| 340 |
has_glass: str,
|
| 341 |
is_generated: str,
|
| 342 |
transparent: str,
|
| 343 |
near_light: str,
|
| 344 |
+
changed_column: str | None = None,
|
| 345 |
):
|
| 346 |
+
values = normalize_filter_values(
|
| 347 |
+
{
|
| 348 |
+
"main_category": main_category,
|
| 349 |
+
"material_name": material_name,
|
| 350 |
+
"env_name": env_name,
|
| 351 |
+
"has_glass": has_glass,
|
| 352 |
+
"is_generated": is_generated,
|
| 353 |
+
"transparent": transparent,
|
| 354 |
+
"near_light": near_light,
|
| 355 |
+
},
|
| 356 |
+
changed_column=changed_column,
|
| 357 |
)
|
| 358 |
+
filtered, rows = filtered_instance_rows(values)
|
| 359 |
summary = f"Matched **{len(filtered)}** preview instances, showing **{len(rows)}**."
|
| 360 |
gallery_items = build_instance_gallery_items(rows, preview_df)
|
| 361 |
slider_empty = gr.update(minimum=1, maximum=1, step=1, value=1, interactive=False)
|
| 362 |
+
return [
|
| 363 |
+
*text_filter_updates(values),
|
| 364 |
+
summary,
|
| 365 |
+
gallery_items,
|
| 366 |
+
rows,
|
| 367 |
+
{},
|
| 368 |
+
{},
|
| 369 |
+
None,
|
| 370 |
+
None,
|
| 371 |
+
None,
|
| 372 |
+
None,
|
| 373 |
+
None,
|
| 374 |
+
slider_empty,
|
| 375 |
+
[],
|
| 376 |
+
]
|
| 377 |
+
|
| 378 |
+
def make_filter_handler(changed_column: str):
|
| 379 |
+
def handler(
|
| 380 |
+
main_category: str,
|
| 381 |
+
material_name: str,
|
| 382 |
+
env_name: str,
|
| 383 |
+
has_glass: str,
|
| 384 |
+
is_generated: str,
|
| 385 |
+
transparent: str,
|
| 386 |
+
near_light: str,
|
| 387 |
+
):
|
| 388 |
+
return filter_gallery(
|
| 389 |
+
main_category,
|
| 390 |
+
material_name,
|
| 391 |
+
env_name,
|
| 392 |
+
has_glass,
|
| 393 |
+
is_generated,
|
| 394 |
+
transparent,
|
| 395 |
+
near_light,
|
| 396 |
+
changed_column=changed_column,
|
| 397 |
+
)
|
| 398 |
+
|
| 399 |
+
return handler
|
| 400 |
|
| 401 |
def on_instance_select(rows: list[dict[str, Any]], evt: gr.SelectData):
|
| 402 |
if not rows:
|
| 403 |
slider_empty = gr.update(minimum=1, maximum=1, step=1, value=1, interactive=False)
|
| 404 |
+
return {}, {}, None, None, None, None, None, slider_empty, []
|
| 405 |
idx = evt.index[0] if isinstance(evt.index, tuple) else evt.index
|
| 406 |
if not isinstance(idx, int) or idx < 0 or idx >= len(rows):
|
| 407 |
raise IndexError(f"Selected gallery index is out of range: {evt.index!r}")
|
|
|
|
| 419 |
value=1,
|
| 420 |
interactive=True,
|
| 421 |
)
|
| 422 |
+
return (
|
| 423 |
+
build_instance_metadata(row),
|
| 424 |
+
build_llm_tags(row),
|
| 425 |
+
download_glb(row["glb_path"]),
|
| 426 |
+
*render_frame_images(frame_items, 1),
|
| 427 |
+
slider_ready,
|
| 428 |
+
frame_items,
|
| 429 |
+
)
|
| 430 |
|
| 431 |
def on_frame_change(frame_idx: float, frame_items: list[dict[str, Any]]):
|
| 432 |
return render_frame_images(frame_items, frame_idx)
|
|
|
|
| 442 |
)
|
| 443 |
|
| 444 |
with gr.Row():
|
| 445 |
+
main_category = gr.Dropdown(label="main_category", choices=main_category_choices, value=FILTER_ALL)
|
| 446 |
material_name = gr.Dropdown(label="material_name", choices=material_name_choices, value=FILTER_ALL)
|
| 447 |
env_name = gr.Dropdown(label="env_name", choices=env_name_choices, value=FILTER_ALL)
|
| 448 |
with gr.Row():
|
|
|
|
| 462 |
|
| 463 |
with gr.Row():
|
| 464 |
instance_meta = gr.JSON(label="Instance Metadata")
|
| 465 |
+
llm_tags = gr.JSON(label="LLM Tags")
|
| 466 |
model_viewer = gr.Model3D(
|
| 467 |
label="3D Preview (GLB)",
|
| 468 |
clear_color=(0.35, 0.35, 0.38, 1.0),
|
|
|
|
| 487 |
frame_state = gr.State([])
|
| 488 |
|
| 489 |
filter_inputs = [
|
| 490 |
+
main_category,
|
| 491 |
material_name,
|
| 492 |
env_name,
|
| 493 |
has_glass,
|
|
|
|
| 496 |
near_light,
|
| 497 |
]
|
| 498 |
filter_outputs = [
|
| 499 |
+
main_category,
|
| 500 |
+
material_name,
|
| 501 |
+
env_name,
|
| 502 |
summary,
|
| 503 |
instance_gallery,
|
| 504 |
instance_state,
|
| 505 |
instance_meta,
|
| 506 |
+
llm_tags,
|
| 507 |
model_viewer,
|
| 508 |
rgb_image,
|
| 509 |
mask_image,
|
|
|
|
| 512 |
frame_slider,
|
| 513 |
frame_state,
|
| 514 |
]
|
| 515 |
+
for filter_component, changed_column in [
|
| 516 |
+
(main_category, "main_category"),
|
| 517 |
+
(material_name, "material_name"),
|
| 518 |
+
(env_name, "env_name"),
|
| 519 |
+
(has_glass, "has_glass"),
|
| 520 |
+
(is_generated, "is_generated"),
|
| 521 |
+
(transparent, "transparent"),
|
| 522 |
+
(near_light, "near_light"),
|
| 523 |
+
]:
|
| 524 |
filter_component.change(
|
| 525 |
+
fn=make_filter_handler(changed_column),
|
| 526 |
inputs=filter_inputs,
|
| 527 |
outputs=filter_outputs,
|
| 528 |
)
|
|
|
|
| 531 |
inputs=[instance_state],
|
| 532 |
outputs=[
|
| 533 |
instance_meta,
|
| 534 |
+
llm_tags,
|
| 535 |
model_viewer,
|
| 536 |
rgb_image,
|
| 537 |
mask_image,
|
utils.py
CHANGED
|
@@ -93,7 +93,7 @@ def _apply_text_equals(df: pd.DataFrame, column: str, selected_value: str, all_l
|
|
| 93 |
|
| 94 |
def filter_dataframe_advanced(
|
| 95 |
df: pd.DataFrame,
|
| 96 |
-
|
| 97 |
material_name: str = FILTER_ALL,
|
| 98 |
env_name: str = FILTER_ALL,
|
| 99 |
has_glass: str = FILTER_ALL,
|
|
@@ -101,9 +101,9 @@ def filter_dataframe_advanced(
|
|
| 101 |
transparent: str = FILTER_ALL,
|
| 102 |
near_light: str = FILTER_ALL,
|
| 103 |
) -> pd.DataFrame:
|
| 104 |
-
"""Filter by
|
| 105 |
selected = df
|
| 106 |
-
selected = _apply_text_equals(selected, "
|
| 107 |
selected = _apply_text_equals(selected, "material_name", material_name)
|
| 108 |
selected = _apply_text_equals(selected, "env_name", env_name)
|
| 109 |
selected = apply_bool_filter(selected, "hasGlass", has_glass)
|
|
|
|
| 93 |
|
| 94 |
def filter_dataframe_advanced(
|
| 95 |
df: pd.DataFrame,
|
| 96 |
+
main_category: str = FILTER_ALL,
|
| 97 |
material_name: str = FILTER_ALL,
|
| 98 |
env_name: str = FILTER_ALL,
|
| 99 |
has_glass: str = FILTER_ALL,
|
|
|
|
| 101 |
transparent: str = FILTER_ALL,
|
| 102 |
near_light: str = FILTER_ALL,
|
| 103 |
) -> pd.DataFrame:
|
| 104 |
+
"""Filter by category/material/environment exact selection and four tri-state bool fields."""
|
| 105 |
selected = df
|
| 106 |
+
selected = _apply_text_equals(selected, "main_category", main_category)
|
| 107 |
selected = _apply_text_equals(selected, "material_name", material_name)
|
| 108 |
selected = _apply_text_equals(selected, "env_name", env_name)
|
| 109 |
selected = apply_bool_filter(selected, "hasGlass", has_glass)
|