This workflow follows the Agent → OpenRouter Chat recipe pattern — see all workflows that pair these two integrations.
The workflow JSON
Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →
{
"name": "AI Storyboard Splitter & Dispatcher | AI \u5206\u955c\u62c6\u89e3\u8c03\u5ea6\u5668\uff08\u4e3b\u6d41\u7a0b\uff0c\u6309\u955c\u5934\u6d3e\u53d1\u7ed9\u5b50\u5de5\u4f5c\u6d41\uff09",
"active": false,
"nodes": [
{
"parameters": {
"content": "## AI \u5206\u955c\u62c6\u89e3\u8c03\u5ea6\u5668 | Storyboard Splitter & Dispatcher\n\n**Built:** 2026-01\u3000|\u3000**Nodes:** 14\n\n**Model stack:** gemini-3-pro-preview, sora-2\n\n**External services:** n/a\n\nAll credentials are `YOUR_*` placeholders \u2014 fill them in before the first run.\nSetup guide and placeholder reference: see the repository README.\n\n---\n\n## \u4e2d\u6587\u8bf4\u660e\n\n**\u6784\u5efa\u65f6\u95f4\uff1a** 2026-01\u3000|\u3000**\u8282\u70b9\u6570\uff1a** 14\n\n**\u6a21\u578b\u6808\uff1a** gemini-3-pro-preview, sora-2\n\n**\u5916\u90e8\u670d\u52a1\uff1a** n/a\n\n\u6240\u6709\u51ed\u8bc1\u90fd\u662f `YOUR_*` \u5360\u4f4d\u7b26\uff0c\u9996\u6b21\u8fd0\u884c\u524d\u8bf7\u5148\u586b\u597d\u3002\n\u90e8\u7f72\u6b65\u9aa4\u548c\u5360\u4f4d\u7b26\u5bf9\u7167\u8868\u89c1\u4ed3\u5e93 README\u3002\n",
"height": 640,
"width": 760,
"color": 4
},
"id": "snapshot-meta-ai-story",
"name": "Overview | \u5de5\u4f5c\u6d41\u8bf4\u660e",
"type": "n8n-nodes-base.stickyNote",
"typeVersion": 1,
"position": [
-3808,
60
]
},
{
"parameters": {},
"id": "0731f12f-9523-4d3e-a733-9af1ede2b599",
"name": "When clicking \u2018Execute workflow\u2019",
"type": "n8n-nodes-base.manualTrigger",
"position": [
-3808,
640
],
"typeVersion": 1
},
{
"parameters": {
"fileSelector": "/mnt/external/shared/12*.txt",
"options": {}
},
"id": "7e9aa995-dc3e-4559-a437-26d288e3fd8c",
"name": "Read/Write Files from Disk",
"type": "n8n-nodes-base.readWriteFile",
"position": [
-3408,
640
],
"typeVersion": 1
},
{
"parameters": {
"operation": "text",
"options": {}
},
"id": "3bfbad2f-dd77-4aa0-b67f-61c7d6c96079",
"name": "Extract from File",
"type": "n8n-nodes-base.extractFromFile",
"position": [
-3184,
640
],
"typeVersion": 1.1
},
{
"parameters": {
"jsCode": "// n8n Code\u8282\u70b9 - \u5c0f\u8bf4\u667a\u80fd\u5206\u7247\n// \u8f93\u5165\uff1aExtract from File\u8282\u70b9\u7684\u8f93\u51fa\n// \u8f93\u51fa\uff1a\u591a\u4e2aitem\uff0c\u6bcf\u4e2a\u5305\u542b\u4e00\u4e2a\u5206\u7247\n\nconst targetLength = 3000; // \u76ee\u6807\u5b57\u6570\uff0c\u53ef\u6839\u636e\u9700\u8981\u8c03\u6574\nconst minLength = targetLength * 0.5; // \u6700\u5c0f\u957f\u5ea6\uff0850%\uff09\nconst maxLength = targetLength * 1.5; // \u6700\u5927\u957f\u5ea6\uff08150%\uff09\n\n// \u83b7\u53d6\u8f93\u5165\u6587\u672c - fullData\u662f\u5bf9\u8c61\u4e0d\u662f\u6570\u7ec4\nconst firstItem = $input.first().json;\nlet inputText = '';\n\nif (firstItem.fullData && firstItem.fullData.data) {\n inputText = firstItem.fullData.data;\n} else if (firstItem.data) {\n inputText = firstItem.data;\n} else if (firstItem.text) {\n inputText = firstItem.text;\n}\n\nif (!inputText.trim()) {\n throw new Error('\u8f93\u5165\u6587\u672c\u4e3a\u7a7a');\n}\n\n// \u5904\u7406Windows\u6362\u884c\u7b26\nconst lines = inputText.replace(/\\r\\n/g, '\\n').split('\\n');\nconst segments = [];\nlet currentSegment = '';\nlet currentLength = 0;\nlet segmentStartLine = 0;\n\nfor (let i = 0; i < lines.length; i++) {\n const line = lines[i].trim();\n \n // \u68c0\u6d4b\u7ae0\u8282\u6807\u9898\n const isChapterTitle = /^\u7b2c[\u4e00\u4e8c\u4e09\u56db\u4e94\u516d\u4e03\u516b\u4e5d\u5341\u767e\u5343\u4e07\\d]+\u7ae0/.test(line) || \n /^Chapter\\s*\\d+/i.test(line) ||\n /^\u7b2c[\u4e00\u4e8c\u4e09\u56db\u4e94\u516d\u4e03\u516b\u4e5d\u5341\u767e\u5343\u4e07\\d]+\u8282/.test(line);\n \n const lineLength = line.length;\n \n // \u7b56\u75651: \u5982\u679c\u5f53\u524d\u884c\u662f\u7ae0\u8282\u6807\u9898\uff0c\u4e14\u7d2f\u79ef\u957f\u5ea6\u5df2\u8d85\u8fc7\u6700\u5c0f\u957f\u5ea6\uff0c\u5219\u5207\u5206\n if (isChapterTitle && currentLength >= minLength) {\n if (currentSegment.trim()) {\n segments.push({\n content: currentSegment.trim(),\n length: currentLength,\n startLine: segmentStartLine + 1,\n endLine: i,\n segmentIndex: segments.length + 1\n });\n }\n currentSegment = line + '\\n';\n currentLength = lineLength;\n segmentStartLine = i;\n }\n // \u7b56\u75652: \u5982\u679c\u7d2f\u79ef\u957f\u5ea6\u8d85\u8fc7\u6700\u5927\u957f\u5ea6\uff0c\u5f3a\u5236\u5207\u5206\n else if (currentLength + lineLength >= maxLength) {\n currentSegment += line + '\\n';\n segments.push({\n content: currentSegment.trim(),\n length: currentLength + lineLength,\n startLine: segmentStartLine + 1,\n endLine: i + 1,\n segmentIndex: segments.length + 1,\n forceSplit: true\n });\n currentSegment = '';\n currentLength = 0;\n segmentStartLine = i + 1;\n }\n // \u6b63\u5e38\u7d2f\u79ef\n else {\n currentSegment += line + '\\n';\n currentLength += lineLength;\n }\n}\n\n// \u5904\u7406\u6700\u540e\u4e00\u6bb5\nif (currentSegment.trim()) {\n segments.push({\n content: currentSegment.trim(),\n length: currentLength,\n startLine: segmentStartLine + 1,\n endLine: lines.length,\n segmentIndex: segments.length + 1,\n isLastSegment: true\n });\n}\n\n// \u8fd4\u56de\u7ed3\u679c\uff0c\u6bcf\u4e2a\u5206\u7247\u4f5c\u4e3a\u4e00\u4e2aitem\nreturn segments.map((segment, index) => {\n return {\n json: {\n segmentIndex: segment.segmentIndex,\n content: segment.content,\n length: segment.length,\n startLine: segment.startLine,\n endLine: segment.endLine,\n totalSegments: segments.length,\n forceSplit: segment.forceSplit || false,\n isLastSegment: segment.isLastSegment || false,\n // \u989d\u5916\u4fe1\u606f\n estimatedMinutes: Math.round((segment.length / 200) * 10) / 10, // \u6309200\u5b57/\u5206\u949f\u8ba1\u7b97\n recommendedScenes: Math.ceil(segment.length / 500), // \u63a8\u8350\u573a\u666f\u6570\uff08\u6bcf500\u5b57\u4e00\u4e2a\u573a\u666f\uff09\n // \u63d0\u53d6\u5f00\u5934\u4f5c\u4e3a\u9884\u89c8\n preview: segment.content.substring(0, 100) + (segment.content.length > 100 ? '...' : '')\n }\n };\n});"
},
"id": "dfca9f81-0a46-43e7-a914-398fe6fabf99",
"name": "Code in JavaScript",
"type": "n8n-nodes-base.code",
"position": [
-2736,
640
],
"typeVersion": 2
},
{
"parameters": {
"jsCode": "return $input.all().map(item => {\n return {\n json: {\n keys: Object.keys(item.json),\n fullData: item.json\n }\n };\n});"
},
"id": "00f62159-1a27-4b8d-b4fb-36a4c622aae3",
"name": "Code in JavaScript1",
"type": "n8n-nodes-base.code",
"position": [
-2960,
640
],
"typeVersion": 2
},
{
"parameters": {
"jsCode": "// n8n Code Node - JavaScript \u7248\u672c\n// \u4f5c\u7528\uff1a\u5c06\u5f53\u524d\u7ae0\u8282\u4e0e\u4e0b\u4e00\u7ae0\u7684\u5f00\u5934\u5408\u5e76\uff0c\u751f\u6210 agent_context \u4f9b AI \u4f7f\u7528\n\n// 1. \u83b7\u53d6\u8f93\u5165\u6570\u636e (n8n \u4e2d\u6240\u6709\u8f93\u5165\u90fd\u5728 'items' \u6570\u7ec4\u91cc)\n// \u5047\u8bbe\u4e0a\u4e00\u4e2a\u8282\u70b9\u8f93\u51fa\u7684\u662f\u4e00\u4e2a\u7ae0\u8282\u5217\u8868\uff0c\u6216\u8005\u591a\u4e2a Item\n// \u6211\u4eec\u5148\u5bf9 items \u8fdb\u884c\u6392\u5e8f\uff0c\u9632\u6b62\u987a\u5e8f\u4e71\u4e86\u5bfc\u81f4\u627e\u4e0d\u5230\u6b63\u786e\u7684\u201c\u4e0b\u4e00\u7ae0\u201d\n// \u6ce8\u610f\uff1an8n \u7684\u6570\u636e\u901a\u5e38\u5305\u88f9\u5728 item.json \u4e0b\nitems.sort((a, b) => {\n return (a.json.segmentIndex || 0) - (b.json.segmentIndex || 0);\n});\n\n// \u5b9a\u4e49\u4e0b\u4e00\u7ae0\u9884\u89c8\u7684\u5b57\u6570\u9650\u5236\nconst PREVIEW_LENGTH = 500;\n\n// 2. \u904d\u5386\u5904\u7406\u6bcf\u4e2a\u7ae0\u8282\nfor (let i = 0; i < items.length; i++) {\n const currentItem = items[i].json;\n \n // \u83b7\u53d6\u5f53\u524d\u7ae0\u8282\u57fa\u672c\u4fe1\u606f\n const currentContent = currentItem.content || '';\n // \u5c1d\u8bd5\u63d0\u53d6\u6807\u9898\uff0c\u5982\u679c preview \u5b57\u6bb5\u7b2c\u4e00\u884c\u662f\u6807\u9898\n const chapterTitle = (currentItem.preview || '').split('\\n')[0] || `\u7b2c ${currentItem.segmentIndex} \u7ae0`;\n\n let nextChapterContent = \"\";\n let hasNext = false;\n\n // 3. \"\u5077\u770b\" \u4e0b\u4e00\u7ae0 (Look-ahead)\n if (i + 1 < items.length) {\n const nextItem = items[i + 1].json;\n const rawNextContent = nextItem.content || '';\n \n // \u622a\u53d6\u524d 500 \u5b57\n nextChapterContent = rawNextContent.substring(0, PREVIEW_LENGTH);\n hasNext = true;\n }\n\n // 4. \u6784\u5efa Prompt \u4e0a\u4e0b\u6587 (Core Logic)\n const agentContext = `\n=== \u3010\u5f53\u524d\u5236\u4f5c\u5185\u5bb9\u3011 ===\n\u7ae0\u8282ID: ${currentItem.segmentIndex}\n\u6807\u9898: ${chapterTitle}\n\n${currentContent}\n\n=== \u3010\u4e0b\u4e00\u7ae0\u5267\u60c5\u9884\u89c8 (\u7528\u4e8e\u57cb\u60ac\u5ff5\u94a9\u5b50)\u3011 ===\n(\u6ce8\u610f\uff1a\u4ee5\u4e0b\u5185\u5bb9\u4ec5\u4f9b\u53c2\u8003\uff0c\u7528\u4e8e\u5728\u89c6\u9891\u7ed3\u5c3e\u5236\u4f5c\u60ac\u5ff5\uff0c\u4e0d\u8981\u5c06\u5176\u4f5c\u4e3a\u672c\u96c6\u7684\u4e3b\u8981\u5267\u60c5\uff0c\u9664\u975e\u4e3a\u4e86\u8fde\u8d2f\u6027\u9700\u8981\u63d0\u524d\u5f15\u5165)\n\n${nextChapterContent}${hasNext ? \"...\" : \"(\u5df2\u662f\u6700\u540e\u4e00\u7ae0)\"}\n`;\n\n // 5. \u5c06\u7ed3\u679c\u5199\u5165\u5230 json \u5bf9\u8c61\u4e2d\n // \u5728 n8n \u4e2d\uff0c\u76f4\u63a5\u4fee\u6539 item.json \u5373\u53ef\u5c06\u6570\u636e\u4f20\u9012\u7ed9\u4e0b\u4e00\u4e2a\u8282\u70b9\n currentItem.agent_context = agentContext;\n \n // \u4e5f\u53ef\u4ee5\u4fdd\u7559\u4e00\u4e0b\u539f\u59cb\u7684\u9884\u89c8\u6570\u636e\uff0c\u65b9\u4fbf\u8c03\u8bd5\n currentItem.next_chapter_preview_raw = nextChapterContent;\n}\n\n// 6. \u8fd4\u56de\u5904\u7406\u540e\u7684\u6570\u636e\n// n8n \u8981\u6c42 Code \u8282\u70b9\u5fc5\u987b\u8fd4\u56de items \u6570\u7ec4\nreturn items;"
},
"id": "46ab5a7b-cc57-4308-bf6c-42a62dee6e1e",
"name": "Code in JavaScript2",
"type": "n8n-nodes-base.code",
"position": [
-2512,
640
],
"typeVersion": 2
},
{
"parameters": {
"options": {}
},
"id": "d55c7e96-6c0f-4162-bca6-c1c60d331692",
"name": "Loop Over Items",
"type": "n8n-nodes-base.splitInBatches",
"position": [
-2288,
640
],
"typeVersion": 3
},
{
"parameters": {
"assignments": {
"assignments": [
{
"id": "79e16d70-1c4f-4aed-abe8-2d6e1beadc49",
"name": "\u5f53\u524d\u5185\u5bb9\u811a\u672c",
"type": "string",
"value": "={{ $json.agent_context }}"
},
{
"id": "03c647c0-881b-4678-9375-4370b65174ac",
"name": "\u4e0b\u671f\u9884\u544a\u94a9\u5b50",
"type": "string",
"value": "={{ $json.next_chapter_preview_raw }}"
},
{
"id": "0a4bc7d7-f731-4081-8882-c752282ffe22",
"name": "segmentIndex",
"type": "number",
"value": "={{ $json.segmentIndex }}"
}
]
},
"options": {}
},
"id": "79309a50-4048-4c48-b9a4-30730c7245ee",
"name": "Edit Fields",
"type": "n8n-nodes-base.set",
"position": [
-2064,
640
],
"typeVersion": 3.4
},
{
"parameters": {
"rule": {
"interval": [
{}
]
}
},
"id": "1cf021d4-babd-4556-b938-08e3447708fa",
"name": "Schedule Trigger",
"type": "n8n-nodes-base.scheduleTrigger",
"position": [
-3696,
960
],
"typeVersion": 1.2,
"disabled": true
},
{
"parameters": {
"model": "google/gemini-3-pro-preview",
"options": {}
},
"type": "@n8n/n8n-nodes-langchain.lmChatOpenRouter",
"typeVersion": 1,
"position": [
-1840,
832
],
"id": "4ed73e6f-ba26-4c13-b143-5946055dfd92",
"name": "OpenRouter Chat Model",
"credentials": {
"openRouterApi": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"workflowId": {
"__rl": true,
"mode": "list",
"cachedResultName": "sora2+banan2\u6a21\u677f"
},
"workflowInputs": {
"mappingMode": "defineBelow",
"value": {},
"matchingColumns": [],
"schema": [],
"attemptToConvertTypes": false,
"convertFieldsToString": true
},
"options": {}
},
"id": "323f2460-d241-44d5-a60e-b0f6dc57cb2b",
"name": "Call 'sora2+banan2\u6a21\u677f'",
"type": "n8n-nodes-base.executeWorkflow",
"position": [
-1264,
640
],
"typeVersion": 1.3
},
{
"parameters": {
"jsCode": "// \u63d0\u53d6\u6240\u6709\u5206\u955c\u5e76\u8f6c\u6362\u4e3a\u6807\u51c6\u6570\u7ec4\nconst input = $input.first().json;\n\nlet storyboard;\nif (typeof input.output === 'string') {\n // \u5904\u7406\u53ef\u80fd\u5b58\u5728\u7684 markdown \u5305\u88f9\n const jsonStr = input.output.replace(/```json\\n?/g, '').replace(/```\\n?/g, '');\n storyboard = JSON.parse(jsonStr);\n} else {\n storyboard = input.output;\n}\n\nconst allShots = [];\n\n// \u3010\u4fee\u590d\u70b9 1\u3011\u83b7\u53d6\u5168\u5c40\u573a\u666f\u4fe1\u606f\uff08\u56e0\u4e3a JSON \u4e2d scenes \u548c shots \u662f\u5206\u5f00\u7684\uff09\n// \u5982\u679c scenes \u6570\u7ec4\u5b58\u5728\uff0c\u53d6\u7b2c\u4e00\u4e2a\u4f5c\u4e3a\u9ed8\u8ba4\u573a\u666f\u4fe1\u606f\nconst defaultScene = (storyboard.scenes && storyboard.scenes.length > 0) \n ? storyboard.scenes[0] \n : { scene_name: 'Unknown', location_description: '' };\n\n// \u3010\u4fee\u590d\u70b9 2\u3011\u76f4\u63a5\u904d\u5386\u6839\u76ee\u5f55\u4e0b\u7684 shots \u6570\u7ec4\uff0c\u4e0d\u518d\u5d4c\u5957\u904d\u5386 scenes\nconst shotsList = storyboard.shots || [];\n\nshotsList.forEach(shot => {\n allShots.push({\n // \u57fa\u7840\u4fe1\u606f\n shot_id: shot.shot_id,\n time_code: shot.time_code,\n duration_seconds: shot.duration_seconds,\n \n // \u3010\u4fee\u590d\u70b9 3\u3011\u4ece\u5168\u5c40\u53d8\u91cf\u83b7\u53d6\u573a\u666f\u4fe1\u606f\n scene_name: defaultScene.scene_name,\n location: defaultScene.location_description || defaultScene.location, // \u517c\u5bb9 AI \u53ef\u80fd\u8f93\u51fa\u7684\u4e0d\u540c\u5b57\u6bb5\u540d\n \n // \u6545\u4e8b\u5185\u5bb9\n story_beat: shot.narrative.story_beat,\n voiceover: shot.narrative.voiceover,\n dialogue: shot.narrative.dialogue || [],\n sound_fx: shot.narrative.sound_fx,\n \n // \u89c6\u89c9\u63cf\u8ff0\n image_prompt: shot.visual.image_prompt,\n // \u5b89\u5168\u8bbf\u95ee key_visual_elements\uff0c\u9632\u6b62 AI \u5076\u5c14\u6f0f\u6389\u67d0\u4e9b\u5b57\u6bb5\u62a5\u9519\n subject: shot.visual.key_visual_elements?.subject || '',\n action: shot.visual.key_visual_elements?.action || '',\n environment: shot.visual.key_visual_elements?.environment || '',\n lighting: shot.visual.key_visual_elements?.lighting || '',\n mood: shot.visual.key_visual_elements?.mood || '',\n color_scheme: shot.visual.key_visual_elements?.color_scheme || '',\n \n // \u955c\u5934\u53c2\u6570\n shot_type: shot.visual.camera?.shot_type || '',\n angle: shot.visual.camera?.angle || '',\n movement: shot.visual.camera?.movement || '',\n focus: shot.visual.camera?.focus || '',\n \n // \u8868\u6f14\u7ec6\u8282\n expression: shot.performance?.expression || '',\n gesture: shot.performance?.gesture || '',\n posture: shot.performance?.posture || '',\n eye_contact: shot.performance?.eye_contact || ''\n });\n});\n\nreturn allShots.map(shot => ({ json: shot }));"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
-1488,
640
],
"id": "e89d3e3d-85cd-459e-992c-753fdc72a2b7",
"name": "Code in JavaScript3"
},
{
"parameters": {
"jsCode": "// \u63d0\u53d6\u6240\u6709\u5206\u955c\u5e76\u8f6c\u6362\u4e3a\u6807\u51c6\u6570\u7ec4\nconst input = $input.first().json;\n\n// \u89e3\u6790 output \u5b57\u6bb5\u4e2d\u7684 JSON \u5b57\u7b26\u4e32\nlet storyboard;\nif (typeof input.output === 'string') {\n // \u53bb\u6389 markdown \u4ee3\u7801\u5757\u6807\u8bb0\n const jsonStr = input.output.replace(/```json\\n?/g, '').replace(/```\\n?/g, '');\n storyboard = JSON.parse(jsonStr);\n} else {\n storyboard = input.output;\n}\n\n// \u63d0\u53d6\u6240\u6709 shots \u5230\u4e00\u4e2a\u6570\u7ec4\nconst allShots = [];\n\n// \u904d\u5386\u6240\u6709 scenes\nstoryboard.scenes.forEach(scene => {\n scene.shots.forEach(shot => {\n allShots.push({\n shot_id: shot.shot_id,\n time_code: shot.time_code,\n duration_seconds: shot.duration_seconds,\n scene_name: scene.scene_name,\n location: scene.location,\n \n // \u6545\u4e8b\u5185\u5bb9\n story_beat: shot.narrative.story_beat,\n voiceover: shot.narrative.voiceover,\n dialogue: shot.narrative.dialogue,\n sound_fx: shot.narrative.sound_fx,\n \n // \u89c6\u89c9\u63cf\u8ff0\n image_prompt: shot.visual.image_prompt,\n subject: shot.visual.key_visual_elements.subject,\n action: shot.visual.key_visual_elements.action,\n environment: shot.visual.key_visual_elements.environment,\n lighting: shot.visual.key_visual_elements.lighting,\n mood: shot.visual.key_visual_elements.mood,\n color_scheme: shot.visual.key_visual_elements.color_scheme,\n \n // \u955c\u5934\u53c2\u6570\n shot_type: shot.visual.camera.shot_type,\n angle: shot.visual.camera.angle,\n movement: shot.visual.camera.movement,\n focus: shot.visual.camera.focus\n });\n });\n});\n\n// \u5904\u7406 scenes_continued\uff08\u5982\u679c\u6709\uff09\nif (storyboard.scenes_continued) {\n storyboard.scenes_continued.forEach(scene => {\n scene.shots.forEach(shot => {\n allShots.push({\n shot_id: shot.shot_id,\n time_code: shot.time_code,\n duration_seconds: shot.duration_seconds,\n scene_name: scene.scene_name,\n location: scene.location,\n story_beat: shot.narrative.story_beat,\n voiceover: shot.narrative.voiceover,\n dialogue: shot.narrative.dialogue,\n sound_fx: shot.narrative.sound_fx,\n image_prompt: shot.visual.image_prompt,\n subject: shot.visual.key_visual_elements.subject,\n action: shot.visual.key_visual_elements.action,\n environment: shot.visual.key_visual_elements.environment,\n lighting: shot.visual.key_visual_elements.lighting,\n mood: shot.visual.key_visual_elements.mood,\n color_scheme: shot.visual.key_visual_elements.color_scheme,\n shot_type: shot.visual.camera.shot_type,\n angle: shot.visual.camera.angle,\n movement: shot.visual.camera.movement,\n focus: shot.visual.camera.focus\n });\n });\n });\n}\n\nreturn allShots.map(shot => ({ json: shot }));"
},
"id": "be3468d3-4758-4a84-b8aa-edea5d77790b",
"name": "Code in JavaScript4\uff08\u539f\u5185\u5bb9\uff09",
"type": "n8n-nodes-base.code",
"position": [
-1504,
480
],
"typeVersion": 2
},
{
"parameters": {
"promptType": "define",
"text": "=={{ $json['\u5f53\u524d\u5185\u5bb9\u811a\u672c'] }}\n\n\u4f60\u5c06\u628a\u4ee5\u4e0a\u8d22\u7ecf/\u5e73\u53f0\u89c4\u5219\u5185\u5bb9\uff0c\u6539\u5199\u6210\u865a\u62df\u535a\u4e3b @your_persona \u7684\u7b2c {{ $json.segmentIndex }} \u671f\u53e3\u64ad\u89c6\u9891\u5206\u955cJSON\u3002\n\n\u786c\u6027\u8981\u6c42\uff1a\n1) \u4e25\u683c\u9075\u5b88 System Prompt \u7684\u8f93\u51faJSON\u7ed3\u6784\u4e0e\u5b57\u6bb5\u8def\u5f84\uff08\u540e\u7eed\u8282\u70b9\u4f9d\u8d56\uff09\u3002\n2) \u5355\u573a\u666f\uff1a\u5c45\u5bb6\u5f55\u64ad\u5de5\u4f5c\u5ba4\uff1b\u4e3b\u89d2\u56fa\u5b9a\uff1a@your_persona\uff1b\u4e0d\u8981\u5916\u8c8c\u63cf\u8ff0\u3002\n3) \u6bcf\u4e2ashot\u56fa\u5b9a10\u79d2\uff1btime_code\u630910\u79d2\u9012\u589e\u8fde\u7eed\uff1b\u603b\u65f6\u957f=total_shots*10\u3002\n4) \u8fde\u8d2f\u6027\u534f\u8bae\u5fc5\u987b\u6267\u884c\uff1a\u6bcf\u4e2ashot\u5fc5\u987b\u5305\u542b0.0-0.5s\u4e0e9.5-10.0s\u951a\u5b9a\u6bb5\uff1b\u53f0\u8bcd\u5fc5\u987b\u57289.2s\u524d\u8bf4\u5b8c\u3002\n5) \u7981\u7528\u5957\u8bdd\uff1a\u53ea\u6709S01\u5141\u8bb8\u5f00\u573a\u62db\u547c\uff1b\u53ea\u6709\u6700\u540e\u4e00\u955c\u5141\u8bb8\u5173\u6ce8/\u70b9\u8d5e/\u8bc4\u8bba/\u4e0b\u671f\u89c1/\u62dc\u62dc\u7b49\uff1b\u4e2d\u95f4\u955c\u5934\u4e25\u7981\u51fa\u73b0\u8fd9\u4e9b\u8bcd\u3002\n6) visual.image_prompt\u8981\u8f93\u51fa\u4f46\u8981\u77ed\uff1b\u63a7\u5236\u91cd\u70b9\u653e\u5728 key_visual_elements/camera/performance/continuity/timing_plan\u3002\n7) \u5141\u8bb8\u5c11\u91cf\u5f3a\u76f8\u5173 overlays\uff08\u753b\u4e2d\u753b/\u5b57\u5e55\u5361/\u7b80\u56fe\uff09\u6765\u7f13\u89e3A-roll\u5355\u8c03\uff0c\u4f46\u5fc5\u987b\u4e0e\u53f0\u8bcd\u5f3a\u76f8\u5173\uff0c\u4e14\u4e0d\u7834\u574f\u951a\u5b9a\u6bb5\u3002\n\n\u53ef\u9009\u201c\u4e0b\u671f\u9884\u544a\u94a9\u5b50\u201d\uff08\u53ea\u7528\u4e8e\u6700\u540e\u4e00\u955c\u505a\u60ac\u5ff5\uff0c\u4e0d\u8981\u62a2\u5360\u672c\u671f\u4e3b\u4f53\u5185\u5bb9\uff09\uff1a\n{{ $json['\u4e0b\u671f\u9884\u544a\u94a9\u5b50'] }}\n\n\u53ea\u8f93\u51faJSON\uff0c\u4e0d\u8981\u4efb\u4f55\u89e3\u91ca\u6216markdown\u5305\u88f9\u3002",
"options": {
"systemMessage": "=\u4f60\u7684\u8eab\u4efd\uff1a\n\u4f60\u662f\u201c\u53e3\u64ad\u77ed\u89c6\u9891\u5206\u955c\u5bfc\u6f14 + \u63d0\u793a\u8bcd\u5de5\u7a0b\u5e08\u201d\uff0c\u4e3a\u865a\u62df\u535a\u4e3b @your_persona \u751f\u6210\u53ef\u7528\u4e8e\u540e\u7eed Sora-2 \u6587\u751f\u89c6\u9891\u7684\u5206\u955cJSON\u3002\n\u4f60\u64c5\u957f\u628a\u201c\u5e73\u53f0\u89c4\u5219/\u8d22\u7ecf\u4e8b\u4ef6/\u91d1\u878d\u79d1\u666e\u201d\u53d8\u6210\u5f3a\u8282\u594f\u3001\u5f3a\u53ef\u63a7\u7684\u53e3\u64ad\u955c\u5934\u811a\u672c\u3002\n\n\u6700\u9ad8\u4f18\u5148\u7ea7\u786c\u89c4\u5219\uff08\u5fc5\u987b\u5168\u90e8\u9075\u5b88\uff09\uff1a\n1) \u53ea\u8f93\u51fa \u7eafJSON\uff08\u4e00\u4e2aJSON\u5bf9\u8c61\uff09\uff0c\u4e0d\u8981\u4efb\u4f55\u89e3\u91ca\u3001\u4e0d\u8981markdown\u3001\u4e0d\u8981\u4ee3\u7801\u5757\u56f4\u680f\uff0c\u4e0d\u8981\u591a\u4f59\u6587\u5b57\u3002\n2) \u5355\u573a\u666f\u56fa\u5b9a\uff1a\u5c45\u5bb6\u5f55\u64ad\u5de5\u4f5c\u5ba4\u3002\u4e3b\u89d2\u56fa\u5b9a\uff1a@your_persona\u3002\u63cf\u8ff0\u65f6\u53ea\u5199\u201c@your_persona\u201d\u6216\u201c\u535a\u4e3b\u201d\uff0c\u4e0d\u8981\u5199\u5916\u8c8c\u7ec6\u8282\u3002\n3) Sora\u9650\u5236\uff1a\u6bcf\u6761\u89c6\u9891\u7247\u6bb5\u53ea\u80fd 10\u79d2\u3002\u4f60\u7684\u5206\u955c\u5fc5\u987b\u505a\u5230\uff1a\u6bcf\u4e2ashot\u56fa\u5b9a10\u79d2\uff0ctime_code\u4e25\u683c\u630910\u79d2\u9012\u589e\u8fde\u7eed\u65e0\u91cd\u53e0\u3002\n4) \u8fde\u8d2f\u6027\u534f\u8bae\uff08Segment Continuity Contract\uff09\uff1a\n - \u6bcf\u4e2a10\u79d2shot\u5fc5\u987b\u5305\u542b\u201c\u5f00\u5934\u951a\u5b9a0.0-0.5s\u201d\u548c\u201c\u7ed3\u5c3e\u951a\u5b9a9.5-10.0s\u201d\n - \u951a\u5b9a\u6bb5\u8981\u6c42\uff1a\u5634\u5df4\u95ed\u5408\u3001\u624b\u56de\u5230\u4f11\u606f\u4f4d\u3001\u8eab\u4f53\u7a33\u5b9a\u3001\u76ee\u5149\u56de\u5230\u955c\u5934\uff08\u4e3a\u62fc\u63a5\u7559\u5e72\u51c0\u5207\u70b9\uff09\n - \u53f0\u8bcd\u5fc5\u987b\u57289.2s\u4e4b\u524d\u81ea\u7136\u8bf4\u5b8c\uff0c9.2-10.0s\u7559\u7ed9\u6536\u52bf\u548c\u547c\u5438\uff08\u907f\u514d\u62fc\u63a5\u5361\u987f/\u53e3\u578b\u65ad\u88c2\uff09\n - \u76f8\u90bbshot\u7684 continuity_out \u5e94\u5c3d\u91cf\u4e0e\u4e0b\u4e00shot\u7684 continuity_in \u5339\u914d\uff08\u59ff\u6001/\u624b\u4f4d/\u8868\u60c5\u5ef6\u7eed\uff09\n5) \u4e2d\u6bb5\u7981\u7528\u5957\u8bdd\uff1a\n - \u53ea\u6709 S01 \u5141\u8bb8\u201c\u5f00\u573a\u62db\u547c/\u6293\u6ce8\u610f\u529b\u201d\u7c7b\u53e5\u5f0f\n - \u53ea\u6709\u6700\u540e\u4e00\u955c\u5141\u8bb8\u201c\u5173\u6ce8/\u70b9\u8d5e/\u8bc4\u8bba/\u4e0b\u671f\u89c1/\u62dc\u62dc\u201d\u7b49\u884c\u52a8\u53f7\u53ec\n - \u4efb\u4f55\u4e2d\u95f4\u955c\u5934\uff08S02\u5230\u5012\u6570\u7b2c\u4e8c\u955c\uff09\u4e25\u7981\u51fa\u73b0\uff1ahello/\u55e8/\u6211\u662fxxx/\u5173\u6ce8/\u70b9\u8d5e/\u8bc4\u8bba/\u62dc\u62dc/\u4e0b\u671f\u89c1/\u8bb0\u5f97\u5173\u6ce8 \u7b49\u7b49\n6) \u5185\u5bb9\u51c6\u786e\u6027\uff1a\n - \u5bf9\u5e73\u53f0\u89c4\u5219/\u6570\u503c/\u9608\u503c/\u7981\u6b62\u9879\uff1a\u5c3d\u91cf\u5fe0\u5b9e\uff0c\u4e0d\u8981\u778e\u7f16\u3002\u5982\u679c\u8f93\u5165\u6ca1\u6709\u7ed9\u51fa\u5177\u4f53\u6570\u503c\uff0c\u4e0d\u8981\u786c\u9020\u6570\u5b57\uff0c\u53ef\u7528\u201c\u901a\u5e38/\u4e00\u822c/\u4ee5\u5e73\u53f0\u6700\u65b0\u89c4\u5219\u4e3a\u51c6\u201d\u66ff\u4ee3\u3002\n7) \u53f0\u8bcd\u65f6\u957f\u63a7\u5236\uff1a\n - \u6bcf\u955c\u593410\u79d2\uff0c\u5efa\u8bae\u53e3\u64ad\u603b\u5b57\u6570 32-38\u5b57\uff08\u4e0d\u542b\u3010\u535a\u4e3b\u3011\u6807\u7b7e\uff0c\u4e0d\u542b\u6807\u70b9\uff09\u3002\n - \u5fc5\u987b\u586b\u5199 voiceover_length\uff08\u4f30\u7b97\u5373\u53ef\uff0c\u4f46\u8981\u843d\u5728\u5408\u7406\u533a\u95f4\uff09\u3002\n8) \u89c6\u89c9\u8981\u6c42\uff08\u7528\u4e8e\u540e\u7eed\u89c6\u9891\u63d0\u793a\u8bcd\uff0c\u4e0d\u7528\u4e8e\u751f\u6210\u56fe\u7247\uff09\uff1a\n - visual.image_prompt \u4ecd\u7136\u8981\u8f93\u51fa\uff0c\u4f46\u8981\u6c42\u201c\u77ed\u800c\u7cbe\u201d\uff0c\u4e3b\u8981\u63cf\u8ff0\uff1a\u8868\u60c5+\u624b\u52bf+\u59ff\u6001+\u56fa\u5b9a\u573a\u666f\u5143\u7d20+\u5149\u7ebf\n - \u5173\u952e\u753b\u9762\u4fe1\u606f\u5fc5\u987b\u7ed3\u6784\u5316\u5199\u5728 key_visual_elements + camera + performance \u5b57\u6bb5\u91cc\uff08\u8fd9\u662f\u540e\u7eed\u63a7\u5236\u7684\u4e3b\u5165\u53e3\uff09\n\n\u955c\u5934\u8282\u594f\u5efa\u8bae\uff08\u9075\u5b88\u4f46\u4e0d\u6b7b\u677f\uff09\uff1a\n- S01\uff1a\u9ad8\u80fd\u94a9\u5b50\uff08\u53cd\u76f4\u89c9/\u75db\u70b9/\u8b66\u793a\uff09\uff0c\u80fd\u91cf\u9ad8\n- S02\uff1a\u5b89\u629a+\u5efa\u7acb\u4fe1\u4efb\uff0c\u80fd\u91cf\u4e2d\n- S03-S(\u5012\u65702)\uff1a\u5e72\u8d27\u62c6\u89e3\uff08\u5bf9\u6bd4/\u5217\u4e3e/\u5f3a\u8c03\uff09\uff0c\u80fd\u91cf\u4e2d\u9ad8\u6ce2\u52a8\n- \u6700\u540e\u4e00\u955c\uff1a\u603b\u7ed3\u91d1\u53e5 + \u884c\u52a8\u53f7\u53ec + \u53ef\u9009\u201c\u4e0b\u671f\u9884\u544a\u94a9\u5b50\u201d\n\nB-roll / \u753b\u4e2d\u753b\uff08\u53ef\u9009\uff0c\u4f46\u8981\u5f3a\u76f8\u5173\uff09\uff1a\n- \u9ed8\u8ba4\u662fA-roll\u53e3\u64ad\uff08\u535a\u4e3b\u59cb\u7ec8\u5728\u753b\u9762\u4e2d\uff09\n- \u9700\u8981\u589e\u5f3a\u4fe1\u606f\u5bc6\u5ea6\u65f6\uff0c\u5141\u8bb8 overlays\uff08\u753b\u4e2d\u753b/\u5b57\u5e55\u5361/\u7b80\u56fe\uff09\u53e0\u52a0 1-3\u79d2\uff0c\u5fc5\u987b\u4e0e\u5f53\u53e5\u53f0\u8bcd\u5f3a\u76f8\u5173\n- \u5c3d\u91cf\u907f\u514d\u6574\u6bb5\u5207\u8d70\u7eafB-roll\uff1b\u5982\u5fc5\u987b\u5168\u5c4f\u4fe1\u606f\u5361\uff0c\u8981\u6c420.0-0.5s\u4e0e9.5-10.0s\u4ecd\u56de\u5230A-roll\u951a\u5b9a\n\n\u8f93\u51faJSON\u7ed3\u6784\u8981\u6c42\uff08\u5fc5\u987b\u5305\u542b\u8fd9\u4e9b\u5b57\u6bb5\uff0c\u5141\u8bb8\u65b0\u589e\u4f46\u4e0d\u8981\u5220\u6539\u5173\u952e\u8def\u5f84\uff09\uff1a\n\u9876\u5c42\uff1a\n- meta: chapter_id, title, duration_seconds, total_shots, theme, emotional_arc, target_audience, forbidden_policy\n- scenes: \u4ec51\u4e2ascene\uff0cscene_name/location\u56fa\u5b9a\u4e3a\u201c\u5c45\u5bb6\u5f55\u64ad\u5de5\u4f5c\u5ba4\u201d\n- final_hook\n- quality_check\n\n\u6bcf\u4e2a shot \u5fc5\u987b\u5305\u542b\uff1a\n- shot_id (S01..), time_code (mm:ss-mm:ss), duration_seconds=10\n- narrative: story_beat, voiceover, voiceover_length, dialogue[], sound_fx, is_opening, is_ending\n- visual:\n - image_prompt (\u77ed\u800c\u7cbe)\n - key_visual_elements: subject/action/environment/lighting/mood/color_scheme\n - camera: shot_type/angle/movement/focus\n - overlays: (\u53ef\u9009\u6570\u7ec4) \u6bcf\u4e2aoverlay\u542b type, t_range, content, placement, style\n- emotion: primary_emotion, intensity(1-5), transition\n- performance: expression/gesture/posture/eye_contact\n- continuity:\n - continuity_in: (0.0-0.5s\u951a\u5b9a\u72b6\u6001\u63cf\u8ff0)\n - continuity_out: (9.5-10.0s\u951a\u5b9a\u72b6\u6001\u63cf\u8ff0)\n- timing_plan: (\u6570\u7ec4\uff0c\u63d0\u4f9b\u5173\u952e\u65f6\u95f4\u6bb5\u52a8\u4f5c\u4e0e\u53f0\u8bcd\u5206\u914d\uff0c\u5fc5\u987b\u542b0.0-0.5\u4e0e9.5-10.0\u4e24\u6bb5\uff1b\u5176\u4f59\u6bb5\u5efa\u8bae1-3\u6bb5\u5373\u53ef\uff0c\u907f\u514d\u8fc7\u957f)\n - \u6bcf\u6761\u542b t_range, action, expression, gesture, voiceover_chunk(\u53ef\u4e3a\u7a7a)\n\nquality_check \u5fc5\u987b\u5305\u542b\uff08\u7528\u4e8e\u81ea\u52a8\u68c0\u6d4b\uff09\uff1a\n- timecode_continuous: true/false\n- all_shots_10s: true/false\n- forbidden_phrases_passed: true/false\n- voiceover_fit_10s: true/false\n- continuity_anchor_present: true/false\n- notes: \u7b80\u77ed\u5b57\u7b26\u4e32\u6570\u7ec4\uff08\u6700\u591a5\u6761\uff09\n\n\u6267\u884c\u65b9\u5f0f\uff1a\n\u6839\u636e\u7528\u6237\u63d0\u4f9b\u7684\u201c\u5f53\u524d\u5185\u5bb9\u811a\u672c\u201d\uff08\u5e73\u53f0\u89c4\u5219/\u8d22\u7ecf\u4e8b\u4ef6\u6587\u672c\uff09\u4e0e\u53ef\u9009\u201c\u4e0b\u671f\u9884\u544a\u94a9\u5b50\u201d\uff0c\u751f\u6210\u4e00\u5957\u5b8c\u6574\u5206\u955cJSON\u3002\u53ea\u8f93\u51faJSON\u3002\n"
}
},
"id": "44b97f54-c0fe-4923-81be-13f6d0f52ebb",
"name": "AI Agent1",
"type": "@n8n/n8n-nodes-langchain.agent",
"position": [
-1840,
640
],
"typeVersion": 3
}
],
"connections": {
"When clicking \u2018Execute workflow\u2019": {
"main": [
[
{
"node": "Read/Write Files from Disk",
"type": "main",
"index": 0
}
]
]
},
"Read/Write Files from Disk": {
"main": [
[
{
"node": "Extract from File",
"type": "main",
"index": 0
}
]
]
},
"Extract from File": {
"main": [
[
{
"node": "Code in JavaScript1",
"type": "main",
"index": 0
}
]
]
},
"Code in JavaScript": {
"main": [
[
{
"node": "Code in JavaScript2",
"type": "main",
"index": 0
}
]
]
},
"Code in JavaScript1": {
"main": [
[
{
"node": "Code in JavaScript",
"type": "main",
"index": 0
}
]
]
},
"Code in JavaScript2": {
"main": [
[
{
"node": "Loop Over Items",
"type": "main",
"index": 0
}
]
]
},
"Loop Over Items": {
"main": [
[],
[
{
"node": "Edit Fields",
"type": "main",
"index": 0
}
]
]
},
"Edit Fields": {
"main": [
[
{
"node": "AI Agent1",
"type": "main",
"index": 0
}
]
]
},
"Schedule Trigger": {
"main": [
[
{
"node": "Read/Write Files from Disk",
"type": "main",
"index": 0
}
]
]
},
"OpenRouter Chat Model": {
"ai_languageModel": [
[
{
"node": "AI Agent1",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Code in JavaScript3": {
"main": [
[
{
"node": "Call 'sora2+banan2\u6a21\u677f'",
"type": "main",
"index": 0
}
]
]
},
"AI Agent1": {
"main": [
[
{
"node": "Code in JavaScript3",
"type": "main",
"index": 0
},
{
"node": "Code in JavaScript4\uff08\u539f\u5185\u5bb9\uff09",
"type": "main",
"index": 0
}
]
]
}
},
"settings": {
"executionOrder": "v1",
"availableInMCP": false
},
"createdAt": "2026-01-07 04:35:18.456",
"updatedAt": "2026-02-25 15:55:38.121"
}
Credentials you'll need
Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.
openRouterApi
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
AI Storyboard Splitter & Dispatcher | AI 分镜拆解调度器(主流程,按镜头派发给子工作流). Uses readWriteFile, lmChatOpenRouter, agent. Event-driven trigger; 15 nodes.
Source: https://github.com/gaoorange/n8n-ai-content-factory/blob/main/workflows/talking-head-video-pipeline/ai-storyboard-splitter-dispatcher.json — original creator credit. Request a take-down →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
RAG CHATBOT Main. Uses telegram, telegramTrigger, lmChatOpenAi, n8n-nodes-mcp. Event-driven trigger; 87 nodes.
Sora 2 Pro Talking-Head Video Generator | AI 数字人口播视频生成(Sora 2 Pro + MiniMax TTS + FFmpeg 自动合成). Uses httpRequest, agent, lmChatOpenRouter, dataTable. Event-driven trigger; 74 nodes.
This workflow helps to automatically discover undocumented API endpoints by analysing JavaScript files from the website's HTML code.
Turbo Videogen. Uses lmChatOpenRouter, agent, httpRequest, formTrigger. Event-driven trigger; 41 nodes.
pass@k. Uses agent, executeCommand, readWriteFile, n8n-nodes-mcp. Event-driven trigger; 27 nodes.