- Wordpress improvements - Multi-language support

- Styling of the administrative interface in line with askeveai.com website
This commit is contained in:
Josako
2024-08-15 16:44:54 +02:00
parent c2177fe9ea
commit 688f2300b9
9 changed files with 585 additions and 49 deletions

View File

@@ -15,6 +15,7 @@
<script src="https://kit.fontawesome.com/42d5adcbca.js" crossorigin="anonymous"></script> <script src="https://kit.fontawesome.com/42d5adcbca.js" crossorigin="anonymous"></script>
<!-- Material Icons --> <!-- Material Icons -->
<link href="https://fonts.googleapis.com/icon?family=Material+Icons+Round" rel="stylesheet"> <link href="https://fonts.googleapis.com/icon?family=Material+Icons+Round" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined" rel="stylesheet" />
<!-- CSS Files --> <!-- CSS Files -->
<link id="pagestyle" href="{{url_for('static', filename='assets/css/material-kit-pro.css')}}" rel="stylesheet" /> <link id="pagestyle" href="{{url_for('static', filename='assets/css/material-kit-pro.css')}}" rel="stylesheet" />
<link id="pagestyle" href="{{url_for('static', filename='assets/css/eveai.css')}}" rel="stylesheet" /> <link id="pagestyle" href="{{url_for('static', filename='assets/css/eveai.css')}}" rel="stylesheet" />

View File

