rocket-welder-sdk 1.1.44__py3-none-any.whl → 1.1.45__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.
@@ -15,7 +15,12 @@ import numpy as np
15
15
  from .connection_string import ConnectionMode, ConnectionString, Protocol
16
16
  from .controllers import DuplexShmController, IController, OneWayShmController
17
17
  from .frame_metadata import FrameMetadata # noqa: TC001 - used at runtime in callbacks
18
- from .high_level.connection_strings import KeyPointsConnectionString, SegmentationConnectionString
18
+ from .graphics import ILayerCanvas, IStageSink, IStageWriter, RgbColor, StageSink
19
+ from .high_level.connection_strings import (
20
+ GraphicsConnectionString,
21
+ KeyPointsConnectionString,
22
+ SegmentationConnectionString,
23
+ )
19
24
  from .high_level.frame_sink_factory import FrameSinkFactory
20
25
  from .keypoints_protocol import IKeyPointsSink, IKeyPointsWriter, KeyPointsSink
21
26
  from .opencv_controller import OpenCvController
@@ -188,25 +193,26 @@ class RocketWelderClient:
188
193
 
189
194
  def start_with_writers(
190
195
  self,
191
- on_frame: Callable[[Mat, ISegmentationResultWriter, IKeyPointsWriter, Mat], None], # type: ignore[valid-type]
196
+ on_frame: Callable[[Mat, ISegmentationResultWriter, IKeyPointsWriter, IStageWriter, Mat], None], # type: ignore[valid-type]
192
197
  cancellation_token: Optional[threading.Event] = None,
193
198
  ) -> None:
