Русский · English
A Telegram bot that automates job search and applications on hh.ru with LLM-based relevance scoring and auto-generated cover letters.
- Search vacancies via configurable filters using browser automation (Playwright).
- Score each vacancy via any OpenAI-compatible LLM (Groq, DeepSeek, OpenRouter, Z.AI, Together, OpenAI, local Ollama, etc.).
- Route by score:
- 80+ → automatic apply with auto-generated cover letter.
- 50–79 → sent to Telegram for manual decision (buttons: «Apply / Skip / Open on hh.ru»).
- < 50 → auto-skip.
- Autopilot: background search loop every 30 minutes + summary every 2 hours.
- Company blacklist (whole-word match) and «remote-only» filter.
Using automation on hh.ru may violate the user agreement and result in account suspension. Use at your own risk. The bot is a pet project for a single user — multi-tenant deploy is not intended and the code has not undergone legal review.
- Python 3.10+ (requires
Browser | Nonesyntax) aiogram 3.x— Telegram botplaywright— hh.ru browser automationhttpx[socks]— HTTP client with SOCKS5 proxy supportpython-dotenv— configsqlite3(Python stdlib) — storage
git clone https://github.com/<YOUR_USERNAME>/hh-bot.git
cd hh-bot
python -m venv .venv
# Windows:
.venv\Scripts\activate
# macOS/Linux:
source .venv/bin/activate
pip install -r requirements.txt
playwright install chromium
playwright install msedge # for interactive login — visible Edge windowCopy .env.example to .env and fill in values:
cp .env.example .envTELEGRAM_BOT_TOKEN=... # get from @BotFather
TELEGRAM_ADMIN_ID=... # your Telegram user_id (ask @userinfobot)
HH_LOGIN=+79001234567 # phone number for hh.ru
LLM_BASE_URL=https://api.groq.com/openai/v1
LLM_API_KEY=...
LLM_MODEL=llama-3.3-70b-versatile
RESUME_FILE=resume.txt
Place resume.txt in the project root — a plain-text file with your
résumé. The bot uses it as candidate context when scoring vacancies and
generating cover letters.
Any provider with an OpenAI-compatible Chat Completions API is
supported. Examples in .env.example. Easiest is Groq (free tier):
- Sign up at https://console.groq.com
- Create an API key
- Set
LLM_API_KEY
If your LLM provider is blocked on your network:
LLM_PROXY=socks5://user:pass@host:port
python main.pyOn first run the bot will prompt for authorization. In Telegram, send:
/login
A visible Edge browser window will open — log in to hh.ru manually (captcha, SMS, whatever). The bot will pick up the session and switch to headless mode.
| Command | What it does |
|---|---|
/start |
Status, command list |
/login |
Open the browser for interactive hh.ru login |
/addfilter |
Add a search filter (title, keywords, city, salary, experience) |
/filters |
List active filters |
/search |
Run a manual search across all filters |
/autopilot |
Trigger one autopilot cycle manually |
/recheck |
Re-score un-scored vacancies |
/stats |
Application statistics |
hh-bot/
├── main.py # Entry point: bot + autopilot
├── config.py # Config from .env
├── ai/
│ ├── llm_client.py # Universal OpenAI-compatible client
│ ├── analyzer.py # Vacancy relevance scoring
│ └── cover_letter.py # Cover letter generation
├── bot/
│ ├── handlers.py # Telegram commands and callbacks
│ ├── autopilot.py # Background search loop
│ └── keyboards.py # Inline keyboards
├── parser/
│ └── hh_client.py # Playwright client for hh.ru
└── db/
├── models.py # SQLite schema (vacancies, responses, filters, logs)
└── storage.py # CRUD
- Access to all commands is restricted by
TELEGRAM_ADMIN_ID— the bot is single-user. - hh.ru cookies are stored in
hh_cookies.json(in.gitignore). - Vacancy descriptions are isolated with markers in the LLM prompt — partial protection against prompt injection via vacancy text.
- All secrets via
.env, nothing is hardcoded.
- hh.ru selectors are hardcoded — UI redesigns may require updates
to
parser/hh_client.py. - City grid in
_resolve_areacovers only the 15 largest cities. Others are searched without region filter (with a warning in logs). - DB is sync —
sqlite3blocks the event loop at large volumes. For a single user this is fine. - No tests on business logic.
PolyForm Noncommercial License 1.0.0 — full text in LICENSE.
In short:
- Allowed: read the code, clone, fork, study, experiment, use for personal non-commercial purposes, in coursework and research, in hobby projects.
- Allowed for organizations: charitable, educational, research, government, healthcare, environmental.
- Not allowed: using the code in commercial products, reselling, building paid services or features on it, monetizing in any way.
- On distribution: preserve the license text and the author's copyright.
If you need commercial use — contact me for a separate commercial license.