synapse-sdk 1.0.0b5__py3-none-any.whl → 2025.12.3__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.
- synapse_sdk/__init__.py +24 -0
- synapse_sdk/cli/code_server.py +305 -33
- synapse_sdk/clients/agent/__init__.py +2 -1
- synapse_sdk/clients/agent/container.py +143 -0
- synapse_sdk/clients/agent/ray.py +296 -38
- synapse_sdk/clients/backend/annotation.py +1 -1
- synapse_sdk/clients/backend/core.py +31 -4
- synapse_sdk/clients/backend/data_collection.py +82 -7
- synapse_sdk/clients/backend/hitl.py +1 -1
- synapse_sdk/clients/backend/ml.py +1 -1
- synapse_sdk/clients/base.py +211 -61
- synapse_sdk/loggers.py +46 -0
- synapse_sdk/plugins/README.md +1340 -0
- synapse_sdk/plugins/categories/base.py +59 -9
- synapse_sdk/plugins/categories/export/actions/__init__.py +3 -0
- synapse_sdk/plugins/categories/export/actions/export/__init__.py +28 -0
- synapse_sdk/plugins/categories/export/actions/export/action.py +165 -0
- synapse_sdk/plugins/categories/export/actions/export/enums.py +113 -0
- synapse_sdk/plugins/categories/export/actions/export/exceptions.py +53 -0
- synapse_sdk/plugins/categories/export/actions/export/models.py +74 -0
- synapse_sdk/plugins/categories/export/actions/export/run.py +195 -0
- synapse_sdk/plugins/categories/export/actions/export/utils.py +187 -0
- synapse_sdk/plugins/categories/export/templates/config.yaml +19 -1
- synapse_sdk/plugins/categories/export/templates/plugin/__init__.py +390 -0
- synapse_sdk/plugins/categories/export/templates/plugin/export.py +153 -177
- synapse_sdk/plugins/categories/neural_net/actions/train.py +1130 -32
- synapse_sdk/plugins/categories/neural_net/actions/tune.py +157 -4
- synapse_sdk/plugins/categories/neural_net/templates/config.yaml +7 -4
- synapse_sdk/plugins/categories/pre_annotation/actions/__init__.py +4 -0
- synapse_sdk/plugins/categories/pre_annotation/actions/pre_annotation/__init__.py +3 -0
- synapse_sdk/plugins/categories/pre_annotation/actions/pre_annotation/action.py +10 -0
- synapse_sdk/plugins/categories/pre_annotation/actions/to_task/__init__.py +28 -0
- synapse_sdk/plugins/categories/pre_annotation/actions/to_task/action.py +148 -0
- synapse_sdk/plugins/categories/pre_annotation/actions/to_task/enums.py +269 -0
- synapse_sdk/plugins/categories/pre_annotation/actions/to_task/exceptions.py +14 -0
- synapse_sdk/plugins/categories/pre_annotation/actions/to_task/factory.py +76 -0
- synapse_sdk/plugins/categories/pre_annotation/actions/to_task/models.py +100 -0
- synapse_sdk/plugins/categories/pre_annotation/actions/to_task/orchestrator.py +248 -0
- synapse_sdk/plugins/categories/pre_annotation/actions/to_task/run.py +64 -0
- synapse_sdk/plugins/categories/pre_annotation/actions/to_task/strategies/__init__.py +17 -0
- synapse_sdk/plugins/categories/pre_annotation/actions/to_task/strategies/annotation.py +265 -0
- synapse_sdk/plugins/categories/pre_annotation/actions/to_task/strategies/base.py +170 -0
- synapse_sdk/plugins/categories/pre_annotation/actions/to_task/strategies/extraction.py +83 -0
- synapse_sdk/plugins/categories/pre_annotation/actions/to_task/strategies/metrics.py +92 -0
- synapse_sdk/plugins/categories/pre_annotation/actions/to_task/strategies/preprocessor.py +243 -0
- synapse_sdk/plugins/categories/pre_annotation/actions/to_task/strategies/validation.py +143 -0
- synapse_sdk/plugins/categories/upload/actions/upload/__init__.py +19 -0
- synapse_sdk/plugins/categories/upload/actions/upload/action.py +236 -0
- synapse_sdk/plugins/categories/upload/actions/upload/context.py +185 -0
- synapse_sdk/plugins/categories/upload/actions/upload/enums.py +493 -0
- synapse_sdk/plugins/categories/upload/actions/upload/exceptions.py +36 -0
- synapse_sdk/plugins/categories/upload/actions/upload/factory.py +138 -0
- synapse_sdk/plugins/categories/upload/actions/upload/models.py +214 -0
- synapse_sdk/plugins/categories/upload/actions/upload/orchestrator.py +183 -0
- synapse_sdk/plugins/categories/upload/actions/upload/registry.py +113 -0
- synapse_sdk/plugins/categories/upload/actions/upload/run.py +179 -0
- synapse_sdk/plugins/categories/upload/actions/upload/steps/__init__.py +1 -0
- synapse_sdk/plugins/categories/upload/actions/upload/steps/base.py +107 -0
- synapse_sdk/plugins/categories/upload/actions/upload/steps/cleanup.py +62 -0
- synapse_sdk/plugins/categories/upload/actions/upload/steps/collection.py +63 -0
- synapse_sdk/plugins/categories/upload/actions/upload/steps/generate.py +91 -0
- synapse_sdk/plugins/categories/upload/actions/upload/steps/initialize.py +82 -0
- synapse_sdk/plugins/categories/upload/actions/upload/steps/metadata.py +235 -0
- synapse_sdk/plugins/categories/upload/actions/upload/steps/organize.py +201 -0
- synapse_sdk/plugins/categories/upload/actions/upload/steps/upload.py +104 -0
- synapse_sdk/plugins/categories/upload/actions/upload/steps/validate.py +71 -0
- synapse_sdk/plugins/categories/upload/actions/upload/strategies/__init__.py +1 -0
- synapse_sdk/plugins/categories/upload/actions/upload/strategies/base.py +82 -0
- synapse_sdk/plugins/categories/upload/actions/upload/strategies/data_unit/__init__.py +1 -0
- synapse_sdk/plugins/categories/upload/actions/upload/strategies/data_unit/batch.py +39 -0
- synapse_sdk/plugins/categories/upload/actions/upload/strategies/data_unit/single.py +29 -0
- synapse_sdk/plugins/categories/upload/actions/upload/strategies/file_discovery/__init__.py +1 -0
- synapse_sdk/plugins/categories/upload/actions/upload/strategies/file_discovery/flat.py +300 -0
- synapse_sdk/plugins/categories/upload/actions/upload/strategies/file_discovery/recursive.py +287 -0
- synapse_sdk/plugins/categories/upload/actions/upload/strategies/metadata/__init__.py +1 -0
- synapse_sdk/plugins/categories/upload/actions/upload/strategies/metadata/excel.py +174 -0
- synapse_sdk/plugins/categories/upload/actions/upload/strategies/metadata/none.py +16 -0
- synapse_sdk/plugins/categories/upload/actions/upload/strategies/upload/__init__.py +1 -0
- synapse_sdk/plugins/categories/upload/actions/upload/strategies/upload/sync.py +84 -0
- synapse_sdk/plugins/categories/upload/actions/upload/strategies/validation/__init__.py +1 -0
- synapse_sdk/plugins/categories/upload/actions/upload/strategies/validation/default.py +60 -0
- synapse_sdk/plugins/categories/upload/actions/upload/utils.py +250 -0
- synapse_sdk/plugins/categories/upload/templates/README.md +470 -0
- synapse_sdk/plugins/categories/upload/templates/config.yaml +28 -2
- synapse_sdk/plugins/categories/upload/templates/plugin/__init__.py +310 -0
- synapse_sdk/plugins/categories/upload/templates/plugin/upload.py +82 -20
- synapse_sdk/plugins/models.py +111 -9
- synapse_sdk/plugins/templates/plugin-config-schema.json +7 -0
- synapse_sdk/plugins/templates/schema.json +7 -0
- synapse_sdk/plugins/utils/__init__.py +3 -0
- synapse_sdk/plugins/utils/ray_gcs.py +66 -0
- synapse_sdk/shared/__init__.py +25 -0
- synapse_sdk/utils/converters/dm/__init__.py +42 -41
- synapse_sdk/utils/converters/dm/base.py +137 -0
- synapse_sdk/utils/converters/dm/from_v1.py +208 -562
- synapse_sdk/utils/converters/dm/to_v1.py +258 -304
- synapse_sdk/utils/converters/dm/tools/__init__.py +214 -0
- synapse_sdk/utils/converters/dm/tools/answer.py +95 -0
- synapse_sdk/utils/converters/dm/tools/bounding_box.py +132 -0
- synapse_sdk/utils/converters/dm/tools/bounding_box_3d.py +121 -0
- synapse_sdk/utils/converters/dm/tools/classification.py +75 -0
- synapse_sdk/utils/converters/dm/tools/keypoint.py +117 -0
- synapse_sdk/utils/converters/dm/tools/named_entity.py +111 -0
- synapse_sdk/utils/converters/dm/tools/polygon.py +122 -0
- synapse_sdk/utils/converters/dm/tools/polyline.py +124 -0
- synapse_sdk/utils/converters/dm/tools/prompt.py +94 -0
- synapse_sdk/utils/converters/dm/tools/relation.py +86 -0
- synapse_sdk/utils/converters/dm/tools/segmentation.py +141 -0
- synapse_sdk/utils/converters/dm/tools/segmentation_3d.py +83 -0
- synapse_sdk/utils/converters/dm/types.py +168 -0
- synapse_sdk/utils/converters/dm/utils.py +162 -0
- synapse_sdk/utils/converters/dm_legacy/__init__.py +56 -0
- synapse_sdk/utils/converters/dm_legacy/from_v1.py +627 -0
- synapse_sdk/utils/converters/dm_legacy/to_v1.py +367 -0
- synapse_sdk/utils/file/__init__.py +58 -0
- synapse_sdk/utils/file/archive.py +32 -0
- synapse_sdk/utils/file/checksum.py +56 -0
- synapse_sdk/utils/file/chunking.py +31 -0
- synapse_sdk/utils/file/download.py +385 -0
- synapse_sdk/utils/file/encoding.py +40 -0
- synapse_sdk/utils/file/io.py +22 -0
- synapse_sdk/utils/file/upload.py +165 -0
- synapse_sdk/utils/file/video/__init__.py +29 -0
- synapse_sdk/utils/file/video/transcode.py +307 -0
- synapse_sdk/utils/{file.py → file.py.backup} +77 -0
- synapse_sdk/utils/network.py +272 -0
- synapse_sdk/utils/storage/__init__.py +6 -2
- synapse_sdk/utils/storage/providers/file_system.py +6 -0
- {synapse_sdk-1.0.0b5.dist-info → synapse_sdk-2025.12.3.dist-info}/METADATA +19 -2
- {synapse_sdk-1.0.0b5.dist-info → synapse_sdk-2025.12.3.dist-info}/RECORD +134 -74
- synapse_sdk/devtools/docs/.gitignore +0 -20
- synapse_sdk/devtools/docs/README.md +0 -41
- synapse_sdk/devtools/docs/blog/2019-05-28-first-blog-post.md +0 -12
- synapse_sdk/devtools/docs/blog/2019-05-29-long-blog-post.md +0 -44
- synapse_sdk/devtools/docs/blog/2021-08-01-mdx-blog-post.mdx +0 -24
- synapse_sdk/devtools/docs/blog/2021-08-26-welcome/docusaurus-plushie-banner.jpeg +0 -0
- synapse_sdk/devtools/docs/blog/2021-08-26-welcome/index.md +0 -29
- synapse_sdk/devtools/docs/blog/authors.yml +0 -25
- synapse_sdk/devtools/docs/blog/tags.yml +0 -19
- synapse_sdk/devtools/docs/docusaurus.config.ts +0 -138
- synapse_sdk/devtools/docs/package-lock.json +0 -17455
- synapse_sdk/devtools/docs/package.json +0 -47
- synapse_sdk/devtools/docs/sidebars.ts +0 -44
- synapse_sdk/devtools/docs/src/components/HomepageFeatures/index.tsx +0 -71
- synapse_sdk/devtools/docs/src/components/HomepageFeatures/styles.module.css +0 -11
- synapse_sdk/devtools/docs/src/css/custom.css +0 -30
- synapse_sdk/devtools/docs/src/pages/index.module.css +0 -23
- synapse_sdk/devtools/docs/src/pages/index.tsx +0 -21
- synapse_sdk/devtools/docs/src/pages/markdown-page.md +0 -7
- synapse_sdk/devtools/docs/static/.nojekyll +0 -0
- synapse_sdk/devtools/docs/static/img/docusaurus-social-card.jpg +0 -0
- synapse_sdk/devtools/docs/static/img/docusaurus.png +0 -0
- synapse_sdk/devtools/docs/static/img/favicon.ico +0 -0
- synapse_sdk/devtools/docs/static/img/logo.png +0 -0
- synapse_sdk/devtools/docs/static/img/undraw_docusaurus_mountain.svg +0 -171
- synapse_sdk/devtools/docs/static/img/undraw_docusaurus_react.svg +0 -170
- synapse_sdk/devtools/docs/static/img/undraw_docusaurus_tree.svg +0 -40
- synapse_sdk/devtools/docs/tsconfig.json +0 -8
- synapse_sdk/plugins/categories/export/actions/export.py +0 -346
- synapse_sdk/plugins/categories/export/enums.py +0 -7
- synapse_sdk/plugins/categories/neural_net/actions/gradio.py +0 -151
- synapse_sdk/plugins/categories/pre_annotation/actions/to_task.py +0 -943
- synapse_sdk/plugins/categories/upload/actions/upload.py +0 -954
- {synapse_sdk-1.0.0b5.dist-info → synapse_sdk-2025.12.3.dist-info}/WHEEL +0 -0
- {synapse_sdk-1.0.0b5.dist-info → synapse_sdk-2025.12.3.dist-info}/entry_points.txt +0 -0
- {synapse_sdk-1.0.0b5.dist-info → synapse_sdk-2025.12.3.dist-info}/licenses/LICENSE +0 -0
- {synapse_sdk-1.0.0b5.dist-info → synapse_sdk-2025.12.3.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"""Utilities for converting HTTP URLs to Ray GCS URLs."""
|
|
2
|
+
|
|
3
|
+
import tempfile
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def convert_http_to_ray_gcs(http_url: str) -> str:
|
|
8
|
+
"""Convert HTTP URL to Ray GCS URL by downloading and uploading to Ray's GCS.
|
|
9
|
+
|
|
10
|
+
Ray's working_dir only accepts certain protocols (gcs://, s3://, gs://, https://).
|
|
11
|
+
When SYNAPSE_PLUGIN_STORAGE is an HTTP URL (Django media server), this function
|
|
12
|
+
converts it to a Ray-compatible gcs:// URL by:
|
|
13
|
+
1. Downloading the file from HTTP
|
|
14
|
+
2. Uploading it to Ray's Global Control Store (GCS)
|
|
15
|
+
3. Returning the content-addressable gcs:// URI
|
|
16
|
+
|
|
17
|
+
Args:
|
|
18
|
+
http_url: HTTP/HTTPS URL to plugin zip file
|
|
19
|
+
|
|
20
|
+
Returns:
|
|
21
|
+
gcs:// URL that Ray can use for working_dir
|
|
22
|
+
Example: "gcs://_ray_pkg_abc123def456.zip"
|
|
23
|
+
|
|
24
|
+
Raises:
|
|
25
|
+
RuntimeError: If Ray is not initialized or not installed
|
|
26
|
+
requests.exceptions.RequestException: If HTTP download fails
|
|
27
|
+
|
|
28
|
+
Note:
|
|
29
|
+
- Ray must be initialized (ray.init()) before calling this function
|
|
30
|
+
- The gcs:// URI is content-addressable (same file = same URI)
|
|
31
|
+
- Ray automatically deduplicates uploads via package_exists()
|
|
32
|
+
"""
|
|
33
|
+
try:
|
|
34
|
+
import ray
|
|
35
|
+
except ImportError:
|
|
36
|
+
raise RuntimeError(
|
|
37
|
+
'Ray is not installed but is required for HTTP → GCS conversion. Install ray with: pip install ray'
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
if not ray.is_initialized():
|
|
41
|
+
raise RuntimeError(
|
|
42
|
+
'Ray must be initialized before converting HTTP URLs to GCS. '
|
|
43
|
+
'Call ray.init() before submitting jobs with HTTP storage.'
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
from ray._private.runtime_env.packaging import (
|
|
47
|
+
get_uri_for_package,
|
|
48
|
+
package_exists,
|
|
49
|
+
upload_package_to_gcs,
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
from synapse_sdk.plugins.upload import download_file
|
|
53
|
+
|
|
54
|
+
# Download HTTP file to temporary location
|
|
55
|
+
with tempfile.TemporaryDirectory() as temp_dir:
|
|
56
|
+
local_path = Path(download_file(http_url, temp_dir))
|
|
57
|
+
|
|
58
|
+
# Generate content-addressable gcs:// URI based on file content
|
|
59
|
+
gcs_uri = get_uri_for_package(local_path)
|
|
60
|
+
|
|
61
|
+
# Check if already exists in Ray GCS (deduplication)
|
|
62
|
+
if not package_exists(gcs_uri):
|
|
63
|
+
# Upload to Ray's Global Control Store
|
|
64
|
+
upload_package_to_gcs(gcs_uri, local_path.read_bytes())
|
|
65
|
+
|
|
66
|
+
return gcs_uri
|
synapse_sdk/shared/__init__.py
CHANGED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import os
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def needs_sentry_init():
|
|
5
|
+
return os.getenv('SENTRY_DSN') is not None
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def init_sentry():
|
|
9
|
+
import sentry_sdk
|
|
10
|
+
from sentry_sdk.integrations.ray import RayIntegration
|
|
11
|
+
|
|
12
|
+
dsn = os.getenv('SENTRY_DSN')
|
|
13
|
+
if dsn is None:
|
|
14
|
+
return
|
|
15
|
+
|
|
16
|
+
sentry_sdk.init(
|
|
17
|
+
dsn=dsn,
|
|
18
|
+
environment=os.getenv('DEPLOYMENT_TARGET', 'development'),
|
|
19
|
+
integrations=[RayIntegration()],
|
|
20
|
+
send_default_pii=True,
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def worker_process_setup_hook(*_, **__):
|
|
25
|
+
init_sentry()
|
|
@@ -1,56 +1,57 @@
|
|
|
1
|
-
|
|
1
|
+
"""
|
|
2
|
+
DM Schema V1/V2 Bidirectional Converter
|
|
2
3
|
|
|
3
|
-
|
|
4
|
+
"""
|
|
4
5
|
|
|
6
|
+
from typing import Any
|
|
5
7
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
+
from .types import (
|
|
9
|
+
AnnotationMeta,
|
|
10
|
+
V2AnnotationData,
|
|
11
|
+
V2ConversionResult,
|
|
12
|
+
)
|
|
8
13
|
|
|
9
|
-
SUPPORTED_TOOLS = SupportedTools.get_all_values()
|
|
10
14
|
|
|
11
|
-
|
|
12
|
-
|
|
15
|
+
def convert_v1_to_v2(v1_data: dict[str, Any]) -> V2ConversionResult:
|
|
16
|
+
"""Convert DM Schema V1 data to V2 (separated result)
|
|
13
17
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
"""
|
|
17
|
-
self.file_type = file_type
|
|
18
|
-
self.tool_processors = self._setup_tool_processors()
|
|
18
|
+
Args:
|
|
19
|
+
v1_data: DM Schema V1 format data
|
|
19
20
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
21
|
+
Returns:
|
|
22
|
+
V2ConversionResult: Separated conversion result
|
|
23
|
+
- annotation_data: V2 common annotation structure
|
|
24
|
+
- annotation_meta: Preserved V1 top-level structure
|
|
25
|
+
"""
|
|
26
|
+
from .from_v1 import DMV1ToV2Converter
|
|
24
27
|
|
|
25
|
-
|
|
26
|
-
|
|
28
|
+
converter = DMV1ToV2Converter()
|
|
29
|
+
return converter.convert(v1_data)
|
|
27
30
|
|
|
28
|
-
for tool in tools:
|
|
29
|
-
# For other tools, use generic method names
|
|
30
|
-
method_name = f'_convert_{tool.method_name}'
|
|
31
31
|
|
|
32
|
-
|
|
33
|
-
|
|
32
|
+
def convert_v2_to_v1(
|
|
33
|
+
v2_data: V2ConversionResult | dict[str, Any],
|
|
34
|
+
annotation_meta: AnnotationMeta | None = None,
|
|
35
|
+
) -> dict[str, Any]:
|
|
36
|
+
"""Convert DM Schema V2 data to V1
|
|
34
37
|
|
|
35
|
-
|
|
38
|
+
Args:
|
|
39
|
+
v2_data: DM Schema V2 format data
|
|
40
|
+
annotation_meta: Optional V1 top-level structure passed separately
|
|
36
41
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
42
|
+
Returns:
|
|
43
|
+
DM Schema V1 format data
|
|
44
|
+
"""
|
|
45
|
+
from .to_v1 import DMV2ToV1Converter
|
|
40
46
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
warning_msg = f"Warning: Unknown tool type '{tool_type}'"
|
|
44
|
-
if item_id:
|
|
45
|
-
warning_msg += f' for item {item_id}'
|
|
46
|
-
print(warning_msg)
|
|
47
|
+
converter = DMV2ToV1Converter()
|
|
48
|
+
return converter.convert(v2_data, annotation_meta)
|
|
47
49
|
|
|
48
|
-
def _extract_media_type_info(self, media_id):
|
|
49
|
-
"""Extract media type information from media ID."""
|
|
50
|
-
media_type = media_id.split('_')[0] if '_' in media_id else media_id
|
|
51
|
-
media_type_plural = media_type + 's' if not media_type.endswith('s') else media_type
|
|
52
|
-
return media_type, media_type_plural
|
|
53
50
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
51
|
+
__all__ = [
|
|
52
|
+
'convert_v1_to_v2',
|
|
53
|
+
'convert_v2_to_v1',
|
|
54
|
+
'V2ConversionResult',
|
|
55
|
+
'V2AnnotationData',
|
|
56
|
+
'AnnotationMeta',
|
|
57
|
+
]
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
"""
|
|
2
|
+
DM Schema V1/V2 Converter Base Class
|
|
3
|
+
|
|
4
|
+
Created: 2025-12-11
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from abc import ABC, abstractmethod
|
|
8
|
+
from typing import TYPE_CHECKING, Any
|
|
9
|
+
|
|
10
|
+
from .types import MEDIA_TYPE_MAP, SUPPORTED_FILE_TYPES
|
|
11
|
+
from .utils import detect_file_type, extract_media_type_info
|
|
12
|
+
|
|
13
|
+
if TYPE_CHECKING:
|
|
14
|
+
from .tools import ToolProcessor
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class BaseDMConverter(ABC):
|
|
18
|
+
"""DM Schema Converter Base Class
|
|
19
|
+
|
|
20
|
+
Abstract base class for all DM converters.
|
|
21
|
+
|
|
22
|
+
Attributes:
|
|
23
|
+
file_type: File type to process (None for auto-detection)
|
|
24
|
+
SUPPORTED_FILE_TYPES: Tuple of supported file types
|
|
25
|
+
MEDIA_TYPE_MAP: Media type mapping dictionary
|
|
26
|
+
|
|
27
|
+
Example:
|
|
28
|
+
>>> class MyConverter(BaseDMConverter):
|
|
29
|
+
... def convert(self, data):
|
|
30
|
+
... # implementation
|
|
31
|
+
... pass
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
SUPPORTED_FILE_TYPES = SUPPORTED_FILE_TYPES
|
|
35
|
+
MEDIA_TYPE_MAP = MEDIA_TYPE_MAP
|
|
36
|
+
|
|
37
|
+
def __init__(self, file_type: str | None = None) -> None:
|
|
38
|
+
"""
|
|
39
|
+
Args:
|
|
40
|
+
file_type: File type to process (None for auto-detection)
|
|
41
|
+
|
|
42
|
+
Raises:
|
|
43
|
+
ValueError: Unsupported file type
|
|
44
|
+
"""
|
|
45
|
+
if file_type is not None and file_type not in self.SUPPORTED_FILE_TYPES:
|
|
46
|
+
raise ValueError(
|
|
47
|
+
f'Unsupported file type: {file_type}. Supported types: {", ".join(self.SUPPORTED_FILE_TYPES)}'
|
|
48
|
+
)
|
|
49
|
+
self.file_type = file_type
|
|
50
|
+
self._tool_processors: dict[str, 'ToolProcessor'] = {}
|
|
51
|
+
self._setup_tool_processors()
|
|
52
|
+
|
|
53
|
+
@abstractmethod
|
|
54
|
+
def _setup_tool_processors(self) -> None:
|
|
55
|
+
"""Register tool processors
|
|
56
|
+
|
|
57
|
+
Subclasses implement this to register supported tool processors.
|
|
58
|
+
|
|
59
|
+
Example:
|
|
60
|
+
>>> def _setup_tool_processors(self):
|
|
61
|
+
... from .tools import BoundingBoxProcessor, PolygonProcessor
|
|
62
|
+
... self.register_processor(BoundingBoxProcessor())
|
|
63
|
+
... self.register_processor(PolygonProcessor())
|
|
64
|
+
"""
|
|
65
|
+
...
|
|
66
|
+
|
|
67
|
+
def register_processor(self, processor: 'ToolProcessor') -> None:
|
|
68
|
+
"""Register a tool processor
|
|
69
|
+
|
|
70
|
+
Use this method to register processors when adding new tool support.
|
|
71
|
+
Allows extension without modifying existing code (AR-001).
|
|
72
|
+
|
|
73
|
+
Args:
|
|
74
|
+
processor: ToolProcessor implementation
|
|
75
|
+
|
|
76
|
+
Example:
|
|
77
|
+
>>> class KeypointProcessor:
|
|
78
|
+
... tool_name = "keypoint"
|
|
79
|
+
... def to_v2(self, v1_annotation, v1_data): ...
|
|
80
|
+
... def to_v1(self, v2_annotation): ...
|
|
81
|
+
>>> converter.register_processor(KeypointProcessor())
|
|
82
|
+
"""
|
|
83
|
+
self._tool_processors[processor.tool_name] = processor
|
|
84
|
+
|
|
85
|
+
def get_processor(self, tool_name: str) -> 'ToolProcessor | None':
|
|
86
|
+
"""Get a registered tool processor
|
|
87
|
+
|
|
88
|
+
Args:
|
|
89
|
+
tool_name: Tool name (e.g., 'bounding_box', 'polygon')
|
|
90
|
+
|
|
91
|
+
Returns:
|
|
92
|
+
Registered processor or None
|
|
93
|
+
"""
|
|
94
|
+
return self._tool_processors.get(tool_name)
|
|
95
|
+
|
|
96
|
+
@abstractmethod
|
|
97
|
+
def convert(self, data: dict[str, Any]) -> dict[str, Any]:
|
|
98
|
+
"""Perform data conversion
|
|
99
|
+
|
|
100
|
+
Args:
|
|
101
|
+
data: Input data (V1 or V2)
|
|
102
|
+
|
|
103
|
+
Returns:
|
|
104
|
+
Converted data (V2 or V1)
|
|
105
|
+
|
|
106
|
+
Raises:
|
|
107
|
+
ValueError: Data cannot be converted
|
|
108
|
+
"""
|
|
109
|
+
...
|
|
110
|
+
|
|
111
|
+
def _detect_file_type(self, data: dict[str, Any], is_v2: bool = False) -> str:
|
|
112
|
+
"""Auto-detect file type from data
|
|
113
|
+
|
|
114
|
+
Args:
|
|
115
|
+
data: Input data
|
|
116
|
+
is_v2: Whether the format is V2
|
|
117
|
+
|
|
118
|
+
Returns:
|
|
119
|
+
Detected file type ('image', 'video', etc.)
|
|
120
|
+
|
|
121
|
+
Raises:
|
|
122
|
+
ValueError: Unable to detect file type
|
|
123
|
+
"""
|
|
124
|
+
if self.file_type:
|
|
125
|
+
return self.file_type
|
|
126
|
+
return detect_file_type(data, is_v2)
|
|
127
|
+
|
|
128
|
+
def _extract_media_type_info(self, media_id: str) -> tuple[str, str]:
|
|
129
|
+
"""Extract type information from media ID
|
|
130
|
+
|
|
131
|
+
Args:
|
|
132
|
+
media_id: Media ID (e.g., 'image_1', 'video_2')
|
|
133
|
+
|
|
134
|
+
Returns:
|
|
135
|
+
(singular, plural) tuple (e.g., ('image', 'images'))
|
|
136
|
+
"""
|
|
137
|
+
return extract_media_type_info(media_id)
|