Christen Millerdurai commited on
Commit
237ddb2
·
1 Parent(s): e319a3a

converted to gradio app

Browse files
.gitignore ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ __pycache__/
2
+ *.py[cod]
3
+ EgoForce/
4
+ .hf-download/
Dockerfile DELETED
@@ -1,72 +0,0 @@
1
- FROM nvidia/cuda:12.6.3-cudnn-devel-ubuntu22.04
2
-
3
- ARG DEBIAN_FRONTEND=noninteractive
4
- ARG PYTHON_VERSION=3.10
5
- ARG EGOFORCE_REPO_URL=https://github.com/dfki-av/EgoForce
6
- ARG EGOFORCE_REF=main
7
-
8
- ENV HOME=/home/user \
9
- APP_HOME=/home/user/app \
10
- EGOFORCE_ROOT=/home/user/app/EgoForce \
11
- PATH=/home/user/.local/bin:/home/user/.venv/bin:$PATH \
12
- PYTHONUNBUFFERED=1 \
13
- PIP_NO_CACHE_DIR=1 \
14
- PIP_DISABLE_PIP_VERSION_CHECK=1 \
15
- CUDA_HOME=/usr/local/cuda \
16
- FORCE_CUDA=1 \
17
- TORCH_CUDA_ARCH_LIST="7.5;8.0;8.6;8.9" \
18
- NVIDIA_VISIBLE_DEVICES=all \
19
- NVIDIA_DRIVER_CAPABILITIES=compute,utility,graphics \
20
- PYOPENGL_PLATFORM=egl \
21
- MPLBACKEND=Agg
22
-
23
- RUN apt-get update && apt-get install -y --no-install-recommends \
24
- python3.10 \
25
- python3.10-dev \
26
- python3-pip \
27
- python3.10-venv \
28
- git \
29
- curl \
30
- ca-certificates \
31
- ffmpeg \
32
- build-essential \
33
- cmake \
34
- ninja-build \
35
- pkg-config \
36
- libglib2.0-0 \
37
- libsm6 \
38
- libxext6 \
39
- libxrender1 \
40
- libgl1 \
41
- libglvnd0 \
42
- libegl1 \
43
- libglu1-mesa \
44
- libgl1-mesa-dev \
45
- libegl1-mesa-dev \
46
- libgles2-mesa-dev \
47
- libgl1-mesa-dri \
48
- && rm -rf /var/lib/apt/lists/*
49
-
50
- RUN ln -sf /usr/bin/python3.10 /usr/local/bin/python && \
51
- ln -sf /usr/bin/pip3 /usr/local/bin/pip
52
-
53
- RUN useradd -m -u 1000 user
54
- USER user
55
-
56
- WORKDIR $APP_HOME
57
-
58
- RUN python -m venv /home/user/.venv
59
-
60
- COPY --chown=user scripts/ $APP_HOME/scripts/
61
-
62
- RUN chmod +x $APP_HOME/scripts/install_egoforce.sh $APP_HOME/scripts/start.sh
63
-
64
- RUN git clone --depth 1 --branch "${EGOFORCE_REF}" "${EGOFORCE_REPO_URL}" "$EGOFORCE_ROOT"
65
-
66
- RUN bash $APP_HOME/scripts/install_egoforce.sh
67
-
68
- WORKDIR $EGOFORCE_ROOT
69
-
70
- EXPOSE 7860
71
-
72
- CMD ["bash", "/home/user/app/scripts/start.sh"]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
README.md CHANGED
@@ -3,8 +3,10 @@ title: EgoForce
3
  emoji: 🐠
4
  colorFrom: gray
5
  colorTo: purple
6
- sdk: docker
7
- app_port: 7860
 
 
8
  pinned: false
9
  license: cc-by-nc-4.0
10
  short_description: Forearm-Guided Camera-Space 3D Hand Pose
@@ -12,11 +14,12 @@ suggested_hardware: a10g-small
12
  startup_duration_timeout: 1h
13
  ---
14
 
15
- This Space builds a Docker image that:
16
 
17
- - Clones `EgoForce` Repo.
18
- - Installs the CUDA-enabled Python and system dependencies required by the demo
19
- - Downloads the `_DATA` model assets from `chris10/EgoForce` on the Hugging Face Hub
20
- - Launches `demo/run_app.py` on port `7860`
21
 
22
- The runtime is Docker-based because the EgoForce demo depends on CUDA, Torch-TensorRT, MMCV, ffmpeg, and headless rendering support.
 
 
 
 
 
3
  emoji: 🐠
4
  colorFrom: gray
5
  colorTo: purple
6
+ sdk: gradio
7
+ sdk_version: 6.9.0
8
+ python_version: "3.10"
9
+ app_file: app.py
10
  pinned: false
11
  license: cc-by-nc-4.0
12
  short_description: Forearm-Guided Camera-Space 3D Hand Pose
 
14
  startup_duration_timeout: 1h
15
  ---
16
 
17
+ This Space runs the EgoForce video demo with the Hugging Face Gradio SDK.
18
 
19
+ At startup, `app.py`:
 
 
 
20
 
21
+ - Clones `https://github.com/dfki-av/EgoForce` into the Space runtime.
22
+ - Downloads the `_DATA` model assets from `chris10/EgoForce` on the Hugging Face Hub.
23
+ - Launches the upstream Gradio demo at `demo/run_app.py`.
24
+
25
+ Most Python dependencies are declared in `requirements.txt`, with build prerequisites in `pre-requirements.txt`. Packages that need custom pip flags or repo-local subdirectories are installed by `app.py` after the EgoForce source checkout. Debian packages needed for OpenCV, ffmpeg, headless rendering, and compiled extensions are declared in `packages.txt`.
app.py ADDED
@@ -0,0 +1,204 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ import importlib.util
4
+ import os
5
+ import runpy
6
+ import shlex
7
+ import shutil
8
+ import site
9
+ import subprocess
10
+ import sys
11
+ from pathlib import Path
12
+
13
+ SPACE_ROOT = Path(__file__).resolve().parent
14
+ EGOFORCE_REPO_URL = os.environ.get("EGOFORCE_REPO_URL", "https://github.com/dfki-av/EgoForce")
15
+ EGOFORCE_REF = os.environ.get("EGOFORCE_REF", "main")
16
+ EGOFORCE_ROOT = Path(os.environ.get("EGOFORCE_ROOT", SPACE_ROOT / "EgoForce")).resolve()
17
+ EGOFORCE_ASSETS_REPO_ID = os.environ.get("EGOFORCE_ASSETS_REPO_ID", "chris10/EgoForce")
18
+
19
+
20
+ def run_command(command: list[str], cwd: Path | None = None) -> None:
21
+ print(f"+ {shlex.join(command)}", flush=True)
22
+ subprocess.run(command, cwd=str(cwd) if cwd else None, check=True)
23
+
24
+
25
+ def configure_runtime_environment() -> None:
26
+ os.environ.setdefault("EGOFORCE_ROOT", str(EGOFORCE_ROOT))
27
+ configure_cuda_environment()
28
+ os.environ.setdefault("FORCE_CUDA", "1")
29
+ os.environ.setdefault("TORCH_CUDA_ARCH_LIST", "7.5;8.0;8.6;8.9")
30
+ os.environ.setdefault("PYOPENGL_PLATFORM", "egl")
31
+ os.environ.setdefault("MPLBACKEND", "Agg")
32
+ os.environ.setdefault("TOKENIZERS_PARALLELISM", "false")
33
+
34
+
35
+ def candidate_site_packages() -> list[Path]:
36
+ paths = [Path(path) for path in site.getsitepackages()]
37
+ user_site = site.getusersitepackages()
38
+ if user_site:
39
+ paths.append(Path(user_site))
40
+ return paths
41
+
42
+
43
+ def find_python_cuda_home() -> Path | None:
44
+ for site_packages in candidate_site_packages():
45
+ cuda_home = site_packages / "nvidia" / "cuda_nvcc"
46
+ if (cuda_home / "bin" / "nvcc").exists():
47
+ return cuda_home
48
+ return None
49
+
50
+
51
+ def configure_cuda_environment() -> None:
52
+ current_cuda_home = os.environ.get("CUDA_HOME")
53
+ if current_cuda_home and (Path(current_cuda_home) / "bin" / "nvcc").exists():
54
+ cuda_home = Path(current_cuda_home)
55
+ else:
56
+ cuda_home = find_python_cuda_home() or Path(current_cuda_home or "/usr/local/cuda")
57
+ os.environ["CUDA_HOME"] = str(cuda_home)
58
+
59
+ cuda_bin = cuda_home / "bin"
60
+ if cuda_bin.exists():
61
+ os.environ["PATH"] = f"{cuda_bin}:{os.environ.get('PATH', '')}"
62
+
63
+
64
+ def ensure_egoforce_repo() -> Path:
65
+ demo_entrypoint = EGOFORCE_ROOT / "demo" / "run_app.py"
66
+ if demo_entrypoint.exists():
67
+ return EGOFORCE_ROOT
68
+
69
+ if EGOFORCE_ROOT.exists() and any(EGOFORCE_ROOT.iterdir()):
70
+ raise RuntimeError(
71
+ f"{EGOFORCE_ROOT} exists, but demo/run_app.py was not found. "
72
+ "Delete that directory or set EGOFORCE_ROOT to a clean location."
73
+ )
74
+
75
+ EGOFORCE_ROOT.parent.mkdir(parents=True, exist_ok=True)
76
+ command = ["git", "clone", "--depth", "1"]
77
+ if EGOFORCE_REF:
78
+ command.extend(["--branch", EGOFORCE_REF])
79
+ command.extend([EGOFORCE_REPO_URL, str(EGOFORCE_ROOT)])
80
+ run_command(command)
81
+
82
+ if (EGOFORCE_ROOT / ".gitmodules").exists():
83
+ run_command(["git", "submodule", "update", "--init", "--recursive"], cwd=EGOFORCE_ROOT)
84
+
85
+ if not demo_entrypoint.exists():
86
+ raise RuntimeError(f"EgoForce demo entrypoint not found at {demo_entrypoint}")
87
+
88
+ return EGOFORCE_ROOT
89
+
90
+
91
+ def package_available(module_name: str) -> bool:
92
+ return importlib.util.find_spec(module_name) is not None
93
+
94
+
95
+ def pip_install(requirement: str, *extra_args: str) -> None:
96
+ command = [
97
+ sys.executable,
98
+ "-m",
99
+ "pip",
100
+ "install",
101
+ "--no-cache-dir",
102
+ requirement,
103
+ *extra_args,
104
+ ]
105
+ run_command(command)
106
+
107
+
108
+ def ensure_runtime_python_packages(repo_root: Path) -> None:
109
+ datapipes_path = repo_root / "thirdparty" / "datapipes"
110
+ install_plan = [
111
+ ("mmcv", "mmcv==2.1.0", ("--no-build-isolation",)),
112
+ ("anycalib", "git+https://github.com/javrtg/AnyCalib.git", ("--no-build-isolation",)),
113
+ ("chumpy", "git+https://github.com/mattloper/chumpy.git", ("--no-build-isolation",)),
114
+ ("pytorch3d", "git+https://github.com/facebookresearch/pytorch3d.git", ("--no-build-isolation",)),
115
+ ("datapipes", str(datapipes_path), ()),
116
+ ("mmdet", str(repo_root / "thirdparty" / "mmdetection"), ("--no-build-isolation",)),
117
+ ]
118
+
119
+ for module_name, requirement, extra_args in install_plan:
120
+ if package_available(module_name):
121
+ continue
122
+ pip_install(requirement, *extra_args)
123
+
124
+
125
+ def validate_assets(repo_root: Path) -> None:
126
+ data_dir = repo_root / "_DATA"
127
+ required_paths = [
128
+ data_dir / "model_weights.pth",
129
+ data_dir / "epoch_460.pth",
130
+ data_dir / "detector.torchscript",
131
+ data_dir / "mano",
132
+ data_dir / "models" / "param_data.npy",
133
+ ]
134
+ missing = [str(path) for path in required_paths if not path.exists()]
135
+ if missing:
136
+ raise RuntimeError(f"Missing required EgoForce assets: {missing}")
137
+
138
+
139
+ def ensure_egoforce_assets(repo_root: Path) -> None:
140
+ from huggingface_hub import snapshot_download
141
+
142
+ try:
143
+ validate_assets(repo_root)
144
+ print(f"Using existing EgoForce assets at {repo_root / '_DATA'}", flush=True)
145
+ return
146
+ except RuntimeError:
147
+ pass
148
+
149
+ target_data_dir = repo_root / "_DATA"
150
+ cache_root = repo_root / ".hf-download"
151
+
152
+ if cache_root.exists():
153
+ shutil.rmtree(cache_root)
154
+
155
+ print(f"Downloading EgoForce assets from {EGOFORCE_ASSETS_REPO_ID}", flush=True)
156
+ snapshot_path = Path(
157
+ snapshot_download(
158
+ repo_id=EGOFORCE_ASSETS_REPO_ID,
159
+ repo_type="model",
160
+ allow_patterns=["_DATA/**"],
161
+ local_dir=cache_root,
162
+ )
163
+ )
164
+ source_data_dir = snapshot_path / "_DATA"
165
+ if not source_data_dir.exists():
166
+ raise RuntimeError(f"Downloaded snapshot did not contain {source_data_dir}")
167
+
168
+ shutil.copytree(source_data_dir, target_data_dir, dirs_exist_ok=True)
169
+ shutil.rmtree(cache_root, ignore_errors=True)
170
+ validate_assets(repo_root)
171
+ print(f"Downloaded EgoForce assets to {target_data_dir}", flush=True)
172
+
173
+
174
+ def launch_upstream_gradio(repo_root: Path) -> None:
175
+ demo_entrypoint = repo_root / "demo" / "run_app.py"
176
+ server_name = os.environ.get("GRADIO_SERVER_NAME", "0.0.0.0")
177
+ server_port = os.environ.get("PORT") or os.environ.get("GRADIO_SERVER_PORT") or "7860"
178
+
179
+ os.chdir(repo_root)
180
+ sys.path.insert(0, str(repo_root))
181
+ sys.argv = [
182
+ str(demo_entrypoint),
183
+ "--server-name",
184
+ server_name,
185
+ "--server-port",
186
+ str(server_port),
187
+ ]
188
+
189
+ if os.environ.get("GRADIO_SHARE", "").lower() in {"1", "true", "yes"}:
190
+ sys.argv.append("--share")
191
+
192
+ runpy.run_path(str(demo_entrypoint), run_name="__main__")
193
+
194
+
195
+ def main() -> None:
196
+ configure_runtime_environment()
197
+ repo_root = ensure_egoforce_repo()
198
+ ensure_runtime_python_packages(repo_root)
199
+ ensure_egoforce_assets(repo_root)
200
+ launch_upstream_gradio(repo_root)
201
+
202
+
203
+ if __name__ == "__main__":
204
+ main()
packages.txt ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ git
2
+ git-lfs
3
+ curl
4
+ ca-certificates
5
+ ffmpeg
6
+ build-essential
7
+ cmake
8
+ ninja-build
9
+ pkg-config
10
+ python3-dev
11
+ libglib2.0-0
12
+ libsm6
13
+ libxext6
14
+ libxrender1
15
+ libgl1
16
+ libglvnd0
17
+ libegl1
18
+ libglu1-mesa
19
+ libgl1-mesa-dev
20
+ libegl1-mesa-dev
21
+ libgles2-mesa-dev
22
+ libgl1-mesa-dri
pre-requirements.txt ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ pip>=25.0
2
+ setuptools==81.0.0
3
+ wheel
4
+ cython
5
+ pybind11
6
+ packaging
7
+ ninja
requirements.txt ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --extra-index-url https://download.pytorch.org/whl/cu126
2
+ --find-links https://download.pytorch.org/whl/torch-tensorrt
3
+
4
+ numpy==1.26.4
5
+ torch==2.8.0
6
+ torchvision==0.23.0
7
+ torch_tensorrt==2.8.0+cu126
8
+ nvidia-cuda-nvcc-cu12==12.6.*
9
+ opencv-python==4.11.0.86
10
+ pillow==11.3.0
11
+ matplotlib==3.10.6
12
+ pyyaml==6.0.2
13
+ easydict==1.13
14
+ h5py==3.15.1
15
+ tqdm==4.67.1
16
+ aiofiles==24.1.0
17
+ async-lru==2.0.5
18
+ timm==1.0.20
19
+ smplx==0.1.28
20
+ addict==2.4.0
21
+ pycocotools==2.0.10
22
+ trimesh==4.11.3
23
+ sortedcontainers==2.4.0
24
+ openmim==0.3.9
25
+ lmdb==2.0.0
26
+ ultralytics==8.4.23
27
+ lap==0.5.13
28
+ pyrender==0.1.45
29
+ fvcore==0.1.5.post20221221
30
+ iopath==0.1.10
31
+ yacs==0.1.8
32
+ projectaria_client_sdk==1.1.0
33
+ huggingface_hub
34
+ hf_xet
scripts/__pycache__/download_egoforce_data.cpython-313.pyc DELETED
Binary file (1.77 kB)
 
scripts/download_egoforce_data.py DELETED
@@ -1,41 +0,0 @@
1
- from __future__ import annotations
2
-
3
- import os
4
- import shutil
5
- from pathlib import Path
6
-
7
- from huggingface_hub import snapshot_download
8
-
9
-
10
- def main() -> None:
11
- repo_root = Path(os.environ["EGOFORCE_ROOT"]).resolve()
12
- target_data_dir = repo_root / "_DATA"
13
- cache_root = repo_root / ".hf-download"
14
-
15
- if target_data_dir.exists():
16
- print(f"Using existing EgoForce assets at {target_data_dir}")
17
- return
18
-
19
- if cache_root.exists():
20
- shutil.rmtree(cache_root)
21
-
22
- snapshot_path = Path(
23
- snapshot_download(
24
- repo_id=os.environ.get("EGOFORCE_ASSETS_REPO_ID", "chris10/EgoForce"),
25
- repo_type="model",
26
- allow_patterns=["_DATA/**"],
27
- local_dir=cache_root,
28
- )
29
- )
30
- source_data_dir = snapshot_path / "_DATA"
31
-
32
- if not source_data_dir.exists():
33
- raise SystemExit(f"Downloaded snapshot did not contain {source_data_dir}")
34
-
35
- shutil.copytree(source_data_dir, target_data_dir)
36
- shutil.rmtree(cache_root, ignore_errors=True)
37
- print(f"Downloaded EgoForce assets to {target_data_dir}")
38
-
39
-
40
- if __name__ == "__main__":
41
- main()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
scripts/install_egoforce.sh DELETED
@@ -1,44 +0,0 @@
1
- #!/usr/bin/env bash
2
- set -euxo pipefail
3
-
4
- : "${EGOFORCE_ROOT:?EGOFORCE_ROOT must be set}"
5
-
6
- cd "$EGOFORCE_ROOT"
7
-
8
- python -m pip install --upgrade pip setuptools==81.0.0 wheel cython pybind11
9
- python -m pip install torch==2.8.0 torchvision==0.23.0 --index-url https://download.pytorch.org/whl/cu126
10
- python -m pip install torch_tensorrt==2.8.0+cu126 --find-links https://download.pytorch.org/whl/torch-tensorrt
11
- python -m pip install -r scripts/requirements.txt
12
- python -m pip install mmcv==2.1.0 --no-build-isolation
13
-
14
- python -m pip install git+https://github.com/javrtg/AnyCalib.git --no-build-isolation
15
- python -m pip install git+https://github.com/mattloper/chumpy.git --no-build-isolation
16
- python -m pip install git+https://github.com/facebookresearch/pytorch3d.git --no-build-isolation
17
-
18
- python -m pip install ./thirdparty/datapipes
19
- python -m pip install ./thirdparty/mmdetection --no-build-isolation
20
-
21
- python -m pip install projectaria_client_sdk==1.1.0 --no-cache-dir
22
- python -m pip install huggingface_hub hf_xet
23
-
24
- python /home/user/app/scripts/download_egoforce_data.py
25
-
26
- python - <<'PY'
27
- from pathlib import Path
28
-
29
- repo_root = Path.cwd()
30
- required_paths = [
31
- repo_root / "_DATA" / "model_weights.pth",
32
- repo_root / "_DATA" / "epoch_460.pth",
33
- repo_root / "_DATA" / "detector.torchscript",
34
- repo_root / "_DATA" / "mano",
35
- ]
36
-
37
- missing = [str(path) for path in required_paths if not path.exists()]
38
- if missing:
39
- raise SystemExit(f"Missing required EgoForce assets after download: {missing}")
40
-
41
- print("Verified EgoForce assets in", repo_root / "_DATA")
42
- PY
43
-
44
- python -m pip install numpy==1.26.4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
scripts/start.sh DELETED
@@ -1,20 +0,0 @@
1
- #!/usr/bin/env bash
2
- set -euo pipefail
3
-
4
- : "${EGOFORCE_ROOT:?EGOFORCE_ROOT must be set}"
5
-
6
- cd "$EGOFORCE_ROOT"
7
-
8
- if [[ ! -f demo/run_app.py ]]; then
9
- echo "EgoForce demo entrypoint not found at $EGOFORCE_ROOT/demo/run_app.py" >&2
10
- exit 1
11
- fi
12
-
13
- if [[ ! -d _DATA ]]; then
14
- echo "EgoForce _DATA directory is missing at $EGOFORCE_ROOT/_DATA" >&2
15
- exit 1
16
- fi
17
-
18
- exec python demo/run_app.py \
19
- --server-name 0.0.0.0 \
20
- --server-port "${PORT:-7860}"