synapse-sdk 1.0.0a6__py3-none-any.whl → 1.0.0a8__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.

Files changed (50) hide show
  1. synapse_sdk/clients/backend/annotation.py +10 -10
  2. synapse_sdk/clients/backend/dataset.py +6 -5
  3. synapse_sdk/clients/backend/integration.py +8 -0
  4. synapse_sdk/clients/backend/ml.py +8 -7
  5. synapse_sdk/clients/base.py +7 -1
  6. synapse_sdk/loggers.py +74 -12
  7. synapse_sdk/plugins/categories/base.py +54 -38
  8. synapse_sdk/plugins/categories/data_validation/actions/validation.py +1 -1
  9. synapse_sdk/plugins/categories/data_validation/templates/config.yaml +3 -0
  10. synapse_sdk/plugins/categories/data_validation/templates/plugin/__init__.py +0 -0
  11. synapse_sdk/plugins/categories/data_validation/templates/plugin/validation.py +5 -0
  12. synapse_sdk/plugins/categories/export/actions/export.py +1 -1
  13. synapse_sdk/plugins/categories/import/actions/import.py +1 -1
  14. synapse_sdk/plugins/categories/neural_net/actions/deployment.py +2 -1
  15. synapse_sdk/plugins/categories/neural_net/actions/inference.py +1 -1
  16. synapse_sdk/plugins/categories/neural_net/actions/test.py +2 -2
  17. synapse_sdk/plugins/categories/neural_net/actions/train.py +120 -15
  18. synapse_sdk/plugins/categories/neural_net/templates/plugin/train.py +1 -1
  19. synapse_sdk/plugins/categories/post_annotation/actions/post_annotation.py +1 -1
  20. synapse_sdk/plugins/categories/post_annotation/templates/config.yaml +3 -0
  21. synapse_sdk/plugins/categories/post_annotation/templates/plugin/__init__.py +0 -0
  22. synapse_sdk/plugins/categories/post_annotation/templates/plugin/post_annotation.py +3 -0
  23. synapse_sdk/plugins/categories/pre_annotation/actions/pre_annotation.py +1 -1
  24. synapse_sdk/plugins/categories/pre_annotation/templates/config.yaml +3 -0
  25. synapse_sdk/plugins/categories/pre_annotation/templates/plugin/__init__.py +0 -0
  26. synapse_sdk/plugins/categories/pre_annotation/templates/plugin/pre_annotation.py +3 -0
  27. synapse_sdk/plugins/categories/smart_tool/__init__.py +0 -0
  28. synapse_sdk/plugins/categories/smart_tool/actions/__init__.py +0 -0
  29. synapse_sdk/plugins/categories/smart_tool/actions/auto_label.py +22 -0
  30. synapse_sdk/plugins/categories/smart_tool/templates/config.yaml +6 -0
  31. synapse_sdk/plugins/categories/smart_tool/templates/plugin/__init__.py +0 -0
  32. synapse_sdk/plugins/categories/smart_tool/templates/plugin/auto_label.py +11 -0
  33. synapse_sdk/plugins/enums.py +5 -0
  34. synapse_sdk/plugins/exceptions.py +6 -0
  35. synapse_sdk/plugins/models.py +40 -4
  36. synapse_sdk/plugins/templates/hooks/pre_prompt.py +1 -0
  37. synapse_sdk/plugins/templates/synapse-{{cookiecutter.plugin_code}}-plugin/config.yaml +0 -12
  38. synapse_sdk/plugins/templates/synapse-{{cookiecutter.plugin_code}}-plugin/pyproject.toml +1 -1
  39. synapse_sdk/utils/file.py +15 -0
  40. synapse_sdk/utils/pydantic/__init__.py +0 -0
  41. synapse_sdk/utils/pydantic/config.py +4 -0
  42. synapse_sdk/utils/pydantic/errors.py +33 -0
  43. synapse_sdk/utils/pydantic/validators.py +7 -0
  44. synapse_sdk/utils/storage.py +1 -1
  45. {synapse_sdk-1.0.0a6.dist-info → synapse_sdk-1.0.0a8.dist-info}/METADATA +2 -2
  46. {synapse_sdk-1.0.0a6.dist-info → synapse_sdk-1.0.0a8.dist-info}/RECORD +50 -30
  47. {synapse_sdk-1.0.0a6.dist-info → synapse_sdk-1.0.0a8.dist-info}/WHEEL +1 -1
  48. {synapse_sdk-1.0.0a6.dist-info → synapse_sdk-1.0.0a8.dist-info}/LICENSE +0 -0
  49. {synapse_sdk-1.0.0a6.dist-info → synapse_sdk-1.0.0a8.dist-info}/entry_points.txt +0 -0
  50. {synapse_sdk-1.0.0a6.dist-info → synapse_sdk-1.0.0a8.dist-info}/top_level.txt +0 -0
@@ -7,23 +7,23 @@ class AnnotationClientMixin(BaseClient):
7
7
  path = f'projects/{pk}/'
8
8
  return self._get(path)
9
9
 
10
- def get_label_tag(self, pk):
11
- path = f'label_tags/{pk}/'
10
+ def get_task_tag(self, pk):
11
+ path = f'task_tags/{pk}/'
12
12
  return self._get(path)
13
13
 
14
- def list_label_tags(self, data):
15
- path = 'label_tags/'
14
+ def list_task_tags(self, data):
15
+ path = 'task_tags/'
16
16
  return self._list(path, data=data)
17
17
 
18
- def list_labels(self, data, url_conversion=None, list_all=False):
19
- path = 'labels/'
18
+ def list_tasks(self, data, url_conversion=None, list_all=False):
19
+ path = 'tasks/'
20
20
  url_conversion = get_default_url_conversion(url_conversion, files_fields=['files'])
21
21
  return self._list(path, data=data, url_conversion=url_conversion, list_all=list_all)
22
22
 
23
- def create_labels(self, data):
24
- path = 'labels/'
23
+ def create_tasks(self, data):
24
+ path = 'tasks/'
25
25
  return self._post(path, data=data)
26
26
 
27
- def set_tags_labels(self, data, params=None):
28
- path = 'labels/set_tags/'
27
+ def set_tags_tasks(self, data, params=None):
28
+ path = 'tasks/set_tags/'
29
29
  return self._post(path, data=data, params=params)
@@ -1,4 +1,5 @@
1
1
  from multiprocessing import Pool
2
+
2
3
  from tqdm import tqdm
3
4
 
4
5
  from synapse_sdk.clients.base import BaseClient
@@ -32,15 +33,15 @@ class DatasetClientMixin(BaseClient):
32
33
  data_units = self.create_data_units(batch)
33
34
 
34
35
  if project_id:
35
- labels_data = []
36
+ tasks_data = []
36
37
  for data, data_unit in zip(batch, data_units):
37
- label_data = {'project': project_id, 'data_unit': data_unit['id']}
38
+ task_data = {'project': project_id, 'data_unit': data_unit['id']}
38
39
  if 'ground_truth' in data:
39
- label_data['ground_truth'] = data['ground_truth']
40
+ task_data['ground_truth'] = data['ground_truth']
40
41
 
41
- labels_data.append(label_data)
42
+ tasks_data.append(task_data)
42
43
 
43
- self.create_labels(labels_data)
44
+ self.create_tasks(tasks_data)
44
45
 
45
46
  def import_data_file(self, data, dataset_id):
46
47
  for name, path in data['files'].items():
@@ -27,6 +27,14 @@ class IntegrationClientMixin(BaseClient):
27
27
  files = {'file': data.pop('file')}
28
28
  return self._post(path, data=data, files=files)
29
29
 
30
+ def list_jobs(self, params=None):
31
+ path = 'jobs/'
32
+ return self._get(path, params=params)
33
+
34
+ def update_job(self, pk, data):
35
+ path = f'jobs/{pk}/'
36
+ return self._patch(path, data=data)
37
+
30
38
  def list_job_console_logs(self, pk):
