Local LLM resume pipeline. Resumes are read from a Google Drive folder or a local path / Drive file id via CLI.
| Step | Action | Module |
|---|---|---|
| 1 | Download resume, extract CandidateProfile (pypdf / vision) |
graph.py → llm.py |
| 2 | Duplicate check by email | graph.py → memory.py |
| 3 | Summarize + fit assessment (agentic branch) | graph.py → llm.py → telegram_tools.py |
| 4 | Log to Google Sheets (approved / rejected + reason) |
graph.py → google_tools.py |
| 5 | Find calendar slot (14:00 or 16:00 weekdays, 1 hour each) | graph.py → google_tools.py |
| 6 | Telegram approval (LangGraph interrupt) | graph.py → telegram_tools.py → memory.py |
| 7 | Create Google Calendar event | graph.py → google_tools.py |
| 8 | Draft Gmail invite (local Qwen, never auto-send) | graph.py → llm.py → google_tools.py |
| 9 | Update sheet (interview scheduled) |
graph.py → google_tools.py + memory.py |
| 10 | SQLite memory + Telegram chatbot Q&A | memory.py + telegram_tools.py |
All LLM calls go through llm.call_llm only.
| Key | Purpose |
|---|---|
DRIVE_FOLDER_ID |
Drive folder watched for new resumes |
GOOGLE_SA_KEY |
Path to service account JSON |
SHEET_ID |
Google Sheet id for candidate ledger |
CALENDAR_ID |
Calendar id for free/busy and events |
TELEGRAM_BOT_TOKEN |
BotFather token |
TELEGRAM_CHAT_ID |
Target chat/group id |
MODEL_NAME |
Ollama text model (Qwen) |
VISION_MODEL |
Ollama vision model (llama3.2-vision) |
INTERVIEWER_NAME |
Shown in calendar/email |
INTERVIEWER_EMAIL |
Organizer email |
TIMEZONE |
Required for correct slot times — IANA name matching your Google Calendar (e.g. Asia/Tehran, Europe/Amsterdam) |
POLL_INTERVAL |
Drive poll seconds (default 60) |
MEMORY_DB |
SQLite path (default ./data/memory.db) |
OLLAMA_KEEP_ALIVE |
Keep model loaded between calls (default 30m) |
Share the Drive folder, Sheet, and Calendar with the service account email (Calendar needs Make changes to events).
Calendar events are created without attendee invites by default — service accounts cannot send invites on personal Gmail without Google Workspace domain-wide delegation. Candidate contact info is stored in the event description; the Gmail draft step covers the actual invite.
Optional: set CALENDAR_USE_ATTENDEES=true only if you have Workspace domain-wide delegation configured.
pip install -r requirements.txt
ollama pull qwen2.5:7b
ollama pull llama3.2-visionPlace your service account JSON at ./secrets/service-account.json (or set GOOGLE_SA_KEY).
# Watch the Drive folder (default)
python main.py
# Verbose logging — each pipeline step is logged as STEP 1..9
python main.py -v
# Process one Drive file id or local path
python main.py 1abcDriveFileIdHere -v
python main.py C:\path\to\resume.pdf -v
# Console-only (no Telegram bot thread)
python main.py --no-bot C:\path\to\resume.pdf -vEach resume logs steps like STEP 1: read_resume, STEP 2: dup_check, … through STEP 9.
Text-native PDFs use Qwen for structured extraction; scanned/image PDFs and image files use llama3.2-vision first, then Qwen for JSON.
- Fit summaries are posted automatically.
- After slot-finding, the bot asks Schedule {name} for {slot}? with Yes/No buttons (or reply
yes/no). - Free-text questions (
who did we add today?,reschedule Jane Doe) use memory + Sheet data viacall_llm.
email | name | current_role | years_experience | skills | status | reason | slot | event_id | processed_at
Status values: rejected (with reason), approved, declined, interview scheduled.