"""Verify Phase 4 canonical flow on all 4 failing JDs with handcrafted v4 LLM responses.""" import os, sys, io, shutil, pdfplumber sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8') # Make sure the source PDF is in the expected place src_pdf = r'C:\Users\Nxtwave\Desktop\resume\Saiteja_Tirunagari_Resume A 26 - Copy.pdf' dst_pdf = 'data/resume/resume.pdf' os.makedirs(os.path.dirname(dst_pdf), exist_ok=True) if not os.path.exists(dst_pdf): shutil.copyfile(src_pdf, dst_pdf) from src.resume_parser_v2 import parse_resume_pdf_cached from src.resume_renderer import render_resume_docx from src.resume_model import Resume, Role, Education, Contact from src.ats_scorer import score_resume from src.resume_customizer import ResumeCustomizer, _read_docx_text # Load canonical resume base = parse_resume_pdf_cached(dst_pdf) print(f'Loaded canonical resume: {base.name}, {len(base.roles)} roles, {len(base.education)} edu entries') def make_tailored_for(jd_text: str, role: str, company: str, kw_focus: list[str]) -> Resume: """Build a handcrafted tailored Resume for a JD, weaving focus keywords.""" # Recruiter pitch + summary summary = ( f"Strong-fit candidate for {role} at {company}: 5+ years of PM experience " f"directly applicable to {kw_focus[0] if kw_focus else 'this role'}. " f"Owned end-to-end product modules from discovery through launch, authored PRDs, " f"user stories, wireframes, and acceptance criteria, and partnered with engineering, " f"design, and QA across sprints. Drove A/B testing on Mixpanel, Amplitude, and GA4 to " f"track activation, adoption, retention, funnel conversion, and revenue impact. " f"Hands-on with Jira and Figma; integrated CRM workflows via APIs and webhooks. " f"{' '.join(['Familiar with ' + k + '.' for k in kw_focus[:3]])}" ) # Tailored roles — pick 5-7 bullets per role, rewritten roles = [ Role( title=base.roles[0].title, company=base.roles[0].company, location=base.roles[0].location, dates=base.roles[0].dates, bullets=[ "Owned end-to-end product modules for the NIAT Application Portal, partnering with engineering, design, and QA across sprint planning and releases.", "Authored PRDs, user stories, wireframes, and acceptance criteria for 8 cross-functional releases tracked via Jira and Figma.", "Tracked activation, adoption, retention, funnel conversion, and revenue impact via Mixpanel, Amplitude, and GA4 dashboards integrated with CRM via APIs and webhooks.", "Drove A/B experiments lifting payment conversion from 27.37% to 63.24% (+35.87 pp), scaling to 141,269 OTP-verified leads.", "Translated business goals into roadmap items aligned with founders/leadership; established KPIs and prioritization frameworks.", "Partnered with data science on AI chatbot productization; gained exposure to MLOps workflows and model validation pipelines.", f"Worked adjacent to {', '.join(kw_focus[:2])} through cross-functional product integrations.", ], ), Role( title=base.roles[1].title, company=base.roles[1].company, location=base.roles[1].location, dates=base.roles[1].dates, bullets=[ "Managed 20 customer-success specialists covering 40,000 customers; maintained 95%+ satisfaction and <5% refund rate via SLA-driven production support.", "Coordinated UAT with business stakeholders; documented test results and obtained formal sign-off before production deployment.", "Led 0→1 product initiatives partnering with engineering on Xplore and Social Emotional Learning pilots.", ], ), Role( title=base.roles[2].title, company=base.roles[2].company, location=base.roles[2].location, dates=base.roles[2].dates, bullets=[ "Increased user retention by 8% by redesigning onboarding using UX research and customer empathy frameworks.", "Conducted extensive A/B testing and user research to identify pain points and refine features.", "Gathered and analysed user requirements through stakeholder interviews; produced FSDs and acceptance criteria.", ], ), Role( title=base.roles[3].title, company=base.roles[3].company, location=base.roles[3].location, dates=base.roles[3].dates, bullets=[ "Launched EdTech portfolio of 275 apps with 3M+ cumulative downloads; managed end-to-end IT projects from requirements gathering to production.", "Drove user acquisition via Google Ads, LinkedIn, and paid social; established strategic partnerships and end-to-end P&L.", "Built data-driven culture focused on conversion optimization, KPIs, and stakeholder alignment.", ], ), ] achievements = [ "Scaled product funnel to 141,269 verified leads with ₹1,120+ Cr annual pipeline", "Lifted A/B-tested payment conversion +35.87 pp via CRM-integrated nudges", "Reduced OCR processing cost 97.5% (₹4 → ₹0.10/page) through automation", "Generated 6,776 leads via AI-driven conversational chatbot", ] return Resume( name=base.name, contact=base.contact, summary=summary, roles=roles, achievements=achievements, education=base.education, ) # Test each of the 4 failing JDs jd_focus = { 'airtel_pm': ('Product Manager', 'Airtel', ['MLOps', 'A/B testing']), 'sumo_logic_pm': ('Product Manager', 'Sumo Logic', ['SIEM', 'SOAR', 'threat detection']), 'edgeverve_pm': ('Product Manager', 'EdgeVerve', ['MLOps', 'foundation models', 'AI-First']), 'aditya_birla_apm': ('Associate Product Manager', 'Aditya Birla Capital', ['FSD', 'UAT', 'requirements elicitation']), } out_dir = 'data/output/resumes/_phase4_canonical_test' os.makedirs(out_dir, exist_ok=True) rc = ResumeCustomizer.__new__(ResumeCustomizer) rc.resume_text = '' # not used in v4 path print() print('━' * 75) print(f'{"JD":<48} {"Before":>7} {"After":>7} {"JD-match":>10} {"Pages":>6}') print('━' * 75) for jd_file, (role, company, focus) in jd_focus.items(): with open(f'tests/fixtures/jds/{jd_file}.txt', encoding='utf-8') as f: jd = f.read() tailored = make_tailored_for(jd, role, company, focus) docx_path = os.path.join(out_dir, f'{company.replace(" ", "_")}_{jd_file}.docx') render_resume_docx(tailored, docx_path) # Score BEFORE injection r_before = score_resume(_read_docx_text(docx_path), jd) # Apply injection safety net rc._inject_missing_keywords(docx_path, jd) # Score AFTER injection text = _read_docx_text(docx_path) r = score_resume(text, jd) # Get page count from src.pdf_writer import docx_to_pdf try: pdf = docx_to_pdf(docx_path) with pdfplumber.open(pdf) as p: pages = len(p.pages) except Exception: pages = '?' print(f'{(role + " @ " + company):<48} {r_before["ats_score"]:>6} {r["ats_score"]:>6} {r["matched_count"]}/{r["total_jd_kw"]:<3} {pages}') print('━' * 75) print(f'\nOutput at: {os.path.abspath(out_dir)}')