31
39
  path = f'jobs/{pk}/console_logs/'
32
40
  return self._get(path)
@@ -3,6 +3,10 @@ from synapse_sdk.clients.utils import get_default_url_conversion
3
3
 
4
4
 
5
5
  class MLClientMixin(BaseClient):
6
+ def list_models(self, params=None):
7
+ path = 'models/'
8
+ return self._get(path, params=params)
9
+
6
10
  def get_model(self, pk, params=None, url_conversion=None):
7
11
  path = f'models/{pk}/'
8
12
  url_conversion = get_default_url_conversion(
@@ -12,13 +16,10 @@ class MLClientMixin(BaseClient):
12
16
 
13
17
  def create_model(self, data):
14
18
  path = 'models/'
15
- return self._post(path, data=data)
16
-
17
- def update_model(self, pk, data, files=None):
18
- path = f'models/{pk}/'
19
- return self._patch(path, data=data, files=files)
19
+ files = {'file': data.pop('file')}
20
+ return self._post(path, data=data, files=files)
20
21
 
21
- def list_train_dataset(self, params=None, url_conversion=None, list_all=False):
22
- path = 'train_dataset/'
22
+ def list_ground_truth_events(self, params=None, url_conversion=None, list_all=False):
23
+ path = 'ground_truth_events/'
23
24
  url_conversion = get_default_url_conversion(url_conversion, files_fields=['files'])
24
25
  return self._list(path, params=params, url_conversion=url_conversion, list_all=list_all)
@@ -1,5 +1,5 @@
1
- import os
2
1
  import json
2
+ import os
3
3
  from pathlib import Path
4
4
 
5
5
  import requests
@@ -33,6 +33,9 @@ class BaseClient:
33
33
  if kwargs.get('files') is not None:
34
34
  for name, file in kwargs['files'].items():
35
35
  kwargs['files'][name] = Path(str(file)).open(mode='rb')
36
+ for name, value in kwargs['data'].items():
37
+ if isinstance(value, dict):
38
+ kwargs['data'][name] = json.dumps(value)
36
39
  else:
37
40
  headers['Content-Type'] = 'application/json'
38
41
  if 'data' in kwargs:
@@ -79,3 +82,6 @@ class BaseClient:
79
82
  yield from response['results']
80
83
  if response['next']:
81
84
  yield from self._list_all(response['next'], url_conversion, **kwargs)
85
+
86
+ def exists(self, api, *args, **kwargs):
87
+ return getattr(self, api)(*args, **kwargs)['count'] > 0
synapse_sdk/loggers.py CHANGED
@@ -1,24 +1,78 @@
1
1
  import datetime
2
+ import time
2
3
 
3
4
  from synapse_sdk.clients.exceptions import ClientError
4
5
 
5
6
 
6
7
  class BaseLogger:
7
- progress_records = {}
8
+ progress_record = {}
9
+ progress_categories = None
10
+ current_category = None
11
+ time_begin_per_category = {}
8
12
 
9
- def set_progress(self, current, total, category=''):
10
- percent = 0
11
- if total > 0:
12
- percent = (current / total) * 100
13
- percent = float(round(percent, 2))
13
+ def __init__(self, progress_categories=None):
14
+ self.progress_categories = progress_categories
15
+ if progress_categories:
16
+ self.progress_record['categories'] = progress_categories
14
17
 
15
- self.progress_records[category] = {'current': current, 'total': total, 'percent': percent}
18
+ def set_progress(self, current, total, category=None):
19
+ assert 0 <= current <= total and total > 0
20
+ assert category is not None or 'categories' not in self.progress_record
21
+
22
+ percent = (current / total) * 100
23
+ percent = round(percent, 2)
24
+ # TODO current 0 으로 시작하지 않아도 작동되도록 수정
25
+ if current == 0:
26
+ self.time_begin_per_category[category] = time.time()
27
+ time_remaining = None
28
+ else:
29
+ seconds_per_item = (time.time() - self.time_begin_per_category[category]) / current
30
+ time_remaining = round(seconds_per_item * (total - current), 2)
31
+
32
+ current_progress = {'percent': percent, 'time_remaining': time_remaining}
33
+
34
+ if category:
35
+ self.current_category = category
36
+ self.progress_record['categories'][category].update(current_progress)
37
+ else:
38
+ self.progress_record.update(current_progress)
39
+
40
+ def get_current_progress(self):
41
+ categories = self.progress_record.get('categories')
42
+
43
+ if categories:
44
+ category_progress = None
45
+
46
+ overall = 0
47
+ for category, category_record in categories.items():
48
+ if category == self.current_category:
49
+ break
50
+ overall += category_record['proportion']
51
+
52
+ category_record = categories[self.current_category]
53
+ category_percent = category_record.get('percent', 0)
54
+ if not category_progress and 'percent' in category_record:
55
+ category_progress = {
56
+ 'category': self.current_category,
57
+ 'percent': category_percent,
58
+ 'time_remaining': category_record.get('time_remaining'),
59
+ }
60
+ if category_percent > 0:
61
+ overall += round(category_record['proportion'] / 100 * category_percent, 2)
62
+ progress = {'overall': overall, **category_progress}
63
+ else:
64
+ progress = {
65
+ 'overall': self.progress_record.get('percent'),
66
+ 'time_remaining': self.progress_record.get('time_remaining'),
67
+ }
68
+
69
+ return progress
16
70
 
17
71
 
18
72
  class ConsoleLogger(BaseLogger):
19
- def set_progress(self, current, total, category=''):
73
+ def set_progress(self, current, total, category=None):
20
74
  super().set_progress(current, total, category=category)
21
- print(self.progress_records)
75
+ print(self.get_current_progress())
22
76
 
23
77
  def log(self, action, data):
24
78
  print(action, data)
@@ -29,13 +83,21 @@ class BackendLogger(BaseLogger):
29
83
  client = None
30
84
  job_id = None
31
85
 
32
- def __init__(self, client, job_id):
86
+ def __init__(self, client, job_id, **kwargs):
87
+ super().__init__(**kwargs)
33
88
  self.client = client
34
89
  self.job_id = job_id
35
90
 
36
- def set_progress(self, current, total, category=''):
91
+ def set_progress(self, current, total, category=None):
37
92
  super().set_progress(current, total, category=category)
38
- # TODO set_progress to the job
93
+ try:
94
+ progress_record = {
95
+ 'record': self.progress_record,
96
+ 'current_progress': self.get_current_progress(),
97
+ }
98
+ self.client.update_job(self.job_id, data={'progress_record': progress_record})
99
+ except ClientError:
100
+ pass
39
101
 
40
102
  def log(self, action, data):
41
103
  print(action, data)
@@ -6,27 +6,36 @@ from pprint import pprint
6
6
 
7
7
  import ray
8
8
  import requests
9
+ from pydantic import ValidationError
9
10
  from ray.dashboard.modules.job.sdk import JobSubmissionClient
10
11
 
11
- from synapse_sdk.clients.backend import BackendClient
12
- from synapse_sdk.loggers import ConsoleLogger, BackendLogger
13
12
  from synapse_sdk.plugins.enums import RunMethod
14
- from synapse_sdk.plugins.models import PluginRelease
15
- from synapse_sdk.plugins.upload import build_and_upload, archive_and_upload, download_and_upload
13
+ from synapse_sdk.plugins.exceptions import ActionValidationError
14
+ from synapse_sdk.plugins.models import PluginRelease, Run
15
+ from synapse_sdk.plugins.upload import archive_and_upload, build_and_upload, download_and_upload
16
16
  from synapse_sdk.utils.module_loading import import_string
17
+ from synapse_sdk.utils.pydantic.errors import pydantic_to_drf_error
17
18
 
18
19
 
19
20
  class Action:
21
+ # class 변수
20
22
  name = None
21
23
  category = None
22
24
  method = None
25
+ run_class = Run
26
+ params_model = None
27
+ progress_categories = None
28
+
29
+ # init 변수
23
30
  params = None
24
31
  plugin_config = None
25
32
  plugin_release = None
26
33
  config = None
27
- client = None
28
- logger = None
29
- debug = False
34
+ job_id = None
35
+ direct = None
36
+ debug = None
37
+ envs = None
38
+ run = None
30
39
 
31
40
  default_envs = [
32
41
  'RAY_DASHBOARD_URL',
@@ -48,7 +57,7 @@ class Action:
48
57
  self.direct = direct
49
58
  self.debug = debug
50
59
  self.envs = {**envs, **self.get_default_envs()} if envs else self.get_default_envs()
51
- self.set_logger()
60
+ self.run = self.get_run()
52
61
 
53
62
  @cached_property
54
63
  def entrypoint(self):
@@ -58,6 +67,10 @@ class Action:
58
67
  def plugin_storage_url(self):
59
68
  return self.envs['SYNAPSE_PLUGIN_STORAGE']
60
69
 
70
+ @property
71
+ def client(self):
72
+ return self.run.client
73
+
61
74
  @property
62
75
  def plugin_url(self):
63
76
  if self.debug:
@@ -84,16 +97,15 @@ class Action:
84
97
  self.envs['SYNAPSE_DEBUG_MODULES'] = ','.join(debug_modules)
85
98
  return debug_modules
86
99
 
87
- def set_logger(self):
88
- if self.job_id:
89
- client = BackendClient(
90
- self.envs['SYNAPSE_PLUGIN_RUN_HOST'],
91
- self.envs['SYNAPSE_PLUGIN_RUN_USER_TOKEN'],
92
- self.envs['SYNAPSE_PLUGIN_RUN_TENANT'],
93
- )
94
- self.logger = BackendLogger(client, self.job_id)
95
- else:
96
- self.logger = ConsoleLogger()
100
+ def get_run(self):
101
+ context = {
102
+ 'plugin_release': self.plugin_release,
103
+ 'progress_categories': self.progress_categories,
104
+ 'params': self.params,
105
+ 'envs': self.envs,
106
+ 'debug': self.debug,
107
+ }
108
+ return self.run_class(self.job_id, context)
97
109
 
98
110
  def get_default_envs(self):
99
111
  return {env: os.environ[env] for env in self.default_envs if env in os.environ}
@@ -105,7 +117,7 @@ class Action:
105
117
  }
106
118
 
107
119
  if self.debug:
108
- runtime_env['pip'] = self.debug_modules + runtime_env['pip']
120
+ runtime_env['pip'] += self.debug_modules
109
121
 
110
122
  # 맨 마지막에 진행되어야 함
111
123
  runtime_env['env_vars'] = self.envs
@@ -114,18 +126,30 @@ class Action:
114
126
  pprint(runtime_env)
115
127
  return runtime_env
116
128
 
117
- def run(self):
118
- return self.entrypoint(self, **self.params)
129
+ def validate_params(self):
130
+ if self.params_model:
131
+ try:
132
+ self.params_model.model_validate(self.params, context={'action': self})
133
+ except ValidationError as e:
134
+ raise ActionValidationError({'params': pydantic_to_drf_error(e)})
119
135
 
120
136
  def run_action(self):
137
+ self.validate_params()
121
138
  if self.direct:
122
139
  if self.method == RunMethod.RESTAPI:
123
- return self.run_by_restapi()
140
+ return self.start_by_restapi()
124
141
  else:
125
- return self.run()
126
- return getattr(self, f'run_by_{self.method.value}')()
142
+ result = self.start()
143
+ self.post_action_by_job(result)
144
+ return result
145
+ return getattr(self, f'start_by_{self.method.value}')()
127
146
 
128
- def run_by_task(self):
147
+ def start(self):
148
+ if self.method == RunMethod.JOB:
149
+ return self.entrypoint(self.run, **self.params)
150
+ return self.entrypoint(**self.params)
151
+
152
+ def start_by_task(self):
129
153
  @ray.remote(runtime_env=self.get_runtime_env())
130
154
  def run_task(category, action, *args, **kwargs):
131
155
  from synapse_sdk.plugins.utils import get_action_class
@@ -149,7 +173,7 @@ class Action:
149
173
  kwargs['direct'] = True
150
174
  return ray.get(run_task.remote(self.category.value, self.name, *args, **kwargs))
151
175
 
152
- def run_by_job(self):
176
+ def start_by_job(self):
153
177
  main_options = []
154
178
  options = ['run', '--direct']
155
179
  arguments = [self.name, f'{json.dumps(json.dumps(self.params))}']
@@ -169,7 +193,7 @@ class Action:
169
193
  runtime_env=self.get_runtime_env(),
170
194
  )
