synapse-sdk 1.0.0a35__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.

Files changed (307) hide show
  1. synapse_sdk/__init__.py +24 -0
  2. synapse_sdk/cli/__init__.py +308 -5
  3. synapse_sdk/cli/alias/utils.py +1 -1
  4. synapse_sdk/cli/code_server.py +687 -0
  5. synapse_sdk/cli/config.py +440 -0
  6. synapse_sdk/cli/devtools.py +90 -0
  7. synapse_sdk/cli/plugin/publish.py +23 -15
  8. synapse_sdk/clients/agent/__init__.py +9 -3
  9. synapse_sdk/clients/agent/container.py +133 -0
  10. synapse_sdk/clients/agent/core.py +19 -0
  11. synapse_sdk/clients/agent/ray.py +298 -9
  12. synapse_sdk/clients/backend/__init__.py +28 -12
  13. synapse_sdk/clients/backend/annotation.py +9 -1
  14. synapse_sdk/clients/backend/core.py +31 -4
  15. synapse_sdk/clients/backend/data_collection.py +186 -0
  16. synapse_sdk/clients/backend/hitl.py +1 -1
  17. synapse_sdk/clients/backend/integration.py +4 -3
  18. synapse_sdk/clients/backend/ml.py +1 -1
  19. synapse_sdk/clients/backend/models.py +35 -1
  20. synapse_sdk/clients/base.py +309 -36
  21. synapse_sdk/clients/ray/serve.py +2 -0
  22. synapse_sdk/devtools/__init__.py +0 -0
  23. synapse_sdk/devtools/config.py +94 -0
  24. synapse_sdk/devtools/docs/.gitignore +20 -0
  25. synapse_sdk/devtools/docs/README.md +41 -0
  26. synapse_sdk/devtools/docs/blog/2019-05-28-first-blog-post.md +12 -0
  27. synapse_sdk/devtools/docs/blog/2019-05-29-long-blog-post.md +44 -0
  28. synapse_sdk/devtools/docs/blog/2021-08-01-mdx-blog-post.mdx +24 -0
  29. synapse_sdk/devtools/docs/blog/2021-08-26-welcome/docusaurus-plushie-banner.jpeg +0 -0
  30. synapse_sdk/devtools/docs/blog/2021-08-26-welcome/index.md +29 -0
  31. synapse_sdk/devtools/docs/blog/authors.yml +25 -0
  32. synapse_sdk/devtools/docs/blog/tags.yml +19 -0
  33. synapse_sdk/devtools/docs/docs/api/clients/agent.md +43 -0
  34. synapse_sdk/devtools/docs/docs/api/clients/annotation-mixin.md +378 -0
  35. synapse_sdk/devtools/docs/docs/api/clients/backend.md +420 -0
  36. synapse_sdk/devtools/docs/docs/api/clients/base.md +257 -0
  37. synapse_sdk/devtools/docs/docs/api/clients/core-mixin.md +477 -0
  38. synapse_sdk/devtools/docs/docs/api/clients/data-collection-mixin.md +422 -0
  39. synapse_sdk/devtools/docs/docs/api/clients/hitl-mixin.md +554 -0
  40. synapse_sdk/devtools/docs/docs/api/clients/index.md +391 -0
  41. synapse_sdk/devtools/docs/docs/api/clients/integration-mixin.md +571 -0
  42. synapse_sdk/devtools/docs/docs/api/clients/ml-mixin.md +578 -0
  43. synapse_sdk/devtools/docs/docs/api/clients/ray.md +342 -0
  44. synapse_sdk/devtools/docs/docs/api/index.md +52 -0
  45. synapse_sdk/devtools/docs/docs/api/plugins/categories.md +43 -0
  46. synapse_sdk/devtools/docs/docs/api/plugins/models.md +114 -0
  47. synapse_sdk/devtools/docs/docs/api/plugins/utils.md +328 -0
  48. synapse_sdk/devtools/docs/docs/categories.md +0 -0
  49. synapse_sdk/devtools/docs/docs/cli-usage.md +280 -0
  50. synapse_sdk/devtools/docs/docs/concepts/index.md +38 -0
  51. synapse_sdk/devtools/docs/docs/configuration.md +83 -0
  52. synapse_sdk/devtools/docs/docs/contributing.md +306 -0
  53. synapse_sdk/devtools/docs/docs/examples/index.md +29 -0
  54. synapse_sdk/devtools/docs/docs/faq.md +179 -0
  55. synapse_sdk/devtools/docs/docs/features/converters/index.md +455 -0
  56. synapse_sdk/devtools/docs/docs/features/index.md +24 -0
  57. synapse_sdk/devtools/docs/docs/features/utils/file.md +415 -0
  58. synapse_sdk/devtools/docs/docs/features/utils/network.md +378 -0
  59. synapse_sdk/devtools/docs/docs/features/utils/storage.md +57 -0
  60. synapse_sdk/devtools/docs/docs/features/utils/types.md +51 -0
  61. synapse_sdk/devtools/docs/docs/installation.md +94 -0
  62. synapse_sdk/devtools/docs/docs/introduction.md +47 -0
  63. synapse_sdk/devtools/docs/docs/plugins/categories/neural-net-plugins/train-action-overview.md +814 -0
  64. synapse_sdk/devtools/docs/docs/plugins/categories/pre-annotation-plugins/pre-annotation-plugin-overview.md +198 -0
  65. synapse_sdk/devtools/docs/docs/plugins/categories/pre-annotation-plugins/to-task-action-development.md +1645 -0
  66. synapse_sdk/devtools/docs/docs/plugins/categories/pre-annotation-plugins/to-task-overview.md +717 -0
  67. synapse_sdk/devtools/docs/docs/plugins/categories/pre-annotation-plugins/to-task-template-development.md +1380 -0
  68. synapse_sdk/devtools/docs/docs/plugins/categories/upload-plugins/upload-plugin-action.md +948 -0
  69. synapse_sdk/devtools/docs/docs/plugins/categories/upload-plugins/upload-plugin-overview.md +544 -0
  70. synapse_sdk/devtools/docs/docs/plugins/categories/upload-plugins/upload-plugin-template.md +766 -0
  71. synapse_sdk/devtools/docs/docs/plugins/export-plugins.md +1092 -0
  72. synapse_sdk/devtools/docs/docs/plugins/plugins.md +852 -0
  73. synapse_sdk/devtools/docs/docs/quickstart.md +78 -0
  74. synapse_sdk/devtools/docs/docs/troubleshooting.md +519 -0
  75. synapse_sdk/devtools/docs/docs/tutorial-basics/_category_.json +8 -0
  76. synapse_sdk/devtools/docs/docs/tutorial-basics/congratulations.md +23 -0
  77. synapse_sdk/devtools/docs/docs/tutorial-basics/create-a-blog-post.md +34 -0
  78. synapse_sdk/devtools/docs/docs/tutorial-basics/create-a-document.md +57 -0
  79. synapse_sdk/devtools/docs/docs/tutorial-basics/create-a-page.md +43 -0
  80. synapse_sdk/devtools/docs/docs/tutorial-basics/deploy-your-site.md +31 -0
  81. synapse_sdk/devtools/docs/docs/tutorial-basics/markdown-features.mdx +152 -0
  82. synapse_sdk/devtools/docs/docs/tutorial-extras/_category_.json +7 -0
  83. synapse_sdk/devtools/docs/docs/tutorial-extras/img/docsVersionDropdown.png +0 -0
  84. synapse_sdk/devtools/docs/docs/tutorial-extras/img/localeDropdown.png +0 -0
  85. synapse_sdk/devtools/docs/docs/tutorial-extras/manage-docs-versions.md +55 -0
  86. synapse_sdk/devtools/docs/docs/tutorial-extras/translate-your-site.md +88 -0
  87. synapse_sdk/devtools/docs/docusaurus.config.ts +148 -0
  88. synapse_sdk/devtools/docs/i18n/ko/code.json +325 -0
  89. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/api/clients/agent.md +43 -0
  90. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/api/clients/annotation-mixin.md +289 -0
  91. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/api/clients/backend.md +420 -0
  92. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/api/clients/base.md +257 -0
  93. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/api/clients/core-mixin.md +417 -0
  94. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/api/clients/data-collection-mixin.md +356 -0
  95. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/api/clients/hitl-mixin.md +192 -0
  96. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/api/clients/index.md +391 -0
  97. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/api/clients/integration-mixin.md +479 -0
  98. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/api/clients/ml-mixin.md +284 -0
  99. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/api/clients/ray.md +342 -0
  100. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/api/index.md +52 -0
  101. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/api/plugins/models.md +114 -0
  102. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/categories.md +0 -0
  103. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/cli-usage.md +280 -0
  104. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/concepts/index.md +38 -0
  105. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/configuration.md +83 -0
  106. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/contributing.md +306 -0
  107. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/examples/index.md +29 -0
  108. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/faq.md +179 -0
  109. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/features/converters/index.md +30 -0
  110. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/features/index.md +24 -0
  111. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/features/utils/file.md +415 -0
  112. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/features/utils/network.md +378 -0
  113. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/features/utils/storage.md +60 -0
  114. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/features/utils/types.md +51 -0
  115. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/installation.md +94 -0
  116. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/introduction.md +47 -0
  117. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/plugins/categories/neural-net-plugins/train-action-overview.md +815 -0
  118. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/plugins/categories/pre-annotation-plugins/pre-annotation-plugin-overview.md +198 -0
  119. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/plugins/categories/pre-annotation-plugins/to-task-action-development.md +1645 -0
  120. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/plugins/categories/pre-annotation-plugins/to-task-overview.md +717 -0
  121. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/plugins/categories/pre-annotation-plugins/to-task-template-development.md +1380 -0
  122. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/plugins/categories/upload-plugins/upload-plugin-action.md +948 -0
  123. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/plugins/categories/upload-plugins/upload-plugin-overview.md +544 -0
  124. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/plugins/categories/upload-plugins/upload-plugin-template.md +766 -0
  125. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/plugins/export-plugins.md +1092 -0
  126. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/plugins/plugins.md +117 -0
  127. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/quickstart.md +78 -0
  128. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/troubleshooting.md +519 -0
  129. synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current.json +34 -0
  130. synapse_sdk/devtools/docs/i18n/ko/docusaurus-theme-classic/footer.json +42 -0
  131. synapse_sdk/devtools/docs/i18n/ko/docusaurus-theme-classic/navbar.json +18 -0
  132. synapse_sdk/devtools/docs/package-lock.json +18784 -0
  133. synapse_sdk/devtools/docs/package.json +48 -0
  134. synapse_sdk/devtools/docs/sidebars.ts +122 -0
  135. synapse_sdk/devtools/docs/src/components/HomepageFeatures/index.tsx +71 -0
  136. synapse_sdk/devtools/docs/src/components/HomepageFeatures/styles.module.css +11 -0
  137. synapse_sdk/devtools/docs/src/css/custom.css +30 -0
  138. synapse_sdk/devtools/docs/src/pages/index.module.css +23 -0
  139. synapse_sdk/devtools/docs/src/pages/index.tsx +21 -0
  140. synapse_sdk/devtools/docs/src/pages/markdown-page.md +7 -0
  141. synapse_sdk/devtools/docs/static/.nojekyll +0 -0
  142. synapse_sdk/devtools/docs/static/img/docusaurus-social-card.jpg +0 -0
  143. synapse_sdk/devtools/docs/static/img/docusaurus.png +0 -0
  144. synapse_sdk/devtools/docs/static/img/favicon.ico +0 -0
  145. synapse_sdk/devtools/docs/static/img/logo.png +0 -0
  146. synapse_sdk/devtools/docs/static/img/undraw_docusaurus_mountain.svg +171 -0
  147. synapse_sdk/devtools/docs/static/img/undraw_docusaurus_react.svg +170 -0
  148. synapse_sdk/devtools/docs/static/img/undraw_docusaurus_tree.svg +40 -0
  149. synapse_sdk/devtools/docs/tsconfig.json +8 -0
  150. synapse_sdk/devtools/server.py +41 -0
  151. synapse_sdk/devtools/streamlit_app/__init__.py +5 -0
  152. synapse_sdk/devtools/streamlit_app/app.py +128 -0
  153. synapse_sdk/devtools/streamlit_app/services/__init__.py +11 -0
  154. synapse_sdk/devtools/streamlit_app/services/job_service.py +233 -0
  155. synapse_sdk/devtools/streamlit_app/services/plugin_service.py +236 -0
  156. synapse_sdk/devtools/streamlit_app/services/serve_service.py +95 -0
  157. synapse_sdk/devtools/streamlit_app/ui/__init__.py +15 -0
  158. synapse_sdk/devtools/streamlit_app/ui/config_tab.py +76 -0
  159. synapse_sdk/devtools/streamlit_app/ui/deployment_tab.py +66 -0
  160. synapse_sdk/devtools/streamlit_app/ui/http_tab.py +125 -0
  161. synapse_sdk/devtools/streamlit_app/ui/jobs_tab.py +573 -0
  162. synapse_sdk/devtools/streamlit_app/ui/serve_tab.py +346 -0
  163. synapse_sdk/devtools/streamlit_app/ui/status_bar.py +118 -0
  164. synapse_sdk/devtools/streamlit_app/utils/__init__.py +40 -0
  165. synapse_sdk/devtools/streamlit_app/utils/json_viewer.py +197 -0
  166. synapse_sdk/devtools/streamlit_app/utils/log_formatter.py +38 -0
  167. synapse_sdk/devtools/streamlit_app/utils/styles.py +241 -0
  168. synapse_sdk/devtools/streamlit_app/utils/ui_components.py +289 -0
  169. synapse_sdk/devtools/streamlit_app.py +10 -0
  170. synapse_sdk/loggers.py +65 -7
  171. synapse_sdk/plugins/README.md +1340 -0
  172. synapse_sdk/plugins/categories/base.py +73 -11
  173. synapse_sdk/plugins/categories/data_validation/actions/validation.py +72 -0
  174. synapse_sdk/plugins/categories/data_validation/templates/plugin/validation.py +33 -5
  175. synapse_sdk/plugins/categories/export/actions/__init__.py +3 -0
  176. synapse_sdk/plugins/categories/export/actions/export/__init__.py +28 -0
  177. synapse_sdk/plugins/categories/export/actions/export/action.py +165 -0
  178. synapse_sdk/plugins/categories/export/actions/export/enums.py +113 -0
  179. synapse_sdk/plugins/categories/export/actions/export/exceptions.py +53 -0
  180. synapse_sdk/plugins/categories/export/actions/export/models.py +74 -0
  181. synapse_sdk/plugins/categories/export/actions/export/run.py +195 -0
  182. synapse_sdk/plugins/categories/export/actions/{export.py → export/utils.py} +47 -82
  183. synapse_sdk/plugins/categories/export/templates/config.yaml +19 -1
  184. synapse_sdk/plugins/categories/export/templates/plugin/__init__.py +390 -0
  185. synapse_sdk/plugins/categories/export/templates/plugin/export.py +153 -129
  186. synapse_sdk/plugins/categories/neural_net/actions/deployment.py +9 -62
  187. synapse_sdk/plugins/categories/neural_net/actions/train.py +1062 -32
  188. synapse_sdk/plugins/categories/neural_net/actions/tune.py +534 -0
  189. synapse_sdk/plugins/categories/neural_net/templates/config.yaml +27 -5
  190. synapse_sdk/plugins/categories/neural_net/templates/plugin/inference.py +26 -10
  191. synapse_sdk/plugins/categories/pre_annotation/actions/__init__.py +4 -0
  192. synapse_sdk/plugins/categories/pre_annotation/actions/pre_annotation/__init__.py +3 -0
  193. synapse_sdk/plugins/categories/pre_annotation/actions/pre_annotation/action.py +10 -0
  194. synapse_sdk/plugins/categories/pre_annotation/actions/to_task/__init__.py +28 -0
  195. synapse_sdk/plugins/categories/pre_annotation/actions/to_task/action.py +145 -0
  196. synapse_sdk/plugins/categories/pre_annotation/actions/to_task/enums.py +269 -0
  197. synapse_sdk/plugins/categories/pre_annotation/actions/to_task/exceptions.py +14 -0
  198. synapse_sdk/plugins/categories/pre_annotation/actions/to_task/factory.py +76 -0
  199. synapse_sdk/plugins/categories/pre_annotation/actions/to_task/models.py +97 -0
  200. synapse_sdk/plugins/categories/pre_annotation/actions/to_task/orchestrator.py +250 -0
  201. synapse_sdk/plugins/categories/pre_annotation/actions/to_task/run.py +64 -0
  202. synapse_sdk/plugins/categories/pre_annotation/actions/to_task/strategies/__init__.py +17 -0
  203. synapse_sdk/plugins/categories/pre_annotation/actions/to_task/strategies/annotation.py +287 -0
  204. synapse_sdk/plugins/categories/pre_annotation/actions/to_task/strategies/base.py +170 -0
  205. synapse_sdk/plugins/categories/pre_annotation/actions/to_task/strategies/extraction.py +83 -0
  206. synapse_sdk/plugins/categories/pre_annotation/actions/to_task/strategies/metrics.py +87 -0
  207. synapse_sdk/plugins/categories/pre_annotation/actions/to_task/strategies/preprocessor.py +127 -0
  208. synapse_sdk/plugins/categories/pre_annotation/actions/to_task/strategies/validation.py +143 -0
  209. synapse_sdk/plugins/categories/pre_annotation/actions/to_task.py +966 -0
  210. synapse_sdk/plugins/categories/pre_annotation/templates/config.yaml +19 -0
  211. synapse_sdk/plugins/categories/pre_annotation/templates/plugin/to_task.py +40 -0
  212. synapse_sdk/plugins/categories/upload/actions/upload/__init__.py +19 -0
  213. synapse_sdk/plugins/categories/upload/actions/upload/action.py +232 -0
  214. synapse_sdk/plugins/categories/upload/actions/upload/context.py +185 -0
  215. synapse_sdk/plugins/categories/upload/actions/upload/enums.py +471 -0
  216. synapse_sdk/plugins/categories/upload/actions/upload/exceptions.py +36 -0
  217. synapse_sdk/plugins/categories/upload/actions/upload/factory.py +138 -0
  218. synapse_sdk/plugins/categories/upload/actions/upload/models.py +203 -0
  219. synapse_sdk/plugins/categories/upload/actions/upload/orchestrator.py +183 -0
  220. synapse_sdk/plugins/categories/upload/actions/upload/registry.py +113 -0
  221. synapse_sdk/plugins/categories/upload/actions/upload/run.py +179 -0
  222. synapse_sdk/plugins/categories/upload/actions/upload/steps/__init__.py +1 -0
  223. synapse_sdk/plugins/categories/upload/actions/upload/steps/base.py +107 -0
  224. synapse_sdk/plugins/categories/upload/actions/upload/steps/cleanup.py +62 -0
  225. synapse_sdk/plugins/categories/upload/actions/upload/steps/collection.py +63 -0
  226. synapse_sdk/plugins/categories/upload/actions/upload/steps/generate.py +84 -0
  227. synapse_sdk/plugins/categories/upload/actions/upload/steps/initialize.py +82 -0
  228. synapse_sdk/plugins/categories/upload/actions/upload/steps/metadata.py +235 -0
  229. synapse_sdk/plugins/categories/upload/actions/upload/steps/organize.py +203 -0
  230. synapse_sdk/plugins/categories/upload/actions/upload/steps/upload.py +97 -0
  231. synapse_sdk/plugins/categories/upload/actions/upload/steps/validate.py +71 -0
  232. synapse_sdk/plugins/categories/upload/actions/upload/strategies/__init__.py +1 -0
  233. synapse_sdk/plugins/categories/upload/actions/upload/strategies/base.py +82 -0
  234. synapse_sdk/plugins/categories/upload/actions/upload/strategies/data_unit/__init__.py +1 -0
  235. synapse_sdk/plugins/categories/upload/actions/upload/strategies/data_unit/batch.py +39 -0
  236. synapse_sdk/plugins/categories/upload/actions/upload/strategies/data_unit/single.py +29 -0
  237. synapse_sdk/plugins/categories/upload/actions/upload/strategies/file_discovery/__init__.py +1 -0
  238. synapse_sdk/plugins/categories/upload/actions/upload/strategies/file_discovery/flat.py +258 -0
  239. synapse_sdk/plugins/categories/upload/actions/upload/strategies/file_discovery/recursive.py +281 -0
  240. synapse_sdk/plugins/categories/upload/actions/upload/strategies/metadata/__init__.py +1 -0
  241. synapse_sdk/plugins/categories/upload/actions/upload/strategies/metadata/excel.py +174 -0
  242. synapse_sdk/plugins/categories/upload/actions/upload/strategies/metadata/none.py +16 -0
  243. synapse_sdk/plugins/categories/upload/actions/upload/strategies/upload/__init__.py +1 -0
  244. synapse_sdk/plugins/categories/upload/actions/upload/strategies/upload/sync.py +84 -0
  245. synapse_sdk/plugins/categories/upload/actions/upload/strategies/validation/__init__.py +1 -0
  246. synapse_sdk/plugins/categories/upload/actions/upload/strategies/validation/default.py +60 -0
  247. synapse_sdk/plugins/categories/upload/actions/upload/utils.py +250 -0
  248. synapse_sdk/plugins/categories/upload/templates/README.md +470 -0
  249. synapse_sdk/plugins/categories/upload/templates/config.yaml +29 -2
  250. synapse_sdk/plugins/categories/upload/templates/plugin/__init__.py +294 -0
  251. synapse_sdk/plugins/categories/upload/templates/plugin/upload.py +88 -30
  252. synapse_sdk/plugins/models.py +122 -16
  253. synapse_sdk/plugins/templates/plugin-config-schema.json +406 -0
  254. synapse_sdk/plugins/templates/schema.json +491 -0
  255. synapse_sdk/plugins/templates/synapse-{{cookiecutter.plugin_code}}-plugin/requirements.txt +1 -1
  256. synapse_sdk/plugins/utils/__init__.py +46 -0
  257. synapse_sdk/plugins/utils/actions.py +119 -0
  258. synapse_sdk/plugins/utils/config.py +203 -0
  259. synapse_sdk/plugins/{utils.py → utils/legacy.py} +26 -46
  260. synapse_sdk/plugins/utils/ray_gcs.py +66 -0
  261. synapse_sdk/plugins/utils/registry.py +58 -0
  262. synapse_sdk/shared/__init__.py +25 -0
  263. synapse_sdk/shared/enums.py +93 -0
  264. synapse_sdk/utils/converters/__init__.py +240 -0
  265. synapse_sdk/utils/converters/coco/__init__.py +0 -0
  266. synapse_sdk/utils/converters/coco/from_dm.py +322 -0
  267. synapse_sdk/utils/converters/coco/to_dm.py +215 -0
  268. synapse_sdk/utils/converters/dm/__init__.py +56 -0
  269. synapse_sdk/utils/converters/dm/from_v1.py +627 -0
  270. synapse_sdk/utils/converters/dm/to_v1.py +367 -0
  271. synapse_sdk/utils/converters/pascal/__init__.py +0 -0
  272. synapse_sdk/utils/converters/pascal/from_dm.py +244 -0
  273. synapse_sdk/utils/converters/pascal/to_dm.py +214 -0
  274. synapse_sdk/utils/converters/yolo/__init__.py +0 -0
  275. synapse_sdk/utils/converters/yolo/from_dm.py +384 -0
  276. synapse_sdk/utils/converters/yolo/to_dm.py +267 -0
  277. synapse_sdk/utils/dataset.py +46 -0
  278. synapse_sdk/utils/encryption.py +158 -0
  279. synapse_sdk/utils/file/__init__.py +39 -0
  280. synapse_sdk/utils/file/archive.py +32 -0
  281. synapse_sdk/utils/file/checksum.py +56 -0
  282. synapse_sdk/utils/file/chunking.py +31 -0
  283. synapse_sdk/utils/file/download.py +385 -0
  284. synapse_sdk/utils/file/encoding.py +40 -0
  285. synapse_sdk/utils/file/io.py +22 -0
  286. synapse_sdk/utils/file/video/__init__.py +29 -0
  287. synapse_sdk/utils/file/video/transcode.py +307 -0
  288. synapse_sdk/utils/{file.py → file.py.backup} +84 -2
  289. synapse_sdk/utils/http.py +138 -0
  290. synapse_sdk/utils/network.py +293 -0
  291. synapse_sdk/utils/storage/__init__.py +36 -2
  292. synapse_sdk/utils/storage/providers/__init__.py +141 -0
  293. synapse_sdk/utils/storage/providers/file_system.py +134 -0
  294. synapse_sdk/utils/storage/providers/http.py +190 -0
  295. synapse_sdk/utils/storage/providers/s3.py +54 -6
  296. synapse_sdk/utils/storage/providers/sftp.py +31 -0
  297. synapse_sdk/utils/storage/registry.py +6 -0
  298. synapse_sdk-2025.11.7.dist-info/METADATA +122 -0
  299. synapse_sdk-2025.11.7.dist-info/RECORD +386 -0
  300. {synapse_sdk-1.0.0a35.dist-info → synapse_sdk-2025.11.7.dist-info}/WHEEL +1 -1
  301. synapse_sdk/clients/backend/dataset.py +0 -102
  302. synapse_sdk/plugins/categories/upload/actions/upload.py +0 -293
  303. synapse_sdk-1.0.0a35.dist-info/METADATA +0 -47
  304. synapse_sdk-1.0.0a35.dist-info/RECORD +0 -137
  305. {synapse_sdk-1.0.0a35.dist-info → synapse_sdk-2025.11.7.dist-info}/entry_points.txt +0 -0
  306. {synapse_sdk-1.0.0a35.dist-info → synapse_sdk-2025.11.7.dist-info}/licenses/LICENSE +0 -0
  307. {synapse_sdk-1.0.0a35.dist-info → synapse_sdk-2025.11.7.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,1092 @@
1
+ ---
2
+ id: export-plugins
3
+ title: Export 플러그인
4
+ sidebar_position: 2
5
+ ---
6
+
7
+ # Export 플러그인
8
+
9
+ Export 플러그인은 Synapse 플랫폼에서 주석이 달린 데이터, 그라운드 트루스 데이터셋, 할당 및 작업을 내보내기 위한 데이터 내보내기 및 변환 작업을 제공합니다.
10
+
11
+ ## 개요
12
+
13
+ **사용 가능한 액션:**
14
+
15
+ - `export` - 다양한 소스(할당, 그라운드 트루스, 작업)에서 사용자 정의 처리와 함께 데이터 내보내기
16
+
17
+ **사용 사례:**
18
+
19
+ - 훈련용 주석 데이터셋 내보내기
20
+ - 그라운드 트루스 데이터를 사용자 정의 형식으로 변환
21
+ - 배포용 데이터 패키지 생성
22
+ - 할당 결과의 배치 처리
23
+ - 외부 도구용 주석 데이터 변환
24
+
25
+ **지원되는 내보내기 대상:**
26
+
27
+ - `assignment` - 주석이 있는 할당 데이터 내보내기
28
+ - `ground_truth` - 그라운드 트루스 데이터셋 버전 내보내기
29
+ - `task` - 관련 주석이 있는 작업 데이터 내보내기
30
+
31
+ ## BaseExporter와 Exporter 클래스 구조도
32
+
33
+ 다음 다이어그램은 BaseExporter 클래스와 Exporter 클래스 간의 관계와 메서드 구현을 보여줍니다:
34
+
35
+ ```mermaid
36
+ classDiagram
37
+ %% Light/Dark mode compatible colors using CSS variables
38
+ classDef baseClass fill:#f0f8ff,stroke:#4169e1,stroke-width:2px,color:#000
39
+ classDef childClass fill:#f0fff0,stroke:#228b22,stroke-width:2px,color:#000
40
+ classDef method fill:#fff8dc,stroke:#daa520,stroke-width:1px,color:#000
41
+ classDef abstractMethod fill:#ffe4e1,stroke:#dc143c,stroke-width:1px,color:#000
42
+ classDef helperMethod fill:#f5f5f5,stroke:#696969,stroke-width:1px,color:#000
43
+
44
+ class BaseExporter {
45
+ %% Core attributes
46
+ +run: object
47
+ +export_items: Generator
48
+ +path_root: Path
49
+ +params: dict
50
+
51
+ %% Main workflow methods
52
+ +export(export_items, results, **kwargs) dict
53
+ +process_data_conversion(export_item) object
54
+ +process_file_saving(...) bool
55
+ +setup_output_directories(path, flag) dict
56
+
57
+ %% Abstract methods (to be implemented)
58
+ +convert_data(data)* object
59
+ +before_convert(data)* object
60
+ +after_convert(data)* object
61
+
62
+ %% File operations
63
+ +save_original_file(result, path, errors) ExportStatus
64
+ +save_as_json(result, path, errors) ExportStatus
65
+ +get_original_file_name(files) str
66
+
67
+ %% Helper methods
68
+ -_create_unique_export_path(name) Path
69
+ -_save_error_list(path, json_errors, file_errors)
70
+ -_process_original_file_saving(...) bool
71
+ -_process_json_file_saving(...) bool
72
+ }
73
+
74
+ class Exporter {
75
+ %% Inherited from BaseExporter
76
+ +export(export_items, results, **kwargs) dict
77
+
78
+ %% Implemented abstract methods
79
+ +convert_data(data) object
80
+ +before_convert(data) object
81
+ +after_convert(data) object
82
+ }
83
+
84
+ %% Inheritance relationship
85
+ BaseExporter <|-- Exporter
86
+
87
+ %% Apply styles
88
+ class BaseExporter baseClass
89
+ class Exporter childClass
90
+ ```
91
+
92
+ ### 메서드 실행 플로우
93
+
94
+ Export 작업의 전체 실행 흐름을 보여주는 플로우차트입니다:
95
+
96
+ ```mermaid
97
+ flowchart TD
98
+ %% Start
99
+ A[export 메서드 호출] --> B[경로와 메트릭 초기화]
100
+ B --> C[출력 디렉토리 설정]
101
+ C --> D[export_items 순환]
102
+
103
+ %% Data processing pipeline
104
+ D --> E[process_data_conversion]
105
+ E --> F[before_convert]
106
+ F --> G[convert_data]
107
+ G --> H[after_convert]
108
+
109
+ %% File saving pipeline
110
+ H --> I[process_file_saving]
111
+ I --> J{원본 파일 저장?}
112
+ J -->|예| K[_process_original_file_saving]
113
+ J -->|아니오| L[_process_json_file_saving]
114
+ K --> L
115
+
116
+ %% Continue or finish
117
+ L --> M{더 많은 항목?}
118
+ M -->|예| D
119
+ M -->|아니오| N[오류 목록 저장]
120
+ N --> O[내보내기 경로 반환]
121
+
122
+ %% Error handling
123
+ K --> P{원본 파일 실패?}
124
+ P -->|예| Q[다음 항목으로 건너뛰기]
125
+ P -->|아니오| L
126
+
127
+ L --> R{JSON 파일 실패?}
128
+ R -->|예| Q
129
+ R -->|아니오| S[메트릭 업데이트]
130
+ S --> M
131
+ Q --> M
132
+
133
+ %% Styling for light/dark compatibility
134
+ classDef startEnd fill:#e1f5fe,stroke:#01579b,color:#000
135
+ classDef process fill:#f3e5f5,stroke:#4a148c,color:#000
136
+ classDef decision fill:#fff3e0,stroke:#e65100,color:#000
137
+ classDef data fill:#e8f5e8,stroke:#2e7d32,color:#000
138
+ classDef error fill:#ffebee,stroke:#c62828,color:#000
139
+
140
+ class A,O startEnd
141
+ class B,C,E,F,G,H,I,K,L,N,S process
142
+ class J,M,P,R decision
143
+ class D data
144
+ class Q error
145
+ ```
146
+
147
+ ### 주요 관계 및 책임
148
+
149
+ **BaseExporter (추상 기본 클래스)**
150
+
151
+ - **핵심 기능**: 완전한 내보내기 워크플로우 인프라 제공
152
+ - **템플릿 메서드**: `export()` 메서드가 전체 프로세스 조율
153
+ - **훅 메서드**: 커스터마이징을 위한 `convert_data()`, `before_convert()`, `after_convert()`
154
+ - **유틸리티**: 파일 작업, 디렉토리 설정, 오류 처리, 진행률 추적
155
+
156
+ **Exporter (구체적 구현)**
157
+
158
+ - **상속**: `BaseExporter` 확장
159
+ - **최소 구현**: 추상 메서드들의 기본 구현 제공
160
+ - **위임 동작**: 대부분의 메서드가 부모 클래스에 위임
161
+ - **커스터마이징 지점**: 특정 로직을 위해 변환 메서드 오버라이드
162
+
163
+ ### 메서드 카테고리
164
+
165
+ - **🔵 핵심 워크플로우**: 주요 내보내기 조율 메서드
166
+ - **🟢 템플릿/훅**: 서브클래스에서 오버라이드하도록 설계된 메서드
167
+ - **🟡 파일 작업**: 구체적인 파일 저장 및 처리 메서드
168
+ - **🔸 헬퍼/유틸리티**: 내부 작업을 위한 프라이빗 메서드
169
+
170
+ 이 설계는 **템플릿 메서드 패턴**을 따르며, `BaseExporter.export()`가 알고리즘 골격을 정의하고 서브클래스가 훅 메서드를 통해 특정 단계를 커스터마이징합니다.
171
+
172
+ ## 플러그인 설정
173
+
174
+ Export 플러그인 템플릿은 필터링 및 플러그인 검색을 위한 설정 필드를 포함합니다:
175
+
176
+ ```yaml
177
+ actions:
178
+ export:
179
+ entrypoint: plugin.export.Exporter
180
+ annotation_types:
181
+ - image
182
+ - video
183
+ - audio
184
+ - text
185
+ - pcd
186
+ - prompt
187
+
188
+ data_types:
189
+ - image
190
+ - video
191
+ - audio
192
+ - text
193
+ - pcd
194
+ ```
195
+
196
+ ### 설정 필드
197
+
198
+ - **data_types**: Export 플러그인 필터링을 위한 지원 데이터 타입 목록 (플러그인 레벨 필터)
199
+
200
+ - 지원 값: `image`, `video`, `audio`, `text`, `pcd`
201
+ - 플랫폼에서 사용자의 데이터 타입에 따라 관련 export 플러그인을 필터링하고 표시하는 데 사용됩니다
202
+
203
+ - **annotation_types**: Export 플러그인 필터링을 위한 어노테이션 타입 목록 (액션 레벨 필터)
204
+ - 지원 값: `image`, `video`, `audio`, `text`, `pcd`, `prompt`
205
+ - 각 액션의 설정 내에서 정의됩니다 (예: `actions.export.annotation_types`)
206
+ - 플랫폼에서 사용자의 주석 타입에 따라 관련 export 플러그인을 필터링하고 표시하는 데 사용됩니다
207
+ - 각 액션마다 다른 어노테이션 타입 요구사항을 가질 수 있습니다
208
+
209
+ **모범 사례**: 플러그인의 실제 기능을 정확히 반영하도록 이 필드들을 커스터마이징하세요. 템플릿에는 모든 일반적인 타입이 예시로 포함되어 있지만, 플러그인이 실제로 지원하는 항목에 맞게 목록을 수정해야 합니다.
210
+
211
+ ## BaseExporter 클래스 구조
212
+
213
+ 새로운 BaseExporter 클래스는 export 플러그인을 위한 객체지향적 접근 방식을 제공합니다:
214
+
215
+ ```python
216
+ from synapse_sdk.plugins.categories.export.templates.plugin import BaseExporter
217
+
218
+ class Exporter(BaseExporter):
219
+ """플러그인 export 액션 인터페이스."""
220
+
221
+ def __init__(self, run, export_items, path_root, **params):
222
+ """플러그인 export 액션 클래스를 초기화합니다."""
223
+ super().__init__(run, export_items, path_root, **params)
224
+
225
+ def convert_data(self, data):
226
+ """데이터 변환 로직을 구현하세요."""
227
+ return data
228
+
229
+ def before_convert(self, data):
230
+ """변환 전 데이터 전처리를 수행합니다."""
231
+ return data
232
+
233
+ def after_convert(self, data):
234
+ """변환 후 데이터 후처리를 수행합니다."""
235
+ return data
236
+ ```
237
+
238
+ ## BaseExporter의 핵심 기능
239
+
240
+ ### 자동 제공 유틸리티
241
+
242
+ - **완전한 export 워크플로우**: `export()` 메서드가 전체 export 프로세스를 관리
243
+ - **데이터 변환 파이프라인**: `process_data_conversion()` 메서드로 before_convert → convert_data → after_convert 처리
244
+ - **파일 저장 관리**: `process_file_saving()` 메서드로 원본 파일과 JSON 파일 저장 처리 (오버라이드 가능)
245
+ - **디렉토리 설정**: `setup_output_directories()` 메서드로 출력 디렉토리 구조 생성 (오버라이드 가능)
246
+
247
+ ### 필수 메서드 (서브클래스에서 구현해야 함)
248
+
249
+ - **convert_data()**: export 중 데이터 변환
250
+
251
+ ### 선택적 메서드 (서브클래스에서 오버라이드 가능)
252
+
253
+ - **save_original_file()**: export 항목의 원본 파일 저장
254
+ - **save_as_json()**: 데이터를 JSON 파일로 저장
255
+ - **before_convert()**: 변환 전 데이터 전처리
256
+ - **after_convert()**: 변환 후 데이터 후처리
257
+ - **process_file_saving()**: 사용자 정의 파일 저장 로직
258
+ - **additional_file_saving()**: 모든 export 항목 처리 후 추가 파일 저장
259
+
260
+ ### 헬퍼 메서드
261
+
262
+ - **\_process_original_file_saving()**: 메트릭과 함께 원본 파일 저장 처리
263
+ - **\_process_json_file_saving()**: 메트릭과 함께 JSON 파일 저장 처리
264
+
265
+ ### 자동 제공 유틸리티
266
+
267
+ - `self.run.set_progress()`를 통한 진행률 추적
268
+ - `self.run.log_message()` 및 기타 run 메서드를 통한 로깅
269
+ - run 메서드를 통한 오류 처리 및 메트릭 수집
270
+
271
+ ## 추가 파일 저장 (Additional File Saving)
272
+
273
+ `additional_file_saving()` 메서드는 모든 export 항목이 처리된 후에 호출되며, 모든 처리된 항목의 집합적 데이터에 의존하는 파일을 저장하기 위해 설계되었습니다. 다음과 같은 용도로 유용합니다:
274
+
275
+ - 메타데이터 파일 (예: 데이터셋 통계, 클래스 매핑)
276
+ - 설정 파일 (예: YOLO용 dataset.yaml, classes.txt)
277
+ - 요약 파일 (예: export 보고서, 처리 로그)
278
+ - 인덱스 파일 (예: 파일 목록, 디렉토리 구조)
279
+
280
+ ### 메서드 시그니처
281
+
282
+ ```python
283
+ def additional_file_saving(self, unique_export_path):
284
+ """모든 export 항목 처리 후 추가 파일 저장.
285
+
286
+ 이 메서드는 주 export 루프가 완료된 후 호출되며, 모든 처리된 export 항목의
287
+ 집합적 데이터를 기반으로 생성되어야 하는 파일들(예: 메타데이터 파일,
288
+ 설정 파일, 요약 파일 등)을 저장하기 위한 것입니다.
289
+
290
+ Args:
291
+ unique_export_path (str): 추가 파일이 저장될 고유한 export 디렉토리 경로.
292
+ """
293
+ pass
294
+ ```
295
+
296
+ ### 사용 예시
297
+
298
+ ```python
299
+ class YOLOExporter(BaseExporter):
300
+ def __init__(self, run, export_items, path_root, **params):
301
+ super().__init__(run, export_items, path_root, **params)
302
+ self.class_names = set()
303
+ self.dataset_stats = {
304
+ 'total_images': 0,
305
+ 'total_annotations': 0,
306
+ 'class_distribution': {}
307
+ }
308
+
309
+ def convert_data(self, data):
310
+ # 변환 중 클래스와 통계 추적
311
+ for annotation in data.get('annotations', []):
312
+ class_name = annotation['class_name']
313
+ self.class_names.add(class_name)
314
+ self.dataset_stats['class_distribution'][class_name] = \
315
+ self.dataset_stats['class_distribution'].get(class_name, 0) + 1
316
+
317
+ self.dataset_stats['total_images'] += 1
318
+ self.dataset_stats['total_annotations'] += len(data.get('annotations', []))
319
+
320
+ return data # ... 나머지 변환 로직
321
+
322
+ def additional_file_saving(self, unique_export_path):
323
+ """YOLO 설정 및 메타데이터 파일 저장."""
324
+ data_dir = Path(unique_export_path) / 'data'
325
+ data_dir.mkdir(exist_ok=True)
326
+
327
+ # 1. classes.txt 파일 저장
328
+ classes_file = data_dir / 'classes.txt'
329
+ with classes_file.open('w') as f:
330
+ for class_name in sorted(self.class_names):
331
+ f.write(f"{class_name}\n")
332
+ self.run.log_message(f"클래스 파일 저장: {classes_file}")
333
+
334
+ # 2. dataset.yaml 파일 저장
335
+ dataset_config = {
336
+ 'path': str(unique_export_path),
337
+ 'train': 'images',
338
+ 'val': 'images',
339
+ 'names': {i: name for i, name in enumerate(sorted(self.class_names))}
340
+ }
341
+
342
+ dataset_file = data_dir / 'dataset.yaml'
343
+ with dataset_file.open('w') as f:
344
+ yaml.dump(dataset_config, f, default_flow_style=False)
345
+ self.run.log_message(f"데이터셋 설정 저장: {dataset_file}")
346
+
347
+ # 3. export 통계 저장
348
+ stats_file = data_dir / 'export_stats.json'
349
+ with stats_file.open('w') as f:
350
+ json.dump(self.dataset_stats, f, indent=2)
351
+ self.run.log_message(f"export 통계 저장: {stats_file}")
352
+ ```
353
+
354
+ ### 일반적인 사용 사례
355
+
356
+ #### 1. 데이터셋 설정 파일
357
+
358
+ ```python
359
+ def additional_file_saving(self, unique_export_path):
360
+ # 훈련 프레임워크용 데이터셋 설정 생성
361
+ config = {
362
+ 'dataset_name': self.params.get('name'),
363
+ 'created_at': datetime.now().isoformat(),
364
+ 'total_samples': len(self.processed_items),
365
+ 'classes': list(self.class_mapping.keys())
366
+ }
367
+
368
+ config_file = Path(unique_export_path) / 'dataset_config.json'
369
+ with config_file.open('w') as f:
370
+ json.dump(config, f, indent=2)
371
+ ```
372
+
373
+ #### 2. Export 요약 보고서
374
+
375
+ ```python
376
+ def additional_file_saving(self, unique_export_path):
377
+ # export 요약 생성
378
+ summary = {
379
+ 'export_info': {
380
+ 'plugin_name': self.__class__.__name__,
381
+ 'export_time': datetime.now().isoformat(),
382
+ 'export_path': str(unique_export_path)
383
+ },
384
+ 'statistics': self.get_export_statistics(),
385
+ 'errors': self.get_error_summary()
386
+ }
387
+
388
+ summary_file = Path(unique_export_path) / 'export_summary.json'
389
+ with summary_file.open('w') as f:
390
+ json.dump(summary, f, indent=2)
391
+ ```
392
+
393
+ #### 3. 인덱스 및 매니페스트 파일
394
+
395
+ ```python
396
+ def additional_file_saving(self, unique_export_path):
397
+ # 처리된 항목들에 대한 파일 인덱스 생성
398
+ file_index = []
399
+ for item in self.processed_items:
400
+ file_index.append({
401
+ 'original_file': item['original_filename'],
402
+ 'json_file': f"{item['stem']}.json",
403
+ 'processed_at': item['timestamp']
404
+ })
405
+
406
+ index_file = Path(unique_export_path) / 'file_index.json'
407
+ with index_file.open('w') as f:
408
+ json.dump(file_index, f, indent=2)
409
+ ```
410
+
411
+ ## 주요 특징
412
+
413
+ - **진행률 추적**: `run.set_progress()`로 내장 진행률 모니터링
414
+ - **오류 처리**: 자동 오류 수집 및 보고
415
+ - **메트릭 로깅**: `run.log_metrics()`로 성공/실패율 추적
416
+ - **파일 관리**: 원본 파일과 처리된 JSON 데이터 모두 처리
417
+ - **로깅**: `run.log_message()` 및 사용자 정의 이벤트로 포괄적인 로깅
418
+
419
+ ## 실용적인 예시
420
+
421
+ ### YOLO 형식 Exporter with 커스텀 디렉토리 구조
422
+
423
+ 다음은 YOLO 형식으로 데이터를 내보내면서 `setup_output_directories`와 `process_file_saving`을 활용하는 완전한 예시입니다:
424
+
425
+ ```python
426
+ from synapse_sdk.plugins.categories.export.templates.plugin import BaseExporter
427
+ import os
428
+ import json
429
+
430
+ class YOLOExporter(BaseExporter):
431
+ """YOLO 형식으로 데이터를 내보내는 플러그인."""
432
+
433
+ def __init__(self, run, export_items, path_root, **params):
434
+ super().__init__(run, export_items, path_root, **params)
435
+ self.class_mapping = {}
436
+
437
+ def setup_output_directories(self, unique_export_path, save_original_file_flag):
438
+ """YOLO 프로젝트 구조에 맞는 디렉토리 생성."""
439
+ directories = ['images', 'labels', 'data']
440
+
441
+ for directory in directories:
442
+ dir_path = os.path.join(unique_export_path, directory)
443
+ os.makedirs(dir_path, exist_ok=True)
444
+ self.run.log_message(f"YOLO 디렉토리 생성: {dir_path}")
445
+
446
+ return unique_export_path
447
+
448
+ def convert_data(self, data):
449
+ """주석 데이터를 YOLO 형식으로 변환."""
450
+ converted_annotations = []
451
+
452
+ for annotation in data.get('annotations', []):
453
+ # 바운딩 박스를 YOLO 형식으로 변환
454
+ bbox = annotation['geometry']['bbox']
455
+ image_width = data['image']['width']
456
+ image_height = data['image']['height']
457
+
458
+ # YOLO 형식: center_x, center_y, width, height (정규화)
459
+ center_x = (bbox['x'] + bbox['width'] / 2) / image_width
460
+ center_y = (bbox['y'] + bbox['height'] / 2) / image_height
461
+ width = bbox['width'] / image_width
462
+ height = bbox['height'] / image_height
463
+
464
+ # 클래스 ID 매핑
465
+ class_name = annotation['class_name']
466
+ if class_name not in self.class_mapping:
467
+ self.class_mapping[class_name] = len(self.class_mapping)
468
+
469
+ class_id = self.class_mapping[class_name]
470
+
471
+ converted_annotations.append({
472
+ 'class_id': class_id,
473
+ 'center_x': center_x,
474
+ 'center_y': center_y,
475
+ 'width': width,
476
+ 'height': height
477
+ })
478
+
479
+ return {
480
+ 'yolo_annotations': converted_annotations,
481
+ 'class_mapping': self.class_mapping,
482
+ 'image_info': data['image']
483
+ }
484
+
485
+ def process_file_saving(
486
+ self,
487
+ final_data,
488
+ unique_export_path,
489
+ save_original_file_flag,
490
+ errors_json_file_list,
491
+ errors_original_file_list,
492
+ original_file_metrics_record,
493
+ data_file_metrics_record,
494
+ current_index,
495
+ ):
496
+ """YOLO 형식으로 파일 저장 처리."""
497
+ try:
498
+ export_item = self.export_items[current_index - 1]
499
+ base_name = os.path.splitext(export_item.original_file.name)[0]
500
+
501
+ # 1. 이미지 파일을 images 폴더에 저장
502
+ if save_original_file_flag:
503
+ images_dir = os.path.join(unique_export_path, 'images')
504
+ image_path = os.path.join(images_dir, export_item.original_file.name)
505
+ import shutil
506
+ shutil.copy2(export_item.original_file.path, image_path)
507
+ self.run.log_message(f"이미지 저장: {image_path}")
508
+
509
+ # 2. YOLO 라벨 파일을 labels 폴더에 저장
510
+ labels_dir = os.path.join(unique_export_path, 'labels')
511
+ label_path = os.path.join(labels_dir, f"{base_name}.txt")
512
+
513
+ with open(label_path, 'w') as f:
514
+ for ann in final_data.get('yolo_annotations', []):
515
+ line = f"{ann['class_id']} {ann['center_x']} {ann['center_y']} {ann['width']} {ann['height']}\n"
516
+ f.write(line)
517
+
518
+ self.run.log_message(f"YOLO 라벨 저장: {label_path}")
519
+
520
+ # 3. 클래스 매핑 파일 저장 (한 번만)
521
+ if current_index == 1: # 첫 번째 파일 처리 시에만
522
+ classes_path = os.path.join(unique_export_path, 'data', 'classes.txt')
523
+ with open(classes_path, 'w') as f:
524
+ for class_name, class_id in sorted(final_data['class_mapping'].items(), key=lambda x: x[1]):
525
+ f.write(f"{class_name}\n")
526
+ self.run.log_message(f"클래스 파일 저장: {classes_path}")
527
+
528
+ return True
529
+
530
+ except Exception as e:
531
+ self.run.log_message(f"파일 저장 중 오류: {str(e)}", level="error")
532
+ errors_json_file_list.append(f"Export item {current_index}: {str(e)}")
533
+ return True # 다른 파일 처리를 계속하기 위해 True 반환
534
+ ```
535
+
536
+ 이 예시는 BaseExporter의 핵심 확장 포인트인 `setup_output_directories`와 `process_file_saving`을 활용하여:
537
+
538
+ - YOLO 프로젝트 구조 (`images/`, `labels/`, `data/`) 생성
539
+ - 이미지 파일과 YOLO 라벨 파일을 적절한 위치에 저장
540
+ - 클래스 매핑 파일 관리
541
+ - 진행률 추적과 오류 처리
542
+
543
+ 이를 보여줍니다.
544
+
545
+ ## 빠른 시작 가이드
546
+
547
+ BaseExporter를 사용하여 간단한 플러그인을 만드는 단계별 가이드입니다:
548
+
549
+ ### 1단계: 기본 클래스 상속
550
+
551
+ ```python
552
+ from synapse_sdk.plugins.categories.export.templates.plugin import BaseExporter
553
+
554
+ class MyExporter(BaseExporter):
555
+ def convert_data(self, data):
556
+ # 필수: 데이터 변환 로직 구현
557
+ return data # 또는 변환된 데이터 반환
558
+ ```
559
+
560
+ ### 2단계: 필요에 따라 추가 메서드 오버라이드
561
+
562
+ ```python
563
+ def before_convert(self, data):
564
+ # 선택적: 변환 전 전처리
565
+ return data
566
+
567
+ def after_convert(self, converted_data):
568
+ # 선택적: 변환 후 후처리
569
+ return converted_data
570
+
571
+ def save_as_json(self, converted_data, output_path):
572
+ # 선택적: 사용자 정의 저장 형식
573
+ # 기본적으로는 JSON 형식으로 저장됨
574
+ pass
575
+ ```
576
+
577
+ ### 3단계: 플러그인 등록
578
+
579
+ 플러그인 디렉토리 구조:
580
+
581
+ ```
582
+ my_plugin/
583
+ ├── __init__.py
584
+ ├── plugin.py # MyExporter 클래스 정의
585
+ └── manifest.yaml # 플러그인 메타데이터
586
+ ```
587
+
588
+ ## Export 액션 아키텍처
589
+
590
+ 데이터 내보내기 처리의 다양한 측면을 위한 특화된 구성 요소를 갖춘 모듈화된 아키텍처로 export 시스템이 리팩터링되었습니다:
591
+
592
+ ```mermaid
593
+ classDiagram
594
+ %% Light/Dark mode compatible colors with semi-transparency
595
+ classDef baseClass fill:#e1f5fe80,stroke:#0288d1,stroke-width:2px
596
+ classDef childClass fill:#c8e6c980,stroke:#388e3c,stroke-width:2px
597
+ classDef modelClass fill:#fff9c480,stroke:#f57c00,stroke-width:2px
598
+ classDef utilClass fill:#f5f5f580,stroke:#616161,stroke-width:2px
599
+ classDef enumClass fill:#ffccbc80,stroke:#d32f2f,stroke-width:2px
600
+
601
+ class ExportAction {
602
+ +name: str = "export"
603
+ +category: PluginCategory.EXPORT
604
+ +method: RunMethod.JOB
605
+ +run_class: ExportRun
606
+ +params_model: ExportParams
607
+ +progress_categories: dict
608
+ +metrics_categories: dict
609
+
610
+ +start() dict
611
+ +get_exporter(...) object
612
+ +_get_export_items(target, filter) Generator
613
+ +_create_target_handler(target) object
614
+ }
615
+
616
+ class ExportRun {
617
+ +log_message_with_code(code, args, level) None
618
+ +log_export_event(code, args, level) None
619
+ +export_log_json_file(id, file_info, status) None
620
+ +export_log_original_file(id, file_info, status) None
621
+ +ExportEventLog: BaseModel
622
+ +DataFileLog: BaseModel
623
+ +MetricsRecord: BaseModel
624
+ }
625
+
626
+ class ExportParams {
627
+ +name: str
628
+ +storage: int
629
+ +target: Literal["assignment", "ground_truth", "task"]
630
+ +filter: dict
631
+ +path: str
632
+ +save_original_file: bool = True
633
+ +extra_params: dict = {}
634
+
635
+ +check_storage_exists(value) str
636
+ +validate_target_filter(cls, values) dict
637
+ }
638
+
639
+ class LogCode {
640
+ +EXPORT_STARTED: str
641
+ +ITEMS_DISCOVERED: str
642
+ +CONVERSION_STARTED: str
643
+ +CONVERSION_COMPLETED: str
644
+ +FILE_SAVED: str
645
+ +EXPORT_COMPLETED: str
646
+ +EXPORT_FAILED: str
647
+ }
648
+
649
+ class ExportStatus {
650
+ +SUCCESS: str = "success"
651
+ +FAILED: str = "failed"
652
+ +SKIPPED: str = "skipped"
653
+ }
654
+
655
+ class ExportError {
656
+ +message: str
657
+ +code: str
658
+ }
659
+
660
+ class ExportValidationError {
661
+ +message: str
662
+ +field: str
663
+ }
664
+
665
+ class ExportTargetError {
666
+ +message: str
667
+ +target: str
668
+ }
669
+
670
+ %% Relationships
671
+ ExportAction --> ExportRun : uses
672
+ ExportAction --> ExportParams : validates with
673
+ ExportRun --> LogCode : logs with
674
+ ExportRun --> ExportStatus : tracks status
675
+ ExportAction --> ExportError : may raise
676
+ ExportAction --> ExportValidationError : may raise
677
+ ExportAction --> ExportTargetError : may raise
678
+
679
+ %% Apply styles
680
+ class ExportAction baseClass
681
+ class ExportRun childClass
682
+ class ExportParams modelClass
683
+ class LogCode,ExportStatus enumClass
684
+ class ExportError,ExportValidationError,ExportTargetError utilClass
685
+ ```
686
+
687
+ ### 모듈화된 구조
688
+
689
+ Export 액션은 깔끔한 모듈화된 구성을 따릅니다:
690
+
691
+ ```
692
+ synapse_sdk/plugins/categories/export/actions/export/
693
+ ├── __init__.py # 깔끔한 모듈 인터페이스
694
+ ├── action.py # ExportAction 클래스
695
+ ├── enums.py # ExportStatus, LogCode + LOG_MESSAGES
696
+ ├── exceptions.py # Export 특화 예외
697
+ ├── models.py # ExportParams 모델
698
+ ├── run.py # ExportRun 클래스
699
+ └── utils.py # 대상 핸들러 및 유틸리티
700
+ ```
701
+
702
+ **주요 장점:**
703
+
704
+ - **향상된 유지보수성**: 작고 집중된 파일로 이해하고 수정하기 쉬움
705
+ - **코드 일관성**: Export 액션이 이제 upload 액션과 동일한 패턴을 따름
706
+ - **더 나은 구성**: 관련 기능이 논리적으로 그룹화됨
707
+ - **향상된 가독성**: 모듈 전반에 걸친 명확한 관심사 분리
708
+
709
+ ## Export 플러그인 생성
710
+
711
+ Export 플러그인은 더 나은 구성과 재사용성을 위해 BaseExporter 클래스 기반 접근 방식을 사용합니다. 커스텀 export 플러그인을 생성하는 방법은 다음과 같습니다:
712
+
713
+ ### 1단계: Export 플러그인 템플릿 생성
714
+
715
+ ```bash
716
+ synapse plugin create
717
+ # 카테고리로 'export' 선택
718
+ # export 템플릿으로 플러그인이 생성됩니다
719
+ ```
720
+
721
+ ### 2단계: Export 매개변수 커스터마이징
722
+
723
+ `ExportParams` 모델이 필요한 매개변수를 정의합니다:
724
+
725
+ ```python
726
+ from synapse_sdk.plugins.categories.export.actions.export.models import ExportParams
727
+ from pydantic import BaseModel
728
+ from typing import Literal
729
+
730
+ class CustomExportParams(ExportParams):
731
+ # 커스텀 매개변수 추가
732
+ output_format: Literal['json', 'csv', 'xml'] = 'json'
733
+ include_metadata: bool = True
734
+ compression: bool = False
735
+ ```
736
+
737
+ ### 3단계: 데이터 변환 구현
738
+
739
+ `plugin/export.py`의 `Exporter` 클래스에서 필요한 메서드를 구현합니다:
740
+
741
+ ```python
742
+ from datetime import datetime
743
+ from synapse_sdk.plugins.categories.export.templates.plugin import BaseExporter
744
+
745
+ class Exporter(BaseExporter):
746
+ """COCO 형식 변환을 포함한 커스텀 export 플러그인."""
747
+
748
+ def convert_data(self, data):
749
+ """주석 데이터를 원하는 형식으로 변환합니다."""
750
+ # 예시: COCO 형식으로 변환
751
+ if data.get('data_type') == 'image_detection':
752
+ return self.convert_to_coco_format(data)
753
+ elif data.get('data_type') == 'image_classification':
754
+ return self.convert_to_classification_format(data)
755
+ return data
756
+
757
+ def before_convert(self, export_item):
758
+ """변환 전 데이터 전처리."""
759
+ # 검증, 필터링 또는 전처리 추가
760
+ if not export_item.get('data'):
761
+ return None # 빈 항목 건너뛰기
762
+
763
+ # 커스텀 메타데이터 추가
764
+ export_item['processed_at'] = datetime.now().isoformat()
765
+ return export_item
766
+
767
+ def after_convert(self, converted_data):
768
+ """변환된 데이터 후처리."""
769
+ # 최종 마무리, 검증 또는 형식 지정 추가
770
+ if 'annotations' in converted_data:
771
+ converted_data['annotation_count'] = len(converted_data['annotations'])
772
+ return converted_data
773
+
774
+ def convert_to_coco_format(self, data):
775
+ """예시: COCO 검출 형식으로 변환."""
776
+ coco_data = {
777
+ "images": [],
778
+ "annotations": [],
779
+ "categories": []
780
+ }
781
+
782
+ # 주석 데이터를 COCO 형식으로 변환
783
+ for annotation in data.get('annotations', []):
784
+ coco_annotation = {
785
+ "id": annotation['id'],
786
+ "image_id": annotation['image_id'],
787
+ "category_id": annotation['category_id'],
788
+ "bbox": annotation['bbox'],
789
+ "area": annotation.get('area', 0),
790
+ "iscrowd": 0
791
+ }
792
+ coco_data["annotations"].append(coco_annotation)
793
+
794
+ return coco_data
795
+ ```
796
+
797
+ ### 4단계: Export 대상 구성
798
+
799
+ Export 액션은 다양한 데이터 소스를 지원합니다:
800
+
801
+ ```python
802
+ # 다양한 대상에 대한 필터 예시
803
+ filters = {
804
+ # 그라운드 트루스 내보내기용
805
+ "ground_truth": {
806
+ "ground_truth_dataset_version": 123,
807
+ "expand": ["data"]
808
+ },
809
+
810
+ # 할당 내보내기용
811
+ "assignment": {
812
+ "project": 456,
813
+ "status": "completed",
814
+ "expand": ["data"]
815
+ },
816
+
817
+ # 작업 내보내기용
818
+ "task": {
819
+ "project": 456,
820
+ "assignment": 789,
821
+ "expand": ["data_unit", "assignment"]
822
+ }
823
+ }
824
+ ```
825
+
826
+ ### 5단계: 파일 작업 처리
827
+
828
+ BaseExporter 메서드를 오버라이드하여 파일 저장 및 구성을 커스터마이징합니다:
829
+
830
+ ```python
831
+ import json
832
+ from pathlib import Path
833
+ from synapse_sdk.plugins.categories.export.actions.export.enums import ExportStatus
834
+
835
+ class Exporter(BaseExporter):
836
+ """다중 형식 지원을 포함한 커스텀 export 플러그인."""
837
+
838
+ def save_as_json(self, result, base_path, error_file_list):
839
+ """다양한 형식으로 커스텀 JSON 저장."""
840
+ file_name = Path(self.get_original_file_name(result['files'])).stem
841
+
842
+ # 매개변수에 따른 출력 형식 선택
843
+ if self.params.get('output_format') == 'csv':
844
+ return self.save_as_csv(result, base_path, error_file_list)
845
+ elif self.params.get('output_format') == 'xml':
846
+ return self.save_as_xml(result, base_path, error_file_list)
847
+
848
+ # 기본 JSON 처리
849
+ json_data = result['data']
850
+ file_info = {'file_name': f'{file_name}.json'}
851
+
852
+ try:
853
+ with (base_path / f'{file_name}.json').open('w', encoding='utf-8') as f:
854
+ json.dump(json_data, f, indent=4, ensure_ascii=False)
855
+ status = ExportStatus.SUCCESS
856
+ except Exception as e:
857
+ error_file_list.append([f'{file_name}.json', str(e)])
858
+ status = ExportStatus.FAILED
859
+
860
+ self.run.export_log_json_file(result['id'], file_info, status)
861
+ return status
862
+
863
+ def setup_output_directories(self, unique_export_path, save_original_file_flag):
864
+ """커스텀 디렉토리 구조."""
865
+ # 형식별 디렉토리 생성
866
+ output_paths = super().setup_output_directories(unique_export_path, save_original_file_flag)
867
+
868
+ # 출력 형식에 따른 커스텀 디렉토리 추가
869
+ format_dir = unique_export_path / self.params.get('output_format', 'json')
870
+ format_dir.mkdir(parents=True, exist_ok=True)
871
+ output_paths['format_output_path'] = format_dir
872
+
873
+ return output_paths
874
+ ```
875
+
876
+ ### 6단계: 사용 예시
877
+
878
+ 다양한 구성으로 export 플러그인 실행:
879
+
880
+ ```bash
881
+ # 그라운드 트루스 데이터 기본 내보내기
882
+ synapse plugin run export '{
883
+ "name": "my_export",
884
+ "storage": 1,
885
+ "target": "ground_truth",
886
+ "filter": {"ground_truth_dataset_version": 123},
887
+ "path": "exports/ground_truth",
888
+ "save_original_file": true
889
+ }' --plugin my-export-plugin
890
+
891
+ # 커스텀 매개변수로 할당 내보내기
892
+ synapse plugin run export '{
893
+ "name": "assignment_export",
894
+ "storage": 1,
895
+ "target": "assignment",
896
+ "filter": {"project": 456, "status": "completed"},
897
+ "path": "exports/assignments",
898
+ "save_original_file": false,
899
+ "extra_params": {
900
+ "output_format": "coco",
901
+ "include_metadata": true
902
+ }
903
+ }' --plugin custom-coco-export
904
+ ```
905
+
906
+ ## 일반적인 Export 패턴
907
+
908
+ ```python
909
+ # 패턴 1: 형식별 변환
910
+ class Exporter(BaseExporter):
911
+ def convert_data(self, data):
912
+ """YOLO 형식으로 변환."""
913
+ if data.get('task_type') == 'object_detection':
914
+ return self.convert_to_yolo_format(data)
915
+ return data
916
+
917
+ # 패턴 2: 조건부 파일 구성
918
+ class Exporter(BaseExporter):
919
+ def setup_output_directories(self, unique_export_path, save_original_file_flag):
920
+ # 부모 메서드 호출
921
+ output_paths = super().setup_output_directories(unique_export_path, save_original_file_flag)
922
+
923
+ # 카테고리별 별도 폴더 생성
924
+ for category in ['train', 'val', 'test']:
925
+ category_path = unique_export_path / category
926
+ category_path.mkdir(parents=True, exist_ok=True)
927
+ output_paths[f'{category}_path'] = category_path
928
+
929
+ return output_paths
930
+
931
+ # 패턴 3: 검증을 포함한 배치 처리
932
+ class Exporter(BaseExporter):
933
+ def before_convert(self, export_item):
934
+ # 필수 필드 검증
935
+ required_fields = ['data', 'files', 'id']
936
+ for field in required_fields:
937
+ if field not in export_item:
938
+ raise ValueError(f"필수 필드가 누락됨: {field}")
939
+ return export_item
940
+ ```
941
+
942
+ ## 개발 팁 및 모범 사례
943
+
944
+ ### 1. 오류 처리
945
+
946
+ ```python
947
+ def convert_data(self, data):
948
+ try:
949
+ # 변환 로직
950
+ result = self.process_annotations(data)
951
+ return result
952
+ except Exception as e:
953
+ self.run.log_message(f"변환 중 오류 발생: {str(e)}", level="error")
954
+ raise # BaseExporter가 오류를 자동으로 처리
955
+ ```
956
+
957
+ ### 2. 진행률 추적
958
+
959
+ ```python
960
+ def convert_data(self, data):
961
+ annotations = data.get('annotations', [])
962
+ total = len(annotations)
963
+
964
+ for i, annotation in enumerate(annotations):
965
+ # 진행률 업데이트 (0-100 사이의 값)
966
+ progress = int((i / total) * 100)
967
+ self.run.set_progress(progress)
968
+
969
+ # 변환 로직...
970
+
971
+ return converted_data
972
+ ```
973
+
974
+ ### 3. 메트릭 수집
975
+
976
+ ```python
977
+ def after_convert(self, converted_data):
978
+ # 유용한 메트릭 수집
979
+ metrics = {
980
+ 'total_exported': len(converted_data.get('annotations', [])),
981
+ 'processing_time': time.time() - self.start_time,
982
+ 'success_rate': self.calculate_success_rate(),
983
+ }
984
+
985
+ self.run.log_metrics(metrics)
986
+ return converted_data
987
+ ```
988
+
989
+ ### 4. 로깅 활용
990
+
991
+ ```python
992
+ def convert_data(self, data):
993
+ self.run.log_message("데이터 변환 시작", level="info")
994
+
995
+ if not data.get('annotations'):
996
+ self.run.log_message("주석 데이터가 없습니다", level="warning")
997
+ return data
998
+
999
+ # 변환 로직...
1000
+
1001
+ self.run.log_message(f"변환 완료: {len(result)} 항목 처리됨", level="success")
1002
+ return result
1003
+ ```
1004
+
1005
+ ### 5. 매개변수 처리
1006
+
1007
+ ```python
1008
+ def __init__(self, run, export_items, path_root, **params):
1009
+ super().__init__(run, export_items, path_root, **params)
1010
+
1011
+ # 사용자 정의 매개변수 처리
1012
+ self.output_format = params.get('output_format', 'json')
1013
+ self.include_metadata = params.get('include_metadata', True)
1014
+ self.compression = params.get('compression', False)
1015
+ ```
1016
+
1017
+ ## 모범 사례
1018
+
1019
+ ### 데이터 처리
1020
+
1021
+ - **메모리 효율성**: 대용량 데이터셋 처리를 위해 제너레이터 사용
1022
+ - **오류 복구**: 개별 항목에 대한 우아한 오류 처리 구현
1023
+ - **진행률 보고**: 장시간 실행되는 내보내기의 진행률을 정기적으로 업데이트
1024
+ - **데이터 검증**: 변환 전 데이터 구조 검증
1025
+
1026
+ ```python
1027
+ class Exporter(BaseExporter):
1028
+ def export(self, export_items=None, results=None, **kwargs):
1029
+ """커스텀 처리를 위한 주 export 메서드 오버라이드."""
1030
+ # 제너레이터를 소비하지 않고 항목 수를 카운트하기 위해 tee 사용
1031
+ items_to_process = export_items if export_items is not None else self.export_items
1032
+ export_items_count, export_items_process = tee(items_to_process)
1033
+ total = sum(1 for _ in export_items_count)
1034
+
1035
+ # 오류 처리가 포함된 커스텀 처리
1036
+ for no, export_item in enumerate(export_items_process, start=1):
1037
+ try:
1038
+ # 내장 데이터 변환 파이프라인 사용
1039
+ processed_item = self.process_data_conversion(export_item)
1040
+ self.run.set_progress(no, total, category='dataset_conversion')
1041
+ except Exception as e:
1042
+ self.run.log_message(f"항목 {no} 처리 중 오류: {str(e)}", "ERROR")
1043
+ continue
1044
+
1045
+ # 표준 처리를 위해 부모의 export 메서드 호출
1046
+ # 또는 자체 완전한 워크플로우 구현
1047
+ return super().export(export_items, results, **kwargs)
1048
+ ```
1049
+
1050
+ ### 파일 관리
1051
+
1052
+ - **고유 경로**: 타임스탬프나 카운터 접미사로 파일 충돌 방지
1053
+ - **디렉토리 구조**: 출력 파일을 논리적으로 구성
1054
+ - **오류 로깅**: 디버깅을 위해 실패한 파일 추적
1055
+ - **정리**: 완료 시 임시 파일 제거
1056
+
1057
+ ```python
1058
+ class Exporter(BaseExporter):
1059
+ def setup_output_directories(self, unique_export_path, save_original_file_flag):
1060
+ """고유한 export 디렉토리 구조 생성."""
1061
+ # BaseExporter는 이미 _create_unique_export_path를 통해 고유 경로 생성을 처리함
1062
+ # 이 메서드는 내부 디렉토리 구조를 설정함
1063
+ output_paths = super().setup_output_directories(unique_export_path, save_original_file_flag)
1064
+
1065
+ # 필요에 따라 커스텀 서브디렉토리 추가
1066
+ custom_dir = unique_export_path / 'custom_output'
1067
+ custom_dir.mkdir(parents=True, exist_ok=True)
1068
+ output_paths['custom_output_path'] = custom_dir
1069
+
1070
+ return output_paths
1071
+ ```
1072
+
1073
+ ### 형식 변환
1074
+
1075
+ - **유연한 템플릿**: 여러 데이터 타입과 함께 작동하는 템플릿 설계
1076
+ - **스키마 검증**: 예상 스키마에 대한 출력 검증
1077
+ - **메타데이터 보존**: 변환 중 중요한 메타데이터 유지
1078
+ - **버전 호환성**: 다양한 데이터 스키마 버전 처리
1079
+
1080
+ ## 자주 묻는 질문
1081
+
1082
+ **Q: BaseExporter를 사용하지 않고 직접 구현할 수 있나요?**
1083
+ A: 가능하지만 권장하지 않습니다. BaseExporter는 진행률 추적, 오류 처리, 메트릭 수집 등의 기본 기능을 자동으로 제공합니다.
1084
+
1085
+ **Q: 여러 파일 형식으로 동시에 내보낼 수 있나요?**
1086
+ A: `process_file_saving()` 메서드를 오버라이드하여 여러 형식으로 저장할 수 있습니다.
1087
+
1088
+ **Q: 대용량 데이터셋을 처리할 때 메모리 사용량을 최적화하려면?**
1089
+ A: `convert_data()`에서 한 번에 모든 데이터를 로드하지 말고, 스트리밍 방식으로 처리하는 것을 고려해보세요.
1090
+
1091
+ **Q: 진행률이 올바르게 표시되지 않는다면?**
1092
+ A: `self.run.set_progress()`를 적절한 간격으로 호출하고 있는지 확인하세요. 0-100 사이의 정수 값을 사용해야 합니다.