runapi-kling 0.3.5 → 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: e03ccf39a5c619e3404ed1ffbb8a463be891fa9b0f1ce7d76162de338d11b8b9
4
- data.tar.gz: 92b04c1acc98b79fc9a83d21f53bb5e07205bdbfe43e20c760e6520876dedb3d
3
+ metadata.gz: bf93e2f75b6755cae286b37459790683c4811e5d3a2e64fd0e76a2918c9811c5
4
+ data.tar.gz: 538697ef0ab20941aaad011b8fc76c453c40df530a94c5aae39f983d023808fb
5
5
  SHA512:
6
- metadata.gz: 9582e0fa8edbfec5825c133f7e89cbd31e9b3918132f0b1d223a95c1269fea5f3bf836eadf7eefebb4fba13007c28b5d50dfe100752d885111530c98f7019306
7
- data.tar.gz: 97b958a9e8798d94b9ac1dcd0705bf84b508ff8eab1f46e88179e0dfacbc6df3451e9063196ff0587f386c675088accfeb6c5da3bbd93b39ce61bc783a7635ce
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,50 +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
- mode = param(params, :mode) || "std"
81
- if param(params, :enable_sound) == true && mode != "pro"
82
- raise Core::ValidationError, "enable_sound requires mode pro for #{V26_MODEL}"
83
- end
84
- return unless last_frame_image_url
85
-
86
- raise Core::ValidationError, "last_frame_image_url requires mode pro for #{V26_MODEL}" unless mode == "pro"
87
-
88
- duration_seconds = param(params, :duration_seconds) || 5
89
- return if duration_seconds.to_i == 5
90
-
91
- raise Core::ValidationError, "last_frame_image_url requires duration_seconds 5 for #{V26_MODEL}"
92
- end
93
-
94
- def reject_unsupported_v3_turbo_fields!(params)
95
- return unless param(params, :model) == V3_TURBO_MODEL
96
-
97
- field = V3_TURBO_UNSUPPORTED_FIELDS.find { |candidate| field_present?(params, candidate) }
98
- raise Core::ValidationError, "#{field} is not supported by #{V3_TURBO_MODEL}" if field
99
- end
100
48
  end
101
49
  end
102
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,24 +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
- V26_MODEL = "kling-v2.6"
17
15
  V3_TURBO_MODEL = "kling-v3-turbo-text-to-video"
18
- V3_TURBO_UNSUPPORTED_FIELDS = %i[
19
- enable_sound
20
- negative_prompt
21
- cfg_scale
22
- multi_shots
23
- multi_prompt
24
- first_frame_image_url
25
- last_frame_image_url
26
- kling_elements
27
- ].freeze
28
16
 
29
17
  def initialize(http)
30
18
  @http = http
@@ -45,7 +33,6 @@ module RunApi
45
33
  # @return [RunApi::Kling::Types::TextToVideoResponse] task creation result with id
46
34
  def create(options: nil, **params)
47
35
  params = compact_params(params)
48
- validate_params!(params)
49
36
  request(:post, ENDPOINT, body: params, options: options)
50
37
  end
51
38
 
@@ -56,66 +43,6 @@ module RunApi
56
43
  def get(id, options: nil)
57
44
  request(:get, "#{ENDPOINT}/#{id}", options: options)
58
45
  end
