runapi-wan 0.2.6 → 0.2.8

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: dbc05521adf750d4146cf35031cc55dad92fd762f83048f56cb5083e702e0d4f
4
- data.tar.gz: b717b95a9b712d242de851922717953f0b6ef8dd7a77b70ccce17c169343287e
3
+ metadata.gz: 3ac7d4f40ceba4493f0b3759807014b881b46d80993c6e0803f062b02e76365e
4
+ data.tar.gz: be804d111c08b94f2be6562370bb2be17d841ca671ffea88cf593e4717a85e76
5
5
  SHA512:
6
- metadata.gz: c4b5da04973ec6bde472f9ea0fd9cb746b749855a6292e69edeb0b08b303d8a7056d058a019e4de209d3a56f60091e756b9e6d566ffc68ae942273acf4063c55
7
- data.tar.gz: b94bac6024b1adb20f4c8500b1e0e14f15f09344bb55a81285cbca87d1cb8feef4c35c9e6653d1f58cd904a1662550b753732f166d7e54a47e0dc141b5d90e94
6
+ metadata.gz: 14b6dc707f14c258f3f286b9fbee0fcb43d73c0753511135d474e4b3bf3d2e3b25bfe5fdd9d9e876adc4b6e2716a6dc1b9aa1bdf0c2fda7d14ef44f42148b2dc
7
+ data.tar.gz: ad772becf04fa4abddb64c130bb9662eaeb574f828c9308c0ff5829d4a8517e886d13b60d29e4dce7acf35c44812b2466628d458ac9ee8e514e5a7c8259f3880
data/README.md CHANGED
@@ -1,8 +1,8 @@
1
- # Wan Video API Ruby SDK for RunAPI
1
+ # Wan API Ruby SDK for RunAPI
2
2
 
3
- The wan video api Ruby 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 Ruby.
3
+ The Wan Ruby SDK is the language-specific package for Wan on RunAPI. Use this package for video generation, animation, and video editing workflows when your application needs request bodies, task status lookup, and consistent RunAPI errors in Ruby.
4
4
 
5
- This wan video api README is the Ruby 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.
5
+ This README is the Ruby 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.
6
6
 
7
7
  ## Install
8
8
 
@@ -13,7 +13,7 @@ gem install runapi-wan
13
13
  ## Quick start
14
14
 
