runapi-minimax-h3 0.1.0__tar.gz
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.
- runapi_minimax_h3-0.1.0/LICENSE +21 -0
- runapi_minimax_h3-0.1.0/PKG-INFO +45 -0
- runapi_minimax_h3-0.1.0/README.md +27 -0
- runapi_minimax_h3-0.1.0/pyproject.toml +34 -0
- runapi_minimax_h3-0.1.0/src/runapi/minimax_h3/__init__.py +24 -0
- runapi_minimax_h3-0.1.0/src/runapi/minimax_h3/client.py +28 -0
- runapi_minimax_h3-0.1.0/src/runapi/minimax_h3/contract_gen.py +84 -0
- runapi_minimax_h3-0.1.0/src/runapi/minimax_h3/py.typed +0 -0
- runapi_minimax_h3-0.1.0/src/runapi/minimax_h3/resources/__init__.py +4 -0
- runapi_minimax_h3-0.1.0/src/runapi/minimax_h3/resources/image_to_video.py +61 -0
- runapi_minimax_h3-0.1.0/src/runapi/minimax_h3/resources/text_to_video.py +61 -0
- runapi_minimax_h3-0.1.0/src/runapi/minimax_h3/types.py +24 -0
- runapi_minimax_h3-0.1.0/tests/test_client.py +68 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 RunAPI
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: runapi-minimax-h3
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: RunAPI MiniMax H3 SDK for text-to-video, reference-media, and image-to-video workflows in JavaScript, Python, Ruby, Go, Java, and PHP
|
|
5
|
+
Project-URL: Homepage, https://runapi.ai/models/minimax-h3
|
|
6
|
+
Project-URL: Documentation, https://runapi.ai/docs/resources/sdks
|
|
7
|
+
Project-URL: Source, https://github.com/runapi-ai/minimax-h3-sdk
|
|
8
|
+
Project-URL: Issues, https://github.com/runapi-ai/minimax-h3-sdk/issues
|
|
9
|
+
Project-URL: Changelog, https://github.com/runapi-ai/minimax-h3-sdk/blob/main/CHANGELOG.md
|
|
10
|
+
Project-URL: Release Notes, https://github.com/runapi-ai/minimax-h3-sdk/releases/tag/python%2Fv0.1.0
|
|
11
|
+
Author-email: RunAPI <contact@runapi.ai>
|
|
12
|
+
License-Expression: Apache-2.0
|
|
13
|
+
License-File: LICENSE
|
|
14
|
+
Keywords: api,golang,gradle,image-to-video,java,maven,minimax-h3,python,ruby,runapi,runapi-ai,sdk,text-to-video,typescript,video-generation
|
|
15
|
+
Requires-Python: >=3.9
|
|
16
|
+
Requires-Dist: runapi-core>=0.4.0
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
|
|
19
|
+
# MiniMax H3 API Python SDK for RunAPI
|
|
20
|
+
|
|
21
|
+
Use `runapi-minimax-h3` for MiniMax H3 video tasks in Python.
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
pip install runapi-minimax-h3
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
```python
|
|
28
|
+
from runapi.minimax_h3 import MiniMaxH3Client
|
|
29
|
+
|
|
30
|
+
client = MiniMaxH3Client()
|
|
31
|
+
result = client.text_to_video.run(
|
|
32
|
+
model="minimax-h3",
|
|
33
|
+
prompt="A cinematic tracking shot through a rain-soaked city",
|
|
34
|
+
aspect_ratio="16:9",
|
|
35
|
+
)
|
|
36
|
+
print(result.videos[0].url)
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Use `text_to_video` for prompt-only or reference-media generation. Use `image_to_video` with a first frame, last frame, or both. Each resource provides `create`, `get`, and `run`.
|
|
40
|
+
|
|
41
|
+
- [Model reference](https://runapi.ai/models/minimax-h3)
|
|
42
|
+
- [API reference](https://runapi.ai/docs/api/minimax-h3/text-to-video)
|
|
43
|
+
- [Pricing and rate limits](https://runapi.ai/models/minimax-h3)
|
|
44
|
+
|
|
45
|
+
Licensed under the Apache License, Version 2.0.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# MiniMax H3 API Python SDK for RunAPI
|
|
2
|
+
|
|
3
|
+
Use `runapi-minimax-h3` for MiniMax H3 video tasks in Python.
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
pip install runapi-minimax-h3
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
```python
|
|
10
|
+
from runapi.minimax_h3 import MiniMaxH3Client
|
|
11
|
+
|
|
12
|
+
client = MiniMaxH3Client()
|
|
13
|
+
result = client.text_to_video.run(
|
|
14
|
+
model="minimax-h3",
|
|
15
|
+
prompt="A cinematic tracking shot through a rain-soaked city",
|
|
16
|
+
aspect_ratio="16:9",
|
|
17
|
+
)
|
|
18
|
+
print(result.videos[0].url)
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Use `text_to_video` for prompt-only or reference-media generation. Use `image_to_video` with a first frame, last frame, or both. Each resource provides `create`, `get`, and `run`.
|
|
22
|
+
|
|
23
|
+
- [Model reference](https://runapi.ai/models/minimax-h3)
|
|
24
|
+
- [API reference](https://runapi.ai/docs/api/minimax-h3/text-to-video)
|
|
25
|
+
- [Pricing and rate limits](https://runapi.ai/models/minimax-h3)
|
|
26
|
+
|
|
27
|
+
Licensed under the Apache License, Version 2.0.
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "runapi-minimax-h3"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "RunAPI MiniMax H3 SDK for text-to-video, reference-media, and image-to-video workflows in JavaScript, Python, Ruby, Go, Java, and PHP"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.9"
|
|
11
|
+
license = "Apache-2.0"
|
|
12
|
+
authors = [{ name = "RunAPI", email = "contact@runapi.ai" }]
|
|
13
|
+
keywords = ["runapi", "runapi-ai", "minimax-h3", "api", "sdk", "typescript", "python", "ruby", "golang", "java", "maven", "gradle", "video-generation", "text-to-video", "image-to-video"]
|
|
14
|
+
dependencies = ["runapi-core>=0.4.0"]
|
|
15
|
+
|
|
16
|
+
[project.urls]
|
|
17
|
+
Homepage = "https://runapi.ai/models/minimax-h3"
|
|
18
|
+
Documentation = "https://runapi.ai/docs/resources/sdks"
|
|
19
|
+
Source = "https://github.com/runapi-ai/minimax-h3-sdk"
|
|
20
|
+
Issues = "https://github.com/runapi-ai/minimax-h3-sdk/issues"
|
|
21
|
+
Changelog = "https://github.com/runapi-ai/minimax-h3-sdk/blob/main/CHANGELOG.md"
|
|
22
|
+
"Release Notes" = "https://github.com/runapi-ai/minimax-h3-sdk/releases/tag/python%2Fv0.1.0"
|
|
23
|
+
|
|
24
|
+
[tool.hatch.build.targets.wheel]
|
|
25
|
+
packages = ["src/runapi"]
|
|
26
|
+
|
|
27
|
+
[tool.uv]
|
|
28
|
+
package = true
|
|
29
|
+
|
|
30
|
+
[dependency-groups]
|
|
31
|
+
dev = ["pytest>=8"]
|
|
32
|
+
|
|
33
|
+
[tool.runapi]
|
|
34
|
+
slug = "minimax-h3"
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"""MiniMax H3 client for RunAPI."""
|
|
2
|
+
|
|
3
|
+
from runapi.core import (
|
|
4
|
+
AuthenticationError,
|
|
5
|
+
InsufficientCreditsError,
|
|
6
|
+
NotFoundError,
|
|
7
|
+
RateLimitError,
|
|
8
|
+
TaskFailedError,
|
|
9
|
+
TaskTimeoutError,
|
|
10
|
+
ValidationError,
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
from .client import MiniMaxH3Client
|
|
14
|
+
|
|
15
|
+
__all__ = [
|
|
16
|
+
"MiniMaxH3Client",
|
|
17
|
+
"AuthenticationError",
|
|
18
|
+
"RateLimitError",
|
|
19
|
+
"InsufficientCreditsError",
|
|
20
|
+
"NotFoundError",
|
|
21
|
+
"ValidationError",
|
|
22
|
+
"TaskFailedError",
|
|
23
|
+
"TaskTimeoutError",
|
|
24
|
+
]
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"""MiniMax H3 client."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Any, Optional
|
|
6
|
+
|
|
7
|
+
from runapi.core import ProviderClient
|
|
8
|
+
|
|
9
|
+
from .resources.image_to_video import ImageToVideo
|
|
10
|
+
from .resources.text_to_video import TextToVideo
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class MiniMaxH3Client(ProviderClient):
|
|
14
|
+
"""MiniMax H3 text-to-video and image-to-video client.
|
|
15
|
+
|
|
16
|
+
Example::
|
|
17
|
+
|
|
18
|
+
client = MiniMaxH3Client(api_key="sk-...")
|
|
19
|
+
result = client.text_to_video.run(
|
|
20
|
+
model="minimax-h3", prompt="A neon city street"
|
|
21
|
+
)
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
def __init__(self, api_key: Optional[str] = None, **options: Any) -> None:
|
|
25
|
+
super().__init__(api_key, **options)
|
|
26
|
+
http = self._http
|
|
27
|
+
self.text_to_video = TextToVideo(http)
|
|
28
|
+
self.image_to_video = ImageToVideo(http)
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
CONTRACT = {
|
|
2
|
+
"image-to-video": {
|
|
3
|
+
"models": ["minimax-h3"],
|
|
4
|
+
"fields_by_model": {
|
|
5
|
+
"minimax-h3": {
|
|
6
|
+
"duration_seconds": {
|
|
7
|
+
"enum": [4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
|
|
8
|
+
"type": "integer"
|
|
9
|
+
},
|
|
10
|
+
"model": {
|
|
11
|
+
"required": True
|
|
12
|
+
},
|
|
13
|
+
"output_resolution": {
|
|
14
|
+
"enum": ["768p", "2k"]
|
|
15
|
+
},
|
|
16
|
+
"prompt": {
|
|
17
|
+
"required": True,
|
|
18
|
+
"min": 1,
|
|
19
|
+
"max": 7000,
|
|
20
|
+
"length": True
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
"rules": [{
|
|
25
|
+
"required_any": ["first_frame_image_url", "last_frame_image_url"]
|
|
26
|
+
}]
|
|
27
|
+
},
|
|
28
|
+
"text-to-video": {
|
|
29
|
+
"models": ["minimax-h3"],
|
|
30
|
+
"fields_by_model": {
|
|
31
|
+
"minimax-h3": {
|
|
32
|
+
"aspect_ratio": {
|
|
33
|
+
"enum": ["adaptive", "21:9", "16:9", "4:3", "1:1", "3:4", "9:16"]
|
|
34
|
+
},
|
|
35
|
+
"duration_seconds": {
|
|
36
|
+
"enum": [4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
|
|
37
|
+
"type": "integer"
|
|
38
|
+
},
|
|
39
|
+
"model": {
|
|
40
|
+
"required": True
|
|
41
|
+
},
|
|
42
|
+
"output_resolution": {
|
|
43
|
+
"enum": ["768p", "2k"]
|
|
44
|
+
},
|
|
45
|
+
"prompt": {
|
|
46
|
+
"required": True,
|
|
47
|
+
"min": 1,
|
|
48
|
+
"max": 7000,
|
|
49
|
+
"length": True
|
|
50
|
+
},
|
|
51
|
+
"reference_audio_urls": {
|
|
52
|
+
"max_items": 3
|
|
53
|
+
},
|
|
54
|
+
"reference_image_urls": {
|
|
55
|
+
"max_items": 9
|
|
56
|
+
},
|
|
57
|
+
"reference_video_urls": {
|
|
58
|
+
"max_items": 3
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
"rules": [{
|
|
63
|
+
"when": {
|
|
64
|
+
"reference_audio_urls": {
|
|
65
|
+
"present": True
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
"required_any": ["reference_image_urls", "reference_video_urls"]
|
|
69
|
+
}, {
|
|
70
|
+
"enum": {
|
|
71
|
+
"aspect_ratio": ["21:9", "16:9", "4:3", "1:1", "3:4", "9:16"]
|
|
72
|
+
},
|
|
73
|
+
"when": {
|
|
74
|
+
"reference_image_urls": {
|
|
75
|
+
"present": False
|
|
76
|
+
},
|
|
77
|
+
"reference_video_urls": {
|
|
78
|
+
"present": False
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
"required": ["aspect_ratio"]
|
|
82
|
+
}]
|
|
83
|
+
}
|
|
84
|
+
}
|
|
File without changes
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"""MiniMax H3 image-to-video resource."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Any, Dict, Optional
|
|
6
|
+
|
|
7
|
+
from runapi.core import Resource, RequestOptions
|
|
8
|
+
|
|
9
|
+
from ..contract_gen import CONTRACT
|
|
10
|
+
from ..types import (
|
|
11
|
+
CompletedVideoTaskResponse,
|
|
12
|
+
VideoTaskResponse,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class ImageToVideo(Resource):
|
|
17
|
+
"""Generate videos from a source image with MiniMax H3 models."""
|
|
18
|
+
|
|
19
|
+
ENDPOINT = "/api/v1/minimax_h3/image_to_video"
|
|
20
|
+
|
|
21
|
+
RESPONSE_CLASS = VideoTaskResponse
|
|
22
|
+
COMPLETED_RESPONSE_CLASS = CompletedVideoTaskResponse
|
|
23
|
+
|
|
24
|
+
def run(self, options: Optional[RequestOptions] = None, **params: Any) -> Any:
|
|
25
|
+
"""Create an image-to-video task and poll until it completes.
|
|
26
|
+
|
|
27
|
+
Args:
|
|
28
|
+
**params: Image-to-video parameters (model, prompt, ...).
|
|
29
|
+
|
|
30
|
+
Returns:
|
|
31
|
+
The completed task with videos.
|
|
32
|
+
"""
|
|
33
|
+
task = self.create(options=options, **params)
|
|
34
|
+
return self._poll_until_complete(lambda: self.get(task.id, options=options))
|
|
35
|
+
|
|
36
|
+
def create(self, options: Optional[RequestOptions] = None, **params: Any) -> Any:
|
|
37
|
+
"""Create an image-to-video task and return immediately with an ``id``.
|
|
38
|
+
|
|
39
|
+
Args:
|
|
40
|
+
**params: Image-to-video parameters (model, prompt, ...).
|
|
41
|
+
|
|
42
|
+
Returns:
|
|
43
|
+
The task creation result with an id.
|
|
44
|
+
"""
|
|
45
|
+
compacted = self._compact_params(params)
|
|
46
|
+
self._validate_params(compacted)
|
|
47
|
+
return self._request("post", self.ENDPOINT, body=compacted, options=options)
|
|
48
|
+
|
|
49
|
+
def get(self, id: str, options: Optional[RequestOptions] = None) -> Any:
|
|
50
|
+
"""Fetch the current status of an image-to-video task.
|
|
51
|
+
|
|
52
|
+
Args:
|
|
53
|
+
id: The task id.
|
|
54
|
+
|
|
55
|
+
Returns:
|
|
56
|
+
The current task status.
|
|
57
|
+
"""
|
|
58
|
+
return self._request("get", f"{self.ENDPOINT}/{id}", options=options)
|
|
59
|
+
|
|
60
|
+
def _validate_params(self, params: Dict[str, Any]) -> None:
|
|
61
|
+
self._validate_contract(CONTRACT["image-to-video"], params)
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"""MiniMax H3 text-to-video resource."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Any, Dict, Optional
|
|
6
|
+
|
|
7
|
+
from runapi.core import Resource, RequestOptions
|
|
8
|
+
|
|
9
|
+
from ..contract_gen import CONTRACT
|
|
10
|
+
from ..types import (
|
|
11
|
+
CompletedVideoTaskResponse,
|
|
12
|
+
VideoTaskResponse,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class TextToVideo(Resource):
|
|
17
|
+
"""Generate videos from text prompts with MiniMax H3 models."""
|
|
18
|
+
|
|
19
|
+
ENDPOINT = "/api/v1/minimax_h3/text_to_video"
|
|
20
|
+
|
|
21
|
+
RESPONSE_CLASS = VideoTaskResponse
|
|
22
|
+
COMPLETED_RESPONSE_CLASS = CompletedVideoTaskResponse
|
|
23
|
+
|
|
24
|
+
def run(self, options: Optional[RequestOptions] = None, **params: Any) -> Any:
|
|
25
|
+
"""Create a text-to-video task and poll until it completes.
|
|
26
|
+
|
|
27
|
+
Args:
|
|
28
|
+
**params: Text-to-video parameters (model, prompt, ...).
|
|
29
|
+
|
|
30
|
+
Returns:
|
|
31
|
+
The completed task with videos.
|
|
32
|
+
"""
|
|
33
|
+
task = self.create(options=options, **params)
|
|
34
|
+
return self._poll_until_complete(lambda: self.get(task.id, options=options))
|
|
35
|
+
|
|
36
|
+
def create(self, options: Optional[RequestOptions] = None, **params: Any) -> Any:
|
|
37
|
+
"""Create a text-to-video task and return immediately with an ``id``.
|
|
38
|
+
|
|
39
|
+
Args:
|
|
40
|
+
**params: Text-to-video parameters (model, prompt, ...).
|
|
41
|
+
|
|
42
|
+
Returns:
|
|
43
|
+
The task creation result with an id.
|
|
44
|
+
"""
|
|
45
|
+
compacted = self._compact_params(params)
|
|
46
|
+
self._validate_params(compacted)
|
|
47
|
+
return self._request("post", self.ENDPOINT, body=compacted, options=options)
|
|
48
|
+
|
|
49
|
+
def get(self, id: str, options: Optional[RequestOptions] = None) -> Any:
|
|
50
|
+
"""Fetch the current status of a text-to-video task.
|
|
51
|
+
|
|
52
|
+
Args:
|
|
53
|
+
id: The task id.
|
|
54
|
+
|
|
55
|
+
Returns:
|
|
56
|
+
The current task status.
|
|
57
|
+
"""
|
|
58
|
+
return self._request("get", f"{self.ENDPOINT}/{id}", options=options)
|
|
59
|
+
|
|
60
|
+
def _validate_params(self, params: Dict[str, Any]) -> None:
|
|
61
|
+
self._validate_contract(CONTRACT["text-to-video"], params)
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"""MiniMax H3 model lists, enums, and response models."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from runapi.core import BaseModel, TaskResponse, optional, required
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class MediaUrl(BaseModel):
|
|
9
|
+
url = optional(str)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class VideoTaskResponse(TaskResponse):
|
|
13
|
+
"""Response for a video generation task."""
|
|
14
|
+
|
|
15
|
+
id = required(str)
|
|
16
|
+
status = optional(str, enum=lambda: TaskResponse.Status.ALL)
|
|
17
|
+
videos = optional([lambda: MediaUrl])
|
|
18
|
+
error = optional(str)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class CompletedVideoTaskResponse(VideoTaskResponse):
|
|
22
|
+
"""Narrowed response from ``run()`` once polling observes completion."""
|
|
23
|
+
|
|
24
|
+
videos = required([lambda: MediaUrl])
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
|
|
3
|
+
from runapi.core.errors import ValidationError
|
|
4
|
+
from runapi.minimax_h3 import MiniMaxH3Client
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class FakeHttp:
|
|
8
|
+
def __init__(self, response=None):
|
|
9
|
+
self.response = response or {"id": "task_1", "status": "pending"}
|
|
10
|
+
self.calls = []
|
|
11
|
+
|
|
12
|
+
def request(self, method, path, body=None, options=None):
|
|
13
|
+
self.calls.append((method, path, body))
|
|
14
|
+
return self.response
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def test_posts_reference_media_through_text_to_video():
|
|
18
|
+
fake = FakeHttp()
|
|
19
|
+
client = MiniMaxH3Client(api_key="k", http_client=fake)
|
|
20
|
+
client.text_to_video.create(
|
|
21
|
+
model="minimax-h3",
|
|
22
|
+
prompt="Continue the performance",
|
|
23
|
+
reference_image_urls=["https://cdn.runapi.ai/public/samples/image.jpg"],
|
|
24
|
+
reference_audio_urls=["https://cdn.runapi.ai/public/samples/voice.mp3"],
|
|
25
|
+
aspect_ratio="adaptive",
|
|
26
|
+
)
|
|
27
|
+
assert fake.calls == [("post", "/api/v1/minimax_h3/text_to_video", {
|
|
28
|
+
"model": "minimax-h3",
|
|
29
|
+
"prompt": "Continue the performance",
|
|
30
|
+
"reference_image_urls": ["https://cdn.runapi.ai/public/samples/image.jpg"],
|
|
31
|
+
"reference_audio_urls": ["https://cdn.runapi.ai/public/samples/voice.mp3"],
|
|
32
|
+
"aspect_ratio": "adaptive",
|
|
33
|
+
})]
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def test_posts_last_frame_only_through_image_to_video():
|
|
37
|
+
fake = FakeHttp()
|
|
38
|
+
client = MiniMaxH3Client(api_key="k", http_client=fake)
|
|
39
|
+
client.image_to_video.create(
|
|
40
|
+
model="minimax-h3", prompt="Animate", last_frame_image_url="https://cdn.runapi.ai/public/samples/image.jpg"
|
|
41
|
+
)
|
|
42
|
+
assert fake.calls[0][1] == "/api/v1/minimax_h3/image_to_video"
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def test_rejects_audio_only_references():
|
|
46
|
+
client = MiniMaxH3Client(api_key="k", http_client=FakeHttp())
|
|
47
|
+
with pytest.raises(ValidationError, match="one of reference_image_urls, reference_video_urls is required"):
|
|
48
|
+
client.text_to_video.create(
|
|
49
|
+
model="minimax-h3", prompt="Continue", reference_audio_urls=["https://cdn.runapi.ai/public/samples/voice.mp3"]
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def test_requires_aspect_ratio_without_references():
|
|
54
|
+
client = MiniMaxH3Client(api_key="k", http_client=FakeHttp())
|
|
55
|
+
with pytest.raises(ValidationError, match="aspect_ratio is required when reference_image_urls is absent and reference_video_urls is absent"):
|
|
56
|
+
client.text_to_video.create(model="minimax-h3", prompt="Continue")
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def test_rejects_adaptive_aspect_ratio_without_references():
|
|
60
|
+
client = MiniMaxH3Client(api_key="k", http_client=FakeHttp())
|
|
61
|
+
with pytest.raises(ValidationError, match="aspect_ratio must be one of:"):
|
|
62
|
+
client.text_to_video.create(model="minimax-h3", prompt="Continue", aspect_ratio="adaptive")
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def test_requires_first_or_last_frame():
|
|
66
|
+
client = MiniMaxH3Client(api_key="k", http_client=FakeHttp())
|
|
67
|
+
with pytest.raises(ValidationError, match="one of first_frame_image_url, last_frame_image_url is required"):
|
|
68
|
+
client.image_to_video.create(model="minimax-h3", prompt="Animate")
|