pynode-flow 0.2.4__tar.gz → 0.2.6__tar.gz

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 (326) hide show
  1. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/.gitignore +3 -0
  2. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/PKG-INFO +171 -68
  3. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/README.md +170 -67
  4. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/_version.py +3 -3
  5. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/CameraNode/camera_node.py +8 -8
  6. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/FrameSourceNode/frame_source_node.py +8 -8
  7. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/ImageUploadNode/image_upload_node.py +13 -20
  8. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/OmronCameraNode/omron_camera_node.py +7 -7
  9. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/SliceNode/slice_collector_node.py +247 -9
  10. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/SliceNode/slice_image_node.py +124 -15
  11. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/SocketNode/ndjson_protocol.py +3 -1
  12. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/SocketNode/udp_in_node.py +4 -1
  13. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/SocketNode/udp_protocol.py +3 -1
  14. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/TrackerNode/supervision_tracker_node.py +4 -1
  15. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/VideoReaderNode/video_reader_node.py +192 -36
  16. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/base_node.py +14 -8
  17. pynode_flow-0.2.6/pynode/nodes/pacing.py +124 -0
  18. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/static/examples/README.md +14 -4
  19. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/static/examples/manifest.json +14 -0
  20. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/static/js/debug.js +13 -0
  21. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/static/js/nodes.js +64 -20
  22. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode_flow.egg-info/PKG-INFO +171 -68
  23. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode_flow.egg-info/SOURCES.txt +2 -2
  24. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode_flow.egg-info/scm_file_list.json +2 -2
  25. pynode_flow-0.2.6/pynode_flow.egg-info/scm_version.json +8 -0
  26. pynode_flow-0.2.6/tests/test_frame_pacing.py +191 -0
  27. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/tests/test_video_reader_node.py +98 -0
  28. pynode_flow-0.2.4/plan-pynodeRepoReview.prompt.md +0 -117
  29. pynode_flow-0.2.4/plan-pynodeReview-2026-07-18.prompt.md +0 -135
  30. pynode_flow-0.2.4/pynode_flow.egg-info/scm_version.json +0 -8
  31. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/.claude/skills/pynode-workflows/SKILL.md +0 -0
  32. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/.dockerignore +0 -0
  33. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/.github/workflows/ci.yml +0 -0
  34. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/.github/workflows/publish.yaml +0 -0
  35. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/DOCKER.md +0 -0
  36. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/Dockerfile +0 -0
  37. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/Dockerfile.cpu +0 -0
  38. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/INSTALL.md +0 -0
  39. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/LICENSE +0 -0
  40. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/MANIFEST.in +0 -0
  41. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/docker-compose.yml +0 -0
  42. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/docker-entrypoint.sh +0 -0
  43. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/docs/CREATING_NODES.md +0 -0
  44. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/docs/CUSTOM_NODES.md +0 -0
  45. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/docs/DOCKER.md +0 -0
  46. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/docs/EXTENSIBILITY.md +0 -0
  47. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/docs/UI_COMPONENTS.md +0 -0
  48. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/examples/README.md +0 -0
  49. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/examples/camera_workflow.py +0 -0
  50. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/examples/camera_yolo_workflow.py +0 -0
  51. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/install_nodes.bat +0 -0
  52. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/install_nodes.sh +0 -0
  53. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/__init__.py +0 -0
  54. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/__main__.py +0 -0
  55. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/_perf.py +0 -0
  56. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/api/__init__.py +0 -0
  57. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/api/helpers.py +0 -0
  58. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/api/nodes.py +0 -0
  59. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/api/services.py +0 -0
  60. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/api/sse.py +0 -0
  61. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/api/uploads.py +0 -0
  62. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/api/workflows.py +0 -0
  63. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/config.py +0 -0
  64. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/install_nodes.py +0 -0
  65. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/main.py +0 -0
  66. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/node_registry.py +0 -0
  67. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/AutoSyncNode/auto_sync_node.py +0 -0
  68. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/BBoxMetricsNode/__init__.py +0 -0
  69. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/BBoxMetricsNode/bbox_metrics_node.py +0 -0
  70. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/BBoxMetricsNode/requirements.txt +0 -0
  71. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/BatchNode/__init__.py +0 -0
  72. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/BatchNode/batch_node.py +0 -0
  73. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/BatchNode/requirements.txt +0 -0
  74. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/CameraNode/__init__.py +0 -0
  75. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/CameraNode/requirements.txt +0 -0
  76. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/ChangeNode/__init__.py +0 -0
  77. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/ChangeNode/change_node.py +0 -0
  78. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/ChangeNode/requirements.txt +0 -0
  79. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/ConfidenceFilterNode/__init__.py +0 -0
  80. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/ConfidenceFilterNode/confidence_filter_node.py +0 -0
  81. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/ConfidenceFilterNode/requirements.txt +0 -0
  82. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/ControlSliderNode/control_slider_node.py +0 -0
  83. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/CounterNode/__init__.py +0 -0
  84. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/CounterNode/counter_node.py +0 -0
  85. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/CropNode/__init__.py +0 -0
  86. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/CropNode/crop_node.py +0 -0
  87. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/CropNode/requirements.txt +0 -0
  88. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/DebugNode/__init__.py +0 -0
  89. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/DebugNode/debug_node.py +0 -0
  90. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/DebugNode/requirements.txt +0 -0
  91. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/DelayNode/delay_node.py +0 -0
  92. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/DelayNode/requirements.txt +0 -0
  93. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/DrawPredictionsNode/__init__.py +0 -0
  94. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/DrawPredictionsNode/draw_predictions_node.py +0 -0
  95. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/DrawPredictionsNode/requirements.txt +0 -0
  96. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/ErrorNode/error_node.py +0 -0
  97. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/ErrorNode/requirements.txt +0 -0
  98. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/FilterNode/__init__.py +0 -0
  99. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/FilterNode/filter_node.py +0 -0
  100. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/FilterNode/requirements.txt +0 -0
  101. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/FrameSourceNode/__init__.py +0 -0
  102. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/FrameSourceNode/requirements.txt +0 -0
  103. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/FunctionNode/__init__.py +0 -0
  104. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/FunctionNode/function_node.py +0 -0
  105. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/FunctionNode/requirements.txt +0 -0
  106. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/GateNode/gate_node.py +0 -0
  107. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/GateNode/requirements.txt +0 -0
  108. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/ImageFormatNode/__init__.py +0 -0
  109. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/ImageFormatNode/image_format_node.py +0 -0
  110. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/ImageFormatNode/requirements.txt +0 -0
  111. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/ImageViewerNode/__init__.py +0 -0
  112. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/ImageViewerNode/image_viewer_node.py +0 -0
  113. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/ImageViewerNode/requirements.txt +0 -0
  114. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/ImageWriterNode/__init__.py +0 -0
  115. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/ImageWriterNode/imagewriter_node.py +0 -0
  116. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/ImageWriterNode/requirements.txt +0 -0
  117. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/InferenceNode/InferenceEngine/__init__.py +0 -0
  118. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/InferenceNode/InferenceEngine/device_detection.py +0 -0
  119. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/InferenceNode/InferenceEngine/engines/base_engine.py +0 -0
  120. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/InferenceNode/InferenceEngine/engines/example_engine_template.py +0 -0
  121. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/InferenceNode/InferenceEngine/engines/onnx_engine.py +0 -0
  122. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/InferenceNode/InferenceEngine/engines/pass_engine.py +0 -0
  123. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/InferenceNode/InferenceEngine/engines/ultralytics_engine.py +0 -0
  124. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/InferenceNode/InferenceEngine/inference_engine_factory.py +0 -0
  125. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/InferenceNode/InferenceEngine/readme.md +0 -0
  126. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/InferenceNode/InferenceEngine/result_converters.py +0 -0
  127. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/InferenceNode/inference_node.py +0 -0
  128. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/InferenceNode/requirements.txt +0 -0
  129. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/InjectNode/inject_node.py +0 -0
  130. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/InjectNode/requirements.txt +0 -0
  131. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/JoinNode/__init__.py +0 -0
  132. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/JoinNode/join_node.py +0 -0
  133. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/JoinNode/requirements.txt +0 -0
  134. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/LabelFilterNode/__init__.py +0 -0
  135. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/LabelFilterNode/label_filter_node.py +0 -0
  136. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/LabelFilterNode/requirements.txt +0 -0
  137. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/LinkNode/__init__.py +0 -0
  138. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/LinkNode/link_bus.py +0 -0
  139. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/LinkNode/link_in_node.py +0 -0
  140. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/LinkNode/link_out_node.py +0 -0
  141. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/LinkNode/requirements.txt +0 -0
  142. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/MQTTNode/__init__.py +0 -0
  143. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/MQTTNode/mqtt_in_node.py +0 -0
  144. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/MQTTNode/mqtt_out_node.py +0 -0
  145. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/MQTTNode/mqtt_service.py +0 -0
  146. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/MQTTNode/requirements.txt +0 -0
  147. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/MessageWriterNode/__init__.py +0 -0
  148. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/MessageWriterNode/messagereader_node.py +0 -0
  149. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/MessageWriterNode/messagewriter_node.py +0 -0
  150. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/OmronCameraNode/__init__.py +0 -0
  151. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/OmronCameraNode/requirements.txt +0 -0
  152. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/OpenCV/__init__.py +0 -0
  153. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/OpenCV/arithmetic_node.py +0 -0
  154. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/OpenCV/bitwise_node.py +0 -0
  155. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/OpenCV/blend_node.py +0 -0
  156. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/OpenCV/blob_detector_node.py +0 -0
  157. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/OpenCV/blur_node.py +0 -0
  158. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/OpenCV/color_space_node.py +0 -0
  159. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/OpenCV/colormap_node.py +0 -0
  160. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/OpenCV/contours_node.py +0 -0
  161. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/OpenCV/denormalize_coords_node.py +0 -0
  162. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/OpenCV/draw_node.py +0 -0
  163. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/OpenCV/edge_detector_node.py +0 -0
  164. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/OpenCV/equirectangular_node.py +0 -0
  165. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/OpenCV/fft_node.py +0 -0
  166. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/OpenCV/focus_estimation_node.py +0 -0
  167. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/OpenCV/frequency_filter_node.py +0 -0
  168. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/OpenCV/histogram_node.py +0 -0
  169. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/OpenCV/hough_circles_node.py +0 -0
  170. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/OpenCV/hough_lines_node.py +0 -0
  171. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/OpenCV/in_range_node.py +0 -0
  172. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/OpenCV/morphology_node.py +0 -0
  173. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/OpenCV/normalize_coords_node.py +0 -0
  174. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/OpenCV/paste_node.py +0 -0
  175. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/OpenCV/perspective_node.py +0 -0
  176. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/OpenCV/realsense_depth_node.py +0 -0
  177. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/OpenCV/requirements.txt +0 -0
  178. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/OpenCV/resize_node.py +0 -0
  179. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/OpenCV/rotate_node.py +0 -0
  180. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/OpenCV/template_match_node.py +0 -0
  181. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/OpenCV/threshold_node.py +0 -0
  182. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/PointInShapeNode/__init__.py +0 -0
  183. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/PointInShapeNode/point_in_shape_node.py +0 -0
  184. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/PointInShapeNode/requirements.txt +0 -0
  185. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/PolygonMetricsNode/__init__.py +0 -0
  186. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/PolygonMetricsNode/polygon_metrics_node.py +0 -0
  187. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/PolygonMetricsNode/requirements.txt +0 -0
  188. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/QueueLengthProbeNode/__init__.py +0 -0
  189. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/QueueLengthProbeNode/queue_length_probe_node.py +0 -0
  190. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/Qwen3VLMNode/__init__.py +0 -0
  191. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/Qwen3VLMNode/qwen3_vlm_node.py +0 -0
  192. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/Qwen3VLMNode/requirements.txt +0 -0
  193. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/RESTEndpointNode/__init__.py +0 -0
  194. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/RESTEndpointNode/rest_endpoint_node.py +0 -0
  195. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/RangeNode/__init__.py +0 -0
  196. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/RangeNode/range_node.py +0 -0
  197. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/RangeNode/requirements.txt +0 -0
  198. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/RateProbeNode/__init__.py +0 -0
  199. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/RateProbeNode/rate_probe_node.py +0 -0
  200. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/RateProbeNode/requirements.txt +0 -0
  201. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/RoboflowUploadNode/__init__.py +0 -0
  202. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/RoboflowUploadNode/requirements.txt +0 -0
  203. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/RoboflowUploadNode/roboflow_upload_node.py +0 -0
  204. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/SliceNode/README.md +0 -0
  205. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/SliceNode/__init__.py +0 -0
  206. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/SliceNode/merge_predictions_node.py +0 -0
  207. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/SliceNode/requirements.txt +0 -0
  208. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/SocketNode/__init__.py +0 -0
  209. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/SocketNode/interop/README.md +0 -0
  210. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/SocketNode/interop/nodered-example-flow.json +0 -0
  211. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/SocketNode/nodered_snippets.py +0 -0
  212. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/SocketNode/requirements.txt +0 -0
  213. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/SocketNode/tcp_in_node.py +0 -0
  214. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/SocketNode/tcp_out_node.py +0 -0
  215. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/SocketNode/udp_out_node.py +0 -0
  216. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/SocketNode/udp_probe.py +0 -0
  217. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/SplitNode/__init__.py +0 -0
  218. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/SplitNode/requirements.txt +0 -0
  219. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/SplitNode/split_node.py +0 -0
  220. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/SwitchNode/requirements.txt +0 -0
  221. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/SwitchNode/switch_node.py +0 -0
  222. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/SyncNode/__init__.py +0 -0
  223. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/SyncNode/sync_node.py +0 -0
  224. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/TemplateNode/requirements.txt +0 -0
  225. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/TemplateNode/template_node.py +0 -0
  226. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/TrackerNode/__init__.py +0 -0
  227. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/TrackerNode/tracker_node.py +0 -0
  228. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/UltralyticsNode/__init__.py +0 -0
  229. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/UltralyticsNode/model_paths.py +0 -0
  230. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/UltralyticsNode/requirements.txt +0 -0
  231. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/UltralyticsNode/ultralytics_node.py +0 -0
  232. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/UnknownNode/__init__.py +0 -0
  233. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/VLLMNode/__init__.py +0 -0
  234. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/VLLMNode/vllm_node.py +0 -0
  235. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/VideoReaderNode/__init__.py +0 -0
  236. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/VideoWriterNode/__init__.py +0 -0
  237. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/VideoWriterNode/video_writer_node.py +0 -0
  238. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/WebhookNode/__init__.py +0 -0
  239. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/WebhookNode/webhook_node.py +0 -0
  240. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/__init__.py +0 -0
  241. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/image_utils.py +0 -0
  242. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/info.py +0 -0
  243. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/mDNSNode/__init__.py +0 -0
  244. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/mDNSNode/mdns_broadcast_node.py +0 -0
  245. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/mDNSNode/mdns_discovery_node.py +0 -0
  246. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/mDNSNode/mdns_manager.py +0 -0
  247. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/mDNSNode/requirements.txt +0 -0
  248. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/messages.py +0 -0
  249. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/server.py +0 -0
  250. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/static/examples/01-hello-world.json +0 -0
  251. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/static/examples/02-function-transform.json +0 -0
  252. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/static/examples/03-switch-routing.json +0 -0
  253. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/static/examples/04-flow-control.json +0 -0
  254. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/static/examples/05-webcam-viewer.json +0 -0
  255. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/static/examples/06-webcam-yolo.json +0 -0
  256. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/static/examples/07-blur-people.json +0 -0
  257. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/static/examples/08-video-yolo-recorder.json +0 -0
  258. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/static/examples/09-mqtt-pub-sub.json +0 -0
  259. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/static/examples/10-person-alert-mqtt.json +0 -0
  260. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/static/examples/16-socket-bridge.json +0 -0
  261. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/static/examples/17-slider-crop.json +0 -0
  262. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/static/images/favicon4.png +0 -0
  263. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/static/index.html +0 -0
  264. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/static/js/README.md +0 -0
  265. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/static/js/auth.js +0 -0
  266. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/static/js/clipboard.js +0 -0
  267. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/static/js/config.js +0 -0
  268. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/static/js/connections.js +0 -0
  269. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/static/js/events.js +0 -0
  270. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/static/js/history.js +0 -0
  271. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/static/js/main.js +0 -0
  272. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/static/js/minimap.js +0 -0
  273. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/static/js/mqtt-services.js +0 -0
  274. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/static/js/palette.js +0 -0
  275. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/static/js/properties.js +0 -0
  276. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/static/js/selection.js +0 -0
  277. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/static/js/state.js +0 -0
  278. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/static/js/ui-utils.js +0 -0
  279. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/static/js/viewport.js +0 -0
  280. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/static/js/workflow.js +0 -0
  281. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/static/js/workflows.js +0 -0
  282. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/static/style.css +0 -0
  283. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/workflow_engine.py +0 -0
  284. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/workflow_manager.py +0 -0
  285. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode_flow.egg-info/dependency_links.txt +0 -0
  286. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode_flow.egg-info/entry_points.txt +0 -0
  287. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode_flow.egg-info/requires.txt +0 -0
  288. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode_flow.egg-info/top_level.txt +0 -0
  289. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pyproject.toml +0 -0
  290. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/requirements.txt +0 -0
  291. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/setup.bat +0 -0
  292. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/setup.cfg +0 -0
  293. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/setup.py +0 -0
  294. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/setup.sh +0 -0
  295. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/tests/__init__.py +0 -0
  296. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/tests/conftest.py +0 -0
  297. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/tests/test_api_auth.py +0 -0
  298. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/tests/test_api_errors.py +0 -0
  299. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/tests/test_api_nodes.py +0 -0
  300. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/tests/test_api_security.py +0 -0
  301. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/tests/test_api_workflows.py +0 -0
  302. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/tests/test_base_node_messaging.py +0 -0
  303. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/tests/test_camera_node_backend.py +0 -0
  304. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/tests/test_concurrency.py +0 -0
  305. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/tests/test_config.py +0 -0
  306. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/tests/test_control_slider_node.py +0 -0
  307. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/tests/test_counter_sse.py +0 -0
  308. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/tests/test_crop_node.py +0 -0
  309. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/tests/test_debug_workflow_scope.py +0 -0
  310. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/tests/test_delay_rate_limit.py +0 -0
  311. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/tests/test_device_detection.py +0 -0
  312. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/tests/test_function_node.py +0 -0
  313. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/tests/test_image_upload_node.py +0 -0
  314. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/tests/test_link_nodes.py +0 -0
  315. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/tests/test_message_reader_pickle.py +0 -0
  316. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/tests/test_models_dir.py +0 -0
  317. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/tests/test_mqtt_services.py +0 -0
  318. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/tests/test_node_registration.py +0 -0
  319. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/tests/test_node_types_api.py +0 -0
  320. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/tests/test_persistence.py +0 -0
  321. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/tests/test_range_node.py +0 -0
  322. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/tests/test_send_copy_semantics.py +0 -0
  323. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/tests/test_serialization.py +0 -0
  324. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/tests/test_socket_nodes.py +0 -0
  325. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/tests/test_workflow_engine.py +0 -0
  326. {pynode_flow-0.2.4 → pynode_flow-0.2.6}/tests/test_workflow_roundtrip.py +0 -0
