- Adapting TRAICIE_SELECTION_SPECIALIST to retrieve prefered contact times using a form iso free text

- Improvement of DynamicForm en FormField to handle boolean values.
This commit is contained in:
Josako
2025-07-24 14:43:08 +02:00
parent fc3cae1986
commit 8a85b4540f
6 changed files with 684 additions and 70 deletions

View File

@@ -35,11 +35,13 @@ KO_CRITERIA_MET_MESSAGE = "We processed your answers with a positive result."
RQC_MESSAGE = "You are well suited for this job."
CONTACT_DATA_QUESTION = ("Are you willing to provide us with your contact data, so we can contact you to continue "
"the selection process?")
CONTACT_DATA_GUIDING_MESSAGE = ("Thank you for trusting your contact data with us. Below you find a form to help you "
"to provide us the necessary information.")
NO_CONTACT_DATA_QUESTION = ("We are sorry to hear that. The only way to proceed with the selection process is "
"to provide us with your contact data. Do you want to provide us with your contact data?"
"if not, we thank you, and we'll end the selection process.")
CONTACT_DATA_PROCESSED_MESSAGE = "We successfully processed your contact data."
CONTACT_TIME_QUESTION = "When do you prefer us to contact you? Provide us with some preferred weekdays and times!"
CONTACT_DATA_PROCESSED_MESSAGE = "Thank you for allowing us to contact you."
CONTACT_TIME_QUESTION = "When do you prefer us to contact you? You can select some options in the provided form"
NO_CONTACT_TIME_MESSAGE = ("We could not process your preferred contact time. Can you please provide us with your "
"preferred contact time?")
CONTACT_TIME_PROCESSED_MESSAGE = ("We successfully processed your preferred contact time. We will contact you as soon "
@@ -85,7 +87,7 @@ class SpecialistExecutor(CrewAIBaseSpecialistExecutor):
self._add_state_result_relation("competency_questions")
self._add_state_result_relation("competency_scores")
self._add_state_result_relation("personal_contact_data")
self._add_state_result_relation("contact_time")
self._add_state_result_relation("contact_time_prefs")
def _instantiate_specialist(self):
verbose = self.tuning
@@ -264,11 +266,13 @@ class SpecialistExecutor(CrewAIBaseSpecialistExecutor):
contact_form = cache_manager.specialist_forms_config_cache.get_config("PERSONAL_CONTACT_FORM", "1.0")
contact_form = TranslationServices.translate_config(self.tenant_id, contact_form, "fields",
arguments.language)
guiding_message = TranslationServices.translate(self.tenant_id, CONTACT_DATA_GUIDING_MESSAGE,
arguments.language)
rag_output = self._check_and_execute_rag(arguments, formatted_context, citations)
if rag_output:
answer = f"{rag_output.answer}"
answer = f"{rag_output.answer}\n\n{guiding_message}"
else:
answer = ""
answer = guiding_message
self.flow.state.answer = answer
self.flow.state.form_request = contact_form
@@ -291,6 +295,9 @@ class SpecialistExecutor(CrewAIBaseSpecialistExecutor):
answer = (
f"{TranslationServices.translate(self.tenant_id, CONTACT_DATA_PROCESSED_MESSAGE, arguments.language)}\n"
f"{TranslationServices.translate(self.tenant_id, CONTACT_TIME_QUESTION, arguments.language)}")
time_pref_form = cache_manager.specialist_forms_config_cache.get_config("CONTACT_TIME_PREFERENCES_SIMPLE", "1.0")
time_pref_form = TranslationServices.translate_config(self.tenant_id, time_pref_form, "fields",
arguments.language)
rag_output = self._check_and_execute_rag(arguments, formatted_context, citations)
if rag_output:
@@ -299,6 +306,7 @@ class SpecialistExecutor(CrewAIBaseSpecialistExecutor):
self.flow.state.answer = answer
self.flow.state.phase = "contact_time_evaluation"
self.flow.state.personal_contact_data = arguments.form_values
self.flow.state.form_request = time_pref_form
results = SelectionResult.create_for_type(self.type, self.type_version,)
return results
@@ -306,29 +314,21 @@ class SpecialistExecutor(CrewAIBaseSpecialistExecutor):
def execute_contact_time_evaluation_state(self, arguments: SpecialistArguments, formatted_context, citations) \
-> SpecialistResult:
self.log_tuning("Traicie Selection Specialist contact_time_evaluation started", {})
contact_time_answer = HumanAnswerServices.get_answer_to_question(self.tenant_id, CONTACT_TIME_QUESTION,
arguments.question, arguments.language)
rag_output = self._check_and_execute_rag(arguments, formatted_context, citations)
if contact_time_answer == "No answer provided":
answer = TranslationServices.translate(self.tenant_id, NO_CONTACT_TIME_MESSAGE, arguments.language)
if rag_output:
answer = f"{answer}\n\n{rag_output.answer}"
message = TranslationServices.translate(self.tenant_id, CONTACT_TIME_PROCESSED_MESSAGE, arguments.language)
self.flow.state.answer = answer
self.flow.state.phase = "contact_time_evaluation"
answer = TranslationServices.translate(self.tenant_id, CONTACT_TIME_PROCESSED_MESSAGE, arguments.language)
if rag_output:
answer = f"{rag_output.answer}\n\n{message}"
results = SelectionResult.create_for_type(self.type, self.type_version,)
else:
answer = TranslationServices.translate(self.tenant_id, CONTACT_TIME_PROCESSED_MESSAGE, arguments.language)
if rag_output:
answer = f"{answer}\n\n{rag_output.answer}"
self.flow.state.answer = answer
self.flow.state.phase = "candidate_selected"
current_app.logger.debug(f"Contact time evaluation: {arguments.form_values}")
self.flow.state.contact_time_prefs = arguments.form_values
self.flow.state.answer = answer
self.flow.state.phase = "candidate_selected"
self.flow.state.contact_time = contact_time_answer
results = SelectionResult.create_for_type(self.type, self.type_version,)
results = SelectionResult.create_for_type(self.type, self.type_version,)
current_app.logger.debug(f"Results: {results.model_dump()}")
return results
@@ -481,6 +481,14 @@ class PersonalContactData(BaseModel):
consent: bool = Field(..., description="Consent", alias="consent")
class ContactTimePreferences(BaseModel):
early: Optional[bool] = Field(None, description="Early", alias="early")
late_morning: Optional[bool] = Field(None, description="Late Morning", alias="late_morning")
afternoon: Optional[bool] = Field(None, description="Afternoon", alias="afternoon")
evening: Optional[bool] = Field(None, description="Evening", alias="evening")
other: Optional[str] = Field(None, description="Other", alias="other")
class SelectionInput(BaseModel):
# RAG elements
language: Optional[str] = Field(None, alias="language")
@@ -508,7 +516,7 @@ class SelectionFlowState(EveAIFlowState):
rag_output: Optional[RAGOutput] = None
ko_criteria_answers: Optional[Dict[str, str]] = None
personal_contact_data: Optional[PersonalContactData] = None
contact_time: Optional[str] = None
contact_time_prefs: Optional[ContactTimePreferences] = None
citations: Optional[List[Dict[str, Any]]] = None
@@ -516,7 +524,7 @@ class SelectionResult(SpecialistResult):
rag_output: Optional[RAGOutput] = Field(None, alias="rag_output")
ko_criteria_answers: Optional[Dict[str, str]] = Field(None, alias="ko_criteria_answers")
personal_contact_data: Optional[PersonalContactData] = Field(None, alias="personal_contact_data")
contact_time: Optional[str] = None
contact_time_prefs: Optional[ContactTimePreferences] = None
class SelectionFlow(EveAICrewAIFlow[SelectionFlowState]):