File size: 7,517 Bytes
0e70529
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
150
151
152
153
154
"""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)}')