@camstack/addon-pipeline 1.1.4 → 1.1.5

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 (33) hide show
  1. package/dist/audio-analyzer/index.js +16 -15
  2. package/dist/audio-analyzer/index.mjs +16 -15
  3. package/dist/audio-codec-nodeav/index.js +1 -1
  4. package/dist/audio-codec-nodeav/index.mjs +1 -1
  5. package/dist/decoder-nodeav/index.js +1 -1
  6. package/dist/decoder-nodeav/index.mjs +1 -1
  7. package/dist/detection-pipeline/index.js +195 -38
  8. package/dist/detection-pipeline/index.mjs +195 -38
  9. package/dist/{dist-OlOI9pHn.js → dist-BhpOMzzH.js} +28 -4
  10. package/dist/{dist-CAgJixja.mjs → dist-GFzs5acw.mjs} +28 -4
  11. package/dist/motion-wasm/index.js +1 -1
  12. package/dist/motion-wasm/index.mjs +1 -1
  13. package/dist/pipeline-runner/index.js +1 -1
  14. package/dist/pipeline-runner/index.mjs +1 -1
  15. package/dist/recorder/index.js +1 -1
  16. package/dist/recorder/index.mjs +1 -1
  17. package/dist/stream-broker/_stub.js +2 -2
  18. package/dist/stream-broker/{_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-D08yXBHc.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-DQYrh0ie.mjs} +3 -3
  19. package/dist/stream-broker/{_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-FRD2eBuz.mjs → _virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-S6ETjGtN.mjs} +1 -1
  20. package/dist/stream-broker/{_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-CHcXI1Wf.mjs → _virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-5vetl3CL.mjs} +1 -1
  21. package/dist/stream-broker/{hostInit-DPGCWkwA.mjs → hostInit-DvWdWFSe.mjs} +3 -3
  22. package/dist/stream-broker/index.js +1 -1
  23. package/dist/stream-broker/index.mjs +1 -1
  24. package/dist/stream-broker/remoteEntry.js +1 -1
  25. package/embed-dist/assets/{MaskShapeCanvas-DI4BY7W2-Ds2bhSfK.js → MaskShapeCanvas-DI4BY7W2-Bulflbu5.js} +1 -1
  26. package/embed-dist/assets/{MotionZonesSettings-NcxxQN8r-W7yVVry1.js → MotionZonesSettings-NcxxQN8r-DJ9keq4q.js} +1 -1
  27. package/embed-dist/assets/{PrivacyMaskSettings-APgPLF7p-30DllvBT.js → PrivacyMaskSettings-APgPLF7p-CRsjkTB1.js} +1 -1
  28. package/embed-dist/assets/{index-D8CZDqZG.js → index-DBB2e2P1.js} +9 -9
  29. package/embed-dist/index.html +1 -1
  30. package/package.json +1 -1
  31. package/python/postprocessors/__init__.py +2 -0
  32. package/python/postprocessors/clip.py +35 -0
  33. package/python/postprocessors/test_clip.py +33 -0
@@ -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-D8CZDqZG.js"></script>
7
+ <script type="module" crossorigin src="./assets/index-DBB2e2P1.js"></script>
8
8
  <link rel="stylesheet" crossorigin href="./assets/index-ZhDdp1Nd.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.4",
3
+ "version": "1.1.5",
4
4
  "description": "CamStack Pipeline bundle — runner, detection, motion, decoders, audio + stream broker. Multi-entry npm package shipping 7 addons under a single bundle.",
5
5
  "keywords": [
6
6
  "camstack",
@@ -7,6 +7,7 @@ from .yolo import postprocess_yolo
7
7
  from .yolo_seg import postprocess_yolo_seg
8
8
  from .scrfd import postprocess_scrfd
9
9
  from .arcface import postprocess_arcface
10
+ from .clip import postprocess_clip
10
11
  from .softmax import postprocess_softmax
11
12
  from .ctc import postprocess_ctc
12
13
  from .saliency import postprocess_saliency
@@ -17,6 +18,7 @@ POSTPROCESSORS = {
17
18
  "yolo-seg": postprocess_yolo_seg,
18
19
  "scrfd": postprocess_scrfd,
19
20
  "arcface": postprocess_arcface,
21
+ "clip": postprocess_clip,
20
22
  "softmax": postprocess_softmax,
21
23
  "ctc": postprocess_ctc,
22
24
  "saliency": postprocess_saliency,
@@ -0,0 +1,35 @@
1
+ """CLIP image embedding postprocessor.
2
+
3
+ Input: raw embedding tensor from a CLIP vision encoder (e.g. MobileCLIP S0/S1/S2)
4
+ Output: {"kind": "embedding", "embedding": [...], "embeddingNorm": [...]}
5
+
6
+ MobileCLIP uses resize 256×256 + rescale /255 only (no ImageNet mean/std).
7
+ The existing inference_pool resize_image path already produces this layout —
8
+ preprocessMode:'resize' + inputNormalization:'none' is the correct config.
9
+ """
10
+ import numpy as np
11
+
12
+
13
+ def postprocess_clip(
14
+ predictions: dict,
15
+ config: dict,
16
+ orig_w: int,
17
+ orig_h: int,
18
+ scale: float,
19
+ pad: tuple[int, int],
20
+ ) -> dict:
21
+ """L2-normalize the CLIP embedding vector."""
22
+ # Get the first output tensor (vision encoder emits a single embedding)
23
+ raw = np.array(list(predictions.values())[0]).flatten().astype(np.float32)
24
+
25
+ norm = np.linalg.norm(raw)
26
+ if norm == 0:
27
+ normalized = np.zeros_like(raw)
28
+ else:
29
+ normalized = raw / norm
30
+
31
+ return {
32
+ "kind": "embedding",
33
+ "embedding": raw.tolist(),
34
+ "embeddingNorm": normalized.tolist(),
35
+ }
@@ -0,0 +1,33 @@
1
+ """Tests for the CLIP embedding postprocessor."""
2
+ import numpy as np
3
+ import pytest
4
+ from postprocessors.clip import postprocess_clip
5
+
6
+
7
+ def test_clip_output_kind() -> None:
8
+ vec = np.ones(512, dtype=np.float32)
9
+ predictions = {"output": vec.reshape(1, 512)}
10
+ result = postprocess_clip(predictions, {}, 640, 480, 1.0, (0, 0))
11
+ assert result["kind"] == "embedding"
12
+
13
+
14
+ def test_clip_embedding_length() -> None:
15
+ vec = np.ones(512, dtype=np.float32)
16
+ predictions = {"output": vec.reshape(1, 512)}
17
+ result = postprocess_clip(predictions, {}, 640, 480, 1.0, (0, 0))
18
+ assert len(result["embedding"]) == 512
19
+
20
+
21
+ def test_clip_embedding_norm_is_unit() -> None:
22
+ vec = np.array([3.0, 4.0] + [0.0] * 510, dtype=np.float32)
23
+ predictions = {"output": vec.reshape(1, 512)}
24
+ result = postprocess_clip(predictions, {}, 640, 480, 1.0, (0, 0))
25
+ norm = float(np.linalg.norm(result["embeddingNorm"]))
26
+ assert abs(norm - 1.0) < 1e-5
27
+
28
+
29
+ def test_clip_zero_vector_does_not_divide_by_zero() -> None:
30
+ vec = np.zeros(512, dtype=np.float32)
31
+ predictions = {"output": vec.reshape(1, 512)}
32
+ result = postprocess_clip(predictions, {}, 640, 480, 1.0, (0, 0))
33
+ assert all(v == 0.0 for v in result["embeddingNorm"])