runapi-kling 0.4.0 → 0.5.0

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: 2a748b5cc9170e92d4df37d437bf1a710be9cf5365fad3feff5ff6e33864b431
4
- data.tar.gz: 13111124fda673639366a861a8cc462f33b87d109290e0f9a72c6c83d51a136c
3
+ metadata.gz: bf93e2f75b6755cae286b37459790683c4811e5d3a2e64fd0e76a2918c9811c5
4
+ data.tar.gz: 538697ef0ab20941aaad011b8fc76c453c40df530a94c5aae39f983d023808fb
5
5
  SHA512:
6
- metadata.gz: 4eab84e87121ff70aba5816b318f13da73191e25c1098fc0d03ad51bbe59646c08681fb694734d813a9110ecd71ed914cb454ab1fe2882e07e152981ed5688ba
7
- data.tar.gz: 9c6ead94e0d1918904c6b2bd0aa5f75dfa37ccea1839a944c560f2ca50a63cb69b12ef8489f9af51587b6770d0f60635a6c86fc9e7e9ac988e43d4be5a6ca141
6
+ metadata.gz: d967b14bff9d5bd99b05880d763efa3b0a2e19f2484b5bbc0f808747ecb1d055b6847f84f6a5c8c31b4419ac790b97baf4b4e7cb82acd6c2953e5ce80cf47813
7
+ data.tar.gz: 65cf7d9b4300bbbee92b5ea670509b59c27499bdf9042d72e1a338206025eaccd5735a40a60300dec2ab784fb6721aa9aff0e9937688e0247f622191343b9489
@@ -32,7 +32,6 @@ module RunApi
32
32
  # @return [RunApi::Kling::Types::AiAvatarResponse] task creation result with id
33
33
  def create(options: nil, **params)
34
34
  params = compact_params(params)
35
- validate_params!(params)
36
35
  request(:post, ENDPOINT, body: params, options: options)
37
36
  end
38
37
 
@@ -43,12 +42,6 @@ module RunApi
43
42
  def get(id, options: nil)
44
43
  request(:get, "#{ENDPOINT}/#{id}", options: options)
45
44
  end
46
-
47
- private
48
-
49
- def validate_params!(params)
50
- validate_contract!(CONTRACT["avatar"], params)
51
- end
52
45
  end
53
46
  end
54
47
  end
@@ -22,7 +22,6 @@ module RunApi
22
22
 
23
23
  def create(options: nil, **params)
24
24
  params = compact_params(params)
25
- validate_contract!(CONTRACT["edit-video"], params)
26
25
  request(:post, ENDPOINT, body: params, options: options)
27
26
  end
28
27
 
@@ -20,7 +20,6 @@ module RunApi
20
20
 
21
21
  def create(options: nil, **params)
22
22
  params = compact_params(params)
23
- validate_contract!(CONTRACT["extend-video"], params)
24
23
  request(:post, ENDPOINT, body: params, options: options)
25
24
  end
26
25
 
@@ -7,7 +7,6 @@ module RunApi
7
7
  # Generate videos from an input image.
8
8
  class ImageToVideo
9
9
  include RunApi::Core::ResourceHelpers
10
- include O1ReferenceValidation
11
10
 
12
11
  ENDPOINT = "/api/v1/kling/image_to_video"
13
12
 
@@ -16,12 +15,6 @@ module RunApi
16
15
  V26_MODEL = "kling-v2.6"
17
16
  V3_OMNI_MODEL = "kling-v3-omni"
18
17
  V3_TURBO_MODEL = "kling-v3-turbo-image-to-video"
19
- V3_TURBO_UNSUPPORTED_FIELDS = %i[
20
- aspect_ratio
21
- negative_prompt
22
- cfg_scale
23
- last_frame_image_url
24
- ].freeze
25
18
 
26
19
  def initialize(http)
27
20
  @http = http
@@ -42,7 +35,6 @@ module RunApi
42
35
  # @return [RunApi::Kling::Types::ImageToVideoResponse] task creation result with id
43
36
  def create(options: nil, **params)
44
37
  params = compact_params(params)
45
- validate_params!(params)
46
38
  request(:post, ENDPOINT, body: params, options: options)
47
39
  end
48
40
 
@@ -53,48 +45,6 @@ module RunApi
53
45
  def get(id, options: nil)
54
46
  request(:get, "#{ENDPOINT}/#{id}", options: options)
55
47
  end
56
-
57
- private
58
-
59
- def validate_params!(params)
60
- reject_unsupported_v3_turbo_fields!(params)
61
- validate_contract!(CONTRACT["image-to-video"], params)
62
- validate_kling_o1_references!(params)
63
-
64
- # Bespoke last-frame rules that the generated contract cannot express.
65
- model = param(params, :model)
66
- last_frame_image_url = param(params, :last_frame_image_url)
67
- if model == V26_MODEL
68
- validate_v26_params!(params, last_frame_image_url)
69
- elsif last_frame_image_url && model == V3_OMNI_MODEL
70
- duration_seconds = param(params, :duration_seconds) || 5
71
- return if duration_seconds.to_i == 5
72
-
73
- raise Core::ValidationError, "last_frame_image_url requires duration_seconds 5 for #{V3_OMNI_MODEL}"
74
- elsif last_frame_image_url && !%w[kling-o1 kling-v2.5-turbo-image-to-video-pro kling-v2.1-pro].include?(model)
75
- raise Core::ValidationError, "last_frame_image_url is only supported by kling-v2.5-turbo-image-to-video-pro and kling-v2.1-pro"
76
- end
77
- end
78
-
79
- def validate_v26_params!(params, last_frame_image_url)
80
- return unless last_frame_image_url
81
-
82
- mode = param(params, :mode) || "std"
83
-
84
- raise Core::ValidationError, "last_frame_image_url requires mode pro for #{V26_MODEL}" unless mode == "pro"
85
-
86
- duration_seconds = param(params, :duration_seconds) || 5
87
- return if duration_seconds.to_i == 5
88
-
89
- raise Core::ValidationError, "last_frame_image_url requires duration_seconds 5 for #{V26_MODEL}"
90
- end
91
-
92
- def reject_unsupported_v3_turbo_fields!(params)
93
- return unless param(params, :model) == V3_TURBO_MODEL
94
-
95
- field = V3_TURBO_UNSUPPORTED_FIELDS.find { |candidate| field_present?(params, candidate) }
96
- raise Core::ValidationError, "#{field} is not supported by #{V3_TURBO_MODEL}" if field
97
- end
98
48
  end
