Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 60 additions & 4 deletions levelup/app.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import json
import re
from typing import Any, cast
from typing import Any, Optional, cast

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


def analyzecv_pdf_withllm(text: str, report_language: str) -> dict[str, Any] | None:
prompt = get_resume_analysis_prompt(text, report_language)
def analyzecv_pdf_withllm(
text: str, report_language: str, target_role: Optional[str] = None
) -> dict[str, Any] | None:
prompt = get_resume_analysis_prompt(text, report_language, target_role)
try:
response = Model.generate_content(prompt)
raw_text = (response.text or "").strip()
Expand Down Expand Up @@ -334,8 +336,62 @@ def display_analysis_tabs(result: dict[str, Any]) -> None:
index=language_options.index("English"),
)

role_options = [
"No specific target role",
"Data Scientist",
"Data Analyst",
"Data Engineer",
"Machine Learning Engineer",
"AI Engineer",
"MLOps Engineer",
"Deep Learning Engineer",
"Business Intelligence Analyst",
"Data Architect",
"AI Product Manager",
"Software Engineer",
"Backend Engineer",
"Frontend Engineer",
"Full Stack Engineer",
"Mobile Developer",
"DevOps Engineer",
"Cloud Engineer",
"Solution Architect",
"Application Developer",
"QA Engineer",
"Test Automation Engineer",
"Manual Tester",
"Cybersecurity Analyst",
"Security Engineer",
"Security Architect",
"SOC Analyst",
"Penetration Tester",
"Product Manager",
"Product Owner",
"Scrum Master",
"Project Manager",
"System Administrator",
"Network Engineer",
"IT Support Specialist",
"Platform Engineer",
"UX Designer",
"UI Designer",
"Product Designer",
]

selected_role_label = st.selectbox(
"Choose a target role for the report",
role_options,
index=0,
)

selected_role: Optional[str]
if selected_role_label == "No specific target role":
selected_role = None
else:
selected_role = selected_role_label

if st.button("Analyze Resume"):
with st.spinner("Analyzing Resume..."):
result = analyzecv_pdf_withllm(text, selected_language)
result = analyzecv_pdf_withllm(text, selected_language, selected_role)
if result:
display_analysis_tabs(result)
167 changes: 132 additions & 35 deletions levelup/prompts.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,83 @@
def get_resume_analysis_prompt(text: str, report_language: str) -> str:
"""Builds the full LLM prompt for resume analysis.
def get_resume_analysis_prompt(
text: str, report_language: str, target_role: str | None = None
) -> str:
"""Builds the full LLM prompt for resume analysis, with optional strong target-role conditioning."""

notes = {
"domain": "",
"competency": "",
"insights": "",
"recommendations": "",
"missing_skills": "",
"benchmarking": "",
"summary": "",
"strengths": "",
}

target_role_block = ""
if target_role is not None:
target_role_block = f"""
TARGET ROLE FOCUS:
- The candidate explicitly targets the role: "{target_role}".
- All scores, justifications, insights, and recommendations must be evaluated relative to global expectations for "{target_role}" at the candidate’s apparent seniority level.
- 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).
- Every justification, strength, observation, insight, recommendation, and benchmarking comment must explicitly refer to the candidate’s fit for "{target_role}".
- You may mention other suitable roles or domains, but always describe them in relation to the candidate’s primary fit for "{target_role}".

