diff --git a/kie_api/kling3_video.py b/kie_api/kling3_video.py index 9ca0866..6783326 100644 --- a/kie_api/kling3_video.py +++ b/kie_api/kling3_video.py @@ -256,6 +256,12 @@ def _build_kling3_payload( for shot in payload_input.get("multi_prompt", []): referenced |= _extract_referenced_elements(str(shot.get("prompt") or "")) + if referenced and not frame_urls: + raise _validation_error( + "Prompt uses @element references but no first_frame/image_urls were provided. " + "Connect first_frame when using elements." + ) + if elements: if len(elements) > ELEMENT_BATCH_MAX: raise _validation_error(f"At most {ELEMENT_BATCH_MAX} elements are supported in this node.") diff --git a/nodes.py b/nodes.py index 43dd69e..8201816 100644 --- a/nodes.py +++ b/nodes.py @@ -793,6 +793,11 @@ Rules: Outputs: - VIDEO: ComfyUI video output compatible with SaveVideo """ + SHOTS_TEXT_PLACEHOLDER = ( + "shot1 | 4 | Wide cinematic opening with @element_name\n" + "shot2 | 3 | Medium tracking shot with @element_name\n" + "shot3 | 3 | Close-up emotional finale with @element_name" + ) @classmethod def INPUT_TYPES(cls): @@ -805,7 +810,7 @@ Outputs: "prompt": ("STRING", {"multiline": True, "default": ""}), }, "optional": { - "shots_text": ("STRING", {"multiline": True, "default": ""}), + "shots_text": ("STRING", {"multiline": True, "default": cls.SHOTS_TEXT_PLACEHOLDER}), "first_frame": ("IMAGE",), "last_frame": ("IMAGE",), "sound": ("BOOLEAN", {"default": True}), @@ -885,6 +890,11 @@ Outputs: - STRING: payload_json (exact payload that would be sent to createTask) - STRING: notes """ + SHOTS_TEXT_PLACEHOLDER = ( + "shot1 | 4 | Wide cinematic opening with @element_name\n" + "shot2 | 3 | Medium tracking shot with @element_name\n" + "shot3 | 3 | Close-up emotional finale with @element_name" + ) @classmethod def INPUT_TYPES(cls): @@ -897,7 +907,7 @@ Outputs: "prompt": ("STRING", {"multiline": True, "default": ""}), }, "optional": { - "shots_text": ("STRING", {"multiline": True, "default": ""}), + "shots_text": ("STRING", {"multiline": True, "default": cls.SHOTS_TEXT_PLACEHOLDER}), "first_frame": ("IMAGE",), "last_frame": ("IMAGE",), "sound": ("BOOLEAN", {"default": True}), @@ -954,10 +964,37 @@ Outputs: elements=merged_elements, log=log, ) - notes = ( - "Preflight only: payload built after validation/uploads. " - "No createTask call was made." - ) + payload_input = payload.get("input", {}) + image_urls = payload_input.get("image_urls") or [] + has_aspect_ratio = "aspect_ratio" in payload_input + element_items = payload_input.get("kling_elements") or [] + element_names = [ + str(item.get("name")).strip() + for item in element_items + if isinstance(item, dict) and item.get("name") + ] + + notes_lines = [ + "VALID: Kling 3.0 preflight checks passed.", + "No createTask call was made.", + f"Mode: {payload_input.get('mode')}", + f"Multi-shots: {payload_input.get('multi_shots')}", + f"Duration sent: {payload_input.get('duration')}s", + f"Frame inputs resolved: {len(image_urls)}", + f"Aspect ratio in payload: {'yes' if has_aspect_ratio else 'no (auto from start/end frames)'}", + f"Elements provided: {len(element_items)}", + ] + + if payload_input.get("multi_shots"): + shot_count = len(payload_input.get("multi_prompt") or []) + notes_lines.append(f"Shot count: {shot_count}") + else: + notes_lines.append(f"Sound enabled: {bool(payload_input.get('sound', False))}") + + if element_names: + notes_lines.append("Element names: " + ", ".join(element_names)) + + notes = "\n".join(notes_lines) return (json.dumps(payload, indent=2, ensure_ascii=False), notes) diff --git a/web/docs/KIE_Kling3_Preflight.md b/web/docs/KIE_Kling3_Preflight.md index 663c730..29e6432 100644 --- a/web/docs/KIE_Kling3_Preflight.md +++ b/web/docs/KIE_Kling3_Preflight.md @@ -14,8 +14,13 @@ Validate Kling 3.0 inputs and build the exact payload JSON without submitting a ## Outputs - `payload_json` (STRING): exact request payload after validation and upload URL resolution. -- `notes` (STRING): confirms this node does not call `createTask`. +- `notes` (STRING): validation summary with detected settings and status. ## Notes - This node still uploads required input media to produce valid URLs in payload. - In multi-shot mode, duration is auto-calculated from shot durations. +- `notes` returns a `VALID` summary when checks pass, including: + - mode, single/multi-shot status, resolved duration + - frame count and aspect-ratio handling + - element count and names + - shot count (multi-shot) or sound status (single-shot) diff --git a/web/docs/KIE_Kling3_Video.md b/web/docs/KIE_Kling3_Video.md index d0c2a8e..f7033bd 100644 --- a/web/docs/KIE_Kling3_Video.md +++ b/web/docs/KIE_Kling3_Video.md @@ -3,6 +3,7 @@ Generate Kling 3.0 videos in single-shot or multi-shot mode. > Status: Experimental (development pass). Not production-ready yet. +> Credit Warning: Kling 3.0 can consume significant credits. Use `KIE Kling 3.0 Preflight` first. ## Inputs - `mode` (COMBO): `std` or `pro` @@ -27,8 +28,47 @@ Generate Kling 3.0 videos in single-shot or multi-shot mode. - shot durations are summed automatically and sent as the final payload duration - If both start and end frames are provided, aspect ratio is auto-adapted from frames. - `@element_name` references in prompt(s) must match provided elements. +- If prompts use `@element_name`, connect `first_frame` (KIE requires image_urls for element-referenced prompts). +- If no frames and no elements are used, the node runs as text-to-video. - Multi-shot total duration must stay within `3..15` seconds. +## Prompt vs Multi-Prompt +- Single-shot (`multi_shots=false`): use `prompt`. +- Multi-shot (`multi_shots=true`): use `shots_text` only. +- `shots_text` format: + - `duration | prompt` + - or `label | duration | prompt` +- Example: + - `shot1 | 4 | A woman exits a spaceship with @dog` + - `shot2 | 3 | Medium tracking shot of @dog running` + - `shot3 | 3 | Emotional close-up of @dog and @old_woman` + +## Element Naming and References +- Define elements upstream with `KIE Kling Elements`. +- Batch them with `KIE Kling Elements Batch`. +- Reference in prompt with `@element_name`. +- Allowed element names: letters, numbers, `_`, `-` only. +- Spaces in element names are invalid. + +## Scenario Matrix +- Single-shot with first frame only: + - Valid +- Single-shot with first + last frame: + - Valid + - `aspect_ratio` omitted in payload (auto-adapt from frames) +- Multi-shot with first frame only: + - Valid +- Multi-shot with last frame connected: + - Invalid +- Multi-shot with sound enabled: + - Invalid +- Prompt references `@element` but elements missing: + - Invalid +- Prompt references `@element` but first frame missing: + - Invalid +- No frames, no elements: + - Valid text-to-video + ## Cost note - Kling 3.0 usage cost is tied to generated duration. - In multi-shot mode, cost follows the computed total shot duration (max 15s).