synapse-sdk 1.0.0a23__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/__init__.py +310 -5
- synapse_sdk/cli/alias/__init__.py +22 -0
- synapse_sdk/cli/alias/create.py +36 -0
- synapse_sdk/cli/alias/dataclass.py +31 -0
- synapse_sdk/cli/alias/default.py +16 -0
- synapse_sdk/cli/alias/delete.py +15 -0
- synapse_sdk/cli/alias/list.py +19 -0
- synapse_sdk/cli/alias/read.py +15 -0
- synapse_sdk/cli/alias/update.py +17 -0
- synapse_sdk/cli/alias/utils.py +61 -0
- synapse_sdk/cli/code_server.py +687 -0
- synapse_sdk/cli/config.py +440 -0
- synapse_sdk/cli/devtools.py +90 -0
- synapse_sdk/cli/plugin/__init__.py +33 -0
- synapse_sdk/cli/{create_plugin.py → plugin/create.py} +2 -2
- synapse_sdk/{plugins/cli → cli/plugin}/publish.py +23 -15
- synapse_sdk/clients/agent/__init__.py +9 -3
- synapse_sdk/clients/agent/container.py +143 -0
- synapse_sdk/clients/agent/core.py +19 -0
- synapse_sdk/clients/agent/ray.py +298 -9
- synapse_sdk/clients/backend/__init__.py +30 -12
- synapse_sdk/clients/backend/annotation.py +13 -5
- synapse_sdk/clients/backend/core.py +31 -4
- synapse_sdk/clients/backend/data_collection.py +186 -0
- synapse_sdk/clients/backend/hitl.py +17 -0
- synapse_sdk/clients/backend/integration.py +16 -1
- synapse_sdk/clients/backend/ml.py +5 -1
- synapse_sdk/clients/backend/models.py +78 -0
- synapse_sdk/clients/base.py +384 -41
- synapse_sdk/clients/ray/serve.py +2 -0
- synapse_sdk/clients/validators/collections.py +31 -0
- synapse_sdk/devtools/config.py +94 -0
- synapse_sdk/devtools/server.py +41 -0
- synapse_sdk/devtools/streamlit_app/__init__.py +5 -0
- synapse_sdk/devtools/streamlit_app/app.py +128 -0
- synapse_sdk/devtools/streamlit_app/services/__init__.py +11 -0
- synapse_sdk/devtools/streamlit_app/services/job_service.py +233 -0
- synapse_sdk/devtools/streamlit_app/services/plugin_service.py +236 -0
- synapse_sdk/devtools/streamlit_app/services/serve_service.py +95 -0
- synapse_sdk/devtools/streamlit_app/ui/__init__.py +15 -0
- synapse_sdk/devtools/streamlit_app/ui/config_tab.py +76 -0
- synapse_sdk/devtools/streamlit_app/ui/deployment_tab.py +66 -0
- synapse_sdk/devtools/streamlit_app/ui/http_tab.py +125 -0
- synapse_sdk/devtools/streamlit_app/ui/jobs_tab.py +573 -0
- synapse_sdk/devtools/streamlit_app/ui/serve_tab.py +346 -0
- synapse_sdk/devtools/streamlit_app/ui/status_bar.py +118 -0
- synapse_sdk/devtools/streamlit_app/utils/__init__.py +40 -0
- synapse_sdk/devtools/streamlit_app/utils/json_viewer.py +197 -0
- synapse_sdk/devtools/streamlit_app/utils/log_formatter.py +38 -0
- synapse_sdk/devtools/streamlit_app/utils/styles.py +241 -0
- synapse_sdk/devtools/streamlit_app/utils/ui_components.py +289 -0
- synapse_sdk/devtools/streamlit_app.py +10 -0
- synapse_sdk/loggers.py +120 -9
- synapse_sdk/plugins/README.md +1340 -0
- synapse_sdk/plugins/__init__.py +0 -13
- synapse_sdk/plugins/categories/base.py +117 -11
- synapse_sdk/plugins/categories/data_validation/actions/validation.py +72 -0
- synapse_sdk/plugins/categories/data_validation/templates/plugin/validation.py +33 -5
- 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 +21 -0
- synapse_sdk/plugins/categories/export/templates/plugin/__init__.py +390 -0
- synapse_sdk/plugins/categories/export/templates/plugin/export.py +160 -0
- synapse_sdk/plugins/categories/neural_net/actions/deployment.py +13 -12
- synapse_sdk/plugins/categories/neural_net/actions/train.py +1134 -31
- synapse_sdk/plugins/categories/neural_net/actions/tune.py +534 -0
- synapse_sdk/plugins/categories/neural_net/base/inference.py +1 -1
- synapse_sdk/plugins/categories/neural_net/templates/config.yaml +32 -4
- synapse_sdk/plugins/categories/neural_net/templates/plugin/inference.py +26 -10
- 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/{export/actions/export.py → pre_annotation/actions/pre_annotation/action.py} +4 -4
- 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/pre_annotation/templates/config.yaml +19 -0
- synapse_sdk/plugins/categories/pre_annotation/templates/plugin/to_task.py +40 -0
- synapse_sdk/plugins/categories/smart_tool/templates/config.yaml +2 -0
- synapse_sdk/plugins/categories/upload/__init__.py +0 -0
- synapse_sdk/plugins/categories/upload/actions/__init__.py +0 -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 +33 -0
- synapse_sdk/plugins/categories/upload/templates/plugin/__init__.py +310 -0
- synapse_sdk/plugins/categories/upload/templates/plugin/upload.py +102 -0
- synapse_sdk/plugins/enums.py +3 -1
- synapse_sdk/plugins/models.py +148 -11
- synapse_sdk/plugins/templates/plugin-config-schema.json +406 -0
- synapse_sdk/plugins/templates/schema.json +491 -0
- synapse_sdk/plugins/templates/synapse-{{cookiecutter.plugin_code}}-plugin/config.yaml +1 -0
- synapse_sdk/plugins/templates/synapse-{{cookiecutter.plugin_code}}-plugin/requirements.txt +1 -1
- synapse_sdk/plugins/utils/__init__.py +46 -0
- synapse_sdk/plugins/utils/actions.py +119 -0
- synapse_sdk/plugins/utils/config.py +203 -0
- synapse_sdk/plugins/{utils.py → utils/legacy.py} +26 -46
- synapse_sdk/plugins/utils/ray_gcs.py +66 -0
- synapse_sdk/plugins/utils/registry.py +58 -0
- synapse_sdk/shared/__init__.py +25 -0
- synapse_sdk/shared/enums.py +93 -0
- synapse_sdk/types.py +19 -0
- synapse_sdk/utils/converters/__init__.py +240 -0
- synapse_sdk/utils/converters/coco/__init__.py +0 -0
- synapse_sdk/utils/converters/coco/from_dm.py +322 -0
- synapse_sdk/utils/converters/coco/to_dm.py +215 -0
- synapse_sdk/utils/converters/dm/__init__.py +57 -0
- synapse_sdk/utils/converters/dm/base.py +137 -0
- synapse_sdk/utils/converters/dm/from_v1.py +273 -0
- synapse_sdk/utils/converters/dm/to_v1.py +321 -0
- 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/converters/pascal/__init__.py +0 -0
- synapse_sdk/utils/converters/pascal/from_dm.py +244 -0
- synapse_sdk/utils/converters/pascal/to_dm.py +214 -0
- synapse_sdk/utils/converters/yolo/__init__.py +0 -0
- synapse_sdk/utils/converters/yolo/from_dm.py +384 -0
- synapse_sdk/utils/converters/yolo/to_dm.py +267 -0
- synapse_sdk/utils/dataset.py +46 -0
- synapse_sdk/utils/encryption.py +158 -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.backup +301 -0
- synapse_sdk/utils/http.py +138 -0
- synapse_sdk/utils/network.py +309 -0
- synapse_sdk/utils/storage/__init__.py +72 -0
- synapse_sdk/utils/storage/providers/__init__.py +183 -0
- synapse_sdk/utils/storage/providers/file_system.py +134 -0
- synapse_sdk/utils/storage/providers/gcp.py +13 -0
- synapse_sdk/utils/storage/providers/http.py +190 -0
- synapse_sdk/utils/storage/providers/s3.py +91 -0
- synapse_sdk/utils/storage/providers/sftp.py +47 -0
- synapse_sdk/utils/storage/registry.py +17 -0
- synapse_sdk-2025.12.3.dist-info/METADATA +123 -0
- synapse_sdk-2025.12.3.dist-info/RECORD +279 -0
- {synapse_sdk-1.0.0a23.dist-info → synapse_sdk-2025.12.3.dist-info}/WHEEL +1 -1
- synapse_sdk/clients/backend/dataset.py +0 -51
- synapse_sdk/plugins/categories/import/actions/import.py +0 -10
- synapse_sdk/plugins/cli/__init__.py +0 -21
- synapse_sdk/plugins/templates/synapse-{{cookiecutter.plugin_code}}-plugin/.env +0 -24
- synapse_sdk/plugins/templates/synapse-{{cookiecutter.plugin_code}}-plugin/.env.dist +0 -24
- synapse_sdk/plugins/templates/synapse-{{cookiecutter.plugin_code}}-plugin/main.py +0 -4
- synapse_sdk/utils/file.py +0 -168
- synapse_sdk/utils/storage.py +0 -91
- synapse_sdk-1.0.0a23.dist-info/METADATA +0 -44
- synapse_sdk-1.0.0a23.dist-info/RECORD +0 -114
- /synapse_sdk/{plugins/cli → cli/plugin}/run.py +0 -0
- /synapse_sdk/{plugins/categories/import → clients/validators}/__init__.py +0 -0
- /synapse_sdk/{plugins/categories/import/actions → devtools}/__init__.py +0 -0
- {synapse_sdk-1.0.0a23.dist-info → synapse_sdk-2025.12.3.dist-info}/entry_points.txt +0 -0
- {synapse_sdk-1.0.0a23.dist-info → synapse_sdk-2025.12.3.dist-info/licenses}/LICENSE +0 -0
- {synapse_sdk-1.0.0a23.dist-info → synapse_sdk-2025.12.3.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
"""Serve Applications tab UI component."""
|
|
2
|
+
|
|
3
|
+
import time
|
|
4
|
+
import traceback
|
|
5
|
+
from datetime import datetime
|
|
6
|
+
from typing import Dict, Optional
|
|
7
|
+
|
|
8
|
+
import streamlit as st
|
|
9
|
+
|
|
10
|
+
from synapse_sdk.clients.exceptions import ClientError
|
|
11
|
+
|
|
12
|
+
from ..services.serve_service import ServeService
|
|
13
|
+
from ..utils.json_viewer import render_json_as_table, render_json_compact
|
|
14
|
+
from ..utils.styles import get_status_badge_html
|
|
15
|
+
from ..utils.ui_components import render_action_button, render_empty_state, render_section_header
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class ServeTab:
|
|
19
|
+
"""UI component for the Serve Applications tab."""
|
|
20
|
+
|
|
21
|
+
def __init__(self, serve_service: ServeService, agent_id: Optional[int] = None, agent_info: Optional[Dict] = None):
|
|
22
|
+
self.serve_service = serve_service
|
|
23
|
+
self.agent_id = agent_id
|
|
24
|
+
self.agent_info = agent_info or {}
|
|
25
|
+
|
|
26
|
+
def render(self):
|
|
27
|
+
"""Render the Serve Applications tab."""
|
|
28
|
+
if not self.serve_service.backend_client:
|
|
29
|
+
st.error('Backend client not configured. Please check your backend configuration.')
|
|
30
|
+
return
|
|
31
|
+
|
|
32
|
+
# Check if we should show app details
|
|
33
|
+
if 'selected_app' in st.session_state:
|
|
34
|
+
self.render_app_details(st.session_state['selected_app'])
|
|
35
|
+
return
|
|
36
|
+
|
|
37
|
+
# Auto-refresh controls
|
|
38
|
+
col1, col2, col3 = st.columns([1, 1, 2])
|
|
39
|
+
with col1:
|
|
40
|
+
if render_action_button('Refresh', key='refresh_apps', icon='🔄', type='secondary'):
|
|
41
|
+
st.rerun()
|
|
42
|
+
|
|
43
|
+
with col2:
|
|
44
|
+
auto_refresh = st.checkbox('Auto-refresh', value=False, key='serve_auto_refresh')
|
|
45
|
+
|
|
46
|
+
with col3:
|
|
47
|
+
if auto_refresh:
|
|
48
|
+
refresh_interval = st.selectbox(
|
|
49
|
+
'Refresh interval',
|
|
50
|
+
options=[2, 5, 10, 30],
|
|
51
|
+
index=1, # Default to 5 seconds
|
|
52
|
+
format_func=lambda x: f'{x}s',
|
|
53
|
+
key='serve_refresh_interval',
|
|
54
|
+
)
|
|
55
|
+
st.caption(f'Auto-refreshing every {refresh_interval} seconds')
|
|
56
|
+
|
|
57
|
+
# Create a container for applications display to ensure proper rendering
|
|
58
|
+
apps_container = st.container()
|
|
59
|
+
|
|
60
|
+
with apps_container:
|
|
61
|
+
try:
|
|
62
|
+
applications = self.serve_service.list_serve_applications(self.agent_id, self.agent_info)
|
|
63
|
+
|
|
64
|
+
if not applications:
|
|
65
|
+
render_empty_state(
|
|
66
|
+
'No serve applications found',
|
|
67
|
+
icon='🚀',
|
|
68
|
+
action_label='Refresh',
|
|
69
|
+
action_callback=lambda: st.rerun(),
|
|
70
|
+
)
|
|
71
|
+
if auto_refresh:
|
|
72
|
+
refresh_interval = st.session_state.get('serve_refresh_interval', 5)
|
|
73
|
+
placeholder = st.empty()
|
|
74
|
+
with placeholder.container():
|
|
75
|
+
st.info(f'Refreshing in {refresh_interval} seconds...')
|
|
76
|
+
time.sleep(refresh_interval)
|
|
77
|
+
placeholder.empty()
|
|
78
|
+
st.rerun()
|
|
79
|
+
return
|
|
80
|
+
|
|
81
|
+
# Display applications in table format
|
|
82
|
+
st.success(f'Showing {len(applications)} applications')
|
|
83
|
+
self._render_applications_table(applications)
|
|
84
|
+
|
|
85
|
+
except ClientError as e:
|
|
86
|
+
st.error(f'Failed to fetch serve applications: {e.reason}')
|
|
87
|
+
except Exception as e:
|
|
88
|
+
st.error(f'Unexpected error: {e}')
|
|
89
|
+
st.code(traceback.format_exc())
|
|
90
|
+
|
|
91
|
+
# Auto-refresh implementation
|
|
92
|
+
if auto_refresh:
|
|
93
|
+
refresh_interval = st.session_state.get('serve_refresh_interval', 5)
|
|
94
|
+
placeholder = st.empty()
|
|
95
|
+
with placeholder.container():
|
|
96
|
+
st.info(f'Refreshing in {refresh_interval} seconds...')
|
|
97
|
+
time.sleep(refresh_interval)
|
|
98
|
+
placeholder.empty()
|
|
99
|
+
st.rerun()
|
|
100
|
+
|
|
101
|
+
def _render_applications_table(self, applications):
|
|
102
|
+
"""Render the applications table."""
|
|
103
|
+
# Table header
|
|
104
|
+
header_cols = st.columns([2, 1.5, 1, 1, 1.2, 1.2, 0.6])
|
|
105
|
+
headers = ['Application', 'Plugin', 'Status', 'Active', 'Job', 'Created', '']
|
|
106
|
+
|
|
107
|
+
for i, header in enumerate(headers):
|
|
108
|
+
with header_cols[i]:
|
|
109
|
+
st.markdown(
|
|
110
|
+
f"<div style='color:#666; font-size:13px; font-weight:600; padding: 4px 0;'>{header}</div>",
|
|
111
|
+
unsafe_allow_html=True,
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
st.markdown("<hr style='margin: 8px 0; border: none; border-top: 1px solid #e0e0e0'>", unsafe_allow_html=True)
|
|
115
|
+
|
|
116
|
+
# Table rows
|
|
117
|
+
for app in applications:
|
|
118
|
+
cols = st.columns([2, 1.5, 1, 1, 1.2, 1.2, 0.6])
|
|
119
|
+
|
|
120
|
+
# Application Name (with ID as fallback)
|
|
121
|
+
with cols[0]:
|
|
122
|
+
app_id = app.get('id', 'N/A')
|
|
123
|
+
# Try to get application name from various possible fields
|
|
124
|
+
app_name = (
|
|
125
|
+
app.get('name')
|
|
126
|
+
or app.get('display_name')
|
|
127
|
+
or app.get('deployment_name')
|
|
128
|
+
or (app.get('data', {}).get('name') if isinstance(app.get('data'), dict) else None)
|
|
129
|
+
or f'Deployment {str(app_id)[:8]}...'
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
# Display name with ID as tooltip/subtitle
|
|
133
|
+
st.markdown(
|
|
134
|
+
f"<div style='font-size:13px; padding: 6px 0;'>"
|
|
135
|
+
f"<div style='font-weight: 500;'>{app_name}</div>"
|
|
136
|
+
f"<div style='font-size: 11px; color: #666; font-family: monospace;'>{str(app_id)[:8]}...</div>"
|
|
137
|
+
f'</div>',
|
|
138
|
+
unsafe_allow_html=True,
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
# Plugin
|
|
142
|
+
with cols[1]:
|
|
143
|
+
plugin_release = app.get('plugin_release', 'N/A')
|
|
144
|
+
# Try to extract plugin name or code from release info
|
|
145
|
+
plugin_name = app.get('plugin_name') or app.get('plugin_code')
|
|
146
|
+
if not plugin_name and isinstance(app.get('data'), dict):
|
|
147
|
+
plugin_name = app.get('data', {}).get('plugin_name') or app.get('data', {}).get('plugin_code')
|
|
148
|
+
|
|
149
|
+
if plugin_name:
|
|
150
|
+
st.markdown(
|
|
151
|
+
f"<div style='font-size:13px; padding: 6px 0;'>"
|
|
152
|
+
f'<div>{plugin_name}</div>'
|
|
153
|
+
f"<div style='font-size: 11px; color: #666;'>v{plugin_release}</div>"
|
|
154
|
+
f'</div>',
|
|
155
|
+
unsafe_allow_html=True,
|
|
156
|
+
)
|
|
157
|
+
else:
|
|
158
|
+
display_pr = (
|
|
159
|
+
str(plugin_release)[:12] + '...' if len(str(plugin_release)) > 12 else str(plugin_release)
|
|
160
|
+
)
|
|
161
|
+
st.markdown(
|
|
162
|
+
f"<div style='font-size:13px; padding: 6px 0;'>{display_pr}</div>", unsafe_allow_html=True
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
# Status
|
|
166
|
+
with cols[2]:
|
|
167
|
+
status = app.get('status', 'Unknown')
|
|
168
|
+
st.markdown(get_status_badge_html(status), unsafe_allow_html=True)
|
|
169
|
+
|
|
170
|
+
# Is Active
|
|
171
|
+
with cols[3]:
|
|
172
|
+
is_active = app.get('is_active', False)
|
|
173
|
+
active_text = 'Yes' if is_active else 'No'
|
|
174
|
+
active_color = '#28a745' if is_active else '#6c757d'
|
|
175
|
+
st.markdown(
|
|
176
|
+
f"<div style='font-size:13px; padding: 6px 0; color: {active_color};'>{active_text}</div>",
|
|
177
|
+
unsafe_allow_html=True,
|
|
178
|
+
)
|
|
179
|
+
|
|
180
|
+
# Job
|
|
181
|
+
with cols[4]:
|
|
182
|
+
job_id = app.get('job', 'N/A')
|
|
183
|
+
display_job = str(job_id)[:10] + '...' if len(str(job_id)) > 10 else str(job_id)
|
|
184
|
+
st.markdown(f"<div style='font-size:13px; padding: 6px 0;'>{display_job}</div>", unsafe_allow_html=True)
|
|
185
|
+
|
|
186
|
+
# Created
|
|
187
|
+
with cols[5]:
|
|
188
|
+
created = app.get('created')
|
|
189
|
+
if created:
|
|
190
|
+
try:
|
|
191
|
+
created_dt = datetime.fromisoformat(created.replace('+09:00', '+09:00'))
|
|
192
|
+
time_str = created_dt.strftime('%m/%d %H:%M')
|
|
193
|
+
st.markdown(
|
|
194
|
+
f"<div style='font-size:13px; padding: 6px 0;'>{time_str}</div>",
|
|
195
|
+
unsafe_allow_html=True,
|
|
196
|
+
)
|
|
197
|
+
except Exception:
|
|
198
|
+
st.markdown(
|
|
199
|
+
f"<div style='font-size:13px; padding: 6px 0;'>{str(created)[:16]}</div>",
|
|
200
|
+
unsafe_allow_html=True,
|
|
201
|
+
)
|
|
202
|
+
else:
|
|
203
|
+
st.markdown("<div style='font-size:13px; padding: 6px 0;'>-</div>", unsafe_allow_html=True)
|
|
204
|
+
|
|
205
|
+
# Actions
|
|
206
|
+
with cols[6]:
|
|
207
|
+
details_key = f'app_details_{app_id}_{hash(str(app))}'
|
|
208
|
+
|
|
209
|
+
def select_app(app_data):
|
|
210
|
+
st.session_state['selected_app'] = app_data
|
|
211
|
+
|
|
212
|
+
if render_action_button(
|
|
213
|
+
'', key=details_key, icon='→', type='minimal', on_click=select_app, args=(app,), help='View details'
|
|
214
|
+
):
|
|
215
|
+
pass
|
|
216
|
+
|
|
217
|
+
st.markdown(
|
|
218
|
+
"<hr style='margin: 6px 0; border: none; border-top: 1px solid #f0f0f0'>",
|
|
219
|
+
unsafe_allow_html=True,
|
|
220
|
+
)
|
|
221
|
+
|
|
222
|
+
def render_app_details(self, app):
|
|
223
|
+
"""Render the serve deployment details page."""
|
|
224
|
+
app_id = app.get('id', 'Unknown')
|
|
225
|
+
|
|
226
|
+
# Try to get application name
|
|
227
|
+
app_name = (
|
|
228
|
+
app.get('name')
|
|
229
|
+
or app.get('display_name')
|
|
230
|
+
or app.get('deployment_name')
|
|
231
|
+
or (app.get('data', {}).get('name') if isinstance(app.get('data'), dict) else None)
|
|
232
|
+
or f'Deployment {str(app_id)[:8]}...'
|
|
233
|
+
)
|
|
234
|
+
|
|
235
|
+
# Header with back button
|
|
236
|
+
col1, col2 = st.columns([1, 4])
|
|
237
|
+
with col1:
|
|
238
|
+
if render_action_button('Back', key='back_to_apps', icon='←', type='secondary'):
|
|
239
|
+
del st.session_state['selected_app']
|
|
240
|
+
st.rerun()
|
|
241
|
+
with col2:
|
|
242
|
+
render_section_header(app_name, f'ID: {app_id}')
|
|
243
|
+
|
|
244
|
+
# Status badge with spacing
|
|
245
|
+
status = app.get('status', 'Unknown')
|
|
246
|
+
st.markdown(f"<div style='margin: 12px 0;'>{get_status_badge_html(status)}</div>", unsafe_allow_html=True)
|
|
247
|
+
|
|
248
|
+
# Deployment Information section
|
|
249
|
+
render_section_header('Deployment Information')
|
|
250
|
+
col1, col2 = st.columns(2)
|
|
251
|
+
|
|
252
|
+
with col1:
|
|
253
|
+
# Show name if different from the generated one
|
|
254
|
+
if app.get('name') or app.get('display_name') or app.get('deployment_name'):
|
|
255
|
+
display_name = app.get('name') or app.get('display_name') or app.get('deployment_name')
|
|
256
|
+
st.markdown(
|
|
257
|
+
f"<div style='margin-bottom: 12px;'><strong>Name:</strong> {display_name}</div>",
|
|
258
|
+
unsafe_allow_html=True,
|
|
259
|
+
)
|
|
260
|
+
st.markdown(
|
|
261
|
+
f"<div style='margin-bottom: 12px;'><strong>ID:</strong> <code>{app.get('id', 'N/A')}</code></div>",
|
|
262
|
+
unsafe_allow_html=True,
|
|
263
|
+
)
|
|
264
|
+
st.markdown(
|
|
265
|
+
f"<div style='margin-bottom: 12px;'><strong>Status:</strong> {status}</div>", unsafe_allow_html=True
|
|
266
|
+
)
|
|
267
|
+
status_display = app.get('status_display', 'N/A')
|
|
268
|
+
st.markdown(
|
|
269
|
+
f"<div style='margin-bottom: 12px;'><strong>Status Display:</strong> {status_display}</div>",
|
|
270
|
+
unsafe_allow_html=True,
|
|
271
|
+
)
|
|
272
|
+
is_active = 'Yes' if app.get('is_active') else 'No'
|
|
273
|
+
st.markdown(
|
|
274
|
+
f"<div style='margin-bottom: 12px;'><strong>Active:</strong> {is_active}</div>",
|
|
275
|
+
unsafe_allow_html=True,
|
|
276
|
+
)
|
|
277
|
+
|
|
278
|
+
with col2:
|
|
279
|
+
# Display plugin info with enriched data
|
|
280
|
+
plugin_release = app.get('plugin_release', 'N/A')
|
|
281
|
+
plugin_name = app.get('plugin_name') or app.get('plugin_code')
|
|
282
|
+
plugin_version = app.get('plugin_version')
|
|
283
|
+
|
|
284
|
+
if plugin_name and plugin_version:
|
|
285
|
+
plugin_display = f'{plugin_name} (v{plugin_version})'
|
|
286
|
+
elif plugin_name:
|
|
287
|
+
plugin_display = plugin_name
|
|
288
|
+
else:
|
|
289
|
+
plugin_display = f'Plugin #{plugin_release}'
|
|
290
|
+
|
|
291
|
+
st.markdown(
|
|
292
|
+
f"<div style='margin-bottom: 12px;'><strong>Plugin:</strong> {plugin_display}</div>",
|
|
293
|
+
unsafe_allow_html=True,
|
|
294
|
+
)
|
|
295
|
+
|
|
296
|
+
# Display agent info with enriched data
|
|
297
|
+
agent_id = app.get('agent', 'N/A')
|
|
298
|
+
agent_name = app.get('agent_name')
|
|
299
|
+
agent_url = app.get('agent_url')
|
|
300
|
+
|
|
301
|
+
if agent_name and agent_url:
|
|
302
|
+
agent_display = f'{agent_name} @ {agent_url}'
|
|
303
|
+
elif agent_name:
|
|
304
|
+
agent_display = agent_name
|
|
305
|
+
elif agent_url:
|
|
306
|
+
agent_display = agent_url
|
|
307
|
+
else:
|
|
308
|
+
agent_display = f'Agent #{agent_id}'
|
|
309
|
+
|
|
310
|
+
st.markdown(
|
|
311
|
+
f"<div style='margin-bottom: 12px;'><strong>Agent:</strong> {agent_display}</div>",
|
|
312
|
+
unsafe_allow_html=True,
|
|
313
|
+
)
|
|
314
|
+
st.markdown(
|
|
315
|
+
f"<div style='margin-bottom: 12px;'><strong>Job:</strong> {app.get('job', 'N/A')}</div>",
|
|
316
|
+
unsafe_allow_html=True,
|
|
317
|
+
)
|
|
318
|
+
|
|
319
|
+
created = app.get('created')
|
|
320
|
+
if created:
|
|
321
|
+
try:
|
|
322
|
+
created_dt = datetime.fromisoformat(created.replace('+09:00', '+09:00'))
|
|
323
|
+
formatted_time = created_dt.strftime('%Y-%m-%d %H:%M:%S')
|
|
324
|
+
st.markdown(
|
|
325
|
+
f"<div style='margin-bottom: 12px;'><strong>Created:</strong> {formatted_time}</div>",
|
|
326
|
+
unsafe_allow_html=True,
|
|
327
|
+
)
|
|
328
|
+
except Exception:
|
|
329
|
+
st.markdown(
|
|
330
|
+
f"<div style='margin-bottom: 12px;'><strong>Created:</strong> {created}</div>",
|
|
331
|
+
unsafe_allow_html=True,
|
|
332
|
+
)
|
|
333
|
+
else:
|
|
334
|
+
st.markdown(
|
|
335
|
+
"<div style='margin-bottom: 12px;'><strong>Created:</strong> N/A</div>", unsafe_allow_html=True
|
|
336
|
+
)
|
|
337
|
+
|
|
338
|
+
# Data section
|
|
339
|
+
data = app.get('data', {})
|
|
340
|
+
if data:
|
|
341
|
+
st.markdown("<div style='margin-top: 30px;'></div>", unsafe_allow_html=True)
|
|
342
|
+
# Use table for simple data, compact for complex
|
|
343
|
+
if isinstance(data, dict) and all(not isinstance(v, (dict, list)) for v in data.values()):
|
|
344
|
+
render_json_as_table(data, 'Deployment Data')
|
|
345
|
+
else:
|
|
346
|
+
render_json_compact(data, 'Deployment Data')
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
"""Status bar component for displaying connection and system information."""
|
|
2
|
+
|
|
3
|
+
from typing import Dict, Optional
|
|
4
|
+
|
|
5
|
+
import streamlit as st
|
|
6
|
+
|
|
7
|
+
from synapse_sdk.clients.backend import BackendClient
|
|
8
|
+
from synapse_sdk.devtools.config import get_backend_config
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class StatusBar:
|
|
12
|
+
"""Status bar UI component."""
|
|
13
|
+
|
|
14
|
+
def __init__(
|
|
15
|
+
self,
|
|
16
|
+
*,
|
|
17
|
+
backend_client: Optional[BackendClient] = None,
|
|
18
|
+
agent_id: Optional[int] = None,
|
|
19
|
+
agent_info: Optional[Dict] = None,
|
|
20
|
+
):
|
|
21
|
+
self.backend_client = backend_client
|
|
22
|
+
self.agent_id = agent_id
|
|
23
|
+
self.agent_info = agent_info or {}
|
|
24
|
+
|
|
25
|
+
def render(self):
|
|
26
|
+
"""Render the status bar."""
|
|
27
|
+
backend_config = get_backend_config()
|
|
28
|
+
|
|
29
|
+
# Use a single horizontal layout
|
|
30
|
+
if backend_config and self.backend_client:
|
|
31
|
+
host = backend_config.get('host', 'Unknown')
|
|
32
|
+
# Extract just the domain/host part
|
|
33
|
+
if '://' in host:
|
|
34
|
+
host_display = host.split('://')[1].split('/')[0]
|
|
35
|
+
else:
|
|
36
|
+
host_display = host.split('/')[0]
|
|
37
|
+
|
|
38
|
+
# Build agent display HTML
|
|
39
|
+
agent_html = ''
|
|
40
|
+
if self.agent_info:
|
|
41
|
+
agent_name = self.agent_info.get('name', f'Agent-{self.agent_id}')
|
|
42
|
+
agent_url = self.agent_info.get('url', 'unknown')
|
|
43
|
+
agent_html = (
|
|
44
|
+
'<div style="display: flex; align-items: center; gap: 8px;">'
|
|
45
|
+
'<span style="color: #495057; font-weight: 500;">Agent:</span>'
|
|
46
|
+
f'<span style="color: #212529; font-family: monospace;">{agent_name} @ {agent_url}</span>'
|
|
47
|
+
'</div>'
|
|
48
|
+
)
|
|
49
|
+
elif self.agent_id:
|
|
50
|
+
agent_html = (
|
|
51
|
+
'<div style="display: flex; align-items: center; gap: 8px;">'
|
|
52
|
+
'<span style="color: #495057; font-weight: 500;">Agent:</span>'
|
|
53
|
+
f'<span style="color: #212529; font-family: monospace;">#{self.agent_id}</span>'
|
|
54
|
+
'</div>'
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
# Create compact horizontal status bar
|
|
58
|
+
status_html = (
|
|
59
|
+
'<div style="'
|
|
60
|
+
'background: linear-gradient(90deg, #f8f9fa 0%, #e9ecef 100%);'
|
|
61
|
+
'border-bottom: 1px solid #dee2e6;'
|
|
62
|
+
'padding: 8px 16px;'
|
|
63
|
+
'margin: -1rem -3rem 1rem -3rem;'
|
|
64
|
+
'display: flex;'
|
|
65
|
+
'align-items: center;'
|
|
66
|
+
'gap: 24px;'
|
|
67
|
+
'font-size: 13px;'
|
|
68
|
+
'">'
|
|
69
|
+
'<div style="display: flex; align-items: center; gap: 8px;">'
|
|
70
|
+
'<span style="'
|
|
71
|
+
'width: 8px;'
|
|
72
|
+
'height: 8px;'
|
|
73
|
+
'background-color: #28a745;'
|
|
74
|
+
'border-radius: 50%;'
|
|
75
|
+
'display: inline-block;'
|
|
76
|
+
'"></span>'
|
|
77
|
+
'<span style="color: #495057; font-weight: 500;">Backend:</span>'
|
|
78
|
+
f'<span style="color: #212529; font-family: monospace;">{host_display}</span>'
|
|
79
|
+
'</div>'
|
|
80
|
+
f'{agent_html}'
|
|
81
|
+
'<div style="margin-left: auto; color: #6c757d; font-size: 11px;">'
|
|
82
|
+
'Synapse DevTools'
|
|
83
|
+
'</div>'
|
|
84
|
+
'</div>'
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
st.markdown(status_html, unsafe_allow_html=True)
|
|
88
|
+
|
|
89
|
+
else:
|
|
90
|
+
# Not connected status - compact horizontal bar
|
|
91
|
+
disconnected_html = (
|
|
92
|
+
'<div style="'
|
|
93
|
+
'background: linear-gradient(90deg, #fff5f5 0%, #ffe0e0 100%);'
|
|
94
|
+
'border-bottom: 1px solid #f5c6cb;'
|
|
95
|
+
'padding: 8px 16px;'
|
|
96
|
+
'margin: -1rem -3rem 1rem -3rem;'
|
|
97
|
+
'display: flex;'
|
|
98
|
+
'align-items: center;'
|
|
99
|
+
'gap: 24px;'
|
|
100
|
+
'font-size: 13px;'
|
|
101
|
+
'">'
|
|
102
|
+
'<div style="display: flex; align-items: center; gap: 8px;">'
|
|
103
|
+
'<span style="'
|
|
104
|
+
'width: 8px;'
|
|
105
|
+
'height: 8px;'
|
|
106
|
+
'background-color: #dc3545;'
|
|
107
|
+
'border-radius: 50%;'
|
|
108
|
+
'display: inline-block;'
|
|
109
|
+
'"></span>'
|
|
110
|
+
'<span style="color: #721c24; font-weight: 500;">Backend:</span>'
|
|
111
|
+
'<span style="color: #721c24;">Not configured</span>'
|
|
112
|
+
'</div>'
|
|
113
|
+
'<div style="margin-left: auto; color: #721c24; font-size: 11px;">'
|
|
114
|
+
'Synapse DevTools'
|
|
115
|
+
'</div>'
|
|
116
|
+
'</div>'
|
|
117
|
+
)
|
|
118
|
+
st.markdown(disconnected_html, unsafe_allow_html=True)
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"""Utilities for the Streamlit app."""
|
|
2
|
+
|
|
3
|
+
from .json_viewer import (
|
|
4
|
+
render_json_as_table,
|
|
5
|
+
render_json_compact,
|
|
6
|
+
render_json_tree,
|
|
7
|
+
render_metrics_grid,
|
|
8
|
+
)
|
|
9
|
+
from .log_formatter import format_log_line
|
|
10
|
+
from .styles import CUSTOM_CSS, get_status_badge_html
|
|
11
|
+
from .ui_components import (
|
|
12
|
+
render_action_button,
|
|
13
|
+
render_divider,
|
|
14
|
+
render_empty_state,
|
|
15
|
+
render_info_card,
|
|
16
|
+
render_key_value_pair,
|
|
17
|
+
render_metric_card,
|
|
18
|
+
render_progress_bar,
|
|
19
|
+
render_section_header,
|
|
20
|
+
render_table_header,
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
__all__ = [
|
|
24
|
+
'CUSTOM_CSS',
|
|
25
|
+
'format_log_line',
|
|
26
|
+
'get_status_badge_html',
|
|
27
|
+
'render_json_compact',
|
|
28
|
+
'render_json_as_table',
|
|
29
|
+
'render_json_tree',
|
|
30
|
+
'render_metrics_grid',
|
|
31
|
+
'render_action_button',
|
|
32
|
+
'render_section_header',
|
|
33
|
+
'render_info_card',
|
|
34
|
+
'render_metric_card',
|
|
35
|
+
'render_key_value_pair',
|
|
36
|
+
'render_divider',
|
|
37
|
+
'render_table_header',
|
|
38
|
+
'render_empty_state',
|
|
39
|
+
'render_progress_bar',
|
|
40
|
+
]
|