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.

@@ -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
- if self.is_gradio_deployment:
34
- from ray.serve.gradio_integrations import GradioServer
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.0a38
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=oetIwZoee5vxriPX3r1onmxgwojUyaRTlnBIdaQ1zk8,3895
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=Qb5FihoX1J0wsF2UAckc0d0c3IMHn0NrX9Vt3cXAwt4,6732
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.0a38.dist-info/licenses/LICENSE,sha256=bKzmC5YAg4V1Fhl8OO_tqY8j62hgdncAkN7VrdjmrGk,1101
136
- synapse_sdk-1.0.0a38.dist-info/METADATA,sha256=GxLFIbbXbVYUjusRE7MAZefelK_XNYz0oGTOOCNuybU,1160
137
- synapse_sdk-1.0.0a38.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
138
- synapse_sdk-1.0.0a38.dist-info/entry_points.txt,sha256=VNptJoGoNJI8yLXfBmhgUefMsmGI0m3-0YoMvrOgbxo,48
139
- synapse_sdk-1.0.0a38.dist-info/top_level.txt,sha256=ytgJMRK1slVOKUpgcw3LEyHHP7S34J6n_gJzdkcSsw8,12
140
- synapse_sdk-1.0.0a38.dist-info/RECORD,,
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,,