@@ -196,3 +196,6 @@ checkpoints/
196
196
  output/
197
197
  output_low/
198
198
  output_not/
199
+
200
+ # Working prompt / plan files (local scratch, not part of the project)
201
+ *.prompt.md
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pynode-flow
3
- Version: 0.2.4
3
+ Version: 0.2.6
4
4
  Summary: Python based Node-RED-like visual workflow system
5
5
  Author: olkham
6
6
  License-Expression: MIT
@@ -76,26 +76,41 @@ https://github.com/user-attachments/assets/0b53085a-2cc6-4c26-bd43-e0de1e0716a2
76
76
  - **Fully Extensible**: Third-party nodes can be added without modifying core code
77
77
  - **UI Components**: Nodes can define interactive controls (buttons, toggles, displays) in their cards
78
78
  - **Node-RED Compatible Messages**: Message structure with `payload` and `topic` fields
79
- - **Built-in Nodes**:
80
- - **InjectNode**: Generate messages with configurable payloads
81
- - **FunctionNode**: Execute custom Python code on messages
82
- - **DebugNode**: Display messages in the debug panel
83
- - **ChangeNode**: Modify message properties
84
- - **SwitchNode**: Route messages based on conditions
85
- - **DelayNode**: Delay message delivery
86
- - **GateNode**: Control message flow with real-time toggle
87
- - **LinkNode**: Pass messages between flows via named channels (Link In / Link Out)
88
- - **RateProbeNode**: Monitor message throughput
89
- - **QueueLengthProbeNode**: Monitor queue lengths
90
- - **CounterNode**: Count messages
91
- - **MQTTNode**: MQTT communication
92
- - **MessageWriterNode**: Save message data
93
- - **VideoWriterNode**: Save video output
94
- - **Vision Nodes**: Camera input, YOLO detection, tracking, image processing, display, and file output
79
+ - **Multiple Workspaces**: Several independent flows, each with its own deploy/run state
95
80
  - **REST API**: Complete API for programmatic workflow management
