Spaces:
Running on Zero
Running on Zero
NLag commited on
Commit ·
29e24be
1
Parent(s): 43c7537
Set default exercise router repo
Browse files
README.md
CHANGED
|
@@ -265,8 +265,9 @@ comparison or fallback.
|
|
| 265 |
|
| 266 |
To publish and load the router from Hugging Face, use the setup notes in
|
| 267 |
[docs/huggingface-router-release.md](docs/huggingface-router-release.md). The draft model card is in
|
| 268 |
-
[docs/huggingface-router-model-card.md](docs/huggingface-router-model-card.md).
|
| 269 |
-
|
|
|
|
| 270 |
|
| 271 |
Custom unknown clips can be uploaded into the data volume at `/data/raw/custom_unknown/` before the
|
| 272 |
`features` stage. Use consented clips only; useful unknown examples include idle standing, walking
|
|
|
|
| 265 |
|
| 266 |
To publish and load the router from Hugging Face, use the setup notes in
|
| 267 |
[docs/huggingface-router-release.md](docs/huggingface-router-release.md). The draft model card is in
|
| 268 |
+
[docs/huggingface-router-model-card.md](docs/huggingface-router-model-card.md). Runtime loading uses
|
| 269 |
+
`build-small-hackathon/pozify-exercise-router` by default; set `POZIFY_ROUTER_HF_REPO_ID` only to
|
| 270 |
+
override it.
|
| 271 |
|
| 272 |
Custom unknown clips can be uploaded into the data volume at `/data/raw/custom_unknown/` before the
|
| 273 |
`features` stage. Use consented clips only; useful unknown examples include idle standing, walking
|
docs/huggingface-router-model-card.md
CHANGED
|
@@ -88,10 +88,11 @@ Summary:
|
|
| 88 |
|
| 89 |
## Runtime Loading
|
| 90 |
|
| 91 |
-
Pozify
|
|
|
|
| 92 |
|
| 93 |
```bash
|
| 94 |
-
export POZIFY_ROUTER_HF_REPO_ID=
|
| 95 |
```
|
| 96 |
|
| 97 |
For private repositories, authenticate with `hf auth login` or set `HF_TOKEN`.
|
|
|
|
| 88 |
|
| 89 |
## Runtime Loading
|
| 90 |
|
| 91 |
+
Pozify loads this repository by default. Set `POZIFY_ROUTER_HF_REPO_ID` only to override the default
|
| 92 |
+
with another compatible router repo:
|
| 93 |
|
| 94 |
```bash
|
| 95 |
+
export POZIFY_ROUTER_HF_REPO_ID=owner/other-pozify-router
|
| 96 |
```
|
| 97 |
|
| 98 |
For private repositories, authenticate with `hf auth login` or set `HF_TOKEN`.
|
docs/huggingface-router-release.md
CHANGED
|
@@ -15,7 +15,7 @@ Official references:
|
|
| 15 |
The configured model repository is:
|
| 16 |
|
| 17 |
```text
|
| 18 |
-
|
| 19 |
```
|
| 20 |
|
| 21 |
Create a user access token at:
|
|
@@ -53,7 +53,7 @@ Upload the model card and artifacts:
|
|
| 53 |
|
| 54 |
```bash
|
| 55 |
uv run python scripts/upload_exercise_router_to_hf.py \
|
| 56 |
-
--repo-id
|
| 57 |
--private
|
| 58 |
```
|
| 59 |
|
|
@@ -69,10 +69,11 @@ The upload script creates the repository if needed and uploads:
|
|
| 69 |
|
| 70 |
## Runtime Configuration
|
| 71 |
|
| 72 |
-
|
|
|
|
| 73 |
|
| 74 |
```bash
|
| 75 |
-
export POZIFY_ROUTER_HF_REPO_ID=
|
| 76 |
```
|
| 77 |
|
| 78 |
Optional:
|
|
@@ -82,8 +83,8 @@ export POZIFY_ROUTER_HF_REVISION=main
|
|
| 82 |
```
|
| 83 |
|
| 84 |
For private repositories, authenticate with `uv run hf auth login` or set `HF_TOKEN` before running
|
| 85 |
-
the app. The loader first tries Hugging Face
|
| 86 |
-
|
| 87 |
|
| 88 |
Disable Hub loading explicitly:
|
| 89 |
|
|
|
|
| 15 |
The configured model repository is:
|
| 16 |
|
| 17 |
```text
|
| 18 |
+
build-small-hackathon/pozify-exercise-router
|
| 19 |
```
|
| 20 |
|
| 21 |
Create a user access token at:
|
|
|
|
| 53 |
|
| 54 |
```bash
|
| 55 |
uv run python scripts/upload_exercise_router_to_hf.py \
|
| 56 |
+
--repo-id build-small-hackathon/pozify-exercise-router \
|
| 57 |
--private
|
| 58 |
```
|
| 59 |
|
|
|
|
| 69 |
|
| 70 |
## Runtime Configuration
|
| 71 |
|
| 72 |
+
The runtime loader uses `build-small-hackathon/pozify-exercise-router` by default. Override the
|
| 73 |
+
model repository ID only when you want to test or deploy a different router repo:
|
| 74 |
|
| 75 |
```bash
|
| 76 |
+
export POZIFY_ROUTER_HF_REPO_ID=owner/other-pozify-router
|
| 77 |
```
|
| 78 |
|
| 79 |
Optional:
|
|
|
|
| 83 |
```
|
| 84 |
|
| 85 |
For private repositories, authenticate with `uv run hf auth login` or set `HF_TOKEN` before running
|
| 86 |
+
the app. The loader first tries Hugging Face using the default repo or the override above. If Hub
|
| 87 |
+
loading fails, it falls back to local files under `models/exercise_router/active/`.
|
| 88 |
|
| 89 |
Disable Hub loading explicitly:
|
| 90 |
|
src/pozify/ml/exercise_router_inference.py
CHANGED
|
@@ -14,6 +14,7 @@ from pozify.ml.exercise_router_temporal import TorchTemporalRouter
|
|
| 14 |
|
| 15 |
DEFAULT_MODEL_DIR = Path("models/exercise_router/active")
|
| 16 |
ACTIVE_SELECTION_FILENAME = "router_selection.json"
|
|
|
|
| 17 |
HF_REPO_ID_ENV = "POZIFY_ROUTER_HF_REPO_ID"
|
| 18 |
HF_REVISION_ENV = "POZIFY_ROUTER_HF_REVISION"
|
| 19 |
HF_DISABLE_ENV = "POZIFY_ROUTER_DISABLE_HF"
|
|
@@ -84,7 +85,7 @@ def load_router_model_from_hf(
|
|
| 84 |
if _env_truthy(os.getenv(HF_DISABLE_ENV)):
|
| 85 |
return None
|
| 86 |
|
| 87 |
-
repo_id = repo_id or os.getenv(HF_REPO_ID_ENV)
|
| 88 |
if not repo_id:
|
| 89 |
return None
|
| 90 |
|
|
|
|
| 14 |
|
| 15 |
DEFAULT_MODEL_DIR = Path("models/exercise_router/active")
|
| 16 |
ACTIVE_SELECTION_FILENAME = "router_selection.json"
|
| 17 |
+
DEFAULT_HF_REPO_ID = "build-small-hackathon/pozify-exercise-router"
|
| 18 |
HF_REPO_ID_ENV = "POZIFY_ROUTER_HF_REPO_ID"
|
| 19 |
HF_REVISION_ENV = "POZIFY_ROUTER_HF_REVISION"
|
| 20 |
HF_DISABLE_ENV = "POZIFY_ROUTER_DISABLE_HF"
|
|
|
|
| 85 |
if _env_truthy(os.getenv(HF_DISABLE_ENV)):
|
| 86 |
return None
|
| 87 |
|
| 88 |
+
repo_id = repo_id or os.getenv(HF_REPO_ID_ENV) or DEFAULT_HF_REPO_ID
|
| 89 |
if not repo_id:
|
| 90 |
return None
|
| 91 |
|
tests/test_exercise_classifier.py
CHANGED
|
@@ -2,6 +2,7 @@ from __future__ import annotations
|
|
| 2 |
|
| 3 |
import json
|
| 4 |
import math
|
|
|
|
| 5 |
from pathlib import Path
|
| 6 |
import sys
|
| 7 |
import tempfile
|
|
@@ -22,6 +23,8 @@ from pozify.ml.exercise_router_features import (
|
|
| 22 |
window_vector_feature_names,
|
| 23 |
)
|
| 24 |
from pozify.ml.exercise_router_inference import (
|
|
|
|
|
|
|
| 25 |
RouterModelBundle,
|
| 26 |
WindowRouterPrediction,
|
| 27 |
aggregate_window_predictions,
|
|
@@ -210,7 +213,8 @@ class ExerciseRouterModelLoadingTests(unittest.TestCase):
|
|
| 210 |
encoding="utf-8",
|
| 211 |
)
|
| 212 |
|
| 213 |
-
|
|
|
|
| 214 |
|
| 215 |
self.assertIsNotNone(bundle)
|
| 216 |
assert bundle is not None
|
|
@@ -258,6 +262,43 @@ class ExerciseRouterModelLoadingTests(unittest.TestCase):
|
|
| 258 |
self.assertEqual(bundle.model_kind, "baseline")
|
| 259 |
self.assertEqual(bundle.labels, tuple(ROUTER_LABELS))
|
| 260 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 261 |
|
| 262 |
class ExerciseClassifierStepTests(unittest.TestCase):
|
| 263 |
def test_manual_override_bypasses_model_and_validates_contract(self) -> None:
|
|
@@ -274,12 +315,13 @@ class ExerciseClassifierStepTests(unittest.TestCase):
|
|
| 274 |
|
| 275 |
def test_missing_model_falls_back_to_unknown(self) -> None:
|
| 276 |
with tempfile.TemporaryDirectory() as temp_dir:
|
| 277 |
-
|
| 278 |
-
|
| 279 |
-
|
| 280 |
-
|
| 281 |
-
|
| 282 |
-
|
|
|
|
| 283 |
|
| 284 |
self.assertEqual(result.exercise, "unknown")
|
| 285 |
self.assertTrue(result.fallback_required)
|
|
|
|
| 2 |
|
| 3 |
import json
|
| 4 |
import math
|
| 5 |
+
import os
|
| 6 |
from pathlib import Path
|
| 7 |
import sys
|
| 8 |
import tempfile
|
|
|
|
| 23 |
window_vector_feature_names,
|
| 24 |
)
|
| 25 |
from pozify.ml.exercise_router_inference import (
|
| 26 |
+
DEFAULT_HF_REPO_ID,
|
| 27 |
+
HF_DISABLE_ENV,
|
| 28 |
RouterModelBundle,
|
| 29 |
WindowRouterPrediction,
|
| 30 |
aggregate_window_predictions,
|
|
|
|
| 213 |
encoding="utf-8",
|
| 214 |
)
|
| 215 |
|
| 216 |
+
with patch.dict(os.environ, {HF_DISABLE_ENV: "1"}):
|
| 217 |
+
bundle = load_router_model(model_dir)
|
| 218 |
|
| 219 |
self.assertIsNotNone(bundle)
|
| 220 |
assert bundle is not None
|
|
|
|
| 262 |
self.assertEqual(bundle.model_kind, "baseline")
|
| 263 |
self.assertEqual(bundle.labels, tuple(ROUTER_LABELS))
|
| 264 |
|
| 265 |
+
def test_hf_loader_defaults_to_pozify_router_repo(self) -> None:
|
| 266 |
+
with tempfile.TemporaryDirectory() as temp_dir:
|
| 267 |
+
model_dir = Path(temp_dir)
|
| 268 |
+
artifact_path = model_dir / "router.joblib"
|
| 269 |
+
selection_path = model_dir / "router_selection.json"
|
| 270 |
+
joblib.dump(
|
| 271 |
+
{
|
| 272 |
+
"model": _FakePushUpModel(),
|
| 273 |
+
"labels": list(ROUTER_LABELS),
|
| 274 |
+
"model_kind": "baseline",
|
| 275 |
+
},
|
| 276 |
+
artifact_path,
|
| 277 |
+
)
|
| 278 |
+
selection_path.write_text(
|
| 279 |
+
json.dumps({"selected_artifact": artifact_path.name}),
|
| 280 |
+
encoding="utf-8",
|
| 281 |
+
)
|
| 282 |
+
|
| 283 |
+
def fake_download(*, repo_id: str, filename: str, revision: str | None) -> Path:
|
| 284 |
+
self.assertEqual(repo_id, DEFAULT_HF_REPO_ID)
|
| 285 |
+
self.assertIsNone(revision)
|
| 286 |
+
return {"router_selection.json": selection_path, "router.joblib": artifact_path}[filename]
|
| 287 |
+
|
| 288 |
+
with (
|
| 289 |
+
patch.dict(os.environ, {}, clear=True),
|
| 290 |
+
patch(
|
| 291 |
+
"pozify.ml.exercise_router_inference._hf_hub_download",
|
| 292 |
+
side_effect=fake_download,
|
| 293 |
+
),
|
| 294 |
+
):
|
| 295 |
+
bundle = load_router_model_from_hf()
|
| 296 |
+
|
| 297 |
+
self.assertIsNotNone(bundle)
|
| 298 |
+
assert bundle is not None
|
| 299 |
+
self.assertEqual(bundle.model_kind, "baseline")
|
| 300 |
+
self.assertEqual(bundle.labels, tuple(ROUTER_LABELS))
|
| 301 |
+
|
| 302 |
|
| 303 |
class ExerciseClassifierStepTests(unittest.TestCase):
|
| 304 |
def test_manual_override_bypasses_model_and_validates_contract(self) -> None:
|
|
|
|
| 315 |
|
| 316 |
def test_missing_model_falls_back_to_unknown(self) -> None:
|
| 317 |
with tempfile.TemporaryDirectory() as temp_dir:
|
| 318 |
+
with patch.dict(os.environ, {HF_DISABLE_ENV: "1"}):
|
| 319 |
+
result = exercise_classifier.run(
|
| 320 |
+
_sequence("push_up"),
|
| 321 |
+
_profile("auto"),
|
| 322 |
+
mock=False,
|
| 323 |
+
model_dir=Path(temp_dir),
|
| 324 |
+
)
|
| 325 |
|
| 326 |
self.assertEqual(result.exercise, "unknown")
|
| 327 |
self.assertTrue(result.fallback_required)
|