omnius 1.0.679 → 1.0.681

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -234,6 +234,7 @@ The same surface drives the **Generate** tab in the web UI (`http://127.0.0.1:11
234
234
  - `/indicator` reconciles daemon ownership and health before launching the tray; the tray polls every 10 seconds and turns its version row into a retryable verified-update action only when an update exists.
235
235
  - Dashboard, tray, and TUI update actions now share an exact-version global transaction with live phase/output and package, executable, daemon, hash, restart, and tray verification.
236
236
  - TTS exposes GLaDOS, Overwatch, `luxtts:announcer-testchamber03`, and configurable Voicebox models; ASR independently exposes Whisper, managed `transcribe-cli`, Nemotron readiness, and pinned Microsoft VibeVoice ASR with Jetson/ARM64 CUDA-aware setup.
237
+ - LuxTTS auto-setup on Jetson ARM64 requires CPU ONNX Runtime at import time, validates CUDA Torch separately against the host runtime, preserves existing caches during repair, and never substitutes generic PyPI Torch or automatic sudo for an AGX Orin deployment.
237
238
  - `/realtime` and REST `realtime: true` provide short, natural, SOUL.md-aware conversation for ASR/TTS clients.
238
239
  - Endpoint setup and sponsor setup aggregate models from all enabled endpoints, including external OpenAI-compatible routers.
239
240
  - `/sponsor` can expose text inference and media generation for image, video, sound, and music with per-modality limits.
@@ -0,0 +1,306 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ detect-torch.py — Reusable PyTorch version and install URL detection.
4
+
5
+ Detects the current platform/architecture/GPU environment and outputs
6
+ the correct pip install arguments for PyTorch + torchaudio.
7
+
8
+ Supports:
9
+ - x86_64 Linux with NVIDIA CUDA (cu118, cu121, cu124)
10
+ - x86_64 Linux CPU-only
11
+ - aarch64 Linux (ARM) CPU-only
12
+ - aarch64 Linux Jetson (NVIDIA GPU via JetPack wheels)
13
+ - macOS x86_64 (CPU)
14
+ - macOS arm64 / Apple Silicon (MPS via default PyPI)
15
+ - Windows x86_64 (CUDA or CPU)
16
+
17
+ Output: JSON to stdout with fields:
18
+ {
19
+ "platform": "linux",
20
+ "arch": "x86_64" | "aarch64" | "arm64",
21
+ "accelerator": "cuda" | "mps" | "cpu",
22
+ "cuda_version": "12.4" | null,
23
+ "is_jetson": false,
24
+ "pip_args": ["torch", "torchaudio", "--index-url", "..."],
25
+ "pip_args_str": "torch torchaudio --index-url ...",
26
+ "description": "x86_64 Linux CUDA 12.4"
27
+ }
28
+
29
+ Usage from shell:
30
+ python3 scripts/detect-torch.py
31
+ python3 scripts/detect-torch.py --pip-args # just the pip install args
32
+ python3 scripts/detect-torch.py --index-url # just the --index-url value
33
+
34
+ Usage from Node.js (via child_process):
35
+ const result = execSync('python3 scripts/detect-torch.py').toString();
36
+ const spec = JSON.parse(result);
37
+ await shell(`pip install ${spec.pip_args_str}`);
38
+
39
+ Derived from hydra/service_router/.services/depth_any/app.py bootstrap logic.
40
+ """
41
+
42
+ import json
43
+ import os
44
+ import platform
45
+ import subprocess
46
+ import sys
47
+ from pathlib import Path
48
+
49
+
50
+ def detect_cuda_version():
51
+ """Detect NVIDIA CUDA version from nvidia-smi or nvcc."""
52
+ # Try nvidia-smi first (works even without nvcc)
53
+ try:
54
+ result = subprocess.run(
55
+ ["nvidia-smi", "--query-gpu=driver_version", "--format=csv,noheader,nounits"],
56
+ capture_output=True, text=True, timeout=5
57
+ )
58
+ if result.returncode == 0:
59
+ # nvidia-smi works — now get CUDA version
60
+ result2 = subprocess.run(
61
+ ["nvidia-smi"],
62
+ capture_output=True, text=True, timeout=5
63
+ )
64
+ if result2.returncode == 0:
65
+ import re
66
+ match = re.search(r"CUDA Version:\s*(\d+\.\d+)", result2.stdout)
67
+ if match:
68
+ return match.group(1)
69
+ except Exception:
70
+ pass
71
+
72
+ # Try nvcc (Jetson, or systems with CUDA toolkit)
73
+ try:
74
+ result = subprocess.run(
75
+ ["nvcc", "--version"],
76
+ capture_output=True, text=True, timeout=5
77
+ )
78
+ if result.returncode == 0:
79
+ import re
80
+ match = re.search(r"release (\d+\.\d+)", result.stdout)
81
+ if match:
82
+ return match.group(1)
83
+ except Exception:
84
+ pass
85
+
86
+ return None
87
+
88
+
89
+ def is_jetson():
90
+ """Detect NVIDIA Jetson (aarch64 + /etc/nv_tegra_release)."""
91
+ return (
92
+ platform.machine().lower() in ("aarch64", "arm64")
93
+ and Path("/etc/nv_tegra_release").exists()
94
+ )
95
+
96
+
97
+ def jetson_torch_wheel_url():
98
+ """Find the best Jetson PyTorch wheel URL from NVIDIA's index."""
99
+ import re
100
+ import urllib.request
101
+
102
+ py_tag = f"cp{sys.version_info.major}{sys.version_info.minor}"
103
+
104
+ # Check env override first
105
+ env_wheel = os.environ.get("JETSON_TORCH_WHEEL")
106
+ if env_wheel:
107
+ return env_wheel
108
+
109
+ # Try NVIDIA's Jetson wheel index
110
+ release_text = ""
111
+ try:
112
+ release_text = Path("/etc/nv_tegra_release").read_text()
113
+ except Exception:
114
+ pass
115
+
116
+ # Determine JetPack version -> index URL
117
+ indexes = []
118
+ if "R36" in release_text and "REVISION: 4" in release_text:
119
+ indexes.extend([
120
+ "https://developer.download.nvidia.com/compute/redist/jp/v61",
121
+ "https://developer.download.nvidia.com/compute/redist/jp/v60",
122
+ ])
123
+ elif "R36" in release_text:
124
+ indexes.append("https://developer.download.nvidia.com/compute/redist/jp/v60")
125
+ elif "R35" in release_text:
126
+ indexes.append("https://developer.download.nvidia.com/compute/redist/jp/v51")
127
+ else:
128
+ indexes.extend([
129
+ "https://developer.download.nvidia.com/compute/redist/jp/v60",
130
+ "https://developer.download.nvidia.com/compute/redist/jp/v51",
131
+ ])
132
+
133
+ for idx_url in indexes:
134
+ try:
135
+ with urllib.request.urlopen(f"{idx_url}/pytorch/", timeout=10) as resp:
136
+ html = resp.read().decode("utf-8", "ignore")
137
+ pattern = rf'href="(torch-([0-9a-zA-Z\\.\\+]+)\\.nv[^"]*{py_tag}[^"]*linux_aarch64\\.whl)"'
138
+ matches = re.findall(pattern, html)
139
+ best = None
140
+ for fname, ver in matches:
141
+ base_ver = ver.split("+")[0]
142
+ parts = tuple(int(x) for x in base_ver.split(".")[:3] if x.isdigit())
143
+ if best is None or parts > best[0]:
144
+ best = (parts, fname, base_ver)
145
+ if best:
146
+ return f"{idx_url}/pytorch/{best[1]}"
147
+ except Exception:
148
+ continue
149
+
150
+ return None
151
+
152
+
153
+ def detect_torch_spec():
154
+ """Detect the optimal PyTorch install spec for this system."""
155
+ machine = platform.machine().lower()
156
+ system = platform.system().lower()
157
+
158
+ spec = {
159
+ "platform": system,
160
+ "arch": machine,
161
+ "accelerator": "cpu",
162
+ "cuda_version": None,
163
+ "is_jetson": False,
164
+ "pip_args": [],
165
+ "pip_args_str": "",
166
+ "torchaudio_version": None,
167
+ "error": None,
168
+ "description": "",
169
+ }
170
+
171
+ # ── macOS ──────────────────────────────────────────────────────────
172
+ if system == "darwin":
173
+ if machine in ("arm64", "aarch64"):
174
+ # Apple Silicon — MPS acceleration via default PyPI wheels
175
+ spec["accelerator"] = "mps"
176
+ spec["pip_args"] = ["torch", "torchaudio"]
177
+ spec["description"] = "macOS Apple Silicon (MPS)"
178
+ else:
179
+ # Intel Mac — CPU only
180
+ spec["pip_args"] = ["torch", "torchaudio"]
181
+ spec["description"] = "macOS Intel (CPU)"
182
+ spec["pip_args_str"] = " ".join(spec["pip_args"])
183
+ return spec
184
+
185
+ # ── Windows ────────────────────────────────────────────────────────
186
+ if system == "windows":
187
+ cuda_ver = detect_cuda_version()
188
+ if cuda_ver:
189
+ spec["accelerator"] = "cuda"
190
+ spec["cuda_version"] = cuda_ver
191
+ major_minor = cuda_ver.split(".")
192
+ cu_tag = f"cu{major_minor[0]}{major_minor[1]}" if len(major_minor) >= 2 else "cu124"
193
+ spec["pip_args"] = ["torch", "torchaudio", "--index-url", f"https://download.pytorch.org/whl/{cu_tag}"]
194
+ spec["description"] = f"Windows CUDA {cuda_ver}"
195
+ else:
196
+ spec["pip_args"] = ["torch", "torchaudio", "--index-url", "https://download.pytorch.org/whl/cpu"]
197
+ spec["description"] = "Windows CPU"
198
+ spec["pip_args_str"] = " ".join(spec["pip_args"])
199
+ return spec
200
+
201
+ # ── Linux ──────────────────────────────────────────────────────────
202
+
203
+ # Check for Jetson first (aarch64 + NVIDIA GPU via JetPack)
204
+ if is_jetson():
205
+ spec["is_jetson"] = True
206
+ spec["accelerator"] = "cuda"
207
+ spec["cuda_version"] = detect_cuda_version()
208
+
209
+ wheel_url = jetson_torch_wheel_url()
210
+ if wheel_url:
211
+ # Jetson needs wheel URL directly (not index-url)
212
+ spec["pip_args"] = [wheel_url]
213
+ spec["pip_args_str"] = wheel_url
214
+ import re
215
+ version_match = re.search(r"/torch-(\d+)\.(\d+)", wheel_url)
216
+ if version_match:
217
+ spec["torchaudio_version"] = f"{version_match.group(1)}.{version_match.group(2)}.0"
218
+ spec["description"] = f"Jetson aarch64 CUDA {spec['cuda_version'] or '?'} (JetPack wheel)"
219
+ else:
220
+ # Generic PyPI ARM Torch is not a JetPack ABI contract. Fail
221
+ # closed instead of installing a wheel that can report an old or
222
+ # insufficient driver on otherwise healthy Orin hardware.
223
+ spec["error"] = (
224
+ "No environment-matched NVIDIA Jetson Torch wheel was found. "
225
+ "Set JETSON_TORCH_WHEEL to an exact wheel for this L4T, CUDA, "
226
+ "Python ABI, and architecture."
227
+ )
228
+ spec["description"] = f"Jetson aarch64 CUDA {spec['cuda_version'] or '?'} (unsupported until an exact wheel is supplied)"
229
+ return spec
230
+
231
+ # Non-Jetson aarch64 (ARM server, Raspberry Pi, etc.)
232
+ if machine in ("aarch64", "arm64", "armv7l"):
233
+ cuda_ver = detect_cuda_version()
234
+ if cuda_ver:
235
+ spec["accelerator"] = "cuda"
236
+ spec["cuda_version"] = cuda_ver
237
+ # ARM + CUDA (e.g., Grace Hopper) — use generic pip (PyTorch publishes aarch64+cuda wheels on PyPI)
238
+ spec["pip_args"] = ["torch", "torchaudio"]
239
+ spec["description"] = f"Linux aarch64 CUDA {cuda_ver}"
240
+ else:
241
+ # ARM CPU — PyTorch publishes aarch64 CPU wheels on PyPI since 2.0+
242
+ # Do NOT use --index-url whl/cpu (no aarch64 there)
243
+ spec["pip_args"] = ["torch", "torchaudio"]
244
+ spec["description"] = "Linux aarch64 CPU"
245
+ spec["pip_args_str"] = " ".join(spec["pip_args"])
246
+ return spec
247
+
248
+ # x86_64 Linux
249
+ cuda_ver = detect_cuda_version()
250
+ if cuda_ver:
251
+ spec["accelerator"] = "cuda"
252
+ spec["cuda_version"] = cuda_ver
253
+ # Map CUDA version to PyTorch index tag
254
+ major = int(cuda_ver.split(".")[0])
255
+ minor = int(cuda_ver.split(".")[1]) if "." in cuda_ver else 0
256
+ if major >= 12 and minor >= 4:
257
+ cu_tag = "cu124"
258
+ elif major >= 12 and minor >= 1:
259
+ cu_tag = "cu121"
260
+ elif major >= 11 and minor >= 8:
261
+ cu_tag = "cu118"
262
+ else:
263
+ cu_tag = "cu121" # default fallback
264
+ spec["pip_args"] = ["torch", "torchaudio", "--index-url", f"https://download.pytorch.org/whl/{cu_tag}"]
265
+ spec["description"] = f"Linux x86_64 CUDA {cuda_ver} ({cu_tag})"
266
+ else:
267
+ spec["pip_args"] = ["torch", "torchaudio", "--index-url", "https://download.pytorch.org/whl/cpu"]
268
+ spec["description"] = "Linux x86_64 CPU"
269
+
270
+ spec["pip_args_str"] = " ".join(spec["pip_args"])
271
+ return spec
272
+
273
+
274
+ def main():
275
+ spec = detect_torch_spec()
276
+
277
+ if len(sys.argv) > 1:
278
+ flag = sys.argv[1]
279
+ if flag == "--pip-args":
280
+ print(spec["pip_args_str"])
281
+ return
282
+ elif flag == "--index-url":
283
+ for i, arg in enumerate(spec["pip_args"]):
284
+ if arg == "--index-url" and i + 1 < len(spec["pip_args"]):
285
+ print(spec["pip_args"][i + 1])
286
+ return
287
+ print("") # no index-url (use default PyPI)
288
+ return
289
+ elif flag == "--description":
290
+ print(spec["description"])
291
+ return
292
+ elif flag == "--accelerator":
293
+ print(spec["accelerator"])
294
+ return
295
+ elif flag == "--json":
296
+ pass # fall through to JSON output
297
+ else:
298
+ print(f"Unknown flag: {flag}", file=sys.stderr)
299
+ print("Usage: detect-torch.py [--pip-args|--index-url|--description|--accelerator|--json]", file=sys.stderr)
300
+ sys.exit(1)
301
+
302
+ print(json.dumps(spec, indent=2))
303
+
304
+
305
+ if __name__ == "__main__":
306
+ main()