JAA-ATS-Tool / scripts /verify_aggressive_weaving.py
saitejatirunagari's picture
fix(phase4.1): aggressive bullet weaving + canonical-tuned scoring
8e3dfba
Raw
History Blame
7.49 kB
"""
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.')