171
195
 
172
- def run_by_restapi(self):
196
+ def start_by_restapi(self):
173
197
  path = self.params.pop('path', '')
174
198
  method = self.params.pop('method')
175
199
 
@@ -178,14 +202,6 @@ class Action:
178
202
  # TODO ok response가 아닌 경우 대응하기
179
203
  return response.json()
180
204
 
181
- def set_progress(self, current, total, category=''):
182
- self.logger.set_progress(current, total, category)
183
-
184
- def log(self, action, data):
185
- self.logger.log(action, data)
186
-
187
- def log_event(self, message):
188
- self.logger.log('event', {'content': message})
189
-
190
- def end_log(self):
191
- self.log_event('Plugin run is complete.')
205
+ def post_action_by_job(self, result):
206
+ if self.client:
207
+ self.client.update_job(self.job_id, data={'result': result})
@@ -1,6 +1,6 @@
1
1
  from synapse_sdk.plugins.categories.base import Action
2
2
  from synapse_sdk.plugins.categories.decorators import register_action
3
- from synapse_sdk.plugins.enums import RunMethod, PluginCategory
3
+ from synapse_sdk.plugins.enums import PluginCategory, RunMethod
4
4
 
5
5
 
6
6
  @register_action
@@ -0,0 +1,3 @@
1
+ actions:
2
+ validation:
3
+ entrypoint: plugin.validation.validate
@@ -0,0 +1,5 @@
1
+ def validate(data, assignment_id, **kwargs):
2
+ errors = []
3
+ if data.get('errors'):
4
+ errors += data['errors']
5
+ return errors
@@ -1,6 +1,6 @@
1
1
  from synapse_sdk.plugins.categories.base import Action
2
2
  from synapse_sdk.plugins.categories.decorators import register_action
3
- from synapse_sdk.plugins.enums import RunMethod, PluginCategory
3
+ from synapse_sdk.plugins.enums import PluginCategory, RunMethod
4
4
 
5
5
 
6
6
  @register_action
@@ -1,6 +1,6 @@
1
1
  from synapse_sdk.plugins.categories.base import Action
2
2
  from synapse_sdk.plugins.categories.decorators import register_action
3
- from synapse_sdk.plugins.enums import RunMethod, PluginCategory
3
+ from synapse_sdk.plugins.enums import PluginCategory, RunMethod
4
4
 
5
5
 
6
6
  @register_action
@@ -17,7 +17,8 @@ class DeploymentAction(Action):
17
17
  def get_actor_options(self):
18
18
  return {'runtime_env': self.get_runtime_env()}
19
19
 
20
- def run(self):
20
+ def start(self):
21
21
  deployment = self.get_deployment()
22
22
  serve.delete(self.plugin_release.code)
23
+ # TODO add run object
23
24
  serve.run(deployment.bind(), name=self.plugin_release.code, route_prefix=f'/{self.plugin_release.checksum}')
@@ -1,6 +1,6 @@
1
1
  from synapse_sdk.plugins.categories.base import Action
2
2
  from synapse_sdk.plugins.categories.decorators import register_action
3
- from synapse_sdk.plugins.enums import RunMethod, PluginCategory
3
+ from synapse_sdk.plugins.enums import PluginCategory, RunMethod
4
4
 
5
5
 
6
6
  @register_action
