OClick/1.1 Detailed Letter/Telegram

    Shared 2/13/2026

    1 views

    Visual Workflow

    JSON Code

    {
      "id": "cr9sSd8cfwjqWFKD",
      "meta": {
        "instanceId": "a7951da00dc167f722a4bd0bc0e175503754ae4ae331d85018109ce22f7c48f6",
        "templateCredsSetupCompleted": true
      },
      "name": "OClick/1.1 Detailed Letter/Telegram copy",
      "tags": [],
      "nodes": [
        {
          "id": "8638bbc7-67f4-4728-833d-3001f2796aae",
          "name": "Delete Collection1",
          "type": "n8n-nodes-qdrant.qdrant",
          "position": [
            -16,
            1344
          ],
          "parameters": {
            "operation": "deleteCollection",
            "collectionName": {
              "__rl": true,
              "mode": "name",
              "value": "vacancies"
            },
            "requestOptions": {}
          },
          "credentials": {
            "qdrantRestApi": {
              "id": "5UV8rQE53hqsh82x",
              "name": "Qdrant account"
            }
          },
          "typeVersion": 1
        },
        {
          "id": "dc80d89f-d90c-4c02-818c-f21dee05238f",
          "name": "When clicking ‘Execute workflow’",
          "type": "n8n-nodes-base.manualTrigger",
          "position": [
            -240,
            1344
          ],
          "parameters": {},
          "typeVersion": 1
        },
        {
          "id": "c9cf5d34-1f61-47d8-a541-3258675e98ee",
          "name": "Sticky Note",
          "type": "n8n-nodes-base.stickyNote",
          "position": [
            -320,
            1104
          ],
          "parameters": {
            "width": 693,
            "height": 410,
            "content": "## Clear Databases"
          },
          "typeVersion": 1
        },
        {
          "id": "1b120327-3310-443f-9838-2afae2ecf13f",
          "name": "Create Collection",
          "type": "n8n-nodes-qdrant.qdrant",
          "position": [
            208,
            1344
          ],
          "parameters": {
            "vectors": "{\n  \"size\": 4096,\n  \"distance\": \"Cosine\",\n  \"on_disk\": true,\n  \"datatype\": \"float32\"\n}",
            "operation": "createCollection",
            "walConfig": "{\n  \"wal_capacity_mb\": 32,\n  \"wal_segments_ahead\": 0,\n  \"wal_retain_closed\": 1\n}",
            "hnswConfig": "{\n  \"m\": 16,\n  \"ef_construct\": 100,\n  \"full_scan_threshold\": 10000,\n  \"max_indexing_threads\": 0,\n  \"on_disk\": false\n}",
            "shardNumber": 1,
            "onDiskPayload": true,
            "collectionName": "vacancies",
            "requestOptions": {},
            "optimizersConfig": "{\n  \"deleted_threshold\": 0.2,\n  \"vacuum_min_vector_number\": 1000,\n  \"default_segment_number\": 0,\n  \"max_segment_size\": null,\n  \"memmap_threshold\": null,\n  \"indexing_threshold\": 10000,\n  \"flush_interval_sec\": 5,\n  \"max_optimization_threads\": null\n}",
            "strictModeConfig": "{\n  \"enabled\": false\n}",
            "replicationFactor": 1,
            "writeConsistencyFactor": 1
          },
          "credentials": {
            "qdrantRestApi": {
              "id": "5UV8rQE53hqsh82x",
              "name": "Qdrant account"
            }
          },
          "executeOnce": false,
          "typeVersion": 1
        },
        {
          "id": "9f40f280-4f71-4aed-8435-d552e0d6feaf",
          "name": "Schedule Trigger",
          "type": "n8n-nodes-base.scheduleTrigger",
          "position": [
            -512,
            1600
          ],
          "parameters": {
            "rule": {
              "interval": [
                {
                  "field": "hours"
                }
              ]
            }
          },
          "typeVersion": 1.2
        },
        {
          "id": "2edbfde7-7686-4916-8539-e6a723b41cf1",
          "name": "Auto-search",
          "type": "n8n-nodes-base.httpRequest",
          "position": [
            -80,
            1600
          ],
          "parameters": {
            "url": "https://api.hh.ru/saved_searches/vacancies",
            "options": {
              "batching": {
                "batch": {
                  "batchSize": 30
                }
              }
            },
            "sendQuery": true,
            "sendHeaders": true,
            "authentication": "genericCredentialType",
            "genericAuthType": "oAuth2Api",
            "queryParameters": {
              "parameters": [
                {
                  "name": "per_page",
                  "value": "10"
                }
              ]
            },
            "headerParameters": {
              "parameters": [
                {
                  "name": "User-Agent",
                  "value": "OClick/1.1 (shimorowm@gmail.com)"
                }
              ]
            }
          },
          "credentials": {
            "oAuth2Api": {
              "id": "l9tyPEWtPvzUKFXJ",
              "name": "HH OAuth2"
            }
          },
          "typeVersion": 4.2
        },
        {
          "id": "698d41f7-9e70-4e72-955d-bba1052fcd3c",
          "name": "Split Out",
          "type": "n8n-nodes-base.splitOut",
          "position": [
            144,
            1600
          ],
          "parameters": {
            "options": {},
            "fieldToSplitOut": "items"
          },
          "typeVersion": 1
        },
        {
          "id": "4e68e8ad-19ac-4d28-8013-ef282fd9d668",
          "name": "If",
          "type": "n8n-nodes-base.if",
          "position": [
            -288,
            1872
          ],
          "parameters": {
            "options": {},
            "conditions": {
              "options": {
                "version": 2,
                "leftValue": "",
                "caseSensitive": true,
                "typeValidation": "strict"
              },
              "combinator": "and",
              "conditions": [
                {
                  "id": "96d0a2cc-b2ed-4a93-941b-2278aa255c79",
                  "operator": {
                    "type": "number",
                    "operation": "gt"
                  },
                  "leftValue": "={{ $json.new_items.count }}",
                  "rightValue": 0
                }
              ]
            }
          },
          "typeVersion": 2.2
        },
        {
          "id": "9f1b909e-79c0-4218-81f5-12882161556f",
          "name": "Split Out1",
          "type": "n8n-nodes-base.splitOut",
          "position": [
            144,
            1856
          ],
          "parameters": {
            "options": {},
            "fieldToSplitOut": "items"
          },
          "typeVersion": 1
        },
        {
          "id": "01f941c2-83f7-407b-87d7-03432e3af998",
          "name": "Remove Duplicates",
          "type": "n8n-nodes-base.removeDuplicates",
          "position": [
            144,
            2128
          ],
          "parameters": {
            "compare": "selectedFields",
            "options": {},
            "fieldsToCompare": "id"
          },
          "typeVersion": 2
        },
        {
          "id": "25dc1ea7-4add-40f2-8d26-17b8a7b96405",
          "name": "Chunking",
          "type": "n8n-nodes-base.code",
          "position": [
            1392,
            2048
          ],
          "parameters": {
            "jsCode": "const items = $input.all();\nconst out = [];\n\nfor (const item of items) {\n  const doc = item.json.data ?? item.json;\n  if (!doc) continue;\n\n  // гарантируем, что sections — массив (в твоём случае они всегда есть)\n  const sections = Array.isArray(doc.sections) ? doc.sections : [];\n\n  let secIndex = 0;\n  for (const sec of sections) {\n    // безопасные дефолты\n    const sectionName = sec && sec.section ? String(sec.section) : `section_${secIndex}`;\n    const sectionText = sec && sec.text ? String(sec.text).trim() : '';\n\n    // Unicode-safe slug (короткий, для id)\n    const rawSlug = sectionName.toLowerCase().replace(/\\s+/g, '_');\n    const sectionSlug = rawSlug.replace(/[^\\p{L}\\p{N}_-]/gu, '').slice(0, 50) || `sec${secIndex}`;\n\n    // уникальный id чанка\n    const chunkId = `${doc.id ?? 'doc'}_${secIndex}_${sectionSlug}`;\n\n    // content: заголовок секции + текст\n    //const content = `### ${sectionName}\\n\\n${sectionText}`;\n    const content = `${sectionText}`;\n\n    // сохраняем в metadata только поля, которые соответствуют исходной схеме документа\n    const metadata = {\n      // id чанка (уникален)\n      id: chunkId,\n      // оригинальный документный id\n      document_id: doc.id ?? null,\n      // основной набор полей из оригинального документа (копируем как есть)\n      title: doc.title ?? null,\n      salary_range: doc.salary_range ?? null,\n      location: doc.location ?? null,\n      // experience — копируем целиком (объект {id, name} или null)\n      experience: doc.experience ?? null,\n      // ключевые навыки — сохраняем оригинал (массив объектов или пустой массив)\n      key_skills: doc.key_skills ?? [],\n      source_url: doc.source_url ?? null,\n      employment_type: doc.employment_type ?? null,\n      work_format: doc.work_format ?? [],\n      company: doc.company ?? null,\n      // информация о секции для удобства поиска/фильтрации\n      section: sectionName\n    };\n\n    out.push({ json: { content, metadata } });\n    secIndex++;\n  }\n\n  // если sections пустой — сейчас мы не создаём чанков (поведение по умолчанию)\n}\n\nreturn out;\n"
          },
          "executeOnce": false,
          "typeVersion": 2
        },
        {
          "id": "e0fa7c21-96a1-455a-b650-1f67bc92423f",
          "name": "Token Splitter",
          "type": "@n8n/n8n-nodes-langchain.textSplitterTokenSplitter",
          "position": [
            2544,
            2480
          ],
          "parameters": {
            "chunkSize": 500,
            "chunkOverlap": 100
          },
          "typeVersion": 1
        },
        {
          "id": "c82ccef8-45dd-4756-abb6-d133257bf157",
          "name": "Save To Qdrant",
          "type": "@n8n/n8n-nodes-langchain.vectorStoreQdrant",
          "position": [
            2368,
            2048
          ],
          "parameters": {
            "mode": "insert",
            "options": {},
            "qdrantCollection": {
              "__rl": true,
              "mode": "id",
              "value": "vacancies"
            }
          },
          "credentials": {
            "qdrantApi": {
              "id": "sFfERYppMeBnFNeA",
              "name": "Local QdrantApi database"
            }
          },
          "typeVersion": 1.3
        },
        {
          "id": "3ef51f3e-b7bb-4d52-b609-ea19923431b5",
          "name": "Set Payload",
          "type": "n8n-nodes-qdrant.qdrant",
          "onError": "continueErrorOutput",
          "position": [
            2672,
            2048
          ],
          "parameters": {
            "filter": "={\n    \"must\": [\n      {\n        \"key\": \"metadata.chunk_id\",\n        \"match\": {\n          \"value\": \"{{ $json.metadata.chunk_id }}\"\n        }\n      }\n    ]\n}",
            "points": "=",
            "payload": "={\n  \"vacancy_id\": {{ $('Chunking').item.json.metadata.document_id }},\n  \"location\": {{ $('Chunking').item.json.metadata.location ? $('Chunking').item.json.metadata.location.toJsonString() : \"null\" }},\n  \"source_url\": \"{{ $('Chunking').item.json.metadata.source_url }}\",\n  \"employment_type_id\": {{ $('Chunking').item.json.metadata.employment_type.id.toJsonString() }},\n  \"work_format\": {{ JSON.stringify($('Chunking').item.json.metadata.work_format) }}\n}",
            "resource": "payload",
            "operation": "setPayload",
            "collectionName": {
              "__rl": true,
              "mode": "name",
              "value": "vacancies"
            },
            "requestOptions": {
              "timeout": 10000,
              "allowUnauthorizedCerts": true
            }
          },
          "credentials": {
            "qdrantRestApi": {
              "id": "5UV8rQE53hqsh82x",
              "name": "Qdrant account"
            }
          },
          "retryOnFail": false,
          "typeVersion": 1
        },
        {
          "id": "2245926e-336e-4886-bd61-a4cacce1476b",
          "name": "Information Extractor",
          "type": "@n8n/n8n-nodes-langchain.informationExtractor",
          "position": [
            944,
            2144
          ],
          "parameters": {
            "text": "={{ $json.sections }}",
            "options": {
              "systemPromptTemplate": "Ты — эксперт по извлечению информации на нескольких языках. Ты работаешь с описаниями вакансий на русском и английском.\n\n# Инструкция по языку (высший приоритет): \n- Определи основной язык входного текста (русский или английский). \n- Вывод строго на том же языке. \n- Никогда не переводи и не транслитерируй. \n- Сохраняй любые смешанные сегменты (например, русские + английские термины). \n- Следуйте всем последующим правилам извлечения и форматирования.\n\nТвоя задача — создать чистый, хорошо форматированный JSON-объект с ключами: responsibilities, requirements, additional.\n\n# Правила (строгое применение по порядку):\n\n1) Приоритет извлечения:\n- Всегда отдавай предпочтение извлечению по заголовкам. Если найден релевантный заголовок, извлекай только содержимое под ним. \n- Если явного заголовка нет, логически определи секцию по контексту.\n\n2) Правила для полей:\n- Применяй точные правила извлечения для каждого поля (RESPONSIBILITIES, REQUIREMENTS, ADDITIONAL).\n\n3) Очистка HTML и форматирование:\n- Удаляй все HTML-теги. \n- Преобразовывай <br>, <br/> и <br /> в \"; \". \n- Сохраняй только простой текст и элементы списков; остальные теги и разметку удаляй.\n\n4) Форматирование вывода (СТРОГО):\n- Каждый элемент или предложение ДОЛЖНА начинаться с заглавной буквы (например, \"Разрабатывать REST API; Проектировать архитектуру\", а не \"разрабатывать\" или \"- разрабатывать\"). \n- Строго разделяй элементы \"; \" (точка с запятой + пробел). \n- Никогда не начинайте строку или фразу с \"-\", \"—\", \"•\" или \"*\". \n- Всегда используй заглавную букву после каждой точки с запятой. \n- Не добавляй знаки препинания после последнего предложения. \n- Не добавляй лишние пробелы, переносы строк или повторяющиеся разделители.\n\n# Пример корректного вывода:\n\"Проектировать архитектуру системы; Писать unit-тесты; Поддерживать CI/CD pipelines\"\n\n# Пример некорректного вывода:\n\"- проектировать архитектуру системы; писать unit-тесты; поддерживать ci/cd pipelines.\""
            },
            "attributes": {
              "attributes": [
                {
                  "name": "responsibilities",
                  "description": "# RESPONSIBILITIES — строгие правила:\n- Извлекай ТОЛЬКО обязанности / задачи, которые будет выполнять кандидат.\n- Используй извлечение по заголовкам: если найден заголовок, например \"Обязанности\" или \"Задачи\", извлекайте только содержимое под ним.\n- НЕ включай маркетинговые или условия работы (например: \"Мы предлагаем\", \"Удалённая работа\", \"Health insurance\", \"Flexible schedule\", \"Заработная плата\", \"Команда\", \"Onboarding\", \"Corporate events\", \"Мы обеспечиваем\").\n- Если строка содержит одновременно задачу и бонус/условие, ИСКЛЮЧИ её из обязанностей (по умолчанию).\n- Сохраняй оригинальную формулировку, но удаляйте все HTML-теги; заменяйте переносы строк и маркеры списков на \"; \".\n- Технические термины (языки, фреймворки, библиотеки, инструменты, версии, CamelCase, слэши, дефисы) сохраняйте точно так, как в исходном тексте. Не переводите, не транслитерируйте. \n- Сохраняйте заглавную букву в начале каждого предложения для описательных слов, но не меняйте имена технологий. \n\n# Правило согласования языка:\n- Язык извлечённого текста должен точно соответствовать исходному.\n- Если вход на русском — вывод на русском.\n- Если вход на английском — вывод на английском.\n- Никогда не переводите и не переформулируйте терминологию."
                },
                {
                  "name": "requirements",
                  "required": true,
                  "description": "# REQUIREMENTS — строгие правила:\n- Извлекай ТОЛЬКО обязательные требования / необходимый опыт или навыки, явно указанные как требования (например: \"Требуется\", \"Необходимый опыт\", \"Мы ожидаем\").\n- Предпочтение: если найден заголовок \"Требования\" или \"Необходимый опыт\", извлекай только эту секцию.\n- Сохраняйте все технические термины, версии и детали (например: \"Java 21\", \"Spring Boot 3.5+\", \"Kafka\", \"PostgreSQL\").\n- Не включай маркетинговые или необязательные фразы (их можно направить в \"additional\", если явно указывают на желательные навыки).\n- Формат: разделяй элементы строго через \"; \".\n- Технические термины (языки, фреймворки, библиотеки, инструменты, версии, CamelCase, слэши, дефисы) сохраняйте точно так, как в исходном тексте. Не переводите, не транслитерируйте. \n- Сохраняйте заглавную букву в начале каждого предложения для описательных слов, но не меняйте имена технологий. \n# Правило согласования языка:\n- Язык извлечённого текста должен точно соответствовать исходному.\n- Если вход на русском — вывод на русском.\n- Если вход на английском — вывод на английском.\n- Никогда не переводи и не переформулируй терминологию."
                },
                {
                  "name": "additional",
                  "description": "# ADDITIONAL — строгие правила:\n- Извлекай ТОЛЬКО желательные / опциональные навыки или опыт, явно указанные фразами вроде \"Будет плюсом\", \"Желательно\", \"Desirable\", \"Приветствуется\", \"Will be a plus\".\n- Сначала используй извлечение по заголовкам: если найден заголовок \"Будет плюсом\" или \"Желательно\", бери только его содержимое.\n- Также включай предложения, содержащие индикаторы желательности (см. список выше).\n- НЕ включай льготы, бонусы или условия работы (см. блоклист). Если строка содержит одновременно желательный навык и бонус, классифицируй её как БОНУС и ИСКЛЮЧИ из \"additional\".\n- Если релевантных опциональных пунктов нет — ОПУСТИТЕ поле \"additional\" (не возвращайте пустую строку).\n- Сохраняй оригинальную формулировку и переносы строк, заменяя их на \"; \".\n- Технические термины (языки, фреймворки, библиотеки, инструменты, версии, CamelCase, слэши, дефисы) сохраняйте точно так, как в исходном тексте. Не переводите, не транслитерируйте. \n- Сохраняйте заглавную букву в начале каждого предложения для описательных слов, но не меняйте имена технологий. \n# Правило согласования языка:\n- Язык извлечённого текста должен точно соответствовать исходному.\n- Если вход на русском — вывод на русском.\n- Если вход на английском — вывод на английском.\n- Никогда не переводи и не переформулируй терминологию.\nБлоклист: [\"мы предоставляем\",\"официальн\",\"удал\",\"гибк\",\"дмс\",\"зарплат\",\"компенсац\",\"корпоратив\",\"адаптац\",\"аккредит\",\"трудоустройств\", \"график\", \"условия\", \"предлагаем\"]"
                }
              ]
            }
          },
          "executeOnce": false,
          "retryOnFail": true,
          "typeVersion": 1.2
        },
        {
          "id": "154a2e99-d977-4097-a97b-53bfb0b6c228",
          "name": "ObjToStrArr",
          "type": "n8n-nodes-base.code",
          "position": [
            1104,
            1872
          ],
          "parameters": {
            "jsCode": "const items = $input.all();\n\nreturn items.map(item => {\n  // Преобразуем key_skills в массив строк\n  if (Array.isArray(item.json.key_skills)) {\n    item.json.key_skills = item.json.key_skills.map(skill => skill.name);\n  }\n\n  // Преобразуем work_format в массив строк по id\n  if (Array.isArray(item.json.work_format)) {\n    item.json.work_format = item.json.work_format.map(format => format.id);\n  }\n\n  return item;\n});"
          },
          "typeVersion": 2
        },
        {
          "id": "51b324db-af92-4d08-9d9b-2a957d693b45",
          "name": "Sections cleanup",
          "type": "n8n-nodes-base.code",
          "position": [
            1296,
            2272
          ],
          "parameters": {
            "jsCode": "const input = $input.first().json.output;\nconst sections = Object.keys(input)\n  .map(key => ({\n    section: key,\n    text: input[key].replace(/\\n/g, ' ')\n  }))\n  .filter(section => section.text.trim() !== '');\nreturn [{ json: { sections } }];"
          },
          "typeVersion": 2
        },
        {
          "id": "1fa8df0d-40bf-4f64-acfd-212701c44faf",
          "name": "Load Content/Metadata",
          "type": "@n8n/n8n-nodes-langchain.documentDefaultDataLoader",
          "position": [
            2464,
            2272
          ],
          "parameters": {
            "options": {
              "metadata": {
                "metadataValues": [
                  {
                    "name": "chunk_id",
                    "value": "={{ $('Chunking').item.json.metadata.id }}"
                  },
                  {
                    "name": "title",
                    "value": "={{ $('Chunking').item.json.metadata.title }}"
                  },
                  {
                    "name": "experience_id",
                    "value": "={{ $('Chunking').item.json.metadata.experience.id }}"
                  },
                  {
                    "name": "key_skills",
                    "value": "={{ $('Chunking').item.json.metadata.key_skills }}"
                  },
                  {
                    "name": "company",
                    "value": "={{ $('Chunking').item.json.metadata.company }}"
                  },
                  {
                    "name": "section",
                    "value": "={{ $('Chunking').item.json.metadata.section }}"
                  }
                ]
              }
            },
            "jsonData": "={{ $('Chunking').item.json.content }}",
            "jsonMode": "expressionData",
            "textSplittingMode": "custom"
          },
          "typeVersion": 1.1
        },
        {
          "id": "48d0c20c-7fd6-4ac4-b3d6-a8c111505da6",
          "name": "Payload Extraction",
          "type": "n8n-nodes-base.set",
          "position": [
            368,
            2128
          ],
          "parameters": {
            "options": {},
            "assignments": {
              "assignments": [
                {
                  "id": "cbca6f2d-469e-4be9-a42f-02e4403eb2f8",
                  "name": "id",
                  "type": "string",
                  "value": "={{ $json.id }}"
                },
                {
                  "id": "8dc8b87c-bfb7-4655-abd7-c54e5d30a4d4",
                  "name": "title",
                  "type": "string",
                  "value": "={{ $json.name }}"
                },
                {
                  "id": "91281710-76ee-4531-bf5c-ca6e4c5707be",
                  "name": "salary_range",
                  "type": "object",
                  "value": "={{ $json.salary_range }}"
                },
                {
                  "id": "f1953bd7-2ba2-4fb7-b9a8-cf226bf58b25",
                  "name": "location",
                  "type": "string",
                  "value": "={{ $json.address.city }}"
                },
                {
                  "id": "c197a189-80ba-4834-8c3a-40e33dfa0759",
                  "name": "experience",
                  "type": "object",
                  "value": "={{ $json.experience }}"
                },
                {
                  "id": "d2a8f427-565e-49e2-a606-3c5a6cac1836",
                  "name": "sections",
                  "type": "string",
                  "value": "={{ $json.description }}"
                },
                {
                  "id": "ba314b21-e78c-425e-b975-10bb2432ef3d",
                  "name": "key_skills",
                  "type": "array",
                  "value": "={{ $json.key_skills }}"
                },
                {
                  "id": "6b91dc6d-84cf-4ec8-b9f5-decc788efd3f",
                  "name": "source_url",
                  "type": "string",
                  "value": "={{ $json.alternate_url }}"
                },
                {
                  "id": "0a9e300a-f2ea-4ada-be3d-ef971441e80f",
                  "name": "employment_type",
                  "type": "object",
                  "value": "={{ $json.employment_form }}"
                },
                {
                  "id": "8bbaf1fc-9da7-4fc7-84ca-850a8e1905ea",
                  "name": "work_format",
                  "type": "array",
                  "value": "={{ $json.work_format }}"
                },
                {
                  "id": "5b72d543-b957-4dfb-aaa1-f55b1a685248",
                  "name": "company",
                  "type": "string",
                  "value": "={{ $json.employer.name }}"
                }
              ]
            }
          },
          "typeVersion": 3.4
        },
        {
          "id": "f5913dfe-3497-4103-94b6-0d34d09f6ae2",
          "name": "Scroll Points",
          "type": "n8n-nodes-qdrant.qdrant",
          "position": [
            1568,
            2048
          ],
          "parameters": {
            "limit": 100,
            "filter": "={\n  \"must\": [\n      {\n        \"key\": \"vacancy_id\",\n        \"match\": {\n          \"value\": {{ $json.metadata.document_id }}\n        }\n      }\n    ]\n}",
            "resource": "point",
            "operation": "scrollPoints",
            "collectionName": {
              "__rl": true,
              "mode": "list",
              "value": "vacancies",
              "cachedResultName": "vacancies"
            },
            "requestOptions": {}
          },
          "credentials": {
            "qdrantRestApi": {
              "id": "5UV8rQE53hqsh82x",
              "name": "Qdrant account"
            }
          },
          "typeVersion": 1
        },
        {
          "id": "d0e8d314-0b4f-46b6-b635-47840f1f1576",
          "name": "If1",
          "type": "n8n-nodes-base.if",
          "position": [
            1744,
            2048
          ],
          "parameters": {
            "options": {},
            "conditions": {
              "options": {
                "version": 2,
                "leftValue": "",
                "caseSensitive": true,
                "typeValidation": "strict"
              },
              "combinator": "and",
              "conditions": [
                {
                  "id": "62eac888-357f-4c41-9e12-163819307fd6",
                  "operator": {
                    "type": "array",
                    "operation": "notEmpty",
                    "singleValue": true
                  },
                  "leftValue": "={{ $json.result.points }}",
                  "rightValue": ""
                }
              ]
            }
          },
          "typeVersion": 2.2
        },
        {
          "id": "ea783bd8-2f4f-4a8b-bd22-456605bbbffe",
          "name": "Delete Points",
          "type": "n8n-nodes-qdrant.qdrant",
          "position": [
            1968,
            1952
          ],
          "parameters": {
            "filter": "={\n  \"must\": [\n      {\n        \"key\": \"vacancy_id\",\n        \"match\": {\n          \"value\": {{ $json.result.points[0].payload.vacancy_id }}\n        }\n      }\n    ]\n}",
            "points": "null",
            "resource": "point",
            "operation": "deletePoints",
            "collectionName": {
              "__rl": true,
              "mode": "list",
              "value": "vacancies",
              "cachedResultName": "vacancies"
            },
            "requestOptions": {}
          },
          "credentials": {
            "qdrantRestApi": {
              "id": "5UV8rQE53hqsh82x",
              "name": "Qdrant account"
            }
          },
          "typeVersion": 1
        },
        {
          "id": "c97d612b-143d-4e95-bed1-e4c762e95965",
          "name": "qwen3-embedd-save",
          "type": "@n8n/n8n-nodes-langchain.embeddingsOllama",
          "position": [
            2176,
            2272
          ],
          "parameters": {
            "model": "qwen3-embedding:8b"
          },
          "credentials": {
            "ollamaApi": {
              "id": "JrVtVfb5WaGIXcqR",
              "name": "Ollama RTX"
            }
          },
          "typeVersion": 1
        },
        {
          "id": "0742baef-1e63-42a8-b14b-4861c3ec367a",
          "name": "qwen3:4b:it:q8-extract",
          "type": "@n8n/n8n-nodes-langchain.lmOllama",
          "position": [
            848,
            2352
          ],
          "parameters": {
            "model": "qwen3:4b-instruct-2507-q8_0",
            "options": {
              "topK": 1,
              "topP": 1,
              "format": "json",
              "numCtx": 8192,
              "lowVram": false,
              "mainGpu": 0,
              "useMMap": true,
              "numBatch": 128,
              "useMLock": true,
              "numThread": 14,
              "vocabOnly": false,
              "temperature": 0,
              "repeatPenalty": 1,
              "penalizeNewline": false,
              "presencePenalty": 0,
              "frequencyPenalty": 0
            }
          },
          "credentials": {
            "ollamaApi": {
              "id": "JrVtVfb5WaGIXcqR",
              "name": "Ollama RTX"
            }
          },
          "typeVersion": 1
        },
        {
          "id": "51c2876d-78d9-4c01-9803-bd045ff3aede",
          "name": "Get New Vacancies",
          "type": "n8n-nodes-base.httpRequest",
          "position": [
            -80,
            1856
          ],
          "parameters": {
            "url": "={{ $json.new_items.url }}",
            "options": {
              "batching": {
                "batch": {
                  "batchSize": 30
                }
              }
            },
            "sendQuery": true,
            "sendHeaders": true,
            "authentication": "genericCredentialType",
            "genericAuthType": "oAuth2Api",
            "queryParameters": {
              "parameters": [
                {
                  "name": "per_page",
                  "value": "60"
                }
              ]
            },
            "headerParameters": {
              "parameters": [
                {
                  "name": "User-Agent",
                  "value": "OClick/1.1 (shimorowm@gmail.com)"
                }
              ]
            }
          },
          "credentials": {
            "oAuth2Api": {
              "id": "l9tyPEWtPvzUKFXJ",
              "name": "HH OAuth2"
            }
          },
          "typeVersion": 4.2
        },
        {
          "id": "e413f625-e123-4a4d-9d08-5d115b1e0817",
          "name": "Get Vacancy Details",
          "type": "n8n-nodes-base.httpRequest",
          "position": [
            -288,
            2128
          ],
          "parameters": {
            "url": "=https://api.hh.ru/vacancies/{{ $json.id }}",
            "options": {
              "batching": {
                "batch": {
                  "batchSize": 30
                }
              }
            },
            "sendHeaders": true,
            "headerParameters": {
              "parameters": [
                {
                  "name": "User-Agent",
                  "value": "OClick/1.1 (shimorowm@gmail.com)"
                }
              ]
            }
          },
          "typeVersion": 4.2
        },
        {
          "id": "83b6f014-296c-4545-bc0d-d35c99463362",
          "name": "Loop Over Jobs",
          "type": "n8n-nodes-base.splitInBatches",
          "position": [
            592,
            2128
          ],
          "parameters": {
            "options": {}
          },
          "typeVersion": 3
        },
        {
          "id": "70326db7-08c4-472f-a432-c17076e31d6a",
          "name": "If not enough data",
          "type": "n8n-nodes-base.if",
          "position": [
            3904,
            1904
          ],
          "parameters": {
            "options": {},
            "conditions": {
              "options": {
                "version": 2,
                "leftValue": "",
                "caseSensitive": true,
                "typeValidation": "strict"
              },
              "combinator": "and",
              "conditions": [
                {
                  "id": "0b94e219-2673-4302-b263-0feeb5bc7fe2",
                  "operator": {
                    "type": "string",
                    "operation": "notContains"
                  },
                  "leftValue": "={{ $json.output }}",
                  "rightValue": "Нет данных"
                },
                {
                  "id": "7e202110-3b82-4354-bb3d-701f3a030b4a",
                  "operator": {
                    "type": "string",
                    "operation": "notContains"
                  },
                  "leftValue": "={{ $json.output }}",
                  "rightValue": "Нет совпадений"
                },
                {
                  "id": "cc9ccb62-0364-45c3-9a1e-ab5cc714b1de",
                  "operator": {
                    "type": "string",
                    "operation": "notContains"
                  },
                  "leftValue": "={{ $json.output }}",
                  "rightValue": "No data"
                }
              ]
            }
          },
          "typeVersion": 2.2
        },
        {
          "id": "abbb7110-aa9b-4af4-ac03-29329b0628d7",
          "name": "Loop Over Descriptions",
          "type": "n8n-nodes-base.splitInBatches",
          "position": [
            3120,
            1888
          ],
          "parameters": {
            "options": {}
          },
          "typeVersion": 3
        },
        {
          "id": "68380169-3663-4943-bdbf-69d7091778ca",
          "name": "Send Negogiation",
          "type": "n8n-nodes-base.httpRequest",
          "onError": "continueErrorOutput",
          "position": [
            4304,
            1888
          ],
          "parameters": {
            "url": "https://api.hh.ru/negotiations",
            "method": "POST",
            "options": {},
            "sendBody": true,
            "contentType": "multipart-form-data",
            "sendHeaders": true,
            "authentication": "genericCredentialType",
            "bodyParameters": {
              "parameters": [
                {
                  "name": "message",
                  "value": "={{ $('If not enough data').item.json.output }}"
                },
                {
                  "name": "resume_id",
                  "value": "054142d0ff0f5da2090039ed1f47344b585273"
                },
                {
                  "name": "vacancy_id",
                  "value": "={{ $('Loop Over Descriptions').item.json.id }}"
                }
              ]
            },
            "genericAuthType": "oAuth2Api",
            "headerParameters": {
              "parameters": [
                {
                  "name": "User-Agent",
                  "value": "OClick/1.1 (shimorowm@gmail.com)"
                }
              ]
            }
          },
          "credentials": {
            "oAuth2Api": {
              "id": "l9tyPEWtPvzUKFXJ",
              "name": "HH OAuth2"
            }
          },
          "typeVersion": 4.2
        },
        {
          "id": "3f047621-bd1c-4f9d-8bb9-82f561984f4c",
          "name": "qwen3:4b:it:q8-generate",
          "type": "@n8n/n8n-nodes-langchain.lmChatOllama",
          "position": [
            3072,
            2272
          ],
          "parameters": {
            "model": "qwen3:4b-instruct-2507-q8_0",
            "options": {
              "topK": 20,
              "topP": 1,
              "numCtx": 8192,
              "numBatch": 1,
              "numThread": 14,
              "temperature": 0.7,
              "repeatPenalty": 1,
              "penalizeNewline": false,
              "presencePenalty": 0.2,
              "frequencyPenalty": 0
            }
          },
          "credentials": {
            "ollamaApi": {
              "id": "JrVtVfb5WaGIXcqR",
              "name": "Ollama RTX"
            }
          },
          "typeVersion": 1
        },
        {
          "id": "b9187a1c-3925-4fcc-beb3-3d708e3045aa",
          "name": "Format List",
          "type": "n8n-nodes-base.code",
          "position": [
            4128,
            1888
          ],
          "parameters": {
            "jsCode": "const newItems = $('Loop Over Descriptions').all().map(item => {\n  const newSections = item.json.sections.map(section => {\n    const listItems = section.text\n      .split(';')\n      .map(s => s.trim())\n      .filter(Boolean)\n      .map(s => `- ${s}`)\n      .join('\\n');\n    return {\n      ...section,\n      textList: listItems\n    };\n  });\n  return {\n    json: {\n      ...item.json,\n      sections: newSections\n    }\n  };\n});\n\nreturn newItems;"
          },
          "typeVersion": 2
        },
        {
          "id": "3c9009a6-7645-40fe-ad6b-b3465ea69d83",
          "name": "Edit Fields",
          "type": "n8n-nodes-base.set",
          "position": [
            3680,
            1904
          ],
          "parameters": {
            "options": {},
            "assignments": {
              "assignments": [
                {
                  "id": "9bb3c667-a07a-4890-ac97-b6fcc8076a2e",
                  "name": "output",
                  "type": "string",
                  "value": "={{ $json.output.replaceAll('—', '-') }}"
                }
              ]
            }
          },
          "typeVersion": 3.4
        },
        {
          "id": "70ffee5e-8d87-44e9-a2ef-b09d6684d6f8",
          "name": "Code in JavaScript1",
          "type": "n8n-nodes-base.code",
          "position": [
            768,
            2144
          ],
          "parameters": {
            "mode": "runOnceForEachItem",
            "jsCode": "let html = $json.sections;\nhtml = html.replace(/<br\\s*\\/?>/gi, '\\n');\nhtml = html.replace(/<[^>]+>/g, '');\nhtml = html.trim();\n\nreturn {\n  json: {\n    ...$json,\n    sections: html\n  }\n};"
          },
          "typeVersion": 2
        },
        {
          "id": "1894bc5d-bae2-41cb-be29-d5ba8384acfe",
          "name": "Create Telegraph account",
          "type": "n8n-nodes-base.httpRequest",
          "position": [
            -240,
            1168
          ],
          "parameters": {
            "url": "https://api.telegra.ph/createAccount",
            "method": "POST",
            "options": {},
            "sendQuery": true,
            "queryParameters": {
              "parameters": [
                {
                  "name": "short_name",
                  "value": "xsarif"
                },
                {
                  "name": "author_name",
                  "value": "Max"
                },
                {
                  "name": "author_url",
                  "value": "https://t.me/xsarif"
                }
              ]
            }
          },
          "typeVersion": 4.2
        },
        {
          "id": "adb57ca0-24a1-4536-b135-9cbfb94eccf8",
          "name": "HTTP Request",
          "type": "n8n-nodes-base.httpRequest",
          "position": [
            4944,
            1888
          ],
          "parameters": {
            "url": "https://api.telegra.ph/createPage",
            "method": "POST",
            "options": {},
            "jsonBody": "={{ $json }}",
            "sendBody": true,
            "specifyBody": "json"
          },
          "typeVersion": 4.2
        },
        {
          "id": "95995bf6-aec4-43d2-9cfc-65dc67050b20",
          "name": "Format Error",
          "type": "n8n-nodes-base.code",
          "position": [
            4528,
            1968
          ],
          "parameters": {
            "mode": "runOnceForEachItem",
            "jsCode": "// Example error message input\nconst errorMessage = $json.error.message;\n\n// Remove the status code and dash prefix\nconst jsonString = errorMessage.replace(/^\\d+\\s*-\\s*/, '');\n\n// Remove the surrounding quotes if present\nconst trimmed = jsonString.replace(/^\"|\"$/g, '');\n\n// Unescape the JSON string\nconst unescaped = trimmed.replace(/\\\\\"/g, '\"');\n\n// Parse the JSON\nconst parsed = JSON.parse(unescaped);\n\nreturn { json: parsed };"
          },
          "typeVersion": 2
        },
        {
          "id": "5b2b5af9-3e7e-4d34-8f00-b88691de22c0",
          "name": "Code in JavaScript",
          "type": "n8n-nodes-base.code",
          "position": [
            4752,
            1872
          ],
          "parameters": {
            "jsCode": "return [\n  {\n    json: {\n      access_token: \"76a4239f7feeb1d21685fca42b308b3fb016b4dbe8f0a7142a18bedbc3ae\",\n      title: `СОПР: ${$('Loop Over Descriptions').first().json.company} / ${$('Loop Over Descriptions').first().json.title}`,\n      author_name: \"Max\",\n      content: [\n        {\n          tag: \"p\",\n          children: [\n            $('If not enough data').first().json.output\n          ]\n        }\n      ],\n      return_content: true\n    }\n  }\n];"
          },
          "typeVersion": 2
        },
        {
          "id": "b56122bc-d693-4390-83d8-b9699d222c02",
          "name": "Send a text message",
          "type": "n8n-nodes-base.telegram",
          "position": [
            5152,
            1952
          ],
          "webhookId": "90ce5141-bd08-41a6-a310-f0262a8f6e67",
          "parameters": {
            "text": "=<b>СОПРОВОДИТЕЛЬНО ПИСЬМО:</b>\n{{ $json.result.url }}\n\n<b>ОПИСАНИЕ ВАКАНСИИ:</b>\n<i>Должность:</i> {{ $('Loop Over Descriptions').item.json.title }}\n\n<b><i>СЕКЦИИ</i>:\n\nЗадачи</b>:\n<pre>{{ $('Format List').item.json.sections[0].textList }}</pre>\n\n<b>Требования</b>:\n<pre>{{ $('Format List').item.json.sections[1].textList }}</pre>\n\n<b>Дополнительные</b>\n<pre>{{ $('Format List').item.json.sections[2].textList }}</pre>\n\n<b>Вакансия:</b> {{ $('Loop Over Descriptions').item.json.source_url }}\n\n<b>ERROR:</b>\n<pre>{{ \n  $('Format Error').isExecuted \n    ? JSON.stringify($('Format Error').first().json, null, 2) \n    : 'No error occurred.' \n}}</pre>",
            "chatId": "1047435962",
            "additionalFields": {
              "parse_mode": "HTML",
              "appendAttribution": false
            }
          },
          "credentials": {
            "telegramApi": {
              "id": "0NGQ5PdzE0w0e3p0",
              "name": "Telegram account"
            }
          },
          "typeVersion": 1.2
        },
        {
          "id": "1965e276-306a-4d36-a935-9b065660dd48",
          "name": "Ollama Health",
          "type": "n8n-nodes-base.httpRequest",
          "position": [
            -288,
            1600
          ],
          "parameters": {
            "url": "http://192.168.0.100:11434",
            "options": {
              "timeout": 5000
            }
          },
          "typeVersion": 4.2
        },
        {
          "id": "73af861e-f08f-4329-879f-0b678db94044",
          "name": "AI Agent",
          "type": "@n8n/n8n-nodes-langchain.agent",
          "notes": "Cover Letter",
          "position": [
            3344,
            1904
          ],
          "parameters": {
            "text": "Создай сопроводительное письмо для пользователя, используя актуальное описание вакансии",
            "options": {
              "systemMessage": "Ты — топ-эксперт по сопроводительным письмам для IT-вакансий России 2025 года. Ты написал >500 000 откликов с откликом 25–40% на middle-вакансии.\n\nУ тебя два источника данных:\n1. ОБЯЗАТЕЛЬНО Используй Get_Job_Description (title, company, key_skills[], responsibilities, requirements, experience_id), чтобы получить данные вакансии, иначе пользователь не получит нужную вакансию\n2. ОБЯЗАТЕЛЬНО Используй Get_User_Resume для получения резюме пользователя, иначе пользователь не сможет получить релевантное письмо\n\nОбязательный анализ (выполняй строго):\n1. Выдели топ-8 самых важных пунктов из responsibilities + requirements + key_skills (по приоритету).\n2. Найди ВСЕ пересечения с резюме, но выбери только 6–8 САМЫХ РАЗНООБРАЗНЫХ (разработка, тестирование, DevOps, архитектура и т.д.).\n3. Убедись, что в письме нет повторений одних и тех же слов/фраз больше 2–3 раз.\n4. Для блока «Однако, что мне действительно понравилось» выбери 1 пункт из responsibilities с сильным пересечением, но НЕ тестирование, если оно уже доминирует в письме.\n\nСтруктура письма (жёстко, длина 160–210 слов):\n\nЗдравствуйте!\n\nЯ — Java-разработчик с опытом [5–6 ключевых пересечений из топа, через запятую: обязательно включи 2–3 ключевых слова из key_skills вакансии].\n\nВ последние несколько лет активно занимался [основная деятельность под вакансию, но с балансом: если вакансия QA-heavy — всё равно упомяни Spring Boot / микросервисы].\n\nОдин из ключевых проектов — MicroRestBank, [коротко свяжи с обязанностями вакансии, 1 предложение].\n\nБлагодаря ему я [6–8 РАЗНООБРАЗНЫХ действий через точку с запятой — перефразируй опыт под вакансию, но сохраняй баланс: разработка, тестирование, CI/CD, БД и т.д.; избегай повторов слов «тестировал», «автотесты»].\n\nОднако, что мне действительно понравилось — это [1 пункт из responsibilities, который НЕ тестирование (например рефакторинг, работа с Maven/Gradle, взаимодействие с командой, SQL, планирование спринта)], что существенно [польза].\n\nМне интересна позиция [точное title] в \"[company]\", где я смогу применить свой опыт в [4–5 разнообразных пунктов из responsibilities/key_skills] и внести реальный вклад в развитие продукта.\n\nБуду рад обсудить свою кандидатуру подробнее.\n\nПравила, которые ты НИКОГДА не нарушаешь:\n– Ключевые фразы дословно.\n– Нет повторениям одним и тем же словам/фразам (максимум 2–3 раза на слово).\n– Баланс 60/40 или 50/50: если вакансия сильно QA — всё равно оставляй видимыми микросервисы, Spring Boot, архитектуру.\n– Естественный живой язык, как будто пишет человек, а не робот.\n– Обязательно используй ключевые слова из key_skills естественно (для ATS).\n– Никогда не придумывай достижения.\n– Если experience_id between1And3 или выше — только формулировка «внести реальный вклад».\n\nСейчас напиши письмо для предоставленных данных.",
              "enableStreaming": false,
              "returnIntermediateSteps": true
            },
            "promptType": "define"
          },
          "notesInFlow": true,
          "typeVersion": 2.2
        },
        {
          "id": "1223c29e-ad5d-4483-bb47-4624f468903f",
          "name": "Merge1",
          "type": "n8n-nodes-base.merge",
          "position": [
            816,
            1872
          ],
          "parameters": {
            "mode": "combine",
            "options": {
              "clashHandling": {
                "values": {
                  "resolveClash": "preferLast"
                }
              }
            },
            "combineBy": "combineByPosition"
          },
          "typeVersion": 3.2
        },
        {
          "id": "b7d4b9cd-227b-4fed-9846-164cb791ae6f",
          "name": "Merge2",
          "type": "n8n-nodes-base.merge",
          "position": [
            2192,
            2048
          ],
          "parameters": {},
          "typeVersion": 3.2
        },
        {
          "id": "7f7d7e4b-e8eb-4d30-a206-b342b36d53f5",
          "name": "Merge3",
          "type": "n8n-nodes-base.merge",
          "position": [
            2896,
            1888
          ],
          "parameters": {
            "mode": "chooseBranch"
          },
          "typeVersion": 3.2
        },
        {
          "id": "f1a61554-f87d-45f1-9bbe-6f346aa570ad",
          "name": "When chat message received",
          "type": "@n8n/n8n-nodes-langchain.chatTrigger",
          "position": [
            -352,
            2816
          ],
          "webhookId": "e0c2cc7f-e923-4d4d-b583-d12bb403c617",
          "parameters": {
            "options": {}
          },
          "typeVersion": 1.3
        },
        {
          "id": "7362b31a-1f19-4768-91da-a738aca685f2",
          "name": "HTTP Request1",
          "type": "n8n-nodes-base.httpRequest",
          "position": [
            -176,
            2368
          ],
          "parameters": {
            "url": "=https://api.hh.ru/vacancies/{{ $json.chatInput }}",
            "options": {},
            "sendHeaders": true,
            "authentication": "genericCredentialType",
            "genericAuthType": "oAuth2Api",
            "headerParameters": {
              "parameters": [
                {
                  "name": "User-Agent",
                  "value": "OClick/1.1 (shimorowm@gmail.com)"
                }
              ]
            }
          },
          "credentials": {
            "oAuth2Api": {
              "id": "l9tyPEWtPvzUKFXJ",
              "name": "HH OAuth2"
            }
          },
          "typeVersion": 4.2
        },
        {
          "id": "a7af9135-2e9c-4efe-9acd-ac2e239aa3d5",
          "name": "Embeddings OpenAI",
          "type": "@n8n/n8n-nodes-langchain.embeddingsOpenAi",
          "position": [
            2320,
            2304
          ],
          "parameters": {
            "model": "Qwen3-Embedding-8B-Q8_0",
            "options": {}
          },
          "credentials": {
            "openAiApi": {
              "id": "KB5XbkoIGYZV5FeN",
              "name": "OpenAi account"
            }
          },
          "typeVersion": 1.2
        },
        {
          "id": "fc57c170-f258-43a4-adfc-b9a289608e9f",
          "name": "OpenAI Chat Model",
          "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
          "position": [
            1056,
            2368
          ],
          "parameters": {
            "model": {
              "__rl": true,
              "mode": "list",
              "value": "Qwen3VL-8B-Instruct-Q4_K_M",
              "cachedResultName": "Qwen3VL-8B-Instruct-Q4_K_M"
            },
            "options": {
              "topP": 1,
              "maxRetries": 2,
              "temperature": 0,
              "responseFormat": "json_object",
              "presencePenalty": 0,
              "frequencyPenalty": 0
            }
          },
          "credentials": {
            "openAiApi": {
              "id": "KB5XbkoIGYZV5FeN",
              "name": "OpenAi account"
            }
          },
          "typeVersion": 1.2
        },
        {
          "id": "6fd4fd4d-e3b9-495d-a412-02fd876795bc",
          "name": "OpenAI Chat Model1",
          "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
          "position": [
            2928,
            2416
          ],
          "parameters": {
            "model": {
              "__rl": true,
              "mode": "list",
              "value": "Qwen3VL-8B-Instruct-Q4_K_M",
              "cachedResultName": "Qwen3VL-8B-Instruct-Q4_K_M"
            },
            "options": {
              "topP": 1,
              "temperature": 0.7,
              "responseFormat": "text",
              "presencePenalty": 0,
              "frequencyPenalty": 0
            }
          },
          "credentials": {
            "openAiApi": {
              "id": "KB5XbkoIGYZV5FeN",
              "name": "OpenAi account"
            }
          },
          "typeVersion": 1.2
        },
        {
          "id": "027fee08-63e4-48ab-88b6-8efb413d42db",
          "name": "Actual Job Tool1",
          "type": "@n8n/n8n-nodes-langchain.toolWorkflow",
          "position": [
            3808,
            2288
          ],
          "parameters": {
            "workflowId": {
              "__rl": true,
              "mode": "list",
              "value": "DYD8jG0rE6pBVgUy",
              "cachedResultUrl": "/workflow/DYD8jG0rE6pBVgUy",
              "cachedResultName": "Parse job's description"
            },
            "description": "Actual Job Description's",
            "workflowInputs": {
              "value": {
                "query": "={{ $('Loop Over Descriptions').item.json.id }}"
              },
              "schema": [
                {
                  "id": "query",
                  "type": "string",
                  "display": true,
                  "removed": false,
                  "required": false,
                  "displayName": "query",
                  "defaultMatch": false,
                  "canBeUsedToMatch": true
                }
              ],
              "mappingMode": "defineBelow",
              "matchingColumns": [],
              "attemptToConvertTypes": false,
              "convertFieldsToString": false
            }
          },
          "typeVersion": 2.2
        },
        {
          "id": "a5de94e0-539c-4ab6-92af-317a596ae1d5",
          "name": "qwen3:4b:it:q8-generate1",
          "type": "@n8n/n8n-nodes-langchain.lmChatOllama",
          "position": [
            3248,
            2416
          ],
          "parameters": {
            "model": "qwen3:4b-instruct-2507-q8_0",
            "options": {
              "topK": 20,
              "topP": 1,
              "numCtx": 8192,
              "numBatch": 1,
              "numThread": 14,
              "temperature": 0.7,
              "repeatPenalty": 1,
              "penalizeNewline": false,
              "presencePenalty": 0.2,
              "frequencyPenalty": 0
            }
          },
          "credentials": {
            "ollamaApi": {
              "id": "JrVtVfb5WaGIXcqR",
              "name": "Ollama RTX"
            }
          },
          "typeVersion": 1
        },
        {
          "id": "70ae1a5c-04c4-4bbb-9217-bb40b1618902",
          "name": "Get Job Description",
          "type": "@n8n/n8n-nodes-langchain.toolWorkflow",
          "position": [
            3600,
            2416
          ],
          "parameters": {
            "workflowId": {
              "__rl": true,
              "mode": "list",
              "value": "DYD8jG0rE6pBVgUy",
              "cachedResultUrl": "/workflow/DYD8jG0rE6pBVgUy",
              "cachedResultName": "Parse job's description"
            },
            "description": "Get Actual Job Description",
            "workflowInputs": {
              "value": {
                "query": "={{ $('Loop Over Descriptions').item.json.id }}"
              },
              "schema": [
                {
                  "id": "query",
                  "type": "string",
                  "display": true,
                  "removed": false,
                  "required": false,
                  "displayName": "query",
                  "defaultMatch": false,
                  "canBeUsedToMatch": true
                }
              ],
              "mappingMode": "defineBelow",
              "matchingColumns": [],
              "attemptToConvertTypes": false,
              "convertFieldsToString": false
            }
          },
          "typeVersion": 2.2
        },
        {
          "id": "98fe261a-8528-4445-83d3-c09683ac46ff",
          "name": "Get User Resume",
          "type": "@n8n/n8n-nodes-langchain.agentTool",
          "position": [
            3296,
            2192
          ],
          "parameters": {
            "text": "Максим Кришталь\nКонтакты: +7 (996) 7667277; shimorowm@gmail.com\nСпециализации: Программист, разработчик; Java-разработчик\n\n# Опыт работы — 1 год 4 месяца\nMicroRestBank\nДолжность: Java-разработчик\nРазработка комплексного банковского приложения на основе микросервисной архитектуры.\nОписание: Проект MicroRestBank представляет собой платформу для управления пользователями и банковскими картами через RESTful API. Система включает в себя функции создания карт, их блокировки, управления пользователями и осуществления денежных переводов.\nАрхитектура и Реализация: Спроектировал и разработал набор независимых микросервисов на Java 21 и Spring Boot 3, включая:\n- Разрабатывал и отлаживал серверный Java-код (Spring Boot 3, Spring Data JPA, Spring Security) - опыт root-cause analysis и hotfix’ов в продакшн/стейдж окружениях.\n- Единая точка входа для всех клиентских запросов, реализованная на Spring Cloud Gateway.\n- Создал и поддерживал механизмы аутентификации и авторизации с Keycloak (OAuth2, JWT), в т.ч. стратегию ролей и прав доступа.\n- Сервис-дискавери для динамического взаимодействия между сервисами (Spring Cloud Netflix Eureka).\n- Проектировал и реализовал интеграционные механизмы между микросервисами (REST, Kafka), обеспечив надёжную асинхронную репликацию данных.\n- Реализовал асинхронное взаимодействие между сервисами для обновления данных с помощью Apache Kafka и Debezium (Change Data Capture).\n- Управлял схемами БД и миграциями (PostgreSQL, Liquibase); писал оптимизированные SQL-запросы для аналитики и исправления ошибок.\n- Документировал API с использованием OpenAPI (Swagger).\n- Писал unit и интеграционные тесты (JUnit, Mockito) и автоматизировал сценарии сборки/деплоя.\n- Настроил CI/CD и контейнеризацию (Gradle, Docker, Docker Compose) для локальной и командной разработки.\nСтек:\n- Бэкенд: Java 21, Spring Boot 3, Spring Framework, Spring Data JPA, Spring Security\n- Микросервисы: Microservices Architecture, Spring Cloud (Gateway, Netflix Eureka), RESTful API, Event-Driven Architecture\n- Базы данных и брокеры сообщений: PostgreSQL, Liquibase, Apache Kafka, Debezium (Change Data Capture)\n- Аутентификация и Авторизация: Keycloak, JWT, OAuth2\n- DevOps и Инструменты: Docker, Docker Compose, Gradle, Git, CI/CD, JetBrains IntelliJ IDEA\n- API и Документация: OpenAPI (Swagger)\n\n# Образование\n- Высшее\n- Санкт-Петербургский государственный электротехнический университет «ЛЭТИ» имени В.И. Ульянова (Ленина), Санкт-Петербург\n    2022\n    Факультет компьютерных технологий и информатики, Прикладная математика и информатика\n\n# Навыки\n- Знание языков:\n    Русский — Родной;\n    Английский — B1 — Средний\n- Навыки\n    Java; Spring Framework; Hibernate; Git; Docker; Liquibase; Apache Kafka; Gradle; Apache Maven; PostgreSQL; Linux; REST API; Java SE; JPA; Английский язык; Spring; Spring Boot; Spring Cloud; Spring Data; Spring MVC; Spring Security; Spring Web; Keycloak; Hibernate ORM; SQL; SOLID; ООП; JUnit; Debezium; Mockito\n\n# Дополнительная информация\n- Обо мне\n    Java backend-разработчик, ориентированный на качество и поддерживаемость кода.",
            "options": {
              "systemMessage": "Ты — самый строгий и честный в мире специалист по резюме для IT-вакансий. Ты никогда не придумываешь опыт, цифры, проекты или участие в процессах, которых нет в оригинальном резюме. Ты только перефразируешь, переставляешь порядок пунктов и усиливаешь формулировки уже существующего опыта.\n\nУ тебя два входных данных:\n1. vacancy_json или текст вакансии (title, company, key_skills[], responsibilities, requirements) из Get_Job_Description.\n2. original_resume — текущее резюме соискателя в любом формате.\n\nЗадача: создать улучшенную версию резюме, максимально релевантную под вакансию.\n\nОбязательные правила (нарушишь — ты уволен):\n– Можно только:\n  - Перефразировать существующие пункты под ключевые слова вакансии (например, \"Писал unit и интеграционные тесты (JUnit, Mockito)\" → \"Разрабатывал unit- и интеграционные тесты на Java с использованием JUnit и Mockito\").\n  - Переставлять порядок пунктов (релевантные под вакансию — наверх).\n  - Усиливать глаголы (Реализовал → Спроектировал и реализовал).\n  - Добавлять точные ключевые слова из key_skills вакансии в стек или навыки, если они уже есть в резюме.\n– Если в вакансии есть навык, которого нет в резюме — просто игнорируй, не упоминай его.\n– Метрики (цифры) можно добавлять ТОЛЬКО если они уже есть в оригинальном резюме.\n\nОбязательный анализ перед написанием:\n1. Выдели топ-10 ключевых слов/фраз из вакансии (responsibilities → key_skills → requirements).\n2. Найди ВСЕ прямые пересечения в original_resume.\n3. Определи, какие существующие пункты можно перефразировать под эти слова.\n\nВыводи строго в этом формате (для использования как tool в другом промпте):\n{\n  \"personal\": {...},\n  \"summary\": \"...\",\n  \"key_skills\": [\"...\"],\n  \"work_experience\": [\n    {\n      \"company\": \"...\",\n      \"position\": \"...\",\n      \"period\": \"...\",\n      \"achievements\": [\"...\", \"...\"]\n    }\n  ],\n  \"tech_stack\": {...},\n  \"education\": \"...\"\n}\n\nТеперь улучши резюме для предоставленной вакансии и original_resume."
            },
            "toolDescription": "Get Updated User resume"
          },
          "typeVersion": 2.2
        },
        {
          "id": "e05d9fb5-23bd-483b-a1bc-4c5bd802ebc6",
          "name": "AI Agent1",
          "type": "@n8n/n8n-nodes-langchain.agent",
          "notes": "Cover Letter",
          "position": [
            64,
            2736
          ],
          "parameters": {
            "text": "Создай сопроводительное письмо основываясь на актуальном резюме и вакансии",
            "options": {
              "systemMessage": "Ты — топ-эксперт по сопроводительным письмам для IT-вакансий России 2025 года. Отклик 30–45% на middle-вакансии.\n\nУ тебя есть два ОБЯЗАТЕЛЬНЫХ инструмента:\n1. Resume_Agent_Tool — возвращает полное резюме пользователя (в markdown или JSON).\n2. Get_Job_Description_Tool — возвращает данные вакансии.\n\nЖЁСТКОЕ ПРАВИЛО, КОТОРОЕ ТЫ НИКОГДА НЕ НАРУШАЕШЬ:\n– Ты НЕ ИМЕЕШЬ ПРАВА писать сопроводительное письмо, пока не получил результаты ОБОИХ tool'ов.\n– Только после получения и анализа обоих ответов — пиши письмо.\n– Если хотя бы один tool не вызван — ты обязан вызвать его, а не писать финальный ответ.\n\nОбязательный анализ после получения данных:\n1. Выдели топ-8 пунктов из responsibilities + requirements + key_skills.\n2. Найди 6–8 самых разнообразных пересечений с резюме (разработка, тестирование, DevOps, БД, архитектура и т.д.).\n3. Убедись: нет повторений слов больше 2–3 раз.\n4. Для блока «Однако, что мне действительно понравилось» — выбери пункт из responsibilities, который НЕ тестирование, если оно уже доминирует.\n\nСтруктура письма (жёстко, 160–210 слов):\n\nЗдравствуйте!\n\nЯ — [позиция из вакансии или резюме] с опытом [5–6 ключевых пересечений через запятую, обязательно 2–3 точных ключевых слова из key_skills].\n\nВ последние несколько лет активно занимался [основная деятельность под вакансию с балансом: даже если QA-heavy — сохрани Spring Boot / микросервисы].\n\nОдин из ключевых проектов — MicroRestBank, [коротко свяжи с обязанностями вакансии].\n\nБлагодаря ему я [6–8 разнообразных действий через точку с запятой — перефразируй под вакансию, избегай повторов].\n\nОднако, что мне действительно понравилось — это [1 пункт из responsibilities, НЕ тестирование, если оно доминирует], что существенно [польза из опыта].\n\nМне интересна позиция [точное title вакансии] в \"[company]\", где я смогу применить свой опыт в [4–5 разнообразных пунктов из responsibilities/key_skills] и внести реальный вклад в развитие продукта.\n\nБуду рад обсудить свою кандидатуру подробнее.\n\nДополнительные правила:\n– Ключевые фразы дословно.\n– Баланс 50/50 или 60/40 — всегда оставляй видимыми сильные стороны резюме (микросервисы, Kafka, Keycloak и т.д.).\n– Естественный живой язык.\n– Обязательно используй ключевые слова из key_skills для ATS.\n– Никогда не придумывай достижения.\n– Для experience_id between1And3 и выше — только «внести реальный вклад».\n\nНАЧИНАЙ РАБОТУ С ВЫЗОВА Resume_Agent_Tool.",
              "enableStreaming": false,
              "returnIntermediateSteps": true
            },
            "promptType": "define"
          },
          "notesInFlow": true,
          "typeVersion": 2.2
        },
        {
          "id": "47941222-7e09-43b7-a741-bb13a5a14232",
          "name": "Resume Agent Tool",
          "type": "@n8n/n8n-nodes-langchain.agentTool",
          "position": [
            64,
            3104
          ],
          "parameters": {
            "text": "Максим Кришталь\nКонтакты: +7 (996) 7667277; shimorowm@gmail.com\nСпециализации: Программист, разработчик; Java-разработчик\n\n# Опыт работы — 1 год 4 месяца\nMicroRestBank\nДолжность: Java-разработчик\nРазработка комплексного банковского приложения на основе микросервисной архитектуры.\nОписание: Проект MicroRestBank представляет собой платформу для управления пользователями и банковскими картами через RESTful API. Система включает в себя функции создания карт, их блокировки, управления пользователями и осуществления денежных переводов.\nАрхитектура и Реализация: Спроектировал и разработал набор независимых микросервисов на Java 21 и Spring Boot 3, включая:\n- Разрабатывал и отлаживал серверный Java-код (Spring Boot 3, Spring Data JPA, Spring Security) - опыт root-cause analysis и hotfix’ов в продакшн/стейдж окружениях.\n- Единая точка входа для всех клиентских запросов, реализованная на Spring Cloud Gateway.\n- Создал и поддерживал механизмы аутентификации и авторизации с Keycloak (OAuth2, JWT), в т.ч. стратегию ролей и прав доступа.\n- Сервис-дискавери для динамического взаимодействия между сервисами (Spring Cloud Netflix Eureka).\n- Проектировал и реализовал интеграционные механизмы между микросервисами (REST, Kafka), обеспечив надёжную асинхронную репликацию данных.\n- Реализовал асинхронное взаимодействие между сервисами для обновления данных с помощью Apache Kafka и Debezium (Change Data Capture).\n- Управлял схемами БД и миграциями (PostgreSQL, Liquibase); писал оптимизированные SQL-запросы для аналитики и исправления ошибок.\n- Документировал API с использованием OpenAPI (Swagger).\n- Писал unit и интеграционные тесты (JUnit, Mockito) и автоматизировал сценарии сборки/деплоя.\n- Настроил CI/CD и контейнеризацию (Gradle, Docker, Docker Compose) для локальной и командной разработки.\nСтек:\n- Бэкенд: Java 21, Spring Boot 3, Spring Framework, Spring Data JPA, Spring Security\n- Микросервисы: Microservices Architecture, Spring Cloud (Gateway, Netflix Eureka), RESTful API, Event-Driven Architecture\n- Базы данных и брокеры сообщений: PostgreSQL, Liquibase, Apache Kafka, Debezium (Change Data Capture)\n- Аутентификация и Авторизация: Keycloak, JWT, OAuth2\n- DevOps и Инструменты: Docker, Docker Compose, Gradle, Git, CI/CD, JetBrains IntelliJ IDEA\n- API и Документация: OpenAPI (Swagger)\n\n# Образование\n- Высшее\n- Санкт-Петербургский государственный электротехнический университет «ЛЭТИ» имени В.И. Ульянова (Ленина), Санкт-Петербург\n    2022\n    Факультет компьютерных технологий и информатики, Прикладная математика и информатика\n\n# Навыки\n- Знание языков:\n    Русский — Родной;\n    Английский — B1 — Средний\n- Навыки\n    Java; Spring Framework; Hibernate; Git; Docker; Liquibase; Apache Kafka; Gradle; Apache Maven; PostgreSQL; Linux; REST API; Java SE; JPA; Английский язык; Spring; Spring Boot; Spring Cloud; Spring Data; Spring MVC; Spring Security; Spring Web; Keycloak; Hibernate ORM; SQL; SOLID; ООП; JUnit; Debezium; Mockito\n\n# Дополнительная информация\n- Обо мне\n    Java backend-разработчик, ориентированный на качество и поддерживаемость кода.",
            "options": {
              "systemMessage": "Ты — самый строгий и честный в мире специалист по резюме для IT-вакансий. Ты никогда не придумываешь опыт, цифры, проекты или участие в процессах, которых нет в оригинальном резюме. Ты только перефразируешь, переставляешь порядок пунктов и усиливаешь формулировки уже существующего опыта.\n\nУ тебя два входных данных:\n1. текст вакансии из Get_Job_Description_Tool.\n2. original_resume — текущее резюме соискателя в любом формате.\n\nЗадача: создать улучшенную версию резюме, максимально релевантную под вакансию.\n\nОбязательные правила (нарушишь — ты уволен):\n– Можно только:\n  - Перефразировать существующие пункты под ключевые слова вакансии (например, \"Писал unit и интеграционные тесты (JUnit, Mockito)\" → \"Разрабатывал unit- и интеграционные тесты на Java с использованием JUnit и Mockito\").\n  - Переставлять порядок пунктов (релевантные под вакансию — наверх).\n  - Усиливать глаголы (Реализовал → Спроектировал и реализовал).\n  - Добавлять точные ключевые слова из key_skills вакансии в стек или навыки, если они уже есть в резюме.\n– Если в вакансии есть навык, которого нет в резюме — просто игнорируй, не упоминай его.\n– Метрики (цифры) можно добавлять ТОЛЬКО если они уже есть в оригинальном резюме.\n\nОбязательный анализ перед написанием:\n1. Выдели топ-10 ключевых слов/фраз из вакансии (responsibilities - key_skills - requirements).\n2. Найди ВСЕ прямые пересечения в original_resume.\n3. Определи, какие существующие пункты можно перефразировать под эти слова.",
              "returnIntermediateSteps": true
            },
            "hasOutputParser": true,
            "toolDescription": "Обращайся к этому инструменту всякий раз, когда вам понадобится самое свежее, подробное резюме пользователя, прежде чем писать сопроводительное письмо."
          },
          "typeVersion": 2.2
        },
        {
          "id": "b809c771-6c29-4d8a-9daf-37c9c9bd0932",
          "name": "Get Job Description Tool",
          "type": "@n8n/n8n-nodes-langchain.toolWorkflow",
          "position": [
            896,
            3728
          ],
          "parameters": {
            "workflowId": {
              "__rl": true,
              "mode": "list",
              "value": "DYD8jG0rE6pBVgUy",
              "cachedResultUrl": "/workflow/DYD8jG0rE6pBVgUy",
              "cachedResultName": "Parse job's description"
            },
            "description": "Get Actual Job Description",
            "workflowInputs": {
              "value": {
                "query": "127181485"
              },
              "schema": [
                {
                  "id": "query",
                  "type": "string",
                  "display": true,
                  "removed": false,
                  "required": false,
                  "displayName": "query",
                  "defaultMatch": false,
                  "canBeUsedToMatch": true
                }
              ],
              "mappingMode": "defineBelow",
              "matchingColumns": [],
              "attemptToConvertTypes": false,
              "convertFieldsToString": false
            }
          },
          "typeVersion": 2.2
        },
        {
          "id": "b21cfec1-d28b-46df-82fe-5409b7b5c312",
          "name": "Get Job Description Tool1",
          "type": "@n8n/n8n-nodes-langchain.toolWorkflow",
          "position": [
            656,
            3008
          ],
          "parameters": {
            "workflowId": {
              "__rl": true,
              "mode": "list",
              "value": "DYD8jG0rE6pBVgUy",
              "cachedResultUrl": "/workflow/DYD8jG0rE6pBVgUy",
              "cachedResultName": "Parse job's description"
            },
            "description": "Обращайся к этому инструменту всякий раз, когда вам понадобится самое свежее, подробное описание вакансии, прежде чем писать сопроводительное письмо.",
            "workflowInputs": {
              "value": {
                "query": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('query', `Vacancy id to look up in the job database`, 'string') }}"
              },
              "schema": [
                {
                  "id": "query",
                  "type": "string",
                  "display": true,
                  "removed": false,
                  "required": false,
                  "displayName": "query",
                  "defaultMatch": false,
                  "canBeUsedToMatch": true
                }
              ],
              "mappingMode": "defineBelow",
              "matchingColumns": [],
              "attemptToConvertTypes": false,
              "convertFieldsToString": false
            }
          },
          "typeVersion": 2.2
        },
        {
          "id": "0bea15dd-dbf0-467d-a72c-5fe974abf581",
          "name": "OpenAI Chat Model2",
          "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
          "position": [
            -448,
            3600
          ],
          "parameters": {
            "model": {
              "__rl": true,
              "mode": "list",
              "value": "Qwen3VL-4B-Instruct",
              "cachedResultName": "Qwen3VL-4B-Instruct"
            },
            "options": {}
          },
          "credentials": {
            "openAiApi": {
              "id": "KB5XbkoIGYZV5FeN",
              "name": "OpenAi account"
            }
          },
          "typeVersion": 1.2
        },
        {
          "id": "c3e8b9ea-6cc6-4b68-bdc6-c819b1245fe7",
          "name": "Structured Output Parser",
          "type": "@n8n/n8n-nodes-langchain.outputParserStructured",
          "position": [
            48,
            3360
          ],
          "parameters": {
            "autoFix": true,
            "jsonSchemaExample": "[\n  {\n  \"personal\": {\n    \"fullName\": \"Максим\",\n    \"experience\": \"noExperience\",\n    \"email\": \"\",\n    \"phone\": \"\"\n  },\n  \"summary\": \"Обо мне\",\n  \"work_experience\": [\n    {\n      \"company\": \"MicroRestBank\",\n      \"position\": \"Java-разработчик\",\n      \"period\": \"1 год 4 месяца\",\n      \"achievements\": [\"Спроектировал\", \"Реализовал\"]\n    }\n  ],\n  \"tech_stack\": {\n    \"frameworks\": [],\n    \"security\": [],\n    \"tools\": [],\n    \"architecture\": [],\n    \"other\": []\n  },\n  \"education\": \"\"\n}\n]"
          },
          "typeVersion": 1.3
        }
      ],
      "active": false,
      "pinData": {},
      "settings": {
        "executionOrder": "v1"
      },
      "versionId": "925a5374-5c5e-40be-8c52-a4bd0900e93e",
      "connections": {
        "If": {
          "main": [
            [
              {
                "node": "Get New Vacancies",
                "type": "main",
                "index": 0
              }
            ],
            []
          ]
        },
        "If1": {
          "main": [
            [
              {
                "node": "Delete Points",
                "type": "main",
                "index": 0
              }
            ],
            [
              {
                "node": "Merge2",
                "type": "main",
                "index": 1
              }
            ]
          ]
        },
        "Merge1": {
          "main": [
            [
              {
                "node": "ObjToStrArr",
                "type": "main",
                "index": 0
              }
            ]
          ]
        },
        "Merge2": {
          "main": [
            [
              {
                "node": "Save To Qdrant",
                "type": "main",
                "index": 0
              }
            ]
          ]
        },
        "Merge3": {
          "main": [
            [
              {
                "node": "Loop Over Descriptions",
                "type": "main",
                "index": 0
              }
            ]
          ]
        },
        "AI Agent": {
          "main": [
            [
              {
                "node": "Edit Fields",
                "type": "main",
                "index": 0
              }
            ]
          ]
        },
        "Chunking": {
          "main": [
            [
              {
                "node": "Scroll Points",
                "type": "main",
                "index": 0
              }
            ]
          ]
        },
        "Split Out": {
          "main": [
            [
              {
                "node": "If",
                "type": "main",
                "index": 0
              }
            ]
          ]
        },
        "Split Out1": {
          "main": [
            [
              {
                "node": "Get Vacancy Details",
                "type": "main",
                "index": 0
              }
            ]
          ]
        },
        "Auto-search": {
          "main": [
            [
              {
                "node": "Split Out",
                "type": "main",
                "index": 0
              }
            ]
          ]
        },
        "Edit Fields": {
          "main": [
            [
              {
                "node": "If not enough data",
                "type": "main",
                "index": 0
              }
            ]
          ]
        },
        "Format List": {
          "main": [
            [
              {
                "node": "Send Negogiation",
                "type": "main",
                "index": 0
              }
            ]
          ]
        },
        "ObjToStrArr": {
          "main": [
            [
              {
                "node": "Chunking",
                "type": "main",
                "index": 0
              },
              {
                "node": "Merge3",
                "type": "main",
                "index": 0
              }
            ]
          ]
        },
        "Set Payload": {
          "main": [
            [
              {
                "node": "Merge3",
                "type": "main",
                "index": 1
              }
            ]
          ]
        },
        "Format Error": {
          "main": [
            [
              {
                "node": "Code in JavaScript",
                "type": "main",
                "index": 0
              }
            ]
          ]
        },
        "HTTP Request": {
          "main": [
            [
              {
                "node": "Send a text message",
                "type": "main",
                "index": 0
              }
            ]
          ]
        },
        "Delete Points": {
          "main": [
            [
              {
                "node": "Merge2",
                "type": "main",
                "index": 0
              }
            ]
          ]
        },
        "HTTP Request1": {
          "main": [
            [
              {
                "node": "Remove Duplicates",
                "type": "main",
                "index": 0
              }
            ]
          ]
        },
        "Ollama Health": {
          "main": [
            [
              {
                "node": "Auto-search",
                "type": "main",
                "index": 0
              }
            ]
          ]
        },
        "Scroll Points": {
          "main": [
            [
              {
                "node": "If1",
                "type": "main",
                "index": 0
              }
            ]
          ]
        },
        "Loop Over Jobs": {
          "main": [
            [
              {
                "node": "Merge1",
                "type": "main",
                "index": 1
              }
            ],
            [
              {
                "node": "Code in JavaScript1",
                "type": "main",
                "index": 0
              }
            ]
          ]
        },
        "Save To Qdrant": {
          "main": [
            [
              {
                "node": "Set Payload",
                "type": "main",
                "index": 0
              }
            ]
          ]
        },
        "Token Splitter": {
          "ai_textSplitter": [
            [
              {
                "node": "Load Content/Metadata",
                "type": "ai_textSplitter",
                "index": 0
              }
            ]
          ]
        },
        "Get User Resume": {
          "ai_tool": [
            [
              {
                "node": "AI Agent",
                "type": "ai_tool",
                "index": 0
              }
            ]
          ]
        },
        "Actual Job Tool1": {
          "ai_tool": [
            []
          ]
        },
        "Schedule Trigger": {
          "main": [
            [
              {
                "node": "Ollama Health",
                "type": "main",
                "index": 0
              }
            ]
          ]
        },
        "Sections cleanup": {
          "main": [
            [
              {
                "node": "Loop Over Jobs",
                "type": "main",
                "index": 0
              }
            ]
          ]
        },
        "Send Negogiation": {
          "main": [
            [
              {
                "node": "Code in JavaScript",
                "type": "main",
                "index": 0
              }
            ],
            [
              {
                "node": "Format Error",
                "type": "main",
                "index": 0
              }
            ]
          ]
        },
        "Embeddings OpenAI": {
          "ai_embedding": [
            []
          ]
        },
        "Get New Vacancies": {
          "main": [
            [
              {
                "node": "Split Out1",
                "type": "main",
                "index": 0
              }
            ]
          ]
        },
        "OpenAI Chat Model": {
          "ai_languageModel": [
            []
          ]
        },
        "Remove Duplicates": {
          "main": [
            [
              {
                "node": "Payload Extraction",
                "type": "main",
                "index": 0
              }
            ]
          ]
        },
        "Resume Agent Tool": {
          "ai_tool": [
            [
              {
                "node": "AI Agent1",
                "type": "ai_tool",
                "index": 0
              }
            ]
          ]
        },
        "qwen3-embedd-save": {
          "ai_embedding": [
            [
              {
                "node": "Save To Qdrant",
                "type": "ai_embedding",
                "index": 0
              }
            ]
          ]
        },
        "Code in JavaScript": {
          "main": [
            [
              {
                "node": "HTTP Request",
                "type": "main",
                "index": 0
              }
            ]
          ]
        },
        "Delete Collection1": {
          "main": [
            [
              {
                "node": "Create Collection",
                "type": "main",
                "index": 0
              }
            ]
          ]
        },
        "If not enough data": {
          "main": [
            [
              {
                "node": "Format List",
                "type": "main",
                "index": 0
              }
            ],
            [
              {
                "node": "Loop Over Descriptions",
                "type": "main",
                "index": 0
              }
            ]
          ]
        },
        "OpenAI Chat Model1": {
          "ai_languageModel": [
            []
          ]
        },
        "OpenAI Chat Model2": {
          "ai_languageModel": [
            [
              {
                "node": "AI Agent1",
                "type": "ai_languageModel",
                "index": 0
              },
              {
                "node": "Resume Agent Tool",
                "type": "ai_languageModel",
                "index": 0
              },
              {
                "node": "Structured Output Parser",
                "type": "ai_languageModel",
                "index": 0
              }
            ]
          ]
        },
        "Payload Extraction": {
          "main": [
            [
              {
                "node": "Loop Over Jobs",
                "type": "main",
                "index": 0
              },
              {
                "node": "Merge1",
                "type": "main",
                "index": 0
              }
            ]
          ]
        },
        "Code in JavaScript1": {
          "main": [
            [
              {
                "node": "Information Extractor",
                "type": "main",
                "index": 0
              }
            ]
          ]
        },
        "Get Job Description": {
          "ai_tool": [
            [
              {
                "node": "Get User Resume",
                "type": "ai_tool",
                "index": 0
              },
              {
                "node": "AI Agent",
                "type": "ai_tool",
                "index": 0
              }
            ]
          ]
        },
        "Get Vacancy Details": {
          "main": [
            [
              {
                "node": "Remove Duplicates",
                "type": "main",
                "index": 0
              }
            ]
          ]
        },
        "Send a text message": {
          "main": [
            [
              {
                "node": "Loop Over Descriptions",
                "type": "main",
                "index": 0
              }
            ]
          ]
        },
        "Information Extractor": {
          "main": [
            [
              {
                "node": "Sections cleanup",
                "type": "main",
                "index": 0
              }
            ]
          ]
        },
        "Load Content/Metadata": {
          "ai_document": [
            [
              {
                "node": "Save To Qdrant",
                "type": "ai_document",
                "index": 0
              }
            ]
          ]
        },
        "Loop Over Descriptions": {
          "main": [
            [],
            [
              {
                "node": "AI Agent",
                "type": "main",
                "index": 0
              }
            ]
          ]
        },
        "qwen3:4b:it:q8-extract": {
          "ai_languageModel": [
            [
              {
                "node": "Information Extractor",
                "type": "ai_languageModel",
                "index": 0
              }
            ]
          ]
        },
        "qwen3:4b:it:q8-generate": {
          "ai_languageModel": [
            [
              {
                "node": "AI Agent",
                "type": "ai_languageModel",
                "index": 0
              }
            ]
          ]
        },
        "Get Job Description Tool": {
          "ai_tool": [
            [
              {
                "node": "Resume Agent Tool",
                "type": "ai_tool",
                "index": 0
              },
              {
                "node": "AI Agent1",
                "type": "ai_tool",
                "index": 0
              }
            ]
          ]
        },
        "Structured Output Parser": {
          "ai_outputParser": [
            [
              {
                "node": "Resume Agent Tool",
                "type": "ai_outputParser",
                "index": 0
              }
            ]
          ]
        },
        "qwen3:4b:it:q8-generate1": {
          "ai_languageModel": [
            [
              {
                "node": "Get User Resume",
                "type": "ai_languageModel",
                "index": 0
              }
            ]
          ]
        },
        "Get Job Description Tool1": {
          "ai_tool": [
            []
          ]
        },
        "When chat message received": {
          "main": [
            [
              {
                "node": "AI Agent1",
                "type": "main",
                "index": 0
              }
            ]
          ]
        },
        "When clicking ‘Execute workflow’": {
          "main": [
            [
              {
                "node": "Delete Collection1",
                "type": "main",
                "index": 0
              }
            ]
          ]
        }
      }
    }