@@ -220,21 +220,33 @@
{% macro render_pagination(pagination, endpoint) %} {% macro render_pagination(pagination, endpoint) %}
<nav aria-label="Page navigation"> <nav aria-label="Page navigation">
<ul class="pagination"> <ul class="pagination">
<!-- Previous Button -->
<li class="page-item {{ 'disabled' if not pagination.has_prev }}"> <li class="page-item {{ 'disabled' if not pagination.has_prev }}">
<a class="page-link" href="{{ url_for(endpoint, page=pagination.prev_num) if pagination.has_prev else 'javascript:;' }}" tabindex="-1"> <a class="page-link" href="{{ url_for(endpoint, page=pagination.prev_num) if pagination.has_prev else 'javascript:;' }}" tabindex="-1">
<i class="fa fa-angle-left"></i> <span class="material-symbols-outlined">keyboard_double_arrow_left</span>
<span class="sr-only">Previous</span> {# <span class="sr-only">Previous</span>#}
</a> </a>
</li> </li>
<!-- Page Number Buttons -->
{% for page in pagination.iter_pages(left_edge=1, left_current=2, right_current=3, right_edge=1) %} {% for page in pagination.iter_pages(left_edge=1, left_current=2, right_current=3, right_edge=1) %}
<li class="page-item {{ 'active' if page == pagination.page }}"> <li class="page-item {{ 'active' if page == pagination.page }}">
<a class="page-link" href="{{ url_for(endpoint, page=page) }}">{{ page }} {% if page == pagination.page %}<span class="sr-only">(current)</span>{% endif %}</a> <a class="page-link" href="{{ url_for(endpoint, page=page) }}">
{% if page == pagination.page %}
<span class="material-symbols-outlined">target</span>
{# <span class="sr-only">(current)</span>#}
{% else %}
{{ page }}
{% endif %}
</a>
</li> </li>
{% endfor %} {% endfor %}
<!-- Next Button -->
<li class="page-item {{ 'disabled' if not pagination.has_next }}"> <li class="page-item {{ 'disabled' if not pagination.has_next }}">
<a class="page-link" href="{{ url_for(endpoint, page=pagination.next_num) if pagination.has_next else 'javascript:;' }}"> <a class="page-link" href="{{ url_for(endpoint, page=pagination.next_num) if pagination.has_next else 'javascript:;' }}">
<i class="fa fa-angle-right"></i> <span class="material-symbols-outlined">keyboard_double_arrow_right</span>
<span class="sr-only">Next</span> {# <span class="sr-only">Next</span>#}
</a> </a>
</li> </li>
</ul> </ul>

View File

@@ -13,7 +13,7 @@
<li class="nav-item dropdown dropdown-hover mx-2"> <li class="nav-item dropdown dropdown-hover mx-2">
<a role="button" class="nav-link ps-2 d-flex cursor-pointer align-items-center" id="{{ title | replace(' ', '') }}" data-bs-toggle="dropdown" aria-expanded="false"> <a role="button" class="nav-link ps-2 d-flex cursor-pointer align-items-center" id="{{ title | replace(' ', '') }}" data-bs-toggle="dropdown" aria-expanded="false">
{% if icon %} {% if icon %}
<i class="material-icons opacity-6 me-2 text-md">{{ icon }}</i> <span class="material-symbols-outlined" style="font-variation-settings: 'FILL' 0, 'wght' 400, 'GRAD' 0, 'opsz' 24;">{{ icon }}</span>
{% endif %} {% endif %}
{{ title }} {{ title }}
<img src="{{ url_for('static', filename='assets/img/down-arrow-dark.svg') }}" alt="down-arrow" class="arrow ms-2"> <img src="{{ url_for('static', filename='assets/img/down-arrow-dark.svg') }}" alt="down-arrow" class="arrow ms-2">
@@ -68,7 +68,7 @@
<div class="collapse navbar-collapse w-100 pt-3 pb-2 py-lg-0" id="navigation"> <div class="collapse navbar-collapse w-100 pt-3 pb-2 py-lg-0" id="navigation">
<ul class="navbar-nav navbar-nav-hover mx-auto"> <ul class="navbar-nav navbar-nav-hover mx-auto">
{% if current_user.is_authenticated %} {% if current_user.is_authenticated %}
{{ dropdown('Tenant Configuration', 'contacts', [ {{ dropdown('Tenant Configuration', 'source_environment', [
{'name': 'Tenant List', 'url': '/user/select_tenant', 'roles': ['Super User']}, {'name': 'Tenant List', 'url': '/user/select_tenant', 'roles': ['Super User']},
{'name': 'Tenant Registration', 'url': '/user/tenant', 'roles': ['Super User']}, {'name': 'Tenant Registration', 'url': '/user/tenant', 'roles': ['Super User']},
{'name': 'Tenant Overview', 'url': '/user/tenant_overview', 'roles': ['Super User', 'Tenant Admin']}, {'name': 'Tenant Overview', 'url': '/user/tenant_overview', 'roles': ['Super User', 'Tenant Admin']},
@@ -80,7 +80,7 @@
]) }} ]) }}
{% endif %} {% endif %}
{% if current_user.is_authenticated %} {% if current_user.is_authenticated %}
{{ dropdown('Document Mgmt', 'contacts', [ {{ dropdown('Document Mgmt', 'note_stack', [
{'name': 'Add Document', 'url': '/document/add_document', 'roles': ['Super User', 'Tenant Admin']}, {'name': 'Add Document', 'url': '/document/add_document', 'roles': ['Super User', 'Tenant Admin']},
{'name': 'Add URL', 'url': '/document/add_url', 'roles': ['Super User', 'Tenant Admin']}, {'name': 'Add URL', 'url': '/document/add_url', 'roles': ['Super User', 'Tenant Admin']},
{'name': 'Add a list of URLs', 'url': '/document/add_urls', 'roles': ['Super User', 'Tenant Admin']}, {'name': 'Add a list of URLs', 'url': '/document/add_urls', 'roles': ['Super User', 'Tenant Admin']},
@@ -90,17 +90,17 @@
]) }} ]) }}
{% endif %} {% endif %}
{% if current_user.is_authenticated %} {% if current_user.is_authenticated %}
{{ dropdown('Interactions', 'contacts', [ {{ dropdown('Interactions', 'hub', [
{'name': 'Chat Sessions', 'url': '/interaction/chat_sessions', 'roles': ['Super User', 'Tenant Admin']}, {'name': 'Chat Sessions', 'url': '/interaction/chat_sessions', 'roles': ['Super User', 'Tenant Admin']},
]) }} ]) }}
{% endif %} {% endif %}
{% if current_user.is_authenticated %} {% if current_user.is_authenticated %}
{{ dropdown(current_user.user_name, 'contacts', [ {{ dropdown(current_user.user_name, 'person', [
{'name': 'Session Defaults', 'url': '/session_defaults', 'roles': ['Super User', 'Tenant Admin']}, {'name': 'Session Defaults', 'url': '/session_defaults', 'roles': ['Super User', 'Tenant Admin']},
{'name': 'Logout', 'url': '/logout'} {'name': 'Logout', 'url': '/logout'}
]) }} ]) }}
{% else %} {% else %}
{{ dropdown('Account', 'contacts', [ {{ dropdown('Account', 'person', [
{'name': 'Login', 'url': '/login'} {'name': 'Login', 'url': '/login'}
]) }} ]) }}
{% endif %} {% endif %}

View File

@@ -13,7 +13,7 @@
--algorithm-color-llm: #800080; /* Purple for RAG_LLM */ --algorithm-color-llm: #800080; /* Purple for RAG_LLM */
/*--font-family: 'Arial, sans-serif'; !* Default font family *!*/ /*--font-family: 'Arial, sans-serif'; !* Default font family *!*/
--font-family: 'ui-sans-serif, -apple-system, system-ui, Segoe UI, Roboto, Ubuntu, Cantarell, Noto Sans, sans-serif, Helvetica, Apple Color Emoji, Arial, Segoe UI Emoji, Segoe UI Symbol'; --font-family: 'Segoe UI, Roboto, Cantarell, Noto Sans, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol';
--font-color: #e9e9e9; /* Default font color */ --font-color: #e9e9e9; /* Default font color */
--user-message-font-color: #e9e9e9; /* User message font color */ --user-message-font-color: #e9e9e9; /* User message font color */
--bot-message-font-color: #e9e9e9; /* Bot message font color */ --bot-message-font-color: #e9e9e9; /* Bot message font color */
@@ -91,7 +91,7 @@
.chat-container { .chat-container {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
height: 99vh; height: 75vh;
/*max-height: 100vh;*/ /*max-height: 100vh;*/
max-width: 600px; max-width: 600px;
margin: auto; margin: auto;
@@ -103,6 +103,13 @@
color: var(--font-color); /* Apply the default font color */ color: var(--font-color); /* Apply the default font color */
} }
.disclaimer {
font-size: 0.7em;
text-align: right;
padding: 5px 20px 5px 5px;
margin-bottom: 5px;
}
.messages-area { .messages-area {
flex: 1; flex: 1;
overflow-y: auto; overflow-y: auto;
@@ -115,6 +122,7 @@
margin-bottom: 10px; margin-bottom: 10px;
padding: 10px; padding: 10px;
border-radius: 15px; border-radius: 15px;
font-size: 1rem;
} }
.message.user { .message.user {
@@ -150,21 +158,50 @@
} }
.question-area { .question-area {
padding: 10px;
display: flex; display: flex;
flex-direction: row;
align-items: center; align-items: center;
background-color: var(--user-message-bg); background-color: var(--user-message-bg);
padding: 10px;
} }
.question-area input { .language-select-container {
width: 100%;
margin-bottom: 10px; /* Spacing between the dropdown and the textarea */
}
.language-select {
width: 100%;
margin-bottom: 5px; /* Space between the dropdown and the send button */
padding: 8px;
border-radius: 5px;
border: 1px solid var(--input-border);
background-color: var(--input-bg);
color: var(--input-text-color);
font-size: 1rem;
}
.question-area textarea {
flex: 1; flex: 1;
border: none; border: none;
padding: 10px; padding: 10px;
border-radius: 15px; border-radius: 15px;
margin-right: 10px; background-color: var(--input-bg);
background-color: var(--input-bg); /* Apply input background color */ border: 1px solid var(--input-border);
border: 1px solid var(--input-border); /* Apply input border color */ color: var(--input-text-color);
color: var(--input-text-color); /* Apply input text color */ font-family: var(--font-family); /* Apply the default font family */
font-size: 1rem;
resize: vertical;
min-height: 60px;
max-height: 150px;
overflow-y: auto;
margin-right: 10px; /* Space between textarea and right-side container */
}
.right-side {
display: flex;
flex-direction: column;
align-items: center;
} }
.question-area button { .question-area button {
@@ -176,8 +213,9 @@
/* Styles for the send icon */ /* Styles for the send icon */
.send-icon { .send-icon {
font-size: 24px; /* Size of the icon */ font-size: 24px;
color: var(--button-color); /* Color of the icon */ color: var(--button-color);
cursor: pointer;
} }
.send-icon.disabled { .send-icon.disabled {

View File

@@ -3,11 +3,9 @@
Plugin Name: EveAI Chat Widget Plugin Name: EveAI Chat Widget
Plugin URI: https://askeveai.com/ Plugin URI: https://askeveai.com/
Description: Integrates the EveAI chat interface into your WordPress site. Description: Integrates the EveAI chat interface into your WordPress site.
Version: 1.2 Version: 1.3.20
Author: Josako, Pieter Laroy Author: Josako, Pieter Laroy
Author URI: https://askeveai.com/about/ Author URI: https://askeveai.com/about/
License: GPLv2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html
*/ */
// Enqueue necessary scripts and styles // Enqueue necessary scripts and styles
@@ -28,6 +26,7 @@ function eveai_chat_shortcode($atts) {
$api_key = esc_js($options['api_key']); $api_key = esc_js($options['api_key']);
$domain = esc_js($options['domain']); $domain = esc_js($options['domain']);
$language = esc_js($options['language']); $language = esc_js($options['language']);
$supported_languages = esc_js($options['supported_languages']);
// Generate a unique ID for this instance of the chat widget // Generate a unique ID for this instance of the chat widget
$chat_id = 'chat-container-' . uniqid(); $chat_id = 'chat-container-' . uniqid();
@@ -39,7 +38,8 @@ function eveai_chat_shortcode($atts) {
'$tenant_id', '$tenant_id',
'$api_key', '$api_key',
'$domain', '$domain',
'$language' '$language',
'$supported_languages'
); );
eveAI.initializeChat('$chat_id'); eveAI.initializeChat('$chat_id');
}); });
@@ -81,6 +81,7 @@ function eveai_chat_register_settings() {
add_settings_field('eveai_chat_api_key', 'API Key', 'eveai_chat_api_key_input', 'eveai-chat-settings', 'eveai_chat_main'); add_settings_field('eveai_chat_api_key', 'API Key', 'eveai_chat_api_key_input', 'eveai-chat-settings', 'eveai_chat_main');
add_settings_field('eveai_chat_domain', 'Domain', 'eveai_chat_domain_input', 'eveai-chat-settings', 'eveai_chat_main'); add_settings_field('eveai_chat_domain', 'Domain', 'eveai_chat_domain_input', 'eveai-chat-settings', 'eveai_chat_main');
add_settings_field('eveai_chat_language', 'Default Language', 'eveai_chat_language_input', 'eveai-chat-settings', 'eveai_chat_main'); add_settings_field('eveai_chat_language', 'Default Language', 'eveai_chat_language_input', 'eveai-chat-settings', 'eveai_chat_main');
add_settings_field('eveai_chat_supported_languages', 'Supported Languages', 'eveai_chat_supported_languages_input', 'eveai-chat-settings', 'eveai_chat_main');
} }
add_action('admin_init', 'eveai_chat_register_settings'); add_action('admin_init', 'eveai_chat_register_settings');
@@ -108,11 +109,20 @@ function eveai_chat_language_input() {
echo "<input id='eveai_chat_language' name='eveai_chat_options[language]' type='text' value='" . esc_attr($options['language']) . "' />"; echo "<input id='eveai_chat_language' name='eveai_chat_options[language]' type='text' value='" . esc_attr($options['language']) . "' />";
} }
function eveai_chat_supported_languages_input() {
$options = get_option('eveai_chat_options');
$supported_languages = isset($options['supported_languages']) ? $options['supported_languages'] : 'en,fr,de,es';
echo "<input id='eveai_chat_supported_languages' name='eveai_chat_options[supported_languages]' type='text' value='" . esc_attr($supported_languages) . "' />";
echo "<p class='description'>Enter comma-separated language codes (e.g., en,fr,de,es)</p>";
}
function eveai_chat_options_validate($input) { function eveai_chat_options_validate($input) {
$new_input = array(); $new_input = array();
$new_input['tenant_id'] = sanitize_text_field($input['tenant_id']); $new_input['tenant_id'] = sanitize_text_field($input['tenant_id']);
$new_input['api_key'] = sanitize_text_field($input['api_key']); $new_input['api_key'] = sanitize_text_field($input['api_key']);
$new_input['domain'] = esc_url_raw($input['domain']); $new_input['domain'] = esc_url_raw($input['domain']);
$new_input['language'] = sanitize_text_field($input['language']); $new_input['language'] = sanitize_text_field($input['language']);
$new_input['supported_languages'] = sanitize_text_field($input['supported_languages']);
return $new_input; return $new_input;
} }

View File

@@ -1,6 +1,6 @@
class EveAIChatWidget extends HTMLElement { class EveAIChatWidget extends HTMLElement {
static get observedAttributes() { static get observedAttributes() {
return ['tenant-id', 'api-key', 'domain', 'language']; return ['tenant-id', 'api-key', 'domain', 'language', 'languages'];
} }
constructor() { constructor() {
@@ -12,6 +12,7 @@ class EveAIChatWidget extends HTMLElement {
this.heartbeatInterval = null; this.heartbeatInterval = null;
this.idleTime = 0; // in milliseconds this.idleTime = 0; // in milliseconds
this.maxConnectionIdleTime = 1 * 60 * 60 * 1000; // 1 hours in milliseconds this.maxConnectionIdleTime = 1 * 60 * 60 * 1000; // 1 hours in milliseconds
this.languages = []
console.log('EveAIChatWidget constructor called'); console.log('EveAIChatWidget constructor called');
} }
@@ -19,15 +20,17 @@ class EveAIChatWidget extends HTMLElement {
console.log('connectedCallback called'); console.log('connectedCallback called');
this.innerHTML = this.getTemplate(); this.innerHTML = this.getTemplate();
this.messagesArea = this.querySelector('.messages-area'); this.messagesArea = this.querySelector('.messages-area');
this.questionInput = this.querySelector('.question-area input'); this.questionInput = this.querySelector('.question-area textarea');
this.sendButton = this.querySelector('.send-icon'); this.sendButton = this.querySelector('.send-icon');
this.languageSelect = this.querySelector('.language-select');
this.statusLine = this.querySelector('.status-line'); this.statusLine = this.querySelector('.status-line');
this.statusMessage = this.querySelector('.status-message'); this.statusMessage = this.querySelector('.status-message');
this.connectionStatusIcon = this.querySelector('.connection-status-icon'); this.connectionStatusIcon = this.querySelector('.connection-status-icon');
this.sendButton.addEventListener('click', () => this.handleSendMessage()); this.sendButton.addEventListener('click', () => this.handleSendMessage());
this.questionInput.addEventListener('keydown', (event) => { this.questionInput.addEventListener('keydown', (event) => {
if (event.key === 'Enter') { if (event.key === 'Enter' && !event.shiftKey) {
event.preventDefault(); // Prevent adding a new line
this.handleSendMessage(); this.handleSendMessage();
} }
}); });
@@ -38,6 +41,30 @@ class EveAIChatWidget extends HTMLElement {
} }
} }
populateLanguageDropdown() {
// Clear existing options
this.languageSelect.innerHTML = '';
console.log(`languages for options: ${this.languages}`)
// Populate with new options
this.languages.forEach(lang => {
const option = document.createElement('option');
option.value = lang;
option.textContent = lang.toUpperCase();
if (lang === this.currentLanguage) {
option.selected = true;
}
console.log(`Adding option for language: ${lang}`)
this.languageSelect.appendChild(option);
});
// Add event listener for language change
this.languageSelect.addEventListener('change', (e) => {
this.currentLanguage = e.target.value;
// You might want to emit an event or update the backend about the language change
});
}
attributeChangedCallback(name, oldValue, newValue) { attributeChangedCallback(name, oldValue, newValue) {
console.log(`attributeChangedCallback called: ${name} changed from ${oldValue} to ${newValue}`); console.log(`attributeChangedCallback called: ${name} changed from ${oldValue} to ${newValue}`);
this.updateAttributes(); this.updateAttributes();
@@ -45,6 +72,9 @@ class EveAIChatWidget extends HTMLElement {
if (this.areAllAttributesSet() && !this.socket) { if (this.areAllAttributesSet() && !this.socket) {
console.log('All attributes set in attributeChangedCallback, initializing socket'); console.log('All attributes set in attributeChangedCallback, initializing socket');
this.attributesSet = true; this.attributesSet = true;
console.log('All attributes are set, populating language dropdown');
this.populateLanguageDropdown();
console.log('All attributes are set, initializing socket')
this.initializeSocket(); this.initializeSocket();
} }
} }
@@ -54,11 +84,16 @@ class EveAIChatWidget extends HTMLElement {
this.apiKey = this.getAttribute('api-key'); this.apiKey = this.getAttribute('api-key');
this.domain = this.getAttribute('domain'); this.domain = this.getAttribute('domain');
this.language = this.getAttribute('language'); this.language = this.getAttribute('language');
const languageAttr = this.getAttribute('languages');
this.languages = languageAttr ? languageAttr.split(',') : [];
this.currentLanguage = this.language;
console.log('Updated attributes:', { console.log('Updated attributes:', {
tenantId: this.tenantId, tenantId: this.tenantId,
apiKey: this.apiKey, apiKey: this.apiKey,
domain: this.domain, domain: this.domain,
language: this.language language: this.language,
currentLanguage: this.currentLanguage,
languages: this.languages
}); });
} }
@@ -67,13 +102,34 @@ class EveAIChatWidget extends HTMLElement {
const apiKey = this.getAttribute('api-key'); const apiKey = this.getAttribute('api-key');
const domain = this.getAttribute('domain'); const domain = this.getAttribute('domain');
const language = this.getAttribute('language'); const language = this.getAttribute('language');
const languages = this.getAttribute('languages');
console.log('Checking if all attributes are set:', { console.log('Checking if all attributes are set:', {
tenantId, tenantId,
apiKey, apiKey,
domain, domain,
language language,
languages
}); });
return tenantId && apiKey && domain && language; return tenantId && apiKey && domain && language && languages;
}
createLanguageDropdown() {
const select = document.createElement('select');
select.id = 'languageSelect';
this.languages.forEach(lang => {
const option = document.createElement('option');
option.value = lang;
option.textContent = lang.toUpperCase();
if (lang === this.currentLanguage) {
option.selected = true;
}
select.appendChild(option);
});
select.addEventListener('change', (e) => {
this.currentLanguage = e.target.value;
// You might want to emit an event or update the backend about the language change
});
return select;
} }
initializeSocket() { initializeSocket() {
@@ -81,15 +137,11 @@ class EveAIChatWidget extends HTMLElement {
console.log('Socket already initialized'); console.log('Socket already initialized');
return; return;
} }
if (!this.domain || this.domain === 'null') {
console.error('Domain attribute is missing or invalid'); console.log(`Initializing socket connection to Evie`);
this.setStatusMessage('EveAI Chat Widget needs further configuration by site administrator.');
return;
}
console.log(`Initializing socket connection to ${this.domain}`);
// Ensure apiKey is passed in the query parameters // Ensure apiKey is passed in the query parameters
this.socket = io(this.domain, { this.socket = io('https://evie.askeveai.com', {
path: '/chat/socket.io/', path: '/chat/socket.io/',
transports: ['websocket', 'polling'], transports: ['websocket', 'polling'],
query: { query: {
@@ -104,7 +156,7 @@ class EveAIChatWidget extends HTMLElement {
timeout: 20000 // Connection timeout timeout: 20000 // Connection timeout
}); });
console.log(`Finished initializing socket connection to ${this.domain}`); console.log(`Finished initializing socket connection to Evie`);
this.socket.on('connect', (data) => { this.socket.on('connect', (data) => {
console.log('Socket connected OK'); console.log('Socket connected OK');
@@ -243,9 +295,13 @@ class EveAIChatWidget extends HTMLElement {
return ` return `
<div class="chat-container"> <div class="chat-container">
<div class="messages-area"></div> <div class="messages-area"></div>
<div class="disclaimer">Evie can make mistakes. Please double-check responses.</div>
<div class="question-area"> <div class="question-area">
<input type="text" placeholder="Type your message here..." /> <textarea placeholder="Type your message here..." rows="3"></textarea>
<i class="material-icons send-icon outlined">send</i> <div class="right-side">
<select class="language-select"></select>
<i class="material-icons send-icon outlined">send</i>
</div>
</div> </div>
<div class="status-line"> <div class="status-line">
<i class="material-icons connection-status-icon">link_off</i> <i class="material-icons connection-status-icon">link_off</i>
@@ -370,12 +426,15 @@ toggleFeedback(thumbsUp, thumbsDown, feedback, interactionId) {
console.error('JWT token is not available'); console.error('JWT token is not available');
return; return;
} }
const selectedLanguage = this.languageSelect.value;
console.log('Sending message to backend'); console.log('Sending message to backend');
this.socket.emit('user_message', { this.socket.emit('user_message', {
tenantId: this.tenantId, tenantId: this.tenantId,
token: this.jwtToken, token: this.jwtToken,
message, message,
language: this.language, language: selectedLanguage,
timezone: this.userTimezone timezone: this.userTimezone
}); });
this.setStatusMessage('Processing started ...') this.setStatusMessage('Processing started ...')

View File

@@ -1,12 +1,13 @@
// static/js/eveai-sdk.js // static/js/eveai-sdk.js
class EveAI { class EveAI {
constructor(tenantId, apiKey, domain, language) { constructor(tenantId, apiKey, domain, language, languages) {
this.tenantId = tenantId; this.tenantId = tenantId;
this.apiKey = apiKey; this.apiKey = apiKey;
this.domain = domain; this.domain = domain;
this.language = language; this.language = language;
this.languages = languages;
console.log('EveAI constructor:', { tenantId, apiKey, domain }); console.log('EveAI constructor:', { tenantId, apiKey, domain, language, languages });
} }
initializeChat(containerId) { initializeChat(containerId) {
@@ -19,6 +20,7 @@ class EveAI {
chatWidget.setAttribute('api-key', this.apiKey); chatWidget.setAttribute('api-key', this.apiKey);
chatWidget.setAttribute('domain', this.domain); chatWidget.setAttribute('domain', this.domain);
chatWidget.setAttribute('language', this.language); chatWidget.setAttribute('language', this.language);
chatWidget.setAttribute('languages', this.languages);
}); });
} else { } else {
console.error('Container not found'); console.error('Container not found');

View File

@@ -3,7 +3,7 @@ Contributors: Josako
Tags: chat, ai Tags: chat, ai
Requires at least: 5.0 Requires at least: 5.0
Tested up to: 5.9 Tested up to: 5.9
Stable tag: 1.2 Stable tag: 1.3.0
License: GPLv2 or later License: GPLv2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html License URI: http://www.gnu.org/licenses/gpl-2.0.html
@@ -27,17 +27,32 @@ Contact your EveAI service provider to obtain your Tenant ID, API Key, and Domai
== Changelog == == Changelog ==
= 1.2 = = 1.3.3 - =
* ensure all attributes (also height and supportedLanguages) are set before initializing the socket
* Bugfixing
= 1.3.2 =
* Correct supportedLanguages to be an Array
= 1.3.1 =
* Correct evie domain
= 1.3.0 =
* Enable user to select language
* Make Question area multi-line
* Enable height to be set in shortcode
= 1.2.0 =
* Create shortcodes * Create shortcodes
= 1.1 = = 1.1.0 =
* Added configurable settings * Added configurable settings
* Improved security with server-side API key handling * Improved security with server-side API key handling
= 1.0 = = 1.0.0 =
* Initial release * Initial release
== Upgrade Notice == == Upgrade Notice ==
= 1.1 = = 1.1.0 =
This version adds configurable settings and improves security. Please update your EveAI credentials after upgrading. This version adds configurable settings and improves security. Please update your EveAI credentials after upgrading.

View File

@@ -8,6 +8,405 @@
--bs-danger: #9c2d66; --bs-danger: #9c2d66;
} }
/* Overriding the background gradient and text colors */
.bg-gradient-success {
background: linear-gradient(90deg, var(--bs-primary) 0%, var(--bs-secondary) 100%);
}
.shadow-success {
box-shadow: 0px 4px 20px 0px rgba(118, 89, 154, 0.5); /* Adjusting shadow color */
}
.border-radius-lg {
border-radius: 1rem; /* Assuming you want to keep the large border-radius */
}
.text-white {
color: #f8e1a9 !important; /* Adjust text to the EveAI success color */
}
.text-sm {
font-size: 0.875rem; /* Adjust size if needed, keeping original */
}
/* Override for the link with text-success and text-gradient classes */
.text-success {
color: var(--bs-primary) !important; /* Use EveAI primary color */
}
.text-gradient {
background-image: linear-gradient(90deg, var(--bs-primary), var(--bs-secondary));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
.font-weight-bold {
font-weight: 700; /* Retain bold text */
}
/* Navbar customization */
.navbar-light .navbar-brand {
color: var(--bs-primary) !important; /* Primary color for the brand text */
}
.navbar-light .navbar-nav .nav-link {
color: var(--bs-secondary) !important; /* Secondary color for the nav links */
}
/* Ensure consistent alignment for all dropdown icons */
.navbar-nav .nav-link i.material-icons {
font-size: 24px; /* Ensures all icons are the same size */
vertical-align: middle; /* Align icons vertically with text */
margin-right: 8px; /* Space between icon and text */
line-height: 1; /* Prevents misalignment due to line-height issues */
}
.navbar-nav .nav-link {
display: flex;
align-items: center; /* Aligns icon and text vertically */
padding: 0; /* Remove any additional padding */
}
/* Adjust the size and spacing of the material-symbols-outlined icons */
.navbar-nav .nav-link .material-symbols-outlined {
font-size: 20px; /* Adjust the icon size */
vertical-align: middle; /* Ensure vertical alignment with text */
margin-right: 8px; /* Add space between the icon and the text */
line-height: 1; /* Maintain alignment */
}
.navbar-light .navbar-nav .nav-link:hover,
.navbar-light .navbar-nav .nav-link:focus {
color: var(--bs-primary) !important; /* Primary color on hover/focus */
}
.bg-white {
background-color: var(--bs-light) !important; /* Adjust the background to a custom light color if needed */
}
.btn.bg-gradient-primary {
background: linear-gradient(90deg, var(--bs-primary) 0%, var(--bs-secondary) 100%);
color: var(--bs-white) !important; /* Ensures text is readable on the gradient */
border: none;
}
.navbar-toggler .navbar-toggler-bar {
background-color: var(--bs-secondary); /* Adjusts color of the toggler bars */
}
.dropdown-menu {
background-color: var(--bs-light); /* Light background for dropdown */
border-radius: 0.375rem; /* Retains rounded corners */
}
.dropdown-item {
color: var(--bs-primary) !important; /* Primary color for dropdown items */
}
.dropdown-item:hover,
.dropdown-item:focus {
background-color: var(--bs-secondary) !important; /* Secondary color for hover/focus background */
color: var(--bs-white) !important; /* White text on hover/focus */
}
.btn.bg-gradient-primary {
background: linear-gradient(90deg, var(--bs-primary) 0%, var(--bs-secondary) 100%);
color: var(--bs-white) !important;
}
/* Page header customization */
.page-header {
background-size: cover;
background-position: center;
min-height: 25vh;
position: relative;
}
.page-header .mask {
background: linear-gradient(90deg, var(--bs-primary), var(--bs-secondary)) !important; /* Gradient overlay */
opacity: 0.8; /* Adjust opacity to let the background image show through */
}
.page-header h1 {
color: var(--bs-success) !important; /* Use the success color for the header text */
margin-top: -1.5rem; /* Adjusted margin to align text properly */
}
.page-header p.lead {
color: var(--bs-info) !important; /* Use the info color for the lead text */
padding-left: 1.5rem;
padding-right: 1.5rem;
}
/* Ensure consistent padding */
.page-header .container {
padding-top: 3rem;
padding-bottom: 3rem;
}
.page-header .col-lg-7 {
margin-top: -5rem; /* Adjust margin to improve vertical alignment */
}
/* Card and table customization */
.card {
border: 1px solid var(--bs-secondary) !important; /* Secondary color for the card border */
border-radius: 0.5rem; /* Keeps the border-radius consistent */
box-shadow: 0 4px 8px rgba(118, 89, 154, 0.2); /* Soft shadow with primary color */
}
.table {
color: var(--bs-body-color) !important; /* Ensure the text color matches the theme */
background-color: var(--bs-light) !important; /* Light background color */
border-collapse: separate !important; /* Ensure borders do not collapse */
border-spacing: 0; /* Remove spacing between table cells */
border-radius: 0.375rem; /* Rounded corners */
overflow: hidden; /* Ensure the rounded corners apply to the entire table */
border: 1px solid var(--bs-secondary) !important; /* Apply border with secondary color */
}
.table thead th {
color: var(--bs-info) !important; /* Info color for the table headers */
background-color: var(--bs-light) !important; /* Background for table headers */
border-bottom: 1px solid var(--bs-secondary) !important; /* Secondary color for the header bottom border */
}
/* Ensures corners are colored */
.table thead th:first-child {
border-top-left-radius: 0.375rem !important;
}
.table thead th:last-child {
border-top-right-radius: 0.375rem !important;
}
.table tbody tr:last-child td:first-child {
border-bottom-left-radius: 0.375rem !important;
}
.table tbody tr:last-child td:last-child {
border-bottom-right-radius: 0.375rem !important;
}
.table tbody tr {
border-top: 1px solid var(--bs-gray-300) !important; /* Subtle border between rows */
}
.table tbody tr:hover {
background-color: var(--bs-secondary) !important; /* Secondary color on row hover */
color: var(--bs-white) !important; /* White text on hover */
}
.table tbody tr:hover a,
.table tbody tr:hover p,
.table tbody tr:hover td {
color: var(--bs-white) !important; /* Ensure all text, links, and paragraphs change to white */
}
.table tbody tr:hover .text-xs {
color: var(--bs-white) !important; /* Ensure the smaller text also changes to white */
}
.table .text-xs {
color: var(--bs-body-color) !important; /* Consistent text color in the table cells */
}
input[type="radio"] {
accent-color: var(--bs-primary); /* Primary color for radio buttons */
}
/* Buttons customization */
.btn-primary {
background-color: var(--bs-primary) !important;
border-color: var(--bs-primary) !important;
color: var(--bs-white) !important;
}
.btn-secondary {
background-color: var(--bs-secondary) !important;
border-color: var(--bs-secondary) !important;
color: var(--bs-white) !important;
}
/* Adjust the form group margin */
.form-group {
margin-top: 1.5rem; /* Adjust for better spacing */
}
/* Card footer customization */
.card-footer {
/*background-color: var(--bs-light) !important; !* Light background for the footer *!*/
padding-top: 1rem; /* Adjust padding for consistent spacing */
padding-bottom: 1rem; /* Adjust padding for consistent spacing */
/*border-top: 1px solid var(--bs-secondary) !important; !* Border with secondary color *!*/
padding-left: 0 !important;
padding-right: 0 !important;
}
.card-footer .pagination {
padding-left: 0 !important; /* Remove extra padding */
padding-right: 0 !important; /* Remove extra padding */
}
/* Pagination customization */
.pagination {
display: flex;
justify-content: center;
padding-left: 0;
list-style: none;
border-radius: 0.375rem;
margin-left: 0 !important;
margin-right: 0 !important;
padding-left: 0 !important; /* Add some padding inside the pagination */
padding-right: 0 !important; /* Add some padding inside the pagination */
}
.pagination .page-item {
margin-left: 0 !important;
margin-right: 0 !important;
}
.page-item.disabled .page-link {
color: var(--bs-gray-500) !important; /* Disabled state color */
background-color: var(--bs-gray-200) !important; /* Disabled state background */
border-color: var(--bs-gray-300) !important; /* Disabled state border */
}
.page-item.active .page-link {
z-index: 1;
color: var(--bs-white) !important; /* Active page color */
background-color: var(--bs-primary) !important; /* Active page background */
border-color: var(--bs-primary) !important; /* Active page border */
}
.page-item .page-link {
border-radius: 50% !important; /* Ensure circular buttons */
margin: 0 5px; /* Add some spacing between buttons */
}
.page-link {
color: var(--bs-primary) !important; /* Default link color */
background-color: var(--bs-light) !important; /* Light background for links */
border: 1px solid var(--bs-secondary) !important; /* Border with secondary color */
border-radius: 0.375rem; /* Rounded corners */
padding: 0.5rem 0.75rem;
margin: 0 0.25rem; /* Adjust margin for spacing */
}
.page-link:hover {
color: var(--bs-white) !important; /* Hover state text color */
background-color: var(--bs-secondary) !important; /* Hover state background */
border-color: var(--bs-secondary) !important; /* Hover state border */
}
.page-link i.fa {
margin-right: 0.25rem; /* Add spacing between icon and text */
}
/* Align text centrally */
.text-center {
text-align: center !important;
}
/* Form and Input Fields */
.form-group label.form-label {
color: var(--bs-secondary) !important; /* Secondary color for labels */
font-weight: 500; /* Slightly bolder labels */
}
.form-group:last-of-type {
margin-bottom: 2rem; /* Adjust this value to control spacing */
}
.form-control {
background-color: var(--bs-light) !important; /* Light background for input fields */
border-color: var(--bs-secondary) !important; /* Secondary color for borders */
color: var(--bs-body-color) !important; /* Text color consistent with the theme */
}
.form-control:disabled {
background-color: var(--bs-gray-100) !important; /* Gray background for disabled fields */
color: var(--bs-gray-600) !important; /* Dimmed text color for disabled fields */
}
.form-check-input:checked {
background-color: var(--bs-primary) !important; /* Primary color for checked checkboxes */
border-color: var(--bs-primary) !important; /* Primary color for checkbox border */
}
.form-check-label {
color: var(--bs-body-color) !important; /* Consistent text color for check labels */
}
/* Tabs Navigation */
.nav-pills .nav-link {
color: var(--bs-primary) !important; /* Primary color for inactive tab text */
border-radius: 0.375rem !important; /* Rounded corners for tabs */
transition: background-color 0.3s ease, color 0.3s ease; /* Smooth transitions */
}
.nav-pills .nav-link.active {
background-color: var(--bs-primary) !important; /* Primary background for active tab */
color: var(--bs-white) !important; /* White text for active tab */
}
.nav-pills .nav-link:hover {
background-color: var(--bs-secondary) !important; /* Secondary background on hover */
color: var(--bs-white) !important; /* White text on hover */
}
/* Tabs Content */
.tab-pane {
padding-top: 1rem; /* Consistent padding inside tabs */
}
.moving-tab {
background-color: var(--bs-primary) !important; /* Primary color for the moving tab indicator */
}
/* Buttons */
.btn-primary:hover {
background-color: var(--bs-secondary) !important;
border-color: var(--bs-secondary) !important;
}
#copy-message {
color: var(--bs-success) !important; /* Success color for the copy message */
}
/* Danger Button Styling */
.btn-danger {
background-color: var(--bs-danger) !important; /* Use the danger color from the EveAI theme */
border-color: var(--bs-danger) !important;
color: var(--bs-white) !important; /* Ensure text is white for readability */
transition: background-color 0.3s ease, color 0.3s ease; /* Smooth transition on hover */
}
.btn-danger:hover {
background-color: darken(var(--bs-danger), 10%) !important; /* Darken the background on hover */
border-color: darken(var(--bs-danger), 10%) !important; /* Darken the border on hover */
}
/* Success Alert Styling */
.alert-success {
background-color: var(--bs-success) !important; /* EveAI success background color */
color: var(--bs-dark) !important; /* Dark color for the text for better readability */
border-color: var(--bs-success) !important; /* Matching border color */
border-radius: 0.375rem; /* Rounded corners for the alert box */
padding: 1rem; /* Consistent padding */
box-shadow: 0px 4px 10px rgba(118, 89, 154, 0.2); /* Soft shadow for some depth */
}
.alert-success .alert-heading {
color: var(--bs-dark) !important; /* Ensure the heading stands out */
font-weight: 600; /* Slightly bolder heading */
}
.alert-success p {
margin-bottom: 0; /* Remove extra margin from paragraphs inside alerts */
}
.form-control { .form-control {
border: 1px solid #d2d6da; border: 1px solid #d2d6da;
padding: 0.625rem 0.75rem; padding: 0.625rem 0.75rem;