Optimizador de CV con IA

Avanzado

Este es unAI Summarization, Multimodal AIflujo de automatización del dominio deautomatización que contiene 18 nodos.Utiliza principalmente nodos como Set, Code, Gmail, Merge, Webhook. Coincidir CVs con descripciones de puestos usando Gemini para análisis y reportes por correo

Requisitos previos
  • Cuenta de Google y credenciales de API de Gmail
  • Punto final de HTTP Webhook (n8n generará automáticamente)
  • Pueden requerirse credenciales de autenticación para la API de destino
  • Clave de API de Google Gemini
Vista previa del flujo de trabajo
Visualización de las conexiones entre nodos, con soporte para zoom y panorámica
Exportar flujo de trabajo
Copie la siguiente configuración JSON en n8n para importar y usar este flujo de trabajo
{
  "id": "TzPKUZdrlcTUenHQ",
  "meta": {
    "instanceId": "d1dc073e8e3059a23e2730f69cb1b90065a2ac39039fea0727fdf9bee77a9131",
    "templateCredsSetupCompleted": true
  },
  "name": "AI CV Optimizer",
  "tags": [],
  "nodes": [
    {
      "id": "08a1bb78-33db-4698-9970-c5b38c25835c",
      "name": "Webhook - Formulario de Optimizador de CV",
      "type": "n8n-nodes-base.webhook",
      "position": [
        -224,
        272
      ],
      "webhookId": "d50feff6-c48f-41e8-8df2-62ee9864907c",
      "parameters": {
        "path": "cv-optimizer",
        "options": {},
        "responseMode": "responseNode",
        "multipleMethods": true
      },
      "typeVersion": 2.1
    },
    {
      "id": "310ffa59-1f26-4ddd-881d-c5819b89d7f1",
      "name": "Webhook Response - Formulario HTML",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        0,
        176
      ],
      "parameters": {
        "options": {},
        "respondWith": "text",
        "responseBody": "=<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"UTF-8\" />\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n  <title>AI CV Optimizer</title>\n  <style>\n    :root {\n      --primary: #2563eb;\n      --primary-hover: #1e4ed8;\n      --gray-light: #f9fafb;\n      --gray: #ccc;\n      --text-dark: #333;\n      --radius: 10px;\n    }\n    body {\n      font-family: Arial, sans-serif;\n      background: var(--gray-light);\n      margin: 0;\n      padding: 0;\n      display: flex;\n      justify-content: center;\n      align-items: center;\n      min-height: 100vh;\n    }\n    .container {\n      background: white;\n      padding: 2rem;\n      border-radius: var(--radius);\n      box-shadow: 0 6px 16px rgba(0,0,0,0.1);\n      max-width: 420px;\n      width: 100%;\n    }\n    h2 {\n      margin-bottom: 1.5rem;\n      color: var(--text-dark);\n      font-size: 1.5rem;\n      text-align: center;\n    }\n    label {\n      font-weight: 600;\n      display: block;\n      margin: 1rem 0 0.5rem;\n    }\n    input[type=\"file\"], input[type=\"text\"], input[type=\"email\"] {\n      width: 100%;\n      padding: 0.75rem;\n      border: 1px solid var(--gray);\n      border-radius: var(--radius);\n      font-size: 0.95rem;\n      box-sizing: border-box;\n    }\n    input:focus {\n      border-color: var(--primary);\n      outline: none;\n      box-shadow: 0 0 0 3px rgba(37,99,235,0.15);\n    }\n    button {\n      margin-top: 1.5rem;\n      padding: 0.9rem;\n      background: var(--primary);\n      color: white;\n      border: none;\n      border-radius: var(--radius);\n      width: 100%;\n      font-size: 1rem;\n      font-weight: 600;\n      cursor: pointer;\n      transition: background 0.2s ease;\n    }\n    button:hover {\n      background: var(--primary-hover);\n    }\n    button:disabled {\n      background: #9ca3af;\n      cursor: not-allowed;\n    }\n    .status {\n      margin-top: 1rem;\n      font-size: 0.9rem;\n      text-align: center;\n    }\n    .status.success { color: green; }\n    .status.error { color: red; }\n  </style>\n</head>\n<body>\n  <div class=\"container\">\n    <h2>AI CV Optimizer</h2>\n    <form id=\"cvForm\">\n      <label for=\"cv\">Upload your CV (PDF):</label>\n      <input type=\"file\" id=\"cv\" name=\"cv\" accept=\"application/pdf\" required />\n\n      <label for=\"job_url\">Job Posting URL:</label>\n      <input type=\"text\" id=\"job_url\" name=\"job_url\" placeholder=\"https://linkedin.com/job/123\" required />\n\n      <label for=\"email\">Your Email:</label>\n      <input type=\"email\" id=\"email\" name=\"email\" placeholder=\"you@example.com\" required/>\n\n      <button type=\"submit\">Check My CV</button>\n      <div class=\"status\" id=\"status\"></div>\n    </form>\n  </div>\n\n  <script>\n    const form = document.getElementById(\"cvForm\");\n    const statusDiv = document.getElementById(\"status\");\n\n    form.addEventListener(\"submit\", async (e) => {\n      e.preventDefault();\n\n      const formData = new FormData(form);\n      statusDiv.textContent = \"⏳ Uploading and analyzing your CV...\";\n      statusDiv.className = \"status\";\n\n      try {\n        const res = await fetch(\"https://n8nworkflow.eu/webhook-test/cv-optimizer\", {\n          method: \"POST\",\n          body: formData\n        });\n\n        if (!res.ok) {\n          throw new Error(\"Server error: \" + res.statusText);\n        }\n\n        const data = await res.json();\n        console.log(\"n8n response:\", data);\n        statusDiv.textContent = \"✅ CV submitted successfully! Check your email for results.\";\n        statusDiv.className = \"status success\";\n      } catch (err) {\n        console.error(err);\n        statusDiv.textContent = \"❌ Error: \" + err.message;\n        statusDiv.className = \"status error\";\n      }\n    });\n  </script>\n</body>\n</html>"
      },
      "typeVersion": 1.4
    },
    {
      "id": "5f221527-5476-49cb-a166-eb3213f5d4a6",
      "name": "Extraer Texto del CV (PDF)",
      "type": "n8n-nodes-base.extractFromFile",
      "position": [
        0,
        384
      ],
      "parameters": {
        "options": {},
        "operation": "pdf",
        "binaryPropertyName": "=cv"
      },
      "typeVersion": 1
    },
    {
      "id": "75eb814c-8d04-4310-bc01-3fcaf1640634",
      "name": "Preparar Texto del CV",
      "type": "n8n-nodes-base.set",
      "position": [
        224,
        384
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "be5e5936-7940-43be-b905-62b54d9db076",
              "name": "cv_text",
              "type": "string",
              "value": "={{ $json.text }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "da50a5a9-a727-45f9-b07c-e75844f89d45",
      "name": "Obtener Descripción del Puesto",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        448,
        304
      ],
      "parameters": {
        "url": "={{ $(' Webhook - CV Optimizer Form').item.json.body.job_url }}",
        "options": {}
      },
      "typeVersion": 4.2
    },
    {
      "id": "405c1c1d-afa1-4b9e-a595-a7eef3772303",
      "name": "Combinar Datos de CV + Puesto",
      "type": "n8n-nodes-base.merge",
      "position": [
        896,
        368
      ],
      "parameters": {
        "mode": "combine",
        "options": {},
        "combineBy": "combineByPosition"
      },
      "typeVersion": 3.2
    },
    {
      "id": "f7e1ebf8-5e4e-48b8-a384-d88f53d771bb",
      "name": "Gemini Model - Principal",
      "type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
      "position": [
        1120,
        592
      ],
      "parameters": {
        "options": {}
      },
      "credentials": {
        "googlePalmApi": {
          "id": "qQGrvqnSPqWFH6I6",
          "name": "Google Gemini(PaLM) Api account 5"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "cf43c082-b2ae-42e0-8d3d-83db4a4d9f9d",
      "name": "Analizar Salida de IA JSON",
      "type": "@n8n/n8n-nodes-langchain.outputParserStructured",
      "position": [
        1248,
        592
      ],
      "parameters": {
        "autoFix": true,
        "jsonSchemaExample": "{\n  \"job_title\": \"Frontend Developer (React)\",\n  \"location\": \"Helsinki, Finland\",\n  \"fit_summary\": \"The candidate has solid React, TypeScript, and JavaScript experience, supported by practical work on full-stack applications. They also demonstrate CI/CD knowledge and testing skills (Cypress, Jest), which align well with the role. However, the CV does not explicitly highlight advanced CSS frameworks or accessibility practices that are emphasized in the job description.\",\n  \"recommendation\": \"Consider\",\n  \"fit_score\": 7,\n  \"missing_critical\": [\n    \"Advanced CSS framework experience (e.g., Tailwind, Material UI)\",\n    \"Accessibility (WCAG) best practices\"\n  ],\n  \"cv_optimization\": \"Add a section highlighting hands-on experience with CSS frameworks (Tailwind, Material UI) and accessibility best practices (WCAG). Include concrete project examples that demonstrate user-focused design and frontend performance improvements.\",\n  \"final_recommendation\": \" The candidate is a good potential match but should strengthen their CV by explicitly mentioning CSS framework expertise and accessibility knowledge to move from 'Consider' to a stronger 'Apply'.\"\n}"
      },
      "typeVersion": 1.3
    },
    {
      "id": "51bd8f61-dea2-4763-beb3-d0171ca55660",
      "name": "Gemini Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
      "position": [
        1328,
        800
      ],
      "parameters": {
        "options": {}
      },
      "credentials": {
        "googlePalmApi": {
          "id": "qQGrvqnSPqWFH6I6",
          "name": "Google Gemini(PaLM) Api account 5"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "a0bbfaab-6717-4a88-9766-97d70dec3f03",
      "name": "Nota Adhesiva",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -224,
        -304
      ],
      "parameters": {
        "width": 512,
        "height": 272,
        "content": "## AI CV Optimizer: Match Your CV to Job Descriptions with AI\n\nThis workflow uses AI to automatically analyze a candidate’s CV against any job posting. It extracts key skills, requirements, and gaps, then generates a clear fit summary, recommendations, and optimization tips. Candidates also receive a structured email report, helping them improve their CV and focus on the right roles.\n\nNo more guesswork, the workflow delivers objective. \n### AI-powered career insights in minutes."
      },
      "typeVersion": 1
    },
    {
      "id": "91fb8dbc-2126-47dc-a4ae-a42d8b9c4397",
      "name": "Nota Adhesiva1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1152,
        192
      ],
      "parameters": {
        "color": 6,
        "width": 224,
        "content": "### AI - Compare CV with Job\n\nYou can adjust the AI Agent prompt for output schema, scoring, or language.\n"
      },
      "typeVersion": 1
    },
    {
      "id": "0343291b-6da2-4155-9a52-164f4c4ab1d1",
      "name": "Nota Adhesiva2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1088,
        736
      ],
      "parameters": {
        "color": 5,
        "width": 208,
        "height": 112,
        "content": "###  Gemini / AI \nCredentials:  \nUse **Google Gemini/PaLM** credential."
      },
      "typeVersion": 1
    },
    {
      "id": "14e53603-87f5-4d4e-92ef-216eb5917964",
      "name": "Nota Adhesiva5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1584,
        528
      ],
      "parameters": {
        "color": 5,
        "width": 192,
        "height": 96,
        "content": "### Send report \nSend Email\nCredentials: Use **Gmail OAuth2** credential. (required)."
      },
      "typeVersion": 1
    },
    {
      "id": "c05f35ba-eeb9-4752-80ef-23eefbcca0f2",
      "name": "Enviar informe",
      "type": "n8n-nodes-base.gmail",
      "position": [
        1616,
        368
      ],
      "webhookId": "ce5d269e-ee40-4c92-9479-e5af8baec199",
      "parameters": {
        "sendTo": "={{ $(' Webhook - CV Optimizer Form').item.json.body.email }}",
        "message": "=<p>Hi,</p>\n\n<p>We’ve analyzed your CV against the job posting for <b>{{ $json.output.job_title }}</b> in <b>{{ $json.output.location }}</b>.</p>\n\n<p><b>Summary:</b><br>\n{{ $json.output.fit_summary }}</p>\n\n<p><b>Critical gaps identified:</b></p>\n<ul>\n  {{ $json.output.missing_critical.map(gap => `<li>${gap}</li>`).join(\"\") }}\n</ul>\n\n<p><b>FinalFit Score:</b> {{ $json.output.fit_score }} / 10 <b> Recommendation: <b/> {{ $json.output.recommendation }}</p>\n<p>\n<b>Tips for improving CV: </b>{{ $json.output.cv_optimization }}\n</p>\n<p><b>AI Advice:</b><br>\n{{ $json.output.final_recommendation }}\n</p>\n\n<p>Best of luck with your applications,<br>AI CV Optimizer</p>",
        "options": {},
        "subject": "=Your CV Review: {{ $json.output.job_title }} in {{ $json.output.location }}"
      },
      "credentials": {
        "gmailOAuth2": {
          "id": "jkKHvU2Pb9X5WJk5",
          "name": "Gmail account"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "8918b88f-f90d-4e68-b28b-84dd68ad854a",
      "name": "Nota Adhesiva11",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -16,
        16
      ],
      "parameters": {
        "color": 5,
        "width": 160,
        "height": 144,
        "content": "### Submission form\n**POST (required)**\n- `Upload CV`\n- `Job Link` \n- `email` "
      },
      "typeVersion": 1
    },
    {
      "id": "03491b28-4df7-4be4-88b1-4128e92fe9b7",
      "name": "Analizador de CV con IA",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        1152,
        368
      ],
      "parameters": {
        "text": "=CV:\n{{ $json[\"cv_text\"] ? $json[\"cv_text\"].slice(0, 18000) : \"\" }}\n\nJOB:\n{{ $json[\"job_text\"] ? $json[\"job_text\"].slice(0, 18000) : \"\" }}\n\nTasks:\n1) Extract the \"job_title\" and \"location\".  \n2) Identify \"matched_skills\" and \"missing_critical\" skills.  \n3) Write a short \"advice\" paragraph (max 100 words).  \n4) Write a friendly \"email_body\" addressed to the candidate, summarizing:\n   - Job title & location  \n   - What they already match well  \n   - Areas to improve or learn for better fit  \n   - A motivating closing sentence \n5)5) Write a short final_recommendation paragraph.\n\n6) Provide **two recommendations**:  \n   - \"recommendation\": Apply / Consider / Not a fit (must align with fit_score)  \n   - \"cv_optimization\": Clear advice on how to improve the CV for similar roles.  \n6) The \"fit_score\" must always align with \"recommendation\":  \n   - Apply → fit_score between 9 and 10  \n   - Consider → fit_score between 7 and 8  \n   - Not a fit → fit_score between 1 and 6  \n\n⚠️ IMPORTANT: Return ONLY valid JSON in this schema:\n{\n  \"job_title\": \"string\",\n  \"location\": \"string\",\n  \"fit_score\": 0,\n  \"recommendation\": \"Apply|Consider|Not a fit\",\n\"final_recommendation\": [\"string\"],\n  \"matched_skills\": [\"string\"],\n  \"missing_critical\": [\"string\"],\n  \"advice\": \"string\",\n  \"cv_optimization\": \"string\",\n  \"email_body\": \"string\"\n}",
        "options": {
          "systemMessage": "You are a professional career assistant.  \nYour task is to compare a candidate’s CV with a job description and return a structured JSON output.  \n\n⚠️ RULES:  \n- Follow the schema exactly.  \n- Every field must be included.  \n- All values must be plain text, arrays, or integers — never nested objects.  \n- `fit_score` must be an integer (1–10) aligned with `recommendation`:  \n   - \"Apply\" → 9–10  \n   - \"Consider\" → 7–8  \n   - \"Not a fit\" → 1–6  \n- Do not add responsibilities, requirements, or benefits.  \n- Do not include any text outside the JSON.  \n\nSchema:\n{\n  \"job_title\": \"string\",\n  \"location\": \"string\",\n  \"fit_score\": 0,\n  \"recommendation\": \"Apply|Consider|Not a fit\",\n  \"matched_skills\": [\"string\"],\n  \"missing_critical\": [\"string\"],\n  \"advice\": \"string\",\n  \"cv_optimization\": \"string\",\n  \"email_body\": \"string\",\n\"final_recommendation\": : \"string\",\n\n}"
        },
        "promptType": "define",
        "hasOutputParser": true
      },
      "typeVersion": 2.2
    },
    {
      "id": "798f0b85-bd22-4ad8-a9c3-a3535d955069",
      "name": "Limpiador de Texto de Puesto",
      "type": "n8n-nodes-base.code",
      "position": [
        672,
        304
      ],
      "parameters": {
        "jsCode": "const raw = $json.data || \"\";\nconst text = raw\n  .replace(/<script[\\s\\S]*?<\\/script>/gi, \"\")\n  .replace(/<style[\\s\\S]*?<\\/style>/gi, \"\")\n  .replace(/<\\/?[^>]+(>|$)/g, \" \")\n  .replace(/\\s+/g, \" \")\n  .trim();\nreturn [{ job_text: text }];"
      },
      "typeVersion": 2
    },
    {
      "id": "eef4754b-adb0-4859-93df-cfc361f8175c",
      "name": "Nota Adhesiva3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        384,
        -304
      ],
      "parameters": {
        "color": 2,
        "width": 304,
        "height": 144,
        "content": "## Customization checklist\n✅ Update Webhook URL\n✅ Configure Google Gemini credentials\n✅ Set Gmail OAuth2 credentials\n✅ Adjust AI prompt if schema changes"
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "pinData": {},
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "039ce290-aa42-4e4a-a346-65841445a6a6",
  "connections": {
    "51bd8f61-dea2-4763-beb3-d0171ca55660": {
      "ai_languageModel": [
        [
          {
            "node": "cf43c082-b2ae-42e0-8d3d-83db4a4d9f9d",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "03491b28-4df7-4be4-88b1-4128e92fe9b7": {
      "main": [
        [
          {
            "node": "c05f35ba-eeb9-4752-80ef-23eefbcca0f2",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "75eb814c-8d04-4310-bc01-3fcaf1640634": {
      "main": [
        [
          {
            "node": "da50a5a9-a727-45f9-b07c-e75844f89d45",
            "type": "main",
            "index": 0
          },
          {
            "node": "405c1c1d-afa1-4b9e-a595-a7eef3772303",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "798f0b85-bd22-4ad8-a9c3-a3535d955069": {
      "main": [
        [
          {
            "node": "405c1c1d-afa1-4b9e-a595-a7eef3772303",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "da50a5a9-a727-45f9-b07c-e75844f89d45": {
      "main": [
        [
          {
            "node": "798f0b85-bd22-4ad8-a9c3-a3535d955069",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "405c1c1d-afa1-4b9e-a595-a7eef3772303": {
      "main": [
        [
          {
            "node": "03491b28-4df7-4be4-88b1-4128e92fe9b7",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "cf43c082-b2ae-42e0-8d3d-83db4a4d9f9d": {
      "ai_outputParser": [
        [
          {
            "node": "03491b28-4df7-4be4-88b1-4128e92fe9b7",
            "type": "ai_outputParser",
            "index": 0
          }
        ]
      ]
    },
    "5f221527-5476-49cb-a166-eb3213f5d4a6": {
      "main": [
        [
          {
            "node": "75eb814c-8d04-4310-bc01-3fcaf1640634",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "f7e1ebf8-5e4e-48b8-a384-d88f53d771bb": {
      "ai_languageModel": [
        [
          {
            "node": "03491b28-4df7-4be4-88b1-4128e92fe9b7",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "08a1bb78-33db-4698-9970-c5b38c25835c": {
      "main": [
        [
          {
            "node": "310ffa59-1f26-4ddd-881d-c5819b89d7f1",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "5f221527-5476-49cb-a166-eb3213f5d4a6",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}
Preguntas frecuentes

¿Cómo usar este flujo de trabajo?

Copie el código de configuración JSON de arriba, cree un nuevo flujo de trabajo en su instancia de n8n y seleccione "Importar desde JSON", pegue la configuración y luego modifique la configuración de credenciales según sea necesario.

¿En qué escenarios es adecuado este flujo de trabajo?

Avanzado - Resumen de IA, IA Multimodal

¿Es de pago?

Este flujo de trabajo es completamente gratuito, puede importarlo y usarlo directamente. Sin embargo, tenga en cuenta que los servicios de terceros utilizados en el flujo de trabajo (como la API de OpenAI) pueden requerir un pago por su cuenta.

Información del flujo de trabajo
Nivel de dificultad
Avanzado
Número de nodos18
Categoría2
Tipos de nodos12
Descripción de la dificultad

Adecuado para usuarios avanzados, flujos de trabajo complejos con 16+ nodos

Enlaces externos
Ver en n8n.io

Compartir este flujo de trabajo

Categorías

Categorías: 34