Spaces:
Running
Running
Deploy hyper3labs/HyperView from Hyper3Labs/hyperview-spaces@355e826
Browse files- .hyperview/extensions/hello-world-intro/extension.toml +8 -0
- .hyperview/extensions/hello-world-intro/panel.jsx +80 -0
- Dockerfile +5 -6
- README.md +12 -6
- demo.py +60 -12
.hyperview/extensions/hello-world-intro/extension.toml
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
name = "hello-world-intro"
|
| 2 |
+
description = "Short orientation panel for the HyperView Hello World workspace"
|
| 3 |
+
|
| 4 |
+
[[panels]]
|
| 5 |
+
id = "hello-world-intro"
|
| 6 |
+
title = "Start here"
|
| 7 |
+
position = "right"
|
| 8 |
+
file = "panel.jsx"
|
.hyperview/extensions/hello-world-intro/panel.jsx
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
const sdk = globalThis.HyperViewPanelSDK;
|
| 2 |
+
if (!sdk || sdk.version !== "2") {
|
| 3 |
+
throw new Error("HyperViewPanelSDK v2 is not available on window.");
|
| 4 |
+
}
|
| 5 |
+
|
| 6 |
+
const { React, components, hooks } = sdk;
|
| 7 |
+
const { Panel } = components;
|
| 8 |
+
const { usePanelState, useSelection } = hooks;
|
| 9 |
+
|
| 10 |
+
const geometryColors = {
|
| 11 |
+
Euclidean: "#67e8f9",
|
| 12 |
+
Spherical: "#a78bfa",
|
| 13 |
+
"Hyperbolic · Poincare": "#fb923c",
|
| 14 |
+
};
|
| 15 |
+
|
| 16 |
+
export default function HelloWorldIntro() {
|
| 17 |
+
const { props } = usePanelState();
|
| 18 |
+
const { selectedIds } = useSelection();
|
| 19 |
+
const geometries = Array.isArray(props.geometries) ? props.geometries : [];
|
| 20 |
+
|
| 21 |
+
return (
|
| 22 |
+
<Panel>
|
| 23 |
+
<div className="hello-world-intro">
|
| 24 |
+
<span className="hello-world-kicker">HyperView Hello World</span>
|
| 25 |
+
<h2>One image collection.<br />Three geometries.</h2>
|
| 26 |
+
<p className="hello-world-lede">
|
| 27 |
+
Every map contains the same {props.sampleCount || 300} {props.dataset || "iNaturalist"} observations.
|
| 28 |
+
What changes is the representation and the geometry used to lay it out.
|
| 29 |
+
</p>
|
| 30 |
+
|
| 31 |
+
<div className="hello-world-geometry-list">
|
| 32 |
+
{geometries.map((geometry) => (
|
| 33 |
+
<article key={geometry.name}>
|
| 34 |
+
<i style={{ background: geometryColors[geometry.name] || "#94a3b8" }} />
|
| 35 |
+
<span>
|
| 36 |
+
<strong>{geometry.name}</strong>
|
| 37 |
+
<small>{geometry.model} · {geometry.dimension}</small>
|
| 38 |
+
</span>
|
| 39 |
+
</article>
|
| 40 |
+
))}
|
| 41 |
+
</div>
|
| 42 |
+
|
| 43 |
+
<div className="hello-world-steps">
|
| 44 |
+
<strong>Try this</strong>
|
| 45 |
+
<ol>
|
| 46 |
+
<li>Rotate and zoom each map.</li>
|
| 47 |
+
<li>Select a cluster in one view.</li>
|
| 48 |
+
<li>Compare where that selection lands in the other geometries.</li>
|
| 49 |
+
<li>Open Samples to inspect the underlying observations.</li>
|
| 50 |
+
</ol>
|
| 51 |
+
</div>
|
| 52 |
+
|
| 53 |
+
<div className={`hello-world-selection${selectedIds.length ? " is-active" : ""}`}>
|
| 54 |
+
<span>{selectedIds.length ? selectedIds.length : "No"}</span>
|
| 55 |
+
{selectedIds.length === 1 ? " observation selected" : " observations selected"}
|
| 56 |
+
</div>
|
| 57 |
+
</div>
|
| 58 |
+
|
| 59 |
+
<style>{`
|
| 60 |
+
.hello-world-intro { height: 100%; overflow: auto; padding: 22px; color: var(--hv-color-foreground); background: radial-gradient(circle at 90% 0%, color-mix(in srgb, var(--hv-color-accent) 12%, transparent), transparent 32%); }
|
| 61 |
+
.hello-world-kicker { color: var(--hv-color-accent); font: 600 10px/1.2 ui-monospace, SFMono-Regular, Menlo, monospace; letter-spacing: .16em; text-transform: uppercase; }
|
| 62 |
+
.hello-world-intro h2 { margin: 12px 0 10px; font: 650 27px/1.08 system-ui, sans-serif; letter-spacing: -.035em; }
|
| 63 |
+
.hello-world-lede { margin: 0; color: var(--hv-color-muted-foreground); font: 13px/1.55 system-ui, sans-serif; }
|
| 64 |
+
.hello-world-geometry-list { display: grid; gap: 8px; margin: 20px 0; }
|
| 65 |
+
.hello-world-geometry-list article { display: flex; align-items: center; gap: 11px; padding: 11px 12px; border: 1px solid var(--hv-color-border); border-radius: 10px; background: color-mix(in srgb, var(--hv-color-surface) 86%, transparent); }
|
| 66 |
+
.hello-world-geometry-list i { width: 8px; height: 30px; border-radius: 999px; }
|
| 67 |
+
.hello-world-geometry-list span { display: grid; gap: 2px; }
|
| 68 |
+
.hello-world-geometry-list strong { font: 600 12px/1.2 system-ui, sans-serif; }
|
| 69 |
+
.hello-world-geometry-list small { color: var(--hv-color-muted-foreground); font: 10px/1.2 ui-monospace, SFMono-Regular, Menlo, monospace; }
|
| 70 |
+
.hello-world-steps { padding: 14px; border: 1px solid var(--hv-color-border); border-radius: 12px; background: var(--hv-color-surface-muted); font: 12px/1.5 system-ui, sans-serif; }
|
| 71 |
+
.hello-world-steps > strong { font-size: 11px; letter-spacing: .08em; text-transform: uppercase; }
|
| 72 |
+
.hello-world-steps ol { margin: 9px 0 0; padding-left: 19px; color: var(--hv-color-muted-foreground); }
|
| 73 |
+
.hello-world-steps li + li { margin-top: 5px; }
|
| 74 |
+
.hello-world-selection { display: flex; align-items: baseline; gap: 6px; margin-top: 14px; color: var(--hv-color-muted-foreground); font: 11px/1.2 ui-monospace, SFMono-Regular, Menlo, monospace; }
|
| 75 |
+
.hello-world-selection span { color: var(--hv-color-foreground); font-size: 18px; font-weight: 650; }
|
| 76 |
+
.hello-world-selection.is-active span { color: var(--hv-color-accent); }
|
| 77 |
+
`}</style>
|
| 78 |
+
</Panel>
|
| 79 |
+
);
|
| 80 |
+
}
|
Dockerfile
CHANGED
|
@@ -21,7 +21,7 @@ WORKDIR $HOME/app
|
|
| 21 |
|
| 22 |
RUN pip install --upgrade pip
|
| 23 |
|
| 24 |
-
ARG HYPERVIEW_VERSION=1.
|
| 25 |
ARG HYPER_MODELS_VERSION=0.3.1
|
| 26 |
|
| 27 |
# Install CPU-only PyTorch first so the Space does not pull the default CUDA bundle,
|
|
@@ -31,12 +31,11 @@ RUN pip install "hyperview==${HYPERVIEW_VERSION}" && python -c "import hyperview
|
|
| 31 |
RUN pip install "hyper-models[ml]==${HYPER_MODELS_VERSION}" && python -c "import hyper_models; print('hyper_models', hyper_models.__version__)"
|
| 32 |
|
| 33 |
COPY --chown=user demo.py ./demo.py
|
|
|
|
| 34 |
|
| 35 |
-
#
|
| 36 |
-
#
|
| 37 |
-
#
|
| 38 |
-
# visitors get the viewer commands and nothing else, so provider registration,
|
| 39 |
-
# extension install, tool execution and compute stay closed.
|
| 40 |
ENV HYPERVIEW_NO_AUTH=1
|
| 41 |
ENV HYPERVIEW_DATASETS_DIR=/home/user/app/demo_data/datasets \
|
| 42 |
HYPERVIEW_MEDIA_DIR=/home/user/app/demo_data/media
|
|
|
|
| 21 |
|
| 22 |
RUN pip install --upgrade pip
|
| 23 |
|
| 24 |
+
ARG HYPERVIEW_VERSION=1.1.1
|
| 25 |
ARG HYPER_MODELS_VERSION=0.3.1
|
| 26 |
|
| 27 |
# Install CPU-only PyTorch first so the Space does not pull the default CUDA bundle,
|
|
|
|
| 31 |
RUN pip install "hyper-models[ml]==${HYPER_MODELS_VERSION}" && python -c "import hyper_models; print('hyper_models', hyper_models.__version__)"
|
| 32 |
|
| 33 |
COPY --chown=user demo.py ./demo.py
|
| 34 |
+
COPY --chown=user .hyperview ./.hyperview
|
| 35 |
|
| 36 |
+
# Only POST/PATCH/DELETE under /api/ are token-gated -- media GETs stay open
|
| 37 |
+
# either way. This marks the server public so viewer commands run without the
|
| 38 |
+
# token, while provider.register, extension.install, tools and compute get 403.
|
|
|
|
|
|
|
| 39 |
ENV HYPERVIEW_NO_AUTH=1
|
| 40 |
ENV HYPERVIEW_DATASETS_DIR=/home/user/app/demo_data/datasets \
|
| 41 |
HYPERVIEW_MEDIA_DIR=/home/user/app/demo_data/media
|
README.md
CHANGED
|
@@ -8,14 +8,15 @@ app_port: 7860
|
|
| 8 |
pinned: false
|
| 9 |
---
|
| 10 |
|
| 11 |
-
# HyperView
|
| 12 |
|
| 13 |
-
This is the main HyperView
|
| 14 |
-
sample through
|
|
|
|
| 15 |
|
| 16 |
- CLIP (`openai/clip-vit-base-patch32`) in Euclidean 3D
|
| 17 |
- CLIP (`openai/clip-vit-base-patch32`) in spherical 3D
|
| 18 |
-
-
|
| 19 |
|
| 20 |
The sample is drawn from `evendrow/inat24_tiny`, a compact iNaturalist 2024
|
| 21 |
subset with 1,000 images, 100 species, and taxonomy metadata. The visible label
|
|
@@ -25,7 +26,7 @@ rights holder.
|
|
| 25 |
|
| 26 |
The Docker image installs released packages from PyPI:
|
| 27 |
|
| 28 |
-
- `hyperview==1.
|
| 29 |
- `hyper-models[ml]==0.3.1`
|
| 30 |
|
| 31 |
## Dataset
|
|
@@ -46,7 +47,8 @@ The default stratified sample contains 300 images:
|
|
| 46 |
| mollusks | 10 |
|
| 47 |
|
| 48 |
This keeps the demo small enough for Hugging Face CPU Spaces while preserving a
|
| 49 |
-
real biological hierarchy for geometry comparison.
|
|
|
|
| 50 |
|
| 51 |
## Reuse This Template
|
| 52 |
|
|
@@ -61,3 +63,7 @@ When copying this folder for another dataset:
|
|
| 61 |
|
| 62 |
This folder is synchronized to `hyper3labs/HyperView` by GitHub Actions from
|
| 63 |
the `hyperview-spaces` deployment repository.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 8 |
pinned: false
|
| 9 |
---
|
| 10 |
|
| 11 |
+
# HyperView Hello World
|
| 12 |
|
| 13 |
+
This is the main HyperView starter Space. It shows the same higher-resolution,
|
| 14 |
+
taxonomy-backed image sample through three geometric views and includes a small
|
| 15 |
+
custom introduction panel built with the public HyperView panel SDK:
|
| 16 |
|
| 17 |
- CLIP (`openai/clip-vit-base-patch32`) in Euclidean 3D
|
| 18 |
- CLIP (`openai/clip-vit-base-patch32`) in spherical 3D
|
| 19 |
+
- Hyper3-CLIP (`hyper3-clip-v0.5`) in hyperbolic Poincare 2D
|
| 20 |
|
| 21 |
The sample is drawn from `evendrow/inat24_tiny`, a compact iNaturalist 2024
|
| 22 |
subset with 1,000 images, 100 species, and taxonomy metadata. The visible label
|
|
|
|
| 26 |
|
| 27 |
The Docker image installs released packages from PyPI:
|
| 28 |
|
| 29 |
+
- `hyperview==1.1.1`
|
| 30 |
- `hyper-models[ml]==0.3.1`
|
| 31 |
|
| 32 |
## Dataset
|
|
|
|
| 47 |
| mollusks | 10 |
|
| 48 |
|
| 49 |
This keeps the demo small enough for Hugging Face CPU Spaces while preserving a
|
| 50 |
+
real biological hierarchy for geometry comparison. Images are resized only
|
| 51 |
+
when they exceed 1024 × 1024, avoiding the tiny 32 × 32 appearance of CIFAR.
|
| 52 |
|
| 53 |
## Reuse This Template
|
| 54 |
|
|
|
|
| 63 |
|
| 64 |
This folder is synchronized to `hyper3labs/HyperView` by GitHub Actions from
|
| 65 |
the `hyperview-spaces` deployment repository.
|
| 66 |
+
|
| 67 |
+
Because `hyper3-clip-v0.5` is gated on Hugging Face, the running Space needs an
|
| 68 |
+
`HF_TOKEN` Space secret with read access to the model. The GitHub deployment
|
| 69 |
+
credential does not become a runtime secret automatically.
|
demo.py
CHANGED
|
@@ -1,10 +1,11 @@
|
|
| 1 |
#!/usr/bin/env python
|
| 2 |
-
"""HyperView
|
| 3 |
|
| 4 |
from __future__ import annotations
|
| 5 |
|
| 6 |
import os
|
| 7 |
import re
|
|
|
|
| 8 |
from collections import Counter
|
| 9 |
from pathlib import Path
|
| 10 |
|
|
@@ -16,7 +17,15 @@ import hyperview as hv
|
|
| 16 |
SPACE_HOST = "0.0.0.0"
|
| 17 |
SPACE_PORT = 7860
|
| 18 |
|
| 19 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 20 |
HF_DATASET = "evendrow/inat24_tiny"
|
| 21 |
HF_SPLIT = "train"
|
| 22 |
SAMPLE_SEED = 42
|
|
@@ -34,20 +43,21 @@ TARGET_SUPERCATEGORY_COUNTS = {
|
|
| 34 |
"mollusks": 10,
|
| 35 |
}
|
| 36 |
SAMPLE_COUNT = sum(TARGET_SUPERCATEGORY_COUNTS.values())
|
| 37 |
-
IMAGE_MAX_SIZE = (
|
|
|
|
| 38 |
|
| 39 |
EMBEDDING_LAYOUTS = [
|
| 40 |
{
|
| 41 |
"name": "CLIP",
|
| 42 |
"provider": "embed-anything",
|
| 43 |
"model": "openai/clip-vit-base-patch32",
|
| 44 |
-
"layouts": ["euclidean:3d", "spherical"],
|
| 45 |
},
|
| 46 |
{
|
| 47 |
-
"name": "
|
| 48 |
"provider": "hyper-models",
|
| 49 |
-
"model": "
|
| 50 |
-
"layouts": ["poincare"],
|
| 51 |
},
|
| 52 |
]
|
| 53 |
|
|
@@ -104,7 +114,7 @@ def save_image(row: dict, destination: Path) -> None:
|
|
| 104 |
|
| 105 |
image = ImageOps.exif_transpose(image).convert("RGB")
|
| 106 |
image.thumbnail(IMAGE_MAX_SIZE, Image.Resampling.LANCZOS)
|
| 107 |
-
image.save(destination, format="JPEG", quality=
|
| 108 |
|
| 109 |
|
| 110 |
def existing_label_counts(dataset: hv.Dataset) -> Counter[str]:
|
|
@@ -209,6 +219,16 @@ def build_dataset() -> tuple[hv.Dataset, dict[str, str]]:
|
|
| 209 |
return dataset, layout_keys
|
| 210 |
|
| 211 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 212 |
def build_demo_view(layout_keys: dict[str, str]) -> hv.ui.View:
|
| 213 |
"""Open the showcase on its three geometries, side by side.
|
| 214 |
|
|
@@ -217,13 +237,13 @@ def build_demo_view(layout_keys: dict[str, str]) -> hv.ui.View:
|
|
| 217 |
though three layouts exist -- the one thing this demo is here to show.
|
| 218 |
"""
|
| 219 |
|
| 220 |
-
panels: list[hv.ui.Scatter | hv.ui.Samples] = []
|
| 221 |
previous_id: str | None = None
|
| 222 |
for label, layout_key in layout_keys.items():
|
| 223 |
name, layout = label.split(":", 1)
|
| 224 |
panel = hv.ui.Scatter(
|
| 225 |
id=f"map-{layout.replace(':', '-')}",
|
| 226 |
-
title=
|
| 227 |
layout_key=layout_key,
|
| 228 |
position="center",
|
| 229 |
reference_panel_id=previous_id,
|
|
@@ -241,19 +261,47 @@ def build_demo_view(layout_keys: dict[str, str]) -> hv.ui.View:
|
|
| 241 |
layout=hv.ui.PanelLayout(height=260, min_height=180),
|
| 242 |
)
|
| 243 |
)
|
| 244 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 245 |
|
| 246 |
|
| 247 |
def main() -> None:
|
| 248 |
dataset, layout_keys = build_dataset()
|
| 249 |
print(f"Starting HyperView on {SPACE_HOST}:{SPACE_PORT}", flush=True)
|
| 250 |
-
hv.launch(
|
| 251 |
dataset,
|
| 252 |
host=SPACE_HOST,
|
| 253 |
port=SPACE_PORT,
|
| 254 |
open_browser=False,
|
| 255 |
view=build_demo_view(layout_keys),
|
|
|
|
|
|
|
| 256 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 257 |
|
| 258 |
|
| 259 |
if __name__ == "__main__":
|
|
|
|
| 1 |
#!/usr/bin/env python
|
| 2 |
+
"""HyperView Hello World: one dataset, three embedding geometries."""
|
| 3 |
|
| 4 |
from __future__ import annotations
|
| 5 |
|
| 6 |
import os
|
| 7 |
import re
|
| 8 |
+
import sys
|
| 9 |
from collections import Counter
|
| 10 |
from pathlib import Path
|
| 11 |
|
|
|
|
| 17 |
SPACE_HOST = "0.0.0.0"
|
| 18 |
SPACE_PORT = 7860
|
| 19 |
|
| 20 |
+
# Build the workspace and exit instead of serving it. This is how a Static
|
| 21 |
+
# Space is produced: build, exit, export.
|
| 22 |
+
BUILD_ONLY = os.environ.get("HYPERVIEW_BUILD_ONLY", "").lower() in {
|
| 23 |
+
"1",
|
| 24 |
+
"true",
|
| 25 |
+
"yes",
|
| 26 |
+
} or "--build-only" in sys.argv[1:]
|
| 27 |
+
|
| 28 |
+
DATASET_NAME = "hello_world_inat24_multigeometry"
|
| 29 |
HF_DATASET = "evendrow/inat24_tiny"
|
| 30 |
HF_SPLIT = "train"
|
| 31 |
SAMPLE_SEED = 42
|
|
|
|
| 43 |
"mollusks": 10,
|
| 44 |
}
|
| 45 |
SAMPLE_COUNT = sum(TARGET_SUPERCATEGORY_COUNTS.values())
|
| 46 |
+
IMAGE_MAX_SIZE = (1024, 1024)
|
| 47 |
+
INTRO_EXTENSION = Path(__file__).parent / ".hyperview" / "extensions" / "hello-world-intro"
|
| 48 |
|
| 49 |
EMBEDDING_LAYOUTS = [
|
| 50 |
{
|
| 51 |
"name": "CLIP",
|
| 52 |
"provider": "embed-anything",
|
| 53 |
"model": "openai/clip-vit-base-patch32",
|
| 54 |
+
"layouts": ["euclidean:3d", "spherical:3d"],
|
| 55 |
},
|
| 56 |
{
|
| 57 |
+
"name": "Hyper3-CLIP",
|
| 58 |
"provider": "hyper-models",
|
| 59 |
+
"model": "hyper3-clip-v0.5",
|
| 60 |
+
"layouts": ["poincare:2d"],
|
| 61 |
},
|
| 62 |
]
|
| 63 |
|
|
|
|
| 114 |
|
| 115 |
image = ImageOps.exif_transpose(image).convert("RGB")
|
| 116 |
image.thumbnail(IMAGE_MAX_SIZE, Image.Resampling.LANCZOS)
|
| 117 |
+
image.save(destination, format="JPEG", quality=92, optimize=True)
|
| 118 |
|
| 119 |
|
| 120 |
def existing_label_counts(dataset: hv.Dataset) -> Counter[str]:
|
|
|
|
| 219 |
return dataset, layout_keys
|
| 220 |
|
| 221 |
|
| 222 |
+
def geometry_title(name: str, layout: str) -> str:
|
| 223 |
+
geometry, _, dimension = layout.partition(":")
|
| 224 |
+
geometry_name = {
|
| 225 |
+
"euclidean": "Euclidean",
|
| 226 |
+
"spherical": "Spherical",
|
| 227 |
+
"poincare": "Hyperbolic · Poincare",
|
| 228 |
+
}.get(geometry, geometry.title())
|
| 229 |
+
return f"{name} · {geometry_name}{f' {dimension.upper()}' if dimension else ''}"
|
| 230 |
+
|
| 231 |
+
|
| 232 |
def build_demo_view(layout_keys: dict[str, str]) -> hv.ui.View:
|
| 233 |
"""Open the showcase on its three geometries, side by side.
|
| 234 |
|
|
|
|
| 237 |
though three layouts exist -- the one thing this demo is here to show.
|
| 238 |
"""
|
| 239 |
|
| 240 |
+
panels: list[hv.ui.Scatter | hv.ui.Samples | hv.ui.ExtensionPanel] = []
|
| 241 |
previous_id: str | None = None
|
| 242 |
for label, layout_key in layout_keys.items():
|
| 243 |
name, layout = label.split(":", 1)
|
| 244 |
panel = hv.ui.Scatter(
|
| 245 |
id=f"map-{layout.replace(':', '-')}",
|
| 246 |
+
title=geometry_title(name, layout),
|
| 247 |
layout_key=layout_key,
|
| 248 |
position="center",
|
| 249 |
reference_panel_id=previous_id,
|
|
|
|
| 261 |
layout=hv.ui.PanelLayout(height=260, min_height=180),
|
| 262 |
)
|
| 263 |
)
|
| 264 |
+
intro = hv.ui.ExtensionPanel(
|
| 265 |
+
id="hello-world-intro",
|
| 266 |
+
extension="hello-world-intro",
|
| 267 |
+
panel="hello-world-intro",
|
| 268 |
+
title="Start here",
|
| 269 |
+
position="right",
|
| 270 |
+
layout=hv.ui.PanelLayout(width=360, min_width=300, max_width=440),
|
| 271 |
+
props={
|
| 272 |
+
"sampleCount": SAMPLE_COUNT,
|
| 273 |
+
"dataset": "iNat24 Tiny",
|
| 274 |
+
"geometries": [
|
| 275 |
+
{"name": "Euclidean", "model": "CLIP", "dimension": "3D"},
|
| 276 |
+
{"name": "Spherical", "model": "CLIP", "dimension": "3D"},
|
| 277 |
+
{
|
| 278 |
+
"name": "Hyperbolic · Poincare",
|
| 279 |
+
"model": "Hyper3-CLIP",
|
| 280 |
+
"dimension": "2D",
|
| 281 |
+
},
|
| 282 |
+
],
|
| 283 |
+
},
|
| 284 |
+
)
|
| 285 |
+
panels.append(intro)
|
| 286 |
+
return hv.ui.View(*panels, active_panel=intro.id)
|
| 287 |
|
| 288 |
|
| 289 |
def main() -> None:
|
| 290 |
dataset, layout_keys = build_dataset()
|
| 291 |
print(f"Starting HyperView on {SPACE_HOST}:{SPACE_PORT}", flush=True)
|
| 292 |
+
session = hv.launch(
|
| 293 |
dataset,
|
| 294 |
host=SPACE_HOST,
|
| 295 |
port=SPACE_PORT,
|
| 296 |
open_browser=False,
|
| 297 |
view=build_demo_view(layout_keys),
|
| 298 |
+
extensions=[str(INTRO_EXTENSION)],
|
| 299 |
+
block=False,
|
| 300 |
)
|
| 301 |
+
if BUILD_ONLY:
|
| 302 |
+
print("Workspace built; stopping before serving (build-only).", flush=True)
|
| 303 |
+
return
|
| 304 |
+
session.wait()
|
| 305 |
|
| 306 |
|
| 307 |
if __name__ == "__main__":
|