@@ -1,10 +1,10 @@
1
1
  from synapse_sdk.plugins.categories.base import Action
2
2
  from synapse_sdk.plugins.categories.decorators import register_action
3
- from synapse_sdk.plugins.enums import RunMethod, PluginCategory
3
+ from synapse_sdk.plugins.enums import PluginCategory, RunMethod
4
4
 
5
5
 
6
6
  @register_action
7
7
  class TestAction(Action):
8
8
  name = 'test'
9
9
  category = PluginCategory.NEURAL_NET
10
- method = RunMethod.TASK
10
+ method = RunMethod.JOB
@@ -1,6 +1,60 @@
1
+ import copy
2
+ import tempfile
3
+ from decimal import Decimal
4
+ from pathlib import Path
5
+ from typing import Annotated
6
+
7
+ from pydantic import AfterValidator, BaseModel, field_validator
8
+ from pydantic_core import PydanticCustomError
9
+
10
+ from synapse_sdk.clients.exceptions import ClientError
1
11
  from synapse_sdk.plugins.categories.base import Action
2
12
  from synapse_sdk.plugins.categories.decorators import register_action
3
- from synapse_sdk.plugins.enums import RunMethod, PluginCategory
13
+ from synapse_sdk.plugins.enums import PluginCategory, RunMethod
14
+ from synapse_sdk.plugins.models import Run
15
+ from synapse_sdk.utils.file import archive
16
+ from synapse_sdk.utils.pydantic.validators import non_blank
17
+
18
+
19
+ class TrainRun(Run):
20
+ def log_metric(self, x, i, **kwargs):
21
+ self.log(x, {x: i, **kwargs})
22
+
23
+
24
+ class Hyperparameter(BaseModel):
25
+ batch_size: int
26
+ iterations: int
27
+ learning_rate: Decimal
28
+
29
+
30
+ class TrainParams(BaseModel):
31
+ name: Annotated[str, AfterValidator(non_blank)]
32
+ description: str
33
+ checkpoint: int | None
34
+ dataset: int
35
+ hyperparameter: Hyperparameter
36
+
37
+ @field_validator('name')
38
+ @staticmethod
39
+ def unique_name(value, info):
40
+ action = info.context['action']
41
+ client = action.client
42
+ try:
43
+ model_exists = client.exists('list_models', params={'name': value})
44
+ job_exists = client.exists(
45
+ 'list_jobs',
46
+ params={
47
+ 'ids_ex': action.job_id,
48
+ 'category': 'neural_net',
49
+ 'action': 'train',
50
+ 'is_active': True,
51
+ 'params': f'name:{value}',
52
+ },
53
+ )
54
+ assert not model_exists and not job_exists, '존재하는 학습 이름입니다.'
55
+ except ClientError:
56
+ raise PydanticCustomError('client_error', '')
57
+ return value
4
58
 
5
59
 
6
60
  @register_action
@@ -8,30 +62,81 @@ class TrainAction(Action):
8
62
  name = 'train'
9
63
  category = PluginCategory.NEURAL_NET
10
64
  method = RunMethod.JOB
65
+ run_class = TrainRun
66
+ params_model = TrainParams
67
+ progress_categories = {
68
+ 'dataset': {
69
+ 'proportion': 20,
70
+ },
71
+ 'train': {
72
+ 'proportion': 75,
73
+ },
74
+ 'model_upload': {
75
+ 'proportion': 5,
76
+ },
77
+ }
11
78
 
12
- def get_dataset(self):
13
- return {}
14
-
15
- def run(self):
79
+ def start(self):
16
80
  hyperparameter = self.params['hyperparameter']
17
81
 
18
82
  # download dataset
19
- self.log_event('Preparing dataset for training.')
83
+ self.run.log_event('Preparing dataset for training.')
20
84
  input_dataset = self.get_dataset()
21
85
 
22
86
  # train dataset
23
- self.log_event('Starting model training.')
87
+ self.run.log_event('Starting model training.')
24
88
 
25
- model_files = self.entrypoint(self, input_dataset, hyperparameter)
89
+ result = self.entrypoint(self.run, input_dataset, hyperparameter)
26
90
 
27
91
  # upload model_data
28
- self.log_event('Registering model data.')
92
+ self.run.log_event('Registering model data.')
93
+ self.run.set_progress(0, 1, category='model_upload')
94
+ model = self.create_model(result)
95
+ self.run.set_progress(1, 1, category='model_upload')
29
96
 
30
- self.end_log()
31
- return model_files
97
+ self.run.end_log()
98
+ return {'model_id': model['id']}
32
99
 
33
- def log_metric(self, x, i, **kwargs):
34
- self.log(x, {x: i, **kwargs})
100
+ def get_dataset(self):
101
+ client = self.run.client
102
+ assert bool(client)
103
+
104
+ input_dataset = {}
105
+
106
+ ground_truths, count_dataset = client.list_ground_truth_events(
107
+ params={
108
+ 'fields': ['category', 'files', 'data'],
109
+ 'ground_truth_dataset_versions': self.params['dataset'],
110
+ },
111
+ list_all=True,
112
+ )
113
+ self.run.set_progress(0, count_dataset, category='dataset')
114
+ for i, ground_truth in enumerate(ground_truths, start=1):
115
+ self.run.set_progress(i, count_dataset, category='dataset')
116
+ try:
117
+ input_dataset[ground_truth['category']].append(ground_truth)
118
+ except KeyError:
119
+ input_dataset[ground_truth['category']] = [ground_truth]
120
+
121
+ return input_dataset
122
+
123
+ def create_model(self, path):
124
+ if not self.client:
125
+ print(path)
126
+
127
+ params = copy.deepcopy(self.params)
128
+ configuration_fields = ['hyperparameter']
129
+ configuration = {field: params.pop(field) for field in configuration_fields}
130
+
131
+ with tempfile.TemporaryDirectory() as temp_path:
132
+ input_path = Path(path)
133
+ archive_path = Path(temp_path, 'archive.zip')
134
+ archive(input_path, archive_path)
35
135
 
36
- def log_model(self, files, status=None):
37
- pass
136
+ return self.client.create_model({
137
+ 'plugin': self.plugin_release.plugin,
138
+ 'version': self.plugin_release.version,
139
+ 'file': str(archive_path),
140
+ 'configuration': configuration,
141
+ **params,
142
+ })
@@ -9,6 +9,6 @@ def train(run, dataset, hyperparameter, checkpoint=None):
9
9
  loss = float(round((count_iterations - i) / count_iterations, 2))
10
10
  miou = 1 - loss
11
11
  run.log_metric('iteration', i, loss=loss, miou=miou)
12
- run.set_progress(i, count_iterations, category='iteration')
12
+ run.set_progress(i, count_iterations, category='train')
13
13
 
14
14
  return {'weight': '/tmp/agent/test/a.txt', 'config': '/tmp/agent/test/b.txt'}
@@ -1,6 +1,6 @@
1
1
  from synapse_sdk.plugins.categories.base import Action
2
2
  from synapse_sdk.plugins.categories.decorators import register_action
3
- from synapse_sdk.plugins.enums import RunMethod, PluginCategory
3
+ from synapse_sdk.plugins.enums import PluginCategory, RunMethod
4
4
 
5
5
 
6
6
  @register_action
@@ -0,0 +1,3 @@
1
+ actions:
2
+ post_annotation:
3
+ entrypoint: plugin.post_annotation.post_annotate
@@ -0,0 +1,3 @@
1
+ def post_annotate(data, assignment_id, **kwargs):
2
+ data['post_annotate'] = 'hello world'
3
+ return data
@@ -1,6 +1,6 @@
1
1
  from synapse_sdk.plugins.categories.base import Action
2
2
  from synapse_sdk.plugins.categories.decorators import register_action
3
- from synapse_sdk.plugins.enums import RunMethod, PluginCategory
3
+ from synapse_sdk.plugins.enums import PluginCategory, RunMethod
4
4
 
5
5
 
