{
  "name": "RSS Collector - Scraping and Validation",
  "nodes": [
    {
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "hours",
              "hoursInterval": 6
            }
          ]
        }
      },
      "id": "schedule-trigger",
      "name": "Schedule Trigger - 6h",
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.2,
      "position": [
        250,
        300
      ]
    },
    {
      "parameters": {
        "authentication": "serviceAccount",
        "resource": "row",
        "operation": "get",
        "tableId": "rss_sources",
        "returnAll": true,
        "filterType": "string",
        "filterString": "ativo=eq.true"
      },
      "id": "get-rss-sources",
      "name": "Buscar Fontes RSS Ativas",
      "type": "n8n-nodes-base.supabase",
      "typeVersion": 1,
      "position": [
        450,
        300
      ],
      "credentials": {
        "supabaseApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "batchSize": 1,
        "options": {}
      },
      "id": "split-sources",
      "name": "Loop Over RSS Sources",
      "type": "n8n-nodes-base.splitInBatches",
      "typeVersion": 3,
      "position": [
        650,
        300
      ]
    },
    {
      "parameters": {
        "url": "={{ $json.url_feed }}",
        "options": {
          "quantity": 20
        }
      },
      "id": "rss-feed-read",
      "name": "Ler Feed RSS",
      "type": "n8n-nodes-base.rssFeedRead",
      "typeVersion": 1,
      "position": [
        850,
        300
      ]
    },
    {
      "parameters": {
        "jsCode": "// Extrair e preparar dados dos itens do feed\nconst items = $input.all();\nconst feedItems = [];\nconst sourceData = $('Loop Over RSS Sources').item.json;\n\nfor (const item of items) {\n  feedItems.push({\n    url_original: item.json.link,\n    titulo_original: item.json.title,\n    descricao: item.json.description || item.json.contentSnippet || '',\n    data_publicacao: item.json.pubDate || item.json.isoDate || new Date().toISOString(),\n    rss_source_id: sourceData.id,\n    rss_source_nome: sourceData.nome,\n    config_scraping: sourceData.config_scraping || {}\n  });\n}\n\nreturn feedItems.map(item => ({ json: item }));"
      },
      "id": "extract-feed-data",
      "name": "Extrair URLs dos Itens",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1050,
        300
      ]
    },
    {
      "parameters": {
        "batchSize": 1,
        "options": {}
      },
      "id": "split-feed-items",
      "name": "Loop Over Feed Items",
      "type": "n8n-nodes-base.splitInBatches",
      "typeVersion": 3,
      "position": [
        1250,
        300
      ]
    },
    {
      "parameters": {
        "jsCode": "// Preparar dados para verifica\u00e7\u00e3o de duplicatas\nconst currentItem = $json;\n\n// Garantir que temos os dados necess\u00e1rios\nif (!currentItem.url_original) {\n  throw new Error('url_original n\u00e3o encontrado no item atual');\n}\n\nreturn [{\n  json: {\n    url_original: currentItem.url_original,\n    titulo_original: currentItem.titulo_original || '',\n    descricao: currentItem.descricao || '',\n    data_publicacao: currentItem.data_publicacao || new Date().toISOString(),\n    rss_source_id: currentItem.rss_source_id,\n    rss_source_nome: currentItem.rss_source_nome || '',\n    config_scraping: currentItem.config_scraping || {}\n  }\n}];"
      },
      "id": "prepare-duplicate-check",
      "name": "Preparar Dados para Verifica\u00e7\u00e3o",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1450,
        300
      ]
    },
    {
      "parameters": {
        "authentication": "serviceAccount",
        "resource": "row",
        "operation": "get",
        "tableId": "materias_originais",
        "returnAll": false,
        "limit": 1,
        "filterType": "string",
        "filterString": "=url_original=eq.{{ $json.url_original }}"
      },
      "id": "check-duplicates",
      "name": "Verificar Duplicatas",
      "type": "n8n-nodes-base.supabase",
      "typeVersion": 1,
      "position": [
        1650,
        300
      ],
      "credentials": {
        "supabaseApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict"
          },
          "conditions": [
            {
              "id": "not-exists",
              "leftValue": "={{ $json.id }}",
              "rightValue": "",
              "operator": {
                "type": "string",
                "operation": "isEmpty"
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "id": "if-not-duplicate",
      "name": "IF: URL n\u00e3o existe?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [
        1850,
        300
      ]
    },
    {
      "parameters": {
        "method": "GET",
        "url": "={{ $('Extrair URLs dos Itens').item.json.url_original }}",
        "options": {
          "headers": {
            "entries": [
              {
                "name": "User-Agent",
                "value": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
              }
            ]
          },
          "timeout": 30000,
          "response": {
            "response": {
              "responseFormat": "text"
            }
          }
        }
      },
      "id": "scrape-content",
      "name": "Scraping do Conte\u00fado",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        2050,
        200
      ],
      "continueOnFail": true
    },
    {
      "parameters": {
        "jsCode": "// Preparar seletores CSS baseado na config ou usar defaults\nconst feedData = $('Preparar Dados para Verifica\u00e7\u00e3o').item.json;\nconst configScraping = feedData.config_scraping || {};\n\nconst htmlContent = $json.data || '';\n\nreturn [{\n  json: {\n    html: htmlContent,\n    url_original: feedData.url_original,\n    titulo_original: feedData.titulo_original,\n    data_publicacao: feedData.data_publicacao,\n    rss_source_id: feedData.rss_source_id,\n    rss_source_nome: feedData.rss_source_nome,\n    seletor_titulo: configScraping.seletor_titulo || 'h1, .post-title, .entry-title, article h1, .article-title',\n    seletor_conteudo: configScraping.seletor_conteudo || 'article, .post-content, .entry-content, .content, main, .article-body',\n    seletor_imagem: configScraping.seletor_imagem || 'meta[property=\"og:image\"], .featured-image img, article img:first-of-type'\n  }\n}];"
      },
      "id": "prepare-selectors",
      "name": "Preparar Seletores CSS",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        2250,
        200
      ]
    },
    {
      "parameters": {
        "jsCode": "// Extrair conte\u00fado usando seletores CSS\nconst { JSDOM } = require('jsdom');\nconst html = $json.html;\nconst dom = new JSDOM(html);\nconst document = dom.window.document;\n\n// Fun\u00e7\u00e3o auxiliar para extrair texto\nfunction extractText(selector) {\n  const elements = document.querySelectorAll(selector);\n  for (const el of elements) {\n    if (el && el.textContent.trim()) {\n      return el.textContent.trim();\n    }\n  }\n  return '';\n}\n\n// Fun\u00e7\u00e3o auxiliar para extrair HTML\nfunction extractHTML(selector) {\n  const elements = document.querySelectorAll(selector);\n  for (const el of elements) {\n    if (el && el.innerHTML.trim()) {\n      return el.innerHTML.trim();\n    }\n  }\n  return '';\n}\n\n// Fun\u00e7\u00e3o auxiliar para extrair atributo de imagem\nfunction extractImage(selector) {\n  const elements = document.querySelectorAll(selector);\n  for (const el of elements) {\n    if (el) {\n      return el.getAttribute('content') || el.getAttribute('src') || '';\n    }\n  }\n  return '';\n}\n\nconst tituloExtraido = extractText($json.seletor_titulo);\nconst conteudoHTML = extractHTML($json.seletor_conteudo);\nconst imagemDestaque = extractImage($json.seletor_imagem);\n\nreturn [{\n  json: {\n    url_original: $json.url_original,\n    titulo_original: tituloExtraido || $json.titulo_original,\n    conteudo_html: conteudoHTML,\n    imagem_destaque: imagemDestaque,\n    data_publicacao: $json.data_publicacao,\n    rss_source_id: $json.rss_source_id,\n    rss_source_nome: $json.rss_source_nome\n  }\n}];"
      },
      "id": "extract-with-css",
      "name": "Extrair com Seletores",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        2450,
        200
      ]
    },
    {
      "parameters": {
        "jsCode": "// Limpar HTML e extrair apenas texto\nfunction cleanHTML(html) {\n  if (!html) return '';\n  \n  // Remover scripts, styles e comments\n  let text = html.replace(/<script\\b[^<]*(?:(?!<\\/script>)<[^<]*)*<\\/script>/gi, '');\n  text = text.replace(/<style\\b[^<]*(?:(?!<\\/style>)<[^<]*)*<\\/style>/gi, '');\n  text = text.replace(/<!--[\\s\\S]*?-->/g, '');\n  \n  // Adicionar quebras de linha antes de elementos block\n  text = text.replace(/<\\/(p|div|h[1-6]|li|td|tr|section|article)>/gi, '\\n');\n  text = text.replace(/<br\\s*\\/?>/gi, '\\n');\n  \n  // Remover todas as tags HTML\n  text = text.replace(/<[^>]+>/g, ' ');\n  \n  // Decodificar entidades HTML comuns\n  text = text.replace(/&nbsp;/g, ' ');\n  text = text.replace(/&amp;/g, '&');\n  text = text.replace(/&lt;/g, '<');\n  text = text.replace(/&gt;/g, '>');\n  text = text.replace(/&quot;/g, '\"');\n  text = text.replace(/&#39;/g, \"'\");\n  text = text.replace(/&apos;/g, \"'\");\n  \n  // Remover m\u00faltiplos espa\u00e7os e quebras de linha\n  text = text.replace(/[ \\t]+/g, ' ');\n  text = text.replace(/\\n\\s*\\n/g, '\\n\\n');\n  text = text.trim();\n  \n  // Limitar a 15000 caracteres para an\u00e1lise da IA\n  return text.substring(0, 15000);\n}\n\nconst conteudoLimpo = cleanHTML($json.conteudo_html);\nconst tituloFinal = $json.titulo_original;\n\n// Validar se tem conte\u00fado m\u00ednimo\nif (conteudoLimpo.length < 300) {\n  throw new Error('Conte\u00fado muito curto (menos de 300 caracteres)');\n}\n\nreturn [{\n  json: {\n    url_original: $json.url_original,\n    titulo_original: tituloFinal,\n    conteudo_original: conteudoLimpo,\n    imagem_destaque: $json.imagem_destaque,\n    data_publicacao: $json.data_publicacao,\n    rss_source_id: $json.rss_source_id,\n    rss_source_nome: $json.rss_source_nome\n  }\n}];"
      },
      "id": "clean-html",
      "name": "Limpar HTML",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        2650,
        200
      ],
      "continueOnFail": true
    },
    {
      "parameters": {
        "promptType": "define",
        "text": "=**T\u00edtulo:** {{ $json.titulo_original }}\n\n**Conte\u00fado (primeiros 5000 caracteres):**\n{{ $json.conteudo_original.substring(0, 5000) }}\n\n**Fonte:** {{ $json.rss_source_nome }}\n\n**Responda APENAS com JSON no formato:**\n{\n  \"relevante\": true ou false,\n  \"motivo\": \"explica\u00e7\u00e3o breve em 1 linha\",\n  \"categoria_sugerida\": \"tecnologia\" ou \"marketing\" ou \"ia\" ou \"automacao\" ou \"outro\",\n  \"confianca\": 0.0 a 1.0\n}",
        "options": {
          "systemMessage": "Voc\u00ea \u00e9 um agente especializado em avaliar a relev\u00e2ncia de conte\u00fados para um blog de tecnologia, marketing digital, automa\u00e7\u00e3o e IA.\n\nAnalise o artigo fornecido e determine se ele \u00e9 RELEVANTE ou N\u00c3O RELEVANTE.\n\n**Crit\u00e9rios de Relev\u00e2ncia:**\n\u2705 RELEVANTE se for sobre:\n- Tecnologia, programa\u00e7\u00e3o, desenvolvimento web/mobile\n- Intelig\u00eancia Artificial, Machine Learning, automa\u00e7\u00e3o\n- Marketing digital, SEO, redes sociais\n- Neg\u00f3cios digitais, empreendedorismo tech\n- Inova\u00e7\u00e3o, tend\u00eancias tecnol\u00f3gicas\n- Produtividade, ferramentas, software\n\n\u274c N\u00c3O RELEVANTE se for sobre:\n- Pol\u00edtica, esportes, entretenimento\n- Fofocas, celebridades\n- Conte\u00fado muito curto ou superficial\n- Spam, conte\u00fado promocional excessivo\n- Temas completamente fora do escopo tech/marketing\n\n**IMPORTANTE:** Responda APENAS com um JSON v\u00e1lido, sem markdown, sem explica\u00e7\u00f5es adicionais."
        }
      },
      "id": "ai-relevance",
      "name": "IA: Avaliar Relev\u00e2ncia",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "typeVersion": 1.3,
      "position": [
        2850,
        200
      ]
    },
    {
      "parameters": {
        "options": {
          "temperature": 0.3,
          "maxOutputTokens": 500
        }
      },
      "id": "gemini-model",
      "name": "Google Gemini Chat Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
      "typeVersion": 1,
      "position": [
        2850,
        400
      ],
      "credentials": {
        "googlePalmApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "// Parsear e validar resposta da IA\nlet avaliacaoIA;\nconst feedData = $('Limpar HTML').item.json;\n\ntry {\n  // AI Agent retorna a resposta no campo 'output'\n  const agentOutput = $json.output || $json.message || $json.text || $json.content || '';\n  \n  // Tentar parsear como JSON\n  if (typeof agentOutput === 'object') {\n    avaliacaoIA = agentOutput;\n  } else if (typeof agentOutput === 'string') {\n    // Extrair JSON do texto (pode vir com markdown ou texto adicional)\n    const jsonMatch = agentOutput.match(/\\{[\\s\\S]*\\}/);\n    if (jsonMatch) {\n      avaliacaoIA = JSON.parse(jsonMatch[0]);\n    } else {\n      throw new Error('Resposta da IA n\u00e3o cont\u00e9m JSON v\u00e1lido');\n    }\n  } else {\n    throw new Error('Formato de resposta inesperado');\n  }\n  \n  // Validar campos obrigat\u00f3rios\n  if (typeof avaliacaoIA.relevante !== 'boolean') {\n    avaliacaoIA.relevante = false;\n    avaliacaoIA.motivo = 'Resposta inv\u00e1lida da IA';\n  }\n  \n} catch (error) {\n  console.error('Erro ao processar resposta da IA:', error.message);\n  console.error('Resposta recebida:', JSON.stringify($json, null, 2));\n  avaliacaoIA = {\n    relevante: false,\n    motivo: 'Erro ao processar resposta: ' + error.message,\n    categoria_sugerida: 'outro',\n    confianca: 0\n  };\n}\n\nreturn [{\n  json: {\n    ...feedData,\n    relevante: avaliacaoIA.relevante === true,\n    motivo_ia: avaliacaoIA.motivo || 'Sem motivo especificado',\n    categoria_sugerida: avaliacaoIA.categoria_sugerida || 'outro',\n    confianca_ia: avaliacaoIA.confianca || 0.5\n  }\n}];"
      },
      "id": "parse-ai-response",
      "name": "Parsear Resposta IA",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        3050,
        200
      ]
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict"
          },
          "conditions": [
            {
              "id": "is-relevant",
              "leftValue": "={{ $json.relevante }}",
              "rightValue": "true",
              "operator": {
                "type": "boolean",
                "operation": "equals"
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "id": "if-relevant",
      "name": "IF: Conte\u00fado Relevante?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [
        3250,
        200
      ]
    },
    {
      "parameters": {
        "authentication": "serviceAccount",
        "resource": "row",
        "operation": "create",
        "tableId": "materias_originais",
        "dataMode": "defineBelow",
        "fieldsUi": {
          "fieldValues": [
            {
              "fieldName": "rss_source_id",
              "fieldValue": "={{ $json.rss_source_id }}"
            },
            {
              "fieldName": "url_original",
              "fieldValue": "={{ $json.url_original }}"
            },
            {
              "fieldName": "titulo_original",
              "fieldValue": "={{ $json.titulo_original }}"
            },
            {
              "fieldName": "conteudo_original",
              "fieldValue": "={{ $json.conteudo_original }}"
            },
            {
              "fieldName": "data_publicacao",
              "fieldValue": "={{ $json.data_publicacao }}"
            },
            {
              "fieldName": "processado",
              "fieldValue": "false"
            },
            {
              "fieldName": "relevante",
              "fieldValue": "true"
            }
          ]
        }
      },
      "id": "save-materia",
      "name": "Salvar Mat\u00e9ria no Banco",
      "type": "n8n-nodes-base.supabase",
      "typeVersion": 1,
      "position": [
        3450,
        100
      ],
      "credentials": {
        "supabaseApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "method": "POST",
        "url": "={{ $env.N8N_WEBHOOK_BASE_URL }}/gerar-conteudo",
        "options": {
          "headers": {
            "entries": [
              {
                "name": "Content-Type",
                "value": "application/json"
              }
            ]
          },
          "bodyParameters": {
            "parameters": [
              {
                "name": "materia_id",
                "value": "={{ $json.id }}"
              },
              {
                "name": "titulo_original",
                "value": "={{ $('Parsear Resposta IA').item.json.titulo_original }}"
              },
              {
                "name": "conteudo_original",
                "value": "={{ $('Parsear Resposta IA').item.json.conteudo_original }}"
              },
              {
                "name": "rss_source_nome",
                "value": "={{ $('Parsear Resposta IA').item.json.rss_source_nome }}"
              },
              {
                "name": "categoria",
                "value": "={{ $('Parsear Resposta IA').item.json.categoria_sugerida }}"
              }
            ]
          }
        },
        "sendBody": true,
        "bodyContentType": "json"
      },
      "id": "trigger-content-generation",
      "name": "Disparar Gera\u00e7\u00e3o de Conte\u00fado",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        3650,
        100
      ],
      "continueOnFail": true
    },
    {
      "parameters": {
        "jsCode": "// Log de sucesso\nconst materia = $('Parsear Resposta IA').item.json;\nconst saved = $json;\n\nconsole.log(`\u2705 Mat\u00e9ria salva com sucesso!`);\nconsole.log(`\ud83d\udcdd T\u00edtulo: ${materia.titulo_original}`);\nconsole.log(`\ud83c\udd94 ID: ${saved.id}`);\nconsole.log(`\ud83d\udd17 URL: ${materia.url_original}`);\nconsole.log(`\ud83e\udd16 Motivo IA: ${materia.motivo_ia}`);\nconsole.log(`\ud83d\udcc1 Categoria: ${materia.categoria_sugerida}`);\nconsole.log(`\ud83d\udcca Confian\u00e7a: ${(materia.confianca_ia * 100).toFixed(1)}%`);\n\nreturn [{\n  json: {\n    status: 'sucesso',\n    materia_id: saved.id,\n    titulo: materia.titulo_original,\n    url: materia.url_original,\n    categoria: materia.categoria_sugerida,\n    timestamp: new Date().toISOString()\n  }\n}];"
      },
      "id": "log-success",
      "name": "Log de Sucesso",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        3850,
        100
      ]
    },
    {
      "parameters": {
        "jsCode": "// Log de conte\u00fado irrelevante\nconst data = $json;\n\nconsole.log(`\u26a0\ufe0f Conte\u00fado marcado como IRRELEVANTE`);\nconsole.log(`\ud83d\udcdd T\u00edtulo: ${data.titulo_original}`);\nconsole.log(`\ud83d\udd17 URL: ${data.url_original}`);\nconsole.log(`\u274c Motivo: ${data.motivo_ia}`);\nconsole.log(`\ud83d\udcc1 Categoria: ${data.categoria_sugerida}`);\n\nreturn [{\n  json: {\n    status: 'ignorado',\n    motivo: data.motivo_ia,\n    titulo: data.titulo_original\n  }\n}];"
      },
      "id": "log-irrelevant",
      "name": "Log Irrelevante",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        3450,
        300
      ]
    },
    {
      "parameters": {
        "jsCode": "// Estat\u00edsticas finais do processamento\nconst sourcesNode = $('Buscar Fontes RSS Ativas');\nconst feedNode = $('Ler Feed RSS');\nconst newItemsNode = $('IF: URL n\u00e3o existe?');\nconst relevantNode = $('IF: Conte\u00fado Relevante?');\nconst savedNode = $('Salvar Mat\u00e9ria no Banco');\n\nconst stats = {\n  feeds_processados: sourcesNode.itemCount || 0,\n  artigos_encontrados: feedNode.itemCount || 0,\n  artigos_novos: newItemsNode.itemCount || 0,\n  artigos_relevantes: relevantNode.itemCount || 0,\n  artigos_salvos: savedNode.itemCount || 0,\n  taxa_relevancia: newItemsNode.itemCount > 0 \n    ? ((relevantNode.itemCount / newItemsNode.itemCount) * 100).toFixed(1) + '%'\n    : '0%',\n  timestamp: new Date().toISOString(),\n  duracao: '{{ $execution.duration }}ms'\n};\n\nconsole.log('\\n\ud83d\udcca ========== ESTAT\u00cdSTICAS DO PROCESSAMENTO RSS ==========');\nconsole.log(`\ud83d\udd04 Feeds processados: ${stats.feeds_processados}`);\nconsole.log(`\ud83d\udcf0 Artigos encontrados: ${stats.artigos_encontrados}`);\nconsole.log(`\ud83c\udd95 Artigos novos (n\u00e3o duplicados): ${stats.artigos_novos}`);\nconsole.log(`\u2705 Artigos relevantes: ${stats.artigos_relevantes}`);\nconsole.log(`\ud83d\udcbe Artigos salvos: ${stats.artigos_salvos}`);\nconsole.log(`\ud83d\udcc8 Taxa de relev\u00e2ncia: ${stats.taxa_relevancia}`);\nconsole.log(`\u23f1\ufe0f Dura\u00e7\u00e3o total: ${stats.duracao}`);\nconsole.log(`\ud83d\udd50 Timestamp: ${stats.timestamp}`);\nconsole.log('========================================================\\n');\n\nreturn [{ json: stats }];"
      },
      "id": "final-stats",
      "name": "Estat\u00edsticas Finais",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        4050,
        200
      ]
    }
  ],
  "connections": {
    "Schedule Trigger - 6h": {
      "main": [
        [
          {
            "node": "Buscar Fontes RSS Ativas",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Buscar Fontes RSS Ativas": {
      "main": [
        [
          {
            "node": "Loop Over RSS Sources",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Loop Over RSS Sources": {
      "main": [
        null,
        [
          {
            "node": "Ler Feed RSS",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Ler Feed RSS": {
      "main": [
        [
          {
            "node": "Extrair URLs dos Itens",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extrair URLs dos Itens": {
      "main": [
        [
          {
            "node": "Loop Over Feed Items",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Loop Over Feed Items": {
      "main": [
        null,
        [
          {
            "node": "Preparar Dados para Verifica\u00e7\u00e3o",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Preparar Dados para Verifica\u00e7\u00e3o": {
      "main": [
        [
          {
            "node": "Verificar Duplicatas",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Verificar Duplicatas": {
      "main": [
        [
          {
            "node": "IF: URL n\u00e3o existe?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "IF: URL n\u00e3o existe?": {
      "main": [
        [
          {
            "node": "Scraping do Conte\u00fado",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Loop Over Feed Items",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Scraping do Conte\u00fado": {
      "main": [
        [
          {
            "node": "Preparar Seletores CSS",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Preparar Seletores CSS": {
      "main": [
        [
          {
            "node": "Extrair com Seletores",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extrair com Seletores": {
      "main": [
        [
          {
            "node": "Limpar HTML",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Limpar HTML": {
      "main": [
        [
          {
            "node": "IA: Avaliar Relev\u00e2ncia",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "IA: Avaliar Relev\u00e2ncia": {
      "main": [
        [
          {
            "node": "Parsear Resposta IA",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Google Gemini Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "IA: Avaliar Relev\u00e2ncia",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Parsear Resposta IA": {
      "main": [
        [
          {
            "node": "IF: Conte\u00fado Relevante?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "IF: Conte\u00fado Relevante?": {
      "main": [
        [
          {
            "node": "Salvar Mat\u00e9ria no Banco",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Log Irrelevante",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Salvar Mat\u00e9ria no Banco": {
      "main": [
        [
          {
            "node": "Disparar Gera\u00e7\u00e3o de Conte\u00fado",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Disparar Gera\u00e7\u00e3o de Conte\u00fado": {
      "main": [
        [
          {
            "node": "Log de Sucesso",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Log de Sucesso": {
      "main": [
        [
          {
            "node": "Estat\u00edsticas Finais",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Log Irrelevante": {
      "main": [
        []
      ]
    }
  },
  "settings": {
    "executionOrder": "v1",
    "saveManualExecutions": true,
    "callerPolicy": "workflowsFromSameOwner",
    "errorWorkflow": "error-handler"
  },
  "staticData": null,
  "tags": [
    {
      "name": "automation",
      "id": "1"
    },
    {
      "name": "rss",
      "id": "2"
    },
    {
      "name": "content",
      "id": "3"
    }
  ],
  "triggerCount": 1,
  "updatedAt": "2025-01-15T10:00:00.000Z",
  "versionId": "1"
}