This workflow follows the Agent → Chainllm 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": "veo limpo new",
"nodes": [
{
"parameters": {
"mode": "runOnceForEachItem",
"jsCode": "function sanitizeText(text) {\n if (!text) return \"\";\n return text\n .toString()\n // remove caracteres de controle invis\u00edveis\n .replace(/[\\x00-\\x1F\\x7F]/g, \" \")\n // remove backslashes\n .replace(/\\\\/g, \"\")\n // remove aspas duplas\n .replace(/\"/g, \"\")\n // remove quebras de linha e tabs\n .replace(/[\\r\\n\\t]+/g, \" \")\n // normaliza espa\u00e7os\n .replace(/\\s+/g, \" \")\n .trim();\n}\n\n\nconst input = $('Remove caracteres especiais').item.json;\nconsole.log(\"=== INPUT HIST\u00d3RIA (Remove caracteres especiais) ===\");\nconsole.log(input);\n\nconst firstSceneImage = $('Generate First Scene Image').item.json.predictions?.[0]?.bytesBase64Encoded || null;\nconst sessionId = input.metadata?.sessionId || \"unknown-session\";\nconsole.log(\"Session ID:\", sessionId);\n\nconst scenes = Array.isArray(input.scenes) ? input.scenes : [];\nconsole.log(\"Total de scenes encontradas:\", scenes.length);\n\nconst voice = input.voice_guide || {};\nconsole.log(\"Guia vocal:\", voice);\n\nconst processedScenes = scenes.map((scene, index) => {\n console.log(`--- Processando scene ${index + 1} ---`);\n console.log(scene);\n\n const veoPromptParts = [\n sanitizeText(scene.prompt || \"\"),\n scene.audio_cues ? `Narra\u00e7\u00e3o: ${sanitizeText(scene.audio_cues)}` : null,\n voice.style ? `Estilo vocal: ${sanitizeText(voice.style)}` : null,\n index === 0\n ? \"M\u00fasica: piano melanc\u00f3lico suave\"\n : index === 1\n ? \"M\u00fasica: cordas esperan\u00e7osas crescendo\"\n : \"M\u00fasica: orquestra inspiradora e vibrante\"\n ].filter(Boolean);\n\n const veoPrompt = veoPromptParts.join(\". \");\n\n return {\n id: scene.id || `scene_${index}`,\n duration: scene.duration || null,\n sceneIndex: index,\n isFirstScene: index === 0,\n isLastScene: index === scenes.length - 1,\n previousSceneIndex: index > 0 ? index - 1 : null,\n nextSceneIndex: index < scenes.length - 1 ? index + 1 : null,\n sessionId,\n totalScenes: scenes.length,\n\n prompt: veoPrompt,\n audioPrompt: sanitizeText(scene.audio_cues || \"\"),\n rawPrompt: sanitizeText(scene.prompt || \"\"),\n continuity_elements: Array.isArray(scene.continuity_elements) ? scene.continuity_elements : [],\n bytesBase64Encoded: index === 0 ? firstSceneImage : null\n };\n});\n\nconsole.log(\"=== SCENES PROCESSADAS ===\");\nconsole.log(processedScenes);\n\nconst combinedAudio = processedScenes\n .map(s => s.audioPrompt)\n .filter(Boolean)\n .join(\" \");\n\nconsole.log(\"=== \u00c1UDIO COMBINADO ===\");\nconsole.log(combinedAudio);\n\nreturn {\n json: {\n output: processedScenes,\n combinedAudio\n }\n};\n"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
224,
-1120
],
"id": "adf14b17-9aef-406b-a8d3-139e41ed81aa",
"name": "Prepare Scenes with Continuity"
},
{
"parameters": {
"options": {}
},
"type": "n8n-nodes-base.moveBinaryData",
"typeVersion": 1,
"position": [
1328,
-608
],
"id": "96d754f6-ac5d-478a-836b-121bd3586719",
"name": "Convert to Binary Output"
},
{
"parameters": {
"respondWith": "binary",
"options": {}
},
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1.1,
"position": [
1536,
-608
],
"id": "682e1efa-0f66-4fe3-8d69-304a39d42121",
"name": "Send Final Video"
},
{
"parameters": {
"url": "http://n8n:5678/webhook/config?section=apis",
"options": {
"timeout": 10000
}
},
"id": "f51fc9d6-052e-4724-93cc-8e05e99664c1",
"name": "Get Config1",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
-16,
-1456
]
},
{
"parameters": {
"jsCode": "let raw = $input.first().json.text || '';\nraw = raw.trim();\n\n// Remove blocos markdown tipo ```json ... ``` ou apenas ```\nraw = raw.replace(/```json/i, '').replace(/```/g, '').trim();\n\n// Remove poss\u00edveis linhas isoladas que s\u00f3 tenham \"json\"\nraw = raw.replace(/^json\\s*/i, '').trim();\n\nlet parsed;\ntry {\n parsed = JSON.parse(raw);\n} catch (err) {\n throw new Error(\n \"Erro ao fazer JSON.parse: \" + err.message +\n \"\\nTexto recebido (preview):\\n\" + raw.substring(0, 200)\n );\n}\n\n// \ud83d\udd11 Retorno no formato que o n8n exige\nif (Array.isArray(parsed)) {\n return parsed.map(p => ({ json: p }));\n} else {\n return [{ json: parsed }];\n}\n"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
-224,
-1120
],
"id": "fd6aca12-78de-4545-88c1-d27c629dbc88",
"name": "Remove caracteres especiais"
},
{
"parameters": {
"method": "POST",
"url": "https://generativelanguage.googleapis.com/v1beta/models/imagen-4.0-generate-001:predict",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "x-goog-api-key",
"value": "={{ $('Get Config1').item.json.data.apis.google.gemini_api_key }}"
}
]
},
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={\n \"instances\": [\n {\n \"prompt\": \"{{ $json.scenes[0].video_prompt }}. {{ $json.visual_guide.style }}. Single unified scene, no composite shots, no picture-in-picture, no multiple panels. No text, watermarks, logos, subtitles.\"\n }\n ],\n \"parameters\": {\n \"sampleCount\": 1,\n \"aspectRatio\": \"16:9\",\n \"quality\": \"high\"\n }\n}",
"options": {
"timeout": 30000
}
},
"id": "b64466be-6640-4c58-9b85-969aaeee4e19",
"name": "Generate First Scene Image",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
0,
-1120
]
},
{
"parameters": {
"options": {}
},
"id": "b0f4c95e-f5f6-42a8-970a-3b571460b794",
"name": "Prompt Input",
"type": "@n8n/n8n-nodes-langchain.chatTrigger",
"position": [
-240,
-1456
],
"typeVersion": 1.1
},
{
"parameters": {
"operation": "toBinary",
"sourceProperty": "predictions[0].bytesBase64Encoded",
"options": {}
},
"type": "n8n-nodes-base.convertToFile",
"typeVersion": 1.1,
"position": [
-576,
-1136
],
"id": "240d68e5-37d3-4338-85eb-89cd37d2fb38",
"name": "Convert Generated Image"
},
{
"parameters": {
"jsCode": "// Inicializa o estado para o AI Agent\nconst scenes = $input.first().json.output || [];\nconst sessionId = scenes[0]?.sessionId || 'unknown';\n\n// Cria estrutura de estado inicial\nconst initialState = {\n sessionId: sessionId,\n totalScenes: scenes.length,\n scenes: scenes.map((scene, idx) => ({\n index: idx,\n id: scene.id,\n prompt: scene.prompt,\n bytesBase64Encoded: scene.bytesBase64Encoded,\n continuityData: scene.continuityData,\n status: 'pending', // pending, processing, video_ready, done, failed, error\n operationName: null,\n videoPath: null,\n frameBase64: null,\n retryAttempt: 0,\n error: null\n })),\n currentSceneIndex: 0,\n completedCount: 0,\n failedCount: 0,\n startedAt: new Date().toISOString(),\n maxRetries: 3\n};\n\nreturn {\n json: {\n sessionId: sessionId,\n state: initialState,\n message: 'Estado inicial criado. Iniciando processamento aut\u00f4nomo...'\n }\n};"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
448,
-1120
],
"id": "67361c29-899d-4fb9-9fe1-44bf70ec6546",
"name": "Initialize Agent State"
},
{
"parameters": {
"operation": "create",
"databaseId": 292721,
"tableId": 680992,
"fieldsUi": {
"fieldValues": [
{
"fieldId": 5621560,
"fieldValue": "={{ $json.sessionId }}"
},
{
"fieldId": 5621567,
"fieldValue": "={{ $json['state.scenes'].bytesBase64Encoded }}"
},
{
"fieldId": 5621563,
"fieldValue": "={{ $json['state.scenes'].prompt }}"
},
{
"fieldId": 5621564,
"fieldValue": "={{ $json['state.scenes'].status }}"
},
{
"fieldId": 5621561,
"fieldValue": "={{ $json['state.scenes'].id }}"
}
]
}
},
"id": "43861346-3093-42c8-8f9e-0de93b658a5c",
"name": "Baserow",
"type": "n8n-nodes-base.baserow",
"typeVersion": 1,
"position": [
896,
-1120
],
"credentials": {
"baserowApi": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"fieldToSplitOut": "state.sessionId, state.scenes",
"include": "allOtherFields",
"options": {}
},
"type": "n8n-nodes-base.splitOut",
"typeVersion": 1,
"position": [
672,
-1120
],
"id": "8dd52514-cbea-4baa-96ed-1e563a342328",
"name": "Split Out"
},
{
"parameters": {
"jsCode": "const sessionId = $input.first().json.session_id || $input.first().json.body?.sessionId;\n\nif (!sessionId) {\n throw new Error('sessionId \u00e9 obrigat\u00f3rio');\n}\n\nreturn { json: { sessionId } };"
},
"id": "e10de33c-81bd-499c-86aa-6788501079b4",
"name": "Prepare Session",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1120,
-1120
]
},
{
"parameters": {
"promptType": "define",
"text": "=Voc\u00ea \u00e9 o GERADOR DE V\u00cdDEOS \u2013 respons\u00e1vel por iniciar a cria\u00e7\u00e3o de v\u00eddeos. \nSession ID: {{ $json.sessionId }}\n\n\ud83c\udfac Responsabilidade \n- Encontrar a pr\u00f3xima cena e iniciar sua gera\u00e7\u00e3o. \n- Se houver cenas j\u00e1 em processing, apenas encaminhe ao pr\u00f3ximo agente. \n\n\ud83d\udccb Fluxo \n1. Use **Tool checkProcessingScenes** : \n - Se a tool retornar uma cena com status \"processing\" \u2192 retorne imediatamente: \n {\n \"status\": \"processing_found\",\n \"rowId\": \"[ID]\",\n \"sessionId\": \"{{ $json.sessionId }}\",\n \"sceneIndex\": \"[scene_X]\",\n \"log\": \"Cena em processamento detectada \u2192 encaminhando\"\n } \n - Se a tool n\u00e3o retornar resultados \u2192 continue para o pr\u00f3ximo passo. \n\n2. Use **Tool checkPendingScenes2**: \n - Se a tool retornar uma cena \"pending\" \u2192 chame **generateVideo** e retorne: \n {\n \"status\": \"video_created\",\n \"rowId\": \"[ID]\",\n \"sessionId\": \"{{ $json.sessionId }}\",\n \"sceneIndex\": \"[scene_X]\",\n \"log\": \"V\u00eddeo iniciado para cena [X]\"\n } \n\n - Se a tool n\u00e3o retornar nenhuma cena pendente \u2192 retorne: \n {\n \"status\": \"all_videos_created\",\n \"rowId\": \"\",\n \"sessionId\": \"{{ $json.sessionId }}\",\n \"sceneIndex\": \"\",\n \"log\": \"Todas as cenas j\u00e1 foram iniciadas\"\n } \n\n\ud83d\udd27 Regras \n- Sempre use **a sa\u00edda real da tool**. Nunca invente valores. \n- Apenas uma chamada por tool por execu\u00e7\u00e3o. \n- Ignore \"done\" e \"error\". \n- Nunca tente processar ou baixar v\u00eddeos. \n- PARE ap\u00f3s retornar uma resposta. \n\n\ud83d\udccc IMPORTANTE: \n- Sempre inclua os 5 campos: \"status\", \"rowId\", \"sessionId\", \"sceneIndex\" e \"log\". \n- \"status\" deve ser um dos: video_created, processing_found, all_videos_created, error. \n- \"sceneIndex\" deve manter o formato \"scene_X\". \n- Se n\u00e3o houver cena correspondente \u2192 use vazio (\"\") em rowId e sceneIndex. \n- Use exatamente esta estrutura JSON, sem adicionar ou omitir campos. \n\n\ud83d\udccc FORMATO FINAL OBRIGAT\u00d3RIO: \n- Retorne apenas o JSON puro. \n- N\u00e3o use ```json ou qualquer bloco de c\u00f3digo. \n- N\u00e3o adicione texto antes ou depois. \n- Sempre inclua os 5 campos: \"status\", \"rowId\", \"sessionId\", \"sceneIndex\", \"log\". \n",
"hasOutputParser": true,
"options": {
"systemMessage": "Voc\u00ea \u00e9 o INICIADOR de v\u00eddeos. Encontre cenas pendentes, inicie gera\u00e7\u00e3o, passe adiante.",
"maxIterations": 10
}
},
"id": "6336b01b-e47d-47bc-9344-b396418f91e2",
"name": "Video Creator Agent",
"type": "@n8n/n8n-nodes-langchain.agent",
"typeVersion": 1.8,
"position": [
-304,
-832
]
},
{
"parameters": {
"promptType": "define",
"text": "=# \ud83c\udfac PROCESSADOR DE V\u00cdDEOS\n**Respons\u00e1vel por completar v\u00eddeos iniciados e gerenciar progresso de cenas.**\n\n## \ud83d\udce5 DADOS DE ENTRADA\n```\nDados: {{ JSON.stringify($json, null, 2) }}\n```\n\n## \ud83d\udd10 PAR\u00c2METROS OBRIGAT\u00d3RIOS (getProcessedVideo)\n- **sessionId**: string (obrigat\u00f3rio)\n- **sceneIndex**: INTEIRO (extrair de \"scene_X\" \u2192 \"scene_1\" = 1)\n- **rowId**: INTEIRO\n\n---\n\n## \ud83d\udd04 FLUXO DE EXECU\u00c7\u00c3O (4 ETAPAS)\n\n### 1\ufe0f\u20e3 VALIDA\u00c7\u00c3O INICIAL\n```\n\u274c Se faltar sessionId:\n \u2192 Retorne: {\"status\":\"processing_error\",\"log\":\"sem sessionId\"}\n \u2192 V\u00c1 PARA ETAPA 4) checkAllDone\n\n\u26a0\ufe0f Se faltar rowId/sceneIndex:\n \u2192 Tente obter via checkPendingScenes3 (pr\u00f3xima n\u00e3o-done)\n \u2192 Extrair n\u00famero do sceneIndex\n```\n\n### 2\ufe0f\u20e3 EVENTOS IMEDIATOS (Gatilho para getProcessedVideo)\n```\n\u2705 TRIGGERS: status \u2208 {\"video_created\", \"processing_found\", \"processing\"}\n\nA\u00c7\u00c3O:\n\u2192 CHAME getProcessedVideo(sessionId, sceneIndex=n\u00famero, rowId=n\u00famero)\n\u2192 Se retornar cena DIFERENTE da solicitada = OK (a pedida j\u00e1 est\u00e1 done)\n```\n\n### 3\ufe0f\u20e3 STATUS DE CONTROLE (Finaliza\u00e7\u00e3o direta)\n```\n\ud83c\udfc1 BYPASS: status \u2208 {\"all_videos_created\", \"all_done\", \"finalize\", \"check_progress\"}\n\nA\u00c7\u00c3O:\n\u2192 N\u00c3O chame getProcessedVideo\n\u2192 Prossiga direto para ETAPA 4)\n```\n\n### 4\ufe0f\u20e3 CHECKALLDONE (\u26a0\ufe0f SEMPRE OBRIGAT\u00d3RIO)\n```\n\ud83d\udd0d CHAME SEMPRE: checkAllDone(sessionId)\n\nINTERPRETA\u00c7\u00c3O:\n\u2022 Resposta vazia OU igual a [{\"response\": \"[\\n {}\\n]\"}] \u2192 done == total\n\u2022 Caso normal: conte done vs total nas respostas\n```\n\n---\n\n## \ud83d\udcca DECIS\u00d5ES DE SA\u00cdDA\n\n### \ud83c\udfaf CASO 1: TUDO CONCLU\u00cdDO\n**Condi\u00e7\u00e3o:** `done == total`\n```json\n{\n \"status\": \"all_completed\",\n \"rowId\": \"{{ $json.rowId }}\",\n \"sessionId\": \"{{ $json.sessionId }}\",\n \"sceneIndex\": {{ Number(($json.sceneIndex||\"\").toString().match(/\\d+/)?.[0] || 0) }},\n \"hasNextScene\": false,\n \"log\": \"[done]/[total]\"\n}\n```\n\n### \ud83c\udfac CASO 2: CENA CONCLU\u00cdDA\n**Condi\u00e7\u00e3o:** `done < total` E houve conclus\u00e3o nesta execu\u00e7\u00e3o\n- getProcessedVideo indicou: done/completed/success\n- OU retornou cena diferente da pedida\n```json\n{\n \"status\": \"scene_completed\",\n \"rowId\": \"{{ $json.rowId }}\",\n \"sessionId\": \"{{ $json.sessionId }}\",\n \"sceneIndex\": {{ Number(($json.sceneIndex||\"\").toString().match(/\\d+/)?.[0] || 0) }},\n \"hasNextScene\": true,\n \"log\": \"[done]/[total]\"\n}\n```\n\n### \u23f3 CASO 3: AINDA PROCESSANDO\n**Condi\u00e7\u00e3o:** Status = processing/generating/in_progress OU desconhecido\n```json\n{\n \"status\": \"still_processing\",\n \"rowId\": \"{{ $json.rowId }}\",\n \"sessionId\": \"{{ $json.sessionId }}\",\n \"sceneIndex\": {{ Number(($json.sceneIndex||\"\").toString().match(/\\d+/)?.[0] || 0) }},\n \"log\": \"[done]/[total]\"\n}\n```\n> \u26a0\ufe0f **IMPORTANTE:** Em `still_processing` inclua `hasNextScene` = true\n\n---\n\n## \ud83d\udeab REGRAS CR\u00cdTICAS - NUNCA FA\u00c7A:\n- \u274c Retornar resposta vazia\n- \u274c Tratar cena diferente como erro\n- \u274c Usar `hasNextScene=false` quando `done < total`\n- \u274c Pular a ETAPA 4) checkAllDone\n\n---\n\n## \u2705 RESUMO OPERACIONAL\n\n### \ud83d\udd00 FLUXOS PRINCIPAIS:\n```\nFLUXO A: video_created/processing_found/processing\n\u2514\u2500\u25ba getProcessedVideo() \u25ba checkAllDone() \u25ba sa\u00edda\n\nFLUXO B: all_videos_created/all_done/finalize/check_progress \n\u2514\u2500\u25ba pular getProcessedVideo \u25ba checkAllDone() \u25ba sa\u00edda\n\nFLUXO C: qualquer outro caso\n\u2514\u2500\u25ba checkAllDone() \u25ba sa\u00edda\n```\n\n### \ud83c\udfaf ORDEM DE PRIORIDADE:\n1. **Valida\u00e7\u00e3o** (sessionId obrigat\u00f3rio)\n2. **Gatilhos** (chamar getProcessedVideo se aplic\u00e1vel)\n3. **Bypass** (pular getProcessedVideo se aplic\u00e1vel) \n4. **CheckAllDone** (SEMPRE executar)\n5. **Sa\u00edda** (baseada em done vs total)\n\n---\n\n## \ud83d\udccb EXEMPLO DE PROCESSAMENTO\n\n**Input com status \"processing\":**\n```json\n{\n \"success\": true,\n \"id\": 200,\n \"session_id\": \"video-de-superacao-1759003088098\",\n \"index\": \"scene_2\", \n \"status\": \"processing\"\n}\n```\n\n**A\u00e7\u00e3o:** \n1. \u2705 Validar sessionId\n2. \u2705 Status=\"processing\" \u2192 TRIGGER \u2192 chamar getProcessedVideo()\n3. \u2705 Executar checkAllDone()\n4. \u2705 Decidir sa\u00edda baseada em done/total",
"hasOutputParser": true,
"options": {
"systemMessage": "You are a helpful assistant",
"maxIterations": 5
}
},
"id": "b35b7996-cf89-48c6-89d0-e8ab3423098e",
"name": "Video Processor Agent",
"type": "@n8n/n8n-nodes-langchain.agent",
"typeVersion": 1.8,
"position": [
336,
-832
],
"retryOnFail": true
},
{
"parameters": {
"method": "POST",
"url": "={{ $env.WEBHOOK_URL }}/webhook/creat-video",
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={\n \"rowId\": {{ $fromAI(\"rowId\", \"ID da linha no Baserow da cena pendente\") }}\n}",
"options": {}
},
"id": "8735a4fb-cbc8-4179-b9b6-9b7ecc81bf06",
"name": "Tool generateVideo",
"type": "n8n-nodes-base.httpRequestTool",
"typeVersion": 4.2,
"position": [
-224,
-608
]
},
{
"parameters": {
"toolDescription": "Chama webhook para verificar/obter v\u00eddeo da cena atual. Use quando status for \u2018video_created\u2019 ou \u2018processing_found\u2019, ou quando uma cena estiver em \u2018processing\u2019/com \u2018create_url_video\u2019. Par\u00e2metros: sessionId (string), sceneIndex (int), rowId (int).",
"method": "POST",
"url": "={{ $env.WEBHOOK_URL }}/webhook/get-video",
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={\n \"sessionId\": \"{{ $fromAI(\"sessionId\", \"ID da sess\u00e3o\") }}\",\n \"sceneIndex\": {{ $fromAI(\"sceneIndex\", \"\u00cdndice num\u00e9rico da cena (ex: 1, 2, 3)\") }},\n \"rowId\": {{ $fromAI(\"rowId\", \"ID da linha no Baserow\") }}\n}",
"options": {},
"optimizeResponse": true
},
"id": "8e2d2533-a18c-4896-8e83-28f5a259a693",
"name": "Tool getProcessedVideo",
"type": "n8n-nodes-base.httpRequestTool",
"typeVersion": 4.2,
"position": [
416,
-608
]
},
{
"parameters": {
"options": {
"temperature": 0.1
}
},
"id": "f1f4be8f-fa67-4697-9213-4b02de90817b",
"name": "Gemini Creator Model",
"type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
"typeVersion": 1,
"position": [
-480,
-608
],
"credentials": {
"googlePalmApi": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"options": {
"temperature": 0.1
}
},
"id": "159a2903-70bf-4464-951e-8a55de508a4c",
"name": "Gemini Processor Model",
"type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
"typeVersion": 1,
"position": [
160,
-608
],
"credentials": {
"googlePalmApi": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict",
"version": 1
},
"conditions": [
{
"id": "has-next-scene",
"leftValue": "={{ $json.hasNextScene }}",
"rightValue": true,
"operator": {
"type": "boolean",
"operation": "equals"
}
}
],
"combinator": "and"
},
"options": {}
},
"type": "n8n-nodes-base.if",
"typeVersion": 2,
"position": [
1104,
-832
],
"id": "b5f7ddf3-e754-4568-bcee-20379fbe551e",
"name": "Continue Processing?"
},
{
"parameters": {
"jsCode": "const currentData = $input.first().json;\n\n// Se still_processing, mant\u00e9m os mesmos dados para retry\nif (currentData.status === 'still_processing') {\n return {\n json: {\n ...currentData,\n iteration: (currentData.iteration || 0) + 1,\n log: `Retry ${(currentData.iteration || 0) + 1}: Aguardando v\u00eddeo ${currentData.sceneIndex}`\n }\n };\n}\n\n// Se scene_completed, prepara pr\u00f3xima busca\nif ( currentData.hasNextScene) {\n return {\n json: {\n sessionId: currentData.sessionId,\n iteration: (currentData.iteration || 0) + 1,\n lastProcessed: currentData.rowId,\n lastSceneIndex: currentData.sceneIndex,\n log: `Itera\u00e7\u00e3o ${(currentData.iteration || 0) + 1}: Buscando pr\u00f3xima cena`\n }\n };\n}"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1328,
-832
],
"id": "0cfce723-3cb6-40d1-acee-defb1059e703",
"name": "Prepare Next Iteration"
},
{
"parameters": {},
"type": "@n8n/n8n-nodes-langchain.memoryBufferWindow",
"typeVersion": 1.3,
"position": [
-352,
-608
],
"id": "604f1800-0e85-43ce-aba4-860dadd7ef4a",
"name": "Creator Memory"
},
{
"parameters": {
"contextWindowLength": 10
},
"type": "@n8n/n8n-nodes-langchain.memoryBufferWindow",
"typeVersion": 1.3,
"position": [
288,
-608
],
"id": "da81697b-1877-48c5-a564-cab7690a33ba",
"name": "Processor Memory"
},
{
"parameters": {
"toolDescription": "Busca pr\u00f3xima cena PENDENTE para gerar v\u00eddeo. Retorna apenas cenas com status 'pending'.",
"url": "https://api.baserow.io/api/database/rows/table/680992/?user_field_names=true&size=5&filter__session_id__equal={sessionId}&filter__status__equal=pending&order_by=index&exclude=frame_base64",
"sendHeaders": true,
"parametersHeaders": {
"values": [
{
"name": "Authorization",
"valueProvider": "fieldValue",
"value": "=Token your-token-here"
}
]
},
"placeholderDefinitions": {
"values": [
{
"name": "sessionId",
"description": "ID da sess\u00e3o para filtrar cenas pendentes",
"type": "string"
}
]
},
"optimizeResponse": true
},
"type": "@n8n/n8n-nodes-langchain.toolHttpRequest",
"typeVersion": 1.1,
"position": [
-96,
-608
],
"id": "720b9ee8-9a21-48e6-a57c-82f6e9fc354a",
"name": "Tool checkPendingScenes2"
},
{
"parameters": {
"toolDescription": "Busca cenas em PROCESSAMENTO que precisam ser verificadas/finalizadas.",
"url": "https://api.baserow.io/api/database/rows/table/680992/?user_field_names=true&size=5&filter__session_id__equal={sessionId}&filter__status__equal=processing&order_by=index&exclude=frame_base64",
"sendHeaders": true,
"parametersHeaders": {
"values": [
{
"name": "Authorization",
"valueProvider": "fieldValue",
"value": "=Token your-token-here"
}
]
},
"placeholderDefinitions": {
"values": [
{
"name": "sessionId",
"description": "ID da sess\u00e3o para filtrar cenas pendentes",
"type": "string"
}
]
},
"optimizeResponse": true
},
"type": "@n8n/n8n-nodes-langchain.toolHttpRequest",
"typeVersion": 1.1,
"position": [
32,
-608
],
"id": "05fd6e34-989d-4407-a4a3-2fbbb9c057bd",
"name": "Tool checkProcessingScenes"
},
{
"parameters": {
"jsCode": "let raw = $json.output || $json.text || JSON.stringify($json);\n\n// Remove blocos de markdown e espa\u00e7os extras\nraw = raw.replace(/```json|```/gi, \"\").trim();\n\n// Tenta detectar JSON dentro de texto maior\nconst match = raw.match(/\\{[\\s\\S]*\\}/);\nif (match) {\n raw = match[0]; // pega s\u00f3 o trecho entre { }\n}\n\nlet parsed;\ntry {\n parsed = JSON.parse(raw);\n} catch (e) {\n parsed = {\n status: \"error\",\n rowId: \"\",\n sessionId: $json.sessionId || \"\",\n sceneIndex: \"\",\n log: \"Falha ao parsear JSON: \" + e.message\n };\n}\n\nreturn parsed;\n"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
80,
-832
],
"id": "7341e0d5-0a60-4586-87c6-f30f97bc618b",
"name": "Parse data"
},
{
"parameters": {
"jsCode": "// Helpers\nconst toNumber = (v) => {\n const m = (v ?? \"\").toString().match(/\\d+/);\n return m ? Number(m[0]) : 0;\n};\nconst clean = (s) =>\n String(s).replace(/```json|```/gi, \"\").replace(/\\b(False|True|None)\\b/g, (x) =>\n x === \"False\" ? \"false\" : x === \"True\" ? \"true\" : \"null\"\n );\nconst tryParse = (v) => {\n if (v == null) return null;\n if (typeof v === \"object\") return v;\n const s = clean(v).trim();\n try { return JSON.parse(s); } catch {}\n const mArr = s.match(/\\[[\\s\\S]*\\]/);\n const mObj = s.match(/\\{[\\s\\S]*\\}/);\n const pick = mArr?.[0] ?? mObj?.[0] ?? null;\n if (!pick) return null;\n try { return JSON.parse(pick); } catch {}\n return null;\n};\n\nlet raw = $json.output ?? $json.text ?? $json;\nlet parsed = tryParse(raw);\n\nif (!parsed) {\n parsed = {\n status: \"processing_error\",\n rowId: $json.rowId || \"\",\n sessionId: $json.sessionId || \"\",\n sceneIndex: toNumber($json.sceneIndex),\n log: \"Falha ao parsear output do agente\",\n };\n}\n\n// normaliza tipos\nif (parsed.sceneIndex !== undefined) parsed.sceneIndex = toNumber(parsed.sceneIndex);\nif (typeof parsed.rowId === \"string\") parsed.rowId = toNumber(parsed.rowId);\n\n// log\nconsole.log(\"PARSED Status:\", parsed.status);\nconsole.log(\"PARSED HasNextScene:\", parsed.hasNextScene);\nconsole.log(\"PARSED HasNextScene Type:\", typeof parsed.hasNextScene);\n\nreturn [{ json: parsed }];\n"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
688,
-832
],
"id": "e96160a8-189f-402c-a7d5-83c38898aca6",
"name": "Parse data processor"
},
{
"parameters": {
"toolDescription": "Busca pr\u00f3xima cena PENDENTE para gerar v\u00eddeo. Retorna apenas cenas com status 'pending'.",
"url": "https://api.baserow.io/api/database/rows/table/680992/?user_field_names=true&size=5&filter__session_id__equal={sessionId}&filter__status__equal=pending&order_by=index&exclude=frame_base64",
"sendHeaders": true,
"parametersHeaders": {
"values": [
{
"name": "Authorization",
"valueProvider": "fieldValue",
"value": "=Token your-token-here"
}
]
},
"placeholderDefinitions": {
"values": [
{
"name": "sessionId",
"description": "ID da sess\u00e3o para filtrar cenas pendentes",
"type": "string"
}
]
},
"optimizeResponse": true
},
"type": "@n8n/n8n-nodes-langchain.toolHttpRequest",
"typeVersion": 1.1,
"position": [
544,
-608
],
"id": "60897b75-9b24-47cc-80dd-89e3e2383a9a",
"name": "Tool checkPendingScenes3"
},
{
"parameters": {
"promptType": "define",
"text": "=Analise a descri\u00e7\u00e3o e extraia todos os par\u00e2metros necess\u00e1rios em um JSON completo:\n\n{\n \"g_style\": \"visual style/genre\",\n \"g_mood\": \"overall mood/atmosphere\",\n \"g_lighting\": \"lighting conditions\",\n \"g_color_palette\": \"dominant color palette\",\n \"g_voice_prompt\": \"desired voice style and tone\",\n \"g_negative_prompt\": \"visual elements to avoid\",\n \"g_negative_audio_prompt\": \"undesired sounds\",\n \"g_numero_videos\": 3,\n \"camera_movement\": \"slow pan/zoom/static\",\n \"motion_intensity\": \"low/medium/high\",\n \"title\": \"t\u00edtulo do projeto\",\n \"negative_voice_prompt\": \"elementos vocais indesejados\"\n}\n\nDescri\u00e7\u00e3o: {{ $('Prompt Input').item.json.chatInput }}\n\n\u26a0\ufe0f REGRAS:\n- Responda com JSON v\u00e1lido apenas\n- Use infer\u00eancia criativa para preencher campos ausentes\n- Mantenha coes\u00e3o est\u00e9tica, emocional e vocal\n- Portugu\u00eas brasileiro obrigat\u00f3rio",
"hasOutputParser": true,
"batching": {}
},
"id": "c5619cd0-f505-480b-9bbb-fcab2f59b54f",
"name": "Extrai Par\u00e2metros",
"type": "@n8n/n8n-nodes-langchain.chainLlm",
"position": [
192,
-1456
],
"typeVersion": 1.7,
"executeOnce": false
},
{
"parameters": {
"jsCode": "// Pega o conte\u00fado do primeiro item\nlet raw = $input.first().json.text || \"\";\n\n// Remove blocos de markdown\nraw = raw.replace(/```json|```/gi, \"\").trim();\n\n// Faz parse do JSON contido\nlet input;\ntry {\n input = JSON.parse(raw);\n} catch (e) {\n input = {};\n}\n\n// Define t\u00edtulo\nlet titulo = input.title || \"video-projeto\";\n\n// Sanitiza\u00e7\u00e3o para slug\ntitulo = titulo.toLowerCase()\n .normalize(\"NFD\")\n .replace(/[\\u0300-\\u036f]/g, \"\")\n .replace(/[^a-z0-9\\s-]/g, \"\")\n .trim();\n\n// Limita a no m\u00e1ximo 3 palavras\nlet palavras = titulo.split(/\\s+/).slice(0, 3);\ntitulo = palavras.join(\"-\")\n .replace(/-+/g, \"-\")\n .replace(/^-+|-+$/g, \"\");\n\n// Adiciona timestamp para unicidade\nconst timestamp = Date.now();\nconst slug = `${titulo}-${timestamp}`;\n\n// Retorno consolidado\nreturn [\n {\n json: {\n ...input,\n slug,\n sessionId: slug,\n timestamp\n }\n }\n];\n"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
544,
-1456
],
"id": "5b05127f-7ec2-4b46-8646-4fa040e4cb32",
"name": "Processa + Slug",
"onError": "continueRegularOutput"
},
{
"parameters": {
"command": "=mkdir -p /tmp/videos/{{ $json.slug }}"
},
"type": "n8n-nodes-base.executeCommand",
"typeVersion": 1,
"position": [
768,
-1456
],
"id": "98c4181d-0735-460b-b96a-56ce739126ea",
"name": "Cria Diret\u00f3rio",
"onError": "continueRegularOutput"
},
{
"parameters": {
"options": {
"maxOutputTokens": 4096,
"temperature": 0.4,
"topK": 32,
"topP": 1,
"safetySettings": {
"values": [
{
"category": "HARM_CATEGORY_HARASSMENT",
"threshold": "BLOCK_NONE"
},
{
"category": "HARM_CATEGORY_HATE_SPEECH",
"threshold": "BLOCK_NONE"
},
{
"category": "HARM_CATEGORY_SEXUALLY_EXPLICIT",
"threshold": "BLOCK_NONE"
},
{
"category": "HARM_CATEGORY_DANGEROUS_CONTENT",
"threshold": "BLOCK_NONE"
}
]
}
}
},
"type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
"position": [
192,
-1280
],
"name": "Gemini Unified",
"id": "3c912846-3ba8-4969-b2d9-b8b33ba38ee4",
"typeVersion": 1,
"credentials": {
"googlePalmApi": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"promptType": "define",
"text": "=Crie roteiro {{ $('Processa + Slug').item.json.g_numero_videos }} cenas 8s. RETORNE APENAS JSON V\u00c1LIDO COMPLETO.\n\n\u26a0\ufe0f TAMANHO M\u00c1XIMO POR CAMPO (CR\u00cdTICO):\n{{ $('Processa + Slug').item.json.g_numero_videos <= 3 ? '\u2022 prompt: 280-320 chars\\n\u2022 video_prompt: 150-180 chars\\n\u2022 audio_cues: 100-120 chars' : $('Processa + Slug').item.json.g_numero_videos <= 6 ? '\u2022 prompt: 200-250 chars\\n\u2022 video_prompt: 100-130 chars\\n\u2022 audio_cues: 80-100 chars' : '\u2022 prompt: 150-180 chars\\n\u2022 video_prompt: 80-100 chars\\n\u2022 audio_cues: 60-80 chars' }}\n\n\ud83d\udccb TEMPLATE OBRIGAT\u00d3RIO:\n{\n \"title\": \"{{ $('Processa + Slug').item.json.title }}\",\n \"metadata\": {\n \"slug\": \"{{ $('Processa + Slug').item.json.slug }}\",\n \"sessionId\": \"{{ $('Processa + Slug').item.json.sessionId }}\",\n \"total_scenes\": {{ $('Processa + Slug').item.json.g_numero_videos }},\n \"timestamp\": {{ $('Processa + Slug').item.json.timestamp }}\n },\n \"visual_guide\": {\n \"style\": \"{{ $('Processa + Slug').item.json.g_style }}\",\n \"lighting\": \"{{ $('Processa + Slug').item.json.g_lighting }}\"\n },\n \"scenes\": [\n {\n \"id\": \"scene_1\",\n \"duration\": \"8s\",\n \"prompt\": \"[M\u00c1XIMO {{ $('Processa + Slug').item.json.g_numero_videos <= 3 ? '320' : $('Processa + Slug').item.json.g_numero_videos <= 6 ? '250' : '180' }} CHARS]\",\n \"video_prompt\": \"[MOVIMENTO ESPEC\u00cdFICO. M\u00c1XIMO {{ $('Processa + Slug').item.json.g_numero_videos <= 3 ? '180' : $('Processa + Slug').item.json.g_numero_videos <= 6 ? '130' : '100' }} CHARS]\",\n \"audio_cues\": \"[NARRA\u00c7\u00c3O. M\u00c1XIMO {{ $('Processa + Slug').item.json.g_numero_videos <= 3 ? '120' : $('Processa + Slug').item.json.g_numero_videos <= 6 ? '100' : '80' }} CHARS]\"\n }\n ]\n}\n\n\ud83d\udea8 REGRAS ABSOLUTAS:\n1. COMPLETE O JSON - se necess\u00e1rio, corte textos mas NUNCA deixe JSON incompleto\n2. N\u00c3O REPITA informa\u00e7\u00f5es entre campos (sem duplica\u00e7\u00e3o)\n3. FOQUE EM MOVIMENTO no video_prompt (Veo usa frame anterior como base)\n4. PORTUGU\u00caS BRASILEIRO em audio_cues\n5. SE APROXIMANDO DO LIMITE: termine a cena atual e feche o JSON\n\n\ud83c\udfaf PRIORIDADES DE CORTE (se necess\u00e1rio):\n1\u00b0 Remova adjetivos e adv\u00e9rbios desnecess\u00e1rios\n2\u00b0 Simplifique descri\u00e7\u00f5es visuais (Veo j\u00e1 tem refer\u00eancia)\n3\u00b0 Reduza narra\u00e7\u00e3o ao essencial\n4\u00b0 Use abrevia\u00e7\u00f5es: \"mov.\" por \"movimento\", \"prog.\" por \"progress\u00e3o\"\n\n\u2705 EXEMPLO CENA OTIMIZADA:\n{\n \"id\": \"scene_1\",\n \"duration\": \"8s\",\n \"prompt\": \"Pessoa sentada, cabe\u00e7a baixa, ambiente escuro. Luz fraca, sombras profundas. Movimento lento levanta cabe\u00e7a, olha janela.\",\n \"video_prompt\": \"Pessoa levanta cabe\u00e7a lentamente, olha para janela. Mov. suave.\",\n \"audio_cues\": \"Narrador: \u00c0s vezes a esperan\u00e7a surge quando menos esperamos.\"\n}\n\n\u26d4 NUNCA:\n- Deixe JSON incompleto\n- Use mais caracteres que o limite\n- Duplique informa\u00e7\u00f5es\n- Adicione campos extras n\u00e3o solicitados\n- Escreva fora do JSON\n- altere o session_id ou slug eles s\u00e3o unique keys\n\nT\u00cdTULO: {{ $('Processa + Slug').item.json.title }}\nCENAS: {{ $('Processa + Slug').item.json.g_numero_videos }}\nVOZ: {{ $('Processa + Slug').item.json.g_voice_prompt }}\n\nRETORNE APENAS O JSON!",
"hasOutputParser": true,
"batching": {}
},
"id": "8cf37d29-8763-4604-9f26-0d156c4ed0d9",
"name": "Roteiro \u2192 JSON Final",
"type": "@n8n/n8n-nodes-langchain.chainLlm",
"position": [
976,
-1456
],
"typeVersion": 1.7,
"executeOnce": false
},
{
"parameters": {
"options": {
"maxOutputTokens": 4096,
"temperature": 0.4,
"topK": 32,
"topP": 1,
"safetySettings": {
"values": [
{
"category": "HARM_CATEGORY_HARASSMENT",
"threshold": "BLOCK_NONE"
},
{
"category": "HARM_CATEGORY_HATE_SPEECH",
"threshold": "BLOCK_NONE"
},
{
"category": "HARM_CATEGORY_SEXUALLY_EXPLICIT",
"threshold": "BLOCK_NONE"
},
{
"category": "HARM_CATEGORY_DANGEROUS_CONTENT",
"threshold": "BLOCK_NONE"
}
]
}
}
},
"type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
"position": [
976,
-1280
],
"name": "Gemini Unified1",
"id": "beb48646-5060-482a-aca0-1b31a93c32c4",
"typeVersion": 1,
"credentials": {
"googlePalmApi": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"command": "=ffmpeg -y \\\n $(ls /tmp/videos/{{ $json.sessionId }}/scene_*.mp4 2>/dev/null | sort -V | sed 's/^/-i /') \\\n -filter_complex \"$(ls /tmp/videos/{{ $json.sessionId }}/scene_*.mp4 2>/dev/null | sort -V | \\\n awk '{printf \"[%d:v][%d:a]\", NR-1, NR-1} END {printf \"concat=n=\" NR \":v=1:a=1[v][a]\"}')\" \\\n -map \"[v]\" -map \"[a]\" \\\n -c:v libx264 -preset fast -crf 23 \\\n -c:a aac -b:a 192k -ar 48000 -ac 2 \\\n -pix_fmt yuv420p -movflags +faststart \\\n /tmp/videos/{{ $json.sessionId }}/final_video.mp4\n"
},
"type": "n8n-nodes-base.executeCommand",
"typeVersion": 1,
"position": [
1088,
-608
],
"id": "9910ebfe-8f35-4040-be43-957063447de7",
"name": "Execute Command1"
},
{
"parameters": {
"toolDescription": "Busca se todos os items de um sessionId est\u00e3o done",
"url": "https://api.baserow.io/api/database/rows/table/680992/?user_field_names=true&filter__session_id__equal={sessionId}&exclude=frame_base64&include=id,session_id,index,status&order_by=index&size=200",
"sendHeaders": true,
"parametersHeaders": {
"values": [
{
"name": "Authorization",
"valueProvider": "fieldValue",
"value": "=Token your-token-here"
}
]
},
"placeholderDefinitions": {
"values": [
{
"name": "sessionId",
"description": "ID da sess\u00e3o para filtrar cenas pendentes",
"type": "string"
}
]
}
},
"type": "@n8n/n8n-nodes-langchain.toolHttpRequest",
"typeVersion": 1.1,
"position": [
688,
-608
],
"id": "6e7690e5-2dc4-4c72-938b-7ef413eff49f",
"name": "Tool checkAllDone"
},
{
"parameters": {
"jsCode": "const input = $input.first().json;\n\n// aceita objeto j\u00e1 parseado; n\u00e3o cheque \"output\"\nif (!input.status) {\n return [{\n json: {\n status: \"processing_error\",\n rowId: input.rowId || \"\",\n sessionId: input.sessionId || \"\",\n sceneIndex: input.sceneIndex ?? 0,\n hasNextScene: true, // mant\u00e9m o loop\n log: \"Agente sem status \u2014 assumindo trabalho pendente\"\n }\n }];\n}\n\nreturn [$input.first()];\n"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
880,
-832
],
"id": "7e2df20f-a169-46c2-bb32-e1b72178446a",
"name": "Fix Empty Output"
}
],
"connections": {
"Prepare Scenes with Continuity": {
"main": [
[
{
"node": "Initialize Agent State",
"type": "main",
"index": 0
}
]
]
},
"Convert to Binary Output": {
"main": [
[
{
"node": "Send Final Video",
"type": "main",
"index": 0
}
]
]
},
"Get Config1": {
"main": [
[
{
"node": "Extrai Par\u00e2metros",
"type": "main",
"index": 0
}
]
]
},
"Remove caracteres especiais": {
"main": [
[
{
"node": "Generate First Scene Image",
"type": "main",
"index": 0
}
]
]
},
"Generate First Scene Image": {
"main": [
[
{
"node": "Prepare Scenes with Continuity",
"type": "main",
"index": 0
},
{
"node": "Convert Generated Image",
"type": "main",
"index": 0
}
]
]
},
"Prompt Input": {
"main": [
[
{
"node": "Get Config1",
"type": "main",
"index": 0
}
]
]
},
"Initialize Agent State": {
"main": [
[
{
"node": "Split Out",
"type": "main",
"index": 0
}
]
]
},
"Split Out": {
"main": [
[
{
"node": "Baserow",
"type": "main",
"index": 0
}
]
]
},
"Baserow": {
"main": [
[
{
"node": "Prepare Session",
"type": "main",
"index": 0
}
]
]
},
"Prepare Session": {
"main": [
[
{
"node": "Video Creator Agent",
"type": "main",
"index": 0
}
]
]
},
"Video Creator Agent": {
"main": [
[
{
"node": "Parse data",
"type": "main",
"index": 0
}
]
]
},
"Video Processor Agent": {
"main": [
[
{
"node": "Parse data processor",
"type": "main",
"index": 0
}
]
]
},
"Continue Processing?": {
"main": [
[
{
"node": "Prepare Next Iteration",
"type": "main",
"index": 0
}
],
[
{
"node": "Execute Command1",
"type": "main",
"index": 0
}
]
]
},
"Prepare Next Iteration": {
"main": [
[
{
"node": "Video Creator Agent",
"type": "main",
"index": 0
}
]
]
},
"Tool generateVideo": {
"ai_tool": [
[
{
"node": "Video Creator Agent",
"type": "ai_tool",
"index": 0
}
]
]
},
"Tool getProcessedVideo": {
"ai_tool": [
[
{
"node": "Video Processor Agent",
"type": "ai_tool",
"index": 0
}
]
]
},
"Gemini Creator Model": {
"ai_languageModel": [
[
{
"node": "Video Creator Agent",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Gemini Processor Model": {
"ai_languageModel": [
[
{
"node": "Video Processor Agent",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Creator Memory": {
"ai_memory": [
[
{
"node": "Video Creator Agent",
"type": "ai_memory",
"index": 0
}
]
]
},
"Processor Memory": {
"ai_memory": [
[
{
"node": "Video Processor Agent",
"type": "ai_memory",
"index": 0
}
]
]
},
"Tool checkPendingScenes2": {
"ai_tool": [
[
{
"node": "Video Creator Agent",
"type": "ai_tool",
"index": 0
}
]
]
},
"Tool checkProcessingScenes": {
"ai_tool": [
[
{
"node": "Video Creator Agent",
"type": "ai_tool",
"index": 0
}
]
]
},
"Parse data": {
"main": [
[
{
"node": "Video Processor Agent",
"type": "main",
"index": 0
}
]
]
},
"Parse data processor": {
"main": [
[
{
"node": "Fix Empty Output",
"type": "main",
"index": 0
}
]
]
},
"Tool checkPendingScenes3": {
"ai_tool": [
[
{
"node": "Video Processor Agent",
"type": "ai_tool",
"index": 0
}
]
]
},
"Extrai Par\u00e2metros": {
"main": [
[
{
"node": "Processa + Slug",
"type": "main",
"index": 0
}
]
]
},
"Processa + Slug": {
"main": [
[
{
"node": "Cria Diret\u00f3rio",
"type": "main",
"index": 0
}
]
]
},
"Cria Diret\u00f3rio": {
"main": [
[
{
"node": "Roteiro \u2192 JSON Final",
"type": "main",
"index": 0
}
]
]
},
"Gemini Unified": {
"ai_languageModel": [
[
{
"node": "Extrai Par\u00e2metros",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Gemini Unified1": {
"ai_languageModel": [
[
{
"node": "Roteiro \u2192 JSON Final",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Roteiro \u2192 JSON Final": {
"main": [
[
{
"node": "Remove caracteres especiais",
"type": "main",
"index": 0
}
]
]
},
"Execute Command1": {
"main": [
[
{
"node": "Convert to Binary Output",
"type": "main",
"index": 0
}
]
]
},
"Tool checkAllDone": {
"ai_tool": [
[
{
"node": "Video Processor Agent",
"type": "ai_tool",
"index": 0
}
]
]
},
"Fix Empty Output": {
"main": [
[
{
"node": "Continue Processing?",
"type": "main",
"index": 0
}
]
]
}
},
"active": false,
"settings": {
"executionOrder": "v1"
},
"versionId": "0e52a357-ab8b-4c3c-b37e-ca0499a7acbe",
"meta": {
"templateCredsSetupCompleted": true
},
"id": "YvnBcPchRSgrydfy",
"tags": []
}
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.
baserowApigooglePalmApi
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
veo limpo new. Uses moveBinaryData, httpRequest, chatTrigger, baserow. Webhook trigger; 36 nodes.
Source: https://github.com/GabrielMBatista/workflow-veo3/blob/253fb7cd0a559b5ac39e618d99f9af82df4191fd/workflows/veo3.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.
secretaria. Uses postgres, n8n-nodes-evolution-api, openAi, httpRequest. Webhook trigger; 71 nodes.
This workflow acts as an AI-powered research assistant that takes a topic from the user, performs multi-step intelligent research, and stores the final report in Notion. It uses advanced search, conte
This workflow transforms WhatsApp into a powerful personal AI using n8n + Green-API. Send text or voice messages — the assistant understands intent and handles daily tasks automatically. 💰 Expense & i
This workflow turns a spreadsheet row into a fully formatted, media-rich WordPress article. It pulls the outline and brand context from Google Sheets/Docs, drafts the article with Anthropic or Gemini,
This workflow contains community nodes that are only compatible with the self-hosted version of n8n.