Upgrade DeepFashion demo to HyperView 0.6.2
Browse files- .hyperview/extensions/fashion-search-readout/panel.js +16 -1
- Dockerfile +1 -1
- demo.py +42 -26
.hyperview/extensions/fashion-search-readout/panel.js
CHANGED
|
@@ -681,6 +681,18 @@ export default function FashionSearchComparisonPanel() {
|
|
| 681 |
return () => observer.disconnect();
|
| 682 |
}, [mode]);
|
| 683 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 684 |
const showExampleEvidence = React.useCallback(
|
| 685 |
async (item, model, source = "fashion-demo:query") => {
|
| 686 |
if (!item || !model?.layoutKey) return;
|
|
@@ -695,12 +707,13 @@ export default function FashionSearchComparisonPanel() {
|
|
| 695 |
focus: "samples",
|
| 696 |
persist: false,
|
| 697 |
});
|
|
|
|
| 698 |
} catch (error) {
|
| 699 |
const message = error instanceof Error ? error.message : String(error);
|
| 700 |
setPanelError(`Could not load the sample evidence panel: ${message}`);
|
| 701 |
}
|
| 702 |
},
|
| 703 |
-
[commands],
|
| 704 |
);
|
| 705 |
|
| 706 |
const chooseExample = React.useCallback(
|
|
@@ -784,6 +797,7 @@ export default function FashionSearchComparisonPanel() {
|
|
| 784 |
focus: "samples",
|
| 785 |
persist: false,
|
| 786 |
});
|
|
|
|
| 787 |
} catch (error) {
|
| 788 |
const message = error instanceof Error ? error.message : String(error);
|
| 789 |
setPanelError(`Could not select target item: ${message}`);
|
|
@@ -815,6 +829,7 @@ export default function FashionSearchComparisonPanel() {
|
|
| 815 |
focus: "samples",
|
| 816 |
persist: false,
|
| 817 |
});
|
|
|
|
| 818 |
} catch (error) {
|
| 819 |
const message = error instanceof Error ? error.message : String(error);
|
| 820 |
setPanelError(`Could not select ranked result: ${message}`);
|
|
|
|
| 681 |
return () => observer.disconnect();
|
| 682 |
}, [mode]);
|
| 683 |
|
| 684 |
+
const selectSimilarityAnchor = React.useCallback(
|
| 685 |
+
async (sampleId) => {
|
| 686 |
+
if (!sampleId || !commands.setSelection) return;
|
| 687 |
+
await commands.setSelection([sampleId], {
|
| 688 |
+
persist: false,
|
| 689 |
+
source: "panel",
|
| 690 |
+
clearLasso: false,
|
| 691 |
+
});
|
| 692 |
+
},
|
| 693 |
+
[commands],
|
| 694 |
+
);
|
| 695 |
+
|
| 696 |
const showExampleEvidence = React.useCallback(
|
| 697 |
async (item, model, source = "fashion-demo:query") => {
|
| 698 |
if (!item || !model?.layoutKey) return;
|
|
|
|
| 707 |
focus: "samples",
|
| 708 |
persist: false,
|
| 709 |
});
|
| 710 |
+
await selectSimilarityAnchor(item.queryId);
|
| 711 |
} catch (error) {
|
| 712 |
const message = error instanceof Error ? error.message : String(error);
|
| 713 |
setPanelError(`Could not load the sample evidence panel: ${message}`);
|
| 714 |
}
|
| 715 |
},
|
| 716 |
+
[commands, selectSimilarityAnchor],
|
| 717 |
);
|
| 718 |
|
| 719 |
const chooseExample = React.useCallback(
|
|
|
|
| 797 |
focus: "samples",
|
| 798 |
persist: false,
|
| 799 |
});
|
| 800 |
+
await selectSimilarityAnchor(item.queryId);
|
| 801 |
} catch (error) {
|
| 802 |
const message = error instanceof Error ? error.message : String(error);
|
| 803 |
setPanelError(`Could not select target item: ${message}`);
|
|
|
|
| 829 |
focus: "samples",
|
| 830 |
persist: false,
|
| 831 |
});
|
| 832 |
+
await selectSimilarityAnchor(result.sampleId);
|
| 833 |
} catch (error) {
|
| 834 |
const message = error instanceof Error ? error.message : String(error);
|
| 835 |
setPanelError(`Could not select ranked result: ${message}`);
|
Dockerfile
CHANGED
|
@@ -20,7 +20,7 @@ WORKDIR $HOME/app
|
|
| 20 |
|
| 21 |
RUN pip install --upgrade pip
|
| 22 |
|
| 23 |
-
ARG HYPERVIEW_VERSION=0.6.
|
| 24 |
ARG HYPER_MODELS_VERSION=0.3.0
|
| 25 |
|
| 26 |
# Install CPU-only PyTorch first so the Space does not pull the default CUDA bundle.
|
|
|
|
| 20 |
|
| 21 |
RUN pip install --upgrade pip
|
| 22 |
|
| 23 |
+
ARG HYPERVIEW_VERSION=0.6.2
|
| 24 |
ARG HYPER_MODELS_VERSION=0.3.0
|
| 25 |
|
| 26 |
# Install CPU-only PyTorch first so the Space does not pull the default CUDA bundle.
|
demo.py
CHANGED
|
@@ -309,6 +309,7 @@ def ensure_layouts(dataset: hv.Dataset) -> dict[str, str]:
|
|
| 309 |
)
|
| 310 |
print(warning, flush=True)
|
| 311 |
RUNTIME_WARNINGS.append(warning)
|
|
|
|
| 312 |
spec.update(
|
| 313 |
{
|
| 314 |
"display_name": "Hyper3-CLIP unavailable (CLIP fallback)",
|
|
@@ -317,21 +318,22 @@ def ensure_layouts(dataset: hv.Dataset) -> dict[str, str]:
|
|
| 317 |
"layout_dimension": MODEL_SPECS[0]["layout_dimension"],
|
| 318 |
"panel_title": "Hyper3-CLIP unavailable - showing CLIP fallback",
|
| 319 |
"fallback": True,
|
| 320 |
-
"
|
| 321 |
}
|
| 322 |
)
|
| 323 |
-
layouts[spec["key"]] =
|
| 324 |
continue
|
| 325 |
raise
|
| 326 |
-
spec["space_key"] = space_key
|
| 327 |
print(f"Ensuring {spec['display_name']} layout...", flush=True)
|
| 328 |
-
|
| 329 |
space_key=space_key,
|
| 330 |
layout=spec["layout"],
|
| 331 |
n_neighbors=20,
|
| 332 |
min_dist=0.08,
|
| 333 |
metric=spec["metric"],
|
| 334 |
)
|
|
|
|
|
|
|
| 335 |
return layouts
|
| 336 |
|
| 337 |
|
|
@@ -355,7 +357,6 @@ def model_panel_props(layouts: dict[str, str]) -> list[dict[str, Any]]:
|
|
| 355 |
"displayName": spec["display_name"],
|
| 356 |
"buttonLabel": spec["button_label"],
|
| 357 |
"layoutKey": layout_key,
|
| 358 |
-
"spaceKey": spec.get("space_key"),
|
| 359 |
}
|
| 360 |
)
|
| 361 |
return props
|
|
@@ -366,10 +367,10 @@ def neighbor_summary(dataset: hv.Dataset, sample_id: str, model_key: str) -> dic
|
|
| 366 |
if spec is None:
|
| 367 |
return {}
|
| 368 |
query = dataset[sample_id]
|
| 369 |
-
|
| 370 |
-
if
|
| 371 |
return {}
|
| 372 |
-
neighbors = dataset.find_similar(sample_id, k=10,
|
| 373 |
query_product = query.metadata.get("product_key")
|
| 374 |
query_category = query.metadata.get("category")
|
| 375 |
product_hits = sum(1 for sample, _distance in neighbors if sample.metadata.get("product_key") == query_product)
|
|
@@ -445,52 +446,67 @@ def build_demo_view(dataset: hv.Dataset, layouts: dict[str, str]) -> hv.ui.View:
|
|
| 445 |
extension="fashion-search-readout",
|
| 446 |
panel="fashion-comparison",
|
| 447 |
position="center",
|
| 448 |
-
|
| 449 |
-
|
|
|
|
|
|
|
| 450 |
props={
|
| 451 |
**shared_props,
|
| 452 |
"mode": "results",
|
| 453 |
-
"dockview": {
|
| 454 |
-
"closeSamplesPanel": False,
|
| 455 |
-
"hideExplorerPanel": True,
|
| 456 |
-
"initialWidth": int(os.environ.get("FASHION_RESULTS_WIDTH", "760")),
|
| 457 |
-
"minimumWidth": 620,
|
| 458 |
-
},
|
| 459 |
},
|
| 460 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 461 |
|
| 462 |
if not ENABLE_CONTEXT_MAPS:
|
| 463 |
-
return hv.ui.View(results_panel)
|
| 464 |
|
| 465 |
clip_spec = MODEL_SPECS[0]
|
| 466 |
candidate_spec = MODEL_SPECS[1]
|
| 467 |
-
|
| 468 |
-
|
| 469 |
-
|
| 470 |
-
|
|
|
|
| 471 |
clip_map = hv.ui.Scatter(
|
| 472 |
id="fashion-map-clip",
|
| 473 |
title="Context Map: CLIP",
|
| 474 |
layout_key=layouts["clip"],
|
| 475 |
-
position="
|
| 476 |
reference_panel_id="grid",
|
| 477 |
direction="below",
|
| 478 |
geometry=clip_spec["geometry"],
|
| 479 |
layout_dimension=clip_spec["layout_dimension"],
|
| 480 |
-
|
| 481 |
)
|
| 482 |
candidate_map = hv.ui.Scatter(
|
| 483 |
id="fashion-map-hyper3",
|
| 484 |
title="Context Map: Hyper3",
|
| 485 |
layout_key=layouts["candidate"],
|
| 486 |
-
position="
|
| 487 |
reference_panel_id="fashion-map-clip",
|
| 488 |
direction="right",
|
| 489 |
geometry=candidate_spec["geometry"],
|
| 490 |
layout_dimension=candidate_spec["layout_dimension"],
|
| 491 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 492 |
)
|
| 493 |
-
return hv.ui.View(results_panel, clip_map, candidate_map)
|
| 494 |
|
| 495 |
|
| 496 |
def initial_target_sample_id() -> str | None:
|
|
|
|
| 309 |
)
|
| 310 |
print(warning, flush=True)
|
| 311 |
RUNTIME_WARNINGS.append(warning)
|
| 312 |
+
fallback_layout_key = layouts["clip"]
|
| 313 |
spec.update(
|
| 314 |
{
|
| 315 |
"display_name": "Hyper3-CLIP unavailable (CLIP fallback)",
|
|
|
|
| 318 |
"layout_dimension": MODEL_SPECS[0]["layout_dimension"],
|
| 319 |
"panel_title": "Hyper3-CLIP unavailable - showing CLIP fallback",
|
| 320 |
"fallback": True,
|
| 321 |
+
"layout_key": fallback_layout_key,
|
| 322 |
}
|
| 323 |
)
|
| 324 |
+
layouts[spec["key"]] = fallback_layout_key
|
| 325 |
continue
|
| 326 |
raise
|
|
|
|
| 327 |
print(f"Ensuring {spec['display_name']} layout...", flush=True)
|
| 328 |
+
layout_key = dataset.compute_visualization(
|
| 329 |
space_key=space_key,
|
| 330 |
layout=spec["layout"],
|
| 331 |
n_neighbors=20,
|
| 332 |
min_dist=0.08,
|
| 333 |
metric=spec["metric"],
|
| 334 |
)
|
| 335 |
+
spec["layout_key"] = layout_key
|
| 336 |
+
layouts[spec["key"]] = layout_key
|
| 337 |
return layouts
|
| 338 |
|
| 339 |
|
|
|
|
| 357 |
"displayName": spec["display_name"],
|
| 358 |
"buttonLabel": spec["button_label"],
|
| 359 |
"layoutKey": layout_key,
|
|
|
|
| 360 |
}
|
| 361 |
)
|
| 362 |
return props
|
|
|
|
| 367 |
if spec is None:
|
| 368 |
return {}
|
| 369 |
query = dataset[sample_id]
|
| 370 |
+
layout_key = spec.get("layout_key")
|
| 371 |
+
if layout_key is None:
|
| 372 |
return {}
|
| 373 |
+
neighbors = dataset.find_similar(sample_id, k=10, layout_key=str(layout_key))
|
| 374 |
query_product = query.metadata.get("product_key")
|
| 375 |
query_category = query.metadata.get("category")
|
| 376 |
product_hits = sum(1 for sample, _distance in neighbors if sample.metadata.get("product_key") == query_product)
|
|
|
|
| 446 |
extension="fashion-search-readout",
|
| 447 |
panel="fashion-comparison",
|
| 448 |
position="center",
|
| 449 |
+
layout=hv.ui.PanelLayout(
|
| 450 |
+
width=int(os.environ.get("FASHION_RESULTS_WIDTH", "760")),
|
| 451 |
+
min_width=560,
|
| 452 |
+
),
|
| 453 |
props={
|
| 454 |
**shared_props,
|
| 455 |
"mode": "results",
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 456 |
},
|
| 457 |
)
|
| 458 |
+
samples_panel = hv.ui.Samples(
|
| 459 |
+
id="grid",
|
| 460 |
+
title="Samples",
|
| 461 |
+
position="center",
|
| 462 |
+
reference_panel_id="fashion-ranked-results",
|
| 463 |
+
direction="right",
|
| 464 |
+
layout=hv.ui.PanelLayout(
|
| 465 |
+
width=int(os.environ.get("FASHION_SAMPLES_WIDTH", "900")),
|
| 466 |
+
min_width=480,
|
| 467 |
+
min_height=420,
|
| 468 |
+
),
|
| 469 |
+
)
|
| 470 |
|
| 471 |
if not ENABLE_CONTEXT_MAPS:
|
| 472 |
+
return hv.ui.View(results_panel, samples_panel, active_panel="fashion-ranked-results")
|
| 473 |
|
| 474 |
clip_spec = MODEL_SPECS[0]
|
| 475 |
candidate_spec = MODEL_SPECS[1]
|
| 476 |
+
map_layout = hv.ui.PanelLayout(
|
| 477 |
+
height=int(os.environ.get("FASHION_MAP_HEIGHT", "280")),
|
| 478 |
+
min_height=220,
|
| 479 |
+
min_width=260,
|
| 480 |
+
)
|
| 481 |
clip_map = hv.ui.Scatter(
|
| 482 |
id="fashion-map-clip",
|
| 483 |
title="Context Map: CLIP",
|
| 484 |
layout_key=layouts["clip"],
|
| 485 |
+
position="center",
|
| 486 |
reference_panel_id="grid",
|
| 487 |
direction="below",
|
| 488 |
geometry=clip_spec["geometry"],
|
| 489 |
layout_dimension=clip_spec["layout_dimension"],
|
| 490 |
+
layout=map_layout,
|
| 491 |
)
|
| 492 |
candidate_map = hv.ui.Scatter(
|
| 493 |
id="fashion-map-hyper3",
|
| 494 |
title="Context Map: Hyper3",
|
| 495 |
layout_key=layouts["candidate"],
|
| 496 |
+
position="center",
|
| 497 |
reference_panel_id="fashion-map-clip",
|
| 498 |
direction="right",
|
| 499 |
geometry=candidate_spec["geometry"],
|
| 500 |
layout_dimension=candidate_spec["layout_dimension"],
|
| 501 |
+
layout=map_layout,
|
| 502 |
+
)
|
| 503 |
+
return hv.ui.View(
|
| 504 |
+
results_panel,
|
| 505 |
+
samples_panel,
|
| 506 |
+
clip_map,
|
| 507 |
+
candidate_map,
|
| 508 |
+
active_panel="fashion-ranked-results",
|
| 509 |
)
|
|
|
|
| 510 |
|
| 511 |
|
| 512 |
def initial_target_sample_id() -> str | None:
|