runapi-kling 0.2.12 → 0.2.13
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 +4 -4
- data/README.md +17 -0
- data/lib/runapi/kling/contract_gen.rb +92 -13
- data/lib/runapi/kling/resources/image_to_video.rb +3 -1
- data/lib/runapi/kling/resources/o1_reference_validation.rb +176 -0
- data/lib/runapi/kling/resources/text_to_video.rb +2 -0
- data/lib/runapi/kling.rb +1 -0
- metadata +4 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3ee363d9aca47d12b9532fe37133181c95bc914e233c127ce86dc7ef9cde3000
|
|
4
|
+
data.tar.gz: 06e2eea2612c5d2a6eaba6264a7c050d2d61b9cb80c26cfea581139a17baed20
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 6bc711db4985a209433276045dfb1174b4295f7256075287da212e98f4f443e8b2670a99f3344410b6441d507cd10465f691b46b97b129b9b22066a7d5a1a085
|
|
7
|
+
data.tar.gz: b5e93c8807bacc42d3988ee2e1146011733ec0f0d5f9eda7d9fff97b7ad81ed72d6db39f7ee2ba1b2e334c69044026efde4c65fe2f7d250ad37762cb6d6552df
|
data/README.md
CHANGED
|
@@ -22,6 +22,23 @@ task = client.text_to_video.create(
|
|
|
22
22
|
status = client.text_to_video.get(task.id)
|
|
23
23
|
```
|
|
24
24
|
|
|
25
|
+
## Kling O1 reference media
|
|
26
|
+
|
|
27
|
+
```ruby
|
|
28
|
+
result = client.text_to_video.run(
|
|
29
|
+
model: "kling-o1",
|
|
30
|
+
prompt: "Keep <<<image_1>>> beside the performer from <<<video_1>>>",
|
|
31
|
+
reference_image_urls: ["https://cdn.runapi.ai/public/samples/portrait.jpg"],
|
|
32
|
+
reference_video_url: "https://cdn.runapi.ai/public/samples/video.mp4",
|
|
33
|
+
reference_video_type: "feature",
|
|
34
|
+
preserve_reference_video_audio: true,
|
|
35
|
+
mode: "pro",
|
|
36
|
+
duration_seconds: 5
|
|
37
|
+
)
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Number reference images in prompt order as `<<<image_1>>>`, `<<<image_2>>>`, and so on; the optional video is `<<<video_1>>>`. With a video, send at most four images. Do not combine `last_frame_image_url` with reference images or a reference video. A `feature` reference video may be used with the required first frame; `base` cannot be combined with frame inputs. O1 requests are five seconds and keep sound disabled. Pricing and limits: https://runapi.ai/models/kling/o1.
|
|
41
|
+
|
|
25
42
|
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
43
|
|
|
27
44
|
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.
|
|
@@ -86,8 +86,39 @@ module RunApi
|
|
|
86
86
|
}
|
|
87
87
|
},
|
|
88
88
|
"image-to-video" => {
|
|
89
|
-
"models" => ["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"],
|
|
89
|
+
"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"],
|
|
90
90
|
"fields_by_model" => {
|
|
91
|
+
"kling-o1" => {
|
|
92
|
+
"aspect_ratio" => {
|
|
93
|
+
"enum" => ["16:9", "9:16", "1:1"]
|
|
94
|
+
},
|
|
95
|
+
"duration_seconds" => {
|
|
96
|
+
"enum" => [5],
|
|
97
|
+
"type" => "integer"
|
|
98
|
+
},
|
|
99
|
+
"first_frame_image_url" => {
|
|
100
|
+
"required" => true
|
|
101
|
+
},
|
|
102
|
+
"mode" => {
|
|
103
|
+
"enum" => ["std", "pro"]
|
|
104
|
+
},
|
|
105
|
+
"model" => {
|
|
106
|
+
"required" => true
|
|
107
|
+
},
|
|
108
|
+
"prompt" => {
|
|
109
|
+
"required" => true,
|
|
110
|
+
"min" => 1,
|
|
111
|
+
"max" => 2500,
|
|
112
|
+
"length" => true
|
|
113
|
+
},
|
|
114
|
+
"reference_image_urls" => {
|
|
115
|
+
"min_items" => 1,
|
|
116
|
+
"max_items" => 7
|
|
117
|
+
},
|
|
118
|
+
"reference_video_type" => {
|
|
119
|
+
"enum" => ["base", "feature"]
|
|
120
|
+
}
|
|
121
|
+
},
|
|
91
122
|
"kling-v2.1-master-image-to-video" => {
|
|
92
123
|
"duration_seconds" => {
|
|
93
124
|
"enum" => [5, 10],
|
|
@@ -219,40 +250,45 @@ module RunApi
|
|
|
219
250
|
}
|
|
220
251
|
},
|
|
221
252
|
"rules" => [{
|
|
253
|
+
"when" => {
|
|
254
|
+
"model" => "kling-o1"
|
|
255
|
+
},
|
|
256
|
+
"forbidden" => ["output_resolution", "negative_prompt", "cfg_scale"]
|
|
257
|
+
}, {
|
|
222
258
|
"when" => {
|
|
223
259
|
"model" => "kling-v2.1-master-image-to-video"
|
|
224
260
|
},
|
|
225
|
-
"forbidden" => ["output_resolution", "enable_sound"]
|
|
261
|
+
"forbidden" => ["output_resolution", "enable_sound", "reference_image_urls", "reference_video_url", "reference_video_type", "preserve_reference_video_audio"]
|
|
226
262
|
}, {
|
|
227
263
|
"when" => {
|
|
228
264
|
"model" => "kling-v2.1-pro"
|
|
229
265
|
},
|
|
230
|
-
"forbidden" => ["output_resolution", "enable_sound"]
|
|
266
|
+
"forbidden" => ["output_resolution", "enable_sound", "reference_image_urls", "reference_video_url", "reference_video_type", "preserve_reference_video_audio"]
|
|
231
267
|
}, {
|
|
232
268
|
"when" => {
|
|
233
269
|
"model" => "kling-v2.1-standard"
|
|
234
270
|
},
|
|
235
|
-
"forbidden" => ["output_resolution", "enable_sound"]
|
|
271
|
+
"forbidden" => ["output_resolution", "enable_sound", "reference_image_urls", "reference_video_url", "reference_video_type", "preserve_reference_video_audio"]
|
|
236
272
|
}, {
|
|
237
273
|
"when" => {
|
|
238
274
|
"model" => "kling-v2.5-turbo-image-to-video-pro"
|
|
239
275
|
},
|
|
240
|
-
"forbidden" => ["output_resolution", "enable_sound"]
|
|
276
|
+
"forbidden" => ["output_resolution", "enable_sound", "reference_image_urls", "reference_video_url", "reference_video_type", "preserve_reference_video_audio"]
|
|
241
277
|
}, {
|
|
242
278
|
"when" => {
|
|
243
279
|
"model" => "kling-v2.6"
|
|
244
280
|
},
|
|
245
|
-
"forbidden" => ["output_resolution", "negative_prompt", "cfg_scale"]
|
|
281
|
+
"forbidden" => ["output_resolution", "negative_prompt", "cfg_scale", "reference_image_urls", "reference_video_url", "reference_video_type", "preserve_reference_video_audio"]
|
|
246
282
|
}, {
|
|
247
283
|
"when" => {
|
|
248
284
|
"model" => "kling-v3-omni"
|
|
249
285
|
},
|
|
250
|
-
"forbidden" => ["negative_prompt", "cfg_scale"]
|
|
286
|
+
"forbidden" => ["negative_prompt", "cfg_scale", "reference_image_urls", "reference_video_url", "reference_video_type", "preserve_reference_video_audio"]
|
|
251
287
|
}, {
|
|
252
288
|
"when" => {
|
|
253
289
|
"model" => "kling-v3-turbo-image-to-video"
|
|
254
290
|
},
|
|
255
|
-
"forbidden" => ["enable_sound", "aspect_ratio", "negative_prompt", "cfg_scale", "last_frame_image_url"]
|
|
291
|
+
"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"]
|
|
256
292
|
}]
|
|
257
293
|
},
|
|
258
294
|
"motion-control" => {
|
|
@@ -310,7 +346,7 @@ module RunApi
|
|
|
310
346
|
}]
|
|
311
347
|
},
|
|
312
348
|
"text-to-video" => {
|
|
313
|
-
"models" => ["kling-3.0", "kling-v2.1-master-text-to-video", "kling-v2.5-turbo-text-to-video-pro", "kling-v2.6", "kling-v3-omni", "kling-v3-turbo-text-to-video"],
|
|
349
|
+
"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-turbo-text-to-video"],
|
|
314
350
|
"fields_by_model" => {
|
|
315
351
|
"kling-3.0" => {
|
|
316
352
|
"aspect_ratio" => {
|
|
@@ -327,6 +363,34 @@ module RunApi
|
|
|
327
363
|
"enum" => ["720p", "1080p", "4k"]
|
|
328
364
|
}
|
|
329
365
|
},
|
|
366
|
+
"kling-o1" => {
|
|
367
|
+
"aspect_ratio" => {
|
|
368
|
+
"enum" => ["16:9", "9:16", "1:1"]
|
|
369
|
+
},
|
|
370
|
+
"duration_seconds" => {
|
|
371
|
+
"enum" => [5],
|
|
372
|
+
"type" => "integer"
|
|
373
|
+
},
|
|
374
|
+
"mode" => {
|
|
375
|
+
"enum" => ["std", "pro"]
|
|
376
|
+
},
|
|
377
|
+
"model" => {
|
|
378
|
+
"required" => true
|
|
379
|
+
},
|
|
380
|
+
"prompt" => {
|
|
381
|
+
"required" => true,
|
|
382
|
+
"min" => 1,
|
|
383
|
+
"max" => 2500,
|
|
384
|
+
"length" => true
|
|
385
|
+
},
|
|
386
|
+
"reference_image_urls" => {
|
|
387
|
+
"min_items" => 1,
|
|
388
|
+
"max_items" => 7
|
|
389
|
+
},
|
|
390
|
+
"reference_video_type" => {
|
|
391
|
+
"enum" => ["base", "feature"]
|
|
392
|
+
}
|
|
393
|
+
},
|
|
330
394
|
"kling-v2.1-master-text-to-video" => {
|
|
331
395
|
"aspect_ratio" => {
|
|
332
396
|
"enum" => ["16:9", "9:16", "1:1"]
|
|
@@ -416,25 +480,40 @@ module RunApi
|
|
|
416
480
|
}
|
|
417
481
|
},
|
|
418
482
|
"rules" => [{
|
|
483
|
+
"when" => {
|
|
484
|
+
"model" => "kling-3.0"
|
|
485
|
+
},
|
|
486
|
+
"forbidden" => ["reference_image_urls", "reference_video_url", "reference_video_type", "preserve_reference_video_audio"]
|
|
487
|
+
}, {
|
|
488
|
+
"when" => {
|
|
489
|
+
"model" => "kling-o1"
|
|
490
|
+
},
|
|
491
|
+
"forbidden" => ["output_resolution", "negative_prompt", "cfg_scale", "multi_shots", "multi_prompt", "first_frame_image_url", "last_frame_image_url", "kling_elements"]
|
|
492
|
+
}, {
|
|
493
|
+
"when" => {
|
|
494
|
+
"model" => "kling-v2.1-master-text-to-video"
|
|
495
|
+
},
|
|
496
|
+
"forbidden" => ["mode", "reference_image_urls", "reference_video_url", "reference_video_type", "preserve_reference_video_audio"]
|
|
497
|
+
}, {
|
|
419
498
|
"when" => {
|
|
420
499
|
"model" => "kling-v2.5-turbo-text-to-video-pro"
|
|
421
500
|
},
|
|
422
|
-
"forbidden" => ["mode"]
|
|
501
|
+
"forbidden" => ["mode", "reference_image_urls", "reference_video_url", "reference_video_type", "preserve_reference_video_audio"]
|
|
423
502
|
}, {
|
|
424
503
|
"when" => {
|
|
425
504
|
"model" => "kling-v2.6"
|
|
426
505
|
},
|
|
427
|
-
"forbidden" => ["output_resolution", "negative_prompt", "cfg_scale", "multi_shots", "multi_prompt", "first_frame_image_url", "last_frame_image_url", "kling_elements"]
|
|
506
|
+
"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"]
|
|
428
507
|
}, {
|
|
429
508
|
"when" => {
|
|
430
509
|
"model" => "kling-v3-omni"
|
|
431
510
|
},
|
|
432
|
-
"forbidden" => ["negative_prompt", "cfg_scale", "multi_shots", "multi_prompt", "first_frame_image_url", "last_frame_image_url", "kling_elements"]
|
|
511
|
+
"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"]
|
|
433
512
|
}, {
|
|
434
513
|
"when" => {
|
|
435
514
|
"model" => "kling-v3-turbo-text-to-video"
|
|
436
515
|
},
|
|
437
|
-
"forbidden" => ["enable_sound", "negative_prompt", "cfg_scale", "multi_shots", "multi_prompt", "first_frame_image_url", "last_frame_image_url", "kling_elements"]
|
|
516
|
+
"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"]
|
|
438
517
|
}]
|
|
439
518
|
}
|
|
440
519
|
}.freeze
|
|
@@ -7,6 +7,7 @@ module RunApi
|
|
|
7
7
|
# Generate videos from an input image.
|
|
8
8
|
class ImageToVideo
|
|
9
9
|
include RunApi::Core::ResourceHelpers
|
|
10
|
+
include O1ReferenceValidation
|
|
10
11
|
|
|
11
12
|
ENDPOINT = "/api/v1/kling/image_to_video"
|
|
12
13
|
|
|
@@ -58,6 +59,7 @@ module RunApi
|
|
|
58
59
|
def validate_params!(params)
|
|
59
60
|
reject_unsupported_v3_turbo_fields!(params)
|
|
60
61
|
validate_contract!(CONTRACT["image-to-video"], params)
|
|
62
|
+
validate_kling_o1_references!(params)
|
|
61
63
|
|
|
62
64
|
# Bespoke last-frame rules that the generated contract cannot express.
|
|
63
65
|
model = param(params, :model)
|
|
@@ -69,7 +71,7 @@ module RunApi
|
|
|
69
71
|
return if duration_seconds.to_i == 5
|
|
70
72
|
|
|
71
73
|
raise Core::ValidationError, "last_frame_image_url requires duration_seconds 5 for #{V3_OMNI_MODEL}"
|
|
72
|
-
elsif last_frame_image_url && !%w[kling-v2.5-turbo-image-to-video-pro kling-v2.1-pro].include?(model)
|
|
74
|
+
elsif last_frame_image_url && !%w[kling-o1 kling-v2.5-turbo-image-to-video-pro kling-v2.1-pro].include?(model)
|
|
73
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"
|
|
74
76
|
end
|
|
75
77
|
end
|
|
@@ -0,0 +1,176 @@
|
|
|
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
|
|
@@ -7,6 +7,7 @@ module RunApi
|
|
|
7
7
|
# Generate videos from text prompts.
|
|
8
8
|
class TextToVideo
|
|
9
9
|
include RunApi::Core::ResourceHelpers
|
|
10
|
+
include O1ReferenceValidation
|
|
10
11
|
|
|
11
12
|
ENDPOINT = "/api/v1/kling/text_to_video"
|
|
12
13
|
|
|
@@ -62,6 +63,7 @@ module RunApi
|
|
|
62
63
|
reject_unsupported_v3_turbo_fields!(params)
|
|
63
64
|
validate_contract!(CONTRACT["text-to-video"], params)
|
|
64
65
|
validate_v26_params!(params)
|
|
66
|
+
validate_kling_o1_references!(params)
|
|
65
67
|
|
|
66
68
|
# Bespoke cross-field rules the contract cannot express.
|
|
67
69
|
multi_shots = param(params, :multi_shots) == true
|
data/lib/runapi/kling.rb
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
require "runapi/core"
|
|
4
4
|
require_relative "kling/types"
|
|
5
5
|
require_relative "kling/contract_gen"
|
|
6
|
+
require_relative "kling/resources/o1_reference_validation"
|
|
6
7
|
require_relative "kling/resources/text_to_video"
|
|
7
8
|
require_relative "kling/resources/ai_avatar"
|
|
8
9
|
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.2.
|
|
4
|
+
version: 0.2.13
|
|
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.
|
|
18
|
+
version: 0.3.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.
|
|
25
|
+
version: 0.3.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
|
|
@@ -44,6 +44,7 @@ files:
|
|
|
44
44
|
- lib/runapi/kling/resources/extend_video.rb
|
|
45
45
|
- lib/runapi/kling/resources/image_to_video.rb
|
|
46
46
|
- lib/runapi/kling/resources/motion_control.rb
|
|
47
|
+
- lib/runapi/kling/resources/o1_reference_validation.rb
|
|
47
48
|
- lib/runapi/kling/resources/text_to_video.rb
|
|
48
49
|
- lib/runapi/kling/types.rb
|
|
49
50
|
homepage: https://runapi.ai/models/kling
|