synapse-sdk 1.0.0a38__py3-none-any.whl → 1.0.0a39__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of synapse-sdk might be problematic. Click here for more details.
- synapse_sdk/plugins/categories/neural_net/actions/deployment.py +3 -52
- synapse_sdk/plugins/categories/neural_net/actions/gradio.py +149 -0
- synapse_sdk/utils/file.py +5 -0
- {synapse_sdk-1.0.0a38.dist-info → synapse_sdk-1.0.0a39.dist-info}/METADATA +2 -1
- {synapse_sdk-1.0.0a38.dist-info → synapse_sdk-1.0.0a39.dist-info}/RECORD +9 -8
- {synapse_sdk-1.0.0a38.dist-info → synapse_sdk-1.0.0a39.dist-info}/WHEEL +0 -0
- {synapse_sdk-1.0.0a38.dist-info → synapse_sdk-1.0.0a39.dist-info}/entry_points.txt +0 -0
- {synapse_sdk-1.0.0a38.dist-info → synapse_sdk-1.0.0a39.dist-info}/licenses/LICENSE +0 -0
- {synapse_sdk-1.0.0a38.dist-info → synapse_sdk-1.0.0a39.dist-info}/top_level.txt +0 -0
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
from packaging import version
|
|
2
|
-
|
|
3
1
|
from synapse_sdk.clients.exceptions import ClientError
|
|
4
|
-
from synapse_sdk.i18n import gettext as _
|
|
5
2
|
from synapse_sdk.plugins.categories.base import Action
|
|
6
3
|
from synapse_sdk.plugins.categories.decorators import register_action
|
|
7
4
|
from synapse_sdk.plugins.enums import PluginCategory, RunMethod
|
|
@@ -30,28 +27,9 @@ class DeploymentAction(Action):
|
|
|
30
27
|
|
|
31
28
|
ray_actor_options = self.get_actor_options()
|
|
32
29
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
self.assert_gradio_version()
|
|
37
|
-
|
|
38
|
-
# GradioIngress differs from serve.ingress(app), thus the difference in self.entrypoint callable
|
|
39
|
-
try:
|
|
40
|
-
entrypoint = self.entrypoint().app
|
|
41
|
-
except (TypeError, ImportError):
|
|
42
|
-
raise ClientError(
|
|
43
|
-
400,
|
|
44
|
-
_(
|
|
45
|
-
'Gradio app is not callable.'
|
|
46
|
-
'Please ensure that your Deployment class defines a callable `app` function'
|
|
47
|
-
),
|
|
48
|
-
)
|
|
49
|
-
|
|
50
|
-
deployment = GradioServer.options(ray_actor_options=ray_actor_options).bind(entrypoint)
|
|
51
|
-
else:
|
|
52
|
-
deployment = serve.deployment(ray_actor_options=ray_actor_options)(
|
|
53
|
-
serve.ingress(app)(self.entrypoint)
|
|
54
|
-
).bind(self.envs['SYNAPSE_PLUGIN_RUN_HOST'])
|
|
30
|
+
deployment = serve.deployment(ray_actor_options=ray_actor_options)(serve.ingress(app)(self.entrypoint)).bind(
|
|
31
|
+
self.envs['SYNAPSE_PLUGIN_RUN_HOST']
|
|
32
|
+
)
|
|
55
33
|
|
|
56
34
|
serve.delete(self.plugin_release.code)
|
|
57
35
|
|
|
@@ -78,30 +56,3 @@ class DeploymentAction(Action):
|
|
|
78
56
|
except ClientError:
|
|
79
57
|
pass
|
|
80
58
|
return None
|
|
81
|
-
|
|
82
|
-
@property
|
|
83
|
-
def is_gradio_deployment(self):
|
|
84
|
-
return self.config.get('gradio_app', False)
|
|
85
|
-
|
|
86
|
-
def assert_gradio_version(self):
|
|
87
|
-
"""Assert gradio version is not greater than 3.50.2.
|
|
88
|
-
Ray Serve cannot pickle gradio endpoints, thus gradio version greater than 3.50.2 is not supported (SSE Issues)
|
|
89
|
-
"""
|
|
90
|
-
GRADIO_VERSION_MAX_ALLOWED = '3.50.2'
|
|
91
|
-
|
|
92
|
-
gradio_installed = False
|
|
93
|
-
gradio_version = None
|
|
94
|
-
for req in self.requirements:
|
|
95
|
-
if req.startswith('gradio=='):
|
|
96
|
-
gradio_installed = True
|
|
97
|
-
gradio_version = req.split('==')[1]
|
|
98
|
-
break
|
|
99
|
-
|
|
100
|
-
assert gradio_installed, _(
|
|
101
|
-
'Gradio is not installed or version is not specified. Please install gradio==3.50.2 to use this feature.'
|
|
102
|
-
)
|
|
103
|
-
|
|
104
|
-
if version.parse(gradio_version) > version.parse(GRADIO_VERSION_MAX_ALLOWED):
|
|
105
|
-
raise AssertionError(
|
|
106
|
-
f'Gradio version {gradio_version} is greater than maximum allowed version {GRADIO_VERSION_MAX_ALLOWED}'
|
|
107
|
-
)
|
|
@@ -0,0 +1,149 @@
|
|
|
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
|
+
|
|
10
|
+
|
|
11
|
+
@register_action
|
|
12
|
+
class GradioAction(Action):
|
|
13
|
+
name = 'gradio'
|
|
14
|
+
category = PluginCategory.NEURAL_NET
|
|
15
|
+
method = RunMethod.JOB
|
|
16
|
+
|
|
17
|
+
@property
|
|
18
|
+
def working_directory(self):
|
|
19
|
+
dir = Path.cwd() / self.config['directory'].replace('.', '/')
|
|
20
|
+
assert dir.is_dir(), f'Working directory {dir} does not exist.'
|
|
21
|
+
return dir
|
|
22
|
+
|
|
23
|
+
@property
|
|
24
|
+
def _requirements(self):
|
|
25
|
+
return self.config.get('requirements', ['gradio>=5'])
|
|
26
|
+
|
|
27
|
+
@property
|
|
28
|
+
def tag(self):
|
|
29
|
+
_tag = f'{self.plugin_release.code}-{self.plugin_release.checksum}'
|
|
30
|
+
return _tag.replace('@', '-')
|
|
31
|
+
|
|
32
|
+
@cached_property
|
|
33
|
+
def deploy_port(self):
|
|
34
|
+
return self._get_avail_ports_host()
|
|
35
|
+
|
|
36
|
+
def deploy(self):
|
|
37
|
+
self.run.log('deploy', 'Start deploying')
|
|
38
|
+
|
|
39
|
+
try:
|
|
40
|
+
# Write Dockerfile and requirements.txt
|
|
41
|
+
path_dockerfile = self.write_dockerfile_template()
|
|
42
|
+
self.write_requirements(path_dockerfile.parent / 'requirements.txt')
|
|
43
|
+
|
|
44
|
+
# Build docker image
|
|
45
|
+
self.build_docker_image(path_dockerfile)
|
|
46
|
+
|
|
47
|
+
# Run docker image
|
|
48
|
+
self.run_docker_image()
|
|
49
|
+
except Exception as e:
|
|
50
|
+
self.run.log('deploy', f'Error: {e}')
|
|
51
|
+
raise e
|
|
52
|
+
|
|
53
|
+
def start(self):
|
|
54
|
+
self.deploy()
|
|
55
|
+
return {'endpoint': f'http://localhost:{self.deploy_port}'}
|
|
56
|
+
|
|
57
|
+
def write_dockerfile_template(self):
|
|
58
|
+
dockerfile_path = self.working_directory / 'Dockerfile'
|
|
59
|
+
|
|
60
|
+
with open(dockerfile_path, 'w') as f:
|
|
61
|
+
f.write("""FROM python:3.10
|
|
62
|
+
WORKDIR /home/user/app
|
|
63
|
+
|
|
64
|
+
RUN pip install --no-cache-dir pip -U && \\
|
|
65
|
+
pip install --no-cache-dir uvicorn
|
|
66
|
+
|
|
67
|
+
RUN apt-get update && \\
|
|
68
|
+
apt-get install -y curl && \\
|
|
69
|
+
curl -fsSL https://deb.nodesource.com/setup_22.x | bash - && \\
|
|
70
|
+
apt-get install -y nodejs && \\
|
|
71
|
+
rm -rf /var/lib/apt/lists/* && \\
|
|
72
|
+
apt-get clean
|
|
73
|
+
|
|
74
|
+
COPY . /home/user/app
|
|
75
|
+
|
|
76
|
+
RUN pip install --no-cache-dir -r requirements.txt
|
|
77
|
+
|
|
78
|
+
EXPOSE 7860
|
|
79
|
+
|
|
80
|
+
CMD ["python", "app.py"]
|
|
81
|
+
""")
|
|
82
|
+
return dockerfile_path
|
|
83
|
+
|
|
84
|
+
def write_requirements(self, path):
|
|
85
|
+
with open(path, 'w') as f:
|
|
86
|
+
f.write('\n'.join(self._requirements))
|
|
87
|
+
|
|
88
|
+
def build_docker_image(self, path_dockerfile):
|
|
89
|
+
self.run.log('deploy', 'Start building docker image')
|
|
90
|
+
result = subprocess.run(
|
|
91
|
+
[
|
|
92
|
+
'docker',
|
|
93
|
+
'build',
|
|
94
|
+
'-t',
|
|
95
|
+
self.tag,
|
|
96
|
+
'-f',
|
|
97
|
+
str(path_dockerfile),
|
|
98
|
+
'.',
|
|
99
|
+
],
|
|
100
|
+
cwd=self.working_directory,
|
|
101
|
+
check=True,
|
|
102
|
+
)
|
|
103
|
+
print(result)
|
|
104
|
+
|
|
105
|
+
@staticmethod
|
|
106
|
+
def _get_avail_ports_host(start_port=8900, end_port=8999):
|
|
107
|
+
import nmap
|
|
108
|
+
|
|
109
|
+
nm = nmap.PortScanner()
|
|
110
|
+
|
|
111
|
+
scan_range = f'{start_port}-{end_port}'
|
|
112
|
+
nm.scan(hosts='host.docker.internal', arguments=f'-p {scan_range}')
|
|
113
|
+
|
|
114
|
+
try:
|
|
115
|
+
open_ports = nm['host.docker.internal']['tcp'].keys()
|
|
116
|
+
open_ports = [int(port) for port in open_ports]
|
|
117
|
+
except KeyError:
|
|
118
|
+
open_ports = []
|
|
119
|
+
|
|
120
|
+
for port in range(start_port, end_port + 1):
|
|
121
|
+
if port not in open_ports:
|
|
122
|
+
return port
|
|
123
|
+
|
|
124
|
+
raise IOError(f'No free ports available in range {start_port}-{end_port}')
|
|
125
|
+
|
|
126
|
+
def run_docker_image(self):
|
|
127
|
+
self.run.log('deploy', 'Start running docker image')
|
|
128
|
+
|
|
129
|
+
# Check for existing container
|
|
130
|
+
self.run.log('deploy', 'Check for existing container')
|
|
131
|
+
with contextlib.suppress(subprocess.CalledProcessError):
|
|
132
|
+
subprocess.run(['docker', 'stop', self.tag], check=True)
|
|
133
|
+
subprocess.run(['docker', 'rm', self.tag], check=True)
|
|
134
|
+
|
|
135
|
+
# Run docker image
|
|
136
|
+
self.run.log('deploy', 'Starting docker container')
|
|
137
|
+
subprocess.run(
|
|
138
|
+
[
|
|
139
|
+
'docker',
|
|
140
|
+
'run',
|
|
141
|
+
'-d',
|
|
142
|
+
'--name',
|
|
143
|
+
self.tag,
|
|
144
|
+
'-p',
|
|
145
|
+
f'{self.deploy_port}:7860',
|
|
146
|
+
self.tag,
|
|
147
|
+
],
|
|
148
|
+
check=True,
|
|
149
|
+
)
|
synapse_sdk/utils/file.py
CHANGED
|
@@ -4,6 +4,7 @@ import hashlib
|
|
|
4
4
|
import json
|
|
5
5
|
import mimetypes
|
|
6
6
|
import operator
|
|
7
|
+
import re
|
|
7
8
|
import zipfile
|
|
8
9
|
from functools import reduce
|
|
9
10
|
from pathlib import Path
|
|
@@ -197,6 +198,10 @@ def convert_file_to_base64(file_path):
|
|
|
197
198
|
Returns:
|
|
198
199
|
str: Base64 encoded string of the file contents
|
|
199
200
|
"""
|
|
201
|
+
# FIXME base64 is sent sometimes.
|
|
202
|
+
if file_path.startswith('data:'):
|
|
203
|
+
return file_path
|
|
204
|
+
|
|
200
205
|
# Convert string path to Path object
|
|
201
206
|
path = Path(file_path)
|
|
202
207
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: synapse-sdk
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.0a39
|
|
4
4
|
Summary: synapse sdk
|
|
5
5
|
Author-email: datamaker <developer@datamaker.io>
|
|
6
6
|
License: MIT
|
|
@@ -21,6 +21,7 @@ Requires-Dist: universal-pathlib
|
|
|
21
21
|
Requires-Dist: fsspec[gcs,s3,sftp]
|
|
22
22
|
Provides-Extra: all
|
|
23
23
|
Requires-Dist: ray[all]; extra == "all"
|
|
24
|
+
Requires-Dist: python-nmap; extra == "all"
|
|
24
25
|
Dynamic: license-file
|
|
25
26
|
|
|
26
27
|
This is the SDK to develop synapse plugins
|
|
@@ -67,7 +67,8 @@ synapse_sdk/plugins/categories/export/templates/plugin/__init__.py,sha256=47DEQp
|
|
|
67
67
|
synapse_sdk/plugins/categories/export/templates/plugin/export.py,sha256=39XLGo8ui5FscbwZyX3JwmrJqGGvOYrY3FMYDKXwTOQ,5192
|
|
68
68
|
synapse_sdk/plugins/categories/neural_net/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
69
69
|
synapse_sdk/plugins/categories/neural_net/actions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
70
|
-
synapse_sdk/plugins/categories/neural_net/actions/deployment.py,sha256=
|
|
70
|
+
synapse_sdk/plugins/categories/neural_net/actions/deployment.py,sha256=y2LrS-pwazqRI5O0q1NUy45NQYsBj6ykbrXnDMs_fqE,1987
|
|
71
|
+
synapse_sdk/plugins/categories/neural_net/actions/gradio.py,sha256=Tb9vHZAmUXEi1Hp1CIn_XP4URERVuLGHOiQrlPztjy8,4326
|
|
71
72
|
synapse_sdk/plugins/categories/neural_net/actions/inference.py,sha256=0a655ELqNVjPFZTJDiw4EUdcMCPGveUEKyoYqpwMFBU,1019
|
|
72
73
|
synapse_sdk/plugins/categories/neural_net/actions/test.py,sha256=JY25eg-Fo6WbgtMkGoo_qNqoaZkp3AQNEypJmeGzEog,320
|
|
73
74
|
synapse_sdk/plugins/categories/neural_net/actions/train.py,sha256=kve6iTCg2kUeavMQTR2JFuoYDu-QWZFFlB58ZICQtdM,5406
|
|
@@ -118,7 +119,7 @@ synapse_sdk/shared/enums.py,sha256=WMZPag9deVF7VCXaQkLk7ly_uX1KwbNzRx9TdvgaeFE,1
|
|
|
118
119
|
synapse_sdk/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
119
120
|
synapse_sdk/utils/dataset.py,sha256=zWTzFmv589izFr62BDuApi3r5FpTsdm-5AmriC0AEdM,1865
|
|
120
121
|
synapse_sdk/utils/debug.py,sha256=F7JlUwYjTFZAMRbBqKm6hxOIz-_IXYA8lBInOS4jbS4,100
|
|
121
|
-
synapse_sdk/utils/file.py,sha256=
|
|
122
|
+
synapse_sdk/utils/file.py,sha256=Wu8ixvEHglNXCVxT-vZTt7vUFkAAK1M1EJSk89P_3FQ,6844
|
|
122
123
|
synapse_sdk/utils/module_loading.py,sha256=chHpU-BZjtYaTBD_q0T7LcKWtqKvYBS4L0lPlKkoMQ8,1020
|
|
123
124
|
synapse_sdk/utils/network.py,sha256=wg-oFM0gKK5REqIUO8d-x9yXJfqbnkSbbF0_qyxpwz4,412
|
|
124
125
|
synapse_sdk/utils/string.py,sha256=rEwuZ9SAaZLcQ8TYiwNKr1h2u4CfnrQx7SUL8NWmChg,216
|
|
@@ -132,9 +133,9 @@ synapse_sdk/utils/storage/providers/__init__.py,sha256=x7RGwZryT2FpVxS7fGWryRVpq
|
|
|
132
133
|
synapse_sdk/utils/storage/providers/gcp.py,sha256=i2BQCu1Kej1If9SuNr2_lEyTcr5M_ncGITZrL0u5wEA,363
|
|
133
134
|
synapse_sdk/utils/storage/providers/s3.py,sha256=W94rQvhGRXti3R4mYP7gmU5pcyCQpGFIBLvxxqLVdRM,2231
|
|
134
135
|
synapse_sdk/utils/storage/providers/sftp.py,sha256=_8s9hf0JXIO21gvm-JVS00FbLsbtvly4c-ETLRax68A,1426
|
|
135
|
-
synapse_sdk-1.0.
|
|
136
|
-
synapse_sdk-1.0.
|
|
137
|
-
synapse_sdk-1.0.
|
|
138
|
-
synapse_sdk-1.0.
|
|
139
|
-
synapse_sdk-1.0.
|
|
140
|
-
synapse_sdk-1.0.
|
|
136
|
+
synapse_sdk-1.0.0a39.dist-info/licenses/LICENSE,sha256=bKzmC5YAg4V1Fhl8OO_tqY8j62hgdncAkN7VrdjmrGk,1101
|
|
137
|
+
synapse_sdk-1.0.0a39.dist-info/METADATA,sha256=KiYa0ezmc90xuDLUMsnMSGoLQoskOtwsKBR1Fp4dbDY,1203
|
|
138
|
+
synapse_sdk-1.0.0a39.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
|
|
139
|
+
synapse_sdk-1.0.0a39.dist-info/entry_points.txt,sha256=VNptJoGoNJI8yLXfBmhgUefMsmGI0m3-0YoMvrOgbxo,48
|
|
140
|
+
synapse_sdk-1.0.0a39.dist-info/top_level.txt,sha256=ytgJMRK1slVOKUpgcw3LEyHHP7S34J6n_gJzdkcSsw8,12
|
|
141
|
+
synapse_sdk-1.0.0a39.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|