Skip to content

Commit 67b5b5f

Browse files
committed
feat: add context and task documentation for hackathon participation
1 parent baacc8d commit 67b5b5f

File tree

5 files changed

+354
-1
lines changed

5 files changed

+354
-1
lines changed

.gitignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,6 @@ scripts_ignored/
6363

6464
# AI Context (Agent files)
6565
.claude/
66-
context/
6766
CLAUDE.md
6867
TASKS.md
6968
TESTS.md

context/BRIEF.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
- AGENT Convos are in: .specstory
2+
- nuscens_fixture md file has the
3+
-

context/TASK.md

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
We want to participate in the hackathon (we are already registered) by nvidia: https://luma.com/nvidia-cosmos-cookoff
2+
3+
4+
- in that page they mention the following:
5+
​Build something great with Cosmos Reason 2—post-train for a specialized reasoning model, a data curation tool, a robot brain that understands a new domain, or a video analytics agent.
6+
7+
- in the huggingface of cosmos reason they mention the following:
8+
Data curation and annotation — Enable developers to automate high-quality curation and annotation of massive, diverse training datasets. Experience NVIDIA Cosmos Curator, powered by Cosmos Reason, a framework that enables developers to quickly filter, annotate, and deduplicate large amounts of sensor data necessary for physical AI development.
9+
10+
- they also mention their own data curation pipeline
11+
this is the link: https://github.com/nvidia-cosmos/cosmos-curate (git cloned in ./cosmos-curate)
12+
13+
- another interesting thing is the video-search and summarization: https://github.com/NVIDIA-AI-Blueprints/video-search-and-summarization
14+
15+
- we build an opensource project called hyperview which is a dataset curation tool
16+
you can find it in ../HyperView (or https://github.com/Hyper3Labs/HyperView)
17+
- in thi repo nvidia-hyper, we have hard forked HyperView to align it with the hackathon.
18+
19+
- if necessary we have access to a slurm cluster with some H100s, if needed, let me know
20+
21+
22+
- I had a chance to ask them some questions:
23+
24+
Hi, thanks for offering this opportunity. Just had a 2 questions:
25+
26+
i) In the original description of the cookoff it was mentioned that a data curation tool could be something cool to build. can you elaborate on the data curation tool and what you had in mind regarding that. is it okay if we use cosmos-curate to do some parts of the curation?
27+
28+
ii) we would like to visualize the embeddings, is there a Cosmos 2 Embedding model? we are currently using Cosmos-Emebd1
29+
30+
thanks again!
31+
32+
33+
- this was their response:
34+
35+
1) You can use Cosmos Reason 2 as a component in your data processing pipeline. Cosmos reason is a VLM that can help you filter, label or annotate data. https://nvidia-cosmos.github.io/cosmos-cookbook/recipes/post_training/reason2/video_caption_vqa/post_training.html
36+
2)On top of it then, you can use Cosmos Curate and/or Cosmos Embed.
Lines changed: 231 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,231 @@
1+
# nuScenes Fixture Setup (Fresh Clone, Local Testing Only)
2+
3+
## Important: this is a fixture workflow
4+
5+
This guide creates a **local testing fixture** for HyperView.
6+
7+
- It is for **UI/API smoke testing and iteration**.
8+
- It is **not** a real Cosmos-Curate production run.
9+
- Captions/embeddings in the fixture are synthetic (generated by `scripts/create_nuscenes_fixture.py`).
10+
- Videos are built from local nuScenes camera frames to avoid solid-color test clips.
11+
12+
## Prerequisites
13+
14+
- macOS/Linux shell
15+
- `uv` installed
16+
- `node` + `npm` installed
17+
- `ffmpeg` installed (for frame->mp4 clip generation)
18+
- nuScenes mini data available under `~/nuscenes`
19+
- Must include:
20+
- `~/nuscenes/v1.0-mini`
21+
- `~/nuscenes/samples`
22+
- `~/nuscenes/sweeps`
23+
24+
Check quickly:
25+
26+
```bash
27+
ls -d ~/nuscenes/v1.0-mini ~/nuscenes/samples ~/nuscenes/sweeps
28+
```
29+
30+
If `ffmpeg` is missing on macOS:
31+
32+
```bash
33+
brew install ffmpeg
34+
```
35+
36+
## 1) Fresh clone + dependencies
37+
38+
```bash
39+
git clone <YOUR_FORK_OR_REPO_URL> nvidia-hyper
40+
cd nvidia-hyper
41+
42+
uv sync
43+
cd frontend
44+
npm install
45+
cd ..
46+
```
47+
48+
## 2) Build nuScenes source clips (real image frames -> mp4)
49+
50+
This creates `48` short clips from `~/nuscenes/sweeps/CAM_FRONT`:
51+
52+
```bash
53+
uv run python - <<'PY'
54+
import glob
55+
import os
56+
import shutil
57+
import subprocess
58+
from pathlib import Path
59+
60+
src_dir = Path.home() / 'nuscenes' / 'sweeps' / 'CAM_FRONT'
61+
out_dir = Path('/private/tmp/nuscenes_source_clips')
62+
work_root = Path('/private/tmp/nuscenes_frames_work')
63+
64+
num_clips = 48
65+
frames_per_clip = 20
66+
stride = 12
67+
fps = 10
68+
69+
if not src_dir.exists():
70+
raise SystemExit(f'Missing source dir: {src_dir}')
71+
72+
frames = sorted(glob.glob(str(src_dir / '*.jpg')))
73+
if len(frames) < frames_per_clip:
74+
raise SystemExit(f'Not enough frames: {len(frames)}')
75+
76+
out_dir.mkdir(parents=True, exist_ok=True)
77+
work_root.mkdir(parents=True, exist_ok=True)
78+
79+
for old in out_dir.glob('*.mp4'):
80+
old.unlink()
81+
82+
max_possible = 1 + (len(frames) - frames_per_clip) // stride
83+
clips_to_make = min(num_clips, max_possible)
84+
85+
for clip_idx in range(clips_to_make):
86+
start = clip_idx * stride
87+
chunk = frames[start:start + frames_per_clip]
88+
if len(chunk) < frames_per_clip:
89+
break
90+
91+
clip_work = work_root / f'clip_{clip_idx + 1:03d}'
92+
if clip_work.exists():
93+
shutil.rmtree(clip_work)
94+
clip_work.mkdir(parents=True, exist_ok=True)
95+
96+
for i, src in enumerate(chunk, start=1):
97+
dst = clip_work / f'{i:04d}.jpg'
98+
os.symlink(src, dst)
99+
100+
out_mp4 = out_dir / f'clip_{clip_idx + 1:03d}.mp4'
101+
subprocess.run(
102+
[
103+
'ffmpeg', '-y', '-v', 'error',
104+
'-framerate', str(fps),
105+
'-i', str(clip_work / '%04d.jpg'),
106+
'-vf', 'scale=640:360:force_original_aspect_ratio=decrease,pad=640:360:(ow-iw)/2:(oh-ih)/2',
107+
'-c:v', 'libx264', '-pix_fmt', 'yuv420p',
108+
str(out_mp4),
109+
],
110+
check=True,
111+
)
112+
113+
print(f'Created {len(list(out_dir.glob("*.mp4")))} clips in {out_dir}')
114+
PY
115+
```
116+
117+
## 3) Create the full fixture artifacts
118+
119+
This creates:
120+
121+
- `/private/tmp/nuscenes_fixture_real/split_output`
122+
- `/private/tmp/nuscenes_fixture_real/dedup_output`
123+
124+
```bash
125+
uv run python scripts/create_nuscenes_fixture.py \
126+
--source-clips-path /private/tmp/nuscenes_source_clips \
127+
--output-root /private/tmp/nuscenes_fixture_real \
128+
--num-clips 48 \
129+
--embedding-dim 256
130+
```
131+
132+
## 4) Run backend (fixed port `6263`)
133+
134+
```bash
135+
lsof -ti tcp:6263 | xargs -r kill -9
136+
137+
uv run python scripts/load_cosmos_curate.py \
138+
--split-output-path /private/tmp/nuscenes_fixture_real/split_output \
139+
--dataset-name nuscenes_fixture_real_live \
140+
--no-persist \
141+
--no-browser \
142+
--port 6263
143+
```
144+
145+
## 5) Run frontend (fixed port `3001`)
146+
147+
Open a second terminal:
148+
149+
```bash
150+
cd frontend
151+
PORT=3001 npm run dev -- --webpack
152+
```
153+
154+
Open:
155+
156+
- `http://127.0.0.1:3001`
157+
158+
## 6) Smoke-check that video serving works
159+
160+
In another terminal:
161+
162+
```bash
163+
uv run python - <<'PY'
164+
import json
165+
import os
166+
import urllib.request
167+
168+
base = 'http://127.0.0.1:6263'
169+
ds = json.load(urllib.request.urlopen(base + '/api/dataset'))
170+
print('dataset=', ds.get('name'))
171+
172+
samples = json.load(urllib.request.urlopen(base + '/api/samples?offset=0&limit=1')).get('samples', [])
173+
if not samples:
174+
raise SystemExit('No samples loaded')
175+
176+
sid = samples[0]['id']
177+
video = urllib.request.urlopen(base + f'/api/video/{sid}')
178+
print('video_status=', video.status, 'content_type=', video.headers.get('Content-Type'))
179+
180+
all_samples = json.load(urllib.request.urlopen(base + '/api/samples?offset=0&limit=500')).get('samples', [])
181+
missing = 0
182+
for sample in all_samples:
183+
metadata = sample.get('metadata') or {}
184+
path = metadata.get('video_path') or sample.get('filepath') or ''
185+
ok = isinstance(path, str) and path.endswith('.mp4') and os.path.exists(path)
186+
if not ok:
187+
missing += 1
188+
print('total=', len(all_samples), 'missing_video_paths=', missing)
189+
PY
190+
```
191+
192+
Expected:
193+
194+
- `dataset= nuscenes_fixture_real_live`
195+
- `video_status= 200`
196+
- `content_type= video/mp4`
197+
- `missing_video_paths= 0`
198+
199+
## Troubleshooting
200+
201+
### I still see solid-color videos
202+
203+
Most common causes:
204+
205+
1. Backend still points to old synthetic fixture (example: `/private/tmp/cookoff_fixture_256`).
206+
2. Browser has stale frontend state/cache.
207+
3. Another backend process is running on `6263`.
208+
209+
Fix:
210+
211+
```bash
212+
lsof -ti tcp:6263 | xargs -r kill -9
213+
```
214+
215+
Then restart backend with:
216+
217+
```bash
218+
uv run python scripts/load_cosmos_curate.py \
219+
--split-output-path /private/tmp/nuscenes_fixture_real/split_output \
220+
--dataset-name nuscenes_fixture_real_live \
221+
--no-persist \
222+
--no-browser \
223+
--port 6263
224+
```
225+
226+
Then hard refresh frontend (`Cmd+Shift+R`).
227+
228+
### I only have `v1.0-mini` JSON metadata, no images
229+
230+
You need the nuScenes media folders (`samples/`, `sweeps/`) under `~/nuscenes`.
231+
Without those, clip generation cannot run.

