magic_hour 0.35.0__py3-none-any.whl → 0.36.1__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 magic_hour might be problematic. Click here for more details.
- magic_hour/README.md +35 -0
- magic_hour/core/base_client.py +6 -5
- magic_hour/core/query.py +12 -6
- magic_hour/core/request.py +3 -3
- magic_hour/core/response.py +18 -14
- magic_hour/core/utils.py +3 -3
- magic_hour/environment.py +1 -1
- magic_hour/helpers/__init__.py +3 -0
- magic_hour/helpers/download.py +75 -0
- magic_hour/resources/v1/README.md +33 -0
- magic_hour/resources/v1/ai_clothes_changer/README.md +73 -0
- magic_hour/resources/v1/ai_clothes_changer/client.py +146 -0
- magic_hour/resources/v1/ai_face_editor/README.md +110 -0
- magic_hour/resources/v1/ai_face_editor/client.py +168 -0
- magic_hour/resources/v1/ai_gif_generator/README.md +59 -0
- magic_hour/resources/v1/ai_gif_generator/client.py +119 -0
- magic_hour/resources/v1/ai_headshot_generator/README.md +60 -0
- magic_hour/resources/v1/ai_headshot_generator/client.py +140 -0
- magic_hour/resources/v1/ai_image_editor/README.md +64 -0
- magic_hour/resources/v1/ai_image_editor/client.py +136 -0
- magic_hour/resources/v1/ai_image_generator/README.md +66 -0
- magic_hour/resources/v1/ai_image_generator/client.py +139 -0
- magic_hour/resources/v1/ai_image_upscaler/README.md +67 -0
- magic_hour/resources/v1/ai_image_upscaler/client.py +150 -0
- magic_hour/resources/v1/ai_meme_generator/README.md +71 -0
- magic_hour/resources/v1/ai_meme_generator/client.py +127 -0
- magic_hour/resources/v1/ai_photo_editor/README.md +98 -7
- magic_hour/resources/v1/ai_photo_editor/client.py +174 -0
- magic_hour/resources/v1/ai_qr_code_generator/README.md +63 -0
- magic_hour/resources/v1/ai_qr_code_generator/client.py +123 -0
- magic_hour/resources/v1/ai_talking_photo/README.md +74 -0
- magic_hour/resources/v1/ai_talking_photo/client.py +170 -0
- magic_hour/resources/v1/animation/README.md +100 -0
- magic_hour/resources/v1/animation/client.py +218 -0
- magic_hour/resources/v1/auto_subtitle_generator/README.md +69 -0
- magic_hour/resources/v1/auto_subtitle_generator/client.py +178 -0
- magic_hour/resources/v1/face_detection/README.md +59 -0
- magic_hour/resources/v1/face_detection/__init__.py +10 -2
- magic_hour/resources/v1/face_detection/client.py +179 -0
- magic_hour/resources/v1/face_swap/README.md +105 -8
- magic_hour/resources/v1/face_swap/client.py +242 -0
- magic_hour/resources/v1/face_swap_photo/README.md +84 -0
- magic_hour/resources/v1/face_swap_photo/client.py +172 -0
- magic_hour/resources/v1/files/README.md +40 -0
- magic_hour/resources/v1/files/client.py +350 -0
- magic_hour/resources/v1/files/client_test.py +414 -0
- magic_hour/resources/v1/files/upload_urls/README.md +8 -0
- magic_hour/resources/v1/image_background_remover/README.md +68 -0
- magic_hour/resources/v1/image_background_remover/client.py +130 -0
- magic_hour/resources/v1/image_projects/README.md +52 -0
- magic_hour/resources/v1/image_projects/__init__.py +10 -2
- magic_hour/resources/v1/image_projects/client.py +138 -0
- magic_hour/resources/v1/image_projects/client_test.py +527 -0
- magic_hour/resources/v1/image_to_video/README.md +77 -9
- magic_hour/resources/v1/image_to_video/client.py +186 -0
- magic_hour/resources/v1/lip_sync/README.md +87 -9
- magic_hour/resources/v1/lip_sync/client.py +210 -0
- magic_hour/resources/v1/photo_colorizer/README.md +59 -0
- magic_hour/resources/v1/photo_colorizer/client.py +130 -0
- magic_hour/resources/v1/text_to_video/README.md +68 -0
- magic_hour/resources/v1/text_to_video/client.py +151 -0
- magic_hour/resources/v1/video_projects/README.md +52 -0
- magic_hour/resources/v1/video_projects/__init__.py +10 -2
- magic_hour/resources/v1/video_projects/client.py +137 -0
- magic_hour/resources/v1/video_projects/client_test.py +527 -0
- magic_hour/resources/v1/video_to_video/README.md +98 -10
- magic_hour/resources/v1/video_to_video/client.py +222 -0
- magic_hour/types/params/__init__.py +58 -0
- magic_hour/types/params/v1_ai_clothes_changer_generate_body_assets.py +33 -0
- magic_hour/types/params/v1_ai_face_editor_generate_body_assets.py +17 -0
- magic_hour/types/params/v1_ai_headshot_generator_generate_body_assets.py +17 -0
- magic_hour/types/params/v1_ai_image_editor_generate_body_assets.py +17 -0
- magic_hour/types/params/v1_ai_image_upscaler_generate_body_assets.py +17 -0
- magic_hour/types/params/v1_ai_photo_editor_generate_body_assets.py +17 -0
- magic_hour/types/params/v1_ai_talking_photo_generate_body_assets.py +26 -0
- magic_hour/types/params/v1_animation_generate_body_assets.py +39 -0
- magic_hour/types/params/v1_auto_subtitle_generator_generate_body_assets.py +17 -0
- magic_hour/types/params/v1_face_detection_generate_body_assets.py +17 -0
- magic_hour/types/params/v1_face_swap_create_body.py +12 -0
- magic_hour/types/params/v1_face_swap_create_body_style.py +33 -0
- magic_hour/types/params/v1_face_swap_generate_body_assets.py +56 -0
- magic_hour/types/params/v1_face_swap_generate_body_assets_face_mappings_item.py +25 -0
- magic_hour/types/params/v1_face_swap_photo_generate_body_assets.py +47 -0
- magic_hour/types/params/v1_face_swap_photo_generate_body_assets_face_mappings_item.py +25 -0
- magic_hour/types/params/v1_image_background_remover_generate_body_assets.py +27 -0
- magic_hour/types/params/v1_image_to_video_generate_body_assets.py +17 -0
- magic_hour/types/params/v1_lip_sync_generate_body_assets.py +36 -0
- magic_hour/types/params/v1_photo_colorizer_generate_body_assets.py +17 -0
- magic_hour/types/params/v1_video_to_video_generate_body_assets.py +27 -0
- magic_hour-0.36.1.dist-info/METADATA +306 -0
- {magic_hour-0.35.0.dist-info → magic_hour-0.36.1.dist-info}/RECORD +93 -65
- magic_hour-0.35.0.dist-info/METADATA +0 -166
- {magic_hour-0.35.0.dist-info → magic_hour-0.36.1.dist-info}/LICENSE +0 -0
- {magic_hour-0.35.0.dist-info → magic_hour-0.36.1.dist-info}/WHEEL +0 -0
|
@@ -1,3 +1,54 @@
|
|
|
1
|
+
# v1_image_projects
|
|
2
|
+
|
|
3
|
+
## Module Functions
|
|
4
|
+
|
|
5
|
+
<!-- CUSTOM DOCS START -->
|
|
6
|
+
|
|
7
|
+
### Check results <a name="check-result"></a>
|
|
8
|
+
|
|
9
|
+
Poll the details API to check on the status of the rendering. Optionally can also download the output
|
|
10
|
+
|
|
11
|
+
#### Parameters
|
|
12
|
+
|
|
13
|
+
| Parameter | Required | Description | Example |
|
|
14
|
+
| --------------------- | :------: | ---------------------------------------------------------------------------------------------------- | ---------------- |
|
|
15
|
+
| `id` | ✓ | Unique ID of the image project. This value is returned by all of the POST APIs that create an image. | `"cuid-example"` |
|
|
16
|
+
| `wait_for_completion` | ✗ | Whether to wait for the project to complete. | `True` |
|
|
17
|
+
| `download_outputs` | ✗ | Whether to download the generated files | `True` |
|
|
18
|
+
| `download_directory` | ✗ | Directory to save downloaded files (defaults to current directory) | `"./outputs"` |
|
|
19
|
+
|
|
20
|
+
#### Synchronous Client
|
|
21
|
+
|
|
22
|
+
```python
|
|
23
|
+
from magic_hour import Client
|
|
24
|
+
from os import getenv
|
|
25
|
+
|
|
26
|
+
client = Client(token=getenv("API_TOKEN"))
|
|
27
|
+
res = client.v1.image_projects.check_result(
|
|
28
|
+
id="cuid-example",
|
|
29
|
+
wait_for_completion=True,
|
|
30
|
+
download_outputs=True,
|
|
31
|
+
download_directory="outputs",
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
#### Asynchronous Client
|
|
37
|
+
|
|
38
|
+
```python
|
|
39
|
+
from magic_hour import AsyncClient
|
|
40
|
+
from os import getenv
|
|
41
|
+
|
|
42
|
+
client = AsyncClient(token=getenv("API_TOKEN"))
|
|
43
|
+
res = await client.v1.image_projects.check_result(
|
|
44
|
+
id="cuid-example",
|
|
45
|
+
wait_for_completion=True,
|
|
46
|
+
download_outputs=True,
|
|
47
|
+
download_directory="outputs",
|
|
48
|
+
)
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
<!-- CUSTOM DOCS END -->
|
|
1
52
|
|
|
2
53
|
### Delete image <a name="delete"></a>
|
|
3
54
|
|
|
@@ -83,3 +134,4 @@ res = await client.v1.image_projects.get(id="cuid-example")
|
|
|
83
134
|
|
|
84
135
|
##### Example
|
|
85
136
|
`{"created_at": "1970-01-01T00:00:00", "credits_charged": 5, "downloads": [{"expires_at": "2024-10-19T05:16:19.027Z", "url": "https://videos.magichour.ai/id/output.png"}], "enabled": True, "error": {"code": "no_source_face", "message": "Please use an image with a detectable face"}, "id": "cuid-example", "image_count": 1, "name": "Example Name", "status": "complete", "total_frame_cost": 5, "type_": "AI_IMAGE"}`
|
|
137
|
+
|
|
@@ -1,4 +1,12 @@
|
|
|
1
|
-
from .client import
|
|
1
|
+
from .client import (
|
|
2
|
+
AsyncImageProjectsClient,
|
|
3
|
+
ImageProjectsClient,
|
|
4
|
+
V1ImageProjectsGetResponseWithDownloads,
|
|
5
|
+
)
|
|
2
6
|
|
|
3
7
|
|
|
4
|
-
__all__ = [
|
|
8
|
+
__all__ = [
|
|
9
|
+
"AsyncImageProjectsClient",
|
|
10
|
+
"ImageProjectsClient",
|
|
11
|
+
"V1ImageProjectsGetResponseWithDownloads",
|
|
12
|
+
]
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import logging
|
|
3
|
+
import os
|
|
4
|
+
import pydantic
|
|
5
|
+
import time
|
|
1
6
|
import typing
|
|
2
7
|
|
|
3
8
|
from magic_hour.core import (
|
|
@@ -6,13 +11,87 @@ from magic_hour.core import (
|
|
|
6
11
|
SyncBaseClient,
|
|
7
12
|
default_request_options,
|
|
8
13
|
)
|
|
14
|
+
from magic_hour.helpers.download import download_files_async, download_files_sync
|
|
9
15
|
from magic_hour.types import models
|
|
10
16
|
|
|
11
17
|
|
|
18
|
+
logger = logging.getLogger(__name__)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class V1ImageProjectsGetResponseWithDownloads(models.V1ImageProjectsGetResponse):
|
|
22
|
+
downloaded_paths: typing.Optional[typing.List[str]] = pydantic.Field(
|
|
23
|
+
default=None, alias="downloaded_paths"
|
|
24
|
+
)
|
|
25
|
+
"""
|
|
26
|
+
The paths to the downloaded files.
|
|
27
|
+
|
|
28
|
+
This field is only populated if `download_outputs` is True and the image project is complete.
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
|
|
12
32
|
class ImageProjectsClient:
|
|
13
33
|
def __init__(self, *, base_client: SyncBaseClient):
|
|
14
34
|
self._base_client = base_client
|
|
15
35
|
|
|
36
|
+
def check_result(
|
|
37
|
+
self,
|
|
38
|
+
id: str,
|
|
39
|
+
wait_for_completion: bool,
|
|
40
|
+
download_outputs: bool,
|
|
41
|
+
download_directory: typing.Optional[str] = None,
|
|
42
|
+
) -> V1ImageProjectsGetResponseWithDownloads:
|
|
43
|
+
"""
|
|
44
|
+
Check the result of an image project with optional waiting and downloading.
|
|
45
|
+
|
|
46
|
+
This method retrieves the status of an image project and optionally waits for completion
|
|
47
|
+
and downloads the output files.
|
|
48
|
+
|
|
49
|
+
Args:
|
|
50
|
+
id: Unique ID of the image project
|
|
51
|
+
wait_for_completion: Whether to wait for the image project to complete
|
|
52
|
+
download_outputs: Whether to download the outputs
|
|
53
|
+
download_directory: The directory to download the outputs to. If not provided,
|
|
54
|
+
the outputs will be downloaded to the current working directory
|
|
55
|
+
|
|
56
|
+
Returns:
|
|
57
|
+
V1ImageProjectsGetResponseWithDownloads: The image project response with optional
|
|
58
|
+
downloaded file paths included
|
|
59
|
+
"""
|
|
60
|
+
api_response = self.get(id=id)
|
|
61
|
+
if not wait_for_completion:
|
|
62
|
+
response = V1ImageProjectsGetResponseWithDownloads(
|
|
63
|
+
**api_response.model_dump()
|
|
64
|
+
)
|
|
65
|
+
return response
|
|
66
|
+
|
|
67
|
+
poll_interval = float(os.getenv("MAGIC_HOUR_POLL_INTERVAL", "0.5"))
|
|
68
|
+
|
|
69
|
+
status = api_response.status
|
|
70
|
+
|
|
71
|
+
while status not in ["complete", "error", "canceled"]:
|
|
72
|
+
api_response = self.get(id=id)
|
|
73
|
+
status = api_response.status
|
|
74
|
+
time.sleep(poll_interval)
|
|
75
|
+
|
|
76
|
+
if api_response.status != "complete":
|
|
77
|
+
log = logger.error if api_response.status == "error" else logger.info
|
|
78
|
+
log(
|
|
79
|
+
f"Image project {id} has status {api_response.status}: {api_response.error}"
|
|
80
|
+
)
|
|
81
|
+
return V1ImageProjectsGetResponseWithDownloads(**api_response.model_dump())
|
|
82
|
+
|
|
83
|
+
if not download_outputs:
|
|
84
|
+
return V1ImageProjectsGetResponseWithDownloads(**api_response.model_dump())
|
|
85
|
+
|
|
86
|
+
downloaded_paths = download_files_sync(
|
|
87
|
+
downloads=api_response.downloads,
|
|
88
|
+
download_directory=download_directory,
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
return V1ImageProjectsGetResponseWithDownloads(
|
|
92
|
+
**api_response.model_dump(), downloaded_paths=downloaded_paths
|
|
93
|
+
)
|
|
94
|
+
|
|
16
95
|
def delete(
|
|
17
96
|
self, *, id: str, request_options: typing.Optional[RequestOptions] = None
|
|
18
97
|
) -> None:
|
|
@@ -95,6 +174,65 @@ class AsyncImageProjectsClient:
|
|
|
95
174
|
def __init__(self, *, base_client: AsyncBaseClient):
|
|
96
175
|
self._base_client = base_client
|
|
97
176
|
|
|
177
|
+
async def check_result(
|
|
178
|
+
self,
|
|
179
|
+
id: str,
|
|
180
|
+
wait_for_completion: bool,
|
|
181
|
+
download_outputs: bool,
|
|
182
|
+
download_directory: typing.Optional[str] = None,
|
|
183
|
+
) -> V1ImageProjectsGetResponseWithDownloads:
|
|
184
|
+
"""
|
|
185
|
+
Check the result of an image project with optional waiting and downloading.
|
|
186
|
+
|
|
187
|
+
This method retrieves the status of an image project and optionally waits for completion
|
|
188
|
+
and downloads the output files.
|
|
189
|
+
|
|
190
|
+
Args:
|
|
191
|
+
id: Unique ID of the image project
|
|
192
|
+
wait_for_completion: Whether to wait for the image project to complete
|
|
193
|
+
download_outputs: Whether to download the outputs
|
|
194
|
+
download_directory: The directory to download the outputs to. If not provided,
|
|
195
|
+
the outputs will be downloaded to the current working directory
|
|
196
|
+
|
|
197
|
+
Returns:
|
|
198
|
+
V1ImageProjectsGetResponseWithDownloads: The image project response with optional
|
|
199
|
+
downloaded file paths included
|
|
200
|
+
"""
|
|
201
|
+
api_response = await self.get(id=id)
|
|
202
|
+
if not wait_for_completion:
|
|
203
|
+
response = V1ImageProjectsGetResponseWithDownloads(
|
|
204
|
+
**api_response.model_dump()
|
|
205
|
+
)
|
|
206
|
+
return response
|
|
207
|
+
|
|
208
|
+
poll_interval = float(os.getenv("MAGIC_HOUR_POLL_INTERVAL", "0.5"))
|
|
209
|
+
|
|
210
|
+
status = api_response.status
|
|
211
|
+
|
|
212
|
+
while status not in ["complete", "error", "canceled"]:
|
|
213
|
+
api_response = await self.get(id=id)
|
|
214
|
+
status = api_response.status
|
|
215
|
+
await asyncio.sleep(poll_interval)
|
|
216
|
+
|
|
217
|
+
if api_response.status != "complete":
|
|
218
|
+
log = logger.error if api_response.status == "error" else logger.info
|
|
219
|
+
log(
|
|
220
|
+
f"Image project {id} has status {api_response.status}: {api_response.error}"
|
|
221
|
+
)
|
|
222
|
+
return V1ImageProjectsGetResponseWithDownloads(**api_response.model_dump())
|
|
223
|
+
|
|
224
|
+
if not download_outputs:
|
|
225
|
+
return V1ImageProjectsGetResponseWithDownloads(**api_response.model_dump())
|
|
226
|
+
|
|
227
|
+
downloaded_paths = await download_files_async(
|
|
228
|
+
downloads=api_response.downloads,
|
|
229
|
+
download_directory=download_directory,
|
|
230
|
+
)
|
|
231
|
+
|
|
232
|
+
return V1ImageProjectsGetResponseWithDownloads(
|
|
233
|
+
**api_response.model_dump(), downloaded_paths=downloaded_paths
|
|
234
|
+
)
|
|
235
|
+
|
|
98
236
|
async def delete(
|
|
99
237
|
self, *, id: str, request_options: typing.Optional[RequestOptions] = None
|
|
100
238
|
) -> None:
|