{
  "name": "Veo 3.1 \u2014 Finance Tip (Video-Only, GPT-4.1 \u2192 Veo Preview)",
  "nodes": [
    {
      "parameters": {},
      "id": "ManualTrigger",
      "name": "Manual Trigger",
      "type": "n8n-nodes-base.manualTrigger",
      "typeVersion": 1,
      "position": [
        -560,
        0
      ]
    },
    {
      "parameters": {
        "functionCode": "const runId = Date.now().toString(36) + '-' + Math.random().toString(36).slice(2,8);\nreturn [{ json: { runId } }];"
      },
      "id": "MakeRunId",
      "name": "Make runId",
      "type": "n8n-nodes-base.function",
      "typeVersion": 2,
      "position": [
        -380,
        0
      ]
    },
    {
      "parameters": {
        "keepOnlySet": true,
        "values": {
          "string": [
            {
              "name": "topic",
              "value": "One quick way to start a $1K emergency fund"
            },
            {
              "name": "durationSeconds",
              "value": "20"
            },
            {
              "name": "aspectRatio",
              "value": "9:16"
            },
            {
              "name": "negativePrompt",
              "value": "nudity, explicit, low quality, glitch, distorted, disfigured"
            }
          ]
        }
      },
      "id": "Config",
      "name": "Config",
      "type": "n8n-nodes-base.set",
      "typeVersion": 2,
      "position": [
        -200,
        0
      ]
    },
    {
      "parameters": {
        "model": "gpt-4.1",
        "messages": [
          {
            "type": "system",
            "text": "You write concise 20-second finance scripts (\u224845\u201360 words) for vertical videos. Tone: soft, confident, warm, non-preachy, actionable. No emojis. No tickers, no guarantees, no solicitation. Return only the spoken script\u2014no labels."
          },
          {
            "type": "user",
            "text": "Topic: {{$json[\"/previousNode:Config\"].topic}}\nAudience: beginners under money stress\nConstraint: 45\u201360 words max\nPersona: calm, intimate, reassuring feminine voice\nEnd with 1 gentle CTA to follow for daily tips"
          }
        ],
        "responseType": "text"
      },
      "id": "OpenAI_Script",
      "name": "Script (OpenAI GPT-4.1)",
      "type": "n8n-nodes-chat.openAiAssistant",
      "typeVersion": 1,
      "position": [
        40,
        0
      ]
    },
    {
      "parameters": {
        "functionCode": "const text = items[0].json?.text || items[0].json?.data?.[0]?.content || '';\nconst cfg = $json[\"/previousNode:Config\"];\nconst runId = $json[\"/previousNode:Make runId\"].runId;\nconst prompt = `Soft, photorealistic, vertical ${cfg.aspectRatio} video (~${cfg.durationSeconds}s) of an attractive adult woman delivering a calm, intimate personal-finance tip in a soft whisper. Professional, tasteful; avoid sexualization. Subtle head/eye movement, natural micro-expressions. Clean neutral background, shallow depth of field, soft key light.\n\nVOICEOVER (use exactly this text, paced to ${cfg.durationSeconds}s):\\n${text}\n\nCompliance: educational only, no guarantees, no securities recommendations.\nRunId:${runId}`;\nreturn [{ json: { script: text, prompt, aspectRatio: cfg.aspectRatio, durationSeconds: Number(cfg.durationSeconds), negativePrompt: cfg.negativePrompt } }];"
      },
      "id": "BuildPrompt",
      "name": "Build Veo Prompt",
      "type": "n8n-nodes-base.function",
      "typeVersion": 2,
      "position": [
        260,
        0
      ]
    },
    {
      "parameters": {
        "url": "https://generativelanguage.googleapis.com/v1beta/models/veo-3.1-generate-preview:predictLongRunning",
        "method": "POST",
        "sendBody": true,
        "jsonParameters": true,
        "responseFormat": "json",
        "authentication": "none",
        "headerParametersJson": "={\"x-goog-api-key\": $env.GEMINI_API_KEY, \"Content-Type\": \"application/json\"}",
        "bodyParametersJson": "={\n  \"instances\": [\n    {\n      \"prompt\": $json.prompt,\n      \"aspectRatio\": $json.aspectRatio,\n      \"durationSeconds\": $json.durationSeconds\n    }\n  ],\n  \"parameters\": {\n    \"preset\": \"fast\",\n    \"negativePrompt\": $json.negativePrompt\n  }\n}"
      },
      "id": "VeoCreate",
      "name": "Veo 3.1 \u2014 Create Job (Preview)",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4,
      "position": [
        520,
        0
      ]
    },
    {
      "parameters": {
        "keepOnlySet": true,
        "values": {
          "string": [
            {
              "name": "operationName",
              "value": "={{$json[\"name\"]}}"
            }
          ]
        }
      },
      "id": "StoreOp",
      "name": "Store Operation",
      "type": "n8n-nodes-base.set",
      "typeVersion": 2,
      "position": [
        720,
        0
      ]
    },
    {
      "parameters": {
        "amount": 8,
        "unit": "seconds"
      },
      "id": "Wait8s",
      "name": "Wait 8s",
      "type": "n8n-nodes-base.wait",
      "typeVersion": 1,
      "position": [
        720,
        160
      ]
    },
    {
      "parameters": {
        "url": "={{\"https://generativelanguage.googleapis.com/v1beta/\" + $json[\"operationName\"]}}",
        "method": "GET",
        "responseFormat": "json",
        "authentication": "none",
        "headerParametersJson": "={\"x-goog-api-key\": $env.GEMINI_API_KEY}"
      },
      "id": "PollOp",
      "name": "Poll Operation",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4,
      "position": [
        920,
        60
      ]
    },
    {
      "parameters": {
        "conditions": {
          "collection": [
            {
              "type": "boolean",
              "value1": "={{$json.done === true}}"
            }
          ]
        }
      },
      "id": "IfDone",
      "name": "Done?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [
        1120,
        60
      ]
    },
    {
      "parameters": {
        "amount": 5,
        "unit": "seconds"
      },
      "id": "WaitLoop",
      "name": "Wait (loop)",
      "type": "n8n-nodes-base.wait",
      "typeVersion": 1,
      "position": [
        1120,
        -80
      ]
    },
    {
      "parameters": {
        "functionCode": "return items;"
      },
      "id": "LoopBack",
      "name": "Loop",
      "type": "n8n-nodes-base.function",
      "typeVersion": 2,
      "position": [
        1300,
        -80
      ]
    },
    {
      "parameters": {
        "functionCode": "const op = items[0].json;\nconst url = op?.response?.generateVideoResponse?.generatedSamples?.[0]?.video?.uri;\nif (!url) throw new Error('Operation complete but no video URL found.');\nreturn [{ json: { videoUrl: url } }];"
      },
      "id": "ExtractUrl",
      "name": "Extract Video URL",
      "type": "n8n-nodes-base.function",
      "typeVersion": 2,
      "position": [
        1320,
        60
      ]
    },
    {
      "parameters": {
        "message": "\u2705 Veo render complete: {{$json[\"/previousNode:Extract Video URL\"].videoUrl}}",
        "raiseMessage": true
      },
      "id": "Success",
      "name": "Success",
      "type": "n8n-nodes-base.noOp",
      "typeVersion": 1,
      "position": [
        1520,
        60
      ]
    }
  ],
  "connections": {
    "Manual Trigger": {
      "main": [
        [
          {
            "node": "Make runId",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Make runId": {
      "main": [
        [
          {
            "node": "Config",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Config": {
      "main": [
        [
          {
            "node": "Script (OpenAI GPT-4.1)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Script (OpenAI GPT-4.1)": {
      "main": [
        [
          {
            "node": "Build Veo Prompt",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Veo Prompt": {
      "main": [
        [
          {
            "node": "Veo 3.1 \u2014 Create Job (Preview)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Veo 3.1 \u2014 Create Job (Preview)": {
      "main": [
        [
          {
            "node": "Store Operation",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Store Operation": {
      "main": [
        [
          {
            "node": "Poll Operation",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Wait 8s",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wait 8s": {
      "main": [
        [
          {
            "node": "Poll Operation",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Poll Operation": {
      "main": [
        [
          {
            "node": "Done?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Done?": {
      "main": [
        [
          {
            "node": "Extract Video URL",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Wait (loop)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wait (loop)": {
      "main": [
        [
          {
            "node": "Loop",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Loop": {
      "main": [
        [
          {
            "node": "Poll Operation",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract Video URL": {
      "main": [
        [
          {
            "node": "Success",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1"
  },
  "meta": {
    "version": "1.114.x",
    "notes": "Phase 1: video-only. Uses n8n built-in OpenAI credential (select in node UI). AI Studio key in env as GEMINI_API_KEY."
  }
}