99
49
  end
100
50
  end
@@ -32,7 +32,6 @@ module RunApi
32
32
  # @return [RunApi::Kling::Types::MotionControlResponse] task creation result with id
33
33
  def create(options: nil, **params)
34
34
  params = compact_params(params)
35
- validate_params!(params)
36
35
  request(:post, ENDPOINT, body: params, options: options)
37
36
  end
38
37
 
@@ -43,12 +42,6 @@ module RunApi
43
42
  def get(id, options: nil)
44
43
  request(:get, "#{ENDPOINT}/#{id}", options: options)
45
44
  end
46
-
47
- private
48
-
49
- def validate_params!(params)
50
- validate_contract!(CONTRACT["motion-control"], params)
51
- end
52
45
  end
53
46
  end
54
47
  end
@@ -7,23 +7,12 @@ module RunApi
7
7
  # Generate videos from text prompts.
8
8
  class TextToVideo
9
9
  include RunApi::Core::ResourceHelpers
10
- include O1ReferenceValidation
11
10
 
12
11
  ENDPOINT = "/api/v1/kling/text_to_video"
13
12
 
14
13
  RESPONSE_CLASS = Types::TextToVideoResponse
15
14
  COMPLETED_RESPONSE_CLASS = Types::CompletedTextToVideoResponse
16
15
  V3_TURBO_MODEL = "kling-v3-turbo-text-to-video"
17
- V3_TURBO_UNSUPPORTED_FIELDS = %i[
18
- enable_sound
19
- negative_prompt
20
- cfg_scale
21
- multi_shots
22
- multi_prompt
23
- first_frame_image_url
24
- last_frame_image_url
25
- kling_elements
26
- ].freeze
27
16
 
28
17
  def initialize(http)
29
18
  @http = http
@@ -44,7 +33,6 @@ module RunApi
44
33
  # @return [RunApi::Kling::Types::TextToVideoResponse] task creation result with id
45
34
  def create(options: nil, **params)
46
35
  params = compact_params(params)
47
- validate_params!(params)
48
36
  request(:post, ENDPOINT, body: params, options: options)
49
37
  end
50
38
 
@@ -55,58 +43,6 @@ module RunApi
55
43
  def get(id, options: nil)
56
44
  request(:get, "#{ENDPOINT}/#{id}", options: options)
57
45
  end
58
-
59
- private
60
-
61
- def validate_params!(params)
62
- reject_unsupported_v3_turbo_fields!(params)
63
- validate_contract!(CONTRACT["text-to-video"], params)
64
- validate_kling_o1_references!(params)
65
-
66
- # Bespoke cross-field rules the contract cannot express.
67
- multi_shots = param(params, :multi_shots) == true
68
-
69
- if multi_shots
70
- raise Core::ValidationError, "enable_sound must be true when multi_shots is true" unless param(params, :enable_sound) == true
71
- raise Core::ValidationError, "last_frame_image_url is not supported when multi_shots is true" if param(params, :last_frame_image_url)
72
-
73
- multi_prompt = param(params, :multi_prompt)
74
- validate_multi_prompt!(multi_prompt)
75
- else
76
- raise Core::ValidationError, "prompt is required" unless param(params, :prompt)
77
- end
78
- end
79
-
80
- def reject_unsupported_v3_turbo_fields!(params)
81
- return unless param(params, :model) == V3_TURBO_MODEL
82
-
83
- field = V3_TURBO_UNSUPPORTED_FIELDS.find { |candidate| field_present?(params, candidate) }
84
- raise Core::ValidationError, "#{field} is not supported by #{V3_TURBO_MODEL}" if field
85
- end
86
-
87
- def validate_multi_prompt!(multi_prompt)
88
- unless multi_prompt.is_a?(Array) && multi_prompt.any?
89
- raise Core::ValidationError, "multi_prompt must be a non-empty array when multi_shots is true"
90
- end
91
-
92
- multi_prompt.each_with_index do |shot, index|
93
- prompt = shot.is_a?(Hash) ? (shot[:prompt] || shot["prompt"]) : nil
94
- duration_seconds = shot.is_a?(Hash) ? (shot[:duration_seconds] || shot["duration_seconds"]) : nil
95
-
96
- raise Core::ValidationError, "multi_prompt[#{index}].prompt is required" if prompt.nil? || prompt.empty?
97
-
98
- if prompt.length > Types::MULTI_PROMPT_MAX_LENGTH
99
- raise Core::ValidationError, "multi_prompt[#{index}].prompt exceeds #{Types::MULTI_PROMPT_MAX_LENGTH} characters"
100
- end
101
-
102
- raise Core::ValidationError, "multi_prompt[#{index}].duration_seconds is required" if duration_seconds.nil?
103
-
104
- dur_int = duration_seconds.to_i
105
- unless Types::MULTI_PROMPT_DURATION_RANGE.cover?(dur_int)
106
- raise Core::ValidationError, "multi_prompt[#{index}].duration_seconds must be between #{Types::MULTI_PROMPT_DURATION_RANGE.min} and #{Types::MULTI_PROMPT_DURATION_RANGE.max}"
107
- end
108
- end
109
- end
110
46
  end
111
47
  end
