omnius 1.0.430 → 1.0.432

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.
@@ -84,6 +84,76 @@ def emit_transcript(text: str, is_final: bool = False, doa=None, consensus=None)
84
84
  event["consensus"] = bool(consensus)
85
85
  emit(event)
86
86
 
87
+
88
+ def host_cuda_hardware_present() -> bool:
89
+ """Best-effort CUDA hardware hint, including Jetson/Orin nodes."""
90
+ for path in (
91
+ "/dev/nvidiactl",
92
+ "/dev/nvidia0",
93
+ "/dev/nvhost-gpu",
94
+ "/proc/driver/nvidia/gpus",
95
+ "/sys/devices/gpu.0",
96
+ ):
97
+ if os.path.exists(path):
98
+ return True
99
+ visible = os.environ.get("NVIDIA_VISIBLE_DEVICES", "").strip().lower()
100
+ return bool(visible and visible not in ("none", "void", "no"))
101
+
102
+
103
+ def select_whisper_device() -> str:
104
+ """Force Whisper onto CUDA whenever PyTorch can see a CUDA device.
105
+
106
+ CPU is only allowed when CUDA is genuinely unavailable to this Python
107
+ runtime. If CUDA is visible but unusable, fail loudly instead of silently
108
+ degrading into slow CPU transcription.
109
+ """
110
+ try:
111
+ import torch
112
+ except Exception as e:
113
+ if host_cuda_hardware_present():
114
+ emit_error(f"CUDA hardware appears present, but PyTorch could not be imported for CUDA Whisper ({e}); refusing CPU fallback.")
115
+ sys.exit(1)
116
+ emit_status(f"PyTorch unavailable for CUDA probe ({e}); using CPU because CUDA is not available to Whisper.")
117
+ return "cpu"
118
+
119
+ try:
120
+ cuda_count = int(torch.cuda.device_count())
121
+ cuda_available = bool(torch.cuda.is_available() and cuda_count > 0)
122
+ except Exception as e:
123
+ if host_cuda_hardware_present():
124
+ emit_error(f"CUDA hardware appears present, but PyTorch CUDA probe failed ({e}); refusing CPU fallback.")
125
+ sys.exit(1)
126
+ emit_status(f"CUDA probe failed ({e}); using CPU because CUDA is not available to Whisper.")
127
+ return "cpu"
128
+
129
+ if not cuda_available:
130
+ cuda_version = getattr(getattr(torch, "version", None), "cuda", None)
131
+ if host_cuda_hardware_present():
132
+ emit_error(f"CUDA hardware appears present, but PyTorch reports CUDA unavailable (torch.version.cuda={cuda_version}, device_count={cuda_count}); refusing CPU fallback.")
133
+ sys.exit(1)
134
+ emit_status(f"CUDA unavailable to PyTorch (torch.version.cuda={cuda_version}, device_count={cuda_count}); using CPU fallback.")
135
+ return "cpu"
136
+
137
+ raw_index = os.environ.get("OMNIUS_ASR_CUDA_DEVICE", "0").strip() or "0"
138
+ try:
139
+ device_index = int(raw_index)
140
+ except ValueError:
141
+ emit_error(f"Invalid OMNIUS_ASR_CUDA_DEVICE={raw_index!r}; refusing CPU fallback because CUDA is available.")
142
+ sys.exit(1)
143
+ if device_index < 0 or device_index >= cuda_count:
144
+ emit_error(f"OMNIUS_ASR_CUDA_DEVICE={device_index} outside available CUDA device range 0..{cuda_count - 1}; refusing CPU fallback.")
145
+ sys.exit(1)
146
+
147
+ try:
148
+ torch.cuda.set_device(device_index)
149
+ name = torch.cuda.get_device_name(device_index)
150
+ except Exception as e:
151
+ emit_error(f"CUDA is available but cuda:{device_index} could not be selected ({e}); refusing CPU fallback.")
152
+ sys.exit(1)
153
+
154
+ emit_status(f"CUDA available; forcing Whisper onto cuda:{device_index} ({name}).")
155
+ return f"cuda:{device_index}"
156
+
87
157
  # ---------------------------------------------------------------------------
88
158
  # Venv bootstrap
89
159
  # ---------------------------------------------------------------------------
@@ -344,18 +414,15 @@ def main():
344
414
 
345
415
  import whisper
346
416
 
347
- emit_status(f"Loading Whisper {args.model} model...")
417
+ device = select_whisper_device()
418
+ emit_status(f"Loading Whisper {args.model} model on {device}...")
348
419
  try:
349
- device = "cpu"
350
- try:
351
- import torch
352
- if torch.cuda.is_available():
353
- device = "cuda"
354
- except ImportError:
355
- pass
356
420
  model = whisper.load_model(args.model, device=device)
357
421
  except Exception as e:
358
- emit_error(f"Failed to load model: {e}")
422
+ if str(device).startswith("cuda"):
423
+ emit_error(f"Failed to load model on {device}; refusing CPU fallback because CUDA is available: {e}")
424
+ else:
425
+ emit_error(f"Failed to load model on CPU fallback: {e}")
359
426
  sys.exit(1)
360
427
 
361
428
  # Consensus model: hallucinations (mixed-language garbage on noisy or
@@ -363,7 +430,7 @@ def main():
363
430
  consensus_model = None
364
431
  consensus_name = (args.consensus_model or "off").strip().lower()
365
432
  if consensus_name not in ("off", "none", "", args.model):
366
- emit_status(f"Loading consensus Whisper {consensus_name} model...")
433
+ emit_status(f"Loading consensus Whisper {consensus_name} model on {device}...")
367
434
  try:
368
435
  consensus_model = whisper.load_model(consensus_name, device=device)
369
436
  except Exception as e:
@@ -377,7 +444,7 @@ def main():
377
444
 
378
445
  emit({"type": "ready"})
379
446
 
380
- fp16 = (device == "cuda")
447
+ fp16 = str(device).startswith("cuda")
381
448
 
382
449
  def run_transcribe(m, samples):
383
450
  return m.transcribe(
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "omnius",
3
- "version": "1.0.430",
3
+ "version": "1.0.432",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "omnius",
9
- "version": "1.0.430",
9
+ "version": "1.0.432",
10
10
  "bundleDependencies": [
11
11
  "image-to-ascii"
12
12
  ],
@@ -5388,9 +5388,9 @@
5388
5388
  }
5389
5389
  },
5390
5390
  "node_modules/node-abi": {
5391
- "version": "3.93.0",
5392
- "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.93.0.tgz",
5393
- "integrity": "sha512-Cu6yUpX5Iavugm8BeX7c0wgU9CvOqfd1yM6A1d2q2ZMjym7GjpASv2GdRcTq3Fx+Sb5OgBkEEpw4VnAbY6Y5RA==",
5391
+ "version": "3.94.0",
5392
+ "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.94.0.tgz",
5393
+ "integrity": "sha512-W5ZNO5KRPB5TkYmGVD9F6YqhsglXJzE6etpbmT+f6EQElhiX/UTG551cnsRGvLG3fyZEg9HwaDmNmj5nwJ4z9g==",
5394
5394
  "license": "MIT",
5395
5395
  "dependencies": {
5396
5396
  "semver": "^7.3.5"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "omnius",
3
- "version": "1.0.430",
3
+ "version": "1.0.432",
4
4
  "description": "AI coding agent powered by open-source models (Ollama/vLLM) — interactive TUI with agentic tool-calling loop",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",