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 0000000..719fbc0 Binary files /dev/null and b/eveai_chat_client/static/assets/img/eveai_logo.png differ 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 0000000..acce115 Binary files /dev/null and b/eveai_chat_client/static/assets/img/eveai_logo.webp differ 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 0000000..719fbc0 Binary files /dev/null and b/eveai_chat_client/static/assets/img/favicon.png differ 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!
-
- - -