CONSISTENCY REQUIREMENTS FOR SCORES:
- The "overall_score" MUST always represent the candidate’s overall fit for "{target_role}" only.
- In "overall_summary.role_suitability":
- The FIRST item MUST have "role": "{target_role}".
- Its "score" MUST be EXACTLY equal to "overall_score".
- NO other role_suitability entry may have a score higher than "overall_score".
- When evaluating suitability for "{target_role}", heavily weight core role-specific capabilities.
- If the candidate’s experience is primarily in a different domain than "{target_role}" (e.g., Data Science vs Software Engineering),
and there is limited direct evidence of core "{target_role}" responsibilities (such as algorithms/data structures, software design, testing, CI/CD, scalable services), then:
- The "{target_role}" role_suitability score (and thus "overall_score") MUST NOT exceed 70.
- 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.
"""
notes["domain"] = f"""
- For each domain, interpret the score as: "How strong is this candidate in this domain while working as "{target_role}"?".
- At least one domain must clearly correspond to "{target_role}" (or a closely related domain label), and the justification must reference "{target_role}" explicitly.
"""
notes["competency"] = f"""
- Each competency score must be benchmarked against typical expectations for "{target_role}" at the candidate’s current level.
- Strengths and observations must clearly explain how they support or limit performance as "{target_role}".
"""
notes["insights"] = f"""
- Explicitly classify the candidate’s current fit for "{target_role}" as strong, moderate, or weak, with clear reasoning.
- State whether "{target_role}" is realistic in the short to medium term and under which conditions.
"""
notes["recommendations"] = f"""
- All recommendations must be framed as concrete actions that increase the candidate’s competitiveness for "{target_role}".
"""
notes["missing_skills"] = f"""
- When identifying missing skills, prioritize gaps that are most important for succeeding as "{target_role}" in the global market at this level.
"""
notes["benchmarking"] = f"""
- 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.
"""
notes["summary"] = f"""
- 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.
"""
notes["strengths"] = f"""
- 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.
- 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.
- Avoid listing strengths that are only relevant to the candidate’s original role and do not materially contribute to performance as "{target_role}".
- 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).
- Focus on strengths that are clearly relevant to "{target_role}". Do not mention strengths that are not suitable for the target role.
"""
else:
notes["strengths"] = """
- 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.
- Focus on strengths that are robust and transferable across multiple plausible career paths (e.g., strong programming fundamentals, problem solving, ownership, communication).
- Avoid overly narrow, niche strengths that are locked into a single, highly specific role unless that role is clearly dominant in the CV.
"""

primary_role_for_json = (
target_role if target_role is not None else "Primary Likely Role"
)

Guides the model to analyze a CV across language, domain fit,
competencies, insights, recommendations, benchmarking, and summary.
Returns the complete formatted prompt string.
"""
return f"""
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.

Expand All @@ -26,44 +99,70 @@ def get_resume_analysis_prompt(text: str, report_language: str) -> str:
- Pick one specific platform/standard per item instead of categories.
- Exclude anything already present in the CV. Deduplicate closely related items.

{target_role_block}

* 1. LANGUAGE DETECTION
Identify the dominant language of the CV.

* 2. CAREER DOMAIN MATCHING
Identify the top 3 most suitable career domains for this candidate.
For each domain:
- Give a score out of 100
- Justify why the candidate fits that domain (based on experience, skills, education, etc.)
- Optionally mention related roles the candidate could consider
- Give a score out of 100.
- Justify why the candidate fits that domain (based on experience, skills, education, and impact).
- Optionally mention related roles the candidate could consider.
{notes["domain"]}

* 3. COMPETENCY EVALUATION
Evaluate the candidate across 10 dimensions. For each, give:
- A score out of 100
- Specific strengths and examples from the CV
- Observations or red flags (if any)
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:
- Assign a score out of 100.
- Describe concrete strengths and examples from the CV.
- Note any observations or red flags (e.g., lack of scale, missing ownership, shallow impact).
{notes["competency"]}

* 4. STRATEGIC INSIGHTS & INTERPRETATION
- Based on the full CV, what type of roles is this candidate most suited for now?
- What future roles could be targeted with slight improvements?
- Are there signs of underutilized potential?
- Does the profile indicate a specialist or generalist tendency?
- Are there inconsistencies or missing data that should be improved?
Based on the full CV:
- Which types of roles is this candidate most suited for now?
- Which future roles could be realistic with incremental improvements?
- Are there signs of underutilized potential (e.g., skills that are not fully leveraged)?
- Does the profile suggest a specialist or generalist tendency?
- Are there any inconsistencies, gaps, or missing data that should be clarified or improved?
{notes["insights"]}

* 5. DEVELOPMENT RECOMMENDATIONS
Provide clear, practical and personalized suggestions for how the candidate can improve:
- Skills, certifications, degrees
- Portfolio, communication, network
Provide clear, practical, and personalized suggestions on how the candidate can strengthen their profile:
- Skills, tools, and methods to learn or deepen.
- Certifications or degrees that would be valuable.
- Portfolio, project, or publication ideas.
- Improvements in communication, stakeholder management, and professional networking.
{notes["recommendations"]}

* 6. MISSING SKILLS & EXPERIENCE MISMATCH
Explicitly identify:
- Up to 5 missing or weakly represented skills relevant to the candidate’s likely target roles.
- Any mismatched experience (e.g., experience unrelated to stated goals or domain misalignment).
* 6. MISSING SKILLS & EXPERIENCE MISMATCH
Explicitly identify:
- Up to 5 missing or weakly represented skills that are relevant to the candidate’s likely or explicit target roles.
- 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.
{notes["missing_skills"]}

* 7. COMPARATIVE BENCHMARKING
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.
Compare the candidate’s profile against general industry and global professional standards at a similar career level. Consider:
- Depth and breadth of skills.
- Scope and impact of experience.
- Ownership, autonomy, and complexity of work.
Indicate whether the candidate appears above, at, or below typical benchmarks.
{notes["benchmarking"]}

* 8. KEY STRENGTHS INSIGHTS (key_strengths)
Provide 3–5 high-level strategic insights about the candidate’s profile, career trajectory, and market positioning.
- Focus on strengths that are most relevant to the candidate’s current and near-future roles.
{notes["strengths"]}

* 8. OVERALL SUMMARY
Provide a concise synthesis of the entire evaluation. Include the total score, key strengths, areas for improvement, and an assessment of overall talent potential.
* 9. OVERALL SUMMARY
Provide a concise synthesis of the entire evaluation. Include:
- A single overall score (0–100) summarizing the profile.
- Key strengths.
- Priority areas for improvement.
- An overall view of talent potential (High / Moderate / Needs Development).
- A short assessment of the candidate’s role suitability across 2–3 key roles.
{notes["summary"]}

Absolutely follow the JSON format shown below. Do not add any text, comments, or explanations outside the JSON structure.

Expand All @@ -81,13 +180,11 @@ def get_resume_analysis_prompt(text: str, report_language: str) -> str:
"Recommendation 2"
],
"missing_skills": [
{{"skill": "Python", "priority": "Critical"}},
{{"skill": "PySpark", "priority": "Nice to have"}},
{{"skill": "Docker", "priority": "Important"}}
{{"skill": "ExampleSkill1", "priority": "Critical"}},
{{"skill": "ExampleSkill2", "priority": "Important"}}
],
"mismatched_experience": [
"Example 1",
"Example 2"
"Example of experience that does not fully align with the candidate’s direction"
],
"comparative_benchmarking": "Paragraph comparing this candidate against general industry standards. If not applicable, leave empty.",
"overall_summary": {{
Expand All @@ -96,8 +193,8 @@ def get_resume_analysis_prompt(text: str, report_language: str) -> str:
"areas_to_improve": ["Weakness 1", "Weakness 2"],
"talent_potential": "High / Moderate / Needs Development",
"role_suitability": [
{{"role": "Data Scientist", "score": 82}},
{{"role": "Machine Learning Engineer", "score": 78}}
{{"role": "{primary_role_for_json}", "score": 82}},
{{"role": "Secondary Likely or Related Role", "score": 78}}
]
}}
}}
Expand Down
Loading