Spaces:
Sleeping
Sleeping
File size: 7,492 Bytes
8e3dfba | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 | """
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.')
|