6
6
  @register_action
@@ -0,0 +1,3 @@
1
+ actions:
2
+ pre_annotation:
3
+ entrypoint: plugin.pre_annotation.pre_annotate
@@ -0,0 +1,3 @@
1
+ def pre_annotate(data, assignment_id, **kwargs):
2
+ data['pre_annotate'] = 'hello world'
3
+ return data
File without changes
@@ -0,0 +1,22 @@
1
+ from synapse_sdk.plugins.categories.base import Action
2
+ from synapse_sdk.plugins.categories.decorators import register_action
3
+ from synapse_sdk.plugins.enums import PluginCategory, RunMethod
4
+
5
+
6
+ @register_action
7
+ class AutoLabelAction(Action):
8
+ name = 'label'
9
+ category = PluginCategory.SMART_TOOL
10
+ method = RunMethod.TASK
11
+
12
+ def get_auto_label(self):
13
+ return self.entrypoint(**self.params)
14
+
15
+ def run_model(self, input_data):
16
+ return {}
17
+
18
+ def start(self):
19
+ auto_label = self.get_auto_label()
20
+ input_data = auto_label.handle_input(self.params['input_data'])
21
+ output_data = self.run_model(input_data)
22
+ return auto_label.handle_output(output_data)
@@ -0,0 +1,6 @@
1
+ actions:
2
+ auto_label:
3
+ category: interactive_segmentation
4
+ entrypoint: plugin.auto_label.MyAutoLabel
5
+ model:
6
+ neural_nets: [sam2]
@@ -0,0 +1,11 @@
1
+ class MyAutoLabel:
2
+ def __init__(self, **kwargs):
3
+ pass
4
+
5
+ def handle_input(self, input_data):
6
+ """smart tool의 input을 model의 input 형태로 변환"""
7
+ return
8
+
9
+ def handle_output(self, output_data):
10
+ """model의 output을 smart tool의 output 형태로 변환"""
11
+ return
@@ -11,6 +11,11 @@ class PluginCategory(Enum):
11
11
  NEURAL_NET = 'neural_net'
12
12
  EXPORT = 'export'
13
13
  IMPORT = 'import'
14
+ SMART_TOOL = 'smart_tool'
14
15
  POST_ANNOTATION = 'post_annotation'
15
16
  PRE_ANNOTATION = 'pre_annotation'
16
17
  DATA_VALIDATION = 'data_validation'
18
+
19
+ @classmethod
20
+ def choices(cls):
21
+ return [(member.value, member.name.replace('_', ' ').title()) for member in cls]
@@ -0,0 +1,6 @@
1
+ class ActionValidationError(Exception):
2
+ errors = None
3
+
4
+ def __init__(self, errors, *args):
5
+ self.errors = errors
6
+ super().__init__(errors, *args)
@@ -1,7 +1,9 @@
1
1
  import os
2
2
  from functools import cached_property
3
- from typing import Dict, Any
3
+ from typing import Any, Dict
4
4
 
5
+ from synapse_sdk.clients.backend import BackendClient
6
+ from synapse_sdk.loggers import BackendLogger, ConsoleLogger
5
7
  from synapse_sdk.plugins.utils import read_plugin_config
6
8
  from synapse_sdk.utils.storage import get_storage
7
9
  from synapse_sdk.utils.string import hash_text
@@ -9,12 +11,14 @@ from synapse_sdk.utils.string import hash_text
9
11
 
10
12
  class PluginRelease:
11
13
  config: Dict[str, Any]
14
+ envs = None
12
15
 
13
- def __init__(self, config=None, plugin_path=None):
16
+ def __init__(self, config=None, plugin_path=None, envs=None):
14
17
  if config:
15
18
  self.config = config
16
19
  else:
17
20
  self.config = read_plugin_config(plugin_path=plugin_path)
21
+ self.envs = envs
18
22
 
19
23
  @cached_property
20
24
  def plugin(self):
@@ -59,8 +63,40 @@ class PluginRelease:
59
63
  return os.path.join(serve_address, self.checksum, path)
60
64
 
61
65
 
62
- class Job:
66
+ class Run:
67
+ logger = None
63
68
  job_id = None
69
+ context = None
64
70
 
65
- def __init__(self, job_id):
71
+ def __init__(self, job_id, context):
66
72
  self.job_id = job_id
73
+ self.context = context
74
+ self.set_logger()
75
+
76
+ def set_logger(self):
77
+ kwargs = {'progress_categories': self.context['progress_categories']}
78
+ if self.job_id:
79
+ client = BackendClient(
80
+ self.context['envs']['SYNAPSE_PLUGIN_RUN_HOST'],
81
+ self.context['envs']['SYNAPSE_PLUGIN_RUN_USER_TOKEN'],
82
+ self.context['envs']['SYNAPSE_PLUGIN_RUN_TENANT'],
83
+ )
84
+ self.logger = BackendLogger(client, self.job_id, **kwargs)
85
+ else:
86
+ self.logger = ConsoleLogger(**kwargs)
87
+
88
+ @property
89
+ def client(self):
90
+ return getattr(self.logger, 'client', None)
91
+
92
+ def set_progress(self, current, total, category=''):
93
+ self.logger.set_progress(current, total, category)
94
+
95
+ def log(self, action, data):
96
+ self.logger.log(action, data)
97
+
98
+ def log_event(self, message):
99
+ self.logger.log('event', {'content': message})
100
+
101
+ def end_log(self):
102
+ self.log_event('Plugin run is complete.')
@@ -1,5 +1,6 @@
1
1
  import json
2
2
  from pathlib import Path
3
+
3
4
  from synapse_sdk.plugins.utils import get_plugin_categories
4
5
  from synapse_sdk.utils.file import get_dict_from_file
5
6
 
@@ -4,15 +4,3 @@ version: {{ cookiecutter.version }}
4
4
  readme: README.md
5
5
  description: {{ cookiecutter.description }}
6
6
  category: {{ cookiecutter.category }}
7
- actions:
8
- train:
9
- dataset: datamaker
10
- entrypoint: plugin.train.train
11
- deployment:
12
- entrypoint: plugin.inference.MockNetInference
13
- inference:
14
- method: restapi
15
- endpoints:
16
- - method: get
17
- test:
18
- entrypoint: plugin.test.test
@@ -2,7 +2,7 @@
2
2
  line-length = 120
3
3
 
4
4
  [tool.ruff.lint]
5
- select = ['E', 'F', 'Q']
5
+ select = ['E', 'F', 'I', 'Q']
6
6
  ignore = ['W191', 'E111', 'E114', 'E117', 'D206', 'D300', 'Q000', 'Q001', 'Q002', 'Q003', 'COM812', 'COM819', 'ISC001', 'ISC002']
7
7
 
8
8
  [tool.ruff.lint.pydocstyle]
synapse_sdk/utils/file.py CHANGED
@@ -1,6 +1,7 @@
1
1
  import hashlib
2
2
  import json
3
3
  import operator
4
+ import zipfile
4
5
  from functools import reduce
5
6
  from pathlib import Path
6
7
 
@@ -68,3 +69,17 @@ def calculate_checksum(file_path, prefix=''):
68
69
  if prefix:
69
70
  return f'dev-{checksum}'
70
71
  return checksum
