synapse-sdk 1.0.0a60__py3-none-any.whl → 1.0.0a62__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/cli/__init__.py +26 -19
- synapse_sdk/cli/devtools.py +18 -9
- synapse_sdk/devtools/config.py +1 -1
- synapse_sdk/devtools/server.py +40 -42
- synapse_sdk/devtools/utils.py +52 -0
- synapse_sdk/devtools/web/dist/index.html +2 -2
- synapse_sdk/devtools/web/src/components/LogViewer.jsx +15 -1
- synapse_sdk/devtools/web/src/components/NavigationSidebar.jsx +4 -13
- synapse_sdk/devtools/web/src/utils/api.js +23 -6
- synapse_sdk/plugins/categories/neural_net/templates/config.yaml +15 -3
- synapse_sdk/plugins/categories/neural_net/templates/plugin/inference.py +26 -10
- {synapse_sdk-1.0.0a60.dist-info → synapse_sdk-1.0.0a62.dist-info}/METADATA +1 -1
- {synapse_sdk-1.0.0a60.dist-info → synapse_sdk-1.0.0a62.dist-info}/RECORD +17 -16
- {synapse_sdk-1.0.0a60.dist-info → synapse_sdk-1.0.0a62.dist-info}/WHEEL +0 -0
- {synapse_sdk-1.0.0a60.dist-info → synapse_sdk-1.0.0a62.dist-info}/entry_points.txt +0 -0
- {synapse_sdk-1.0.0a60.dist-info → synapse_sdk-1.0.0a62.dist-info}/licenses/LICENSE +0 -0
- {synapse_sdk-1.0.0a60.dist-info → synapse_sdk-1.0.0a62.dist-info}/top_level.txt +0 -0
synapse_sdk/cli/__init__.py
CHANGED
|
@@ -106,18 +106,36 @@ def display_connection_status():
|
|
|
106
106
|
click.echo() # Empty line for spacing
|
|
107
107
|
|
|
108
108
|
|
|
109
|
-
def run_devtools(build=
|
|
109
|
+
def run_devtools(build=True):
|
|
110
110
|
"""Run devtools with default settings"""
|
|
111
111
|
try:
|
|
112
|
+
from synapse_sdk.devtools.config import get_server_config
|
|
112
113
|
from synapse_sdk.devtools.server import create_devtools_server
|
|
114
|
+
from synapse_sdk.devtools.utils import find_available_port, is_port_available
|
|
113
115
|
|
|
114
116
|
if build:
|
|
115
|
-
click.echo('Building
|
|
117
|
+
click.echo('Building...')
|
|
116
118
|
build_frontend()
|
|
117
119
|
|
|
118
120
|
click.echo('Starting Synapse Devtools...')
|
|
119
|
-
|
|
120
|
-
server
|
|
121
|
+
|
|
122
|
+
# Get server configuration defaults
|
|
123
|
+
server_config = get_server_config()
|
|
124
|
+
host = server_config['host']
|
|
125
|
+
port = server_config['port']
|
|
126
|
+
|
|
127
|
+
# Check if the port is available, fallback to next available port if not
|
|
128
|
+
if not is_port_available(host, port):
|
|
129
|
+
try:
|
|
130
|
+
fallback_port = find_available_port(host, port + 1)
|
|
131
|
+
click.echo(click.style(f'Port {port} is in use, falling back to port {fallback_port}', fg='yellow'))
|
|
132
|
+
port = fallback_port
|
|
133
|
+
except RuntimeError as e:
|
|
134
|
+
click.echo(click.style(f'Failed to find available port: {e}', fg='red'), err=True)
|
|
135
|
+
return
|
|
136
|
+
|
|
137
|
+
server = create_devtools_server(host=host, port=port)
|
|
138
|
+
server.start_server()
|
|
121
139
|
except ImportError:
|
|
122
140
|
click.echo(
|
|
123
141
|
click.style(
|
|
@@ -153,21 +171,20 @@ def build_frontend():
|
|
|
153
171
|
try:
|
|
154
172
|
# Install dependencies if node_modules doesn't exist
|
|
155
173
|
if not (devtools_dir / 'node_modules').exists():
|
|
156
|
-
click.echo('Installing
|
|
174
|
+
click.echo('Installing dependencies...')
|
|
157
175
|
result = subprocess.run(['npm', 'install'], cwd=devtools_dir, capture_output=True, text=True)
|
|
158
176
|
if result.returncode != 0:
|
|
159
177
|
click.echo(click.style(f'npm install failed:\n{result.stderr}', fg='red'), err=True)
|
|
160
178
|
return False
|
|
161
179
|
|
|
162
180
|
# Build the frontend
|
|
163
|
-
click.echo('Building frontend...')
|
|
164
181
|
result = subprocess.run(['npm', 'run', 'build'], cwd=devtools_dir, capture_output=True, text=True)
|
|
165
182
|
|
|
166
183
|
if result.returncode != 0:
|
|
167
184
|
click.echo(click.style(f'Frontend build failed:\n{result.stderr}', fg='red'), err=True)
|
|
168
185
|
return False
|
|
169
186
|
|
|
170
|
-
click.echo(click.style('
|
|
187
|
+
click.echo(click.style('Build completed successfully!', fg='green'))
|
|
171
188
|
return True
|
|
172
189
|
|
|
173
190
|
except Exception as e:
|
|
@@ -184,23 +201,13 @@ def run_config():
|
|
|
184
201
|
|
|
185
202
|
@click.group(invoke_without_command=True)
|
|
186
203
|
@click.option('--dev-tools', is_flag=True, help='Start devtools immediately')
|
|
187
|
-
@click.option('--build', is_flag=True, help='Build frontend before starting devtools (only with --dev-tools)')
|
|
188
204
|
@click.pass_context
|
|
189
|
-
def cli(ctx, dev_tools
|
|
205
|
+
def cli(ctx, dev_tools):
|
|
190
206
|
"""Synapse SDK - Interactive CLI"""
|
|
191
207
|
|
|
192
208
|
# Handle --dev-tools flag
|
|
193
209
|
if dev_tools:
|
|
194
|
-
|
|
195
|
-
run_devtools(build=True)
|
|
196
|
-
else:
|
|
197
|
-
run_devtools(build=False)
|
|
198
|
-
return
|
|
199
|
-
|
|
200
|
-
# Handle --build flag without --dev-tools (show warning)
|
|
201
|
-
if build and not dev_tools:
|
|
202
|
-
click.echo(click.style('Warning: --build flag requires --dev-tools flag', fg='yellow'))
|
|
203
|
-
click.echo('Use: synapse --dev-tools --build')
|
|
210
|
+
run_devtools()
|
|
204
211
|
return
|
|
205
212
|
|
|
206
213
|
if ctx.invoked_subcommand is None:
|
synapse_sdk/cli/devtools.py
CHANGED
|
@@ -9,15 +9,15 @@ from synapse_sdk.i18n import gettext as _
|
|
|
9
9
|
@click.command()
|
|
10
10
|
@click.option('--host', default=None, help='Host to bind the devtools server')
|
|
11
11
|
@click.option('--port', default=None, type=int, help='Port to bind the devtools server')
|
|
12
|
-
@click.option('--no-browser', is_flag=True, help='Do not open browser automatically')
|
|
13
12
|
@click.option('--debug', is_flag=True, help='Run in debug mode')
|
|
14
|
-
|
|
15
|
-
def devtools(host, port, no_browser, debug, build):
|
|
13
|
+
def devtools(host, port, debug):
|
|
16
14
|
"""Start the Synapse devtools web interface"""
|
|
17
15
|
|
|
18
16
|
try:
|
|
19
17
|
from synapse_sdk.devtools.config import get_server_config
|
|
20
18
|
from synapse_sdk.devtools.server import create_devtools_server
|
|
19
|
+
from synapse_sdk.devtools.utils import find_available_port, is_port_available
|
|
20
|
+
|
|
21
21
|
except ImportError:
|
|
22
22
|
click.echo(
|
|
23
23
|
click.style(
|
|
@@ -27,12 +27,11 @@ def devtools(host, port, no_browser, debug, build):
|
|
|
27
27
|
)
|
|
28
28
|
sys.exit(1)
|
|
29
29
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
from synapse_sdk.cli import build_frontend
|
|
30
|
+
click.echo('Building assets...')
|
|
31
|
+
from synapse_sdk.cli import build_frontend
|
|
33
32
|
|
|
34
|
-
|
|
35
|
-
|
|
33
|
+
if not build_frontend():
|
|
34
|
+
click.echo(click.style('Build failed, continuing with existing assets...', fg='yellow'))
|
|
36
35
|
|
|
37
36
|
if debug:
|
|
38
37
|
click.echo(_('Starting devtools in debug mode...'))
|
|
@@ -47,13 +46,23 @@ def devtools(host, port, no_browser, debug, build):
|
|
|
47
46
|
final_host = host if host is not None else server_config['host']
|
|
48
47
|
final_port = port if port is not None else server_config['port']
|
|
49
48
|
|
|
49
|
+
# Check if the port is available, fallback to next available port if not
|
|
50
|
+
if not is_port_available(final_host, final_port):
|
|
51
|
+
try:
|
|
52
|
+
fallback_port = find_available_port(final_host, final_port + 1)
|
|
53
|
+
click.echo(click.style(f'Port {final_port} is in use, falling back to port {fallback_port}', fg='yellow'))
|
|
54
|
+
final_port = fallback_port
|
|
55
|
+
except RuntimeError as e:
|
|
56
|
+
click.echo(click.style(f'Failed to find available port: {e}', fg='red'), err=True)
|
|
57
|
+
sys.exit(1)
|
|
58
|
+
|
|
50
59
|
# Create and start the devtools server
|
|
51
60
|
# Pass the current working directory as the plugin directory
|
|
52
61
|
plugin_directory = os.getcwd()
|
|
53
62
|
server = create_devtools_server(host=final_host, port=final_port, plugin_directory=plugin_directory)
|
|
54
63
|
|
|
55
64
|
try:
|
|
56
|
-
server.start_server(
|
|
65
|
+
server.start_server()
|
|
57
66
|
except KeyboardInterrupt:
|
|
58
67
|
click.echo(_('\nDevtools stopped.'))
|
|
59
68
|
except Exception as e:
|
synapse_sdk/devtools/config.py
CHANGED
|
@@ -76,7 +76,7 @@ def get_server_config() -> Dict:
|
|
|
76
76
|
config = load_devtools_config()
|
|
77
77
|
server = config.get('server', {})
|
|
78
78
|
|
|
79
|
-
return {'host': server.get('host', '
|
|
79
|
+
return {'host': server.get('host', '0.0.0.0'), 'port': server.get('port', 8080)}
|
|
80
80
|
|
|
81
81
|
|
|
82
82
|
def set_server_config(host: str = None, port: int = None):
|
synapse_sdk/devtools/server.py
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import json
|
|
2
2
|
import logging
|
|
3
|
-
import webbrowser
|
|
4
3
|
from contextlib import asynccontextmanager
|
|
5
4
|
from datetime import datetime
|
|
6
5
|
from importlib.metadata import version
|
|
@@ -20,12 +19,13 @@ from synapse_sdk.clients.backend import BackendClient
|
|
|
20
19
|
from synapse_sdk.clients.exceptions import ClientError
|
|
21
20
|
from synapse_sdk.devtools.config import get_backend_config, load_devtools_config
|
|
22
21
|
from synapse_sdk.devtools.models import ConfigResponse, ConfigUpdateRequest
|
|
22
|
+
from synapse_sdk.devtools.utils import get_display_host
|
|
23
23
|
|
|
24
24
|
logger = logging.getLogger(__name__)
|
|
25
25
|
|
|
26
26
|
|
|
27
27
|
class DevtoolsServer:
|
|
28
|
-
def __init__(self, host: str = '
|
|
28
|
+
def __init__(self, host: str = '0.0.0.0', port: int = 8080, plugin_directory: str = None):
|
|
29
29
|
self.host = host
|
|
30
30
|
self.port = port
|
|
31
31
|
|
|
@@ -263,9 +263,11 @@ class DevtoolsServer:
|
|
|
263
263
|
|
|
264
264
|
def _inject_env_vars(self, html_content: str) -> str:
|
|
265
265
|
"""Inject environment variables into HTML"""
|
|
266
|
+
# Use display host for frontend access (resolves 0.0.0.0 to actual IP)
|
|
267
|
+
display_host = get_display_host(self.host)
|
|
266
268
|
env_script = f"""<script>
|
|
267
269
|
window.VITE_API_PORT = {self.port};
|
|
268
|
-
window.VITE_API_HOST = '{
|
|
270
|
+
window.VITE_API_HOST = '{display_host}';
|
|
269
271
|
</script>"""
|
|
270
272
|
|
|
271
273
|
# Insert before closing head tag
|
|
@@ -360,14 +362,38 @@ class DevtoolsServer:
|
|
|
360
362
|
raise HTTPException(status_code=503, detail='Agent client not configured')
|
|
361
363
|
|
|
362
364
|
async def log_generator():
|
|
365
|
+
import asyncio
|
|
366
|
+
|
|
363
367
|
try:
|
|
364
|
-
#
|
|
365
|
-
|
|
366
|
-
|
|
368
|
+
# Run the synchronous generator in a thread to avoid blocking
|
|
369
|
+
loop = asyncio.get_event_loop()
|
|
370
|
+
log_iter = self.agent_client.tail_job_logs(job_id, stream_timeout=3)
|
|
371
|
+
|
|
372
|
+
while True:
|
|
373
|
+
# Check if client disconnected before getting next log
|
|
367
374
|
if await request.is_disconnected():
|
|
368
375
|
logger.info(f'Client disconnected, stopping log stream for job {job_id}')
|
|
369
376
|
break
|
|
370
|
-
|
|
377
|
+
|
|
378
|
+
try:
|
|
379
|
+
# Get next log line with timeout to allow periodic disconnect checks
|
|
380
|
+
log_line = await loop.run_in_executor(None, lambda: next(log_iter, None))
|
|
381
|
+
|
|
382
|
+
if log_line is None:
|
|
383
|
+
break
|
|
384
|
+
|
|
385
|
+
# Check again before yielding
|
|
386
|
+
if await request.is_disconnected():
|
|
387
|
+
logger.info(f'Client disconnected before yield, stopping log stream for job {job_id}')
|
|
388
|
+
break
|
|
389
|
+
|
|
390
|
+
# Convert plain text to SSE format
|
|
391
|
+
if log_line.strip():
|
|
392
|
+
yield f'data: {log_line.strip()}\n\n'
|
|
393
|
+
|
|
394
|
+
except StopIteration:
|
|
395
|
+
break
|
|
396
|
+
|
|
371
397
|
except ClientError as e:
|
|
372
398
|
logger.warning(f'Agent client error in log streaming for job {job_id}: {e.reason}')
|
|
373
399
|
if e.status == 408:
|
|
@@ -383,7 +409,7 @@ class DevtoolsServer:
|
|
|
383
409
|
logger.info(f'Log streaming ended for job {job_id}')
|
|
384
410
|
|
|
385
411
|
try:
|
|
386
|
-
return StreamingResponse(log_generator(), media_type='text/
|
|
412
|
+
return StreamingResponse(log_generator(), media_type='text/event-stream')
|
|
387
413
|
except Exception as e:
|
|
388
414
|
logger.error(f'Failed to setup log stream for job {job_id}: {e}')
|
|
389
415
|
raise HTTPException(status_code=500, detail=f'Failed to setup log stream for job {job_id}')
|
|
@@ -786,44 +812,16 @@ class DevtoolsServer:
|
|
|
786
812
|
self.websocket_connections.remove(connection)
|
|
787
813
|
logger.info('Removed disconnected WebSocket connection')
|
|
788
814
|
|
|
789
|
-
def start_server(self
|
|
815
|
+
def start_server(self):
|
|
790
816
|
"""Start the devtools server"""
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
def open_browser_delayed():
|
|
796
|
-
import os
|
|
797
|
-
import time
|
|
798
|
-
|
|
799
|
-
time.sleep(1.5)
|
|
800
|
-
|
|
801
|
-
try:
|
|
802
|
-
# Redirect stderr to suppress xdg-open error messages
|
|
803
|
-
old_stderr = os.dup(2)
|
|
804
|
-
with open(os.devnull, 'w') as devnull:
|
|
805
|
-
os.dup2(devnull.fileno(), 2)
|
|
806
|
-
webbrowser.open(url)
|
|
807
|
-
os.dup2(old_stderr, 2)
|
|
808
|
-
os.close(old_stderr)
|
|
809
|
-
except Exception:
|
|
810
|
-
# Restore stderr if something went wrong
|
|
811
|
-
try:
|
|
812
|
-
os.dup2(old_stderr, 2)
|
|
813
|
-
os.close(old_stderr)
|
|
814
|
-
except Exception as e:
|
|
815
|
-
logger.error(f'Failed to restore stderr: {e}')
|
|
816
|
-
|
|
817
|
-
# Always show the URL since we can't reliably detect browser success
|
|
818
|
-
print(f'Open devtools on your browser: {url}')
|
|
819
|
-
|
|
820
|
-
import threading
|
|
821
|
-
|
|
822
|
-
threading.Thread(target=open_browser_delayed, daemon=True).start()
|
|
817
|
+
# Use display host for browser opening and URL display
|
|
818
|
+
display_host = get_display_host(self.host)
|
|
819
|
+
url = f'http://{display_host}:{self.port}'
|
|
820
|
+
print(f'Open devtools on your browser: {url}')
|
|
823
821
|
|
|
824
822
|
uvicorn.run(self.app, host=self.host, port=self.port, log_level='warning', access_log=False)
|
|
825
823
|
|
|
826
824
|
|
|
827
|
-
def create_devtools_server(host: str = '
|
|
825
|
+
def create_devtools_server(host: str = '0.0.0.0', port: int = 8080, plugin_directory: str = None) -> DevtoolsServer:
|
|
828
826
|
"""Factory function to create a devtools server instance"""
|
|
829
827
|
return DevtoolsServer(host=host, port=port, plugin_directory=plugin_directory)
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import socket
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def is_port_available(host: str, port: int) -> bool:
|
|
5
|
+
"""Check if a port is available on the given host"""
|
|
6
|
+
try:
|
|
7
|
+
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
|
|
8
|
+
sock.settimeout(1)
|
|
9
|
+
result = sock.connect_ex((host, port))
|
|
10
|
+
return result != 0
|
|
11
|
+
except (socket.error, OSError):
|
|
12
|
+
return False
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def find_available_port(host: str, start_port: int, max_attempts: int = 10) -> int:
|
|
16
|
+
"""Find an available port starting from start_port"""
|
|
17
|
+
for port in range(start_port, start_port + max_attempts):
|
|
18
|
+
if is_port_available(host, port):
|
|
19
|
+
return port
|
|
20
|
+
raise RuntimeError(f'No available port found in range {start_port}-{start_port + max_attempts - 1}')
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def get_local_ip() -> str:
|
|
24
|
+
"""Get the local IP address for client access"""
|
|
25
|
+
try:
|
|
26
|
+
# In WSL, return localhost since the server is accessible via localhost
|
|
27
|
+
if _is_wsl():
|
|
28
|
+
return '127.0.0.1'
|
|
29
|
+
|
|
30
|
+
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s:
|
|
31
|
+
s.connect(('8.8.8.8', 80))
|
|
32
|
+
return s.getsockname()[0]
|
|
33
|
+
except Exception:
|
|
34
|
+
# Fallback to localhost if we can't determine the local IP
|
|
35
|
+
return '127.0.0.1'
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def _is_wsl() -> bool:
|
|
39
|
+
"""Check if we're running in WSL"""
|
|
40
|
+
try:
|
|
41
|
+
with open('/proc/version', 'r') as f:
|
|
42
|
+
content = f.read().lower()
|
|
43
|
+
return 'microsoft' in content or 'wsl' in content
|
|
44
|
+
except Exception:
|
|
45
|
+
return False
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def get_display_host(server_host: str) -> str:
|
|
49
|
+
"""Get the appropriate host for display and frontend access"""
|
|
50
|
+
if server_host == '0.0.0.0':
|
|
51
|
+
return get_local_ip()
|
|
52
|
+
return server_host
|
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
<meta name="theme-color" content="#000000" />
|
|
7
7
|
<link rel="shortcut icon" type="image/ico" href="/assets/favicon-mtvwWgEY.ico" />
|
|
8
8
|
<title>Synapse SDK</title>
|
|
9
|
-
<script type="module" crossorigin src="/assets/index-
|
|
10
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
9
|
+
<script type="module" crossorigin src="/assets/index-C-6muTAU.js"></script>
|
|
10
|
+
<link rel="stylesheet" crossorigin href="/assets/index-DaWyc9aY.css">
|
|
11
11
|
</head>
|
|
12
12
|
<body>
|
|
13
13
|
<noscript>You need to enable JavaScript to run this app.</noscript>
|
|
@@ -186,6 +186,10 @@ export default function LogViewer(props) {
|
|
|
186
186
|
startStreaming();
|
|
187
187
|
});
|
|
188
188
|
|
|
189
|
+
onCleanup(() => {
|
|
190
|
+
stopStreaming();
|
|
191
|
+
});
|
|
192
|
+
|
|
189
193
|
return (
|
|
190
194
|
<div class="github-log-viewer">
|
|
191
195
|
{/* Header */}
|
|
@@ -208,9 +212,19 @@ export default function LogViewer(props) {
|
|
|
208
212
|
</div>
|
|
209
213
|
</div>
|
|
210
214
|
|
|
215
|
+
{/* Error State */}
|
|
216
|
+
<Show when={error()}>
|
|
217
|
+
<div class="alert alert-error mb-2">
|
|
218
|
+
<svg xmlns="http://www.w3.org/2000/svg" class="stroke-current shrink-0 h-6 w-6" fill="none" viewBox="0 0 24 24">
|
|
219
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z" />
|
|
220
|
+
</svg>
|
|
221
|
+
<span>{error()}</span>
|
|
222
|
+
</div>
|
|
223
|
+
</Show>
|
|
224
|
+
|
|
211
225
|
{/* Container */}
|
|
212
226
|
<div class="log-container" ref={logContainerRef} onScroll={handleScroll}>
|
|
213
|
-
<Show when={logs().length === 0}>
|
|
227
|
+
<Show when={logs().length === 0 && !error()}>
|
|
214
228
|
<div class="log-empty">
|
|
215
229
|
<div class="empty-state">
|
|
216
230
|
<svg class="empty-icon" viewBox="0 0 24 24" width="24" height="24">
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useLocation, useNavigate } from "@solidjs/router";
|
|
2
2
|
import { createSignal, Show } from "solid-js";
|
|
3
|
-
import {
|
|
3
|
+
import { MenuIcon, CloseIcon, DocumentIcon } from "./icons";
|
|
4
4
|
import { createStatusResource } from "../utils/api";
|
|
5
5
|
|
|
6
6
|
export default function NavigationSidebar() {
|
|
@@ -15,23 +15,17 @@ export default function NavigationSidebar() {
|
|
|
15
15
|
{
|
|
16
16
|
id: "home",
|
|
17
17
|
label: "Jobs",
|
|
18
|
-
icon: HomeIcon,
|
|
19
18
|
path: "/",
|
|
20
|
-
description: "View and manage Ray jobs"
|
|
21
19
|
},
|
|
22
20
|
{
|
|
23
21
|
id: "applications",
|
|
24
|
-
label: "Serve
|
|
25
|
-
icon: CubeIcon,
|
|
22
|
+
label: "Serve Application",
|
|
26
23
|
path: "/serve_applications",
|
|
27
|
-
description: "Ray Serve applications"
|
|
28
24
|
},
|
|
29
25
|
{
|
|
30
26
|
id: "plugin",
|
|
31
|
-
label: "Plugin
|
|
32
|
-
icon: SettingsIcon,
|
|
27
|
+
label: "Plugin",
|
|
33
28
|
path: "/plugin",
|
|
34
|
-
description: "Develop and test plugins"
|
|
35
29
|
}
|
|
36
30
|
];
|
|
37
31
|
|
|
@@ -89,7 +83,6 @@ export default function NavigationSidebar() {
|
|
|
89
83
|
<nav class="flex-1 p-6 py-8 overflow-y-auto">
|
|
90
84
|
<ul class="space-y-2">
|
|
91
85
|
{navigationItems.map((item) => {
|
|
92
|
-
const Icon = item.icon;
|
|
93
86
|
const active = isActive(item.path);
|
|
94
87
|
|
|
95
88
|
return (
|
|
@@ -102,10 +95,8 @@ export default function NavigationSidebar() {
|
|
|
102
95
|
}`}
|
|
103
96
|
onClick={() => handleNavigation(item.path)}
|
|
104
97
|
>
|
|
105
|
-
<Icon class="w-5 h-5 flex-shrink-0" />
|
|
106
98
|
<div class="flex-1 min-w-0">
|
|
107
99
|
<div class="text-sm font-medium">{item.label}</div>
|
|
108
|
-
<div class="text-xs text-slate-500 truncate">{item.description}</div>
|
|
109
100
|
</div>
|
|
110
101
|
</button>
|
|
111
102
|
</li>
|
|
@@ -120,7 +111,7 @@ export default function NavigationSidebar() {
|
|
|
120
111
|
<div class="flex items-center justify-between">
|
|
121
112
|
<span>SDK {status()?.devtools?.version || "Unknown"}</span>
|
|
122
113
|
<a
|
|
123
|
-
href="https://docs.synapse.
|
|
114
|
+
href="https://docs.synapse.sh"
|
|
124
115
|
target="_blank"
|
|
125
116
|
rel="noopener noreferrer"
|
|
126
117
|
class="text-slate-600 hover:text-slate-900"
|
|
@@ -333,12 +333,29 @@ export function createJobLogsStream(jobId) {
|
|
|
333
333
|
const lines = buffer.split(/\r?\n/);
|
|
334
334
|
buffer = lines.pop() || "";
|
|
335
335
|
|
|
336
|
-
const
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
336
|
+
for (const line of lines) {
|
|
337
|
+
if (!line.trim()) continue;
|
|
338
|
+
|
|
339
|
+
// Handle SSE format (data: prefix)
|
|
340
|
+
if (line.startsWith('data: ')) {
|
|
341
|
+
const content = line.substring(6).trim();
|
|
342
|
+
|
|
343
|
+
// Check if this is an error message from the server
|
|
344
|
+
if (content.includes('Agent client error') ||
|
|
345
|
+
content.includes('Agent connection error') ||
|
|
346
|
+
content.includes('Agent error:') ||
|
|
347
|
+
content.includes('Unexpected error:')) {
|
|
348
|
+
setError(content);
|
|
349
|
+
// Still add as a log entry so user can see the error
|
|
350
|
+
setLogs(prev => [...prev, parseLogLine(content)]);
|
|
351
|
+
} else {
|
|
352
|
+
// Normal log line
|
|
353
|
+
setLogs(prev => [...prev, parseLogLine(content)]);
|
|
354
|
+
}
|
|
355
|
+
} else {
|
|
356
|
+
// Handle non-SSE format (backward compatibility)
|
|
357
|
+
setLogs(prev => [...prev, parseLogLine(line)]);
|
|
358
|
+
}
|
|
342
359
|
}
|
|
343
360
|
}
|
|
344
361
|
|
|
@@ -13,12 +13,24 @@ actions:
|
|
|
13
13
|
dataset: dataset
|
|
14
14
|
entrypoint: plugin.train.train
|
|
15
15
|
metrics:
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
train:
|
|
17
|
+
epoch:
|
|
18
|
+
loss: # Use the plugin's internal variable as the key, and the user-facing title in name.
|
|
19
|
+
name: Loss
|
|
20
|
+
validation:
|
|
21
|
+
epoch:
|
|
22
|
+
acc:
|
|
23
|
+
name: Accuracy
|
|
19
24
|
hyperparameters:
|
|
20
25
|
ui_schema: |
|
|
21
26
|
Dumped FormKit Schema for hyperparameters
|
|
27
|
+
visualizations:
|
|
28
|
+
validation_samples_per_epochs: # put in log_visualization name
|
|
29
|
+
type: vis_type
|
|
30
|
+
name: user-facing title
|
|
31
|
+
options:
|
|
32
|
+
group_name: Epoch
|
|
33
|
+
thumbnail_size: [50, 50]
|
|
22
34
|
options:
|
|
23
35
|
visualize: false # Whether to visualize the training process
|
|
24
36
|
deployment:
|
|
@@ -1,14 +1,30 @@
|
|
|
1
|
-
from
|
|
1
|
+
from pydantic import BaseModel
|
|
2
2
|
|
|
3
|
+
# for load file with synapse
|
|
4
|
+
# from synapse_sdk.types import FileField
|
|
5
|
+
from synapse_sdk.plugins.categories.neural_net.base.inference import BaseInference, app
|
|
3
6
|
|
|
4
|
-
class MockNetInference:
|
|
5
|
-
model_id = None
|
|
6
7
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
return model_id
|
|
8
|
+
class InputData(BaseModel): # Pydantic
|
|
9
|
+
input_string: str
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
11
|
+
|
|
12
|
+
class ResNetInference(BaseInference):
|
|
13
|
+
async def _get_model(self, model): # Load model
|
|
14
|
+
model_directory_path = model['path']
|
|
15
|
+
|
|
16
|
+
# implement model_load code
|
|
17
|
+
model = model_directory_path
|
|
18
|
+
|
|
19
|
+
return model # return loaded_model
|
|
20
|
+
|
|
21
|
+
@app.post('/load_model')
|
|
22
|
+
async def load_model(self):
|
|
23
|
+
await self.get_model()
|
|
24
|
+
|
|
25
|
+
@app.post('/')
|
|
26
|
+
async def infer(self, data: InputData):
|
|
27
|
+
model = await self.get_model()
|
|
28
|
+
results = model(data.input_string) # This is Sample code. implement your model's prediction code
|
|
29
|
+
|
|
30
|
+
return results
|
|
@@ -6,9 +6,9 @@ synapse_sdk/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
|
6
6
|
synapse_sdk/i18n.py,sha256=VXMR-Zm_1hTAg9iPk3YZNNq-T1Bhx1J2fEtRT6kyYbg,766
|
|
7
7
|
synapse_sdk/loggers.py,sha256=hi-m5y4x0OcR2Esf7o849fWpdKrzCGOR4AxazbB7ShE,6528
|
|
8
8
|
synapse_sdk/types.py,sha256=khzn8KpgxFdn1SrpbcuX84m_Md1Mz_HIoUoPq8uok40,698
|
|
9
|
-
synapse_sdk/cli/__init__.py,sha256=
|
|
9
|
+
synapse_sdk/cli/__init__.py,sha256=RLZwqbtoC90-tw_2ErakY8-GxSNf6Ms2lNePBd_y-9U,9694
|
|
10
10
|
synapse_sdk/cli/config.py,sha256=ooIHI7ZDA1yLtisxk_Xn1ptz4sM5j7TDivxaPvBUONE,11886
|
|
11
|
-
synapse_sdk/cli/devtools.py,sha256=
|
|
11
|
+
synapse_sdk/cli/devtools.py,sha256=Wm6b5iif12Tl1wkn688F_d0gQG5mKfu274rRM9QANyk,2609
|
|
12
12
|
synapse_sdk/cli/alias/__init__.py,sha256=jDy8N_KupVy7n_jKKWhjQOj76-mR-uoVvMoyzObUkuI,405
|
|
13
13
|
synapse_sdk/cli/alias/create.py,sha256=P9uX_dbafSdpO4UM4A4l6fyu88I3plaUPnIk72z5-wQ,1132
|
|
14
14
|
synapse_sdk/cli/alias/dataclass.py,sha256=avVaUvBmtdVkM9GD_MilCXk0kVQSbh2p5s5XEqL4kMs,1498
|
|
@@ -44,9 +44,10 @@ synapse_sdk/clients/ray/serve.py,sha256=eFhCYIv_irc_2RyuV3bzeWIVyz_1NlqwoNVh5KSW
|
|
|
44
44
|
synapse_sdk/clients/validators/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
45
45
|
synapse_sdk/clients/validators/collections.py,sha256=LtnwvutsScubOUcZ2reGHLCzseXxtNIdnH2nv098aUU,1195
|
|
46
46
|
synapse_sdk/devtools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
47
|
-
synapse_sdk/devtools/config.py,sha256=
|
|
47
|
+
synapse_sdk/devtools/config.py,sha256=ODAfnXD4TBZQM2dxL7pcHlx6JfkZo15Kwf1MEenbics,2509
|
|
48
48
|
synapse_sdk/devtools/models.py,sha256=6tdpNblSvE5VQ97J0NZreFkD0jK8v6JuJK4ap0DX2w8,1112
|
|
49
|
-
synapse_sdk/devtools/server.py,sha256=
|
|
49
|
+
synapse_sdk/devtools/server.py,sha256=xLRgZuaHuq8a38WW0-TVDavhNxJZ89EOexPSy88BAU0,35160
|
|
50
|
+
synapse_sdk/devtools/utils.py,sha256=-f3ZxnRpYg6suNQIL-m4n1DhvLdQEbS4e9Mk9tQ8crE,1706
|
|
50
51
|
synapse_sdk/devtools/docs/.gitignore,sha256=fCv2uiY7oUmiiFhHqfcYbg169Y-q4-AfLmmnRl98_sw,233
|
|
51
52
|
synapse_sdk/devtools/docs/README.md,sha256=yBzWf0K1ef4oymFXDaHo0nYWEgMQJqsOyrkNhIOPQrY,774
|
|
52
53
|
synapse_sdk/devtools/docs/docusaurus.config.ts,sha256=zH1dxP4hmKsYWTo1OYMBIeE0Cj5dC8KChVtkORNQB5E,3129
|
|
@@ -83,7 +84,7 @@ synapse_sdk/devtools/web/package-lock.json,sha256=U8D6cfTZGAhYnGAt7cn0zRapKWvqQQ
|
|
|
83
84
|
synapse_sdk/devtools/web/package.json,sha256=XhFiaskku7iVMh33AYrwQUim5Sw3x0m0mFheJBt701w,579
|
|
84
85
|
synapse_sdk/devtools/web/pnpm-lock.yaml,sha256=BvWYbeMzrQJjyWukCiGCLuBwpq-314RtTfJjEBn_23Y,34021
|
|
85
86
|
synapse_sdk/devtools/web/vite.config.js,sha256=mCx0SMeHaJQ6YiwVCjFW2wnKo3ET31CeBQWL-oWGIMI,275
|
|
86
|
-
synapse_sdk/devtools/web/dist/index.html,sha256=
|
|
87
|
+
synapse_sdk/devtools/web/dist/index.html,sha256=U2XwWhEkLtEiIM2k2bkDsNOYHG2_NUEiI70jU7LwPVA,603
|
|
87
88
|
synapse_sdk/devtools/web/src/App.jsx,sha256=ldhadXC3mCQqfAKKU1DHo8f3zSHmH9ZarVC8HrUwIgk,302
|
|
88
89
|
synapse_sdk/devtools/web/src/App.module.css,sha256=CkYPpB5DZOSEnOqliwEyYcdZx8jrPkVS6hCs0DP7x9o,472
|
|
89
90
|
synapse_sdk/devtools/web/src/index.css,sha256=xEcCf4tGnShIHHT_Josx7-wvA1Kb-aeQ_joj0QkPgag,9960
|
|
@@ -93,12 +94,12 @@ synapse_sdk/devtools/web/src/router.jsx,sha256=RX22-qz1SdFzTkRz-z8KQWRHM5Opq0iiQ
|
|
|
93
94
|
synapse_sdk/devtools/web/src/assets/favicon.ico,sha256=DnJqOB_Vx-5-V5YPnqX_ajVAcQVd0HG_EwBSrVqJnj0,15086
|
|
94
95
|
synapse_sdk/devtools/web/src/components/Breadcrumbs.jsx,sha256=K1oANO1dz7DdZlIWwrvoHmLzJMphylbxeYv5zXORCWk,1271
|
|
95
96
|
synapse_sdk/devtools/web/src/components/Layout.jsx,sha256=tAJbm1uOpoLjBarYhfTGy3fyIrDMpnK8_mJtmbc4L54,269
|
|
96
|
-
synapse_sdk/devtools/web/src/components/LogViewer.jsx,sha256=
|
|
97
|
+
synapse_sdk/devtools/web/src/components/LogViewer.jsx,sha256=3rdszzAocjxSyiyyBaOS9WYdepO76-Xo0fqnYJ7YmwY,8840
|
|
97
98
|
synapse_sdk/devtools/web/src/components/MessageViewer.jsx,sha256=maCiK1D3P-Y5UJaaq_rIfU481GTmB9pFiPygMk2EK3I,5029
|
|
98
|
-
synapse_sdk/devtools/web/src/components/NavigationSidebar.jsx,sha256=
|
|
99
|
+
synapse_sdk/devtools/web/src/components/NavigationSidebar.jsx,sha256=IW2PiUOiJuLW1HrBoFjAfFdKYKK8eodimdgL3Za7dmk,3993
|
|
99
100
|
synapse_sdk/devtools/web/src/components/ServerStatusBar.jsx,sha256=vBH36S9Wcjy-3rTw9gtJE-Q-R_6IJ8qDpDDeRNlMW6I,8234
|
|
100
101
|
synapse_sdk/devtools/web/src/components/icons.jsx,sha256=PWLGyluP0sudc0Qlc7jcbCcEMXocaX_oFULvRVMepKc,7690
|
|
101
|
-
synapse_sdk/devtools/web/src/utils/api.js,sha256=
|
|
102
|
+
synapse_sdk/devtools/web/src/utils/api.js,sha256=dPVeAnYpQGVE83xcPILL1p7cW9gOYADACPMl-xYe9M4,10861
|
|
102
103
|
synapse_sdk/devtools/web/src/views/ApplicationDetailView.jsx,sha256=wMXIkRkiykWZZrMGZ8bymmzpoN6miHN7RUqL5eLt9P4,9640
|
|
103
104
|
synapse_sdk/devtools/web/src/views/ApplicationsView.jsx,sha256=LKfIWGf7isXc6_Fxaxei_8gM5bbQ_zWkGrfw8Qe5vpI,9081
|
|
104
105
|
synapse_sdk/devtools/web/src/views/HomeView.jsx,sha256=ri2Rq_RzEzfYqNRKna1cI2pWHcvGoWRSS1oZXxGDAGc,8038
|
|
@@ -138,9 +139,9 @@ synapse_sdk/plugins/categories/neural_net/actions/train.py,sha256=i406Ar0V74Qwdv
|
|
|
138
139
|
synapse_sdk/plugins/categories/neural_net/actions/tune.py,sha256=C2zv3o0S-5Hjjsms8ULDGD-ad_DdNTqCPOcDqXa0v1Y,13494
|
|
139
140
|
synapse_sdk/plugins/categories/neural_net/base/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
140
141
|
synapse_sdk/plugins/categories/neural_net/base/inference.py,sha256=R5DASI6-5vzsjDOYxqeGGMBjnav5qHF4hNJT8zNUR3I,1097
|
|
141
|
-
synapse_sdk/plugins/categories/neural_net/templates/config.yaml,sha256=
|
|
142
|
+
synapse_sdk/plugins/categories/neural_net/templates/config.yaml,sha256=TMdvthf0zQYYTHf0IibKJ6InziRCWM4100C1DKkJVqU,1094
|
|
142
143
|
synapse_sdk/plugins/categories/neural_net/templates/plugin/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
143
|
-
synapse_sdk/plugins/categories/neural_net/templates/plugin/inference.py,sha256=
|
|
144
|
+
synapse_sdk/plugins/categories/neural_net/templates/plugin/inference.py,sha256=rXvECCewVlLSotv7UaIyyGfEv0OODlXBuk1JwBLNhh8,838
|
|
144
145
|
synapse_sdk/plugins/categories/neural_net/templates/plugin/test.py,sha256=kYyk7l4UtcDUAH4nkdVUGrHHHjxI4p1U13HSLnmGPyE,53
|
|
145
146
|
synapse_sdk/plugins/categories/neural_net/templates/plugin/train.py,sha256=R4sjNjqRHOJApdKy1p3wXiCPC0Hn_NQf44LJCDopY9E,460
|
|
146
147
|
synapse_sdk/plugins/categories/post_annotation/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -204,9 +205,9 @@ synapse_sdk/utils/storage/providers/__init__.py,sha256=x7RGwZryT2FpVxS7fGWryRVpq
|
|
|
204
205
|
synapse_sdk/utils/storage/providers/gcp.py,sha256=i2BQCu1Kej1If9SuNr2_lEyTcr5M_ncGITZrL0u5wEA,363
|
|
205
206
|
synapse_sdk/utils/storage/providers/s3.py,sha256=W94rQvhGRXti3R4mYP7gmU5pcyCQpGFIBLvxxqLVdRM,2231
|
|
206
207
|
synapse_sdk/utils/storage/providers/sftp.py,sha256=_8s9hf0JXIO21gvm-JVS00FbLsbtvly4c-ETLRax68A,1426
|
|
207
|
-
synapse_sdk-1.0.
|
|
208
|
-
synapse_sdk-1.0.
|
|
209
|
-
synapse_sdk-1.0.
|
|
210
|
-
synapse_sdk-1.0.
|
|
211
|
-
synapse_sdk-1.0.
|
|
212
|
-
synapse_sdk-1.0.
|
|
208
|
+
synapse_sdk-1.0.0a62.dist-info/licenses/LICENSE,sha256=bKzmC5YAg4V1Fhl8OO_tqY8j62hgdncAkN7VrdjmrGk,1101
|
|
209
|
+
synapse_sdk-1.0.0a62.dist-info/METADATA,sha256=EZ7nVLBGFvc5_j9iIq5_9HYxUfcMa7XBfHnhc0JR24I,1130
|
|
210
|
+
synapse_sdk-1.0.0a62.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
211
|
+
synapse_sdk-1.0.0a62.dist-info/entry_points.txt,sha256=VNptJoGoNJI8yLXfBmhgUefMsmGI0m3-0YoMvrOgbxo,48
|
|
212
|
+
synapse_sdk-1.0.0a62.dist-info/top_level.txt,sha256=ytgJMRK1slVOKUpgcw3LEyHHP7S34J6n_gJzdkcSsw8,12
|
|
213
|
+
synapse_sdk-1.0.0a62.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|