diff --git a/backend/app/agent/linking_and_ranking_pipeline/experience_pipeline.py b/backend/app/agent/linking_and_ranking_pipeline/experience_pipeline.py
index acc47595a..2cd14a16a 100644
--- a/backend/app/agent/linking_and_ranking_pipeline/experience_pipeline.py
+++ b/backend/app/agent/linking_and_ranking_pipeline/experience_pipeline.py
@@ -8,7 +8,9 @@
from app.agent.agent_types import LLMStats
from app.agent.experience.work_type import WorkType
+from app.agent.linking_and_ranking_pipeline.infer_icatus_activities import InferIcatusActivitiesTool
from app.agent.linking_and_ranking_pipeline.cluster_responsibilities_tool import ClusterResponsibilitiesTool
+from .infer_icatus_activities.utils import IcatusClassificationLevel
from .infer_occupation_tool import InferOccupationTool
from .pick_top_skills_tool import PickTopSkillsTool
from .skill_linking_tool import SkillLinkingTool
@@ -96,6 +98,12 @@ class ExperiencePipelineConfig(BaseModel):
to the skills associated with the occupations found."
"""
+ icatus_classification_level: IcatusClassificationLevel = IcatusClassificationLevel.FIRST_LEVEL
+ """
+ Default is ClassificationLevel.FIRST_LEVEL
+ The classification level to use when inferring the icatus activities from the experience title and responsibilities.
+ """
+
model_config = ConfigDict(
extra="forbid"
)
@@ -143,6 +151,10 @@ def __init__(self, *, config: ExperiencePipelineConfig, search_services: SearchS
self._search_services = search_services
self._cluster_responsibilities_tool = ClusterResponsibilitiesTool()
self._infer_occupations_tool = InferOccupationTool(search_services.occupation_skill_search_service)
+ self._infer_icatus_activities_tool = InferIcatusActivitiesTool(
+ search_services.occupation_skill_search_service,
+ classification_level=config.icatus_classification_level
+ )
self._skills_linking_tool = SkillLinkingTool(search_services.skill_search_service)
self._top_skills_picker = PickTopSkillsTool()
self._logger = logging.getLogger(__class__.__name__)
@@ -289,14 +301,26 @@ async def handle_cluster(self, *,
llm_stats = []
# 2.1 Infer the occupations and associated skills
- inferred_occupations_response = await self._infer_occupations_tool.execute(experience_title=experience_title,
- company=company_name,
- work_type=work_type,
- responsibilities=responsibilities,
- country_of_interest=country_of_interest,
- number_of_titles=config.number_of_occupation_alt_titles,
- top_k=config.number_of_occupations_per_cluster,
- top_p=config.number_of_occupations_candidates_per_title)
+ if work_type == WorkType.UNSEEN_UNPAID:
+ inferred_occupations_response = await self._infer_icatus_activities_tool.execute(
+ experience_title=experience_title,
+ company=company_name,
+ work_type=work_type,
+ responsibilities=responsibilities,
+ country_of_interest=country_of_interest,
+ number_of_titles=config.number_of_occupation_alt_titles,
+ top_k=config.number_of_occupations_per_cluster,
+ top_p=config.number_of_occupations_candidates_per_title,
+ )
+ else:
+ inferred_occupations_response = await self._infer_occupations_tool.execute(experience_title=experience_title,
+ company=company_name,
+ work_type=work_type,
+ responsibilities=responsibilities,
+ country_of_interest=country_of_interest,
+ number_of_titles=config.number_of_occupation_alt_titles,
+ top_k=config.number_of_occupations_per_cluster,
+ top_p=config.number_of_occupations_candidates_per_title)
llm_stats.extend(inferred_occupations_response.llm_stats)
occupation_labels = [esco_occupation.occupation.preferredLabel for esco_occupation in inferred_occupations_response.esco_occupations]
# 2.2 Link responsibilities to the associated skills
diff --git a/backend/app/agent/linking_and_ranking_pipeline/infer_icatus_activities/__init__.py b/backend/app/agent/linking_and_ranking_pipeline/infer_icatus_activities/__init__.py
new file mode 100644
index 000000000..378042829
--- /dev/null
+++ b/backend/app/agent/linking_and_ranking_pipeline/infer_icatus_activities/__init__.py
@@ -0,0 +1 @@
+from .infer_icatus_activities_tool import InferIcatusActivitiesTool
\ No newline at end of file
diff --git a/backend/app/agent/linking_and_ranking_pipeline/infer_icatus_activities/_icatus_classification_llm.py b/backend/app/agent/linking_and_ranking_pipeline/infer_icatus_activities/_icatus_classification_llm.py
new file mode 100644
index 000000000..378430751
--- /dev/null
+++ b/backend/app/agent/linking_and_ranking_pipeline/infer_icatus_activities/_icatus_classification_llm.py
@@ -0,0 +1,81 @@
+import json
+import logging
+from typing import Optional
+
+from textwrap import dedent
+
+from pydantic import BaseModel
+
+from app.agent.agent_types import LLMStats
+from app.agent.llm_caller import LLMCaller
+from common_libs.llm.generative_models import GeminiGenerativeLLM
+from common_libs.llm.models_utils import LLMConfig, MODERATE_TEMPERATURE_GENERATION_CONFIG, JSON_GENERATION_CONFIG
+
+from .utils import IcatusClassificationLevel, IcatusFirstLevelNode, IcatusSecondLevelNode, TopLevelDivision
+
+class ClassificationLLMResponse(BaseModel):
+ icatus_node: TopLevelDivision | IcatusFirstLevelNode | IcatusSecondLevelNode
+ llm_stats: list[LLMStats]
+
+
+class _ClassificationLLMOutput(BaseModel):
+ reasoning: Optional[str]
+ dependent: bool
+ code: str
+
+
+def _get_prompt(*,
+ experience_title: str,
+ responsibilities: list[str],
+ ):
+ return dedent(""" \
+
+ 'Experience Title': {experience_title}
+ 'Responsibilities': {responsibilities}
+
+ """).format(
+ experience_title=experience_title,
+ responsibilities=json.dumps(responsibilities),
+ )
+
+
+class _IcatusClassificationLLM:
+ def __init__(self,
+ classification_level: IcatusClassificationLevel,
+ logger: logging.Logger):
+ self.classification_level = classification_level
+ self._llm = GeminiGenerativeLLM(
+ system_instructions=classification_level.get_prompt(),
+ # Even if we are generating a JSON output, we still need to set the generation config to MODERATE_TEMPERATURE_GENERATION_CONFIG
+ # as we want to generate a more creative response.
+ config=LLMConfig(generation_config=MODERATE_TEMPERATURE_GENERATION_CONFIG | JSON_GENERATION_CONFIG)
+ )
+ self._llm_caller: LLMCaller[_ClassificationLLMOutput] = LLMCaller[_ClassificationLLMOutput](
+ model_response_type=_ClassificationLLMOutput)
+ self._logger = logger
+
+ async def execute(
+ self, *,
+ experience_title: str,
+ responsibilities: list[str],
+ ) -> ClassificationLLMResponse:
+ """
+ Returns a classified Icatus Node depending on the experience title and responsibilities.
+ """
+
+ prompt = _get_prompt(
+ experience_title=experience_title,
+ responsibilities=responsibilities,
+ )
+ llm_response, llm_stats = await self._llm_caller.call_llm(
+ llm=self._llm,
+ llm_input=prompt,
+ logger=self._logger
+ )
+ if not llm_response.code:
+ self._logger.warning("Failed to classify the experience.")
+ raise ValueError("Experience was not classified correctly.")
+ return ClassificationLLMResponse(
+ icatus_node=self.classification_level.get_node_from_code(llm_response.code),
+ llm_stats=llm_stats
+ )
diff --git a/backend/app/agent/linking_and_ranking_pipeline/infer_icatus_activities/infer_icatus_activities_tool.py b/backend/app/agent/linking_and_ranking_pipeline/infer_icatus_activities/infer_icatus_activities_tool.py
new file mode 100644
index 000000000..ef1719c51
--- /dev/null
+++ b/backend/app/agent/linking_and_ranking_pipeline/infer_icatus_activities/infer_icatus_activities_tool.py
@@ -0,0 +1,99 @@
+import asyncio
+import logging
+
+from app.agent.experience.work_type import WorkType
+from app.agent.linking_and_ranking_pipeline.infer_occupation_tool.infer_occupation_tool import InferOccupationTool, InferOccupationToolOutput
+from app.countries import Country
+
+from ._icatus_classification_llm import _IcatusClassificationLLM
+from ..infer_occupation_tool._contextualization_llm import _ContextualizationLLM
+from .utils import IcatusTerminalNode, TopLevelDivision, IcatusClassificationLevel
+from app.vector_search.esco_search_service import OccupationSkillSearchService
+
+
+class InferIcatusActivitiesTool:
+ def __init__(
+ self,
+ occupation_skill_search_service: OccupationSkillSearchService,
+ classification_level: IcatusClassificationLevel
+ ):
+ self._logger = logging.getLogger(self.__class__.__name__)
+ self._occupation_skill_search_service = occupation_skill_search_service
+ self._infer_occupations_tool = InferOccupationTool(self._occupation_skill_search_service)
+ self.classification_level = classification_level
+
+ async def find_occupations(self, nodes: list[IcatusTerminalNode]):
+ occupation_data = await asyncio.gather(*(self._occupation_skill_search_service.get_by_esco_code(code=node.code) for node in nodes))
+ return occupation_data
+
+ def find_terminal_icatus_nodes(self, classification_response):
+ if self.classification_level == IcatusClassificationLevel.TOP_LEVEL and classification_response.icatus_node == TopLevelDivision.VOLUNTEERING: # Volunteering
+ return [node for node in IcatusTerminalNode if node.value.startswith("I5")]
+ elif self.classification_level == IcatusClassificationLevel.TOP_LEVEL:
+ return [node for node in IcatusTerminalNode if not node.value.startswith("I5")]
+ else:
+ return classification_response.icatus_node.get_terminal_nodes()
+
+ async def execute(self, *,
+ experience_title: str,
+ company: str,
+ work_type: WorkType,
+ responsibilities: list[str],
+ country_of_interest: Country,
+ number_of_titles: int,
+ top_k: int,
+ top_p: int,
+ ) -> InferOccupationToolOutput:
+
+ # 1. Classify the experience as one of the icatus skills
+ icatus_classification_llm = _IcatusClassificationLLM(
+ classification_level=self.classification_level,
+ logger=self._logger
+ )
+ classification_response = await icatus_classification_llm.execute(
+ experience_title=experience_title,
+ responsibilities=responsibilities,
+ )
+ # 2. Consider different possibilities based on the output
+
+ terminal_icatus_nodes = self.find_terminal_icatus_nodes(classification_response)
+ icatus_occupations = await self.find_occupations(terminal_icatus_nodes)
+ contextualization_llm = _ContextualizationLLM(
+ country_of_interest=country_of_interest,
+ number_of_titles=number_of_titles,
+ logger=self._logger)
+ icatus_contextualization_response = await contextualization_llm.execute(
+ experience_title=experience_title,
+ company=company,
+ work_type=work_type,
+ responsibilities=responsibilities,
+ number_of_titles=number_of_titles
+ )
+ if classification_response.icatus_node.is_volunteering() and len(icatus_occupations)< top_k:
+ # 2.1 If the classification is volunteering, proceed with the usual inference
+ # and pre-attaches existing volunteering occupations
+ esco_occupations = await self._infer_occupations_tool.execute(
+ experience_title=experience_title,
+ company=company,
+ work_type=work_type,
+ responsibilities=responsibilities,
+ country_of_interest=country_of_interest,
+ number_of_titles=number_of_titles,
+ top_k=top_k - len(terminal_icatus_nodes),
+ top_p=top_p
+ )
+ return InferOccupationToolOutput(
+ contextual_titles=icatus_contextualization_response.contextual_titles + esco_occupations.contextual_titles,
+ esco_occupations=icatus_occupations+esco_occupations.esco_occupations,
+ responsibilities=responsibilities,
+ llm_stats=classification_response.llm_stats +icatus_contextualization_response.llm_stats
+ )
+
+ # 2.2 If the classification is not volunteering return a pre-fixed list of occupations
+ # with their contextualized titles
+
+ return InferOccupationToolOutput(contextual_titles=icatus_contextualization_response.contextual_titles,
+ esco_occupations=icatus_occupations,
+ responsibilities=responsibilities,
+ llm_stats=classification_response.llm_stats + icatus_contextualization_response.llm_stats
+ )
diff --git a/backend/app/agent/linking_and_ranking_pipeline/infer_icatus_activities/utils.py b/backend/app/agent/linking_and_ranking_pipeline/infer_icatus_activities/utils.py
new file mode 100644
index 000000000..814eacae3
--- /dev/null
+++ b/backend/app/agent/linking_and_ranking_pipeline/infer_icatus_activities/utils.py
@@ -0,0 +1,255 @@
+import enum
+from textwrap import dedent
+
+class TopLevelDivision(enum.Enum):
+ VOLUNTEERING = "volunteering"
+ NON_VOLUNTEERING = "non_volunteering"
+
+ def is_volunteering(self):
+ return self == TopLevelDivision.VOLUNTEERING
+
+
+
+class IcatusFirstLevelNode(enum.Enum):
+ I3 = ("I3", "unpaid domestic services for household and family members", """Refers to activities to provide services for own final use (excluding unpaid caregiving services for household and family members classified under major division 4).
+Provision of 'services' is beyond the 2008 SNA production boundary but inside the General production boundary and covers:
+(i) household accounting and management, purchasing and/or transporting goods;
+(ii) preparing and/or serving meals, household waste disposal and recycling;
+(iii) cleaning, decorating and maintaining one's own dwelling or premises, durables and other goods, and gardening;
+(iv) caring for domestic animals or pets;
+(v) childcare and instruction, transporting and caring for elderly, dependent or other household and family members, etc. (major division 4)
+
+'Households and family members' refers to 'household members and related family members living in other households' who are related, to a specified degree, through blood, adoption or marriage.
+
+Note: In these divisions of activities it is assumed that working time arrangements are generally more informal or flexible compared to those under 1. Thus, this division does not include specific groups for short breaks and for lunch breaks. Activities associated with such breaks from work are classified in the corresponding class; for example, eating snack/meals is classified under 921 Eating meals/snack.""")
+ I4 = ("I4", "unpaid caregiving services for household and family members", """Refers to activities to provide caregiving services for own final use (excludes unpaid domestic services for household and family members classified under major division 3).
+Provision of 'services' is beyond the 2008 SNA production boundary but inside the General production boundary and covers:
+(i) household accounting and management, purchasing and/or transporting goods (major division 3);
+(ii) preparing and/or serving meals, household waste disposal and recycling (major division 3);
+(iii) cleaning, decorating and maintaining one's own dwelling or premises, durables and other goods, and gardening (classified under major division 3);
+(iv) caring for domestic animals or pets (classified under major division 3);
+(v) childcare and instruction, transporting and caring for elderly, dependent or other household and family members, etc.
+
+Care work refers to all those activities which are undertaken for family members including those belonging to another household either to comply with the law or out of love/moral obligations (obligation or in some countries by law).
+
+'Households and family members' refers to 'household members and related family members living in other households' who are related, to a specified degree, through blood, adoption or marriage.
+
+Note: In these divisions of activities it is assumed that working time arrangements are generally more informal or flexible compared to those under 11. Thus, this division does not include specific groups for short breaks and for lunch breaks. Activities associated with such breaks from work are classified in the corresponding class; for example, eating snack/meals is classified under 921 Eating meals/snack.""")
+ I5 = ("I5", "unpaid volunteer, trainee and other unpaid work", """Unpaid volunteer: Refers to any unpaid, non-compulsory activity to produce goods or provide services for others
+- 'Unpaid' is interpreted as the absence of remuneration in cash or in kind for work done or hours worked; nevertheless, volunteer workers may receive some small form of support or stipend in cash, when below one third of local market wages (e.g. for out–of–pocket expenses or to cover living expenses incurred for the activity), or in kind (e.g. meals, transportation, symbolic gifts).
+- 'Non-compulsory' is interpreted as work carried out without civil, legal or administrative requirement, that are different from the fulfilment of social responsibilities of a communal, cultural or religious nature;
+- Production 'for others' refers to work performed:
+(i) through, or for organizations comprising market and non-market units (i.e. organization-based volunteering) including through or for self-help, mutual aid or community-based groups of which the volunteer is a member (Division 52)
+(ii) for households other than the household of the volunteer worker or of related family members (i.e. direct volunteering) (Division 51)
+(Source: 19th ICLS para. 37)
+
+Unpaid trainee: Refers to any unpaid activity to produce goods or provide services for others, in order to acquire workplace experience or skills in a trade or profession.
+- 'Unpaid' is interpreted as the absence of remuneration in cash or in kind for work done or hours worked; nevertheless, these workers may receive some form of support, such as transfers of education stipends or grants, or occasional in cash or in kind support (e.g. a meal, drinks).
+- 'For others' refers to work performed in market and non-market units that are owned by non-household or non-family members.
+- Acquiring 'workplace experience or skills' may occur through traditional, formal or informal arrangements whether or not a specific qualification or certification is issued.
+(Source: 19th ICLS para. 33)
+
+Other unpaid work refers to activities such as unpaid community service and unpaid work by prisoners, when ordered by a court or similar authority, and unpaid military or alternative civilian service, and any other compulsory work performed without pay for others.
+(Source: 19th ICLS para. 8)""")
+
+ def __new__(cls, code, definition, description):
+ obj = object.__new__(cls)
+ obj._value_ = code
+ obj.code = code
+ obj.definition = definition
+ obj.description = description
+ return obj
+
+ def get_second_level_nodes(self):
+ return [node for node in IcatusSecondLevelNode if node.value.startswith(self.code)]
+
+ def get_terminal_nodes(self):
+ return [node for node in IcatusTerminalNode if node.value.startswith(self.code)]
+
+ def is_volunteering(self):
+ if self.code.startswith("I5"):
+ return True
+ return False
+
+ def get_prompt(self):
+ return f"{self.code}. {self.definition}: {self.description}"
+
+
+
+class IcatusSecondLevelNode(enum.Enum):
+ I31 = ("I31", "food and meals management and preparation", "Refers to all activities in connection with food and meals management and preparation for household and family members")
+ I32 = ("I32", "cleaning and maintaining of own dwelling and surroundings", "Refers to the cleaning and maintenance of the dwelling and surroundings.")
+ I33 = ("I33", "do-it-yourself decoration, maintenance and repair","Refers to decorating, maintaining and repairing of own dwelling, personal and household goods.")
+ I34 = ("I34", "care and maintenance of textiles and footwear", "Refers to caring and maintaining of textiles and footwear for household and family members.")
+ I35 = ("I35", "household management for own final use", "Refers to the management of the household. Activities can be undertaken outside or from home.")
+ I36 = ("I36", "pet care", "Refers to the care of own household or family member's pets.")
+ I37 = ("I37", "shopping for own household and family members", "Refers to the purchase of consumer and capital goods, and services for own household and family members.")
+ I41 = ("I41", "childcare and instruction", """Refers to the provision of care (physical and medical) and instruction to children.
+
+According to the Convention on the Rights of the Child, a child is defined as a person below the age of 18, unless the laws of a particular country set the legal age for adulthood younger. The Committee on the Rights of the Child, the monitoring body for the Convention, has encouraged States to review the age of majority if it is set below 18 and to increase the level of protection for all children under 18.
+
+According to the Principles and Recommendations for Population and Housing Censuses revision 3 (paragraph 3.441), for statistical purposes, “children” are defined as persons under 15 years of age, and “youths” are defined as those aged 15-24.""")
+ I42 = ("I42", "care for dependent adults", """Refers to the assistance and care provided to dependent adults.
+Dependent adults refers to persons suffering any physical or mental illness or any disability or impairment who require assistance or help from other person to undertake daily activities including older persons.
+This does not include adults who require temporary assistance.""")
+ I43 = ("I43", "help to non-dependent adult household and family members", """Refers to the provision of help to non-dependent adult household and family members.
+
+- 'Household and family members' refers to 'household members and related family members living in other households' who are related, to a specified degree, through blood, adoption or marriage.
+- Non-dependent adult refers to persons NOT suffering any physical or mental illness or any disability or impairment. Non-dependent adults might requiere temporary care and supervision due to temporary illness.""")
+ I44 = ("I44", "Refers to the travelling and/or accompanying goods or persons related to unpaid caregiving services for household and family members", "Refers to the travelling and/or accompanying goods or persons related to unpaid caregiving services for household and family members")
+ I51 = ("I51", "unpaid direct volunteering for other households", "Refers to unpaid, non-compulsory activities to produce goods or provide services as help to other households, not arranged by an organization.")
+ I52 = ("I52", "unpaid community- and organization-based volunteering", "Refers to unpaid, non-compulsory activities to produce goods or provide services as help, arranged by the community or an organization.")
+
+ def __new__(cls, code, definition, description):
+ obj = object.__new__(cls)
+ obj._value_ = code
+ obj.code = code
+ obj.definition = definition
+ obj.description = description
+ return obj
+
+ def get_first_level_nodes(self):
+ return IcatusFirstLevelNode(self.code[:2])
+
+ def get_terminal_nodes(self):
+ return [node for node in IcatusTerminalNode if node.value.startswith(self.code)]
+
+ def is_volunteering(self):
+ if self.code.startswith("I5"):
+ return True
+ return False
+
+ def get_prompt(self):
+ parent_node = self.get_first_level_nodes()
+ return f"""{self.code}. {parent_node.definition} - {self.definition}.
+{parent_node.description}. {self.description}"""
+
+class IcatusTerminalNode(enum.Enum):
+ I31_0 = ("I31_0", "food and meals management and preparation")
+ I32_0 = ("I32_0", "cleaning and maintaining of own dwelling and surroundings")
+ I33_0 = ("I33_0", "do-it-yourself decoration, maintenance and repair")
+ I34_0 = ("I34_0", "care and maintenance of textiles and footwear")
+ I35_0 = ("I35_0", "household management for own final use")
+ I36_0 = ("I36_0", "pet care")
+ I37_0 = ("I37_0", "shopping for own household and family members")
+ I41_0 = ("I41_0", "childcare and instruction")
+ I42_0 = ("I42_0", "care for dependent adults")
+ I43_0 = ("I43_0", "help to non-dependent adult household and family members")
+ I44_0 = ("I44_0", "travelling and accompanying goods or persons related to unpaid caregiving services for household and family members")
+ I51_1 = ("I51_1", "fixing and building things in other people's homes without getting paid")
+ I51_2 = ("I51_2", "shopping for others without getting paid")
+ I51_3 = ("I51_3", "caring for and teaching for children outside of your home without getting paid")
+ I51_4 = ("I51_4", "helping adults outside of your home who need care without getting paid")
+ I51_5 = ("I51_5", "helping in other people's businesses without getting paid")
+ I52_1 = ("I52_1", "cleaning or fixing roads or buildings without getting paid")
+ I52_2 = ("I52_2", "cooking or cleaning for other people's homes without getting paid")
+ I52_3 = ("I52_3", "helping with sports, music or other cultural activities without getting paid")
+ I52_4 = ("I52_4", "helping with office work without getting paid")
+
+ def __new__(cls, code, description):
+ obj = object.__new__(cls)
+ obj._value_ = code
+ obj.code = code
+ obj.description = description
+ return obj
+
+ def get_parent_node(self):
+ return IcatusSecondLevelNode(self.value[:3])
+
+ def is_volunteering(self):
+ if self.code.startswith("I5"):
+ return True
+ return False
+
+LEVEL_TO_PROMPT = [
+ dedent("""\
+
+ You are an expert in classifying experiences in the unseen economy as either volunteering or non_volunteering.
+ You should classify an experience as 'volunteering' or 'non_volunteering'. Volunteering work is described as unpaid work for other household, communities or organizations. On the other hand, work for one's own household or family members is not considered volunteering.
+ In identifying dependent, keep in mind that household and family members are dependent and they pertain to non-volunteering work, while everyone else including neighbors, communities and so on are non-dependent, which pertain volunteering work.
+ You are given an experience title, together with responsibilities that the user had with respect to that experience.
+ Your task is to return a json output as described below.
+
+ #Input Structure
+ The input structure is composed of:
+ 'Experience Title': The title of the experience.
+ 'Responsibilities': A list of responsibilities/activities/skills/behaviour that we know about the job.
+ You should use the above information only to infer the context and you shouldn't return it as output.
+
+ #JSON Output instructions
+ Your response must always be a JSON object with the following schema:
+ {
+ "dependent": boolean identifying if the experience is for a dependent adult or not,
+ "reasoning": Why you chose to return the specific title and how it aligns with the input,
+ "code": a string between either `volunteering` or `non_volunteering`.
+ }
+
+ """),
+ dedent("""\
+
+ You are an expert in classifying experiences in the unseen economy as one of the top level classes of the ICATUS database.
+ You should classify an experience as one of the following:
+ """) +'\n'.join([node.get_prompt() for node in IcatusFirstLevelNode])+dedent("""
+ You are given an experience title, together with responsibilities that the user had with respect to that experience.
+ In identifying dependent, keep in mind that household and family members are dependent and they pertain to the codes I3 and I4, while everyone else including neighbors, communities and so on are non-dependent, which pertain to the code I5.
+ Your task is to return a json output as described below.
+
+ #Input Structure
+ The input structure is composed of:
+ 'Experience Title': The title of the experience.
+ 'Responsibilities': A list of responsibilities/activities/skills/behaviour that we know about the job.
+ You should use the above information only to infer the context and you shouldn't return it as output.
+
+ #JSON Output instructions
+ Your response must always be a JSON object with the following schema:
+ {
+ "dependent": boolean identifying if the experience is for a dependent adult or not,
+ "reasoning": Why you chose to return the specific title and how it aligns with the input,
+ "code": One of I3, I4 and I5, depending on how much the experience matches the description and whether dependent is true.
+ }
+
+ """),
+ dedent("""\
+
+ You are an expert in classifying experiences in the unseen economy as one of the top level classes of the ICATUS database.
+ You should classify an experience as one of the following:
+ """) +'\n'.join([node.get_prompt() for node in IcatusSecondLevelNode])+dedent("""
+ You are given an experience title, together with responsibilities that the user had with respect to that experience.
+ In identifying dependent, keep in mind that household and family members are dependent and they pertain to the codes starting with I3 and I4, while everyone else including neighbors, communities and so on are non-dependent, which pertain to codes starting with I5.
+ Your task is to return a json output as described below.
+
+ #Input Structure
+ The input structure is composed of:
+ 'Experience Title': The title of the experience.
+ 'Responsibilities': A list of responsibilities/activities/skills/behaviour that we know about the job.
+ You should use the above information only to infer the context and you shouldn't return it as output.
+
+ #JSON Output instructions
+ Your response must always be a JSON object with the following schema:
+ {
+ "dependent": boolean identifying if the experience is for a dependent adult or not,
+ "reasoning": Why you chose to return the specific dependent and title and how it aligns with the input,
+ "code": One of the provided ICATUS codes with structure `Ixx`, depending on how much the experience matches the description.
+ }
+
+ """)
+
+]
+
+class IcatusClassificationLevel(enum.Enum):
+ TOP_LEVEL = (TopLevelDivision, 0)
+ FIRST_LEVEL = (IcatusFirstLevelNode, 1)
+ SECOND_LEVEL = (IcatusSecondLevelNode, 2)
+
+ def __new__(cls, level_enum, index):
+ obj = object.__new__(cls)
+ obj._value_ = index
+ obj.level_enum = level_enum
+ obj.index = index
+ return obj
+
+ def get_prompt(self):
+ return LEVEL_TO_PROMPT[self.value]
+
+ def get_node_from_code(self, code: str):
+ return self.level_enum(code)
diff --git a/backend/app/agent/linking_and_ranking_pipeline/skill_linking_tool/skills_linking_tool.py b/backend/app/agent/linking_and_ranking_pipeline/skill_linking_tool/skills_linking_tool.py
index d9e734ca2..37ded497c 100644
--- a/backend/app/agent/linking_and_ranking_pipeline/skill_linking_tool/skills_linking_tool.py
+++ b/backend/app/agent/linking_and_ranking_pipeline/skill_linking_tool/skills_linking_tool.py
@@ -72,7 +72,7 @@ async def execute(self, *,
for skill in occupation_skills_entity.associated_skills:
if is_icatus and (not only_high_signal_skills or skill.signallingValueLabel == "high"):
esco_skills_uuids.append(skill.UUID)
- elif not is_icatus and (not only_essential_skills or skill.relationType == "essential"):
+ elif not is_icatus and (not only_essential_skills or skill.relationType == "essential") or not associated_skill.relationType:
esco_skills_uuids.append(skill.UUID)
# remove duplicates
esco_skills_uuids = list(set(esco_skills_uuids))
diff --git a/backend/evaluation_tests/linking_and_ranking_pipeline/experience_pipeline_test.py b/backend/evaluation_tests/linking_and_ranking_pipeline/experience_pipeline_test.py
index df2919047..49192749b 100644
--- a/backend/evaluation_tests/linking_and_ranking_pipeline/experience_pipeline_test.py
+++ b/backend/evaluation_tests/linking_and_ranking_pipeline/experience_pipeline_test.py
@@ -1,5 +1,6 @@
import logging
from typing import Optional, Awaitable
+import json
import pytest
@@ -20,6 +21,37 @@ class ExperiencePipelineTestCase(CompassTestCase):
given_work_type: WorkType
expected_top_skills: list[str]
+ @classmethod
+ def from_custom_dict(cls, data: dict):
+ # Custom parsing logic
+ parsed_data = {}
+ parsed_data["name"] = data['name']
+ parsed_data["given_experience_title"] = data['given_experience_title']
+ parsed_data["given_responsibilities"] = data['given_responsibilities']
+ parsed_data["given_company_name"] = data['given_company_name']
+ parsed_data["given_country_of_interest"] = Country(data['given_country_of_interest'])
+ parsed_data["given_work_type"] = WorkType(data['given_work_type'])
+ parsed_data["expected_top_skills"] = data['expected_top_skills']
+ print(parsed_data)
+ return cls.model_validate(parsed_data)
+
+def get_test_cases_from_jsonl(jsonl_path):
+ all_test_cases = []
+ with open(jsonl_path, 'rt') as json_file:
+ for line in json_file:
+ test_case = json.loads(line)
+ all_test_cases.append(
+ ExperiencePipelineTestCase(
+ name = test_case['name'],
+ given_experience_title = test_case['given_experience_title'],
+ given_responsibilities = test_case['given_responsibilities'],
+ given_company_name = test_case['given_company_name'],
+ given_country_of_interest = Country(test_case['given_country_of_interest']),
+ given_work_type = WorkType(test_case['given_work_type']),
+ expected_top_skills = test_case['expected_top_skills']
+ )
+ )
+ return all_test_cases
test_cases = [
ExperiencePipelineTestCase(
@@ -140,14 +172,14 @@ class ExperiencePipelineTestCase(CompassTestCase):
expected_top_skills=['evaluate garment quality']
),
ExperiencePipelineTestCase(
- name="Icatus I34_4",
- given_experience_title="I clean my shoes",
- given_company_name="Home",
- given_responsibilities=['Repair and restore damaged clothing and footwear to a presentable condition.'],
- given_country_of_interest=Country.SOUTH_AFRICA,
- given_work_type=WorkType.UNSEEN_UNPAID,
- expected_top_skills=['manufacture wearing apparel products']
- ),
+ name="Icatus I34_4",
+ given_experience_title="I clean my shoes",
+ given_company_name="Home",
+ given_responsibilities=['Repair and restore damaged clothing and footwear to a presentable condition.'],
+ given_country_of_interest=Country.SOUTH_AFRICA,
+ given_work_type=WorkType.UNSEEN_UNPAID,
+ expected_top_skills=['manufacture wearing apparel products']
+ ),
ExperiencePipelineTestCase(
name="Icatus I32_1",
given_experience_title="I clean the windows ",
diff --git a/backend/evaluation_tests/linking_and_ranking_pipeline/icatus_synthetic_responsibilities.jsonl b/backend/evaluation_tests/linking_and_ranking_pipeline/icatus_synthetic_responsibilities.jsonl
new file mode 100644
index 000000000..88d5ca0c1
--- /dev/null
+++ b/backend/evaluation_tests/linking_and_ranking_pipeline/icatus_synthetic_responsibilities.jsonl
@@ -0,0 +1,100 @@
+{"name": "I31_0-0", "given_experience_title": "I cook meat dishes for my family", "given_company_name": "Home", "given_responsibilities": ["Prepare and cook meat dishes according to family preferences and dietary needs"], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["cook meat dishes"]}
+{"name": "I31_0-1", "given_experience_title": "I prepare meals for my family and friends", "given_company_name": "Home", "given_responsibilities": ["Wash and iron tablecloths, napkins, and other linens used for meal preparation and dining"], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["clean household linens"]}
+{"name": "I31_0-2", "given_experience_title": "I help prepare meals for my family and friends", "given_company_name": "Home", "given_responsibilities": ["Arrange tables and set the table for meals, including placing silverware, napkins, and glasses."], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["arrange tables"]}
+{"name": "I31_0-3", "given_experience_title": "I plan and prepare meals for my family, ensuring compliance with food safety regulations and ethical sourcing practices.", "given_company_name": "Home", "given_responsibilities": ["Research and understand legislation regarding animal origin products, ensuring compliance with regulations for safe and ethical food preparation."], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["legislation about animal origin products"]}
+{"name": "I31_0-4", "given_experience_title": "I helped prepare a large meal for a community event", "given_company_name": "Home", "given_responsibilities": ["Prepared chicken breasts for a large group by marinating and grilling them"], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["prepare meat products for use in a dish"]}
+{"name": "I32_0-0", "given_experience_title": "I maintain a clean and comfortable home environment", "given_company_name": "Home", "given_responsibilities": ["Vacuum carpets and rugs regularly to remove dirt, dust, and allergens, ensuring a clean and healthy living space"], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["vacuum surfaces"]}
+{"name": "I32_0-1", "given_experience_title": "I helped my neighbor fix a leaky gas pipe in their kitchen", "given_company_name": "Home", "given_responsibilities": ["Prepared copper gas-lines pipes for installation, ensuring proper connections and safety standards were met."], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["prepare copper gas-lines pipes"]}
+{"name": "I32_0-2", "given_experience_title": "I maintain a safe and secure environment for my family in our home", "given_company_name": "Home", "given_responsibilities": ["Ensure that all areas are free of hazards, such as loose objects, slippery surfaces, or exposed electrical wires, to prevent accidents and injuries."], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["secure working area"]}
+{"name": "I32_0-3", "given_experience_title": "Maintaining my garden by removing weeds", "given_company_name": "Home", "given_responsibilities": ["Identify and remove weeds from my garden beds and pathways, using hand tools and environmentally friendly methods to prevent their regrowth."], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["perform weed control operations"]}
+{"name": "I32_0-4", "given_experience_title": "I repaired a broken washing machine in my home", "given_company_name": "Home", "given_responsibilities": ["Collected the broken washing machine and prepared it for disposal"], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["collect broken appliances"]}
+{"name": "I33_0-0", "given_experience_title": "I reupholstered my dining room chairs", "given_company_name": "Home", "given_responsibilities": ["Selected appropriate fabric types based on durability, comfort, and aesthetic preferences for the dining room chairs."], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["fabric types"]}
+{"name": "I33_0-1", "given_experience_title": "I replaced the brake pads on my car", "given_company_name": "Home", "given_responsibilities": ["Inspecting and replacing worn brake pads to ensure optimal braking performance"], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["maintain braking system"]}
+{"name": "I33_0-2", "given_experience_title": "I rewired the lighting in my kitchen", "given_company_name": "Home", "given_responsibilities": ["I studied the existing electrical wiring plans to understand the current setup and then created a new plan for the kitchen lighting, ensuring proper circuit allocation and safety standards."], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["electrical wiring plans"]}
+{"name": "I33_0-3", "given_experience_title": "I repaired a leaky faucet in my bathroom", "given_company_name": "Home", "given_responsibilities": ["Ensured personal safety by wearing appropriate gloves and eye protection while handling tools and potentially hazardous materials"], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["use personal protection equipment"]}
+{"name": "I33_0-4", "given_experience_title": "I repaired the fence in my backyard", "given_company_name": "Home", "given_responsibilities": ["Worked in various weather conditions to repair the fence, ensuring it was structurally sound and aesthetically pleasing."], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["work in outdoor conditions"]}
+{"name": "I34_0-0", "given_experience_title": "I help my family members mend and clean their clothes and shoes", "given_company_name": "Home", "given_responsibilities": ["I identify and separate different types of accessories, such as buttons, zippers, and laces, to ensure they are cleaned or repaired appropriately."], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["distinguish accessories"]}
+{"name": "I34_0-1", "given_experience_title": "I maintain the washing machine and dryer in my household", "given_company_name": "Home", "given_responsibilities": ["Perform routine maintenance tasks on the washing machine and dryer, including cleaning, troubleshooting minor issues, and ensuring optimal performance."], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["perform machine maintenance"]}
+{"name": "I34_0-2", "given_experience_title": "I help my family wash and clean clothes", "given_company_name": "Home", "given_responsibilities": ["Remove stains from clothing using various methods, such as pre-treating, soaking, and washing"], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["eliminate stains"]}
+{"name": "I34_0-3", "given_experience_title": "I helped fix a friend's ripped jeans", "given_company_name": "Home", "given_responsibilities": ["I identified the tear, assessed the damage, and devised a solution to repair the jeans using a sewing machine and thread."], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["create solutions to problems"]}
+{"name": "I34_0-4", "given_experience_title": "I help mend clothes for family and friends", "given_company_name": "Home", "given_responsibilities": ["Cutting and patching holes in clothing to repair tears and rips"], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["cut fabrics"]}
+{"name": "I35_0-0", "given_experience_title": "I track our household expenses and income to ensure we stay within budget", "given_company_name": "Home", "given_responsibilities": ["Maintain accurate records of household income and expenses, including bills, groceries, and other expenditures"], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["maintain financial records"]}
+{"name": "I35_0-1", "given_experience_title": "I manage my household budget and allocate funds for bills", "given_company_name": "Home", "given_responsibilities": ["I track all household bills and allocate funds from the household budget to ensure timely payment"], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["allocate bills"]}
+{"name": "I35_0-2", "given_experience_title": "I track and manage our family budget", "given_company_name": "Home", "given_responsibilities": ["Create and maintain a detailed record of all household income and expenses, ensuring accurate tracking of payroll and other financial transactions."], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["manage payroll reports"]}
+{"name": "I35_0-3", "given_experience_title": "I helped my family create a weekly meal plan by interviewing each member about their dietary preferences and scheduling needs.", "given_company_name": "Home", "given_responsibilities": ["I documented the interviews with each family member, noting their dietary preferences, allergies, and availability for meal preparation and cleanup, to create a comprehensive meal plan that met everyone's needs."], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["document interviews"]}
+{"name": "I35_0-4", "given_experience_title": "I plan and manage household activities to ensure everyone's needs are met", "given_company_name": "Home", "given_responsibilities": ["Identify and address the needs and preferences of household members to create a positive and satisfying living experience"], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["manage the customer experience"]}
+{"name": "I36_0-0", "given_experience_title": "I helped care for my neighbor's dog while they were on vacation", "given_company_name": "Home", "given_responsibilities": ["Prepared and provided nutritious meals for the dog, ensuring they received the appropriate amount of food based on their age, breed, and activity level."], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["animal nutrition"]}
+{"name": "I36_0-1", "given_experience_title": "I walk my neighbor's dog every day", "given_company_name": "Home", "given_responsibilities": ["Implement daily exercise routines for the dog, including walking, running, and playing fetch, to ensure its physical and mental well-being."], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["implement exercise activities for animals"]}
+{"name": "I36_0-2", "given_experience_title": "I volunteer at the local animal shelter", "given_company_name": "Home", "given_responsibilities": ["Communicate with potential adopters about the needs and personalities of the animals"], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["communicate with customers"]}
+{"name": "I36_0-3", "given_experience_title": "I volunteered at a local animal shelter, caring for cats and dogs", "given_company_name": "Home", "given_responsibilities": ["Ensured the cleanliness and safety of the animal enclosures, including regular cleaning, refilling food and water, and maintaining a comfortable living environment for the animals."], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["maintain animal accommodation"]}
+{"name": "I36_0-4", "given_experience_title": "I volunteer at a local animal shelter, caring for dogs", "given_company_name": "Home", "given_responsibilities": ["Bathe dogs, ensuring they are clean and comfortable"], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["bathe dogs"]}
+{"name": "I37_0-0", "given_experience_title": "Assisted my grandmother with grocery shopping", "given_company_name": "Home", "given_responsibilities": ["Helped my grandmother navigate the store, select items, and carry groceries to the car"], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["assist disable passengers"]}
+{"name": "I37_0-1", "given_experience_title": "I help my family stay up-to-date on the latest fashion trends", "given_company_name": "Home", "given_responsibilities": ["I research and identify current fashion trends to help my family make informed clothing and accessory purchases"], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["trends in fashion"]}
+{"name": "I37_0-2", "given_experience_title": "I helped my grandmother shop for groceries after her knee surgery", "given_company_name": "Home", "given_responsibilities": ["I helped my grandmother choose groceries that were easy for her to prepare and eat, and I made sure that she had everything she needed to stay healthy."], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["empathise with the healthcare user"]}
+{"name": "I37_0-3", "given_experience_title": "Assisted my grandmother with her daily tasks and medication while she was recovering from surgery at home", "given_company_name": "Home", "given_responsibilities": ["Provided emotional support, assisted with medication reminders and administration, and helped with daily tasks like bathing and dressing to ensure my grandmother's comfort and well-being."], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["support nurses"]}
+{"name": "I37_0-4", "given_experience_title": "I handle customer service inquiries for online grocery orders for my family", "given_company_name": "Home", "given_responsibilities": ["Follow up with vendors and retailers to address any issues or concerns related to purchased items, ensuring timely resolution and customer satisfaction."], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["provide customer follow-up services"]}
+{"name": "I41_0-0", "given_experience_title": "I am responsible for the care and well-being of my younger siblings", "given_company_name": "Home", "given_responsibilities": ["I ensure their safety by implementing age-appropriate rules and supervision, and by teaching them about potential dangers and how to stay safe."], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["promote the safeguarding of young people"]}
+{"name": "I41_0-1", "given_experience_title": "I helped my younger sibling overcome their anxiety about starting school", "given_company_name": "Home", "given_responsibilities": ["Developed strategies and implemented techniques to manage my sibling's anxiety, including positive reinforcement and calming exercises, leading to a more positive school experience."], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["behavioural disorders"]}
+{"name": "I41_0-2", "given_experience_title": "Preparing healthy meals for children", "given_company_name": "Home", "given_responsibilities": ["Plan and prepare nutritious and appealing meals for children, considering their age, dietary needs, and preferences, using various cooking techniques."], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["use cooking techniques"]}
+{"name": "I41_0-3", "given_experience_title": "I helped my younger sibling learn to ride a bike", "given_company_name": "Home", "given_responsibilities": ["I took responsibility for ensuring my sibling's safety while learning to ride a bike, including making sure they wore a helmet and explaining the rules of the road."], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["accept own accountability"]}
+{"name": "I41_0-4", "given_experience_title": "Helping my younger sibling with their homework and emotional needs", "given_company_name": "Home", "given_responsibilities": ["Consulting with my parents and teachers to understand their learning challenges and provide appropriate support"], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["consult student's support system"]}
+{"name": "I42_0-0", "given_experience_title": "Assisted an elderly neighbor with managing their mail and correspondence", "given_company_name": "Home", "given_responsibilities": ["Sorted and organized incoming mail, ensuring timely delivery of important documents and bills"], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["handle mail"]}
+{"name": "I42_0-1", "given_experience_title": "Volunteering at a senior center and providing support to elderly residents", "given_company_name": "Home", "given_responsibilities": ["Ensuring the safety and well-being of children who may visit or be present at the senior center, by implementing and adhering to safeguarding policies and procedures."], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["promote the safeguarding of young people"]}
+{"name": "I42_0-2", "given_experience_title": "Volunteered at a local clinic providing healthcare to teenagers", "given_company_name": "Home", "given_responsibilities": ["Provided medical care and advice to adolescents, including managing common health issues, promoting healthy habits, and addressing concerns related to their physical and mental well-being."], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["adolescence medicine"]}
+{"name": "I42_0-3", "given_experience_title": "Volunteering at a local hospital to support patients and their families", "given_company_name": "Home", "given_responsibilities": ["Collaborate with nurses, doctors, and other healthcare professionals to provide comprehensive care to patients, ensuring smooth communication and coordination of services."], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["work in multidisciplinary health teams"]}
+{"name": "I42_0-4", "given_experience_title": "I volunteer at a senior center, providing phone support to elderly individuals", "given_company_name": "Home", "given_responsibilities": ["Communicate with seniors via telephone to address their needs, provide companionship, and offer support"], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["communicate by telephone"]}
+{"name": "I43_0-0", "given_experience_title": "Assisted my mother in adjusting to life after a stroke", "given_company_name": "Home", "given_responsibilities": ["Provided emotional support, helped with daily tasks, and adapted the home environment to accommodate her physical limitations."], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["support individuals to adjust to physical disability"]}
+{"name": "I43_0-1", "given_experience_title": "Assisted my elderly grandmother with daily tasks and ensured her safety in the home", "given_company_name": "Home", "given_responsibilities": ["Monitored my grandmother's health and well-being, ensuring she was safe from falls and other hazards, and promptly addressing any concerns or needs."], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["ensure safety of healthcare users"]}
+{"name": "I43_0-2", "given_experience_title": "Assisted my grandmother with her recovery after a fall", "given_company_name": "Home", "given_responsibilities": ["Monitored her condition, adjusted her care plan based on her changing needs, and communicated with medical professionals as necessary"], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["respond to changing situations in health care"]}
+{"name": "I43_0-3", "given_experience_title": "I organized weekly family game nights to foster connection and shared experiences.", "given_company_name": "Home", "given_responsibilities": ["Plan and facilitate activities that encourage interaction and communication among family members, promoting a sense of belonging and reducing social isolation."], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["promote prevention of social isolation"]}
+{"name": "I43_0-4", "given_experience_title": "I help prepare meals for my family, ensuring everyone's dietary needs are met.", "given_company_name": "Home", "given_responsibilities": ["Identify and manage food allergies in the household, ensuring all meals are prepared safely and appropriately."], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["food allergies"]}
+{"name": "I44_0-0", "given_experience_title": "I plan activities for my children and their friends", "given_company_name": "Home", "given_responsibilities": ["Plan and organize activities for children, including games, crafts, and outings"], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["plan youth activities"]}
+{"name": "I44_0-1", "given_experience_title": "I volunteer as a mentor for at-risk youth", "given_company_name": "Home", "given_responsibilities": ["Provide guidance and encouragement to help youth develop positive self-esteem, build healthy relationships, and make responsible choices."], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["support the positiveness of youths"]}
+{"name": "I44_0-2", "given_experience_title": "I help my child with their homework and school projects", "given_company_name": "Home", "given_responsibilities": ["Assist my child with understanding their schoolwork and completing assignments"], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["assist students in their learning"]}
+{"name": "I44_0-3", "given_experience_title": "I help my child with their homework and provide constructive feedback on their work", "given_company_name": "Home", "given_responsibilities": ["Provide constructive feedback to my child on their homework, focusing on areas for improvement and celebrating their successes"], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["give constructive feedback"]}
+{"name": "I44_0-4", "given_experience_title": "I help my child learn to tie their shoes and button their clothes", "given_company_name": "Home", "given_responsibilities": ["Assist my child in developing fine motor skills and self-sufficiency by teaching them how to tie their shoes and button their clothes"], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["assist children in developing personal skills"]}
+{"name": "I51_1-0", "given_experience_title": "Shoveled snow from my neighbor's driveway after a blizzard", "given_company_name": "Home", "given_responsibilities": ["Removed snow from the driveway and walkway to ensure safe access to the home"], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["remove snow"]}
+{"name": "I51_1-1", "given_experience_title": "Volunteering at a Habitat for Humanity build", "given_company_name": "Home", "given_responsibilities": ["Interpreting 3D plans to understand the layout and construction details of the house being built"], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["interpret 3D plans"]}
+{"name": "I51_1-2", "given_experience_title": "I helped my neighbor fix their broken washing machine", "given_company_name": "Home", "given_responsibilities": ["Used a multimeter to diagnose the issue with the washing machine's control board and replaced faulty components"], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["use diagnostic tools for electronic repairs"]}
+{"name": "I51_1-3", "given_experience_title": "Volunteering at a local community center to help fix broken doors", "given_company_name": "Home", "given_responsibilities": ["Using traditional tools like screwdrivers, hammers, and nails to repair damaged door frames and hinges"], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["use traditional toolbox tools"]}
+{"name": "I51_1-4", "given_experience_title": "I helped clean out my neighbor's attic", "given_company_name": "Home", "given_responsibilities": ["Cleaned and organized the attic, including removing dust, cobwebs, and debris from hard-to-reach areas."], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["clean confined spaces"]}
+{"name": "I51_2-0", "given_experience_title": "I helped my grandmother choose a new pair of boots for her birthday", "given_company_name": "Home", "given_responsibilities": ["I researched current fashion trends for boots and helped her choose a pair that was both stylish and comfortable"], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["apply fashion trends to footwear and leather goods"]}
+{"name": "I51_2-1", "given_experience_title": "I helped my elderly neighbor with grocery shopping", "given_company_name": "Home", "given_responsibilities": ["Handled and transported my neighbor's shopping bags and luggage to ensure their safety and convenience"], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["handle guest luggage"]}
+{"name": "I51_2-2", "given_experience_title": "I help my elderly neighbor with grocery shopping", "given_company_name": "Home", "given_responsibilities": ["Maintain a positive and respectful relationship with my neighbor, ensuring their needs and preferences are met during the shopping process."], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["maintain relationship with customers"]}
+{"name": "I51_2-3", "given_experience_title": "I helped my friend choose a new outfit for a job interview", "given_company_name": "Home", "given_responsibilities": ["Advised on clothing style and provided feedback on different outfit options to help my friend choose an appropriate and professional look for the interview"], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["advise on clothing style"]}
+{"name": "I51_2-4", "given_experience_title": "I helped my neighbor with their grocery shopping", "given_company_name": "Home", "given_responsibilities": ["Followed a list of items provided by my neighbor to ensure all necessary groceries were purchased"], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["execute working instructions"]}
+{"name": "I51_3-0", "given_experience_title": "Volunteering at a local daycare center", "given_company_name": "Home", "given_responsibilities": ["Providing care and attention to infants, including feeding, changing diapers, and soothing them"], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["baby care"]}
+{"name": "I51_3-1", "given_experience_title": "Volunteer at a local after-school program for underprivileged children", "given_company_name": "Home", "given_responsibilities": ["Identify the individual learning needs of each child and tailor educational activities accordingly"], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["identify clients' needs"]}
+{"name": "I51_3-2", "given_experience_title": "Volunteer at a local after-school program", "given_company_name": "Home", "given_responsibilities": ["Prepare healthy snacks and meals for the children, using various food preparation techniques to ensure nutritional and appealing options."], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["use food preparation techniques"]}
+{"name": "I51_3-3", "given_experience_title": "Volunteer at a local after-school program for underprivileged children", "given_company_name": "Home", "given_responsibilities": ["Coordinate educational programs for children, including planning activities, managing resources, and ensuring a safe and engaging learning environment"], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["coordinate educational programmes"]}
+{"name": "I51_3-4", "given_experience_title": "Volunteering as a reading tutor at the local library", "given_company_name": "Home", "given_responsibilities": ["Provide constructive feedback to children on their reading skills, helping them improve their comprehension and fluency."], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["give constructive feedback"]}
+{"name": "I51_4-0", "given_experience_title": "Volunteering at a local disability support center", "given_company_name": "Home", "given_responsibilities": ["Providing assistance with daily living activities, such as dressing, bathing, and mobility, to individuals with disabilities"], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["disability care"]}
+{"name": "I51_4-1", "given_experience_title": "Volunteering at a senior center to help residents with communication difficulties", "given_company_name": "Home", "given_responsibilities": ["Assisted residents with various communication needs, including those with hearing impairments, speech difficulties, and cognitive challenges, to ensure their well-being and social engagement."], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["support social service users with specific communication needs"]}
+{"name": "I51_4-2", "given_experience_title": "I help clean the homes of elderly neighbors", "given_company_name": "Home", "given_responsibilities": ["Vacuum carpets and floors to maintain a clean and healthy living environment"], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["vacuum surfaces"]}
+{"name": "I51_4-3", "given_experience_title": "Volunteering at a senior center to help seniors stay active", "given_company_name": "Home", "given_responsibilities": ["Lead group exercise classes, provide nutritional advice, and encourage healthy eating habits to promote overall well-being."], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["promote healthy lifestyle"]}
+{"name": "I51_4-4", "given_experience_title": "Volunteer at a local senior center", "given_company_name": "Home", "given_responsibilities": ["Maintain effective communication channels between staff, volunteers, and residents to ensure smooth operations and address any concerns promptly."], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["maintain internal communication systems"]}
+{"name": "I51_5-0", "given_experience_title": "Volunteered at a local bookstore, assisting with customer service and book organization", "given_company_name": "Home", "given_responsibilities": ["Processed customer orders, ensuring accurate fulfillment of requested books and related information"], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["process commissioned instructions"]}
+{"name": "I51_5-1", "given_experience_title": "Volunteered at a local bakery to help with safety procedures", "given_company_name": "Home", "given_responsibilities": ["Ensured compliance with fire safety regulations, including conducting fire drills and maintaining fire extinguishers"], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["fire safety regulations"]}
+{"name": "I51_5-2", "given_experience_title": "Volunteered at a local bakery to help with pest control", "given_company_name": "Home", "given_responsibilities": ["Performed routine pest control checks and implemented preventative measures to ensure a pest-free environment for the bakery."], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["perform pest control"]}
+{"name": "I51_5-3", "given_experience_title": "Assisted with organizing a local farmers market", "given_company_name": "Home", "given_responsibilities": ["Followed instructions from the market organizer to set up booths, arrange produce, and manage customer flow"], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["execute working instructions"]}
+{"name": "I51_5-4", "given_experience_title": "Volunteered at a local bookstore, assisting with customer service and processing returns", "given_company_name": "Home", "given_responsibilities": ["Processed customer refunds for returned or damaged items, ensuring accurate calculations and timely processing"], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["process refunds"]}
+{"name": "I52_1-0", "given_experience_title": "Volunteering to help paint lines on the local park's basketball court", "given_company_name": "Home", "given_responsibilities": ["Using paint and stencils to demarcate the court lines and boundaries for safe and organized play."], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["perform demarcation"]}
+{"name": "I52_1-1", "given_experience_title": "Volunteering to repair a local park's walking path", "given_company_name": "Home", "given_responsibilities": ["Assessing the structural integrity of the path, designing a repair plan, and overseeing the implementation of the repair using sustainable materials"], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["civil engineering"]}
+{"name": "I52_1-2", "given_experience_title": "Volunteered to help clean and repair the roof of a local community center", "given_company_name": "Home", "given_responsibilities": ["Ensured adherence to safety procedures while working at heights, including using proper harnesses and fall protection equipment"], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["follow safety procedures when working at heights"]}
+{"name": "I52_1-3", "given_experience_title": "Volunteering to repair a local park's retaining wall", "given_company_name": "Home", "given_responsibilities": ["Finish mortar joints on the retaining wall to ensure a smooth and durable surface"], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["finish mortar joints"]}
+{"name": "I52_1-4", "given_experience_title": "I volunteered to help repair potholes on a local road", "given_company_name": "Home", "given_responsibilities": ["Moved soil to fill in potholes and ensure a smooth road surface"], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["move soil"]}
+{"name": "I52_2-0", "given_experience_title": "I helped a friend clean their house after a difficult time", "given_company_name": "Home", "given_responsibilities": ["I observed the environment for any signs of drug use, such as paraphernalia or unusual behavior, and discreetly disposed of any potentially harmful items."], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["detect drug abuse"]}
+{"name": "I52_2-1", "given_experience_title": "I volunteer at a local soup kitchen to prepare meals for the homeless", "given_company_name": "Home", "given_responsibilities": ["Use food cutting tools to prepare vegetables and other ingredients for the daily soup and bread meals"], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["use food cutting tools"]}
+{"name": "I52_2-2", "given_experience_title": "I volunteer to cook meals for elderly neighbors", "given_company_name": "Home", "given_responsibilities": ["Maintain strict personal hygiene standards to ensure the safety and quality of the food prepared."], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["maintain personal hygiene standards"]}
+{"name": "I52_2-3", "given_experience_title": "I taught my neighbor's children how to cook simple meals", "given_company_name": "Home", "given_responsibilities": ["Train and guide individuals on basic cooking techniques and recipes, ensuring they understand the process and can prepare meals independently."], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["train employees"]}
+{"name": "I52_2-4", "given_experience_title": "I volunteer to clean the local community center", "given_company_name": "Home", "given_responsibilities": ["Maintain high standards of personal hygiene while cleaning to ensure the safety and health of the community members who use the center."], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["maintain personal hygiene standards when cleaning"]}
+{"name": "I52_3-0", "given_experience_title": "Volunteer Assistant Coach for Youth Soccer Team", "given_company_name": "Home", "given_responsibilities": ["Organise and lead weekly training sessions for the youth soccer team, ensuring a safe and engaging environment for all players."], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["organise training"]}
+{"name": "I52_3-1", "given_experience_title": "Volunteer at an amusement park", "given_company_name": "Home", "given_responsibilities": ["Provide information to visitors about the park's attractions, shows, and events"], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["provide amusement park information"]}
+{"name": "I52_3-2", "given_experience_title": "Volunteer Music Instructor for Community Youth Program", "given_company_name": "Home", "given_responsibilities": ["Gather feedback from participants on the music program, including their enjoyment, learning experience, and suggestions for improvement."], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["measure customer feedback"]}
+{"name": "I52_3-3", "given_experience_title": "Volunteered as a translator at an international music festival", "given_company_name": "Home", "given_responsibilities": ["Communicated with participants and performers from different countries, translating instructions, announcements, and conversations to ensure smooth operation and enjoyment of the event."], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["speak different languages"]}
+{"name": "I52_3-4", "given_experience_title": "Volunteer Coach for Youth Soccer Team", "given_company_name": "Home", "given_responsibilities": ["Apply latest sport science findings to design training programs and drills that enhance player performance, focusing on technique, strength, and conditioning."], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["apply latest sport science findings"]}
+{"name": "I52_4-0", "given_experience_title": "Volunteered at a local non-profit organization, assisting with office tasks", "given_company_name": "Home", "given_responsibilities": ["Created and issued sales invoices for donations received by the organization"], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["issue sales invoices"]}
+{"name": "I52_4-1", "given_experience_title": "Assisted with office administration", "given_company_name": "Home", "given_responsibilities": ["Maintain accurate records of promotions, including dates, promotions, and employee information"], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["keep promotions records"]}
+{"name": "I52_4-2", "given_experience_title": "Volunteering at the local library, helping with administrative tasks", "given_company_name": "Home", "given_responsibilities": ["Delivering inter-library loans and other correspondence to patrons and other libraries"], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["deliver correspondence"]}
+{"name": "I52_4-3", "given_experience_title": "Volunteered at a local non-profit organization, assisting with administrative tasks", "given_company_name": "Home", "given_responsibilities": ["Ensured efficient and secure document sharing procedures by utilizing the organization's preferred platforms and protocols"], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["document sharing procedures"]}
+{"name": "I52_4-4", "given_experience_title": "Volunteering at the local library", "given_company_name": "Home", "given_responsibilities": ["Using Microsoft Word to create and format documents for library events"], "given_country_of_interest": "South Africa", "given_work_type": "Unpaid other", "expected_top_skills": ["use microsoft office"]}
diff --git a/backend/evaluation_tests/linking_and_ranking_pipeline/infer_icatus_activities_tool/__init__.py b/backend/evaluation_tests/linking_and_ranking_pipeline/infer_icatus_activities_tool/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/backend/evaluation_tests/linking_and_ranking_pipeline/infer_icatus_activities_tool/infer_icatus_activities_tool_test.py b/backend/evaluation_tests/linking_and_ranking_pipeline/infer_icatus_activities_tool/infer_icatus_activities_tool_test.py
new file mode 100644
index 000000000..12aa79ab6
--- /dev/null
+++ b/backend/evaluation_tests/linking_and_ranking_pipeline/infer_icatus_activities_tool/infer_icatus_activities_tool_test.py
@@ -0,0 +1,59 @@
+import json
+import logging
+import random
+
+import pytest
+
+from app.agent.linking_and_ranking_pipeline.infer_icatus_activities import InferIcatusActivitiesTool
+from app.agent.linking_and_ranking_pipeline.infer_icatus_activities.utils import IcatusClassificationLevel
+from app.server_dependencies.db_dependencies import CompassDBProvider
+from app.vector_search.embeddings_model import GoogleGeckoEmbeddingService
+from app.vector_search.esco_search_service import OccupationSkillSearchService
+from app.vector_search.settings import VectorSearchSettings
+from .test_icatus_inference_test_case import test_cases
+from evaluation_tests.get_test_cases_to_run_func import get_test_cases_to_run
+from evaluation_tests.linking_and_ranking_pipeline.infer_occupation_tool.test_occupation_inference_test_case import InferOccupationToolTestCase
+
+
+@pytest.fixture(scope="function")
+async def setup_agent_tool():
+ db = await CompassDBProvider.get_taxonomy_db()
+ settings = VectorSearchSettings()
+ embedding_service = GoogleGeckoEmbeddingService()
+ search_service = OccupationSkillSearchService(db, embedding_service, settings)
+ tool = InferIcatusActivitiesTool(search_service, classification_level=IcatusClassificationLevel.FIRST_LEVEL)
+ return tool
+
+
+@pytest.mark.asyncio
+@pytest.mark.evaluation_test
+@pytest.mark.parametrize(
+ "test_case", get_test_cases_to_run(test_cases),
+ ids=[f"{index} - {case.name} - {case.given_experience_title}" for index, case in enumerate(get_test_cases_to_run(test_cases))])
+async def test_occupation_inference_tool(test_case: InferOccupationToolTestCase, setup_agent_tool):
+ tool = await setup_agent_tool
+ # GIVEN an experience and a country of interest
+ # shuffle the responsibilities to ensure the test is not dependent on the order of the responsibilities
+ random.shuffle(test_case.given_responsibilities)
+ # WHEN the tool is executed with the given experience and country
+
+ result = await tool.execute(
+ experience_title=test_case.given_experience_title,
+ company=test_case.given_company,
+ work_type=test_case.given_work_type,
+ responsibilities=test_case.given_responsibilities,
+ country_of_interest=test_case.given_country_of_interest,
+ top_k=test_case.given_top_k,
+ top_p=test_case.given_top_p,
+ number_of_titles=test_case.number_of_titles
+ )
+ logging.log(logging.INFO, "Given Title '%s' -> Contextual Titles: %s", test_case.given_experience_title,
+ json.dumps(result.contextual_titles))
+
+ occupations = [{"title": skill_occupation.occupation.preferredLabel, "description": skill_occupation.occupation.description} for skill_occupation in
+ result.esco_occupations]
+ logging.log(logging.INFO, "Found ESCO Occupations(preferredLabel,code): \n -%s", json.dumps(occupations))
+ # expected_occupations_found should be a subset of the preferred labels of the occupations
+ labels = [skill_occupation.occupation.preferredLabel for skill_occupation in result.esco_occupations]
+ logging.log(logging.INFO, "Found ESCO Occupations: \n -%s", "\n -".join(labels))
+ assert set(test_case.expected_occupations_found).issubset(labels)
diff --git a/backend/evaluation_tests/linking_and_ranking_pipeline/infer_icatus_activities_tool/test_icatus_inference_test_case.py b/backend/evaluation_tests/linking_and_ranking_pipeline/infer_icatus_activities_tool/test_icatus_inference_test_case.py
new file mode 100644
index 000000000..ac5e8a468
--- /dev/null
+++ b/backend/evaluation_tests/linking_and_ranking_pipeline/infer_icatus_activities_tool/test_icatus_inference_test_case.py
@@ -0,0 +1,445 @@
+from typing import Optional
+
+from app.agent.experience.work_type import WorkType
+from app.countries import Country
+from evaluation_tests.compass_test_case import CompassTestCase
+
+
+class InferIcatusActivitiesToolTestCase(CompassTestCase):
+ given_experience_title: str
+ given_company: Optional[str] = None
+ given_work_type: WorkType
+ given_responsibilities: list[str]
+ given_country_of_interest: Country
+ given_top_k: int = 10
+ given_top_p: int = 20
+ number_of_titles: int = 5
+ expected_occupations_found: list[str]
+
+
+test_cases = [
+ InferIcatusActivitiesToolTestCase(
+ name="Icatus I42_0_4",
+ given_experience_title="I keep company to my grandma when she is not feeling well",
+ given_work_type=WorkType.UNSEEN_UNPAID,
+ given_company="home",
+ given_country_of_interest=Country.SOUTH_AFRICA,
+ given_responsibilities=[],
+ expected_occupations_found=["helping adults who need care or are sick"],
+ ),
+ InferIcatusActivitiesToolTestCase(
+ name="Icatus I42_0_3",
+ given_experience_title="I fill my grandma’s taxes",
+ given_work_type=WorkType.UNSEEN_UNPAID,
+ given_company="home",
+ given_country_of_interest=Country.SOUTH_AFRICA,
+ given_responsibilities=[],
+ expected_occupations_found=["helping adults who need care or are sick"],
+ ),
+ InferIcatusActivitiesToolTestCase(
+ name="Icatus I42_0_2",
+ given_experience_title="I give my uncle his medication ",
+ given_work_type=WorkType.UNSEEN_UNPAID,
+ given_company="home",
+ given_country_of_interest=Country.SOUTH_AFRICA,
+ given_responsibilities=[],
+ expected_occupations_found=["helping adults who need care or are sick"],
+ ),
+ InferIcatusActivitiesToolTestCase(
+ name="Icatus I42_0_1",
+ given_experience_title="I make my grandma have lunch and I help her wash herself",
+ given_work_type=WorkType.UNSEEN_UNPAID,
+ given_company="home",
+ given_country_of_interest=Country.SOUTH_AFRICA,
+ given_responsibilities=[],
+ expected_occupations_found=["helping adults who need care or are sick"],
+ ),
+ InferIcatusActivitiesToolTestCase(
+ name="Icatus I42_0_6",
+ given_experience_title="I take care of my dad’s medical appointments",
+ given_work_type=WorkType.UNSEEN_UNPAID,
+ given_company="home",
+ given_country_of_interest=Country.SOUTH_AFRICA,
+ given_responsibilities=[],
+ expected_occupations_found=["helping adults who need care or are sick"],
+ ),
+ InferIcatusActivitiesToolTestCase(
+ name="Icatus I42_0_5",
+ given_experience_title="I keep an eye on my Grandpa",
+ given_work_type=WorkType.UNSEEN_UNPAID,
+ given_company="home",
+ given_country_of_interest=Country.SOUTH_AFRICA,
+ given_responsibilities=[],
+ expected_occupations_found=["helping adults who need care or are sick"],
+ ),
+ InferIcatusActivitiesToolTestCase(
+ name="Icatus I41_0_1",
+ given_experience_title="I change my little brother’s diapers",
+ given_work_type=WorkType.UNSEEN_UNPAID,
+ given_company="home",
+ given_country_of_interest=Country.SOUTH_AFRICA,
+ given_responsibilities=[],
+ expected_occupations_found=["caring for and teaching children in your family"],
+ ),
+ InferIcatusActivitiesToolTestCase(
+ name="Icatus I41_0_3",
+ given_experience_title="I help my sister with her homework. ",
+ given_work_type=WorkType.UNSEEN_UNPAID,
+ given_company="home",
+ given_country_of_interest=Country.SOUTH_AFRICA,
+ given_responsibilities=[],
+ expected_occupations_found=["caring for and teaching children in your family"],
+ ),
+ InferIcatusActivitiesToolTestCase(
+ name="Icatus I41_0_7",
+ given_experience_title="I go to teacher/parents meetings.",
+ given_work_type=WorkType.UNSEEN_UNPAID,
+ given_company="home",
+ given_country_of_interest=Country.SOUTH_AFRICA,
+ given_responsibilities=[],
+ expected_occupations_found=["caring for and teaching children in your family"],
+ ),
+ InferIcatusActivitiesToolTestCase(
+ name="Icatus I41_0_6",
+ given_experience_title="I keep an eye on my siblings during the day",
+ given_work_type=WorkType.UNSEEN_UNPAID,
+ given_company="home",
+ given_country_of_interest=Country.SOUTH_AFRICA,
+ given_responsibilities=[],
+ expected_occupations_found=["caring for and teaching children in your family"],
+ ),
+ InferIcatusActivitiesToolTestCase(
+ name="Icatus I41_0_5",
+ given_experience_title="I play football with my cousins",
+ given_work_type=WorkType.UNSEEN_UNPAID,
+ given_company="home",
+ given_country_of_interest=Country.SOUTH_AFRICA,
+ given_responsibilities=[],
+ expected_occupations_found=["caring for and teaching children in your family"],
+ ),
+ InferIcatusActivitiesToolTestCase(
+ name="Icatus I41_0_2",
+ given_experience_title="I give my brother medication",
+ given_work_type=WorkType.UNSEEN_UNPAID,
+ given_company="home",
+ given_country_of_interest=Country.SOUTH_AFRICA,
+ given_responsibilities=[],
+ expected_occupations_found=["caring for and teaching children in your family"],
+ ),
+ InferIcatusActivitiesToolTestCase(
+ name="Icatus I41_0_4",
+ given_experience_title="I read bedtime stories to my niece",
+ given_work_type=WorkType.UNSEEN_UNPAID,
+ given_company="home",
+ given_country_of_interest=Country.SOUTH_AFRICA,
+ given_responsibilities=[],
+ expected_occupations_found=["caring for and teaching children in your family"],
+ ),
+ InferIcatusActivitiesToolTestCase(
+ name="Icatus I44_0_3",
+ given_experience_title="I take my grandma to the supermarket",
+ given_work_type=WorkType.UNSEEN_UNPAID,
+ given_company="home",
+ given_country_of_interest=Country.SOUTH_AFRICA,
+ given_responsibilities=[],
+ expected_occupations_found=["accompanying own children and/or dependent adults"],
+ ),
+ InferIcatusActivitiesToolTestCase(
+ name="Icatus I44_0_2",
+ given_experience_title="I bring my sister to school",
+ given_work_type=WorkType.UNSEEN_UNPAID,
+ given_company="home",
+ given_country_of_interest=Country.SOUTH_AFRICA,
+ given_responsibilities=[],
+ expected_occupations_found=["accompanying own children and/or dependent adults"],
+ ),
+ InferIcatusActivitiesToolTestCase(
+ name="Icatus I43_0_2",
+ given_experience_title="I take care of my brother when he is having a hard time",
+ given_work_type=WorkType.UNSEEN_UNPAID,
+ given_company="home",
+ given_country_of_interest=Country.SOUTH_AFRICA,
+ given_responsibilities=[],
+ expected_occupations_found=["helping other adults in the house or family"],
+ ),
+ InferIcatusActivitiesToolTestCase(
+ name="Icatus I43_0_1",
+ given_experience_title="I help my brother move because he broke his ankle",
+ given_work_type=WorkType.UNSEEN_UNPAID,
+ given_company="home",
+ given_country_of_interest=Country.SOUTH_AFRICA,
+ given_responsibilities=[],
+ expected_occupations_found=["helping other adults in the house or family"],
+ ),
+ InferIcatusActivitiesToolTestCase(
+ name="Icatus I34_0_2",
+ given_experience_title="I dry the laundry",
+ given_work_type=WorkType.UNSEEN_UNPAID,
+ given_company="home",
+ given_country_of_interest=Country.SOUTH_AFRICA,
+ given_responsibilities=[],
+ expected_occupations_found=["cleaning or fixing clothes and shoes"],
+ ),
+ InferIcatusActivitiesToolTestCase(
+ name="Icatus I34_0_1",
+ given_experience_title="I clean the sheets",
+ given_work_type=WorkType.UNSEEN_UNPAID,
+ given_company="home",
+ given_country_of_interest=Country.SOUTH_AFRICA,
+ given_responsibilities=[],
+ expected_occupations_found=["cleaning or fixing clothes and shoes"],
+ ),
+ InferIcatusActivitiesToolTestCase(
+ name="Icatus I34_0_3",
+ given_experience_title="I iron my dad’s shirts",
+ given_work_type=WorkType.UNSEEN_UNPAID,
+ given_company="home",
+ given_country_of_interest=Country.SOUTH_AFRICA,
+ given_responsibilities=[],
+ expected_occupations_found=["cleaning or fixing clothes and shoes"],
+ ),
+ InferIcatusActivitiesToolTestCase(
+ name="Icatus I34_0_4",
+ given_experience_title="I clean my shoes",
+ given_work_type=WorkType.UNSEEN_UNPAID,
+ given_company="home",
+ given_country_of_interest=Country.SOUTH_AFRICA,
+ given_responsibilities=[],
+ expected_occupations_found=["cleaning or fixing clothes and shoes"],
+ ),
+ InferIcatusActivitiesToolTestCase(
+ name="Icatus I32_0_1",
+ given_experience_title="I clean the windows",
+ given_work_type=WorkType.UNSEEN_UNPAID,
+ given_company="home",
+ given_country_of_interest=Country.SOUTH_AFRICA,
+ given_responsibilities=[],
+ expected_occupations_found=["cleaning and looking after your home or garden"],
+ ),
+ InferIcatusActivitiesToolTestCase(
+ name="Icatus I32_0_2",
+ given_experience_title="I take away the snow around the house",
+ given_work_type=WorkType.UNSEEN_UNPAID,
+ given_company="home",
+ given_country_of_interest=Country.SOUTH_AFRICA,
+ given_responsibilities=[],
+ expected_occupations_found=["cleaning and looking after your home or garden"],
+ ),
+ InferIcatusActivitiesToolTestCase(
+ name="Icatus I32_0_3",
+ given_experience_title="I make compost with vegetable peals",
+ given_work_type=WorkType.UNSEEN_UNPAID,
+ given_company="home",
+ given_country_of_interest=Country.SOUTH_AFRICA,
+ given_responsibilities=[],
+ expected_occupations_found=["cleaning and looking after your home or garden"],
+ ),
+ InferIcatusActivitiesToolTestCase(
+ name="Icatus I32_0_4",
+ given_experience_title="I water the plants",
+ given_work_type=WorkType.UNSEEN_UNPAID,
+ given_company="home",
+ given_country_of_interest=Country.SOUTH_AFRICA,
+ given_responsibilities=[],
+ expected_occupations_found=["cleaning and looking after your home or garden"],
+ ),
+ InferIcatusActivitiesToolTestCase(
+ name="Icatus I33_0_1",
+ given_experience_title="I paint the house’s walls",
+ given_work_type=WorkType.UNSEEN_UNPAID,
+ given_company="home",
+ given_country_of_interest=Country.SOUTH_AFRICA,
+ given_responsibilities=[],
+ expected_occupations_found=["fixing things in your home or car"],
+ ),
+ InferIcatusActivitiesToolTestCase(
+ name="Icatus I33_0_2",
+ given_experience_title="I install the TV",
+ given_work_type=WorkType.UNSEEN_UNPAID,
+ given_company="home",
+ given_country_of_interest=Country.SOUTH_AFRICA,
+ given_responsibilities=[],
+ expected_occupations_found=["fixing things in your home or car"],
+ ),
+ InferIcatusActivitiesToolTestCase(
+ name="Icatus I33_0_3",
+ given_experience_title="I change the car’s oil",
+ given_work_type=WorkType.UNSEEN_UNPAID,
+ given_company="home",
+ given_country_of_interest=Country.SOUTH_AFRICA,
+ given_responsibilities=[],
+ expected_occupations_found=["fixing things in your home or car"],
+ ),
+ InferIcatusActivitiesToolTestCase(
+ name="Icatus I31_0_3",
+ given_experience_title="I do the dishes",
+ given_work_type=WorkType.UNSEEN_UNPAID,
+ given_company="home",
+ given_country_of_interest=Country.SOUTH_AFRICA,
+ given_responsibilities=[],
+ expected_occupations_found=["cooking and planning meals"],
+ ),
+ InferIcatusActivitiesToolTestCase(
+ name="Icatus I31_0_1",
+ given_experience_title="I make cookies for my daughter",
+ given_work_type=WorkType.UNSEEN_UNPAID,
+ given_company="home",
+ given_country_of_interest=Country.SOUTH_AFRICA,
+ given_responsibilities=[],
+ expected_occupations_found=["cooking and planning meals"],
+ ),
+ InferIcatusActivitiesToolTestCase(
+ name="Icatus I31_0_2",
+ given_experience_title="I set the table and serve my family",
+ given_work_type=WorkType.UNSEEN_UNPAID,
+ given_company="home",
+ given_country_of_interest=Country.SOUTH_AFRICA,
+ given_responsibilities=[],
+ expected_occupations_found=["cooking and planning meals"],
+ ),
+ InferIcatusActivitiesToolTestCase(
+ name="Icatus I31_0_4",
+ given_experience_title="I put fruits in bocals to store them for the winter.",
+ given_work_type=WorkType.UNSEEN_UNPAID,
+ given_company="home",
+ given_country_of_interest=Country.SOUTH_AFRICA,
+ given_responsibilities=[],
+ expected_occupations_found=["cooking and planning meals"],
+ ),
+ InferIcatusActivitiesToolTestCase(
+ name="Icatus I35_0_2",
+ given_experience_title="I check the savings to plan for trips.",
+ given_work_type=WorkType.UNSEEN_UNPAID,
+ given_company="home",
+ given_country_of_interest=Country.SOUTH_AFRICA,
+ given_responsibilities=[],
+ expected_occupations_found=["managing and planning for your household"],
+ ),
+ InferIcatusActivitiesToolTestCase(
+ name="Icatus I35_0_1",
+ given_experience_title="I pay my bills online.",
+ given_work_type=WorkType.UNSEEN_UNPAID,
+ given_company="home",
+ given_country_of_interest=Country.SOUTH_AFRICA,
+ given_responsibilities=[],
+ expected_occupations_found=["managing and planning for your household"],
+ ),
+ InferIcatusActivitiesToolTestCase(
+ name="Icatus I36_0_1",
+ given_experience_title="I play with my dog outside.",
+ given_work_type=WorkType.UNSEEN_UNPAID,
+ given_company="home",
+ given_country_of_interest=Country.SOUTH_AFRICA,
+ given_responsibilities=[],
+ expected_occupations_found=["taking care of pets"],
+ ),
+ InferIcatusActivitiesToolTestCase(
+ name="Icatus I36_0_2",
+ given_experience_title="I take my dog to the dog-sitter.",
+ given_work_type=WorkType.UNSEEN_UNPAID,
+ given_company="home",
+ given_country_of_interest=Country.SOUTH_AFRICA,
+ given_responsibilities=[],
+ expected_occupations_found=["taking care of pets"],
+ ),
+ InferIcatusActivitiesToolTestCase(
+ name="Icatus I37_0_2",
+ given_experience_title="I look for a hairdresser for my mom and pay for an appointment.",
+ given_work_type=WorkType.UNSEEN_UNPAID,
+ given_company="home",
+ given_country_of_interest=Country.SOUTH_AFRICA,
+ given_responsibilities=[],
+ expected_occupations_found=["shopping for your family or household"],
+ ),
+ InferIcatusActivitiesToolTestCase(
+ name="Icatus I37_0_1",
+ given_experience_title="I buy my parents fournitures.",
+ given_work_type=WorkType.UNSEEN_UNPAID,
+ given_company="home",
+ given_country_of_interest=Country.SOUTH_AFRICA,
+ given_responsibilities=[],
+ expected_occupations_found=["shopping for your family or household"],
+ ),
+ InferIcatusActivitiesToolTestCase(
+ name="Icatus I52_0_3",
+ given_experience_title="I take care of yougnpeople in the community.",
+ given_work_type=WorkType.UNSEEN_UNPAID,
+ given_company="home",
+ given_country_of_interest=Country.SOUTH_AFRICA,
+ given_responsibilities=[],
+ expected_occupations_found=["helping with sports, music or other cultural activities without getting paid"],
+ ),
+ InferIcatusActivitiesToolTestCase(
+ name="Icatus I52_0_4",
+ given_experience_title="I help my church with accounting. ",
+ given_work_type=WorkType.UNSEEN_UNPAID,
+ given_company="home",
+ given_country_of_interest=Country.SOUTH_AFRICA,
+ given_responsibilities=[],
+ expected_occupations_found=["helping with office work without getting paid"],
+ ),
+ InferIcatusActivitiesToolTestCase(
+ name="Icatus I52_0_2",
+ given_experience_title="I sell cake at my dauther’s school baking parties",
+ given_work_type=WorkType.UNSEEN_UNPAID,
+ given_company="home",
+ given_country_of_interest=Country.SOUTH_AFRICA,
+ given_responsibilities=[],
+ expected_occupations_found=["cooking or cleaning for other people's homes without getting paid"],
+ ),
+ InferIcatusActivitiesToolTestCase(
+ name="Icatus I52_0_1",
+ given_experience_title="I help clean the beach after a storm.",
+ given_work_type=WorkType.UNSEEN_UNPAID,
+ given_company="home",
+ given_country_of_interest=Country.SOUTH_AFRICA,
+ given_responsibilities=[],
+ expected_occupations_found=["cleaning or fixing roads or buildings without getting paid"],
+ ),
+ InferIcatusActivitiesToolTestCase(
+ name="Icatus I51_0_4",
+ given_experience_title="I check on my eldery neighboor when it’s very hot outside.",
+ given_work_type=WorkType.UNSEEN_UNPAID,
+ given_company="home",
+ given_country_of_interest=Country.SOUTH_AFRICA,
+ given_responsibilities=[],
+ expected_occupations_found=["helping adults outside of your home who need care without getting paid"],
+ ),
+ InferIcatusActivitiesToolTestCase(
+ name="Icatus I51_0_3",
+ given_experience_title="I teach my young neighbor spanish.",
+ given_work_type=WorkType.UNSEEN_UNPAID,
+ given_company="home",
+ given_country_of_interest=Country.SOUTH_AFRICA,
+ given_responsibilities=[],
+ expected_occupations_found=["caring for and teaching for children outside of your home without getting paid"],
+ ),
+ InferIcatusActivitiesToolTestCase(
+ name="Icatus I51_0_1",
+ given_experience_title="I babysit my cousin’s cats.",
+ given_work_type=WorkType.UNSEEN_UNPAID,
+ given_company="home",
+ given_country_of_interest=Country.SOUTH_AFRICA,
+ given_responsibilities=[],
+ expected_occupations_found=["fixing and building things in other people's homes without getting paid"],
+ ),
+ InferIcatusActivitiesToolTestCase(
+ name="Icatus I51_0_2",
+ given_experience_title="I bring groceries to my elderly neighbor.",
+ given_work_type=WorkType.UNSEEN_UNPAID,
+ given_company="home",
+ given_country_of_interest=Country.SOUTH_AFRICA,
+ given_responsibilities=[],
+ expected_occupations_found=["shopping for others without getting paid"],
+ ),
+ InferIcatusActivitiesToolTestCase(
+ name="Icatus I51_0_5",
+ given_experience_title="I replace my uncle in his shop when he is away.",
+ given_work_type=WorkType.UNSEEN_UNPAID,
+ given_company="home",
+ given_country_of_interest=Country.SOUTH_AFRICA,
+ given_responsibilities=[],
+ expected_occupations_found=["helping in other people's businesses without getting paid"],
+ ),
+ # Add more test cases as needed
+]
diff --git a/backend/scripts/generate_synthetic_responsibilities.py b/backend/scripts/generate_synthetic_responsibilities.py
new file mode 100644
index 000000000..b86da2aa5
--- /dev/null
+++ b/backend/scripts/generate_synthetic_responsibilities.py
@@ -0,0 +1,91 @@
+import json
+import logging
+from textwrap import dedent
+from tqdm import tqdm
+from pydantic import BaseModel
+import random
+
+from app.agent.llm_caller import LLMCaller
+from app.server_dependencies.db_dependencies import CompassDBProvider
+from app.vector_search.embeddings_model import GoogleGeckoEmbeddingService
+from app.vector_search.esco_search_service import OccupationSkillSearchService
+from app.vector_search.settings import VectorSearchSettings
+from app.agent.linking_and_ranking_pipeline.infer_icatus_activities.utils import IcatusTerminalNode
+from common_libs.llm.generative_models import GeminiGenerativeLLM
+from common_libs.llm.models_utils import LLMConfig, MODERATE_TEMPERATURE_GENERATION_CONFIG, JSON_GENERATION_CONFIG
+
+class ExperienceLLMOutput(BaseModel):
+ reasoning: str
+ experience_title: str
+ responsibility: str
+
+def _get_system_instructions():
+ return dedent("""\
+
+ You are an expert in identifying examples of experiences and responsibilities associated to them, given some general definition from a database.
+ You are given an experience title and a skill associated with it, from a database focusing on the unseen economy, for types of work that is not paid or done for hire, including work in one's household and volunteering.
+ Your task is to generate both an example of an experience title, along with a specific responsibility that reflects the input components.
+ The experience title should reflect the provided title and the responsibility should reflect the skill associated with it.
+ For example, if the occupation title is 'cleaning or fixing roads or buildings without getting paid' and the skill is 'remove road surface', you could generate an experience title like 'I help clean the beach after a storm' and a responsibility like 'Remove debris and debris-laden surfaces to restore the beach to a clean and safe condition'.
+ #Input Structure
+ The input structure is composed of:
+ 'Occupation Title': The occupation title.
+ 'Skill': The skill associated with the occupation.
+ You should use the above information only to infer the context and you shouldn't return it as output.
+ #JSON Output instructions
+ Your response must always be a JSON object with the following schema:
+ {
+ "reasoning": Why you chose to return the specific title and responsibility and how they align with the input,
+ "experience_title": The experience title that you generated,
+ "responsibility": The responsibility that you generated
+ }
+ """)
+
+def generate_prompt(occupation_title: str, skill_title: str):
+ return f"Occupation Title: {occupation_title}\nSkill: {skill_title}"
+
+async def setup_search_service_tool():
+ db = await CompassDBProvider.get_taxonomy_db()
+ settings = VectorSearchSettings()
+ embedding_service = GoogleGeckoEmbeddingService()
+ search_service = OccupationSkillSearchService(db, embedding_service, settings)
+ return search_service
+
+async def setup_llm_tools():
+ llm = GeminiGenerativeLLM(
+ system_instructions=_get_system_instructions(),
+ config=LLMConfig(generation_config=MODERATE_TEMPERATURE_GENERATION_CONFIG | JSON_GENERATION_CONFIG)
+ )
+ llm_caller : LLMCaller[ExperienceLLMOutput] = LLMCaller[ExperienceLLMOutput](
+ model_response_type=ExperienceLLMOutput)
+ logger = logging.getLogger(__name__)
+ return llm, llm_caller, logger
+
+async def generate_synthetic_responsibilities(output_path: str, skills_per_occupation=5):
+ search_service = await setup_search_service_tool()
+ llm, llm_caller, logger = await setup_llm_tools()
+ with open(output_path, "wt") as fout:
+ for code in tqdm([node.code for node in IcatusTerminalNode]):
+ occupation = await search_service.get_by_esco_code(code=code)
+ skills = random.sample(occupation.associated_skills, skills_per_occupation)
+ for index, skill in enumerate(skills):
+ prompt = generate_prompt(occupation.occupation.preferredLabel, skill.preferredLabel)
+ result, _ = await llm_caller.call_llm(
+ llm=llm,
+ llm_input=prompt,
+ logger=logger
+ )
+ experience_dict = {
+ "name": f"{code}-{index}",
+ "given_experience_title": result.experience_title,
+ "given_company_name": "Home",
+ "given_responsibilities": [result.responsibility],
+ "given_country_of_interest": "South Africa",
+ "given_work_type": "Unpaid other",
+ "expected_top_skills": [skill.preferredLabel],
+ }
+ fout.write(json.dumps(experience_dict)+"\n")
+
+if __name__ == "__main__":
+ import asyncio
+ asyncio.run(generate_synthetic_responsibilities("synthetic_responsibilities.jsonl"))
\ No newline at end of file