runapi-kling 0.2.2__tar.gz → 0.3.0__tar.gz

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.
@@ -1,18 +1,18 @@
1
- Metadata-Version: 2.4
1
+ Metadata-Version: 2.5
2
2
  Name: runapi-kling
3
- Version: 0.2.2
4
- Summary: RunAPI Kling SDK for text-to-video, image-to-video, avatar, and motion-control workflows in JavaScript, Python, Ruby, Go, Java, and PHP
3
+ Version: 0.3.0
4
+ Summary: RunAPI Kling SDK for text-to-video, image-to-video, source-video editing, avatar, and motion-control workflows in JavaScript, Python, Ruby, Go, Java, and PHP
5
5
  Project-URL: Homepage, https://runapi.ai/models/kling
6
6
  Project-URL: Documentation, https://runapi.ai/docs/resources/sdks
7
7
  Project-URL: Source, https://github.com/runapi-ai/kling-sdk
8
8
  Project-URL: Issues, https://github.com/runapi-ai/kling-sdk/issues
9
9
  Project-URL: Changelog, https://github.com/runapi-ai/kling-sdk/blob/main/CHANGELOG.md
10
- Project-URL: Release Notes, https://github.com/runapi-ai/kling-sdk/releases/tag/python%2Fv0.2.2
10
+ Project-URL: Release Notes, https://github.com/runapi-ai/kling-sdk/releases/tag/python%2Fv0.3.0
11
11
  Author-email: RunAPI <contact@runapi.ai>
12
12
  License-Expression: Apache-2.0
13
13
  Keywords: api,golang,gradle,java,kling,kling-ai-api,maven,python,ruby,runapi,runapi-ai,sdk,text-to-video,typescript,video-api,video-generation
14
14
  Requires-Python: >=3.9
15
- Requires-Dist: runapi-core>=0.3.3
15
+ Requires-Dist: runapi-core>=0.7.0
16
16
  Description-Content-Type: text/markdown
17
17
 
18
18
  # Kling API Python SDK for RunAPI
