synapse-sdk 1.0.0a13__py3-none-any.whl → 2025.11.7__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/__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/cli/plugin/publish.py +45 -0
- synapse_sdk/{plugins/cli → cli/plugin}/run.py +12 -5
- synapse_sdk/clients/agent/__init__.py +9 -3
- synapse_sdk/clients/agent/container.py +133 -0
- synapse_sdk/clients/agent/core.py +19 -0
- synapse_sdk/clients/agent/ray.py +298 -9
- synapse_sdk/clients/backend/__init__.py +41 -12
- synapse_sdk/clients/backend/annotation.py +13 -5
- synapse_sdk/clients/backend/core.py +59 -0
- synapse_sdk/clients/backend/data_collection.py +186 -0
- synapse_sdk/clients/backend/hitl.py +17 -0
- synapse_sdk/clients/backend/integration.py +19 -4
- synapse_sdk/clients/backend/ml.py +10 -7
- synapse_sdk/clients/backend/models.py +78 -0
- synapse_sdk/clients/base.py +381 -34
- 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/docs/.gitignore +20 -0
- synapse_sdk/devtools/docs/README.md +41 -0
- synapse_sdk/devtools/docs/blog/2019-05-28-first-blog-post.md +12 -0
- synapse_sdk/devtools/docs/blog/2019-05-29-long-blog-post.md +44 -0
- synapse_sdk/devtools/docs/blog/2021-08-01-mdx-blog-post.mdx +24 -0
- synapse_sdk/devtools/docs/blog/2021-08-26-welcome/docusaurus-plushie-banner.jpeg +0 -0
- synapse_sdk/devtools/docs/blog/2021-08-26-welcome/index.md +29 -0
- synapse_sdk/devtools/docs/blog/authors.yml +25 -0
- synapse_sdk/devtools/docs/blog/tags.yml +19 -0
- synapse_sdk/devtools/docs/docs/api/clients/agent.md +43 -0
- synapse_sdk/devtools/docs/docs/api/clients/annotation-mixin.md +378 -0
- synapse_sdk/devtools/docs/docs/api/clients/backend.md +420 -0
- synapse_sdk/devtools/docs/docs/api/clients/base.md +257 -0
- synapse_sdk/devtools/docs/docs/api/clients/core-mixin.md +477 -0
- synapse_sdk/devtools/docs/docs/api/clients/data-collection-mixin.md +422 -0
- synapse_sdk/devtools/docs/docs/api/clients/hitl-mixin.md +554 -0
- synapse_sdk/devtools/docs/docs/api/clients/index.md +391 -0
- synapse_sdk/devtools/docs/docs/api/clients/integration-mixin.md +571 -0
- synapse_sdk/devtools/docs/docs/api/clients/ml-mixin.md +578 -0
- synapse_sdk/devtools/docs/docs/api/clients/ray.md +342 -0
- synapse_sdk/devtools/docs/docs/api/index.md +52 -0
- synapse_sdk/devtools/docs/docs/api/plugins/categories.md +43 -0
- synapse_sdk/devtools/docs/docs/api/plugins/models.md +114 -0
- synapse_sdk/devtools/docs/docs/api/plugins/utils.md +328 -0
- synapse_sdk/devtools/docs/docs/categories.md +0 -0
- synapse_sdk/devtools/docs/docs/cli-usage.md +280 -0
- synapse_sdk/devtools/docs/docs/concepts/index.md +38 -0
- synapse_sdk/devtools/docs/docs/configuration.md +83 -0
- synapse_sdk/devtools/docs/docs/contributing.md +306 -0
- synapse_sdk/devtools/docs/docs/examples/index.md +29 -0
- synapse_sdk/devtools/docs/docs/faq.md +179 -0
- synapse_sdk/devtools/docs/docs/features/converters/index.md +455 -0
- synapse_sdk/devtools/docs/docs/features/index.md +24 -0
- synapse_sdk/devtools/docs/docs/features/utils/file.md +415 -0
- synapse_sdk/devtools/docs/docs/features/utils/network.md +378 -0
- synapse_sdk/devtools/docs/docs/features/utils/storage.md +57 -0
- synapse_sdk/devtools/docs/docs/features/utils/types.md +51 -0
- synapse_sdk/devtools/docs/docs/installation.md +94 -0
- synapse_sdk/devtools/docs/docs/introduction.md +47 -0
- synapse_sdk/devtools/docs/docs/plugins/categories/neural-net-plugins/train-action-overview.md +814 -0
- synapse_sdk/devtools/docs/docs/plugins/categories/pre-annotation-plugins/pre-annotation-plugin-overview.md +198 -0
- synapse_sdk/devtools/docs/docs/plugins/categories/pre-annotation-plugins/to-task-action-development.md +1645 -0
- synapse_sdk/devtools/docs/docs/plugins/categories/pre-annotation-plugins/to-task-overview.md +717 -0
- synapse_sdk/devtools/docs/docs/plugins/categories/pre-annotation-plugins/to-task-template-development.md +1380 -0
- synapse_sdk/devtools/docs/docs/plugins/categories/upload-plugins/upload-plugin-action.md +948 -0
- synapse_sdk/devtools/docs/docs/plugins/categories/upload-plugins/upload-plugin-overview.md +544 -0
- synapse_sdk/devtools/docs/docs/plugins/categories/upload-plugins/upload-plugin-template.md +766 -0
- synapse_sdk/devtools/docs/docs/plugins/export-plugins.md +1092 -0
- synapse_sdk/devtools/docs/docs/plugins/plugins.md +852 -0
- synapse_sdk/devtools/docs/docs/quickstart.md +78 -0
- synapse_sdk/devtools/docs/docs/troubleshooting.md +519 -0
- synapse_sdk/devtools/docs/docs/tutorial-basics/_category_.json +8 -0
- synapse_sdk/devtools/docs/docs/tutorial-basics/congratulations.md +23 -0
- synapse_sdk/devtools/docs/docs/tutorial-basics/create-a-blog-post.md +34 -0
- synapse_sdk/devtools/docs/docs/tutorial-basics/create-a-document.md +57 -0
- synapse_sdk/devtools/docs/docs/tutorial-basics/create-a-page.md +43 -0
- synapse_sdk/devtools/docs/docs/tutorial-basics/deploy-your-site.md +31 -0
- synapse_sdk/devtools/docs/docs/tutorial-basics/markdown-features.mdx +152 -0
- synapse_sdk/devtools/docs/docs/tutorial-extras/_category_.json +7 -0
- synapse_sdk/devtools/docs/docs/tutorial-extras/img/docsVersionDropdown.png +0 -0
- synapse_sdk/devtools/docs/docs/tutorial-extras/img/localeDropdown.png +0 -0
- synapse_sdk/devtools/docs/docs/tutorial-extras/manage-docs-versions.md +55 -0
- synapse_sdk/devtools/docs/docs/tutorial-extras/translate-your-site.md +88 -0
- synapse_sdk/devtools/docs/docusaurus.config.ts +148 -0
- synapse_sdk/devtools/docs/i18n/ko/code.json +325 -0
- synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/api/clients/agent.md +43 -0
- synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/api/clients/annotation-mixin.md +289 -0
- synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/api/clients/backend.md +420 -0
- synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/api/clients/base.md +257 -0
- synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/api/clients/core-mixin.md +417 -0
- synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/api/clients/data-collection-mixin.md +356 -0
- synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/api/clients/hitl-mixin.md +192 -0
- synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/api/clients/index.md +391 -0
- synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/api/clients/integration-mixin.md +479 -0
- synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/api/clients/ml-mixin.md +284 -0
- synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/api/clients/ray.md +342 -0
- synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/api/index.md +52 -0
- synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/api/plugins/models.md +114 -0
- synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/categories.md +0 -0
- synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/cli-usage.md +280 -0
- synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/concepts/index.md +38 -0
- synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/configuration.md +83 -0
- synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/contributing.md +306 -0
- synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/examples/index.md +29 -0
- synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/faq.md +179 -0
- synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/features/converters/index.md +30 -0
- synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/features/index.md +24 -0
- synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/features/utils/file.md +415 -0
- synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/features/utils/network.md +378 -0
- synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/features/utils/storage.md +60 -0
- synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/features/utils/types.md +51 -0
- synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/installation.md +94 -0
- synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/introduction.md +47 -0
- synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/plugins/categories/neural-net-plugins/train-action-overview.md +815 -0
- synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/plugins/categories/pre-annotation-plugins/pre-annotation-plugin-overview.md +198 -0
- synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/plugins/categories/pre-annotation-plugins/to-task-action-development.md +1645 -0
- synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/plugins/categories/pre-annotation-plugins/to-task-overview.md +717 -0
- synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/plugins/categories/pre-annotation-plugins/to-task-template-development.md +1380 -0
- synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/plugins/categories/upload-plugins/upload-plugin-action.md +948 -0
- synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/plugins/categories/upload-plugins/upload-plugin-overview.md +544 -0
- synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/plugins/categories/upload-plugins/upload-plugin-template.md +766 -0
- synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/plugins/export-plugins.md +1092 -0
- synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/plugins/plugins.md +117 -0
- synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/quickstart.md +78 -0
- synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/troubleshooting.md +519 -0
- synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current.json +34 -0
- synapse_sdk/devtools/docs/i18n/ko/docusaurus-theme-classic/footer.json +42 -0
- synapse_sdk/devtools/docs/i18n/ko/docusaurus-theme-classic/navbar.json +18 -0
- synapse_sdk/devtools/docs/package-lock.json +18784 -0
- synapse_sdk/devtools/docs/package.json +48 -0
- synapse_sdk/devtools/docs/sidebars.ts +122 -0
- synapse_sdk/devtools/docs/src/components/HomepageFeatures/index.tsx +71 -0
- synapse_sdk/devtools/docs/src/components/HomepageFeatures/styles.module.css +11 -0
- synapse_sdk/devtools/docs/src/css/custom.css +30 -0
- synapse_sdk/devtools/docs/src/pages/index.module.css +23 -0
- synapse_sdk/devtools/docs/src/pages/index.tsx +21 -0
- synapse_sdk/devtools/docs/src/pages/markdown-page.md +7 -0
- synapse_sdk/devtools/docs/static/.nojekyll +0 -0
- synapse_sdk/devtools/docs/static/img/docusaurus-social-card.jpg +0 -0
- synapse_sdk/devtools/docs/static/img/docusaurus.png +0 -0
- synapse_sdk/devtools/docs/static/img/favicon.ico +0 -0
- synapse_sdk/devtools/docs/static/img/logo.png +0 -0
- synapse_sdk/devtools/docs/static/img/undraw_docusaurus_mountain.svg +171 -0
- synapse_sdk/devtools/docs/static/img/undraw_docusaurus_react.svg +170 -0
- synapse_sdk/devtools/docs/static/img/undraw_docusaurus_tree.svg +40 -0
- synapse_sdk/devtools/docs/tsconfig.json +8 -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 +74 -9
- synapse_sdk/plugins/README.md +1340 -0
- synapse_sdk/plugins/__init__.py +0 -13
- synapse_sdk/plugins/categories/base.py +145 -30
- 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 +29 -14
- synapse_sdk/plugins/categories/neural_net/actions/inference.py +13 -1
- synapse_sdk/plugins/categories/neural_net/actions/train.py +1084 -38
- synapse_sdk/plugins/categories/neural_net/actions/tune.py +534 -0
- synapse_sdk/plugins/categories/neural_net/base/__init__.py +0 -0
- synapse_sdk/plugins/categories/neural_net/base/inference.py +37 -0
- synapse_sdk/plugins/categories/neural_net/templates/config.yaml +30 -5
- 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 +145 -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 +97 -0
- synapse_sdk/plugins/categories/pre_annotation/actions/to_task/orchestrator.py +250 -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 +287 -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 +87 -0
- synapse_sdk/plugins/categories/pre_annotation/actions/to_task/strategies/preprocessor.py +127 -0
- synapse_sdk/plugins/categories/pre_annotation/actions/to_task/strategies/validation.py +143 -0
- synapse_sdk/plugins/categories/pre_annotation/actions/to_task.py +966 -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 +5 -2
- 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 +232 -0
- synapse_sdk/plugins/categories/upload/actions/upload/context.py +185 -0
- synapse_sdk/plugins/categories/upload/actions/upload/enums.py +471 -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 +203 -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 +84 -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 +203 -0
- synapse_sdk/plugins/categories/upload/actions/upload/steps/upload.py +97 -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 +258 -0
- synapse_sdk/plugins/categories/upload/actions/upload/strategies/file_discovery/recursive.py +281 -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 +294 -0
- synapse_sdk/plugins/categories/upload/templates/plugin/upload.py +102 -0
- synapse_sdk/plugins/enums.py +3 -1
- synapse_sdk/plugins/models.py +140 -16
- 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/legacy.py +95 -0
- 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 +56 -0
- synapse_sdk/utils/converters/dm/from_v1.py +627 -0
- synapse_sdk/utils/converters/dm/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 +39 -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/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.11.7.dist-info/METADATA +122 -0
- synapse_sdk-2025.11.7.dist-info/RECORD +386 -0
- {synapse_sdk-1.0.0a13.dist-info → synapse_sdk-2025.11.7.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/cli/publish.py +0 -37
- 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/plugins/utils.py +0 -50
- synapse_sdk/utils/file.py +0 -87
- synapse_sdk/utils/storage.py +0 -91
- synapse_sdk-1.0.0a13.dist-info/METADATA +0 -43
- synapse_sdk-1.0.0a13.dist-info/RECORD +0 -111
- /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.0a13.dist-info → synapse_sdk-2025.11.7.dist-info}/entry_points.txt +0 -0
- {synapse_sdk-1.0.0a13.dist-info → synapse_sdk-2025.11.7.dist-info/licenses}/LICENSE +0 -0
- {synapse_sdk-1.0.0a13.dist-info → synapse_sdk-2025.11.7.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
"""Job service for managing job operations."""
|
|
2
|
+
|
|
3
|
+
from datetime import datetime
|
|
4
|
+
from typing import Dict, List, Optional
|
|
5
|
+
|
|
6
|
+
from synapse_sdk.clients.backend import BackendClient
|
|
7
|
+
from synapse_sdk.clients.exceptions import ClientError
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class JobService:
|
|
11
|
+
"""Service for job-related operations."""
|
|
12
|
+
|
|
13
|
+
def __init__(self, backend_client: Optional[BackendClient] = None):
|
|
14
|
+
self.backend_client = backend_client
|
|
15
|
+
|
|
16
|
+
def list_jobs(self, agent_id: Optional[int] = None, agent_info: Optional[Dict] = None) -> List[Dict]:
|
|
17
|
+
"""List jobs from the backend."""
|
|
18
|
+
if not self.backend_client:
|
|
19
|
+
return []
|
|
20
|
+
|
|
21
|
+
try:
|
|
22
|
+
params = {}
|
|
23
|
+
if agent_id:
|
|
24
|
+
params['agent'] = agent_id
|
|
25
|
+
|
|
26
|
+
jobs_response = self.backend_client.list_jobs(params=params)
|
|
27
|
+
|
|
28
|
+
# Handle paginated response - extract results
|
|
29
|
+
if jobs_response is None:
|
|
30
|
+
return []
|
|
31
|
+
elif isinstance(jobs_response, dict) and 'results' in jobs_response:
|
|
32
|
+
jobs = jobs_response['results']
|
|
33
|
+
else:
|
|
34
|
+
jobs = jobs_response if isinstance(jobs_response, list) else []
|
|
35
|
+
|
|
36
|
+
# Remove None jobs and sort by created time (most recent first)
|
|
37
|
+
valid_jobs = [job for job in jobs if job is not None]
|
|
38
|
+
valid_jobs.sort(key=lambda job: job.get('created', ''), reverse=True)
|
|
39
|
+
|
|
40
|
+
# Try to enrich jobs with plugin names
|
|
41
|
+
enriched_jobs = []
|
|
42
|
+
for job in valid_jobs:
|
|
43
|
+
enriched_job = job.copy()
|
|
44
|
+
|
|
45
|
+
# Try to get plugin info
|
|
46
|
+
if 'plugin_release' in job:
|
|
47
|
+
try:
|
|
48
|
+
# Try to fetch plugin release details
|
|
49
|
+
plugin_release_response = self.backend_client.get(f'/plugin_releases/{job["plugin_release"]}/')
|
|
50
|
+
if plugin_release_response and isinstance(plugin_release_response, dict):
|
|
51
|
+
# Get version from plugin release
|
|
52
|
+
enriched_job['plugin_version'] = plugin_release_response.get('version')
|
|
53
|
+
|
|
54
|
+
# Try to get plugin details from the plugin ID
|
|
55
|
+
plugin_id = plugin_release_response.get('plugin')
|
|
56
|
+
if plugin_id:
|
|
57
|
+
try:
|
|
58
|
+
plugin_response = self.backend_client.get(f'/plugins/{plugin_id}/')
|
|
59
|
+
if plugin_response and isinstance(plugin_response, dict):
|
|
60
|
+
enriched_job['plugin_name'] = plugin_response.get('name')
|
|
61
|
+
enriched_job['plugin_code'] = plugin_response.get('code')
|
|
62
|
+
except Exception:
|
|
63
|
+
# Fallback to config if plugin fetch fails
|
|
64
|
+
config = plugin_release_response.get('config', {})
|
|
65
|
+
enriched_job['plugin_name'] = config.get('name') or config.get('code')
|
|
66
|
+
enriched_job['plugin_code'] = config.get('code')
|
|
67
|
+
else:
|
|
68
|
+
# Fallback to config if no plugin ID
|
|
69
|
+
config = plugin_release_response.get('config', {})
|
|
70
|
+
enriched_job['plugin_name'] = config.get('name') or config.get('code')
|
|
71
|
+
enriched_job['plugin_code'] = config.get('code')
|
|
72
|
+
except Exception:
|
|
73
|
+
pass
|
|
74
|
+
|
|
75
|
+
# Try to get agent info
|
|
76
|
+
if 'agent' in job:
|
|
77
|
+
# First check if we have local agent info
|
|
78
|
+
if agent_info and job.get('agent') == agent_id:
|
|
79
|
+
enriched_job['agent_name'] = agent_info.get('name')
|
|
80
|
+
enriched_job['agent_url'] = agent_info.get('url')
|
|
81
|
+
else:
|
|
82
|
+
# Try to fetch agent details from API
|
|
83
|
+
try:
|
|
84
|
+
agent_response = self.backend_client.get(f'/agents/{job["agent"]}/')
|
|
85
|
+
if agent_response and isinstance(agent_response, dict):
|
|
86
|
+
enriched_job['agent_name'] = agent_response.get('name')
|
|
87
|
+
enriched_job['agent_url'] = agent_response.get('url')
|
|
88
|
+
except Exception:
|
|
89
|
+
pass
|
|
90
|
+
|
|
91
|
+
enriched_jobs.append(enriched_job)
|
|
92
|
+
|
|
93
|
+
return enriched_jobs
|
|
94
|
+
except ClientError:
|
|
95
|
+
raise
|
|
96
|
+
except Exception as e:
|
|
97
|
+
raise Exception(f'Failed to list jobs: {e}')
|
|
98
|
+
|
|
99
|
+
def get_job_logs(self, job_id: str):
|
|
100
|
+
"""Get all logs for a job at once."""
|
|
101
|
+
if not self.backend_client:
|
|
102
|
+
raise Exception('Backend client not configured')
|
|
103
|
+
|
|
104
|
+
try:
|
|
105
|
+
# Get logs from console_logs endpoint (returns list of strings)
|
|
106
|
+
logs_response = self.backend_client.list_job_console_logs(job_id)
|
|
107
|
+
|
|
108
|
+
# API returns a list of log strings
|
|
109
|
+
if isinstance(logs_response, list):
|
|
110
|
+
if not logs_response:
|
|
111
|
+
# Empty list means no logs yet
|
|
112
|
+
yield 'No logs available for this job yet.\n'
|
|
113
|
+
else:
|
|
114
|
+
for log_entry in logs_response:
|
|
115
|
+
# Each entry is already a formatted string with timestamp
|
|
116
|
+
yield str(log_entry) + '\n' if not str(log_entry).endswith('\n') else str(log_entry)
|
|
117
|
+
elif logs_response:
|
|
118
|
+
# Fallback for unexpected format
|
|
119
|
+
yield str(logs_response) + '\n'
|
|
120
|
+
else:
|
|
121
|
+
yield 'No logs available for this job yet.\n'
|
|
122
|
+
|
|
123
|
+
except Exception as e:
|
|
124
|
+
from synapse_sdk.clients.exceptions import ClientError
|
|
125
|
+
|
|
126
|
+
# Check if it's a ClientError with specific status
|
|
127
|
+
if isinstance(e, ClientError):
|
|
128
|
+
if e.status == 404:
|
|
129
|
+
yield 'Job not found or logs not available.\n'
|
|
130
|
+
elif e.status == 401:
|
|
131
|
+
yield 'Unauthorized to access job logs.\n'
|
|
132
|
+
else:
|
|
133
|
+
# Check for Korean error message in the reason
|
|
134
|
+
error_str = str(e.reason) if hasattr(e, 'reason') else str(e)
|
|
135
|
+
if '찾을 수 없습니다' in error_str:
|
|
136
|
+
yield 'Job logs not found. The job may not have generated any logs yet.\n'
|
|
137
|
+
else:
|
|
138
|
+
yield f'Failed to fetch logs: {error_str}\n'
|
|
139
|
+
else:
|
|
140
|
+
error_str = str(e)
|
|
141
|
+
if '찾을 수 없습니다' in error_str or '404' in error_str or 'Not found' in error_str:
|
|
142
|
+
yield 'Job logs not found. The job may not have generated any logs yet.\n'
|
|
143
|
+
elif '401' in error_str or 'Unauthorized' in error_str:
|
|
144
|
+
yield 'Unauthorized to access job logs.\n'
|
|
145
|
+
else:
|
|
146
|
+
yield f'Failed to fetch logs: {error_str}\n'
|
|
147
|
+
|
|
148
|
+
def stream_job_logs(self, job_id: str):
|
|
149
|
+
"""Stream logs for a job (simulated streaming since tail endpoint doesn't exist)."""
|
|
150
|
+
if not self.backend_client:
|
|
151
|
+
raise Exception('Backend client not configured')
|
|
152
|
+
|
|
153
|
+
# Since tail_console_logs endpoint returns 404, we'll simulate streaming
|
|
154
|
+
# by fetching all logs and yielding them one by one
|
|
155
|
+
try:
|
|
156
|
+
from synapse_sdk.clients.exceptions import ClientError
|
|
157
|
+
|
|
158
|
+
# Get logs from console_logs endpoint (returns list of strings)
|
|
159
|
+
logs_response = self.backend_client.list_job_console_logs(job_id)
|
|
160
|
+
|
|
161
|
+
# API returns a list of log strings
|
|
162
|
+
if isinstance(logs_response, list):
|
|
163
|
+
if not logs_response:
|
|
164
|
+
# Empty list means no logs yet
|
|
165
|
+
yield 'No logs available for this job yet.\n'
|
|
166
|
+
else:
|
|
167
|
+
# Yield logs one by one to simulate streaming
|
|
168
|
+
for log_entry in logs_response:
|
|
169
|
+
# Each entry is already a formatted string with timestamp
|
|
170
|
+
yield str(log_entry) + '\n' if not str(log_entry).endswith('\n') else str(log_entry)
|
|
171
|
+
elif logs_response:
|
|
172
|
+
# Fallback for unexpected format
|
|
173
|
+
yield str(logs_response) + '\n'
|
|
174
|
+
else:
|
|
175
|
+
yield 'No logs available for this job yet.\n'
|
|
176
|
+
|
|
177
|
+
except Exception as e:
|
|
178
|
+
# Check if it's a ClientError with specific status
|
|
179
|
+
if isinstance(e, ClientError):
|
|
180
|
+
if e.status == 404:
|
|
181
|
+
yield 'Job not found or logs not available.\n'
|
|
182
|
+
elif e.status == 401:
|
|
183
|
+
yield 'Unauthorized to access job logs.\n'
|
|
184
|
+
else:
|
|
185
|
+
# Check for Korean error message in the reason
|
|
186
|
+
error_str = str(e.reason) if hasattr(e, 'reason') else str(e)
|
|
187
|
+
if '찾을 수 없습니다' in error_str:
|
|
188
|
+
yield 'Job logs not found. The job may not have generated any logs yet.\n'
|
|
189
|
+
else:
|
|
190
|
+
yield f'Failed to stream logs: {error_str}\n'
|
|
191
|
+
else:
|
|
192
|
+
error_str = str(e)
|
|
193
|
+
if '찾을 수 없습니다' in error_str or '404' in error_str or 'Not found' in error_str:
|
|
194
|
+
yield 'Job logs not found. The job may not have generated any logs yet.\n'
|
|
195
|
+
elif '401' in error_str or 'Unauthorized' in error_str:
|
|
196
|
+
yield 'Unauthorized to access job logs.\n'
|
|
197
|
+
else:
|
|
198
|
+
yield f'Failed to stream logs: {error_str}\n'
|
|
199
|
+
|
|
200
|
+
@staticmethod
|
|
201
|
+
def format_duration(created: str, completed: Optional[str] = None) -> str:
|
|
202
|
+
"""Format duration between created and completed timestamps."""
|
|
203
|
+
if not created:
|
|
204
|
+
return '-'
|
|
205
|
+
|
|
206
|
+
try:
|
|
207
|
+
created_dt = datetime.fromisoformat(created.replace('+09:00', '+09:00'))
|
|
208
|
+
if completed:
|
|
209
|
+
completed_dt = datetime.fromisoformat(completed.replace('+09:00', '+09:00'))
|
|
210
|
+
duration = completed_dt - created_dt
|
|
211
|
+
total_seconds = int(duration.total_seconds())
|
|
212
|
+
if total_seconds < 60:
|
|
213
|
+
return f'{total_seconds}s'
|
|
214
|
+
else:
|
|
215
|
+
minutes = total_seconds // 60
|
|
216
|
+
seconds = total_seconds % 60
|
|
217
|
+
return f'{minutes}m {seconds}s'
|
|
218
|
+
else:
|
|
219
|
+
return '...'
|
|
220
|
+
except Exception:
|
|
221
|
+
return '-'
|
|
222
|
+
|
|
223
|
+
@staticmethod
|
|
224
|
+
def format_timestamp(timestamp: str) -> str:
|
|
225
|
+
"""Format timestamp for display."""
|
|
226
|
+
if not timestamp:
|
|
227
|
+
return '-'
|
|
228
|
+
|
|
229
|
+
try:
|
|
230
|
+
dt = datetime.fromisoformat(timestamp.replace('+09:00', '+09:00'))
|
|
231
|
+
return dt.strftime('%m/%d %H:%M')
|
|
232
|
+
except Exception:
|
|
233
|
+
return timestamp[:16] if len(timestamp) > 16 else timestamp
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
"""Plugin service for managing plugin operations."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import os
|
|
5
|
+
import time
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from typing import Dict, Optional
|
|
8
|
+
|
|
9
|
+
import yaml
|
|
10
|
+
|
|
11
|
+
from synapse_sdk.cli.plugin.publish import _publish
|
|
12
|
+
from synapse_sdk.clients.backend import BackendClient
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class PluginService:
|
|
16
|
+
"""Service for plugin-related operations."""
|
|
17
|
+
|
|
18
|
+
def __init__(self, plugin_directory: Path, backend_client: Optional[BackendClient] = None):
|
|
19
|
+
self.plugin_directory = plugin_directory
|
|
20
|
+
self.config_path = plugin_directory / 'config.yaml'
|
|
21
|
+
self.test_http_path = plugin_directory / 'test.http'
|
|
22
|
+
self.backend_client = backend_client
|
|
23
|
+
|
|
24
|
+
def load_config(self) -> Dict:
|
|
25
|
+
"""Load plugin configuration from config.yaml."""
|
|
26
|
+
if not self.config_path.exists():
|
|
27
|
+
return {}
|
|
28
|
+
|
|
29
|
+
try:
|
|
30
|
+
with open(self.config_path, 'r') as f:
|
|
31
|
+
return yaml.safe_load(f)
|
|
32
|
+
except Exception:
|
|
33
|
+
return {}
|
|
34
|
+
|
|
35
|
+
def save_config(self, config: Dict) -> bool:
|
|
36
|
+
"""Save plugin configuration to config.yaml."""
|
|
37
|
+
try:
|
|
38
|
+
# Backup existing config
|
|
39
|
+
if self.config_path.exists():
|
|
40
|
+
backup_path = self.config_path.with_suffix('.yaml.bak')
|
|
41
|
+
self.config_path.rename(backup_path)
|
|
42
|
+
|
|
43
|
+
# Write new config
|
|
44
|
+
with open(self.config_path, 'w') as f:
|
|
45
|
+
yaml.dump(config, f, default_flow_style=False, allow_unicode=True, indent=2)
|
|
46
|
+
|
|
47
|
+
return True
|
|
48
|
+
except Exception:
|
|
49
|
+
# Restore backup if write failed
|
|
50
|
+
backup_path = self.config_path.with_suffix('.yaml.bak')
|
|
51
|
+
if backup_path.exists():
|
|
52
|
+
backup_path.rename(self.config_path)
|
|
53
|
+
return False
|
|
54
|
+
|
|
55
|
+
def parse_test_http(self) -> Dict[str, Dict]:
|
|
56
|
+
"""Parse test.http file and extract action parameters."""
|
|
57
|
+
if not self.test_http_path.exists():
|
|
58
|
+
return {}
|
|
59
|
+
|
|
60
|
+
requests = {}
|
|
61
|
+
current_request_name = None
|
|
62
|
+
current_body_lines = []
|
|
63
|
+
in_body = False
|
|
64
|
+
|
|
65
|
+
try:
|
|
66
|
+
with open(self.test_http_path, 'r') as f:
|
|
67
|
+
for line in f:
|
|
68
|
+
line = line.strip()
|
|
69
|
+
if line.startswith('###'):
|
|
70
|
+
# Process previous request
|
|
71
|
+
if current_request_name and current_body_lines:
|
|
72
|
+
try:
|
|
73
|
+
full_request = json.loads(''.join(current_body_lines))
|
|
74
|
+
if 'params' in full_request:
|
|
75
|
+
requests[current_request_name] = full_request['params']
|
|
76
|
+
except json.JSONDecodeError:
|
|
77
|
+
pass
|
|
78
|
+
|
|
79
|
+
# Start new request
|
|
80
|
+
current_request_name = line.replace('###', '').strip()
|
|
81
|
+
current_body_lines = []
|
|
82
|
+
in_body = False
|
|
83
|
+
elif current_request_name and line.startswith('{'):
|
|
84
|
+
in_body = True
|
|
85
|
+
current_body_lines.append(line)
|
|
86
|
+
elif in_body and current_request_name:
|
|
87
|
+
current_body_lines.append(line)
|
|
88
|
+
|
|
89
|
+
# Process last request
|
|
90
|
+
if current_request_name and current_body_lines:
|
|
91
|
+
try:
|
|
92
|
+
full_request = json.loads(''.join(current_body_lines))
|
|
93
|
+
if 'params' in full_request:
|
|
94
|
+
requests[current_request_name] = full_request['params']
|
|
95
|
+
except json.JSONDecodeError:
|
|
96
|
+
pass
|
|
97
|
+
|
|
98
|
+
return requests
|
|
99
|
+
except Exception:
|
|
100
|
+
return {}
|
|
101
|
+
|
|
102
|
+
def update_test_http_params(self, action: str, new_params: Dict) -> bool:
|
|
103
|
+
"""Update parameters for a specific action in test.http."""
|
|
104
|
+
if not self.test_http_path.exists():
|
|
105
|
+
return False
|
|
106
|
+
|
|
107
|
+
try:
|
|
108
|
+
with open(self.test_http_path, 'r') as f:
|
|
109
|
+
lines = f.readlines()
|
|
110
|
+
|
|
111
|
+
current_action = None
|
|
112
|
+
in_json = False
|
|
113
|
+
json_start_line = -1
|
|
114
|
+
json_lines = []
|
|
115
|
+
updated = False
|
|
116
|
+
|
|
117
|
+
for i, line in enumerate(lines):
|
|
118
|
+
if line.strip().startswith('###'):
|
|
119
|
+
current_action = line.replace('###', '').strip()
|
|
120
|
+
in_json = False
|
|
121
|
+
json_lines = []
|
|
122
|
+
elif current_action and line.strip().startswith('{'):
|
|
123
|
+
in_json = True
|
|
124
|
+
json_start_line = i
|
|
125
|
+
json_lines = [line]
|
|
126
|
+
elif in_json:
|
|
127
|
+
json_lines.append(line)
|
|
128
|
+
if line.strip() == '}':
|
|
129
|
+
if current_action == action:
|
|
130
|
+
try:
|
|
131
|
+
full_json = json.loads(''.join(json_lines))
|
|
132
|
+
full_json['params'] = new_params
|
|
133
|
+
new_json = json.dumps(full_json, indent=2)
|
|
134
|
+
lines[json_start_line : i + 1] = [new_json + '\n']
|
|
135
|
+
updated = True
|
|
136
|
+
break
|
|
137
|
+
except json.JSONDecodeError:
|
|
138
|
+
pass
|
|
139
|
+
in_json = False
|
|
140
|
+
json_lines = []
|
|
141
|
+
|
|
142
|
+
if updated:
|
|
143
|
+
with open(self.test_http_path, 'w') as f:
|
|
144
|
+
f.writelines(lines)
|
|
145
|
+
return True
|
|
146
|
+
|
|
147
|
+
return False
|
|
148
|
+
except Exception:
|
|
149
|
+
return False
|
|
150
|
+
|
|
151
|
+
def execute_plugin_action(
|
|
152
|
+
self, action: str, params: Dict, plugin_code: str, agent_id: Optional[int] = None, debug: bool = True
|
|
153
|
+
) -> Dict:
|
|
154
|
+
"""Execute a plugin action via HTTP request."""
|
|
155
|
+
if not self.backend_client:
|
|
156
|
+
return {'success': False, 'error': 'Backend client not configured'}
|
|
157
|
+
|
|
158
|
+
if not plugin_code:
|
|
159
|
+
return {'success': False, 'error': 'Plugin code not found in configuration'}
|
|
160
|
+
|
|
161
|
+
plugin_url = f'{self.backend_client.base_url}/plugins/{plugin_code}/run/'
|
|
162
|
+
|
|
163
|
+
headers = {
|
|
164
|
+
'Accept': 'application/json; indent=4',
|
|
165
|
+
'Content-Type': 'application/json',
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
# Get auth headers from backend client
|
|
169
|
+
auth_headers = self.backend_client._get_headers()
|
|
170
|
+
headers.update(auth_headers)
|
|
171
|
+
|
|
172
|
+
payload = {
|
|
173
|
+
'agent': agent_id or 2,
|
|
174
|
+
'action': action,
|
|
175
|
+
'params': params,
|
|
176
|
+
'debug': debug,
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
start_time = time.time()
|
|
180
|
+
|
|
181
|
+
try:
|
|
182
|
+
import requests
|
|
183
|
+
|
|
184
|
+
response = requests.post(plugin_url, json=payload, headers=headers, timeout=30)
|
|
185
|
+
execution_time = int((time.time() - start_time) * 1000)
|
|
186
|
+
|
|
187
|
+
try:
|
|
188
|
+
response_data = response.json()
|
|
189
|
+
except Exception:
|
|
190
|
+
response_data = response.text
|
|
191
|
+
|
|
192
|
+
return {
|
|
193
|
+
'success': response.status_code < 400,
|
|
194
|
+
'status_code': response.status_code,
|
|
195
|
+
'response_data': response_data,
|
|
196
|
+
'execution_time': execution_time,
|
|
197
|
+
'url': plugin_url,
|
|
198
|
+
'method': 'POST',
|
|
199
|
+
'headers': headers,
|
|
200
|
+
'payload': payload,
|
|
201
|
+
}
|
|
202
|
+
except Exception as e:
|
|
203
|
+
execution_time = int((time.time() - start_time) * 1000)
|
|
204
|
+
return {
|
|
205
|
+
'success': False,
|
|
206
|
+
'status_code': 500,
|
|
207
|
+
'error': str(e),
|
|
208
|
+
'execution_time': execution_time,
|
|
209
|
+
'url': plugin_url,
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
def publish_plugin(self, host: str, access_token: str, debug: bool = True) -> Dict:
|
|
213
|
+
"""Publish plugin to Synapse platform."""
|
|
214
|
+
original_cwd = os.getcwd()
|
|
215
|
+
try:
|
|
216
|
+
os.chdir(str(self.plugin_directory))
|
|
217
|
+
|
|
218
|
+
debug_modules = os.getenv('SYNAPSE_DEBUG_MODULES', '')
|
|
219
|
+
plugin_release = _publish(host, access_token, debug, debug_modules)
|
|
220
|
+
|
|
221
|
+
return {
|
|
222
|
+
'success': True,
|
|
223
|
+
'message': (
|
|
224
|
+
f'Successfully published "{plugin_release.name}" ({plugin_release.code}) to synapse backend!'
|
|
225
|
+
),
|
|
226
|
+
'plugin_code': plugin_release.code,
|
|
227
|
+
'version': plugin_release.version,
|
|
228
|
+
'name': plugin_release.name,
|
|
229
|
+
}
|
|
230
|
+
except Exception as e:
|
|
231
|
+
return {
|
|
232
|
+
'success': False,
|
|
233
|
+
'error': str(e),
|
|
234
|
+
}
|
|
235
|
+
finally:
|
|
236
|
+
os.chdir(original_cwd)
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"""Serve service for managing serve deployments."""
|
|
2
|
+
|
|
3
|
+
from typing import Dict, List, Optional
|
|
4
|
+
|
|
5
|
+
from synapse_sdk.clients.backend import BackendClient
|
|
6
|
+
from synapse_sdk.clients.exceptions import ClientError
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class ServeService:
|
|
10
|
+
"""Service for serve deployment operations."""
|
|
11
|
+
|
|
12
|
+
def __init__(self, backend_client: Optional[BackendClient] = None):
|
|
13
|
+
self.backend_client = backend_client
|
|
14
|
+
|
|
15
|
+
def list_serve_applications(self, agent_id: Optional[int] = None, agent_info: Optional[Dict] = None) -> List[Dict]:
|
|
16
|
+
"""List serve applications from the backend."""
|
|
17
|
+
if not self.backend_client:
|
|
18
|
+
return []
|
|
19
|
+
|
|
20
|
+
try:
|
|
21
|
+
params = {}
|
|
22
|
+
if agent_id:
|
|
23
|
+
params['agent'] = agent_id
|
|
24
|
+
|
|
25
|
+
apps_response = self.backend_client.list_serve_applications(params=params)
|
|
26
|
+
|
|
27
|
+
# Handle paginated response - extract results
|
|
28
|
+
if apps_response is None:
|
|
29
|
+
return []
|
|
30
|
+
elif isinstance(apps_response, dict) and 'results' in apps_response:
|
|
31
|
+
applications = apps_response['results']
|
|
32
|
+
else:
|
|
33
|
+
applications = apps_response if isinstance(apps_response, list) else []
|
|
34
|
+
|
|
35
|
+
# Remove None applications
|
|
36
|
+
valid_apps = [app for app in applications if app is not None]
|
|
37
|
+
|
|
38
|
+
# Try to enrich applications with plugin and agent names
|
|
39
|
+
enriched_apps = []
|
|
40
|
+
for app in valid_apps:
|
|
41
|
+
enriched_app = app.copy()
|
|
42
|
+
|
|
43
|
+
# Try to get plugin info
|
|
44
|
+
if 'plugin_release' in app:
|
|
45
|
+
try:
|
|
46
|
+
# Try to fetch plugin release details
|
|
47
|
+
plugin_release_response = self.backend_client.get(f'/plugin_releases/{app["plugin_release"]}/')
|
|
48
|
+
if plugin_release_response and isinstance(plugin_release_response, dict):
|
|
49
|
+
# Get version from plugin release
|
|
50
|
+
enriched_app['plugin_version'] = plugin_release_response.get('version')
|
|
51
|
+
|
|
52
|
+
# Try to get plugin details from the plugin ID
|
|
53
|
+
plugin_id = plugin_release_response.get('plugin')
|
|
54
|
+
if plugin_id:
|
|
55
|
+
try:
|
|
56
|
+
plugin_response = self.backend_client.get(f'/plugins/{plugin_id}/')
|
|
57
|
+
if plugin_response and isinstance(plugin_response, dict):
|
|
58
|
+
enriched_app['plugin_name'] = plugin_response.get('name')
|
|
59
|
+
enriched_app['plugin_code'] = plugin_response.get('code')
|
|
60
|
+
except Exception:
|
|
61
|
+
# Fallback to config if plugin fetch fails
|
|
62
|
+
config = plugin_release_response.get('config', {})
|
|
63
|
+
enriched_app['plugin_name'] = config.get('name') or config.get('code')
|
|
64
|
+
enriched_app['plugin_code'] = config.get('code')
|
|
65
|
+
else:
|
|
66
|
+
# Fallback to config if no plugin ID
|
|
67
|
+
config = plugin_release_response.get('config', {})
|
|
68
|
+
enriched_app['plugin_name'] = config.get('name') or config.get('code')
|
|
69
|
+
enriched_app['plugin_code'] = config.get('code')
|
|
70
|
+
except Exception:
|
|
71
|
+
pass
|
|
72
|
+
|
|
73
|
+
# Try to get agent info
|
|
74
|
+
if 'agent' in app:
|
|
75
|
+
# First check if we have local agent info
|
|
76
|
+
if agent_info and app.get('agent') == agent_id:
|
|
77
|
+
enriched_app['agent_name'] = agent_info.get('name')
|
|
78
|
+
enriched_app['agent_url'] = agent_info.get('url')
|
|
79
|
+
else:
|
|
80
|
+
# Try to fetch agent details from API
|
|
81
|
+
try:
|
|
82
|
+
agent_response = self.backend_client.get(f'/agents/{app["agent"]}/')
|
|
83
|
+
if agent_response and isinstance(agent_response, dict):
|
|
84
|
+
enriched_app['agent_name'] = agent_response.get('name')
|
|
85
|
+
enriched_app['agent_url'] = agent_response.get('url')
|
|
86
|
+
except Exception:
|
|
87
|
+
pass
|
|
88
|
+
|
|
89
|
+
enriched_apps.append(enriched_app)
|
|
90
|
+
|
|
91
|
+
return enriched_apps
|
|
92
|
+
except ClientError:
|
|
93
|
+
raise
|
|
94
|
+
except Exception as e:
|
|
95
|
+
raise Exception(f'Failed to list serve applications: {e}')
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"""UI components for the Streamlit app."""
|
|
2
|
+
|
|
3
|
+
from .config_tab import ConfigTab
|
|
4
|
+
from .deployment_tab import DeploymentTab
|
|
5
|
+
from .http_tab import HttpTab
|
|
6
|
+
from .jobs_tab import JobsTab
|
|
7
|
+
from .serve_tab import ServeTab
|
|
8
|
+
|
|
9
|
+
__all__ = [
|
|
10
|
+
'ConfigTab',
|
|
11
|
+
'DeploymentTab',
|
|
12
|
+
'HttpTab',
|
|
13
|
+
'JobsTab',
|
|
14
|
+
'ServeTab',
|
|
15
|
+
]
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"""Configuration tab UI component."""
|
|
2
|
+
|
|
3
|
+
import streamlit as st
|
|
4
|
+
|
|
5
|
+
from ..services.plugin_service import PluginService
|
|
6
|
+
from ..utils.ui_components import render_info_card
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class ConfigTab:
|
|
10
|
+
"""UI component for the Configuration tab."""
|
|
11
|
+
|
|
12
|
+
def __init__(self, plugin_service: PluginService):
|
|
13
|
+
self.plugin_service = plugin_service
|
|
14
|
+
|
|
15
|
+
def render(self):
|
|
16
|
+
"""Render the Configuration tab."""
|
|
17
|
+
config = st.session_state.get('config', self.plugin_service.load_config())
|
|
18
|
+
|
|
19
|
+
if not config:
|
|
20
|
+
render_info_card(
|
|
21
|
+
'No Configuration',
|
|
22
|
+
'No plugin configuration file found. Please create a config.yaml file.',
|
|
23
|
+
type='error',
|
|
24
|
+
)
|
|
25
|
+
return
|
|
26
|
+
|
|
27
|
+
# Display file path
|
|
28
|
+
render_info_card('Configuration File', str(self.plugin_service.config_path), type='neutral', icon='📁')
|
|
29
|
+
|
|
30
|
+
# Configuration form
|
|
31
|
+
with st.form('config_form'):
|
|
32
|
+
col1, col2 = st.columns(2)
|
|
33
|
+
|
|
34
|
+
with col1:
|
|
35
|
+
config['name'] = st.text_input('Plugin Name', value=config.get('name', ''))
|
|
36
|
+
config['code'] = st.text_input('Code', value=config.get('code', ''))
|
|
37
|
+
config['version'] = st.text_input('Version', value=config.get('version', ''))
|
|
38
|
+
|
|
39
|
+
categories = [
|
|
40
|
+
'neural_net',
|
|
41
|
+
'export',
|
|
42
|
+
'upload',
|
|
43
|
+
'smart_tool',
|
|
44
|
+
'post_annotation',
|
|
45
|
+
'pre_annotation',
|
|
46
|
+
'data_validation',
|
|
47
|
+
]
|
|
48
|
+
current_category = config.get('category', '')
|
|
49
|
+
category_index = categories.index(current_category) if current_category in categories else 0
|
|
50
|
+
config['category'] = st.selectbox('Category', categories, index=category_index)
|
|
51
|
+
|
|
52
|
+
with col2:
|
|
53
|
+
data_types = ['image', 'text', 'video', 'pcd', 'audio']
|
|
54
|
+
current_data_type = config.get('data_type', '')
|
|
55
|
+
data_type_index = data_types.index(current_data_type) if current_data_type in data_types else 0
|
|
56
|
+
config['data_type'] = st.selectbox('Data Type', data_types, index=data_type_index)
|
|
57
|
+
|
|
58
|
+
package_managers = ['pip', 'uv']
|
|
59
|
+
current_pm = config.get('package_manager', '')
|
|
60
|
+
pm_index = package_managers.index(current_pm) if current_pm in package_managers else 0
|
|
61
|
+
config['package_manager'] = st.selectbox('Package Manager', package_managers, index=pm_index)
|
|
62
|
+
|
|
63
|
+
config['description'] = st.text_area('Description', value=config.get('description', ''), height=100)
|
|
64
|
+
|
|
65
|
+
config_tasks = config.get('tasks', [])
|
|
66
|
+
tasks_str = ', '.join(config_tasks) if isinstance(config_tasks, list) else config.get('tasks', '')
|
|
67
|
+
tasks_input = st.text_input('Task Types (comma-separated)', value=tasks_str)
|
|
68
|
+
config['tasks'] = [t.strip() for t in tasks_input.split(',') if t.strip()]
|
|
69
|
+
|
|
70
|
+
if st.form_submit_button('Save Configuration', type='primary'):
|
|
71
|
+
st.session_state['config'] = config
|
|
72
|
+
if self.plugin_service.save_config(config):
|
|
73
|
+
st.success('✅ Configuration saved successfully!')
|
|
74
|
+
st.rerun()
|
|
75
|
+
else:
|
|
76
|
+
st.error('Failed to save configuration')
|