112
48
  end
@@ -2,15 +2,8 @@
2
2
 
3
3
  module RunApi
4
4
  module Kling
5
- # Type definitions and constants for Kling video generation.
5
+ # Type definitions for Kling video generation.
6
6
  module Types
7
- # Per-shot duration range in multi-shot mode (seconds). Bespoke constant for
8
- # the multi_prompt[] nested-array validation, which the contract cannot express.
9
- MULTI_PROMPT_DURATION_RANGE = (1..12)
10
-
11
- # Maximum character length for each multi-shot prompt segment.
12
- MULTI_PROMPT_MAX_LENGTH = 500
13
-
14
7
  # A generated video file with a download URL.
15
8
  class Video < RunApi::Core::BaseModel
16
9
  optional :url, String
data/lib/runapi/kling.rb CHANGED
@@ -2,8 +2,6 @@
2
2
 
3
3
  require "runapi/core"
4
4
  require_relative "kling/types"
5
- require_relative "kling/contract_gen"
6
- require_relative "kling/resources/o1_reference_validation"
7
5
  require_relative "kling/resources/text_to_video"
8
6
  require_relative "kling/resources/ai_avatar"
9
7
  require_relative "kling/resources/image_to_video"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: runapi-kling
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - RunAPI
@@ -15,14 +15,14 @@ dependencies:
15
15
  requirements:
16
16
  - - "~>"
17
17
  - !ruby/object:Gem::Version
18
- version: 0.5.2
18
+ version: 0.6.0
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.5.2
25
+ version: 0.6.0
26
26
  description: The Kling Ruby SDK is the language-specific package for Kling on RunAPI.
27
27
  Use this package for video generation, animation, and video editing workflows when
28
28
  your application needs request bodies, task status lookup, and consistent RunAPI
@@ -39,13 +39,11 @@ files:
39
39
  - lib/runapi-kling.rb
40
40
  - lib/runapi/kling.rb
41
41
  - lib/runapi/kling/client.rb
42
- - lib/runapi/kling/contract_gen.rb
43
42
  - lib/runapi/kling/resources/ai_avatar.rb
44
43
  - lib/runapi/kling/resources/edit_video.rb
45
44
  - lib/runapi/kling/resources/extend_video.rb
46
45
  - lib/runapi/kling/resources/image_to_video.rb
47
46
  - lib/runapi/kling/resources/motion_control.rb
48
- - lib/runapi/kling/resources/o1_reference_validation.rb
49
47
  - lib/runapi/kling/resources/text_to_video.rb
50
48
  - lib/runapi/kling/types.rb
51
49
  homepage: https://runapi.ai/models/kling
