From 9a88582fffdde99a3a4475eff5869d90046afde1 Mon Sep 17 00:00:00 2001 From: Josako Date: Sat, 2 Aug 2025 16:36:41 +0200 Subject: [PATCH] - Refinement of the chat client to have better visible clues for user vs chatbot messages - Introduction of interview_phase and normal phase in TRAICIE_SELECTION_SPECIALIST to make interaction with bot more human. - More and random humanised messages to TRAICIE_SELECTION_SPECIALIST --- common/utils/chat_utils.py | 9 +- common/utils/model_utils.py | 2 - config/agents/globals/RAG_AGENT/1.1.0.yaml | 2 +- .../1.0.0.yaml | 2 +- .../CHAT_CLIENT_CUSTOMISATION/1.0.0.yaml | 38 +- .../globals/DOCX_PROCESSOR/1.0.0.yaml | 2 +- .../1.0.0.yaml | 4 +- .../1.0.0.yaml | 4 +- .../MINIMAL_PERSONAL_CONTACT_FORM/1.0.0.yaml | 31 + .../1.1.0.yaml | 29 + .../TRAICIE_SELECTION_SPECIALIST/1.5.0.yaml | 121 +++ .../globals/ADVANCED_RAG_TASK/1.0.0.yaml | 43 + config/tasks/globals/RAG_TASK/1.1.0.yaml | 35 +- .../1.0.0.yaml | 29 + .../1.0.0.yaml | 30 - .../1.0.0.yaml | 23 + config/type_defs/specialist_form_types.py | 4 + config/type_defs/task_types.py | 19 +- docker/rebuild_chat_client.sh | 4 + docker/release_and_tag_eveai.sh | 4 +- documentation/ICON_MANAGEMENT_GUIDE.md | 86 +- .../static/assets/css/chat-components.css | 63 +- .../static/assets/css/chat-input.css | 77 +- .../static/assets/css/chat-message.css | 43 + eveai_chat_client/static/assets/css/form.css | 18 + .../static/assets/img/eveai_logo.png | Bin 0 -> 7821 bytes .../static/assets/img/eveai_logo.svg | 21 + .../static/assets/img/eveai_logo.webp | Bin 0 -> 20186 bytes .../assets/{images => img}/evie_working.webp | Bin .../static/assets/img/favicon.png | Bin 0 -> 7821 bytes .../assets/vue-components/ChatInput.vue | 80 +- .../assets/vue-components/ChatMessage.vue | 83 +- .../assets/vue-components/DynamicForm.vue | 211 ++++- .../assets/vue-components/FormField.vue | 25 +- .../assets/vue-components/MessageHistory.vue | 95 ++- eveai_chat_client/templates/base.html | 16 +- .../language_level/language_level_v1_0.py | 11 +- .../tone_of_voice/tone_of_voice_v1_0.py | 11 +- .../outputs/globals/rag/rag_v1_0.py | 4 + .../traicie/advanced_rag/advanced_rag_v1_0.py | 12 + .../affirmative_answer_v1_0.py | 10 + .../interview_mode/interview_mode_v1_0.py | 10 + .../1_0.py | 144 ++++ .../specialists/crewai_base_classes.py | 4 +- .../specialists/crewai_base_specialist.py | 11 +- .../TRAICIE_ROLE_DEFINITION_SPECIALIST/1_3.py | 2 +- .../TRAICIE_SELECTION_SPECIALIST/1_4.py | 173 ++-- .../TRAICIE_SELECTION_SPECIALIST/1_5.py | 793 ++++++++++++++++++ nginx/package.json | 8 +- requirements.txt | 2 +- 50 files changed, 2064 insertions(+), 384 deletions(-) create mode 100644 config/specialist_forms/globals/MINIMAL_PERSONAL_CONTACT_FORM/1.0.0.yaml create mode 100644 config/specialists/traicie/TRAICIE_KO_INTERVIEW_DEFINITION_SPECIALIST/1.1.0.yaml create mode 100644 config/specialists/traicie/TRAICIE_SELECTION_SPECIALIST/1.5.0.yaml create mode 100644 config/tasks/globals/ADVANCED_RAG_TASK/1.0.0.yaml create mode 100644 config/tasks/traicie/TRAICIE_AFFIRMATIVE_ANSWER_CHECK_TASK/1.0.0.yaml delete mode 100644 config/tasks/traicie/TRAICIE_COMPETENCIES_INTERVIEW_DEFINITION/1.0.0.yaml create mode 100644 config/tasks/traicie/TRAICIE_DETERMINE_INTERVIEW_MODE_TASK/1.0.0.yaml create mode 100644 eveai_chat_client/static/assets/img/eveai_logo.png create mode 100644 eveai_chat_client/static/assets/img/eveai_logo.svg create mode 100644 eveai_chat_client/static/assets/img/eveai_logo.webp rename eveai_chat_client/static/assets/{images => img}/evie_working.webp (100%) create mode 100644 eveai_chat_client/static/assets/img/favicon.png create mode 100644 eveai_chat_workers/outputs/traicie/advanced_rag/advanced_rag_v1_0.py create mode 100644 eveai_chat_workers/outputs/traicie/affirmative_answer/affirmative_answer_v1_0.py create mode 100644 eveai_chat_workers/outputs/traicie/interview_mode/interview_mode_v1_0.py create mode 100644 eveai_chat_workers/retrievers/traicie/TRAICIE_ROLE_DEFINITION_BY_ROLE_IDENTIFICATION/1_0.py create mode 100644 eveai_chat_workers/specialists/traicie/TRAICIE_SELECTION_SPECIALIST/1_5.py diff --git a/common/utils/chat_utils.py b/common/utils/chat_utils.py index 0788bbd..9b7fd87 100644 --- a/common/utils/chat_utils.py +++ b/common/utils/chat_utils.py @@ -31,11 +31,12 @@ def get_default_chat_customisation(tenant_customisation=None): 'progress_tracker_insights': 'No Information', 'form_title_display': 'Full Title', 'active_background_color': '#ffffff', - 'active_text_color': '#212529', 'history_background': 10, - 'history_user_message_background': -10, - 'history_ai_message_background': 0, - 'history_message_text_color': '#212529', + 'ai_message_background': '#ffffff', + 'ai_message_text_color': '#212529', + 'human_message_background': '#212529', + 'human_message_text_color': '#ffffff', + } # If no tenant customization is provided, return the defaults diff --git a/common/utils/model_utils.py b/common/utils/model_utils.py index 10108b1..3a239d7 100644 --- a/common/utils/model_utils.py +++ b/common/utils/model_utils.py @@ -57,9 +57,7 @@ def replace_variable_in_template(template: str, variable: str, value: str) -> st str: Template with variable placeholder replaced """ - current_app.logger.info(f"Replacing variable {variable} with value {value}") modified_template = template.replace(f"{{{variable}}}", value or "") - current_app.logger.info(f"Modified template: {modified_template}") return modified_template diff --git a/config/agents/globals/RAG_AGENT/1.1.0.yaml b/config/agents/globals/RAG_AGENT/1.1.0.yaml index 68709d8..1676cd0 100644 --- a/config/agents/globals/RAG_AGENT/1.1.0.yaml +++ b/config/agents/globals/RAG_AGENT/1.1.0.yaml @@ -15,7 +15,7 @@ backstory: > include a salutation or closing greeting in your answer. {custom_backstory} full_model_name: "mistral.mistral-medium-latest" -temperature: 0.3 +temperature: 0.5 metadata: author: "Josako" date_added: "2025-01-08" diff --git a/config/catalogs/traicie/TRAICIE_ROLE_DEFINITION_CATALOG/1.0.0.yaml b/config/catalogs/traicie/TRAICIE_ROLE_DEFINITION_CATALOG/1.0.0.yaml index f8bbb4f..d5e8ca9 100644 --- a/config/catalogs/traicie/TRAICIE_ROLE_DEFINITION_CATALOG/1.0.0.yaml +++ b/config/catalogs/traicie/TRAICIE_ROLE_DEFINITION_CATALOG/1.0.0.yaml @@ -3,7 +3,7 @@ name: "Role Definition Catalog" description: "A Catalog containing information specific to a specific role" configuration: tagging_fields: - role_identification: + role_reference: type: "string" required: true description: "A unique identification for the role" diff --git a/config/customisations/globals/CHAT_CLIENT_CUSTOMISATION/1.0.0.yaml b/config/customisations/globals/CHAT_CLIENT_CUSTOMISATION/1.0.0.yaml index 79db237..c8f9273 100644 --- a/config/customisations/globals/CHAT_CLIENT_CUSTOMISATION/1.0.0.yaml +++ b/config/customisations/globals/CHAT_CLIENT_CUSTOMISATION/1.0.0.yaml @@ -55,11 +55,6 @@ configuration: description: "Primary Color" type: "color" required: false - active_text_color: - name: "Active Interaction Text Color" - description: "Secondary Color" - type: "color" - required: false history_background: name: "History Background" description: "Percentage to lighten (+) / darken (-) the user message background" @@ -67,27 +62,28 @@ configuration: min_value: -50 max_value: 50 required: false - history_user_message_background: - name: "History User Message Background" - description: "Percentage to lighten (+) / darken (-) the user message background" - type: "integer" - min_value: -50 - max_value: 50 + ai_message_background: + name: "AI (Bot) Message Background Color" + description: "AI (Bot) Message Background Color" + type: "color" required: false - history_ai_message_background: - name: "History AI Message Background" - description: "Percentage to lighten (+) / darken (-) the AI message background" - type: "integer" - min_value: -50 - max_value: 50 + ai_message_text_color: + name: "AI (Bot) Message Text Color" + description: "AI (Bot) Message Text Color" + type: "color" required: false - history_message_text_color: - name: "History Text Color" - description: "History Message Text Color" + human_message_background: + name: "Human Message Background Color" + description: "Human Message Background Color" + type: "color" + required: false + human_message_text_color: + name: "Human Message Text Color" + description: "Human Message Text Color" type: "color" required: false metadata: author: "Josako" date_added: "2024-06-06" - changes: "Initial version" + changes: "Adaptations to make color choosing more consistent and user friendly" description: "Parameters allowing to customise the chat client" \ No newline at end of file diff --git a/config/processors/globals/DOCX_PROCESSOR/1.0.0.yaml b/config/processors/globals/DOCX_PROCESSOR/1.0.0.yaml index 3426a64..69b21c7 100644 --- a/config/processors/globals/DOCX_PROCESSOR/1.0.0.yaml +++ b/config/processors/globals/DOCX_PROCESSOR/1.0.0.yaml @@ -42,7 +42,7 @@ configuration: image_handling: name: "Image Handling" type: "enum" - description: "How to handle embedded images" + description: "How to handle embedded img" required: false default: "skip" allowed_values: ["skip", "extract", "placeholder"] diff --git a/config/retrievers/traicie/TRAICIE_ROLE_DEFINITION_BY_ROLE_IDENTIFICATION/1.0.0.yaml b/config/retrievers/traicie/TRAICIE_ROLE_DEFINITION_BY_ROLE_IDENTIFICATION/1.0.0.yaml index 78a7d10..99bb3da 100644 --- a/config/retrievers/traicie/TRAICIE_ROLE_DEFINITION_BY_ROLE_IDENTIFICATION/1.0.0.yaml +++ b/config/retrievers/traicie/TRAICIE_ROLE_DEFINITION_BY_ROLE_IDENTIFICATION/1.0.0.yaml @@ -14,8 +14,8 @@ configuration: required: true default: 0.3 arguments: - role_identification: - name: "Role Identification" + role_reference: + name: "Role Reference" type: "string" description: "The role information needs to be retrieved for" required: true diff --git a/config/retrievers/traicie/TRAICIE_ROLE_DEFINITION_VACANCY_TEXT/1.0.0.yaml b/config/retrievers/traicie/TRAICIE_ROLE_DEFINITION_VACANCY_TEXT/1.0.0.yaml index 41fce76..0b21e8d 100644 --- a/config/retrievers/traicie/TRAICIE_ROLE_DEFINITION_VACANCY_TEXT/1.0.0.yaml +++ b/config/retrievers/traicie/TRAICIE_ROLE_DEFINITION_VACANCY_TEXT/1.0.0.yaml @@ -19,8 +19,8 @@ arguments: type: "string" description: "Query to retrieve embeddings" required: true - role_identification: - name: "Role Identification" + role_reference: + name: "Role Reference" type: "string" description: "The role information needs to be retrieved for" required: true diff --git a/config/specialist_forms/globals/MINIMAL_PERSONAL_CONTACT_FORM/1.0.0.yaml b/config/specialist_forms/globals/MINIMAL_PERSONAL_CONTACT_FORM/1.0.0.yaml new file mode 100644 index 0000000..0b62127 --- /dev/null +++ b/config/specialist_forms/globals/MINIMAL_PERSONAL_CONTACT_FORM/1.0.0.yaml @@ -0,0 +1,31 @@ +type: "PERSONAL_CONTACT_FORM" +version: "1.0.0" +name: "Personal Contact Form" +icon: "person" +fields: + name: + name: "Name" + description: "Your name" + type: "str" + required: true +# It is possible to also add a field 'context'. It allows you to provide an elaborate piece of information. + email: + name: "Email" + type: "str" + description: "Your Name" + required: true + phone: + name: "Phone Number" + type: "str" + description: "Your Phone Number" + required: true + consent: + name: "Consent" + type: "boolean" + description: "Consent" + required: true +metadata: + author: "Josako" + date_added: "2025-07-29" + changes: "Initial Version" + description: "Personal Contact Form" diff --git a/config/specialists/traicie/TRAICIE_KO_INTERVIEW_DEFINITION_SPECIALIST/1.1.0.yaml b/config/specialists/traicie/TRAICIE_KO_INTERVIEW_DEFINITION_SPECIALIST/1.1.0.yaml new file mode 100644 index 0000000..1a551b7 --- /dev/null +++ b/config/specialists/traicie/TRAICIE_KO_INTERVIEW_DEFINITION_SPECIALIST/1.1.0.yaml @@ -0,0 +1,29 @@ +version: "1.1.0" +name: "Traicie KO Criteria Interview Definition Specialist" +framework: "crewai" +partner: "traicie" +chat: false +configuration: +arguments: + specialist_id: + name: "specialist_id" + description: "ID of the specialist for which to define KO Criteria Questions and Asnwers" + type: "integer" + required: true +results: + asset_id: + name: "asset_id" + description: "ID of the Asset containing questions and answers for each of the defined KO Criteria" + type: "integer" + required: true +agents: + - type: "TRAICIE_HR_BP_AGENT" + version: "1.0" +tasks: + - type: "TRAICIE_KO_CRITERIA_INTERVIEW_DEFINITION_TASK" + version: "1.0" +metadata: + author: "Josako" + date_added: "2025-07-01" + changes: "Initial Version" + description: "Specialist assisting in questions and answers definition for KO Criteria" \ No newline at end of file diff --git a/config/specialists/traicie/TRAICIE_SELECTION_SPECIALIST/1.5.0.yaml b/config/specialists/traicie/TRAICIE_SELECTION_SPECIALIST/1.5.0.yaml new file mode 100644 index 0000000..c50509f --- /dev/null +++ b/config/specialists/traicie/TRAICIE_SELECTION_SPECIALIST/1.5.0.yaml @@ -0,0 +1,121 @@ +version: "1.4.0" +name: "Traicie Selection Specialist" +framework: "crewai" +partner: "traicie" +chat: true +configuration: + name: + name: "Name" + description: "The name the specialist is called upon." + type: "str" + required: true + role_reference: + name: "Role Reference" + description: "A customer reference to the role" + type: "str" + required: false + make: + name: "Make" + description: "The make for which the role is defined and the selection specialist is created" + type: "system" + system_name: "tenant_make" + required: true + competencies: + name: "Competencies" + description: "An ordered list of competencies." + type: "ordered_list" + list_type: "competency_details" + required: true + tone_of_voice: + name: "Tone of Voice" + description: "The tone of voice the specialist uses to communicate" + type: "enum" + allowed_values: ["Professional & Neutral", "Warm & Empathetic", "Energetic & Enthusiastic", "Accessible & Informal", "Expert & Trustworthy", "No-nonsense & Goal-driven"] + default: "Professional & Neutral" + required: true + language_level: + name: "Language Level" + description: "Language level to be used when communicating, relating to CEFR levels" + type: "enum" + allowed_values: ["Basic", "Standard", "Professional"] + default: "Standard" + required: true + welcome_message: + name: "Welcome Message" + description: "Introductory text given by the specialist - but translated according to Tone of Voice, Language Level and Starting Language" + type: "text" + required: false +competency_details: + title: + name: "Title" + description: "Competency Title" + type: "str" + required: true + description: + name: "Description" + description: "Description (in context of the role) of the competency" + type: "text" + required: true + is_knockout: + name: "KO" + description: "Defines if the competency is a knock-out criterium" + type: "boolean" + required: true + default: false + assess: + name: "Assess" + description: "Indication if this competency is to be assessed" + type: "boolean" + required: true + default: true +arguments: + region: + name: "Region" + type: "str" + description: "The region of the specific vacancy" + required: false + working_schedule: + name: "Work Schedule" + type: "str" + description: "The work schedule or employment type of the specific vacancy" + required: false + start_date: + name: "Start Date" + type: "date" + description: "The start date of the specific vacancy" + required: false + language: + name: "Language" + type: "str" + description: "The language (2-letter code) used to start the conversation" + required: true + interaction_mode: + name: "Interaction Mode" + type: "enum" + description: "The interaction mode the specialist will start working in." + allowed_values: ["orientation", "selection"] + default: "orientation" + required: true +results: + competencies: + name: "competencies" + type: "List[str, str]" + description: "List of vacancy competencies and their descriptions" + required: false +agents: + - type: "TRAICIE_RECRUITER_AGENT" + version: "1.0" + - type: "RAG_AGENT" + version: "1.1" +tasks: + - type: "TRAICIE_DETERMINE_INTERVIEW_MODE_TASK" + version: "1.0" + - type: "TRAICIE_AFFIRMATIVE_ANSWER_CHECK_TASK" + version: "1.0" + - type: "ADVANCED_RAG_TASK" + version: "1.0" +metadata: + author: "Josako" + date_added: "2025-07-30" + changes: "Update for a Full Virtual Assistant Experience" + description: "Assistant to assist in candidate selection" \ No newline at end of file diff --git a/config/tasks/globals/ADVANCED_RAG_TASK/1.0.0.yaml b/config/tasks/globals/ADVANCED_RAG_TASK/1.0.0.yaml new file mode 100644 index 0000000..cc98934 --- /dev/null +++ b/config/tasks/globals/ADVANCED_RAG_TASK/1.0.0.yaml @@ -0,0 +1,43 @@ +version: "1.0.0" +name: "Advanced RAG Task" +task_description: > + Answer the following question (in between triple £): + + £££{question}£££ + + Base your answer on the following context (in between triple $): + + $$${context}$$$ + + Take into account the following history of the conversation (in between triple €): + + €€€{history}€€€ + + The HUMAN parts indicate the interactions by the end user, the AI parts are your interactions. + + Best Practices are: + + - Answer the provided question as precisely and directly as you can, combining elements of the provided context. + - Always focus your answer on the actual question. + - Limit repetition in your answers to an absolute minimum, unless absolutely necessary. + - Always be friendly and helpful for the end user. + + Tune your answers to the following: + + - You use the following Tone of Voice for your answer: {tone_of_voice}, i.e. {tone_of_voice_context} + - You use the following Language Level for your answer: {language_level}, i.e. {language_level_context} + + Use the following language in your communication: {language} + + If the question cannot be answered using the given context, answer "I have insufficient information to answer this + question." and give the appropriate indication. + + {custom_description} + +expected_output: > + +metadata: + author: "Josako" + date_added: "2025-07-30" + description: "A Task that performs RAG and checks for human answers" + changes: "Initial version" diff --git a/config/tasks/globals/RAG_TASK/1.1.0.yaml b/config/tasks/globals/RAG_TASK/1.1.0.yaml index a941103..457a51e 100644 --- a/config/tasks/globals/RAG_TASK/1.1.0.yaml +++ b/config/tasks/globals/RAG_TASK/1.1.0.yaml @@ -1,19 +1,32 @@ version: "1.0.0" name: "RAG Task" task_description: > - Answer the question based on the following context, and taking into account the history of the discussion. Try not to - repeat answers already given in the recent history, unless confirmation is required or repetition is essential to - give a coherent answer. + Answer the following question (in between triple £): + + £££{question}£££ + + Base your answer on the following context (in between triple $): + + $$${context}$$$ + + Take into account the following history of the conversation (in between triple €): + + €€€{history}€€€ + + The HUMAN parts indicate the interactions by the end user, the AI parts are your interactions. + + Best Practices are: + + - Answer the provided question as precisely and directly as you can, combining elements of the provided context. + - Always focus your answer on the actual HUMAN question. + - Try not to repeat your answers (preceded by AI), unless absolutely necessary. + - Focus your answer on the question at hand. + - Always be friendly and helpful for the end user. + {custom_description} - Use the following {language} in your communication, and cite the sources used at the end of the full conversation. + Use the following {language} in your communication. If the question cannot be answered using the given context, answer "I have insufficient information to answer this - question." - Context (in between triple $): - $$${context}$$$ - History (in between triple €): - €€€{history}€€€ - Question (in between triple £): - £££{question}£££ + question." and give the appropriate indication. expected_output: > Your answer. metadata: diff --git a/config/tasks/traicie/TRAICIE_AFFIRMATIVE_ANSWER_CHECK_TASK/1.0.0.yaml b/config/tasks/traicie/TRAICIE_AFFIRMATIVE_ANSWER_CHECK_TASK/1.0.0.yaml new file mode 100644 index 0000000..0fd3038 --- /dev/null +++ b/config/tasks/traicie/TRAICIE_AFFIRMATIVE_ANSWER_CHECK_TASK/1.0.0.yaml @@ -0,0 +1,29 @@ +version: "1.0.0" +name: "Traicie Affirmative Answer Check" +task_description: > + You are provided with the following end user answer (in between triple £): + + £££{question}£££ + + This is the history of the conversation (in between triple €): + + €€€{history}€€€ + + (In this history, user interactions are preceded by 'HUMAN', and your interactions with 'AI'.) + + Check if the user has given an affirmative answer or not. + Please note that this answer can be very short: + - Affirmative answers: e.g. Yes, OK, Sure, Of Course + - Negative answers: e.g. No, not really, No, I'd rather not. + + Please consider that the answer will be given in {language}! + + {custom_description} + +expected_output: > + Your determination if the answer was affirmative (true) or negative (false) +metadata: + author: "Josako" + date_added: "2025-07-30" + description: "A Task to check if the answer to a question is affirmative" + changes: "Initial version" diff --git a/config/tasks/traicie/TRAICIE_COMPETENCIES_INTERVIEW_DEFINITION/1.0.0.yaml b/config/tasks/traicie/TRAICIE_COMPETENCIES_INTERVIEW_DEFINITION/1.0.0.yaml deleted file mode 100644 index f120e40..0000000 --- a/config/tasks/traicie/TRAICIE_COMPETENCIES_INTERVIEW_DEFINITION/1.0.0.yaml +++ /dev/null @@ -1,30 +0,0 @@ -version: "1.0.0" -name: "KO Criteria Interview Definition" -task_description: > - In context of a vacancy in your company {tenant_name}, you are provided with a set of competencies. (both description - and title). The competencies are in between triple backquotes. You need to prepare for the interviews, - and are to provide for each of these ko criteria: - - - A question to ask the recruitment candidate describing the context of the competency. Use your experience to not - just ask a closed question, but a question from which you can indirectly derive a positive or negative qualification of - the competency based on the answer of the candidate. - - Apply the following tone of voice in both questions and answers: {tone_of_voice} - Apply the following language level in both questions and answers: {language_level} - Respect the language of the competencies, and return all output in the same language. - - ```{competencies}``` - - {custom_description} - -expected_output: > - For each of the ko criteria, you provide: - - the exact title in the original language - - the question - - a set of answers, with for each answer an indication if it is the correct answer, or a false response. - {custom_expected_output} -metadata: - author: "Josako" - date_added: "2025-06-15" - description: "A Task to define interview Q&A from given KO Criteria" - changes: "Initial Version" diff --git a/config/tasks/traicie/TRAICIE_DETERMINE_INTERVIEW_MODE_TASK/1.0.0.yaml b/config/tasks/traicie/TRAICIE_DETERMINE_INTERVIEW_MODE_TASK/1.0.0.yaml new file mode 100644 index 0000000..c19893e --- /dev/null +++ b/config/tasks/traicie/TRAICIE_DETERMINE_INTERVIEW_MODE_TASK/1.0.0.yaml @@ -0,0 +1,23 @@ +version: "1.0.0" +name: "Traicie Determine Interview Mode" +task_description: > + you are provided with the following user input (in between triple backquotes): + + ```{question}``` + + If this user input contains one or more questions, your answer is simply 'RAG'. In all other cases, your answer is + 'CHECK'. + + Best practices to be applied: + - A question doesn't always have an ending question mark. It can be a query for more information, such as 'I'd like + to understand ...', 'I'd like to know more about...'. Or it is possible the user didn't enter a question mark. Take + into account the user might be working on a mobile device like a phone, making typing not as obvious. + - If there is a question mark, then normally you are provided with a question of course. + +expected_output: > + Your Answer. +metadata: + author: "Josako" + date_added: "2025-07-30" + description: "A Task to determine the interview mode based on the last user input" + changes: "Initial version" diff --git a/config/type_defs/specialist_form_types.py b/config/type_defs/specialist_form_types.py index 2523db4..f9d3b31 100644 --- a/config/type_defs/specialist_form_types.py +++ b/config/type_defs/specialist_form_types.py @@ -12,4 +12,8 @@ SPECIALIST_FORM_TYPES = { "name": "Contact Time Preferences Form", "description": "A form for entering contact time preferences", }, + "MINIMAL_PERSONAL_CONTACT_FORM": { + "name": "Personal Contact Form", + "description": "A form for entering your personal contact details", + } } \ No newline at end of file diff --git a/config/type_defs/task_types.py b/config/type_defs/task_types.py index 00648b9..3c7df5a 100644 --- a/config/type_defs/task_types.py +++ b/config/type_defs/task_types.py @@ -37,14 +37,23 @@ TASK_TYPES = { "description": "A Task to get Competencies from a Vacancy Text", "partner": "traicie" }, - "TRAICIE_GET_KO_CRITERIA_TASK": { - "name": "Traicie Get KO Criteria", - "description": "A Task to get KO Criteria from a Vacancy Text", - "partner": "traicie" - }, "TRAICIE_KO_CRITERIA_INTERVIEW_DEFINITION_TASK": { "name": "Traicie KO Criteria Interview Definition", "description": "A Task to define KO Criteria questions to be used during the interview", "partner": "traicie" + }, + "TRAICIE_ADVANCED_RAG_TASK": { + "name": "Traicie Advanced RAG", + "description": "A Task to perform Advanced RAG taking into account previous questions, tone of voice and language level", + "partner": "traicie" + }, + "TRAICIE_AFFIRMATIVE_ANSWER_CHECK_TASK": { + "name": "Traicie Affirmative Answer Check", + "description": "A Task to check if the answer to a question is affirmative", + "partner": "traicie" + }, + "TRAICIE_DETERMINE_INTERVIEW_MODE_TASK": { + "name": "Traicie Determine Interview Mode", + "description": "A Task to determine the interview mode based on the last user input", } } diff --git a/docker/rebuild_chat_client.sh b/docker/rebuild_chat_client.sh index 4416a09..f93ccf6 100755 --- a/docker/rebuild_chat_client.sh +++ b/docker/rebuild_chat_client.sh @@ -3,6 +3,10 @@ cd /Volumes/OWC4M2_1/Development/Josako/EveAI/TBD/docker source ./docker_env_switch.sh dev +echo "Copying client images" +cp -fv ../eveai_chat_client/static/assets/img/* ../nginx/static/assets/img + + dcdown eveai_chat_client nginx cd ../nginx diff --git a/docker/release_and_tag_eveai.sh b/docker/release_and_tag_eveai.sh index c5bcbdc..5813220 100755 --- a/docker/release_and_tag_eveai.sh +++ b/docker/release_and_tag_eveai.sh @@ -31,10 +31,10 @@ fi # Path to your docker-compose file DOCKER_COMPOSE_FILE="compose_dev.yaml" -# Get all the images defined in docker-compose +# Get all the img defined in docker-compose IMAGES=$(docker compose -f $DOCKER_COMPOSE_FILE config | grep 'image:' | awk '{ print $2 }') -# Start tagging only relevant images +# Start tagging only relevant img for DOCKER_IMAGE in $IMAGES; do # Check if the image belongs to your Docker account and ends with :latest if [[ $DOCKER_IMAGE == $DOCKER_ACCOUNT* && $DOCKER_IMAGE == *:latest ]]; then diff --git a/documentation/ICON_MANAGEMENT_GUIDE.md b/documentation/ICON_MANAGEMENT_GUIDE.md index 75500e9..45ae858 100644 --- a/documentation/ICON_MANAGEMENT_GUIDE.md +++ b/documentation/ICON_MANAGEMENT_GUIDE.md @@ -108,7 +108,91 @@ const { loadIcon } = useFormIcon(() => props.formData); 1. **ChatInput.vue** - Uses `useIconManager()` composable 2. **ChatMessage.vue** - Uses `useIconManager()` composable -3. **DynamicForm.vue** - Uses `useIconManager()` composable +3. **DynamicForm.vue** - Uses `useIconManager()` composable with boolean icon support + +## 🔘 Boolean Value Display + +### Overview + +Boolean values in read-only DynamicForm components are automatically displayed using Material Icons instead of text for improved user experience. + +### Icon Mapping + +```javascript +const booleanIconMapping = { + true: 'check_circle', // Green checkmark icon + false: 'cancel' // Red cancel/cross icon +}; +``` + +### Visual Styling + +- **True values**: Green `check_circle` icon (#4caf50) +- **False values**: Red `cancel` icon (#f44336) +- **Size**: 20px font size with middle vertical alignment +- **Accessibility**: Includes `aria-label` and `title` attributes + +### Usage Example + +```vue + + + + + +``` + +### Implementation Details + +- **Automatic icon loading**: Boolean icons (`check_circle`, `cancel`) are preloaded when DynamicForm mounts +- **Read-only only**: Edit mode continues to use standard HTML checkboxes +- **Accessibility**: Each icon includes Dutch labels ('Ja'/'Nee') for screen readers +- **Responsive**: Icons scale appropriately with form styling + +### CSS Classes + +```css +.boolean-icon { + font-size: 20px; + vertical-align: middle; +} + +.boolean-true { + color: #4caf50; /* Green for true */ +} + +.boolean-false { + color: #f44336; /* Red for false */ +} + +.field-value.boolean-value { + display: flex; + align-items: center; +} +``` ### Zero Legacy Code Remaining ✅ diff --git a/eveai_chat_client/static/assets/css/chat-components.css b/eveai_chat_client/static/assets/css/chat-components.css index 76d8ee5..c52711c 100644 --- a/eveai_chat_client/static/assets/css/chat-components.css +++ b/eveai_chat_client/static/assets/css/chat-components.css @@ -79,23 +79,14 @@ } /* Chat Input styling */ -.chat-input-container { - width: 100%; - position: relative; - padding: 20px; /* Interne padding voor ChatInput */ - box-sizing: border-box; - max-width: 1000px; /* Optimale breedte */ - margin-left: auto; - margin-right: auto; /* Horizontaal centreren */ -} .chat-input { display: flex; align-items: flex-end; gap: 12px; padding: 20px; - background: var(--active-background-color); - color: var(--active-text-color); + background: var(--human-message-background); + color: var(--human-message-text-color); border-radius: 15px; box-shadow: 0 2px 15px rgba(0,0,0,0.1); border: 1px solid rgba(0,0,0,0.05); @@ -113,37 +104,6 @@ gap: 8px; } -.send-btn { - width: 45px; - height: 45px; - border: none; - border-radius: 50%; - background: var(--active-background-color); - color: var(--active-text-color); - cursor: pointer; - display: flex; - align-items: center; - justify-content: center; - font-size: 18px; - transition: all 0.2s ease; - box-shadow: 0 2px 10px rgba(0,0,0,0.1); -} - -.send-btn:hover:not(:disabled) { - background: var(--active-text-color); - color: var(--active-background-color); - transform: scale(1.05); - box-shadow: 0 4px 15px rgba(0,0,0,0.2); -} - -.send-btn:disabled { - background: #ccc; - cursor: not-allowed; - transform: none; - box-shadow: none; -} - - /* Character counter */ .character-counter { position: absolute; @@ -152,7 +112,7 @@ font-size: 12px; color: #666; padding: 2px 6px; - background: rgba(255,255,255,0.9); + background: rgba(255,255,255,0.2); border-radius: 10px; backdrop-filter: blur(5px); } @@ -190,11 +150,6 @@ max-width: 100%; /* Op mobiel volledige breedte gebruiken */ } - .chat-input-container { - padding: 15px; - max-width: 100%; /* Op mobiel volledige breedte gebruiken */ - } - .chat-input { padding: 15px; gap: 10px; @@ -224,10 +179,6 @@ .message-history-container { padding: 12px; } - - .chat-input-container { - padding: 12px; - } } /* Loading states */ @@ -343,16 +294,16 @@ /* User message bubble styling */ .message.user .message-content { - background: var(--history-user-message-background); - color: var(--history-message-text-color); + background: var(--human-message-background); + color: var(--human-message-text-color); border-bottom-right-radius: 4px; } /* AI/Bot message bubble styling */ .message.ai .message-content, .message.bot .message-content { - background: var(--history-ai-message-background); - color: var(--history-message-text-color); + background: var(--ai-message-background); + color: var(--ai-message-text-color); border-bottom-left-radius: 4px; margin-right: 60px; } diff --git a/eveai_chat_client/static/assets/css/chat-input.css b/eveai_chat_client/static/assets/css/chat-input.css index 9a4e060..6991d08 100644 --- a/eveai_chat_client/static/assets/css/chat-input.css +++ b/eveai_chat_client/static/assets/css/chat-input.css @@ -1,14 +1,6 @@ /* ChatInput component styling */ /* Algemene container */ -.chat-input-container { - width: 100%; - padding: 10px; - background-color: #fff; - border-top: 1px solid #e0e0e0; - font-family: Arial, sans-serif; - font-size: 14px; -} /* Input veld en knoppen */ .chat-input { @@ -42,38 +34,6 @@ gap: 8px; } -/* Verzendknop */ -.send-btn { - display: flex; - align-items: center; - justify-content: center; - width: 40px; - height: 40px; - background-color: #0084ff; - color: white; - border: none; - border-radius: 50%; - cursor: pointer; - transition: background-color 0.2s; -} - -.send-btn:hover { - background-color: #0077e6; -} - -.send-btn:disabled { - background-color: #ccc; - cursor: not-allowed; -} - -.send-btn.form-mode { - background-color: #4caf50; -} - -.send-btn.form-mode:hover { - background-color: #43a047; -} - /* Loading spinner */ .loading-spinner { display: inline-block; @@ -85,3 +45,40 @@ 100% { transform: rotate(360deg); } } +/* Form actions container */ +.form-actions { + display: flex; + justify-content: flex-end; + align-items: center; + padding: 10px 0; + margin-top: 10px; +} + +/* Form send actions container - for send button within form */ +.form-send-actions { + display: flex; + justify-content: flex-end; + align-items: center; + padding: 10px 0; + margin-top: 10px; +} + +/* Dynamic form container transitions */ +.dynamic-form-container { + transition: opacity 0.3s ease-in-out, transform 0.3s ease-in-out; + transform: translateY(0); + opacity: 1; +} + +/* Chat input transitions */ +.chat-input { + transition: opacity 0.3s ease-in-out, transform 0.3s ease-in-out; + transform: translateY(0); + opacity: 1; +} + +/* Smooth transitions for mode switching */ +.chat-input-container > * { + transition: opacity 0.2s ease-in-out; +} + diff --git a/eveai_chat_client/static/assets/css/chat-message.css b/eveai_chat_client/static/assets/css/chat-message.css index c1e4671..6fce9ac 100644 --- a/eveai_chat_client/static/assets/css/chat-message.css +++ b/eveai_chat_client/static/assets/css/chat-message.css @@ -149,3 +149,46 @@ font-family: Arial, sans-serif; font-size: 14px; } + +/* Ensure forms in messages use full available width */ +.message .dynamic-form-container { + width: 100%; + max-width: none; +} + +.message .dynamic-form { + width: 100%; +} + +.message .form-fields { + width: 100%; +} + +/* Optimize form field layout in messages to prevent unnecessary label wrapping */ +.message .form-field { + display: grid; + grid-template-columns: 30% 70%; + gap: 12px; + align-items: start; + width: 100%; +} + +/* Ensure form field inputs use full available space */ +.message .form-field input, +.message .form-field select, +.message .form-field textarea { + width: 100%; + box-sizing: border-box; +} + +/* Special handling for radio fields in messages */ +.message .form-field.radio-field { + display: block; + width: 100%; +} + +.message .form-field.radio-field .field-label { + display: block; + margin-bottom: 8px; + width: 100%; +} diff --git a/eveai_chat_client/static/assets/css/form.css b/eveai_chat_client/static/assets/css/form.css index 31ebad5..69c3569 100644 --- a/eveai_chat_client/static/assets/css/form.css +++ b/eveai_chat_client/static/assets/css/form.css @@ -124,3 +124,21 @@ .text-value { white-space: pre-wrap; } + +/* Loading spinner for send button */ +.form-actions .loading-spinner { + display: inline-block; + animation: spin 1s linear infinite; +} + +@keyframes spin { + 0% { transform: rotate(0deg); } + 100% { transform: rotate(360deg); } +} + +/* Flexbox layout for single send button */ +.form-actions.with-send-button { + display: flex; + justify-content: flex-end; + align-items: center; +} diff --git a/eveai_chat_client/static/assets/img/eveai_logo.png b/eveai_chat_client/static/assets/img/eveai_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..719fbc070289f9d40e7dbe6e37069b03b30663e4 GIT binary patch literal 7821 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 literal 0 HcmV?d00001 diff --git a/eveai_chat_client/static/assets/img/eveai_logo.svg b/eveai_chat_client/static/assets/img/eveai_logo.svg new file mode 100644 index 0000000..cd17c22 --- /dev/null +++ b/eveai_chat_client/static/assets/img/eveai_logo.svg @@ -0,0 +1,21 @@ + + + + + + + + + \ No newline at end of file diff --git a/eveai_chat_client/static/assets/img/eveai_logo.webp b/eveai_chat_client/static/assets/img/eveai_logo.webp new file mode 100644 index 0000000000000000000000000000000000000000..acce1158a4c047cee4343fc5898b4fb27bfe811b GIT binary patch literal 20186 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 S=Pd~&8vklU2>u-i;6DH=g8Fs< literal 0 HcmV?d00001 diff --git a/eveai_chat_client/static/assets/images/evie_working.webp b/eveai_chat_client/static/assets/img/evie_working.webp similarity index 100% rename from eveai_chat_client/static/assets/images/evie_working.webp rename to eveai_chat_client/static/assets/img/evie_working.webp diff --git a/eveai_chat_client/static/assets/img/favicon.png b/eveai_chat_client/static/assets/img/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..719fbc070289f9d40e7dbe6e37069b03b30663e4 GIT binary patch literal 7821 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 literal 0 HcmV?d00001 diff --git a/eveai_chat_client/static/assets/vue-components/ChatInput.vue b/eveai_chat_client/static/assets/vue-components/ChatInput.vue index 4c9fb83..e289595 100644 --- a/eveai_chat_client/static/assets/vue-components/ChatInput.vue +++ b/eveai_chat_client/static/assets/vue-components/ChatInput.vue @@ -26,14 +26,16 @@ :form-values="formValues" :api-prefix="apiPrefix" :is-submitting="isLoading" - :hide-actions="true" + :show-send-button="true" + :is-submitting-form="isLoading" + :send-button-text="'Verstuur formulier'" @update:form-values="updateFormValues" + @form-enter-pressed="sendMessage" + @form-send-submit="handleFormSendSubmit" > - - -
+
@@ -196,7 +199,7 @@ export default { default: null } }, - emits: ['update:modelValue', 'open-privacy-modal', 'open-terms-modal'], + emits: ['update:modelValue', 'open-privacy-modal', 'open-terms-modal', 'keydown-enter'], setup() { // Consent text constants (English base) const consentTexts = { @@ -321,6 +324,25 @@ export default { openTermsModal(event) { event.preventDefault(); this.$emit('open-terms-modal'); + }, + + // Handle Enter key press for text and number inputs + handleEnterKey(event) { + console.log('FormField: Enter pressed in field:', this.fieldId); + event.preventDefault(); + this.$emit('keydown-enter'); + }, + + // Handle keydown for textarea (Enter to submit, Shift+Enter for line breaks) + handleTextareaKeydown(event) { + console.log('FormField: Textarea keydown in field:', this.fieldId, 'Key:', event.key, 'Ctrl:', event.ctrlKey, 'Shift:', event.shiftKey); + if (event.key === 'Enter' && !event.shiftKey) { + // Plain Enter submits the form + console.log('FormField: Textarea Enter triggered for field:', this.fieldId); + event.preventDefault(); + this.$emit('keydown-enter'); + } + // Shift+Enter allows line breaks in textarea } } }; @@ -462,7 +484,6 @@ export default { .field-context { margin-bottom: 8px; font-size: 0.9rem; - color: #666; padding: 8px; border-radius: 4px; text-align: left; diff --git a/eveai_chat_client/static/assets/vue-components/MessageHistory.vue b/eveai_chat_client/static/assets/vue-components/MessageHistory.vue index 184ab1f..7819fe4 100644 --- a/eveai_chat_client/static/assets/vue-components/MessageHistory.vue +++ b/eveai_chat_client/static/assets/vue-components/MessageHistory.vue @@ -7,32 +7,35 @@
- -
-
💬
-
Nog geen berichten
-
Start een gesprek door een bericht te typen!
-
- - -