""" candidate.py — the board-agnostic candidate model (used by every adapter). = parsed résumé (source of truth) + confirmed facts not on the résumé (the "answer bank") + the rule for writing a tailored motivation. This never changes per board — it's the user's data. Grow CONFIRMED over time as new screening questions get answered (the answer-bank flywheel). """ from __future__ import annotations import json from datetime import date, timedelta from parse_resume import parse_resume_to_profile from browser_config import RESUME_PATH # Durable answers that aren't on a résumé. Extend as new questions recur. CONFIRMED = { "preferred_email": "rahul.gupta2608@yahoo.com", "citizenship": "Indian citizen, based in India", "work_auth": ("Authorized to work in India. NOT authorized to work in the US; would require " "visa sponsorship for any US-based role."), "availability": "Available to start soon (within ~2 weeks).", } async def build_candidate(pdf_path: str = RESUME_PATH) -> dict: profile = await parse_resume_to_profile(pdf_path) return {"profile": profile, "facts": CONFIRMED, "resume_path": pdf_path} def candidate_prompt_block(cand: dict) -> str: today = date.today() soon = today + timedelta(days=14) f = cand["facts"] return f"""CANDIDATE PROFILE (parsed from résumé — source of truth): {json.dumps(cand["profile"], indent=2, ensure_ascii=False)} CONFIRMED FACTS (override any résumé guess): - Preferred contact email: {f["preferred_email"]} - {f["citizenship"]}. {f["work_auth"]} * "authorized to work where the job is located?" -> YES if the role is in India, NO if US. * "require visa sponsorship?" -> NO if India role, YES if US role. Honesty over optimism — never overstate authorization. - {f["availability"]} Today is {today:%Y-%m-%d}; for a start-date picker choose a FUTURE date near {soon:%Y-%m-%d}, never a past date. - MOTIVATION: for any "why this role" / "about you" / "additional information" free-text field, write a genuine 2-4 sentence answer TAILORED to THIS specific job (use its title / company / description visible on screen) grounded in the candidate's real background above. NEVER leave it blank — a blank motivation makes a weak application. Résumé file to upload when asked: {cand["resume_path"]}"""