career_monitor
# HH Career Monitor
Монитор вакансий HH.ru с уведомлениями в Telegram и анализом по кнопке через Mistral API. Дополнительно: MCP-инструменты для DeepSeek Harness — чтение вакансий, текстовых PDF и управление монитором.
**Статус: экспериментальный pet-проект для Windows.** Уведомления не зависят от оценки нейросети: каждая новая вакансия из выбранной выдачи попадает в Telegram. Модель вызывается только по кнопке. Автоматических откликов работодателям нет.
## Что делает
- Проверяет сохранённую выдачу каждые 15 минут, включая пагинацию.
- На первом запуске запоминает существующие ID без рассылки старых вакансий.
- Хранит очередь уведомлений и историю на диске; повторная проверка не рассылает те же ID.
- Принимает кнопку анализа только от владельца настроенного личного Telegram-чата.
- Отправляет текст вакансии и краткий профиль кандидата в Mistral: возвращает название, ссылку, короткий вывод и, при положительном выводе, черновик письма.
- Читает локальные PDF по страницам без загрузки документа во внешний сервис. OCR не реализован.
- Хранит API-ключи через Windows DPAPI, отдельно от кода и промптов.
## Как устроено
```mermaid
flowchart LR
HH[Выдача HH] --> Browser[Playwright / Chromium]
Browser --> Queue[Новые ID и очередь на диске]
Queue --> TG[Telegram: название и ссылка]
TG -->|Кнопка владельца| Job[Очередь анализа]
Profile[Локальный профиль] --> Job
Job --> Mistral[Mistral API]
Mistral --> Result[Вывод и условное письмо в Telegram]
Harness[DeepSeek Harness / MCP] --> Browser
Harness --> PDF[Локальный PDF → текст]
```
Модель не управляет расписанием и не решает, отправлять ли уведомление. Один процесс монитора использует отдельный постоянный профиль браузера HH. Telegram, Chromium и Mistral работают на компьютере пользователя; отдельного сервера нет.
## Требования
- Windows 10/11, Node.js 22+, npm, Windows PowerShell 5.1.
- Интернет, отдельный Telegram-бот и личный чат с ним.
- Ключ Mistral — только для анализа, мониторинг работает без него.
- Для PDF: Python 3.10+ и зависимости из `requirements.txt`.
- Для режима пресета: установленный DeepSeek Harness с `dsh-persona` и `dsh-mcp-client`.
Цены, доступность моделей и бесплатные лимиты определяет провайдер. Проект не обещает бесплатный безлимит и не включает платный тариф автоматически.
## Установка
```powershell
git clone https://github.com/oziksman/hh-career-monitor.git
cd hh-career-monitor
npm ci
npx playwright install chromium
npm run init
# Необязательно, для PDF:
python -m pip install -r requirements.txt
```
`init` создаёт личные настройки в `src/` и пресет в `.local/career-review/`. Существующие настройки не перезаписываются. Эти файлы исключены из Git. Если перемещаете папку проекта, повторите `npm run init` и заново скопируйте пресет.
1. В `src/monitor-config.json` укажите свою ссылку поиска HH. Начните с `enabled: false`.
2. Заполните `src/profile-summary.txt`: подтверждённый опыт, образование, языки, условия работы. Именно этот файл отправляется в Mistral. Не добавляйте паспорт, телефон, адрес и секреты.
3. `src/profile.txt` — более подробный профиль для локального инструмента `read_profile`; используйте заголовки ПРОФИЛЬ, ОПЫТ, ОГРАНИЧЕНИЯ. Он не отправляется в Mistral автоматически.
## Telegram и Mistral
Создайте отдельного бота через [BotFather](https://t.me/BotFather), откройте его личный чат и отправьте `/start`. Затем в PowerShell:
```powershell
& .\src\setup-telegram.ps1
```
Введите токен в скрытое поле. Выбирайте **номер пункта меню**, а не числовой chat ID. Скрипт отправит тестовое сообщение. На время настройки остановите другие процессы этого бота: один бот должен иметь только одного обработчика `getUpdates`, без webhook.
Для анализа:
```powershell
& .\src\setup-mistral.ps1 -Model ministral-14b-2512
```
Скрипт проверяет ключ коротким запросом, затем сохраняет его и выбранную модель. Поддерживается также `mistral-small-latest`; доступность зависит от аккаунта. При HTTP 429 изучите квоту и ограничение конкретной модели. Автоматического переключения на платную модель нет. Не меняйте execution policy всей системы ради установки; используйте разрешённый в своей среде способ запуска локальных скриптов.
## Запуск без Harness
```powershell
npm run console
```
В открытой консоли последовательно введите:
```text
login
```
В открывшемся Chromium вручную войдите в HH, убедитесь, что нужная выдача доступна. Затем в консоли:
```text
login_done
start
status
```
Команды: `status`, `start`, `stop`, `check`, `login`, `login_done`, `quit`. `check` запускает проверку в фоне; её результат смотрите повторным `status`. Оставьте процесс запущенным. `quit` завершает процесс; `stop` выключает расписание поиска, но обработчик уже имеющихся кнопок Telegram остаётся активным до выхода.
## Подключение к DeepSeek Harness
Используйте **один** способ запуска: консоль или MCP внутри Harness, иначе второй процесс получит ошибку блокировки.
Скопируйте два сгенерированных файла в новый каталог пресета. Существующий Career Review не перезаписывайте без резервной копии:
```powershell
$presetPath = Join-Path $env:USERPROFILE '.dsh/.agent-presets/hh-career-monitor'
New-Item -ItemType Directory -Path $presetPath -Force
Copy-Item .\.local\career-review\preset.yml $presetPath
Copy-Item .\.local\career-review\agent.cordis.yml $presetPath
dsh web
```
При нестандартном `DSH_HOME` используйте соответствующий каталог. Выберите пресет **Career Review**. Модель чата может быть локальной; анализ Telegram использует отдельный Mistral API.
Примеры запросов в чат:
```text
Вызови mcp__career_monitor__monitor с action="login".
Я вошёл в HH. Вызови action="login_done".
Запусти монитор: action="start".
Покажи полный результат action="status" без предположений.
```
После изменения кода перезапустите процесс целиком. Обновление страницы браузера не перезапускает MCP.
## Проверка состояния
Из другой консоли в каталоге проекта:
```powershell
npm run status
```
Команда читает heartbeat и время последнего успеха; не создаёт второй монитор и не отправляет сообщений. `running: false` означает отсутствие текущей операции, а не остановленное расписание.
| Статус | Значение |
| --- | --- |
| `waiting_for_next_check` | Включён, ожидает очередной проверки |
| `busy` | Выполняет проверку или анализ |
| `waiting_for_login` | Открыто окно ручного входа |
| `stale` | Успешных проверок не было более двух интервалов |
| `heartbeat_stale` | Процесс существует, но heartbeat устарел |
| `process_not_running` | Процесс из heartbeat не найден |
| `error` | Зафиксирована ошибка проверки |
| `disabled` | Расписание выключено |
Есть отдельные поля `analysisError`, `pendingErrors` (в MCP/консольном status) и `lastError`. Само наличие процесса или `enabled: true` не доказывает работоспособность. Heartbeat не является watchdog и не перезапускает зависший процесс.
## Пример результата
Условный пример формата, не настоящая вакансия или оценка:
```text
Аналитик отчётности
https://hh.ru/vacancy/<ID>
Вывод: Скорее подходит. Задачи по Excel и отчётности соответствуют
подтверждённому опыту. Условия работы из другой страны нужно уточнить.
Сопроводительное письмо:
Здравствуйте! Меня заинтересовала ваша вакансия. В предыдущей работе
я готовил регулярную отчётность и автоматизировал обработку данных...
```
## Ограничения и наблюдения
- LLM может выдумать требования, перепутать зарплатные ориентиры или слишком строго отклонить смежную роль. Промпт уменьшает эти ошибки, но не исключает их. Решение об отклике принимает человек.
- HH может запросить CAPTCHA/повторный вход или изменить разметку. Защита не обходится. Соблюдайте правила сайта; проект не является официальной интеграцией HH.
- ПК должен работать и не спать. После простоя вакансии могут исчезнуть из суточной выдачи. Полного восстановления пропущенных публикаций нет.
- В исходном локальном использовании наблюдалась остановка успешных проверок при живом процессе. Причина не установлена; публичная версия добавляет диагностику, но не заявляет, что устранила зависание.
- При сбое между отправкой сообщения и сохранением состояния возможны дубли. Exactly-once доставка не гарантируется.
- Анализ выполняется последовательно. Во время длинного анализа новые нажатия могут обрабатываться с задержкой. Повторное нажатие для уже обработанной вакансии не генерирует новый ответ.
- До 10 страниц выдачи и 20 уведомлений за проверку по умолчанию. При неполной выдаче первоначальная база не сохраняется. Лимиты доступны в конфигурации.
- Проверки тестами не требуют живых ключей и не доказывают доступность внешних сервисов. Публичная переносимая сборка требует отдельной проверки на чистой машине.
## Разработка
```powershell
npm run check
npm test
```
Тесты проверяют очередь при ошибке доставки, дедупликацию, авторизацию кнопки и интерпретацию статусов. CI выполняет их на Windows. Полезные настройки окружения: `CAREER_BROWSER_PATH` (свой Chrome), `CAREER_PYTHON` (Python для PDF), `CAREER_POWERSHELL` (PowerShell). По умолчанию используются Chromium Playwright, `python` и `powershell.exe`.
Код в `src/`, настройка пресета в `scripts/init.cjs`, шаблоны в `examples/`. Локальные конфиги, профили браузеров, ключи DPAPI и результаты анализа не должны попадать в Git. Подробности — [SECURITY.md](SECURITY.md).
Проект развивается с использованием AI-инструментов. Лицензия исходного кода — [MIT](LICENSE); зависимости имеют собственные лицензии.
TDQS
Scored across 1 tool
Only one tool exists, so there is no possibility of ambiguity or overlap between tools. The single 'monitor' tool clearly bundles all control actions, making selection trivial.
With a single tool, there are no naming conventions to compare or contradict. The name 'monitor' is a simple verb that broadly reflects its purpose, though it is somewhat vague, consistency is perfect.
A single tool for a niche monitoring purpose is borderline; it works but feels thin for the variety of actions (start, stop, login, etc.) it claims to handle. The server could benefit from separating concerns into distinct tools, but the count is not extreme.
The tool covers the main lifecycle actions (start, stop, check, login), but lacks configuration options such as customizing the search query or notification filters. It also depends on external setup, leaving gaps that could cause agent failures when specific monitoring needs arise.