@camstack/addon-pipeline 1.1.68 → 1.1.70

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.
Files changed (28) hide show
  1. package/dist/audio-analyzer/index.js +1 -1
  2. package/dist/audio-analyzer/index.mjs +1 -1
  3. package/dist/detection-pipeline/index.js +155 -27
  4. package/dist/detection-pipeline/index.mjs +155 -27
  5. package/dist/{dist-BxxVKcnw.js → dist-BWn5k0A5.js} +37 -2
  6. package/dist/{dist-DkGHtAaK.mjs → dist-CurVt3xC.mjs} +37 -2
  7. package/dist/motion-wasm/index.js +1 -1
  8. package/dist/motion-wasm/index.mjs +1 -1
  9. package/dist/pipeline-runner/index.js +7 -3
  10. package/dist/pipeline-runner/index.mjs +7 -3
  11. package/dist/recorder/index.js +1 -1
  12. package/dist/recorder/index.mjs +1 -1
  13. package/dist/{step-definitions-CAs0RD2N.js → step-definitions-B7e8rPe3.js} +114 -187
  14. package/dist/{step-definitions-Delhq28w.mjs → step-definitions-BKm17nce.mjs} +114 -187
  15. package/dist/stream-broker/_stub.js +1 -1
  16. package/dist/stream-broker/{_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-BUXIIogo.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-yAAGMET5.mjs} +2 -2
  17. package/dist/stream-broker/{_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-DlALQ_wp.mjs → _virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-CDBALHSV.mjs} +1 -1
  18. package/dist/stream-broker/{hostInit-D7_95hNV.mjs → hostInit-DUzRsTmt.mjs} +2 -2
  19. package/dist/stream-broker/index.js +1 -1
  20. package/dist/stream-broker/index.mjs +1 -1
  21. package/dist/stream-broker/remoteEntry.js +1 -1
  22. package/embed-dist/assets/{MaskShapeCanvas-DI4BY7W2-CRvzj7Of.js → MaskShapeCanvas-DI4BY7W2-D6bWMuew.js} +1 -1
  23. package/embed-dist/assets/{MotionZonesSettings-NcxxQN8r-CBgvPUB-.js → MotionZonesSettings-NcxxQN8r-C-1enV21.js} +1 -1
  24. package/embed-dist/assets/{PrivacyMaskSettings-APgPLF7p-DH07fe1k.js → PrivacyMaskSettings-APgPLF7p-By9pdGP7.js} +1 -1
  25. package/embed-dist/assets/{index-BkoPcGtQ.js → index-BPGh79kn.js} +5 -5
  26. package/embed-dist/index.html +1 -1
  27. package/package.json +1 -1
  28. package/python/inference_pool.py +38 -3
@@ -4,7 +4,7 @@
4
4
  <meta charset="utf-8" />
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1" />
6
6
  <title>CamStack Embed</title>
7
- <script type="module" crossorigin src="./assets/index-BkoPcGtQ.js"></script>
7
+ <script type="module" crossorigin src="./assets/index-BPGh79kn.js"></script>
8
8
  <link rel="stylesheet" crossorigin href="./assets/index-D2pF9Z3W.css">
9
9
  </head>
10
10
  <body>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-pipeline",
3
- "version": "1.1.68",
3
+ "version": "1.1.70",
4
4
  "description": "CamStack Pipeline bundle — runner, detection, motion, audio + stream broker. Multi-entry npm package shipping pipeline addons under a single bundle.",
5
5
  "keywords": [
6
6
  "camstack",
@@ -447,7 +447,7 @@ def _acquire_coreml_model(ct: Any, path: str, compute_units: Any) -> tuple[Any,
447
447
  return model, spec
448
448
 
449
449
 
450
- def _init_runtime(runtime: str) -> None:
450
+ def _init_runtime(runtime: str, device: str = "") -> None:
451
451
  global _runtime, _runtime_lib
452
452
  _runtime = runtime
453
453
  if runtime == "coreml":
@@ -472,7 +472,41 @@ def _init_runtime(runtime: str) -> None:
472
472
  lib_path = os.environ.get(
473
473
  "CAMSTACK_EDGETPU_LIB", "/data/deps/edgetpu/lib/libedgetpu.so.1",
474
474
  )
475
- delegate = load_delegate(lib_path)
475
+ # Multiple Corals coexist and run concurrently, one pool each. libedgetpu
476
+ # addresses a specific unit by an ordinal device string ("usb", "usb:1",
477
+ # "pci:0", …); the orchestrator passes it as the pool `device`. Omitted /
478
+ # bare "usb" ⇒ the first available Coral (single-Coral default).
479
+ dev = (device or "").strip()
480
+ opts = {"device": dev} if dev and dev not in ("usb", "all", "default") else None
481
+ # The Coral is a SINGLE-CONTEXT USB device: only ONE process may hold the
482
+ # libedgetpu delegate at a time. When a prior pool (e.g. a previous runner
483
+ # generation, or a just-disposed device pool) is still releasing the USB,
484
+ # a fresh load_delegate fails transiently. Retry with backoff instead of
485
+ # hard-failing the whole pool — the device frees within a second or two of
486
+ # the old holder exiting. (A genuinely-held device still fails after the
487
+ # retries, with the real libedgetpu error surfaced.)
488
+ import time as _time
489
+ last_err = None
490
+ delegate = None
491
+ for attempt in range(6):
492
+ try:
493
+ delegate = load_delegate(lib_path, opts) if opts else load_delegate(lib_path)
494
+ break
495
+ except Exception as e: # noqa: BLE001 — surface the real error after retries
496
+ last_err = e
497
+ sys.stderr.write(
498
+ f"EdgeTPU: delegate load attempt {attempt + 1}/6 failed "
499
+ f"(device={dev or 'usb'}): {e}\n"
500
+ )
501
+ sys.stderr.flush()
502
+ _time.sleep(0.75 * (attempt + 1))
503
+ if delegate is None:
504
+ raise ValueError(
505
+ f"EdgeTPU: delegate not available after 6 attempts on device "
506
+ f"'{dev or 'usb'}' — the Coral is held by another process or "
507
+ f"absent. Last error: {last_err}"
508
+ )
509
+ sys.stderr.write(f"EdgeTPU: delegate bound to device '{dev or 'usb'}'\n")
476
510
  _runtime_lib = {
477
511
  "Interpreter": Interpreter,
478
512
  "delegate": delegate,
@@ -1765,6 +1799,7 @@ async def _run() -> None:
1765
1799
  sys.exit(1)
1766
1800
  config = json.loads(payload)
1767
1801
  runtime = config.get("runtime", "coreml")
1802
+ pool_device = str(config.get("device", "") or "")
1768
1803
  concurrency = int(config.get("concurrency", 1) or 1)
1769
1804
  batch_mode = str(config.get("batch_mode", "none"))
1770
1805
  if batch_mode not in ("none", "list", "window"):
@@ -1777,7 +1812,7 @@ async def _run() -> None:
1777
1812
  f"batch_mode={batch_mode}, window_ms={window_ms}, max_batch={max_batch_size})\n"
1778
1813
  )
1779
1814
  sys.stderr.flush()
1780
- _init_runtime(runtime)
1815
+ _init_runtime(runtime, pool_device)
1781
1816
 
1782
1817
  models: list[ModelSlot] = []
1783
1818
  for i, mc in enumerate(config.get("models", [])):