synapse-sdk 1.0.0b23__py3-none-any.whl → 1.0.0b24__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/ray.md +1 -1
- synapse_sdk/devtools/docs/docs/api/index.md +5 -5
- synapse_sdk/devtools/docs/docs/features/utils/file.md +415 -0
- synapse_sdk/devtools/docs/docs/{api → features}/utils/network.md +1 -1
- synapse_sdk/devtools/docs/docs/plugins/export-plugins.md +140 -0
- synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/api/clients/ray.md +1 -1
- synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/api/index.md +5 -5
- synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/features/index.md +5 -5
- 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/{api → features}/utils/network.md +1 -1
- synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/plugins/export-plugins.md +138 -0
- synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/plugins/plugins.md +48 -2
- synapse_sdk/devtools/docs/sidebars.ts +10 -10
- synapse_sdk/plugins/categories/export/templates/plugin/__init__.py +17 -2
- 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 +124 -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-1.0.0b23.dist-info → synapse_sdk-1.0.0b24.dist-info}/METADATA +2 -1
- {synapse_sdk-1.0.0b23.dist-info → synapse_sdk-1.0.0b24.dist-info}/RECORD +34 -25
- synapse_sdk/devtools/docs/docs/api/utils/file.md +0 -195
- synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/api/utils/file.md +0 -195
- /synapse_sdk/devtools/docs/docs/{api → features}/utils/storage.md +0 -0
- /synapse_sdk/devtools/docs/docs/{api → features}/utils/types.md +0 -0
- /synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/{api → features}/utils/storage.md +0 -0
- /synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/{api → features}/utils/types.md +0 -0
- /synapse_sdk/utils/{file.py → file.py.backup} +0 -0
- {synapse_sdk-1.0.0b23.dist-info → synapse_sdk-1.0.0b24.dist-info}/WHEEL +0 -0
- {synapse_sdk-1.0.0b23.dist-info → synapse_sdk-1.0.0b24.dist-info}/entry_points.txt +0 -0
- {synapse_sdk-1.0.0b23.dist-info → synapse_sdk-1.0.0b24.dist-info}/licenses/LICENSE +0 -0
- {synapse_sdk-1.0.0b23.dist-info → synapse_sdk-1.0.0b24.dist-info}/top_level.txt +0 -0
synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/features/utils/file.md
ADDED
|
@@ -0,0 +1,415 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: file
|
|
3
|
+
title: 파일 유틸리티
|
|
4
|
+
sidebar_position: 1
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# 파일 유틸리티
|
|
8
|
+
|
|
9
|
+
더 나은 유지보수성과 기능성을 위해 모듈형 구조로 구성된 포괄적인 파일 작업 및 처리 유틸리티입니다.
|
|
10
|
+
|
|
11
|
+
## 모듈 개요
|
|
12
|
+
|
|
13
|
+
파일 유틸리티는 다양한 작업을 위한 전문화된 모듈로 구성된 모듈형 구조로 리팩토링되었습니다:
|
|
14
|
+
|
|
15
|
+
- **`synapse_sdk.utils.file.archive`** - ZIP 아카이브 생성 및 추출
|
|
16
|
+
- **`synapse_sdk.utils.file.checksum`** - 파일 해시 계산 및 검증
|
|
17
|
+
- **`synapse_sdk.utils.file.chunking`** - 메모리 효율적인 청크 단위 파일 읽기
|
|
18
|
+
- **`synapse_sdk.utils.file.download`** - 비동기 지원을 포함한 파일 다운로드 유틸리티
|
|
19
|
+
- **`synapse_sdk.utils.file.encoding`** - Base64 인코딩 및 파일 형식 처리
|
|
20
|
+
- **`synapse_sdk.utils.file.io`** - JSON/YAML 파일용 일반 I/O 작업
|
|
21
|
+
- **`synapse_sdk.utils.file.video`** - 비디오 트랜스코딩 및 형식 변환
|
|
22
|
+
|
|
23
|
+
### 하위 호환성
|
|
24
|
+
|
|
25
|
+
모든 함수는 메인 모듈 임포트를 통해 여전히 액세스할 수 있습니다:
|
|
26
|
+
|
|
27
|
+
```python
|
|
28
|
+
# 두 방법 모두 동일하게 작동합니다
|
|
29
|
+
from synapse_sdk.utils.file import read_file_in_chunks, download_file
|
|
30
|
+
from synapse_sdk.utils.file.chunking import read_file_in_chunks
|
|
31
|
+
from synapse_sdk.utils.file.download import download_file
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## 아카이브 작업
|
|
35
|
+
|
|
36
|
+
ZIP 아카이브를 생성하고 추출하는 함수입니다.
|
|
37
|
+
|
|
38
|
+
```python
|
|
39
|
+
from synapse_sdk.utils.file.archive import archive, unarchive
|
|
40
|
+
|
|
41
|
+
# 아카이브 생성
|
|
42
|
+
archive('/path/to/directory', '/path/to/output.zip')
|
|
43
|
+
|
|
44
|
+
# 아카이브 추출
|
|
45
|
+
unarchive('/path/to/archive.zip', '/path/to/extract/directory')
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## 청크 파일 작업
|
|
49
|
+
|
|
50
|
+
### read_file_in_chunks
|
|
51
|
+
|
|
52
|
+
효율적인 메모리 사용을 위해 파일을 청크 단위로 읽습니다. 대용량 파일이나 업로드 또는 해싱을 위해 파일을 청크 단위로 처리할 때 특히 유용합니다.
|
|
53
|
+
|
|
54
|
+
```python
|
|
55
|
+
from synapse_sdk.utils.file.chunking import read_file_in_chunks
|
|
56
|
+
|
|
57
|
+
# 기본 50MB 청크로 파일 읽기
|
|
58
|
+
for chunk in read_file_in_chunks('/path/to/large_file.bin'):
|
|
59
|
+
process_chunk(chunk)
|
|
60
|
+
|
|
61
|
+
# 사용자 정의 청크 크기로 읽기 (10MB)
|
|
62
|
+
for chunk in read_file_in_chunks('/path/to/file.bin', chunk_size=1024*1024*10):
|
|
63
|
+
upload_chunk(chunk)
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
**매개변수:**
|
|
67
|
+
|
|
68
|
+
- `file_path` (str | Path): 읽을 파일의 경로
|
|
69
|
+
- `chunk_size` (int, 선택사항): 각 청크의 바이트 크기. 기본값은 50MB (52,428,800 바이트)
|
|
70
|
+
|
|
71
|
+
**반환값:**
|
|
72
|
+
|
|
73
|
+
- 파일 내용 청크를 바이트로 생성하는 제너레이터
|
|
74
|
+
|
|
75
|
+
**예외:**
|
|
76
|
+
|
|
77
|
+
- `FileNotFoundError`: 파일이 존재하지 않는 경우
|
|
78
|
+
- `PermissionError`: 권한으로 인해 파일을 읽을 수 없는 경우
|
|
79
|
+
- `OSError`: 파일 읽기 중 OS 수준 오류가 발생하는 경우
|
|
80
|
+
|
|
81
|
+
### 사용 사례
|
|
82
|
+
|
|
83
|
+
**대용량 파일 처리**: 메모리에 맞지 않는 파일을 효율적으로 처리:
|
|
84
|
+
|
|
85
|
+
```python
|
|
86
|
+
import hashlib
|
|
87
|
+
|
|
88
|
+
def calculate_hash_for_large_file(file_path):
|
|
89
|
+
hash_md5 = hashlib.md5()
|
|
90
|
+
for chunk in read_file_in_chunks(file_path):
|
|
91
|
+
hash_md5.update(chunk)
|
|
92
|
+
return hash_md5.hexdigest()
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
**청크 업로드 통합**: `CoreClientMixin.create_chunked_upload` 메서드와 원활하게 통합:
|
|
96
|
+
|
|
97
|
+
```python
|
|
98
|
+
from synapse_sdk.clients.backend.core import CoreClientMixin
|
|
99
|
+
|
|
100
|
+
client = CoreClientMixin(base_url='https://api.example.com')
|
|
101
|
+
result = client.create_chunked_upload('/path/to/large_file.zip')
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
**모범 사례:**
|
|
105
|
+
|
|
106
|
+
- 최적의 업로드 성능을 위해 기본 청크 크기(50MB) 사용
|
|
107
|
+
- 사용 가능한 메모리와 네트워크 조건에 따라 청크 크기 조정
|
|
108
|
+
- 매우 큰 파일(>1GB)의 경우 더 나은 진행률 추적을 위해 작은 청크 사용 고려
|
|
109
|
+
- 파일 작업 시 항상 예외 처리
|
|
110
|
+
|
|
111
|
+
## 체크섬 함수
|
|
112
|
+
|
|
113
|
+
### calculate_checksum
|
|
114
|
+
|
|
115
|
+
일반 파일의 체크섬을 계산합니다:
|
|
116
|
+
|
|
117
|
+
```python
|
|
118
|
+
from synapse_sdk.utils.file.checksum import calculate_checksum
|
|
119
|
+
|
|
120
|
+
checksum = calculate_checksum('/path/to/file.bin')
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### get_checksum_from_file
|
|
124
|
+
|
|
125
|
+
Django 의존성 없이 파일형 객체의 체크섬을 계산합니다. 이 함수는 `read()` 메서드가 있는 모든 파일형 객체와 함께 작동하므로 Django의 File 객체, BytesIO, StringIO 및 일반 파일 객체와 호환됩니다.
|
|
126
|
+
|
|
127
|
+
```python
|
|
128
|
+
import hashlib
|
|
129
|
+
from io import BytesIO
|
|
130
|
+
from synapse_sdk.utils.file.checksum import get_checksum_from_file
|
|
131
|
+
|
|
132
|
+
# BytesIO를 사용한 기본 사용법 (기본값은 SHA1)
|
|
133
|
+
data = BytesIO(b'Hello, world!')
|
|
134
|
+
checksum = get_checksum_from_file(data)
|
|
135
|
+
print(checksum) # 16진수 문자열로 된 SHA1 해시
|
|
136
|
+
|
|
137
|
+
# 다른 해시 알고리즘 사용
|
|
138
|
+
checksum_md5 = get_checksum_from_file(data, digest_mod=hashlib.md5)
|
|
139
|
+
checksum_sha256 = get_checksum_from_file(data, digest_mod=hashlib.sha256)
|
|
140
|
+
|
|
141
|
+
# 실제 파일 객체와 함께
|
|
142
|
+
with open('/path/to/file.txt', 'rb') as f:
|
|
143
|
+
checksum = get_checksum_from_file(f)
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
**매개변수:**
|
|
147
|
+
|
|
148
|
+
- `file` (IO[Any]): 청크 단위 읽기를 지원하는 read() 메서드가 있는 파일형 객체
|
|
149
|
+
- `digest_mod` (Callable[[], Any], 선택사항): hashlib의 해시 알고리즘. 기본값은 `hashlib.sha1`
|
|
150
|
+
|
|
151
|
+
**반환값:**
|
|
152
|
+
|
|
153
|
+
- `str`: 파일 내용의 16진수 다이제스트
|
|
154
|
+
|
|
155
|
+
**주요 기능:**
|
|
156
|
+
|
|
157
|
+
- **메모리 효율성**: 대용량 파일 처리를 위해 4KB 청크로 파일 읽기
|
|
158
|
+
- **자동 파일 포인터 재설정**: 파일 객체가 시킹을 지원하는 경우 처음으로 재설정
|
|
159
|
+
- **텍스트/바이너리 불가지론**: 텍스트(StringIO)와 바이너리(BytesIO) 파일 객체 모두 처리
|
|
160
|
+
- **Django 의존성 없음**: Django 없이 작동하면서 Django File 객체와 호환
|
|
161
|
+
- **유연한 해시 알고리즘**: 모든 hashlib 알고리즘 지원(SHA1, SHA256, MD5 등)
|
|
162
|
+
|
|
163
|
+
## 다운로드 함수
|
|
164
|
+
|
|
165
|
+
동기 및 비동기 지원을 모두 포함한 URL에서 파일을 다운로드하는 유틸리티입니다.
|
|
166
|
+
|
|
167
|
+
```python
|
|
168
|
+
from synapse_sdk.utils.file.download import download_file, adownload_file
|
|
169
|
+
|
|
170
|
+
# 동기 다운로드
|
|
171
|
+
local_path = download_file(url, destination)
|
|
172
|
+
|
|
173
|
+
# 비동기 다운로드
|
|
174
|
+
import asyncio
|
|
175
|
+
local_path = await adownload_file(url, destination)
|
|
176
|
+
|
|
177
|
+
# 여러 파일의 URL을 경로로 변환
|
|
178
|
+
from synapse_sdk.utils.file.download import files_url_to_path
|
|
179
|
+
paths = files_url_to_path(url_list, destination_directory)
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
## 인코딩 함수
|
|
183
|
+
|
|
184
|
+
파일용 Base64 인코딩 유틸리티입니다.
|
|
185
|
+
|
|
186
|
+
```python
|
|
187
|
+
from synapse_sdk.utils.file.encoding import convert_file_to_base64
|
|
188
|
+
|
|
189
|
+
# 파일을 base64로 변환
|
|
190
|
+
base64_data = convert_file_to_base64('/path/to/file.jpg')
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
## I/O 함수
|
|
194
|
+
|
|
195
|
+
구조화된 데이터 파일용 일반 I/O 작업입니다.
|
|
196
|
+
|
|
197
|
+
```python
|
|
198
|
+
from synapse_sdk.utils.file.io import get_dict_from_file, get_temp_path
|
|
199
|
+
|
|
200
|
+
# JSON 또는 YAML 파일에서 딕셔너리 로드
|
|
201
|
+
config = get_dict_from_file('/path/to/config.json')
|
|
202
|
+
settings = get_dict_from_file('/path/to/settings.yaml')
|
|
203
|
+
|
|
204
|
+
# 임시 파일 경로 얻기
|
|
205
|
+
temp_path = get_temp_path()
|
|
206
|
+
temp_subpath = get_temp_path('subdir/file.tmp')
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
## 비디오 트랜스코딩
|
|
210
|
+
|
|
211
|
+
형식 변환, 압축 및 최적화를 위해 FFmpeg를 사용하는 고급 비디오 트랜스코딩 기능입니다.
|
|
212
|
+
|
|
213
|
+
### 요구사항
|
|
214
|
+
|
|
215
|
+
- **ffmpeg-python**: `pip install ffmpeg-python`
|
|
216
|
+
- **FFmpeg**: 시스템에 설치되어 PATH에서 사용 가능해야 함
|
|
217
|
+
|
|
218
|
+
### 지원되는 비디오 형식
|
|
219
|
+
|
|
220
|
+
비디오 모듈은 다양한 입력 형식을 지원합니다:
|
|
221
|
+
- **MP4** (.mp4, .m4v)
|
|
222
|
+
- **AVI** (.avi)
|
|
223
|
+
- **MOV** (.mov)
|
|
224
|
+
- **MKV** (.mkv)
|
|
225
|
+
- **WebM** (.webm)
|
|
226
|
+
- **FLV** (.flv)
|
|
227
|
+
- **WMV** (.wmv)
|
|
228
|
+
- **MPEG** (.mpeg, .mpg)
|
|
229
|
+
- **3GP** (.3gp)
|
|
230
|
+
- **OGV** (.ogv)
|
|
231
|
+
|
|
232
|
+
### 핵심 함수
|
|
233
|
+
|
|
234
|
+
#### validate_video_format
|
|
235
|
+
|
|
236
|
+
파일이 지원되는 비디오 형식인지 확인합니다:
|
|
237
|
+
|
|
238
|
+
```python
|
|
239
|
+
from synapse_sdk.utils.file.video.transcode import validate_video_format
|
|
240
|
+
|
|
241
|
+
if validate_video_format('video.mp4'):
|
|
242
|
+
print("지원되는 형식")
|
|
243
|
+
else:
|
|
244
|
+
print("지원되지 않는 형식")
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
#### get_video_info
|
|
248
|
+
|
|
249
|
+
비디오 파일에서 메타데이터를 추출합니다:
|
|
250
|
+
|
|
251
|
+
```python
|
|
252
|
+
from synapse_sdk.utils.file.video.transcode import get_video_info
|
|
253
|
+
|
|
254
|
+
info = get_video_info('input.mp4')
|
|
255
|
+
print(f"재생시간: {info['duration']} 초")
|
|
256
|
+
print(f"해상도: {info['width']}x{info['height']}")
|
|
257
|
+
print(f"비디오 코덱: {info['video_codec']}")
|
|
258
|
+
print(f"오디오 코덱: {info['audio_codec']}")
|
|
259
|
+
print(f"FPS: {info['fps']}")
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
#### transcode_video
|
|
263
|
+
|
|
264
|
+
광범위한 구성 옵션을 가진 주요 트랜스코딩 함수:
|
|
265
|
+
|
|
266
|
+
```python
|
|
267
|
+
from synapse_sdk.utils.file.video.transcode import transcode_video, TranscodeConfig
|
|
268
|
+
from pathlib import Path
|
|
269
|
+
|
|
270
|
+
# 기본 설정으로 기본 트랜스코딩
|
|
271
|
+
output_path = transcode_video('input.avi', 'output.mp4')
|
|
272
|
+
|
|
273
|
+
# 사용자 정의 구성
|
|
274
|
+
config = TranscodeConfig(
|
|
275
|
+
vcodec='libx264', # 비디오 코덱
|
|
276
|
+
preset='fast', # 인코딩 속도 vs 품질
|
|
277
|
+
crf=20, # 품질 (낮을수록 품질 향상)
|
|
278
|
+
acodec='aac', # 오디오 코덱
|
|
279
|
+
audio_bitrate='128k', # 오디오 비트레이트
|
|
280
|
+
resolution='1920x1080', # 출력 해상도
|
|
281
|
+
fps=30, # 프레임 레이트
|
|
282
|
+
start_time=10.0, # 10초부터 시작
|
|
283
|
+
duration=60.0 # 60초만 처리
|
|
284
|
+
)
|
|
285
|
+
|
|
286
|
+
output_path = transcode_video('input.mkv', 'output.mp4', config)
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
#### TranscodeConfig 옵션
|
|
290
|
+
|
|
291
|
+
```python
|
|
292
|
+
@dataclass
|
|
293
|
+
class TranscodeConfig:
|
|
294
|
+
vcodec: str = 'libx264' # 비디오 코덱 (libx264, libx265 등)
|
|
295
|
+
preset: str = 'medium' # 인코딩 프리셋 (fast, medium, slow)
|
|
296
|
+
crf: int = 28 # 품질 팩터 (0-51, 낮을수록 품질 향상)
|
|
297
|
+
acodec: str = 'aac' # 오디오 코덱 (aac, opus 등)
|
|
298
|
+
audio_bitrate: str = '128k' # 오디오 비트레이트
|
|
299
|
+
movflags: str = '+faststart' # MP4 최적화 플래그
|
|
300
|
+
resolution: Optional[str] = None # 출력 해상도 (예: '1920x1080')
|
|
301
|
+
fps: Optional[int] = None # 출력 프레임 레이트
|
|
302
|
+
start_time: Optional[float] = None # 시작 시간(초)
|
|
303
|
+
duration: Optional[float] = None # 처리할 재생시간(초)
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
#### 진행률 콜백 지원
|
|
307
|
+
|
|
308
|
+
콜백 함수로 트랜스코딩 진행률을 모니터링합니다:
|
|
309
|
+
|
|
310
|
+
```python
|
|
311
|
+
def progress_callback(progress_percent):
|
|
312
|
+
print(f"진행률: {progress_percent:.1f}%")
|
|
313
|
+
|
|
314
|
+
output_path = transcode_video(
|
|
315
|
+
'input.mp4',
|
|
316
|
+
'output.mp4',
|
|
317
|
+
progress_callback=progress_callback
|
|
318
|
+
)
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
#### optimize_for_web
|
|
322
|
+
|
|
323
|
+
사전 정의된 설정으로 빠른 웹 최적화:
|
|
324
|
+
|
|
325
|
+
```python
|
|
326
|
+
from synapse_sdk.utils.file.video.transcode import optimize_for_web
|
|
327
|
+
|
|
328
|
+
# 빠른 시작으로 웹 스트리밍을 위해 최적화
|
|
329
|
+
web_video = optimize_for_web('input.mov', 'web_output.mp4')
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
이 함수는 최적화된 설정을 사용합니다:
|
|
333
|
+
- 빠른 인코딩 프리셋
|
|
334
|
+
- 웹 친화적 압축 (CRF 23)
|
|
335
|
+
- 스트리밍용 빠른 시작 플래그
|
|
336
|
+
- 더 나은 웹 호환성을 위한 프래그먼트 키프레임
|
|
337
|
+
|
|
338
|
+
### 오류 처리
|
|
339
|
+
|
|
340
|
+
비디오 모듈은 특정 예외를 제공합니다:
|
|
341
|
+
|
|
342
|
+
```python
|
|
343
|
+
from synapse_sdk.utils.file.video.transcode import (
|
|
344
|
+
VideoTranscodeError,
|
|
345
|
+
UnsupportedFormatError,
|
|
346
|
+
FFmpegNotFoundError,
|
|
347
|
+
TranscodingFailedError
|
|
348
|
+
)
|
|
349
|
+
|
|
350
|
+
try:
|
|
351
|
+
transcode_video('input.xyz', 'output.mp4')
|
|
352
|
+
except UnsupportedFormatError:
|
|
353
|
+
print("입력 형식이 지원되지 않음")
|
|
354
|
+
except FFmpegNotFoundError:
|
|
355
|
+
print("FFmpeg가 설치되지 않음")
|
|
356
|
+
except TranscodingFailedError as e:
|
|
357
|
+
print(f"트랜스코딩 실패: {e}")
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
### 고급 사용 예제
|
|
361
|
+
|
|
362
|
+
**배치 처리**:
|
|
363
|
+
|
|
364
|
+
```python
|
|
365
|
+
import os
|
|
366
|
+
from pathlib import Path
|
|
367
|
+
|
|
368
|
+
input_dir = Path('/path/to/videos')
|
|
369
|
+
output_dir = Path('/path/to/output')
|
|
370
|
+
|
|
371
|
+
for video_file in input_dir.glob('*'):
|
|
372
|
+
if validate_video_format(video_file):
|
|
373
|
+
output_file = output_dir / f"{video_file.stem}.mp4"
|
|
374
|
+
try:
|
|
375
|
+
transcode_video(video_file, output_file)
|
|
376
|
+
print(f"처리됨: {video_file.name}")
|
|
377
|
+
except VideoTranscodeError as e:
|
|
378
|
+
print(f"{video_file.name} 처리 실패: {e}")
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
**품질 최적화**:
|
|
382
|
+
|
|
383
|
+
```python
|
|
384
|
+
# 보관용 고품질
|
|
385
|
+
archive_config = TranscodeConfig(
|
|
386
|
+
preset='slow',
|
|
387
|
+
crf=18,
|
|
388
|
+
audio_bitrate='256k'
|
|
389
|
+
)
|
|
390
|
+
|
|
391
|
+
# 모바일용 작은 크기
|
|
392
|
+
mobile_config = TranscodeConfig(
|
|
393
|
+
preset='fast',
|
|
394
|
+
crf=28,
|
|
395
|
+
resolution='1280x720',
|
|
396
|
+
audio_bitrate='96k'
|
|
397
|
+
)
|
|
398
|
+
|
|
399
|
+
# 다른 구성 적용
|
|
400
|
+
archive_output = transcode_video(input_file, 'archive.mp4', archive_config)
|
|
401
|
+
mobile_output = transcode_video(input_file, 'mobile.mp4', mobile_config)
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
**비디오 클리핑**:
|
|
405
|
+
|
|
406
|
+
```python
|
|
407
|
+
# 1분부터 시작하여 30초 클립 추출
|
|
408
|
+
clip_config = TranscodeConfig(
|
|
409
|
+
start_time=60.0, # 1분에서 시작
|
|
410
|
+
duration=30.0, # 30초 추출
|
|
411
|
+
crf=20 # 고품질
|
|
412
|
+
)
|
|
413
|
+
|
|
414
|
+
clip = transcode_video('long_video.mp4', 'clip.mp4', clip_config)
|
|
415
|
+
```
|
|
@@ -373,6 +373,6 @@ production_limits = StreamLimits(
|
|
|
373
373
|
|
|
374
374
|
## 참고
|
|
375
375
|
|
|
376
|
-
- [RayClient](
|
|
376
|
+
- [RayClient](../../api/clients/ray.md) - 네트워크 유틸리티의 주요 소비자
|
|
377
377
|
- [File Utils](./file.md) - 파일 작업 및 처리
|
|
378
378
|
- [Storage](./storage.md) - Storage 제공자
|
synapse_sdk/devtools/docs/i18n/ko/docusaurus-plugin-content-docs/current/plugins/export-plugins.md
CHANGED
|
@@ -213,6 +213,7 @@ class Exporter(BaseExporter):
|
|
|
213
213
|
- **before_convert()**: 변환 전 데이터 전처리
|
|
214
214
|
- **after_convert()**: 변환 후 데이터 후처리
|
|
215
215
|
- **process_file_saving()**: 사용자 정의 파일 저장 로직
|
|
216
|
+
- **additional_file_saving()**: 모든 export 항목 처리 후 추가 파일 저장
|
|
216
217
|
|
|
217
218
|
### 헬퍼 메서드
|
|
218
219
|
|
|
@@ -225,6 +226,143 @@ class Exporter(BaseExporter):
|
|
|
225
226
|
- `self.run.log_message()` 및 기타 run 메서드를 통한 로깅
|
|
226
227
|
- run 메서드를 통한 오류 처리 및 메트릭 수집
|
|
227
228
|
|
|
229
|
+
## 추가 파일 저장 (Additional File Saving)
|
|
230
|
+
|
|
231
|
+
`additional_file_saving()` 메서드는 모든 export 항목이 처리된 후에 호출되며, 모든 처리된 항목의 집합적 데이터에 의존하는 파일을 저장하기 위해 설계되었습니다. 다음과 같은 용도로 유용합니다:
|
|
232
|
+
|
|
233
|
+
- 메타데이터 파일 (예: 데이터셋 통계, 클래스 매핑)
|
|
234
|
+
- 설정 파일 (예: YOLO용 dataset.yaml, classes.txt)
|
|
235
|
+
- 요약 파일 (예: export 보고서, 처리 로그)
|
|
236
|
+
- 인덱스 파일 (예: 파일 목록, 디렉토리 구조)
|
|
237
|
+
|
|
238
|
+
### 메서드 시그니처
|
|
239
|
+
|
|
240
|
+
```python
|
|
241
|
+
def additional_file_saving(self, unique_export_path):
|
|
242
|
+
"""모든 export 항목 처리 후 추가 파일 저장.
|
|
243
|
+
|
|
244
|
+
이 메서드는 주 export 루프가 완료된 후 호출되며, 모든 처리된 export 항목의
|
|
245
|
+
집합적 데이터를 기반으로 생성되어야 하는 파일들(예: 메타데이터 파일,
|
|
246
|
+
설정 파일, 요약 파일 등)을 저장하기 위한 것입니다.
|
|
247
|
+
|
|
248
|
+
Args:
|
|
249
|
+
unique_export_path (str): 추가 파일이 저장될 고유한 export 디렉토리 경로.
|
|
250
|
+
"""
|
|
251
|
+
pass
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
### 사용 예시
|
|
255
|
+
|
|
256
|
+
```python
|
|
257
|
+
class YOLOExporter(BaseExporter):
|
|
258
|
+
def __init__(self, run, export_items, path_root, **params):
|
|
259
|
+
super().__init__(run, export_items, path_root, **params)
|
|
260
|
+
self.class_names = set()
|
|
261
|
+
self.dataset_stats = {
|
|
262
|
+
'total_images': 0,
|
|
263
|
+
'total_annotations': 0,
|
|
264
|
+
'class_distribution': {}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
def convert_data(self, data):
|
|
268
|
+
# 변환 중 클래스와 통계 추적
|
|
269
|
+
for annotation in data.get('annotations', []):
|
|
270
|
+
class_name = annotation['class_name']
|
|
271
|
+
self.class_names.add(class_name)
|
|
272
|
+
self.dataset_stats['class_distribution'][class_name] = \
|
|
273
|
+
self.dataset_stats['class_distribution'].get(class_name, 0) + 1
|
|
274
|
+
|
|
275
|
+
self.dataset_stats['total_images'] += 1
|
|
276
|
+
self.dataset_stats['total_annotations'] += len(data.get('annotations', []))
|
|
277
|
+
|
|
278
|
+
return data # ... 나머지 변환 로직
|
|
279
|
+
|
|
280
|
+
def additional_file_saving(self, unique_export_path):
|
|
281
|
+
"""YOLO 설정 및 메타데이터 파일 저장."""
|
|
282
|
+
data_dir = Path(unique_export_path) / 'data'
|
|
283
|
+
data_dir.mkdir(exist_ok=True)
|
|
284
|
+
|
|
285
|
+
# 1. classes.txt 파일 저장
|
|
286
|
+
classes_file = data_dir / 'classes.txt'
|
|
287
|
+
with classes_file.open('w') as f:
|
|
288
|
+
for class_name in sorted(self.class_names):
|
|
289
|
+
f.write(f"{class_name}\n")
|
|
290
|
+
self.run.log_message(f"클래스 파일 저장: {classes_file}")
|
|
291
|
+
|
|
292
|
+
# 2. dataset.yaml 파일 저장
|
|
293
|
+
dataset_config = {
|
|
294
|
+
'path': str(unique_export_path),
|
|
295
|
+
'train': 'images',
|
|
296
|
+
'val': 'images',
|
|
297
|
+
'names': {i: name for i, name in enumerate(sorted(self.class_names))}
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
dataset_file = data_dir / 'dataset.yaml'
|
|
301
|
+
with dataset_file.open('w') as f:
|
|
302
|
+
yaml.dump(dataset_config, f, default_flow_style=False)
|
|
303
|
+
self.run.log_message(f"데이터셋 설정 저장: {dataset_file}")
|
|
304
|
+
|
|
305
|
+
# 3. export 통계 저장
|
|
306
|
+
stats_file = data_dir / 'export_stats.json'
|
|
307
|
+
with stats_file.open('w') as f:
|
|
308
|
+
json.dump(self.dataset_stats, f, indent=2)
|
|
309
|
+
self.run.log_message(f"export 통계 저장: {stats_file}")
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
### 일반적인 사용 사례
|
|
313
|
+
|
|
314
|
+
#### 1. 데이터셋 설정 파일
|
|
315
|
+
```python
|
|
316
|
+
def additional_file_saving(self, unique_export_path):
|
|
317
|
+
# 훈련 프레임워크용 데이터셋 설정 생성
|
|
318
|
+
config = {
|
|
319
|
+
'dataset_name': self.params.get('name'),
|
|
320
|
+
'created_at': datetime.now().isoformat(),
|
|
321
|
+
'total_samples': len(self.processed_items),
|
|
322
|
+
'classes': list(self.class_mapping.keys())
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
config_file = Path(unique_export_path) / 'dataset_config.json'
|
|
326
|
+
with config_file.open('w') as f:
|
|
327
|
+
json.dump(config, f, indent=2)
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
#### 2. Export 요약 보고서
|
|
331
|
+
```python
|
|
332
|
+
def additional_file_saving(self, unique_export_path):
|
|
333
|
+
# export 요약 생성
|
|
334
|
+
summary = {
|
|
335
|
+
'export_info': {
|
|
336
|
+
'plugin_name': self.__class__.__name__,
|
|
337
|
+
'export_time': datetime.now().isoformat(),
|
|
338
|
+
'export_path': str(unique_export_path)
|
|
339
|
+
},
|
|
340
|
+
'statistics': self.get_export_statistics(),
|
|
341
|
+
'errors': self.get_error_summary()
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
summary_file = Path(unique_export_path) / 'export_summary.json'
|
|
345
|
+
with summary_file.open('w') as f:
|
|
346
|
+
json.dump(summary, f, indent=2)
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
#### 3. 인덱스 및 매니페스트 파일
|
|
350
|
+
```python
|
|
351
|
+
def additional_file_saving(self, unique_export_path):
|
|
352
|
+
# 처리된 항목들에 대한 파일 인덱스 생성
|
|
353
|
+
file_index = []
|
|
354
|
+
for item in self.processed_items:
|
|
355
|
+
file_index.append({
|
|
356
|
+
'original_file': item['original_filename'],
|
|
357
|
+
'json_file': f"{item['stem']}.json",
|
|
358
|
+
'processed_at': item['timestamp']
|
|
359
|
+
})
|
|
360
|
+
|
|
361
|
+
index_file = Path(unique_export_path) / 'file_index.json'
|
|
362
|
+
with index_file.open('w') as f:
|
|
363
|
+
json.dump(file_index, f, indent=2)
|
|
364
|
+
```
|
|
365
|
+
|
|
228
366
|
## 주요 특징
|
|
229
367
|
|
|
230
368
|
- **진행률 추적**: `run.set_progress()`로 내장 진행률 모니터링
|
|
@@ -67,5 +67,51 @@ Synapse 플랫폼에서 주석이 달린 데이터, 그라운드 트루스 데
|
|
|
67
67
|
- `ground_truth` - 그라운드 트루스 데이터셋 버전 내보내기
|
|
68
68
|
- `task` - 관련 주석이 있는 작업 데이터 내보내기
|
|
69
69
|
|
|
70
|
-
Export 플러그인에 대한 자세한 정보, BaseExporter 클래스 구조, 구현 예시 및 모범 사례는 [Export 플러그인](
|
|
71
|
-
|
|
70
|
+
Export 플러그인에 대한 자세한 정보, BaseExporter 클래스 구조, 구현 예시 및 모범 사례는 [Export 플러그인](./export-plugins) 문서를 참조하세요.
|
|
71
|
+
|
|
72
|
+
## 플러그인 구성
|
|
73
|
+
|
|
74
|
+
플러그인은 YAML 구성 파일을 사용하여 구성되며, 이 파일은 메타데이터, 종속성, 패키지 관리 옵션 및 액션을 정의합니다.
|
|
75
|
+
|
|
76
|
+
### 패키지 관리
|
|
77
|
+
|
|
78
|
+
```yaml
|
|
79
|
+
# 플러그인 메타데이터 (필수)
|
|
80
|
+
name: "my-ml-plugin" # 필수: 플러그인 이름
|
|
81
|
+
version: "1.0.0" # 필수: 버전
|
|
82
|
+
category: "neural_net" # 필수: 카테고리
|
|
83
|
+
description: "사용자 정의 ML 플러그인" # 필수: 설명
|
|
84
|
+
|
|
85
|
+
# 패키지 관리 (선택사항)
|
|
86
|
+
package_manager: "pip" # 선택사항: "pip" 또는 "uv" (기본값: "pip")
|
|
87
|
+
|
|
88
|
+
# 패키지 매니저 옵션 (선택사항)
|
|
89
|
+
# uv만 지원 pip_install_options: 지원 예정
|
|
90
|
+
# uv의 경우 기본값은 ['--no-cache']입니다
|
|
91
|
+
package_manager_options: ["--no-cache", "--quiet"] # 선택사항: 설치 옵션
|
|
92
|
+
|
|
93
|
+
# 액션 정의 (필수)
|
|
94
|
+
actions: # 필수: 최소 하나의 액션 필요
|
|
95
|
+
train:
|
|
96
|
+
entrypoint: "plugin.train.TrainAction" # 필수
|
|
97
|
+
method: "job" # 필수: 실행 방법
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
**구성 옵션 설명:**
|
|
101
|
+
|
|
102
|
+
**필수 필드:**
|
|
103
|
+
- `name`: 플러그인 이름
|
|
104
|
+
- `version`: 플러그인 버전
|
|
105
|
+
- `category`: 플러그인 카테고리 (`neural_net`, `export` 등)
|
|
106
|
+
- `description`: 플러그인 설명
|
|
107
|
+
- `actions`: 플러그인 액션 정의 (최소 하나 필요)
|
|
108
|
+
- `entrypoint`: 액션의 진입점 클래스
|
|
109
|
+
- `method`: 실행 방법 (`job`, `task`, `serve` 등)
|
|
110
|
+
|
|
111
|
+
**선택사항 필드:**
|
|
112
|
+
- `package_manager`: 종속성에 사용할 패키지 매니저 (기본값: `"pip"`)
|
|
113
|
+
- 지원 값: `"pip"` 또는 `"uv"`
|
|
114
|
+
- `package_manager_options`: 패키지 설치 명령에 대한 사용자 제공 옵션
|
|
115
|
+
- 현재 Ray 2.44.1에서는 `uv`만 지원됩니다
|
|
116
|
+
- `uv`의 경우 기본값은 `["--no-cache"]`입니다
|
|
117
|
+
- 사용자 정의 옵션이 기본값과 병합됩니다
|
|
@@ -25,6 +25,16 @@ const sidebars: SidebarsConfig = {
|
|
|
25
25
|
'features/converters/converters',
|
|
26
26
|
],
|
|
27
27
|
},
|
|
28
|
+
{
|
|
29
|
+
type: 'category',
|
|
30
|
+
label: 'Utilities',
|
|
31
|
+
items: [
|
|
32
|
+
'features/utils/file',
|
|
33
|
+
'features/utils/network',
|
|
34
|
+
'features/utils/storage',
|
|
35
|
+
'features/utils/types',
|
|
36
|
+
],
|
|
37
|
+
},
|
|
28
38
|
{
|
|
29
39
|
type: 'category',
|
|
30
40
|
label: 'Plugin System',
|
|
@@ -49,16 +59,6 @@ const sidebars: SidebarsConfig = {
|
|
|
49
59
|
'api/clients/base',
|
|
50
60
|
],
|
|
51
61
|
},
|
|
52
|
-
{
|
|
53
|
-
type: 'category',
|
|
54
|
-
label: 'Utilities',
|
|
55
|
-
items: [
|
|
56
|
-
'api/utils/file',
|
|
57
|
-
'api/utils/network',
|
|
58
|
-
'api/utils/storage',
|
|
59
|
-
'api/utils/types',
|
|
60
|
-
],
|
|
61
|
-
},
|
|
62
62
|
],
|
|
63
63
|
},
|
|
64
64
|
'configuration',
|
|
@@ -306,6 +306,20 @@ class BaseExporter:
|
|
|
306
306
|
|
|
307
307
|
return True
|
|
308
308
|
|
|
309
|
+
def additional_file_saving(self, unique_export_path):
|
|
310
|
+
"""Save additional files after processing all export items.
|
|
311
|
+
|
|
312
|
+
This method is called after the main export loop completes and is intended
|
|
313
|
+
for saving files that need to be created based on the collective data from
|
|
314
|
+
all processed export items (e.g., metadata files, configuration files,
|
|
315
|
+
summary files, etc.).
|
|
316
|
+
|
|
317
|
+
Args:
|
|
318
|
+
unique_export_path (str): The unique export directory path where
|
|
319
|
+
additional files should be saved.
|
|
320
|
+
"""
|
|
321
|
+
pass
|
|
322
|
+
|
|
309
323
|
def export(self, export_items=None, results=None, **_kwargs) -> dict:
|
|
310
324
|
"""Main export method that can be overridden by subclasses for custom logic.
|
|
311
325
|
|
|
@@ -340,8 +354,8 @@ class BaseExporter:
|
|
|
340
354
|
|
|
341
355
|
total = self.params['count']
|
|
342
356
|
|
|
343
|
-
original_file_metrics_record = self.run.MetricsRecord(stand_by=total)
|
|
344
|
-
data_file_metrics_record = self.run.MetricsRecord(stand_by=total)
|
|
357
|
+
original_file_metrics_record = self.run.MetricsRecord(stand_by=total, success=0, failed=0)
|
|
358
|
+
data_file_metrics_record = self.run.MetricsRecord(stand_by=total, success=0, failed=0)
|
|
345
359
|
|
|
346
360
|
# progress init
|
|
347
361
|
self.run.set_progress(0, total, category='dataset_conversion')
|
|
@@ -367,6 +381,7 @@ class BaseExporter:
|
|
|
367
381
|
if not should_continue:
|
|
368
382
|
continue
|
|
369
383
|
|
|
384
|
+
self.additional_file_saving(unique_export_path)
|
|
370
385
|
self.run.end_log()
|
|
371
386
|
|
|
372
387
|
# Save error list files
|