72
+
73
+
74
+ def archive(input_path, output_path):
75
+ input_path = Path(input_path)
76
+ output_path = Path(output_path)
77
+
78
+ with zipfile.ZipFile(output_path, mode='w', compression=zipfile.ZIP_DEFLATED) as zipf:
79
+ if input_path.is_file():
80
+ zipf.write(input_path, input_path.name)
81
+ else:
82
+ for file_path in input_path.rglob('*'):
83
+ if file_path.is_file(): # Only add files, skip directories
84
+ arcname = file_path.relative_to(input_path.parent)
85
+ zipf.write(file_path, arcname)
File without changes
@@ -0,0 +1,4 @@
1
+ ERROR_MESSAGES = {
2
+ 'missing': '필수 값을 확인해주세요.',
3
+ 'blank': '필수 값을 확인해주세요.',
4
+ }
@@ -0,0 +1,33 @@
1
+ from typing import Any, Dict
2
+
3
+ from synapse_sdk.utils.pydantic.config import ERROR_MESSAGES
4
+
5
+
6
+ def pydantic_to_drf_error(e):
7
+ """
8
+ Convert a pydantic ValidationError into a DRF-style error response.
9
+ """
10
+ drf_errors: Dict[str, Any] = {}
11
+
12
+ for error in e.errors():
13
+ field_path = error['loc']
14
+ context_error = error.get('ctx', {}).get('error')
15
+
16
+ error_msg = context_error or ERROR_MESSAGES.get(error['type'], error['msg'])
17
+
18
+ # Convert the field path into a nested dictionary structure
19
+ current = drf_errors
20
+ for i, key in enumerate(field_path[:-1]):
21
+ current = current.setdefault(str(key), {})
22
+
23
+ # Set the error message at the final location
24
+ final_key = str(field_path[-1])
25
+ if final_key in current:
26
+ if isinstance(current[final_key], list):
27
+ current[final_key].append(error_msg)
28
+ else:
29
+ current[final_key] = [current[final_key], error_msg]
30
+ else:
31
+ current[final_key] = [error_msg]
32
+
33
+ return drf_errors
@@ -0,0 +1,7 @@
1
+ from pydantic_core import PydanticCustomError
2
+
3
+
4
+ def non_blank(value):
5
+ if not value.strip():
6
+ raise PydanticCustomError('blank', '필수 값을 확인해주세요.')
7
+ return value
@@ -1,5 +1,5 @@
1
1
  import os
2
- from urllib.parse import urlparse, parse_qs
2
+ from urllib.parse import parse_qs, urlparse
3
3
 
4
4
  import boto3
5
5
  from botocore.exceptions import ClientError
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: synapse-sdk
3
- Version: 1.0.0a6
3
+ Version: 1.0.0a8
4
4
  Summary: synapse sdk
5
5
  Author-email: datamaker <developer@datamaker.io>
6
6
  License: MIT
@@ -17,6 +17,6 @@ Requires-Dist: python-dotenv
17
17
  Requires-Dist: pyyaml
18
18
  Requires-Dist: pydantic
19
19
  Provides-Extra: all
20
- Requires-Dist: ray[all] ; extra == 'all'
20
+ Requires-Dist: ray[all]; extra == "all"
21
21
 
22
22
  This is the SDK to develop synapse plugins
@@ -1,77 +1,97 @@
1
1
  synapse_sdk/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- synapse_sdk/loggers.py,sha256=7wB18EZ092YQayNgXN_8JzS3vi0BjV5Xu0o2aTkcfNA,1468
2
+ synapse_sdk/loggers.py,sha256=avoceBBu9VuSNS_CC3M5X8rWmAlk5xCTYEAVqxAXzBM,4008
3
3
  synapse_sdk/cli/__init__.py,sha256=WmYGW1qZEXXIGJe3SGr8QjOStY4svuZKK1Lp_aPvtPs,140
4
4
  synapse_sdk/cli/create_plugin.py,sha256=egbW_92WwxfHz50Gy4znX5Bf5fxDdQj3GFyd0l3Y3SY,228
5
5
  synapse_sdk/clients/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
- synapse_sdk/clients/base.py,sha256=IuZY9-me62lPRgmMjXPhqy8cVLbtVSyT9acj19KMQkU,2788
6
+ synapse_sdk/clients/base.py,sha256=HfUJDP5FerRkiCJ0eaAZvs4F_kv73PtZ5FSnz_lKV0o,3069
7
7
  synapse_sdk/clients/exceptions.py,sha256=ylv7x10eOp4aA3a48jwonnvqvkiYwzJYXjkVkRTAjwk,220
8
8
  synapse_sdk/clients/utils.py,sha256=8pPJTdzHiRPSbZMoQYHAgR2BAMO6u_R_jMV6a2p34iQ,392
9
9
  synapse_sdk/clients/agent/__init__.py,sha256=n4exZwc8gwuH6zqZUhstcD_sqIdm-ZoPvUcAxnCrnOQ,609
10
10
  synapse_sdk/clients/agent/service.py,sha256=NnRu0XPVRqry6PWN_8-3iuzdXx20zO1lPXw-yVWQbdg,1433
11
11
  synapse_sdk/clients/backend/__init__.py,sha256=850EjxNoGWXJpVZLRIaajrymBuW0MXiP3M3onRHDGbQ,800
12
- synapse_sdk/clients/backend/annotation.py,sha256=Zt1VA3fScYCxy_Ss1TEzqu7jYdNxlNBRYAjZfuEWOSI,989
13
- synapse_sdk/clients/backend/dataset.py,sha256=abZr9FyVzgnEpk1POK6m1FfbzWKnqWTo7wyQwwS5VvM,1743
14
- synapse_sdk/clients/backend/integration.py,sha256=jrymq6kyoM1CwWJuh8BcJAXoVFaY5cOaLTHYdFn4pwo,1410
15
- synapse_sdk/clients/backend/ml.py,sha256=l4rGLBZgLUYQOBePvWAoNyz-yZgJuhC-1KCFeZOYDuQ,1012
12
+ synapse_sdk/clients/backend/annotation.py,sha256=eZc5EidgR_RfMGwvv1r1_mLkPdRd8e52c4zuuMjMX34,979
13
+ synapse_sdk/clients/backend/dataset.py,sha256=X8R71vff1gLytlEaOnKhBWjVQaZcIG_WYy32new4Vq0,1737
14
+ synapse_sdk/clients/backend/integration.py,sha256=wYfxRI2miZIwC1n7JoVRuSeq1cw5FkNIpKMxcMjj-b0,1628
15
+ synapse_sdk/clients/backend/ml.py,sha256=SwA4_noRCZ1dVIzyXfrs2zHuRlQZdZt17o1We5QOxl8,1053
16
16
  synapse_sdk/plugins/__init__.py,sha256=9vsbYhxah4_ofTaG0x0qLFID_raHNkO57Y8A31Ws-lU,222
17
- synapse_sdk/plugins/enums.py,sha256=lQZqO2bEeBKdk6q-SMjfOLDlgxv7BuIPk3fXeUFfHRs,327
18
- synapse_sdk/plugins/models.py,sha256=LmhJCWfyBeTDFgw-qwkQAwRRW_zsPOHOZdhI5c8jomE,1606
17
+ synapse_sdk/plugins/enums.py,sha256=s59P6Oz2WAK9IX-kLVhNOvNKYJifKlWBhPpZbc9-ttE,486
18
+ synapse_sdk/plugins/exceptions.py,sha256=RFRz2SIHc4WmTd7sKZOMrQtD5nm4ldtb8CzG9VG65OE,167
19
+ synapse_sdk/plugins/models.py,sha256=pzzJl9zKL8v2XjBQC0UR-W9rG4Vyp95DzJ9MMG2W5L0,2835
19
20
  synapse_sdk/plugins/upload.py,sha256=SSCHUR4HJ_mdLN7mUkk5UlXmL9028SKP6tpBS2rpf0A,3175
20
21
  synapse_sdk/plugins/utils.py,sha256=n3s-zFnj4hrGWFtaBTJFbaupI8qUQL6S8_5YcbxOmeY,1482
21
22
  synapse_sdk/plugins/categories/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
22
- synapse_sdk/plugins/categories/base.py,sha256=mf1duSt1Kt3FrgbXVlps64D1-OmkQx_HI1Z8HKkoA1E,6575
23
+ synapse_sdk/plugins/categories/base.py,sha256=QBC96T0VIe-Lp63itjh0E13dgRriU7FT4_xZw7-7Zw8,7060
23
24
  synapse_sdk/plugins/categories/decorators.py,sha256=Gw6T-UHwpCKrSt596X-g2sZbY_Z1zbbogowClj7Pr5Q,518
