AutomationFlowsAI & RAG › AI Content Relevance Analyzer with OpenAI

AI Content Relevance Analyzer with OpenAI

Original n8n title: AI Relevance Analyzer - Improved

AI Relevance Analyzer - Improved. Uses postgres, openAi, telegram. Webhook trigger; 6 nodes.

Webhook trigger★★★★☆ complexityAI-powered6 nodesPostgresOpenAITelegram
AI & RAG Trigger: Webhook Nodes: 6 Complexity: ★★★★☆ AI nodes: yes Added:

This workflow follows the OpenAI → Postgres 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 →

Download .json
{
  "name": "AI Relevance Analyzer - Improved",
  "nodes": [
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "webhook/ai-analyzer",
        "options": {}
      },
      "id": "analyzer_trigger",
      "name": "Analyzer Trigger - Secured",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2,
      "position": [
        300,
        300
      ]
    },
    {
      "parameters": {
        "operation": "executeQuery",
        "query": "CREATE INDEX IF NOT EXISTS idx_jobs_processed ON jobs (is_processed, scraped_at DESC); CREATE INDEX IF NOT EXISTS idx_relevance_scores_job_user ON relevance_scores (job_id, user_name); SELECT j.*, rs.score as existing_score FROM jobs j WHERE j.is_processed = false AND NOT EXISTS (SELECT 1 FROM relevance_scores rs WHERE rs.job_id = j.id AND rs.user_name = 'Vitalii') ORDER BY j.scraped_at DESC LIMIT 50;",
        "options": {}
      },
      "id": "get_unprocessed_jobs",
      "name": "Get Unprocessed Jobs - Optimized",
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.5,
      "position": [
        500,
        300
      ],
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "resource": "chat",
        "operation": "message",
        "chatModel": "gpt-4o-mini",
        "messages": {
          "messages": [
            {
              "role": "system",
              "content": "\u0422\u0438 \u0435\u043a\u0441\u043f\u0435\u0440\u0442 HR \u0430\u043d\u0430\u043b\u0456\u0442\u0438\u043a \u0434\u043b\u044f \u043e\u0446\u0456\u043d\u043a\u0438 \u0440\u0435\u043b\u0435\u0432\u0430\u043d\u0442\u043d\u043e\u0441\u0442\u0456 \u0432\u0430\u043a\u0430\u043d\u0441\u0456\u0439. \u0410\u043d\u0430\u043b\u0456\u0437\u0443\u0439 \u0432\u0430\u043a\u0430\u043d\u0441\u0456\u0457 \u0434\u043b\u044f \u0443\u043a\u0440\u0430\u0457\u043d\u0441\u044c\u043a\u043e\u0433\u043e \u0440\u043e\u0437\u0440\u043e\u0431\u043d\u0438\u043a\u0430 \u0437 \u0434\u043e\u0441\u0432\u0456\u0434\u043e\u043c Python, JavaScript, \u0432\u0435\u0431-\u0440\u043e\u0437\u0440\u043e\u0431\u043a\u0438.\n\n\u0420\u0415\u0417\u042e\u041c\u0415 \u041a\u041e\u0420\u0418\u0421\u0422\u0423\u0412\u0410\u0427\u0410:\n- \u0414\u043e\u0441\u0432\u0456\u0434: Python, Django, JavaScript, React, Node.js\n- \u0420\u0456\u0432\u0435\u043d\u044c: Middle/Senior Developer\n- \u041c\u043e\u0432\u0438: \u0423\u043a\u0440\u0430\u0457\u043d\u0441\u044c\u043a\u0430 (\u0440\u0456\u0434\u043d\u0430), \u041d\u043e\u0440\u0432\u0435\u0437\u044c\u043a\u0430 (A2), \u0410\u043d\u0433\u043b\u0456\u0439\u0441\u044c\u043a\u0430 (B2)\n- \u041b\u043e\u043a\u0430\u0446\u0456\u044f: \u041e\u0441\u043b\u043e, \u041d\u043e\u0440\u0432\u0435\u0433\u0456\u044f\n- \u0413\u043e\u0442\u043e\u0432\u043d\u0456\u0441\u0442\u044c \u0434\u043e \u0440\u043e\u0431\u043e\u0442\u0438: Full-time, \u0432\u0456\u0434\u0434\u0430\u043b\u0435\u043d\u043e \u0430\u0431\u043e \u043e\u0444\u0456\u0441 \u0432 \u041e\u0441\u043b\u043e\n\n\u041e\u0426\u0406\u041d\u042e\u0419 \u041a\u041e\u0416\u041d\u0423 \u0412\u0410\u041a\u0410\u041d\u0421\u0406\u042e \u0417\u0410 \u041a\u0420\u0418\u0422\u0415\u0420\u0406\u042f\u041c\u0418:\n1. \u0412\u0456\u0434\u043f\u043e\u0432\u0456\u0434\u043d\u0456\u0441\u0442\u044c \u0442\u0435\u0445\u043d\u0456\u0447\u043d\u0438\u0445 \u043d\u0430\u0432\u0438\u0447\u043e\u043a (40%)\n2. \u0420\u0456\u0432\u0435\u043d\u044c \u0434\u043e\u0441\u0432\u0456\u0434\u0443 (30%)\n3. \u041b\u043e\u043a\u0430\u0446\u0456\u044f \u0442\u0430 \u0443\u043c\u043e\u0432\u0438 (20%)\n4. \u041c\u043e\u0432\u043d\u0456 \u0432\u0438\u043c\u043e\u0433\u0438 (10%)\n\n\u0412\u0406\u0414\u041f\u041e\u0412\u0406\u0414\u0410\u0419 JSON:\n{\n  \"score\": 85,\n  \"reasoning\": \"\u0412\u0438\u0441\u043e\u043a\u0438\u0439 \u0437\u0431\u0456\u0433 \u043d\u0430\u0432\u0438\u0447\u043e\u043a Python/Django, \u043b\u043e\u043a\u0430\u0446\u0456\u044f \u041e\u0441\u043b\u043e \u043f\u0456\u0434\u0445\u043e\u0434\u0438\u0442\u044c...\",\n  \"key_matches\": [\"Python\", \"Django\", \"Oslo\"],\n  \"missing_requirements\": [\"5+ years experience\"],\n  \"recommendation\": \"apply\"\n}"
            },
            {
              "role": "user",
              "content": "\u041f\u0440\u043e\u0430\u043d\u0430\u043b\u0456\u0437\u0443\u0439 \u0446\u044e \u0432\u0430\u043a\u0430\u043d\u0441\u0456\u044e:\n\n\u041d\u0430\u0437\u0432\u0430: {{ $json.title }}\n\u041a\u043e\u043c\u043f\u0430\u043d\u0456\u044f: {{ $json.company }}\n\u041b\u043e\u043a\u0430\u0446\u0456\u044f: {{ $json.location }}\n\u0414\u0436\u0435\u0440\u0435\u043b\u043e: {{ $json.source }}\nURL: {{ $json.url }}\n\n\u041e\u0446\u0456\u043d\u0438 \u0440\u0435\u043b\u0435\u0432\u0430\u043d\u0442\u043d\u0456\u0441\u0442\u044c \u0432\u0456\u0434 0 \u0434\u043e 100 \u0442\u0430 \u043f\u043e\u044f\u0441\u043d\u0438 \u0440\u0456\u0448\u0435\u043d\u043d\u044f."
            }
          ]
        }
      },
      "id": "analyze_job_relevance",
      "name": "Analyze Job Relevance - Reliable",
      "type": "n8n-nodes-base.openAi",
      "typeVersion": 1.2,
      "position": [
        700,
        300
      ],
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      },
      "continueOnFail": true,
      "retryOnFail": true,
      "maxTries": 3,
      "waitBetweenTries": 2000
    },
    {
      "parameters": {
        "functionCode": "const items = $input.all();\nconst results = [];\n\nfor (const item of items) {\n  try {\n    const jobData = item.json;\n    let analysis = {};\n    \n    if (item.error) {\n      analysis = {\n        score: 25,\n        reasoning: 'AI analysis failed: ' + item.error.message,\n        key_matches: [],\n        missing_requirements: ['AI analysis error'],\n        recommendation: 'review_manually'\n      };\n    } else {\n      const aiResponse = item.json.message?.content || item.json.text || '';\n      \n      try {\n        const jsonMatch = aiResponse.match(/\\{[\\s\\S]*\\}/);\n        analysis = JSON.parse(jsonMatch ? jsonMatch[0] : aiResponse);\n        analysis.score = Math.min(Math.max(analysis.score || 0, 0), 100);\n      } catch (parseError) {\n        analysis = {\n          score: 30,\n          reasoning: 'JSON parse failed: ' + parseError.message,\n          key_matches: [],\n          missing_requirements: ['JSON parsing error'],\n          recommendation: 'review_manually'\n        };\n      }\n    }\n    \n    results.push({\n      job_id: jobData.id,\n      title: jobData.title,\n      company: jobData.company,\n      url: jobData.url,\n      score: analysis.score,\n      reasoning: (analysis.reasoning || 'No reasoning').replace(/'/g, \"''\"),\n      key_matches: JSON.stringify(analysis.key_matches || []),\n      missing_requirements: JSON.stringify(analysis.missing_requirements || []),\n      recommendation: analysis.recommendation || 'review',\n      ai_analysis: JSON.stringify(analysis),\n      analyzed_at: new Date().toISOString()\n    });\n  } catch (error) {\n    results.push({\n      job_id: item.json?.id || 0,\n      score: 0,\n      reasoning: 'Error: ' + error.message,\n      recommendation: 'error'\n    });\n  }\n}\n\nreturn results;"
      },
      "id": "process_ai_results",
      "name": "Process AI Results - Enhanced",
      "type": "n8n-nodes-base.function",
      "typeVersion": 1,
      "position": [
        900,
        300
      ]
    },
    {
      "parameters": {
        "operation": "executeQuery",
        "query": "INSERT INTO relevance_scores (job_id, user_name, score, reasoning, ai_analysis, created_at) VALUES {{ $json.map(item => `(${item.job_id}, 'Vitalii', ${item.score}, '${item.reasoning}', '${item.ai_analysis.replace(/'/g, \"''\")}', '${item.analyzed_at}')`).join(', ') }}; UPDATE jobs SET is_processed = true WHERE id IN ({{ $json.map(item => item.job_id).join(', ') }}); SELECT j.*, rs.score, rs.reasoning, rs.recommendation FROM jobs j JOIN relevance_scores rs ON j.id = rs.job_id WHERE rs.score >= 80 AND rs.user_name = 'Vitalii' AND j.id IN ({{ $json.map(item => item.job_id).join(', ') }}) ORDER BY rs.score DESC;",
        "options": {}
      },
      "id": "save_analysis_results",
      "name": "Save Analysis Results - Improved",
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.5,
      "position": [
        1100,
        300
      ],
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "chatId": "{{ $env.TELEGRAM_CHAT_ID }}",
        "text": "\ud83e\udde0 AI Analysis Complete\\n\\n\ud83d\udcca Jobs analyzed: {{ $('Process AI Results - Enhanced').all().length }}\\n\ud83c\udfaf High relevance (80%+): {{ $json.length }}\\n\\n{{ $json.length > 0 ? '\u2705 Starting application process...' : '\u2139\ufe0f No high-relevance jobs found' }}\\n\\n\ud83d\udd52 Completed: {{ $now.format('HH:mm DD/MM/YYYY') }}"
      },
      "id": "send_notification",
      "name": "Send Enhanced Notification",
      "type": "n8n-nodes-base.telegram",
      "typeVersion": 1.2,
      "position": [
        1300,
        300
      ],
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      }
    }
  ],
  "connections": {
    "Analyzer Trigger - Secured": {
      "main": [
        [
          {
            "node": "Get Unprocessed Jobs - Optimized",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Unprocessed Jobs - Optimized": {
      "main": [
        [
          {
            "node": "Analyze Job Relevance - Reliable",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Analyze Job Relevance - Reliable": {
      "main": [
        [
          {
            "node": "Process AI Results - Enhanced",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Process AI Results - Enhanced": {
      "main": [
        [
          {
            "node": "Save Analysis Results - Improved",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Save Analysis Results - Improved": {
      "main": [
        [
          {
            "node": "Send Enhanced Notification",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1"
  },
  "staticData": null,
  "tags": [],
  "triggerCount": 0,
  "updatedAt": "2025-01-20T12:00:00.000Z",
  "versionId": "2"
}

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.

Pro

For the full experience including quality scoring and batch install features for each workflow upgrade to Pro

About this workflow

AI Relevance Analyzer - Improved. Uses postgres, openAi, telegram. Webhook trigger; 6 nodes.

Source: https://github.com/SmmShaman/jobbot-norway-public/blob/04db9f51b6c604268bd2be177806f9186ec89e4e/n8n-workflows/02_job_scanner_fixed.json — original creator credit. Request a take-down →

More AI & RAG workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

AI & RAG

Eu Clara – Funil Kiwify Completo. Uses postgres, openAi, httpRequest, gmail. Webhook trigger; 70 nodes.

Postgres, OpenAI, HTTP Request +1
AI & RAG

Lua Nova - Sistema Completo. Uses postgres, httpRequest, openAi. Webhook trigger; 55 nodes.

Postgres, HTTP Request, OpenAI
AI & RAG

User Signup & Verification: The workflow starts when a user signs up. It generates a verification code and sends it via SMS using Twilio. Code Validation: The user replies with the code. The workflow

Postgres, HTTP Request, OpenAI +2
AI & RAG

Pyragogy AI Village - Orchestrazione Master (Architettura Profonda V2). Uses start, postgres, openAi, emailSend. Webhook trigger; 36 nodes.

Start, Postgres, OpenAI +4
AI & RAG

Pyragogy AI Village - Orchestrazione Master (Architettura Profonda V2). Uses start, postgres, openAi, emailSend. Webhook trigger; 35 nodes.

Start, Postgres, OpenAI +3