iatoolkit 0.59.1__py3-none-any.whl → 0.67.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of iatoolkit might be problematic. Click here for more details.
- iatoolkit/__init__.py +2 -0
- iatoolkit/base_company.py +2 -19
- iatoolkit/common/routes.py +28 -25
- iatoolkit/common/session_manager.py +2 -0
- iatoolkit/common/util.py +17 -6
- iatoolkit/company_registry.py +1 -2
- iatoolkit/iatoolkit.py +54 -20
- iatoolkit/locales/en.yaml +167 -0
- iatoolkit/locales/es.yaml +163 -0
- iatoolkit/repositories/database_manager.py +3 -3
- iatoolkit/repositories/document_repo.py +1 -1
- iatoolkit/repositories/models.py +3 -4
- iatoolkit/repositories/profile_repo.py +0 -4
- iatoolkit/services/auth_service.py +44 -32
- iatoolkit/services/branding_service.py +35 -27
- iatoolkit/services/configuration_service.py +140 -0
- iatoolkit/services/dispatcher_service.py +20 -18
- iatoolkit/services/document_service.py +5 -2
- iatoolkit/services/excel_service.py +15 -11
- iatoolkit/services/file_processor_service.py +4 -12
- iatoolkit/services/history_service.py +8 -7
- iatoolkit/services/i18n_service.py +104 -0
- iatoolkit/services/jwt_service.py +7 -9
- iatoolkit/services/language_service.py +79 -0
- iatoolkit/services/load_documents_service.py +4 -4
- iatoolkit/services/mail_service.py +9 -4
- iatoolkit/services/onboarding_service.py +10 -4
- iatoolkit/services/profile_service.py +59 -38
- iatoolkit/services/prompt_manager_service.py +20 -16
- iatoolkit/services/query_service.py +15 -14
- iatoolkit/services/sql_service.py +6 -2
- iatoolkit/services/user_feedback_service.py +70 -29
- iatoolkit/static/js/chat_feedback_button.js +80 -0
- iatoolkit/static/js/chat_help_content.js +124 -0
- iatoolkit/static/js/chat_history_button.js +110 -0
- iatoolkit/static/js/chat_logout_button.js +36 -0
- iatoolkit/static/js/chat_main.js +32 -184
- iatoolkit/static/js/{chat_onboarding.js → chat_onboarding_button.js} +0 -1
- iatoolkit/static/js/chat_prompt_manager.js +94 -0
- iatoolkit/static/js/chat_reload_button.js +35 -0
- iatoolkit/static/styles/chat_iatoolkit.css +251 -205
- iatoolkit/static/styles/chat_modal.css +63 -95
- iatoolkit/static/styles/chat_public.css +107 -0
- iatoolkit/static/styles/landing_page.css +121 -167
- iatoolkit/templates/_company_header.html +20 -0
- iatoolkit/templates/_login_widget.html +10 -10
- iatoolkit/templates/base.html +36 -19
- iatoolkit/templates/change_password.html +24 -22
- iatoolkit/templates/chat.html +121 -93
- iatoolkit/templates/chat_modals.html +113 -74
- iatoolkit/templates/error.html +44 -8
- iatoolkit/templates/forgot_password.html +17 -15
- iatoolkit/templates/index.html +66 -81
- iatoolkit/templates/login_simulation.html +16 -5
- iatoolkit/templates/onboarding_shell.html +1 -2
- iatoolkit/templates/signup.html +22 -20
- iatoolkit/views/base_login_view.py +12 -1
- iatoolkit/views/change_password_view.py +50 -33
- iatoolkit/views/external_login_view.py +5 -11
- iatoolkit/views/file_store_api_view.py +7 -9
- iatoolkit/views/forgot_password_view.py +21 -19
- iatoolkit/views/help_content_api_view.py +54 -0
- iatoolkit/views/history_api_view.py +16 -12
- iatoolkit/views/home_view.py +61 -0
- iatoolkit/views/index_view.py +5 -34
- iatoolkit/views/init_context_api_view.py +16 -13
- iatoolkit/views/llmquery_api_view.py +38 -28
- iatoolkit/views/login_simulation_view.py +14 -2
- iatoolkit/views/login_view.py +48 -33
- iatoolkit/views/logout_api_view.py +49 -0
- iatoolkit/views/profile_api_view.py +46 -0
- iatoolkit/views/prompt_api_view.py +8 -8
- iatoolkit/views/signup_view.py +27 -25
- iatoolkit/views/{tasks_view.py → tasks_api_view.py} +10 -36
- iatoolkit/views/tasks_review_api_view.py +55 -0
- iatoolkit/views/user_feedback_api_view.py +21 -32
- iatoolkit/views/verify_user_view.py +33 -26
- {iatoolkit-0.59.1.dist-info → iatoolkit-0.67.0.dist-info}/METADATA +40 -22
- iatoolkit-0.67.0.dist-info/RECORD +120 -0
- iatoolkit-0.67.0.dist-info/licenses/LICENSE +21 -0
- iatoolkit/static/js/chat_context_reload.js +0 -54
- iatoolkit/static/js/chat_feedback.js +0 -115
- iatoolkit/static/js/chat_history.js +0 -127
- iatoolkit/static/styles/chat_info.css +0 -53
- iatoolkit/templates/_branding_styles.html +0 -53
- iatoolkit/templates/_navbar.html +0 -9
- iatoolkit/templates/header.html +0 -31
- iatoolkit/templates/test.html +0 -9
- iatoolkit/views/chat_token_request_view.py +0 -98
- iatoolkit/views/tasks_review_view.py +0 -83
- iatoolkit-0.59.1.dist-info/RECORD +0 -111
- {iatoolkit-0.59.1.dist-info → iatoolkit-0.67.0.dist-info}/WHEEL +0 -0
- {iatoolkit-0.59.1.dist-info → iatoolkit-0.67.0.dist-info}/top_level.txt +0 -0
iatoolkit/static/js/chat_main.js
CHANGED
|
@@ -1,47 +1,41 @@
|
|
|
1
1
|
// Global variables for request management
|
|
2
2
|
let isRequestInProgress = false;
|
|
3
3
|
let abortController = null;
|
|
4
|
-
|
|
5
4
|
let selectedPrompt = null; // Will hold a lightweight prompt object
|
|
6
5
|
|
|
7
6
|
$(document).ready(function () {
|
|
8
|
-
//
|
|
7
|
+
// Si viene un Token retornado por login con APY-KEY se gatilla el redeem a una sesion de flask
|
|
9
8
|
if (window.redeemToken) {
|
|
10
|
-
const url =
|
|
9
|
+
const url = '/api/redeem_token';
|
|
11
10
|
// No await: dejamos que callToolkit maneje todo internamente
|
|
12
11
|
callToolkit(url, {'token': window.redeemToken}, "POST").catch(() => {});
|
|
13
12
|
}
|
|
14
13
|
|
|
15
|
-
|
|
14
|
+
const layoutContainer = document.querySelector('.chat-layout-container');
|
|
15
|
+
const promptAssistantCollapse = document.getElementById('prompt-assistant-collapse');
|
|
16
|
+
|
|
17
|
+
if (layoutContainer && promptAssistantCollapse) {
|
|
18
|
+
promptAssistantCollapse.addEventListener('show.bs.collapse', function () {
|
|
19
|
+
layoutContainer.classList.add('prompt-assistant-open');
|
|
20
|
+
setTimeout(() => {
|
|
21
|
+
window.scrollTo({ top: document.body.scrollHeight, behavior: 'smooth' });
|
|
22
|
+
}, 300);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
promptAssistantCollapse.addEventListener('hide.bs.collapse', function () {
|
|
26
|
+
layoutContainer.classList.remove('prompt-assistant-open');
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// --- chat main event hadlers ---
|
|
16
31
|
$('#send-button').on('click', handleChatMessage);
|
|
17
32
|
$('#stop-button').on('click', abortCurrentRequest);
|
|
18
33
|
if (window.sendButtonColor)
|
|
19
34
|
$('#send-button i').css('color', window.sendButtonColor);
|
|
20
35
|
|
|
21
|
-
// --- PROMPT ASSISTANT FUNCTIONALITY ---
|
|
22
|
-
$('.input-area').on('click', '.dropdown-menu a.dropdown-item', function (event) {
|
|
23
|
-
event.preventDefault();
|
|
24
|
-
const promptData = $(this).data();
|
|
25
|
-
|
|
26
|
-
const promptObject = {
|
|
27
|
-
prompt: promptData.promptName,
|
|
28
|
-
description: promptData.promptDescription,
|
|
29
|
-
custom_fields: typeof promptData.customFields === 'string' ? JSON.parse(promptData.customFields) : promptData.customFields
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
selectPrompt(promptObject);
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
// Handles the 'clear' button for the prompt selector
|
|
36
|
-
$('#clear-selection-button').on('click', function() {
|
|
37
|
-
resetPromptSelection();
|
|
38
|
-
updateSendButtonState();
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
// --- TEXTAREA FUNCTIONALITY ---
|
|
42
|
-
const questionTextarea = $('#question');
|
|
43
36
|
|
|
44
37
|
// Handles Enter key press to send a message
|
|
38
|
+
const questionTextarea = $('#question');
|
|
45
39
|
questionTextarea.on('keypress', function (event) {
|
|
46
40
|
if (event.key === 'Enter' && !event.shiftKey) {
|
|
47
41
|
event.preventDefault();
|
|
@@ -61,71 +55,8 @@ $(document).ready(function () {
|
|
|
61
55
|
|
|
62
56
|
// Set the initial disabled state of the send button
|
|
63
57
|
updateSendButtonState();
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* Handles the selection of a prompt from the dropdown.
|
|
69
|
-
* @param {object} prompt The prompt object read from data attributes.
|
|
70
|
-
*/
|
|
71
|
-
function selectPrompt(prompt) {
|
|
72
|
-
selectedPrompt = prompt;
|
|
73
|
-
|
|
74
|
-
// Update the dropdown button to show the selected prompt's description
|
|
75
|
-
$('#prompt-select-button').text(prompt.description).addClass('item-selected');
|
|
76
|
-
$('#clear-selection-button').show();
|
|
77
|
-
|
|
78
|
-
// Clear the main textarea, as we are now in "prompt mode"
|
|
79
|
-
$('#question').val('');
|
|
80
|
-
autoResizeTextarea($('#question')[0]); // Reset height after clearing
|
|
81
|
-
|
|
82
|
-
// Store values in hidden fields for backward compatibility or other uses
|
|
83
|
-
$('#prompt-select-value').val(prompt.prompt);
|
|
84
|
-
$('#prompt-select-description').val(prompt.description);
|
|
85
|
-
|
|
86
|
-
// Render the dynamic input fields required by the selected prompt
|
|
87
|
-
renderDynamicInputs(prompt.custom_fields || []);
|
|
88
|
-
updateSendButtonState();
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* Resets the prompt selection and clears associated UI elements.
|
|
93
|
-
*/
|
|
94
|
-
function resetPromptSelection() {
|
|
95
|
-
selectedPrompt = null;
|
|
96
|
-
|
|
97
|
-
$('#prompt-select-button').text('Prompts disponibles ....').removeClass('item-selected');
|
|
98
|
-
$('#clear-selection-button').hide();
|
|
99
|
-
$('#prompt-select-value').val('');
|
|
100
|
-
$('#prompt-select-description').val('');
|
|
101
|
-
|
|
102
|
-
// Clear any dynamically generated input fields
|
|
103
|
-
$('#dynamic-inputs-container').empty();
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
/**
|
|
107
|
-
* Renders the custom input fields for the selected prompt.
|
|
108
|
-
* @param {Array<object>} fields The array of custom field configurations.
|
|
109
|
-
*/
|
|
110
|
-
function renderDynamicInputs(fields) {
|
|
111
|
-
const container = $('#dynamic-inputs-container');
|
|
112
|
-
container.empty();
|
|
113
|
-
|
|
114
|
-
const row = $('<div class="row g-2"></div>');
|
|
115
|
-
fields.forEach(field => {
|
|
116
|
-
const colDiv = $('<div class="col-md"></div>');
|
|
117
|
-
const formFloating = $('<div class="form-floating"></div>');
|
|
118
|
-
const input = $(`<input type="${field.type || 'text'}" class="form-control form-control-soft" id="${field.data_key}-id" ">`);
|
|
119
|
-
const label = $(`<label for="${field.data_key}-id">${field.label}</label>`);
|
|
120
|
-
|
|
121
|
-
formFloating.append(input, label);
|
|
122
|
-
colDiv.append(formFloating);
|
|
123
|
-
row.append(colDiv);
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
container.append(row);
|
|
127
|
-
}
|
|
128
58
|
|
|
59
|
+
});
|
|
129
60
|
|
|
130
61
|
|
|
131
62
|
/**
|
|
@@ -163,7 +94,6 @@ const handleChatMessage = async function () {
|
|
|
163
94
|
}
|
|
164
95
|
|
|
165
96
|
// Simplificado: Si no hay mensaje, el 'finally' se encargará de limpiar.
|
|
166
|
-
// Simplemente salimos de la función.
|
|
167
97
|
if (!displayMessage) {
|
|
168
98
|
return;
|
|
169
99
|
}
|
|
@@ -269,28 +199,6 @@ const toggleSendStopButtons = function (showStop) {
|
|
|
269
199
|
$('#stop-button-container').toggle(showStop);
|
|
270
200
|
};
|
|
271
201
|
|
|
272
|
-
/**
|
|
273
|
-
* Resets the prompt selector to its default state.
|
|
274
|
-
*/
|
|
275
|
-
function resetPromptSelect() {
|
|
276
|
-
$('#prompt-select-button').text('Prompts disponibles ....').removeClass('item-selected');
|
|
277
|
-
$('#prompt-select-value').val('');
|
|
278
|
-
$('#prompt-select-description').val('');
|
|
279
|
-
$('#clear-selection-button').hide();
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
/**
|
|
283
|
-
* Resets the company-specific data input field.
|
|
284
|
-
*/
|
|
285
|
-
function resetSpecificDataInput() {
|
|
286
|
-
if (specificDataConfig && specificDataConfig.enabled) {
|
|
287
|
-
const input = $('#' + specificDataConfig.id);
|
|
288
|
-
input.val('').removeClass('has-content');
|
|
289
|
-
$('#clear-' + specificDataConfig.id + '-button').hide();
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
|
|
294
202
|
/**
|
|
295
203
|
* Generic function to make API calls to the backend.
|
|
296
204
|
* @param {string} apiPath - The API endpoint path.
|
|
@@ -321,21 +229,12 @@ const callToolkit = async function(apiPath, data, method, timeoutMs = 500000) {
|
|
|
321
229
|
|
|
322
230
|
}
|
|
323
231
|
const response = await fetch(url, fetchOptions);
|
|
324
|
-
|
|
325
232
|
clearTimeout(timeoutId);
|
|
326
|
-
|
|
327
233
|
if (!response.ok) {
|
|
328
|
-
if (response.status === 401) {
|
|
329
|
-
const errorMessage = `Tu sesión ha expirado. `;
|
|
330
|
-
const errorIcon = '<i class="bi bi-exclamation-triangle"></i>';
|
|
331
|
-
const infrastructureError = $('<div>').addClass('error-section').html(errorIcon + `<p>${errorMessage}</p>`);
|
|
332
|
-
displayBotMessage(infrastructureError);
|
|
333
|
-
return null;
|
|
334
|
-
}
|
|
335
234
|
try {
|
|
336
235
|
// Intentamos leer el error como JSON, que es el formato esperado de nuestra API.
|
|
337
236
|
const errorData = await response.json();
|
|
338
|
-
const errorMessage = errorData.error_message || '
|
|
237
|
+
const errorMessage = errorData.error_message || t_js('unknown_server_error'); // <-- Translation
|
|
339
238
|
const errorIcon = '<i class="bi bi-exclamation-triangle"></i>';
|
|
340
239
|
const endpointError = $('<div>').addClass('error-section').html(errorIcon + `<p>${errorMessage}</p>`);
|
|
341
240
|
displayBotMessage(endpointError);
|
|
@@ -343,9 +242,7 @@ const callToolkit = async function(apiPath, data, method, timeoutMs = 500000) {
|
|
|
343
242
|
// Si response.json() falla, es porque el cuerpo no era JSON (ej. un 502 con HTML).
|
|
344
243
|
// Mostramos un error genérico y más claro para el usuario.
|
|
345
244
|
const errorMessage = `Error de comunicación con el servidor (${response.status}). Por favor, intente de nuevo más tarde.`;
|
|
346
|
-
|
|
347
|
-
const infrastructureError = $('<div>').addClass('error-section').html(errorIcon + `<p>${errorMessage}</p>`);
|
|
348
|
-
displayBotMessage(infrastructureError);
|
|
245
|
+
toastr.error(errorMessage);
|
|
349
246
|
}
|
|
350
247
|
return null;
|
|
351
248
|
}
|
|
@@ -355,18 +252,7 @@ const callToolkit = async function(apiPath, data, method, timeoutMs = 500000) {
|
|
|
355
252
|
if (error.name === 'AbortError') {
|
|
356
253
|
throw error; // Re-throw to be handled by handleChatMessage
|
|
357
254
|
} else {
|
|
358
|
-
|
|
359
|
-
console.error('Error de red en callToolkit:', {
|
|
360
|
-
url,
|
|
361
|
-
method,
|
|
362
|
-
error,
|
|
363
|
-
message: error?.message,
|
|
364
|
-
stack: error?.stack,
|
|
365
|
-
});
|
|
366
|
-
const friendlyMessage = "Ocurrió un error de red. Por favor, inténtalo de nuevo en unos momentos.";
|
|
367
|
-
const errorIcon = '<i class="bi bi-exclamation-triangle"></i>';
|
|
368
|
-
const commError = $('<div>').addClass('error-section').html(errorIcon + `<p>${friendlyMessage}</p>`);
|
|
369
|
-
displayBotMessage(commError);
|
|
255
|
+
toastr.error(t_js('network_error') );
|
|
370
256
|
}
|
|
371
257
|
return null;
|
|
372
258
|
}
|
|
@@ -387,11 +273,13 @@ const displayUserMessage = function(message, isEditable, originalQuestion) {
|
|
|
387
273
|
userMessage.append(messageText);
|
|
388
274
|
|
|
389
275
|
if (isEditable) {
|
|
390
|
-
const editIcon = $('<i>').addClass('p-2 bi bi-pencil-fill edit-icon').attr('title', 'Edit query').on('click', function () {
|
|
391
|
-
$('#question').val(originalQuestion)
|
|
276
|
+
const editIcon = $('<i>').addClass('p-2 bi bi-pencil-fill edit-icon edit-pencil').attr('title', 'Edit query').on('click', function () {
|
|
277
|
+
$('#question').val(originalQuestion)
|
|
392
278
|
autoResizeTextarea($('#question')[0]);
|
|
393
|
-
|
|
394
279
|
$('#send-button').removeClass('disabled');
|
|
280
|
+
|
|
281
|
+
if (window.innerWidth > 768)
|
|
282
|
+
$('#question').focus();
|
|
395
283
|
});
|
|
396
284
|
userMessage.append(editIcon);
|
|
397
285
|
}
|
|
@@ -424,12 +312,13 @@ const abortCurrentRequest = function () {
|
|
|
424
312
|
const showSpinner = function () {
|
|
425
313
|
if ($('#spinner').length) return;
|
|
426
314
|
const accessibilityClass = (typeof bootstrap !== 'undefined') ? 'visually-hidden' : 'sr-only';
|
|
315
|
+
const spinnerText = t_js('loading');
|
|
427
316
|
const spinner = $(`
|
|
428
317
|
<div id="spinner" style="display: flex; align-items: center; justify-content: start; margin: 10px 0; padding: 10px;">
|
|
429
|
-
<div class="spinner-border
|
|
318
|
+
<div class="spinner-border" role="status" style="width: 1.5rem; height: 1.5rem; margin-right: 15px;">
|
|
430
319
|
<span class="${accessibilityClass}">Loading...</span>
|
|
431
320
|
</div>
|
|
432
|
-
<span style="font-weight: bold; font-size: 15px;"
|
|
321
|
+
<span style="font-weight: bold; font-size: 15px;">${spinnerText}</span>
|
|
433
322
|
</div>
|
|
434
323
|
`);
|
|
435
324
|
$('#chat-container').append(spinner).scrollTop($('#chat-container')[0].scrollHeight);
|
|
@@ -458,44 +347,3 @@ function toBase64(file) {
|
|
|
458
347
|
});
|
|
459
348
|
}
|
|
460
349
|
|
|
461
|
-
/**
|
|
462
|
-
* Displays the document validation results.
|
|
463
|
-
* @param {Array<object>} document_list
|
|
464
|
-
*/
|
|
465
|
-
function display_document_validation(document_list) {
|
|
466
|
-
const requiredFields = ['document_name', 'document_type', 'causes', 'is_valid'];
|
|
467
|
-
for (const doc of document_list) {
|
|
468
|
-
if (!requiredFields.every(field => field in doc)) {
|
|
469
|
-
console.warn("Document with incorrect structure:", doc);
|
|
470
|
-
continue;
|
|
471
|
-
}
|
|
472
|
-
const docValidationSection = $('<div>').addClass('document-section card mt-2 mb-2');
|
|
473
|
-
const cardBody = $('<div>').addClass('card-body');
|
|
474
|
-
const headerDiv = $('<div>').addClass('d-flex justify-content-between align-items-center mb-2');
|
|
475
|
-
const filenameSpan = $(`
|
|
476
|
-
<div>
|
|
477
|
-
<span class="text-primary fw-bold">File: </span>
|
|
478
|
-
<span class="text-secondary">${doc.document_name}</span>
|
|
479
|
-
</div>`);
|
|
480
|
-
const badge_style = doc.is_valid ? 'bg-success' : 'bg-danger';
|
|
481
|
-
const documentBadge = $('<span>')
|
|
482
|
-
.addClass(`badge ${badge_style} p-2`)
|
|
483
|
-
.text(doc.document_type);
|
|
484
|
-
headerDiv.append(filenameSpan).append(documentBadge);
|
|
485
|
-
cardBody.append(headerDiv);
|
|
486
|
-
|
|
487
|
-
if (!doc.is_valid && doc.causes && doc.causes.length > 0) {
|
|
488
|
-
const rejectionSection = $('<div>').addClass('rejection-reasons mt-2');
|
|
489
|
-
rejectionSection.append('<h6 class="text-danger">Rejection Causes:</h6>');
|
|
490
|
-
const causesList = doc.causes.map(cause => `<li class="text-secondary">${cause}</li>`).join('');
|
|
491
|
-
rejectionSection.append(`<ul class="list-unstyled">${causesList}</ul>`);
|
|
492
|
-
cardBody.append(rejectionSection);
|
|
493
|
-
} else if (doc.is_valid) {
|
|
494
|
-
const validSection = $('<div>').addClass('mt-2');
|
|
495
|
-
validSection.append('<p class="text-success fw-bold">Valid document.</p>');
|
|
496
|
-
cardBody.append(validSection);
|
|
497
|
-
}
|
|
498
|
-
docValidationSection.append(cardBody);
|
|
499
|
-
displayBotMessage(docValidationSection);
|
|
500
|
-
}
|
|
501
|
-
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
$(document).ready(function () {
|
|
2
|
+
// --- PROMPT ASSISTANT FUNCTIONALITY ---
|
|
3
|
+
const $promptCollapse = $('#prompt-assistant-collapse');
|
|
4
|
+
|
|
5
|
+
if ($promptCollapse.length) {
|
|
6
|
+
$promptCollapse.on('shown.bs.collapse', function () {
|
|
7
|
+
// Scroll to bottom smoothly when the collapse is shown
|
|
8
|
+
$('html, body').animate(
|
|
9
|
+
{ scrollTop: $(document).height() },
|
|
10
|
+
'slow'
|
|
11
|
+
);
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
$('.input-area').on('click', '.dropdown-menu a.dropdown-item', function (event) {
|
|
16
|
+
event.preventDefault();
|
|
17
|
+
const promptData = $(this).data();
|
|
18
|
+
|
|
19
|
+
const promptObject = {
|
|
20
|
+
prompt: promptData.promptName,
|
|
21
|
+
description: promptData.promptDescription,
|
|
22
|
+
custom_fields: typeof promptData.customFields === 'string' ? JSON.parse(promptData.customFields) : promptData.customFields
|
|
23
|
+
};
|
|
24
|
+
selectPrompt(promptObject);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
// Handles the 'clear' button for the prompt selector
|
|
28
|
+
$('#clear-selection-button').on('click', function() {
|
|
29
|
+
resetPromptSelection();
|
|
30
|
+
updateSendButtonState();
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Handles the selection of a prompt from the dropdown.
|
|
36
|
+
* @param {object} prompt The prompt object read from data attributes.
|
|
37
|
+
*/
|
|
38
|
+
function selectPrompt(prompt) {
|
|
39
|
+
selectedPrompt = prompt;
|
|
40
|
+
|
|
41
|
+
// Update the dropdown button to show the selected prompt's description
|
|
42
|
+
$('#prompt-select-button').text(prompt.description).addClass('item-selected');
|
|
43
|
+
$('#clear-selection-button').show();
|
|
44
|
+
|
|
45
|
+
// Clear the main textarea, as we are now in "prompt mode"
|
|
46
|
+
$('#question').val('');
|
|
47
|
+
autoResizeTextarea($('#question')[0]); // Reset height after clearing
|
|
48
|
+
|
|
49
|
+
// Store values in hidden fields for backward compatibility or other uses
|
|
50
|
+
$('#prompt-select-value').val(prompt.prompt);
|
|
51
|
+
$('#prompt-select-description').val(prompt.description);
|
|
52
|
+
|
|
53
|
+
// Render the dynamic input fields required by the selected prompt
|
|
54
|
+
renderDynamicInputs(prompt.custom_fields || []);
|
|
55
|
+
updateSendButtonState();
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Resets the prompt selection and clears associated UI elements.
|
|
60
|
+
*/
|
|
61
|
+
function resetPromptSelection() {
|
|
62
|
+
selectedPrompt = null;
|
|
63
|
+
|
|
64
|
+
$('#prompt-select-button').text('Prompts disponibles ....').removeClass('item-selected');
|
|
65
|
+
$('#clear-selection-button').hide();
|
|
66
|
+
$('#prompt-select-value').val('');
|
|
67
|
+
$('#prompt-select-description').val('');
|
|
68
|
+
|
|
69
|
+
// Clear any dynamically generated input fields
|
|
70
|
+
$('#dynamic-inputs-container').empty();
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Renders the custom input fields for the selected prompt.
|
|
75
|
+
* @param {Array<object>} fields The array of custom field configurations.
|
|
76
|
+
*/
|
|
77
|
+
function renderDynamicInputs(fields) {
|
|
78
|
+
const container = $('#dynamic-inputs-container');
|
|
79
|
+
container.empty();
|
|
80
|
+
|
|
81
|
+
const row = $('<div class="row g-2"></div>');
|
|
82
|
+
fields.forEach(field => {
|
|
83
|
+
const colDiv = $('<div class="col-md"></div>');
|
|
84
|
+
const formFloating = $('<div class="form-floating"></div>');
|
|
85
|
+
const input = $(`<input type="${field.type || 'text'}" class="form-control form-control-soft" id="${field.data_key}-id" ">`);
|
|
86
|
+
const label = $(`<label for="${field.data_key}-id">${field.label}</label>`);
|
|
87
|
+
|
|
88
|
+
formFloating.append(input, label);
|
|
89
|
+
colDiv.append(formFloating);
|
|
90
|
+
row.append(colDiv);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
container.append(row);
|
|
94
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
$(document).ready(function () {
|
|
2
|
+
$('#force-reload-button').on('click', function() {
|
|
3
|
+
reloadButton(this);
|
|
4
|
+
});
|
|
5
|
+
|
|
6
|
+
async function reloadButton(button) {
|
|
7
|
+
const originalIconClass = 'bi bi-arrow-clockwise';
|
|
8
|
+
const spinnerIconClass = 'spinner-border spinner-border-sm';
|
|
9
|
+
|
|
10
|
+
// Configuración de Toastr para que aparezca abajo a la derecha
|
|
11
|
+
toastr.options = {"positionClass": "toast-bottom-right", "preventDuplicates": true};
|
|
12
|
+
|
|
13
|
+
// 1. Deshabilitar y mostrar spinner
|
|
14
|
+
button.disabled = true;
|
|
15
|
+
const icon = button.querySelector('i');
|
|
16
|
+
icon.className = spinnerIconClass;
|
|
17
|
+
toastr.info(t_js('reload_init'));
|
|
18
|
+
|
|
19
|
+
// 2. prepare the api parameters
|
|
20
|
+
const apiPath = '/api/init-context';
|
|
21
|
+
const payload = {'user_identifier': window.user_identifier};
|
|
22
|
+
|
|
23
|
+
// 3. make the call to callToolkit
|
|
24
|
+
const data = await callToolkit(apiPath, payload, 'POST');
|
|
25
|
+
if (data) {
|
|
26
|
+
if (data.status === 'OK')
|
|
27
|
+
toastr.success(data.message || 'Contexto reloaded.');
|
|
28
|
+
else
|
|
29
|
+
toastr.error(data.error_message || 'error during reload');
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
button.disabled = false;
|
|
33
|
+
icon.className = originalIconClass;
|
|
34
|
+
}
|
|
35
|
+
});
|