File size: 6,795 Bytes
0715b4a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9e91ed6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2ec3155
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0715b4a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
b46cf47
 
 
 
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
import json
from typing import List
from langchain_core.pydantic_v1 import BaseModel, Field
from langchain.output_parsers import PydanticOutputParser
from langchain_core.prompts import PromptTemplate

def load_json_file(filename):
    try:
        with open(filename, 'r', encoding='utf-8') as f:
            return json.load(f)
    except json.JSONDecodeError as e:
        print(f"Error decoding JSON in {filename}: {e}")
        return None

cv_structure = load_json_file('cv_structure.json')
cv_sections = load_json_file('cv_sections.json')

class EducationElement(BaseModel):
    degree_present: bool = Field(description="Whether the degree is present")
    year_present: bool = Field(description="Whether the year is present")
    institution_present: bool = Field(description="Whether the institution is present")
    score: float = Field(description="Score for this education element", ge=0, le=10)

class Education(BaseModel):
    overall_score: float = Field(description="Overall score for the education section", ge=0, le=10)
    elements: List[EducationElement] = Field(description="List of education elements")

class WorkExperienceElement(BaseModel):
    job_title_present: bool = Field(description="Whether the job title is present")
    company_present: bool = Field(description="Whether the company name is present")
    dates_present: bool = Field(description="Whether the start and end dates are present")
    technologies_present: bool = Field(description="Whether the used technologies are present")
    responsibilities_present: bool = Field(description="Whether responsibilities are present")
    achievements_present: bool = Field(description="Whether achievements are present")
    responsibilities_quality: float = Field(description="Quality of responsibilities description", ge=0, le=10)
    achievements_quality: float = Field(description="Quality of achievements description", ge=0, le=10)
    score: float = Field(description="Score for this work experience element", ge=0, le=10)

class WorkExperience(BaseModel):
    overall_score: float = Field(description="Overall score for the work experience section", ge=0, le=10)
    elements: List[WorkExperienceElement] = Field(description="List of work experience elements")

class Profile(BaseModel):
    overall_score: float = Field(description="Overall score for the profile section", ge=0, le=10)
    brief_overview_present: bool = Field(description="Whether a brief overview is present")
    career_goals_present: bool = Field(description="Whether career goals are present")
    objective_present: bool = Field(description="Whether an objective is present")

class ResumeQualityEvaluation(BaseModel):
    education: Education = Field(description="Evaluation of the education section")
    work_experience: WorkExperience = Field(description="Evaluation of the work experience section")
    profile: Profile = Field(description="Evaluation of the profile section")

def get_personal_info_prompt(text):
    return f"""<s>[INST]Extract the personal information from the following CV text. The text may be in any language. Respond with a JSON object in the format {{"city": {{"extracted city name": true/false}}, "country": {{"extracted country name": true/false}}}}. If you can't find the information, set the value to false.

Text:
{text}[/INST]"""

def get_spelling_grammar_prompt(text):
    return f"""<s>[INST]Analyze the following text for spelling and grammar errors. The text may be in any language. Do not correct the errors, just count them. Calculate the percentage of errors.

Text to analyze:
{text}

Respond with a JSON object containing the key 'error_percentage' with the calculated percentage (0-100) of errors.[/INST]"""

def get_section_detection_prompt(text):
    if cv_sections is None:
        return None
    sections_list = ", ".join(cv_sections['sections'].keys())
    return f"""<s>[INST] Analyze this CV text and identify which of the following sections are present: {sections_list}. 
A section is considered present if its content is identifiable, even without an explicit title. 
Consider synonyms and alternative phrasings for section titles.

Sections to look for:
{sections_list}

CV text:
{text}

Respond with a JSON object with a key "present_sections" containing an array of the identified sections. 
Only include sections that are actually present in the CV. [/INST]"""

def get_content_quality_prompt(text):
    parser = PydanticOutputParser(pydantic_object=ResumeQualityEvaluation)
    
    prompt = PromptTemplate(
        template="""<s>[INST]Evaluate the quality of the following resume sections:

{resume}

Provide a detailed evaluation following this format:
{format_instructions}

For each section, evaluate the presence and quality of required elements:

1. Education:
   - Check for the presence of Degree, Year, and Institution for each education entry
   - Provide a score (0-10) for each education entry based on completeness and clarity

2. Work Experience:
   - Check for the presence of Job title, Company, dates, used technologies, Responsibilities, and Achievements for each work experience entry
   - Evaluate the quality of Responsibilities description (0-10)
   - Evaluate the quality of Achievements description (0-10)
   - Provide a score (0-10) for each work experience entry based on completeness, clarity, and the quality of descriptions

3. Profile:
   - Check for the presence of a brief overview, career goals, and objective
   - Provide an overall score (0-10) based on the completeness and clarity of the profile

Provide an overall score for each section on a scale of 0-10 based on the presence of elements and their quality where applicable.[/INST]""",
        input_variables=["resume"],
        partial_variables={"format_instructions": parser.get_format_instructions()}
    )
    
    return prompt.format(resume=text)

def calculate_section_detection_score(detected_sections):
    total_score = 0
    for section in detected_sections:
        if section in cv_sections['sections']:
            total_score += cv_sections['sections'][section]
    return total_score

def calculate_overall_score(evaluation: ResumeQualityEvaluation) -> float:
    education_weight = 0.3
    work_experience_weight = 0.5
    profile_weight = 0.2
    
    overall_score = (
        evaluation.education.overall_score * education_weight +
        evaluation.work_experience.overall_score * work_experience_weight +
        evaluation.profile.overall_score * profile_weight
    )
    
    return round(overall_score, 2)


__all__ = ['ResumeQualityEvaluation', 'get_personal_info_prompt', 'get_spelling_grammar_prompt', 
           'get_section_detection_prompt', 'get_content_quality_prompt', 
           'calculate_section_detection_score', 'calculate_overall_score']