diff --git a/hrflow/schemas.py b/hrflow/schemas.py index f322282..2fe18e5 100644 --- a/hrflow/schemas.py +++ b/hrflow/schemas.py @@ -241,6 +241,12 @@ class Experience(BaseModel): tasks: t.Optional[t.List[GeneralEntitySchema]] = Field( None, description="List of tasks of the Experience." ) + languages: t.Optional[t.List[GeneralEntitySchema]] = Field( + None, description="List of spoken languages of the profile" + ) + interests: t.Optional[t.List[GeneralEntitySchema]] = Field( + None, description="List of interests of the Experience." + ) class Education(BaseModel): @@ -274,6 +280,12 @@ class Education(BaseModel): tasks: t.Optional[t.List[GeneralEntitySchema]] = Field( None, description="List of tasks of the Education." ) + languages: t.Optional[t.List[GeneralEntitySchema]] = Field( + None, description="List of spoken languages of the profile" + ) + interests: t.Optional[t.List[GeneralEntitySchema]] = Field( + None, description="List of interests of the Experience." + ) class Attachment(BaseModel): diff --git a/hrflow/utils/__init__.py b/hrflow/utils/__init__.py index 50b7e47..cfbcd06 100644 --- a/hrflow/utils/__init__.py +++ b/hrflow/utils/__init__.py @@ -1,3 +1,5 @@ # noqa: F401 from .evaluation import generate_parsing_evaluation_report +from .scoring import is_valid_for_scoring +from .searching import is_valid_for_searching from .storing import get_all_jobs, get_all_profiles diff --git a/hrflow/utils/scoring.py b/hrflow/utils/scoring.py new file mode 100644 index 0000000..8067902 --- /dev/null +++ b/hrflow/utils/scoring.py @@ -0,0 +1,75 @@ +import typing as t + +from ..schemas import Education, Experience, HrFlowProfile +from .searching import is_valid_for_searching + + +def is_valid_experiences_for_scoring( + experience_list: t.Optional[t.List[Experience]], +) -> bool: + """ + Check if a list of experiences is valid for scoring + + Args: + experience_list: + List of experiences to check + Return: + True if the list of experiences is valid for + scoring, False otherwise + """ + for experience in experience_list: + if experience.title: + return True + + return False + + +def is_valid_educations_for_scoring( + education_list: t.Optional[t.List[Education]], +) -> bool: + """ + Check if a list of educations is valid for scoring + + Args: + education_list: + List of educations to check + Return: + True if the list of educations is valid for + scoring, False otherwise + """ + for education in education_list: + if education.title or education.school: + return True + return False + + +def is_valid_for_scoring( + profile: t.Union[t.Dict, HrFlowProfile], +) -> bool: + """ + Check if a profile is valid for scoring + + Based on the following schemas https://developers.hrflow.ai/docs/profiles-scoring + + Args: + client: + Hrflow client + profile: or + Profile to check + Return: + True if the profile is valid for scoring, + False otherwise + """ + if isinstance(profile, dict): + profile = HrFlowProfile.parse_obj(profile) + + if not isinstance(profile, HrFlowProfile): + raise ValueError("profile must be a dict or a HrFlowProfile object") + + return is_valid_for_searching(profile) and ( + is_valid_experiences_for_scoring(profile.experiences) + or is_valid_educations_for_scoring(profile.educations) + or bool(profile.summary) + or bool(profile.skills) + or bool(profile.tasks) + ) diff --git a/hrflow/utils/searching.py b/hrflow/utils/searching.py new file mode 100644 index 0000000..c204572 --- /dev/null +++ b/hrflow/utils/searching.py @@ -0,0 +1,67 @@ +import typing as t + +from ..schemas import HrFlowProfile, ProfileInfo + + +def is_valid_info_for_searching(info: ProfileInfo) -> bool: + """ + Check if the info part of a profile is valid for searching + + Based on the following schemas https://developers.hrflow.ai/docs/profiles-searching + + Args: + info: + Info part of the profile + """ + if not isinstance(info, ProfileInfo): + raise ValueError("info must be a ProfileInfo object") + + first_name_score = 1 if info.first_name else 0 + last_name_score = 1 if info.last_name else 0 + phone_score = 1 if info.phone else 0 + date_birth_score = 1 if info.date_birth else 0 + gender_score = 1 if info.gender else 0 + summary_score = 1 if info.summary else 0 + urls_score = 1 if info.urls else 0 + location_score = 1 if info.location else 0 + + info_score = ( + first_name_score + + last_name_score + + phone_score + + date_birth_score + + gender_score + + summary_score + + urls_score + + location_score + ) + info_score = info_score / 8 + has_person = info.first_name and info.last_name + + return info.email or has_person or info_score >= 0.5 + + +def is_valid_for_searching( + profile: t.Union[t.Dict, HrFlowProfile], +) -> bool: + """ + Check if a profile is valid for searching + + Based on the following schemas https://developers.hrflow.ai/docs/profiles-searching + + Args: + client: + Hrflow client + profile: or + Profile to check + Return: + True if the profile is valid for searching, + False otherwise + """ + if isinstance(profile, dict): + profile = HrFlowProfile.parse_obj(profile) + + if not isinstance(profile, HrFlowProfile): + raise ValueError("profile must be a dict or a HrFlowProfile object") + + return is_valid_info_for_searching(profile.info) and bool(profile.text)