{
  "name": "ResumeTailor",
  "nodes": [
    {
      "parameters": {
        "workflowInputs": {
          "values": [
            {
              "name": "job_offer_url"
            }
          ]
        }
      },
      "type": "n8n-nodes-base.executeWorkflowTrigger",
      "typeVersion": 1.1,
      "position": [
        64,
        144
      ],
      "id": "0b9ca23e-8735-402d-b226-7cb635a87baa",
      "name": "When Executed by Another Workflow"
    },
    {
      "parameters": {
        "modelId": {
          "__rl": true,
          "value": "gpt-4o-mini",
          "mode": "list",
          "cachedResultName": "GPT-4O-MINI"
        },
        "responses": {
          "values": [
            {
              "content": "=https://www.ziprecruiter.com/Jobs/Artificial-Intelligence-Engineer?lvk=_RL5wOrIEdcTmUPqkaAw-Q.--O2pq0Un83"
            },
            {
              "role": "system",
              "content": "Eres un Agente de Recuperaci\u00f3n de Informaci\u00f3n de RRHH. Tu \u00fanica misi\u00f3n es seguir un protocolo estricto para extraer informaci\u00f3n de una base de conocimiento, analizar una oferta de trabajo y devolver un JSON completo y preciso.\n\n**Manifiesto de la Base de Conocimiento (`cv_data`):**\nTu base de conocimiento est\u00e1 en Google Drive. Esta tabla es tu \u00fanica fuente de verdad sobre los archivos disponibles y c\u00f3mo leerlos.\n\n| Nombre Exacto del Archivo                | Tipo de Archivo   | Herramienta Correcta para Leer | Prop\u00f3sito del Contenido                          |\n| ----------------------------------------- | ----------------- | -------------------------------- | ------------------------------------------------ |\n| **'datos personales'**                    | Google Sheet      | `googleSheetsTool`               | **OBLIGATORIO:** Nombre, contacto, enlaces.      |\n| **'experiencia laboral'**                 | Google Sheet      | `googleSheetsTool`               | Historial profesional.                           |\n| **'proyectos personales y academicos'**   | Google Sheet      | `googleSheetsTool`               | Proyectos t\u00e9cnicos.                              |\n| **'cursos y certificados'**               | Google Sheet      | `googleSheetsTool`               | Formaci\u00f3n complementaria.                        |\n| **'formacion academica'**                 | Google Sheet      | `googleSheetsTool`               | Educaci\u00f3n universitaria.                         |\n| **'habilidades'**                         | Google Doc        | `googleDocsTool`                 | Lista de competencias.                           |\n| **'Presentaciones personales'**           | Google Doc        | `googleDocsTool`                 | Borradores de res\u00famenes.                         |\n\n**PROTOCOLO DE ACCI\u00d3N OBLIGATORIO Y SECUENCIAL:**\n\n**FASE 1: AN\u00c1LISIS Y PLANIFICACI\u00d3N.**\n1.  Recibe la URL de la oferta y extr\u00e1ela. Su prop\u00f3sito es dar CONTEXTO para la selecci\u00f3n y redacci\u00f3n de la informaci\u00f3n, pero los datos del CV provienen EXCLUSIVAMENTE de los archivos de Google Drive.\n2.  Crea una lista de verificaci\u00f3n mental con TODOS los 7 archivos del manifiesto. Tu misi\u00f3n es leer el contenido de CADA UNO de ellos sin excepci\u00f3n.\n\n**FASE 2: BUCLE DE RECUPERACI\u00d3N EXHAUSTIVA.**\n1.  Para CADA archivo en tu lista, ejecuta el siguiente sub-protocolo de tres pasos:\n    *   **Paso A: BUSCAR ID.** Usa `googleDriveTool` (`fileFolder: search`) con `queryString: \"nombre_exacto_del_archivo\"` para obtener el ID.\n    *   **Paso B: IDENTIFICAR HERRAMIENTA.** Consulta la columna `Herramienta Correcta para Leer` en el Manifiesto.\n    *   **Paso C: LEER CONTENIDO.** Usa la herramienta identificada en el Paso B con el `documentId` obtenido en el Paso A.\n\n2.  **REGLA DE FASE 2:** NO intentes sintetizar ni generar el JSON final durante esta fase. Tu \u00fanico objetivo es recolectar TODA la informaci\u00f3n de TODOS los archivos de la lista.\n\n**FASE 3: S\u00cdNTESIS Y GENERACI\u00d3N DEL JSON FINAL.**\n1.  Una vez, y **SOLO UNA VEZ**, que hayas le\u00eddo TODOS los archivos, pasas a esta fase.\n2.  **DIRECTIVA CR\u00cdTICA:** Al construir el JSON final, el objeto `candidate_profile` DEBE ser poblado PRIMERO con la informaci\u00f3n extra\u00edda del archivo `'datos personales'` (nombre, email, etc.). Este paso no es opcional.\n3.  Despu\u00e9s, analiza la oferta y selecciona las habilidades, experiencias y proyectos m\u00e1s relevantes de la informaci\u00f3n que recolectaste para completar el resto del JSON.\n4.  **REGLA DE ORO (INQUEBRANTABLE):** Tu turno NO puede terminar sin emitir el JSON final una vez que la recuperaci\u00f3n ha comenzado. Si tienes problemas con un archivo, an\u00f3talo, pero SIEMPRE produce el JSON con la informaci\u00f3n que s\u00ed obtuviste.\n\n**Formato de Salida Obligatorio (JSON):**\n{\n  \"job_offer_details\": {\n    \"title\": \"...\",\n    \"company\": \"...\",\n    \"key_requirements\": [...]\n  },\n  \"candidate_profile\": {\n    \"personal_info\": {\n      \"name\": \"Nombre extra\u00eddo de 'datos personales'\",\n      \"email\": \"Email extra\u00eddo de 'datos personales'\",\n      \"phone\": \"Tel\u00e9fono extra\u00eddo de 'datos personales'\",\n      \"linkedin\": \"URL de LinkedIn extra\u00edda de 'datos personales'\",\n      \"github\": \"URL de GitHub extra\u00edda de 'datos personales'\"\n    },\n    \"relevant_skills\": [...],\n    \"key_experiences\": [...],\n    \"highlighted_projects\": [...],\n    \"education\": \"...\",\n    \"suggested_summary\": \"...\"\n  }\n}"
            }
          ]
        },
        "builtInTools": {
          "webSearch": {
            "searchContextSize": "medium"
          }
        },
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.openAi",
      "typeVersion": 2,
      "position": [
        352,
        144
      ],
      "id": "b8da4f99-6d5c-4bfb-8088-c13677769b03",
      "name": "info retriever",
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "get",
        "documentURL": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Doc_ID_or_URL', `no es el nombre del documento, sino su ID. Puede encontrarse con la herramienta de google drive`, 'string') }}",
        "simple": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Simplify', ``, 'boolean') }}"
      },
      "type": "n8n-nodes-base.googleDocsTool",
      "typeVersion": 2,
      "position": [
        288,
        368
      ],
      "id": "3b8808a2-3c84-4470-9dc5-bed10d023bd1",
      "name": "leer docs",
      "credentials": {
        "googleDocsOAuth2Api": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "resource": "fileFolder",
        "limit": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Limit', ``, 'number') }}",
        "queryString": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Search_Query', ``, 'string') }}",
        "returnAll": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Return_All', ``, 'boolean') }}",
        "filter": {
          "folderId": {
            "__rl": true,
            "value": "18oEPa0gYnji2Yt-AeDIwqPiORRZUyn4q",
            "mode": "list",
            "cachedResultName": "cv_data",
            "cachedResultUrl": "https://drive.google.com/drive/folders/18oEPa0gYnji2Yt-AeDIwqPiORRZUyn4q"
          },
          "whatToSearch": "files"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.googleDriveTool",
      "typeVersion": 3,
      "position": [
        416,
        368
      ],
      "id": "2d64f0b6-0584-4247-afaa-6c1e26b12e75",
      "name": "buscar info de docs",
      "credentials": {
        "googleDriveOAuth2Api": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "documentId": {
          "__rl": true,
          "value": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Document', `no es el nombre del documento, sino su ID. Puede encontrarse con la herramienta de google drive`, 'string') }}",
          "mode": "id"
        },
        "sheetName": {
          "__rl": true,
          "value": "=Hoja 1",
          "mode": "name"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.googleSheetsTool",
      "typeVersion": 4.7,
      "position": [
        544,
        368
      ],
      "id": "cead3e9c-07b2-4b70-970c-da5689916dd9",
      "name": "leer sheets",
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "modelId": {
          "__rl": true,
          "value": "gpt-4",
          "mode": "list",
          "cachedResultName": "GPT-4"
        },
        "responses": {
          "values": [
            {
              "role": "system",
              "content": "Eres un redactor profesional de curr\u00edculums (CV) para el sector tecnol\u00f3gico, especializado en perfiles de Ingenier\u00eda de IA, Ciencia de Datos y Desarrollo Python. Eres un experto en presentar la informaci\u00f3n de forma clara, concisa e impactante.\n\n**Contexto:**\nRecibir\u00e1s un objeto JSON con la informaci\u00f3n m\u00e1s relevante de un candidato, ya filtrada y adaptada para una oferta de trabajo espec\u00edfica.\n\n**Tu Tarea:**\n1.  Utiliza el JSON de entrada para estructurar y redactar un CV completo.\n2.  El formato de salida DEBE ser **Markdown**. Utiliza la sintaxis de Markdown (## para t\u00edtulos, * para listas, ** para negritas) para darle un formato profesional. No inventes formatos, solo usa Markdown est\u00e1ndar.\n3.  Aseg\u00farate de que el lenguaje sea profesional, orientado a resultados y utilice verbos de acci\u00f3n.\n4.  Una vez que hayas generado el contenido en Markdown, ejecuta las siguientes acciones en orden:\n    a. Utiliza la herramienta `hoja_de_vida_creada` para crear un nuevo Google Doc. El t\u00edtulo del documento debe ser \"CV - [T\u00edtulo del Puesto] - [Nombre de la Empresa]\". Pasa el contenido Markdown completo al cuerpo del documento.\n    b. Utiliza la herramienta `postulaciones` para a\u00f1adir una nueva fila a la hoja de c\u00e1lculo de seguimiento. Rellena las columnas con la informaci\u00f3n de la oferta y el enlace al Google Doc que acabas de crear. El estado inicial siempre debe ser 'CV Creado'.\n\n**Ejemplo de Estructura de Salida (Markdown):**\n# Nombre del Candidato\n**Contacto:** email@example.com | **LinkedIn:** linkedin.com/in/... | **GitHub:** github.com/...\n\n## Resumen Profesional\n[Usa el 'suggested_summary' del JSON y mej\u00f3ralo si es necesario]\n\n## Habilidades T\u00e9cnicas\n*   **Lenguajes:** [Habilidad 1, Habilidad 2]\n*   **Tecnolog\u00edas:** [Tecnolog\u00eda 1, Tecnolog\u00eda 2]\n\n## Experiencia Laboral Relevante\n**[Cargo]** | **[Empresa]**\n*   [Punto 1 de la descripci\u00f3n, enfocado en logros]\n*   [Punto 2 de la descripci\u00f3n, enfocado en logros]\n\n## Proyectos Destacados\n**[Nombre del Proyecto]**\n*   [Punto 1 de la descripci\u00f3n del proyecto]\n*   [Punto 2 de la descripci\u00f3n del proyecto]\n*   **Tecnolog\u00edas:** [Tecnolog\u00eda 1, Tecnolog\u00eda 2]\n\n## Educaci\u00f3n\n[Tu formaci\u00f3n aqu\u00ed]"
            },
            {
              "content": "={{ $json.output[0].content[0].text }}"
            }
          ]
        },
        "builtInTools": {},
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.openAi",
      "typeVersion": 2,
      "position": [
        752,
        144
      ],
      "id": "33189d3d-81a3-4054-8b26-e4e27c5f9f07",
      "name": "sketch creator",
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "modelId": {
          "__rl": true,
          "value": "gpt-4.1",
          "mode": "list",
          "cachedResultName": "GPT-4.1"
        },
        "responses": {
          "values": [
            {
              "role": "system",
              "content": "Eres una API de Evaluaci\u00f3n de Curr\u00edculums. Tu \u00fanica funci\u00f3n es recibir un borrador de CV y los detalles de una oferta de trabajo, y devolver un an\u00e1lisis estructurado en formato JSON. Eres una m\u00e1quina, no un asistente conversacional. Tu respuesta debe ser \u00daNICAMENTE el objeto JSON.\n\n**PROTOCOLO DE AN\u00c1LISIS:**\n\n1.  **Analizar Oferta:** Recibir\u00e1s los detalles de la oferta. Extrae y resume los 3-5 requisitos m\u00e1s importantes en una lista.\n2.  **Analizar Borrador:** Recibir\u00e1s el borrador del CV en Markdown.\n3.  **Comparar y Evaluar:** Compara el borrador con los requisitos de la oferta. Asigna una puntuaci\u00f3n del 1 al 100 basada en la relevancia, el impacto y la claridad.\n4.  **Generar Recomendaciones:** Crea una lista de recomendaciones espec\u00edficas y accionables para mejorar el borrador.\n\n**REGLA DE SALIDA INQUEBRANTABLE:**\nTu \u00fanica y exclusiva salida debe ser un objeto JSON v\u00e1lido que contenga 4 claves de nivel superior: `job_offer_summary`, `original_draft`, `score` y `recommendations`. NO incluyas NING\u00daN texto, explicaci\u00f3n, saludo o markdown antes o despu\u00e9s de las llaves `{}` del JSON. Tu respuesta debe empezar con `{` y terminar con `}`.\n\n**Formato de Salida Obligatorio y \u00danico (JSON):**\n\n{\n  \"job_offer_summary\": {\n    \"title\": \"T\u00edtulo del Puesto\",\n    \"company\": \"Nombre de la Empresa\",\n    \"key_requirements\": [\n      \"Requisito clave #1 extra\u00eddo de la oferta.\",\n      \"Requisito clave #2 extra\u00eddo de la oferta.\",\n      \"Requisito clave #3 extra\u00eddo de la oferta.\"\n    ]\n  },\n  \"original_draft\": \"[Aqu\u00ed va el texto completo y sin modificar del borrador de CV que recibiste]\",\n  \"score\": [Tu puntuaci\u00f3n num\u00e9rica, ej. 74],\n  \"recommendations\": [\n    \"Recomendaci\u00f3n #1: ...\",\n    \"Recomendaci\u00f3n #2: ...\",\n    \"Recomendaci\u00f3n #3: ...\"\n  ]\n}"
            },
            {
              "content": "={{ $json.cv_text }}"
            }
          ]
        },
        "builtInTools": {},
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.openAi",
      "typeVersion": 2,
      "position": [
        1552,
        64
      ],
      "id": "924b3083-77c2-41f0-8c1e-6e772b4e084a",
      "name": "evaluator",
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "// --- Inicio del C\u00f3digo Corregido y Definitivo ---\n\n// Accede a los datos del nodo anterior ('evaluator').\nconst items = $items();\n\nlet rawText;\n\ntry {\n  // *** RUTA DE ACCESO CORREGIDA ***\n  // Esta es la ruta exacta para llegar al texto dentro de la estructura de entrada.\n  rawText = items[0].json.output[0].content[0].text;\n} catch (error) {\n  // Si la estructura de entrada cambia, este error nos lo dir\u00e1.\n  return [{ json: { error: \"La estructura del INPUT del evaluador ha cambiado. No se pudo encontrar la ruta 'output[0].content[0].text'.\", details: error.message } }];\n}\n\n// Ahora, el resto del c\u00f3digo buscar\u00e1 el JSON dentro de ese texto.\nconst startIndex = rawText.indexOf('{');\nconst endIndex = rawText.lastIndexOf('}');\n\n// Si no se encuentra un JSON DENTRO del campo 'text', devolvemos un error.\nif (startIndex === -1 || endIndex === -1) {\n  // Este error ahora significa que el 'evaluator' no puso el JSON en el campo 'text'.\n  return [{ json: { error: \"No se encontr\u00f3 un objeto JSON dentro del campo 'text' de la respuesta.\" } }];\n}\n\n// Extrae la cadena de texto que contiene \u00fanicamente el JSON.\nconst jsonString = rawText.substring(startIndex, endIndex + 1);\n\nlet parsedData;\n\ntry {\n  // Convierte la cadena de texto JSON en un objeto JavaScript real.\n  parsedData = JSON.parse(jsonString);\n} catch (error) {\n  // Si el JSON est\u00e1 mal formado, este error nos lo indicar\u00e1.\n  return [{ json: { error: \"El JSON extra\u00eddo est\u00e1 mal formado y no se pudo parsear.\", details: error.message } }];\n}\n\n// Devuelve el objeto JSON limpio y estructurado.\nreturn [{\n  json: {\n    job_offer_summary: parsedData.job_offer_summary || {},\n    original_draft: parsedData.original_draft || \"\",\n    score: parsedData.score || 0,\n    recommendations: parsedData.recommendations || []\n  }\n}];\n\n// --- Fin del C\u00f3digo ---"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1904,
        64
      ],
      "id": "602772c5-1a8c-40c2-92ae-663c48074f7c",
      "name": "Code in JavaScript"
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 2
          },
          "conditions": [
            {
              "id": "7e5b2276-2ba5-47d5-a8c7-0672221d11bc",
              "leftValue": "={{ $json.score }}",
              "rightValue": 85,
              "operator": {
                "type": "number",
                "operation": "gte"
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        2128,
        64
      ],
      "id": "432c907f-a7f3-4ef9-a871-a44fc8ec6faf",
      "name": "scoring"
    },
    {
      "parameters": {
        "modelId": {
          "__rl": true,
          "value": "gpt-4",
          "mode": "list",
          "cachedResultName": "GPT-4"
        },
        "responses": {
          "values": [
            {
              "content": "=CV original :{{ $json.original_draft }}"
            },
            {
              "content": "=puntaje obtendo:  {{ $json.score }}"
            },
            {
              "content": "=recomendaciones:\n\n {{ $json.recommendations }}"
            },
            {
              "role": "system",
              "content": "Eres un Editor Maestro de Curr\u00edculums. Tu \u00fanica funci\u00f3n es tomar un borrador de CV, un informe de evaluaci\u00f3n con una puntuaci\u00f3n y una lista de recomendaciones, y aplicar esas recomendaciones para crear la versi\u00f3n final y optimizada del documento.\n\n**Contexto y Misi\u00f3n:**\nTu objetivo es mejorar el borrador inicial (`original_draft`) aplicando sistem\u00e1ticamente cada una de las `recommendations` para incrementar el `score` potencial del CV. El resultado final debe ser un \u00fanico bloque de texto en formato Markdown.\n\n**PROTOCOLO DE EDICI\u00d3N OBLIGATORIO:**\n\n**1. An\u00e1lisis del Input:**\n   - Recibir\u00e1s un objeto JSON con tres claves: `original_draft`, `score` y `recommendations`.\n   - Lee y comprende CADA recomendaci\u00f3n. Son tu \u00fanica gu\u00eda para la edici\u00f3n.\n\n**2. Proceso de Edici\u00f3n Iterativa:**\n   - Toma el `original_draft` como tu base.\n   - Aplica cada recomendaci\u00f3n de la lista una por una. Esto no es opcional. Debes integrar la esencia de cada sugerencia en el texto.\n   - Tu trabajo va m\u00e1s all\u00e1 de copiar y pegar. Debes reescribir, parafrasear y reestructurar secciones del borrador para que las mejoras fluyan de manera natural y profesional.\n     *   **Si una recomendaci\u00f3n pide cuantificar:** Busca la secci\u00f3n relevante y a\u00f1ade m\u00e9tricas l\u00f3gicas (ej. \"Mejor\u00f3 la eficiencia en un 30%\").\n     *   **Si una recomendaci\u00f3n pide reformular:** Reescribe la frase o p\u00e1rrafo para que sea m\u00e1s impactante o se alinee mejor con el tono de la oferta.\n     *   **Si una recomendaci\u00f3n pide a\u00f1adir informaci\u00f3n:** Int\u00e9grala en la secci\u00f3n m\u00e1s apropiada del CV.\n\n**3. Generaci\u00f3n del Output Final:**\n   - Una vez que todas las recomendaciones hayan sido aplicadas, revisa el documento completo una \u00faltima vez para asegurar coherencia y fluidez.\n   - Tu \u00fanica salida debe ser el texto completo del curr\u00edculum finalizado, en formato **Markdown**.\n\n**REGLAS DE SALIDA INQUEBRANTABLES:**\n\n1.  **\u00daNICO OUTPUT DE TEXTO:** Tu respuesta debe ser exclusivamente el texto del CV final en Markdown.\n2.  **SIN EXPLICACIONES:** No incluyas frases como \"Aqu\u00ed est\u00e1 la versi\u00f3n corregida:\", \"He aplicado las siguientes mejoras:\", ni ning\u00fan otro texto conversacional. Tu respuesta debe empezar directamente con el nombre del candidato (ej. `# Jorge Andrey Gonzalez Mosquera...`).\n3.  **CONSERVACI\u00d3N DEL FORMATO:** Mant\u00e9n la estructura de Markdown del borrador original (t\u00edtulos, listas, negritas).\n\n**Ejemplo de L\u00f3gica de Trabajo:**\n\n*   **Input (Recomendaci\u00f3n):** \"En la descripci\u00f3n del trabajo en Concentrix, cambiar 'atender clientes' por 'resolver X tickets t\u00e9cnicos por d\u00eda...'\"\n*   **Tu Proceso Mental:** *Okay, busco la secci\u00f3n 'Experiencia Laboral', encuentro 'Concentrix'. Borro la l\u00ednea original y la reemplazo con la versi\u00f3n mejorada y cuantificada.*\n*   **Output (Fragmento del CV final):**\n    ```markdown\n    ## Experiencia Laboral\n    **English Customer Service Agent** | **Concentrix**\n    *   Resolv\u00eda un promedio de 50 tickets t\u00e9cnicos por d\u00eda, demostrando alta eficiencia en la resoluci\u00f3n de problemas y manteniendo un \u00edndice de satisfacci\u00f3n del cliente del 95%.\n    ...\n    ```"
            },
            {
              "content": "=Recuerda el conjunto de habilidades e informacion del candidato\n\n{{ $('info retriever').item.json.output[0].content[0].text }}"
            }
          ]
        },
        "builtInTools": {},
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.openAi",
      "typeVersion": 2,
      "position": [
        2352,
        160
      ],
      "id": "e690fd47-2699-4aa8-a082-014f6986274f",
      "name": "editor_text",
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "210266bc-7abc-4fd8-abfa-47bc65f32430",
              "name": "output[0].content[0].text",
              "value": "={{ $json.output[0].content[0].text }}",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        1104,
        144
      ],
      "id": "40f05f8d-e05a-4c7d-83e8-e3065682ce25",
      "name": "original"
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "5d647410-968c-42c5-87b5-581e0ce301b2",
              "name": "output[0].content[0].text",
              "value": "={{ $json.output[0].content[0].text }}",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        2704,
        240
      ],
      "id": "5e5beb96-b15b-4031-a4bf-6696fddf8837",
      "name": "edited"
    },
    {
      "parameters": {
        "jsCode": "// Obtenemos todas las entradas posibles\nconst items = $input.all();\nlet finalText = \"\";\n\n// --- PASO 1: B\u00daSQUEDA PRIORITARIA (El Editor) ---\n// Buscamos en todas las entradas si alguna tiene la firma del EDITOR.\n// Nota: Ajusta 'response.content' o 'text' seg\u00fan lo que arroje tu nodo editor_text exactamente.\nconst itemDelEditor = items.find(item => \n    item.json.text || \n    (item.json.response && item.json.response.content) ||\n    (item.json.message && item.json.message.content)\n);\n\n// --- PASO 2: B\u00daSQUEDA SECUNDARIA (El Sketch Original) ---\n// Buscamos si alguna tiene la firma del SKETCH CREATOR.\nconst itemDelCreator = items.find(item => \n    item.json.output && \n    item.json.output[0] && \n    item.json.output[0].content\n);\n\n// --- PASO 3: L\u00d3GICA DE DECISI\u00d3N ---\nif (itemDelEditor) {\n    // \u00a1ENCONTRAMOS UNA CORRECCI\u00d3N! USAMOS ESTA.\n    // (Prioridad m\u00e1xima: Si existe una edici\u00f3n, ignoramos el original)\n    if (itemDelEditor.json.text) {\n        finalText = itemDelEditor.json.text;\n    } else if (itemDelEditor.json.response) {\n        finalText = itemDelEditor.json.response.content;\n    } else {\n        finalText = itemDelEditor.json.message.content;\n    }\n} \nelse if (itemDelCreator) {\n    // No hay edici\u00f3n, as\u00ed que es la primera vuelta. Usamos el original.\n    finalText = itemDelCreator.json.output[0].content[0].text;\n} \nelse {\n    finalText = \"ERROR: No se encontr\u00f3 ni el original ni la edici\u00f3n.\";\n}\n\n// Retornamos el texto limpio para el Evaluador\nreturn [{\n    json: {\n        cv_text: finalText\n    }\n}];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1328,
        144
      ],
      "id": "7d1ee418-0f41-4d39-bd46-b42acd5fe4a3",
      "name": "Code in JavaScript1"
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "5fec50be-d084-4436-be9e-541541c509d0",
              "name": "job_offer_summary.title",
              "value": "={{ $json.job_offer_summary.title }}\n",
              "type": "string"
            },
            {
              "id": "65660499-ae9f-4aa3-a38d-36e8844b11aa",
              "name": "job_offer_summary.company",
              "value": "={{ $json.job_offer_summary.company }}",
              "type": "string"
            },
            {
              "id": "10b3bd0e-5fdb-4de1-a375-c2b00ddf2b1e",
              "name": "job_offer_summary.key_requirements",
              "value": "={{ $json.job_offer_summary.key_requirements }}",
              "type": "string"
            },
            {
              "id": "f1be5b54-0e01-43b6-8cc5-f1141b2a7ea5",
              "name": "original_draft",
              "value": "={{ $json.original_draft }}",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        2416,
        -32
      ],
      "id": "b98b60d5-7e0d-4d76-820a-968462e0b3b7",
      "name": "final"
    },
    {
      "parameters": {
        "modelId": {
          "__rl": true,
          "value": "gpt-4",
          "mode": "list",
          "cachedResultName": "GPT-4"
        },
        "responses": {
          "values": [
            {
              "content": "={{ $json.original_draft }}"
            },
            {
              "role": "system",
              "content": "Eres un Desarrollador Experto en LaTeX y Consultor de Tecnolog\u00eda de RRHH especializado en ATS (Applicant Tracking Systems).\n\nTU MISI\u00d3N:\nRecibir\u00e1s el contenido final de un Curr\u00edculum Vitae (CV) en formato Markdown. Tu tarea es convertirlo en c\u00f3digo LaTeX completo, listo para compilar y optimizado para ser le\u00eddo tanto por humanos como por algoritmos de reclutamiento (ATS).\n\nREGLAS DE DISE\u00d1O Y EST\u00c1NDARES 2025:\n1. Estilo Visual: Moderno, minimalista, limpio y profesional. Usa una fuente Sans-Serif por defecto (como Helvet o Arial) ya que se leen mejor en pantalla.\n2. Compatibilidad ATS:\n   - NO uses columnas flotantes complejas (minipage es aceptable si se usa con cuidado, pero prefiere un dise\u00f1o lineal o tabular simple).\n   - NO uses gr\u00e1ficos, \u00edconos que requieran librer\u00edas externas no est\u00e1ndar, ni cajas de texto flotantes (tikz absoluto).\n   - El flujo de texto debe ser seleccionable y lineal.\n3. Dependencias:\n   - El c\u00f3digo debe ser AUTOCONTENIDO. No asumas que el usuario tiene archivos .cls personalizados.\n   - Usa la clase est\u00e1ndar `article`.\n   - Usa paquetes est\u00e1ndar: `geometry` (m\u00e1rgenes estrechos), `titlesec` (para formato de t\u00edtulos), `enumitem` (para listas compactas), `hyperref` (para enlaces clicables y metadatos PDF), `xcolor` (para acentos de color sutiles).\n\nREGLAS T\u00c9CNICAS DE LATEX:\n1. ESCAPE DE CARACTERES: Es CR\u00cdTICO que escapes correctamente los caracteres especiales de LaTeX que puedan venir en el texto (ej: convertir '%' en '\\%', '&' en '\\&', '$' en '\\$', '#' en '\\#', '_' en '\\_'). Esto es com\u00fan en lenguajes de programaci\u00f3n (C++, C#) y m\u00e9tricas.\n2. Enlaces: Convierte las URLs de LinkedIn/GitHub en enlaces activos usando \\href{url}{texto}.\n3. Estructura:\n   - Encabezado: Nombre grande, datos de contacto debajo centrados o en l\u00ednea.\n   - Secciones: T\u00edtulos claros, en may\u00fasculas o negrita, con una l\u00ednea horizontal separadora si es est\u00e9tico.\n   - Listas: Usa listas con vi\u00f1etas (itemize) compactas (noitemsep) para ahorrar espacio.\n\nFORMATO DE SALIDA:\nTu respuesta debe contener \u00daNICA Y EXCLUSIVAMENTE el bloque de c\u00f3digo LaTeX.\n- Empieza con \\documentclass{article}.\n- Termina con \\end{document}.\n- NO incluyas explicaciones, ni saludos, ni markdown (```latex) envolvente si es posible, o solo el bloque de c\u00f3digo."
            }
          ]
        },
        "builtInTools": {},
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.openAi",
      "typeVersion": 2,
      "position": [
        2688,
        -32
      ],
      "id": "3d25bbeb-22cd-4d73-bedc-c5f76998cba0",
      "name": "latexter",
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "toText",
        "sourceProperty": "output[0].content[0].text",
        "binaryPropertyName": "=data",
        "options": {}
      },
      "type": "n8n-nodes-base.convertToFile",
      "typeVersion": 1.1,
      "position": [
        3040,
        -32
      ],
      "id": "f3b26a9c-1cbe-48de-9ef5-05a6cf93b678",
      "name": "Convert to File"
    },
    {
      "parameters": {
        "name": "={{ $('Code in JavaScript').item.json.job_offer_summary.title }} - {{ $('Code in JavaScript').item.json.job_offer_summary.company }}",
        "driveId": {
          "__rl": true,
          "mode": "list",
          "value": "My Drive"
        },
        "folderId": {
          "__rl": true,
          "value": "1ycf2LoUmeqgDOFyXYJLqh4PkH1i6x140",
          "mode": "list",
          "cachedResultName": "cv_created",
          "cachedResultUrl": "https://drive.google.com/drive/folders/1ycf2LoUmeqgDOFyXYJLqh4PkH1i6x140"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.googleDrive",
      "typeVersion": 3,
      "position": [
        3472,
        -160
      ],
      "id": "89ae1496-da88-453b-95a0-73a018d3b67e",
      "name": "Upload file",
      "credentials": {
        "googleDriveOAuth2Api": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "send",
        "phoneNumberId": "773652655831097",
        "recipientPhoneNumber": "573245649442",
        "messageType": "document",
        "mediaPath": "useMedian8n",
        "additionalFields": {
          "mediaFilename": "={{ $('Code in JavaScript').item.json.job_offer_summary.title }} - {{ $('Code in JavaScript').item.json.job_offer_summary.company }}",
          "mediaCaption": "=Requisitos clave de la oferta:\n\n{{ $('Code in JavaScript').item.json.job_offer_summary.key_requirements }}\n"
        }
      },
      "type": "n8n-nodes-base.whatsApp",
      "typeVersion": 1.1,
      "position": [
        3504,
        112
      ],
      "id": "7b260630-0a05-4427-9e5f-74f8e87973d7",
      "name": "Send message",
      "credentials": {
        "whatsAppApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "b023e4e8-4111-4f00-81f9-e62f34eb438d",
              "name": "status",
              "value": "terminado con exito",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        3744,
        112
      ],
      "id": "194d2080-17ad-49e4-9a32-928559342ada",
      "name": "Edit Fields"
    }
  ],
  "connections": {
    "When Executed by Another Workflow": {
      "main": [
        [
          {
            "node": "info retriever",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "info retriever": {
      "main": [
        [
          {
            "node": "sketch creator",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "leer docs": {
      "ai_tool": [
        [
          {
            "node": "info retriever",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "buscar info de docs": {
      "ai_tool": [
        [
          {
            "node": "info retriever",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "leer sheets": {
      "ai_tool": [
        [
          {
            "node": "info retriever",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "sketch creator": {
      "main": [
        [
          {
            "node": "original",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "evaluator": {
      "main": [
        [
          {
            "node": "Code in JavaScript",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code in JavaScript": {
      "main": [
        [
          {
            "node": "scoring",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "scoring": {
      "main": [
        [
          {
            "node": "final",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "editor_text",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "editor_text": {
      "main": [
        [
          {
            "node": "edited",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "original": {
      "main": [
        [
          {
            "node": "Code in JavaScript1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "edited": {
      "main": [
        [
          {
            "node": "Code in JavaScript1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code in JavaScript1": {
      "main": [
        [
          {
            "node": "evaluator",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "final": {
      "main": [
        [
          {
            "node": "latexter",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "latexter": {
      "main": [
        [
          {
            "node": "Convert to File",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Convert to File": {
      "main": [
        [
          {
            "node": "Upload file",
            "type": "main",
            "index": 0
          },
          {
            "node": "Send message",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send message": {
      "main": [
        [
          {
            "node": "Edit Fields",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "562e7664-f1f4-41a5-9fa7-d6758666afd7",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "id": "FxXgtTpzc3xMHrga",
  "tags": []
}