194
199
  """
195
- Start receiving frames with segmentation and keypoints output support.
200
+ Start receiving frames with segmentation, keypoints, and graphics output support.
196
201
 
197
202
  Creates sinks for streaming AI results to rocket-welder2.
198
203
 
199
204
  Configuration via environment variables:
200
205
  - SEGMENTATION_SINK_URL: URL for segmentation output (e.g., socket:///tmp/seg.sock)
201
206
  - KEYPOINTS_SINK_URL: URL for keypoints output (e.g., socket:///tmp/kp.sock)
207
+ - STAGE_SINK_URL: URL for graphics/stage output (e.g., socket:///tmp/stage.sock)
202
208
 
203
209
  Args:
204
- on_frame: Callback receiving (input_mat, seg_writer, kp_writer, output_mat).
210
+ on_frame: Callback receiving (input_mat, seg_writer, kp_writer, stage_writer, output_mat).
205
211
  The writers are created per-frame and auto-flush on context exit.
206
212
  cancellation_token: Optional cancellation token
207
213
 
208
214
  Example:
209
- def process_frame(input_mat, seg_writer, kp_writer, output_mat):
215
+ def process_frame(input_mat, seg_writer, kp_writer, stage_writer, output_mat):
210
216
  # Run AI inference
211
217
  result = ai_model.infer(input_mat)
212
218
 
@@ -218,6 +224,11 @@ class RocketWelderClient:
218
224
  for kp in result.keypoints:
219
225
  kp_writer.append(kp.id, kp.x, kp.y, kp.confidence)
220
226
 
227
+ # Draw graphics overlay
228
+ layer = stage_writer[0]
229
+ layer.set_font_size(24)
230
+ layer.draw_text("Detection count: 5", 10, 30)
231
+
221
232
  # Copy/draw to output
222
233
  output_mat[:] = input_mat
223
234
 
@@ -248,11 +259,13 @@ class RocketWelderClient:
248
259
  # Create sinks from environment
249
260
  seg_sink = self._get_or_create_segmentation_sink()
250
261
  kp_sink = self._get_or_create_keypoints_sink()
262
+ stage_sink = self._get_or_create_stage_sink()
251
263
 
252
264
  logger.info(
253
- "Starting RocketWelder client with AI output support: seg=%s, kp=%s",
265
+ "Starting RocketWelder client with AI output support: seg=%s, kp=%s, stage=%s",
254
266
  "configured" if seg_sink else "null",
255
267
  "configured" if kp_sink else "null",
268
+ "configured" if stage_sink else "null",
256
269
  )
257
270
 
258
271
  # Wrapper callback that creates per-frame writers
@@ -269,17 +282,26 @@ class RocketWelderClient:
269
282
  frame_metadata.frame_number,
270
283
  )
271
284
  # Use no-op writers
272
- on_frame(
273
- input_mat, _NoOpSegmentationWriter(), _NoOpKeyPointsWriter(), output_mat
274
- )
285
+ with stage_sink.create_writer(frame_metadata.frame_number) as stage_writer:
286
+ on_frame(
287
+ input_mat,
288
+ _NoOpSegmentationWriter(),
289
+ _NoOpKeyPointsWriter(),
290
+ stage_writer,
291
+ output_mat,
292
+ )
275
293
  return
276
294
 
277
- # Create per-frame writers from sinks
295
+ # Create per-frame writers from sinks (all auto-flush on context exit)
278
296
  with seg_sink.create_writer(
279
297
  frame_metadata.frame_number, caps.width, caps.height
280
- ) as seg_writer, kp_sink.create_writer(frame_metadata.frame_number) as kp_writer:
298
+ ) as seg_writer, kp_sink.create_writer(
299
+ frame_metadata.frame_number
300
+ ) as kp_writer, stage_sink.create_writer(
301
+ frame_metadata.frame_number
302
+ ) as stage_writer:
281
303
  # Call user callback with writers
282
- on_frame(input_mat, seg_writer, kp_writer, output_mat)
304
+ on_frame(input_mat, seg_writer, kp_writer, stage_writer, output_mat)
283
305
  # Writers auto-flush on context exit
284
306
 
285
307
  # Start the controller with our wrapper
@@ -324,6 +346,23 @@ class RocketWelderClient:
324
346
  logger.warning("Failed to create keypoints sink from %s: %s", url, ex)
325
347
  return _NullKeyPointsSink()
326
348
 
349
+ def _get_or_create_stage_sink(self) -> IStageSink:
350
+ """Get or create graphics stage sink from environment."""
351
+ import os
352
+
353
+ url = os.environ.get("GRAPHICS_SINK_URL")
354
+ if not url:
355
+ logger.debug("GRAPHICS_SINK_URL not set, using null sink")
356
+ return _NullStageSink()
357
+
358
+ try:
359
+ cs = GraphicsConnectionString.parse(url)
360
+ frame_sink = FrameSinkFactory.create(cs.protocol, cs.address)
361
+ return StageSink(frame_sink=frame_sink, owns_sink=True)
362
+ except Exception as ex:
363
+ logger.warning("Failed to create graphics stage sink from %s: %s", url, ex)
364
+ return _NullStageSink()
365
+
327
366
  def stop(self) -> None:
328
367
  """Stop the client and clean up resources."""
329
368
  with self._lock:
@@ -620,3 +659,162 @@ class _NullSegmentationSink(ISegmentationResultSink):
620
659
  def close(self) -> None:
621
660
  """No-op close."""
622
661
  pass
662
+
663
+
664
+ class _NoOpLayerCanvas(ILayerCanvas):
665
+ """No-op layer canvas that discards all drawing operations."""
666
+
667
+ @property
668
+ def layer_id(self) -> int:
669
+ """The layer ID."""
670
+ return 0
671
+
672
+ # Frame type
673
+ def master(self) -> None:
674
+ """No-op."""
675
+ pass
676
+
677
+ def remain(self) -> None:
678
+ """No-op."""
679
+ pass
680
+
681
+ def clear(self) -> None:
682
+ """No-op."""
683
+ pass
684
+
685
+ # Context state - Styling
686
+ def set_stroke(self, color: RgbColor) -> None:
687
+ """No-op."""
688
+ pass
689
+
690
+ def set_fill(self, color: RgbColor) -> None:
691
+ """No-op."""
692
+ pass
693
+
694
+ def set_thickness(self, width: int) -> None:
695
+ """No-op."""
696
+ pass
697
+
698
+ def set_font_size(self, size: int) -> None:
699
+ """No-op."""
700
+ pass
701
+
702
+ def set_font_color(self, color: RgbColor) -> None:
703
+ """No-op."""
704
+ pass
705
+
706
+ # Context state - Transforms
707
+ def translate(self, dx: float, dy: float) -> None:
708
+ """No-op."""
709
+ pass
710
+
711
+ def rotate(self, degrees: float) -> None:
712
+ """No-op."""
713
+ pass
714
+
715
+ def scale(self, sx: float, sy: float) -> None:
716
+ """No-op."""
717
+ pass
718
+
719
+ def skew(self, kx: float, ky: float) -> None:
720
+ """No-op."""
721
+ pass
722
+
723
+ def set_matrix(
724
+ self,
725
+ scale_x: float,
726
+ skew_x: float,
727
+ trans_x: float,
728
+ skew_y: float,
729
+ scale_y: float,
730
+ trans_y: float,
731
+ ) -> None:
732
+ """No-op."""
733
+ pass
734
+
735
+ # Context stack
736
+ def save(self) -> None:
737
+ """No-op."""
738
+ pass
739
+
740
+ def restore(self) -> None:
741
+ """No-op."""
742
+ pass
743
+
744
+ def reset_context(self) -> None:
745
+ """No-op."""
746
+ pass
747
+
748
+ # Draw operations
749
+ def draw_polygon(self, points: Any) -> None:
750
+ """No-op."""
751
+ pass
752
+
753
+ def draw_text(self, text: str, x: int, y: int) -> None:
754
+ """No-op."""
755
+ pass
756
+
757
+ def draw_circle(self, center_x: int, center_y: int, radius: int) -> None:
758
+ """No-op."""
759
+ pass
760
+
761
+ def draw_rectangle(self, x: int, y: int, width: int, height: int) -> None:
762
+ """No-op."""
763
+ pass
764
+
765
+ def draw_line(self, x1: int, y1: int, x2: int, y2: int) -> None:
766
+ """No-op."""
767
+ pass
768
+
769
+ def draw_jpeg(self, jpeg_data: bytes, x: int, y: int, width: int, height: int) -> None:
770
+ """No-op."""
771
+ pass
772
+
773
+
774
+ # Singleton instance
775
+ _NO_OP_LAYER_CANVAS = _NoOpLayerCanvas()
776
+
777
+
778
+ class _NoOpStageWriter(IStageWriter):
779
+ """No-op stage writer that discards all graphics operations."""
780
+
781
+ @property
782
+ def frame_id(self) -> int:
783
+ """The frame ID."""
784
+ return 0
785
+
786
+ def __getitem__(self, layer_id: int) -> ILayerCanvas:
787
+ """Returns no-op layer canvas."""
788
+ return _NO_OP_LAYER_CANVAS
789
+
790
+ def layer(self, layer_id: int) -> ILayerCanvas:
791
+ """Returns no-op layer canvas."""
792
+ return _NO_OP_LAYER_CANVAS
793
+
794
+ def close(self) -> None:
795
+ """No-op close."""
796
+ pass
797
+
798
+ def __enter__(self) -> _NoOpStageWriter:
799
+ """Context manager entry."""
800
+ return self
801
+
802
+ def __exit__(self, exc_type: object, exc_val: object, exc_tb: object) -> None:
803
+ """Context manager exit."""
804
+ pass
805
+
806
+
807
+ # Singleton instance
808
+ _NO_OP_STAGE_WRITER = _NoOpStageWriter()
809
+
810
+
811
+ class _NullStageSink(IStageSink):
812
+ """Null stage sink that creates no-op writers."""
813
+
814
+ def create_writer(self, frame_id: int) -> IStageWriter:
815
+ """Create a no-op writer."""
816
+ return _NO_OP_STAGE_WRITER
817
+
818
+ def close(self) -> None:
819
+ """No-op close."""
820
+ pass
@@ -27,6 +27,7 @@ SESSION_ID_ENV_VAR = "SessionId"
27
27
  SEGMENTATION_SINK_URL_ENV = "SEGMENTATION_SINK_URL"
28
28
  KEYPOINTS_SINK_URL_ENV = "KEYPOINTS_SINK_URL"
29
29
  ACTIONS_SINK_URL_ENV = "ACTIONS_SINK_URL"
30
+ GRAPHICS_SINK_URL_ENV = "GRAPHICS_SINK_URL"
30
31
 
31
32
 
32
33
  def parse_session_id(session_id: str) -> uuid.UUID:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rocket-welder-sdk
3
- Version: 1.1.44
3
+ Version: 1.1.45
4
4
  Summary: High-performance video streaming SDK for RocketWelder services using ZeroBuffer IPC
5
5
  Home-page: https://github.com/modelingevolution/rocket-welder-sdk
6
6
  Author: ModelingEvolution
@@ -1,4 +1,4 @@
1
- rocket_welder_sdk/__init__.py,sha256=r2zUZzUMZuAPUy5Sat5EWaxeocIjRbdqBDoC1i0C89w,3413
1
+ rocket_welder_sdk/__init__.py,sha256=5hcsNb0zu8dtRHD9sgCAi4YbWJe-1g6cl9jSuLQZk_U,3889
2
2
  rocket_welder_sdk/binary_frame_reader.py,sha256=5IyYO7yv07gLpQ9Toyw1zLkTrnqHLjxIeMVRn8B40-E,6270
3
3
  rocket_welder_sdk/binary_frame_writer.py,sha256=2-VEJNHw0fL30TXsCBHyhHltvgx7KUahmbamwdSU8sw,6658
4
4
  rocket_welder_sdk/bytes_size.py,sha256=Myl29-wyWCIYdbMmgaxXebT8Dz8_Fwcr3fnfaNW81P0,7463
@@ -12,16 +12,22 @@ rocket_welder_sdk/keypoints_protocol.py,sha256=kN8ok6Ptpgl4txoQE9DpKhMoI7zr73vTw
12
12
  rocket_welder_sdk/opencv_controller.py,sha256=MDM6_yFBB9BaMa5jnZRqw7xZZB-WuLr7EPrrfHQ2DK4,9905
13
13
  rocket_welder_sdk/periodic_timer.py,sha256=hnObybmrnf3J47QrNKJhYAytLKwria016123NvPRfQ0,9369
14
14
  rocket_welder_sdk/py.typed,sha256=0cXFZXmes4Y-vnl4lO3HtyyyWaFNw85B7tJdFeCtHDc,67
15
- rocket_welder_sdk/rocket_welder_client.py,sha256=VqxP-GkJKCZCjGZq2tVJ7v5yrh-ztXxlF3CT__818vg,23384
15
+ rocket_welder_sdk/rocket_welder_client.py,sha256=iSyMiIx_5GgL5VI3W4G6o7JlG3A9G8JDlsTwLhQApVU,28609
16
16
  rocket_welder_sdk/segmentation_result.py,sha256=b3xpv6AZyWzm924cd1RfXwCuEwdkPL5TUA0gzT3HpBA,29153
17
- rocket_welder_sdk/session_id.py,sha256=9GM4T6xmcNxR9gxZnDUlQGviNd3x3hT71q8y85XtH6g,1884
17
+ rocket_welder_sdk/session_id.py,sha256=YgnDwmdOcdJTXIObjkrzIkxU2gbMzNko1h1ms4lNIfU,1928
18
18
  rocket_welder_sdk/varint.py,sha256=SmffemQCXToRzs3lb7hWQWDY7NmKv4XG_Wb0oeMrb_I,5058
19
19
  rocket_welder_sdk/external_controls/__init__.py,sha256=ldOLGhLLS5BQL8m4VKFYV0SvsNNlV2tghlc7rkqadU8,699
20
20
  rocket_welder_sdk/external_controls/contracts.py,sha256=3DU6pdpteN50gF2fsS7C2279dGjDa0tZLrLntkBa2LM,2607
21
21
  rocket_welder_sdk/external_controls/contracts_old.py,sha256=XWriuXJZu5caTSS0bcTIOZcKnj-IRCm96voA4gqLBfU,2980
22
+ rocket_welder_sdk/graphics/__init__.py,sha256=4sKaqeu391WfVX1c_TDxAbucy7OJF8Aw8CG77NeggFA,1230
23
+ rocket_welder_sdk/graphics/layer_canvas.py,sha256=FcgrrCaI-2XlVOs4qYTGvpJQdVw_NP2V7D4a1LgLtS4,4580
24
+ rocket_welder_sdk/graphics/protocol.py,sha256=57GOx9rlKGojm7jnXdM2t3bpa4Ykii1o3wQtQ5IO-Hs,1357
25
+ rocket_welder_sdk/graphics/rgb_color.py,sha256=do6y362CTROiLMqbQwdvJF07L8wMWRv3n7-PVWP-Flk,3497
26
+ rocket_welder_sdk/graphics/stage.py,sha256=2hgkKGCxLxcZ64cHBKgxxFHSZOlLue236x5f43cmYk0,15538
27
+ rocket_welder_sdk/graphics/vector_graphics_encoder.py,sha256=lD3cIOAVL_JvKZayIQ_TaQ5fa8S6d9Q45C91PubHMbk,16483
22
28
  rocket_welder_sdk/high_level/__init__.py,sha256=OKbI3l0PFo1Cb_v0kbv16Wr05urz8heVGps0dJcTcG4,1507
23
29
  rocket_welder_sdk/high_level/client.py,sha256=rVnnrn68PEvc68p5acuOBZfEjobWWed8XcssTRzxNr8,11502
24
- rocket_welder_sdk/high_level/connection_strings.py,sha256=3EpFafyrmX_QNhs2nPscC63EMg5ikscvthu-0C6xC1c,9861
30
+ rocket_welder_sdk/high_level/connection_strings.py,sha256=1Hp72V5qDngHGXyjBRFMckz365BMpGVjb3PMSGvCtow,12531
25
31
  rocket_welder_sdk/high_level/data_context.py,sha256=SXJvDpDBFi8Lm4XqSRSHK7YUUHuugXGo4ZRCb6_z5l0,4833
26
32
  rocket_welder_sdk/high_level/frame_sink_factory.py,sha256=tLhMV_qnY-ZUtffIzhycM9znNjYguRumba4vphpNx7E,3493
27
33
  rocket_welder_sdk/high_level/schema.py,sha256=2Vv0rDwahtGswWB_ceaCdc7JDtmbkx4wE2jQePzeTpU,5367
@@ -39,7 +45,7 @@ rocket_welder_sdk/ui/icons.py,sha256=DcDklZkPmiEzlOD4IR7VTJOtGPCuuh_OM_WN7ScghWE
39
45
  rocket_welder_sdk/ui/ui_events_projection.py,sha256=siiNhjLEBOPfTKw1ZhOPGkwIN5rLDH7V9VCZTNrhEtQ,7836
40
46
  rocket_welder_sdk/ui/ui_service.py,sha256=uRdpyJGoCQmtOli_HKSrxLwhZYG-XRuHIYdkmFz1zNk,12026
41
47
  rocket_welder_sdk/ui/value_types.py,sha256=f7OA_9zgXEDPoITc8v8SfAR23I4XeFhE3E2_GcAbR6k,1616
42
- rocket_welder_sdk-1.1.44.dist-info/METADATA,sha256=XszsJzlnvEQCiPGYl-QxGK6TCTEYmWvi0AzvlHOqYKA,24739
43
- rocket_welder_sdk-1.1.44.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
44
- rocket_welder_sdk-1.1.44.dist-info/top_level.txt,sha256=2iZvBjnwVCUW-uDE23-eJld5PZ9-mlPI69QiXM5IrTA,18
45
- rocket_welder_sdk-1.1.44.dist-info/RECORD,,
48
+ rocket_welder_sdk-1.1.45.dist-info/METADATA,sha256=Kw6yzgaMHhKdQ5iskkBWSXP54zGr1vMpgz0mv_PQsvY,24739
49
+ rocket_welder_sdk-1.1.45.dist-info/WHEEL,sha256=qELbo2s1Yzl39ZmrAibXA2jjPLUYfnVhUNTlyF1rq0Y,92
50
+ rocket_welder_sdk-1.1.45.dist-info/top_level.txt,sha256=2iZvBjnwVCUW-uDE23-eJld5PZ9-mlPI69QiXM5IrTA,18
51
+ rocket_welder_sdk-1.1.45.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.9.0)
2
+ Generator: setuptools (80.10.1)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5