24
25
  synapse_sdk/plugins/categories/registry.py,sha256=KdQR8SUlLT-3kgYzDNWawS1uJnAhrcw2j4zFaTpilRs,636
25
26
  synapse_sdk/plugins/categories/templates.py,sha256=FF5FerhkZMeW1YcKLY5cylC0SkWSYdJODA_Qcm4OGYQ,887
26
27
  synapse_sdk/plugins/categories/data_validation/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
27
28
  synapse_sdk/plugins/categories/data_validation/actions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
28
- synapse_sdk/plugins/categories/data_validation/actions/validation.py,sha256=NbEGFytxjakawglZR_Sf9UAjQyuzRxpdwEI1GDbEBW0,338
29
+ synapse_sdk/plugins/categories/data_validation/actions/validation.py,sha256=U1lA36RyGmtRuF1AIpr1mE30z0cByCAC_PDKtEptDTc,338
30
+ synapse_sdk/plugins/categories/data_validation/templates/config.yaml,sha256=Hijb-b3hy0msZsTV_bbr3Hvlk8ok-Rk0a05mlLGTCAg,66
31
+ synapse_sdk/plugins/categories/data_validation/templates/plugin/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
32
+ synapse_sdk/plugins/categories/data_validation/templates/plugin/validation.py,sha256=90I5boUpEXvO3mEuKKBs528ls2A4h8Iw4ReOID2h00Y,139
29
33
  synapse_sdk/plugins/categories/export/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
30
34
  synapse_sdk/plugins/categories/export/actions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
31
- synapse_sdk/plugins/categories/export/actions/export.py,sha256=zpvVB0Dac9ytshJrN2ouDpsGHMuJlap-Ymz4qEw_Hzo,320
35
+ synapse_sdk/plugins/categories/export/actions/export.py,sha256=GboGbFAUFPFqEedqO65L8IbX3AczrIFDoHbHBPaFCN0,320
32
36
  synapse_sdk/plugins/categories/import/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
33
37
  synapse_sdk/plugins/categories/import/actions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
34
- synapse_sdk/plugins/categories/import/actions/import.py,sha256=bkB8x-x7jJfcCnzbz5bOJJy7mPhTKYfIWUdmCoHvpdM,320
38
+ synapse_sdk/plugins/categories/import/actions/import.py,sha256=URn6TOp081odMT5D4NlZ2XEcyKelJx8fxzdoKSkXSAI,320
35
39
  synapse_sdk/plugins/categories/neural_net/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
36
40
  synapse_sdk/plugins/categories/neural_net/actions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
37
- synapse_sdk/plugins/categories/neural_net/actions/deployment.py,sha256=CXdsZcaxvFq0EcTT8w3Z6Ki7Qs4hXPL7Jv-ipXvXKCU,795
38
- synapse_sdk/plugins/categories/neural_net/actions/inference.py,sha256=erM2z7aUTwyzJZqWBlxhTP8dm8cOraI_vUYAqcXkdSY,334
39
- synapse_sdk/plugins/categories/neural_net/actions/test.py,sha256=dAW1zfodlUhoL-sD17tG-CQT0RBxIcHWJ8f1eeZ00M4,321
40
- synapse_sdk/plugins/categories/neural_net/actions/train.py,sha256=ASbqY7ZB0-bVrEOH1uvOkhrYKNt7ZC1aIbPZPfKXZGc,994
41
+ synapse_sdk/plugins/categories/neural_net/actions/deployment.py,sha256=U44sv_5UN2awfkbpyYPH9zOTEBhYn0FfcZwV7ywi-cA,827
42
+ synapse_sdk/plugins/categories/neural_net/actions/inference.py,sha256=qavUxayUDgN5E5Ht0x3cqWF0uPNkwUiZlCmfo574xHE,334
43
+ synapse_sdk/plugins/categories/neural_net/actions/test.py,sha256=JY25eg-Fo6WbgtMkGoo_qNqoaZkp3AQNEypJmeGzEog,320
44
+ synapse_sdk/plugins/categories/neural_net/actions/train.py,sha256=pE0RTruXqX1Jdp4iWDpsRH80V7TnvMnZnAlLOYkRusA,4463
41
45
  synapse_sdk/plugins/categories/neural_net/templates/config.yaml,sha256=pvJFh_NHGZHHFfqrvZm6fHO5lsS7CudaIGboP6wbtY8,252
42
46
  synapse_sdk/plugins/categories/neural_net/templates/plugin/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
43
47
  synapse_sdk/plugins/categories/neural_net/templates/plugin/inference.py,sha256=glYYdRybG3vRe48bYIxvue7bCFGPlEZmYWRoyBsLdZw,123
44
48
  synapse_sdk/plugins/categories/neural_net/templates/plugin/test.py,sha256=kYyk7l4UtcDUAH4nkdVUGrHHHjxI4p1U13HSLnmGPyE,53
45
- synapse_sdk/plugins/categories/neural_net/templates/plugin/train.py,sha256=gtbUe6oVBNV7f_ZXQZ92rWnqRGw_rIUwNabQdgahF6w,504
49
+ synapse_sdk/plugins/categories/neural_net/templates/plugin/train.py,sha256=-QzWrfJGOk6EagQZmC1MMmiOEIr3X1sVGszMJjv5dFg,500
46
50
  synapse_sdk/plugins/categories/post_annotation/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
47
51
  synapse_sdk/plugins/categories/post_annotation/actions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
48
- synapse_sdk/plugins/categories/post_annotation/actions/post_annotation.py,sha256=1tutwNDHpnrCPHzMTsMEk29WPajnZikjBE83j7Z-Xt0,347
52
+ synapse_sdk/plugins/categories/post_annotation/actions/post_annotation.py,sha256=dkPqOPPMUoxn7h1e-momdhqezhTJ7wLf-Dyx04zKfjw,347
53
+ synapse_sdk/plugins/categories/post_annotation/templates/config.yaml,sha256=2g9S-eVnqteKY9E-GWtHZOengb4LdQ3Yt9hDb4S89HA,81
54
+ synapse_sdk/plugins/categories/post_annotation/templates/plugin/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
55
+ synapse_sdk/plugins/categories/post_annotation/templates/plugin/post_annotation.py,sha256=GTsGq6zOZDWQSgP-XPr74qVWil480sYrLIBdk28ZMvQ,108
49
56
  synapse_sdk/plugins/categories/pre_annotation/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
50
57
  synapse_sdk/plugins/categories/pre_annotation/actions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
51
- synapse_sdk/plugins/categories/pre_annotation/actions/pre_annotation.py,sha256=YYQt9HsgXlBclE4Sn0c7p1zqCxWHkIHAwyA-tbqrmPQ,344
58
+ synapse_sdk/plugins/categories/pre_annotation/actions/pre_annotation.py,sha256=6ib3RmnGrjpsQ0e_G-mRH1lfFunQ3gh2M831vuDn7HU,344
59
+ synapse_sdk/plugins/categories/pre_annotation/templates/config.yaml,sha256=bUaibKbb-kai3QAHWbCYbO8nT-DQpV-KhuBszB7i-hI,78
60
+ synapse_sdk/plugins/categories/pre_annotation/templates/plugin/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
61
+ synapse_sdk/plugins/categories/pre_annotation/templates/plugin/pre_annotation.py,sha256=HBHxHuv2gMBzDB2alFfrzI_SZ1Ztk6mo7eFbR5GqHKw,106
62
+ synapse_sdk/plugins/categories/smart_tool/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
63
+ synapse_sdk/plugins/categories/smart_tool/actions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
64
+ synapse_sdk/plugins/categories/smart_tool/actions/auto_label.py,sha256=MZKpLsCGzO1FJsE32D7O3gC2rrTpYZKP1x0oE-Uu8Mc,699
65
+ synapse_sdk/plugins/categories/smart_tool/templates/config.yaml,sha256=lTixdat8b3LZi_JeiUZfAN5oM5iFnqLD5M-xR_xF7M4,145
66
+ synapse_sdk/plugins/categories/smart_tool/templates/plugin/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
67
+ synapse_sdk/plugins/categories/smart_tool/templates/plugin/auto_label.py,sha256=eevNg0nOcYFR4z_L_R-sCvVOYoLWSAH1jwDkAf3YCjY,320
52
68
  synapse_sdk/plugins/cli/__init__.py,sha256=8ogaOhN-RbDNYHqziW8nLsNUxKkZwGkHBdKxTahcm3U,334
