synapse-sdk 2025.9.1__py3-none-any.whl → 2025.9.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of synapse-sdk might be problematic. Click here for more details.
- synapse_sdk/devtools/docs/docs/api/clients/annotation-mixin.md +378 -0
- synapse_sdk/devtools/docs/docs/api/clients/backend.md +368 -1
- 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/plugins/developing-upload-template.md +1463 -0
- synapse_sdk/devtools/docs/docs/plugins/export-plugins.md +161 -34
- synapse_sdk/devtools/docs/docs/plugins/upload-plugins.md +1497 -213
- 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 +378 -11
- 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/plugins/developing-upload-template.md +1463 -0
- synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/plugins/export-plugins.md +161 -34
- synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/plugins/upload-plugins.md +1752 -572
- synapse_sdk/devtools/docs/sidebars.ts +7 -0
- synapse_sdk/plugins/README.md +1 -2
- synapse_sdk/plugins/categories/base.py +23 -0
- 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 +160 -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/plugin/__init__.py +1 -1
- synapse_sdk/plugins/categories/upload/actions/upload/__init__.py +1 -2
- synapse_sdk/plugins/categories/upload/actions/upload/action.py +154 -531
- synapse_sdk/plugins/categories/upload/actions/upload/context.py +185 -0
- synapse_sdk/plugins/categories/upload/actions/upload/factory.py +143 -0
- synapse_sdk/plugins/categories/upload/actions/upload/models.py +66 -29
- synapse_sdk/plugins/categories/upload/actions/upload/orchestrator.py +182 -0
- synapse_sdk/plugins/categories/upload/actions/upload/registry.py +113 -0
- synapse_sdk/plugins/categories/upload/actions/upload/steps/__init__.py +1 -0
- synapse_sdk/plugins/categories/upload/actions/upload/steps/base.py +106 -0
- synapse_sdk/plugins/categories/upload/actions/upload/steps/cleanup.py +62 -0
- synapse_sdk/plugins/categories/upload/actions/upload/steps/collection.py +62 -0
- synapse_sdk/plugins/categories/upload/actions/upload/steps/generate.py +80 -0
- synapse_sdk/plugins/categories/upload/actions/upload/steps/initialize.py +66 -0
- synapse_sdk/plugins/categories/upload/actions/upload/steps/metadata.py +101 -0
- synapse_sdk/plugins/categories/upload/actions/upload/steps/organize.py +89 -0
- synapse_sdk/plugins/categories/upload/actions/upload/steps/upload.py +96 -0
- synapse_sdk/plugins/categories/upload/actions/upload/steps/validate.py +61 -0
- synapse_sdk/plugins/categories/upload/actions/upload/strategies/__init__.py +1 -0
- synapse_sdk/plugins/categories/upload/actions/upload/strategies/base.py +86 -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 +34 -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 +233 -0
- synapse_sdk/plugins/categories/upload/actions/upload/strategies/file_discovery/recursive.py +238 -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/async_upload.py +109 -0
- synapse_sdk/plugins/categories/upload/actions/upload/strategies/upload/sync.py +43 -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 +45 -0
- synapse_sdk/plugins/categories/upload/actions/upload/utils.py +194 -83
- synapse_sdk/plugins/categories/upload/templates/config.yaml +4 -0
- synapse_sdk/plugins/categories/upload/templates/plugin/__init__.py +269 -0
- synapse_sdk/plugins/categories/upload/templates/plugin/upload.py +71 -27
- synapse_sdk/plugins/models.py +5 -0
- {synapse_sdk-2025.9.1.dist-info → synapse_sdk-2025.9.3.dist-info}/METADATA +2 -1
- {synapse_sdk-2025.9.1.dist-info → synapse_sdk-2025.9.3.dist-info}/RECORD +78 -27
- synapse_sdk/plugins/categories/export/actions/export.py +0 -385
- synapse_sdk/plugins/categories/export/enums.py +0 -7
- {synapse_sdk-2025.9.1.dist-info → synapse_sdk-2025.9.3.dist-info}/WHEEL +0 -0
- {synapse_sdk-2025.9.1.dist-info → synapse_sdk-2025.9.3.dist-info}/entry_points.txt +0 -0
- {synapse_sdk-2025.9.1.dist-info → synapse_sdk-2025.9.3.dist-info}/licenses/LICENSE +0 -0
- {synapse_sdk-2025.9.1.dist-info → synapse_sdk-2025.9.3.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,356 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: data-collection-mixin
|
|
3
|
+
title: DataCollectionClientMixin
|
|
4
|
+
sidebar_position: 13
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# DataCollectionClientMixin
|
|
8
|
+
|
|
9
|
+
Synapse 백엔드를 위한 데이터 수집 및 파일 관리 작업을 제공합니다.
|
|
10
|
+
|
|
11
|
+
## 개요
|
|
12
|
+
|
|
13
|
+
`DataCollectionClientMixin`은 데이터 컬렉션, 파일 업로드, 데이터 유닛, 일괄 처리와 관련된 모든 작업을 처리합니다. 이 믹스인은 `BackendClient`에 자동으로 포함되며 대규모 데이터 작업을 관리하기 위한 메서드를 제공합니다.
|
|
14
|
+
|
|
15
|
+
## 데이터 컬렉션 작업
|
|
16
|
+
|
|
17
|
+
### `list_data_collection()`
|
|
18
|
+
|
|
19
|
+
사용 가능한 모든 데이터 컬렉션 목록을 가져옵니다.
|
|
20
|
+
|
|
21
|
+
```python
|
|
22
|
+
collections = client.list_data_collection()
|
|
23
|
+
for collection in collections:
|
|
24
|
+
print(f"컬렉션: {collection['name']} (ID: {collection['id']})")
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
**반환값:**
|
|
28
|
+
|
|
29
|
+
- `list`: 데이터 컬렉션 객체의 목록
|
|
30
|
+
|
|
31
|
+
### `get_data_collection(data_collection_id)`
|
|
32
|
+
|
|
33
|
+
특정 데이터 컬렉션에 대한 상세 정보를 가져옵니다.
|
|
34
|
+
|
|
35
|
+
```python
|
|
36
|
+
collection = client.get_data_collection(123)
|
|
37
|
+
print(f"컬렉션: {collection['name']}")
|
|
38
|
+
print(f"설명: {collection['description']}")
|
|
39
|
+
|
|
40
|
+
# 파일 사양 접근
|
|
41
|
+
file_specs = collection['file_specifications']
|
|
42
|
+
for spec in file_specs:
|
|
43
|
+
print(f"파일 유형: {spec['name']}, 필수: {spec['is_required']}")
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
**매개변수:**
|
|
47
|
+
|
|
48
|
+
- `data_collection_id` (int): 데이터 컬렉션 ID
|
|
49
|
+
|
|
50
|
+
**반환값:**
|
|
51
|
+
|
|
52
|
+
- `dict`: 파일 사양을 포함한 상세 컬렉션 정보
|
|
53
|
+
|
|
54
|
+
**컬렉션 구조:**
|
|
55
|
+
|
|
56
|
+
- `id`: 컬렉션 ID
|
|
57
|
+
- `name`: 컬렉션 이름
|
|
58
|
+
- `description`: 컬렉션 설명
|
|
59
|
+
- `file_specifications`: 필수 파일 유형 및 형식 목록
|
|
60
|
+
- `project`: 연관된 프로젝트 ID
|
|
61
|
+
- `created_at`: 생성 타임스탬프
|
|
62
|
+
|
|
63
|
+
## 파일 작업
|
|
64
|
+
|
|
65
|
+
### `create_data_file(file_path, use_chunked_upload=False)`
|
|
66
|
+
|
|
67
|
+
백엔드에 데이터 파일을 생성하고 업로드합니다.
|
|
68
|
+
|
|
69
|
+
```python
|
|
70
|
+
from pathlib import Path
|
|
71
|
+
|
|
72
|
+
# 작은 파일을 위한 일반 업로드
|
|
73
|
+
data_file = client.create_data_file(Path('/path/to/image.jpg'))
|
|
74
|
+
print(f"업로드된 파일 ID: {data_file['id']}")
|
|
75
|
+
|
|
76
|
+
# 대용량 파일을 위한 청크 업로드 (50MB 이상 권장)
|
|
77
|
+
large_file = client.create_data_file(
|
|
78
|
+
Path('/path/to/large_dataset.zip'),
|
|
79
|
+
use_chunked_upload=True
|
|
80
|
+
)
|
|
81
|
+
print(f"대용량 파일 업로드됨: {large_file['id']}")
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
**매개변수:**
|
|
85
|
+
|
|
86
|
+
- `file_path` (Path): 업로드할 파일을 가리키는 Path 객체
|
|
87
|
+
- `use_chunked_upload` (bool): 대용량 파일을 위한 청크 업로드 활성화
|
|
88
|
+
|
|
89
|
+
**반환값:**
|
|
90
|
+
|
|
91
|
+
- `dict` 또는 `str`: 파일 ID와 메타데이터가 포함된 파일 업로드 응답
|
|
92
|
+
|
|
93
|
+
**청크 업로드를 사용해야 하는 경우:**
|
|
94
|
+
|
|
95
|
+
- 50MB보다 큰 파일
|
|
96
|
+
- 불안정한 네트워크 연결
|
|
97
|
+
- 업로드 진행률 추적이 필요한 경우
|
|
98
|
+
- 더 나은 오류 복구를 위해
|
|
99
|
+
|
|
100
|
+
### `upload_data_file(organized_file, collection_id, use_chunked_upload=False)`
|
|
101
|
+
|
|
102
|
+
정리된 파일 데이터를 특정 컬렉션에 업로드합니다.
|
|
103
|
+
|
|
104
|
+
```python
|
|
105
|
+
# 파일 데이터 정리
|
|
106
|
+
organized_file = {
|
|
107
|
+
'files': {
|
|
108
|
+
'image': Path('/path/to/image.jpg'),
|
|
109
|
+
'annotation': Path('/path/to/annotation.json'),
|
|
110
|
+
'metadata': Path('/path/to/metadata.xml')
|
|
111
|
+
},
|
|
112
|
+
'meta': {
|
|
113
|
+
'origin_file_stem': 'sample_001',
|
|
114
|
+
'origin_file_extension': '.jpg',
|
|
115
|
+
'created_at': '2023-10-01T12:00:00Z',
|
|
116
|
+
'batch_id': 'batch_001'
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
# 컬렉션에 업로드
|
|
121
|
+
result = client.upload_data_file(
|
|
122
|
+
organized_file=organized_file,
|
|
123
|
+
collection_id=123,
|
|
124
|
+
use_chunked_upload=False
|
|
125
|
+
)
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
**매개변수:**
|
|
129
|
+
|
|
130
|
+
- `organized_file` (dict): 파일과 메타데이터가 포함된 구조화된 파일 데이터
|
|
131
|
+
- `collection_id` (int): 대상 데이터 컬렉션 ID
|
|
132
|
+
- `use_chunked_upload` (bool): 청크 업로드 활성화
|
|
133
|
+
|
|
134
|
+
**정리된 파일 구조:**
|
|
135
|
+
|
|
136
|
+
- `files` (dict): 파일 유형을 파일 경로에 매핑하는 딕셔너리
|
|
137
|
+
- `meta` (dict): 파일 그룹과 연관된 메타데이터
|
|
138
|
+
|
|
139
|
+
**반환값:**
|
|
140
|
+
|
|
141
|
+
- `dict`: 파일 참조와 ID가 포함된 업로드 결과
|
|
142
|
+
|
|
143
|
+
### `create_data_units(uploaded_files)`
|
|
144
|
+
|
|
145
|
+
이전에 업로드된 파일에서 데이터 유닛을 생성합니다.
|
|
146
|
+
|
|
147
|
+
```python
|
|
148
|
+
# 업로드된 파일들
|
|
149
|
+
uploaded_files = [
|
|
150
|
+
{
|
|
151
|
+
'id': 1,
|
|
152
|
+
'file': {'image': 'file_id_123', 'annotation': 'file_id_124'},
|
|
153
|
+
'meta': {'batch': 'batch_001'}
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
'id': 2,
|
|
157
|
+
'file': {'image': 'file_id_125', 'annotation': 'file_id_126'},
|
|
158
|
+
'meta': {'batch': 'batch_001'}
|
|
159
|
+
}
|
|
160
|
+
]
|
|
161
|
+
|
|
162
|
+
# 데이터 유닛 생성
|
|
163
|
+
data_units = client.create_data_units(uploaded_files)
|
|
164
|
+
print(f"{len(data_units)}개의 데이터 유닛 생성됨")
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
**매개변수:**
|
|
168
|
+
|
|
169
|
+
- `uploaded_files` (list): 업로드된 파일 구조의 목록
|
|
170
|
+
|
|
171
|
+
**반환값:**
|
|
172
|
+
|
|
173
|
+
- `list`: ID와 메타데이터가 포함된 생성된 데이터 유닛
|
|
174
|
+
|
|
175
|
+
## 일괄 처리
|
|
176
|
+
|
|
177
|
+
믹스인은 대규모 작업을 위한 효율적인 일괄 처리를 지원합니다:
|
|
178
|
+
|
|
179
|
+
```python
|
|
180
|
+
from multiprocessing import Pool
|
|
181
|
+
from pathlib import Path
|
|
182
|
+
|
|
183
|
+
# 예제: 여러 파일 일괄 업로드
|
|
184
|
+
file_paths = [
|
|
185
|
+
Path('/data/batch1/file1.jpg'),
|
|
186
|
+
Path('/data/batch1/file2.jpg'),
|
|
187
|
+
Path('/data/batch1/file3.jpg'),
|
|
188
|
+
# ... 더 많은 파일
|
|
189
|
+
]
|
|
190
|
+
|
|
191
|
+
# 파일을 배치로 처리
|
|
192
|
+
batch_size = 10
|
|
193
|
+
for i in range(0, len(file_paths), batch_size):
|
|
194
|
+
batch = file_paths[i:i+batch_size]
|
|
195
|
+
|
|
196
|
+
# 배치 업로드
|
|
197
|
+
uploaded_files = []
|
|
198
|
+
for file_path in batch:
|
|
199
|
+
result = client.create_data_file(file_path)
|
|
200
|
+
uploaded_files.append({
|
|
201
|
+
'id': len(uploaded_files) + 1,
|
|
202
|
+
'file': {'image': result['id']},
|
|
203
|
+
'meta': {'batch': f'batch_{i//batch_size}'}
|
|
204
|
+
})
|
|
205
|
+
|
|
206
|
+
# 배치용 데이터 유닛 생성
|
|
207
|
+
data_units = client.create_data_units(uploaded_files)
|
|
208
|
+
print(f"배치 {i//batch_size} 처리됨: {len(data_units)}개의 데이터 유닛")
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
## 진행률 추적
|
|
212
|
+
|
|
213
|
+
대용량 업로드의 경우 진행률을 추적할 수 있습니다:
|
|
214
|
+
|
|
215
|
+
```python
|
|
216
|
+
import os
|
|
217
|
+
from tqdm import tqdm
|
|
218
|
+
|
|
219
|
+
def upload_with_progress(file_paths, collection_id):
|
|
220
|
+
"""진행률 추적과 함께 파일 업로드."""
|
|
221
|
+
uploaded_files = []
|
|
222
|
+
|
|
223
|
+
with tqdm(total=len(file_paths), desc="파일 업로드 중") as pbar:
|
|
224
|
+
for file_path in file_paths:
|
|
225
|
+
try:
|
|
226
|
+
# 업로드 방법을 결정하기 위해 파일 크기 확인
|
|
227
|
+
file_size = os.path.getsize(file_path)
|
|
228
|
+
use_chunked = file_size > 50 * 1024 * 1024 # 50MB
|
|
229
|
+
|
|
230
|
+
# 파일 업로드
|
|
231
|
+
result = client.create_data_file(
|
|
232
|
+
file_path,
|
|
233
|
+
use_chunked_upload=use_chunked
|
|
234
|
+
)
|
|
235
|
+
|
|
236
|
+
# 컬렉션용 정리
|
|
237
|
+
organized_file = {
|
|
238
|
+
'files': {'primary': file_path},
|
|
239
|
+
'meta': {
|
|
240
|
+
'origin_file_stem': file_path.stem,
|
|
241
|
+
'origin_file_extension': file_path.suffix,
|
|
242
|
+
'file_size': file_size
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
upload_result = client.upload_data_file(
|
|
247
|
+
organized_file,
|
|
248
|
+
collection_id,
|
|
249
|
+
use_chunked_upload=use_chunked
|
|
250
|
+
)
|
|
251
|
+
|
|
252
|
+
uploaded_files.append(upload_result)
|
|
253
|
+
pbar.update(1)
|
|
254
|
+
|
|
255
|
+
except Exception as e:
|
|
256
|
+
print(f"{file_path} 업로드 실패: {e}")
|
|
257
|
+
pbar.update(1)
|
|
258
|
+
continue
|
|
259
|
+
|
|
260
|
+
return uploaded_files
|
|
261
|
+
|
|
262
|
+
# 사용법
|
|
263
|
+
file_paths = [Path(f'/data/file_{i}.jpg') for i in range(100)]
|
|
264
|
+
results = upload_with_progress(file_paths, collection_id=123)
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
## 데이터 검증
|
|
268
|
+
|
|
269
|
+
### 파일 사양 검증
|
|
270
|
+
|
|
271
|
+
```python
|
|
272
|
+
def validate_files_against_collection(file_paths, collection_id):
|
|
273
|
+
"""컬렉션 사양에 대해 파일을 검증."""
|
|
274
|
+
collection = client.get_data_collection(collection_id)
|
|
275
|
+
file_specs = collection['file_specifications']
|
|
276
|
+
|
|
277
|
+
# 사양 조회 생성
|
|
278
|
+
required_types = {spec['name'] for spec in file_specs if spec['is_required']}
|
|
279
|
+
optional_types = {spec['name'] for spec in file_specs if not spec['is_required']}
|
|
280
|
+
|
|
281
|
+
# 파일 정리 검증
|
|
282
|
+
organized_files = []
|
|
283
|
+
for file_path in file_paths:
|
|
284
|
+
# 경로 또는 메타데이터에서 파일 유형 추출
|
|
285
|
+
file_type = extract_file_type(file_path) # 사용자 정의 함수
|
|
286
|
+
|
|
287
|
+
if file_type in required_types or file_type in optional_types:
|
|
288
|
+
organized_files.append({
|
|
289
|
+
'path': file_path,
|
|
290
|
+
'type': file_type,
|
|
291
|
+
'valid': True
|
|
292
|
+
})
|
|
293
|
+
else:
|
|
294
|
+
print(f"경고: {file_path}에 대한 알 수 없는 파일 유형 '{file_type}'")
|
|
295
|
+
organized_files.append({
|
|
296
|
+
'path': file_path,
|
|
297
|
+
'type': file_type,
|
|
298
|
+
'valid': False
|
|
299
|
+
})
|
|
300
|
+
|
|
301
|
+
return organized_files
|
|
302
|
+
|
|
303
|
+
def extract_file_type(file_path):
|
|
304
|
+
"""경로에서 파일 유형 추출 - 명명 규칙에 따라 구현."""
|
|
305
|
+
# 예제 구현
|
|
306
|
+
if 'image' in str(file_path):
|
|
307
|
+
return 'image'
|
|
308
|
+
elif 'annotation' in str(file_path):
|
|
309
|
+
return 'annotation'
|
|
310
|
+
elif 'metadata' in str(file_path):
|
|
311
|
+
return 'metadata'
|
|
312
|
+
else:
|
|
313
|
+
return 'unknown'
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
## 오류 처리 및 재시도 로직
|
|
317
|
+
|
|
318
|
+
```python
|
|
319
|
+
import time
|
|
320
|
+
from synapse_sdk.clients.exceptions import ClientError
|
|
321
|
+
|
|
322
|
+
def robust_upload(file_path, max_retries=3):
|
|
323
|
+
"""안정성을 위한 재시도 로직이 있는 업로드."""
|
|
324
|
+
for attempt in range(max_retries):
|
|
325
|
+
try:
|
|
326
|
+
result = client.create_data_file(file_path, use_chunked_upload=True)
|
|
327
|
+
return result
|
|
328
|
+
except ClientError as e:
|
|
329
|
+
if e.status_code == 413: # 파일이 너무 큼
|
|
330
|
+
print(f"파일 {file_path}이 너무 큼, 청크 업로드 시도")
|
|
331
|
+
try:
|
|
332
|
+
return client.create_data_file(file_path, use_chunked_upload=True)
|
|
333
|
+
except Exception as retry_e:
|
|
334
|
+
print(f"청크 업로드 실패: {retry_e}")
|
|
335
|
+
if attempt == max_retries - 1:
|
|
336
|
+
raise
|
|
337
|
+
elif e.status_code == 429: # 요청 제한
|
|
338
|
+
wait_time = 2 ** attempt # 지수 백오프
|
|
339
|
+
print(f"요청 제한됨, {wait_time}초 대기 중...")
|
|
340
|
+
time.sleep(wait_time)
|
|
341
|
+
else:
|
|
342
|
+
print(f"업로드 실패 (시도 {attempt + 1}): {e}")
|
|
343
|
+
if attempt == max_retries - 1:
|
|
344
|
+
raise
|
|
345
|
+
except Exception as e:
|
|
346
|
+
print(f"예상치 못한 오류 (시도 {attempt + 1}): {e}")
|
|
347
|
+
if attempt == max_retries - 1:
|
|
348
|
+
raise
|
|
349
|
+
time.sleep(1) # 재시도 전 잠시 대기
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
## 참고
|
|
353
|
+
|
|
354
|
+
- [BackendClient](./backend.md) - 메인 백엔드 클라이언트
|
|
355
|
+
- [CoreClientMixin](./core-mixin.md) - 핵심 파일 작업
|
|
356
|
+
- [AnnotationClientMixin](./annotation-mixin.md) - 태스크 및 어노테이션 관리
|
synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/api/clients/hitl-mixin.md
ADDED
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: hitl-mixin
|
|
3
|
+
title: HITLClientMixin
|
|
4
|
+
sidebar_position: 14
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# HITLClientMixin
|
|
8
|
+
|
|
9
|
+
Synapse 백엔드를 위한 Human-in-the-Loop (HITL) 할당 관리 작업을 제공합니다.
|
|
10
|
+
|
|
11
|
+
## 개요
|
|
12
|
+
|
|
13
|
+
`HITLClientMixin`은 할당 관리 및 태깅을 포함한 human-in-the-loop 워크플로와 관련된 모든 작업을 처리합니다. 이 믹스인은 `BackendClient`에 자동으로 포함되며 인간 어노테이션 및 검토 워크플로를 관리하기 위한 메서드를 제공합니다.
|
|
14
|
+
|
|
15
|
+
## 할당 작업
|
|
16
|
+
|
|
17
|
+
### `get_assignment(pk)`
|
|
18
|
+
|
|
19
|
+
특정 할당에 대한 상세 정보를 가져옵니다.
|
|
20
|
+
|
|
21
|
+
```python
|
|
22
|
+
assignment = client.get_assignment(789)
|
|
23
|
+
print(f"할당: {assignment['id']}")
|
|
24
|
+
print(f"프로젝트: {assignment['project']}")
|
|
25
|
+
print(f"상태: {assignment['status']}")
|
|
26
|
+
print(f"할당자: {assignment['assignee']}")
|
|
27
|
+
print(f"데이터: {assignment['data']}")
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
**매개변수:**
|
|
31
|
+
|
|
32
|
+
- `pk` (int): 할당 ID
|
|
33
|
+
|
|
34
|
+
**반환값:**
|
|
35
|
+
|
|
36
|
+
- `dict`: 완전한 할당 정보
|
|
37
|
+
|
|
38
|
+
**할당 구조:**
|
|
39
|
+
|
|
40
|
+
- `id`: 할당 ID
|
|
41
|
+
- `project`: 연관된 프로젝트 ID
|
|
42
|
+
- `status`: 할당 상태 (`pending`, `in_progress`, `completed`, `rejected`)
|
|
43
|
+
- `assignee`: 할당된 검토자의 사용자 ID
|
|
44
|
+
- `data`: 할당 데이터 및 어노테이션
|
|
45
|
+
- `file`: 연관된 파일
|
|
46
|
+
- `created_at`: 생성 타임스탬프
|
|
47
|
+
- `updated_at`: 마지막 업데이트 타임스탬프
|
|
48
|
+
- `metadata`: 추가 할당 메타데이터
|
|
49
|
+
|
|
50
|
+
### `list_assignments(params=None, url_conversion=None, list_all=False)`
|
|
51
|
+
|
|
52
|
+
포괄적인 필터링 및 페이지네이션 지원과 함께 할당을 나열합니다.
|
|
53
|
+
|
|
54
|
+
```python
|
|
55
|
+
# 특정 프로젝트의 할당 나열
|
|
56
|
+
assignments = client.list_assignments(params={'project': 123})
|
|
57
|
+
|
|
58
|
+
# 상태별 할당 나열
|
|
59
|
+
pending_assignments = client.list_assignments(params={
|
|
60
|
+
'project': 123,
|
|
61
|
+
'status': 'pending'
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
# 특정 할당자의 할당 나열
|
|
65
|
+
user_assignments = client.list_assignments(params={
|
|
66
|
+
'assignee': 456
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
# 모든 할당 가져오기 (페이지네이션 자동 처리)
|
|
70
|
+
all_assignments = client.list_assignments(list_all=True)
|
|
71
|
+
|
|
72
|
+
# 파일에 대한 사용자 정의 URL 변환과 함께 할당 나열
|
|
73
|
+
assignments = client.list_assignments(
|
|
74
|
+
params={'project': 123},
|
|
75
|
+
url_conversion={'files': lambda url: f"https://cdn.example.com{url}"}
|
|
76
|
+
)
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
**매개변수:**
|
|
80
|
+
|
|
81
|
+
- `params` (dict, 선택사항): 필터링 매개변수
|
|
82
|
+
- `url_conversion` (dict, 선택사항): 파일 필드에 대한 사용자 정의 URL 변환
|
|
83
|
+
- `list_all` (bool): True인 경우, 페이지네이션을 자동 처리
|
|
84
|
+
|
|
85
|
+
**일반적인 필터링 params:**
|
|
86
|
+
|
|
87
|
+
- `project`: 프로젝트 ID로 필터링
|
|
88
|
+
- `status`: 할당 상태로 필터링
|
|
89
|
+
- `assignee`: 할당된 사용자 ID로 필터링
|
|
90
|
+
- `created_after`: 생성 날짜로 필터링
|
|
91
|
+
- `updated_after`: 마지막 업데이트 날짜로 필터링
|
|
92
|
+
- `priority`: 할당 우선순위로 필터링
|
|
93
|
+
- `search`: 할당 내용에서 텍스트 검색
|
|
94
|
+
|
|
95
|
+
**반환값:**
|
|
96
|
+
|
|
97
|
+
- `tuple`: `list_all=False`인 경우 (assignments_list, total_count)
|
|
98
|
+
- `list`: `list_all=True`인 경우 모든 할당
|
|
99
|
+
|
|
100
|
+
### `set_tags_assignments(data, params=None)`
|
|
101
|
+
|
|
102
|
+
일괄 작업으로 여러 할당에 태그를 설정합니다.
|
|
103
|
+
|
|
104
|
+
```python
|
|
105
|
+
# 여러 할당에 태그 설정
|
|
106
|
+
client.set_tags_assignments({
|
|
107
|
+
'assignment_ids': [789, 790, 791],
|
|
108
|
+
'tag_ids': [1, 2, 3] # 적용할 태그 ID
|
|
109
|
+
})
|
|
110
|
+
|
|
111
|
+
# 교체 옵션과 함께 태그 설정
|
|
112
|
+
client.set_tags_assignments(
|
|
113
|
+
{
|
|
114
|
+
'assignment_ids': [789, 790],
|
|
115
|
+
'tag_ids': [1, 2]
|
|
116
|
+
},
|
|
117
|
+
params={'replace': True} # 기존 태그 교체
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
# 우선순위 태그 설정
|
|
121
|
+
client.set_tags_assignments({
|
|
122
|
+
'assignment_ids': [789],
|
|
123
|
+
'tag_ids': [5] # 높은 우선순위 태그
|
|
124
|
+
})
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
**매개변수:**
|
|
128
|
+
|
|
129
|
+
- `data` (dict): 일괄 태깅 데이터
|
|
130
|
+
- `params` (dict, 선택사항): 추가 매개변수
|
|
131
|
+
|
|
132
|
+
**데이터 구조:**
|
|
133
|
+
|
|
134
|
+
- `assignment_ids` (list): 태그를 설정할 할당 ID 목록
|
|
135
|
+
- `tag_ids` (list): 적용할 태그 ID 목록
|
|
136
|
+
|
|
137
|
+
**선택적 params:**
|
|
138
|
+
|
|
139
|
+
- `replace` (bool): True인 경우 기존 태그 교체, False인 경우 기존 태그에 추가
|
|
140
|
+
- `notify` (bool): True인 경우 태그 변경을 할당자에게 알림
|
|
141
|
+
|
|
142
|
+
**반환값:**
|
|
143
|
+
|
|
144
|
+
- `dict`: 태깅 작업 결과
|
|
145
|
+
|
|
146
|
+
## 오류 처리
|
|
147
|
+
|
|
148
|
+
```python
|
|
149
|
+
from synapse_sdk.clients.exceptions import ClientError
|
|
150
|
+
|
|
151
|
+
def robust_assignment_operations():
|
|
152
|
+
"""오류 처리가 있는 안정적인 할당 작업 예제."""
|
|
153
|
+
|
|
154
|
+
try:
|
|
155
|
+
# 할당 가져오기 시도
|
|
156
|
+
assignment = client.get_assignment(999)
|
|
157
|
+
except ClientError as e:
|
|
158
|
+
if e.status_code == 404:
|
|
159
|
+
print("할당을 찾을 수 없음")
|
|
160
|
+
return None
|
|
161
|
+
elif e.status_code == 403:
|
|
162
|
+
print("권한이 거부됨 - 액세스 권한 부족")
|
|
163
|
+
return None
|
|
164
|
+
else:
|
|
165
|
+
print(f"할당 가져오기 오류: {e}")
|
|
166
|
+
raise
|
|
167
|
+
|
|
168
|
+
try:
|
|
169
|
+
# 태그 설정 시도
|
|
170
|
+
client.set_tags_assignments({
|
|
171
|
+
'assignment_ids': [999],
|
|
172
|
+
'tag_ids': [1, 2, 3]
|
|
173
|
+
})
|
|
174
|
+
except ClientError as e:
|
|
175
|
+
if e.status_code == 400:
|
|
176
|
+
print(f"잘못된 태깅 데이터: {e.response}")
|
|
177
|
+
elif e.status_code == 404:
|
|
178
|
+
print("할당 또는 태그를 찾을 수 없음")
|
|
179
|
+
else:
|
|
180
|
+
print(f"태그 설정 오류: {e}")
|
|
181
|
+
|
|
182
|
+
return assignment
|
|
183
|
+
|
|
184
|
+
# 안정적인 작업 사용
|
|
185
|
+
assignment = robust_assignment_operations()
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
## 참고
|
|
189
|
+
|
|
190
|
+
- [BackendClient](./backend.md) - 메인 백엔드 클라이언트
|
|
191
|
+
- [AnnotationClientMixin](./annotation-mixin.md) - 태스크 및 어노테이션 관리
|
|
192
|
+
- [IntegrationClientMixin](./integration-mixin.md) - 플러그인 및 작업 관리
|