veed 0.1.0__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.
veed/__init__.py ADDED
@@ -0,0 +1,92 @@
1
+ # Code generated from the VEED OpenAPI spec. DO NOT EDIT.
2
+
3
+ from ._errors import (
4
+ APIConnectionError,
5
+ APIError,
6
+ AuthenticationError,
7
+ InternalServerError,
8
+ InvalidRequestError,
9
+ JobCancelledError,
10
+ JobFailedError,
11
+ NotFoundError,
12
+ PermissionDeniedError,
13
+ RateLimitError,
14
+ VeedError,
15
+ WaitTimeoutError,
16
+ )
17
+ from ._types import (
18
+ JOB_STATUS_CANCELLED,
19
+ JOB_STATUS_COMPLETED,
20
+ JOB_STATUS_FAILED,
21
+ JOB_STATUS_PROCESSING,
22
+ File,
23
+ JobErrorDetail,
24
+ JobStatus,
25
+ )
26
+ from ._version import VERSION
27
+ from .client import AsyncVeed, Veed
28
+ from .resources.cleanAudio import (
29
+ AsyncCleanAudio,
30
+ CleanAudio,
31
+ CleanAudioJob,
32
+ CleanAudioJobError,
33
+ CleanAudioJobErrorCode,
34
+ CleanAudio,
35
+ CleanAudioOutputFormat,
36
+ )
37
+ from .resources.cleanAudioVideo import (
38
+ AsyncCleanAudioVideo,
39
+ CleanAudioVideo,
40
+ CleanAudioVideoJob,
41
+ CleanAudioVideo,
42
+ )
43
+ from .resources.dubbing import (
44
+ AsyncDubbing,
45
+ Dubbing,
46
+ DubbingJob,
47
+ DubbingJobError,
48
+ DubbingJobErrorCode,
49
+ Dubbing,
50
+ )
51
+ from .resources.dubbingPro import (
52
+ AsyncDubbingPro,
53
+ DubbingPro,
54
+ )
55
+ from .resources.fabric import (
56
+ AsyncFabric,
57
+ Fabric,
58
+ FabricJob,
59
+ FabricJobError,
60
+ FabricJobErrorCode,
61
+ FabricVideo,
62
+ FabricResolution,
63
+ )
64
+ from .resources.lipsync20 import (
65
+ AsyncLipsync20,
66
+ Lipsync20,
67
+ Lipsync20Job,
68
+ Lipsync20JobError,
69
+ Lipsync20JobErrorCode,
70
+ Lipsync20Video,
71
+ )
72
+ from .resources.videoBackgroundRemoval import (
73
+ AsyncVideoBackgroundRemoval,
74
+ VideoBackgroundRemoval,
75
+ VideoBackgroundRemovalJob,
76
+ VideoBackgroundRemovalJobError,
77
+ VideoBackgroundRemovalJobErrorCode,
78
+ VideoBackgroundRemovalFiles,
79
+ VideoBackgroundRemovalOutputCodec,
80
+ )
81
+ from .resources.videoBackgroundRemovalFast import (
82
+ AsyncVideoBackgroundRemovalFast,
83
+ VideoBackgroundRemovalFast,
84
+ VideoBackgroundRemovalFastOutputCodec,
85
+ )
86
+ from .resources.videoBackgroundRemovalGreenScreen import (
87
+ AsyncVideoBackgroundRemovalGreenScreen,
88
+ VideoBackgroundRemovalGreenScreen,
89
+ VideoBackgroundRemovalGreenScreenOutputCodec,
90
+ )
91
+
92
+ __version__ = VERSION
veed/_errors.py ADDED
@@ -0,0 +1,139 @@
1
+ # Code generated from the VEED OpenAPI spec. DO NOT EDIT.
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Any, List, Optional
6
+
7
+ # The server chooses Retry-After and no timeout covers a sleep, so an unclamped
8
+ # header is a remote hang.
9
+ MAX_RETRY_AFTER = 60.0
10
+
11
+
12
+ class VeedError(Exception):
13
+ pass
14
+
15
+
16
+ class APIConnectionError(VeedError):
17
+ pass
18
+
19
+
20
+ class APIError(VeedError):
21
+ """HTTP-layer error: the request itself was rejected. For submits this
22
+ means no job was created (per the API contract)."""
23
+
24
+ def __init__(
25
+ self,
26
+ *,
27
+ status_code: int,
28
+ code: str,
29
+ message: str,
30
+ request_id: str,
31
+ details: Optional[List[Any]] = None,
32
+ retry_after: float = 0.0,
33
+ ) -> None:
34
+ self.status_code = status_code
35
+ self.code = code
36
+ self.message = message
37
+ self.request_id = request_id
38
+ self.details = details or []
39
+ self.retry_after = retry_after
40
+ super().__init__(f"veed: {status_code} {code}: {message} (request_id: {request_id})")
41
+
42
+
43
+ class InvalidRequestError(APIError):
44
+ pass
45
+
46
+
47
+ class AuthenticationError(APIError):
48
+ pass
49
+
50
+
51
+ class PermissionDeniedError(APIError):
52
+ pass
53
+
54
+
55
+ class NotFoundError(APIError):
56
+ pass
57
+
58
+
59
+ class RateLimitError(APIError):
60
+ pass
61
+
62
+
63
+ class InternalServerError(APIError):
64
+ pass
65
+
66
+
67
+ _STATUS_MAP = {
68
+ 400: InvalidRequestError,
69
+ 401: AuthenticationError,
70
+ 403: PermissionDeniedError,
71
+ 404: NotFoundError,
72
+ 422: InvalidRequestError,
73
+ 429: RateLimitError,
74
+ }
75
+
76
+
77
+ def error_from_response(resp: Any) -> APIError:
78
+ status = resp.status_code
79
+ cls = _STATUS_MAP.get(status)
80
+ if cls is None:
81
+ cls = InternalServerError if status >= 500 else APIError
82
+ code = ""
83
+ message = ""
84
+ details = None
85
+ request_id = resp.headers.get("X-Request-ID", "")
86
+ try:
87
+ body = resp.json().get("error") or {}
88
+ code = body.get("code", "")
89
+ message = body.get("message", "")
90
+ details = body.get("details")
91
+ request_id = body.get("request_id") or request_id
92
+ except Exception:
93
+ message = resp.text[:200]
94
+ retry_after = 0.0
95
+ ra = resp.headers.get("Retry-After")
96
+ if ra and ra.isdigit():
97
+ retry_after = min(float(ra), MAX_RETRY_AFTER)
98
+ return cls(
99
+ status_code=status,
100
+ code=code,
101
+ message=message,
102
+ request_id=request_id,
103
+ details=details,
104
+ retry_after=retry_after,
105
+ )
106
+
107
+
108
+ class JobFailedError(VeedError):
109
+ """Job-layer failure: the job was accepted, but rendering failed. Raised
110
+ by wait/generate, not as an HTTP error. `code` holds the model-specific
111
+ failure code and `job` the final job object."""
112
+
113
+ def __init__(self, *, job_id: str, code: str, message: str, details: Any = None, job: Any = None) -> None:
114
+ self.job_id = job_id
115
+ self.code = code
116
+ self.message = message
117
+ self.details = details or []
118
+ self.job = job
119
+ super().__init__(f"veed: job {job_id} failed ({code}): {message}")
120
+
121
+
122
+ class JobCancelledError(VeedError):
123
+ def __init__(self, *, job_id: str, job: Any = None) -> None:
124
+ self.job_id = job_id
125
+ self.job = job
126
+ super().__init__(f"veed: job {job_id} was cancelled")
127
+
128
+
129
+ class WaitTimeoutError(VeedError):
130
+ """wait/generate gave up before the job reached a terminal state. The job
131
+ may still finish server-side; resume with wait(job_id)."""
132
+
133
+ def __init__(self, *, job_id: str, timeout: float, job: Any = None) -> None:
134
+ self.job_id = job_id
135
+ self.timeout = timeout
136
+ self.job = job
137
+ super().__init__(
138
+ f"veed: timed out after {timeout}s waiting for job {job_id} (the job may still finish; resume with wait)"
139
+ )
veed/_transport.py ADDED
@@ -0,0 +1,258 @@
1
+ # Code generated from the VEED OpenAPI spec. DO NOT EDIT.
2
+
3
+ from __future__ import annotations
4
+
5
+ import asyncio
6
+ import os
7
+ import random
8
+ import time
9
+ from dataclasses import dataclass
10
+ from typing import Any, Awaitable, Callable, Optional, TypeVar
11
+
12
+ import httpx
13
+
14
+ from ._errors import (
15
+ APIConnectionError,
16
+ APIError,
17
+ JobCancelledError,
18
+ JobFailedError,
19
+ RateLimitError,
20
+ VeedError,
21
+ WaitTimeoutError,
22
+ error_from_response,
23
+ )
24
+ from ._version import VERSION
25
+
26
+ DEFAULT_BASE_URL = "https://api.veed.io"
27
+ DEFAULT_WAIT_TIMEOUT = 900.0
28
+
29
+ T = TypeVar("T")
30
+
31
+
32
+ @dataclass
33
+ class RequestOptions:
34
+ store_io: Optional[bool] = None
35
+ media_expiration_seconds: Optional[int] = None
36
+
37
+
38
+ def _backoff(attempt: int) -> float:
39
+ return random.random() * min(0.5 * (2**attempt), 8.0)
40
+
41
+
42
+ def _retryable(status: int) -> bool:
43
+ # POST retries are safe too: a rejected submit never creates a job.
44
+ return status in (408, 429) or status >= 500
45
+
46
+
47
+ class BaseTransport:
48
+ def __init__(
49
+ self,
50
+ *,
51
+ api_key: Optional[str],
52
+ base_url: Optional[str],
53
+ timeout: float,
54
+ max_retries: int,
55
+ store_io: Optional[bool] = None,
56
+ media_expiration_seconds: Optional[int] = None,
57
+ ) -> None:
58
+ self.api_key = api_key or os.environ.get("VEED_API_KEY") or ""
59
+ if not self.api_key:
60
+ raise VeedError(
61
+ "veed: missing API key: pass api_key=... or set VEED_API_KEY (create keys in your VEED workspace)"
62
+ )
63
+ self.base_url = (base_url or os.environ.get("VEED_BASE_URL") or DEFAULT_BASE_URL).rstrip("/")
64
+ self.timeout = timeout
65
+ self.max_retries = max_retries
66
+ self.store_io = store_io
67
+ self.media_expiration_seconds = media_expiration_seconds
68
+
69
+ def _headers(self, options: Optional[RequestOptions]) -> dict:
70
+ headers = {
71
+ "Authorization": f"Bearer {self.api_key}",
72
+ "Accept": "application/json",
73
+ "User-Agent": f"veed-sdk-python/{VERSION}",
74
+ }
75
+ store_io = self.store_io
76
+ media_expiration = self.media_expiration_seconds
77
+ if options is not None:
78
+ if options.store_io is not None:
79
+ store_io = options.store_io
80
+ if options.media_expiration_seconds is not None:
81
+ media_expiration = options.media_expiration_seconds
82
+ if store_io is not None:
83
+ headers["X-Veed-Store-IO"] = "1" if store_io else "0"
84
+ if media_expiration is not None:
85
+ headers["X-Veed-Media-Expiration-Seconds"] = str(media_expiration)
86
+ return headers
87
+
88
+ @staticmethod
89
+ def _unwrap(resp: httpx.Response) -> Any:
90
+ payload = resp.json()
91
+ if not isinstance(payload, dict) or "data" not in payload:
92
+ raise APIError(
93
+ status_code=resp.status_code,
94
+ code="",
95
+ message="response is missing the data envelope",
96
+ request_id=resp.headers.get("X-Request-ID", ""),
97
+ )
98
+ return payload["data"]
99
+
100
+
101
+ class SyncTransport(BaseTransport):
102
+ def __init__(
103
+ self,
104
+ *,
105
+ api_key: Optional[str] = None,
106
+ base_url: Optional[str] = None,
107
+ timeout: float = 60.0,
108
+ max_retries: int = 2,
109
+ store_io: Optional[bool] = None,
110
+ media_expiration_seconds: Optional[int] = None,
111
+ http_client: Optional[httpx.Client] = None,
112
+ ) -> None:
113
+ super().__init__(
114
+ api_key=api_key,
115
+ base_url=base_url,
116
+ timeout=timeout,
117
+ max_retries=max_retries,
118
+ store_io=store_io,
119
+ media_expiration_seconds=media_expiration_seconds,
120
+ )
121
+ self._client = http_client or httpx.Client(timeout=timeout)
122
+
123
+ def close(self) -> None:
124
+ self._client.close()
125
+
126
+ def request(self, method: str, path: str, *, json_body: Any = None, options: Optional[RequestOptions] = None) -> Any:
127
+ attempt = 0
128
+ while True:
129
+ try:
130
+ resp = self._client.request(
131
+ method, self.base_url + path, json=json_body, headers=self._headers(options)
132
+ )
133
+ except httpx.HTTPError as exc:
134
+ if attempt < self.max_retries:
135
+ time.sleep(_backoff(attempt))
136
+ attempt += 1
137
+ continue
138
+ raise APIConnectionError(f"veed: request failed: {exc}") from exc
139
+ if resp.status_code < 300:
140
+ return self._unwrap(resp)
141
+ err = error_from_response(resp)
142
+ if _retryable(resp.status_code) and attempt < self.max_retries:
143
+ time.sleep(err.retry_after if err.retry_after else _backoff(attempt))
144
+ attempt += 1
145
+ continue
146
+ raise err
147
+
148
+
149
+ class AsyncTransport(BaseTransport):
150
+ def __init__(
151
+ self,
152
+ *,
153
+ api_key: Optional[str] = None,
154
+ base_url: Optional[str] = None,
155
+ timeout: float = 60.0,
156
+ max_retries: int = 2,
157
+ store_io: Optional[bool] = None,
158
+ media_expiration_seconds: Optional[int] = None,
159
+ http_client: Optional[httpx.AsyncClient] = None,
160
+ ) -> None:
161
+ super().__init__(
162
+ api_key=api_key,
163
+ base_url=base_url,
164
+ timeout=timeout,
165
+ max_retries=max_retries,
166
+ store_io=store_io,
167
+ media_expiration_seconds=media_expiration_seconds,
168
+ )
169
+ self._client = http_client or httpx.AsyncClient(timeout=timeout)
170
+
171
+ async def close(self) -> None:
172
+ await self._client.aclose()
173
+
174
+ async def request(
175
+ self, method: str, path: str, *, json_body: Any = None, options: Optional[RequestOptions] = None
176
+ ) -> Any:
177
+ attempt = 0
178
+ while True:
179
+ try:
180
+ resp = await self._client.request(
181
+ method, self.base_url + path, json=json_body, headers=self._headers(options)
182
+ )
183
+ except httpx.HTTPError as exc:
184
+ if attempt < self.max_retries:
185
+ await asyncio.sleep(_backoff(attempt))
186
+ attempt += 1
187
+ continue
188
+ raise APIConnectionError(f"veed: request failed: {exc}") from exc
189
+ if resp.status_code < 300:
190
+ return self._unwrap(resp)
191
+ err = error_from_response(resp)
192
+ if _retryable(resp.status_code) and attempt < self.max_retries:
193
+ await asyncio.sleep(err.retry_after if err.retry_after else _backoff(attempt))
194
+ attempt += 1
195
+ continue
196
+ raise err
197
+
198
+
199
+ def _inspect(job: Any, job_id: str) -> Optional[VeedError]:
200
+ if job.status == "FAILED":
201
+ error = getattr(job, "error", None)
202
+ return JobFailedError(
203
+ job_id=job_id,
204
+ code=error.code if error else "",
205
+ message=error.message if error else "",
206
+ details=error.details if error else None,
207
+ job=job,
208
+ )
209
+ if job.status == "CANCELLED":
210
+ return JobCancelledError(job_id=job_id, job=job)
211
+ return None
212
+
213
+
214
+ def wait_for_job(get_job: Callable[[], T], job_id: str, poll_interval: float, timeout: float) -> T:
215
+ deadline = time.monotonic() + timeout
216
+ last: Optional[T] = None
217
+ while True:
218
+ sleep_s = poll_interval
219
+ try:
220
+ job = get_job()
221
+ last = job
222
+ if job.status == "COMPLETED": # type: ignore[attr-defined]
223
+ return job
224
+ terminal = _inspect(job, job_id)
225
+ if terminal is not None:
226
+ raise terminal
227
+ except RateLimitError as exc:
228
+ # The job keeps rendering server-side, so a rate-limited poll is
229
+ # not fatal to the wait.
230
+ sleep_s = exc.retry_after or poll_interval
231
+ remaining = deadline - time.monotonic()
232
+ if remaining <= 0:
233
+ raise WaitTimeoutError(job_id=job_id, timeout=timeout, job=last)
234
+ # Or a poll answered with Retry-After decides the wait's real length.
235
+ time.sleep(min(sleep_s, remaining))
236
+
237
+
238
+ async def async_wait_for_job(
239
+ get_job: Callable[[], Awaitable[T]], job_id: str, poll_interval: float, timeout: float
240
+ ) -> T:
241
+ deadline = time.monotonic() + timeout
242
+ last: Optional[T] = None
243
+ while True:
244
+ sleep_s = poll_interval
245
+ try:
246
+ job = await get_job()
247
+ last = job
248
+ if job.status == "COMPLETED": # type: ignore[attr-defined]
249
+ return job
250
+ terminal = _inspect(job, job_id)
251
+ if terminal is not None:
252
+ raise terminal
253
+ except RateLimitError as exc:
254
+ sleep_s = exc.retry_after or poll_interval
255
+ remaining = deadline - time.monotonic()
256
+ if remaining <= 0:
257
+ raise WaitTimeoutError(job_id=job_id, timeout=timeout, job=last)
258
+ await asyncio.sleep(min(sleep_s, remaining))
veed/_types.py ADDED
@@ -0,0 +1,37 @@
1
+ # Code generated from the VEED OpenAPI spec. DO NOT EDIT.
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Optional
6
+
7
+ from pydantic import BaseModel, ConfigDict
8
+
9
+ # Kept as str (not an Enum/Literal) so a new server-side status never breaks
10
+ # deserialization in old SDK versions.
11
+ JobStatus = str
12
+
13
+ JOB_STATUS_PROCESSING = "PROCESSING"
14
+ JOB_STATUS_COMPLETED = "COMPLETED"
15
+ JOB_STATUS_FAILED = "FAILED"
16
+ JOB_STATUS_CANCELLED = "CANCELLED"
17
+
18
+
19
+ class VeedModel(BaseModel):
20
+ model_config = ConfigDict(extra="allow")
21
+
22
+
23
+ class File(VeedModel):
24
+ """A downloadable media file produced by a job."""
25
+
26
+ url: str
27
+ content_type: Optional[str] = None
28
+ file_name: Optional[str] = None
29
+ file_size: Optional[int] = None
30
+
31
+
32
+ class JobErrorDetail(VeedModel):
33
+ """One structured entry of a job-level failure."""
34
+
35
+ type: str
36
+ message: str
37
+ field: Optional[str] = None
veed/_version.py ADDED
@@ -0,0 +1,3 @@
1
+ # Code generated from the VEED OpenAPI spec. DO NOT EDIT.
2
+
3
+ VERSION = "0.1.0"
veed/client.py ADDED
@@ -0,0 +1,119 @@
1
+ # Code generated from the VEED OpenAPI spec. DO NOT EDIT.
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Optional
6
+
7
+ import httpx
8
+
9
+ from ._transport import AsyncTransport, SyncTransport
10
+ from .resources import (
11
+ AsyncCleanAudio,
12
+ CleanAudio,
13
+ AsyncCleanAudioVideo,
14
+ CleanAudioVideo,
15
+ AsyncDubbing,
16
+ Dubbing,
17
+ AsyncDubbingPro,
18
+ DubbingPro,
19
+ AsyncFabric,
20
+ Fabric,
21
+ AsyncLipsync20,
22
+ Lipsync20,
23
+ AsyncVideoBackgroundRemoval,
24
+ VideoBackgroundRemoval,
25
+ AsyncVideoBackgroundRemovalFast,
26
+ VideoBackgroundRemovalFast,
27
+ AsyncVideoBackgroundRemovalGreenScreen,
28
+ VideoBackgroundRemovalGreenScreen,
29
+ )
30
+
31
+
32
+ class Veed:
33
+ """VEED API client. Construct once with your API key and reuse; safe to
34
+ share across threads.
35
+
36
+ client = veed.Veed() # reads VEED_API_KEY
37
+ """
38
+
39
+ def __init__(
40
+ self,
41
+ *,
42
+ api_key: Optional[str] = None,
43
+ base_url: Optional[str] = None,
44
+ timeout: float = 60.0,
45
+ max_retries: int = 2,
46
+ store_io: Optional[bool] = None,
47
+ media_expiration_seconds: Optional[int] = None,
48
+ http_client: Optional[httpx.Client] = None,
49
+ ) -> None:
50
+ self._transport = SyncTransport(
51
+ api_key=api_key,
52
+ base_url=base_url,
53
+ timeout=timeout,
54
+ max_retries=max_retries,
55
+ store_io=store_io,
56
+ media_expiration_seconds=media_expiration_seconds,
57
+ http_client=http_client,
58
+ )
59
+ self.cleanAudio = CleanAudio(self._transport)
60
+ self.cleanAudioVideo = CleanAudioVideo(self._transport)
61
+ self.dubbing = Dubbing(self._transport)
62
+ self.dubbingPro = DubbingPro(self._transport)
63
+ self.fabric = Fabric(self._transport)
64
+ self.lipsync20 = Lipsync20(self._transport)
65
+ self.videoBackgroundRemoval = VideoBackgroundRemoval(self._transport)
66
+ self.videoBackgroundRemovalFast = VideoBackgroundRemovalFast(self._transport)
67
+ self.videoBackgroundRemovalGreenScreen = VideoBackgroundRemovalGreenScreen(self._transport)
68
+
69
+ def close(self) -> None:
70
+ self._transport.close()
71
+
72
+ def __enter__(self) -> "Veed":
73
+ return self
74
+
75
+ def __exit__(self, *exc_info: object) -> None:
76
+ self.close()
77
+
78
+
79
+ class AsyncVeed:
80
+ """Async VEED API client (asyncio + httpx.AsyncClient)."""
81
+
82
+ def __init__(
83
+ self,
84
+ *,
85
+ api_key: Optional[str] = None,
86
+ base_url: Optional[str] = None,
87
+ timeout: float = 60.0,
88
+ max_retries: int = 2,
89
+ store_io: Optional[bool] = None,
90
+ media_expiration_seconds: Optional[int] = None,
91
+ http_client: Optional[httpx.AsyncClient] = None,
92
+ ) -> None:
93
+ self._transport = AsyncTransport(
94
+ api_key=api_key,
95
+ base_url=base_url,
96
+ timeout=timeout,
97
+ max_retries=max_retries,
98
+ store_io=store_io,
99
+ media_expiration_seconds=media_expiration_seconds,
100
+ http_client=http_client,
101
+ )
102
+ self.cleanAudio = AsyncCleanAudio(self._transport)
103
+ self.cleanAudioVideo = AsyncCleanAudioVideo(self._transport)
104
+ self.dubbing = AsyncDubbing(self._transport)
105
+ self.dubbingPro = AsyncDubbingPro(self._transport)
106
+ self.fabric = AsyncFabric(self._transport)
107
+ self.lipsync20 = AsyncLipsync20(self._transport)
108
+ self.videoBackgroundRemoval = AsyncVideoBackgroundRemoval(self._transport)
109
+ self.videoBackgroundRemovalFast = AsyncVideoBackgroundRemovalFast(self._transport)
110
+ self.videoBackgroundRemovalGreenScreen = AsyncVideoBackgroundRemovalGreenScreen(self._transport)
111
+
112
+ async def close(self) -> None:
113
+ await self._transport.close()
114
+
115
+ async def __aenter__(self) -> "AsyncVeed":
116
+ return self
117
+
118
+ async def __aexit__(self, *exc_info: object) -> None:
119
+ await self.close()
veed/py.typed ADDED
File without changes
@@ -0,0 +1,12 @@
1
+ # Code generated from the VEED OpenAPI spec. DO NOT EDIT.
2
+
3
+
4
+ from .cleanAudio import CleanAudio, AsyncCleanAudio
5
+ from .cleanAudioVideo import CleanAudioVideo, AsyncCleanAudioVideo
6
+ from .dubbing import Dubbing, AsyncDubbing
7
+ from .dubbingPro import DubbingPro, AsyncDubbingPro
8
+ from .fabric import Fabric, AsyncFabric
9
+ from .lipsync20 import Lipsync20, AsyncLipsync20
10
+ from .videoBackgroundRemoval import VideoBackgroundRemoval, AsyncVideoBackgroundRemoval
11
+ from .videoBackgroundRemovalFast import VideoBackgroundRemovalFast, AsyncVideoBackgroundRemovalFast
12
+ from .videoBackgroundRemovalGreenScreen import VideoBackgroundRemovalGreenScreen, AsyncVideoBackgroundRemovalGreenScreen