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.
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/.gitignore +3 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/PKG-INFO +171 -68
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/README.md +170 -67
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/_version.py +3 -3
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/CameraNode/camera_node.py +8 -8
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/FrameSourceNode/frame_source_node.py +8 -8
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/ImageUploadNode/image_upload_node.py +13 -20
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/OmronCameraNode/omron_camera_node.py +7 -7
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/SliceNode/slice_collector_node.py +247 -9
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/SliceNode/slice_image_node.py +124 -15
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/SocketNode/ndjson_protocol.py +3 -1
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/SocketNode/udp_in_node.py +4 -1
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/SocketNode/udp_protocol.py +3 -1
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/TrackerNode/supervision_tracker_node.py +4 -1
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/VideoReaderNode/video_reader_node.py +192 -36
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/base_node.py +14 -8
- pynode_flow-0.2.6/pynode/nodes/pacing.py +124 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/static/examples/README.md +14 -4
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/static/examples/manifest.json +14 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/static/js/debug.js +13 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/static/js/nodes.js +64 -20
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode_flow.egg-info/PKG-INFO +171 -68
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode_flow.egg-info/SOURCES.txt +2 -2
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode_flow.egg-info/scm_file_list.json +2 -2
- pynode_flow-0.2.6/pynode_flow.egg-info/scm_version.json +8 -0
- pynode_flow-0.2.6/tests/test_frame_pacing.py +191 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/tests/test_video_reader_node.py +98 -0
- pynode_flow-0.2.4/plan-pynodeRepoReview.prompt.md +0 -117
- pynode_flow-0.2.4/plan-pynodeReview-2026-07-18.prompt.md +0 -135
- pynode_flow-0.2.4/pynode_flow.egg-info/scm_version.json +0 -8
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/.claude/skills/pynode-workflows/SKILL.md +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/.dockerignore +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/.github/workflows/ci.yml +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/.github/workflows/publish.yaml +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/DOCKER.md +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/Dockerfile +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/Dockerfile.cpu +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/INSTALL.md +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/LICENSE +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/MANIFEST.in +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/docker-compose.yml +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/docker-entrypoint.sh +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/docs/CREATING_NODES.md +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/docs/CUSTOM_NODES.md +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/docs/DOCKER.md +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/docs/EXTENSIBILITY.md +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/docs/UI_COMPONENTS.md +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/examples/README.md +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/examples/camera_workflow.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/examples/camera_yolo_workflow.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/install_nodes.bat +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/install_nodes.sh +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/__init__.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/__main__.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/_perf.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/api/__init__.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/api/helpers.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/api/nodes.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/api/services.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/api/sse.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/api/uploads.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/api/workflows.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/config.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/install_nodes.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/main.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/node_registry.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/AutoSyncNode/auto_sync_node.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/BBoxMetricsNode/__init__.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/BBoxMetricsNode/bbox_metrics_node.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/BBoxMetricsNode/requirements.txt +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/BatchNode/__init__.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/BatchNode/batch_node.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/BatchNode/requirements.txt +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/CameraNode/__init__.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/CameraNode/requirements.txt +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/ChangeNode/__init__.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/ChangeNode/change_node.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/ChangeNode/requirements.txt +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/ConfidenceFilterNode/__init__.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/ConfidenceFilterNode/confidence_filter_node.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/ConfidenceFilterNode/requirements.txt +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/ControlSliderNode/control_slider_node.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/CounterNode/__init__.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/CounterNode/counter_node.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/CropNode/__init__.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/CropNode/crop_node.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/CropNode/requirements.txt +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/DebugNode/__init__.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/DebugNode/debug_node.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/DebugNode/requirements.txt +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/DelayNode/delay_node.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/DelayNode/requirements.txt +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/DrawPredictionsNode/__init__.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/DrawPredictionsNode/draw_predictions_node.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/DrawPredictionsNode/requirements.txt +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/ErrorNode/error_node.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/ErrorNode/requirements.txt +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/FilterNode/__init__.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/FilterNode/filter_node.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/FilterNode/requirements.txt +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/FrameSourceNode/__init__.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/FrameSourceNode/requirements.txt +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/FunctionNode/__init__.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/FunctionNode/function_node.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/FunctionNode/requirements.txt +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/GateNode/gate_node.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/GateNode/requirements.txt +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/ImageFormatNode/__init__.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/ImageFormatNode/image_format_node.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/ImageFormatNode/requirements.txt +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/ImageViewerNode/__init__.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/ImageViewerNode/image_viewer_node.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/ImageViewerNode/requirements.txt +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/ImageWriterNode/__init__.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/ImageWriterNode/imagewriter_node.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/ImageWriterNode/requirements.txt +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/InferenceNode/InferenceEngine/__init__.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/InferenceNode/InferenceEngine/device_detection.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/InferenceNode/InferenceEngine/engines/base_engine.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/InferenceNode/InferenceEngine/engines/example_engine_template.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/InferenceNode/InferenceEngine/engines/onnx_engine.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/InferenceNode/InferenceEngine/engines/pass_engine.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/InferenceNode/InferenceEngine/engines/ultralytics_engine.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/InferenceNode/InferenceEngine/inference_engine_factory.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/InferenceNode/InferenceEngine/readme.md +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/InferenceNode/InferenceEngine/result_converters.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/InferenceNode/inference_node.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/InferenceNode/requirements.txt +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/InjectNode/inject_node.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/InjectNode/requirements.txt +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/JoinNode/__init__.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/JoinNode/join_node.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/JoinNode/requirements.txt +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/LabelFilterNode/__init__.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/LabelFilterNode/label_filter_node.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/LabelFilterNode/requirements.txt +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/LinkNode/__init__.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/LinkNode/link_bus.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/LinkNode/link_in_node.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/LinkNode/link_out_node.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/LinkNode/requirements.txt +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/MQTTNode/__init__.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/MQTTNode/mqtt_in_node.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/MQTTNode/mqtt_out_node.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/MQTTNode/mqtt_service.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/MQTTNode/requirements.txt +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/MessageWriterNode/__init__.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/MessageWriterNode/messagereader_node.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/MessageWriterNode/messagewriter_node.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/OmronCameraNode/__init__.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/OmronCameraNode/requirements.txt +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/OpenCV/__init__.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/OpenCV/arithmetic_node.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/OpenCV/bitwise_node.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/OpenCV/blend_node.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/OpenCV/blob_detector_node.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/OpenCV/blur_node.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/OpenCV/color_space_node.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/OpenCV/colormap_node.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/OpenCV/contours_node.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/OpenCV/denormalize_coords_node.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/OpenCV/draw_node.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/OpenCV/edge_detector_node.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/OpenCV/equirectangular_node.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/OpenCV/fft_node.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/OpenCV/focus_estimation_node.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/OpenCV/frequency_filter_node.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/OpenCV/histogram_node.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/OpenCV/hough_circles_node.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/OpenCV/hough_lines_node.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/OpenCV/in_range_node.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/OpenCV/morphology_node.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/OpenCV/normalize_coords_node.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/OpenCV/paste_node.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/OpenCV/perspective_node.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/OpenCV/realsense_depth_node.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/OpenCV/requirements.txt +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/OpenCV/resize_node.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/OpenCV/rotate_node.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/OpenCV/template_match_node.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/OpenCV/threshold_node.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/PointInShapeNode/__init__.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/PointInShapeNode/point_in_shape_node.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/PointInShapeNode/requirements.txt +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/PolygonMetricsNode/__init__.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/PolygonMetricsNode/polygon_metrics_node.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/PolygonMetricsNode/requirements.txt +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/QueueLengthProbeNode/__init__.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/QueueLengthProbeNode/queue_length_probe_node.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/Qwen3VLMNode/__init__.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/Qwen3VLMNode/qwen3_vlm_node.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/Qwen3VLMNode/requirements.txt +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/RESTEndpointNode/__init__.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/RESTEndpointNode/rest_endpoint_node.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/RangeNode/__init__.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/RangeNode/range_node.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/RangeNode/requirements.txt +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/RateProbeNode/__init__.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/RateProbeNode/rate_probe_node.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/RateProbeNode/requirements.txt +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/RoboflowUploadNode/__init__.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/RoboflowUploadNode/requirements.txt +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/RoboflowUploadNode/roboflow_upload_node.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/SliceNode/README.md +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/SliceNode/__init__.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/SliceNode/merge_predictions_node.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/SliceNode/requirements.txt +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/SocketNode/__init__.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/SocketNode/interop/README.md +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/SocketNode/interop/nodered-example-flow.json +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/SocketNode/nodered_snippets.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/SocketNode/requirements.txt +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/SocketNode/tcp_in_node.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/SocketNode/tcp_out_node.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/SocketNode/udp_out_node.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/SocketNode/udp_probe.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/SplitNode/__init__.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/SplitNode/requirements.txt +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/SplitNode/split_node.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/SwitchNode/requirements.txt +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/SwitchNode/switch_node.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/SyncNode/__init__.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/SyncNode/sync_node.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/TemplateNode/requirements.txt +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/TemplateNode/template_node.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/TrackerNode/__init__.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/TrackerNode/tracker_node.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/UltralyticsNode/__init__.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/UltralyticsNode/model_paths.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/UltralyticsNode/requirements.txt +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/UltralyticsNode/ultralytics_node.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/UnknownNode/__init__.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/VLLMNode/__init__.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/VLLMNode/vllm_node.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/VideoReaderNode/__init__.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/VideoWriterNode/__init__.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/VideoWriterNode/video_writer_node.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/WebhookNode/__init__.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/WebhookNode/webhook_node.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/__init__.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/image_utils.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/info.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/mDNSNode/__init__.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/mDNSNode/mdns_broadcast_node.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/mDNSNode/mdns_discovery_node.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/mDNSNode/mdns_manager.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/mDNSNode/requirements.txt +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/nodes/messages.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/server.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/static/examples/01-hello-world.json +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/static/examples/02-function-transform.json +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/static/examples/03-switch-routing.json +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/static/examples/04-flow-control.json +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/static/examples/05-webcam-viewer.json +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/static/examples/06-webcam-yolo.json +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/static/examples/07-blur-people.json +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/static/examples/08-video-yolo-recorder.json +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/static/examples/09-mqtt-pub-sub.json +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/static/examples/10-person-alert-mqtt.json +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/static/examples/16-socket-bridge.json +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/static/examples/17-slider-crop.json +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/static/images/favicon4.png +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/static/index.html +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/static/js/README.md +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/static/js/auth.js +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/static/js/clipboard.js +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/static/js/config.js +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/static/js/connections.js +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/static/js/events.js +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/static/js/history.js +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/static/js/main.js +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/static/js/minimap.js +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/static/js/mqtt-services.js +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/static/js/palette.js +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/static/js/properties.js +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/static/js/selection.js +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/static/js/state.js +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/static/js/ui-utils.js +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/static/js/viewport.js +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/static/js/workflow.js +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/static/js/workflows.js +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/static/style.css +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/workflow_engine.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode/workflow_manager.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode_flow.egg-info/dependency_links.txt +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode_flow.egg-info/entry_points.txt +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode_flow.egg-info/requires.txt +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pynode_flow.egg-info/top_level.txt +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/pyproject.toml +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/requirements.txt +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/setup.bat +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/setup.cfg +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/setup.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/setup.sh +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/tests/__init__.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/tests/conftest.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/tests/test_api_auth.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/tests/test_api_errors.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/tests/test_api_nodes.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/tests/test_api_security.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/tests/test_api_workflows.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/tests/test_base_node_messaging.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/tests/test_camera_node_backend.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/tests/test_concurrency.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/tests/test_config.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/tests/test_control_slider_node.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/tests/test_counter_sse.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/tests/test_crop_node.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/tests/test_debug_workflow_scope.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/tests/test_delay_rate_limit.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/tests/test_device_detection.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/tests/test_function_node.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/tests/test_image_upload_node.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/tests/test_link_nodes.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/tests/test_message_reader_pickle.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/tests/test_models_dir.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/tests/test_mqtt_services.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/tests/test_node_registration.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/tests/test_node_types_api.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/tests/test_persistence.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/tests/test_range_node.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/tests/test_send_copy_semantics.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/tests/test_serialization.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/tests/test_socket_nodes.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/tests/test_workflow_engine.py +0 -0
- {pynode_flow-0.2.4 → pynode_flow-0.2.6}/tests/test_workflow_roundtrip.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pynode-flow
|
|
3
|
-
Version: 0.2.
|
|
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
|
-
- **
|
|
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
|
|
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
|
-
|
|
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
|
|
202
|
-
editor: **☰ menu → Examples → pick
|
|
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
|
-
│ ├──
|
|
297
|
-
│ ├──
|
|
298
|
-
│ ├──
|
|
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
|
-
│ │ ├──
|
|
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
|
-
│ │ ├──
|
|
315
|
-
│ │ ├──
|
|
316
|
-
│ │
|
|
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
|
-
│ │ ├──
|
|
327
|
-
│ │ ├──
|
|
328
|
-
│ │ ├──
|
|
329
|
-
│ │ ├──
|
|
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
|
-
├──
|
|
333
|
-
|
|
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
|
-
├──
|
|
343
|
-
├──
|
|
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
|
-
|
|
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/
|
|
442
|
-
- `POST /api/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 **
|
|
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
|
|
487
|
-
5. **
|
|
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
|
-
-
|
|
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
|
-
-
|
|
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.
|