@@ -1,815 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module RunApi
4
- module Kling
5
- CONTRACT = {
6
- "avatar" => {
7
- "models" => ["kling-ai-avatar-pro", "kling-ai-avatar-standard", "kling-ai-avatar-v1-pro", "kling-v1-avatar-standard"],
8
- "fields_by_model" => {
9
- "kling-ai-avatar-pro" => {
10
- "model" => {
11
- "required" => true
12
- },
13
- "prompt" => {
14
- "required" => true
15
- },
16
- "source_audio_url" => {
17
- "required" => true
18
- },
19
- "source_image_url" => {
20
- "required" => true
21
- }
22
- },
23
- "kling-ai-avatar-standard" => {
24
- "model" => {
25
- "required" => true
26
- },
27
- "prompt" => {
28
- "required" => true
29
- },
30
- "source_audio_url" => {
31
- "required" => true
32
- },
33
- "source_image_url" => {
34
- "required" => true
35
- }
36
- },
37
- "kling-ai-avatar-v1-pro" => {
38
- "model" => {
39
- "required" => true
40
- },
41
- "prompt" => {
42
- "required" => true
43
- },
44
- "source_audio_url" => {
45
- "required" => true
46
- },
47
- "source_image_url" => {
48
- "required" => true
49
- }
50
- },
51
- "kling-v1-avatar-standard" => {
52
- "model" => {
53
- "required" => true
54
- },
55
- "prompt" => {
56
- "required" => true
57
- },
58
- "source_audio_url" => {
59
- "required" => true
60
- },
61
- "source_image_url" => {
62
- "required" => true
63
- }
64
- }
65
- }
66
- },
67
- "edit-video" => {
68
- "models" => ["kling-v3-omni-edit", "kling-v3-omni-reference"],
69
- "fields_by_model" => {
70
- "kling-v3-omni-edit" => {
71
- "aspect_ratio" => {
72
- "enum" => ["auto", "16:9", "9:16", "1:1"]
73
- },
74
- "duration_seconds" => {
75
- "enum" => [3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
76
- "type" => "integer"
77
- },
78
- "model" => {
79
- "required" => true
80
- },
81
- "output_resolution" => {
82
- "enum" => ["720p", "1080p", "4k"]
83
- },
84
- "prompt" => {
85
- "required" => true,
86
- "min" => 1,
87
- "max" => 2500,
88
- "length" => true
89
- },
90
- "reference_image_urls" => {
91
- "min_items" => 1,
92
- "max_items" => 4
93
- }
94
- },
95
- "kling-v3-omni-reference" => {
96
- "aspect_ratio" => {
97
- "enum" => ["auto", "16:9", "9:16", "1:1"]
98
- },
99
- "duration_seconds" => {
100
- "enum" => [3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
101
- "type" => "integer"
102
- },
103
- "model" => {
104
- "required" => true
105
- },
106
- "output_resolution" => {
107
- "enum" => ["720p", "1080p", "4k"]
108
- },
109
- "prompt" => {
110
- "required" => true,
111
- "min" => 1,
112
- "max" => 2500,
113
- "length" => true
114
- },
115
- "reference_image_urls" => {
116
- "min_items" => 1,
117
- "max_items" => 4
118
- }
119
- }
120
- },
121
- "rules" => [{
122
- "when" => {
123
- "model" => "kling-v3-omni-edit",
124
- "source_video_url" => {
125
- "present" => true
126
- }
127
- },
128
- "forbidden" => ["source_task_id"]
129
- }, {
130
- "when" => {
131
- "model" => "kling-v3-omni-edit",
132
- "source_task_id" => {
133
- "present" => true
134
- }
135
- },
136
- "forbidden" => ["source_video_url"]
137
- }, {
138
- "enum" => {
139
- "aspect_ratio" => ["auto"],
140
- "duration_seconds" => [5]
141
- },
142
- "when" => {
143
- "model" => "kling-v3-omni-edit",
144
- "source_video_url" => {
145
- "present" => true
146
- },
147
- "reference_image_urls" => {
148
- "present" => false
149
- }
150
- },
151
- "required" => ["aspect_ratio"]
152
- }, {
153
- "enum" => {
154
- "aspect_ratio" => ["auto"],
155
- "duration_seconds" => [5]
156
- },
157
- "when" => {
158
- "model" => "kling-v3-omni-edit",
159
- "source_task_id" => {
160
- "present" => true
161
- },
162
- "reference_image_urls" => {
163
- "present" => false
164
- }
165
- },
166
- "required" => ["aspect_ratio"]
167
- }, {
168
- "enum" => {
169
- "aspect_ratio" => ["16:9", "9:16", "1:1"]
170
- },
171
- "when" => {
172
- "model" => "kling-v3-omni-edit",
173
- "source_video_url" => {
174
- "present" => true
175
- },
176
- "reference_image_urls" => {
177
- "present" => true
178
- }
179
- },
180
- "required" => ["aspect_ratio"]
181
- }, {
182
- "enum" => {
183
- "aspect_ratio" => ["16:9", "9:16", "1:1"]
184
- },
185
- "when" => {
186
- "model" => "kling-v3-omni-edit",
187
- "source_task_id" => {
188
- "present" => true
189
- },
190
- "reference_image_urls" => {
191
- "present" => true
192
- }
193
- },
194
- "required" => ["aspect_ratio"]
195
- }, {
196
- "when" => {
197
- "model" => "kling-v3-omni-edit",
198
- "source_task_id" => {
199
- "present" => false
200
- },
201
- "source_video_url" => {
202
- "present" => false
203
- }
204
- },
205
- "required_any" => ["source_video_url", "source_task_id"]
206
- }, {
207
- "enum" => {
208
- "aspect_ratio" => ["16:9", "9:16", "1:1"],
209
- "enable_sound" => [false]
210
- },
211
- "when" => {
212
- "model" => "kling-v3-omni-reference",
213
- "source_task_id" => {
214
- "present" => true
215
- },
216
- "reference_image_urls" => {
217
- "present" => true
218
- }
219
- },
220
- "required" => ["aspect_ratio"]
221
- }, {
222
- "when" => {
223
- "model" => "kling-v3-omni-reference",
224
- "source_task_id" => {
225
- "present" => false
226
- },
227
- "source_video_url" => {
228
- "present" => false
229
- }
230
- },
231
- "required_any" => ["source_video_url", "source_task_id"]
232
- }, {
233
- "when" => {
234
- "model" => "kling-v3-omni-reference",
235
- "source_video_url" => {
236
- "present" => true
237
- }
238
- },
239
- "forbidden" => ["source_task_id"]
240
- }, {
241
- "when" => {
242
- "model" => "kling-v3-omni-reference",
243
- "source_task_id" => {
244
- "present" => true
245
- }
246
- },
247
- "forbidden" => ["source_video_url"]
248
- }, {
249
- "enum" => {
250
- "aspect_ratio" => ["auto"],
251
- "enable_sound" => [false],
252
- "duration_seconds" => [5]
253
- },
254
- "when" => {
255
- "model" => "kling-v3-omni-reference",
256
- "source_video_url" => {
257
- "present" => true
258
- },
259
- "reference_image_urls" => {
260
- "present" => false
261
- }
262
- },
263
- "required" => ["aspect_ratio"]
264
- }, {
265
- "enum" => {
266
- "aspect_ratio" => ["auto"],
267
- "enable_sound" => [false],
268
- "duration_seconds" => [5]
269
- },
270
- "when" => {
271
- "model" => "kling-v3-omni-reference",
272
- "source_task_id" => {
273
- "present" => true
274
- },
275
- "reference_image_urls" => {
276
- "present" => false
277
- }
278
- },
279
- "required" => ["aspect_ratio"]
280
- }, {
281
- "enum" => {
282
- "aspect_ratio" => ["16:9", "9:16", "1:1"],
283
- "enable_sound" => [false]
284
- },
285
- "when" => {
286
- "model" => "kling-v3-omni-reference",
287
- "source_video_url" => {
288
- "present" => true
289
- },
290
- "reference_image_urls" => {
291
- "present" => true
292
- }
293
- },
294
- "required" => ["aspect_ratio"]
295
- }]
296
- },
297
- "extend-video" => {
298
- "models" => ["kling-v2.5-turbo-image-to-video-pro", "kling-v2.5-turbo-text-to-video-pro"],
299
- "fields_by_model" => {
300
- "kling-v2.5-turbo-image-to-video-pro" => {
301
- "mode" => {
302
- "enum" => ["std", "pro"]
303
- },
304
- "source_task_id" => {
305
- "required" => true
306
- }
307
- },
308
- "kling-v2.5-turbo-text-to-video-pro" => {
309
- "mode" => {
310
- "enum" => ["std", "pro"]
311
- },
312
- "source_task_id" => {
313
- "required" => true
314
- }
315
- }
316
- }
317
- },
318
- "image-to-video" => {
319
- "models" => ["kling-o1", "kling-v2.1-master-image-to-video", "kling-v2.1-pro", "kling-v2.1-standard", "kling-v2.5-turbo-image-to-video-pro", "kling-v2.6", "kling-v3-omni", "kling-v3-turbo-image-to-video"],
320
- "fields_by_model" => {
321
- "kling-o1" => {
322
- "aspect_ratio" => {
323
- "enum" => ["16:9", "9:16", "1:1"]
324
- },
325
- "duration_seconds" => {
326
- "enum" => [5],
327
- "type" => "integer"
328
- },
329
- "first_frame_image_url" => {
330
- "required" => true
331
- },
332
- "mode" => {
333
- "enum" => ["std", "pro"]
334
- },
335
- "model" => {
336
- "required" => true
337
- },
338
- "prompt" => {
339
- "required" => true,
340
- "min" => 1,
341
- "max" => 2500,
342
- "length" => true
343
- },
344
- "reference_image_urls" => {
345
- "min_items" => 1,
346
- "max_items" => 7
347
- },
348
- "reference_video_type" => {
349
- "enum" => ["base", "feature"]
350
- }
351
- },
352
- "kling-v2.1-master-image-to-video" => {
353
- "duration_seconds" => {
354
- "enum" => [5, 10],
355
- "type" => "integer"
356
- },
357
- "first_frame_image_url" => {
358
- "required" => true
359
- },
360
- "model" => {
361
- "required" => true
362
- },
363
- "prompt" => {
364
- "required" => true
365
- }
366
- },
367
- "kling-v2.1-pro" => {
368
- "duration_seconds" => {
369
- "enum" => [5, 10],
370
- "type" => "integer"
371
- },
372
- "first_frame_image_url" => {
373
- "required" => true
374
- },
375
- "model" => {
376
- "required" => true
377
- },
378
- "prompt" => {
379
- "required" => true
380
- }
381
- },
382
- "kling-v2.1-standard" => {
383
- "duration_seconds" => {
384
- "enum" => [5, 10],
385
- "type" => "integer"
386
- },
387
- "first_frame_image_url" => {
388
- "required" => true
389
- },
390
- "model" => {
391
- "required" => true
392
- },
393
- "prompt" => {
394
- "required" => true
395
- }
396
- },
397
- "kling-v2.5-turbo-image-to-video-pro" => {
398
- "duration_seconds" => {
399
- "enum" => [5, 10],
400
- "type" => "integer"
401
- },
402
- "first_frame_image_url" => {
403
- "required" => true
404
- },
405
- "model" => {
406
- "required" => true
407
- },
408
- "prompt" => {
409
- "required" => true
410
- }
411
- },
412
- "kling-v2.6" => {
413
- "aspect_ratio" => {
414
- "enum" => ["16:9", "9:16", "1:1"]
415
- },
416
- "duration_seconds" => {
417
- "enum" => [5, 10],
418
- "type" => "integer"
419
- },
420
- "first_frame_image_url" => {
421
- "required" => true
422
- },
423
- "mode" => {
424
- "enum" => ["std", "pro"]
425
- },
426
- "model" => {
427
- "required" => true
428
- },
429
- "prompt" => {
430
- "required" => true,
431
- "min" => 1,
432
- "max" => 2500,
433
- "length" => true
434
- }
435
- },
436
- "kling-v3-omni" => {
437
- "aspect_ratio" => {
438
- "enum" => ["16:9", "9:16", "1:1"]
439
- },
440
- "duration_seconds" => {
441
- "enum" => [3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
442
- "type" => "integer"
443
- },
444
- "first_frame_image_url" => {
445
- "required" => true
446
- },
447
- "model" => {
448
- "required" => true
449
- },
450
- "output_resolution" => {
451
- "enum" => ["720p", "1080p", "4k"]
452
- },
453
- "prompt" => {
454
- "required" => true,
455
- "min" => 1,
456
- "max" => 2500,
457
- "length" => true
458
- }
459
- },
460
- "kling-v3-turbo-image-to-video" => {
461
- "duration_seconds" => {
462
- "enum" => [3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
463
- "type" => "integer"
464
- },
465
- "first_frame_image_url" => {
466
- "required" => true
467
- },
468
- "model" => {
469
- "required" => true
470
- },
471
- "output_resolution" => {
472
- "enum" => ["720p", "1080p"]
473
- },
474
- "prompt" => {
475
- "required" => true,
476
- "min" => 1,
477
- "max" => 2500,
478
- "length" => true
479
- }
480
- }
481
- },
482
- "rules" => [{
483
- "when" => {
484
- "model" => "kling-o1"
485
- },
486
- "forbidden" => ["output_resolution", "negative_prompt", "cfg_scale"]
487
- }, {
488
- "when" => {
489
- "model" => "kling-v2.1-master-image-to-video"
490
- },
491
- "forbidden" => ["output_resolution", "enable_sound", "reference_image_urls", "reference_video_url", "reference_video_type", "preserve_reference_video_audio"]
492
- }, {
493
- "when" => {
494
- "model" => "kling-v2.1-pro"
495
- },
496
- "forbidden" => ["output_resolution", "enable_sound", "reference_image_urls", "reference_video_url", "reference_video_type", "preserve_reference_video_audio"]
497
- }, {
498
- "when" => {
499
- "model" => "kling-v2.1-standard"
500
- },
501
- "forbidden" => ["output_resolution", "enable_sound", "reference_image_urls", "reference_video_url", "reference_video_type", "preserve_reference_video_audio"]
502
- }, {
503
- "when" => {
504
- "model" => "kling-v2.5-turbo-image-to-video-pro"
505
- },
506
- "forbidden" => ["output_resolution", "enable_sound", "reference_image_urls", "reference_video_url", "reference_video_type", "preserve_reference_video_audio"]
507
- }, {
508
- "enum" => {
509
- "enable_sound" => [false]
510
- },
511
- "when" => {
512
- "mode" => "std",
513
- "model" => "kling-v2.6"
514
- }
515
- }, {
516
- "when" => {
517
- "model" => "kling-v2.6"
518
- },
519
- "forbidden" => ["output_resolution", "negative_prompt", "cfg_scale", "reference_image_urls", "reference_video_url", "reference_video_type", "preserve_reference_video_audio"]
520
- }, {
521
- "enum" => {
522
- "enable_sound" => [false]
523
- },
524
- "when" => {
525
- "mode" => {
526
- "present" => false
527
- },
528
- "model" => "kling-v2.6"
529
- }
530
- }, {
531
- "when" => {
532
- "model" => "kling-v3-omni"
533
- },
534
- "forbidden" => ["negative_prompt", "cfg_scale", "reference_image_urls", "reference_video_url", "reference_video_type", "preserve_reference_video_audio"]
535
- }, {
536
- "when" => {
537
- "model" => "kling-v3-turbo-image-to-video"
538
- },
539
- "forbidden" => ["enable_sound", "aspect_ratio", "negative_prompt", "cfg_scale", "last_frame_image_url", "reference_image_urls", "reference_video_url", "reference_video_type", "preserve_reference_video_audio"]
540
- }]
541
- },
542
- "motion-control" => {
543
- "models" => ["kling-3.0", "kling-v2.6"],
544
- "fields_by_model" => {
545
- "kling-3.0" => {
546
- "background_source" => {
547
- "enum" => ["video", "image"]
548
- },
549
- "character_orientation" => {
550
- "enum" => ["video", "image"]
551
- },
552
- "model" => {
553
- "required" => true
554
- },
555
- "output_resolution" => {
556
- "enum" => ["720p", "1080p"],
557
- "required" => true
558
- },
559
- "reference_video_url" => {
560
- "required" => true
561
- },
562
- "source_image_url" => {
563
- "required" => true
564
- }
565
- },
566
- "kling-v2.6" => {
567
- "character_orientation" => {
568
- "enum" => ["video", "image"],
569
- "required" => true
570
- },
571
- "model" => {
572
- "required" => true
573
- },
574
- "output_resolution" => {
575
- "enum" => ["720p", "1080p"],
576
- "required" => true
577
- },
578
- "prompt" => {
579
- "max" => 2500,
580
- "length" => true
581
- },
582
- "reference_video_url" => {
583
- "required" => true
584
- },
585
- "source_image_url" => {
586
- "required" => true
587
- }
588
- }
589
- },
590
- "rules" => [{
591
- "when" => {
592
- "model" => "kling-v2.6"
593
- },
594
- "forbidden" => ["background_source"]
595
- }]
596
- },
597
- "text-to-video" => {
598
- "models" => ["kling-3.0", "kling-o1", "kling-v2.1-master-text-to-video", "kling-v2.5-turbo-text-to-video-pro", "kling-v2.6", "kling-v3-omni", "kling-v3-omni-reference", "kling-v3-turbo-text-to-video"],
599
- "fields_by_model" => {
600
- "kling-3.0" => {
601
- "aspect_ratio" => {
602
- "enum" => ["16:9", "9:16", "1:1"]
603
- },
604
- "duration_seconds" => {
605
- "enum" => [3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
606
- "type" => "integer"
607
- },
608
- "model" => {
609
- "required" => true
610
- },
611
- "output_resolution" => {
612
- "enum" => ["720p", "1080p", "4k"]
613
- }
614
- },
615
- "kling-o1" => {
616
- "aspect_ratio" => {
617
- "enum" => ["16:9", "9:16", "1:1"]
618
- },
619
- "duration_seconds" => {
620
- "enum" => [5],
621
- "type" => "integer"
622
- },
623
- "mode" => {
624
- "enum" => ["std", "pro"]
625
- },
626
- "model" => {
627
- "required" => true
628
- },
629
- "prompt" => {
630
- "required" => true,
631
- "min" => 1,
632
- "max" => 2500,
633
- "length" => true
634
- },
635
- "reference_image_urls" => {
636
- "min_items" => 1,
637
- "max_items" => 7
638
- },
639
- "reference_video_type" => {
640
- "enum" => ["base", "feature"]
641
- }
642
- },
643
- "kling-v2.1-master-text-to-video" => {
644
- "aspect_ratio" => {
645
- "enum" => ["16:9", "9:16", "1:1"]
646
- },
647
- "duration_seconds" => {
648
- "enum" => [5, 10],
649
- "type" => "integer"
650
- },
651
- "model" => {
652
- "required" => true
653
- }
654
- },
655
- "kling-v2.5-turbo-text-to-video-pro" => {
656
- "aspect_ratio" => {
657
- "enum" => ["16:9", "9:16", "1:1"]
658
- },
659
- "duration_seconds" => {
660
- "enum" => [5, 10],
661
- "type" => "integer"
662
- },
663
- "model" => {
664
- "required" => true
665
- }
666
- },
667
- "kling-v2.6" => {
668
- "aspect_ratio" => {
669
- "enum" => ["16:9", "9:16", "1:1"]
670
- },
671
- "duration_seconds" => {
672
- "enum" => [5, 10],
673
- "type" => "integer"
674
- },
675
- "mode" => {
676
- "enum" => ["std", "pro"]
677
- },
678
- "model" => {
679
- "required" => true
680
- },
681
- "prompt" => {
682
- "required" => true,
683
- "min" => 1,
684
- "max" => 2500,
685
- "length" => true
686
- }
687
- },
688
- "kling-v3-omni" => {
689
- "aspect_ratio" => {
690
- "enum" => ["16:9", "9:16", "1:1"]
691
- },
692
- "duration_seconds" => {
693
- "enum" => [3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
694
- "type" => "integer"
695
- },
696
- "model" => {
697
- "required" => true
698
- },
699
- "output_resolution" => {
700
- "enum" => ["720p", "1080p", "4k"]
701
- },
702
- "prompt" => {
703
- "required" => true,
704
- "min" => 1,
705
- "max" => 2500,
706
- "length" => true
707
- }
708
- },
709
- "kling-v3-omni-reference" => {
710
- "aspect_ratio" => {
711
- "enum" => ["16:9", "9:16", "1:1"],
712
- "required" => true
713
- },
714
- "duration_seconds" => {
715
- "enum" => [3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
716
- "type" => "integer"
717
- },
718
- "model" => {
719
- "required" => true
720
- },
721
- "output_resolution" => {
722
- "enum" => ["720p", "1080p", "4k"]
723
- },
724
- "prompt" => {
725
- "required" => true,
726
- "min" => 1,
727
- "max" => 2500,
728
- "length" => true
729
- },
730
- "reference_image_urls" => {
731
- "required" => true,
732
- "min_items" => 1,
733
- "max_items" => 7
734
- }
735
- },
736
- "kling-v3-turbo-text-to-video" => {
737
- "aspect_ratio" => {
738
- "enum" => ["16:9", "9:16", "1:1"]
739
- },
740
- "duration_seconds" => {
741
- "enum" => [3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
742
- "type" => "integer"
743
- },
744
- "model" => {
745
- "required" => true
746
- },
747
- "output_resolution" => {
748
- "enum" => ["720p", "1080p"]
749
- },
750
- "prompt" => {
751
- "required" => true,
752
- "min" => 1,
753
- "max" => 2500,
754
- "length" => true
755
- }
756
- }
757
- },
758
- "rules" => [{
759
- "when" => {
760
- "model" => "kling-3.0"
761
- },
762
- "forbidden" => ["reference_image_urls", "reference_video_url", "reference_video_type", "preserve_reference_video_audio"]
763
- }, {
764
- "when" => {
765
- "model" => "kling-o1"
766
- },
767
- "forbidden" => ["output_resolution", "negative_prompt", "cfg_scale", "multi_shots", "multi_prompt", "first_frame_image_url", "last_frame_image_url", "kling_elements"]
768
- }, {
769
- "when" => {
770
- "model" => "kling-v2.1-master-text-to-video"
771
- },
772
- "forbidden" => ["mode", "reference_image_urls", "reference_video_url", "reference_video_type", "preserve_reference_video_audio"]
773
- }, {
774
- "when" => {
775
- "model" => "kling-v2.5-turbo-text-to-video-pro"
776
- },
777
- "forbidden" => ["mode", "reference_image_urls", "reference_video_url", "reference_video_type", "preserve_reference_video_audio"]
778
- }, {
779
- "when" => {
780
- "model" => "kling-v2.6"
781
- },
782
- "forbidden" => ["output_resolution", "negative_prompt", "cfg_scale", "multi_shots", "multi_prompt", "first_frame_image_url", "last_frame_image_url", "kling_elements", "reference_image_urls", "reference_video_url", "reference_video_type", "preserve_reference_video_audio"]
783
- }, {
784
- "enum" => {
785
- "enable_sound" => [false]
786
- },
787
- "when" => {
788
- "mode" => "std",
789
- "model" => "kling-v2.6"
790
- }
791
- }, {
792
- "enum" => {
793
- "enable_sound" => [false]
794
- },
795
- "when" => {
796
- "mode" => {
797
- "present" => false
798
- },
799
- "model" => "kling-v2.6"
800
- }
801
- }, {
802
- "when" => {
803
- "model" => "kling-v3-omni"
804
- },
805
- "forbidden" => ["negative_prompt", "cfg_scale", "multi_shots", "multi_prompt", "first_frame_image_url", "last_frame_image_url", "kling_elements", "reference_image_urls", "reference_video_url", "reference_video_type", "preserve_reference_video_audio"]
806
- }, {
807
- "when" => {
808
- "model" => "kling-v3-turbo-text-to-video"
809
- },
810
- "forbidden" => ["enable_sound", "negative_prompt", "cfg_scale", "multi_shots", "multi_prompt", "first_frame_image_url", "last_frame_image_url", "kling_elements", "reference_image_urls", "reference_video_url", "reference_video_type", "preserve_reference_video_audio"]
811
- }]
812
- }
813
- }.freeze
814
- end
815
- end
@@ -1,176 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "ipaddr"
4
- require "uri"
5
-
6
- module RunApi
7
- module Kling
8
- module Resources
9
- module O1ReferenceValidation
10
- O1_MODEL = "kling-o1"
11
- O1_IMAGE_EXTENSIONS = %w[.jpg .jpeg .png].freeze
12
- O1_VIDEO_EXTENSIONS = %w[.mp4 .mov].freeze
13
- O1_NONCANONICAL_IPV4_LITERAL = /\A(?:0x[0-9a-f]+|\d+)(?:\.(?:0x[0-9a-f]+|\d+)){0,3}\z/i
14
- O1_BLOCKED_IP_RANGES = %w[
15
- 0.0.0.0/8
16
- 10.0.0.0/8
17
- 100.64.0.0/10
18
- 127.0.0.0/8
19
- 169.254.0.0/16
20
- 172.16.0.0/12
21
- 192.0.0.0/24
22
- 192.0.2.0/24
23
- 192.88.99.0/24
24
- 192.168.0.0/16
25
- 198.18.0.0/15
26
- 198.51.100.0/24
27
- 203.0.113.0/24
28
- 224.0.0.0/4
29
- 240.0.0.0/4
30
- 255.255.255.255/32
31
- ::/128
32
- ::1/128
33
- 64:ff9b::/96
34
- 64:ff9b:1::/48
35
- 100::/64
36
- 2001::/32
37
- 2001:2::/48
38
- 2001:db8::/32
39
- 2002::/16
40
- 3fff::/20
41
- fc00::/7
42
- fe80::/10
43
- ff00::/8
44
- ].map { |cidr| IPAddr.new(cidr) }.freeze
45
-
46
- private
47
-
48
- def validate_kling_o1_references!(params)
49
- return unless param(params, :model) == O1_MODEL
50
-
51
- if param(params, :enable_sound) == true
52
- raise Core::ValidationError, "enable_sound is not supported by #{O1_MODEL}"
53
- end
54
-
55
- validate_o1_frame_urls!(params)
56
- prompt = param(params, :prompt)
57
- raise Core::ValidationError, "prompt must be a string" unless prompt.is_a?(String)
58
- reference_images = Array(param(params, :reference_image_urls))
59
- reference_video_url = param(params, :reference_video_url)
60
-
61
- if field_present?(params, :last_frame_image_url) &&
62
- (reference_images.any? || field_present?(params, :reference_video_url))
63
- raise Core::ValidationError,
64
- "last_frame_image_url cannot be combined with reference_image_urls or reference_video_url"
65
- end
66
-
67
- if reference_video_url && reference_images.size > 4
68
- raise Core::ValidationError, "reference_image_urls must contain at most 4 items when reference_video_url is present"
69
- end
70
-
71
- validate_o1_reference_images!(prompt, reference_images)
72
- validate_o1_reference_video!(params, prompt, reference_video_url)
73
- end
74
-
75
- def validate_o1_frame_urls!(params)
76
- %i[first_frame_image_url last_frame_image_url].each do |field|
77
- value = param(params, field)
78
- next unless value
79
- validate_o1_media_url!(
80
- value,
81
- field: field,
82
- extensions: O1_IMAGE_EXTENSIONS,
83
- extension_error: "#{field} must use a JPG, JPEG, or PNG URL"
84
- )
85
- end
86
- end
87
-
88
- def validate_o1_reference_images!(prompt, reference_images)
89
- reference_images.each_with_index do |url, index|
90
- field = "reference_image_urls[#{index}]"
91
- raise Core::ValidationError, "#{field} must be a string" unless url.is_a?(String)
92
- validate_o1_media_url!(
93
- url,
94
- field: field,
95
- extensions: O1_IMAGE_EXTENSIONS,
96
- extension_error: "#{field} must use a JPG, JPEG, or PNG URL"
97
- )
98
-
99
- marker = "<<<image_#{index + 1}>>>"
100
- unless prompt.include?(marker)
101
- raise Core::ValidationError, "prompt must reference reference_image_urls[#{index}] as #{marker}"
102
- end
103
- end
104
-
105
- prompt.scan(/<<<image_(\d+)>>>/).flatten.map(&:to_i).each do |index|
106
- next if index.between?(1, reference_images.size)
107
-
108
- raise Core::ValidationError, "prompt references missing image_#{index}"
109
- end
110
- end
111
-
112
- def validate_o1_reference_video!(params, prompt, reference_video_url)
113
- unless reference_video_url
114
- raise Core::ValidationError, "reference_video_type requires reference_video_url" if o1_key?(params, :reference_video_type)
115
- if o1_key?(params, :preserve_reference_video_audio)
116
- raise Core::ValidationError, "preserve_reference_video_audio requires reference_video_url"
117
- end
118
- if (match = prompt.match(/<<<video_([^>]+)>>>/))
119
- raise Core::ValidationError, "prompt references missing video_#{match[1]}"
120
- end
121
- return
122
- end
123
-
124
- validate_o1_media_url!(
125
- reference_video_url,
126
- field: :reference_video_url,
127
- extensions: O1_VIDEO_EXTENSIONS,
128
- extension_error: "reference_video_url must use an MP4 or MOV URL"
129
- )
130
- unless prompt.include?("<<<video_1>>>")
131
- raise Core::ValidationError, "prompt must reference reference_video_url as <<<video_1>>>"
132
- end
133
- if prompt.scan(/<<<video_([^>]+)>>>/).flatten.any? { |index| index != "1" }
134
- raise Core::ValidationError, "prompt may only reference video_1"
135
- end
136
-
137
- reference_video_type = param(params, :reference_video_type) || "base"
138
- return unless reference_video_type == "base"
139
- return unless field_present?(params, :first_frame_image_url) || field_present?(params, :last_frame_image_url)
140
-
141
- raise Core::ValidationError,
142
- "reference_video_type base cannot be combined with first_frame_image_url or last_frame_image_url"
143
- end
144
-
145
- def o1_key?(params, field)
146
- params.key?(field) || params.key?(field.to_s)
147
- end
148
-
149
- def validate_o1_media_url!(value, field:, extensions:, extension_error:)
150
- raise Core::ValidationError, "#{field} must be a string" unless value.is_a?(String)
151
-
152
- uri = URI.parse(value.to_s)
153
- host = uri.hostname
154
- local_host = host&.casecmp?("localhost") || host&.downcase&.end_with?(".localhost")
155
- valid_http_url = (uri.is_a?(URI::HTTP) || uri.is_a?(URI::HTTPS)) &&
156
- host && !uri.userinfo && !local_host && !blocked_o1_ip_literal?(host)
157
- unless valid_http_url
158
- raise Core::ValidationError, "#{field} must be a public HTTP or HTTPS URL"
159
- end
160
- return if extensions.include?(File.extname(uri.path).downcase)
161
-
162
- raise Core::ValidationError, extension_error
163
- rescue URI::InvalidURIError
164
- raise Core::ValidationError, "#{field} must be a public HTTP or HTTPS URL"
165
- end
166
-
167
- def blocked_o1_ip_literal?(host)
168
- ip = IPAddr.new(host).native
169
- O1_BLOCKED_IP_RANGES.any? { |range| range.include?(ip) }
170
- rescue IPAddr::InvalidAddressError
171
- O1_NONCANONICAL_IPV4_LITERAL.match?(host)
172
- end
173
- end
174
- end
175
- end
176
- end