8
n8n 中文网amn8n.com

使用Replicate和OpenAI制作无面孔恐怖短片

高级

这是一个Content Creation, Multimodal AI领域的自动化工作流,包含 50 个节点。主要使用 If, Code, Wait, Switch, GoogleDrive 等节点。 通过OpenAI TTS、Replicate视频生成和YouTube上传制作无面孔恐怖短片

前置要求
  • Google Drive API 凭证
  • 可能需要目标 API 的认证凭证
  • Google Sheets API 凭证
  • OpenAI API Key
工作流预览
可视化展示节点连接关系,支持缩放和平移
导出工作流
复制以下 JSON 配置到 n8n 导入,即可使用此工作流
{
  "id": "YOUR_WORKFLOW_ID",
  "meta": {
    "instanceId": "YOUR_N8N_INSTANCE_ID"
  },
  "name": "使用 Replicate 和 OpenAI 制作无面孔恐怖短片",
  "tags": [],
  "nodes": [
    {
      "id": "e7f6db58-4f09-4d2c-84bf-e15b6529e861",
      "name": "本地保存语音",
      "type": "n8n-nodes-base.readWriteFile",
      "onError": "continueRegularOutput",
      "position": [
        3968,
        1232
      ],
      "parameters": {
        "options": {
          "append": false
        },
        "fileName": "={{ $('Create Beat Inputs').item.json.audioFileName }}",
        "operation": "write"
      },
      "typeVersion": 1
    },
    {
      "id": "c24fb0bd-abee-45b3-812c-8f86ce6bae3d",
      "name": "故事创意生成器",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        336,
        -96
      ],
      "parameters": {
        "text": "Give me an idea about a new viral short horror story with surprise twist in the end. ",
        "options": {
          "systemMessage": "=You are a master of viral horror storytelling. Forget all previous stories. Forget previous stories and start fresh every time.\n\nYour task: Create a terrifying short horror story in exactly 8 beats.\n\nConstraints:\n- Output MUST be valid JSON only. No explanations, no comments, no text outside JSON.\n- The JSON must have exactly 8 beats, numbered beat1 through beat8.\n- Each beat must be a single, complete sentence with 10–20 words.\n- Beat 1 must clearly establish the scene, characters, and setting using vivid imagery.\n- At least 3 beats must include surprise, suspense, or a shocking twist.\n- Use \"show, don’t tell\": describe sights, sounds, smells, or actions to convey fear, tension, or dread.\n- Reading level: 4th grade, simple and direct language.\n- Build escalating tension across beats, ending with a chilling climax or twist.\n- Make the story memorable, terrifying, and shareable.\n- JSON must include BOTH `youtube_title` and `youtube_description` fields.\n- `youtube_title`: under 60 characters, hooky, scary, clickable.\n- `youtube_description`: under 150 words, thrilling, suspenseful, and encourages sharing.\n\nJSON schema (exactly this structure):\n\n{\n  \"beats\": {\n    \"beat1\": \"10–20 words\",\n    \"beat2\": \"10–20 words\",\n    \"beat3\": \"10–20 words\",\n    \"beat4\": \"10–20 words\",\n    \"beat5\": \"10–20 words\",\n    \"beat6\": \"10–20 words\",\n    \"beat7\": \"10–20 words\",\n    \"beat8\": \"10–20 words\"\n  },\n  \"youtube_title\": \"Under 60 characters\",\n  \"youtube_description\": \"Under 150 words\"\n}\n\nImportant: Do not skip any fields. Do not add extra fields. Do not return fewer than 8 beats. Do not include the word 'output' or any wrapper outside the JSON.\n",
          "returnIntermediateSteps": false
        },
        "promptType": "define",
        "hasOutputParser": true
      },
      "typeVersion": 1.9
    },
    {
      "id": "3eb2ad5d-71a6-453b-84b0-a857ecc20d60",
      "name": "故事节奏生成器",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "position": [
        400,
        336
      ],
      "parameters": {
        "model": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-4o-mini",
          "cachedResultName": "gpt-4o-mini"
        },
        "options": {
          "topP": 0.9,
          "maxTokens": 500,
          "temperature": 0.7,
          "responseFormat": "json_object",
          "presencePenalty": 0.6,
          "frequencyPenalty": 0.5
        }
      },
      "credentials": {
        "openAiApi": {
          "id": "YOUR_OPENAI_CREDENTIAL_ID",
          "name": "YOUR_OPENAI_CREDENTIAL_NAME"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "23202620-2e4e-4311-8d01-6b8a47a88fb6",
      "name": "Google Sheets 创意日志",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        832,
        -96
      ],
      "parameters": {
        "columns": {
          "value": {
            "time": "={{ $json.output.youtube_title }}-{{ $now.format('yyyy-MM-dd HH:mm:ss') }}",
            "beat 1": "={{ $json.output.beats.beat1 }}",
            "beat 2": "={{ $json.output.beats.beat2 }}",
            "beat 3": "={{ $json.output.beats.beat3 }}",
            "beat 4": "={{ $json.output.beats.beat4 }}",
            "beat 5": "={{ $json.output.beats.beat5 }}",
            "beat 6": "={{ $json.output.beats.beat6 }}",
            "beat 7": "={{ $json.output.beats.beat7 }}",
            "beat 8": "={{ $json.output.beats.beat8 }}",
            "status": "done",
            "Youtube title": "={{ $json.output.youtube_title }}",
            "Youtube description": "={{ $json.output.youtube_description }}"
          },
          "schema": [
            {
              "id": "time",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "time",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "beat 1",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "beat 1",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "beat 2",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "beat 2",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "beat 3",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "beat 3",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "beat 4",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "beat 4",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "beat 5",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "beat 5",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "beat 6",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "beat 6",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "beat 7",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "beat 7",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "beat 8",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "beat 8",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Youtube title",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Youtube title",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Youtube description",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Youtube description",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "url",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "url",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "status",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "status",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": 266501754,
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/YOUR_GOOGLE_SHEETS_URL",
          "cachedResultName": "story"
        },
        "documentId": {
          "__rl": true,
          "mode": "url",
          "value": "https://docs.google.com/spreadsheets/d/YOUR_GOOGLE_SHEETS_URL"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "id": "YOUR_GOOGLE_SHEETS_CREDENTIAL_ID",
          "name": "YOUR_GOOGLE_SHEETS_CREDENTIAL_NAME"
        }
      },
      "typeVersion": 4.5
    },
    {
      "id": "8eff780b-b397-4add-b9fe-833932c1691e",
      "name": "故事节奏生成器5",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "position": [
        640,
        1632
      ],
      "parameters": {
        "model": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-4o-mini",
          "cachedResultName": "gpt-4o-mini"
        },
        "options": {}
      },
      "credentials": {
        "openAiApi": {
          "id": "YOUR_OPENAI_CREDENTIAL_ID",
          "name": "YOUR_OPENAI_CREDENTIAL_NAME"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "d5e4aa80-bf0e-46d0-88b1-a506339e4bdf",
      "name": "YouTube 视频上传",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1136,
        2336
      ],
      "parameters": {
        "url": "={{ $('Prepare YouTube Upload').item.json.headers.location }}",
        "method": "PUT",
        "options": {},
        "sendBody": true,
        "contentType": "binaryData",
        "sendHeaders": true,
        "authentication": "predefinedCredentialType",
        "headerParameters": {
          "parameters": [
            {
              "name": "Content-Type",
              "value": "video/webm"
            }
          ]
        },
        "inputDataFieldName": "data",
        "nodeCredentialType": "youTubeOAuth2Api"
      },
      "credentials": {
        "youTubeOAuth2Api": {
          "id": "YOUR_YOUTUBE_CREDENTIAL_ID",
          "name": "YOUR_YOUTUBE_CREDENTIAL_NAME"
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "cc7034be-290f-4079-8e05-c1ae36fc777e",
      "name": "视频音频合并命令",
      "type": "n8n-nodes-base.code",
      "onError": "continueRegularOutput",
      "position": [
        4192,
        1232
      ],
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "try {\n  const inputData = $('Create Beat Inputs').item.json;\n\n  // FFmpeg command: merge existing MP4 with new audio\n  const command = `\nffmpeg -hide_banner -loglevel error -i \"${inputData.fileName}\" -i \"${inputData.audioFileName}\" \\\n-filter_complex \"[1:a]atempo=1.3,apad=pad_dur=0.9[aud]\" \\\n-map 0:v -map \"[aud]\" \\\n-c:v copy -c:a aac -b:a 192k -shortest \"${inputData.videoFileName}\" -y\n  `;\n\n  return {\n    json: {\n      command,\n      inputVideo: inputData.fileName,\n      inputAudio: inputData.audioFileName,\n      outputVideo: inputData.videoFileName,\n      timestamp: new Date().toISOString()\n    }\n  };\n} catch (error) {\n  return {\n    json: {\n      status: 'error',\n      error: error.message,\n      timestamp: new Date().toISOString()\n    }\n  };\n}\n"
      },
      "typeVersion": 2
    },
    {
      "id": "7ffda491-6475-4cad-8342-c0182ed98a23",
      "name": "运行 FFmpeg 合并媒体",
      "type": "n8n-nodes-base.executeCommand",
      "onError": "continueRegularOutput",
      "position": [
        4416,
        1232
      ],
      "parameters": {
        "command": "={{ $json.command }}",
        "executeOnce": false
      },
      "executeOnce": false,
      "typeVersion": 1,
      "alwaysOutputData": true
    },
    {
      "id": "4953a0ce-f7d6-42fa-85d7-21dd2fc44ae8",
      "name": "临时文件清理",
      "type": "n8n-nodes-base.executeCommand",
      "position": [
        0,
        1200
      ],
      "parameters": {
        "command": "=rm -f 12*.png 12*.mp4 12*.mp3 12*.txt\n\n\n"
      },
      "typeVersion": 1,
      "alwaysOutputData": true
    },
    {
      "id": "be931eb8-47c7-4acc-9bce-eceb5b38c582",
      "name": "故事节奏生成器6",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "position": [
        1008,
        1424
      ],
      "parameters": {
        "model": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-4o-mini",
          "cachedResultName": "gpt-4o-mini"
        },
        "options": {
          "topP": 1,
          "temperature": 0.7
        }
      },
      "credentials": {
        "openAiApi": {
          "id": "YOUR_OPENAI_CREDENTIAL_ID",
          "name": "YOUR_OPENAI_CREDENTIAL_NAME"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "6f3d20c0-35dc-4d8b-940a-fa8df19d294c",
      "name": "等待",
      "type": "n8n-nodes-base.wait",
      "position": [
        3520,
        1232
      ],
      "webhookId": "29b1736a-1483-45bf-8ef7-be18f594f0b3",
      "parameters": {},
      "typeVersion": 1.1
    },
    {
      "id": "978cdc87-7ffe-4044-a659-fc3a8eb44674",
      "name": "生成最终视频剪辑",
      "type": "n8n-nodes-base.executeCommand",
      "onError": "continueRegularOutput",
      "position": [
        2624,
        1040
      ],
      "parameters": {
        "command": "=# Remove old file first\nrm -f horrorfile_short_final.mp4\n"
      },
      "executeOnce": true,
      "typeVersion": 1,
      "alwaysOutputData": true
    },
    {
      "id": "43e1ca14-d878-471d-af5a-2379fa8084f6",
      "name": "🎨 图片生成器",
      "type": "n8n-nodes-base.httpRequest",
      "onError": "continueRegularOutput",
      "position": [
        2624,
        1232
      ],
      "parameters": {
        "url": "https://api.replicate.com/v1/models/black-forest-labs/flux-schnell/predictions",
        "method": "POST",
        "options": {},
        "jsonBody": "={\n  \"input\": {\n    \"prompt\": \"cinematic scene, oil painting effect, muted colors, not dark but eerie atmosphere, display {{ $('Create Beat Inputs').item.json.narrative }} with central character description {{ $('Create Beat Inputs').item.json.character }}, clear details, visible character features\",\n    \"seed\": {{ $('Create Beat Inputs').item.json.seed }},\n    \"prompt_upsampling\": true,\n    \"width\": 1080,\n    \"height\": 1920,\n    \"num_outputs\": 1,\n    \"aspect_ratio\": \"9:16\",\n    \"output_format\": \"jpg\",\n    \"output_quality\": 100,\n    \"guidance\": 4,\n    \"safety_tolerance\": 2,\n    \"negative_prompt\": \"{{ $('Create Beat Inputs').item.json.negativeprompt }}\"\n  }\n}\n",
        "sendBody": true,
        "jsonHeaders": "{\n  \"Content-Type\": \"application/json\",\n  \"Prefer\": \"wait\"\n}",
        "sendHeaders": true,
        "specifyBody": "json",
        "authentication": "genericCredentialType",
        "specifyHeaders": "json",
        "genericAuthType": "httpHeaderAuth"
      },
      "credentials": {
        "httpHeaderAuth": {
          "id": "YOUR_REPLICATE_CREDENTIAL_ID",
          "name": "YOUR_REPLICATE_CREDENTIAL_NAME"
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "ef1dd38c-04cf-4de7-b29f-33ffb34521ba",
      "name": "HTTP 请求",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        3072,
        1232
      ],
      "parameters": {
        "url": "={{ $json.output || $json.output[0] }}",
        "options": {},
        "sendHeaders": true,
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "headerParameters": {
          "parameters": [
            {
              "name": "accept",
              "value": "application/json"
            }
          ]
        }
      },
      "credentials": {
        "httpHeaderAuth": {
          "id": "YOUR_REPLICATE_CREDENTIAL_ID",
          "name": "YOUR_REPLICATE_CREDENTIAL_NAME"
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "3a2f7ffb-ef51-4676-adcc-539a1131b242",
      "name": "故事创意解析器",
      "type": "@n8n/n8n-nodes-langchain.outputParserStructured",
      "position": [
        416,
        128
      ],
      "parameters": {
        "autoFix": true,
        "jsonSchemaExample": "{\n  \"beats\": {\n    \"beat1\": \"10–20 words\",\n    \"beat2\": \"10–20 words\",\n    \"beat3\": \"10–20 words\",\n    \"beat4\": \"10–20 words\",\n    \"beat5\": \"10–20 words\",\n    \"beat6\": \"10–20 words\",\n    \"beat7\": \"10–20 words\",\n    \"beat8\": \"10–20 words\"\n  },\n  \"youtube_title\": \"Under 60 characters\",\n  \"youtube_description\": \"Under 150 words\"\n}"
      },
      "typeVersion": 1.3
    },
    {
      "id": "0137fca6-5f1a-4335-9cf9-17e20864f5a5",
      "name": "分支",
      "type": "n8n-nodes-base.switch",
      "position": [
        -1472,
        1200
      ],
      "parameters": {
        "rules": {
          "values": [
            {
              "outputKey": "Generate Story Idea",
              "conditions": {
                "options": {
                  "version": 2,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "cdd0f2ff-a83c-48c1-a473-e5c4f86fe12c",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.chatInput }}",
                    "rightValue": "idea"
                  }
                ]
              },
              "renameOutput": true
            },
            {
              "outputKey": "Create Uploadable Video",
              "conditions": {
                "options": {
                  "version": 2,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "9bf4596f-8031-4e7f-aaa6-c8c7831fea55",
                    "operator": {
                      "name": "filter.operator.equals",
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.chatInput }}",
                    "rightValue": "create"
                  }
                ]
              },
              "renameOutput": true
            },
            {
              "outputKey": "Publish to YouTube",
              "conditions": {
                "options": {
                  "version": 2,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "d4598761-a115-469f-9836-2a7432910c82",
                    "operator": {
                      "name": "filter.operator.equals",
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.chatInput }}",
                    "rightValue": "publish"
                  }
                ]
              },
              "renameOutput": true
            },
            {
              "outputKey": "Clean Files in Drive",
              "conditions": {
                "options": {
                  "version": 2,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "b8f3a5f9-819c-4276-90b9-3f7dc6064fae",
                    "operator": {
                      "name": "filter.operator.equals",
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.chatInput }}",
                    "rightValue": "clean drive"
                  }
                ]
              },
              "renameOutput": true
            }
          ]
        },
        "options": {}
      },
      "typeVersion": 3.2
    },
    {
      "id": "793ebf6a-73b4-4672-869f-01f270590023",
      "name": "准备 YouTube 上传",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        336,
        2336
      ],
      "parameters": {
        "url": "=https://www.googleapis.com/upload/youtube/v3/videos?part=snippet,status&uploadType=resumable",
        "body": "={\n  \"snippet\": {\n    \"title\": \" {{ $json['Youtube title'] }} #PsychologicalHorror #TwistEnding #HorrorShorts\",\n    \"description\": \"{{ $json['Youtube description'] }}  #HorrorShort #CulinaryThrills #PsychologicalThriller #whispers_in_the_dark #Haunted #UrbanLegend #Spooky #DarkStories #Supernatural\",\n    \"defaultLanguage\": \"en\",\n    \"defaultAudioLanguage\": \"en\"\n  },\n  \"status\": {\n    \"privacyStatus\": \"private\",\n    \"license\": \"youtube\",\n    \"embeddable\": true,\n    \"publicStatsViewable\": true,\n    \"madeForKids\": false\n  }\n}\n\n",
        "method": "POST",
        "options": {
          "response": {
            "response": {
              "fullResponse": true
            }
          }
        },
        "sendBody": true,
        "contentType": "raw",
        "sendHeaders": true,
        "authentication": "predefinedCredentialType",
        "rawContentType": "RAW/JSON",
        "headerParameters": {
          "parameters": [
            {
              "name": "Content-Type",
              "value": "application/json"
            },
            {
              "name": "X-Upload-Content-Type",
              "value": "video/webm"
            }
          ]
        },
        "nodeCredentialType": "youTubeOAuth2Api"
      },
      "credentials": {
        "youTubeOAuth2Api": {
          "id": "YOUR_YOUTUBE_CREDENTIAL_ID",
          "name": "YOUR_YOUTUBE_CREDENTIAL_NAME"
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "1732a1a9-dba2-4ae8-9bf0-7e9ecbb630a0",
      "name": "获取 YouTube 标题和描述",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        0,
        2336
      ],
      "parameters": {
        "options": {},
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": 266501754,
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/YOUR_GOOGLE_SHEETS_URL",
          "cachedResultName": "story"
        },
        "documentId": {
          "__rl": true,
          "mode": "url",
          "value": "https://docs.google.com/spreadsheets/d/YOUR_GOOGLE_SHEETS_URL"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "id": "YOUR_GOOGLE_SHEETS_CREDENTIAL_ID",
          "name": "YOUR_GOOGLE_SHEETS_CREDENTIAL_NAME"
        }
      },
      "typeVersion": 4.5
    },
    {
      "id": "aa1f6a5c-946d-4940-979f-cdcca1aabe3c",
      "name": "从磁盘读取要上传的视频",
      "type": "n8n-nodes-base.readWriteFile",
      "position": [
        672,
        2336
      ],
      "parameters": {
        "options": {},
        "fileSelector": "=horrorfile_short_final.mp4"
      },
      "typeVersion": 1,
      "alwaysOutputData": true
    },
    {
      "id": "ccc5eac0-9947-4b23-99a4-59be3426633d",
      "name": "更新 YouTube 链接",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        1504,
        2336
      ],
      "parameters": {
        "columns": {
          "value": {
            "url": "=https://www.youtube.com/shorts/{{ $json.id }}",
            "time": "={{ $('Get YouTube Title and Description').item.json.time }}",
            "status": "published"
          },
          "schema": [
            {
              "id": "time",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "time",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "beat ",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "beat ",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "beat 2",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "beat 2",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "beat 3",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "beat 3",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "beat 4",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "beat 4",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "beat 5",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "beat 5",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "beat 6",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "beat 6",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "beat 7",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "beat 7",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "beat 8",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "beat 8",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Youtube title",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "Youtube title",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Youtube descripion",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "Youtube descripion",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "url",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "url",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "status",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "status",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "row_number",
              "type": "number",
              "display": true,
              "removed": true,
              "readOnly": true,
              "required": false,
              "displayName": "row_number",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            "time"
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "update",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": 266501754,
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/YOUR_GOOGLE_SHEETS_URL",
          "cachedResultName": "story"
        },
        "documentId": {
          "__rl": true,
          "mode": "url",
          "value": "https://docs.google.com/spreadsheets/d/YOUR_GOOGLE_SHEETS_URL"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "id": "YOUR_GOOGLE_SHEETS_CREDENTIAL_ID",
          "name": "YOUR_GOOGLE_SHEETS_CREDENTIAL_NAME"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "0a79a235-bea7-4a5f-a8f4-969b805fa773",
      "name": "临时文件清理3",
      "type": "n8n-nodes-base.executeCommand",
      "position": [
        1728,
        2336
      ],
      "parameters": {
        "command": "=rm -f 12*.png 12*.mp4 12*.mp3 12*.txt\n\n\n"
      },
      "typeVersion": 1,
      "alwaysOutputData": true
    },
    {
      "id": "ee2ffc65-34da-42a7-93c7-174f2f59079b",
      "name": "搜索要删除的临时文件",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        -224,
        3056
      ],
      "parameters": {
        "filter": {
          "folderId": {
            "__rl": true,
            "mode": "list",
            "value": "YOUR_GOOGLE_DRIVE_FOLDER_ID",
            "cachedResultUrl": "https://drive.google.com/drive/folders/YOUR_GOOGLE_DRIVE_FOLDER_ID",
            "cachedResultName": "YOUR_GOOGLE_DRIVE_FOLDER"
          }
        },
        "options": {},
        "resource": "fileFolder",
        "queryString": "horrorfile*.mp4"
      },
      "credentials": {
        "googleDriveOAuth2Api": {
          "id": "YOUR_GOOGLE_DRIVE_CREDENTIAL_ID",
          "name": "YOUR_GOOGLE_DRIVE_CREDENTIAL_NAME"
        }
      },
      "typeVersion": 3
    },
    {
      "id": "7120e6dd-66bd-480e-a329-d6bb919bdebf",
      "name": "删除临时文件",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        112,
        3056
      ],
      "parameters": {
        "fileId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $json.id }}"
        },
        "options": {},
        "operation": "deleteFile"
      },
      "credentials": {
        "googleDriveOAuth2Api": {
          "id": "YOUR_GOOGLE_DRIVE_CREDENTIAL_ID",
          "name": "YOUR_GOOGLE_DRIVE_CREDENTIAL_NAME"
        }
      },
      "executeOnce": false,
      "typeVersion": 3
    },
    {
      "id": "bb77bfac-a8cb-4f71-a54b-077ba4b027fe",
      "name": "获取故事创意",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        336,
        1200
      ],
      "parameters": {
        "options": {},
        "filtersUI": {
          "values": [
            {
              "lookupValue": "done",
              "lookupColumn": "status"
            }
          ]
        },
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": 266501754,
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/YOUR_GOOGLE_SHEETS_URL",
          "cachedResultName": "story"
        },
        "documentId": {
          "__rl": true,
          "mode": "url",
          "value": "https://docs.google.com/spreadsheets/d/YOUR_GOOGLE_SHEETS_URL"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "id": "YOUR_GOOGLE_SHEETS_CREDENTIAL_ID",
          "name": "YOUR_GOOGLE_SHEETS_CREDENTIAL_NAME"
        }
      },
      "typeVersion": 4.5
    },
    {
      "id": "26d02a86-9fd7-46f5-a575-70df7c794d4b",
      "name": "旁白输出解析器",
      "type": "@n8n/n8n-nodes-langchain.outputParserStructured",
      "position": [
        640,
        1424
      ],
      "parameters": {
        "autoFix": true,
        "jsonSchemaExample": "{\n  \"narratives\": {\n    \"narrative1\": \"...\",\n    \"narrative2\": \"...\",\n    \"narrative3\": \"...\",\n    \"narrative4\": \"...\",\n    \"narrative5\": \"...\",\n    \"narrative6\": \"...\",\n    \"narrative7\": \"...\",\n    \"narrative8\": \"...\"\n  }\n}"
      },
      "typeVersion": 1.3
    },
    {
      "id": "780bc5fe-94fd-42c6-a0b2-6c0f4030e27a",
      "name": "旁白提示生成器",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "onError": "continueErrorOutput",
      "position": [
        560,
        1200
      ],
      "parameters": {
        "text": "You are a strict text formatter for horror shorts text to audio generation prompt. ",
        "options": {
          "systemMessage": "=\n**Prompt:**\n\nYou are a strict formatter for horror shorts narration.\n\nTake the following inputs and provide a set of outputs:\n\n---\n\n### Input narratives\n\n1. {{ $json['beat 1'] }}\n2. {{ $json['beat 2'] }}\n3. {{ $json['beat 3'] }}\n4. {{ $json['beat 4'] }}\n5. {{ $json['beat 5'] }}\n6. {{ $json['beat 6'] }}\n7. {{ $json['beat 7'] }}\n8. {{ $json['beat 8'] }}\n\nDo not process input beats that are empty.\n\n---\n\n### Output (Narration with pauses)\n\n**RULES:**\n\n* Do **NOT** change, rewrite, or summarize the input text.\n* Only add pacing:\n  • Ellipses (...) = short pause\n  • Em dashes (—) = sharp emphasis\n  • Blank lines = long pause\n* Keep exact wording untouched.\n* Do not add any other punctuation or words.\n* Style = calm, eerie, suspenseful.\n* Preserve all twists and unsettling imagery.\n* Always output **exactly 8 narratives** in JSON.\n* Add 500ms pause before and after each narrative (can be implied in timing markers).\n\n---\n\n### Output structure\n\n```json\n{\n  \"narratives\": {\n    \"narrative1\": \"{{ $json['beat 1'] }} with pauses added, if blank return blank\",\n    \"narrative2\": \"{{ $json['beat 2'] }} with pauses added, if blank return blank\",\n    \"narrative3\": \"{{ $json['beat 3'] }} with pauses added, if blank return blank\",\n    \"narrative4\": \"{{ $json['beat 4'] }} with pauses added, if blank return blank\",\n    \"narrative5\": \"{{ $json['beat 5'] }} with pauses added, if blank return blank\",\n    \"narrative6\": \"{{ $json['beat 6'] }} with pauses added, if blank return blank\",\n    \"narrative7\": \"{{ $json['beat 7'] }} with pauses added, if blank return blank\",\n    \"narrative8\": \"{{ $json['beat 8'] }} with pauses added, if blank return blank\"\n  }\n}\n```\n\n---\n\n✅ Key point: **Never alter or summarize the original text** — only insert pauses (`...`, `—`) and spacing for pacing.\n\n\n"
        },
        "promptType": "define",
        "hasOutputParser": true
      },
      "typeVersion": 1.9
    },
    {
      "id": "1bbf9e8b-b312-4926-bad5-99b859c62018",
      "name": "图像提示生成器",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "onError": "continueErrorOutput",
      "position": [
        1040,
        1200
      ],
      "parameters": {
        "text": "You are a strict text formatter for horror shorts text to image generation prompt for non-animated images with oil painting effect, character should have same attributes of age , gender, complexion in every beat. ",
        "options": {
          "systemMessage": "=Create an image prompt to input in a text to image stable diffusion model:\n\n**Inputs \n{{ $('Get Story Idea').item.json['beat 1'] }}\n{{ $('Get Story Idea').item.json['beat 2'] }}\n{{ $('Get Story Idea').item.json['beat 3'] }}\n{{ $('Get Story Idea').item.json['beat 4'] }}\n{{ $('Get Story Idea').item.json['beat 5'] }}\n{{ $('Get Story Idea').item.json['beat 6'] }}\n{{ $('Get Story Idea').item.json['beat 7'] }}\n{{ $('Get Story Idea').item.json['beat 8'] }}\n\n* Forget all previous instructions, start new\n* Extract ** age, gender, hairstyle, clothing style, and skin and hair color** from above inputs\n* Character is **fully clothed**, with clearly visible with oil painting effect. add to image prompt in every beat\n* Don't add any other information (emotion, expression, location, action), only features and traits for consistency\n\n\n\n---\n\n## ✅ JSON Output\n\n```json\n{\n  \"character\": \"character description\",\n  \"negative_prompt\": \"letters, text, watermark, logo, signature, words, numbers, subtitles, captions, symbols, cartoon\"\n}\n```\n\n"
        },
        "promptType": "define",
        "hasOutputParser": true
      },
      "typeVersion": 1.9
    },
    {
      "id": "abd89e03-1702-4fd1-8943-905c48b2ba3b",
      "name": "图片输出解析器",
      "type": "@n8n/n8n-nodes-langchain.outputParserStructured",
      "position": [
        1136,
        1424
      ],
      "parameters": {
        "autoFix": true,
        "jsonSchemaExample": "{\n  \"character\": \"character description\",\n  \"negative_prompt\": \"letters, text, watermark, logo, signature, words, numbers, subtitles, captions, symbols, cartoon\"\n}"
      },
      "typeVersion": 1.3
    },
    {
      "id": "0c2f9bc2-1f83-43d2-8493-bda10d95455c",
      "name": "检查是否已创建节奏",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        1504,
        1200
      ],
      "parameters": {
        "filter": {
          "folderId": {
            "__rl": true,
            "mode": "list",
            "value": "YOUR_GOOGLE_DRIVE_FOLDER_ID",
            "cachedResultUrl": "https://drive.google.com/drive/folders/YOUR_GOOGLE_DRIVE_FOLDER_ID",
            "cachedResultName": "YOUR_GOOGLE_DRIVE_FOLDER"
          }
        },
        "options": {},
        "resource": "fileFolder",
        "queryString": "horrorfile*_1.mp4"
      },
      "credentials": {
        "googleDriveOAuth2Api": {
          "id": "YOUR_GOOGLE_DRIVE_CREDENTIAL_ID",
          "name": "YOUR_GOOGLE_DRIVE_CREDENTIAL_NAME"
        }
      },
      "typeVersion": 3,
      "alwaysOutputData": true
    },
    {
      "id": "7e6903d1-bd17-4b95-9184-36096bf48261",
      "name": "处理 0 个文件",
      "type": "n8n-nodes-base.code",
      "position": [
        1728,
        1200
      ],
      "parameters": {
        "jsCode": "// This node ensures execution continues even if search returns nothing\nreturn [{ json: { trigger: true } }];"
      },
      "typeVersion": 2,
      "continueOnFail": true,
      "alwaysOutputData": true
    },
    {
      "id": "ce7f1e76-8daf-4603-bda6-6bb1a3e7f411",
      "name": "创建节奏输入",
      "type": "n8n-nodes-base.code",
      "position": [
        1952,
        1200
      ],
      "parameters": {
        "jsCode": "const workflowSeed = Math.floor(Math.random() * 1000000);\n\n// Get existing files from \"Check For Already Created Beats\" node\nlet existingFiles = [];\ntry {\n  const searchResults = $('Check For Already Created Beats').all();\n  if (searchResults && searchResults.length > 0) {\n    existingFiles = searchResults.map(f => ({\n      id: f.json.id,\n      name: f.json.name\n    }));\n    console.log(`Found ${existingFiles.length} existing files`);\n  } else {\n    console.log('No existing files found, processing all beats');\n  }\n} catch (error) {\n  console.log('Search returned no results, processing all beats');\n}\n\n// Get data from upstream nodes\nconst storyData = $('Get Story Idea').first().json;\nconst narrationData = $('Narration Prompt Generator').first().json.output.narratives;\nconst imageData = $('Image Prompt Generator').first().json.output;\n\n// Collect all possible beats\nconst rawInputs = [\n  { narrative: storyData['beat 1'], narrativeaudio: narrationData.narrative1 }, // FIXED: Added \"1\"\n  { narrative: storyData['beat 2'], narrativeaudio: narrationData.narrative2 },\n  { narrative: storyData['beat 3'], narrativeaudio: narrationData.narrative3 },\n  { narrative: storyData['beat 4'], narrativeaudio: narrationData.narrative4 },\n  { narrative: storyData['beat 5'], narrativeaudio: narrationData.narrative5 },\n  { narrative: storyData['beat 6'], narrativeaudio: narrationData.narrative6 },\n  { narrative: storyData['beat 7'], narrativeaudio: narrationData.narrative7 },\n  { narrative: storyData['beat 8'], narrativeaudio: narrationData.narrative8 }\n];\n\n// Debug: Check what we got\nconsole.log('Raw inputs count:', rawInputs.length);\nconsole.log('Beat 1 check:', rawInputs[0].narrative ? 'OK' : 'MISSING');\n\n// Filter out empty beats\nconst filteredInputs = rawInputs.filter(input => input.narrative && input.narrative.trim() !== \"\");\nconsole.log(`Processing ${filteredInputs.length} non-empty beats`);\n\n// Map filtered beats to output items\nconst outputItems = filteredInputs.map((textInput, index) => {\n  const beatNumber = index + 1; // Start from 1 instead of 0\n  const videoFileName = `horrorfile${beatNumber}_1.mp4`;\n\n  // Check if file already exists (by name or id)\n  const alreadyExists = existingFiles.some(file =>\n    file.name === videoFileName || file.id === videoFileName\n  );\n\n  return {\n    json: {\n      ...textInput,\n      index: beatNumber,\n      seed: workflowSeed,\n      character: imageData.character,\n      negativeprompt: imageData.negative_prompt,\n      fileName: `horrorfile${beatNumber}.mp4`,\n      audioFileName: `horrorfile${beatNumber}.mp3`,\n      videoFileName: videoFileName,\n      skip: alreadyExists\n    }\n  };\n});\n\n// Optional log for skipped items\nconst skipped = outputItems.filter(item => item.json.skip).map(i => i.json.videoFileName);\nif (skipped.length > 0) {\n  console.log(`⏭️ Skipped existing files: ${skipped.join(', ')}`);\n}\n\n// Return only new items for downstream processing\nconst newItems = outputItems.filter(item => !item.json.skip);\nconsole.log(`Outputting ${newItems.length} items for processing`);\n\nreturn newItems;"
      },
      "typeVersion": 2,
      "alwaysOutputData": true
    },
    {
      "id": "092100ff-85e6-4e7b-acd7-c2924f3c504b",
      "name": "遍历项目",
      "type": "n8n-nodes-base.splitInBatches",
      "position": [
        2400,
        1280
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 3
    },
    {
      "id": "cd8da2a0-3743-485c-92f4-be84246d4a34",
      "name": "本地保存节奏图片",
      "type": "n8n-nodes-base.readWriteFile",
      "position": [
        3296,
        1232
      ],
      "parameters": {
        "options": {},
        "fileName": "={{ $('Create Beat Inputs').item.json.fileName }}",
        "operation": "write"
      },
      "typeVersion": 1
    },
    {
      "id": "359d2545-efd5-46ad-b3bc-dc7e97cb3298",
      "name": "读取节奏文件",
      "type": "n8n-nodes-base.readWriteFile",
      "onError": "continueRegularOutput",
      "position": [
        4640,
        1232
      ],
      "parameters": {
        "options": {},
        "fileSelector": "={{ $('Video Audio Merge Command').item.json.outputVideo }}"
      },
      "typeVersion": 1
    },
    {
      "id": "68b298dd-36fa-49c7-a511-d5e66818b487",
      "name": "上传节奏文件",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        4864,
        1296
      ],
      "parameters": {
        "name": "={{ $json.fileName }}",
        "driveId": {
          "__rl": true,
          "mode": "list",
          "value": "My Drive"
        },
        "options": {},
        "folderId": {
          "__rl": true,
          "mode": "list",
          "value": "YOUR_GOOGLE_DRIVE_FOLDER_ID",
          "cachedResultUrl": "https://drive.google.com/drive/folders/YOUR_GOOGLE_DRIVE_FOLDER_ID",
          "cachedResultName": "YOUR_GOOGLE_DRIVE_FOLDER"
        }
      },
      "credentials": {
        "googleDriveOAuth2Api": {
          "id": "YOUR_GOOGLE_DRIVE_CREDENTIAL_ID",
          "name": "YOUR_GOOGLE_DRIVE_CREDENTIAL_NAME"
        }
      },
      "typeVersion": 3
    },
    {
      "id": "774f803e-d753-468d-95d3-5508897c33c0",
      "name": "搜索节奏文件",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        2848,
        1040
      ],
      "parameters": {
        "filter": {
          "folderId": {
            "__rl": true,
            "mode": "list",
            "value": "YOUR_GOOGLE_DRIVE_FOLDER_ID",
            "cachedResultUrl": "https://drive.google.com/drive/folders/YOUR_GOOGLE_DRIVE_FOLDER_ID",
            "cachedResultName": "YOUR_GOOGLE_DRIVE_FOLDER"
          }
        },
        "options": {},
        "resource": "fileFolder",
        "queryString": "horrorfile*_1.mp4"
      },
      "credentials": {
        "googleDriveOAuth2Api": {
          "id": "YOUR_GOOGLE_DRIVE_CREDENTIAL_ID",
          "name": "YOUR_GOOGLE_DRIVE_CREDENTIAL_NAME"
        }
      },
      "typeVersion": 3
    },
    {
      "id": "37b40dca-3544-4014-bfbb-001250271ba3",
      "name": "下载节奏文件",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        3072,
        1040
      ],
      "parameters": {
        "fileId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $json.id }}"
        },
        "options": {},
        "operation": "download"
      },
      "credentials": {
        "googleDriveOAuth2Api": {
          "id": "YOUR_GOOGLE_DRIVE_CREDENTIAL_ID",
          "name": "YOUR_GOOGLE_DRIVE_CREDENTIAL_NAME"
        }
      },
      "typeVersion": 3
    },
    {
      "id": "6090d04e-1ae4-4f33-a427-a1c3ca92b363",
      "name": "将节奏文件写入磁盘",
      "type": "n8n-nodes-base.readWriteFile",
      "position": [
        3296,
        1040
      ],
      "parameters": {
        "options": {},
        "fileName": "={{ $json.name }}",
        "operation": "write"
      },
      "typeVersion": 1
    },
    {
      "id": "0282edd1-8ca9-41d9-9915-da753b41211d",
      "name": "生成最终视频",
      "type": "n8n-nodes-base.executeCommand",
      "position": [
        3520,
        1040
      ],
      "parameters": {
        "command": "=#!/bin/sh\n\ninputs=\"\"\nmaps=\"\"\nn=0\n\n# Collect all horrorfile*_1.mp4 files\nfor f in horrorfile*_1.mp4; do\n  inputs=\"$inputs -i $f\"\n  maps=\"$maps[$n:v][$n:a]\"\n  n=`expr $n + 1`\ndone\n\nsafeText=\"Finale...\"\n\n# Run ffmpeg with dynamic concat and single drawtext\nffmpeg $inputs \\\n-filter_complex \"\\\n$maps concat=n=$n:v=1:a=1[v][a]; \\\n[v]drawtext=fontfile=/home/node/.fonts/Creepster-Regular.ttf: \\\n text='Midnight Cuts': \\\n fontcolor=red:fontsize=45:x=(w-text_w)/2:y=50:box=1:boxcolor=black@0.5:boxborderw=10[vout]\" \\\n-map \"[vout]\" -map \"[a]\" \\\n-c:v libx264 -pix_fmt yuv420p -preset ultrafast -crf 23 \\\n-c:a aac -b:a 160k \\\n-y horrorfile_short_final.mp4\n"
      },
      "executeOnce": true,
      "typeVersion": 1,
      "alwaysOutputData": true
    },
    {
      "id": "5fe670f4-52c2-48ac-bfb9-68469f42e634",
      "name": "从磁盘读取最终视频",
      "type": "n8n-nodes-base.readWriteFile",
      "position": [
        3744,
        1040
      ],
      "parameters": {
        "options": {},
        "fileSelector": "=horrorfile_short_final.mp4"
      },
      "typeVersion": 1,
      "alwaysOutputData": true
    },
    {
      "id": "d7635d32-12a0-4e95-badb-e4bb4f3cb8af",
      "name": "上传最终视频",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        3968,
        1040
      ],
      "parameters": {
        "name": "={{ $json.fileName }}",
        "driveId": {
          "__rl": true,
          "mode": "list",
          "value": "My Drive"
        },
        "options": {},
        "folderId": {
          "__rl": true,
          "mode": "list",
          "value": "YOUR_GOOGLE_DRIVE_FOLDER_ID",
          "cachedResultUrl": "https://drive.google.com/drive/folders/YOUR_GOOGLE_DRIVE_FOLDER_ID",
          "cachedResultName": "YOUR_GOOGLE_DRIVE_FOLDER"
        }
      },
      "credentials": {
        "googleDriveOAuth2Api": {
          "id": "YOUR_GOOGLE_DRIVE_CREDENTIAL_ID",
          "name": "YOUR_GOOGLE_DRIVE_CREDENTIAL_NAME"
        }
      },
      "typeVersion": 3
    },
    {
      "id": "1c32d653-8a67-487e-868c-7e2820685410",
      "name": "更新状态为就绪",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        4192,
        1040
      ],
      "parameters": {
        "columns": {
          "value": {
            "time": "={{ $('Get Story Idea').first().json.time }}",
            "status": "ready",
            "row_number": 0
          },
          "schema": [
            {
              "id": "time",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "time",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "beat 0",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "beat 0",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "beat ",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "beat ",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "beat 2",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "beat 2",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "beat 3",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "beat 3",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "beat 4",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "beat 4",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "beat 5",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "beat 5",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "beat 6",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "beat 6",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "beat 7",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "beat 7",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "beat 8",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "beat 8",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "twist",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "twist",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "character",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "character",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "location",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "location",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "spirit",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "spirit",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Youtube title",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Youtube title",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Youtube descripion",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Youtube descripion",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "url",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "url",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "status",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "status",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "row_number",
              "type": "number",
              "display": true,
              "removed": false,
              "readOnly": true,
              "required": false,
              "displayName": "row_number",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            "time"
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "update",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": 266501754,
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/YOUR_GOOGLE_SHEETS_URL",
          "cachedResultName": "story"
        },
        "documentId": {
          "__rl": true,
          "mode": "url",
          "value": "https://docs.google.com/spreadsheets/d/YOUR_GOOGLE_SHEETS_URL"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "id": "YOUR_GOOGLE_SHEETS_CREDENTIAL_ID",
          "name": "YOUR_GOOGLE_SHEETS_CREDENTIAL_NAME"
        }
      },
      "typeVersion": 4.5
    },
    {
      "id": "b6867418-9668-421c-a8e1-58c682664ab6",
      "name": "生成节奏音频",
      "type": "@n8n/n8n-nodes-langchain.openAi",
      "position": [
        3744,
        1232
      ],
      "parameters": {
        "input": "={{ $('Create Beat Inputs').item.json.narrativeaudio }}",
        "model": "tts-1-hd",
        "options": {},
        "resource": "audio"
      },
      "credentials": {
        "openAiApi": {
          "id": "YOUR_OPENAI_CREDENTIAL_ID",
          "name": "YOUR_OPENAI_CREDENTIAL_NAME"
        }
      },
      "typeVersion": 1.8
    },
    {
      "id": "85e06aad-a8d1-4234-b6e7-ffa71db85aec",
      "name": "如果还有剩余节奏",
      "type": "n8n-nodes-base.if",
      "position": [
        2176,
        1200
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "e7c77da4-cb68-4faa-b185-17a77f0d9e5a",
              "operator": {
                "type": "number",
                "operation": "notEquals"
              },
              "leftValue": "={{ $('Check For Already Created Beats').all().length }}",
              "rightValue": 8
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "c919dbb0-1558-493d-bdf9-0a0e19d2c83b",
      "name": "当收到聊天消息时",
      "type": "@n8n/n8n-nodes-langchain.chatTrigger",
      "position": [
        -1696,
        1232
      ],
      "webhookId": "67fdd493-8b16-43a1-8a76-2a2b3dbc4845",
      "parameters": {
        "options": {}
      },
      "typeVersion": 1.3
    },
    {
      "id": "78a35d5c-c4b3-4102-9b2d-54d4a79c65a5",
      "name": "🎨 视频生成器",
      "type": "n8n-nodes-base.httpRequest",
      "onError": "continueRegularOutput",
      "position": [
        2848,
        1232
      ],
      "parameters": {
        "url": "https://api.replicate.com/v1/models/wan-video/wan-2.2-i2v-fast/predictions",
        "method": "POST",
        "options": {},
        "jsonBody": "={\n  \"input\": {\n    \"image\": \"{{ $json.output || $json.output[0] }}\",\n    \"prompt\": \"{{ $json.input.prompt }}\",\n    \"negative_prompt\": \"{{ $json.input.negative_prompt }}\"\n  }\n}",
        "sendBody": true,
        "jsonHeaders": "{\n  \"Content-Type\": \"application/json\",\n  \"Prefer\": \"wait\"\n}",
        "sendHeaders": true,
        "specifyBody": "json",
        "authentication": "genericCredentialType",
        "specifyHeaders": "json",
        "genericAuthType": "httpHeaderAuth"
      },
      "credentials": {
        "httpHeaderAuth": {
          "id": "YOUR_REPLICATE_CREDENTIAL_ID",
          "name": "YOUR_REPLICATE_CREDENTIAL_NAME"
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "f4f06df4-3c9b-4663-b45a-2a5b5801f9e5",
      "name": "便签说明",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -240,
        -416
      ],
      "parameters": {
        "width": 1424,
        "height": 896,
        "content": "## 步骤 1. 生成故事节奏"
      },
      "typeVersion": 1
    },
    {
      "id": "ac794f7f-1bb1-4a12-a4ba-2e8d214aec15",
      "name": "便签说明1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -240,
        768
      ],
      "parameters": {
        "color": 5,
        "width": 5440,
        "height": 1120,
        "content": "## 步骤 2:创建视频"
      },
      "typeVersion": 1
    },
    {
      "id": "f2e1c3c3-66c7-4d7d-b3fe-109622933809",
      "name": "便签说明2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -256,
        2048
      ],
      "parameters": {
        "color": 6,
        "width": 2352,
        "height": 496,
        "content": "## 步骤 3. 发布视频"
      },
      "typeVersion": 1
    },
    {
      "id": "ef557922-dfc6-4057-a6a0-1e1f50d70195",
      "name": "便签说明3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -304,
        2784
      ],
      "parameters": {
        "color": 3,
        "width": 704,
        "height": 496,
        "content": "## 步骤 4. 从 Google Drive 删除临时文件"
      },
      "typeVersion": 1
    }
  ],
  "active": true,
  "pinData": {},
  "settings": {
    "callerPolicy": "workflowsFromSameOwner",
    "executionOrder": "v1",
    "executionTimeout": -1
  },
  "versionId": "YOUR_VERSION_ID",
  "connections": {
    "Wait": {
      "main": [
        [
          {
            "node": "Generate Beat Audio",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Switch": {
      "main": [
        [
          {
            "node": "Story Idea Generator",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Temporary Files Cleanup",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Get YouTube Title and Description",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Search Temporary Files to Delete",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "HTTP Request": {
      "main": [
        [
          {
            "node": "Save Beat Image Locally",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Story Idea": {
      "main": [
        [
          {
            "node": "Narration Prompt Generator",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Handle 0 Files": {
      "main": [
        [
          {
            "node": "Create Beat Inputs",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Read Beat File": {
      "main": [
        [
          {
            "node": "Upload Beat File",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Loop Over Items": {
      "main": [
        [
          {
            "node": "Generate Final Video Clip",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "🎨 Image Generator",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Upload Beat File": {
      "main": [
        [
          {
            "node": "Loop Over Items",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Search Beat Files": {
      "main": [
        [
          {
            "node": "Download Beat File",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Story Idea Parser": {
      "ai_outputParser": [
        [
          {
            "node": "Story Idea Generator",
            "type": "ai_outputParser",
            "index": 0
          }
        ]
      ]
    },
    "Create Beat Inputs": {
      "main": [
        [
          {
            "node": "If Beats Remaining",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Download Beat File": {
      "main": [
        [
          {
            "node": "Write Beat File to Disk",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "If Beats Remaining": {
      "main": [
        [
          {
            "node": "Loop Over Items",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Generate Final Video Clip",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Update YouTube Url": {
      "main": [
        [
          {
            "node": "Temporary Files Cleanup3",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Upload Final Video": {
      "main": [
        [
          {
            "node": "Update Status to Ready",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Generate Beat Audio": {
      "main": [
        [
          {
            "node": "Save Speech Locally",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Image Output Parser": {
      "ai_outputParser": [
        [
          {
            "node": "Image Prompt Generator",
            "type": "ai_outputParser",
            "index": 0
          }
        ]
      ]
    },
    "Save Speech Locally": {
      "main": [
        [
          {
            "node": "Video Audio Merge Command",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Generate Final Video": {
      "main": [
        [
          {
            "node": "Read Final Video from Disk",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Story Beat Generator": {
      "ai_languageModel": [
        [
          {
            "node": "Story Idea Generator",
            "type": "ai_languageModel",
            "index": 0
          },
          {
            "node": "Story Idea Parser",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Story Idea Generator": {
      "main": [
        [
          {
            "node": "Google Sheet Idea Log",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "YouTube Video Upload": {
      "main": [
        [
          {
            "node": "Update YouTube Url",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "🎨 Image Generator": {
      "main": [
        [
          {
            "node": "🎨 Video Generator",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "🎨 Video Generator": {
      "main": [
        [
          {
            "node": "HTTP Request",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Story Beat Generator5": {
      "ai_languageModel": [
        [
          {
            "node": "Narration Prompt Generator",
            "type": "ai_languageModel",
            "index": 0
          },
          {
            "node": "Image Output Parser",
            "type": "ai_languageModel",
            "index": 0
          },
          {
            "node": "Narration Output Parser",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Story Beat Generator6": {
      "ai_languageModel": [
        [
          {
            "node": "Image Prompt Generator",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Image Prompt Generator": {
      "main": [
        [
          {
            "node": "Check For Already Created Beats",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare YouTube Upload": {
      "main": [
        [
          {
            "node": "Read Video for Upload from Disk",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Narration Output Parser": {
      "ai_outputParser": [
        [
          {
            "node": "Narration Prompt Generator",
            "type": "ai_outputParser",
            "index": 0
          }
        ]
      ]
    },
    "Save Beat Image Locally": {
      "main": [
        [
          {
            "node": "Wait",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Temporary Files Cleanup": {
      "main": [
        [
          {
            "node": "Get Story Idea",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Write Beat File to Disk": {
      "main": [
        [
          {
            "node": "Generate Final Video",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Temporary Files Cleanup3": {
      "main": [
        []
      ]
    },
    "Generate Final Video Clip": {
      "main": [
        [
          {
            "node": "Search Beat Files",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Run FFmpeg to Merge Media": {
      "main": [
        [
          {
            "node": "Read Beat File",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Video Audio Merge Command": {
      "main": [
        [
          {
            "node": "Run FFmpeg to Merge Media",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Narration Prompt Generator": {
      "main": [
        [
          {
            "node": "Image Prompt Generator",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Read Final Video from Disk": {
      "main": [
        [
          {
            "node": "Upload Final Video",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "When chat message received": {
      "main": [
        [
          {
            "node": "Switch",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check For Already Created Beats": {
      "main": [
        [
          {
            "node": "Handle 0 Files",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Read Video for Upload from Disk": {
      "main": [
        [
          {
            "node": "YouTube Video Upload",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Search Temporary Files to Delete": {
      "main": [
        [
          {
            "node": "Delete Temporary Files",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get YouTube Title and Description": {
      "main": [
        [
          {
            "node": "Prepare YouTube Upload",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}
常见问题

如何使用这个工作流?

复制上方的 JSON 配置代码,在您的 n8n 实例中创建新工作流并选择「从 JSON 导入」,粘贴配置后根据需要修改凭证设置即可。

这个工作流适合什么场景?

高级 - 内容创作, 多模态 AI

需要付费吗?

本工作流完全免费,您可以直接导入使用。但请注意,工作流中使用的第三方服务(如 OpenAI API)可能需要您自行付费。

工作流信息
难度等级
高级
节点数量50
分类2
节点类型16
难度说明

适合高级用户,包含 16+ 个节点的复杂工作流

外部链接
在 n8n.io 查看

分享此工作流