59
-
60
- private
61
-
62
- def validate_params!(params)
63
- reject_unsupported_v3_turbo_fields!(params)
64
- validate_contract!(CONTRACT["text-to-video"], params)
65
- validate_v26_params!(params)
66
- validate_kling_o1_references!(params)
67
-
68
- # Bespoke cross-field rules the contract cannot express.
69
- multi_shots = param(params, :multi_shots) == true
70
-
71
- if multi_shots
72
- raise Core::ValidationError, "enable_sound must be true when multi_shots is true" unless param(params, :enable_sound) == true
73
- raise Core::ValidationError, "last_frame_image_url is not supported when multi_shots is true" if param(params, :last_frame_image_url)
74
-
75
- multi_prompt = param(params, :multi_prompt)
76
- validate_multi_prompt!(multi_prompt)
77
- else
78
- raise Core::ValidationError, "prompt is required" unless param(params, :prompt)
79
- end
80
- end
81
-
82
- def validate_v26_params!(params)
83
- return unless param(params, :model) == V26_MODEL
84
- return unless param(params, :enable_sound) == true && param(params, :mode) != "pro"
85
-
86
- raise Core::ValidationError, "enable_sound requires mode pro for #{V26_MODEL}"
87
- end
88
-
89
- def reject_unsupported_v3_turbo_fields!(params)
90
- return unless param(params, :model) == V3_TURBO_MODEL
91
-
92
- field = V3_TURBO_UNSUPPORTED_FIELDS.find { |candidate| field_present?(params, candidate) }
93
- raise Core::ValidationError, "#{field} is not supported by #{V3_TURBO_MODEL}" if field
94
- end
95
-
96
- def validate_multi_prompt!(multi_prompt)
97
- unless multi_prompt.is_a?(Array) && multi_prompt.any?
98
- raise Core::ValidationError, "multi_prompt must be a non-empty array when multi_shots is true"
99
- end
100
-
101
- multi_prompt.each_with_index do |shot, index|
102
- prompt = shot.is_a?(Hash) ? (shot[:prompt] || shot["prompt"]) : nil
103
- duration_seconds = shot.is_a?(Hash) ? (shot[:duration_seconds] || shot["duration_seconds"]) : nil
104
-
105
- raise Core::ValidationError, "multi_prompt[#{index}].prompt is required" if prompt.nil? || prompt.empty?
106
-
107
- if prompt.length > Types::MULTI_PROMPT_MAX_LENGTH
108
- raise Core::ValidationError, "multi_prompt[#{index}].prompt exceeds #{Types::MULTI_PROMPT_MAX_LENGTH} characters"
109
- end
110
-
111
- raise Core::ValidationError, "multi_prompt[#{index}].duration_seconds is required" if duration_seconds.nil?
112
-
113
- dur_int = duration_seconds.to_i
114
- unless Types::MULTI_PROMPT_DURATION_RANGE.cover?(dur_int)
115
- raise Core::ValidationError, "multi_prompt[#{index}].duration_seconds must be between #{Types::MULTI_PROMPT_DURATION_RANGE.min} and #{Types::MULTI_PROMPT_DURATION_RANGE.max}"
116
- end
117
- end
118
- end
119
46
  end
120
47
  end
