synapse-sdk 1.0.0b5__py3-none-any.whl → 2025.12.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- synapse_sdk/__init__.py +24 -0
- synapse_sdk/cli/code_server.py +305 -33
- synapse_sdk/clients/agent/__init__.py +2 -1
- synapse_sdk/clients/agent/container.py +143 -0
- synapse_sdk/clients/agent/ray.py +296 -38
- synapse_sdk/clients/backend/annotation.py +1 -1
- synapse_sdk/clients/backend/core.py +31 -4
- synapse_sdk/clients/backend/data_collection.py +82 -7
- synapse_sdk/clients/backend/hitl.py +1 -1
- synapse_sdk/clients/backend/ml.py +1 -1
- synapse_sdk/clients/base.py +211 -61
- synapse_sdk/loggers.py +46 -0
- synapse_sdk/plugins/README.md +1340 -0
- synapse_sdk/plugins/categories/base.py +59 -9
- synapse_sdk/plugins/categories/export/actions/__init__.py +3 -0
- synapse_sdk/plugins/categories/export/actions/export/__init__.py +28 -0
- synapse_sdk/plugins/categories/export/actions/export/action.py +165 -0
- synapse_sdk/plugins/categories/export/actions/export/enums.py +113 -0
- synapse_sdk/plugins/categories/export/actions/export/exceptions.py +53 -0
- synapse_sdk/plugins/categories/export/actions/export/models.py +74 -0
- synapse_sdk/plugins/categories/export/actions/export/run.py +195 -0
- synapse_sdk/plugins/categories/export/actions/export/utils.py +187 -0
- synapse_sdk/plugins/categories/export/templates/config.yaml +19 -1
- synapse_sdk/plugins/categories/export/templates/plugin/__init__.py +390 -0
- synapse_sdk/plugins/categories/export/templates/plugin/export.py +153 -177
- synapse_sdk/plugins/categories/neural_net/actions/train.py +1130 -32
- synapse_sdk/plugins/categories/neural_net/actions/tune.py +157 -4
- synapse_sdk/plugins/categories/neural_net/templates/config.yaml +7 -4
- synapse_sdk/plugins/categories/pre_annotation/actions/__init__.py +4 -0
- synapse_sdk/plugins/categories/pre_annotation/actions/pre_annotation/__init__.py +3 -0
- synapse_sdk/plugins/categories/pre_annotation/actions/pre_annotation/action.py +10 -0
- synapse_sdk/plugins/categories/pre_annotation/actions/to_task/__init__.py +28 -0
- synapse_sdk/plugins/categories/pre_annotation/actions/to_task/action.py +148 -0
- synapse_sdk/plugins/categories/pre_annotation/actions/to_task/enums.py +269 -0
- synapse_sdk/plugins/categories/pre_annotation/actions/to_task/exceptions.py +14 -0
- synapse_sdk/plugins/categories/pre_annotation/actions/to_task/factory.py +76 -0
- synapse_sdk/plugins/categories/pre_annotation/actions/to_task/models.py +100 -0
- synapse_sdk/plugins/categories/pre_annotation/actions/to_task/orchestrator.py +248 -0
- synapse_sdk/plugins/categories/pre_annotation/actions/to_task/run.py +64 -0
- synapse_sdk/plugins/categories/pre_annotation/actions/to_task/strategies/__init__.py +17 -0
- synapse_sdk/plugins/categories/pre_annotation/actions/to_task/strategies/annotation.py +265 -0
- synapse_sdk/plugins/categories/pre_annotation/actions/to_task/strategies/base.py +170 -0
- synapse_sdk/plugins/categories/pre_annotation/actions/to_task/strategies/extraction.py +83 -0
- synapse_sdk/plugins/categories/pre_annotation/actions/to_task/strategies/metrics.py +92 -0
- synapse_sdk/plugins/categories/pre_annotation/actions/to_task/strategies/preprocessor.py +243 -0
- synapse_sdk/plugins/categories/pre_annotation/actions/to_task/strategies/validation.py +143 -0
- synapse_sdk/plugins/categories/upload/actions/upload/__init__.py +19 -0
- synapse_sdk/plugins/categories/upload/actions/upload/action.py +236 -0
- synapse_sdk/plugins/categories/upload/actions/upload/context.py +185 -0
- synapse_sdk/plugins/categories/upload/actions/upload/enums.py +493 -0
- synapse_sdk/plugins/categories/upload/actions/upload/exceptions.py +36 -0
- synapse_sdk/plugins/categories/upload/actions/upload/factory.py +138 -0
- synapse_sdk/plugins/categories/upload/actions/upload/models.py +214 -0
- synapse_sdk/plugins/categories/upload/actions/upload/orchestrator.py +183 -0
- synapse_sdk/plugins/categories/upload/actions/upload/registry.py +113 -0
- synapse_sdk/plugins/categories/upload/actions/upload/run.py +179 -0
- synapse_sdk/plugins/categories/upload/actions/upload/steps/__init__.py +1 -0
- synapse_sdk/plugins/categories/upload/actions/upload/steps/base.py +107 -0
- synapse_sdk/plugins/categories/upload/actions/upload/steps/cleanup.py +62 -0
- synapse_sdk/plugins/categories/upload/actions/upload/steps/collection.py +63 -0
- synapse_sdk/plugins/categories/upload/actions/upload/steps/generate.py +91 -0
- synapse_sdk/plugins/categories/upload/actions/upload/steps/initialize.py +82 -0
- synapse_sdk/plugins/categories/upload/actions/upload/steps/metadata.py +235 -0
- synapse_sdk/plugins/categories/upload/actions/upload/steps/organize.py +201 -0
- synapse_sdk/plugins/categories/upload/actions/upload/steps/upload.py +104 -0
- synapse_sdk/plugins/categories/upload/actions/upload/steps/validate.py +71 -0
- synapse_sdk/plugins/categories/upload/actions/upload/strategies/__init__.py +1 -0
- synapse_sdk/plugins/categories/upload/actions/upload/strategies/base.py +82 -0
- synapse_sdk/plugins/categories/upload/actions/upload/strategies/data_unit/__init__.py +1 -0
- synapse_sdk/plugins/categories/upload/actions/upload/strategies/data_unit/batch.py +39 -0
- synapse_sdk/plugins/categories/upload/actions/upload/strategies/data_unit/single.py +29 -0
- synapse_sdk/plugins/categories/upload/actions/upload/strategies/file_discovery/__init__.py +1 -0
- synapse_sdk/plugins/categories/upload/actions/upload/strategies/file_discovery/flat.py +300 -0
- synapse_sdk/plugins/categories/upload/actions/upload/strategies/file_discovery/recursive.py +287 -0
- synapse_sdk/plugins/categories/upload/actions/upload/strategies/metadata/__init__.py +1 -0
- synapse_sdk/plugins/categories/upload/actions/upload/strategies/metadata/excel.py +174 -0
- synapse_sdk/plugins/categories/upload/actions/upload/strategies/metadata/none.py +16 -0
- synapse_sdk/plugins/categories/upload/actions/upload/strategies/upload/__init__.py +1 -0
- synapse_sdk/plugins/categories/upload/actions/upload/strategies/upload/sync.py +84 -0
- synapse_sdk/plugins/categories/upload/actions/upload/strategies/validation/__init__.py +1 -0
- synapse_sdk/plugins/categories/upload/actions/upload/strategies/validation/default.py +60 -0
- synapse_sdk/plugins/categories/upload/actions/upload/utils.py +250 -0
- synapse_sdk/plugins/categories/upload/templates/README.md +470 -0
- synapse_sdk/plugins/categories/upload/templates/config.yaml +28 -2
- synapse_sdk/plugins/categories/upload/templates/plugin/__init__.py +310 -0
- synapse_sdk/plugins/categories/upload/templates/plugin/upload.py +82 -20
- synapse_sdk/plugins/models.py +111 -9
- synapse_sdk/plugins/templates/plugin-config-schema.json +7 -0
- synapse_sdk/plugins/templates/schema.json +7 -0
- synapse_sdk/plugins/utils/__init__.py +3 -0
- synapse_sdk/plugins/utils/ray_gcs.py +66 -0
- synapse_sdk/shared/__init__.py +25 -0
- synapse_sdk/utils/converters/dm/__init__.py +42 -41
- synapse_sdk/utils/converters/dm/base.py +137 -0
- synapse_sdk/utils/converters/dm/from_v1.py +208 -562
- synapse_sdk/utils/converters/dm/to_v1.py +258 -304
- synapse_sdk/utils/converters/dm/tools/__init__.py +214 -0
- synapse_sdk/utils/converters/dm/tools/answer.py +95 -0
- synapse_sdk/utils/converters/dm/tools/bounding_box.py +132 -0
- synapse_sdk/utils/converters/dm/tools/bounding_box_3d.py +121 -0
- synapse_sdk/utils/converters/dm/tools/classification.py +75 -0
- synapse_sdk/utils/converters/dm/tools/keypoint.py +117 -0
- synapse_sdk/utils/converters/dm/tools/named_entity.py +111 -0
- synapse_sdk/utils/converters/dm/tools/polygon.py +122 -0
- synapse_sdk/utils/converters/dm/tools/polyline.py +124 -0
- synapse_sdk/utils/converters/dm/tools/prompt.py +94 -0
- synapse_sdk/utils/converters/dm/tools/relation.py +86 -0
- synapse_sdk/utils/converters/dm/tools/segmentation.py +141 -0
- synapse_sdk/utils/converters/dm/tools/segmentation_3d.py +83 -0
- synapse_sdk/utils/converters/dm/types.py +168 -0
- synapse_sdk/utils/converters/dm/utils.py +162 -0
- synapse_sdk/utils/converters/dm_legacy/__init__.py +56 -0
- synapse_sdk/utils/converters/dm_legacy/from_v1.py +627 -0
- synapse_sdk/utils/converters/dm_legacy/to_v1.py +367 -0
- synapse_sdk/utils/file/__init__.py +58 -0
- synapse_sdk/utils/file/archive.py +32 -0
- synapse_sdk/utils/file/checksum.py +56 -0
- synapse_sdk/utils/file/chunking.py +31 -0
- synapse_sdk/utils/file/download.py +385 -0
- synapse_sdk/utils/file/encoding.py +40 -0
- synapse_sdk/utils/file/io.py +22 -0
- synapse_sdk/utils/file/upload.py +165 -0
- synapse_sdk/utils/file/video/__init__.py +29 -0
- synapse_sdk/utils/file/video/transcode.py +307 -0
- synapse_sdk/utils/{file.py → file.py.backup} +77 -0
- synapse_sdk/utils/network.py +272 -0
- synapse_sdk/utils/storage/__init__.py +6 -2
- synapse_sdk/utils/storage/providers/file_system.py +6 -0
- {synapse_sdk-1.0.0b5.dist-info → synapse_sdk-2025.12.3.dist-info}/METADATA +19 -2
- {synapse_sdk-1.0.0b5.dist-info → synapse_sdk-2025.12.3.dist-info}/RECORD +134 -74
- synapse_sdk/devtools/docs/.gitignore +0 -20
- synapse_sdk/devtools/docs/README.md +0 -41
- synapse_sdk/devtools/docs/blog/2019-05-28-first-blog-post.md +0 -12
- synapse_sdk/devtools/docs/blog/2019-05-29-long-blog-post.md +0 -44
- synapse_sdk/devtools/docs/blog/2021-08-01-mdx-blog-post.mdx +0 -24
- synapse_sdk/devtools/docs/blog/2021-08-26-welcome/docusaurus-plushie-banner.jpeg +0 -0
- synapse_sdk/devtools/docs/blog/2021-08-26-welcome/index.md +0 -29
- synapse_sdk/devtools/docs/blog/authors.yml +0 -25
- synapse_sdk/devtools/docs/blog/tags.yml +0 -19
- synapse_sdk/devtools/docs/docusaurus.config.ts +0 -138
- synapse_sdk/devtools/docs/package-lock.json +0 -17455
- synapse_sdk/devtools/docs/package.json +0 -47
- synapse_sdk/devtools/docs/sidebars.ts +0 -44
- synapse_sdk/devtools/docs/src/components/HomepageFeatures/index.tsx +0 -71
- synapse_sdk/devtools/docs/src/components/HomepageFeatures/styles.module.css +0 -11
- synapse_sdk/devtools/docs/src/css/custom.css +0 -30
- synapse_sdk/devtools/docs/src/pages/index.module.css +0 -23
- synapse_sdk/devtools/docs/src/pages/index.tsx +0 -21
- synapse_sdk/devtools/docs/src/pages/markdown-page.md +0 -7
- synapse_sdk/devtools/docs/static/.nojekyll +0 -0
- synapse_sdk/devtools/docs/static/img/docusaurus-social-card.jpg +0 -0
- synapse_sdk/devtools/docs/static/img/docusaurus.png +0 -0
- synapse_sdk/devtools/docs/static/img/favicon.ico +0 -0
- synapse_sdk/devtools/docs/static/img/logo.png +0 -0
- synapse_sdk/devtools/docs/static/img/undraw_docusaurus_mountain.svg +0 -171
- synapse_sdk/devtools/docs/static/img/undraw_docusaurus_react.svg +0 -170
- synapse_sdk/devtools/docs/static/img/undraw_docusaurus_tree.svg +0 -40
- synapse_sdk/devtools/docs/tsconfig.json +0 -8
- synapse_sdk/plugins/categories/export/actions/export.py +0 -346
- synapse_sdk/plugins/categories/export/enums.py +0 -7
- synapse_sdk/plugins/categories/neural_net/actions/gradio.py +0 -151
- synapse_sdk/plugins/categories/pre_annotation/actions/to_task.py +0 -943
- synapse_sdk/plugins/categories/upload/actions/upload.py +0 -954
- {synapse_sdk-1.0.0b5.dist-info → synapse_sdk-2025.12.3.dist-info}/WHEEL +0 -0
- {synapse_sdk-1.0.0b5.dist-info → synapse_sdk-2025.12.3.dist-info}/entry_points.txt +0 -0
- {synapse_sdk-1.0.0b5.dist-info → synapse_sdk-2025.12.3.dist-info}/licenses/LICENSE +0 -0
- {synapse_sdk-1.0.0b5.dist-info → synapse_sdk-2025.12.3.dist-info}/top_level.txt +0 -0
|
@@ -1,346 +0,0 @@
|
|
|
1
|
-
import json
|
|
2
|
-
from abc import ABC, abstractmethod
|
|
3
|
-
from datetime import datetime
|
|
4
|
-
from typing import Annotated, Any, Literal
|
|
5
|
-
|
|
6
|
-
from pydantic import AfterValidator, BaseModel, field_validator
|
|
7
|
-
from pydantic_core import PydanticCustomError
|
|
8
|
-
|
|
9
|
-
from synapse_sdk.clients.exceptions import ClientError
|
|
10
|
-
from synapse_sdk.i18n import gettext as _
|
|
11
|
-
from synapse_sdk.plugins.categories.base import Action
|
|
12
|
-
from synapse_sdk.plugins.categories.decorators import register_action
|
|
13
|
-
from synapse_sdk.plugins.categories.export.enums import ExportStatus
|
|
14
|
-
from synapse_sdk.plugins.enums import PluginCategory, RunMethod
|
|
15
|
-
from synapse_sdk.plugins.models import Run
|
|
16
|
-
from synapse_sdk.utils.pydantic.validators import non_blank
|
|
17
|
-
from synapse_sdk.utils.storage import get_pathlib
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
class ExportRun(Run):
|
|
21
|
-
class DataFileLog(BaseModel):
|
|
22
|
-
"""Data file log model."""
|
|
23
|
-
|
|
24
|
-
target_id: int
|
|
25
|
-
data_file_info: str | None
|
|
26
|
-
status: ExportStatus
|
|
27
|
-
error: str | None = None
|
|
28
|
-
created: str
|
|
29
|
-
|
|
30
|
-
class MetricsRecord(BaseModel):
|
|
31
|
-
"""Metrics record model."""
|
|
32
|
-
|
|
33
|
-
stand_by: int
|
|
34
|
-
failed: int
|
|
35
|
-
success: int
|
|
36
|
-
|
|
37
|
-
def log_file(
|
|
38
|
-
self, log_type: str, target_id: int, data_file_info: dict, status: ExportStatus, error: str | None = None
|
|
39
|
-
):
|
|
40
|
-
"""Log export file information.
|
|
41
|
-
|
|
42
|
-
Args:
|
|
43
|
-
log_type (str): The type of log ('export_data_file' or 'export_original_file' or 'etc').
|
|
44
|
-
target_id (int): The ID of the data file.
|
|
45
|
-
data_file_info (dict): The JSON info of the data file.
|
|
46
|
-
status (ExportStatus): The status of the data file.
|
|
47
|
-
error (str | None): The error message, if any.
|
|
48
|
-
"""
|
|
49
|
-
now = datetime.now().isoformat()
|
|
50
|
-
self.log(
|
|
51
|
-
log_type,
|
|
52
|
-
self.DataFileLog(
|
|
53
|
-
target_id=target_id,
|
|
54
|
-
data_file_info=json.dumps(data_file_info),
|
|
55
|
-
status=status.value,
|
|
56
|
-
error=error,
|
|
57
|
-
created=now,
|
|
58
|
-
).model_dump(),
|
|
59
|
-
)
|
|
60
|
-
|
|
61
|
-
def log_metrics(self, record: MetricsRecord, category: str):
|
|
62
|
-
"""Log export metrics.
|
|
63
|
-
|
|
64
|
-
Args:
|
|
65
|
-
record (MetricsRecord): The metrics record to log.
|
|
66
|
-
category (str): The category of the metrics.
|
|
67
|
-
"""
|
|
68
|
-
record = self.MetricsRecord.model_validate(record)
|
|
69
|
-
self.set_metrics(value=record.dict(), category=category)
|
|
70
|
-
|
|
71
|
-
def export_log_json_file(
|
|
72
|
-
self,
|
|
73
|
-
target_id: int,
|
|
74
|
-
data_file_info: dict,
|
|
75
|
-
status: ExportStatus = ExportStatus.STAND_BY,
|
|
76
|
-
error: str | None = None,
|
|
77
|
-
):
|
|
78
|
-
"""Log export json data file."""
|
|
79
|
-
self.log_file('export_data_file', target_id, data_file_info, status, error)
|
|
80
|
-
|
|
81
|
-
def export_log_original_file(
|
|
82
|
-
self,
|
|
83
|
-
target_id: int,
|
|
84
|
-
data_file_info: dict,
|
|
85
|
-
status: ExportStatus = ExportStatus.STAND_BY,
|
|
86
|
-
error: str | None = None,
|
|
87
|
-
):
|
|
88
|
-
"""Log export origin data file."""
|
|
89
|
-
self.log_file('export_original_file', target_id, data_file_info, status, error)
|
|
90
|
-
|
|
91
|
-
def export_log_etc_file(
|
|
92
|
-
self,
|
|
93
|
-
target_id: int,
|
|
94
|
-
data_file_info: dict,
|
|
95
|
-
status: ExportStatus = ExportStatus.STAND_BY,
|
|
96
|
-
error: str | None = None,
|
|
97
|
-
):
|
|
98
|
-
"""Log export etc file."""
|
|
99
|
-
self.log_file('etc', target_id, data_file_info, status, error)
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
class ExportTargetHandler(ABC):
|
|
103
|
-
"""
|
|
104
|
-
Abstract base class for handling export targets.
|
|
105
|
-
|
|
106
|
-
This class defines the blueprint for export target handlers, requiring the implementation
|
|
107
|
-
of methods to validate filters, retrieve results, and process collections of results.
|
|
108
|
-
"""
|
|
109
|
-
|
|
110
|
-
@abstractmethod
|
|
111
|
-
def validate_filter(self, value: dict, client: Any):
|
|
112
|
-
"""
|
|
113
|
-
Validate filter query params to request original data from api.
|
|
114
|
-
|
|
115
|
-
Args:
|
|
116
|
-
value (dict): The filter criteria to validate.
|
|
117
|
-
client (Any): The client used to validate the filter.
|
|
118
|
-
|
|
119
|
-
Raises:
|
|
120
|
-
PydanticCustomError: If the filter criteria are invalid.
|
|
121
|
-
|
|
122
|
-
Returns:
|
|
123
|
-
dict: The validated filter criteria.
|
|
124
|
-
"""
|
|
125
|
-
pass
|
|
126
|
-
|
|
127
|
-
@abstractmethod
|
|
128
|
-
def get_results(self, client: Any, filters: dict):
|
|
129
|
-
"""
|
|
130
|
-
Retrieve original data from target sources.
|
|
131
|
-
|
|
132
|
-
Args:
|
|
133
|
-
client (Any): The client used to retrieve the results.
|
|
134
|
-
filters (dict): The filter criteria to apply.
|
|
135
|
-
|
|
136
|
-
Returns:
|
|
137
|
-
tuple: A tuple containing the results and the total count of results.
|
|
138
|
-
"""
|
|
139
|
-
pass
|
|
140
|
-
|
|
141
|
-
@abstractmethod
|
|
142
|
-
def get_export_item(self, results):
|
|
143
|
-
"""
|
|
144
|
-
Providing elements to build export data.
|
|
145
|
-
|
|
146
|
-
Args:
|
|
147
|
-
results (list): The results to process.
|
|
148
|
-
|
|
149
|
-
Yields:
|
|
150
|
-
generator: A generator that yields processed data items.
|
|
151
|
-
"""
|
|
152
|
-
pass
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
class AssignmentExportTargetHandler(ExportTargetHandler):
|
|
156
|
-
def validate_filter(self, value: dict, client: Any):
|
|
157
|
-
if 'project' not in value:
|
|
158
|
-
raise PydanticCustomError('missing_field', _('Project is required for Assignment.'))
|
|
159
|
-
try:
|
|
160
|
-
client.list_assignments(params=value)
|
|
161
|
-
except ClientError:
|
|
162
|
-
raise PydanticCustomError('client_error', _('Unable to get Assignment.'))
|
|
163
|
-
return value
|
|
164
|
-
|
|
165
|
-
def get_results(self, client: Any, filters: dict):
|
|
166
|
-
return client.list_assignments(params=filters, list_all=True)
|
|
167
|
-
|
|
168
|
-
def get_export_item(self, results):
|
|
169
|
-
for result in results:
|
|
170
|
-
yield {
|
|
171
|
-
'data': result['data'],
|
|
172
|
-
'files': result['file'],
|
|
173
|
-
'id': result['id'],
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
class GroundTruthExportTargetHandler(ExportTargetHandler):
|
|
178
|
-
def validate_filter(self, value: dict, client: Any):
|
|
179
|
-
if 'ground_truth_dataset_version' not in value:
|
|
180
|
-
raise PydanticCustomError('missing_field', _('Ground Truth dataset version is required.'))
|
|
181
|
-
try:
|
|
182
|
-
client.get_ground_truth_version(value['ground_truth_dataset_version'])
|
|
183
|
-
except ClientError:
|
|
184
|
-
raise PydanticCustomError('client_error', _('Unable to get Ground Truth dataset version.'))
|
|
185
|
-
return value
|
|
186
|
-
|
|
187
|
-
def get_results(self, client: Any, filters: dict):
|
|
188
|
-
filters['ground_truth_dataset_versions'] = filters.pop('ground_truth_dataset_version')
|
|
189
|
-
return client.list_ground_truth_events(params=filters, list_all=True)
|
|
190
|
-
|
|
191
|
-
def get_export_item(self, results):
|
|
192
|
-
for result in results:
|
|
193
|
-
files_key = next(iter(result['data_unit']['files']))
|
|
194
|
-
yield {
|
|
195
|
-
'data': result['data'],
|
|
196
|
-
'files': result['data_unit']['files'][files_key],
|
|
197
|
-
'id': result['ground_truth'],
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
class TaskExportTargetHandler(ExportTargetHandler):
|
|
202
|
-
def validate_filter(self, value: dict, client: Any):
|
|
203
|
-
if 'project' not in value:
|
|
204
|
-
raise PydanticCustomError('missing_field', _('Project is required for Task.'))
|
|
205
|
-
try:
|
|
206
|
-
client.list_tasks(params=value)
|
|
207
|
-
except ClientError:
|
|
208
|
-
raise PydanticCustomError('client_error', _('Unable to get Task.'))
|
|
209
|
-
return value
|
|
210
|
-
|
|
211
|
-
def get_results(self, client: Any, filters: dict):
|
|
212
|
-
filters['expand'] = 'data_unit'
|
|
213
|
-
return client.list_tasks(params=filters, list_all=True)
|
|
214
|
-
|
|
215
|
-
def get_export_item(self, results):
|
|
216
|
-
for result in results:
|
|
217
|
-
files_key = next(iter(result['data_unit']['files']))
|
|
218
|
-
yield {
|
|
219
|
-
'data': result['data'],
|
|
220
|
-
'files': result['data_unit']['files'][files_key],
|
|
221
|
-
'id': result['id'],
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
class TargetHandlerFactory:
|
|
226
|
-
@staticmethod
|
|
227
|
-
def get_handler(target: str) -> ExportTargetHandler:
|
|
228
|
-
if target == 'assignment':
|
|
229
|
-
return AssignmentExportTargetHandler()
|
|
230
|
-
elif target == 'ground_truth':
|
|
231
|
-
return GroundTruthExportTargetHandler()
|
|
232
|
-
elif target == 'task':
|
|
233
|
-
return TaskExportTargetHandler()
|
|
234
|
-
else:
|
|
235
|
-
raise ValueError(f'Unknown target: {target}')
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
class ExportParams(BaseModel):
|
|
239
|
-
"""
|
|
240
|
-
Parameters for the export action.
|
|
241
|
-
|
|
242
|
-
Attributes:
|
|
243
|
-
name (str): The name of the action.
|
|
244
|
-
description (str | None): The description of the action.
|
|
245
|
-
storage (int): The storage ID to save the exported data.
|
|
246
|
-
save_original_file (bool): Whether to save the original file.
|
|
247
|
-
path (str): The path to save the exported data.
|
|
248
|
-
target (str): The target source to export data from. (ex. ground_truth, assignment, task)
|
|
249
|
-
filter (dict): The filter criteria to apply.
|
|
250
|
-
"""
|
|
251
|
-
|
|
252
|
-
name: Annotated[str, AfterValidator(non_blank)]
|
|
253
|
-
description: str | None = None
|
|
254
|
-
storage: int
|
|
255
|
-
save_original_file: bool = True
|
|
256
|
-
path: str
|
|
257
|
-
target: Literal['assignment', 'ground_truth', 'task']
|
|
258
|
-
filter: dict
|
|
259
|
-
|
|
260
|
-
@field_validator('storage')
|
|
261
|
-
@staticmethod
|
|
262
|
-
def check_storage_exists(value, info):
|
|
263
|
-
action = info.context['action']
|
|
264
|
-
client = action.client
|
|
265
|
-
try:
|
|
266
|
-
client.get_storage(value)
|
|
267
|
-
except ClientError:
|
|
268
|
-
raise PydanticCustomError('client_error', _('Unable to get storage from Synapse backend.'))
|
|
269
|
-
return value
|
|
270
|
-
|
|
271
|
-
@field_validator('filter')
|
|
272
|
-
@staticmethod
|
|
273
|
-
def check_filter_by_target(value, info):
|
|
274
|
-
action = info.context['action']
|
|
275
|
-
client = action.client
|
|
276
|
-
target = action.params['target']
|
|
277
|
-
handler = TargetHandlerFactory.get_handler(target)
|
|
278
|
-
return handler.validate_filter(value, client)
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
@register_action
|
|
282
|
-
class ExportAction(Action):
|
|
283
|
-
name = 'export'
|
|
284
|
-
category = PluginCategory.EXPORT
|
|
285
|
-
method = RunMethod.JOB
|
|
286
|
-
params_model = ExportParams
|
|
287
|
-
run_class = ExportRun
|
|
288
|
-
progress_categories = {
|
|
289
|
-
'dataset_conversion': {
|
|
290
|
-
'proportion': 100,
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
metrics_categories = {
|
|
294
|
-
'data_file': {
|
|
295
|
-
'stand_by': 0,
|
|
296
|
-
'failed': 0,
|
|
297
|
-
'success': 0,
|
|
298
|
-
},
|
|
299
|
-
'original_file': {
|
|
300
|
-
'stand_by': 0,
|
|
301
|
-
'failed': 0,
|
|
302
|
-
'success': 0,
|
|
303
|
-
},
|
|
304
|
-
'etc': {
|
|
305
|
-
'stand_by': 0,
|
|
306
|
-
'failed': 0,
|
|
307
|
-
'success': 0,
|
|
308
|
-
},
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
def get_filtered_results(self, filters, handler):
|
|
312
|
-
"""Get filtered target results."""
|
|
313
|
-
try:
|
|
314
|
-
result_list = handler.get_results(self.client, filters)
|
|
315
|
-
results = result_list[0]
|
|
316
|
-
count = result_list[1]
|
|
317
|
-
except ClientError:
|
|
318
|
-
raise PydanticCustomError('client_error', _('Unable to get Ground Truth dataset.'))
|
|
319
|
-
return results, count
|
|
320
|
-
|
|
321
|
-
def start(self):
|
|
322
|
-
filters = {'expand': 'data', **self.params['filter']}
|
|
323
|
-
target = self.params['target']
|
|
324
|
-
handler = TargetHandlerFactory.get_handler(target)
|
|
325
|
-
|
|
326
|
-
self.params['results'], self.params['count'] = self.get_filtered_results(filters, handler)
|
|
327
|
-
export_items = handler.get_export_item(self.params['results'])
|
|
328
|
-
|
|
329
|
-
# For the 'ground_truth' target, retrieve project information from the first result and add configuration
|
|
330
|
-
if target == 'ground_truth':
|
|
331
|
-
try:
|
|
332
|
-
first_result = next(iter(self.params['results']))
|
|
333
|
-
project_pk = first_result['project']
|
|
334
|
-
project_info = self.client.get_project(project_pk)
|
|
335
|
-
self.params['configuration'] = project_info.get('configuration', {})
|
|
336
|
-
except StopIteration:
|
|
337
|
-
self.params['configuration'] = {}
|
|
338
|
-
# For the 'assignment' and 'task' targets, retrieve the project from the filter as before
|
|
339
|
-
elif target in ['assignment', 'task'] and 'project' in self.params['filter']:
|
|
340
|
-
project_pk = self.params['filter']['project']
|
|
341
|
-
project_info = self.client.get_project(project_pk)
|
|
342
|
-
self.params['configuration'] = project_info.get('configuration', {})
|
|
343
|
-
|
|
344
|
-
storage = self.client.get_storage(self.params['storage'])
|
|
345
|
-
pathlib_cwd = get_pathlib(storage, self.params['path'])
|
|
346
|
-
return self.entrypoint(self.run, export_items, pathlib_cwd, **self.params)
|
|
@@ -1,151 +0,0 @@
|
|
|
1
|
-
import contextlib
|
|
2
|
-
import subprocess
|
|
3
|
-
from functools import cached_property
|
|
4
|
-
from pathlib import Path
|
|
5
|
-
|
|
6
|
-
from synapse_sdk.plugins.categories.base import Action
|
|
7
|
-
from synapse_sdk.plugins.categories.decorators import register_action
|
|
8
|
-
from synapse_sdk.plugins.enums import PluginCategory, RunMethod
|
|
9
|
-
from synapse_sdk.utils.network import get_available_ports_host
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
@register_action
|
|
13
|
-
class GradioAction(Action):
|
|
14
|
-
name = 'gradio'
|
|
15
|
-
category = PluginCategory.NEURAL_NET
|
|
16
|
-
method = RunMethod.JOB
|
|
17
|
-
|
|
18
|
-
@property
|
|
19
|
-
def working_directory(self):
|
|
20
|
-
dir = Path.cwd() / self.config['directory'].replace('.', '/')
|
|
21
|
-
assert dir.is_dir(), f'Working directory {dir} does not exist.'
|
|
22
|
-
return dir
|
|
23
|
-
|
|
24
|
-
@property
|
|
25
|
-
def requirements_file(self):
|
|
26
|
-
requirements_file = self.working_directory / 'requirements.txt'
|
|
27
|
-
if requirements_file.exists():
|
|
28
|
-
return requirements_file
|
|
29
|
-
|
|
30
|
-
@property
|
|
31
|
-
def tag(self):
|
|
32
|
-
_tag = f'{self.plugin_release.code}-{self.plugin_release.checksum}'
|
|
33
|
-
return _tag.replace('@', '-')
|
|
34
|
-
|
|
35
|
-
@cached_property
|
|
36
|
-
def deploy_port(self):
|
|
37
|
-
return get_available_ports_host()
|
|
38
|
-
|
|
39
|
-
def deploy(self):
|
|
40
|
-
self.run.log('deploy', 'Start deploying')
|
|
41
|
-
|
|
42
|
-
try:
|
|
43
|
-
# Write Dockerfile and requirements.txt
|
|
44
|
-
path_dockerfile = self.write_dockerfile_template()
|
|
45
|
-
self.check_requirements()
|
|
46
|
-
|
|
47
|
-
# Build docker image
|
|
48
|
-
self.build_docker_image(path_dockerfile)
|
|
49
|
-
|
|
50
|
-
# Run docker image
|
|
51
|
-
self.run_docker_image()
|
|
52
|
-
except Exception as e:
|
|
53
|
-
self.run.log('deploy', f'Error: {e}')
|
|
54
|
-
raise e
|
|
55
|
-
|
|
56
|
-
def start(self):
|
|
57
|
-
self.deploy()
|
|
58
|
-
return {'endpoint': f'http://localhost:{self.deploy_port}'}
|
|
59
|
-
|
|
60
|
-
def write_dockerfile_template(self):
|
|
61
|
-
dockerfile_path = self.working_directory / 'Dockerfile'
|
|
62
|
-
|
|
63
|
-
with open(dockerfile_path, 'w') as f:
|
|
64
|
-
f.write("""FROM python:3.12-slim
|
|
65
|
-
WORKDIR /home/user/app
|
|
66
|
-
|
|
67
|
-
RUN pip install --no-cache-dir pip -U && \\
|
|
68
|
-
pip install --no-cache-dir uvicorn
|
|
69
|
-
|
|
70
|
-
RUN apt-get update && \\
|
|
71
|
-
apt-get install -y git nmap ffmpeg libsm6 libxext6 libgl1-mesa-glx && \\
|
|
72
|
-
rm -rf /var/lib/apt/lists/*
|
|
73
|
-
|
|
74
|
-
RUN apt-get update && \\
|
|
75
|
-
apt-get install -y curl && \\
|
|
76
|
-
curl -fsSL https://deb.nodesource.com/setup_22.x | bash - && \\
|
|
77
|
-
apt-get install -y nodejs && \\
|
|
78
|
-
rm -rf /var/lib/apt/lists/* && \\
|
|
79
|
-
apt-get clean
|
|
80
|
-
|
|
81
|
-
COPY requirements_default.txt .
|
|
82
|
-
|
|
83
|
-
COPY requirements.txt .
|
|
84
|
-
|
|
85
|
-
RUN pip install --no-cache-dir -r requirements_default.txt
|
|
86
|
-
|
|
87
|
-
RUN pip install --no-cache-dir -U -r requirements.txt
|
|
88
|
-
|
|
89
|
-
COPY . .
|
|
90
|
-
|
|
91
|
-
EXPOSE 7860
|
|
92
|
-
|
|
93
|
-
CMD ["python", "app.py"]
|
|
94
|
-
""")
|
|
95
|
-
return dockerfile_path
|
|
96
|
-
|
|
97
|
-
def check_requirements(self):
|
|
98
|
-
default_packages = ['gradio', 'synapse-sdk', 'python-nmap']
|
|
99
|
-
with open(self.working_directory / 'requirements_default.txt', 'a') as f:
|
|
100
|
-
f.write('\n' + '\n'.join(default_packages))
|
|
101
|
-
|
|
102
|
-
if self.requirements_file is None:
|
|
103
|
-
with open(self.working_directory / 'requirements.txt', 'a'):
|
|
104
|
-
pass
|
|
105
|
-
|
|
106
|
-
def build_docker_image(self, path_dockerfile):
|
|
107
|
-
self.run.log('deploy', 'Start building docker image')
|
|
108
|
-
result = subprocess.run(
|
|
109
|
-
['docker', 'build', '-t', self.tag, '-f', str(path_dockerfile), '.'],
|
|
110
|
-
cwd=self.working_directory,
|
|
111
|
-
check=True,
|
|
112
|
-
)
|
|
113
|
-
print(result)
|
|
114
|
-
|
|
115
|
-
def run_docker_image(self):
|
|
116
|
-
self.run.log('deploy', 'Start running docker image')
|
|
117
|
-
|
|
118
|
-
# Check for existing container
|
|
119
|
-
self.run.log('deploy', 'Check for existing container')
|
|
120
|
-
with contextlib.suppress(subprocess.CalledProcessError):
|
|
121
|
-
subprocess.run(['docker', 'stop', self.tag], check=True)
|
|
122
|
-
subprocess.run(['docker', 'rm', self.tag], check=True)
|
|
123
|
-
|
|
124
|
-
# Run docker image
|
|
125
|
-
command = [
|
|
126
|
-
'docker',
|
|
127
|
-
'run',
|
|
128
|
-
'-d',
|
|
129
|
-
'--name',
|
|
130
|
-
self.tag,
|
|
131
|
-
'-p',
|
|
132
|
-
f'{self.deploy_port}:7860',
|
|
133
|
-
'-p',
|
|
134
|
-
'8991-8999:8991-8999',
|
|
135
|
-
'--add-host',
|
|
136
|
-
'host.docker.internal:host-gateway',
|
|
137
|
-
'-e',
|
|
138
|
-
'GRADIO_SERVER_NAME=0.0.0.0',
|
|
139
|
-
]
|
|
140
|
-
|
|
141
|
-
# extend synapse env vars
|
|
142
|
-
for key, value in self.envs.items():
|
|
143
|
-
command.extend(['-e', f'{key}={value}'])
|
|
144
|
-
command.append(self.tag)
|
|
145
|
-
|
|
146
|
-
self.run.log('deploy', f'Starting docker container with command: {" ".join(command)}')
|
|
147
|
-
|
|
148
|
-
subprocess.run(
|
|
149
|
-
command,
|
|
150
|
-
check=True,
|
|
151
|
-
)
|