96
81
  - **Export/Import**: Save and load workflows as JSON
97
82
  - **Dynamic Properties**: Node properties and UI components defined in node classes
98
83
 
84
+ ### Built-in Nodes
85
+
86
+ Around 85 node types ship with PyNode, grouped by palette category. Every node
87
+ carries its own documentation in the editor's **Information** panel (ℹ️ tab).
88
+
89
+ | Category | Nodes |
90
+ | --- | --- |
91
+ | **Common** | Inject, Debug, Link In / Link Out (named channels between flows) |
92
+ | **Function** | Function (custom Python), Change, Filter, Delay, Batch, Join, Split, Range, Slider |
93
+ | **Input** | Camera, Frame Source, Video Reader, Image Upload, Message Reader, Omron Camera |
94
+ | **Output** | Image Viewer, Image Writer, Video Writer, Message Writer, Roboflow Upload |
95
+ | **Logic** | Switch (route on conditions), Gate, Sync, Auto Sync |
96
+ | **Network** | MQTT In / Out, UDP In / Out, TCP In / Out, REST Endpoint, Webhook, mDNS Broadcast / Discovery |
97
+ | **Vision** | YOLO, Inference, Tracker, Supervision Tracker, Crop, Slice Image / Slice Collector, Draw Predictions, Confidence Filter, Label Filter, Merge Predictions, Image Format, Qwen3-VL, vLLM |
98
+ | **Analysis** | BBox Metrics, Polygon Metrics, Point in Shape |
99
+ | **OpenCV** | ~28 image-processing nodes: Blur, Threshold, Morphology, Edge Detector, Find Contours, Perspective, Resize, Rotate, Colormap, Histogram, FFT, Template Match, RealSense Depth, and more |
100
+ | **Node Probes** | Rate Probe, Queue Length Probe, Counter |
101
+
102
+ Highlights:
103
+
104
+ - **Slider** — an interactive on-card slider that stamps a live value onto any
105
+ `msg` path; drag it and downstream nodes update immediately.
106
+ - **UDP In / Out, TCP In / Out** — move messages (including video frames)
107
+ between PyNode instances or to anything else that speaks the wire format.
108
+ Their Information panel contains a ready-made **Node-RED flow you can copy
109
+ and import**, pre-set to the node's port.
110
+ - **Video Reader** — video-file playback with on-card transport controls.
111
+ - **Inference** — a multi-backend inference node (ONNX Runtime, Ultralytics)
112
+ that discovers available engines at startup.
113
+
99
114
  ## Quick Start
