sinapsis-data-tools 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- sinapsis_data_readers/src/sinapsis_data_readers/__init__.py +0 -0
- sinapsis_data_readers/src/sinapsis_data_readers/helpers/__init__.py +0 -0
- sinapsis_data_readers/src/sinapsis_data_readers/helpers/coco_dataclasses.py +60 -0
- sinapsis_data_readers/src/sinapsis_data_readers/helpers/file_path_helpers.py +69 -0
- sinapsis_data_readers/src/sinapsis_data_readers/helpers/image_color_space_converter.py +53 -0
- sinapsis_data_readers/src/sinapsis_data_readers/helpers/sklearn_dataset_subset.py +17 -0
- sinapsis_data_readers/src/sinapsis_data_readers/helpers/text_input_helpers.py +16 -0
- sinapsis_data_readers/src/sinapsis_data_readers/templates/__init__.py +55 -0
- sinapsis_data_readers/src/sinapsis_data_readers/templates/audio_readers/__init__.py +0 -0
- sinapsis_data_readers/src/sinapsis_data_readers/templates/audio_readers/audio_reader_pydub.py +152 -0
- sinapsis_data_readers/src/sinapsis_data_readers/templates/audio_readers/audio_reader_soundfile.py +129 -0
- sinapsis_data_readers/src/sinapsis_data_readers/templates/audio_readers/audio_reader_to_bytes.py +57 -0
- sinapsis_data_readers/src/sinapsis_data_readers/templates/audio_readers/base_audio_reader.py +57 -0
- sinapsis_data_readers/src/sinapsis_data_readers/templates/base_file_data_loader.py +184 -0
- sinapsis_data_readers/src/sinapsis_data_readers/templates/datasets_readers/__init__.py +0 -0
- sinapsis_data_readers/src/sinapsis_data_readers/templates/datasets_readers/dataset_splitter.py +233 -0
- sinapsis_data_readers/src/sinapsis_data_readers/templates/datasets_readers/sklearn_datasets.py +144 -0
- sinapsis_data_readers/src/sinapsis_data_readers/templates/datasets_readers/sktime_datasets.py +88 -0
- sinapsis_data_readers/src/sinapsis_data_readers/templates/image_readers/__init__.py +0 -0
- sinapsis_data_readers/src/sinapsis_data_readers/templates/image_readers/base_image_folder_data_loader.py +123 -0
- sinapsis_data_readers/src/sinapsis_data_readers/templates/image_readers/coco_dataset_reader.py +357 -0
- sinapsis_data_readers/src/sinapsis_data_readers/templates/image_readers/csv_dataset_reader.py +151 -0
- sinapsis_data_readers/src/sinapsis_data_readers/templates/image_readers/image_folder_reader_cv2.py +83 -0
- sinapsis_data_readers/src/sinapsis_data_readers/templates/text_readers/__init__.py +0 -0
- sinapsis_data_readers/src/sinapsis_data_readers/templates/text_readers/text_input.py +62 -0
- sinapsis_data_readers/src/sinapsis_data_readers/templates/video_readers/__init__.py +0 -0
- sinapsis_data_readers/src/sinapsis_data_readers/templates/video_readers/base_video_reader.py +300 -0
- sinapsis_data_readers/src/sinapsis_data_readers/templates/video_readers/video_reader_cv2.py +96 -0
- sinapsis_data_readers/src/sinapsis_data_readers/templates/video_readers/video_reader_dali.py +235 -0
- sinapsis_data_readers/src/sinapsis_data_readers/templates/video_readers/video_reader_ffmpeg.py +120 -0
- sinapsis_data_readers/src/sinapsis_data_readers/templates/video_readers/video_reader_torchcodec.py +91 -0
- sinapsis_data_tools-0.1.0.dist-info/METADATA +873 -0
- sinapsis_data_tools-0.1.0.dist-info/RECORD +72 -0
- sinapsis_data_tools-0.1.0.dist-info/WHEEL +5 -0
- sinapsis_data_tools-0.1.0.dist-info/top_level.txt +4 -0
- sinapsis_data_visualization/src/__init__.py +0 -0
- sinapsis_data_visualization/src/sinapsis_data_visualization/__init__.py +0 -0
- sinapsis_data_visualization/src/sinapsis_data_visualization/helpers/__init__.py +0 -0
- sinapsis_data_visualization/src/sinapsis_data_visualization/helpers/annotation_drawer_tools.py +252 -0
- sinapsis_data_visualization/src/sinapsis_data_visualization/helpers/annotation_drawer_types.py +56 -0
- sinapsis_data_visualization/src/sinapsis_data_visualization/helpers/color_utils.py +108 -0
- sinapsis_data_visualization/src/sinapsis_data_visualization/helpers/detection_utils.py +124 -0
- sinapsis_data_visualization/src/sinapsis_data_visualization/helpers/plot_distributions.py +130 -0
- sinapsis_data_visualization/src/sinapsis_data_visualization/helpers/scikit_pca_analysis.py +51 -0
- sinapsis_data_visualization/src/sinapsis_data_visualization/templates/__init__.py +25 -0
- sinapsis_data_visualization/src/sinapsis_data_visualization/templates/base_annotation_drawer.py +103 -0
- sinapsis_data_visualization/src/sinapsis_data_visualization/templates/bbox_drawer.py +105 -0
- sinapsis_data_visualization/src/sinapsis_data_visualization/templates/data_distribution_visualization_template.py +245 -0
- sinapsis_data_visualization/src/sinapsis_data_visualization/templates/key_points_drawer.py +122 -0
- sinapsis_data_visualization/src/sinapsis_data_visualization/templates/label_drawer.py +292 -0
- sinapsis_data_visualization/src/sinapsis_data_visualization/templates/oriented_bbox_drawer.py +121 -0
- sinapsis_data_visualization/src/sinapsis_data_visualization/templates/segmentation_mask_drawer.py +137 -0
- sinapsis_data_writers/src/sinapsis_data_writers/__init__.py +0 -0
- sinapsis_data_writers/src/sinapsis_data_writers/templates/__init__.py +26 -0
- sinapsis_data_writers/src/sinapsis_data_writers/templates/annotation_writers/__init__.py +0 -0
- sinapsis_data_writers/src/sinapsis_data_writers/templates/annotation_writers/base_annotation_writer.py +192 -0
- sinapsis_data_writers/src/sinapsis_data_writers/templates/annotation_writers/coco_annotation_writer.py +290 -0
- sinapsis_data_writers/src/sinapsis_data_writers/templates/audio_writers/__init__.py +0 -0
- sinapsis_data_writers/src/sinapsis_data_writers/templates/audio_writers/audio_writer_soundfile.py +121 -0
- sinapsis_data_writers/src/sinapsis_data_writers/templates/image_writers/__init__.py +0 -0
- sinapsis_data_writers/src/sinapsis_data_writers/templates/image_writers/image_saver.py +183 -0
- sinapsis_data_writers/src/sinapsis_data_writers/templates/image_writers/pdf_to_image_converter.py +101 -0
- sinapsis_data_writers/src/sinapsis_data_writers/templates/video_writers/__init__.py +0 -0
- sinapsis_data_writers/src/sinapsis_data_writers/templates/video_writers/base_video_writer.py +129 -0
- sinapsis_data_writers/src/sinapsis_data_writers/templates/video_writers/video_writer_cv2.py +82 -0
- sinapsis_data_writers/src/sinapsis_data_writers/templates/video_writers/video_writer_ffmpeg.py +89 -0
- sinapsis_generic_data_tools/src/sinapsis_generic_data_tools/__init__.py +1 -0
- sinapsis_generic_data_tools/src/sinapsis_generic_data_tools/helpers/__init__.py +0 -0
- sinapsis_generic_data_tools/src/sinapsis_generic_data_tools/helpers/postprocess.py +33 -0
- sinapsis_generic_data_tools/src/sinapsis_generic_data_tools/templates/__init__.py +20 -0
- sinapsis_generic_data_tools/src/sinapsis_generic_data_tools/templates/mask_non_roi.py +99 -0
- sinapsis_generic_data_tools/src/sinapsis_generic_data_tools/templates/packet_buffer_queue.py +127 -0
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
from pydantic.dataclasses import dataclass
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
@dataclass(frozen=True)
|
|
6
|
+
class CocoJsonKeys:
|
|
7
|
+
"""
|
|
8
|
+
Keys to access the annotations dictionary in coco format
|
|
9
|
+
IMAGES (str): Key to access the 'images' entry.
|
|
10
|
+
FILE_NAME (str): Key to access the 'file_name' entry.
|
|
11
|
+
IMAGE_ID (str): Key to access the 'image_id' entry.
|
|
12
|
+
COCO_LICENSE (str): Key to access the 'coco_license' entry.
|
|
13
|
+
COCO_URL (str): Key to access the 'coco_url' entry.
|
|
14
|
+
HEIGHT (str): Key to access the 'height' entry.
|
|
15
|
+
WIDTH (str): Key to access the 'width' entry.
|
|
16
|
+
DATE (str): Key to access the 'date' entry.
|
|
17
|
+
ANNOTATIONS (str): Key to access the 'annotations' entry.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
IMAGES: str = "images"
|
|
21
|
+
FILE_NAME: str = "file_name"
|
|
22
|
+
IMAGE_ID: str = "id"
|
|
23
|
+
COCO_LICENSE: str = "license"
|
|
24
|
+
COCO_URL: str = "coco_url"
|
|
25
|
+
HEIGHT: str = "height"
|
|
26
|
+
WIDTH: str = "width"
|
|
27
|
+
DATE: str = "date_captured"
|
|
28
|
+
ANNOTATIONS: str = "annotations"
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@dataclass(frozen=True)
|
|
32
|
+
class CocoAnnotationsKeys:
|
|
33
|
+
"""
|
|
34
|
+
Keys to access the annotations fields in the coco-format annotations
|
|
35
|
+
IMAGE_ID (str): key to access the 'image_id' field.
|
|
36
|
+
SEGMENTATIONS (str): key to access the 'segmentations' field.
|
|
37
|
+
BBOX (str): key to access the 'bbox' field.
|
|
38
|
+
ORIENTED_BBOX (str): key to access the 'oriented_bbox' field.
|
|
39
|
+
ANNOTATION_ID (str): key to access the 'annotation_id' field.
|
|
40
|
+
AREA (str): key to access the 'area' field.
|
|
41
|
+
CATEGORY_ID (str): key to access the 'category_id' field.
|
|
42
|
+
IS_CROWD (str): key to access the 'is_crowd' field.
|
|
43
|
+
NUM_KEYPOINTS (str): key to access the 'num_keypoints' field.
|
|
44
|
+
KEYPOINTS (str): key to access the 'keypoints' field.
|
|
45
|
+
SEGMENTS_INFO (str): key to access the 'segments_info' field.
|
|
46
|
+
SCORE (str): key to access the 'score' field.
|
|
47
|
+
"""
|
|
48
|
+
|
|
49
|
+
IMAGE_ID: str = "image_id"
|
|
50
|
+
SEGMENTATIONS: str = "segmentation"
|
|
51
|
+
BBOX: str = "bbox"
|
|
52
|
+
ORIENTED_BBOX: str = "oriented_bbox"
|
|
53
|
+
ANNOTATION_ID: str = "id"
|
|
54
|
+
AREA: str = "area"
|
|
55
|
+
CATEGORY_ID: str = "category_id"
|
|
56
|
+
IS_CROWD: str = "iscrowd"
|
|
57
|
+
NUM_KEYPOINTS: str = "num_keypoints"
|
|
58
|
+
KEYPOINTS: str = "keypoints"
|
|
59
|
+
SEGMENTS_INFO: str = "segments_info"
|
|
60
|
+
SCORE: str = "score"
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def is_regex(fpath: str) -> bool:
|
|
7
|
+
"""
|
|
8
|
+
Determine if the fiven path contains the character (*) indicating that it might be a regular
|
|
9
|
+
expresion or a glob pattern.
|
|
10
|
+
Args:
|
|
11
|
+
fpath (str): the file path to check
|
|
12
|
+
Returns
|
|
13
|
+
(bool): True if the character is in the pattern, false otherwise.
|
|
14
|
+
|
|
15
|
+
"""
|
|
16
|
+
return "*" in fpath
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
SUPPORTED_VIDEO_TYPE_EXT = ["mp4", "wav", "mov"]
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def process_single_path(single_path: str) -> list[str]:
|
|
23
|
+
"""Determines all the paths to be visited according to the single
|
|
24
|
+
path provided
|
|
25
|
+
|
|
26
|
+
Args:
|
|
27
|
+
single_path (str): single path provided
|
|
28
|
+
|
|
29
|
+
Returns:
|
|
30
|
+
list[str]: List of all the paths to be visited when processing the data
|
|
31
|
+
"""
|
|
32
|
+
video_file_paths: list[str] = []
|
|
33
|
+
|
|
34
|
+
if is_regex(single_path):
|
|
35
|
+
search_pattern_start = single_path.find("*")
|
|
36
|
+
search_pattern_end = single_path.rfind("*")
|
|
37
|
+
root_dir = single_path[0:search_pattern_start]
|
|
38
|
+
pattern = single_path[search_pattern_end:]
|
|
39
|
+
video_file_paths += [str(f.resolve()) for f in Path(root_dir).glob(pattern)]
|
|
40
|
+
|
|
41
|
+
elif "." in single_path and single_path.split(".")[-1].lower() in SUPPORTED_VIDEO_TYPE_EXT:
|
|
42
|
+
video_file_paths = [single_path]
|
|
43
|
+
|
|
44
|
+
elif Path(single_path).is_dir():
|
|
45
|
+
for vid_type in SUPPORTED_VIDEO_TYPE_EXT:
|
|
46
|
+
video_file_paths += [str(f.resolve()) for f in Path(single_path).glob(f"**/*{vid_type}")]
|
|
47
|
+
|
|
48
|
+
return video_file_paths
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def parse_file_paths(file_paths: str | list[str]) -> list[str]:
|
|
52
|
+
"""
|
|
53
|
+
Check if the path provided is a single path or a list of paths.
|
|
54
|
+
If it's a single path, parse the content inside.
|
|
55
|
+
If it's a list of paths, loop though the list and parse each of them.
|
|
56
|
+
|
|
57
|
+
Args:
|
|
58
|
+
file_paths (str | list[str]): path or list of paths to parse.
|
|
59
|
+
|
|
60
|
+
Returns:
|
|
61
|
+
list[str]: list of complete paths to process
|
|
62
|
+
"""
|
|
63
|
+
return_file_paths: list[str] = []
|
|
64
|
+
if isinstance(file_paths, str):
|
|
65
|
+
return_file_paths += process_single_path(file_paths)
|
|
66
|
+
elif isinstance(file_paths, list):
|
|
67
|
+
for file_path in file_paths:
|
|
68
|
+
return_file_paths += process_single_path(file_path)
|
|
69
|
+
return return_file_paths
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
from enum import Enum
|
|
3
|
+
|
|
4
|
+
import cv2
|
|
5
|
+
from sinapsis_core.data_containers.data_packet import ImageColor, ImagePacket
|
|
6
|
+
from sinapsis_core.utils.logging_utils import sinapsis_logger
|
|
7
|
+
|
|
8
|
+
color_mapping = {
|
|
9
|
+
(ImageColor.RGB, ImageColor.BGR): cv2.COLOR_RGB2BGR,
|
|
10
|
+
(ImageColor.RGB, ImageColor.GRAY): cv2.COLOR_RGB2GRAY,
|
|
11
|
+
(ImageColor.RGB, ImageColor.RGBA): cv2.COLOR_RGB2RGBA,
|
|
12
|
+
(ImageColor.BGR, ImageColor.RGB): cv2.COLOR_BGR2RGB,
|
|
13
|
+
(ImageColor.BGR, ImageColor.GRAY): cv2.COLOR_BGR2GRAY,
|
|
14
|
+
(ImageColor.BGR, ImageColor.RGBA): cv2.COLOR_BGR2RGBA,
|
|
15
|
+
(ImageColor.GRAY, ImageColor.RGB): cv2.COLOR_GRAY2RGB,
|
|
16
|
+
(ImageColor.GRAY, ImageColor.BGR): cv2.COLOR_GRAY2BGR,
|
|
17
|
+
(ImageColor.GRAY, ImageColor.RGBA): cv2.COLOR_GRAY2RGBA,
|
|
18
|
+
(ImageColor.RGBA, ImageColor.RGB): cv2.COLOR_RGBA2RGB,
|
|
19
|
+
(ImageColor.RGBA, ImageColor.BGR): cv2.COLOR_RGBA2BGR,
|
|
20
|
+
(ImageColor.RGBA, ImageColor.GRAY): cv2.COLOR_RGBA2GRAY,
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def convert_color_space_cv(image: ImagePacket, desired_color_space: Enum) -> ImagePacket:
|
|
25
|
+
"""Converts an image from one color space to another, provided
|
|
26
|
+
they are in the color mapping options.
|
|
27
|
+
|
|
28
|
+
Args:
|
|
29
|
+
image (ImagePacket): Image packet to apply the conversion
|
|
30
|
+
desired_color_space (Enum): Color space to convert the image
|
|
31
|
+
|
|
32
|
+
Returns:
|
|
33
|
+
ImagePacket: Updated ImagePacket with content converted into the new color space
|
|
34
|
+
|
|
35
|
+
Raises:
|
|
36
|
+
ValueError: If the conversion is not possible, return an error.
|
|
37
|
+
|
|
38
|
+
"""
|
|
39
|
+
current_color_space = image.color_space
|
|
40
|
+
|
|
41
|
+
if (current_color_space, desired_color_space) in color_mapping:
|
|
42
|
+
conversion_code = color_mapping[(current_color_space, desired_color_space)]
|
|
43
|
+
try:
|
|
44
|
+
image.content = cv2.cvtColor(image.content, conversion_code)
|
|
45
|
+
image.color_space = desired_color_space
|
|
46
|
+
|
|
47
|
+
except cv2.error:
|
|
48
|
+
sinapsis_logger.error(f"Invalid conversion between {current_color_space} and {desired_color_space}")
|
|
49
|
+
|
|
50
|
+
else:
|
|
51
|
+
raise ValueError(f"Conversion from {current_color_space} to {desired_color_space} is not supported.")
|
|
52
|
+
|
|
53
|
+
return image
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
from typing import Callable
|
|
3
|
+
|
|
4
|
+
from sklearn import datasets
|
|
5
|
+
|
|
6
|
+
_sklearn_supported_loaders = {
|
|
7
|
+
name: getattr(datasets, name) for name in dir(datasets) if name.startswith(("load", "fetch"))
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def __getattr__(name: str) -> Callable:
|
|
12
|
+
if name in _sklearn_supported_loaders:
|
|
13
|
+
return _sklearn_supported_loaders[name]
|
|
14
|
+
raise AttributeError(f"Function `{name}` not found in sklearn.datasets.")
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
__all__ = list(_sklearn_supported_loaders.keys())
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""Module for processing text input from TextPacket objects."""
|
|
3
|
+
|
|
4
|
+
from sinapsis_core.data_containers.data_packet import TextPacket
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def load_input_text(input_data: list[TextPacket]) -> str:
|
|
8
|
+
"""Loads and concatenates the text content of all TextPacket objects into a single string.
|
|
9
|
+
|
|
10
|
+
Args:
|
|
11
|
+
input_data (list[TextPacket]): A list of TextPacket objects containing text content.
|
|
12
|
+
|
|
13
|
+
Returns:
|
|
14
|
+
str: A single string containing the concatenated text from all TextPacket objects.
|
|
15
|
+
"""
|
|
16
|
+
return "".join(t.content for t in input_data)
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
import importlib
|
|
3
|
+
from typing import Callable
|
|
4
|
+
|
|
5
|
+
from sinapsis.templates import _import_template_package
|
|
6
|
+
|
|
7
|
+
_root_lib_path = "sinapsis_data_readers.templates"
|
|
8
|
+
|
|
9
|
+
_template_lookup = {
|
|
10
|
+
"AudioReaderPydub": f"{_root_lib_path}.audio_readers.audio_reader_pydub",
|
|
11
|
+
"AudioReaderSoundfile": f"{_root_lib_path}.audio_readers.audio_reader_soundfile",
|
|
12
|
+
"AudioReaderToBytes": f"{_root_lib_path}.audio_readers.audio_reader_to_bytes",
|
|
13
|
+
"CSVImageDataset": f"{_root_lib_path}.image_readers.csv_dataset_reader",
|
|
14
|
+
"CocoDetectionDatasetCV2": f"{_root_lib_path}.image_readers.coco_dataset_reader",
|
|
15
|
+
"CocoKeypointsDatasetCV2": f"{_root_lib_path}.image_readers.coco_dataset_reader",
|
|
16
|
+
"CocoSegmentationDatasetCV2": f"{_root_lib_path}.image_readers.coco_dataset_reader",
|
|
17
|
+
"ExecuteNTimesAudioReaderPydub": f"{_root_lib_path}.audio_readers.audio_reader_pydub",
|
|
18
|
+
"ExecuteNTimesAudioReaderSoundfile": f"{_root_lib_path}.audio_readers.audio_reader_soundfile",
|
|
19
|
+
"ExecuteNTimesLazyAudioReaderPydub": f"{_root_lib_path}.audio_readers.audio_reader_pydub",
|
|
20
|
+
"ExecuteNTimesLazyAudioReaderSoundfile": f"{_root_lib_path}.audio_readers.audio_reader_soundfile",
|
|
21
|
+
"FolderImageDatasetCV2": f"{_root_lib_path}.image_readers.image_folder_reader_cv2",
|
|
22
|
+
"ImageDatasetSplitter": f"{_root_lib_path}.datasets_readers.dataset_splitter",
|
|
23
|
+
"LazyAudioReaderPydub": f"{_root_lib_path}.audio_readers.audio_reader_pydub",
|
|
24
|
+
"LazyAudioReaderSoundfile": f"{_root_lib_path}.audio_readers.audio_reader_soundfile",
|
|
25
|
+
"MultiVideoReaderCV2": f"{_root_lib_path}.video_readers.video_reader_cv2",
|
|
26
|
+
"MultiVideoReaderDali": f"{_root_lib_path}.video_readers.video_reader_dali",
|
|
27
|
+
"MultiVideoReaderDaliPytorch": f"{_root_lib_path}.video_readers.video_reader_dali",
|
|
28
|
+
"MultiVideoReaderFFMPEG": f"{_root_lib_path}.video_readers.video_reader_ffmpeg",
|
|
29
|
+
"MultiVideoReaderTorchCodec": f"{_root_lib_path}.video_readers.video_reader_torchcodec",
|
|
30
|
+
"TabularDatasetSplitter": f"{_root_lib_path}.datasets_readers.dataset_splitter",
|
|
31
|
+
"TextInput": f"{_root_lib_path}.text_readers.text_input",
|
|
32
|
+
"VideoReaderCV2": f"{_root_lib_path}.video_readers.video_reader_cv2",
|
|
33
|
+
"VideoReaderDali": f"{_root_lib_path}.video_readers.video_reader_dali",
|
|
34
|
+
"VideoReaderDaliPytorch": f"{_root_lib_path}.video_readers.video_reader_dali",
|
|
35
|
+
"VideoReaderFFMPEG": f"{_root_lib_path}.video_readers.video_reader_ffmpeg",
|
|
36
|
+
"VideoReaderTorchCodec": f"{_root_lib_path}.video_readers.video_reader_torchcodec",
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
_ADDITIONAL_TEMPLATE_MODULES = [
|
|
41
|
+
f"{_root_lib_path}.datasets_readers.sklearn_datasets",
|
|
42
|
+
f"{_root_lib_path}.datasets_readers.sktime_datasets",
|
|
43
|
+
]
|
|
44
|
+
for t_module in _ADDITIONAL_TEMPLATE_MODULES:
|
|
45
|
+
_template_lookup |= _import_template_package(t_module)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def __getattr__(name: str) -> Callable:
|
|
49
|
+
if name in _template_lookup:
|
|
50
|
+
module = importlib.import_module(_template_lookup[name])
|
|
51
|
+
return getattr(module, name)
|
|
52
|
+
raise AttributeError(f"template `{name}` not found in {_root_lib_path}")
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
__all__ = list(_template_lookup.keys())
|
|
File without changes
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
import io
|
|
4
|
+
import os
|
|
5
|
+
from typing import cast
|
|
6
|
+
|
|
7
|
+
import numpy as np
|
|
8
|
+
from pydub import AudioSegment
|
|
9
|
+
from sinapsis_core.data_containers.data_packet import AudioPacket, DataContainer
|
|
10
|
+
from sinapsis_core.template_base.multi_execute_template import (
|
|
11
|
+
execute_template_n_times_wrapper,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
from sinapsis_data_readers.templates.audio_readers.base_audio_reader import (
|
|
15
|
+
_AudioBaseReader,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class AudioReaderPydub(_AudioBaseReader):
|
|
20
|
+
"""Audio reader for reading audio data directly from bytes or files using Pydub.
|
|
21
|
+
|
|
22
|
+
This class can read audio data from either a bytes object or a file path,
|
|
23
|
+
using the Pydub library.
|
|
24
|
+
When reading from bytes, it retains the data in byte format.
|
|
25
|
+
When reading from a file, it converts the audio data to a NumPy array.
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
Usage example:
|
|
29
|
+
|
|
30
|
+
agent:
|
|
31
|
+
name: my_test_agent
|
|
32
|
+
templates:
|
|
33
|
+
- template_name: InputTemplate
|
|
34
|
+
class_name: InputTemplate
|
|
35
|
+
attributes: {}
|
|
36
|
+
- template_name: AudioReaderPydub
|
|
37
|
+
class_name: AudioReaderPydub
|
|
38
|
+
template_input: InputTemplate
|
|
39
|
+
attributes:
|
|
40
|
+
audio_file_path: '/path/to/file.mp3'
|
|
41
|
+
source: 'source/of/file'
|
|
42
|
+
sample_rate_khz: 16
|
|
43
|
+
from_bytes: false
|
|
44
|
+
"""
|
|
45
|
+
|
|
46
|
+
class AttributesBaseModel(_AudioBaseReader.AttributesBaseModel):
|
|
47
|
+
"""Attributes for the AudioReaderAudioSegment.
|
|
48
|
+
|
|
49
|
+
Args:
|
|
50
|
+
sample_rate_khz (int):
|
|
51
|
+
Sample rate in khz for the processed audio. Defaults to 16hkz.
|
|
52
|
+
from_bytes (bool):
|
|
53
|
+
Flag to determine if the file is in bytes. Defaults to True
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
"""
|
|
57
|
+
|
|
58
|
+
sample_rate_khz: int = 16
|
|
59
|
+
from_bytes: bool = True
|
|
60
|
+
|
|
61
|
+
def read_file(self) -> AudioPacket | None:
|
|
62
|
+
"""Reads audio data from a file path or bytes and returns an AudioPacket.
|
|
63
|
+
|
|
64
|
+
If reading from bytes, it returns the audio data in bytes format.
|
|
65
|
+
If reading from a file, it returns audio data as a NumPy array.
|
|
66
|
+
|
|
67
|
+
Returns:
|
|
68
|
+
Optional[AudioPacket]: An AudioPacket containing the audio data,
|
|
69
|
+
sample rate, and metadata, or None if there was an error.
|
|
70
|
+
"""
|
|
71
|
+
|
|
72
|
+
audio_data: bytes | np.ndarray
|
|
73
|
+
if self.attributes.from_bytes:
|
|
74
|
+
audio_bytes: bytes = cast(bytes, self.attributes.audio_file_path)
|
|
75
|
+
audio_segment = AudioSegment.from_file(io.BytesIO(audio_bytes))
|
|
76
|
+
|
|
77
|
+
else:
|
|
78
|
+
audio_file_path: str = cast(str, self.attributes.audio_file_path)
|
|
79
|
+
if os.path.exists(audio_file_path):
|
|
80
|
+
audio_segment = AudioSegment.from_file(audio_file_path, format="wav")
|
|
81
|
+
|
|
82
|
+
else:
|
|
83
|
+
self.logger.error("Invalid audio file path: %s", audio_file_path)
|
|
84
|
+
return None
|
|
85
|
+
audio_segment = audio_segment.set_frame_rate(self.attributes.sample_rate_khz * 1000)
|
|
86
|
+
audio_segment = audio_segment.set_channels(1)
|
|
87
|
+
|
|
88
|
+
audio_data = np.array(audio_segment.get_array_of_samples(), dtype=np.float32)
|
|
89
|
+
audio_data = audio_data / (2**15)
|
|
90
|
+
|
|
91
|
+
audio_packet = AudioPacket(
|
|
92
|
+
source=self.attributes.source,
|
|
93
|
+
content=audio_data,
|
|
94
|
+
sample_rate=audio_segment.frame_rate,
|
|
95
|
+
)
|
|
96
|
+
return audio_packet
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
@execute_template_n_times_wrapper
|
|
100
|
+
class ExecuteNTimesAudioReaderPydub(AudioReaderPydub):
|
|
101
|
+
"""
|
|
102
|
+
This template provides functionality to read multiple audios, each of them assigned to
|
|
103
|
+
its own DataContainer and to its own reader process.
|
|
104
|
+
Similar to its base class, it reads the audios using the Pydub library
|
|
105
|
+
"""
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
class LazyAudioReaderPydub(AudioReaderPydub):
|
|
109
|
+
"""Reads an audio file using Pydub, obtaining the file path
|
|
110
|
+
from the generic_field of the DataContainer and setting is as the file_path in the attributes.
|
|
111
|
+
|
|
112
|
+
Usage example:
|
|
113
|
+
|
|
114
|
+
agent:
|
|
115
|
+
name: my_test_agent
|
|
116
|
+
templates:
|
|
117
|
+
- template_name: InputTemplate
|
|
118
|
+
class_name: InputTemplate
|
|
119
|
+
attributes: {}
|
|
120
|
+
- template_name: LazyAudioReaderPydub
|
|
121
|
+
class_name: LazyAudioReaderPydub
|
|
122
|
+
template_input: InputTemplate
|
|
123
|
+
attributes:
|
|
124
|
+
sample_rate_khz: 16
|
|
125
|
+
from_bytes: False
|
|
126
|
+
"""
|
|
127
|
+
|
|
128
|
+
def get_file_path_from_generic_data(self, container: DataContainer) -> None:
|
|
129
|
+
"""Method to retrieve the file path from the genetic data field of DataContainer.
|
|
130
|
+
The method extracts the file path from the generic field and sets as attribute
|
|
131
|
+
|
|
132
|
+
Args:
|
|
133
|
+
container (DataContainer): The DataContainer to extract the file path from
|
|
134
|
+
"""
|
|
135
|
+
file_path = container.generic_data.get("audio_path", "")
|
|
136
|
+
self.attributes.audio_file_path = file_path
|
|
137
|
+
|
|
138
|
+
def execute(self, container: DataContainer) -> DataContainer:
|
|
139
|
+
self.get_file_path_from_generic_data(container)
|
|
140
|
+
if self.attributes.audio_file_path:
|
|
141
|
+
return super().execute(container)
|
|
142
|
+
|
|
143
|
+
return container
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
@execute_template_n_times_wrapper
|
|
147
|
+
class ExecuteNTimesLazyAudioReaderPydub(LazyAudioReaderPydub):
|
|
148
|
+
"""
|
|
149
|
+
This template provides functionality to read multiple audios, each of them assigned to
|
|
150
|
+
its own DataContainer and to its own reader process.
|
|
151
|
+
Similar to its base class, it reads the file path from the generic field of the DataContainer
|
|
152
|
+
"""
|
sinapsis_data_readers/src/sinapsis_data_readers/templates/audio_readers/audio_reader_soundfile.py
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
from typing import cast
|
|
5
|
+
|
|
6
|
+
import soundfile as sf
|
|
7
|
+
from sinapsis_core.data_containers.data_packet import AudioPacket, DataContainer
|
|
8
|
+
from sinapsis_core.template_base.multi_execute_template import (
|
|
9
|
+
execute_template_n_times_wrapper,
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
from sinapsis_data_readers.templates.audio_readers.base_audio_reader import (
|
|
13
|
+
_AudioBaseReader,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class AudioReaderSoundfile(_AudioBaseReader):
|
|
18
|
+
"""Reads audio data from a file path using Soundfile.
|
|
19
|
+
|
|
20
|
+
This class utilizes the Soundfile library to read audio data from a specified file path.
|
|
21
|
+
It returns the audio data wrapped in an AudioPacket, which includes additional metadata
|
|
22
|
+
such as sample rate and source information.
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
Usage example:
|
|
26
|
+
|
|
27
|
+
agent:
|
|
28
|
+
name: my_test_agent
|
|
29
|
+
templates:
|
|
30
|
+
- template_name: InputTemplate
|
|
31
|
+
class_name: InputTemplate
|
|
32
|
+
attributes: {}
|
|
33
|
+
- template_name: AudioReaderSoundfile
|
|
34
|
+
class_name: AudioReaderSoundfile
|
|
35
|
+
template_input: InputTemplate
|
|
36
|
+
attributes:
|
|
37
|
+
audio_file_path: '/path/to/file.mp3'
|
|
38
|
+
source: 'source/of/file'
|
|
39
|
+
sample_rate_khz: 16
|
|
40
|
+
from_bytes: true
|
|
41
|
+
|
|
42
|
+
"""
|
|
43
|
+
|
|
44
|
+
AttributesBaseModel = _AudioBaseReader.AttributesBaseModel
|
|
45
|
+
|
|
46
|
+
def read_file(self) -> AudioPacket | None:
|
|
47
|
+
"""Reads audio data from a file path and returns an AudioPacket.
|
|
48
|
+
|
|
49
|
+
This method checks if the specified audio file exists and attempts to read
|
|
50
|
+
the audio data using the Soundfile library. If successful, it wraps the audio
|
|
51
|
+
data in an AudioPacket and returns it. If the file does not exist or if there
|
|
52
|
+
is an error during reading, it logs the error and returns None.
|
|
53
|
+
|
|
54
|
+
Returns:
|
|
55
|
+
AudioPacket|None: An AudioPacket containing the audio data and
|
|
56
|
+
sample rate, or None if the file could not be read or was invalid.
|
|
57
|
+
"""
|
|
58
|
+
audio_path = cast(str, self.attributes.audio_file_path)
|
|
59
|
+
if os.path.exists(audio_path):
|
|
60
|
+
try:
|
|
61
|
+
audio_content, sample_rate = sf.read(audio_path)
|
|
62
|
+
audio_packet = AudioPacket(
|
|
63
|
+
source=self.attributes.source,
|
|
64
|
+
content=audio_content,
|
|
65
|
+
sample_rate=sample_rate,
|
|
66
|
+
)
|
|
67
|
+
return audio_packet
|
|
68
|
+
except (ValueError, TypeError) as e:
|
|
69
|
+
self.logger.error("Error reading audio file: %s", e)
|
|
70
|
+
return None
|
|
71
|
+
else:
|
|
72
|
+
self.logger.error("Invalid audio file path: %s", audio_path)
|
|
73
|
+
return None
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
@execute_template_n_times_wrapper
|
|
77
|
+
class ExecuteNTimesAudioReaderSoundfile(AudioReaderSoundfile):
|
|
78
|
+
"""
|
|
79
|
+
This template provides functionality to read multiple audios, each of them assigned to
|
|
80
|
+
its own DataContainer and to its own reader process.
|
|
81
|
+
Similar to its base class, it reads the audio using the Soundfile library
|
|
82
|
+
"""
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
class LazyAudioReaderSoundfile(AudioReaderSoundfile):
|
|
86
|
+
"""Reads audio data from a file path using Soundfile.
|
|
87
|
+
|
|
88
|
+
This class utilizes the Soundfile library to read audio data from a specified file path.
|
|
89
|
+
It returns the audio data wrapped in an AudioPacket, which includes additional metadata
|
|
90
|
+
such as sample rate and source information.
|
|
91
|
+
|
|
92
|
+
Usage example:
|
|
93
|
+
|
|
94
|
+
agent:
|
|
95
|
+
name: my_test_agent
|
|
96
|
+
templates:
|
|
97
|
+
- template_name: InputTemplate
|
|
98
|
+
class_name: InputTemplate
|
|
99
|
+
attributes: {}
|
|
100
|
+
- template_name: LazyAudioReaderSoundfile
|
|
101
|
+
class_name: LazyAudioReaderSoundfile
|
|
102
|
+
template_input: InputTemplate
|
|
103
|
+
attributes:
|
|
104
|
+
sample_rate_khz: 16
|
|
105
|
+
from_bytes: true
|
|
106
|
+
"""
|
|
107
|
+
|
|
108
|
+
def get_file_path_from_generic_data(self, container: DataContainer) -> None:
|
|
109
|
+
"""Method to retrieve the file path from the genetic data field of DataContainer.
|
|
110
|
+
The method extracts the file path from the generic field and sets as attribute
|
|
111
|
+
|
|
112
|
+
Args:
|
|
113
|
+
container (DataContainer): The DataContainer to extract the file path from
|
|
114
|
+
"""
|
|
115
|
+
file_path = container.generic_data["audio_path"]
|
|
116
|
+
self.attributes.audio_file_path = file_path
|
|
117
|
+
|
|
118
|
+
def execute(self, container: DataContainer) -> DataContainer:
|
|
119
|
+
self.get_file_path_from_generic_data(container)
|
|
120
|
+
return super().execute(container)
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
@execute_template_n_times_wrapper
|
|
124
|
+
class ExecuteNTimesLazyAudioReaderSoundfile(LazyAudioReaderSoundfile):
|
|
125
|
+
"""
|
|
126
|
+
This template provides functionality to read multiple audios, each of them assigned to
|
|
127
|
+
its own DataContainer and to its own reader process.
|
|
128
|
+
Similar to its base class, it reads the audio using the Soundfile library
|
|
129
|
+
"""
|
sinapsis_data_readers/src/sinapsis_data_readers/templates/audio_readers/audio_reader_to_bytes.py
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
from sinapsis_core.data_containers.data_packet import AudioPacket
|
|
4
|
+
|
|
5
|
+
from sinapsis_data_readers.templates.audio_readers.base_audio_reader import (
|
|
6
|
+
_AudioBaseReader,
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class AudioReaderToBytes(_AudioBaseReader):
|
|
11
|
+
"""
|
|
12
|
+
AudioReader for Reading Audio Files and Converting to Bytes.
|
|
13
|
+
Usage example:
|
|
14
|
+
|
|
15
|
+
agent:
|
|
16
|
+
name: my_test_agent
|
|
17
|
+
templates:
|
|
18
|
+
- template_name: InputTemplate
|
|
19
|
+
class_name: InputTemplate
|
|
20
|
+
attributes: {}
|
|
21
|
+
- template_name: AudioReaderToBytes
|
|
22
|
+
class_name: AudioReaderToBytes
|
|
23
|
+
template_input: InputTemplate
|
|
24
|
+
attributes:
|
|
25
|
+
audio_file_path: '/path/to/file.mp3'
|
|
26
|
+
source: 'source/of/file'
|
|
27
|
+
from_bytes: true
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
def read_file(self) -> AudioPacket | None:
|
|
31
|
+
"""
|
|
32
|
+
Reads an audio file from the specified path and converts it into an `AudioPacket`.
|
|
33
|
+
|
|
34
|
+
Returns:
|
|
35
|
+
AudioPacket: An `AudioPacket` object containing the audio data.
|
|
36
|
+
|
|
37
|
+
Raises:
|
|
38
|
+
FileNotFoundError: If the specified audio file does not exist.
|
|
39
|
+
IOError: If there is an error reading the audio file.
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
try:
|
|
43
|
+
with open(self.attributes.audio_file_path, "rb") as audio_file:
|
|
44
|
+
audio_content = audio_file.read()
|
|
45
|
+
|
|
46
|
+
audio_file.close()
|
|
47
|
+
audio_packet = AudioPacket(
|
|
48
|
+
source=self.attributes.audio_file_path,
|
|
49
|
+
content=audio_content,
|
|
50
|
+
)
|
|
51
|
+
return audio_packet
|
|
52
|
+
except FileNotFoundError:
|
|
53
|
+
self.logger.error(f"Audio file not found: {self.attributes.audio_file_path}")
|
|
54
|
+
return None
|
|
55
|
+
except IOError as e:
|
|
56
|
+
self.logger.error(f"Error reading audio file: {e}")
|
|
57
|
+
return None
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
import abc
|
|
4
|
+
from uuid import uuid4
|
|
5
|
+
|
|
6
|
+
from sinapsis_core.data_containers.data_packet import AudioPacket, DataContainer
|
|
7
|
+
from sinapsis_core.template_base import TemplateAttributes
|
|
8
|
+
|
|
9
|
+
from sinapsis_data_readers.templates.base_file_data_loader import _BaseDataReader
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class _AudioBaseReader(_BaseDataReader):
|
|
13
|
+
PACKET_ATT_NAME = "audios"
|
|
14
|
+
|
|
15
|
+
class AttributesBaseModel(TemplateAttributes):
|
|
16
|
+
"""Attributes for the AudioBaseReader.
|
|
17
|
+
|
|
18
|
+
audio_file_path (str):
|
|
19
|
+
Path to the audio file to be read.
|
|
20
|
+
|
|
21
|
+
source (str):
|
|
22
|
+
The source identifier, defaults to "streamlit".
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
audio_file_path: str
|
|
26
|
+
source: str = str(uuid4())
|
|
27
|
+
|
|
28
|
+
@abc.abstractmethod
|
|
29
|
+
def read_file(self) -> AudioPacket | None:
|
|
30
|
+
"""Abstract method to read the audio data.
|
|
31
|
+
|
|
32
|
+
This method must be implemented by subclasses to
|
|
33
|
+
read the audio data and return an AudioPacket with the content
|
|
34
|
+
of the audio.
|
|
35
|
+
|
|
36
|
+
Returns:
|
|
37
|
+
AudioPacket: The audio data wrapped in an AudioPacket.
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
def has_elements(self) -> bool:
|
|
41
|
+
"""Flag to indicate if there is still content to process"""
|
|
42
|
+
return True
|
|
43
|
+
|
|
44
|
+
def append_packets_to_container(self, container: DataContainer) -> None:
|
|
45
|
+
"""Adds a packet to the input container
|
|
46
|
+
|
|
47
|
+
Args:
|
|
48
|
+
container (DataContainer): container where data is to be appended
|
|
49
|
+
"""
|
|
50
|
+
data_packets_to_add = [self.read_file()]
|
|
51
|
+
if data_packets_to_add:
|
|
52
|
+
data_packets_to_add += getattr(container, self.PACKET_ATT_NAME)
|
|
53
|
+
setattr(container, self.PACKET_ATT_NAME, data_packets_to_add)
|
|
54
|
+
|
|
55
|
+
def make_data_entries(self) -> list[AudioPacket]:
|
|
56
|
+
audio_packets: list[AudioPacket] = []
|
|
57
|
+
return audio_packets
|