121
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.3.5
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.0
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.0
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,778 +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_task_id" => {
125
- "present" => false
126
- },
127
- "source_video_url" => {
128
- "present" => false
129
- }
130
- },
131
- "required_any" => ["source_video_url", "source_task_id"]
132
- }, {
133
- "when" => {
134
- "model" => "kling-v3-omni-edit",
135
- "source_video_url" => {
136
- "present" => true
137
- }
138
- },
139
- "forbidden" => ["source_task_id"]
140
- }, {
141
- "when" => {
142
- "model" => "kling-v3-omni-edit",
143
- "source_task_id" => {
144
- "present" => true
145
- }
146
- },
147
- "forbidden" => ["source_video_url"]
148
- }, {
149
- "enum" => {
150
- "aspect_ratio" => ["auto"],
151
- "duration_seconds" => [5]
152
- },
153
- "when" => {
154
- "model" => "kling-v3-omni-edit",
155
- "source_video_url" => {
156
- "present" => true
157
- },
158
- "reference_image_urls" => {
159
- "present" => false
160
- }
161
- },
162
- "required" => ["aspect_ratio"]
163
- }, {
164
- "enum" => {
165
- "aspect_ratio" => ["auto"],
166
- "duration_seconds" => [5]
167
- },
168
- "when" => {
169
- "model" => "kling-v3-omni-edit",
170
- "source_task_id" => {
171
- "present" => true
172
- },
173
- "reference_image_urls" => {
174
- "present" => false
175
- }
176
- },
177
- "required" => ["aspect_ratio"]
178
- }, {
179
- "enum" => {
180
- "aspect_ratio" => ["16:9", "9:16", "1:1"]
181
- },
182
- "when" => {
183
- "model" => "kling-v3-omni-edit",
184
- "source_video_url" => {
185
- "present" => true
186
- },
187
- "reference_image_urls" => {
188
- "present" => true
189
- }
190
- },
191
- "required" => ["aspect_ratio"]
192
- }, {
193
- "enum" => {
194
- "aspect_ratio" => ["16:9", "9:16", "1:1"]
195
- },
196
- "when" => {
197
- "model" => "kling-v3-omni-edit",
198
- "source_task_id" => {
199
- "present" => true
200
- },
201
- "reference_image_urls" => {
202
- "present" => true
203
- }
204
- },
205
- "required" => ["aspect_ratio"]
206
- }, {
207
- "when" => {
208
- "model" => "kling-v3-omni-reference",
209
- "source_task_id" => {
210
- "present" => false
211
- },
212
- "source_video_url" => {
213
- "present" => false
214
- }
215
- },
216
- "required_any" => ["source_video_url", "source_task_id"]
217
- }, {
218
- "when" => {
219
- "model" => "kling-v3-omni-reference",
220
- "source_video_url" => {
221
- "present" => true
222
- }
223
- },
224
- "forbidden" => ["source_task_id"]
225
- }, {
226
- "when" => {
227
- "model" => "kling-v3-omni-reference",
228
- "source_task_id" => {
229
- "present" => true
230
- }
231
- },
232
- "forbidden" => ["source_video_url"]
233
- }, {
234
- "enum" => {
235
- "aspect_ratio" => ["auto"],
236
- "enable_sound" => [false],
237
- "duration_seconds" => [5]
238
- },
239
- "when" => {
240
- "model" => "kling-v3-omni-reference",
241
- "source_video_url" => {
242
- "present" => true
243
- },
244
- "reference_image_urls" => {
245
- "present" => false
246
- }
247
- },
248
- "required" => ["aspect_ratio"]
249
- }, {
250
- "enum" => {
251
- "aspect_ratio" => ["auto"],
252
- "enable_sound" => [false],
253
- "duration_seconds" => [5]
254
- },
255
- "when" => {
256
- "model" => "kling-v3-omni-reference",
257
- "source_task_id" => {
258
- "present" => true
259
- },
260
- "reference_image_urls" => {
261
- "present" => false
262
- }
263
- },
264
- "required" => ["aspect_ratio"]
265
- }, {
266
- "enum" => {
267
- "aspect_ratio" => ["16:9", "9:16", "1:1"],
268
- "enable_sound" => [false]
269
- },
270
- "when" => {
271
- "model" => "kling-v3-omni-reference",
272
- "source_video_url" => {
273
- "present" => true
274
- },
275
- "reference_image_urls" => {
276
- "present" => true
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_task_id" => {
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
- "when" => {
509
- "model" => "kling-v2.6"
510
- },
511
- "forbidden" => ["output_resolution", "negative_prompt", "cfg_scale", "reference_image_urls", "reference_video_url", "reference_video_type", "preserve_reference_video_audio"]
512
- }, {
513
- "when" => {
514
- "model" => "kling-v3-omni"
515
- },
516
- "forbidden" => ["negative_prompt", "cfg_scale", "reference_image_urls", "reference_video_url", "reference_video_type", "preserve_reference_video_audio"]
517
- }, {
518
- "when" => {
519
- "model" => "kling-v3-turbo-image-to-video"
520
- },
521
- "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"]
522
- }]
523
- },
524
- "motion-control" => {
525
- "models" => ["kling-3.0", "kling-v2.6"],
526
- "fields_by_model" => {
527
- "kling-3.0" => {
528
- "background_source" => {
529
- "enum" => ["video", "image"]
530
- },
531
- "character_orientation" => {
532
- "enum" => ["video", "image"]
533
- },
534
- "model" => {
535
- "required" => true
536
- },
537
- "output_resolution" => {
538
- "enum" => ["720p", "1080p"]
539
- },
540
- "reference_video_url" => {
541
- "required" => true
542
- },
543
- "source_image_url" => {
544
- "required" => true
545
- }
546
- },
547
- "kling-v2.6" => {
548
- "character_orientation" => {
549
- "enum" => ["video", "image"],
550
- "required" => true
551
- },
552
- "model" => {
553
- "required" => true
554
- },
555
- "output_resolution" => {
556
- "enum" => ["720p", "1080p"],
557
- "required" => true
558
- },
559
- "prompt" => {
560
- "max" => 2500,
561
- "length" => true
562
- },
563
- "reference_video_url" => {
564
- "required" => true
565
- },
566
- "source_image_url" => {
567
- "required" => true
568
- }
569
- }
570
- },
571
- "rules" => [{
572
- "when" => {
573
- "model" => "kling-v2.6"
574
- },
575
- "forbidden" => ["background_source"]
576
- }]
577
- },
578
- "text-to-video" => {
579
- "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"],
580
- "fields_by_model" => {
581
- "kling-3.0" => {
582
- "aspect_ratio" => {
583
- "enum" => ["16:9", "9:16", "1:1"]
584
- },
585
- "duration_seconds" => {
586
- "enum" => [3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
587
- "type" => "integer"
588
- },
589
- "model" => {
590
- "required" => true
591
- },
592
- "output_resolution" => {
593
- "enum" => ["720p", "1080p", "4k"]
594
- }
595
- },
596
- "kling-o1" => {
597
- "aspect_ratio" => {
598
- "enum" => ["16:9", "9:16", "1:1"]
599
- },
600
- "duration_seconds" => {
601
- "enum" => [5],
602
- "type" => "integer"
603
- },
604
- "mode" => {
605
- "enum" => ["std", "pro"]
606
- },
607
- "model" => {
608
- "required" => true
609
- },
610
- "prompt" => {
611
- "required" => true,
612
- "min" => 1,
613
- "max" => 2500,
614
- "length" => true
615
- },
616
- "reference_image_urls" => {
617
- "min_items" => 1,
618
- "max_items" => 7
619
- },
620
- "reference_video_type" => {
621
- "enum" => ["base", "feature"]
622
- }
623
- },
624
- "kling-v2.1-master-text-to-video" => {
625
- "aspect_ratio" => {
626
- "enum" => ["16:9", "9:16", "1:1"]
627
- },
628
- "duration_seconds" => {
629
- "enum" => [5, 10],
630
- "type" => "integer"
631
- },
632
- "model" => {
633
- "required" => true
634
- }
635
- },
636
- "kling-v2.5-turbo-text-to-video-pro" => {
637
- "aspect_ratio" => {
638
- "enum" => ["16:9", "9:16", "1:1"]
639
- },
640
- "duration_seconds" => {
641
- "enum" => [5, 10],
642
- "type" => "integer"
643
- },
644
- "model" => {
645
- "required" => true
646
- }
647
- },
648
- "kling-v2.6" => {
649
- "aspect_ratio" => {
650
- "enum" => ["16:9", "9:16", "1:1"]
651
- },
652
- "duration_seconds" => {
653
- "enum" => [5, 10],
654
- "type" => "integer"
655
- },
656
- "mode" => {
657
- "enum" => ["std", "pro"]
658
- },
659
- "model" => {
660
- "required" => true
661
- },
662
- "prompt" => {
663
- "required" => true,
664
- "min" => 1,
665
- "max" => 2500,
666
- "length" => true
667
- }
668
- },
669
- "kling-v3-omni" => {
670
- "aspect_ratio" => {
671
- "enum" => ["16:9", "9:16", "1:1"]
672
- },
673
- "duration_seconds" => {
674
- "enum" => [3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
675
- "type" => "integer"
676
- },
677
- "model" => {
678
- "required" => true
679
- },
680
- "output_resolution" => {
681
- "enum" => ["720p", "1080p", "4k"]
682
- },
683
- "prompt" => {
684
- "required" => true,
685
- "min" => 1,
686
- "max" => 2500,
687
- "length" => true
688
- }
689
- },
690
- "kling-v3-omni-reference" => {
691
- "aspect_ratio" => {
692
- "enum" => ["16:9", "9:16", "1:1"],
693
- "required" => true
694
- },
695
- "duration_seconds" => {
696
- "enum" => [3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
697
- "type" => "integer"
698
- },
699
- "model" => {
700
- "required" => true
701
- },
702
- "output_resolution" => {
703
- "enum" => ["720p", "1080p", "4k"]
704
- },
705
- "prompt" => {
706
- "required" => true,
707
- "min" => 1,
708
- "max" => 2500,
709
- "length" => true
710
- },
711
- "reference_image_urls" => {
712
- "required" => true,
713
- "min_items" => 1,
714
- "max_items" => 7
715
- }
716
- },
717
- "kling-v3-turbo-text-to-video" => {
718
- "aspect_ratio" => {
719
- "enum" => ["16:9", "9:16", "1:1"]
720
- },
721
- "duration_seconds" => {
722
- "enum" => [3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
723
- "type" => "integer"
724
- },
725
- "model" => {
726
- "required" => true
727
- },
728
- "output_resolution" => {
729
- "enum" => ["720p", "1080p"]
730
- },
731
- "prompt" => {
732
- "required" => true,
733
- "min" => 1,
734
- "max" => 2500,
735
- "length" => true
736
- }
737
- }
738
- },
739
- "rules" => [{
740
- "when" => {
741
- "model" => "kling-3.0"
742
- },
743
- "forbidden" => ["reference_image_urls", "reference_video_url", "reference_video_type", "preserve_reference_video_audio"]
744
- }, {
745
- "when" => {
746
- "model" => "kling-o1"
747
- },
748
- "forbidden" => ["output_resolution", "negative_prompt", "cfg_scale", "multi_shots", "multi_prompt", "first_frame_image_url", "last_frame_image_url", "kling_elements"]
749
- }, {
750
- "when" => {
751
- "model" => "kling-v2.1-master-text-to-video"
752
- },
753
- "forbidden" => ["mode", "reference_image_urls", "reference_video_url", "reference_video_type", "preserve_reference_video_audio"]
754
- }, {
755
- "when" => {
756
- "model" => "kling-v2.5-turbo-text-to-video-pro"
757
- },
758
- "forbidden" => ["mode", "reference_image_urls", "reference_video_url", "reference_video_type", "preserve_reference_video_audio"]
759
- }, {
760
- "when" => {
761
- "model" => "kling-v2.6"
762
- },
763
- "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"]
764
- }, {
765
- "when" => {
766
- "model" => "kling-v3-omni"
767
- },
768
- "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"]
769
- }, {
770
- "when" => {
771
- "model" => "kling-v3-turbo-text-to-video"
772
- },
773
- "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"]
774
- }]
775
- }
776
- }.freeze
777
- end
778
- 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