Spaces:
Sleeping
Sleeping
| """ | |
| Simulate a WEAK LLM v4 output (sparse bullets, missing recruiter pitch) and | |
| verify the new aggressive bullet weaving lifts each JD to 90%+. | |
| Models what production looks like when smaller LLMs don't follow the v4 | |
| prompt precisely — exactly the user's reported issue (70-80% on new jobs). | |
| """ | |
| import os, sys, io, shutil | |
| sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8') | |
| 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 | |
| from src.ats_scorer import score_resume, extract_jd_keywords, _kw_in_text | |
| from src.resume_customizer import ResumeCustomizer, _read_docx_text | |
| base = parse_resume_pdf_cached(dst_pdf) | |
| def make_weak_llm_output(role: str, company: str) -> Resume: | |
| """ | |
| Mimic a TYPICAL production LLM output: reasonable-length bullets, generic | |
| phrasing, missing recruiter pitch, no specific JD keyword weaving. This | |
| matches what the user observed (70-80% on new jobs). | |
| """ | |
| return Resume( | |
| name=base.name, | |
| contact=base.contact, | |
| summary=( | |
| f"Product Manager with 5+ years of experience driving product development in fast-paced " | |
| f"EdTech and AI startups. Built funnel optimization tools and AI-powered features that " | |
| f"scaled to 140,000+ users and contributed to 2x revenue growth. Deep expertise in " | |
| f"conversational AI, OCR automation, A/B testing, and cross-functional delivery. Combines " | |
| f"data-driven decision-making with user-centric design to ship measurable outcomes." | |
| ), | |
| roles=[ | |
| Role( | |
| title=base.roles[0].title, | |
| company=base.roles[0].company, | |
| location=base.roles[0].location, | |
| dates=base.roles[0].dates, | |
| bullets=[ | |
| "Led end-to-end revamp of the NIAT Application Portal — a unified digital funnel covering landing pages, OTP login, payment, slot booking, exam, and report flow integrated with CRM and payment systems", | |
| "Scaled to 141,269 OTP-verified leads with 97% personal-details completion and 95% exam-attendance rate across 23,983 attendees", | |
| "Drove payment conversion lift of +35.87 percentage points (27.37% to 63.24%) through coupon-based urgency logic and A/B experimentation", | |
| "Built AI chatbot generating 6,776 leads and 113 enrollments via stage-wise decision trees with CRM-integrated nudges", | |
| "Optimized landing-page funnel achieving 38.02% Visit-to-OTP conversion on highest-intent campaigns through experimentation framework", | |
| "Reduced lead leakage by 25% and increased sales-qualified leads by 18% through CRM automation and event tracking", | |
| ], | |
| ), | |
| 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 refund rate below 5% and satisfaction above 95%", | |
| "Played 0-to-1 role in Xplore Experiment and Social Emotional Learning pilot projects alongside product and engineering teams", | |
| "Sustained 95%+ Monthly Recurring Revenue from existing EMI customers through proactive retention strategies", | |
| ], | |
| ), | |
| 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 the onboarding process using UX research and user-centric principles", | |
| "Conducted extensive A/B testing and UX research to identify pain points and refine features", | |
| "Mentored students through their academic journey using multi-channel communication and performance dashboards", | |
| ], | |
| ), | |
| Role( | |
| title=base.roles[3].title, | |
| company=base.roles[3].company, | |
| location=base.roles[3].location, | |
| dates=base.roles[3].dates, | |
| bullets=[ | |
| "Launched EdTech app portfolio of 275 apps with 3 million+ cumulative downloads", | |
| "Drove user acquisition through Google Ads, LinkedIn, and paid social channels", | |
| "Built performance-driven culture focused on conversion optimization and data-driven decision-making", | |
| ], | |
| ), | |
| ], | |
| achievements=[ | |
| "Scaled NIAT Application Portal to 141,269 OTP-verified leads with ₹1,120+ Cr annual pipeline", | |
| "Lifted payment conversion +35.87 percentage points via CRM-integrated experimentation", | |
| "Reduced OCR processing cost by 97.5% (₹4 to ₹0.10 per page) through automation", | |
| ], | |
| education=base.education, | |
| ) | |
| jd_focus = { | |
| 'airtel_pm': ('Product Manager', 'Airtel'), | |
| 'sumo_logic_pm': ('Product Manager', 'Sumo Logic'), | |
| 'edgeverve_pm': ('Product Manager', 'EdgeVerve'), | |
| 'aditya_birla_apm': ('Associate Product Manager', 'Aditya Birla Capital'), | |
| } | |
| out_dir = 'data/output/resumes/_weave_test' | |
| os.makedirs(out_dir, exist_ok=True) | |
| rc = ResumeCustomizer.__new__(ResumeCustomizer) | |
| rc.resume_text = '' | |
| rc._pending_summary_inject = [] | |
| print('━' * 78) | |
| print(f'{"JD":<48} {"BeforeWeave":>11} {"AfterWeave":>10} {"FinalATS":>9}') | |
| print('━' * 78) | |
| for jd_file, (role, company) in jd_focus.items(): | |
| with open(f'tests/fixtures/jds/{jd_file}.txt', encoding='utf-8') as f: | |
| jd = f.read() | |
| tailored = make_weak_llm_output(role, company) | |
| # Score before weaving (just from the weak LLM bullets) | |
| docx_pre = os.path.join(out_dir, f'{company.replace(" ", "_")}_PRE.docx') | |
| render_resume_docx(tailored, docx_pre) | |
| r_pre = score_resume(_read_docx_text(docx_pre), jd) | |
| # Run aggressive bullet weaving | |
| jd_kw = extract_jd_keywords(jd) | |
| flat = tailored.to_flat_text().lower() | |
| missing = [k for k in jd_kw if not _kw_in_text(k, flat)] | |
| missing = [k for k in missing if len(k) >= 3 and not (len(k) >= 5 and k.endswith(("at", "iz", "ic")))] | |
| rc._weave_keywords_into_bullets(tailored, missing, jd) | |
| # Score after bullet weaving | |
| docx_mid = os.path.join(out_dir, f'{company.replace(" ", "_")}_WOVEN.docx') | |
| render_resume_docx(tailored, docx_mid) | |
| r_mid = score_resume(_read_docx_text(docx_mid), jd) | |
| # Apply summary injection for any leftover keywords | |
| rc._inject_missing_keywords(docx_mid, jd) | |
| r_final = score_resume(_read_docx_text(docx_mid), jd) | |
| print(f'{(role + " @ " + company):<48} {r_pre["ats_score"]:>10} {r_mid["ats_score"]:>9} {r_final["ats_score"]:>7}') | |
| print('━' * 78) | |
| print('Note: "BeforeWeave" = weak LLM v4 output simulating production case.') | |
| print(' "AfterWeave" = after aggressive bullet weaving.') | |
| print(' "FinalATS" = after summary injection for stragglers.') | |