100
115
 
101
116
  ### Install from PyPI (recommended for users)
@@ -116,7 +131,7 @@ pynode
116
131
  or specify a port:
117
132
 
118
133
  ```bash
119
- pynode --port 500
134
+ pynode --port 8080
120
135
  ```
121
136
 
122
137
  See [INSTALL.md](INSTALL.md) for the full list of extras (`vision`, `mqtt`,
@@ -196,10 +211,11 @@ Navigate to `http://localhost:5000`
196
211
 
197
212
  ### Load an Example Workflow
198
213
 
199
- Ten ready-made learning workflows ship with PyNode — from a two-node hello
214
+ Twelve ready-made learning workflows ship with PyNode — from a two-node hello
200
215
  world up to a camera → YOLO → filter → MQTT alert pipeline (including a "blur
201
- every detected person" privacy flow). Load any of them straight from the
202
- editor: **☰ menu → Examples → pick one**, then press **Deploy**. See
216
+ every detected person" privacy flow, a UDP socket bridge and a slider-driven
217
+ crop). Load any of them straight from the editor: **☰ menu → Examples → pick
218
+ one**, then press **Deploy**. See
203
219
  [pynode/static/examples/README.md](pynode/static/examples/README.md) for the
204
220
  guided tour and per-example prerequisites.
205
221
 
@@ -289,58 +305,53 @@ PyNode is designed to be easily extended with custom nodes:
289
305
  ```text
290
306
  pynode/ # Project root
291
307
  ├── pynode/ # Main package
292
- │ ├── __init__.py
293
308
  │ ├── __main__.py # Entry point for 'python -m pynode'
294
309
  │ ├── _version.py # Version (generated by setuptools_scm at build)
295
310
  │ ├── main.py # CLI application
296
- │ ├── server.py # Flask REST API with SSE support
297
- │ ├── workflow_engine.py # Workflow management
298
- │ ├── models/ # ML model storage
311
+ │ ├── config.py # Data/models directory resolution
312
+ │ ├── server.py # Flask app factory, static routes, auth
313
+ │ ├── node_registry.py # Node type discovery and metadata cache
314
+ │ ├── workflow_engine.py # Message routing and node execution
315
+ │ ├── workflow_manager.py # Multiple workflows, persistence and backups
316
+ │ ├── install_nodes.py # 'pynode-install-nodes' per-node dependency installer
317
+ │ ├── api/ # REST API blueprints
318
+ │ │ ├── nodes.py # Node CRUD, actions, frames, uploads
319
+ │ │ ├── workflows.py # Workflow + multi-workflow endpoints
320
+ │ │ ├── services.py # Shared services (MQTT brokers)
321
+ │ │ ├── sse.py # Server-sent events (debug stream)
322
+ │ │ └── uploads.py
299
323
  │ ├── nodes/ # Node implementations (each in its own folder)
300
- │ │ ├── __init__.py
301
324
  │ │ ├── base_node.py # BaseNode class
325
+ │ │ ├── info.py # Info builder for node help panels
326
+ │ │ ├── messages.py # Message construction helpers
302
327
  │ │ ├── InjectNode/ # Generate messages
303
328
  │ │ ├── FunctionNode/ # Custom Python code
304
- │ │ ├── DebugNode/ # Debug output
305
- │ │ ├── ChangeNode/ # Modify messages
306
- │ │ ├── SwitchNode/ # Route based on conditions
307
- │ │ ├── DelayNode/ # Delay messages
308
- │ │ ├── GateNode/ # Control message flow
309
- │ │ ├── RateProbeNode/ # Monitor throughput
310
- │ │ ├── QueueLengthProbeNode/ # Monitor queue lengths
311
- │ │ ├── CounterNode/ # Count messages
312
- │ │ ├── CameraNode/ # Camera input
329
+ │ │ ├── SocketNode/ # UDP/TCP nodes + Node-RED interop flow
313
330
  │ │ ├── UltralyticsNode/ # YOLO detection
314
- │ │ ├── ImageViewerNode/ # Display images
315
- │ │ ├── ImageWriterNode/ # Save images
316
- │ │ ├── TrackerNode/ # Object tracking
317
- │ │ ├── MQTTNode/ # MQTT communication
318
- │ │ ├── MessageWriterNode/ # Save message data
319
- │ │ ├── VideoWriterNode/ # Save video
320
- │ │ ├── OpenCV/ # OpenCV operations
321
- │ │ └── ... # 30+ other node types
331
+ │ │ ├── InferenceNode/ # Multi-backend inference engines
332
+ │ │ ├── OpenCV/ # ~28 OpenCV operations
333
+ │ │ └── ... # ~50 node folders in total
322
334
  │ └── static/ # Web UI
323
335
  │ ├── index.html
324
336
  │ ├── style.css
325
- │ ├── js/ # JavaScript modules
326
- │ │ ├── nodes.js
327
- │ │ ├── events.js
328
- │ │ ├── connections.js
329
- │ │ ├── debug.js
337
+ │ ├── js/ # JavaScript modules (ES modules, no build step)
338
+ │ │ ├── main.js # Entry point
339
+ │ │ ├── nodes.js # Node rendering
340
+ │ │ ├── properties.js # Properties panel
341
+ │ │ ├── selection.js # Selection + Information panel
330
342
  │ │ └── ...
343
+ │ ├── examples/ # Bundled example workflows + manifest.json
331
344
  │ └── images/ # UI assets
332
- ├── examples/ # Example workflows and tutorials
333
- │ ├── camera_workflow.py
334
- │ ├── camera_yolo_workflow.py
335
- │ └── README.md
336
- ├── readmes/ # Extended documentation
337
- ├── models/ # ML models (YOLO, etc.)
345
+ ├── tests/ # pytest suite
346
+ ├── examples/ # Programmatic (Python API) examples
338
347
  ├── docs/ # Documentation files
339
348
  │ ├── CUSTOM_NODES.md # Guide to creating custom nodes
349
+ │ ├── CREATING_NODES.md # Node authoring reference
340
350
  │ ├── UI_COMPONENTS.md # Guide to node UI components
341
351
  │ └── EXTENSIBILITY.md # Extensibility overview
342
- ├── _backup/ # Workflow backups
343
- ├── setup.py # Package installation
352
+ ├── workflows/ # Persisted workflows (workflow.json + _backups/)
353
+ ├── models/ # Downloaded/exported model weights
354
+ ├── setup.py # Shim; metadata lives in pyproject.toml
344
355
  ├── setup.bat / setup.sh # Setup scripts
345
356
  ├── requirements.txt # Convenience installer (deps live in pyproject.toml)
346
357
  ├── pyproject.toml # Package metadata, dependencies and build config
@@ -349,10 +360,12 @@ pynode/ # Project root
349
360
  ├── docker-compose.yml # Docker compose config
350
361
  ├── Dockerfile # Docker build (CUDA)
351
362
  ├── Dockerfile.cpu # Docker build (CPU only)
352
- ├── README.md
353
- └── workflow.json # Current workflow
363
+ └── README.md
354
364
  ```
355
365
 
366
+ > `workflows/` and `models/` are the defaults for a source checkout; both move
367
+ > with `--data-dir` / `--models-dir` (see above).
368
+
356
369
  ## Creating Custom Nodes
357
370
 
358
371
  PyNode is fully extensible. All node information (visual properties, property schemas, and behavior) is contained within the node class itself. The main application has no hardcoded knowledge of specific node types.
@@ -423,28 +436,59 @@ Messages follow the Node-RED format:
423
436
 
424
437
  ## API Endpoints
425
438
 
439
+ All `/api/` routes require the API key when the server is started with
440
+ `--api-key` (see [Securing PyNode](#securing-pynode)).
441
+
442
+ ### Node types
443
+ - `GET /api/node-types` - Palette metadata for every registered node type
444
+ (properties, colours, info HTML)
445
+
426
446
  ### Nodes
427
447
  - `GET /api/nodes` - List all nodes
428
448
  - `POST /api/nodes` - Create a node
429
449
  - `GET /api/nodes/<id>` - Get node details
430
450
  - `PUT /api/nodes/<id>` - Update node
431
451
  - `DELETE /api/nodes/<id>` - Delete node
432
- - `POST /api/nodes/<id>/<action>` - Trigger node action
452
+ - `POST /api/nodes/<id>/<action>` - Trigger a node action (e.g. inject)
453
+ - `GET|POST /api/nodes/<id>/enabled` - Read or set the node's enabled state
454
+ - `PUT /api/nodes/<id>/position` - Move a node on the canvas
455
+ - `GET /api/nodes/<id>/frame` - Latest frame from an image-producing node
456
+ - `GET /api/nodes/<id>/stream` - MJPEG stream from an image-producing node
457
+ - `GET /api/nodes/<id>/rate` - Throughput for a probe node
433
458
 
434
459
  ### Connections
435
460
  - `POST /api/connections` - Create connection
436
461
  - `DELETE /api/connections` - Delete connection
437
462
 
438
- ### Workflow
463
+ ### Workflow (the active flow)
439
464
  - `GET /api/workflow` - Export workflow
440
465
  - `POST /api/workflow` - Import workflow
441
- - `POST /api/workflow/start` - Start workflow
442
- - `POST /api/workflow/stop` - Stop workflow
466
+ - `POST /api/workflow/deploy-changes` - Deploy (optionally only modified nodes)
467
+ - `POST /api/workflow/restart` - Restart the deployed workflow
468
+ - `POST /api/workflow/stop` - Stop the deployed workflow
469
+ - `POST /api/workflow/save` - Persist to disk
470
+ - `GET /api/workflow/deployed` - The currently deployed definition
443
471
  - `GET /api/workflow/stats` - Get statistics
444
472
 
473
+ ### Workflows (multiple flows)
474
+ - `GET /api/workflows` - List workflows
475
+ - `POST /api/workflows` - Create a workflow
476
+ - `PUT /api/workflows/<id>` - Rename/update a workflow
477
+ - `DELETE /api/workflows/<id>` - Delete a workflow
478
+ - `PUT /api/workflows/active` - Switch the active workflow
479
+
445
480
  ### Debug
446
481
  - `GET /api/nodes/<id>/debug` - Get debug messages
447
482
  - `DELETE /api/nodes/<id>/debug` - Clear debug messages
483
+ - `GET /api/debug/stream` - Server-sent event stream of debug messages
484
+
485
+ ### Other
486
+ - `GET /api/version` - Running PyNode version
487
+ - `GET /api/link-channels` - Known Link In/Out channel names
488
+ - `GET|POST /api/services/mqtt`, `GET|PUT|DELETE /api/services/mqtt/<id>`,
489
+ `POST /api/services/mqtt/test` - Shared MQTT broker definitions
490
+ - `POST /api/upload/file`, `POST /api/nodes/<id>/upload_image`,
491
+ `POST /api/nodes/<id>/upload_video` - File uploads
448
492
 
449
493
  ## Example Programmatic Usage
450
494
 
@@ -479,12 +523,16 @@ print(messages)
479
523
 
480
524
  1. **Add Nodes**: Drag nodes from the palette onto the canvas
481
525
  2. **Connect Nodes**: Click an output port and drag to an input port
482
- 3. **Configure Nodes**: Click a node to show its properties panel
526
+ 3. **Configure Nodes**: Click a node to show its properties panel; the **ℹ️
527
+ Information** tab in the right sidebar documents the selected node
483
528
  4. **Test Workflow**:
484
- - Click **Start** to activate the workflow
529
+ - Click **Deploy** to activate the workflow (the ▼ menu offers Deploy
530
+ Modified / Full, Restart and Stop)
485
531
  - Use the **Inject** button on inject nodes to send messages
486
- - View output in the debug panel at the bottom
487
- 5. **Save/Load**: Use Export/Import buttons to save workflows
532
+ - View output in the **🐛 Debug** tab of the right sidebar
533
+ 5. **Multiple Flows**: Use the **+** tab to add another workspace; each flow
534
+ deploys and runs independently
535
+ 6. **Save/Load**: Use ☰ menu → Export / Import to save workflows as JSON
488
536
 
489
537
  ## Extending the System
490
538
 
@@ -528,7 +576,7 @@ Nodes can:
528
576
  - ⬜ SAM3 Node
529
577
  - ✅ REST Endpoint Node
530
578
  - ✅ Webhook Node
531
- - ⬜ UDP/TCP Node
579
+ - ✅ UDP/TCP Node
532
580
 
533
581
  ### Example Flow Documentation Needed
534
582
  - ⬜ Bird seed level monitor
@@ -541,9 +589,64 @@ Nodes can:
541
589
  - ✅ YOLO: Add custom model support
542
590
  - ✅ YOLO: Add custom target HW string
543
591
  - ⬜ Roboflow: RF-DETR
544
- - ⬜ Roboflow: Upload images
592
+ - ✅ Roboflow: Upload images
545
593
  - ⬜ DeepSort: Add option to use a different feature extractor model
546
594
 
595
+ ## Changelog
596
+
597
+ Versions follow the `vX.Y.Z` git tags. The running build is shown next to the
598
+ title in the editor and returned by `GET /api/version`.
599
+
600
+ ### 0.2.4
601
+
602
+ **New nodes**
603
+
604
+ - **UDP In / Out** and **TCP In / Out** (`SocketNode`) — move messages,
605
+ including video frames, between PyNode instances or any program that speaks
606
+ the wire format. UDP uses a chunked binary protocol (PNB1) for large
607
+ payloads; TCP uses newline-delimited JSON. Each node's Information panel
608
+ carries a **copy-and-import Node-RED flow** pre-set to that node's port,
609
+ with a worked interop example and a standalone `udp_probe.py` diagnostic in
610
+ `pynode/nodes/SocketNode/interop/`.
611
+ - **Slider** (`ControlSliderNode`) — an interactive on-card slider that stamps
612
+ a live value onto any `msg` path, with *Send on Change* to emit while
613
+ dragging even with no input wired.
614
+
615
+ **Improvements**
616
+
617
+ - **Range** node: configurable output format.
618
+ - **Crop** node: custom-path bbox source with format and coordinate-space
619
+ selectors.
620
+ - **Image Upload** node: *Repeat Send* re-emits the image at a set rate (and
621
+ the pacing bug that capped 30fps at ~11fps is fixed).
622
+ - **Function** node: built-in code templates.
623
+ - Wider type hints, payload validation and error handling across nodes.
624
+ - Docker: CUDA 12.6 runtime base image, version reporting, and better CUDA
625
+ detection in `setup.sh`.
626
+ - Two new bundled examples: **UDP Socket Bridge** and **Slider-Driven Crop**.
627
+
628
+ ### 0.2.3
629
+
630
+ - Performance: fewer message copies for nodes with a single output.
631
+ - YOLO node: fixed model storage locations (weights now land in the models
632
+ directory rather than the working directory).
633
+
634
+ ### 0.2.2
635
+
636
+ - **Link In / Link Out** nodes for passing messages between flows by channel
637
+ name.
638
+ - Per-flow debug panel and per-flow run state.
639
+ - Camera and rate-probe fixes; MQTT improvements.
640
+ - The first bundled example workflows and general UI/UX fixes.
641
+
642
+ ### 0.2.1
643
+
644
+ - Removed the end-of-life Geti node and its SDK dependency.
645
+
646
+ ### 0.2.0
647
+
648
+ - First PyPI release as **`pynode-flow`**.
649
+
547
650
  ## License
548
651
 
549
652
  MIT License - Feel free to use and modify.