15
15
  ```ruby
16
- require "runapi-wan"
16
+ require "runapi/wan"
17
17
 
18
18
  client = RunApi::Wan::Client.new
19
19
  task = client.text_to_video.create(
@@ -24,9 +24,11 @@ status = client.text_to_video.get(task.id)
24
24
 
25
25
  Use `create` when you want to submit a task and return quickly, `get` when you need the latest task state, and `run` when a script should create and poll until completion. In web request handlers, prefer `create` plus webhook or later `get` polling so a worker is not held open.
26
26
 
27
+ 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.
28
+
27
29
  ## Language notes
28
30
 
29
- Use Ruby keyword arguments and the `RunApi::Wan` error classes when building video jobs, Rails workers, or scripts. The available resources include text to videos, image to videos, speech to videos, animations, images, and video edits. Keep `RUNAPI_API_KEY` in the environment or your secret manager; never commit API keys or callback secrets.
31
+ Use Ruby keyword arguments and the `RunApi::Wan` error classes when building video jobs, Rails workers, 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.
30
32
 
31
33
  ## Links
32
34
 
@@ -2,15 +2,33 @@
2
2
 
3
3
  module RunApi
4
4
  module Wan
5
- class Client
6
- attr_reader :text_to_video, :image_to_video,
7
- :speech_to_video, :animate, :text_to_image, :edit_video
5
+ # Wan video and image generation API client.
6
+ #
7
+ # Spans multiple generation families (2.2 through 2.7) with progressive
8
+ # capability upgrades. Feature availability varies by model variant.
9
+ #
10
+ # @example
11
+ # client = RunApi::Wan::Client.new(api_key: "your-api-key")
12
+ # result = client.text_to_video.run(
13
+ # model: "wan-2.6-text-to-video",
14
+ # prompt: "A scenic mountain landscape with flowing rivers"
15
+ # )
16
+ class Client < RunApi::Core::Client
17
+ # @return [Resources::TextToVideo] Generate videos from text prompts. Supports turbo (2.2) through 2.7 with progressive features.
18
+ attr_reader :text_to_video
19
+ # @return [Resources::ImageToVideo] Generate videos driven by a source image. Flash variants trade fidelity for speed.
20
+ attr_reader :image_to_video
21
+ # @return [Resources::SpeechToVideo] Generate lip-synced talking-head videos from a portrait image and speech audio.
22
+ attr_reader :speech_to_video
23
+ # @return [Resources::Animate] Transfer motion from a reference video onto a subject image (move or replace).
24
+ attr_reader :animate
25
+ # @return [Resources::TextToImage] Generate images with optional color palette, bounding box, and thinking mode.
26
+ attr_reader :text_to_image
27
+ # @return [Resources::EditVideo] Modify existing videos guided by text prompts and optional reference images.
28
+ attr_reader :edit_video
8
29
 
9
30
  def initialize(api_key: nil, **options)
10
- @api_key = Core::Auth.resolve_api_key(api_key)
11
-
12
- client_options = Core::ClientOptions.new(api_key: @api_key, **options)
13
- http = client_options.http_client || Core::HttpClient.new(client_options)
31
+ super
14
32
 
15
33
  @text_to_video = Resources::TextToVideo.new(http)
16
34
  @image_to_video = Resources::ImageToVideo.new(http)
@@ -0,0 +1,310 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RunApi
4
+ module Wan
5
+ CONTRACT = {
6
+ "animate" => {
7
+ "models" => ["wan-2.2-animate-move", "wan-2.2-animate-replace"],
8
+ "fields_by_model" => {
9
+ "wan-2.2-animate-move" => {
10
+ "output_resolution" => {
11
+ "enum" => ["480p", "580p", "720p"]
12
+ },
13
+ "reference_video_url" => {
14
+ "required" => true
15
+ },
16
+ "source_image_url" => {
17
+ "required" => true
18
+ }
19
+ },
20
+ "wan-2.2-animate-replace" => {
21
+ "output_resolution" => {
22
+ "enum" => ["480p", "580p", "720p"]
23
+ },
24
+ "reference_video_url" => {
25
+ "required" => true
26
+ },
27
+ "source_image_url" => {
28
+ "required" => true
29
+ }
30
+ }
31
+ }
32
+ },
33
+ "edit-video" => {
34
+ "models" => ["wan-2.6-edit-video", "wan-2.6-flash-edit-video", "wan-2.7-edit-video"],
35
+ "fields_by_model" => {
36
+ "wan-2.6-edit-video" => {
37
+ "duration_seconds" => {
38
+ "type" => "integer"
39
+ },
40
+ "output_resolution" => {
41
+ "enum" => ["720p", "1080p"]
42
+ },
43
+ "prompt" => {
44
+ "required" => true
45
+ },
46
+ "seed" => {
47
+ "type" => "integer"
48
+ },
49
+ "source_video_urls" => {
50
+ "required" => true
51
+ }
52
+ },
53
+ "wan-2.6-flash-edit-video" => {
54
+ "duration_seconds" => {
55
+ "type" => "integer"
56
+ },
57
+ "prompt" => {
58
+ "required" => true
59
+ },
60
+ "seed" => {
61
+ "type" => "integer"
62
+ },
63
+ "source_video_urls" => {
64
+ "required" => true
65
+ }
66
+ },
67
+ "wan-2.7-edit-video" => {
68
+ "aspect_ratio" => {
69
+ "enum" => ["16:9", "9:16", "1:1", "4:3", "3:4"]
70
+ },
71
+ "duration_seconds" => {
72
+ "type" => "integer"
73
+ },
74
+ "output_resolution" => {
75
+ "enum" => ["720p", "1080p"]
76
+ },
77
+ "seed" => {
78
+ "type" => "integer"
79
+ },
80
+ "source_video_url" => {
81
+ "required" => true
82
+ }
83
+ }
84
+ }
85
+ },
86
+ "image-to-video" => {
87
+ "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"],
88
+ "fields_by_model" => {
89
+ "wan-2.2-a14b-image-to-video-turbo" => {
90
+ "duration_seconds" => {
91
+ "type" => "integer"
92
+ },
93
+ "first_frame_image_url" => {
94
+ "required" => true
95
+ },
96
+ "output_resolution" => {
97
+ "enum" => ["480p", "720p"]
98
+ },
99
+ "seed" => {
100
+ "type" => "integer"
101
+ }
102
+ },
103
+ "wan-2.5-image-to-video" => {
104
+ "duration_seconds" => {
105
+ "required" => true,
106
+ "type" => "integer"
107
+ },
108
+ "first_frame_image_url" => {
109
+ "required" => true
110
+ },
111
+ "output_resolution" => {
112
+ "enum" => ["720p", "1080p"]
113
+ },
114
+ "seed" => {
115
+ "type" => "integer"
116
+ }
117
+ },
118
+ "wan-2.6-flash-image-to-video" => {
119
+ "audio" => {
120
+ "required" => true
121
+ },
122
+ "duration_seconds" => {
123
+ "type" => "integer"
124
+ },
125
+ "first_frame_image_url" => {
126
+ "required" => true
127
+ },
128
+ "output_resolution" => {
129
+ "enum" => ["720p", "1080p"]
130
+ },
131
+ "prompt" => {
132
+ "required" => true
133
+ }
134
+ },
135
+ "wan-2.6-image-to-video" => {
136
+ "duration_seconds" => {
137
+ "type" => "integer"
138
+ },
139
+ "first_frame_image_url" => {
140
+ "required" => true
141
+ },
142
+ "output_resolution" => {
143
+ "enum" => ["720p", "1080p"]
144
+ },
145
+ "prompt" => {
146
+ "required" => true
147
+ }
148
+ },
149
+ "wan-2.7-image-to-video" => {
150
+ "duration_seconds" => {
151
+ "type" => "integer"
152
+ },
153
+ "output_resolution" => {
154
+ "enum" => ["720p", "1080p"]
155
+ },
156
+ "prompt" => {
157
+ "required" => true
158
+ },
159
+ "seed" => {
160
+ "type" => "integer"
161
+ }
162
+ }
163
+ },
164
+ "rules" => [{
165
+ "when" => {
166
+ "model" => "wan-2.6-flash-image-to-video"
167
+ },
168
+ "forbidden" => ["seed"]
169
+ }, {
170
+ "when" => {
171
+ "model" => "wan-2.6-image-to-video"
172
+ },
173
+ "forbidden" => ["seed"]
174
+ }]
175
+ },
176
+ "speech-to-video" => {
177
+ "models" => ["wan-2.2-a14b-speech-to-video-turbo"],
178
+ "fields_by_model" => {
179
+ "wan-2.2-a14b-speech-to-video-turbo" => {
180
+ "frames_per_second" => {
181
+ "type" => "integer"
182
+ },
183
+ "num_frames" => {
184
+ "type" => "integer"
185
+ },
186
+ "num_inference_steps" => {
187
+ "type" => "integer"
188
+ },
189
+ "output_resolution" => {
190
+ "enum" => ["480p", "580p", "720p"]
191
+ },
192
+ "prompt" => {
193
+ "required" => true
194
+ },
195
+ "seed" => {
196
+ "type" => "integer"
197
+ },
198
+ "source_audio_url" => {
199
+ "required" => true
200
+ },
201
+ "source_image_url" => {
202
+ "required" => true
203
+ }
204
+ }
205
+ }
206
+ },
207
+ "text-to-image" => {
208
+ "models" => ["wan-2.7-image", "wan-2.7-image-pro"],
209
+ "fields_by_model" => {
210
+ "wan-2.7-image" => {
211
+ "aspect_ratio" => {
212
+ "enum" => ["1:1", "16:9", "4:3", "21:9", "3:4", "9:16", "8:1", "1:8"]
213
+ },
214
+ "output_count" => {
215
+ "type" => "integer"
216
+ },
217
+ "output_resolution" => {
218
+ "enum" => ["1k", "2k", "4k"]
219
+ },
220
+ "seed" => {
221
+ "type" => "integer"
222
+ }
223
+ },
224
+ "wan-2.7-image-pro" => {
225
+ "aspect_ratio" => {
226
+ "enum" => ["1:1", "16:9", "4:3", "21:9", "3:4", "9:16", "8:1", "1:8"]
227
+ },
228
+ "output_count" => {
229
+ "type" => "integer"
230
+ },
231
+ "output_resolution" => {
232
+ "enum" => ["1k", "2k", "4k"]
233
+ },
234
+ "seed" => {
235
+ "type" => "integer"
236
+ }
237
+ }
238
+ }
239
+ },
240
+ "text-to-video" => {
241
+ "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"],
242
+ "fields_by_model" => {
243
+ "wan-2.2-a14b-text-to-video-turbo" => {
244
+ "duration_seconds" => {
245
+ "type" => "integer"
246
+ },
247
+ "output_resolution" => {
248
+ "enum" => ["480p", "580p", "720p"]
249
+ },
250
+ "seed" => {
251
+ "type" => "integer"
252
+ }
253
+ },
254
+ "wan-2.5-text-to-video" => {
255
+ "duration_seconds" => {
256
+ "type" => "integer"
257
+ },
258
+ "output_resolution" => {
259
+ "enum" => ["720p", "1080p"]
260
+ },
261
+ "seed" => {
262
+ "type" => "integer"
263
+ }
264
+ },
265
+ "wan-2.6-text-to-video" => {
266
+ "duration_seconds" => {
267
+ "type" => "integer"
268
+ },
269
+ "output_resolution" => {
270
+ "enum" => ["720p", "1080p"]
271
+ }
272
+ },
273
+ "wan-2.7-r2v" => {
274
+ "aspect_ratio" => {
275
+ "enum" => ["16:9", "9:16", "1:1", "4:3", "3:4"]
276
+ },
277
+ "duration_seconds" => {
278
+ "min" => 2,
279
+ "max" => 10,
280
+ "type" => "integer"
281
+ },
282
+ "output_resolution" => {
283
+ "enum" => ["720p", "1080p"]
284
+ },
285
+ "seed" => {
286
+ "type" => "integer"
287
+ }
288
+ },
289
+ "wan-2.7-text-to-video" => {
290
+ "duration_seconds" => {
291
+ "type" => "integer"
292
+ },
293
+ "output_resolution" => {
294
+ "enum" => ["720p", "1080p"]
295
+ },
296
+ "seed" => {
297
+ "type" => "integer"
298
+ }
299
+ }
300
+ },
301
+ "rules" => [{
302
+ "when" => {
303
+ "model" => "wan-2.6-text-to-video"
304
+ },
305
+ "forbidden" => ["seed"]
306
+ }]
307
+ }
308
+ }.freeze
309
+ end
310
+ end
@@ -3,6 +3,9 @@
3
3
  module RunApi
4
4
  module Wan
5
5
  module Resources
6
+ # Transfers motion from a reference video onto a subject in the source image.
7
+ # Use wan-2.2-animate-move to preserve the subject and animate its motion,
8
+ # or wan-2.2-animate-replace to swap the subject with the reference video's subject.
6
9
  class Animate
7
10
  include RunApi::Core::ResourceHelpers
8
11
 
@@ -14,32 +17,37 @@ module RunApi
14
17
  @http = http
15
18
  end
16
19
 
17
- def run(**params)
18
- task = create(**params)
19
- poll_until_complete { get(task.id) }
20
+ # Transfer motion and wait until complete.
21
+ #
22
+ # @param params [Hash] animation parameters
23
+ # @return [RunApi::Wan::Types::CompletedVideoTaskResponse] completed animation result
24
+ def run(options: nil, **params)
25
+ task = create(options: options, **params)
26
+ poll_until_complete { get(task.id, options: options) }
20
27
  end
21
28
 
22
- def create(**params)
29
+ # Create an animation task.
30
+ #
31
+ # @param params [Hash] animation parameters
32
+ # @return [RunApi::Wan::Types::VideoTaskResponse] task creation result with id
33
+ def create(options: nil, **params)
23
34
  params = compact_params(params)
24
35
  validate_params!(params)
25
- request(:post, ENDPOINT, body: params)
36
+ request(:post, ENDPOINT, body: params, options: options)
26
37
  end
27
38
 
28
- def get(id)
29
- request(:get, "#{ENDPOINT}/#{id}")
39
+ # Get animation status by task ID.
40
+ #
41
+ # @param id [String] task ID
42
+ # @return [RunApi::Wan::Types::VideoTaskResponse] current task status
43
+ def get(id, options: nil)
44
+ request(:get, "#{ENDPOINT}/#{id}", options: options)
30
45
  end
31
46
 
32
47
  private
33
48
 
34
49
  def validate_params!(params)
35
- raise Core::ValidationError, "model is required" unless param(params, :model)
36
- raise Core::ValidationError, "source_image_url is required" unless param(params, :source_image_url)
37
- raise Core::ValidationError, "reference_video_url is required" unless param(params, :reference_video_url)
38
-
39
- model = param(params, :model)
40
- unless Types::ANIMATE_MODELS.include?(model)
41
- raise Core::ValidationError, "Invalid model: #{model}. Must be one of: #{Types::ANIMATE_MODELS.join(", ")}"
42
- end
50
+ validate_contract!(CONTRACT["animate"], params)
43
51
  end
44
52
  end
45
53
  end
@@ -3,6 +3,9 @@
3
3
  module RunApi
4
4
  module Wan
5
5
  module Resources
6
+ # Modifies existing videos guided by a text prompt and optional reference image.
7
+ # The 2.6 models use source_video_urls (plural, required) while 2.7 uses
8
+ # source_video_url (singular, required). Flash variants support audio and multi-shot.
6
9
  class EditVideo
7
10
  include RunApi::Core::ResourceHelpers
8
11
 
@@ -14,38 +17,37 @@ module RunApi
14
17
  @http = http
15
18
  end
16
19
 
17
- def run(**params)
18
- task = create(**params)
19
- poll_until_complete { get(task.id) }
20
+ # Edit a video and wait until complete.
21
+ #
22
+ # @param params [Hash] video editing parameters
23
+ # @return [RunApi::Wan::Types::CompletedVideoTaskResponse] completed video edit
24
+ def run(options: nil, **params)
25
+ task = create(options: options, **params)
26
+ poll_until_complete { get(task.id, options: options) }
20
27
  end
21
28
 
22
- def create(**params)
29
+ # Create a video editing task.
30
+ #
31
+ # @param params [Hash] video editing parameters
32
+ # @return [RunApi::Wan::Types::VideoTaskResponse] task creation result with id
33
+ def create(options: nil, **params)
23
34
  params = compact_params(params)
24
35
  validate_params!(params)
25
- request(:post, ENDPOINT, body: params)
36
+ request(:post, ENDPOINT, body: params, options: options)
26
37
  end
27
38
 
28
- def get(id)
29
- request(:get, "#{ENDPOINT}/#{id}")
39
+ # Get video editing status by task ID.
40
+ #
41
+ # @param id [String] task ID
42
+ # @return [RunApi::Wan::Types::VideoTaskResponse] current task status
43
+ def get(id, options: nil)
44
+ request(:get, "#{ENDPOINT}/#{id}", options: options)
30
45
  end
31
46
 
32
47
  private
33
48
 
34
49
  def validate_params!(params)
35
- raise Core::ValidationError, "model is required" unless param(params, :model)
36
-
37
- model = param(params, :model)
38
- unless Types::EDIT_VIDEO_MODELS.include?(model)
39
- raise Core::ValidationError, "Invalid model: #{model}. Must be one of: #{Types::EDIT_VIDEO_MODELS.join(", ")}"
40
- end
41
-
42
- if model.include?("2.6")
43
- raise Core::ValidationError, "prompt is required" unless param(params, :prompt)
44
- urls = param(params, :source_video_urls)
45
- raise Core::ValidationError, "source_video_urls is required" if urls.nil? || urls.empty?
46
- else
47
- raise Core::ValidationError, "source_video_url is required" unless param(params, :source_video_url)
48
- end
50
+ validate_contract!(CONTRACT["edit-video"], params)
49
51
  end
50
52
  end
51
53
  end
@@ -3,6 +3,8 @@
3
3
  module RunApi
4
4
  module Wan
5
5
  module Resources
6
+ # Generates videos driven by a source image. Flash variants trade fidelity
7
+ # for speed; 2.7 adds last-frame control, video continuation, and audio features.
6
8
  class ImageToVideo
7
9
  include RunApi::Core::ResourceHelpers
8
10
 
@@ -14,30 +16,37 @@ module RunApi
14
16
  @http = http
15
17
  end
16
18
 
17
- def run(**params)
18
- task = create(**params)
19
- poll_until_complete { get(task.id) }
19
+ # Generate a video from an image and wait until complete.
20
+ #
21
+ # @param params [Hash] image-to-video parameters
22
+ # @return [RunApi::Wan::Types::CompletedVideoTaskResponse] completed video generation
23
+ def run(options: nil, **params)
24
+ task = create(options: options, **params)
25
+ poll_until_complete { get(task.id, options: options) }
20
26
  end
21
27
 
22
- def create(**params)
28
+ # Create an image-to-video generation task.
29
+ #
30
+ # @param params [Hash] image-to-video parameters
31
+ # @return [RunApi::Wan::Types::VideoTaskResponse] task creation result with id
32
+ def create(options: nil, **params)
23
33
  params = compact_params(params)
24
34
  validate_params!(params)
25
- request(:post, ENDPOINT, body: params)
35
+ request(:post, ENDPOINT, body: params, options: options)
26
36
  end
27
37
 
28
- def get(id)
29
- request(:get, "#{ENDPOINT}/#{id}")
38
+ # Get image-to-video status by task ID.
39
+ #
40
+ # @param id [String] task ID
41
+ # @return [RunApi::Wan::Types::VideoTaskResponse] current task status
42
+ def get(id, options: nil)
43
+ request(:get, "#{ENDPOINT}/#{id}", options: options)
30
44
  end
31
45
 
32
46
  private
33
47
 
34
48
  def validate_params!(params)
35
- raise Core::ValidationError, "model is required" unless param(params, :model)
36
-
37
- model = param(params, :model)
38
- unless Types::IMAGE_TO_VIDEO_MODELS.include?(model)
39
- raise Core::ValidationError, "Invalid model: #{model}. Must be one of: #{Types::IMAGE_TO_VIDEO_MODELS.join(", ")}"
40
- end
49
+ validate_contract!(CONTRACT["image-to-video"], params)
41
50
  end
42
51
  end
43
52
  end
@@ -3,6 +3,8 @@
3
3
  module RunApi
4
4
  module Wan
5
5
  module Resources
6
+ # Generates lip-synced talking-head videos from a portrait image and
7
+ # driving speech audio. Both source_image_url and source_audio_url are required.
6
8
  class SpeechToVideo
7
9
  include RunApi::Core::ResourceHelpers
8
10
 
@@ -14,32 +16,37 @@ module RunApi
14
16
  @http = http
15
17
  end
16
18
 
17
- def run(**params)
18
- task = create(**params)
19
- poll_until_complete { get(task.id) }
19
+ # Generate a lip-synced video and wait until complete.
20
+ #
21
+ # @param params [Hash] speech-to-video parameters
22
+ # @return [RunApi::Wan::Types::CompletedVideoTaskResponse] completed video generation
23
+ def run(options: nil, **params)
24
+ task = create(options: options, **params)
25
+ poll_until_complete { get(task.id, options: options) }
20
26
  end
21
27
 
22
- def create(**params)
28
+ # Create a speech-to-video generation task.
29
+ #
30
+ # @param params [Hash] speech-to-video parameters
31
+ # @return [RunApi::Wan::Types::VideoTaskResponse] task creation result with id
32
+ def create(options: nil, **params)
23
33
  params = compact_params(params)
24
34
  validate_params!(params)
25
- request(:post, ENDPOINT, body: params)
35
+ request(:post, ENDPOINT, body: params, options: options)
26
36
  end
27
37
 
28
- def get(id)
29
- request(:get, "#{ENDPOINT}/#{id}")
38
+ # Get speech-to-video status by task ID.
39
+ #
40
+ # @param id [String] task ID
41
+ # @return [RunApi::Wan::Types::VideoTaskResponse] current task status
42
+ def get(id, options: nil)
43
+ request(:get, "#{ENDPOINT}/#{id}", options: options)
30
44
  end
31
45
 
32
46
  private
33
47
 
34
48
  def validate_params!(params)
35
- raise Core::ValidationError, "model is required" unless param(params, :model)
36
- raise Core::ValidationError, "source_image_url is required" unless param(params, :source_image_url)
37
- raise Core::ValidationError, "source_audio_url is required" unless param(params, :source_audio_url)
38
-
39
- model = param(params, :model)
40
- unless Types::SPEECH_TO_VIDEO_MODELS.include?(model)
41
- raise Core::ValidationError, "Invalid model: #{model}. Must be one of: #{Types::SPEECH_TO_VIDEO_MODELS.join(", ")}"
42
- end
49
+ validate_contract!(CONTRACT["speech-to-video"], params)
43
50
  end
44
51
  end
45
52
  end
@@ -3,6 +3,9 @@
3
3
  module RunApi
4
4
  module Wan
5
5
  module Resources
6
+ # Generates images from text prompts with optional color palette and bounding
7
+ # box constraints. Supports batch generation via output_count. Pro model
8
+ # supports thinking_mode for enhanced prompt reasoning.
6
9
  class TextToImage
7
10
  include RunApi::Core::ResourceHelpers
8
11
 
@@ -14,31 +17,38 @@ module RunApi
14
17
  @http = http
15
18
  end
16
19
 
17
- def run(**params)
18
- task = create(**params)
19
- poll_until_complete { get(task.id) }
20
+ # Generate an image and wait until complete.
21
+ #
22
+ # @param params [Hash] text-to-image parameters
23
+ # @return [RunApi::Wan::Types::CompletedImageTaskResponse] completed image generation
24
+ def run(options: nil, **params)
25
+ task = create(options: options, **params)
26
+ poll_until_complete { get(task.id, options: options) }
20
27
  end
21
28
 
22
- def create(**params)
29
+ # Create a text-to-image generation task.
30
+ #
31
+ # @param params [Hash] text-to-image parameters
32
+ # @return [RunApi::Wan::Types::ImageTaskResponse] task creation result with id
33
+ def create(options: nil, **params)
23
34
  params = compact_params(params)
24
35
  validate_params!(params)
25
- request(:post, ENDPOINT, body: params)
36
+ request(:post, ENDPOINT, body: params, options: options)
26
37
  end
27
38
 
28
- def get(id)
29
- request(:get, "#{ENDPOINT}/#{id}")
39
+ # Get text-to-image status by task ID.
40
+ #
41
+ # @param id [String] task ID
42
+ # @return [RunApi::Wan::Types::ImageTaskResponse] current task status
43
+ def get(id, options: nil)
44
+ request(:get, "#{ENDPOINT}/#{id}", options: options)
30
45
  end
31
46
 
32
47
  private
33
48
 
34
49
  def validate_params!(params)
35
- raise Core::ValidationError, "model is required" unless param(params, :model)
50
+ validate_contract!(CONTRACT["text-to-image"], params)
36
51
  raise Core::ValidationError, "prompt is required" unless param(params, :prompt)
37
-
38
- model = param(params, :model)
39
- unless Types::TEXT_TO_IMAGE_MODELS.include?(model)
40
- raise Core::ValidationError, "Invalid model: #{model}. Must be one of: #{Types::TEXT_TO_IMAGE_MODELS.join(", ")}"
41
- end
42
52
  end
43
53
  end
44
54
  end
@@ -3,6 +3,9 @@
3
3
  module RunApi
4
4
  module Wan
5
5
  module Resources
6
+ # Generates videos from text prompts. Supports turbo (2.2) through 2.7
7
+ # with progressive feature upgrades including negative prompts, watermark
8
+ # control, background audio, and R2V multi-reference inputs.
6
9
  class TextToVideo
7
10
  include RunApi::Core::ResourceHelpers
8
11
 
@@ -14,31 +17,38 @@ module RunApi
14
17
  @http = http
15
18
  end
16
19
 
17
- def run(**params)
18
- task = create(**params)
19
- poll_until_complete { get(task.id) }
20
+ # Generate a video and wait until complete.
21
+ #
22
+ # @param params [Hash] text-to-video parameters
23
+ # @return [RunApi::Wan::Types::CompletedVideoTaskResponse] completed video generation
24
+ def run(options: nil, **params)
25
+ task = create(options: options, **params)
26
+ poll_until_complete { get(task.id, options: options) }
20
27
  end
21
28
 
22
- def create(**params)
29
+ # Create a text-to-video generation task.
30
+ #
31
+ # @param params [Hash] text-to-video parameters
32
+ # @return [RunApi::Wan::Types::VideoTaskResponse] task creation result with id
33
+ def create(options: nil, **params)
23
34
  params = compact_params(params)
24
35
  validate_params!(params)
25
- request(:post, ENDPOINT, body: params)
36
+ request(:post, ENDPOINT, body: params, options: options)
26
37
  end
27
38
 
28
- def get(id)
29
- request(:get, "#{ENDPOINT}/#{id}")
39
+ # Get text-to-video status by task ID.
40
+ #
41
+ # @param id [String] task ID
42
+ # @return [RunApi::Wan::Types::VideoTaskResponse] current task status
43
+ def get(id, options: nil)
44
+ request(:get, "#{ENDPOINT}/#{id}", options: options)
30
45
  end
31
46
 
32
47
  private
33
48
 
34
49
  def validate_params!(params)
35
- raise Core::ValidationError, "model is required" unless param(params, :model)
50
+ validate_contract!(CONTRACT["text-to-video"], params)
36
51
  raise Core::ValidationError, "prompt is required" unless param(params, :prompt)
37
-
38
- model = param(params, :model)
39
- unless Types::TEXT_TO_VIDEO_MODELS.include?(model)
40
- raise Core::ValidationError, "Invalid model: #{model}. Must be one of: #{Types::TEXT_TO_VIDEO_MODELS.join(", ")}"
41
- end
42
52
  end
43
53
  end
44
54
  end
@@ -3,39 +3,17 @@
3
3
  module RunApi
4
4
  module Wan
5
5
  module Types
6
- TEXT_TO_VIDEO_MODELS = %w[
7
- wan-2.2-a14b-text-to-video-turbo
8
- wan-2.5-text-to-video
9
- wan-2.6-text-to-video
10
- wan-2.7-text-to-video
11
- wan-2.7-r2v
12
- ].freeze
13
-
14
- IMAGE_TO_VIDEO_MODELS = %w[
15
- wan-2.2-a14b-image-to-video-turbo
16
- wan-2.5-image-to-video
17
- wan-2.6-image-to-video
18
- wan-2.6-flash-image-to-video
19
- wan-2.7-image-to-video
20
- ].freeze
21
-
22
- SPEECH_TO_VIDEO_MODELS = %w[wan-2.2-a14b-speech-to-video-turbo].freeze
23
- ANIMATE_MODELS = %w[wan-2.2-animate-move wan-2.2-animate-replace].freeze
24
- TEXT_TO_IMAGE_MODELS = %w[wan-2.7-image wan-2.7-image-pro].freeze
25
- EDIT_VIDEO_MODELS = %w[
26
- wan-2.6-edit-video
27
- wan-2.6-flash-edit-video
28
- wan-2.7-edit-video
29
- ].freeze
30
-
6
+ # A single generated video result.
31
7
  class Video < RunApi::Core::BaseModel
32
8
  optional :url, String
33
9
  end
34
10
 
11
+ # A single generated image result.
35
12
  class Image < RunApi::Core::BaseModel
36
13
  optional :url, String
37
14
  end
38
15
 
16
+ # Task result for video generation and editing operations.
39
17
  class VideoTaskResponse < RunApi::Core::TaskResponse
40
18
  required :id, String
41
19
  optional :status, String, enum: -> { RunApi::Core::TaskResponse::Status::ALL }
@@ -43,6 +21,7 @@ module RunApi
43
21
  optional :error, String
44
22
  end
45
23
 
24
+ # Task result for text-to-image operations.
46
25
  class ImageTaskResponse < RunApi::Core::TaskResponse
47
26
  required :id, String
48
27
  optional :status, String, enum: -> { RunApi::Core::TaskResponse::Status::ALL }
data/lib/runapi/wan.rb CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  require "runapi/core"
4
4
  require_relative "wan/types"
5
+ require_relative "wan/contract_gen"
5
6
  require_relative "wan/resources/text_to_video"
6
7
  require_relative "wan/resources/image_to_video"
7
8
  require_relative "wan/resources/speech_to_video"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: runapi-wan
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.6
4
+ version: 0.2.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - RunAPI
@@ -15,18 +15,18 @@ dependencies:
15
15
  requirements:
16
16
  - - "~>"
17
17
  - !ruby/object:Gem::Version
18
- version: 0.2.5
18
+ version: 0.2.13
19
19
  type: :runtime
20
20
  prerelease: false
21
21
  version_requirements: !ruby/object:Gem::Requirement
22
22
  requirements:
23
23
  - - "~>"
24
24
  - !ruby/object:Gem::Version
25
- version: 0.2.5
26
- description: The wan video api Ruby SDK is the language-specific package for Wan on
27
- RunAPI. Use this wan video api package for text-to-video, image-to-video, animation,
28
- and video editing flows when your application needs JSON request bodies, task status
29
- lookup, and consistent RunAPI errors in Ruby.
25
+ version: 0.2.13
26
+ description: The Wan Ruby SDK is the language-specific package for Wan on RunAPI.
27
+ Use this package for video generation, animation, and video editing workflows when
28
+ your application needs request bodies, task status lookup, and consistent RunAPI
29
+ errors in Ruby.
30
30
  email:
31
31
  - contact@runapi.ai
32
32
  executables: []
@@ -38,6 +38,7 @@ files:
38
38
  - README.md
39
39
  - lib/runapi/wan.rb
40
40
  - lib/runapi/wan/client.rb
41
+ - lib/runapi/wan/contract_gen.rb
41
42
  - lib/runapi/wan/resources/animate.rb
42
43
  - lib/runapi/wan/resources/edit_video.rb
43
44
  - lib/runapi/wan/resources/image_to_video.rb
@@ -49,9 +50,11 @@ homepage: https://runapi.ai/models/wan
49
50
  licenses:
50
51
  - Apache-2.0
51
52
  metadata:
53
+ runapi_slug: wan
52
54
  homepage_uri: https://runapi.ai/models/wan
53
55
  documentation_uri: https://github.com/runapi-ai/wan-sdk/blob/main/ruby/README.md
54
56
  source_code_uri: https://github.com/runapi-ai/wan-sdk
57
+ bug_tracker_uri: https://github.com/runapi-ai/wan-sdk/issues
55
58
  changelog_uri: https://github.com/runapi-ai/wan-sdk/blob/main/CHANGELOG.md
56
59
  rdoc_options: []
57
60
  require_paths:
@@ -69,5 +72,5 @@ required_rubygems_version: !ruby/object:Gem::Requirement
69
72
  requirements: []
70
73
  rubygems_version: 4.0.10
71
74
  specification_version: 4
72
- summary: Wan Video API Ruby SDK for RunAPI
75
+ summary: Wan API Ruby SDK for RunAPI
73
76
  test_files: []