Kling 3.0: 1 Click Multishot
Upload a start frame and references of your product. Select total duration and number of shots and automatically generate prompts for each shot.
简介
The 'Kling 3.0: 1 Click Multishot' workflow is designed to streamline the process of creating dynamic video content from static images. By leveraging the Kling 3.0 model, this workflow allows users to upload a starting frame along with reference images of a product, then automatically generates a series of prompts for each shot based on the specified duration and number of shots.
The workflow utilizes several specialized nodes, including the KlingOmniProImageToVideoNode for transforming images into video sequences and the comfyui-string-converter for managing prompt data. This setup is particularly useful for content creators and marketers looking to produce engaging video content quickly and efficiently, without the need for extensive manual input.
你需要提供
- 正在读取工作流
在 ComfyUI 中运行。 此工作流无法在本页面运行。你可以在 Comfy Cloud 中打开(已预先加载所需内容),或下载后在自己的 ComfyUI 中使用。
在 Cloud 中试用查看工作流内部
节点图的只读预览。在 Comfy Cloud 中打开或下载后即可编辑节点。
Loading the graph
Open full-size workflow preview- 作者
- Rob
需要自定义节点
- 正在读取工作流
通过代码使用此工作流
尽可能根据工作流图和输入自动生成代码,否则显示已保存的示例。运行代码可能产生费用,请先核对凭据和端点。
What you need
- Runs on
- Comfy Cloud
- 密钥
- COMFY_API_KEY
需要付费的 Cloud 方案和额度。
# Python 3.10+: pip install comfy-sdk==0.4.0
import os
from comfy_sdk import Comfy
api_key = os.environ.get("COMFY_API_KEY", "").strip()
if not api_key: raise RuntimeError("Set COMFY_API_KEY")
os.environ.setdefault("COMFY_BASE_URL", "https://cloud.comfy.org")
client = Comfy(api_key=api_key)
workflow = client.workflows.from_json({
"4": {
"class_type": "LoadImage",
"inputs": {
"image": "comfy_gpu_angled.png"
},
"_meta": {
"title": "Load Start Frame Image"
}
},
"8": {
"class_type": "LoadImage",
"inputs": {
"image": "comfy_gpu_flat.png"
},
"_meta": {
"title": "Load Product Image 1"
}
},
"12": {
"class_type": "LoadImage",
"inputs": {
"image": "comfy_gpu_close_up.png"
},
"_meta": {
"title": "Load Product Image 2"
}
},
"22": {
"class_type": "PrimitiveInt",
"inputs": {
"value": 8
},
"_meta": {
"title": "Number of Seconds (3-15)"
}
},
"23": {
"class_type": "PrimitiveInt",
"inputs": {
"value": 2
},
"_meta": {
"title": "Number of Shots (1-6)"
}
},
"32": {
"class_type": "PreviewAny",
"inputs": {
"source": [
"91:31",
0
]
},
"_meta": {
"title": "Shot 1: Prompt"
}
},
"35": {
"class_type": "PreviewAny",
"inputs": {
"source": [
"91:36",
0
]
},
"_meta": {
"title": "Shot 1: # of Seconds"
}
},
"37": {
"class_type": "PreviewAny",
"inputs": {
"source": [
"91:39",
0
]
},
"_meta": {
"title": "Shot 2: Prompt"
}
},
"38": {
"class_type": "PreviewAny",
"inputs": {
"source": [
"91:40",
0
]
},
"_meta": {
"title": "Shot 2: # of Seconds"
}
},
"46": {
"class_type": "PreviewAny",
"inputs": {
"source": [
"91:49",
0
]
},
"_meta": {
"title": "Shot 3: Prompt"
}
},
"47": {
"class_type": "PreviewAny",
"inputs": {
"source": [
"91:48",
0
]
},
"_meta": {
"title": "Shot 3: # of Seconds"
}
},
"52": {
"class_type": "PreviewAny",
"inputs": {
"source": [
"91:62",
0
]
},
"_meta": {
"title": "Shot 4: # of Seconds"
}
},
"53": {
"class_type": "PreviewAny",
"inputs": {
"source": [
"91:60",
0
]
},
"_meta": {
"title": "Shot 5: Prompt"
}
},
"54": {
"class_type": "PreviewAny",
"inputs": {
"source": [
"91:55",
0
]
},
"_meta": {
"title": "Shot 5: # of Seconds"
}
},
"57": {
"class_type": "PreviewAny",
"inputs": {
"source": [
"91:58",
0
]
},
"_meta": {
"title": "Shot 6: # of Seconds"
}
},
"136": {
"class_type": "StringToInt",
"inputs": {
"data": [
"91:36",
0
]
},
"_meta": {
"title": "Shot 1: Duration"
}
},
"137": {
"class_type": "StringToInt",
"inputs": {
"data": [
"91:40",
0
]
},
"_meta": {
"title": "Shot 2: Duration"
}
},
"138": {
"class_type": "StringToInt",
"inputs": {
"data": [
"91:48",
0
]
},
"_meta": {
"title": "Shot 3: Duration"
}
},
"139": {
"class_type": "StringToInt",
"inputs": {
"data": [
"91:58",
0
]
},
"_meta": {
"title": "Shot 6: Duration"
}
},
"140": {
"class_type": "StringToInt",
"inputs": {
"data": [
"91:62",
0
]
},
"_meta": {
"title": "Shot 4: Duration"
}
},
"141": {
"class_type": "StringToInt",
"inputs": {
"data": [
"91:55",
0
]
},
"_meta": {
"title": "Shot 5: Duration"
}
},
"145": {
"class_type": "PreviewAny",
"inputs": {
"source": [
"91:59",
0
]
},
"_meta": {
"title": "Shot 4: Prompt"
}
},
"148": {
"class_type": "PreviewAny",
"inputs": {
"source": [
"91:61",
0
]
},
"_meta": {
"title": "Shot 6: Prompt"
}
},
"149": {
"class_type": "PrimitiveStringMultiline",
"inputs": {
"value": "You are a creative director and video prompt specialist. Your job is to analyze a product image and generate a sequence of cinematic video prompts for a multi-shot product advertisement.\n\n---\n\n## INPUT\nYou will receive:\n- A product image (used as the visual start frame for Shot 1 only)\n- {N_SHOTS}: the number of shots to generate (1–6)\n- {N_SECONDS}: the total cumulative duration across all shots (max 15 seconds)\n- {USER_STORY}: optional creative direction for vibe, narrative, or tone\n\n---\n\n## STEP 1 — ANALYZE THE IMAGE\nBefore writing any prompts, internally assess the following from the product image:\n- Product type, shape, color, material, and finish\n- Existing lighting mood (hard/soft, warm/cool, dramatic/flat)\n- Background environment — describe it precisely and literally: surface type, color, texture, depth, atmospheric elements (e.g. \"matte dark grey surface, no visible background, soft overhead diffusion\"). This description becomes a locked constant for all shots.\n- Implied brand positioning (luxury, minimal, bold, playful, clinical, etc.)\n\nIf {USER_STORY} is provided, let it override or augment your inferred vibe. If it is empty, rely entirely on your image analysis.\n\n---\n\n## STEP 2 — ASSIGN A SHOT SEQUENCE\nMap {N_SHOTS} to a logical ad narrative arc. Use this as your guide:\n\n| Shot Role | Purpose |\n|---------------|------------------------------------------------------|\n| Hero (Shot 1) | Product reveal — slow, confident, visually grounding |\n| Detail | Extreme close-up of texture, material, or finish |\n| Feature | Product in action, reacting to environment or use |\n| Lifestyle | Product in its natural world or context |\n| Outro | Pull back, final beauty angle, or ambient close |\n\nCompress or expand the arc based on shot count:\n- 1–2 shots: Hero + Outro only\n- 3 shots: Hero, Feature, Outro\n- 4 shots: Hero, Detail, Feature, Outro\n- 5 shots: Hero, Detail, Feature, Lifestyle, Outro\n- 6 shots: Hero, Detail, Detail, Feature, Lifestyle, Outro\n\n---\n\n## STEP 3 — ALLOCATE DURATIONS\nDistribute seconds across shots. Rules:\n- All durations must be integers (whole seconds)\n- Total must equal exactly {N_SECONDS}\n- Weight durations by shot role and inferred pacing:\n - Luxury/cinematic vibe: favor longer Hero and Outro, compress middle shots\n - Energetic/bold vibe: distribute more evenly, keep all shots punchy\n - Default weighting: Hero gets ~25%, Outro gets ~20%, remaining shots split the rest\n\n---\n\n## STEP 4 — WRITE THE PROMPTS\n\n**Shot 1 (I2V — Image to Video):**\nThe product image is the literal start frame. Write a prompt that describes the motion and camera behavior starting from that exact frame. Do not re-describe the product appearance — describe only what moves and how.\n\n**Shots 2–N (T2V — Text to Video):**\nEach prompt must be fully self-contained. Describe the product, the scene, the camera, and the motion clearly enough that a video model with no prior context can generate a coherent, on-brand clip. You must preserve the exact environment from the input image — the same surface, background, depth, and atmosphere. Do not introduce new environments, floors, settings, or atmospheric elements (mist, smoke, reflections, etc.) that were not present in the input image. The environment is a locked constant, not a creative variable.\n\n**Prompt writing rules (apply to all shots):**\n- Write in present tense, descriptive and directive\n- Lead with the most important visual element\n- Specify: camera angle, camera motion, subject action, lighting, mood\n- Keep each prompt between 40–80 words — specific but not overloaded\n- No marketing copy, no voiceover text, no titles or graphics\n- Each shot must feel visually distinct from the others — vary angle, distance, and motion meaningfully\n\n---\n\n## OUTPUT FORMAT\nOutput only the tagged shot blocks. No preamble, no explanation, no additional text.\n\n<shot1_duration>N</shot1_duration>\n<shot1_prompt>Prompt text here</shot1_prompt>\n\n<shot2_duration>N</shot2_duration>\n<shot2_prompt>Prompt text here</shot2_prompt>\n\n...and so on for all {N_SHOTS} shots."
},
"_meta": {
"title": "System Prompt"
}
},
"164": {
"class_type": "GeminiNode",
"inputs": {
"images": [
"4",
0
],
"model": "gemini-3-pro-preview",
"prompt": [
"81:79",
0
],
"seed": 11185935742735,
"system_prompt": [
"149",
0
]
},
"_meta": {
"title": "Google Gemini"
}
},
"165": {
"class_type": "PrimitiveStringMultiline",
"inputs": {
"value": ""
},
"_meta": {
"title": "Prompt Input (copy/paste prompt here to lock)"
}
},
"166": {
"class_type": "PreviewAny",
"inputs": {
"source": [
"164",
0
]
},
"_meta": {
"title": "Preview All Prompts"
}
},
"110:14": {
"class_type": "GetImageSize",
"inputs": {
"image": [
"4",
0
]
},
"_meta": {
"title": "Get Image Size"
}
},
"110:15": {
"class_type": "ResizeAndPadImage",
"inputs": {
"image": [
"8",
0
],
"interpolation": "area",
"padding_color": "white",
"target_height": [
"110:14",
1
],
"target_width": [
"110:14",
0
]
},
"_meta": {
"title": "Resize And Pad Image"
}
},
"110:16": {
"class_type": "ResizeAndPadImage",
"inputs": {
"image": [
"12",
0
],
"interpolation": "area",
"padding_color": "white",
"target_height": [
"110:14",
1
],
"target_width": [
"110:14",
0
]
},
"_meta": {
"title": "Resize And Pad Image"
}
},
"110:6": {
"class_type": "BatchImagesNode",
"inputs": {
"images.image0": [
"4",
0
],
"images.image1": [
"110:15",
0
],
"images.image2": [
"110:16",
0
]
},
"_meta": {
"title": "Batch Images"
}
},
"115:111": {
"class_type": "ComfySwitchNode",
"inputs": {
"on_false": [
"165",
0
],
"on_true": [
"164",
0
],
"switch": [
"115:112",
0
]
},
"_meta": {
"title": "If/Else Switch"
}
},
"115:112": {
"class_type": "StringCompare",
"inputs": {
"case_sensitive": False,
"mode": "Equal",
"string_a": [
"165",
0
],
"string_b": [
"115:113",
0
]
},
"_meta": {
"title": "Compare Text"
}
},
"115:113": {
"class_type": "PrimitiveString",
"inputs": {
"value": ""
},
"_meta": {
"title": "Empty String"
}
},
"81:76": {
"class_type": "SomethingToString",
"inputs": {
"input": [
"23",
0
],
"prefix": "",
"suffix": ""
},
"_meta": {
"title": "Something To String"
}
},
"81:77": {
"class_type": "SomethingToString",
"inputs": {
"input": [
"22",
0
],
"prefix": "",
"suffix": ""
},
"_meta": {
"title": "Something To String"
}
},
"81:78": {
"class_type": "RegexReplace",
"inputs": {
"case_insensitive": True,
"count": 0,
"dotall": False,
"multiline": False,
"regex_pattern": "N_SHOTS",
"replace": [
"81:76",
0
],
"string": [
"81:80",
0
]
},
"_meta": {
"title": "Replace Text (Regex)"
}
},
"81:79": {
"class_type": "RegexReplace",
"inputs": {
"case_insensitive": True,
"count": 0,
"dotall": False,
"multiline": False,
"regex_pattern": "N_SECONDS",
"replace": [
"81:77",
0
],
"string": [
"81:78",
0
]
},
"_meta": {
"title": "Replace Text (Regex)"
}
},
"81:80": {
"class_type": "Text Multiline",
"inputs": {
"text": "Use the input image 1, create a prompt that has N_SHOTS distinct shots. The total time for the shots is N_SECONDS. \n\nUSER_STORY."
},
"_meta": {
"title": "Template User Prompt"
}
},
"91:31": {
"class_type": "RegexExtract",
"inputs": {
"case_insensitive": True,
"dotall": False,
"group_index": 1,
"mode": "First Group",
"multiline": True,
"regex_pattern": "<shot1_prompt>(.+)</shot1_prompt>",
"string": [
"115:111",
0
]
},
"_meta": {
"title": "Extract Text"
}
},
"91:36": {
"class_type": "RegexExtract",
"inputs": {
"case_insensitive": True,
"dotall": False,
"group_index": 1,
"mode": "First Group",
"multiline": True,
"regex_pattern": "<shot1_duration>(\\d+)</shot1_duration>",
"string": [
"115:111",
0
]
},
"_meta": {
"title": "Extract Text"
}
},
"91:39": {
"class_type": "RegexExtract",
"inputs": {
"case_insensitive": True,
"dotall": False,
"group_index": 1,
"mode": "First Group",
"multiline": True,
"regex_pattern": "<shot2_prompt>(.+)</shot2_prompt>",
"string": [
"115:111",
0
]
},
"_meta": {
"title": "Extract Text"
}
},
"91:40": {
"class_type": "RegexExtract",
"inputs": {
"case_insensitive": True,
"dotall": False,
"group_index": 1,
"mode": "First Group",
"multiline": True,
"regex_pattern": "<shot2_duration>(\\d+)</shot2_duration>",
"string": [
"115:111",
0
]
},
"_meta": {
"title": "Extract Text"
}
},
"91:48": {
"class_type": "RegexExtract",
"inputs": {
"case_insensitive": True,
"dotall": False,
"group_index": 1,
"mode": "First Group",
"multiline": True,
"regex_pattern": "<shot3_duration>(\\d+)</shot3_duration>",
"string": [
"115:111",
0
]
},
"_meta": {
"title": "Extract Text"
}
},
"91:49": {
"class_type": "RegexExtract",
"inputs": {
"case_insensitive": True,
"dotall": False,
"group_index": 1,
"mode": "First Group",
"multiline": True,
"regex_pattern": "<shot3_prompt>(.+)</shot3_prompt>",
"string": [
"115:111",
0
]
},
"_meta": {
"title": "Extract Text"
}
},
"91:55": {
"class_type": "RegexExtract",
"inputs": {
"case_insensitive": True,
"dotall": False,
"group_index": 1,
"mode": "First Group",
"multiline": True,
"regex_pattern": "<shot5_duration>(\\d+)</shot5_duration>",
"string": [
"115:111",
0
]
},
"_meta": {
"title": "Extract Text"
}
},
"91:58": {
"class_type": "RegexExtract",
"inputs": {
"case_insensitive": True,
"dotall": False,
"group_index": 1,
"mode": "First Group",
"multiline": True,
"regex_pattern": "<shot6_duration>(\\d+)</shot6_duration>",
"string": [
"115:111",
0
]
},
"_meta": {
"title": "Extract Text"
}
},
"91:59": {
"class_type": "RegexExtract",
"inputs": {
"case_insensitive": True,
"dotall": False,
"group_index": 1,
"mode": "First Group",
"multiline": True,
"regex_pattern": "<shot4_prompt>(.+)</shot4_prompt>",
"string": [
"115:111",
0
]
},
"_meta": {
"title": "Extract Text"
}
},
"91:60": {
"class_type": "RegexExtract",
"inputs": {
"case_insensitive": True,
"dotall": False,
"group_index": 1,
"mode": "First Group",
"multiline": True,
"regex_pattern": "<shot5_prompt>(.+)</shot5_prompt>",
"string": [
"115:111",
0
]
},
"_meta": {
"title": "Extract Text"
}
},
"91:61": {
"class_type": "RegexExtract",
"inputs": {
"case_insensitive": True,
"dotall": False,
"group_index": 1,
"mode": "First Group",
"multiline": True,
"regex_pattern": "<shot6_prompt>(.+)</shot6_prompt>",
"string": [
"115:111",
0
]
},
"_meta": {
"title": "Extract Text"
}
},
"91:62": {
"class_type": "RegexExtract",
"inputs": {
"case_insensitive": True,
"dotall": False,
"group_index": 1,
"mode": "First Group",
"multiline": True,
"regex_pattern": "<shot4_duration>(\\d+)</shot4_duration>",
"string": [
"115:111",
0
]
},
"_meta": {
"title": "Extract Text"
}
}
})
# run() also passes api_key to the partner nodes in this workflow.
job = client.run(workflow, api_key=api_key)常见问答
High-resolution images with clear focus on the subject work best, as they provide more detail for the Kling 3.0 model to generate accurate video content.
Yes, you can review and edit the generated prompts in the Preview Prompts group before finalizing the video production.
The workflow uses the PrimitiveInt nodes to set the duration for each shot, allowing for flexible video pacing based on your specifications.
Absolutely, while it's optimized for product videos, you can use any starting frame and reference images to create a variety of video content.