Skip to content

Commit 7c8c7cd

Browse files
committed
feat: target role option
1 parent 1bf3605 commit 7c8c7cd

2 files changed

Lines changed: 192 additions & 39 deletions

File tree

levelup/app.py

Lines changed: 60 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import json
22
import re
3-
from typing import Any, cast
3+
from typing import Any, Optional, cast
44

55
import google.generativeai as genai
66
import pandas as pd # type: ignore[import-untyped]
@@ -41,8 +41,10 @@ def _extract_json_block(raw_text: str) -> str | None:
4141
return None
4242

4343

44-
def analyzecv_pdf_withllm(text: str, report_language: str) -> dict[str, Any] | None:
45-
prompt = get_resume_analysis_prompt(text, report_language)
44+
def analyzecv_pdf_withllm(
45+
text: str, report_language: str, target_role: Optional[str] = None
46+
) -> dict[str, Any] | None:
47+
prompt = get_resume_analysis_prompt(text, report_language, target_role)
4648
try:
4749
response = Model.generate_content(prompt)
4850
raw_text = (response.text or "").strip()
@@ -334,8 +336,62 @@ def display_analysis_tabs(result: dict[str, Any]) -> None:
334336
index=language_options.index("English"),
335337
)
336338

339+
role_options = [
340+
"No specific target role",
341+
"Data Scientist",
342+
"Data Analyst",
343+
"Data Engineer",
344+
"Machine Learning Engineer",
345+
"AI Engineer",
346+
"MLOps Engineer",
347+
"Deep Learning Engineer",
348+
"Business Intelligence Analyst",
349+
"Data Architect",
350+
"AI Product Manager",
351+
"Software Engineer",
352+
"Backend Engineer",
353+
"Frontend Engineer",
354+
"Full Stack Engineer",
355+
"Mobile Developer",
356+
"DevOps Engineer",
357+
"Cloud Engineer",
358+
"Solution Architect",
359+
"Application Developer",
360+
"QA Engineer",
361+
"Test Automation Engineer",
362+
"Manual Tester",
363+
"Cybersecurity Analyst",
364+
"Security Engineer",
365+
"Security Architect",
366+
"SOC Analyst",
367+
"Penetration Tester",
368+
"Product Manager",
369+
"Product Owner",
370+
"Scrum Master",
371+
"Project Manager",
372+
"System Administrator",
373+
"Network Engineer",
374+
"IT Support Specialist",
375+
"Platform Engineer",
376+
"UX Designer",
377+
"UI Designer",
378+
"Product Designer",
379+
]
380+
381+
selected_role_label = st.selectbox(
382+
"Choose a target role for the report",
383+
role_options,
384+
index=0,
385+
)
386+
387+
selected_role: Optional[str]
388+
if selected_role_label == "No specific target role":
389+
selected_role = None
390+
else:
391+
selected_role = selected_role_label
392+
337393
if st.button("Analyze Resume"):
338394
with st.spinner("Analyzing Resume..."):
339-
result = analyzecv_pdf_withllm(text, selected_language)
395+
result = analyzecv_pdf_withllm(text, selected_language, selected_role)
340396
if result:
341397
display_analysis_tabs(result)

levelup/prompts.py