@@ -65,6 +65,10 @@ result = client.text_to_video.run(
65
65
 
66
66
  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.
67
67
 
68
+ ## Kling V3 Omni source-video editing
69
+
70
+ Use `kling-v3-omni-reference` with `text_to_video` for image-only reference inputs. For a source video, use `edit_video` with either `kling-v3-omni-reference` or `kling-v3-omni-edit`. The reference model keeps sound disabled for source-video requests.
71
+
68
72
  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:
69
73
 
70
74
  ```python
@@ -81,7 +85,7 @@ RunAPI-generated file URLs are temporary. Download and store generated images, v
81
85
 
82
86
  ## Language notes
83
87
 
84
- Pass parameters as keyword arguments and catch the `runapi.kling` error classes when building video jobs, workers, or scripts. The available resources are `text_to_video`, `ai_avatar`, `image_to_video`, and `motion_control`. Keep `RUNAPI_API_KEY` in the environment or your secret manager; never commit API keys or callback secrets.
88
+ Pass parameters as keyword arguments and catch the `runapi.kling` error classes when building video jobs, workers, or scripts. The available resources are `text_to_video`, `edit_video`, `ai_avatar`, `image_to_video`, and `motion_control`. Keep `RUNAPI_API_KEY` in the environment or your secret manager; never commit API keys or callback secrets.
85
89
 
86
90
  ## Links
87
91
 
@@ -48,6 +48,10 @@ result = client.text_to_video.run(
48
48
 
49
49
  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.
50
50
 
51
+ ## Kling V3 Omni source-video editing
52
+
53
+ Use `kling-v3-omni-reference` with `text_to_video` for image-only reference inputs. For a source video, use `edit_video` with either `kling-v3-omni-reference` or `kling-v3-omni-edit`. The reference model keeps sound disabled for source-video requests.
54
+
51
55
  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:
52
56
 
53
57
  ```python
@@ -64,7 +68,7 @@ RunAPI-generated file URLs are temporary. Download and store generated images, v
64
68
 
65
69
  ## Language notes
66
70
 
67
- Pass parameters as keyword arguments and catch the `runapi.kling` error classes when building video jobs, workers, or scripts. The available resources are `text_to_video`, `ai_avatar`, `image_to_video`, and `motion_control`. Keep `RUNAPI_API_KEY` in the environment or your secret manager; never commit API keys or callback secrets.
71
+ Pass parameters as keyword arguments and catch the `runapi.kling` error classes when building video jobs, workers, or scripts. The available resources are `text_to_video`, `edit_video`, `ai_avatar`, `image_to_video`, and `motion_control`. Keep `RUNAPI_API_KEY` in the environment or your secret manager; never commit API keys or callback secrets.
68
72
 
69
73
  ## Links
70
74
 
@@ -4,14 +4,14 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "runapi-kling"
7
- version = "0.2.2"
8
- description = "RunAPI Kling SDK for text-to-video, image-to-video, avatar, and motion-control workflows in JavaScript, Python, Ruby, Go, Java, and PHP"
7
+ version = "0.3.0"
8
+ description = "RunAPI Kling SDK for text-to-video, image-to-video, source-video editing, avatar, and motion-control workflows in JavaScript, Python, Ruby, Go, Java, and PHP"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.9"
11
11
  license = "Apache-2.0"
12
12
  authors = [{ name = "RunAPI", email = "contact@runapi.ai" }]
13
13
  keywords = ["runapi", "runapi-ai", "kling", "api", "sdk", "typescript", "python", "ruby", "golang", "java", "maven", "gradle", "video-generation", "text-to-video", "video-api", "kling-ai-api"]
14
- dependencies = ["runapi-core>=0.3.3"]
14
+ dependencies = ["runapi-core>=0.7.0"]
15
15
 
16
16
  [project.urls]
17
17
  Homepage = "https://runapi.ai/models/kling"
@@ -19,7 +19,7 @@ Documentation = "https://runapi.ai/docs/resources/sdks"
19
19
  Source = "https://github.com/runapi-ai/kling-sdk"
20
20
  Issues = "https://github.com/runapi-ai/kling-sdk/issues"
21
21
  Changelog = "https://github.com/runapi-ai/kling-sdk/blob/main/CHANGELOG.md"
22
- "Release Notes" = "https://github.com/runapi-ai/kling-sdk/releases/tag/python%2Fv0.2.2"
22
+ "Release Notes" = "https://github.com/runapi-ai/kling-sdk/releases/tag/python%2Fv0.3.0"
23
23
 
24
24
  [tool.hatch.build.targets.wheel]
25
25
  packages = ["src/runapi"]
@@ -7,6 +7,7 @@ from typing import Any, Optional
7
7
  from runapi.core import ProviderClient
8
8
 
9
9
  from .resources.ai_avatar import AiAvatar
10
+ from .resources.edit_video import EditVideo
10
11
  from .resources.image_to_video import ImageToVideo
11
12
  from .resources.motion_control import MotionControl
12
13
  from .resources.text_to_video import TextToVideo
@@ -32,3 +33,4 @@ class KlingClient(ProviderClient):
32
33
  self.image_to_video = ImageToVideo(http)
33
34
  self.motion_control = MotionControl(http)
34
35
  self.extend_video = ExtendVideo(http)
36
+ self.edit_video = EditVideo(http)
@@ -60,6 +60,236 @@ CONTRACT = {
60
60
  }
61
61
  }
62
62
  },