53
69
  synapse_sdk/plugins/cli/publish.py,sha256=ecX5vne2MuULon7JvH6NfiNcn7ccdv2SZUd9TakQzCI,1145
54
70
  synapse_sdk/plugins/cli/run.py,sha256=lw1KbsL-xTGllF4NtD2cq-Rh6HMbhi-sO862_Ds-sUo,2330
55
71
  synapse_sdk/plugins/templates/cookiecutter.json,sha256=NxOWk9A_v1pO0Ny4IYT9Cj5iiJ16--cIQrGC67QdR0I,396
56
72
  synapse_sdk/plugins/templates/hooks/post_gen_project.py,sha256=jqlYkY1O2TxIR-Vh3gnwILYy8k-D39Xx66d2KNQVMCs,147
57
- synapse_sdk/plugins/templates/hooks/pre_prompt.py,sha256=YXhPmobVr8WKv-acgYST7Qu_qXmrUYhxiHrnAUO38xs,538
73
+ synapse_sdk/plugins/templates/hooks/pre_prompt.py,sha256=aOAMM623s0sKFGjTZaotAOYFvsNMxeii4tPyhOAFKVE,539
58
74
  synapse_sdk/plugins/templates/synapse-{{cookiecutter.plugin_code}}-plugin/.env.dist,sha256=YlAG5YKwFEiwKm5NUbPsqvOJ9FJKoN0lbT3sxymBJpE,551
59
75
  synapse_sdk/plugins/templates/synapse-{{cookiecutter.plugin_code}}-plugin/.gitignore,sha256=RvBmUbwmzgv0vYzYk2aQ0HpvKyPj6sCpBqsrthCuA4s,243
60
76
  synapse_sdk/plugins/templates/synapse-{{cookiecutter.plugin_code}}-plugin/.pre-commit-config.yaml,sha256=p0yZwCUC8tYS1B0GPkjKiXYoRY9EZlq_ejFP98hB50g,154
61
77
  synapse_sdk/plugins/templates/synapse-{{cookiecutter.plugin_code}}-plugin/README.md,sha256=ETBZv_2Ocgzn4Fe3o5Y842mZiz00ABuAalrXpNVnWU0,56
62
- synapse_sdk/plugins/templates/synapse-{{cookiecutter.plugin_code}}-plugin/config.yaml,sha256=3Sv59w4vAgFasJEn5z7WNborTVlotrqOOVnCLEEz5JI,459
63
- synapse_sdk/plugins/templates/synapse-{{cookiecutter.plugin_code}}-plugin/pyproject.toml,sha256=HHfEE_HquaTlBPCOTQkNXphVtc3QLtU_kCEqKv6C6e8,312
78
+ synapse_sdk/plugins/templates/synapse-{{cookiecutter.plugin_code}}-plugin/config.yaml,sha256=CRfKjPJ6K2UlYbcHMSAYUGzn2TGmV7kDbZmKHwNuq3w,210
79
+ synapse_sdk/plugins/templates/synapse-{{cookiecutter.plugin_code}}-plugin/pyproject.toml,sha256=Usgd80tHZAD1Ug5MAjPfETUZxtKKgZW-xovFEAEbQDo,317
64
80
  synapse_sdk/plugins/templates/synapse-{{cookiecutter.plugin_code}}-plugin/requirements.txt,sha256=F5UwinpTLQFfyakFGTFxgBOo4H-EKD9d4e77WKOPHhk,17
65
81
  synapse_sdk/plugins/templates/synapse-{{cookiecutter.plugin_code}}-plugin/plugin/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
66
82
  synapse_sdk/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
67
83
  synapse_sdk/utils/debug.py,sha256=46sMFQLg_JSRUCymnT3wgszG1QsgrocRGiBjVX38r50,53
68
- synapse_sdk/utils/file.py,sha256=Iptk_DCPsmJzqAABCD3vC6z1yG74fKb5x81LnUCZzYo,1916
84
+ synapse_sdk/utils/file.py,sha256=nuU6POe0F6_WvIB26X9Q6dpcwgys8unt5Qv66n0Bmg4,2482
69
85
  synapse_sdk/utils/module_loading.py,sha256=chHpU-BZjtYaTBD_q0T7LcKWtqKvYBS4L0lPlKkoMQ8,1020
70
- synapse_sdk/utils/storage.py,sha256=U3TScqQNgHQ89s0kUqQ8hm3npQAznIyRqzWDKR0YA3E,2581
86
+ synapse_sdk/utils/storage.py,sha256=a8OVbd38ATr0El4G4kuV07lr_tJZrpIJBSy4GHb0qZ8,2581
71
87
  synapse_sdk/utils/string.py,sha256=rEwuZ9SAaZLcQ8TYiwNKr1h2u4CfnrQx7SUL8NWmChg,216
72
- synapse_sdk-1.0.0a6.dist-info/LICENSE,sha256=bKzmC5YAg4V1Fhl8OO_tqY8j62hgdncAkN7VrdjmrGk,1101
73
- synapse_sdk-1.0.0a6.dist-info/METADATA,sha256=t1xmLp2ooXp2022zUVfStMEkvlAlfke1ZxAVeqjE_1o,568
74
- synapse_sdk-1.0.0a6.dist-info/WHEEL,sha256=R06PA3UVYHThwHvxuRWMqaGcr-PuniXahwjmQRFMEkY,91
75
- synapse_sdk-1.0.0a6.dist-info/entry_points.txt,sha256=VNptJoGoNJI8yLXfBmhgUefMsmGI0m3-0YoMvrOgbxo,48
76
- synapse_sdk-1.0.0a6.dist-info/top_level.txt,sha256=ytgJMRK1slVOKUpgcw3LEyHHP7S34J6n_gJzdkcSsw8,12
77
- synapse_sdk-1.0.0a6.dist-info/RECORD,,
88
+ synapse_sdk/utils/pydantic/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
89
+ synapse_sdk/utils/pydantic/config.py,sha256=1vYOcUI35GslfD1rrqhFkNXXJOXt4IDqOPSx9VWGfNE,123
90
+ synapse_sdk/utils/pydantic/errors.py,sha256=0v0T12eQBr1KrFiEOBu6KMaPK4aPEGEC6etPJGoR5b4,1061
91
+ synapse_sdk/utils/pydantic/validators.py,sha256=G47P8ObPhsePmd_QZDK8EdPnik2CbaYzr_N4Z6En8dc,193
92
+ synapse_sdk-1.0.0a8.dist-info/LICENSE,sha256=bKzmC5YAg4V1Fhl8OO_tqY8j62hgdncAkN7VrdjmrGk,1101
93
+ synapse_sdk-1.0.0a8.dist-info/METADATA,sha256=-qf5IZO1tU5DNWmiT4BMVD_26XoKjF3KaFsAfceIRx8,567
94
+ synapse_sdk-1.0.0a8.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
95
+ synapse_sdk-1.0.0a8.dist-info/entry_points.txt,sha256=VNptJoGoNJI8yLXfBmhgUefMsmGI0m3-0YoMvrOgbxo,48
96
+ synapse_sdk-1.0.0a8.dist-info/top_level.txt,sha256=ytgJMRK1slVOKUpgcw3LEyHHP7S34J6n_gJzdkcSsw8,12
97
+ synapse_sdk-1.0.0a8.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.5.0)
2
+ Generator: setuptools (75.6.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5