system HF Staff commited on
Commit
565d41a
·
verified ·
1 Parent(s): 12f07a0

Deploy hyper3labs/HyperView from Hyper3Labs/hyperview-spaces@355e826

Browse files
.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.0.0
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
- # HyperView 1.0 mints a session token and rejects unauthenticated runtime
36
- # commands. A public Space has no way to hand visitors that token, so panel
37
- # creation and case switching 401 without this. It marks the server public:
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 - iNat24 Tiny Geometry Showcase
12
 
13
- This is the main HyperView demo Space. It shows the same taxonomy-backed image
14
- sample through multiple geometric views:
 
15
 
16
  - CLIP (`openai/clip-vit-base-patch32`) in Euclidean 3D
17
  - CLIP (`openai/clip-vit-base-patch32`) in spherical 3D
18
- - HyCoCLIP (`hycoclip-vit-s`) in Poincare 2D
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.0.0`
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 main Hugging Face Space geometry demo."""
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
- DATASET_NAME = "inat24_tiny_geometry_showcase"
 
 
 
 
 
 
 
 
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 = (768, 768)
 
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": "HyCoCLIP",
48
  "provider": "hyper-models",
49
- "model": "hycoclip-vit-s",
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=90, optimize=True)
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=f"{name} · {layout}",
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
- return hv.ui.View(*panels, active_panel=panels[0].id)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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__":