synapse-sdk 0.1.1a0__tar.gz → 1.0.0a0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of synapse-sdk might be problematic. Click here for more details.
- {synapse_sdk-0.1.1a0 → synapse_sdk-1.0.0a0}/PKG-INFO +3 -1
- {synapse_sdk-0.1.1a0 → synapse_sdk-1.0.0a0}/pyproject.toml +2 -0
- {synapse_sdk-0.1.1a0 → synapse_sdk-1.0.0a0}/requirements.txt +2 -0
- {synapse_sdk-0.1.1a0 → synapse_sdk-1.0.0a0}/synapse/plugins/__init__.py +15 -8
- synapse_sdk-1.0.0a0/synapse/plugins/categories/base.py +185 -0
- synapse_sdk-1.0.0a0/synapse/plugins/categories/data_validation/actions/validation.py +10 -0
- synapse_sdk-1.0.0a0/synapse/plugins/categories/decorators.py +13 -0
- synapse_sdk-1.0.0a0/synapse/plugins/categories/export/actions/export.py +10 -0
- synapse_sdk-1.0.0a0/synapse/plugins/categories/import/actions/import.py +10 -0
- synapse_sdk-1.0.0a0/synapse/plugins/categories/neural_net/actions/deployment.py +23 -0
- synapse_sdk-1.0.0a0/synapse/plugins/categories/neural_net/actions/inference.py +10 -0
- synapse_sdk-1.0.0a0/synapse/plugins/categories/neural_net/actions/test.py +10 -0
- {synapse_sdk-0.1.1a0 → synapse_sdk-1.0.0a0}/synapse/plugins/categories/neural_net/actions/train.py +6 -1
- synapse_sdk-1.0.0a0/synapse/plugins/categories/post_annotation/__init__.py +0 -0
- synapse_sdk-1.0.0a0/synapse/plugins/categories/post_annotation/actions/__init__.py +0 -0
- synapse_sdk-1.0.0a0/synapse/plugins/categories/post_annotation/actions/post_annotation.py +10 -0
- synapse_sdk-1.0.0a0/synapse/plugins/categories/pre_annotation/__init__.py +0 -0
- synapse_sdk-1.0.0a0/synapse/plugins/categories/pre_annotation/actions/__init__.py +0 -0
- synapse_sdk-1.0.0a0/synapse/plugins/categories/pre_annotation/actions/pre_annotation.py +10 -0
- synapse_sdk-1.0.0a0/synapse/plugins/categories/registry.py +16 -0
- synapse_sdk-1.0.0a0/synapse/plugins/enums.py +16 -0
- synapse_sdk-1.0.0a0/synapse/plugins/job.py +5 -0
- synapse_sdk-1.0.0a0/synapse/plugins/upload.py +79 -0
- synapse_sdk-1.0.0a0/synapse/plugins/utils.py +40 -0
- synapse_sdk-1.0.0a0/synapse/utils/__init__.py +0 -0
- synapse_sdk-1.0.0a0/synapse/utils/debug.py +2 -0
- {synapse_sdk-0.1.1a0 → synapse_sdk-1.0.0a0}/synapse_sdk.egg-info/PKG-INFO +3 -1
- {synapse_sdk-0.1.1a0 → synapse_sdk-1.0.0a0}/synapse_sdk.egg-info/SOURCES.txt +18 -2
- {synapse_sdk-0.1.1a0 → synapse_sdk-1.0.0a0}/synapse_sdk.egg-info/requires.txt +2 -0
- synapse_sdk-0.1.1a0/synapse/plugins/categories/__init__.py +0 -11
- synapse_sdk-0.1.1a0/synapse/plugins/categories/base.py +0 -49
- synapse_sdk-0.1.1a0/synapse/plugins/categories/neural_net/actions/deployment.py +0 -24
- synapse_sdk-0.1.1a0/synapse/plugins/categories/neural_net/actions/test.py +0 -6
- synapse_sdk-0.1.1a0/synapse/plugins/utils.py +0 -26
- {synapse_sdk-0.1.1a0 → synapse_sdk-1.0.0a0}/.github/workflows/lint.yml +0 -0
- {synapse_sdk-0.1.1a0 → synapse_sdk-1.0.0a0}/.github/workflows/pypi-publish.yml +0 -0
- {synapse_sdk-0.1.1a0 → synapse_sdk-1.0.0a0}/.gitignore +0 -0
- {synapse_sdk-0.1.1a0 → synapse_sdk-1.0.0a0}/.pre-commit-config.yaml +0 -0
- {synapse_sdk-0.1.1a0 → synapse_sdk-1.0.0a0}/LICENSE +0 -0
- {synapse_sdk-0.1.1a0 → synapse_sdk-1.0.0a0}/README.md +0 -0
- {synapse_sdk-0.1.1a0 → synapse_sdk-1.0.0a0}/setup.cfg +0 -0
- {synapse_sdk-0.1.1a0 → synapse_sdk-1.0.0a0}/synapse/__init__.py +0 -0
- {synapse_sdk-0.1.1a0 → synapse_sdk-1.0.0a0}/synapse/client/__init__.py +0 -0
- {synapse_sdk-0.1.1a0 → synapse_sdk-1.0.0a0}/synapse/client/exceptions.py +0 -0
- {synapse_sdk-0.1.1a0 → synapse_sdk-1.0.0a0}/synapse/client/mixins/__init__.py +0 -0
- {synapse_sdk-0.1.1a0 → synapse_sdk-1.0.0a0}/synapse/client/mixins/annotation.py +0 -0
- {synapse_sdk-0.1.1a0 → synapse_sdk-1.0.0a0}/synapse/client/mixins/dataset.py +0 -0
- {synapse_sdk-0.1.1a0 → synapse_sdk-1.0.0a0}/synapse/client/mixins/integration.py +0 -0
- {synapse_sdk-0.1.1a0 → synapse_sdk-1.0.0a0}/synapse/client/mixins/ml.py +0 -0
- {synapse_sdk-0.1.1a0 → synapse_sdk-1.0.0a0}/synapse/client/utils.py +0 -0
- {synapse_sdk-0.1.1a0 → synapse_sdk-1.0.0a0}/synapse/config.py +0 -0
- {synapse_sdk-0.1.1a0 → synapse_sdk-1.0.0a0}/synapse/loggers.py +0 -0
- {synapse_sdk-0.1.1a0/synapse/plugins/categories/custom_script → synapse_sdk-1.0.0a0/synapse/plugins/categories}/__init__.py +0 -0
- {synapse_sdk-0.1.1a0/synapse/plugins/categories/custom_script/actions → synapse_sdk-1.0.0a0/synapse/plugins/categories/data_validation}/__init__.py +0 -0
- {synapse_sdk-0.1.1a0/synapse/plugins/categories/export → synapse_sdk-1.0.0a0/synapse/plugins/categories/data_validation/actions}/__init__.py +0 -0
- {synapse_sdk-0.1.1a0/synapse/plugins/categories/export/actions → synapse_sdk-1.0.0a0/synapse/plugins/categories/export}/__init__.py +0 -0
- {synapse_sdk-0.1.1a0/synapse/plugins/categories/import → synapse_sdk-1.0.0a0/synapse/plugins/categories/export/actions}/__init__.py +0 -0
- {synapse_sdk-0.1.1a0/synapse/plugins/categories/import/actions → synapse_sdk-1.0.0a0/synapse/plugins/categories/import}/__init__.py +0 -0
- {synapse_sdk-0.1.1a0/synapse/plugins/categories/neural_net → synapse_sdk-1.0.0a0/synapse/plugins/categories/import/actions}/__init__.py +0 -0
- {synapse_sdk-0.1.1a0/synapse/plugins/categories/neural_net/actions → synapse_sdk-1.0.0a0/synapse/plugins/categories/neural_net}/__init__.py +0 -0
- {synapse_sdk-0.1.1a0/synapse/utils → synapse_sdk-1.0.0a0/synapse/plugins/categories/neural_net/actions}/__init__.py +0 -0
- {synapse_sdk-0.1.1a0 → synapse_sdk-1.0.0a0}/synapse/utils/file.py +0 -0
- {synapse_sdk-0.1.1a0 → synapse_sdk-1.0.0a0}/synapse/utils/module_loading.py +0 -0
- {synapse_sdk-0.1.1a0 → synapse_sdk-1.0.0a0}/synapse/utils/string.py +0 -0
- {synapse_sdk-0.1.1a0 → synapse_sdk-1.0.0a0}/synapse_sdk.egg-info/dependency_links.txt +0 -0
- {synapse_sdk-0.1.1a0 → synapse_sdk-1.0.0a0}/synapse_sdk.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: synapse-sdk
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 1.0.0a0
|
|
4
4
|
Summary: synapse sdk
|
|
5
5
|
Author-email: datamaker <developer@datamaker.io>
|
|
6
6
|
License: MIT
|
|
@@ -8,8 +8,10 @@ Classifier: Programming Language :: Python :: 3
|
|
|
8
8
|
Requires-Python: >=3.11
|
|
9
9
|
Description-Content-Type: text/markdown
|
|
10
10
|
License-File: LICENSE
|
|
11
|
+
Requires-Dist: boto3
|
|
11
12
|
Requires-Dist: requests
|
|
12
13
|
Requires-Dist: tqdm
|
|
14
|
+
Requires-Dist: python-dotenv
|
|
13
15
|
Requires-Dist: pyyaml
|
|
14
16
|
Requires-Dist: pydantic
|
|
15
17
|
Requires-Dist: ray[all]
|
|
@@ -1,17 +1,23 @@
|
|
|
1
1
|
import argparse
|
|
2
|
+
import os
|
|
3
|
+
|
|
4
|
+
from dotenv import load_dotenv
|
|
2
5
|
|
|
3
6
|
from synapse.plugins.utils import get_action
|
|
4
7
|
|
|
8
|
+
|
|
5
9
|
action = None
|
|
6
10
|
|
|
7
11
|
|
|
8
|
-
def
|
|
12
|
+
def run():
|
|
9
13
|
global action
|
|
10
14
|
parser = argparse.ArgumentParser(description='synapse plugin runner')
|
|
11
15
|
|
|
12
16
|
# Add arguments
|
|
13
17
|
parser.add_argument('action', help='action to run on this plugin')
|
|
14
18
|
parser.add_argument('params', help='parameter of the action')
|
|
19
|
+
parser.add_argument('--direct', help='run without using ray', action='store_true')
|
|
20
|
+
parser.add_argument('--debug', help='run with debug mode', action='store_true')
|
|
15
21
|
|
|
16
22
|
# Parse arguments
|
|
17
23
|
args = parser.parse_args()
|
|
@@ -19,14 +25,15 @@ def init():
|
|
|
19
25
|
# Access parsed arguments
|
|
20
26
|
action = args.action
|
|
21
27
|
params = args.params
|
|
28
|
+
direct = args.direct
|
|
29
|
+
debug = args.debug
|
|
22
30
|
|
|
23
|
-
|
|
31
|
+
load_dotenv(os.path.join(os.getcwd(), '.env'))
|
|
24
32
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
action.run()
|
|
33
|
+
action = get_action(action, params, direct=direct, debug=debug)
|
|
34
|
+
result = action.run_action()
|
|
35
|
+
if debug:
|
|
36
|
+
print(result)
|
|
30
37
|
|
|
31
38
|
|
|
32
|
-
__all__ = ['
|
|
39
|
+
__all__ = ['run']
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import inspect
|
|
2
|
+
import json
|
|
3
|
+
import os
|
|
4
|
+
from functools import cached_property
|
|
5
|
+
from pprint import pprint
|
|
6
|
+
|
|
7
|
+
import ray
|
|
8
|
+
import requests
|
|
9
|
+
from ray.dashboard.modules.job.sdk import JobSubmissionClient
|
|
10
|
+
|
|
11
|
+
from synapse.loggers import ConsoleLogger
|
|
12
|
+
from synapse.plugins.enums import RunMethod
|
|
13
|
+
from synapse.plugins.upload import upload_path, build_and_upload
|
|
14
|
+
from synapse.plugins.utils import get_plugin_checksum
|
|
15
|
+
from synapse.utils.module_loading import import_string
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class Action:
|
|
19
|
+
name = None
|
|
20
|
+
category = None
|
|
21
|
+
method = None
|
|
22
|
+
params = None
|
|
23
|
+
plugin_config = None
|
|
24
|
+
config = None
|
|
25
|
+
client = None
|
|
26
|
+
logger = None
|
|
27
|
+
debug = False
|
|
28
|
+
|
|
29
|
+
default_envs = [
|
|
30
|
+
'RAY_SERVE_ADDRESS',
|
|
31
|
+
'SYNAPSE_PLUGIN_URL',
|
|
32
|
+
'SYNAPSE_PLUGIN_PATH',
|
|
33
|
+
'SYNAPSE_PLUGIN_BASE_URL',
|
|
34
|
+
'SYNAPSE_PLUGIN_UPLOAD_S3_ENDPOINT_URL',
|
|
35
|
+
'SYNAPSE_PLUGIN_UPLOAD_S3_BUCKET_NAME',
|
|
36
|
+
'SYNAPSE_PLUGIN_UPLOAD_S3_ACCESS_KEY',
|
|
37
|
+
'SYNAPSE_PLUGIN_UPLOAD_S3_SECRET_KEY',
|
|
38
|
+
'SYNAPSE_PLUGIN_UPLOAD_S3_BASE_URL',
|
|
39
|
+
'SYNAPSE_DEBUG_MODULES',
|
|
40
|
+
]
|
|
41
|
+
|
|
42
|
+
def __init__(self, params, plugin_config, envs=None, job_id=None, direct=False, debug=False):
|
|
43
|
+
self.params = params
|
|
44
|
+
self.plugin_config = plugin_config
|
|
45
|
+
self.config = plugin_config['actions'][self.name]
|
|
46
|
+
self.job_id = job_id
|
|
47
|
+
self.direct = direct
|
|
48
|
+
self.debug = debug
|
|
49
|
+
if envs:
|
|
50
|
+
self.envs = {**envs, **self.get_default_envs()}
|
|
51
|
+
else:
|
|
52
|
+
self.envs = self.get_default_envs()
|
|
53
|
+
|
|
54
|
+
# TODO logger 지정 방식 개선
|
|
55
|
+
self.logger = ConsoleLogger()
|
|
56
|
+
|
|
57
|
+
@cached_property
|
|
58
|
+
def plugin_id(self):
|
|
59
|
+
code = self.plugin_config['code']
|
|
60
|
+
version = self.plugin_config['version']
|
|
61
|
+
return f'{code}@{version}'
|
|
62
|
+
|
|
63
|
+
@cached_property
|
|
64
|
+
def plugin_checksum(self):
|
|
65
|
+
return get_plugin_checksum(self.plugin_id)
|
|
66
|
+
|
|
67
|
+
@cached_property
|
|
68
|
+
def plugin_url(self):
|
|
69
|
+
if self.debug:
|
|
70
|
+
plugin_url = self.envs.get('SYNAPSE_PLUGIN_URL')
|
|
71
|
+
if not plugin_url:
|
|
72
|
+
plugin_url = upload_path(self.envs.get('SYNAPSE_PLUGIN_PATH', '.'), **self.get_kwargs_upload_path())
|
|
73
|
+
self.envs['SYNAPSE_PLUGIN_URL'] = plugin_url
|
|
74
|
+
return plugin_url
|
|
75
|
+
base_url = self.envs['SYNAPSE_PLUGIN_BASE_URL']
|
|
76
|
+
return str(os.path.join(base_url, f'{self.plugin_checksum}.zip'))
|
|
77
|
+
|
|
78
|
+
@cached_property
|
|
79
|
+
def entrypoint(self):
|
|
80
|
+
return import_string(self.config['entrypoint'])
|
|
81
|
+
|
|
82
|
+
def get_kwargs_upload_path(self):
|
|
83
|
+
# TODO upload 관련 env 단일화 후 제거
|
|
84
|
+
return {
|
|
85
|
+
'endpoint_url': self.envs['SYNAPSE_PLUGIN_UPLOAD_S3_ENDPOINT_URL'],
|
|
86
|
+
'bucket_name': self.envs['SYNAPSE_PLUGIN_UPLOAD_S3_BUCKET_NAME'],
|
|
87
|
+
'access_key': self.envs['SYNAPSE_PLUGIN_UPLOAD_S3_ACCESS_KEY'],
|
|
88
|
+
'secret_key': self.envs['SYNAPSE_PLUGIN_UPLOAD_S3_SECRET_KEY'],
|
|
89
|
+
'base_url': self.envs['SYNAPSE_PLUGIN_UPLOAD_S3_BASE_URL'],
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
def get_default_envs(self):
|
|
93
|
+
return {env: os.environ[env] for env in self.default_envs if env in os.environ}
|
|
94
|
+
|
|
95
|
+
def get_debug_modules(self):
|
|
96
|
+
debug_modules = []
|
|
97
|
+
for module_path in self.envs.get('SYNAPSE_DEBUG_MODULES', '').split(','):
|
|
98
|
+
if module_path.startswith('http'):
|
|
99
|
+
module_url = module_path
|
|
100
|
+
else:
|
|
101
|
+
module_url = build_and_upload(module_path, **self.get_kwargs_upload_path())
|
|
102
|
+
debug_modules.append(module_url)
|
|
103
|
+
self.envs['SYNAPSE_DEBUG_MODULES'] = ','.join(debug_modules)
|
|
104
|
+
return debug_modules
|
|
105
|
+
|
|
106
|
+
def get_runtime_env(self):
|
|
107
|
+
runtime_env = {
|
|
108
|
+
'pip': ['-r ${RAY_RUNTIME_ENV_CREATE_WORKING_DIR}/requirements.txt'],
|
|
109
|
+
'working_dir': self.plugin_url,
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if self.debug:
|
|
113
|
+
runtime_env['pip'] += self.get_debug_modules()
|
|
114
|
+
|
|
115
|
+
runtime_env['env_vars'] = self.envs
|
|
116
|
+
pprint(runtime_env)
|
|
117
|
+
return runtime_env
|
|
118
|
+
|
|
119
|
+
def run(self):
|
|
120
|
+
return self.entrypoint(self, **self.params)
|
|
121
|
+
|
|
122
|
+
def run_action(self):
|
|
123
|
+
if self.direct:
|
|
124
|
+
if self.method == RunMethod.RESTAPI:
|
|
125
|
+
return self.run_by_restapi()
|
|
126
|
+
else:
|
|
127
|
+
return self.run()
|
|
128
|
+
return getattr(self, f'run_by_{self.method.value}')()
|
|
129
|
+
|
|
130
|
+
def run_by_task(self):
|
|
131
|
+
@ray.remote(runtime_env=self.get_runtime_env())
|
|
132
|
+
def run_task(category, action, *args, **kwargs):
|
|
133
|
+
from synapse.plugins.utils import get_action_class
|
|
134
|
+
|
|
135
|
+
action = get_action_class(category, action)(*args, **kwargs)
|
|
136
|
+
return action.run_action()
|
|
137
|
+
|
|
138
|
+
init_signature = inspect.signature(self.__class__.__init__)
|
|
139
|
+
|
|
140
|
+
args = []
|
|
141
|
+
kwargs = {}
|
|
142
|
+
|
|
143
|
+
for param in init_signature.parameters.values():
|
|
144
|
+
if param.name == 'self':
|
|
145
|
+
continue
|
|
146
|
+
if param.default == param.empty:
|
|
147
|
+
args.append(getattr(self, param.name))
|
|
148
|
+
else:
|
|
149
|
+
kwargs[param.name] = getattr(self, param.name)
|
|
150
|
+
|
|
151
|
+
kwargs['direct'] = True
|
|
152
|
+
return ray.get(run_task.remote(self.category.value, self.name, *args, **kwargs))
|
|
153
|
+
|
|
154
|
+
def run_by_job(self):
|
|
155
|
+
entrypoint_args = [self.name, f'"{json.dumps(self.params)}"']
|
|
156
|
+
if self.debug:
|
|
157
|
+
entrypoint_args.append('--debug')
|
|
158
|
+
|
|
159
|
+
client = JobSubmissionClient()
|
|
160
|
+
return client.submit_job(
|
|
161
|
+
submission_id=self.job_id,
|
|
162
|
+
entrypoint=f'python main.py {" ".join(entrypoint_args)} --direct',
|
|
163
|
+
runtime_env=self.get_runtime_env(),
|
|
164
|
+
)
|
|
165
|
+
|
|
166
|
+
def run_by_restapi(self):
|
|
167
|
+
path = self.params.pop('path', '')
|
|
168
|
+
method = self.params.pop('method')
|
|
169
|
+
|
|
170
|
+
url = os.path.join(self.envs['RAY_SERVE_ADDRESS'], self.plugin_checksum, path)
|
|
171
|
+
response = getattr(requests, method)(url, **self.params)
|
|
172
|
+
# TODO ok response가 아닌 경우 대응하기
|
|
173
|
+
return response.json()
|
|
174
|
+
|
|
175
|
+
def set_progress(self, current, total, category=''):
|
|
176
|
+
self.logger.set_progress(current, total, category)
|
|
177
|
+
|
|
178
|
+
def log(self, action, data):
|
|
179
|
+
self.logger.log(action, data)
|
|
180
|
+
|
|
181
|
+
def log_event(self, message):
|
|
182
|
+
self.logger.log('event', {'content': message})
|
|
183
|
+
|
|
184
|
+
def end_log(self):
|
|
185
|
+
self.log_event('Plugin run is complete.')
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
from synapse.plugins.categories.base import Action
|
|
2
|
+
from synapse.plugins.categories.decorators import register_action
|
|
3
|
+
from synapse.plugins.enums import RunMethod, PluginCategory
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@register_action
|
|
7
|
+
class ValidationAction(Action):
|
|
8
|
+
name = 'validation'
|
|
9
|
+
category = PluginCategory.DATA_VALIDATION
|
|
10
|
+
method = RunMethod.TASK
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
from synapse.plugins.categories.base import Action
|
|
2
|
+
from synapse.plugins.categories.registry import _REGISTERED_ACTIONS
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def register_action(action_class):
|
|
6
|
+
if not issubclass(action_class, Action):
|
|
7
|
+
raise ValueError('Wrapped class must subclass Action class.')
|
|
8
|
+
|
|
9
|
+
try:
|
|
10
|
+
_REGISTERED_ACTIONS[action_class.category.value][action_class.name] = action_class
|
|
11
|
+
except KeyError:
|
|
12
|
+
_REGISTERED_ACTIONS[action_class.category.value] = {action_class.name: action_class}
|
|
13
|
+
return action_class
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
from synapse.plugins.categories.base import Action
|
|
2
|
+
from synapse.plugins.categories.decorators import register_action
|
|
3
|
+
from synapse.plugins.enums import RunMethod, PluginCategory
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@register_action
|
|
7
|
+
class ExportAction(Action):
|
|
8
|
+
name = 'export'
|
|
9
|
+
category = PluginCategory.EXPORT
|
|
10
|
+
method = RunMethod.JOB
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
from synapse.plugins.categories.base import Action
|
|
2
|
+
from synapse.plugins.categories.decorators import register_action
|
|
3
|
+
from synapse.plugins.enums import RunMethod, PluginCategory
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@register_action
|
|
7
|
+
class ImportAction(Action):
|
|
8
|
+
name = 'import'
|
|
9
|
+
category = PluginCategory.IMPORT
|
|
10
|
+
method = RunMethod.JOB
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
from ray import serve
|
|
2
|
+
|
|
3
|
+
from synapse.plugins.categories.base import Action
|
|
4
|
+
from synapse.plugins.categories.decorators import register_action
|
|
5
|
+
from synapse.plugins.enums import PluginCategory, RunMethod
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@register_action
|
|
9
|
+
class DeploymentAction(Action):
|
|
10
|
+
name = 'deployment'
|
|
11
|
+
category = PluginCategory.NEURAL_NET
|
|
12
|
+
method = RunMethod.JOB
|
|
13
|
+
|
|
14
|
+
def get_deployment(self):
|
|
15
|
+
return serve.deployment(ray_actor_options=self.get_actor_options())(self.entrypoint)
|
|
16
|
+
|
|
17
|
+
def get_actor_options(self):
|
|
18
|
+
return {'runtime_env': self.get_runtime_env()}
|
|
19
|
+
|
|
20
|
+
def run(self):
|
|
21
|
+
deployment = self.get_deployment()
|
|
22
|
+
serve.delete(self.plugin_id)
|
|
23
|
+
serve.run(deployment.bind(), name=self.plugin_id, route_prefix=f'/{self.plugin_checksum}')
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
from synapse.plugins.categories.base import Action
|
|
2
|
+
from synapse.plugins.categories.decorators import register_action
|
|
3
|
+
from synapse.plugins.enums import RunMethod, PluginCategory
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@register_action
|
|
7
|
+
class InferenceAction(Action):
|
|
8
|
+
name = 'inference'
|
|
9
|
+
category = PluginCategory.NEURAL_NET
|
|
10
|
+
method = RunMethod.RESTAPI
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
from synapse.plugins.categories.base import Action
|
|
2
|
+
from synapse.plugins.categories.decorators import register_action
|
|
3
|
+
from synapse.plugins.enums import RunMethod, PluginCategory
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@register_action
|
|
7
|
+
class TestAction(Action):
|
|
8
|
+
name = 'test'
|
|
9
|
+
category = PluginCategory.NEURAL_NET
|
|
10
|
+
method = RunMethod.TASK
|
{synapse_sdk-0.1.1a0 → synapse_sdk-1.0.0a0}/synapse/plugins/categories/neural_net/actions/train.py
RENAMED
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
from synapse.plugins.categories.base import Action
|
|
2
|
+
from synapse.plugins.categories.decorators import register_action
|
|
3
|
+
from synapse.plugins.enums import RunMethod, PluginCategory
|
|
2
4
|
from synapse.utils.file import get_dict_from_file, files_url_to_path_from_objs
|
|
3
5
|
from synapse.utils.module_loading import import_string
|
|
4
6
|
|
|
5
7
|
|
|
8
|
+
@register_action
|
|
6
9
|
class TrainAction(Action):
|
|
7
|
-
|
|
10
|
+
name = 'train'
|
|
11
|
+
category = PluginCategory.NEURAL_NET
|
|
12
|
+
method = RunMethod.JOB
|
|
8
13
|
|
|
9
14
|
def get_input_dataset_for_training(self, model_id=None):
|
|
10
15
|
"""
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
from synapse.plugins.categories.base import Action
|
|
2
|
+
from synapse.plugins.categories.decorators import register_action
|
|
3
|
+
from synapse.plugins.enums import RunMethod, PluginCategory
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@register_action
|
|
7
|
+
class PostAnnotationAction(Action):
|
|
8
|
+
name = 'post_annotation'
|
|
9
|
+
category = PluginCategory.POST_ANNOTATION
|
|
10
|
+
method = RunMethod.TASK
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
from synapse.plugins.categories.base import Action
|
|
2
|
+
from synapse.plugins.categories.decorators import register_action
|
|
3
|
+
from synapse.plugins.enums import RunMethod, PluginCategory
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@register_action
|
|
7
|
+
class PreAnnotationAction(Action):
|
|
8
|
+
name = 'pre_annotation'
|
|
9
|
+
category = PluginCategory.PRE_ANNOTATION
|
|
10
|
+
method = RunMethod.TASK
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import pkgutil
|
|
2
|
+
from importlib import import_module
|
|
3
|
+
|
|
4
|
+
from synapse.plugins.enums import PluginCategory
|
|
5
|
+
|
|
6
|
+
_REGISTERED_ACTIONS = {}
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def register_actions():
|
|
10
|
+
if not _REGISTERED_ACTIONS:
|
|
11
|
+
for category in PluginCategory:
|
|
12
|
+
plugin_category_module_name = f'synapse.plugins.categories.{category.value}.actions'
|
|
13
|
+
plugin_category_module = import_module(plugin_category_module_name)
|
|
14
|
+
for _, action_name, _ in pkgutil.iter_modules(plugin_category_module.__path__):
|
|
15
|
+
action_module_name = f'{plugin_category_module_name}.{action_name}'
|
|
16
|
+
import_module(action_module_name)
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
from enum import Enum
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class RunMethod(Enum):
|
|
5
|
+
JOB = 'job'
|
|
6
|
+
TASK = 'task'
|
|
7
|
+
RESTAPI = 'restapi'
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class PluginCategory(Enum):
|
|
11
|
+
NEURAL_NET = 'neural_net'
|
|
12
|
+
EXPORT = 'export'
|
|
13
|
+
IMPORT = 'import'
|
|
14
|
+
POST_ANNOTATION = 'post_annotation'
|
|
15
|
+
PRE_ANNOTATION = 'pre_annotation'
|
|
16
|
+
DATA_VALIDATION = 'data_validation'
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import re
|
|
3
|
+
import subprocess
|
|
4
|
+
import tempfile
|
|
5
|
+
import hashlib
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
import boto3
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def calculate_checksum(file_path):
|
|
12
|
+
md5_hash = hashlib.md5()
|
|
13
|
+
with open(file_path, 'rb') as f:
|
|
14
|
+
for byte_block in iter(lambda: f.read(4096), b''):
|
|
15
|
+
md5_hash.update(byte_block)
|
|
16
|
+
checksum = md5_hash.hexdigest()
|
|
17
|
+
return f'dev-{checksum}'
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def upload_to_s3(file_path, bucket_name, object_name, endpoint_url, access_key, secret_key):
|
|
21
|
+
s3_client = boto3.client(
|
|
22
|
+
's3',
|
|
23
|
+
endpoint_url=endpoint_url,
|
|
24
|
+
aws_access_key_id=access_key,
|
|
25
|
+
aws_secret_access_key=secret_key,
|
|
26
|
+
)
|
|
27
|
+
s3_client.upload_file(file_path, bucket_name, object_name)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def upload_path(
|
|
31
|
+
source_path,
|
|
32
|
+
endpoint_url=None,
|
|
33
|
+
bucket_name=None,
|
|
34
|
+
access_key=None,
|
|
35
|
+
secret_key=None,
|
|
36
|
+
base_url=None,
|
|
37
|
+
):
|
|
38
|
+
if not endpoint_url:
|
|
39
|
+
endpoint_url = os.environ['PLUGIN_UPLOAD_S3_ENDPOINT_URL']
|
|
40
|
+
if not bucket_name:
|
|
41
|
+
bucket_name = os.environ['PLUGIN_UPLOAD_S3_BUCKET_NAME']
|
|
42
|
+
if not access_key:
|
|
43
|
+
access_key = os.environ['PLUGIN_UPLOAD_S3_ACCESS_KEY']
|
|
44
|
+
if not secret_key:
|
|
45
|
+
secret_key = os.environ['PLUGIN_UPLOAD_S3_SECRET_KEY']
|
|
46
|
+
if not base_url:
|
|
47
|
+
base_url = os.environ['PLUGIN_UPLOAD_S3_BASE_URL']
|
|
48
|
+
|
|
49
|
+
with tempfile.TemporaryDirectory() as temp_dir:
|
|
50
|
+
temp_archive_path = os.path.join(temp_dir, 'archive.zip')
|
|
51
|
+
command = f'git ls-files --others --exclude-standard --cached | zip -q --names-stdin {temp_archive_path}'
|
|
52
|
+
|
|
53
|
+
subprocess.run(command, cwd=source_path, shell=True, check=True)
|
|
54
|
+
|
|
55
|
+
checksum = calculate_checksum(temp_archive_path)
|
|
56
|
+
# TODO subpath param으로 받기
|
|
57
|
+
s3_object_name = f'assets/{checksum}.zip'
|
|
58
|
+
|
|
59
|
+
upload_to_s3(temp_archive_path, bucket_name, s3_object_name, endpoint_url, access_key, secret_key)
|
|
60
|
+
return f'{base_url}/{bucket_name}/{s3_object_name}'
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def change_whl_version(whl_name, new_version):
|
|
64
|
+
pattern = r'^(?P<distribution>.+?)-(?P<version>\d+(\.\d+)*)(?P<rest>-.+\.whl)$'
|
|
65
|
+
return re.sub(pattern, rf'\g<distribution>-{new_version}\g<rest>', whl_name)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def build_and_upload(source_path, endpoint_url, bucket_name, access_key, secret_key, base_url, virtualenv_path='.venv'):
|
|
69
|
+
# TODO 이미 빌드한 whl이 있으면 skip
|
|
70
|
+
subprocess.run(f'{virtualenv_path}/bin/python -m build --wheel', cwd=source_path, shell=True, check=True)
|
|
71
|
+
|
|
72
|
+
whl_file = next(Path(source_path, 'dist').glob('*.whl'), None)
|
|
73
|
+
checksum = calculate_checksum(whl_file)
|
|
74
|
+
|
|
75
|
+
# TODO subpath param으로 받기
|
|
76
|
+
s3_object_name = f'assets/{change_whl_version(whl_file.name, checksum)}'
|
|
77
|
+
|
|
78
|
+
upload_to_s3(str(whl_file), bucket_name, s3_object_name, endpoint_url, access_key, secret_key)
|
|
79
|
+
return f'{base_url}/{bucket_name}/{s3_object_name}'
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import json
|
|
2
|
+
|
|
3
|
+
from synapse.plugins.categories.registry import _REGISTERED_ACTIONS, register_actions
|
|
4
|
+
from synapse.utils.file import get_dict_from_file
|
|
5
|
+
from synapse.utils.string import hash_text
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def get_action(action, params_data, *args, **kwargs):
|
|
9
|
+
if isinstance(params_data, str):
|
|
10
|
+
try:
|
|
11
|
+
params = json.loads(params_data)
|
|
12
|
+
except json.JSONDecodeError:
|
|
13
|
+
params = get_dict_from_file(params_data)
|
|
14
|
+
else:
|
|
15
|
+
params = params_data
|
|
16
|
+
|
|
17
|
+
config_data = kwargs.pop('config', False)
|
|
18
|
+
if config_data:
|
|
19
|
+
if isinstance(config_data, str):
|
|
20
|
+
config = get_dict_from_file(config_data)
|
|
21
|
+
else:
|
|
22
|
+
config = config_data
|
|
23
|
+
else:
|
|
24
|
+
config = get_dict_from_file('config.yaml')
|
|
25
|
+
category = config['category']
|
|
26
|
+
return get_action_class(category, action)(params, config, *args, **kwargs)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def get_action_class(category, action):
|
|
30
|
+
register_actions()
|
|
31
|
+
return _REGISTERED_ACTIONS[category][action]
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def get_available_actions(category):
|
|
35
|
+
register_actions()
|
|
36
|
+
return list(_REGISTERED_ACTIONS[category].keys())
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def get_plugin_checksum(plugin_id):
|
|
40
|
+
return hash_text(plugin_id)
|
|
File without changes
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: synapse-sdk
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 1.0.0a0
|
|
4
4
|
Summary: synapse sdk
|
|
5
5
|
Author-email: datamaker <developer@datamaker.io>
|
|
6
6
|
License: MIT
|
|
@@ -8,8 +8,10 @@ Classifier: Programming Language :: Python :: 3
|
|
|
8
8
|
Requires-Python: >=3.11
|
|
9
9
|
Description-Content-Type: text/markdown
|
|
10
10
|
License-File: LICENSE
|
|
11
|
+
Requires-Dist: boto3
|
|
11
12
|
Requires-Dist: requests
|
|
12
13
|
Requires-Dist: tqdm
|
|
14
|
+
Requires-Dist: python-dotenv
|
|
13
15
|
Requires-Dist: pyyaml
|
|
14
16
|
Requires-Dist: pydantic
|
|
15
17
|
Requires-Dist: ray[all]
|
|
@@ -18,21 +18,37 @@ synapse/client/mixins/dataset.py
|
|
|
18
18
|
synapse/client/mixins/integration.py
|
|
19
19
|
synapse/client/mixins/ml.py
|
|
20
20
|
synapse/plugins/__init__.py
|
|
21
|
+
synapse/plugins/enums.py
|
|
22
|
+
synapse/plugins/job.py
|
|
23
|
+
synapse/plugins/upload.py
|
|
21
24
|
synapse/plugins/utils.py
|
|
22
25
|
synapse/plugins/categories/__init__.py
|
|
23
26
|
synapse/plugins/categories/base.py
|
|
24
|
-
synapse/plugins/categories/
|
|
25
|
-
synapse/plugins/categories/
|
|
27
|
+
synapse/plugins/categories/decorators.py
|
|
28
|
+
synapse/plugins/categories/registry.py
|
|
29
|
+
synapse/plugins/categories/data_validation/__init__.py
|
|
30
|
+
synapse/plugins/categories/data_validation/actions/__init__.py
|
|
31
|
+
synapse/plugins/categories/data_validation/actions/validation.py
|
|
26
32
|
synapse/plugins/categories/export/__init__.py
|
|
27
33
|
synapse/plugins/categories/export/actions/__init__.py
|
|
34
|
+
synapse/plugins/categories/export/actions/export.py
|
|
28
35
|
synapse/plugins/categories/import/__init__.py
|
|
29
36
|
synapse/plugins/categories/import/actions/__init__.py
|
|
37
|
+
synapse/plugins/categories/import/actions/import.py
|
|
30
38
|
synapse/plugins/categories/neural_net/__init__.py
|
|
31
39
|
synapse/plugins/categories/neural_net/actions/__init__.py
|
|
32
40
|
synapse/plugins/categories/neural_net/actions/deployment.py
|
|
41
|
+
synapse/plugins/categories/neural_net/actions/inference.py
|
|
33
42
|
synapse/plugins/categories/neural_net/actions/test.py
|
|
34
43
|
synapse/plugins/categories/neural_net/actions/train.py
|
|
44
|
+
synapse/plugins/categories/post_annotation/__init__.py
|
|
45
|
+
synapse/plugins/categories/post_annotation/actions/__init__.py
|
|
46
|
+
synapse/plugins/categories/post_annotation/actions/post_annotation.py
|
|
47
|
+
synapse/plugins/categories/pre_annotation/__init__.py
|
|
48
|
+
synapse/plugins/categories/pre_annotation/actions/__init__.py
|
|
49
|
+
synapse/plugins/categories/pre_annotation/actions/pre_annotation.py
|
|
35
50
|
synapse/utils/__init__.py
|
|
51
|
+
synapse/utils/debug.py
|
|
36
52
|
synapse/utils/file.py
|
|
37
53
|
synapse/utils/module_loading.py
|
|
38
54
|
synapse/utils/string.py
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
from synapse.plugins.categories.neural_net.actions.deployment import DeploymentAction
|
|
2
|
-
from synapse.plugins.categories.neural_net.actions.test import TestAction
|
|
3
|
-
from synapse.plugins.categories.neural_net.actions.train import TrainAction
|
|
4
|
-
|
|
5
|
-
ACTIONS = {
|
|
6
|
-
'neural_net': {
|
|
7
|
-
'deployment': DeploymentAction,
|
|
8
|
-
'train': TrainAction,
|
|
9
|
-
'test': TestAction,
|
|
10
|
-
},
|
|
11
|
-
}
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
from functools import cached_property
|
|
2
|
-
|
|
3
|
-
from synapse.loggers import ConsoleLogger
|
|
4
|
-
from synapse.plugins.utils import get_plugin_checksum
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
class Action:
|
|
8
|
-
params = None
|
|
9
|
-
config = None
|
|
10
|
-
client = None
|
|
11
|
-
logger = None
|
|
12
|
-
|
|
13
|
-
def __init__(self, params, config):
|
|
14
|
-
self.params = params
|
|
15
|
-
self.config = config
|
|
16
|
-
|
|
17
|
-
# TODO logger 지정 방식 개선
|
|
18
|
-
self.logger = ConsoleLogger()
|
|
19
|
-
|
|
20
|
-
@cached_property
|
|
21
|
-
def plugin_id(self):
|
|
22
|
-
code = self.config['code']
|
|
23
|
-
version = self.config['version']
|
|
24
|
-
return f'{code}@{version}'
|
|
25
|
-
|
|
26
|
-
@cached_property
|
|
27
|
-
def plugin_checksum(self):
|
|
28
|
-
return get_plugin_checksum(self.plugin_id)
|
|
29
|
-
|
|
30
|
-
def get_runtime_env(self):
|
|
31
|
-
return {
|
|
32
|
-
# TODO url기반 working_dir 가져오기
|
|
33
|
-
'working_dir': ''
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
def run(self):
|
|
37
|
-
raise NotImplementedError
|
|
38
|
-
|
|
39
|
-
def set_progress(self, current, total, category=''):
|
|
40
|
-
self.logger.set_progress(current, total, category)
|
|
41
|
-
|
|
42
|
-
def log(self, action, data):
|
|
43
|
-
self.logger.log(action, data)
|
|
44
|
-
|
|
45
|
-
def log_event(self, message):
|
|
46
|
-
self.logger.log('event', {'content': message})
|
|
47
|
-
|
|
48
|
-
def end_log(self):
|
|
49
|
-
self.log_event('Plugin run is complete.')
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
from ray import serve
|
|
2
|
-
|
|
3
|
-
from synapse.plugins.categories.base import Action
|
|
4
|
-
from synapse.utils.module_loading import import_string
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
class DeploymentAction(Action):
|
|
8
|
-
deployment = None
|
|
9
|
-
|
|
10
|
-
def __init__(self, *args, **kwargs):
|
|
11
|
-
super().__init__(*args, **kwargs)
|
|
12
|
-
self.deployment = self.get_deployment()
|
|
13
|
-
|
|
14
|
-
def get_deployment(self):
|
|
15
|
-
entrypoint = self.config['actions']['deployment']['entrypoint']
|
|
16
|
-
deployment = import_string(entrypoint)
|
|
17
|
-
return serve.deployment(ray_actor_options=self.get_actor_options())(deployment)
|
|
18
|
-
|
|
19
|
-
def get_actor_options(self):
|
|
20
|
-
return {'runtime_env': self.get_runtime_env()}
|
|
21
|
-
|
|
22
|
-
def run(self):
|
|
23
|
-
serve.delete(self.plugin_id)
|
|
24
|
-
serve.run(self.deployment.bind(), name=self.plugin_id, route_prefix=f'/{self.plugin_checksum}')
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import json
|
|
2
|
-
|
|
3
|
-
from synapse.utils.file import get_dict_from_file
|
|
4
|
-
from synapse.utils.string import hash_text
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
def get_action(action, json_or_path):
|
|
8
|
-
from synapse.plugins.categories import ACTIONS
|
|
9
|
-
|
|
10
|
-
try:
|
|
11
|
-
params = json.loads(json_or_path)
|
|
12
|
-
except json.JSONDecodeError:
|
|
13
|
-
params = get_dict_from_file(json_or_path)
|
|
14
|
-
config = get_dict_from_file('config.yaml')
|
|
15
|
-
category = config['category']
|
|
16
|
-
return ACTIONS[category][action](params, config)
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
def get_available_actions(category):
|
|
20
|
-
from synapse.plugins.categories import ACTIONS
|
|
21
|
-
|
|
22
|
-
return list(ACTIONS[category].keys())
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
def get_plugin_checksum(plugin_id):
|
|
26
|
-
return hash_text(plugin_id)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|