Борьба с рутиной при написании сопроводительных писем с использованием Python
Всем привет!
Не секрет, что сейчас очень сложно устроиться Python backend разработчиком. 1000 и более откликов на одну вакансию уже стало нормой. Не от 2000 как на тестировщика, но тем не менее.
Сейчас уже мало на отлично знать сам Python (в том числе ООП, итераторы/генераторы и прочее), базы данных, фреймворки Django или FastAPI, Docker, git и много чего еще. Требования к кандидатам становятся все более высокими.
Пет проектов на гитхабе уже мало, нужен коммерческий опыт от 1 года (и ни в коем случае не фриланс). Проекты обучающих курсов уже примелькались и есть подозрение, что hr уже просто на автомате увидев один из таких — скипает анкету.
И даже если это всё есть, то можно попасть под фильтр «высшее IT образование» и\или «возраст до 30 лет».
Всё это всем известно, и только некоторые чиновники и курсы по обучению программированию рассказывают про «дефицит айтишников 700_000 человек».
Претендентов на вакансии стало настолько много, что включается еще один фильтр — Сопроводительное письмо. Без которого твой отклик скорее всего потеряется среди сотен\тысяч других. Потому что конкуренция.
После очередного получасового написания одного сопроводительного письма, которое скорее всего даже не прочтут, я решил сократить время его написания.
Здесь подразумевается, что сопроводительное письмо должно не просто дублировать резюме, а подсвечивать мэтчи по скиллам — мои сильные навыки, которые могут пригодиться компании и актуальны для конкретной позиции, показывать мою заинтересованность работы именно в данной компании.
«Как писать сопроводительные письма» — гуглится на раз, общее у них: приветствие, совпадения по скиллам, мотивационный абзац, завершение (с указанием контактов).
Вот пример такого (сгенерировано нейросетью) :
Уважаемый [Имя контактного лица],
Меня зовут [Ваше имя], и я обращаюсь к вам с заявкой на позицию [название вакансии] в вашей компании [название компании]. Я уверен, что мои навыки и опыт в [указать конкретные навыки и опыт], а также моя страсть к [указать интересы или цели], делают меня идеальным кандидатом для этой роли.
В моем последнем опыте работы в [название компании/проекта], я успешно [указать конкретные достижения или проекты], что позволило мне развить [указать навыки или качества, которые пригодятся в новой роли]. Я уверен, что могу принести ценный вклад в вашу команду и помочь достичь [указать конкретные цели или задачи компании].
Я был бы рад обсудить, как я могу внести свой вклад в [название компании] и узнать больше о возможностях, которые вы предлагаете. Спасибо за рассмотрение моей кандидатуры.
С уважением,
[Ваше имя]
Ключевые блоки здесь:
Приветствие: Адресовано конкретному лицу или отделу, что делает письмо более персонализированным.
Введение: Краткое представление себя и указание на позицию, на которую вы подаете заявку.
Основная часть: Описание вашего опыта и навыков, а также того, как вы можете принести пользу компании.
Заключение: Выражение желания обсудить работу и благодарность за рассмотрение вашей кандидатуры.
Эти общие моменты можно хотя бы частично автоматизировать.
Задача ясна, необходимые навыки имеются)
Сначала написал простой парсер с основных агрегаторов вакансий (Хабр, hh) + возможностью прогнать оффлайн вакансию (скопировав туда текст с других ресурсов).
Затем сделал анализ текста на скиллы, которые вставляются в заранее подготовленный шаблон; текст вакансии и компании скармливается нейросети (используется g4f) для генерации мотивационного абзаца.
И получается текстовый файл, в котором необходимые пункты уже стоят на своих местах. Остается только немного его подредактировать и вставить в поле отклика на вакансию.
Всё максимально просто: никаких баз данных, развернутых на сервере докер контейнеров. Ссылка на вакансию вставляется в env файл (там же хранятся другие настройки), скрипт запускается с локального компа, результат сохраняется в текстовом файле — чтобы было удобно редактировать в Notepad++.
Стек: Python 3.11, requests, BeautifulSoup, asyncio, loguru, g4f
Структура проекта:
jobanyway/│
├── env/ # Виртуальное окружение для изоляции зависимостей проекта
├── logs/ # Логи приложения
├── output_files/ # Итоговые txt файлы с сопроводительными письмами, созданными приложением
├── .env # Файл с переменными окружения и личными настройками
├── .gitignore # Исключение файлов и каталогов из системы контроля версий Git
├── README.md # Описание проекта, его установки и использования
├── aggregators.py # Модуль парсинга и обработки провайдеров вакансий (Habr, HH, оффлайн вакансия)
├── main.py # Главный файл приложения
├── main_g4f.py # Генерация текста AI с помощью g4f
├── requirements.txt # Список зависимостей Python для установки через pip
├── requirements_without_g4f.txt # Список зависимостей без g4f
├── settings.py # Настройки приложения
├── simple_vacancy.txt # Простой текстовый файл с оффлайн вакансией
└── templates.py # Файл для работы с шаблонами
Основной файл (main.py) :
Vacancy: Класс, представляющий вакансию. Содержит информацию о вакансии, такую как URL, должность, название компании, текст о компании, зарплата и необходимые навыки. Класс также включает в себя методы для парсинга вакансии в зависимости от провайдера, сравнения навыков вакансии с навыками резюме пользователя.
MyResume: Класс, представляющий резюме пользователя. Содержит информацию о резюме, такую как имя, навыки, ссылка на GitHub и URL файла резюме. Данные берутся из env файла.
CoverLetter: Класс, представляющий сопроводительное письмо для вакансии. Содержит текст письма, путь к файлу письма и методы для создания письма, сохранения его в файл и открытия в локальном текстовом редакторе.
Эти классы используются для обработки информации о вакансиях и резюме пользователя, а также для генерации и сохранения сопроводительных писем.
Парсинг и обработка вакансий различных агрегаторов (aggregators.py) :
Aggregator: Абстрактный базовый класс (ABC) для агрегаторов вакансий. Он определяет общую структуру для всех агрегаторов, включая методы для получения HTML-кода страницы вакансии (`get_soup`) и абстрактный метод для парсинга информации о вакансии (`parse_vacancy`).
HHru: Класс, который наследуется от `Aggregator`, для парсинга информации о вакансиях с сайта «hh.ru». Он переопределяет метод `parse_vacancy`, чтобы извлекать информацию о вакансии, включая навыки, позицию, название компании, текст о компании и зарплату.
Habr: Класс, также наследующийся от `Aggregator`, для парсинга информации о вакансиях с сайта «habr.com». Он также переопределяет метод `parse_vacancy` для извлечения информации о вакансии.
OfflineAggregator: Класс, который также наследует от `Aggregator`, для парсинга информации о вакансии из локального файла. Это может быть полезно если вакансия из других источников, для тестирования или разработки, когда доступ к интернету ограничен или недоступен.
get_text_from_soup: Функция, которая принимает объект BeautifulSoup и имя тега, а также словарь атрибутов, и возвращает текст найденного элемента или `None`, если элемент не найден.
Эти классы и функции используются для извлечения и обработки информации о вакансиях с различных источников.
Файл с шаблонами templates.py
get_letter_from_base_template
Функция принимает словарь, содержащий информацию о вакансии, навыки кандидата и текст, сгенерированный ИИ.
Затем формирует сопроводительное письмо с использованием f-строки, включая имя кандидата и его контакты (извлекаются из переменных окружения), должность вакансии, совпадающие навыки и текст, сгенерированный ИИ.
Если включена настройка INCLUDE_REQUEST_TEXT_TO_RESULT в BASE_SETTINGS, то добавляется исходный текст, использованный для генерации текста ИИ. Возвращает получившуюся строку.
get_text_from_template
Функция принимает строку и возвращает промт для генерации текста нейронной сетью на основе предоставленного шаблона.
Файл settings.py с настройками поведения программы и константами, которые используются в процессе работы программы.
DIR_SETTINGS: Пути к различным директориям и файлам, которые используются в программе. Например, «OFFLINE_VACATION_PATH» по умолчанию указывает на файл simple_vacancy.txt, который содержит данные о вакансии для оффлайн обработки.
«TEXT_EDITOR_PATH» указывает на исполняемый файл текстового редактора (по умолчанию Notepad++).
«SAVE_LOCATION_DIR» и «LOGS_DIR» определяют директории для сохранения выходных файлов и логов соответственно.
BASE_SETTINGS: Логические флаги и уровень логирования, которые контролируют поведение программы.
Например, «OPEN_LOCAL_COVER_LETTER» и «INCLUDE_REQUEST_TEXT_TO_RESULT» определяют, открывать ли локальное письмо с приложением и включать ли текст исходного запроса к ИИ в итоговое письмо.
«RUN_PARSE_OFFLINE_VACATION» включает анализ оффлайн вакансии.
«LOG_LEVEL» устанавливает уровень логирования, а «SAVE_LOG_FILES» определяет, сохранять ли файлы логов.
WORDS_FOR_REPLACE: Используется для замены ключевых слов на их стандартные эквиваленты, например, «django framework» заменяется на «Django».
RESERVED_WORDS: Этот словарь содержит слова, которые должны быть обработаны особым образом, например, «ООП» заменяется на «с использованием ООП».
G4f взял в качестве генерации текста ИИ потому что он 1. бесплатный, 2. не требует ключей для доступа. Но можно использовать любой другой сервис (копипастом промта из готового файла письма).
Преимущества использования AI для написания мотивационной части:
Автоматизация: Экономит время и усилия кандидата (информация о вакансии и компании программой собирается и подставляется в промт для нейросети автоматически).
Персонализация: С помощью AI можно создавать письма, которые более точно соответствуют конкретной вакансии и компании, что может увеличить шансы на успешное прохождение начальных фильтров. НО см. пункт 1 в недостатках.
Обработка больших объемов данных: AI способен анализировать большие объемы данных, что может помочь в выявлении ключевых слов и фраз по заранее грамотно подготовленному промту (например, если текст «О компании» на несколько А4 листов).
Недостатки:
Отсутствие индивидуальности: Использование AI может привести к созданию писем, которые кажутся слишком стандартизированными или автоматизированными, что может негативно сказаться на восприятии кандидата работодателем.
Риск автоматизации слишком часто используемых фраз: AI может неверно интерпретировать данные и включить в письмо фразы, которые уже были широко использованы и могут показаться работодателю неоригинальными или лишними.
Отсутствие эмоциональной составляющей: Сопроводительные письма часто требуют демонстрации личных качеств и мотивации, что может быть сложно передать с помощью AI без дополнительной ручной коррекции или настройки через параметры.
То есть AI является инструментом, который может улучшить процесс написания сопроводительных писем, но не отменяет необходимость тщательного и индивидуального подхода.
Можно использовать сгенерированный AI текст как отправную точку, но затем добавлять свои личные детали и уникальные причины, почему вы хотите работать именно в этой компании.
В итоге сейчас составление сопроводительного письма занимает намного меньше времени и получаешь меньше дизморали когда потенциальный работодатель его даже не читает.
Инструкция как устанавливать и пользоваться в readme файле на гитхабе — https://github.com/zrivkoren/jobanyway
Да, это не полностью автоматизированное решение, потому что по прежнему приходится:
находить подходящую вакансию,
вставлять в программу ссылку на нее,
запускать,
редактировать итоговый текстовый файл,
нажимать в вакансии на Откликнуться, вставлять в поле «Сопроводительное письмо» содержимое текстового файла.
НО здесь решается много рутинных задач:
приветственный и завершающий тексты практически всегда одни и те же (один раз придумал шаблон и потом скрипт сам вставляет в нужные месте),
в приветствии уже стоит позиция вакансии, на которую претендует соискатель (тут место для шутки от hr),
все блоки в письме уже на своем месте, не нужно каждый раз передвигать текст,
уже произведено сравнение скиллов на предмет совпадения (и если их совсем уж мало, то стоит ли вообще откликаться?),
для блока с мотивацией парсится не только сама вакансия, но и информации об организации (не нужно отдельно лезть туда чтобы написать подходящий индивидуальный мотивационный текст),
сгенерированный нейросетью текст дает направление для написания блока с мотивацией,
при использовании сторонних ИИ (тот же chatgpt, например), можно будет вставить готовый промт (на основе сделанного шаблона),
шаблоны можно по необходимости править (всё лежит в одном месте),
в конце файла указаны данные: организация, должность, зарплата (это удобно если в дальнейшем понадобится данная информация)
Цели создать универсальную кнопку «Устрой меня на идеальную работу» не стояло, но вот оптимизировать процесс написания сопроводительного письма, и тем самым ускорить трудоустройство, на мой взгляд вполне получилось.
P.s. Я открыт к предложениям и доступен в телеграме: @zrivkoren1