magic_hour 0.18.0__py3-none-any.whl → 0.20.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.

Potentially problematic release.


This version of magic_hour might be problematic. Click here for more details.

@@ -18,6 +18,7 @@ from .request import (
18
18
  filter_not_given,
19
19
  to_content,
20
20
  to_encodable,
21
+ to_form_urlencoded,
21
22
  RequestOptions,
22
23
  default_request_options,
23
24
  )
@@ -42,6 +43,7 @@ __all__ = [
42
43
  "OAuth2ClientCredentialsForm",
43
44
  "OAuth2PasswordForm",
44
45
  "to_encodable",
46
+ "to_form_urlencoded",
45
47
  "filter_not_given",
46
48
  "to_content",
47
49
  "encode_query_param",
magic_hour/core/query.py CHANGED
@@ -1,3 +1,5 @@
1
+ import json
2
+
1
3
  from typing import Any, Dict, Union
2
4
  from typing_extensions import Literal, Sequence
3
5
  from urllib.parse import quote_plus, quote
@@ -9,13 +11,14 @@ import httpx
9
11
  QueryParams = Dict[
10
12
  str, Union[httpx._types.PrimitiveData, Sequence[httpx._types.PrimitiveData]]
11
13
  ]
14
+ QueryParamStyle = Literal["form", "spaceDelimited", "pipeDelimited", "deepObject"]
12
15
 
13
16
 
14
17
  def encode_query_param(
15
18
  params: QueryParams,
16
19
  name: str,
17
20
  value: Any,
18
- style: Literal["form", "spaceDelimited", "pipeDelimited", "deepObject"] = "form",
21
+ style: QueryParamStyle = "form",
19
22
  explode: bool = True,
20
23
  ):
21
24
  if style == "form":
@@ -30,6 +33,13 @@ def encode_query_param(
30
33
  raise NotImplementedError(f"query param style '{style}' not implemented")
31
34
 
32
35
 
36
+ def _query_str(val: Any) -> str:
37
+ """jsonify value without wrapping quotes for strings"""
38
+ if isinstance(val, str):
39
+ return val
40
+ return json.dumps(val)
41
+
42
+
33
43
  def _encode_form(params: QueryParams, name: str, value: Any, explode: bool):
34
44
  """
35
45
  Encodes query params in the `form` style as defined by OpenAPI with both explode and non-explode
@@ -37,18 +47,18 @@ def _encode_form(params: QueryParams, name: str, value: Any, explode: bool):
37
47
  """
38
48
  if isinstance(value, list) and not explode:
39
49
  # non-explode form lists should be encoded like /users?id=3,4,5
40
- params[name] = quote_plus(",".join(map(str, value)))
50
+ params[name] = quote_plus(",".join(map(_query_str, value)))
41
51
  elif isinstance(value, dict):
42
52
  if explode:
43
53
  # explode form objects should be encoded like /users?key0=val0&key1=val1
44
54
  # the input param name will be omitted
45
55
  for k, v in value.items():
46
- params[k] = quote_plus(str(v))
56
+ params[k] = quote_plus(_query_str(v))
47
57
  else:
48
58
  # non-explode form objects should be encoded like /users?id=key0,val0,key1,val1
49
59
  encoded_chunks = []
50
60
  for k, v in value.items():
51
- encoded_chunks.extend([str(k), str(v)])
61
+ encoded_chunks.extend([str(k), _query_str(v)])
52
62
  params[name] = quote_plus(",".join(encoded_chunks))
53
63
  else:
54
64
  params[name] = value
@@ -61,7 +71,7 @@ def _encode_spaced_delimited(params: QueryParams, name: str, value: Any, explode
61
71
  """
62
72
  if isinstance(value, list) and not explode:
63
73
  # non-explode spaceDelimited lists should be encoded like /users?id=3%204%205
64
- params[name] = quote(" ".join(map(str, value)))
74
+ params[name] = quote(" ".join(map(_query_str, value)))
65
75
  else:
66
76
  # according to the docs, spaceDelimited + explode=false only effects lists,
67
77
  # all other encodings are marked as n/a or are the same as `form` style
@@ -76,7 +86,7 @@ def _encode_pipe_delimited(params: QueryParams, name: str, value: Any, explode:
76
86
  """
77
87
  if isinstance(value, list) and not explode:
78
88
  # non-explode pipeDelimited lists should be encoded like /users?id=3|4|5
79
- params[name] = quote("|".join(map(str, value)))
89
+ params[name] = quote("|".join(map(_query_str, value)))
80
90
  else:
81
91
  # according to the docs, pipeDelimited + explode=false only effects lists,
82
92
  # all other encodings are marked as n/a or are the same as `form` style
@@ -85,12 +95,15 @@ def _encode_pipe_delimited(params: QueryParams, name: str, value: Any, explode:
85
95
 
86
96
 
87
97
  def _encode_deep_object(params: QueryParams, name: str, value: Any, explode: bool):
88
- """ """
89
- if isinstance(value, dict):
98
+ """
99
+ Encodes query params in the `deepObject` style as defined by with both explode and non-explode
100
+ variants.
101
+ """
102
+ if isinstance(value, (dict, list)):
90
103
  _encode_deep_object_key(params, name, value)
91
104
  else:
92
105
  # according to the docs, deepObject style only applies to
93
- # object encodes, encodings for primitives & arrays are listed as n/a,
106
+ # object encodes, encodings for primitives are listed as n/a,
94
107
  # fall back on form style as it is the default for query params
95
108
  _encode_form(params, name, value, explode)
96
109
 
@@ -103,4 +116,4 @@ def _encode_deep_object_key(params: QueryParams, key: str, value: Any):
103
116
  for i, v in enumerate(value):
104
117
  _encode_deep_object_key(params, f"{key}[{i}]", v)
105
118
  else:
106
- params[key] = value
119
+ params[key] = _query_str(value)
@@ -1,12 +1,11 @@
1
- from typing import Any, Dict, Type, Union, Sequence, List
2
- from urllib.parse import quote_plus
1
+ from typing import Any, Dict, Type, Union, List, Mapping
3
2
 
4
3
  import httpx
5
4
  from typing_extensions import TypedDict, Required, NotRequired
6
5
  from pydantic import TypeAdapter, BaseModel
7
6
 
8
7
  from .type_utils import NotGiven
9
- from .query import QueryParams
8
+ from .query import QueryParams, QueryParamStyle, encode_query_param
10
9
 
11
10
  """
12
11
  Request configuration and utility functions for handling HTTP requests.
@@ -96,6 +95,31 @@ def to_encodable(
96
95
  return model_dump(validated_item)
97
96
 
98
97
 
98
+ def to_form_urlencoded(
99
+ *,
100
+ item: Any,
101
+ dump_with: Union[Type, Union[Type, Any]],
102
+ style: Mapping[str, QueryParamStyle],
103
+ explode: Mapping[str, bool],
104
+ ) -> Mapping[str, Any]:
105
+ """
106
+ Encodes object as x-www-form-urlencoded according to style and explode options
107
+ """
108
+ encoded = to_encodable(item=item, dump_with=dump_with)
109
+
110
+ if not isinstance(encoded, dict):
111
+ raise TypeError("x-www-form-urlencoded data must be an object at the top level")
112
+
113
+ form_data: QueryParams = {}
114
+
115
+ for key, val in encoded.items():
116
+ key_style = style.get(key, "form")
117
+ key_explode = explode.get(key, key_style == "form")
118
+ encode_query_param(form_data, key, val, style=key_style, explode=key_explode)
119
+
120
+ return form_data
121
+
122
+
99
123
  def to_content(*, file: httpx._types.FileTypes) -> httpx._types.RequestContent:
100
124
  """
101
125
  Converts the various ways files can be provided to something that is accepted by
@@ -112,24 +136,6 @@ def to_content(*, file: httpx._types.FileTypes) -> httpx._types.RequestContent:
112
136
  return file_content
113
137
 
114
138
 
115
- def encode_param(
116
- value: Any, explode: bool
117
- ) -> Union[httpx._types.PrimitiveData, Sequence[httpx._types.PrimitiveData]]:
118
- """
119
- Encodes parameter values for use in URLs.
120
-
121
- Handles both simple values and collections, with special handling for
122
- unexploded collections (combining them with commas) versus exploded ones.
123
-
124
- Args:
125
- explode: Whether to explode collections into separate parameters
126
- """
127
- if isinstance(value, (list, dict)) and not explode:
128
- return quote_plus(",".join(map(str, value)))
129
- else:
130
- return value
131
-
132
-
133
139
  def filter_not_given(value: Any) -> Any:
134
140
  """Helper function to recursively filter out NotGiven values"""
135
141
  if isinstance(value, NotGiven):
magic_hour/environment.py CHANGED
@@ -5,4 +5,4 @@ class Environment(enum.Enum):
5
5
  """Pre-defined base URLs for the API"""
6
6
 
7
7
  ENVIRONMENT = "https://api.magichour.ai"
8
- MOCK_SERVER = "https://api.sideko.dev/v1/mock/magichour/magic-hour/0.18.0"
8
+ MOCK_SERVER = "https://api.sideko.dev/v1/mock/magichour/magic-hour/0.20.0"
@@ -0,0 +1,31 @@
1
+
2
+ ### create <a name="create"></a>
3
+ AI GIFs
4
+
5
+ Create an AI GIF. Each GIF costs 25 frames.
6
+
7
+ **API Endpoint**: `POST /v1/ai-gif-generator`
8
+
9
+ #### Synchronous Client
10
+
11
+ ```python
12
+ from magic_hour import Client
13
+ from os import getenv
14
+
15
+ client = Client(token=getenv("API_TOKEN"))
16
+ res = client.v1.ai_gif_generator.create(
17
+ style={"prompt": "Cute dancing cat, pixel art"}, name="Ai Gif gif"
18
+ )
19
+ ```
20
+
21
+ #### Asynchronous Client
22
+
23
+ ```python
24
+ from magic_hour import AsyncClient
25
+ from os import getenv
26
+
27
+ client = AsyncClient(token=getenv("API_TOKEN"))
28
+ res = await client.v1.ai_gif_generator.create(
29
+ style={"prompt": "Cute dancing cat, pixel art"}, name="Ai Gif gif"
30
+ )
31
+ ```
@@ -0,0 +1,4 @@
1
+ from .client import AiGifGeneratorClient, AsyncAiGifGeneratorClient
2
+
3
+
4
+ __all__ = ["AiGifGeneratorClient", "AsyncAiGifGeneratorClient"]
@@ -0,0 +1,117 @@
1
+ import typing
2
+
3
+ from magic_hour.core import (
4
+ AsyncBaseClient,
5
+ RequestOptions,
6
+ SyncBaseClient,
7
+ default_request_options,
8
+ to_encodable,
9
+ type_utils,
10
+ )
11
+ from magic_hour.types import models, params
12
+
13
+
14
+ class AiGifGeneratorClient:
15
+ def __init__(self, *, base_client: SyncBaseClient):
16
+ self._base_client = base_client
17
+
18
+ def create(
19
+ self,
20
+ *,
21
+ style: params.V1AiGifGeneratorCreateBodyStyle,
22
+ name: typing.Union[
23
+ typing.Optional[str], type_utils.NotGiven
24
+ ] = type_utils.NOT_GIVEN,
25
+ request_options: typing.Optional[RequestOptions] = None,
26
+ ) -> models.V1AiGifGeneratorCreateResponse:
27
+ """
28
+ AI GIFs
29
+
30
+ Create an AI GIF. Each GIF costs 25 frames.
31
+
32
+ POST /v1/ai-gif-generator
33
+
34
+ Args:
35
+ name: The name of gif
36
+ style: V1AiGifGeneratorCreateBodyStyle
37
+ request_options: Additional options to customize the HTTP request
38
+
39
+ Returns:
40
+ Success
41
+
42
+ Raises:
43
+ ApiError: A custom exception class that provides additional context
44
+ for API errors, including the HTTP status code and response body.
45
+
46
+ Examples:
47
+ ```py
48
+ client.v1.ai_gif_generator.create(
49
+ style={"prompt": "Cute dancing cat, pixel art"}, name="Ai Gif gif"
50
+ )
51
+ ```
52
+ """
53
+ _json = to_encodable(
54
+ item={"name": name, "style": style},
55
+ dump_with=params._SerializerV1AiGifGeneratorCreateBody,
56
+ )
57
+ return self._base_client.request(
58
+ method="POST",
59
+ path="/v1/ai-gif-generator",
60
+ auth_names=["bearerAuth"],
61
+ json=_json,
62
+ cast_to=models.V1AiGifGeneratorCreateResponse,
63
+ request_options=request_options or default_request_options(),
64
+ )
65
+
66
+
67
+ class AsyncAiGifGeneratorClient:
68
+ def __init__(self, *, base_client: AsyncBaseClient):
69
+ self._base_client = base_client
70
+
71
+ async def create(
72
+ self,
73
+ *,
74
+ style: params.V1AiGifGeneratorCreateBodyStyle,
75
+ name: typing.Union[
76
+ typing.Optional[str], type_utils.NotGiven
77
+ ] = type_utils.NOT_GIVEN,
78
+ request_options: typing.Optional[RequestOptions] = None,
79
+ ) -> models.V1AiGifGeneratorCreateResponse:
80
+ """
81
+ AI GIFs
82
+
83
+ Create an AI GIF. Each GIF costs 25 frames.
84
+
85
+ POST /v1/ai-gif-generator
86
+
87
+ Args:
88
+ name: The name of gif
89
+ style: V1AiGifGeneratorCreateBodyStyle
90
+ request_options: Additional options to customize the HTTP request
91
+
92
+ Returns:
93
+ Success
94
+
95
+ Raises:
96
+ ApiError: A custom exception class that provides additional context
97
+ for API errors, including the HTTP status code and response body.
98
+
99
+ Examples:
100
+ ```py
101
+ await client.v1.ai_gif_generator.create(
102
+ style={"prompt": "Cute dancing cat, pixel art"}, name="Ai Gif gif"
103
+ )
104
+ ```
105
+ """
106
+ _json = to_encodable(
107
+ item={"name": name, "style": style},
108
+ dump_with=params._SerializerV1AiGifGeneratorCreateBody,
109
+ )
110
+ return await self._base_client.request(
111
+ method="POST",
112
+ path="/v1/ai-gif-generator",
113
+ auth_names=["bearerAuth"],
114
+ json=_json,
115
+ cast_to=models.V1AiGifGeneratorCreateResponse,
116
+ request_options=request_options or default_request_options(),
117
+ )
@@ -7,6 +7,10 @@ from magic_hour.resources.v1.ai_face_editor import (
7
7
  AiFaceEditorClient,
8
8
  AsyncAiFaceEditorClient,
9
9
  )
10
+ from magic_hour.resources.v1.ai_gif_generator import (
11
+ AiGifGeneratorClient,
12
+ AsyncAiGifGeneratorClient,
13
+ )
10
14
  from magic_hour.resources.v1.ai_headshot_generator import (
11
15
  AiHeadshotGeneratorClient,
12
16
  AsyncAiHeadshotGeneratorClient,
@@ -80,6 +84,7 @@ class V1Client:
80
84
  self.video_projects = VideoProjectsClient(base_client=self._base_client)
81
85
  self.ai_clothes_changer = AiClothesChangerClient(base_client=self._base_client)
82
86
  self.ai_face_editor = AiFaceEditorClient(base_client=self._base_client)
87
+ self.ai_gif_generator = AiGifGeneratorClient(base_client=self._base_client)
83
88
  self.ai_headshot_generator = AiHeadshotGeneratorClient(
84
89
  base_client=self._base_client
85
90
  )
@@ -114,6 +119,7 @@ class AsyncV1Client:
114
119
  base_client=self._base_client
115
120
  )
116
121
  self.ai_face_editor = AsyncAiFaceEditorClient(base_client=self._base_client)
122
+ self.ai_gif_generator = AsyncAiGifGeneratorClient(base_client=self._base_client)
117
123
  self.ai_headshot_generator = AsyncAiHeadshotGeneratorClient(
118
124
  base_client=self._base_client
119
125
  )
@@ -19,7 +19,6 @@ client = Client(token=getenv("API_TOKEN"))
19
19
  res = client.v1.video_to_video.create(
20
20
  assets={"video_file_path": "api-assets/id/1234.mp4", "video_source": "file"},
21
21
  end_seconds=15.0,
22
- height=960,
23
22
  start_seconds=0.0,
24
23
  style={
25
24
  "art_style": "3D Render",
@@ -28,9 +27,10 @@ res = client.v1.video_to_video.create(
28
27
  "prompt_type": "append_default",
29
28
  "version": "default",
30
29
  },
31
- width=512,
32
30
  fps_resolution="HALF",
31
+ height=960,
33
32
  name="Video To Video video",
33
+ width=512,
34
34
  )
35
35
  ```
36
36
 
@@ -44,7 +44,6 @@ client = AsyncClient(token=getenv("API_TOKEN"))
44
44
  res = await client.v1.video_to_video.create(
45
45
  assets={"video_file_path": "api-assets/id/1234.mp4", "video_source": "file"},
46
46
  end_seconds=15.0,
47
- height=960,
48
47
  start_seconds=0.0,
49
48
  style={
50
49
  "art_style": "3D Render",
@@ -53,8 +52,9 @@ res = await client.v1.video_to_video.create(
53
52
  "prompt_type": "append_default",
54
53
  "version": "default",
55
54
  },
56
- width=512,
57
55
  fps_resolution="HALF",
56
+ height=960,
58
57
  name="Video To Video video",
58
+ width=512,
59
59
  )
60
60
  ```
@@ -21,17 +21,21 @@ class VideoToVideoClient:
21
21
  *,
22
22
  assets: params.V1VideoToVideoCreateBodyAssets,
23
23
  end_seconds: float,
24
- height: int,
25
24
  start_seconds: float,
26
25
  style: params.V1VideoToVideoCreateBodyStyle,
27
- width: int,
28
26
  fps_resolution: typing.Union[
29
27
  typing.Optional[typing_extensions.Literal["FULL", "HALF"]],
30
28
  type_utils.NotGiven,
31
29
  ] = type_utils.NOT_GIVEN,
30
+ height: typing.Union[
31
+ typing.Optional[int], type_utils.NotGiven
32
+ ] = type_utils.NOT_GIVEN,
32
33
  name: typing.Union[
33
34
  typing.Optional[str], type_utils.NotGiven
34
35
  ] = type_utils.NOT_GIVEN,
36
+ width: typing.Union[
37
+ typing.Optional[int], type_utils.NotGiven
38
+ ] = type_utils.NOT_GIVEN,
35
39
  request_options: typing.Optional[RequestOptions] = None,
36
40
  ) -> models.V1VideoToVideoCreateResponse:
37
41
  """
@@ -48,13 +52,27 @@ class VideoToVideoClient:
48
52
  fps_resolution: Determines whether the resulting video will have the same frame per second as the original video, or half.
49
53
  * `FULL` - the result video will have the same FPS as the input video
50
54
  * `HALF` - the result video will have half the FPS as the input video
55
+ height: Used to determine the dimensions of the output video.
56
+
57
+ * If height is provided, width will also be required. The larger value between width and height will be used to determine the maximum output resolution while maintaining the original aspect ratio.
58
+ * If both height and width are omitted, the video will be resized according to your subscription's maximum resolution, while preserving aspect ratio.
59
+
60
+ Note: if the video's original resolution is less than the maximum, the video will not be resized.
61
+
62
+ See our [pricing page](https://magichour.ai/pricing) for more details.
51
63
  name: The name of video
64
+ width: Used to determine the dimensions of the output video.
65
+
66
+ * If width is provided, height will also be required. The larger value between width and height will be used to determine the maximum output resolution while maintaining the original aspect ratio.
67
+ * If both height and width are omitted, the video will be resized according to your subscription's maximum resolution, while preserving aspect ratio.
68
+
69
+ Note: if the video's original resolution is less than the maximum, the video will not be resized.
70
+
71
+ See our [pricing page](https://magichour.ai/pricing) for more details.
52
72
  assets: Provide the assets for video-to-video. For video, The `video_source` field determines whether `video_file_path` or `youtube_url` field is used
53
73
  end_seconds: The end time of the input video in seconds
54
- height: The height of the final output video. Must be divisible by 64. The maximum height depends on your subscription. Please refer to our [pricing page](https://magichour.ai/pricing) for more details
55
74
  start_seconds: The start time of the input video in seconds
56
75
  style: V1VideoToVideoCreateBodyStyle
57
- width: The width of the final output video. Must be divisible by 64. The maximum width depends on your subscription. Please refer to our [pricing page](https://magichour.ai/pricing) for more details
58
76
  request_options: Additional options to customize the HTTP request
59
77
 
60
78
  Returns:
@@ -72,7 +90,6 @@ class VideoToVideoClient:
72
90
  "video_source": "file",
73
91
  },
74
92
  end_seconds=15.0,
75
- height=960,
76
93
  start_seconds=0.0,
77
94
  style={
78
95
  "art_style": "3D Render",
@@ -81,22 +98,23 @@ class VideoToVideoClient:
81
98
  "prompt_type": "append_default",
82
99
  "version": "default",
83
100
  },
84
- width=512,
85
101
  fps_resolution="HALF",
102
+ height=960,
86
103
  name="Video To Video video",
104
+ width=512,
87
105
  )
88
106
  ```
89
107
  """
90
108
  _json = to_encodable(
91
109
  item={
92
110
  "fps_resolution": fps_resolution,
111
+ "height": height,
93
112
  "name": name,
113
+ "width": width,
94
114
  "assets": assets,
95
115
  "end_seconds": end_seconds,
96
- "height": height,
97
116
  "start_seconds": start_seconds,
98
117
  "style": style,
99
- "width": width,
100
118
  },
101
119
  dump_with=params._SerializerV1VideoToVideoCreateBody,
102
120
  )
@@ -119,17 +137,21 @@ class AsyncVideoToVideoClient:
119
137
  *,
120
138
  assets: params.V1VideoToVideoCreateBodyAssets,
121
139
  end_seconds: float,
122
- height: int,
123
140
  start_seconds: float,
124
141
  style: params.V1VideoToVideoCreateBodyStyle,
125
- width: int,
126
142
  fps_resolution: typing.Union[
127
143
  typing.Optional[typing_extensions.Literal["FULL", "HALF"]],
128
144
  type_utils.NotGiven,
129
145
  ] = type_utils.NOT_GIVEN,
146
+ height: typing.Union[
147
+ typing.Optional[int], type_utils.NotGiven
148
+ ] = type_utils.NOT_GIVEN,
130
149
  name: typing.Union[
131
150
  typing.Optional[str], type_utils.NotGiven
132
151
  ] = type_utils.NOT_GIVEN,
152
+ width: typing.Union[
153
+ typing.Optional[int], type_utils.NotGiven
154
+ ] = type_utils.NOT_GIVEN,
133
155
  request_options: typing.Optional[RequestOptions] = None,
134
156
  ) -> models.V1VideoToVideoCreateResponse:
135
157
  """
@@ -146,13 +168,27 @@ class AsyncVideoToVideoClient:
146
168
  fps_resolution: Determines whether the resulting video will have the same frame per second as the original video, or half.
147
169
  * `FULL` - the result video will have the same FPS as the input video
148
170
  * `HALF` - the result video will have half the FPS as the input video
171
+ height: Used to determine the dimensions of the output video.
172
+
173
+ * If height is provided, width will also be required. The larger value between width and height will be used to determine the maximum output resolution while maintaining the original aspect ratio.
174
+ * If both height and width are omitted, the video will be resized according to your subscription's maximum resolution, while preserving aspect ratio.
175
+
176
+ Note: if the video's original resolution is less than the maximum, the video will not be resized.
177
+
178
+ See our [pricing page](https://magichour.ai/pricing) for more details.
149
179
  name: The name of video
180
+ width: Used to determine the dimensions of the output video.
181
+
182
+ * If width is provided, height will also be required. The larger value between width and height will be used to determine the maximum output resolution while maintaining the original aspect ratio.
183
+ * If both height and width are omitted, the video will be resized according to your subscription's maximum resolution, while preserving aspect ratio.
184
+
185
+ Note: if the video's original resolution is less than the maximum, the video will not be resized.
186
+
187
+ See our [pricing page](https://magichour.ai/pricing) for more details.
150
188
  assets: Provide the assets for video-to-video. For video, The `video_source` field determines whether `video_file_path` or `youtube_url` field is used
151
189
  end_seconds: The end time of the input video in seconds
152
- height: The height of the final output video. Must be divisible by 64. The maximum height depends on your subscription. Please refer to our [pricing page](https://magichour.ai/pricing) for more details
153
190
  start_seconds: The start time of the input video in seconds
154
191
  style: V1VideoToVideoCreateBodyStyle
155
- width: The width of the final output video. Must be divisible by 64. The maximum width depends on your subscription. Please refer to our [pricing page](https://magichour.ai/pricing) for more details
156
192
  request_options: Additional options to customize the HTTP request
157
193
 
158
194
  Returns:
@@ -170,7 +206,6 @@ class AsyncVideoToVideoClient:
170
206
  "video_source": "file",
171
207
  },
172
208
  end_seconds=15.0,
173
- height=960,
174
209
  start_seconds=0.0,
175
210
  style={
176
211
  "art_style": "3D Render",
@@ -179,22 +214,23 @@ class AsyncVideoToVideoClient:
179
214
  "prompt_type": "append_default",
180
215
  "version": "default",
181
216
  },
182
- width=512,
183
217
  fps_resolution="HALF",
218
+ height=960,
184
219
  name="Video To Video video",
220
+ width=512,
185
221
  )
186
222
  ```
187
223
  """
188
224
  _json = to_encodable(
189
225
  item={
190
226
  "fps_resolution": fps_resolution,
227
+ "height": height,
191
228
  "name": name,
229
+ "width": width,
192
230
  "assets": assets,
193
231
  "end_seconds": end_seconds,
194
- "height": height,
195
232
  "start_seconds": start_seconds,
196
233
  "style": style,
197
- "width": width,
198
234
  },
199
235
  dump_with=params._SerializerV1VideoToVideoCreateBody,
200
236
  )
@@ -1,5 +1,6 @@
1
1
  from .v1_ai_clothes_changer_create_response import V1AiClothesChangerCreateResponse
2
2
  from .v1_ai_face_editor_create_response import V1AiFaceEditorCreateResponse
3
+ from .v1_ai_gif_generator_create_response import V1AiGifGeneratorCreateResponse
3
4
  from .v1_ai_headshot_generator_create_response import (
4
5
  V1AiHeadshotGeneratorCreateResponse,
5
6
  )
@@ -40,6 +41,7 @@ from .v1_video_to_video_create_response import V1VideoToVideoCreateResponse
40
41
  __all__ = [
41
42
  "V1AiClothesChangerCreateResponse",
42
43
  "V1AiFaceEditorCreateResponse",
44
+ "V1AiGifGeneratorCreateResponse",
43
45
  "V1AiHeadshotGeneratorCreateResponse",
44
46
  "V1AiImageGeneratorCreateResponse",
45
47
  "V1AiImageUpscalerCreateResponse",
@@ -0,0 +1,25 @@
1
+ import pydantic
2
+
3
+
4
+ class V1AiGifGeneratorCreateResponse(pydantic.BaseModel):
5
+ """
6
+ Success
7
+ """
8
+
9
+ model_config = pydantic.ConfigDict(
10
+ arbitrary_types_allowed=True,
11
+ populate_by_name=True,
12
+ )
13
+
14
+ frame_cost: int = pydantic.Field(
15
+ alias="frame_cost",
16
+ )
17
+ """
18
+ The frame cost of the image generation
19
+ """
20
+ id: str = pydantic.Field(
21
+ alias="id",
22
+ )
23
+ """
24
+ Unique ID of the image. This value can be used in the [get image project API](https://docs.magichour.ai/api-reference/image-projects/get-image-details) to fetch additional details such as status
25
+ """
@@ -72,5 +72,5 @@ class V1ImageProjectsGetResponse(pydantic.BaseModel):
72
72
  alias="type",
73
73
  )
74
74
  """
75
- The type of the image project. Possible values are AI_HEADSHOT, AI_IMAGE, IMAGE_UPSCALER, FACE_SWAP, PHOTO_EDITOR, QR_CODE, BACKGROUND_REMOVER, CLOTHES_CHANGER, AI_MEME, FACE_EDITOR, PHOTO_COLORIZER
75
+ The type of the image project. Possible values are AI_HEADSHOT, AI_IMAGE, IMAGE_UPSCALER, FACE_SWAP, PHOTO_EDITOR, QR_CODE, BACKGROUND_REMOVER, CLOTHES_CHANGER, AI_MEME, FACE_EDITOR, PHOTO_COLORIZER, AI_GIF
76
76
  """
@@ -18,6 +18,14 @@ from .v1_ai_face_editor_create_body_style import (
18
18
  V1AiFaceEditorCreateBodyStyle,
19
19
  _SerializerV1AiFaceEditorCreateBodyStyle,
20
20
  )
21
+ from .v1_ai_gif_generator_create_body import (
22
+ V1AiGifGeneratorCreateBody,
23
+ _SerializerV1AiGifGeneratorCreateBody,
24
+ )
25
+ from .v1_ai_gif_generator_create_body_style import (
26
+ V1AiGifGeneratorCreateBodyStyle,
27
+ _SerializerV1AiGifGeneratorCreateBodyStyle,
28
+ )
21
29
  from .v1_ai_headshot_generator_create_body import (
22
30
  V1AiHeadshotGeneratorCreateBody,
23
31
  _SerializerV1AiHeadshotGeneratorCreateBody,
@@ -183,6 +191,8 @@ __all__ = [
183
191
  "V1AiFaceEditorCreateBody",
184
192
  "V1AiFaceEditorCreateBodyAssets",
185
193
  "V1AiFaceEditorCreateBodyStyle",
194
+ "V1AiGifGeneratorCreateBody",
195
+ "V1AiGifGeneratorCreateBodyStyle",
186
196
  "V1AiHeadshotGeneratorCreateBody",
187
197
  "V1AiHeadshotGeneratorCreateBodyAssets",
188
198
  "V1AiHeadshotGeneratorCreateBodyStyle",
@@ -228,6 +238,8 @@ __all__ = [
228
238
  "_SerializerV1AiFaceEditorCreateBody",
229
239
  "_SerializerV1AiFaceEditorCreateBodyAssets",
230
240
  "_SerializerV1AiFaceEditorCreateBodyStyle",
241
+ "_SerializerV1AiGifGeneratorCreateBody",
242
+ "_SerializerV1AiGifGeneratorCreateBodyStyle",
231
243
  "_SerializerV1AiHeadshotGeneratorCreateBody",
232
244
  "_SerializerV1AiHeadshotGeneratorCreateBodyAssets",
233
245
  "_SerializerV1AiHeadshotGeneratorCreateBodyStyle",
@@ -0,0 +1,37 @@
1
+ import pydantic
2
+ import typing
3
+ import typing_extensions
4
+
5
+ from .v1_ai_gif_generator_create_body_style import (
6
+ V1AiGifGeneratorCreateBodyStyle,
7
+ _SerializerV1AiGifGeneratorCreateBodyStyle,
8
+ )
9
+
10
+
11
+ class V1AiGifGeneratorCreateBody(typing_extensions.TypedDict):
12
+ """
13
+ V1AiGifGeneratorCreateBody
14
+ """
15
+
16
+ name: typing_extensions.NotRequired[str]
17
+ """
18
+ The name of gif
19
+ """
20
+
21
+ style: typing_extensions.Required[V1AiGifGeneratorCreateBodyStyle]
22
+
23
+
24
+ class _SerializerV1AiGifGeneratorCreateBody(pydantic.BaseModel):
25
+ """
26
+ Serializer for V1AiGifGeneratorCreateBody handling case conversions
27
+ and file omissions as dictated by the API
28
+ """
29
+
30
+ model_config = pydantic.ConfigDict(
31
+ populate_by_name=True,
32
+ )
33
+
34
+ name: typing.Optional[str] = pydantic.Field(alias="name", default=None)
35
+ style: _SerializerV1AiGifGeneratorCreateBodyStyle = pydantic.Field(
36
+ alias="style",
37
+ )
@@ -0,0 +1,28 @@
1
+ import pydantic
2
+ import typing_extensions
3
+
4
+
5
+ class V1AiGifGeneratorCreateBodyStyle(typing_extensions.TypedDict):
6
+ """
7
+ V1AiGifGeneratorCreateBodyStyle
8
+ """
9
+
10
+ prompt: typing_extensions.Required[str]
11
+ """
12
+ The prompt used for the GIF.
13
+ """
14
+
15
+
16
+ class _SerializerV1AiGifGeneratorCreateBodyStyle(pydantic.BaseModel):
17
+ """
18
+ Serializer for V1AiGifGeneratorCreateBodyStyle handling case conversions
19
+ and file omissions as dictated by the API
20
+ """
21
+
22
+ model_config = pydantic.ConfigDict(
23
+ populate_by_name=True,
24
+ )
25
+
26
+ prompt: str = pydantic.Field(
27
+ alias="prompt",
28
+ )
@@ -36,9 +36,16 @@ class V1VideoToVideoCreateBody(typing_extensions.TypedDict):
36
36
  * `HALF` - the result video will have half the FPS as the input video
37
37
  """
38
38
 
39
- height: typing_extensions.Required[int]
39
+ height: typing_extensions.NotRequired[int]
40
40
  """
41
- The height of the final output video. Must be divisible by 64. The maximum height depends on your subscription. Please refer to our [pricing page](https://magichour.ai/pricing) for more details
41
+ Used to determine the dimensions of the output video.
42
+
43
+ * If height is provided, width will also be required. The larger value between width and height will be used to determine the maximum output resolution while maintaining the original aspect ratio.
44
+ * If both height and width are omitted, the video will be resized according to your subscription's maximum resolution, while preserving aspect ratio.
45
+
46
+ Note: if the video's original resolution is less than the maximum, the video will not be resized.
47
+
48
+ See our [pricing page](https://magichour.ai/pricing) for more details.
42
49
  """
43
50
 
44
51
  name: typing_extensions.NotRequired[str]
@@ -53,9 +60,16 @@ class V1VideoToVideoCreateBody(typing_extensions.TypedDict):
53
60
 
54
61
  style: typing_extensions.Required[V1VideoToVideoCreateBodyStyle]
55
62
 
56
- width: typing_extensions.Required[int]
63
+ width: typing_extensions.NotRequired[int]
57
64
  """
58
- The width of the final output video. Must be divisible by 64. The maximum width depends on your subscription. Please refer to our [pricing page](https://magichour.ai/pricing) for more details
65
+ Used to determine the dimensions of the output video.
66
+
67
+ * If width is provided, height will also be required. The larger value between width and height will be used to determine the maximum output resolution while maintaining the original aspect ratio.
68
+ * If both height and width are omitted, the video will be resized according to your subscription's maximum resolution, while preserving aspect ratio.
69
+
70
+ Note: if the video's original resolution is less than the maximum, the video will not be resized.
71
+
72
+ See our [pricing page](https://magichour.ai/pricing) for more details.
59
73
  """
60
74
 
61
75
 
@@ -78,9 +92,7 @@ class _SerializerV1VideoToVideoCreateBody(pydantic.BaseModel):
78
92
  fps_resolution: typing.Optional[typing_extensions.Literal["FULL", "HALF"]] = (
79
93
  pydantic.Field(alias="fps_resolution", default=None)
80
94
  )
81
- height: int = pydantic.Field(
82
- alias="height",
83
- )
95
+ height: typing.Optional[int] = pydantic.Field(alias="height", default=None)
84
96
  name: typing.Optional[str] = pydantic.Field(alias="name", default=None)
85
97
  start_seconds: float = pydantic.Field(
86
98
  alias="start_seconds",
@@ -88,6 +100,4 @@ class _SerializerV1VideoToVideoCreateBody(pydantic.BaseModel):
88
100
  style: _SerializerV1VideoToVideoCreateBodyStyle = pydantic.Field(
89
101
  alias="style",
90
102
  )
91
- width: int = pydantic.Field(
92
- alias="width",
93
- )
103
+ width: typing.Optional[int] = pydantic.Field(alias="width", default=None)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: magic_hour
3
- Version: 0.18.0
3
+ Version: 0.20.0
4
4
  Summary: Python SDK for Magic Hour API
5
5
  Requires-Python: >=3.8,<4.0
6
6
  Classifier: Programming Language :: Python :: 3
@@ -67,6 +67,10 @@ client = AsyncClient(token="my api key")
67
67
 
68
68
  * [create](magic_hour/resources/v1/ai_face_editor/README.md#create) - AI Face Editor
69
69
 
70
+ ### [v1.ai_gif_generator](magic_hour/resources/v1/ai_gif_generator/README.md)
71
+
72
+ * [create](magic_hour/resources/v1/ai_gif_generator/README.md#create) - AI GIFs
73
+
70
74
  ### [v1.ai_headshot_generator](magic_hour/resources/v1/ai_headshot_generator/README.md)
71
75
 
72
76
  * [create](magic_hour/resources/v1/ai_headshot_generator/README.md#create) - AI Headshots
@@ -1,16 +1,16 @@
1
1
  magic_hour/__init__.py,sha256=KIpC-OAJjT6m-WLHmdIdUlsYyicCiX4WHVIwfPG-e0c,203
2
2
  magic_hour/client.py,sha256=DMxeed7El-0q_URdGYXXNStGXJ11l7u6q1bQD8LWQ8g,2038
3
- magic_hour/core/__init__.py,sha256=s2y_QWfn976ilhDlvKGz-QWhAYcRDzvtAYnLbMMOTEA,1167
3
+ magic_hour/core/__init__.py,sha256=YiyAhiYwhYzCN0Kk4jhca5HbxE-ot0fwXzHUL27HZu8,1217
4
4
  magic_hour/core/api_error.py,sha256=K1d47qRbhLBNEaUVbs0NPgxee24X3qGZ37gBhleUzEE,1760
5
5
  magic_hour/core/auth.py,sha256=NSjPcmTyHelRag9FqH1ufbchBWQgGDpH2P0akfppIPo,9130
6
6
  magic_hour/core/base_client.py,sha256=H9FJtNvN3ZfjjnPq4t9HXgh0c1324x1RFtAHXWEnqWk,18846
7
7
  magic_hour/core/binary_response.py,sha256=T-DATvb21P2ZRnYa4LlXmF77VfM8Tut2951QHEQct_U,681
8
- magic_hour/core/query.py,sha256=Z4NB5gSkJ8KMJU2vleHP_dx0NisP0v8S0em5XVlS_tE,4247
9
- magic_hour/core/request.py,sha256=lyHrh2VWY238D7JPbgZJlodTqBlHSmQn4fBJiBfE1Es,5069
8
+ magic_hour/core/query.py,sha256=FdGdyHggFc8weFDSiUuVIEfZ7B2UAU0QOS38bp2ud9o,4627
9
+ magic_hour/core/request.py,sha256=_ikn8iZ2fU9Ubqnt7M9hdEnXGV6AAFHJYmDKBtxEY4I,5263
10
10
  magic_hour/core/response.py,sha256=Sl7nPL2axmz7em_6d9TkFSnQQKUpalWaVWbPPWoXJgM,10180
11
11
  magic_hour/core/type_utils.py,sha256=4bU9WXnMXJ6YTtuqOMiB8t6Xw0RlfVWJ-IDBONlqEtQ,461
12
12
  magic_hour/core/utils.py,sha256=34SiC1vw2A0TkYHONgMA_d09soIIYiiBWRXCZGdwGIk,1669
13
- magic_hour/environment.py,sha256=Qodwn0_lYoL2oFefrZzADTnkrEe6VnzOU_xKyEFeLKs,213
13
+ magic_hour/environment.py,sha256=zppHUVUOt6Y2aej89SSPBfUZtdUSBmh2BLqAIEWj_9Q,213
14
14
  magic_hour/resources/v1/__init__.py,sha256=Aj0sjVcoijjQyieNBxv2_uewPYC2vO2UG-ehoBgCz5E,86
15
15
  magic_hour/resources/v1/ai_clothes_changer/README.md,sha256=KQTvbttct5GcdOJW3NG5gCsWF6G2qlwIoBjBd92TjUs,977
16
16
  magic_hour/resources/v1/ai_clothes_changer/__init__.py,sha256=6W_Y2HxG2sDOBiJyzngK3Q2S3xfQgpK-j8xFRmBAhbQ,142
@@ -18,6 +18,9 @@ magic_hour/resources/v1/ai_clothes_changer/client.py,sha256=gnhqocjO0GjoGM6dFOKk
18
18
  magic_hour/resources/v1/ai_face_editor/README.md,sha256=nhTRDxHPVqkd22FNZcZbtpEBqcV-t8-MavSqfuPh00w,1811
19
19
  magic_hour/resources/v1/ai_face_editor/__init__.py,sha256=RY8GBMQcqsDFbFcUuK-4LPvablq-U9XmSSlQk4HLKmM,126
20
20
  magic_hour/resources/v1/ai_face_editor/client.py,sha256=N5toTWe-Ag2iAhwk-CbWQxGnK6fZ2uHAFEKx15SPl-I,5315
21
+ magic_hour/resources/v1/ai_gif_generator/README.md,sha256=jjNjYamGve_wv4NsD7ehn9lr3ztpqggViUoOhXNHb9k,651
22
+ magic_hour/resources/v1/ai_gif_generator/__init__.py,sha256=SG_WmxUnpQWlfNQoHfdXPEGQEPC0WZPgom8ATaR9jiY,134
23
+ magic_hour/resources/v1/ai_gif_generator/client.py,sha256=uIt2HfyTNtGqn-funDkcGV0lXZtWdMJKS7Jhv99phPo,3489
21
24
  magic_hour/resources/v1/ai_headshot_generator/README.md,sha256=CWihzwUuDVoLBItSDJKGBW1EQthz2REmkLkaaA68yao,705
22
25
  magic_hour/resources/v1/ai_headshot_generator/__init__.py,sha256=4WZ3jfrL2yPhQaPalMJrUEykwUoF3KBtop2VJEij-0s,154
23
26
  magic_hour/resources/v1/ai_headshot_generator/client.py,sha256=PoRzXFJCIyGA4PDOZyK6rQ1PHE6EUXSE7ilu_N9RTEc,4159
@@ -42,7 +45,7 @@ magic_hour/resources/v1/ai_talking_photo/client.py,sha256=TQNwMP3DhDj5jb51diMxcO
42
45
  magic_hour/resources/v1/animation/README.md,sha256=uIVfUwD7iAOe2eJDgrxj4UyYmq9R30fdI3Z0JuEChc4,1477
43
46
  magic_hour/resources/v1/animation/__init__.py,sha256=M6KUe6TEZl_DAdyn1HFQ2kHYanZo6xy3mvUdCN264hQ,114
44
47
  magic_hour/resources/v1/animation/client.py,sha256=YYjggl_hszTW-Sn9SFs3m7bz7PvtRTruhHSSnrkkD9c,6401
45
- magic_hour/resources/v1/client.py,sha256=x9DGi-0Fgqt85FgFWgD49NNFJzzSHtpJTcovT-WX4C4,6339
48
+ magic_hour/resources/v1/client.py,sha256=kxrv1LfFHebey-tVjxlBN6c-9hSYMBqno9rVl54pUUg,6626
46
49
  magic_hour/resources/v1/face_swap/README.md,sha256=g5e_eZu3OsrIuc6ISpXbliIX1uVeYX7MwOfdw74dIoI,1306
47
50
  magic_hour/resources/v1/face_swap/__init__.py,sha256=lyg5uAHyYHEUVAiAZtP3zwjGCEGqq8IWbQKexVdhr00,110
48
51
  magic_hour/resources/v1/face_swap/client.py,sha256=-BpJae7J4PZPUG45BMA3HBB2XhrbHpgWqwwyaDFH88A,8519
@@ -75,12 +78,13 @@ magic_hour/resources/v1/text_to_video/client.py,sha256=HFFj6a9VaYEzEsa--5lI8HhsS
75
78
  magic_hour/resources/v1/video_projects/README.md,sha256=8z3EpBwXMR1nZL-ba34DAkoCfRZ0S2CyMaYCwLBYCEo,1589
76
79
  magic_hour/resources/v1/video_projects/__init__.py,sha256=1aj_tE-GAf8BuQ76RQvjGVn8Y39CjdAJDlcsCPucX0w,130
77
80
  magic_hour/resources/v1/video_projects/client.py,sha256=JvhYhf3phYkdVj8VpWxvxF8qWBRU-WaZYi-8lhVgpSQ,5511
78
- magic_hour/resources/v1/video_to_video/README.md,sha256=yOIRj1EPTVl8rl15SPWhpc2PZi1ddKGMix8WbaxlXzQ,1630
81
+ magic_hour/resources/v1/video_to_video/README.md,sha256=--Z-JVvJ-412coXNU1F1a2Iq2IgR96QTbxQ31ryN8AE,1630
79
82
  magic_hour/resources/v1/video_to_video/__init__.py,sha256=1SHaRLlsrlBkdxxKBYgdbHrGATlRvqlXc22RpjjHaOA,126
80
- magic_hour/resources/v1/video_to_video/client.py,sha256=dYb2zi8MMhm1YUBFxGhFno4ikbMEjcLrs3JofapyP-s,8368
81
- magic_hour/types/models/__init__.py,sha256=9hopLSb427808uWcsoDeDskz3ZBF9akYYMorpKj2MaY,3305
83
+ magic_hour/resources/v1/video_to_video/client.py,sha256=WFmYL3ZBLyKLDBOOOc9tJigtwviI6JLjbH7yJSsiIyM,10404
84
+ magic_hour/types/models/__init__.py,sha256=Zv5G1HTpnPT94bSWyVhAxrijRGsInkXbBaifvaJxsr8,3423
82
85
  magic_hour/types/models/v1_ai_clothes_changer_create_response.py,sha256=gpPZLGvSukhBSK2LzTckn4HFcNDseP_XtfwasxzE2uc,625
83
86
  magic_hour/types/models/v1_ai_face_editor_create_response.py,sha256=mjeIlBOfcvHy9WrtOh0ZKFwrYZbA3gUY46fQ-fIGHuI,621
87
+ magic_hour/types/models/v1_ai_gif_generator_create_response.py,sha256=vcEFAN1F9ef4aMzrZhoAMOOu5I-DJCAKqVtzjb84xW4,623
84
88
  magic_hour/types/models/v1_ai_headshot_generator_create_response.py,sha256=s4OheUpwh5jW1XAP4x_M7j-Xafq_gq9Lbz3NbUsFhs8,628
85
89
  magic_hour/types/models/v1_ai_image_generator_create_response.py,sha256=gqRQUTb1dznt9trj5i4vIc2GcPac910ti7EXzz49btc,625
86
90
  magic_hour/types/models/v1_ai_image_upscaler_create_response.py,sha256=u5z8WHJA7iT3u3EsTcDuAzwJ9JL9wMi0K93JhahjpGk,624
@@ -94,7 +98,7 @@ magic_hour/types/models/v1_face_swap_photo_create_response.py,sha256=d68oxwceXya
94
98
  magic_hour/types/models/v1_files_upload_urls_create_response.py,sha256=ecdnxoo-ZBTa2kAusHq4nyz6RdugzyN7w4oazJt5ri0,460
95
99
  magic_hour/types/models/v1_files_upload_urls_create_response_items_item.py,sha256=AjW1Myj-dB10IdM3zTMEsXouY3tnx8vdN5CW3HLQX_M,799
96
100
  magic_hour/types/models/v1_image_background_remover_create_response.py,sha256=jK_RVF3V0VSZn70FzsEjCrA_SEbpvcDdxy1RSlvsygw,631
97
- magic_hour/types/models/v1_image_projects_get_response.py,sha256=FEt7O6Z_C2pDzFnjkBciC2Cq6A9OfRsq-u8db4JTEqY,2141
101
+ magic_hour/types/models/v1_image_projects_get_response.py,sha256=BC0YSrI07xumBXmv-kbUxhi9aabEjWFU4Oo7RDtGWfw,2149
98
102
  magic_hour/types/models/v1_image_projects_get_response_downloads_item.py,sha256=kC0UhiMug52kxN6Ib1H_u_JQGUbeRc91gjuVaXYaM-c,410
99
103
  magic_hour/types/models/v1_image_projects_get_response_error.py,sha256=R1qg-aIt63h6Q7bQ4AvgeC0lbUg5u35rwFXFvU_gvZs,568
100
104
  magic_hour/types/models/v1_image_to_video_create_response.py,sha256=9I3MptKUR2gdQW6SbGSZr5Usdte9PRSniq-pjwJySk4,736
@@ -106,12 +110,14 @@ magic_hour/types/models/v1_video_projects_get_response_download.py,sha256=nudDCN
106
110
  magic_hour/types/models/v1_video_projects_get_response_downloads_item.py,sha256=DlUuLBSGa7jWoozxferkaOsGc4jASItcjjWbBXGu620,410
107
111
  magic_hour/types/models/v1_video_projects_get_response_error.py,sha256=49QxnXAmYHcvSWuuhbQZeGlUfqVcO4YwZ414GczQnvA,568
108
112
  magic_hour/types/models/v1_video_to_video_create_response.py,sha256=dRQql5qEQvcF0wbGO8M0yabgMef26w5T3JGtgnqLZ-Y,736
109
- magic_hour/types/params/__init__.py,sha256=7ZOYQNGmdT3vCKHSIM1Mi4NBVDcRyggTe0pcMtfngkQ,9805
113
+ magic_hour/types/params/__init__.py,sha256=I8TdaEeRIiRwIkM8i8q4RlYWcYD8dGitWEGEDP9ryYs,10237
110
114
  magic_hour/types/params/v1_ai_clothes_changer_create_body.py,sha256=X5koqrTxYLiKcRMqPF7r-VwQzy4r_7k81o1289zHJvo,1006
111
115
  magic_hour/types/params/v1_ai_clothes_changer_create_body_assets.py,sha256=GGnXOExxXtnHT9wQpDCEkLHQlQB5MbAbYuU47iHGf70,1509
112
116
  magic_hour/types/params/v1_ai_face_editor_create_body.py,sha256=sF7mJbqratllYwQ3slqUTctOndAYnH9BDMJu-49Db-4,1313
113
117
  magic_hour/types/params/v1_ai_face_editor_create_body_assets.py,sha256=lhfVPTuAEFWATi5Su0weYlM_Npd5qEu75LexlJP5UZA,843
114
118
  magic_hour/types/params/v1_ai_face_editor_create_body_style.py,sha256=yNCL--4tDHR6eOltXh842YO0rcjBilJZxOXMcA6xaT4,3502
119
+ magic_hour/types/params/v1_ai_gif_generator_create_body.py,sha256=7kl9B9cjDgnBTp7necRx7E6wbzhrVsZFuYWrr3sLYnU,919
120
+ magic_hour/types/params/v1_ai_gif_generator_create_body_style.py,sha256=xefwoS15Iu9sbhc8oszcH8otTamk-ZTvSMuV1qvcYuQ,611
115
121
  magic_hour/types/params/v1_ai_headshot_generator_create_body.py,sha256=Ydzqxzfo6mMEIUc8R_PTWJujfnTDdzt7Ze4ZYiWxWJM,1405
116
122
  magic_hour/types/params/v1_ai_headshot_generator_create_body_assets.py,sha256=Zzb_CjU9PjGIugafxPIY59JiS1wABQRod29hPRm7xLc,908
117
123
  magic_hour/types/params/v1_ai_headshot_generator_create_body_style.py,sha256=DrX20IwvAhoO0ETO3aNn4YLpfQM5nbUNyz0pm8AO_38,670
@@ -149,10 +155,10 @@ magic_hour/types/params/v1_photo_colorizer_create_body.py,sha256=z6ARPEh1m3UL137
149
155
  magic_hour/types/params/v1_photo_colorizer_create_body_assets.py,sha256=fMC-R5V3gcd-S0LjxNViwtKiLvsxCwEFES31BLWYFp4,859
150
156
  magic_hour/types/params/v1_text_to_video_create_body.py,sha256=ax7CQZQ7keVjOWIsYFTQ9lb_PhhwvfMBXzHWX4x1nB8,1436
151
157
  magic_hour/types/params/v1_text_to_video_create_body_style.py,sha256=9NTboy7J4efsA8tVub2uOZpmgriiggfOyf5uAodBN3o,1065
152
- magic_hour/types/params/v1_video_to_video_create_body.py,sha256=iOb3qGXySlI4unyWPAXDmiLMUSHH6ymuDHeiwpmhKeE,2942
158
+ magic_hour/types/params/v1_video_to_video_create_body.py,sha256=Pgok6GUVHrpW6H3rwdVFA3O5YJvjgviCZkmmHddOSWo,3802
153
159
  magic_hour/types/params/v1_video_to_video_create_body_assets.py,sha256=_-6iA5d8ndka6iJWyWvlJwzRkQcmurJE6hkg-fDwBmQ,1531
154
160
  magic_hour/types/params/v1_video_to_video_create_body_style.py,sha256=2jgpJ3A8LNXksTPQ5pp1tWXtd753zBuhBjA22qqCsTE,5697
155
- magic_hour-0.18.0.dist-info/LICENSE,sha256=F3fxj7JXPgB2K0uj8YXRsVss4u-Dgt_-U3V4VXsivNI,1070
156
- magic_hour-0.18.0.dist-info/METADATA,sha256=VjdrNtXy4yjhjzxXWH2KeBQBX9ooWvvZURFQDfNzXNo,5323
157
- magic_hour-0.18.0.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
158
- magic_hour-0.18.0.dist-info/RECORD,,
161
+ magic_hour-0.20.0.dist-info/LICENSE,sha256=F3fxj7JXPgB2K0uj8YXRsVss4u-Dgt_-U3V4VXsivNI,1070
162
+ magic_hour-0.20.0.dist-info/METADATA,sha256=zAN1JSubDBg-YepmgpXZIdck90lN02P4XV5pDNXADBU,5483
163
+ magic_hour-0.20.0.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
164
+ magic_hour-0.20.0.dist-info/RECORD,,