synapse-sdk 1.0.0b17__py3-none-any.whl → 1.0.0b19__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.
Potentially problematic release.
This version of synapse-sdk might be problematic. Click here for more details.
- synapse_sdk/clients/backend/data_collection.py +2 -2
- synapse_sdk/devtools/docs/docs/contributing.md +1 -1
- synapse_sdk/devtools/docs/docs/features/index.md +4 -4
- synapse_sdk/devtools/docs/docs/plugins/export-plugins.md +786 -0
- synapse_sdk/devtools/docs/docs/{features/plugins/index.md → plugins/plugins.md} +352 -21
- synapse_sdk/devtools/docs/docusaurus.config.ts +8 -0
- synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/plugins/export-plugins.md +788 -0
- synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/plugins/plugins.md +71 -0
- synapse_sdk/devtools/docs/package-lock.json +1366 -37
- synapse_sdk/devtools/docs/package.json +2 -1
- synapse_sdk/devtools/docs/sidebars.ts +8 -1
- synapse_sdk/plugins/categories/export/actions/export.py +2 -1
- synapse_sdk/plugins/categories/export/templates/config.yaml +1 -1
- synapse_sdk/plugins/categories/export/templates/plugin/__init__.py +376 -0
- synapse_sdk/plugins/categories/export/templates/plugin/export.py +56 -190
- synapse_sdk/plugins/categories/upload/actions/upload.py +181 -22
- synapse_sdk/plugins/categories/upload/templates/config.yaml +24 -2
- synapse_sdk/plugins/categories/upload/templates/plugin/upload.py +9 -2
- {synapse_sdk-1.0.0b17.dist-info → synapse_sdk-1.0.0b19.dist-info}/METADATA +1 -1
- {synapse_sdk-1.0.0b17.dist-info → synapse_sdk-1.0.0b19.dist-info}/RECORD +24 -22
- synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/features/plugins/index.md +0 -30
- {synapse_sdk-1.0.0b17.dist-info → synapse_sdk-1.0.0b19.dist-info}/WHEEL +0 -0
- {synapse_sdk-1.0.0b17.dist-info → synapse_sdk-1.0.0b19.dist-info}/entry_points.txt +0 -0
- {synapse_sdk-1.0.0b17.dist-info → synapse_sdk-1.0.0b19.dist-info}/licenses/LICENSE +0 -0
- {synapse_sdk-1.0.0b17.dist-info → synapse_sdk-1.0.0b19.dist-info}/top_level.txt +0 -0
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import asyncio
|
|
1
2
|
import json
|
|
2
3
|
import os
|
|
3
4
|
import shutil
|
|
@@ -5,7 +6,7 @@ from datetime import datetime
|
|
|
5
6
|
from enum import Enum
|
|
6
7
|
from io import BytesIO
|
|
7
8
|
from pathlib import Path
|
|
8
|
-
from typing import Annotated, Any, Dict, List, Optional
|
|
9
|
+
from typing import Annotated, Any, Awaitable, Dict, List, Optional, TypeVar
|
|
9
10
|
|
|
10
11
|
from openpyxl import load_workbook
|
|
11
12
|
from openpyxl.utils.exceptions import InvalidFileException
|
|
@@ -25,6 +26,9 @@ from synapse_sdk.shared.enums import Context
|
|
|
25
26
|
from synapse_sdk.utils.pydantic.validators import non_blank
|
|
26
27
|
from synapse_sdk.utils.storage import get_pathlib
|
|
27
28
|
|
|
29
|
+
# Type variable for generic async return type
|
|
30
|
+
T = TypeVar('T')
|
|
31
|
+
|
|
28
32
|
|
|
29
33
|
class PathAwareJSONEncoder(json.JSONEncoder):
|
|
30
34
|
"""Custom JSON encoder that handles Path-like objects."""
|
|
@@ -178,7 +182,7 @@ class UploadRun(Run):
|
|
|
178
182
|
},
|
|
179
183
|
# Debug information - only for EventLog
|
|
180
184
|
'EXCEL_FILE_VALIDATION_STARTED': {
|
|
181
|
-
'message': 'Excel file validation started
|
|
185
|
+
'message': 'Excel file validation started',
|
|
182
186
|
'level': Context.INFO,
|
|
183
187
|
},
|
|
184
188
|
'EXCEL_WORKBOOK_LOADED': {
|
|
@@ -186,7 +190,7 @@ class UploadRun(Run):
|
|
|
186
190
|
'level': Context.INFO,
|
|
187
191
|
},
|
|
188
192
|
'FILE_ORGANIZATION_STARTED': {
|
|
189
|
-
'message': 'File organization started
|
|
193
|
+
'message': 'File organization started',
|
|
190
194
|
'level': Context.INFO,
|
|
191
195
|
},
|
|
192
196
|
'BATCH_PROCESSING_STARTED': {
|
|
@@ -202,7 +206,7 @@ class UploadRun(Run):
|
|
|
202
206
|
'level': Context.INFO,
|
|
203
207
|
},
|
|
204
208
|
'EXCEL_FILE_NOT_FOUND_PATH': {
|
|
205
|
-
'message': 'Excel metadata file not found
|
|
209
|
+
'message': 'Excel metadata file not found',
|
|
206
210
|
'level': Context.WARNING,
|
|
207
211
|
},
|
|
208
212
|
'EXCEL_SECURITY_VALIDATION_FAILED': {
|
|
@@ -394,6 +398,9 @@ class ExcelMetadataUtils:
|
|
|
394
398
|
class UploadParams(BaseModel):
|
|
395
399
|
"""Upload action parameters.
|
|
396
400
|
|
|
401
|
+
This class defines all configuration parameters for the upload action, including
|
|
402
|
+
advanced asynchronous upload capabilities for improved performance.
|
|
403
|
+
|
|
397
404
|
Args:
|
|
398
405
|
name (str): The name of the action.
|
|
399
406
|
description (str | None): The description of the action.
|
|
@@ -405,6 +412,17 @@ class UploadParams(BaseModel):
|
|
|
405
412
|
excel_metadata_path (str | None): Path to excel file containing metadata.
|
|
406
413
|
Defaults to 'meta.xlsx' or 'meta.xls' in the path directory.
|
|
407
414
|
is_recursive (bool): Enable recursive file discovery in subdirectories. Defaults to False.
|
|
415
|
+
use_async_upload (bool): Enable asynchronous upload data file processing for improved performance.
|
|
416
|
+
Defaults to True.
|
|
417
|
+
max_file_size_mb (int): The maximum file size not using chunked_upload in MB. Defaults to 50MB.
|
|
418
|
+
creating_data_unit_batch_size (int): The batch size for creating data units. Defaults to 100.
|
|
419
|
+
extra_params (dict | None): Extra parameters for the action.
|
|
420
|
+
Example: {"include_metadata": True, "compression": "gzip"}
|
|
421
|
+
|
|
422
|
+
Note:
|
|
423
|
+
Async upload requires plugin developers to implement handle_upload_files_async()
|
|
424
|
+
method for maximum benefit. Default implementation provides compatibility
|
|
425
|
+
but limited performance improvement.
|
|
408
426
|
"""
|
|
409
427
|
|
|
410
428
|
name: Annotated[str, AfterValidator(non_blank)]
|
|
@@ -416,7 +434,9 @@ class UploadParams(BaseModel):
|
|
|
416
434
|
excel_metadata_path: str | None = None
|
|
417
435
|
is_recursive: bool = False
|
|
418
436
|
max_file_size_mb: int = 50
|
|
419
|
-
creating_data_unit_batch_size: int =
|
|
437
|
+
creating_data_unit_batch_size: int = 1
|
|
438
|
+
use_async_upload: bool = True
|
|
439
|
+
extra_params: dict | None = None
|
|
420
440
|
|
|
421
441
|
@field_validator('storage', mode='before')
|
|
422
442
|
@classmethod
|
|
@@ -540,8 +560,6 @@ class UploadAction(Action):
|
|
|
540
560
|
analyze_collection: The progress category for the analyze collection process.
|
|
541
561
|
data_file_upload: The progress category for the upload process.
|
|
542
562
|
generate_data_units: The progress category for the generate data units process.
|
|
543
|
-
generate_tasks: The progress category for the generate tasks process.
|
|
544
|
-
generate_ground_truths: The progress category for the generate ground truths process.
|
|
545
563
|
|
|
546
564
|
Metrics Categories:
|
|
547
565
|
data_file: The metrics category for the data file.
|
|
@@ -581,9 +599,11 @@ class UploadAction(Action):
|
|
|
581
599
|
self.excel_config = ExcelSecurityConfig()
|
|
582
600
|
self.excel_utils = ExcelMetadataUtils(self.excel_config)
|
|
583
601
|
|
|
584
|
-
def get_uploader(self, path, file_specification, organized_files):
|
|
602
|
+
def get_uploader(self, path, file_specification, organized_files, params: Dict = None):
|
|
585
603
|
"""Get uploader from entrypoint."""
|
|
586
|
-
return self.entrypoint(
|
|
604
|
+
return self.entrypoint(
|
|
605
|
+
self.run, path, file_specification, organized_files, extra_params=params.get('extra_params')
|
|
606
|
+
)
|
|
587
607
|
|
|
588
608
|
def _discover_files_recursive(self, dir_path: Path) -> List[Path]:
|
|
589
609
|
"""Discover files recursively in a directory."""
|
|
@@ -797,10 +817,11 @@ class UploadAction(Action):
|
|
|
797
817
|
excel_path = None
|
|
798
818
|
|
|
799
819
|
# Check if user provided a specific excel_metadata_path
|
|
800
|
-
|
|
801
|
-
|
|
820
|
+
excel_metadata_path = self.params.get('excel_metadata_path')
|
|
821
|
+
if excel_metadata_path:
|
|
822
|
+
excel_path = pathlib_cwd / excel_metadata_path
|
|
802
823
|
if not excel_path.exists():
|
|
803
|
-
self.run.log_message_with_code('EXCEL_FILE_NOT_FOUND_PATH'
|
|
824
|
+
self.run.log_message_with_code('EXCEL_FILE_NOT_FOUND_PATH')
|
|
804
825
|
return {}
|
|
805
826
|
else:
|
|
806
827
|
# Look for default meta.xlsx or meta.xls
|
|
@@ -810,7 +831,7 @@ class UploadAction(Action):
|
|
|
810
831
|
return {}
|
|
811
832
|
|
|
812
833
|
try:
|
|
813
|
-
self.run.log_message_with_code('EXCEL_FILE_VALIDATION_STARTED'
|
|
834
|
+
self.run.log_message_with_code('EXCEL_FILE_VALIDATION_STARTED')
|
|
814
835
|
|
|
815
836
|
# Prepare Excel file with security validation
|
|
816
837
|
excel_stream = self._prepare_excel_file(excel_path)
|
|
@@ -852,8 +873,15 @@ class UploadAction(Action):
|
|
|
852
873
|
result: Dict[str, Any] = {}
|
|
853
874
|
|
|
854
875
|
# Setup path object with path and storage.
|
|
855
|
-
|
|
856
|
-
|
|
876
|
+
storage_id = self.params.get('storage')
|
|
877
|
+
if storage_id is None:
|
|
878
|
+
raise ActionError('Storage parameter is required')
|
|
879
|
+
storage = self.client.get_storage(storage_id)
|
|
880
|
+
|
|
881
|
+
path = self.params.get('path')
|
|
882
|
+
if path is None:
|
|
883
|
+
raise ActionError('Path parameter is required')
|
|
884
|
+
pathlib_cwd = get_pathlib(storage, path)
|
|
857
885
|
|
|
858
886
|
# Read excel metadata if configured or default file exists
|
|
859
887
|
excel_metadata: Dict[str, Dict[str, Any]] = {}
|
|
@@ -881,7 +909,7 @@ class UploadAction(Action):
|
|
|
881
909
|
organized_files = self._organize_files(pathlib_cwd, file_specification_template, excel_metadata)
|
|
882
910
|
|
|
883
911
|
# Initialize uploader.
|
|
884
|
-
uploader = self.get_uploader(pathlib_cwd, file_specification_template, organized_files)
|
|
912
|
+
uploader = self.get_uploader(pathlib_cwd, file_specification_template, organized_files, self.params)
|
|
885
913
|
|
|
886
914
|
# Get organized files from the uploader (plugin developer's custom implementation)
|
|
887
915
|
# or use the default organization method if uploader doesn't provide valid files
|
|
@@ -896,7 +924,11 @@ class UploadAction(Action):
|
|
|
896
924
|
if not organized_files:
|
|
897
925
|
self.run.log_message_with_code('NO_FILES_FOUND')
|
|
898
926
|
raise ActionError('Upload is aborted due to missing files.')
|
|
899
|
-
|
|
927
|
+
# Choose upload method based on async parameter
|
|
928
|
+
if self.params.get('use_async_upload', True):
|
|
929
|
+
uploaded_files = self.run_async(self._upload_files_async(organized_files, 10))
|
|
930
|
+
else:
|
|
931
|
+
uploaded_files = self._upload_files(organized_files)
|
|
900
932
|
result['uploaded_files_count'] = len(uploaded_files)
|
|
901
933
|
|
|
902
934
|
# Generate data units for the uploaded data.
|
|
@@ -904,7 +936,7 @@ class UploadAction(Action):
|
|
|
904
936
|
self.run.log_message_with_code('NO_FILES_UPLOADED')
|
|
905
937
|
raise ActionError('Upload is aborted due to no uploaded files.')
|
|
906
938
|
generated_data_units = self._generate_data_units(
|
|
907
|
-
uploaded_files, self.params.get('creating_data_unit_batch_size')
|
|
939
|
+
uploaded_files, self.params.get('creating_data_unit_batch_size', 1)
|
|
908
940
|
)
|
|
909
941
|
result['generated_data_units_count'] = len(generated_data_units)
|
|
910
942
|
|
|
@@ -929,7 +961,9 @@ class UploadAction(Action):
|
|
|
929
961
|
# Initialize progress
|
|
930
962
|
self.run.set_progress(0, 2, category='analyze_collection')
|
|
931
963
|
|
|
932
|
-
collection_id = self.params
|
|
964
|
+
collection_id = self.params.get('data_collection')
|
|
965
|
+
if collection_id is None:
|
|
966
|
+
raise ActionError('Data collection parameter is required')
|
|
933
967
|
self.run.set_progress(1, 2, category='analyze_collection')
|
|
934
968
|
|
|
935
969
|
collection = self.run.client.get_data_collection(collection_id)
|
|
@@ -949,7 +983,9 @@ class UploadAction(Action):
|
|
|
949
983
|
self.run.log_message_with_code('UPLOADING_DATA_FILES')
|
|
950
984
|
|
|
951
985
|
client = self.run.client
|
|
952
|
-
collection_id = self.params
|
|
986
|
+
collection_id = self.params.get('data_collection')
|
|
987
|
+
if collection_id is None:
|
|
988
|
+
raise ActionError('Data collection parameter is required')
|
|
953
989
|
upload_result = []
|
|
954
990
|
current_progress = 0
|
|
955
991
|
success_count = 0
|
|
@@ -980,6 +1016,129 @@ class UploadAction(Action):
|
|
|
980
1016
|
|
|
981
1017
|
return upload_result
|
|
982
1018
|
|
|
1019
|
+
def run_async(self, coro: Awaitable[T]) -> T:
|
|
1020
|
+
"""Run async coroutine safely using asyncio.run().
|
|
1021
|
+
|
|
1022
|
+
This method properly manages event loop lifecycle and prevents
|
|
1023
|
+
resource exhaustion from repeated event loop creation.
|
|
1024
|
+
|
|
1025
|
+
Args:
|
|
1026
|
+
coro: The coroutine to execute
|
|
1027
|
+
|
|
1028
|
+
Returns:
|
|
1029
|
+
The result of the coroutine execution
|
|
1030
|
+
|
|
1031
|
+
Raises:
|
|
1032
|
+
RuntimeError: If called from within an existing event loop
|
|
1033
|
+
"""
|
|
1034
|
+
import concurrent.futures
|
|
1035
|
+
|
|
1036
|
+
def _run_in_thread():
|
|
1037
|
+
"""Run the coroutine in a separate thread to avoid event loop conflicts."""
|
|
1038
|
+
return asyncio.run(coro)
|
|
1039
|
+
|
|
1040
|
+
# Check if we're already in an event loop
|
|
1041
|
+
try:
|
|
1042
|
+
# If this doesn't raise, we're in an event loop
|
|
1043
|
+
asyncio.get_running_loop()
|
|
1044
|
+
# Run in thread pool to avoid "RuntimeError: cannot be called from a running event loop"
|
|
1045
|
+
with concurrent.futures.ThreadPoolExecutor(max_workers=1) as executor:
|
|
1046
|
+
future = executor.submit(_run_in_thread)
|
|
1047
|
+
return future.result()
|
|
1048
|
+
except RuntimeError:
|
|
1049
|
+
# No event loop running, safe to use asyncio.run directly
|
|
1050
|
+
return asyncio.run(coro)
|
|
1051
|
+
|
|
1052
|
+
async def _upload_files_async(
|
|
1053
|
+
self, organized_files: List[Dict[str, Any]], max_concurrent: int = 10
|
|
1054
|
+
) -> List[Dict[str, Any]]:
|
|
1055
|
+
"""Upload files to synapse-backend asynchronously with concurrency control."""
|
|
1056
|
+
# Initialize progress
|
|
1057
|
+
organized_files_count = len(organized_files)
|
|
1058
|
+
self.run.set_progress(0, organized_files_count, category='upload_data_files')
|
|
1059
|
+
self.run.log_message_with_code('UPLOADING_DATA_FILES')
|
|
1060
|
+
|
|
1061
|
+
client = self.run.client
|
|
1062
|
+
collection_id = self.params.get('data_collection')
|
|
1063
|
+
if collection_id is None:
|
|
1064
|
+
raise ActionError('Data collection parameter is required')
|
|
1065
|
+
upload_result = []
|
|
1066
|
+
success_count = 0
|
|
1067
|
+
failed_count = 0
|
|
1068
|
+
|
|
1069
|
+
# Initialize metrics
|
|
1070
|
+
self._update_metrics(organized_files_count, success_count, failed_count, 'data_files')
|
|
1071
|
+
|
|
1072
|
+
# Control concurrency with semaphore
|
|
1073
|
+
semaphore = asyncio.Semaphore(max_concurrent)
|
|
1074
|
+
|
|
1075
|
+
async def upload_single_file(organized_file):
|
|
1076
|
+
async with semaphore:
|
|
1077
|
+
loop = asyncio.get_event_loop()
|
|
1078
|
+
try:
|
|
1079
|
+
# Determine if chunked upload should be used based on file size
|
|
1080
|
+
use_chunked_upload = self._requires_chunked_upload(organized_file)
|
|
1081
|
+
# Run sync upload_data_file in thread pool
|
|
1082
|
+
uploaded_data_file = await loop.run_in_executor(
|
|
1083
|
+
None, lambda: client.upload_data_file(organized_file, collection_id, use_chunked_upload)
|
|
1084
|
+
)
|
|
1085
|
+
self.run.log_data_file(organized_file, UploadStatus.SUCCESS)
|
|
1086
|
+
return {'status': 'success', 'result': uploaded_data_file}
|
|
1087
|
+
except ClientError as e:
|
|
1088
|
+
# Handle API client errors (network, authentication, server errors)
|
|
1089
|
+
self.run.log_data_file(organized_file, UploadStatus.FAILED)
|
|
1090
|
+
self.run.log_message_with_code('FILE_UPLOAD_FAILED', f'Client error: {str(e)}')
|
|
1091
|
+
return {'status': 'failed', 'error': str(e), 'error_type': 'client_error', 'retryable': True}
|
|
1092
|
+
except (OSError, IOError) as e:
|
|
1093
|
+
# Handle file system errors (file not found, permissions, disk full)
|
|
1094
|
+
self.run.log_data_file(organized_file, UploadStatus.FAILED)
|
|
1095
|
+
self.run.log_message_with_code('FILE_UPLOAD_FAILED', f'File system error: {str(e)}')
|
|
1096
|
+
return {'status': 'failed', 'error': str(e), 'error_type': 'file_error', 'retryable': False}
|
|
1097
|
+
except MemoryError as e:
|
|
1098
|
+
# Handle out of memory errors (large files)
|
|
1099
|
+
self.run.log_data_file(organized_file, UploadStatus.FAILED)
|
|
1100
|
+
self.run.log_message_with_code('FILE_UPLOAD_FAILED', f'Memory error (file too large): {str(e)}')
|
|
1101
|
+
return {'status': 'failed', 'error': str(e), 'error_type': 'memory_error', 'retryable': False}
|
|
1102
|
+
except asyncio.TimeoutError as e:
|
|
1103
|
+
# Handle timeout errors (slow network, large files)
|
|
1104
|
+
self.run.log_data_file(organized_file, UploadStatus.FAILED)
|
|
1105
|
+
self.run.log_message_with_code('FILE_UPLOAD_FAILED', f'Upload timeout: {str(e)}')
|
|
1106
|
+
return {'status': 'failed', 'error': str(e), 'error_type': 'timeout_error', 'retryable': True}
|
|
1107
|
+
except ValueError as e:
|
|
1108
|
+
# Handle data validation errors (invalid file format, metadata issues)
|
|
1109
|
+
self.run.log_data_file(organized_file, UploadStatus.FAILED)
|
|
1110
|
+
self.run.log_message_with_code('FILE_UPLOAD_FAILED', f'Data validation error: {str(e)}')
|
|
1111
|
+
return {'status': 'failed', 'error': str(e), 'error_type': 'validation_error', 'retryable': False}
|
|
1112
|
+
except Exception as e:
|
|
1113
|
+
# Handle any remaining unexpected errors
|
|
1114
|
+
self.run.log_data_file(organized_file, UploadStatus.FAILED)
|
|
1115
|
+
self.run.log_message_with_code('FILE_UPLOAD_FAILED', f'Unexpected error: {str(e)}')
|
|
1116
|
+
return {'status': 'failed', 'error': str(e), 'error_type': 'unknown_error', 'retryable': False}
|
|
1117
|
+
|
|
1118
|
+
# Create tasks for all files
|
|
1119
|
+
tasks = [upload_single_file(organized_file) for organized_file in organized_files]
|
|
1120
|
+
|
|
1121
|
+
# Process files with progress updates
|
|
1122
|
+
current_progress = 0
|
|
1123
|
+
for completed_task in asyncio.as_completed(tasks):
|
|
1124
|
+
result = await completed_task
|
|
1125
|
+
current_progress += 1
|
|
1126
|
+
|
|
1127
|
+
if result['status'] == 'success':
|
|
1128
|
+
success_count += 1
|
|
1129
|
+
upload_result.append(result['result'])
|
|
1130
|
+
else:
|
|
1131
|
+
failed_count += 1
|
|
1132
|
+
|
|
1133
|
+
# Update metrics and progress
|
|
1134
|
+
self._update_metrics(organized_files_count, success_count, failed_count, 'data_files')
|
|
1135
|
+
self.run.set_progress(current_progress, organized_files_count, category='upload_data_files')
|
|
1136
|
+
|
|
1137
|
+
# Finish progress
|
|
1138
|
+
self.run.set_progress(organized_files_count, organized_files_count, category='upload_data_files')
|
|
1139
|
+
|
|
1140
|
+
return upload_result
|
|
1141
|
+
|
|
983
1142
|
def _generate_data_units(self, uploaded_files: List[Dict[str, Any]], batch_size: int) -> List[Dict[str, Any]]:
|
|
984
1143
|
"""Generate data units for the uploaded data.
|
|
985
1144
|
|
|
@@ -1073,14 +1232,14 @@ class UploadAction(Action):
|
|
|
1073
1232
|
return organized_files
|
|
1074
1233
|
|
|
1075
1234
|
self.run.log_message_with_code('TYPE_STRUCTURE_DETECTED')
|
|
1076
|
-
self.run.log_message_with_code('FILE_ORGANIZATION_STARTED'
|
|
1235
|
+
self.run.log_message_with_code('FILE_ORGANIZATION_STARTED')
|
|
1077
1236
|
|
|
1078
1237
|
# Collect and process files in a single pass
|
|
1079
1238
|
dataset_files = {}
|
|
1080
1239
|
required_specs = [spec['name'] for spec in file_specification if spec.get('is_required', False)]
|
|
1081
1240
|
|
|
1082
1241
|
# Get recursive setting from params
|
|
1083
|
-
is_recursive = self.params.get('is_recursive',
|
|
1242
|
+
is_recursive = self.params.get('is_recursive', True)
|
|
1084
1243
|
|
|
1085
1244
|
# Process all files from all type directories
|
|
1086
1245
|
for spec_name, dir_path in type_dirs.items():
|
|
@@ -3,5 +3,27 @@ actions:
|
|
|
3
3
|
entrypoint: plugin.upload.Uploader
|
|
4
4
|
options:
|
|
5
5
|
supported_data_type: image # A primary data type of synapse backend collection. (e.g. 'image', 'text', 'video', 'pcd', 'audio')
|
|
6
|
-
ui_schema:
|
|
7
|
-
|
|
6
|
+
ui_schema: # UI schema for the input of extra params
|
|
7
|
+
- $formkit: "radio"
|
|
8
|
+
name: "file_format"
|
|
9
|
+
label: "File Format"
|
|
10
|
+
help: "Select the file format for upload processing"
|
|
11
|
+
required: false
|
|
12
|
+
value: "original"
|
|
13
|
+
options:
|
|
14
|
+
- label: "Keep Original"
|
|
15
|
+
value: "original"
|
|
16
|
+
- label: "Convert to JPEG"
|
|
17
|
+
value: "jpeg"
|
|
18
|
+
- label: "Convert to PNG"
|
|
19
|
+
value: "png"
|
|
20
|
+
- $formkit: "checkbox"
|
|
21
|
+
name: "include_metadata"
|
|
22
|
+
label: "Include Metadata"
|
|
23
|
+
help: "Include file metadata during upload"
|
|
24
|
+
value: true
|
|
25
|
+
- $formkit: "text"
|
|
26
|
+
name: "custom_tag"
|
|
27
|
+
label: "Custom Tag"
|
|
28
|
+
help: "Add a custom tag to uploaded files"
|
|
29
|
+
placeholder: "Enter custom tag"
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import asyncio
|
|
1
2
|
from pathlib import Path
|
|
2
|
-
from typing import List
|
|
3
|
+
from typing import Dict, List
|
|
3
4
|
|
|
4
5
|
|
|
5
6
|
class Uploader:
|
|
@@ -9,7 +10,9 @@ class Uploader:
|
|
|
9
10
|
their own file organization logic.
|
|
10
11
|
"""
|
|
11
12
|
|
|
12
|
-
def __init__(
|
|
13
|
+
def __init__(
|
|
14
|
+
self, run, path: Path, file_specification: List = None, organized_files: List = None, extra_params: Dict = None
|
|
15
|
+
):
|
|
13
16
|
"""Initialize the plugin upload action class.
|
|
14
17
|
|
|
15
18
|
Args:
|
|
@@ -17,11 +20,15 @@ class Uploader:
|
|
|
17
20
|
path: Path object pointing to the upload target directory.
|
|
18
21
|
file_specification: List of specifications that define the structure of files to be uploaded.
|
|
19
22
|
Each specification contains details like file name, type, and requirements.
|
|
23
|
+
organized_files: List of pre-organized files based on the default logic.
|
|
24
|
+
Each item is a dictionary with 'files' and 'meta' keys.
|
|
25
|
+
extra_params: Additional parameters for customization.
|
|
20
26
|
"""
|
|
21
27
|
self.run = run
|
|
22
28
|
self.path = path
|
|
23
29
|
self.file_specification = file_specification
|
|
24
30
|
self.organized_files = organized_files
|
|
31
|
+
self.extra_params = extra_params
|
|
25
32
|
|
|
26
33
|
def handle_upload_files(self) -> List:
|
|
27
34
|
"""Customize the organization of files for upload.
|
|
@@ -34,7 +34,7 @@ synapse_sdk/clients/agent/service.py,sha256=s7KuPK_DB1nr2VHrigttV1WyFonaGHNrPvU8
|
|
|
34
34
|
synapse_sdk/clients/backend/__init__.py,sha256=9FzjQn0ljRhtdaoG3n38Mdgte7GFwIh4OtEmoqVg2_E,2098
|
|
35
35
|
synapse_sdk/clients/backend/annotation.py,sha256=t9KnSdCJ7NvDRkAOKn4lm5hgoawbLCwIHMeo45QiIlQ,1249
|
|
36
36
|
synapse_sdk/clients/backend/core.py,sha256=oXAQwIz2QFuheaG79vXcYQFSlDDU1hxn2oRc6F5jyOc,2197
|
|
37
|
-
synapse_sdk/clients/backend/data_collection.py,sha256=
|
|
37
|
+
synapse_sdk/clients/backend/data_collection.py,sha256=L0TmV-4jXPgKwWu9baKHz_WFRTqMe5nZH-qW-5PlUYM,7742
|
|
38
38
|
synapse_sdk/clients/backend/hitl.py,sha256=1rKczQBKOeEVS0Ynu--mctbBF-zIkSz4_aklfbFY2CU,713
|
|
39
39
|
synapse_sdk/clients/backend/integration.py,sha256=IdjPkllvHJ_vASHSmxsWO3CRlZz2L4eWkMOch7bHWok,2744
|
|
40
40
|
synapse_sdk/clients/backend/ml.py,sha256=ynm1UQ-gJkJ-n1wU_Hjcxdhe8VC1LliNWOUJfurOrRE,1197
|
|
@@ -50,10 +50,10 @@ synapse_sdk/devtools/server.py,sha256=tj-9ICg1bSECvDD1yUZnLeiH7qpUcwrJ6jaD9C1Ba_
|
|
|
50
50
|
synapse_sdk/devtools/streamlit_app.py,sha256=fa17_8NUDCClWp8ESLkPEUD5CTo6bisTFEVXniyUhY8,256
|
|
51
51
|
synapse_sdk/devtools/docs/.gitignore,sha256=fCv2uiY7oUmiiFhHqfcYbg169Y-q4-AfLmmnRl98_sw,233
|
|
52
52
|
synapse_sdk/devtools/docs/README.md,sha256=yBzWf0K1ef4oymFXDaHo0nYWEgMQJqsOyrkNhIOPQrY,774
|
|
53
|
-
synapse_sdk/devtools/docs/docusaurus.config.ts,sha256=
|
|
54
|
-
synapse_sdk/devtools/docs/package-lock.json,sha256=
|
|
55
|
-
synapse_sdk/devtools/docs/package.json,sha256=
|
|
56
|
-
synapse_sdk/devtools/docs/sidebars.ts,sha256
|
|
53
|
+
synapse_sdk/devtools/docs/docusaurus.config.ts,sha256=K1b002RS0x0tsOyib_6CSgUlASEULC9vAX8YDpbsRN4,3229
|
|
54
|
+
synapse_sdk/devtools/docs/package-lock.json,sha256=dtepgbPC8gq5uz-hdcac4hIU-Cs209tX0sfBuB7RfEQ,705694
|
|
55
|
+
synapse_sdk/devtools/docs/package.json,sha256=8veqayA4U3OLpdQaz6AzB59RQwTU-5soeYlYYWIxq28,1187
|
|
56
|
+
synapse_sdk/devtools/docs/sidebars.ts,sha256=ZfHa2kSwhvnDAsTZo6DR3IjeNXC4-J-_jYWSvZOA_zg,1559
|
|
57
57
|
synapse_sdk/devtools/docs/tsconfig.json,sha256=O9BNlRPjPiaVHW2_boShMbmTnh0Z2k0KQO6Alf9FMVY,215
|
|
58
58
|
synapse_sdk/devtools/docs/blog/2019-05-28-first-blog-post.md,sha256=iP7gl_FPqo-qX13lkSRcRoT6ayJNmCkXoyvlm7GH248,312
|
|
59
59
|
synapse_sdk/devtools/docs/blog/2019-05-29-long-blog-post.md,sha256=cM-dhhTeurEWMcdn0Kx-NpNts2YUUraSI_XFk_gVHEE,3122
|
|
@@ -65,7 +65,7 @@ synapse_sdk/devtools/docs/blog/2021-08-26-welcome/index.md,sha256=VEO6buziLWUfcU
|
|
|
65
65
|
synapse_sdk/devtools/docs/docs/categories.md,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
66
66
|
synapse_sdk/devtools/docs/docs/cli-usage.md,sha256=ooFeFINHPwo288WmVkQXs_dee5zDOqo-Cgp186J-3Vo,7258
|
|
67
67
|
synapse_sdk/devtools/docs/docs/configuration.md,sha256=5tyAg0rl_k8XGYG0RT__r43xLdCBBVLDzS-4d8UZUO0,2222
|
|
68
|
-
synapse_sdk/devtools/docs/docs/contributing.md,sha256=
|
|
68
|
+
synapse_sdk/devtools/docs/docs/contributing.md,sha256=U-g4rqrZXWSO_EzNh4AoOgZKFBzJ1OqVll_20nkJyWo,7706
|
|
69
69
|
synapse_sdk/devtools/docs/docs/faq.md,sha256=PZ5JlBQ9BtJ7GWKmyr_X-alHnlIAxPXYwSVpAfHNXg4,4547
|
|
70
70
|
synapse_sdk/devtools/docs/docs/installation.md,sha256=TUXPQ9zhWW68WdimH85GihGMBG-_XcUUzZG2bd0XKX8,1875
|
|
71
71
|
synapse_sdk/devtools/docs/docs/introduction.md,sha256=qaZaU9E8raOm3Eqf7Zxpi9qG26gyS91OK1pWHsnPPMA,1581
|
|
@@ -85,9 +85,10 @@ synapse_sdk/devtools/docs/docs/api/utils/storage.md,sha256=uIpc37trKUm4XHe1fd4au
|
|
|
85
85
|
synapse_sdk/devtools/docs/docs/api/utils/types.md,sha256=l84J1Ooa40xBYdvK1YpeKBT9kaqaWQUMNIFPUiC2e_U,1046
|
|
86
86
|
synapse_sdk/devtools/docs/docs/concepts/index.md,sha256=ezn67P568PvFRPVE4T74j5MuEikgVOX7DV6MxIQBOHo,760
|
|
87
87
|
synapse_sdk/devtools/docs/docs/examples/index.md,sha256=IZnF8veO7PqJYtAQevL1VHt1rBzieCSaXoWTQoXS4lA,504
|
|
88
|
-
synapse_sdk/devtools/docs/docs/features/index.md,sha256=
|
|
88
|
+
synapse_sdk/devtools/docs/docs/features/index.md,sha256=FD2hUzTzFgKa5pcDWPtA6eVw9pLLiRajYi4xA8aJTHg,963
|
|
89
89
|
synapse_sdk/devtools/docs/docs/features/converters/index.md,sha256=W5d5UO8nbOLWs1G9IgdTutlMl-d6M0hDLMJbg8DrCQ8,12713
|
|
90
|
-
synapse_sdk/devtools/docs/docs/
|
|
90
|
+
synapse_sdk/devtools/docs/docs/plugins/export-plugins.md,sha256=W8u8o9PWZQJ-rBvwuw-daWtqsOfFod_j_4yNj4zbOj0,27028
|
|
91
|
+
synapse_sdk/devtools/docs/docs/plugins/plugins.md,sha256=a1OCSovNXLx8vEkx7qJtxlqEQueGgZ37_xvuZecp4ng,24139
|
|
91
92
|
synapse_sdk/devtools/docs/docs/tutorial-basics/_category_.json,sha256=qQVHZ1p0CxHg5Gb4CYNxUSeqZ3LVo4nXN_N0yUMVpDM,180
|
|
92
93
|
synapse_sdk/devtools/docs/docs/tutorial-basics/congratulations.md,sha256=zJbcwKNVYGpLAGJO7e3cTdptFhb6m_NUzYDU5i6MWgc,1078
|
|
93
94
|
synapse_sdk/devtools/docs/docs/tutorial-basics/create-a-blog-post.md,sha256=FNk-D3eiMmoc7sdVKazXibjsKl7-6b65KuEYkGOwcYk,886
|
|
@@ -124,7 +125,8 @@ synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/concept
|
|
|
124
125
|
synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/examples/index.md,sha256=pMAc1VLUXnHCv2xvvx-GBqVQ1Uh4h-u4nrco5UZ2z-Y,613
|
|
125
126
|
synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/features/index.md,sha256=ogU60hHjgRSUlxdoEFTlM7jwbZ3fharaTFuYHp3vya4,1051
|
|
126
127
|
synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/features/converters/index.md,sha256=WpXcLBqC-xlvuoh-AhNOtFSo4qmnBIbR_wqLlazT7zo,1366
|
|
127
|
-
synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/
|
|
128
|
+
synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/plugins/export-plugins.md,sha256=f1fe6zWV5t60QZwCev7e-GIW50itfZviZ8zVZTaoka0,28371
|
|
129
|
+
synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/plugins/plugins.md,sha256=63auCIr_5_IFZgvPDd9XSovM1cv3TSx9U0zQRjrsxkI,3108
|
|
128
130
|
synapse_sdk/devtools/docs/i18n/ko/docusaurus-theme-classic/footer.json,sha256=SCLmysIhJ6XEEfnL7cOQb3s08EG4LA-ColdRRxecIH8,1601
|
|
129
131
|
synapse_sdk/devtools/docs/i18n/ko/docusaurus-theme-classic/navbar.json,sha256=M-ly81cWnesYYtCRcfMvOsKl5P0z52K9kiw0T6GIQ60,429
|
|
130
132
|
synapse_sdk/devtools/docs/src/components/HomepageFeatures/index.tsx,sha256=xaUQaq9OuqoaRAZQo-ZWev0vbmIkn9l04QfUBxlhnnU,1923
|
|
@@ -178,10 +180,10 @@ synapse_sdk/plugins/categories/data_validation/templates/plugin/validation.py,sh
|
|
|
178
180
|
synapse_sdk/plugins/categories/export/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
179
181
|
synapse_sdk/plugins/categories/export/enums.py,sha256=gtyngvQ1DKkos9iKGcbecwTVQQ6sDwbrBPSGPNb5Am0,127
|
|
180
182
|
synapse_sdk/plugins/categories/export/actions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
181
|
-
synapse_sdk/plugins/categories/export/actions/export.py,sha256=
|
|
182
|
-
synapse_sdk/plugins/categories/export/templates/config.yaml,sha256=
|
|
183
|
-
synapse_sdk/plugins/categories/export/templates/plugin/__init__.py,sha256=
|
|
184
|
-
synapse_sdk/plugins/categories/export/templates/plugin/export.py,sha256=
|
|
183
|
+
synapse_sdk/plugins/categories/export/actions/export.py,sha256=BO8N1LT8X9ImDmsqMdrbCUePsMEtOhazCuVtwp_ZmXs,13706
|
|
184
|
+
synapse_sdk/plugins/categories/export/templates/config.yaml,sha256=fAqi-9dH7qEkFDSDFvt0BcZ72d2qbyt1P83L2ti6ELM,58
|
|
185
|
+
synapse_sdk/plugins/categories/export/templates/plugin/__init__.py,sha256=vsaFmW0X7GvKs1YYocYn1Yfp9bzfLnc9grMp4n9UbWk,15400
|
|
186
|
+
synapse_sdk/plugins/categories/export/templates/plugin/export.py,sha256=3dZUEdhj-4YySJ-cPyNAqQvj5xcAXIX4KmXKcacTtd0,2754
|
|
185
187
|
synapse_sdk/plugins/categories/neural_net/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
186
188
|
synapse_sdk/plugins/categories/neural_net/actions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
187
189
|
synapse_sdk/plugins/categories/neural_net/actions/deployment.py,sha256=njhDp05KXbNB9VCa46VgWa8-ftc_f9HcAVpUr0836AM,1838
|
|
@@ -219,10 +221,10 @@ synapse_sdk/plugins/categories/smart_tool/templates/plugin/__init__.py,sha256=47
|
|
|
219
221
|
synapse_sdk/plugins/categories/smart_tool/templates/plugin/auto_label.py,sha256=eevNg0nOcYFR4z_L_R-sCvVOYoLWSAH1jwDkAf3YCjY,320
|
|
220
222
|
synapse_sdk/plugins/categories/upload/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
221
223
|
synapse_sdk/plugins/categories/upload/actions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
222
|
-
synapse_sdk/plugins/categories/upload/actions/upload.py,sha256=
|
|
223
|
-
synapse_sdk/plugins/categories/upload/templates/config.yaml,sha256=
|
|
224
|
+
synapse_sdk/plugins/categories/upload/actions/upload.py,sha256=lFosLHBC0bAI6rC9BYdrmd47VoQRXDtd6hi-0p7oG04,55001
|
|
225
|
+
synapse_sdk/plugins/categories/upload/templates/config.yaml,sha256=BvW1sqs02IgzO_fndxmtQ9CCmlNPwVIiuptQzzA6uAo,998
|
|
224
226
|
synapse_sdk/plugins/categories/upload/templates/plugin/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
225
|
-
synapse_sdk/plugins/categories/upload/templates/plugin/upload.py,sha256=
|
|
227
|
+
synapse_sdk/plugins/categories/upload/templates/plugin/upload.py,sha256=gtKdKVf_PmZ2lRiTVrWT48F1J1yRZ-UGzg4gUgjWE84,1886
|
|
226
228
|
synapse_sdk/plugins/templates/cookiecutter.json,sha256=NxOWk9A_v1pO0Ny4IYT9Cj5iiJ16--cIQrGC67QdR0I,396
|
|
227
229
|
synapse_sdk/plugins/templates/plugin-config-schema.json,sha256=_ff1dnHdWPcWjD1Wy8Wn0aT6TnMD5J5Sdms3RTSWCUs,11805
|
|
228
230
|
synapse_sdk/plugins/templates/schema.json,sha256=E5bZjskN0mqQtk2eLAB1nfXufIoGvyrtkMMP-wGKSdc,14029
|
|
@@ -276,9 +278,9 @@ synapse_sdk/utils/storage/providers/gcp.py,sha256=i2BQCu1Kej1If9SuNr2_lEyTcr5M_n
|
|
|
276
278
|
synapse_sdk/utils/storage/providers/http.py,sha256=2DhIulND47JOnS5ZY7MZUex7Su3peAPksGo1Wwg07L4,5828
|
|
277
279
|
synapse_sdk/utils/storage/providers/s3.py,sha256=ZmqekAvIgcQBdRU-QVJYv1Rlp6VHfXwtbtjTSphua94,2573
|
|
278
280
|
synapse_sdk/utils/storage/providers/sftp.py,sha256=_8s9hf0JXIO21gvm-JVS00FbLsbtvly4c-ETLRax68A,1426
|
|
279
|
-
synapse_sdk-1.0.
|
|
280
|
-
synapse_sdk-1.0.
|
|
281
|
-
synapse_sdk-1.0.
|
|
282
|
-
synapse_sdk-1.0.
|
|
283
|
-
synapse_sdk-1.0.
|
|
284
|
-
synapse_sdk-1.0.
|
|
281
|
+
synapse_sdk-1.0.0b19.dist-info/licenses/LICENSE,sha256=bKzmC5YAg4V1Fhl8OO_tqY8j62hgdncAkN7VrdjmrGk,1101
|
|
282
|
+
synapse_sdk-1.0.0b19.dist-info/METADATA,sha256=JJmW-pCaz5n8V-rNYjuE3Lq6hBhsGFfUYC9RoLM0YO0,3745
|
|
283
|
+
synapse_sdk-1.0.0b19.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
284
|
+
synapse_sdk-1.0.0b19.dist-info/entry_points.txt,sha256=VNptJoGoNJI8yLXfBmhgUefMsmGI0m3-0YoMvrOgbxo,48
|
|
285
|
+
synapse_sdk-1.0.0b19.dist-info/top_level.txt,sha256=ytgJMRK1slVOKUpgcw3LEyHHP7S34J6n_gJzdkcSsw8,12
|
|
286
|
+
synapse_sdk-1.0.0b19.dist-info/RECORD,,
|
synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/features/plugins/index.md
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
id: plugins
|
|
3
|
-
title: 플러그인 시스템
|
|
4
|
-
sidebar_position: 2
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
# 플러그인 시스템
|
|
8
|
-
|
|
9
|
-
Synapse SDK는 다양한 카테고리와 실행 방법에 걸쳐 ML 플러그인을 구축하고 관리하기 위한 포괄적인 플러그인 시스템을 제공합니다. 플러그인 시스템은 다양한 환경에서 배포되고 실행될 수 있는 모듈식, 재사용 가능한 컴포넌트를 가능하게 합니다.
|
|
10
|
-
|
|
11
|
-
## 개요
|
|
12
|
-
|
|
13
|
-
플러그인 시스템은 **액션** 개념을 중심으로 구축됩니다 - 패키징, 배포 및 다양한 컨텍스트에서 실행될 수 있는 개별 작업들입니다. 각 플러그인은 특정 카테고리에 속하며 여러 액션을 지원할 수 있습니다.
|
|
14
|
-
|
|
15
|
-
### 주요 기능
|
|
16
|
-
|
|
17
|
-
- **🔌 모듈식 아키텍처**: 플러그인은 자체 종속성과 구성을 가진 자체 포함형입니다
|
|
18
|
-
- **⚡ 다중 실행 방법**: Job, Task 및 REST API 엔드포인트 지원
|
|
19
|
-
- **📦 분산 실행**: 확장 가능한 분산 컴퓨팅을 위해 구축됨
|
|
20
|
-
- **🛠️ 템플릿 시스템**: 신속한 플러그인 개발을 위한 Cookiecutter 기반 스캐폴딩
|
|
21
|
-
- **📊 진행률 추적**: 내장된 로깅, 메트릭 및 진행률 모니터링
|
|
22
|
-
- **🔄 동적 로딩**: 런타임 플러그인 발견 및 등록
|
|
23
|
-
|
|
24
|
-
## 플러그인 카테고리
|
|
25
|
-
|
|
26
|
-
SDK는 플러그인을 특정 카테고리로 구성하며, 각각은 ML 워크플로우의 다양한 측면을 위해 설계되었습니다:
|
|
27
|
-
|
|
28
|
-
### 1. 신경망 (`neural_net`)
|
|
29
|
-
|
|
30
|
-
ML 모델 훈련, 추론 및 배포 작업들.
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|