runapi-wan 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.
runapi/wan/__init__.py ADDED
@@ -0,0 +1,24 @@
1
+ """Wan 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 WanClient
14
+
15
+ __all__ = [
16
+ "WanClient",
17
+ "AuthenticationError",
18
+ "RateLimitError",
19
+ "InsufficientCreditsError",
20
+ "NotFoundError",
21
+ "ValidationError",
22
+ "TaskFailedError",
23
+ "TaskTimeoutError",
24
+ ]
runapi/wan/client.py ADDED
@@ -0,0 +1,38 @@
1
+ """Wan client."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Any, Optional
6
+
7
+ from runapi.core import ClientOptions, HttpClient, resolve_api_key
8
+
9
+ from .resources.animate import Animate
10
+ from .resources.edit_video import EditVideo
11
+ from .resources.image_to_video import ImageToVideo
12
+ from .resources.speech_to_video import SpeechToVideo
13
+ from .resources.text_to_image import TextToImage
14
+ from .resources.text_to_video import TextToVideo
15
+
16
+
17
+ class WanClient:
18
+ """Wan video and text-to-image client.
19
+
20
+ Example::
21
+
22
+ client = WanClient(api_key="sk-...")
23
+ result = client.text_to_video.run(
24
+ model="wan-2.6-text-to-video",
25
+ prompt="A scenic mountain landscape with flowing rivers",
26
+ )
27
+ """
28
+
29
+ def __init__(self, api_key: Optional[str] = None, **options: Any) -> None:
30
+ resolved_api_key = resolve_api_key(api_key)
31
+ client_options = ClientOptions(api_key=resolved_api_key, **options)
32
+ http = client_options.http_client or HttpClient(client_options)
33
+ self.text_to_video = TextToVideo(http)
34
+ self.image_to_video = ImageToVideo(http)
35
+ self.speech_to_video = SpeechToVideo(http)
36
+ self.animate = Animate(http)
37
+ self.text_to_image = TextToImage(http)
38
+ self.edit_video = EditVideo(http)
@@ -0,0 +1,298 @@
1
+ # Code generated by SdkContractGenerator. DO NOT EDIT.
2
+
3
+ CONTRACT = {
4
+ "animate": {
5
+ "models": ["wan-2.2-animate-move", "wan-2.2-animate-replace"],
6
+ "fields_by_model": {
7
+ "wan-2.2-animate-move": {
8
+ "output_resolution": {
9
+ "enum": ["480p", "580p", "720p"]
10
+ },
11
+ "reference_video_url": {
12
+ "required": True
13
+ },
14
+ "source_image_url": {
15
+ "required": True
16
+ }
17
+ },
18
+ "wan-2.2-animate-replace": {
19
+ "output_resolution": {
20
+ "enum": ["480p", "580p", "720p"]
21
+ },
22
+ "reference_video_url": {
23
+ "required": True
24
+ },
25
+ "source_image_url": {
26
+ "required": True
27
+ }
28
+ }
29
+ }
30
+ },
31
+ "edit-video": {
32
+ "models": ["wan-2.6-edit-video", "wan-2.6-flash-edit-video", "wan-2.7-edit-video"],
33
+ "fields_by_model": {
34
+ "wan-2.6-edit-video": {
35
+ "duration_seconds": {
36
+ "type": "integer"
37
+ },
38
+ "output_resolution": {
39
+ "enum": ["720p", "1080p"]
40
+ },
41
+ "prompt": {
42
+ "required": True
43
+ },
44
+ "seed": {
45
+ "type": "integer"
46
+ },
47
+ "source_video_urls": {
48
+ "required": True
49
+ }
50
+ },
51
+ "wan-2.6-flash-edit-video": {
52
+ "duration_seconds": {
53
+ "type": "integer"
54
+ },
55
+ "prompt": {
56
+ "required": True
57
+ },
58
+ "seed": {
59
+ "type": "integer"
60
+ },
61
+ "source_video_urls": {
62
+ "required": True
63
+ }
64
+ },
65
+ "wan-2.7-edit-video": {
66
+ "aspect_ratio": {
67
+ "enum": ["16:9", "9:16", "1:1", "4:3", "3:4"]
68
+ },
69
+ "duration_seconds": {
70
+ "type": "integer"
71
+ },
72
+ "output_resolution": {
73
+ "enum": ["720p", "1080p"]
74
+ },
75
+ "seed": {
76
+ "type": "integer"
77
+ },
78
+ "source_video_url": {
79
+ "required": True
80
+ }
81
+ }
82
+ }
83
+ },
84
+ "image-to-video": {
85
+ "models": ["wan-2.2-a14b-image-to-video-turbo", "wan-2.5-image-to-video", "wan-2.6-flash-image-to-video", "wan-2.6-image-to-video", "wan-2.7-image-to-video"],
86
+ "fields_by_model": {
87
+ "wan-2.2-a14b-image-to-video-turbo": {
88
+ "duration_seconds": {
89
+ "type": "integer"
90
+ },
91
+ "first_frame_image_url": {
92
+ "required": True
93
+ },
94
+ "output_resolution": {
95
+ "enum": ["480p", "720p"]
96
+ },
97
+ "seed": {
98
+ "type": "integer"
99
+ }
100
+ },
101
+ "wan-2.5-image-to-video": {
102
+ "duration_seconds": {
103
+ "required": True,
104
+ "type": "integer"
105
+ },
106
+ "first_frame_image_url": {
107
+ "required": True
108
+ },
109
+ "output_resolution": {
110
+ "enum": ["720p", "1080p"]
111
+ },
112
+ "seed": {
113
+ "type": "integer"
114
+ }
115
+ },
116
+ "wan-2.6-flash-image-to-video": {
117
+ "audio": {
118
+ "required": True
119
+ },
120
+ "duration_seconds": {
121
+ "type": "integer"
122
+ },
123
+ "first_frame_image_url": {
124
+ "required": True
125
+ },
126
+ "output_resolution": {
127
+ "enum": ["720p", "1080p"]
128
+ },
129
+ "prompt": {
130
+ "required": True
131
+ },
132
+ "seed": {
133
+ "type": "integer"
134
+ }
135
+ },
136
+ "wan-2.6-image-to-video": {
137
+ "duration_seconds": {
138
+ "type": "integer"
139
+ },
140
+ "first_frame_image_url": {
141
+ "required": True
142
+ },
143
+ "output_resolution": {
144
+ "enum": ["720p", "1080p"]
145
+ },
146
+ "prompt": {
147
+ "required": True
148
+ },
149
+ "seed": {
150
+ "type": "integer"
151
+ }
152
+ },
153
+ "wan-2.7-image-to-video": {
154
+ "duration_seconds": {
155
+ "type": "integer"
156
+ },
157
+ "output_resolution": {
158
+ "enum": ["720p", "1080p"]
159
+ },
160
+ "prompt": {
161
+ "required": True
162
+ },
163
+ "seed": {
164
+ "type": "integer"
165
+ }
166
+ }
167
+ }
168
+ },
169
+ "speech-to-video": {
170
+ "models": ["wan-2.2-a14b-speech-to-video-turbo"],
171
+ "fields_by_model": {
172
+ "wan-2.2-a14b-speech-to-video-turbo": {
173
+ "frames_per_second": {
174
+ "type": "integer"
175
+ },
176
+ "num_frames": {
177
+ "type": "integer"
178
+ },
179
+ "num_inference_steps": {
180
+ "type": "integer"
181
+ },
182
+ "output_resolution": {
183
+ "enum": ["480p", "580p", "720p"]
184
+ },
185
+ "prompt": {
186
+ "required": True
187
+ },
188
+ "seed": {
189
+ "type": "integer"
190
+ },
191
+ "source_audio_url": {
192
+ "required": True
193
+ },
194
+ "source_image_url": {
195
+ "required": True
196
+ }
197
+ }
198
+ }
199
+ },
200
+ "text-to-image": {
201
+ "models": ["wan-2.7-image", "wan-2.7-image-pro"],
202
+ "fields_by_model": {
203
+ "wan-2.7-image": {
204
+ "aspect_ratio": {
205
+ "enum": ["1:1", "16:9", "4:3", "21:9", "3:4", "9:16", "8:1", "1:8"]
206
+ },
207
+ "output_count": {
208
+ "type": "integer"
209
+ },
210
+ "output_resolution": {
211
+ "enum": ["1k", "2k", "4k"]
212
+ },
213
+ "seed": {
214
+ "type": "integer"
215
+ }
216
+ },
217
+ "wan-2.7-image-pro": {
218
+ "aspect_ratio": {
219
+ "enum": ["1:1", "16:9", "4:3", "21:9", "3:4", "9:16", "8:1", "1:8"]
220
+ },
221
+ "output_count": {
222
+ "type": "integer"
223
+ },
224
+ "output_resolution": {
225
+ "enum": ["1k", "2k", "4k"]
226
+ },
227
+ "seed": {
228
+ "type": "integer"
229
+ }
230
+ }
231
+ }
232
+ },
233
+ "text-to-video": {
234
+ "models": ["wan-2.2-a14b-text-to-video-turbo", "wan-2.5-text-to-video", "wan-2.6-text-to-video", "wan-2.7-r2v", "wan-2.7-text-to-video"],
235
+ "fields_by_model": {
236
+ "wan-2.2-a14b-text-to-video-turbo": {
237
+ "duration_seconds": {
238
+ "type": "integer"
239
+ },
240
+ "output_resolution": {
241
+ "enum": ["480p", "580p", "720p"]
242
+ },
243
+ "seed": {
244
+ "type": "integer"
245
+ }
246
+ },
247
+ "wan-2.5-text-to-video": {
248
+ "duration_seconds": {
249
+ "type": "integer"
250
+ },
251
+ "output_resolution": {
252
+ "enum": ["720p", "1080p"]
253
+ },
254
+ "seed": {
255
+ "type": "integer"
256
+ }
257
+ },
258
+ "wan-2.6-text-to-video": {
259
+ "duration_seconds": {
260
+ "type": "integer"
261
+ },
262
+ "output_resolution": {
263
+ "enum": ["720p", "1080p"]
264
+ },
265
+ "seed": {
266
+ "type": "integer"
267
+ }
268
+ },
269
+ "wan-2.7-r2v": {
270
+ "aspect_ratio": {
271
+ "enum": ["16:9", "9:16", "1:1", "4:3", "3:4"]
272
+ },
273
+ "duration_seconds": {
274
+ "min": 2,
275
+ "max": 10,
276
+ "type": "integer"
277
+ },
278
+ "output_resolution": {
279
+ "enum": ["720p", "1080p"]
280
+ },
281
+ "seed": {
282
+ "type": "integer"
283
+ }
284
+ },
285
+ "wan-2.7-text-to-video": {
286
+ "duration_seconds": {
287
+ "type": "integer"
288
+ },
289
+ "output_resolution": {
290
+ "enum": ["720p", "1080p"]
291
+ },
292
+ "seed": {
293
+ "type": "integer"
294
+ }
295
+ }
296
+ }
297
+ }
298
+ }
runapi/wan/py.typed ADDED
File without changes
@@ -0,0 +1,15 @@
1
+ from .animate import Animate
2
+ from .edit_video import EditVideo
3
+ from .image_to_video import ImageToVideo
4
+ from .speech_to_video import SpeechToVideo
5
+ from .text_to_image import TextToImage
6
+ from .text_to_video import TextToVideo
7
+
8
+ __all__ = [
9
+ "TextToVideo",
10
+ "ImageToVideo",
11
+ "SpeechToVideo",
12
+ "Animate",
13
+ "TextToImage",
14
+ "EditVideo",
15
+ ]
@@ -0,0 +1,58 @@
1
+ """Wan animate resource."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Any
6
+
7
+ from runapi.core import Resource
8
+
9
+ from ..contract_gen import CONTRACT
10
+ from ..types import (
11
+ CompletedVideoTaskResponse,
12
+ VideoTaskResponse,
13
+ )
14
+
15
+
16
+ class Animate(Resource):
17
+ """Animation operations (animate-move, animate-replace) with Wan models."""
18
+
19
+ ENDPOINT = "/api/v1/wan/animate"
20
+
21
+ RESPONSE_CLASS = VideoTaskResponse
22
+ COMPLETED_RESPONSE_CLASS = CompletedVideoTaskResponse
23
+
24
+ def run(self, **params: Any) -> Any:
25
+ """Transfer motion and poll until it completes.
26
+
27
+ Args:
28
+ **params: animation parameters (model, ...).
29
+
30
+ Returns:
31
+ The completed (narrowed) animation response.
32
+ """
33
+ task = self.create(**params)
34
+ return self._poll_until_complete(lambda: self.get(task.id))
35
+
36
+ def create(self, **params: Any) -> Any:
37
+ """Create a animation task and return immediately with an id.
38
+
39
+ Args:
40
+ **params: animation parameters (model, ...).
41
+
42
+ Returns:
43
+ The task creation result with an id.
44
+ """
45
+ compacted = self._compact_params(params)
46
+ self._validate_contract(CONTRACT["animate"], compacted)
47
+ return self._request("post", self.ENDPOINT, body=compacted)
48
+
49
+ def get(self, id: str) -> Any:
50
+ """Fetch the current status of a animation task.
51
+
52
+ Args:
53
+ id: The task id returned by ``create``.
54
+
55
+ Returns:
56
+ The current task status.
57
+ """
58
+ return self._request("get", f"{self.ENDPOINT}/{id}")
@@ -0,0 +1,58 @@
1
+ """Wan edit-video resource."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Any
6
+
7
+ from runapi.core import Resource
8
+
9
+ from ..contract_gen import CONTRACT
10
+ from ..types import (
11
+ CompletedVideoTaskResponse,
12
+ VideoTaskResponse,
13
+ )
14
+
15
+
16
+ class EditVideo(Resource):
17
+ """Edit videos with Wan models."""
18
+
19
+ ENDPOINT = "/api/v1/wan/edit_video"
20
+
21
+ RESPONSE_CLASS = VideoTaskResponse
22
+ COMPLETED_RESPONSE_CLASS = CompletedVideoTaskResponse
23
+
24
+ def run(self, **params: Any) -> Any:
25
+ """Edit a video and poll until it completes.
26
+
27
+ Args:
28
+ **params: video edit parameters (model, ...).
29
+
30
+ Returns:
31
+ The completed (narrowed) video edit response.
32
+ """
33
+ task = self.create(**params)
34
+ return self._poll_until_complete(lambda: self.get(task.id))
35
+
36
+ def create(self, **params: Any) -> Any:
37
+ """Create a video edit task and return immediately with an id.
38
+
39
+ Args:
40
+ **params: video edit parameters (model, ...).
41
+
42
+ Returns:
43
+ The task creation result with an id.
44
+ """
45
+ compacted = self._compact_params(params)
46
+ self._validate_contract(CONTRACT["edit-video"], compacted)
47
+ return self._request("post", self.ENDPOINT, body=compacted)
48
+
49
+ def get(self, id: str) -> Any:
50
+ """Fetch the current status of a video edit task.
51
+
52
+ Args:
53
+ id: The task id returned by ``create``.
54
+
55
+ Returns:
56
+ The current task status.
57
+ """
58
+ return self._request("get", f"{self.ENDPOINT}/{id}")
@@ -0,0 +1,58 @@
1
+ """Wan image-to-video resource."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Any
6
+
7
+ from runapi.core import Resource
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 Wan models."""
18
+
19
+ ENDPOINT = "/api/v1/wan/image_to_video"
20
+
21
+ RESPONSE_CLASS = VideoTaskResponse
22
+ COMPLETED_RESPONSE_CLASS = CompletedVideoTaskResponse
23
+
24
+ def run(self, **params: Any) -> Any:
25
+ """Generate a video from an image and poll until it completes.
26
+
27
+ Args:
28
+ **params: image-to-video parameters (model, ...).
29
+
30
+ Returns:
31
+ The completed (narrowed) image-to-video response.
32
+ """
33
+ task = self.create(**params)
34
+ return self._poll_until_complete(lambda: self.get(task.id))
35
+
36
+ def create(self, **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, ...).
41
+
42
+ Returns:
43
+ The task creation result with an id.
44
+ """
45
+ compacted = self._compact_params(params)
46
+ self._validate_contract(CONTRACT["image-to-video"], compacted)
47
+ return self._request("post", self.ENDPOINT, body=compacted)
48
+
49
+ def get(self, id: str) -> Any:
50
+ """Fetch the current status of an image-to-video task.
51
+
52
+ Args:
53
+ id: The task id returned by ``create``.
54
+
55
+ Returns:
56
+ The current task status.
57
+ """
58
+ return self._request("get", f"{self.ENDPOINT}/{id}")
@@ -0,0 +1,58 @@
1
+ """Wan speech-to-video resource."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Any
6
+
7
+ from runapi.core import Resource
8
+
9
+ from ..contract_gen import CONTRACT
10
+ from ..types import (
11
+ CompletedVideoTaskResponse,
12
+ VideoTaskResponse,
13
+ )
14
+
15
+
16
+ class SpeechToVideo(Resource):
17
+ """Generate speech-driven talking-head videos with Wan models."""
18
+
19
+ ENDPOINT = "/api/v1/wan/speech_to_video"
20
+
21
+ RESPONSE_CLASS = VideoTaskResponse
22
+ COMPLETED_RESPONSE_CLASS = CompletedVideoTaskResponse
23
+
24
+ def run(self, **params: Any) -> Any:
25
+ """Generate a lip-synced video and poll until it completes.
26
+
27
+ Args:
28
+ **params: speech-to-video parameters (model, ...).
29
+
30
+ Returns:
31
+ The completed (narrowed) speech-to-video response.
32
+ """
33
+ task = self.create(**params)
34
+ return self._poll_until_complete(lambda: self.get(task.id))
35
+
36
+ def create(self, **params: Any) -> Any:
37
+ """Create a speech-to-video task and return immediately with an id.
38
+
39
+ Args:
40
+ **params: speech-to-video parameters (model, ...).
41
+
42
+ Returns:
43
+ The task creation result with an id.
44
+ """
45
+ compacted = self._compact_params(params)
46
+ self._validate_contract(CONTRACT["speech-to-video"], compacted)
47
+ return self._request("post", self.ENDPOINT, body=compacted)
48
+
49
+ def get(self, id: str) -> Any:
50
+ """Fetch the current status of a speech-to-video task.
51
+
52
+ Args:
53
+ id: The task id returned by ``create``.
54
+
55
+ Returns:
56
+ The current task status.
57
+ """
58
+ return self._request("get", f"{self.ENDPOINT}/{id}")
@@ -0,0 +1,60 @@
1
+ """Wan text-to-image resource."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Any
6
+
7
+ from runapi.core import Resource, ValidationError
8
+
9
+ from ..contract_gen import CONTRACT
10
+ from ..types import (
11
+ CompletedImageTaskResponse,
12
+ ImageTaskResponse,
13
+ )
14
+
15
+
16
+ class TextToImage(Resource):
17
+ """Generate images from text prompts with Wan models."""
18
+
19
+ ENDPOINT = "/api/v1/wan/text_to_image"
20
+
21
+ RESPONSE_CLASS = ImageTaskResponse
22
+ COMPLETED_RESPONSE_CLASS = CompletedImageTaskResponse
23
+
24
+ def run(self, **params: Any) -> Any:
25
+ """Generate an image and poll until it completes.
26
+
27
+ Args:
28
+ **params: text-to-image parameters (model, ...).
29
+
30
+ Returns:
31
+ The completed (narrowed) text-to-image response.
32
+ """
33
+ task = self.create(**params)
34
+ return self._poll_until_complete(lambda: self.get(task.id))
35
+
36
+ def create(self, **params: Any) -> Any:
37
+ """Create a text-to-image task and return immediately with an id.
38
+
39
+ Args:
40
+ **params: text-to-image parameters (model, ...).
41
+
42
+ Returns:
43
+ The task creation result with an id.
44
+ """
45
+ compacted = self._compact_params(params)
46
+ self._validate_contract(CONTRACT["text-to-image"], compacted)
47
+ if not compacted.get("prompt"):
48
+ raise ValidationError("prompt is required")
49
+ return self._request("post", self.ENDPOINT, body=compacted)
50
+
51
+ def get(self, id: str) -> Any:
52
+ """Fetch the current status of a text-to-image task.
53
+
54
+ Args:
55
+ id: The task id returned by ``create``.
56
+
57
+ Returns:
58
+ The current task status.
59
+ """
60
+ return self._request("get", f"{self.ENDPOINT}/{id}")
@@ -0,0 +1,60 @@
1
+ """Wan text-to-video resource."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Any
6
+
7
+ from runapi.core import Resource, ValidationError
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 Wan models."""
18
+
19
+ ENDPOINT = "/api/v1/wan/text_to_video"
20
+
21
+ RESPONSE_CLASS = VideoTaskResponse
22
+ COMPLETED_RESPONSE_CLASS = CompletedVideoTaskResponse
23
+
24
+ def run(self, **params: Any) -> Any:
25
+ """Generate a video and poll until it completes.
26
+
27
+ Args:
28
+ **params: text-to-video parameters (model, ...).
29
+
30
+ Returns:
31
+ The completed (narrowed) text-to-video response.
32
+ """
33
+ task = self.create(**params)
34
+ return self._poll_until_complete(lambda: self.get(task.id))
35
+
36
+ def create(self, **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, ...).
41
+
42
+ Returns:
43
+ The task creation result with an id.
44
+ """
45
+ compacted = self._compact_params(params)
46
+ self._validate_contract(CONTRACT["text-to-video"], compacted)
47
+ if not compacted.get("prompt"):
48
+ raise ValidationError("prompt is required")
49
+ return self._request("post", self.ENDPOINT, body=compacted)
50
+
51
+ def get(self, id: str) -> Any:
52
+ """Fetch the current status of a text-to-video task.
53
+
54
+ Args:
55
+ id: The task id returned by ``create``.
56
+
57
+ Returns:
58
+ The current task status.
59
+ """
60
+ return self._request("get", f"{self.ENDPOINT}/{id}")
runapi/wan/types.py ADDED
@@ -0,0 +1,43 @@
1
+ """Wan 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 Video(BaseModel):
9
+ url = optional(str)
10
+
11
+
12
+ class Image(BaseModel):
13
+ url = optional(str)
14
+
15
+
16
+ class VideoTaskResponse(TaskResponse):
17
+ """Wan video task status response."""
18
+
19
+ id = required(str)
20
+ status = optional(str, enum=lambda: TaskResponse.Status.ALL)
21
+ videos = optional([lambda: Video])
22
+ error = optional(str)
23
+
24
+
25
+ class ImageTaskResponse(TaskResponse):
26
+ """Wan image task status response."""
27
+
28
+ id = required(str)
29
+ status = optional(str, enum=lambda: TaskResponse.Status.ALL)
30
+ images = optional([lambda: Image])
31
+ error = optional(str)
32
+
33
+
34
+ class CompletedVideoTaskResponse(VideoTaskResponse):
35
+ """Narrowed response from ``run()`` once polling observes completion."""
36
+
37
+ videos = required([lambda: Video])
38
+
39
+
40
+ class CompletedImageTaskResponse(ImageTaskResponse):
41
+ """Narrowed response from ``run()`` once polling observes completion."""
42
+
43
+ images = required([lambda: Image])
@@ -0,0 +1,75 @@
1
+ Metadata-Version: 2.4
2
+ Name: runapi-wan
3
+ Version: 0.1.0
4
+ Summary: Wan video and text-to-image client for RunAPI
5
+ Project-URL: Homepage, https://runapi.ai/models/wan
6
+ Project-URL: Documentation, https://runapi.ai/docs#sdk-wan
7
+ Author-email: RunAPI <contact@runapi.ai>
8
+ License-Expression: Apache-2.0
9
+ Keywords: ai,image-to-video,runapi,sdk,text-to-image,text-to-video,wan
10
+ Requires-Python: >=3.9
11
+ Requires-Dist: runapi-core
12
+ Description-Content-Type: text/markdown
13
+
14
+ # Wan Video API Python SDK for RunAPI
15
+
16
+ The wan video api Python SDK is the language-specific package for Wan on RunAPI. Use this wan video api package for text-to-video, image-to-video, animation, and video editing flows when your application needs JSON request bodies, task status lookup, and consistent RunAPI errors in Python.
17
+
18
+ This wan video api README is the Python package guide inside the public `wan-sdk` repository. For the repository overview, start at `../README.md`; for model details, use https://runapi.ai/models/wan; for API reference, use https://runapi.ai/docs#wan; for SDK docs, use https://runapi.ai/docs#sdk-wan.
19
+
20
+ ## Install
21
+
22
+ ```bash
23
+ pip install runapi-wan
24
+ ```
25
+
26
+ ## Quick start
27
+
28
+ ```python
29
+ from runapi.wan import WanClient
30
+
31
+ client = WanClient() # reads RUNAPI_API_KEY, or pass api_key="sk-..."
32
+
33
+ task = client.text_to_video.create(
34
+ model="wan-2.6-text-to-video",
35
+ prompt="A scenic mountain landscape with flowing rivers",
36
+ )
37
+ status = client.text_to_video.get(task.id)
38
+
39
+ image = client.text_to_image.create(
40
+ model="wan-2.7-image",
41
+ prompt="A neon city street after rain, cinematic",
42
+ )
43
+ ```
44
+
45
+ Use `create` to submit a task and return quickly, `get` to fetch the latest task state, and `run` when a script should create and poll until completion:
46
+
47
+ ```python
48
+ result = client.text_to_video.run(
49
+ model="wan-2.6-text-to-video",
50
+ prompt="A serene mountain lake at dawn",
51
+ )
52
+ print(result.videos[0].url)
53
+ ```
54
+
55
+ In web request handlers, prefer `create` plus webhook or later `get` polling so a worker is not held open.
56
+
57
+ RunAPI-generated file URLs are temporary. Download and store generated images, videos, audio, or other files in your own durable storage within 7 days; do not treat returned URLs as long-term assets.
58
+
59
+ ## Language notes
60
+
61
+ Pass parameters as keyword arguments and catch the `runapi.wan` error classes when building media jobs or scripts. The available resources are `text_to_video`, `image_to_video`, `speech_to_video`, `animate`, `text_to_image`, and `edit_video`. Keep `RUNAPI_API_KEY` in the environment or your secret manager; never commit API keys or callback secrets.
62
+
63
+ ## Links
64
+
65
+ - Model page: https://runapi.ai/models/wan
66
+ - SDK docs: https://runapi.ai/docs#sdk-wan
67
+ - Product docs: https://runapi.ai/docs#wan
68
+ - Pricing and rate limits: https://runapi.ai/models/wan/2.2-a14b-text-to-video-turbo
69
+ - Provider comparison: https://runapi.ai/providers/alibaba
70
+ - Full catalog: https://runapi.ai/models
71
+ - Repository: https://github.com/runapi-ai/wan-sdk
72
+
73
+ ## License
74
+
75
+ Licensed under the Apache License, Version 2.0.
@@ -0,0 +1,15 @@
1
+ runapi/wan/__init__.py,sha256=h2kV6KJhdVTTKUYl2cqVq4227GrwghKa-kNvd2tRP7w,451
2
+ runapi/wan/client.py,sha256=72FWLFQn0iWQvt8c0bseLKVFBnSuVOZu5jOS80WbfAc,1292
3
+ runapi/wan/contract_gen.py,sha256=qNshFaFmV-c5YJWw7_DWq1gwc2yTQWuBOctGhbbnrnI,9321
4
+ runapi/wan/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
+ runapi/wan/types.py,sha256=7m86S-3fW-t7DodxCBu4aXj2B9lU15JAbASLDuYPvsA,1074
6
+ runapi/wan/resources/__init__.py,sha256=M1Ky5-Uig0jjs0DLqnNwULXUwgBFHNgGSTVyEX5GFb4,351
7
+ runapi/wan/resources/animate.py,sha256=LGADYfg51R0pUaA4mc75_Tn1wwOfMRvWgGN_PB2DU8I,1578
8
+ runapi/wan/resources/edit_video.py,sha256=NSn8281aVCipVNeUqxrzI4CC4cS1aWua_R1CuRjpdMQ,1550
9
+ runapi/wan/resources/image_to_video.py,sha256=0sFv55O0l0--icq_ztFpjv57XkH0uAbalre1AIoObFg,1629
10
+ runapi/wan/resources/speech_to_video.py,sha256=1kOm5bMHOEnuiSODDrfKQQs0eDWmeJhmIO-pIQeA2NY,1640
11
+ runapi/wan/resources/text_to_image.py,sha256=qZGfi-j0IQQG8XOrfAHDwBolyXudrDbvTu_VidmgWKM,1716
12
+ runapi/wan/resources/text_to_video.py,sha256=QUWx-fNxYiNqXwiDpLQe83cikEqEJ2IX0Y1hXy6xidc,1715
13
+ runapi_wan-0.1.0.dist-info/METADATA,sha256=FUgApY2IPLr2A0uKzC4sq-8RtGnQibxOaWBByTJ_Wyw,3003
14
+ runapi_wan-0.1.0.dist-info/WHEEL,sha256=mffPy8wBnZQn2VnJUU5jE99KsxaSfiyMHV9Yt0aLVxs,87
15
+ runapi_wan-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.30.1
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any