plexus-python 0.4.6__py3-none-any.whl → 0.4.7__py3-none-any.whl
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.
- plexus/__init__.py +1 -1
- plexus/client.py +61 -0
- plexus/ws.py +0 -1
- {plexus_python-0.4.6.dist-info → plexus_python-0.4.7.dist-info}/METADATA +1 -1
- plexus_python-0.4.7.dist-info/RECORD +11 -0
- plexus_python-0.4.6.dist-info/RECORD +0 -11
- {plexus_python-0.4.6.dist-info → plexus_python-0.4.7.dist-info}/WHEEL +0 -0
- {plexus_python-0.4.6.dist-info → plexus_python-0.4.7.dist-info}/entry_points.txt +0 -0
- {plexus_python-0.4.6.dist-info → plexus_python-0.4.7.dist-info}/licenses/LICENSE +0 -0
plexus/__init__.py
CHANGED
plexus/client.py
CHANGED
|
@@ -33,6 +33,7 @@ Usage:
|
|
|
33
33
|
Note: Requires authentication. Run 'plexus start' or set PLEXUS_API_KEY.
|
|
34
34
|
"""
|
|
35
35
|
|
|
36
|
+
import base64
|
|
36
37
|
import gzip
|
|
37
38
|
import json
|
|
38
39
|
import logging
|
|
@@ -134,6 +135,7 @@ class Plexus:
|
|
|
134
135
|
self._run_id: Optional[str] = None
|
|
135
136
|
self._session: Optional[requests.Session] = None
|
|
136
137
|
self._store_frames: bool = False
|
|
138
|
+
self._cv2 = None
|
|
137
139
|
|
|
138
140
|
if transport not in ("ws", "http"):
|
|
139
141
|
raise ValueError(f"transport must be 'ws' or 'http', got {transport!r}")
|
|
@@ -342,6 +344,65 @@ class Plexus:
|
|
|
342
344
|
except Exception as e: # pragma: no cover - persistence failure is non-fatal
|
|
343
345
|
logger.debug("failed to persist assigned source_id: %s", e)
|
|
344
346
|
|
|
347
|
+
def send_video_frame(
|
|
348
|
+
self,
|
|
349
|
+
frame,
|
|
350
|
+
camera_id: str = "camera:0",
|
|
351
|
+
quality: int = 85,
|
|
352
|
+
timestamp: Optional[float] = None,
|
|
353
|
+
) -> bool:
|
|
354
|
+
"""
|
|
355
|
+
Send a single video frame to Plexus (WebSocket transport only).
|
|
356
|
+
|
|
357
|
+
Args:
|
|
358
|
+
frame: A numpy array (H, W, C) as returned by cv2.VideoCapture.read()
|
|
359
|
+
camera_id: Logical camera identifier (e.g. "picam:0", "usb:1")
|
|
360
|
+
quality: JPEG compression quality, 1-100. Default 85.
|
|
361
|
+
timestamp: Unix timestamp. If not provided, uses current time.
|
|
362
|
+
|
|
363
|
+
Returns:
|
|
364
|
+
True if the frame was sent successfully.
|
|
365
|
+
|
|
366
|
+
Raises:
|
|
367
|
+
PlexusError: If transport is not 'ws', or if the send fails.
|
|
368
|
+
ImportError: If opencv-python is not installed.
|
|
369
|
+
|
|
370
|
+
Example:
|
|
371
|
+
cap = cv2.VideoCapture(0)
|
|
372
|
+
ret, frame = cap.read()
|
|
373
|
+
px.send_video_frame(frame, camera_id="picam:0")
|
|
374
|
+
"""
|
|
375
|
+
if self.transport != "ws":
|
|
376
|
+
raise PlexusError("send_video_frame requires transport='ws'")
|
|
377
|
+
|
|
378
|
+
if self._cv2 is None:
|
|
379
|
+
try:
|
|
380
|
+
import cv2 as _cv2
|
|
381
|
+
self._cv2 = _cv2
|
|
382
|
+
except ImportError as e:
|
|
383
|
+
raise ImportError(
|
|
384
|
+
"send_video_frame requires opencv-python. "
|
|
385
|
+
"Install with: pip install opencv-python"
|
|
386
|
+
) from e
|
|
387
|
+
|
|
388
|
+
height, width = frame.shape[:2]
|
|
389
|
+
_, buf = self._cv2.imencode(".jpg", frame, [self._cv2.IMWRITE_JPEG_QUALITY, quality])
|
|
390
|
+
b64 = base64.b64encode(buf).decode()
|
|
391
|
+
|
|
392
|
+
ws = self._ensure_ws()
|
|
393
|
+
if not ws.is_authenticated:
|
|
394
|
+
ws.wait_authenticated(timeout=min(self.timeout, 5.0))
|
|
395
|
+
|
|
396
|
+
return ws._send_frame({
|
|
397
|
+
"type": "video_frame",
|
|
398
|
+
"source_id": self.source_id,
|
|
399
|
+
"camera_id": camera_id,
|
|
400
|
+
"frame": b64,
|
|
401
|
+
"width": width,
|
|
402
|
+
"height": height,
|
|
403
|
+
"timestamp": self._normalize_ts_ms(timestamp),
|
|
404
|
+
})
|
|
405
|
+
|
|
345
406
|
def on_command(
|
|
346
407
|
self,
|
|
347
408
|
name: str,
|
plexus/ws.py
CHANGED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
plexus/__init__.py,sha256=5Ef1BoSacfFvLTXaSV84bJWMSelmuX43AzO7QRphoys,345
|
|
2
|
+
plexus/buffer.py,sha256=3ykybqLs7yMXxQWFajAT8nGe3cs_lW8_6Xvn0vQ69dE,9262
|
|
3
|
+
plexus/cli.py,sha256=-2wvHXQzobx3_tDGTXpaE2PlHv884y93Mu29kZE8qZE,14214
|
|
4
|
+
plexus/client.py,sha256=uSmgxeGs3BOFfhtnTwH2L-uia-zyRuJTtTYEjyCMl0g,25016
|
|
5
|
+
plexus/config.py,sha256=wsG6lhNLmKe3JRlVycyRUKQeywnPUPPfrWkXFxYwELE,6179
|
|
6
|
+
plexus/ws.py,sha256=4nmNganwS_1BujdFkH3u3lLBB7rEkPYd_oYrbdYkdY4,14818
|
|
7
|
+
plexus_python-0.4.7.dist-info/METADATA,sha256=4tdaBPCjJn2jWzk52vQLSg6zGtq2RrvSU5eF6yanqbI,8121
|
|
8
|
+
plexus_python-0.4.7.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
|
|
9
|
+
plexus_python-0.4.7.dist-info/entry_points.txt,sha256=YlkOtTn_7Q_IGuJaKdvpU-90dCeBSPx2p_UTGMAz5Zs,43
|
|
10
|
+
plexus_python-0.4.7.dist-info/licenses/LICENSE,sha256=nm3qP1F-JAGcfLpRVtIX24L20LMnRpxmZ2oKZzFpLVo,10755
|
|
11
|
+
plexus_python-0.4.7.dist-info/RECORD,,
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
plexus/__init__.py,sha256=upqHP1A19Sp_CnCeCBHHJ1GUKKzeCJiJw5w3wD2K4cE,345
|
|
2
|
-
plexus/buffer.py,sha256=3ykybqLs7yMXxQWFajAT8nGe3cs_lW8_6Xvn0vQ69dE,9262
|
|
3
|
-
plexus/cli.py,sha256=-2wvHXQzobx3_tDGTXpaE2PlHv884y93Mu29kZE8qZE,14214
|
|
4
|
-
plexus/client.py,sha256=JmEKKRu4ik548uBPMEOCcB_r_asRmuNORZF4snjFosQ,22956
|
|
5
|
-
plexus/config.py,sha256=wsG6lhNLmKe3JRlVycyRUKQeywnPUPPfrWkXFxYwELE,6179
|
|
6
|
-
plexus/ws.py,sha256=aynJTH8LHRA4_U1OfIu-2aaOg1tLniUcWbzB2yuiQvU,14865
|
|
7
|
-
plexus_python-0.4.6.dist-info/METADATA,sha256=d6Vp27f4EsfSHeS0NT6z9oWF85UIsLskMzzborehyQQ,8121
|
|
8
|
-
plexus_python-0.4.6.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
|
|
9
|
-
plexus_python-0.4.6.dist-info/entry_points.txt,sha256=YlkOtTn_7Q_IGuJaKdvpU-90dCeBSPx2p_UTGMAz5Zs,43
|
|
10
|
-
plexus_python-0.4.6.dist-info/licenses/LICENSE,sha256=nm3qP1F-JAGcfLpRVtIX24L20LMnRpxmZ2oKZzFpLVo,10755
|
|
11
|
-
plexus_python-0.4.6.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|