{
    "nodes": [
        {
            "parameters": {
                "path": "form",
                "responseMode": "responseNode",
                "options": {}
            },
            "name": "Página do Formulário",
            "type": "n8n-nodes-base.webhook",
            "typeVersion": 1,
            "position": [
                176,
                -128
            ],
            "id": "8d8ffd64-3c44-44e5-a414-3d6b8dd558f7",
            "webhookId": "7dbd2033-28f4-4bdb-a578-8776ccd34601"
        },
        {
            "parameters": {
                "respondWith": "text",
                "responseBody": "=<!DOCTYPE html>\n<html lang=\"pt-BR\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <title>Gerador de Vídeo - SnapID + fal.ai</title>\n    <style>\n        body { font-family: 'Inter', system-ui, -apple-system, sans-serif; background: #0f172a; color: #f1f5f9; display: flex; justify-content: center; align-items: center; min-height: 100vh; margin: 0; }\n        .container { background: #1e293b; padding: 40px; border-radius: 20px; box-shadow: 0 20px 50px rgba(0,0,0,0.3); text-align: center; max-width: 500px; width: 90%; border: 1px solid #334155; }\n        h2 { margin-bottom: 10px; color: #f8fafc; }\n        p { color: #94a3b8; margin-bottom: 30px; font-size: 0.95rem; }\n        form { text-align: left; }\n        label { display: block; margin-bottom: 8px; font-weight: 500; font-size: 0.9rem; color: #cbd5e1; }\n        input[type=\"file\"], textarea, select {\n            width: 100%; padding: 12px; margin-bottom: 20px; border-radius: 8px; border: 1px solid #475569; background: #0f172a; color: white; box-sizing: border-box;\n        }\n        textarea { resize: vertical; }\n        \n        /* Estilos dos Botões */\n        button, .btn-download { \n            display: block; text-align: center; text-decoration: none; color: #fff; border: none; padding: 14px 20px; border-radius: 10px; cursor: pointer; width: 100%; font-weight: 600; font-size: 1rem; transition: background 0.2s; box-sizing: border-box;\n        }\n        button[type=\"submit\"] { background: #3b82f6; }\n        button[type=\"submit\"]:hover { background: #2563eb; }\n        \n        .btn-download { background: #10b981; margin-top: 15px; }\n        .btn-download:hover { background: #059669; }\n\n        .grid { display: flex; gap: 15px; }\n        \n        /* Estilos da Barra de Progresso */\n        #progressContainer { margin-top: 25px; display: none; text-align: center; }\n        #progressText { color: #94a3b8; font-size: 0.9rem; margin-bottom: 10px; font-weight: 500; }\n        .progress-track { background: #334155; border-radius: 10px; width: 100%; height: 12px; overflow: hidden; }\n        .progress-fill { background: #3b82f6; width: 0%; height: 100%; transition: width 1s linear; }\n        .progress-error { background: #ef4444 !important; } /* Cor vermelha para erro */\n    </style>\n</head>\n<body>\n    <div class=\"container\">\n        <h2>✨ Criar Vídeo com Grok IA</h2>\n        <p>Envie suas imagens e descreva a cena. Nós fazemos o resto.</p>\n        <form id=\"videoForm\" action=\"http://localhost:5678/webhook-test/snapid-upload-images\" method=\"POST\" enctype=\"multipart/form-data\">\n        <label>🖼️ Imagens de Referência:</label>\n        <input type=\"file\" name=\"files\" accept=\"image/*\" multiple required>\n        \n        <label>📝 O que deve acontecer no vídeo? (Prompt):</label>\n        <textarea name=\"prompt\" rows=\"3\" placeholder=\"Ex: Um astronauta caminhando na lua em câmera lenta...\" required></textarea>\n        \n        <div class=\"grid\">\n            <div style=\"flex:1\">\n                <label>📺 Modo:</label>\n                <select name=\"mode\">\n                    <option value=\"normal\" selected>Normal</option>\n                    <option value=\"fun\">Divertido</option>\n                    <option value=\"spicy\">Apimentado</option>\n                </select>\n            </div>\n            \n            <div style=\"flex:1\">\n                <label>📦 Formato:</label>\n                <select name=\"aspect_ratio\">\n                    <option value=\"2:3\">Vertical (2:3)</option>\n                    <option value=\"3:2\">Horizontal (3:2)</option>\n                    <option value=\"1:1\">Quadrado (1:1)</option>\n                    <option value=\"9:16\">Vertical (9:16)</option>\n                    <option value=\"16:9\">Horizontal (16:9)</option>\n                </select>\n            </div>\n            \n            <div style=\"flex:1\">\n                <label>🎥 Resolução:</label>\n                <select name=\"resolution\">\n                    <option value=\"480p\">480p</option>\n                    <option value=\"720p\">720p</option>\n                </select>\n            </div>\n            \n            <div style=\"flex:1\">\n                <label>⏱️ Duração:</label>\n                <select name=\"duration\">\n                    <option value=\"6\">6 Segundos</option>\n                    <option value=\"8\" selected>8 Segundos</option>\n                    <option value=\"10\">10 Segundos</option>\n                    <option value=\"15\">15 Segundos</option>\n                    <option value=\"20\">20 Segundos</option>\n                    <option value=\"25\">25 Segundos</option>\n                    <option value=\"30\">30 Segundos</option>\n                </select>\n            </div>\n        </div>\n        \n        <label>🛡️ Tolerância de Segurança:</label>\n        <select name=\"safety_tolerance\">\n            <option value=\"1\">1 (Rígido)</option>\n            <option value=\"4\" selected>4 (Normal)</option>\n            <option value=\"6\">6 (Permissivo)</option>\n        </select>\n        \n        <button type=\"submit\" id=\"submitBtn\">🚀 Iniciar Geração</button>\n    </form>\n\n\n        <div id=\"progressContainer\">\n            <div id=\"progressText\">Gerando vídeo... 0%</div>\n            <div class=\"progress-track\">\n                <div class=\"progress-fill\" id=\"progressBar\"></div>\n            </div>\n            \n            <a href=\"#\" id=\"downloadBtn\" class=\"btn-download\" style=\"display: none;\" download>⬇️ Baixar Vídeo</a>\n        </div>\n    </div>\n\n    <script>\n        document.getElementById('videoForm').addEventListener('submit', async function(e) {\n            e.preventDefault(); // Evita que a página recarregue\n\n            const form = e.target;\n            const submitBtn = document.getElementById('submitBtn');\n            const progressContainer = document.getElementById('progressContainer');\n            const progressBar = document.getElementById('progressBar');\n            const progressText = document.getElementById('progressText');\n            const downloadBtn = document.getElementById('downloadBtn');\n\n            // Reset visual caso o usuário esteja tentando de novo após um erro\n            progressBar.classList.remove('progress-error');\n            submitBtn.style.display = 'none';\n            progressContainer.style.display = 'block';\n            downloadBtn.style.display = 'none';\n            progressBar.style.width = '0%';\n\n            // Configuração dos 10 minutos (480 segundos)\n            const totalSeconds = 480;\n            let currentSecond = 0;\n\n            // Inicia o timer da barra de progresso\n            const timer = setInterval(() => {\n                currentSecond++;\n                let percentage = (currentSecond / totalSeconds) * 100;\n                \n                // Trava no 99% até o webhook confirmar a resposta\n                if (percentage >= 99) {\n                    percentage = 99;\n                }\n\n                progressBar.style.width = percentage + '%';\n                progressText.innerText = `Gerando vídeo... ${Math.round(percentage)}%`;\n            }, 1000);\n\n            try {\n                // Envia os dados para o n8n em segundo plano\n                const formData = new FormData(form);\n                const response = await fetch(form.action, {\n                    method: 'POST',\n                    body: formData\n                });\n\n                const result = await response.json();\n\n                // Lógica para lidar com ERRO vindo do n8n\n                // Verifica se o JSON tem uma chave \"error\" OU se a URL do vídeo não veio\n                if (!response.ok || result.error || !result.video_url) {\n                    clearInterval(timer);\n                    progressBar.classList.add('progress-error');\n                    progressBar.style.width = '100%';\n                    // Exibe a mensagem de erro vinda do n8n ou uma genérica\n                    progressText.innerText = `❌ ${result.error || 'Ocorreu um problema ao gerar o vídeo. Tente novamente.'}`;\n                    submitBtn.style.display = 'block'; // Mostra o botão para tentar de novo\n                    submitBtn.innerText = '🔄 Tentar Novamente';\n                    return; // Interrompe a execução aqui\n                }\n\n                // Lógica de SUCESSO\n                clearInterval(timer);\n                progressBar.style.width = '100%';\n                progressText.innerText = '✅ Vídeo Concluído!';\n                \n                // Exibe o botão de download com a URL\n                downloadBtn.style.display = 'block';\n                downloadBtn.href = result.video_url;\n\n            } catch (error) {\n                // Em caso de erro de conexão com o servidor do n8n (ex: n8n fora do ar)\n                clearInterval(timer);\n                progressBar.classList.add('progress-error');\n                progressBar.style.width = '100%';\n                progressText.innerText = '❌ Erro de conexão com o servidor.';\n                submitBtn.style.display = 'block'; \n                submitBtn.innerText = '🔄 Tentar Novamente';\n            }\n        });\n    </script>\n</body>\n</html>",
                "options": {
                    "responseHeaders": {
                        "entries": [
                            {
                                "name": "Content-Type",
                                "value": "text/html"
                            }
                        ]
                    }
                }
            },
            "name": "Exibir Formulário",
            "type": "n8n-nodes-base.respondToWebhook",
            "typeVersion": 1,
            "position": [
                432,
                -128
            ],
            "id": "dc7b477c-002a-4f33-a226-c0aa9617550e"
        },
        {
            "parameters": {
                "httpMethod": "POST",
                "path": "snapid-upload-images",
                "responseMode": "responseNode",
                "options": {}
            },
            "name": "Webhook Receiver",
            "type": "n8n-nodes-base.webhook",
            "typeVersion": 1,
            "position": [
                176,
                208
            ],
            "id": "ebc42a26-dd49-4718-b82f-6e89914753af",
            "webhookId": "cf111fab-5285-4cba-9cdb-acae4bd3ef3b"
        },
        {
            "parameters": {
                "method": "POST",
                "url": "https://snapid.com.br/upload",
                "sendQuery": true,
                "queryParameters": {
                    "parameters": [
                        {
                            "name": "key",
                            "value": "SUA-KEY-AQUI"
                        }
                    ]
                },
                "sendBody": true,
                "contentType": "multipart-form-data",
                "bodyParameters": {
                    "parameters": [
                        {
                            "name": "expiration",
                            "value": "86400"
                        },
                        {
                            "parameterType": "formBinaryData",
                            "name": "file",
                            "inputDataFieldName": "files"
                        }
                    ]
                },
                "options": {}
            },
            "name": "Upload to SnapID",
            "type": "n8n-nodes-base.httpRequest",
            "typeVersion": 4,
            "position": [
                736,
                208
            ],
            "id": "92920c57-90b0-408c-8212-fff9fba2cd50"
        },
        {
            "parameters": {
                "jsCode": "const results = [];\n// Pega todos os arquivos binários que chegaram no Webhook\nconst binaries = $input.first().binary;\n\nif (!binaries) {\n  return [];\n}\n\n// Cria um item separado para cada imagem, padronizando o nome para 'files'\nfor (const key of Object.keys(binaries)) {\n  results.push({\n    json: {\n      original_key: key,\n      fileName: binaries[key].fileName\n    },\n    binary: {\n      files: binaries[key] \n    }\n  });\n}\n\nreturn results;"
            },
            "name": "Separar Imagens",
            "type": "n8n-nodes-base.code",
            "typeVersion": 2,
            "position": [
                464,
                208
            ],
            "id": "09d1d893-ed08-4ae0-a35f-7ef8d9917787"
        },
        {
            "parameters": {
                "jsCode": "// 1. Extrai a URL e coloca aspas duplas ao redor de CADA uma delas\nconst urls = $input.all().map(item => `\"${item.json.data.public_url}\"`);\n\nreturn [{\n  json: {\n    // 2. Junta tudo em um único texto, separando por vírgula\n    urls_formatadas: urls.join(\",\") \n  }\n}];"
            },
            "name": "Agrupar URLs (Code)",
            "type": "n8n-nodes-base.code",
            "typeVersion": 2,
            "position": [
                944,
                208
            ],
            "id": "00271ba7-2c38-47a3-ab54-1dcbee2d9b24"
        },
        {
            "parameters": {
                "amount": 30
            },
            "type": "n8n-nodes-base.wait",
            "typeVersion": 1.1,
            "position": [
                1536,
                208
            ],
            "id": "4489a118-eaed-4c83-af19-ee22df06592d",
            "name": "Wait4",
            "webhookId": "9fd30610-c0b9-4f5c-9af5-89b821c11ec3"
        },
        {
            "parameters": {
                "url": "https://api.kie.ai/api/v1/jobs/recordInfo",
                "authentication": "genericCredentialType",
                "genericAuthType": "httpHeaderAuth",
                "sendQuery": true,
                "queryParameters": {
                    "parameters": [
                        {
                            "name": "taskId",
                            "value": "={{ $json.data.taskId }}"
                        }
                    ]
                },
                "options": {}
            },
            "type": "n8n-nodes-base.httpRequest",
            "typeVersion": 4.2,
            "position": [
                1680,
                208
            ],
            "id": "b6f7cf83-937f-42e8-a5bc-601bcc1875d0",
            "name": "Get Video4",
            "credentials": {
                "httpHeaderAuth": {
                    "id": "DWj3ABOMbMqAfLg5",
                    "name": "kie ai"
                }
            }
        },
        {
            "parameters": {
                "content": "## Sora 2 - KIE AI",
                "height": 496,
                "width": 1280,
                "color": 5
            },
            "type": "n8n-nodes-base.stickyNote",
            "typeVersion": 1,
            "position": [
                1312,
                48
            ],
            "id": "383ea09d-1799-47e9-bba8-c355544b3728",
            "name": "Sticky Note5"
        },
        {
            "parameters": {
                "assignments": {
                    "assignments": [
                        {
                            "id": "714ed3d2-1e81-4aae-a977-8151769371a7",
                            "name": "video_url",
                            "value": "={{ $json.data.resultJson }}",
                            "type": "string"
                        }
                    ]
                },
                "options": {}
            },
            "type": "n8n-nodes-base.set",
            "typeVersion": 3.4,
            "position": [
                2032,
                96
            ],
            "id": "e5889d5a-83ca-459b-9ccf-4bc9cb7c3043",
            "name": "Video URL4"
        },
        {
            "parameters": {
                "url": "={{ JSON.parse($json.video_url).resultUrls[0] }}",
                "options": {}
            },
            "type": "n8n-nodes-base.httpRequest",
            "typeVersion": 4.2,
            "position": [
                2224,
                96
            ],
            "id": "a9af3c6b-3d10-40d7-b625-15334154cbe9",
            "name": "Download File"
        },
        {
            "parameters": {
                "rules": {
                    "values": [
                        {
                            "conditions": {
                                "options": {
                                    "caseSensitive": true,
                                    "leftValue": "",
                                    "typeValidation": "strict",
                                    "version": 2
                                },
                                "conditions": [
                                    {
                                        "id": "e173101c-7e77-4b31-ad49-67d394ca7458",
                                        "leftValue": "={{ $json.data.state }}",
                                        "rightValue": "success",
                                        "operator": {
                                            "type": "string",
                                            "operation": "equals",
                                            "name": "filter.operator.equals"
                                        }
                                    }
                                ],
                                "combinator": "and"
                            },
                            "renameOutput": true,
                            "outputKey": "Sucesso"
                        },
                        {
                            "conditions": {
                                "options": {
                                    "caseSensitive": true,
                                    "leftValue": "",
                                    "typeValidation": "strict",
                                    "version": 2
                                },
                                "conditions": [
                                    {
                                        "leftValue": "={{ $json.data.state }}",
                                        "rightValue": "generating",
                                        "operator": {
                                            "type": "string",
                                            "operation": "equals"
                                        },
                                        "id": "e4fc5d01-650e-422c-9711-bed182b93560"
                                    }
                                ],
                                "combinator": "and"
                            },
                            "renameOutput": true,
                            "outputKey": "Gerando"
                        },
                        {
                            "conditions": {
                                "options": {
                                    "caseSensitive": true,
                                    "leftValue": "",
                                    "typeValidation": "strict",
                                    "version": 2
                                },
                                "conditions": [
                                    {
                                        "id": "8ee9bcac-aa9a-4433-b734-e2403fc3b041",
                                        "leftValue": "={{ $json.data.state }}",
                                        "rightValue": "fail",
                                        "operator": {
                                            "type": "string",
                                            "operation": "equals",
                                            "name": "filter.operator.equals"
                                        }
                                    }
                                ],
                                "combinator": "and"
                            },
                            "renameOutput": true,
                            "outputKey": "Erro"
                        },
                        {
                            "conditions": {
                                "options": {
                                    "caseSensitive": true,
                                    "leftValue": "",
                                    "typeValidation": "strict",
                                    "version": 2
                                },
                                "conditions": [
                                    {
                                        "id": "1fcb08a2-a3a2-4a2e-99f4-2326e9ab356b",
                                        "leftValue": "={{ $json.data.state }}",
                                        "rightValue": "waiting",
                                        "operator": {
                                            "type": "string",
                                            "operation": "equals",
                                            "name": "filter.operator.equals"
                                        }
                                    }
                                ],
                                "combinator": "and"
                            },
                            "renameOutput": true,
                            "outputKey": "Esperando"
                        }
                    ]
                },
                "options": {}
            },
            "type": "n8n-nodes-base.switch",
            "typeVersion": 3.3,
            "position": [
                1840,
                176
            ],
            "id": "8f2eef6c-5cb5-46a5-9032-b7309ece63ca",
            "name": "Switch"
        },
        {
            "parameters": {
                "method": "POST",
                "url": "https://api.kie.ai/api/v1/jobs/createTask",
                "sendHeaders": true,
                "headerParameters": {
                    "parameters": [
                        {
                            "name": "Authorization",
                            "value": "Bearer SUA-KEY-AQUI"
                        }
                    ]
                },
                "sendBody": true,
                "specifyBody": "json",
                "jsonBody": "={\n  \"model\": \"grok-imagine/image-to-video\",\n  \"callBackUrl\": \"https://your-domain.com/api/callback\",\n  \"input\": {\n    \"task_id\": \"task_grok_12345678\",\n    \"image_urls\": [\n      {{ $json.urls_formatadas }}\n    ],\n    \"prompt\": {{ JSON.stringify($('Webhook Receiver').item.json.body.prompt) }},\n    \"mode\": \"{{ $('Webhook Receiver').item.json.body.mode }}\",\n    \"duration\": \"{{ $('Webhook Receiver').item.json.body.duration }}\",\n    \"resolution\": \"{{ $('Webhook Receiver').item.json.body.resolution }}\",\n    \"aspect_ratio\": \"{{ $('Webhook Receiver').item.json.body.aspect_ratio }}\"\n  }\n}",
                "options": {
                    "redirect": {
                        "redirect": {}
                    }
                }
            },
            "type": "n8n-nodes-base.httpRequest",
            "typeVersion": 4.4,
            "position": [
                1200,
                208
            ],
            "id": "ec72c695-1d38-4486-a64a-646792202c61",
            "name": "HTTP Request"
        },
        {
            "parameters": {
                "respondWith": "json",
                "responseBody": "={{\n  {\n    \"error\":  \"Falha na geração do vídeo com a IA. Por favor, revise os dados e tente novamente.\"\n  }\n}}",
                "options": {
                    "responseCode": 200
                }
            },
            "id": "c0dd6527-78c1-4a7d-9bb9-e6de3ff4b505",
            "name": "Webhook Erro",
            "type": "n8n-nodes-base.respondToWebhook",
            "typeVersion": 1,
            "position": [
                2416,
                288
            ]
        },
        {
            "parameters": {
                "respondWith": "json",
                "responseBody": "={{\n  {\n    \"video_url\": JSON.parse($json.video_url).resultUrls[0]\n  }\n}}",
                "options": {
                    "responseCode": 200
                }
            },
            "id": "93df8489-ad8b-453e-bfe2-d5cc950d19fc",
            "name": "Webhook Sucesso",
            "type": "n8n-nodes-base.respondToWebhook",
            "typeVersion": 1,
            "position": [
                2416,
                96
            ]
        }
    ],
    "connections": {
        "Página do Formulário": {
            "main": [
                [
                    {
                        "node": "Exibir Formulário",
                        "type": "main",
                        "index": 0
                    }
                ]
            ]
        },
        "Webhook Receiver": {
            "main": [
                [
                    {
                        "node": "Separar Imagens",
                        "type": "main",
                        "index": 0
                    }
                ]
            ]
        },
        "Upload to SnapID": {
            "main": [
                [
                    {
                        "node": "Agrupar URLs (Code)",
                        "type": "main",
                        "index": 0
                    }
                ]
            ]
        },
        "Separar Imagens": {
            "main": [
                [
                    {
                        "node": "Upload to SnapID",
                        "type": "main",
                        "index": 0
                    }
                ]
            ]
        },
        "Agrupar URLs (Code)": {
            "main": [
                [
                    {
                        "node": "HTTP Request",
                        "type": "main",
                        "index": 0
                    }
                ]
            ]
        },
        "Wait4": {
            "main": [
                [
                    {
                        "node": "Get Video4",
                        "type": "main",
                        "index": 0
                    }
                ]
            ]
        },
        "Get Video4": {
            "main": [
                [
                    {
                        "node": "Switch",
                        "type": "main",
                        "index": 0
                    }
                ]
            ]
        },
        "Video URL4": {
            "main": [
                [
                    {
                        "node": "Download File",
                        "type": "main",
                        "index": 0
                    }
                ]
            ]
        },
        "Download File": {
            "main": [
                [
                    {
                        "node": "Webhook Sucesso",
                        "type": "main",
                        "index": 0
                    }
                ]
            ]
        },
        "Switch": {
            "main": [
                [
                    {
                        "node": "Video URL4",
                        "type": "main",
                        "index": 0
                    }
                ],
                [
                    {
                        "node": "Wait4",
                        "type": "main",
                        "index": 0
                    }
                ],
                [
                    {
                        "node": "Webhook Erro",
                        "type": "main",
                        "index": 0
                    }
                ],
                [
                    {
                        "node": "Wait4",
                        "type": "main",
                        "index": 0
                    }
                ]
            ]
        },
        "HTTP Request": {
            "main": [
                [
                    {
                        "node": "Wait4",
                        "type": "main",
                        "index": 0
                    }
                ]
            ]
        }
    },
    "pinData": {},
    "meta": {
        "instanceId": "ea88013e5b7309b0c438c7b5879b0b0d92d2795380298c2786b7759d6ebb26dd"
    }
}