synapse-sdk 1.0.0a74__py3-none-any.whl → 1.0.0a76__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/annotation.py +0 -4
- synapse_sdk/devtools/docs/sidebars.ts +9 -1
- synapse_sdk/plugins/categories/pre_annotation/actions/to_task.py +208 -32
- synapse_sdk/plugins/categories/pre_annotation/templates/config.yaml +3 -0
- synapse_sdk/plugins/utils/__init__.py +43 -0
- synapse_sdk/plugins/utils/actions.py +119 -0
- synapse_sdk/plugins/utils/config.py +203 -0
- synapse_sdk/plugins/utils/legacy.py +95 -0
- synapse_sdk/plugins/utils/registry.py +58 -0
- synapse_sdk/plugins/utils.py +27 -0
- synapse_sdk/shared/enums.py +1 -0
- synapse_sdk/utils/converters/__init__.py +3 -1
- synapse_sdk/utils/converters/dm/__init__.py +109 -0
- synapse_sdk/utils/converters/dm/from_v1.py +415 -0
- synapse_sdk/utils/converters/dm/to_v1.py +254 -0
- synapse_sdk/utils/converters/pascal/__init__.py +0 -0
- synapse_sdk/utils/converters/pascal/from_dm.py +177 -0
- synapse_sdk/utils/converters/pascal/to_dm.py +135 -0
- synapse_sdk/utils/converters/yolo/from_dm.py +24 -18
- synapse_sdk/utils/converters/yolo/to_dm.py +185 -0
- synapse_sdk-1.0.0a76.dist-info/METADATA +107 -0
- {synapse_sdk-1.0.0a74.dist-info → synapse_sdk-1.0.0a76.dist-info}/RECORD +26 -14
- synapse_sdk-1.0.0a74.dist-info/METADATA +0 -37
- {synapse_sdk-1.0.0a74.dist-info → synapse_sdk-1.0.0a76.dist-info}/WHEEL +0 -0
- {synapse_sdk-1.0.0a74.dist-info → synapse_sdk-1.0.0a76.dist-info}/entry_points.txt +0 -0
- {synapse_sdk-1.0.0a74.dist-info → synapse_sdk-1.0.0a76.dist-info}/licenses/LICENSE +0 -0
- {synapse_sdk-1.0.0a74.dist-info → synapse_sdk-1.0.0a76.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
"""Plugin configuration utilities."""
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from typing import Any, Dict, List, Optional, Union
|
|
5
|
+
|
|
6
|
+
from synapse_sdk.utils.file import get_dict_from_file
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def read_plugin_config(plugin_path: Optional[Union[str, Path]] = None) -> Dict[str, Any]:
|
|
10
|
+
"""Read plugin configuration from config.yaml file.
|
|
11
|
+
|
|
12
|
+
Args:
|
|
13
|
+
plugin_path: Path to plugin directory. If None, looks for config.yaml in current directory.
|
|
14
|
+
|
|
15
|
+
Returns:
|
|
16
|
+
Dict containing plugin configuration.
|
|
17
|
+
|
|
18
|
+
Raises:
|
|
19
|
+
FileNotFoundError: If config.yaml file is not found.
|
|
20
|
+
ValueError: If config.yaml is invalid.
|
|
21
|
+
"""
|
|
22
|
+
config_file_name = 'config.yaml'
|
|
23
|
+
if plugin_path:
|
|
24
|
+
config_path = Path(plugin_path) / config_file_name
|
|
25
|
+
else:
|
|
26
|
+
config_path = config_file_name
|
|
27
|
+
|
|
28
|
+
try:
|
|
29
|
+
return get_dict_from_file(config_path)
|
|
30
|
+
except FileNotFoundError:
|
|
31
|
+
raise FileNotFoundError(f'Plugin config file not found: {config_path}')
|
|
32
|
+
except Exception as e:
|
|
33
|
+
raise ValueError(f'Invalid plugin config file: {e}')
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def get_plugin_actions(
|
|
37
|
+
config: Optional[Dict[str, Any]] = None, plugin_path: Optional[Union[str, Path]] = None
|
|
38
|
+
) -> List[str]:
|
|
39
|
+
"""Get list of action names from plugin configuration.
|
|
40
|
+
|
|
41
|
+
Args:
|
|
42
|
+
config: Plugin configuration dictionary. If None, reads from plugin_path.
|
|
43
|
+
plugin_path: Path to plugin directory. Used if config is None.
|
|
44
|
+
|
|
45
|
+
Returns:
|
|
46
|
+
List of action names defined in the plugin.
|
|
47
|
+
|
|
48
|
+
Raises:
|
|
49
|
+
ValueError: If neither config nor plugin_path is provided.
|
|
50
|
+
KeyError: If 'actions' key is missing from config.
|
|
51
|
+
|
|
52
|
+
Examples:
|
|
53
|
+
>>> get_plugin_actions(plugin_path="./my-plugin")
|
|
54
|
+
['train', 'inference', 'test']
|
|
55
|
+
|
|
56
|
+
>>> config = {'actions': {'train': {...}, 'test': {...}}}
|
|
57
|
+
>>> get_plugin_actions(config=config)
|
|
58
|
+
['train', 'test']
|
|
59
|
+
"""
|
|
60
|
+
if config is None:
|
|
61
|
+
if plugin_path is None:
|
|
62
|
+
raise ValueError('Either config or plugin_path must be provided')
|
|
63
|
+
config = read_plugin_config(plugin_path)
|
|
64
|
+
|
|
65
|
+
if 'actions' not in config:
|
|
66
|
+
raise KeyError("'actions' key not found in plugin configuration")
|
|
67
|
+
|
|
68
|
+
actions = config['actions']
|
|
69
|
+
if not isinstance(actions, dict):
|
|
70
|
+
raise ValueError("'actions' must be a dictionary")
|
|
71
|
+
|
|
72
|
+
return list(actions.keys())
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def get_action_config(
|
|
76
|
+
action_name: str, config: Optional[Dict[str, Any]] = None, plugin_path: Optional[Union[str, Path]] = None
|
|
77
|
+
) -> Dict[str, Any]:
|
|
78
|
+
"""Get configuration for a specific action.
|
|
79
|
+
|
|
80
|
+
Args:
|
|
81
|
+
action_name: Name of the action to get config for.
|
|
82
|
+
config: Plugin configuration dictionary. If None, reads from plugin_path.
|
|
83
|
+
plugin_path: Path to plugin directory. Used if config is None.
|
|
84
|
+
|
|
85
|
+
Returns:
|
|
86
|
+
Dictionary containing action configuration.
|
|
87
|
+
|
|
88
|
+
Raises:
|
|
89
|
+
ValueError: If neither config nor plugin_path is provided.
|
|
90
|
+
KeyError: If action is not found in plugin configuration.
|
|
91
|
+
|
|
92
|
+
Examples:
|
|
93
|
+
>>> get_action_config('train', plugin_path="./my-plugin")
|
|
94
|
+
{'entrypoint': 'plugin.train.TrainAction', 'method': 'job'}
|
|
95
|
+
"""
|
|
96
|
+
if config is None:
|
|
97
|
+
if plugin_path is None:
|
|
98
|
+
raise ValueError('Either config or plugin_path must be provided')
|
|
99
|
+
config = read_plugin_config(plugin_path)
|
|
100
|
+
|
|
101
|
+
if 'actions' not in config:
|
|
102
|
+
raise KeyError("'actions' key not found in plugin configuration")
|
|
103
|
+
|
|
104
|
+
actions = config['actions']
|
|
105
|
+
if action_name not in actions:
|
|
106
|
+
available_actions = list(actions.keys())
|
|
107
|
+
raise KeyError(f"Action '{action_name}' not found. Available actions: {available_actions}")
|
|
108
|
+
|
|
109
|
+
return actions[action_name]
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def validate_plugin_config(config: Dict[str, Any]) -> bool:
|
|
113
|
+
"""Validate plugin configuration structure.
|
|
114
|
+
|
|
115
|
+
Args:
|
|
116
|
+
config: Plugin configuration dictionary to validate.
|
|
117
|
+
|
|
118
|
+
Returns:
|
|
119
|
+
True if configuration is valid.
|
|
120
|
+
|
|
121
|
+
Raises:
|
|
122
|
+
ValueError: If configuration is invalid with detailed error message.
|
|
123
|
+
|
|
124
|
+
Examples:
|
|
125
|
+
>>> config = {
|
|
126
|
+
... 'name': 'My Plugin',
|
|
127
|
+
... 'code': 'my-plugin',
|
|
128
|
+
... 'version': '1.0.0',
|
|
129
|
+
... 'category': 'neural_net',
|
|
130
|
+
... 'actions': {'train': {'entrypoint': 'plugin.train.TrainAction'}}
|
|
131
|
+
... }
|
|
132
|
+
>>> validate_plugin_config(config)
|
|
133
|
+
True
|
|
134
|
+
"""
|
|
135
|
+
required_fields = ['name', 'code', 'version', 'category', 'actions']
|
|
136
|
+
|
|
137
|
+
# Check required fields
|
|
138
|
+
for field in required_fields:
|
|
139
|
+
if field not in config:
|
|
140
|
+
raise ValueError(f"Required field '{field}' missing from plugin configuration")
|
|
141
|
+
|
|
142
|
+
# Validate actions structure
|
|
143
|
+
actions = config['actions']
|
|
144
|
+
if not isinstance(actions, dict):
|
|
145
|
+
raise ValueError("'actions' must be a dictionary")
|
|
146
|
+
|
|
147
|
+
if not actions:
|
|
148
|
+
raise ValueError('Plugin must define at least one action')
|
|
149
|
+
|
|
150
|
+
# Validate each action
|
|
151
|
+
for action_name, action_config in actions.items():
|
|
152
|
+
if not isinstance(action_config, dict):
|
|
153
|
+
raise ValueError(f"Action '{action_name}' configuration must be a dictionary")
|
|
154
|
+
|
|
155
|
+
# Check for entrypoint (required for most actions)
|
|
156
|
+
if 'entrypoint' not in action_config and action_config.get('method') != 'restapi':
|
|
157
|
+
raise ValueError(f"Action '{action_name}' missing required 'entrypoint' field")
|
|
158
|
+
|
|
159
|
+
# Validate category
|
|
160
|
+
from synapse_sdk.plugins.enums import PluginCategory
|
|
161
|
+
|
|
162
|
+
valid_categories = [cat.value for cat in PluginCategory]
|
|
163
|
+
if config['category'] not in valid_categories:
|
|
164
|
+
raise ValueError(f"Invalid category '{config['category']}'. Must be one of: {valid_categories}")
|
|
165
|
+
|
|
166
|
+
return True
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
def get_plugin_metadata(
|
|
170
|
+
config: Optional[Dict[str, Any]] = None, plugin_path: Optional[Union[str, Path]] = None
|
|
171
|
+
) -> Dict[str, Any]:
|
|
172
|
+
"""Get plugin metadata (name, version, description, etc.).
|
|
173
|
+
|
|
174
|
+
Args:
|
|
175
|
+
config: Plugin configuration dictionary. If None, reads from plugin_path.
|
|
176
|
+
plugin_path: Path to plugin directory. Used if config is None.
|
|
177
|
+
|
|
178
|
+
Returns:
|
|
179
|
+
Dictionary containing plugin metadata.
|
|
180
|
+
|
|
181
|
+
Examples:
|
|
182
|
+
>>> get_plugin_metadata(plugin_path="./my-plugin")
|
|
183
|
+
{
|
|
184
|
+
'name': 'My Plugin',
|
|
185
|
+
'code': 'my-plugin',
|
|
186
|
+
'version': '1.0.0',
|
|
187
|
+
'category': 'neural_net',
|
|
188
|
+
'description': 'A custom ML plugin'
|
|
189
|
+
}
|
|
190
|
+
"""
|
|
191
|
+
if config is None:
|
|
192
|
+
if plugin_path is None:
|
|
193
|
+
raise ValueError('Either config or plugin_path must be provided')
|
|
194
|
+
config = read_plugin_config(plugin_path)
|
|
195
|
+
|
|
196
|
+
metadata_fields = ['name', 'code', 'version', 'category', 'description']
|
|
197
|
+
metadata = {}
|
|
198
|
+
|
|
199
|
+
for field in metadata_fields:
|
|
200
|
+
if field in config:
|
|
201
|
+
metadata[field] = config[field]
|
|
202
|
+
|
|
203
|
+
return metadata
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"""Legacy utility functions for backward compatibility."""
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
from synapse_sdk.i18n import gettext as _
|
|
6
|
+
from synapse_sdk.plugins.exceptions import ActionError
|
|
7
|
+
|
|
8
|
+
from .actions import get_action
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def read_requirements(file_path):
|
|
12
|
+
"""Read and parse a requirements.txt file.
|
|
13
|
+
|
|
14
|
+
Args:
|
|
15
|
+
file_path: Path to the requirements.txt file
|
|
16
|
+
|
|
17
|
+
Returns:
|
|
18
|
+
List of requirement strings, or None if file doesn't exist
|
|
19
|
+
"""
|
|
20
|
+
file_path = Path(file_path)
|
|
21
|
+
if not file_path.exists():
|
|
22
|
+
return None
|
|
23
|
+
|
|
24
|
+
requirements = []
|
|
25
|
+
for line in file_path.read_text().splitlines():
|
|
26
|
+
stripped_line = line.strip()
|
|
27
|
+
if stripped_line and not stripped_line.startswith('#'):
|
|
28
|
+
requirements.append(stripped_line)
|
|
29
|
+
return requirements
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def run_plugin(
|
|
33
|
+
action,
|
|
34
|
+
params,
|
|
35
|
+
plugin_config=None,
|
|
36
|
+
plugin_path=None,
|
|
37
|
+
modules=None,
|
|
38
|
+
requirements=None,
|
|
39
|
+
envs=None,
|
|
40
|
+
debug=False,
|
|
41
|
+
**kwargs,
|
|
42
|
+
):
|
|
43
|
+
"""Execute a plugin action with the specified parameters.
|
|
44
|
+
|
|
45
|
+
Args:
|
|
46
|
+
action: The action name to execute
|
|
47
|
+
params: Parameters for the action
|
|
48
|
+
plugin_config: Plugin configuration dictionary
|
|
49
|
+
plugin_path: Path to the plugin directory
|
|
50
|
+
modules: List of modules for debugging
|
|
51
|
+
requirements: List of requirements
|
|
52
|
+
envs: Environment variables dictionary
|
|
53
|
+
debug: Whether to run in debug mode
|
|
54
|
+
**kwargs: Additional keyword arguments
|
|
55
|
+
|
|
56
|
+
Returns:
|
|
57
|
+
Result of the action execution
|
|
58
|
+
"""
|
|
59
|
+
from synapse_sdk.plugins.models import PluginRelease
|
|
60
|
+
|
|
61
|
+
if not envs:
|
|
62
|
+
envs = {}
|
|
63
|
+
|
|
64
|
+
if debug:
|
|
65
|
+
if plugin_path and plugin_path.startswith('http'):
|
|
66
|
+
if not plugin_config:
|
|
67
|
+
raise ActionError({'config': _('"plugin_path"가 url인 경우에는 "config"가 필수입니다.')})
|
|
68
|
+
plugin_release = PluginRelease(config=plugin_config)
|
|
69
|
+
else:
|
|
70
|
+
plugin_release = PluginRelease(plugin_path=plugin_path)
|
|
71
|
+
plugin_config = plugin_release.config
|
|
72
|
+
|
|
73
|
+
if action not in plugin_release.actions:
|
|
74
|
+
raise ActionError({'action': _('해당 액션은 존재하지 않습니다.')})
|
|
75
|
+
|
|
76
|
+
if plugin_path:
|
|
77
|
+
envs['SYNAPSE_DEBUG_PLUGIN_PATH'] = plugin_path
|
|
78
|
+
|
|
79
|
+
if modules:
|
|
80
|
+
envs['SYNAPSE_DEBUG_MODULES'] = ','.join(modules)
|
|
81
|
+
|
|
82
|
+
else:
|
|
83
|
+
if plugin_config is None:
|
|
84
|
+
raise ActionError({'config': _('플러그인 설정은 필수입니다.')})
|
|
85
|
+
|
|
86
|
+
action = get_action(
|
|
87
|
+
action,
|
|
88
|
+
params,
|
|
89
|
+
config=plugin_config,
|
|
90
|
+
requirements=requirements,
|
|
91
|
+
envs=envs,
|
|
92
|
+
debug=debug,
|
|
93
|
+
**kwargs,
|
|
94
|
+
)
|
|
95
|
+
return action.run_action()
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"""Plugin registry utilities."""
|
|
2
|
+
|
|
3
|
+
from typing import List
|
|
4
|
+
|
|
5
|
+
from synapse_sdk.plugins.enums import PluginCategory
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def get_plugin_categories() -> List[str]:
|
|
9
|
+
"""Get list of all available plugin categories.
|
|
10
|
+
|
|
11
|
+
Returns:
|
|
12
|
+
List of plugin category names.
|
|
13
|
+
|
|
14
|
+
Examples:
|
|
15
|
+
>>> get_plugin_categories()
|
|
16
|
+
['neural_net', 'export', 'upload', 'smart_tool', 'post_annotation', 'pre_annotation', 'data_validation']
|
|
17
|
+
"""
|
|
18
|
+
return [plugin_category.value for plugin_category in PluginCategory]
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def is_valid_category(category: str) -> bool:
|
|
22
|
+
"""Check if a category is valid.
|
|
23
|
+
|
|
24
|
+
Args:
|
|
25
|
+
category: Category name to validate.
|
|
26
|
+
|
|
27
|
+
Returns:
|
|
28
|
+
True if category is valid, False otherwise.
|
|
29
|
+
|
|
30
|
+
Examples:
|
|
31
|
+
>>> is_valid_category('neural_net')
|
|
32
|
+
True
|
|
33
|
+
>>> is_valid_category('invalid_category')
|
|
34
|
+
False
|
|
35
|
+
"""
|
|
36
|
+
return category in get_plugin_categories()
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def get_category_display_name(category: str) -> str:
|
|
40
|
+
"""Get human-readable display name for a category.
|
|
41
|
+
|
|
42
|
+
Args:
|
|
43
|
+
category: Category name.
|
|
44
|
+
|
|
45
|
+
Returns:
|
|
46
|
+
Human-readable category name.
|
|
47
|
+
|
|
48
|
+
Examples:
|
|
49
|
+
>>> get_category_display_name('neural_net')
|
|
50
|
+
'Neural Net'
|
|
51
|
+
>>> get_category_display_name('data_validation')
|
|
52
|
+
'Data Validation'
|
|
53
|
+
"""
|
|
54
|
+
try:
|
|
55
|
+
plugin_category = PluginCategory(category)
|
|
56
|
+
return plugin_category.name.replace('_', ' ').title()
|
|
57
|
+
except ValueError:
|
|
58
|
+
return category.replace('_', ' ').title()
|
synapse_sdk/plugins/utils.py
CHANGED
|
@@ -43,7 +43,34 @@ def get_plugin_categories():
|
|
|
43
43
|
return [plugin_category.value for plugin_category in PluginCategory]
|
|
44
44
|
|
|
45
45
|
|
|
46
|
+
def get_plugin_actions(config=None, plugin_path=None):
|
|
47
|
+
"""Get list of action names from plugin configuration.
|
|
48
|
+
|
|
49
|
+
Args:
|
|
50
|
+
config: Plugin configuration dictionary. If None, reads from plugin_path.
|
|
51
|
+
plugin_path: Path to plugin directory. Used if config is None.
|
|
52
|
+
|
|
53
|
+
Returns:
|
|
54
|
+
List of action names defined in the plugin.
|
|
55
|
+
"""
|
|
56
|
+
if config is None:
|
|
57
|
+
if plugin_path is None:
|
|
58
|
+
config = read_plugin_config()
|
|
59
|
+
else:
|
|
60
|
+
config = read_plugin_config(plugin_path)
|
|
61
|
+
|
|
62
|
+
if 'actions' not in config:
|
|
63
|
+
raise KeyError("'actions' key not found in plugin configuration")
|
|
64
|
+
|
|
65
|
+
actions = config['actions']
|
|
66
|
+
if not isinstance(actions, dict):
|
|
67
|
+
raise ValueError("'actions' must be a dictionary")
|
|
68
|
+
|
|
69
|
+
return list(actions.keys())
|
|
70
|
+
|
|
71
|
+
|
|
46
72
|
def read_plugin_config(plugin_path=None):
|
|
73
|
+
"""Legacy function for backward compatibility."""
|
|
47
74
|
config_file_name = 'config.yaml'
|
|
48
75
|
if plugin_path:
|
|
49
76
|
config_path = Path(plugin_path) / config_file_name
|
synapse_sdk/shared/enums.py
CHANGED
|
@@ -192,7 +192,9 @@ class ToDMConverter(BaseConverter):
|
|
|
192
192
|
json_filename = os.path.splitext(img_filename)[0] + '.json'
|
|
193
193
|
with open(os.path.join(json_dir, json_filename), 'w', encoding='utf-8') as jf:
|
|
194
194
|
json.dump(dm_json, jf, indent=2, ensure_ascii=False)
|
|
195
|
-
if img_src_path
|
|
195
|
+
if img_src_path:
|
|
196
|
+
if not os.path.exists(img_src_path):
|
|
197
|
+
raise FileNotFoundError(f'Source file does not exist: {img_src_path}')
|
|
196
198
|
shutil.copy(img_src_path, os.path.join(original_file_dir, img_filename))
|
|
197
199
|
else:
|
|
198
200
|
json_dir = os.path.join(output_dir, 'json')
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
from abc import ABC, abstractmethod
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class BaseDMConverter(ABC):
|
|
5
|
+
"""Base class for DM format converters."""
|
|
6
|
+
|
|
7
|
+
SUPPORTED_TOOLS = [
|
|
8
|
+
'bounding_box',
|
|
9
|
+
'named_entity',
|
|
10
|
+
'classification',
|
|
11
|
+
'polyline',
|
|
12
|
+
'keypoint',
|
|
13
|
+
'3d_bounding_box',
|
|
14
|
+
'segmentation',
|
|
15
|
+
'polygon',
|
|
16
|
+
'relation',
|
|
17
|
+
'group',
|
|
18
|
+
]
|
|
19
|
+
|
|
20
|
+
def __init__(self):
|
|
21
|
+
"""Initialize the base converter."""
|
|
22
|
+
self.tool_processors = self._setup_tool_processors()
|
|
23
|
+
|
|
24
|
+
def _setup_tool_processors(self):
|
|
25
|
+
"""Setup tool processor mapping."""
|
|
26
|
+
return {
|
|
27
|
+
'bounding_box': self._process_bounding_box,
|
|
28
|
+
'named_entity': self._process_named_entity,
|
|
29
|
+
'classification': self._process_classification,
|
|
30
|
+
'polyline': self._process_polyline,
|
|
31
|
+
'keypoint': self._process_keypoint,
|
|
32
|
+
'3d_bounding_box': self._process_3d_bounding_box,
|
|
33
|
+
'segmentation': self._process_segmentation,
|
|
34
|
+
'polygon': self._process_polygon,
|
|
35
|
+
'relation': self._process_relation,
|
|
36
|
+
'group': self._process_group,
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
@abstractmethod
|
|
40
|
+
def convert(self):
|
|
41
|
+
"""Convert data from one format to another."""
|
|
42
|
+
pass
|
|
43
|
+
|
|
44
|
+
@abstractmethod
|
|
45
|
+
def _process_bounding_box(self, *args, **kwargs):
|
|
46
|
+
"""Process bounding box annotation."""
|
|
47
|
+
pass
|
|
48
|
+
|
|
49
|
+
@abstractmethod
|
|
50
|
+
def _process_named_entity(self, *args, **kwargs):
|
|
51
|
+
"""Process named entity annotation."""
|
|
52
|
+
pass
|
|
53
|
+
|
|
54
|
+
@abstractmethod
|
|
55
|
+
def _process_classification(self, *args, **kwargs):
|
|
56
|
+
"""Process classification annotation."""
|
|
57
|
+
pass
|
|
58
|
+
|
|
59
|
+
@abstractmethod
|
|
60
|
+
def _process_polyline(self, *args, **kwargs):
|
|
61
|
+
"""Process polyline annotation."""
|
|
62
|
+
pass
|
|
63
|
+
|
|
64
|
+
@abstractmethod
|
|
65
|
+
def _process_keypoint(self, *args, **kwargs):
|
|
66
|
+
"""Process keypoint annotation."""
|
|
67
|
+
pass
|
|
68
|
+
|
|
69
|
+
@abstractmethod
|
|
70
|
+
def _process_3d_bounding_box(self, *args, **kwargs):
|
|
71
|
+
"""Process 3D bounding box annotation."""
|
|
72
|
+
pass
|
|
73
|
+
|
|
74
|
+
@abstractmethod
|
|
75
|
+
def _process_segmentation(self, *args, **kwargs):
|
|
76
|
+
"""Process segmentation annotation."""
|
|
77
|
+
pass
|
|
78
|
+
|
|
79
|
+
@abstractmethod
|
|
80
|
+
def _process_polygon(self, *args, **kwargs):
|
|
81
|
+
"""Process polygon annotation."""
|
|
82
|
+
pass
|
|
83
|
+
|
|
84
|
+
@abstractmethod
|
|
85
|
+
def _process_relation(self, *args, **kwargs):
|
|
86
|
+
"""Process relation annotation."""
|
|
87
|
+
pass
|
|
88
|
+
|
|
89
|
+
@abstractmethod
|
|
90
|
+
def _process_group(self, *args, **kwargs):
|
|
91
|
+
"""Process group annotation."""
|
|
92
|
+
pass
|
|
93
|
+
|
|
94
|
+
def _handle_unknown_tool(self, tool_type, item_id=None):
|
|
95
|
+
"""Handle unknown tool types with consistent warning message."""
|
|
96
|
+
warning_msg = f"Warning: Unknown tool type '{tool_type}'"
|
|
97
|
+
if item_id:
|
|
98
|
+
warning_msg += f' for item {item_id}'
|
|
99
|
+
print(warning_msg)
|
|
100
|
+
|
|
101
|
+
def _extract_media_type_info(self, media_id):
|
|
102
|
+
"""Extract media type information from media ID."""
|
|
103
|
+
media_type = media_id.split('_')[0] if '_' in media_id else media_id
|
|
104
|
+
media_type_plural = media_type + 's' if not media_type.endswith('s') else media_type
|
|
105
|
+
return media_type, media_type_plural
|
|
106
|
+
|
|
107
|
+
def _singularize_media_type(self, media_type_plural):
|
|
108
|
+
"""Convert plural media type to singular."""
|
|
109
|
+
return media_type_plural.rstrip('s')
|