Lines changed: 132 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,83 @@
1-
def get_resume_analysis_prompt(text: str, report_language: str) -> str:
2-
"""Builds the full LLM prompt for resume analysis.
1+
def get_resume_analysis_prompt(
2+
text: str, report_language: str, target_role: str | None = None
3+
) -> str:
4+
"""Builds the full LLM prompt for resume analysis, with optional strong target-role conditioning."""
5+
6+
notes = {
7+
"domain": "",
8+
"competency": "",
9+
"insights": "",
10+
"recommendations": "",
11+
"missing_skills": "",
12+
"benchmarking": "",
13+
"summary": "",
14+
"strengths": "",
15+
}
16+
17+
target_role_block = ""
18+
if target_role is not None:
19+
target_role_block = f"""
20+
TARGET ROLE FOCUS:
21+
- The candidate explicitly targets the role: "{target_role}".
22+
- All scores, justifications, insights, and recommendations must be evaluated relative to global expectations for "{target_role}" at the candidate’s apparent seniority level.
23+
- Every numeric score (domain_scores, competency_scores, overall_score, role_suitability scores) must reflect how strong the candidate is for "{target_role}" (not for their past or current role).
24+
- Every justification, strength, observation, insight, recommendation, and benchmarking comment must explicitly refer to the candidate’s fit for "{target_role}".
25+
- You may mention other suitable roles or domains, but always describe them in relation to the candidate’s primary fit for "{target_role}".
26+
27+
CONSISTENCY REQUIREMENTS FOR SCORES:
28+
- The "overall_score" MUST always represent the candidate’s overall fit for "{target_role}" only.
29+
- In "overall_summary.role_suitability":
30+
- The FIRST item MUST have "role": "{target_role}".
31+
- Its "score" MUST be EXACTLY equal to "overall_score".
32+
- NO other role_suitability entry may have a score higher than "overall_score".
33+
- When evaluating suitability for "{target_role}", heavily weight core role-specific capabilities.
34+
- If the candidate’s experience is primarily in a different domain than "{target_role}" (e.g., Data Science vs Software Engineering),
35+
and there is limited direct evidence of core "{target_role}" responsibilities (such as algorithms/data structures, software design, testing, CI/CD, scalable services), then:
36+
- The "{target_role}" role_suitability score (and thus "overall_score") MUST NOT exceed 70.
37+
- Scores of 80 or above for "{target_role}" require clear, explicit, repeated evidence of strong performance in core "{target_role}" responsibilities, not just adjacent or related work.
38+
"""
39+
notes["domain"] = f"""
40+
- For each domain, interpret the score as: "How strong is this candidate in this domain while working as "{target_role}"?".
41+
- At least one domain must clearly correspond to "{target_role}" (or a closely related domain label), and the justification must reference "{target_role}" explicitly.
42+
"""
43+
notes["competency"] = f"""
44+
- Each competency score must be benchmarked against typical expectations for "{target_role}" at the candidate’s current level.
45+
- Strengths and observations must clearly explain how they support or limit performance as "{target_role}".
46+
"""
47+
notes["insights"] = f"""
48+
- Explicitly classify the candidate’s current fit for "{target_role}" as strong, moderate, or weak, with clear reasoning.
49+
- State whether "{target_role}" is realistic in the short to medium term and under which conditions.
50+
"""
51+
notes["recommendations"] = f"""
52+
- All recommendations must be framed as concrete actions that increase the candidate’s competitiveness for "{target_role}".
53+
"""
54+
notes["missing_skills"] = f"""
55+
- When identifying missing skills, prioritize gaps that are most important for succeeding as "{target_role}" in the global market at this level.
56+
"""
57+
notes["benchmarking"] = f"""
58+
- Compare the candidate specifically with typical professionals working as "{target_role}" at a similar career level, and state whether they are above, at, or below this benchmark.
59+
"""
60+
notes["summary"] = f"""
61+
- Clearly state overall fit for "{target_role}", the main gaps that limit performance in this role, and whether the target is realistic now or requires significant upskilling.
62+
"""
63+
notes["strengths"] = f"""
64+
- Only list the person's strengths that align with the {target_role} role. Do not list strengths that are unrelated to the {target_role} role.
65+
- In all strength-related sections (including "overall_summary.key_strengths"), list strengths that directly support success as "{target_role}" or clearly demonstrate transferable potential toward becoming a stronger "{target_role}" candidate.
66+
- Avoid listing strengths that are only relevant to the candidate’s original role and do not materially contribute to performance as "{target_role}".
67+
- If a skill is strongly domain-specific to the candidate’s original role (e.g., ML/AI/LLM tooling for a Data Scientist), DO NOT list it as a strength for the target role unless it directly supports core responsibilities of "{target_role}" (such as scalable software development, software architecture, performance, reliability, system design, or production engineering).
68+
- Focus on strengths that are clearly relevant to "{target_role}". Do not mention strengths that are not suitable for the target role.
69+
"""
70+
else:
71+
notes["strengths"] = """
72+
- In all strength-related sections (including "overall_summary.key_strengths"), list strengths that best summarize the candidate’s value across their top likely roles inferred from the CV.
73+
- Focus on strengths that are robust and transferable across multiple plausible career paths (e.g., strong programming fundamentals, problem solving, ownership, communication).
74+
- Avoid overly narrow, niche strengths that are locked into a single, highly specific role unless that role is clearly dominant in the CV.
75+
"""
76+
77+
primary_role_for_json = (
78+
target_role if target_role is not None else "Primary Likely Role"
79+
)
380

4-
Guides the model to analyze a CV across language, domain fit,
5-
competencies, insights, recommendations, benchmarking, and summary.
6-
Returns the complete formatted prompt string.
7-
"""
881
return f"""
982
You are a globally experienced HR and career evaluation expert with deep cross-industry insight. You will perform an extremely detailed, holistic analysis of the CV provided below. Go beyond numeric scoring — offer professional interpretation, inferences, and personalized guidance based on the profile.
1083
@@ -26,44 +99,70 @@ def get_resume_analysis_prompt(text: str, report_language: str) -> str:
2699
- Pick one specific platform/standard per item instead of categories.
27100
- Exclude anything already present in the CV. Deduplicate closely related items.
28101
102+
{target_role_block}
103+
29104
* 1. LANGUAGE DETECTION
30105
Identify the dominant language of the CV.
31106
32107
* 2. CAREER DOMAIN MATCHING
33108
Identify the top 3 most suitable career domains for this candidate.
34109
For each domain:
35-
- Give a score out of 100
36-
- Justify why the candidate fits that domain (based on experience, skills, education, etc.)
37-
- Optionally mention related roles the candidate could consider
110+
- Give a score out of 100.
111+
- Justify why the candidate fits that domain (based on experience, skills, education, and impact).
112+
- Optionally mention related roles the candidate could consider.
113+
{notes["domain"]}
38114
39115
* 3. COMPETENCY EVALUATION
40-
Evaluate the candidate across 10 dimensions. For each, give:
41-
- A score out of 100
42-
- Specific strengths and examples from the CV
43-
- Observations or red flags (if any)
116+
Evaluate the candidate across 10 dimensions (for example: Core Technical Skills, Tools & Technologies, Problem Solving, Business Impact, Communication, Leadership, Collaboration, Learning Agility, Domain Knowledge, Delivery & Reliability). For each dimension:
117+
- Assign a score out of 100.
118+
- Describe concrete strengths and examples from the CV.
119+
- Note any observations or red flags (e.g., lack of scale, missing ownership, shallow impact).
120+
{notes["competency"]}
44121
45122
* 4. STRATEGIC INSIGHTS & INTERPRETATION
46-
- Based on the full CV, what type of roles is this candidate most suited for now?
47-
- What future roles could be targeted with slight improvements?
48-
- Are there signs of underutilized potential?
49-
- Does the profile indicate a specialist or generalist tendency?
50-
- Are there inconsistencies or missing data that should be improved?
123+
Based on the full CV:
124+
- Which types of roles is this candidate most suited for now?
125+
- Which future roles could be realistic with incremental improvements?
126+
- Are there signs of underutilized potential (e.g., skills that are not fully leveraged)?
127+
- Does the profile suggest a specialist or generalist tendency?
128+
- Are there any inconsistencies, gaps, or missing data that should be clarified or improved?
129+
{notes["insights"]}
51130
52131
* 5. DEVELOPMENT RECOMMENDATIONS
53-
Provide clear, practical and personalized suggestions for how the candidate can improve:
54-
- Skills, certifications, degrees
55-
- Portfolio, communication, network
132+
Provide clear, practical, and personalized suggestions on how the candidate can strengthen their profile:
133+
- Skills, tools, and methods to learn or deepen.
134+
- Certifications or degrees that would be valuable.
135+
- Portfolio, project, or publication ideas.
136+
- Improvements in communication, stakeholder management, and professional networking.
137+
{notes["recommendations"]}
56138
57-
* 6. MISSING SKILLS & EXPERIENCE MISMATCH
58-
Explicitly identify:
59-
- Up to 5 missing or weakly represented skills relevant to the candidate’s likely target roles.
60-
- Any mismatched experience (e.g., experience unrelated to stated goals or domain misalignment).
139+
* 6. MISSING SKILLS & EXPERIENCE MISMATCH
140+
Explicitly identify:
141+
- Up to 5 missing or weakly represented skills that are relevant to the candidate’s likely or explicit target roles.
142+
- Any mismatched experience (e.g., long periods in unrelated domains, activities that do not support their stated or implied career direction) and how this affects perceived fit.
143+
{notes["missing_skills"]}
61144
62145
* 7. COMPARATIVE BENCHMARKING
63-
Compare the candidate’s profile against general industry and global professional standards at a similar career level. Use widely recognized benchmarks or norms (skills depth, experience breadth, impact level). Do not reference specific datasets or sources; base this on general market understanding. Indicate whether the candidate appears above, average, or below such benchmarks.
146+
Compare the candidate’s profile against general industry and global professional standards at a similar career level. Consider:
147+
- Depth and breadth of skills.
148+
- Scope and impact of experience.
149+
- Ownership, autonomy, and complexity of work.
150+
Indicate whether the candidate appears above, at, or below typical benchmarks.
151+
{notes["benchmarking"]}
152+
153+
* 8. KEY STRENGTHS INSIGHTS (key_strengths)
154+
Provide 3–5 high-level strategic insights about the candidate’s profile, career trajectory, and market positioning.
155+
- Focus on strengths that are most relevant to the candidate’s current and near-future roles.
156+
{notes["strengths"]}
64157
65-
* 8. OVERALL SUMMARY
66-
Provide a concise synthesis of the entire evaluation. Include the total score, key strengths, areas for improvement, and an assessment of overall talent potential.
158+
* 9. OVERALL SUMMARY
159+
Provide a concise synthesis of the entire evaluation. Include:
160+
- A single overall score (0–100) summarizing the profile.
161+
- Key strengths.
162+
- Priority areas for improvement.
163+
- An overall view of talent potential (High / Moderate / Needs Development).
164+
- A short assessment of the candidate’s role suitability across 2–3 key roles.
165+
{notes["summary"]}
67166
68167
Absolutely follow the JSON format shown below. Do not add any text, comments, or explanations outside the JSON structure.
69168
@@ -81,13 +180,11 @@ def get_resume_analysis_prompt(text: str, report_language: str) -> str:
81180
"Recommendation 2"
82181
],
83182
"missing_skills": [
84-
{{"skill": "Python", "priority": "Critical"}},
85-
{{"skill": "PySpark", "priority": "Nice to have"}},
86-
{{"skill": "Docker", "priority": "Important"}}
183+
{{"skill": "ExampleSkill1", "priority": "Critical"}},
184+
{{"skill": "ExampleSkill2", "priority": "Important"}}
87185
],
88186
"mismatched_experience": [
89-
"Example 1",
90-
"Example 2"
187+
"Example of experience that does not fully align with the candidate’s direction"
91188
],
92189
"comparative_benchmarking": "Paragraph comparing this candidate against general industry standards. If not applicable, leave empty.",
93190
"overall_summary": {{
@@ -96,8 +193,8 @@ def get_resume_analysis_prompt(text: str, report_language: str) -> str:
96193
"areas_to_improve": ["Weakness 1", "Weakness 2"],
97194
"talent_potential": "High / Moderate / Needs Development",
98195
"role_suitability": [
99-
{{"role": "Data Scientist", "score": 82}},
100-
{{"role": "Machine Learning Engineer", "score": 78}}
196+
{{"role": "{primary_role_for_json}", "score": 82}},
197+
{{"role": "Secondary Likely or Related Role", "score": 78}}
101198
]
102199
}}
103200
}}

0 commit comments

Comments
 (0)