63
+ "edit-video": {
64
+ "models": ["kling-v3-omni-edit", "kling-v3-omni-reference"],
65
+ "fields_by_model": {
66
+ "kling-v3-omni-edit": {
67
+ "aspect_ratio": {
68
+ "enum": ["auto", "16:9", "9:16", "1:1"]
69
+ },
70
+ "duration_seconds": {
71
+ "enum": [3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
72
+ "type": "integer"
73
+ },
74
+ "model": {
75
+ "required": True
76
+ },
77
+ "output_resolution": {
78
+ "enum": ["720p", "1080p", "4k"]
79
+ },
80
+ "prompt": {
81
+ "required": True,
82
+ "min": 1,
83
+ "max": 2500,
84
+ "length": True
85
+ },
86
+ "reference_image_urls": {
87
+ "min_items": 1,
88
+ "max_items": 4
89
+ }
90
+ },
91
+ "kling-v3-omni-reference": {
92
+ "aspect_ratio": {
93
+ "enum": ["auto", "16:9", "9:16", "1:1"]
94
+ },
95
+ "duration_seconds": {
96
+ "enum": [3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
97
+ "type": "integer"
98
+ },
99
+ "model": {
100
+ "required": True
101
+ },
102
+ "output_resolution": {
103
+ "enum": ["720p", "1080p", "4k"]
104
+ },
105
+ "prompt": {
106
+ "required": True,
107
+ "min": 1,
108
+ "max": 2500,
109
+ "length": True
110
+ },
111
+ "reference_image_urls": {
112
+ "min_items": 1,
113
+ "max_items": 4
114
+ }
115
+ }
116
+ },
117
+ "rules": [{
118
+ "when": {
119
+ "model": "kling-v3-omni-edit",
120
+ "source_task_id": {
121
+ "present": False
122
+ },
123
+ "source_video_url": {
124
+ "present": False
125
+ }
126
+ },
127
+ "required_any": ["source_video_url", "source_task_id"]
128
+ }, {
129
+ "when": {
130
+ "model": "kling-v3-omni-edit",
131
+ "source_video_url": {
132
+ "present": True
133
+ }
134
+ },
135
+ "forbidden": ["source_task_id"]
136
+ }, {
137
+ "when": {
138
+ "model": "kling-v3-omni-edit",
139
+ "source_task_id": {
140
+ "present": True
141
+ }
142
+ },
143
+ "forbidden": ["source_video_url"]
144
+ }, {
145
+ "enum": {
146
+ "aspect_ratio": ["auto"],
147
+ "duration_seconds": [5]
148
+ },
149
+ "when": {
150
+ "model": "kling-v3-omni-edit",
151
+ "source_video_url": {
152
+ "present": True
153
+ },
154
+ "reference_image_urls": {
155
+ "present": False
156
+ }
157
+ },
158
+ "required": ["aspect_ratio"]
159
+ }, {
160
+ "enum": {
161
+ "aspect_ratio": ["auto"],
162
+ "duration_seconds": [5]
163
+ },
164
+ "when": {
165
+ "model": "kling-v3-omni-edit",
166
+ "source_task_id": {
167
+ "present": True
168
+ },
169
+ "reference_image_urls": {
170
+ "present": False
171
+ }
172
+ },
173
+ "required": ["aspect_ratio"]
174
+ }, {
175
+ "enum": {
176
+ "aspect_ratio": ["16:9", "9:16", "1:1"]
177
+ },
178
+ "when": {
179
+ "model": "kling-v3-omni-edit",
180
+ "source_video_url": {
181
+ "present": True
182
+ },
183
+ "reference_image_urls": {
184
+ "present": True
185
+ }
186
+ },
187
+ "required": ["aspect_ratio"]
188
+ }, {
189
+ "enum": {
190
+ "aspect_ratio": ["16:9", "9:16", "1:1"]
191
+ },
192
+ "when": {
193
+ "model": "kling-v3-omni-edit",
194
+ "source_task_id": {
195
+ "present": True
196
+ },
197
+ "reference_image_urls": {
198
+ "present": True
199
+ }
200
+ },
201
+ "required": ["aspect_ratio"]
202
+ }, {
203
+ "when": {
204
+ "model": "kling-v3-omni-reference",
205
+ "source_task_id": {
206
+ "present": False
207
+ },
208
+ "source_video_url": {
209
+ "present": False
210
+ }
211
+ },
212
+ "required_any": ["source_video_url", "source_task_id"]
213
+ }, {
214
+ "when": {
215
+ "model": "kling-v3-omni-reference",
216
+ "source_video_url": {
217
+ "present": True
218
+ }
219
+ },
220
+ "forbidden": ["source_task_id"]
221
+ }, {
222
+ "when": {
223
+ "model": "kling-v3-omni-reference",
224
+ "source_task_id": {
225
+ "present": True
226
+ }
227
+ },
228
+ "forbidden": ["source_video_url"]
229
+ }, {
230
+ "enum": {
231
+ "aspect_ratio": ["auto"],
232
+ "enable_sound": [False],
233
+ "duration_seconds": [5]
234
+ },
235
+ "when": {
236
+ "model": "kling-v3-omni-reference",
237
+ "source_video_url": {
238
+ "present": True
239
+ },
240
+ "reference_image_urls": {
241
+ "present": False
242
+ }
243
+ },
244
+ "required": ["aspect_ratio"]
245
+ }, {
246
+ "enum": {
247
+ "aspect_ratio": ["auto"],
248
+ "enable_sound": [False],
249
+ "duration_seconds": [5]
250
+ },
251
+ "when": {
252
+ "model": "kling-v3-omni-reference",
253
+ "source_task_id": {
254
+ "present": True
255
+ },
256
+ "reference_image_urls": {
257
+ "present": False
258
+ }
259
+ },
260
+ "required": ["aspect_ratio"]
261
+ }, {
262
+ "enum": {
263
+ "aspect_ratio": ["16:9", "9:16", "1:1"],
264
+ "enable_sound": [False]
265
+ },
266
+ "when": {
267
+ "model": "kling-v3-omni-reference",
268
+ "source_video_url": {
269
+ "present": True
270
+ },
271
+ "reference_image_urls": {
272
+ "present": True
273
+ }
274
+ },
275
+ "required": ["aspect_ratio"]
276
+ }, {
277
+ "enum": {
278
+ "aspect_ratio": ["16:9", "9:16", "1:1"],
279
+ "enable_sound": [False]
280
+ },
281
+ "when": {
282
+ "model": "kling-v3-omni-reference",
283
+ "source_task_id": {
284
+ "present": True
285
+ },
286
+ "reference_image_urls": {
287
+ "present": True
288
+ }
289
+ },
290
+ "required": ["aspect_ratio"]
291
+ }]
292
+ },
63
293
  "extend-video": {
64
294
  "models": ["kling-v2.5-turbo-image-to-video-pro", "kling-v2.5-turbo-text-to-video-pro"],
65
295
  "fields_by_model": {
@@ -342,7 +572,7 @@ CONTRACT = {
342
572
  }]
343
573
  },
344
574
  "text-to-video": {
345
- "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"],
575
+ "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"],
346
576
  "fields_by_model": {
347
577
  "kling-3.0": {
348
578
  "aspect_ratio": {
@@ -453,6 +683,33 @@ CONTRACT = {
453
683
  "length": True
454
684
  }
455
685
  },
686
+ "kling-v3-omni-reference": {
687
+ "aspect_ratio": {
688
+ "enum": ["16:9", "9:16", "1:1"],
689
+ "required": True
690
+ },
691
+ "duration_seconds": {
692
+ "enum": [3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
693
+ "type": "integer"
694
+ },
695
+ "model": {
696
+ "required": True
697
+ },
698
+ "output_resolution": {
699
+ "enum": ["720p", "1080p", "4k"]
700
+ },
701
+ "prompt": {
702
+ "required": True,
703
+ "min": 1,
704
+ "max": 2500,
705
+ "length": True
706
+ },
707
+ "reference_image_urls": {
708
+ "required": True,
709
+ "min_items": 1,
710
+ "max_items": 7
711
+ }
712
+ },
456
713
  "kling-v3-turbo-text-to-video": {
457
714
  "aspect_ratio": {
458
715
  "enum": ["16:9", "9:16", "1:1"]
@@ -1,7 +1,8 @@
1
1
  from .ai_avatar import AiAvatar
2
+ from .edit_video import EditVideo
2
3
  from .extend_video import ExtendVideo
3
4
  from .image_to_video import ImageToVideo
4
5
  from .motion_control import MotionControl
5
6
  from .text_to_video import TextToVideo
6
7
 
7
- __all__ = ["TextToVideo", "AiAvatar", "ImageToVideo", "MotionControl", "ExtendVideo"]
8
+ __all__ = ["TextToVideo", "AiAvatar", "EditVideo", "ImageToVideo", "MotionControl", "ExtendVideo"]
@@ -0,0 +1,33 @@
1
+ """Kling source-video editing resource."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Any, Optional
6
+
7
+ from runapi.core import RequestOptions, Resource
8
+
9
+ from ..contract_gen import CONTRACT
10
+ from ..types import CompletedTextToVideoResponse, TextToVideoResponse
11
+
12
+
13
+ class EditVideo(Resource):
14
+ """Edit a source video with a selected Kling V3 Omni model."""
15
+
16
+ ENDPOINT = "/api/v1/kling/edit_video"
17
+ RESPONSE_CLASS = TextToVideoResponse
18
+ COMPLETED_RESPONSE_CLASS = CompletedTextToVideoResponse
19
+
20
+ def run(self, options: Optional[RequestOptions] = None, **params: Any) -> Any:
21
+ """Create an edit-video task and poll until it completes."""
22
+ task = self.create(options=options, **params)
23
+ return self._poll_until_complete(lambda: self.get(task.id, options=options))
24
+
25
+ def create(self, options: Optional[RequestOptions] = None, **params: Any) -> Any:
26
+ """Create an edit-video task with a caller-supplied model."""
27
+ compacted = self._compact_params(params)
28
+ self._validate_contract(CONTRACT["edit-video"], compacted)
29
+ return self._request("post", self.ENDPOINT, body=compacted, options=options)
30
+
31
+ def get(self, id: str, options: Optional[RequestOptions] = None) -> Any:
32
+ """Fetch the current status of an edit-video task."""
33
+ return self._request("get", f"{self.ENDPOINT}/{id}", options=options)
@@ -4,6 +4,7 @@ from runapi.core import config
4
4
  from runapi.core.errors import AuthenticationError, ValidationError
5
5
  from runapi.kling import KlingClient
6
6
  from runapi.kling.resources.ai_avatar import AiAvatar
7
+ from runapi.kling.resources.edit_video import EditVideo
7
8
  from runapi.kling.resources.image_to_video import ImageToVideo
8
9
  from runapi.kling.resources.motion_control import MotionControl
9
10
  from runapi.kling.resources.text_to_video import TextToVideo
@@ -70,6 +71,7 @@ def test_uses_injected_http_client():
70
71
  assert client.ai_avatar._http is fake
71
72
  assert client.image_to_video._http is fake
72
73
  assert client.motion_control._http is fake
74
+ assert client.edit_video._http is fake
73
75
 
74
76
 
75
77
  def test_exposes_resource_accessors():
@@ -78,6 +80,7 @@ def test_exposes_resource_accessors():
78
80
  assert isinstance(client.ai_avatar, AiAvatar)
79
81
  assert isinstance(client.image_to_video, ImageToVideo)
80
82
  assert isinstance(client.motion_control, MotionControl)
83
+ assert isinstance(client.edit_video, EditVideo)
81
84
 
82
85
 
83
86
  # --- text_to_video --------------------------------------------------------
@@ -1046,3 +1049,68 @@ def test_multi_prompt_non_numeric_duration_raises_validation_error():
1046
1049
  enable_sound=True,
1047
1050
  multi_prompt=[{"prompt": "shot one", "duration_seconds": "abc"}],
1048
1051
  )
1052
+
1053
+
1054
+ def test_text_to_video_accepts_reference_image_model():
1055
+ fake = FakeHttp({"id": "reference-image", "status": "processing"})
1056
+ client = KlingClient(api_key="k", http_client=fake)
1057
+ params = {
1058
+ "model": "kling-v3-omni-reference",
1059
+ "prompt": "Keep the subject from the reference image",
1060
+ "reference_image_urls": ["https://cdn.runapi.ai/public/samples/image.jpg"],
1061
+ "aspect_ratio": "16:9",
1062
+ }
1063
+
1064
+ client.text_to_video.create(**params)
1065
+ assert fake.calls == [("post", "/api/v1/kling/text_to_video", params)]
1066
+
1067
+
1068
+ def test_edit_video_create_get_and_run_for_edit_model():
1069
+ fake = FakeHttp(
1070
+ {"id": "edit-create", "status": "processing"},
1071
+ {"id": "edit-get", "status": "processing"},
1072
+ {"id": "edit-run", "status": "processing"},
1073
+ {"id": "edit-run", "status": "completed", "videos": [{"url": "https://file.runapi.ai/edit.mp4"}]},
1074
+ )
1075
+ client = KlingClient(api_key="k", http_client=fake)
1076
+ params = {
1077
+ "model": "kling-v3-omni-edit",
1078
+ "prompt": "Turn the source video into a watercolor scene",
1079
+ "source_video_url": "https://cdn.runapi.ai/public/samples/video.mp4",
1080
+ "aspect_ratio": "auto",
1081
+ }
1082
+
1083
+ client.edit_video.create(**params)
1084
+ client.edit_video.get("edit-get")
1085
+ result = client.edit_video.run(**params)
1086
+
1087
+ assert fake.calls == [
1088
+ ("post", "/api/v1/kling/edit_video", params),
1089
+ ("get", "/api/v1/kling/edit_video/edit-get", None),
1090
+ ("post", "/api/v1/kling/edit_video", params),
1091
+ ("get", "/api/v1/kling/edit_video/edit-run", None),
1092
+ ]
1093
+ assert result.status == "completed"
1094
+
1095
+
1096
+ def test_edit_video_accepts_reference_model_and_requires_model():
1097
+ fake = FakeHttp({"id": "reference-create", "status": "processing"})
1098
+ client = KlingClient(api_key="k", http_client=fake)
1099
+ params = {
1100
+ "model": "kling-v3-omni-reference",
1101
+ "prompt": "Keep the subject from the reference image",
1102
+ "source_video_url": "https://cdn.runapi.ai/public/samples/video.mp4",
1103
+ "reference_image_urls": ["https://cdn.runapi.ai/public/samples/image.jpg"],
1104
+ "aspect_ratio": "16:9",
1105
+ "enable_sound": False,
1106
+ }
1107
+
1108
+ client.edit_video.create(**params)
1109
+ assert fake.calls == [("post", "/api/v1/kling/edit_video", params)]
1110
+
1111
+ with pytest.raises(ValidationError, match="model must be one of"):
1112
+ client.edit_video.create(
1113
+ prompt="Turn the source video into a watercolor scene",
1114
+ source_video_url="https://cdn.runapi.ai/public/samples/video.mp4",
1115
+ aspect_ratio="auto",
1116
+ )