scripts/demo.py

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
#!/usr/bin/env python3
2+
"""Run HyperView demo with CIFAR-10 dataset."""
3+
4+
import argparse
5+
import os
6+
import sys
7+
from pathlib import Path
8+
9+
# Add src to path for development
10+
sys.path.insert(0, str(Path(__file__).parent.parent / "src"))
11+
12+
13+
def main():
14+
parser = argparse.ArgumentParser(description="Run HyperView demo")
15+
parser.add_argument(
16+
"--dataset",
17+
type=str,
18+
default="cifar10_demo",
19+
help="Dataset name to use for persistence (default: cifar10_demo)",
20+
)
21+
parser.add_argument(
22+
"--samples", type=int, default=50000, help="Number of samples to load (default: 50000)"
23+
)
24+
parser.add_argument(
25+
"--port", type=int, default=6263, help="Port to run server on (default: 6263)"
26+
)
27+
parser.add_argument(
28+
"--no-browser", action="store_true", help="Don't open browser automatically"
29+
)
30+
parser.add_argument(
31+
"--no-persist", action="store_true", help="Don't persist to database (use in-memory)"
32+
)
33+
parser.add_argument(
34+
"--model",
35+
type=str,
36+
default="openai/clip-vit-base-patch32",
37+
help=(
38+
"Embedding model_id to use (default: openai/clip-vit-base-patch32). "
39+
"This is passed to Dataset.compute_embeddings(model=...)."
40+
),
41+
)
42+
parser.add_argument(
43+
"--datasets-dir",
44+
"--database-dir",
45+
type=str,
46+
default=None,
47+
help="Override persistence directory (sets HYPERVIEW_DATASETS_DIR)",
48+
)
49+
parser.add_argument(
50+
"--no-server",
51+
action="store_true",
52+
help="Don't start the web server (useful for CI / DB checks)",
53+
)
54+
args = parser.parse_args()
55+
56+
if args.datasets_dir:
57+
os.environ["HYPERVIEW_DATASETS_DIR"] = args.datasets_dir
58+
59+
import hyperview as hv
60+
61+
dataset = hv.Dataset(args.dataset, persist=not args.no_persist)
62+
63+
dataset.add_from_huggingface(
64+
"uoft-cs/cifar10",
65+
split="train",
66+
image_key="img",
67+
label_key="label",
68+
max_samples=args.samples,
69+
)
70+
71+
space_key = dataset.compute_embeddings(model=args.model, show_progress=True)
72+
73+
# Compute a single layout for the UI to display by default.
74+
# Switch to geometry="euclidean" for standard 2D UMAP.
75+
dataset.compute_visualization(space_key=space_key, geometry="poincare")
76+
77+
if args.no_server:
78+
return
79+
80+
hv.launch(dataset, port=args.port, open_browser=not args.no_browser)
81+
82+
83+
if __name__ == "__main__":
84+
main()

0 commit comments

Comments
 (0)