iatoolkit 0.63.1__py3-none-any.whl → 0.69.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.

Files changed (83) hide show
  1. iatoolkit/__init__.py +0 -2
  2. iatoolkit/base_company.py +1 -26
  3. iatoolkit/common/routes.py +11 -2
  4. iatoolkit/common/session_manager.py +2 -0
  5. iatoolkit/common/util.py +17 -0
  6. iatoolkit/company_registry.py +1 -2
  7. iatoolkit/iatoolkit.py +39 -6
  8. iatoolkit/locales/en.yaml +167 -0
  9. iatoolkit/locales/es.yaml +163 -0
  10. iatoolkit/repositories/database_manager.py +8 -3
  11. iatoolkit/repositories/document_repo.py +1 -1
  12. iatoolkit/repositories/models.py +1 -4
  13. iatoolkit/repositories/profile_repo.py +0 -4
  14. iatoolkit/services/auth_service.py +14 -9
  15. iatoolkit/services/branding_service.py +36 -24
  16. iatoolkit/services/company_context_service.py +145 -0
  17. iatoolkit/services/configuration_service.py +133 -0
  18. iatoolkit/services/dispatcher_service.py +51 -48
  19. iatoolkit/services/document_service.py +5 -2
  20. iatoolkit/services/excel_service.py +15 -11
  21. iatoolkit/services/file_processor_service.py +4 -12
  22. iatoolkit/services/history_service.py +8 -7
  23. iatoolkit/services/i18n_service.py +104 -0
  24. iatoolkit/services/jwt_service.py +7 -9
  25. iatoolkit/services/language_service.py +83 -0
  26. iatoolkit/services/load_documents_service.py +4 -4
  27. iatoolkit/services/mail_service.py +9 -4
  28. iatoolkit/services/profile_service.py +61 -38
  29. iatoolkit/services/prompt_manager_service.py +20 -16
  30. iatoolkit/services/query_service.py +19 -15
  31. iatoolkit/services/search_service.py +11 -4
  32. iatoolkit/services/sql_service.py +55 -25
  33. iatoolkit/services/user_feedback_service.py +16 -14
  34. iatoolkit/static/js/chat_feedback_button.js +57 -87
  35. iatoolkit/static/js/chat_help_content.js +124 -0
  36. iatoolkit/static/js/chat_history_button.js +48 -65
  37. iatoolkit/static/js/chat_main.js +27 -24
  38. iatoolkit/static/js/chat_onboarding_button.js +6 -0
  39. iatoolkit/static/js/chat_reload_button.js +28 -45
  40. iatoolkit/static/styles/chat_iatoolkit.css +223 -315
  41. iatoolkit/static/styles/chat_modal.css +63 -97
  42. iatoolkit/static/styles/chat_public.css +107 -0
  43. iatoolkit/static/styles/landing_page.css +0 -1
  44. iatoolkit/static/styles/onboarding.css +7 -0
  45. iatoolkit/templates/_company_header.html +6 -2
  46. iatoolkit/templates/_login_widget.html +42 -0
  47. iatoolkit/templates/base.html +34 -19
  48. iatoolkit/templates/change_password.html +22 -20
  49. iatoolkit/templates/chat.html +59 -27
  50. iatoolkit/templates/chat_modals.html +114 -74
  51. iatoolkit/templates/error.html +12 -13
  52. iatoolkit/templates/forgot_password.html +11 -7
  53. iatoolkit/templates/index.html +8 -3
  54. iatoolkit/templates/login_simulation.html +17 -6
  55. iatoolkit/templates/onboarding_shell.html +4 -2
  56. iatoolkit/templates/signup.html +14 -14
  57. iatoolkit/views/base_login_view.py +19 -9
  58. iatoolkit/views/change_password_view.py +50 -35
  59. iatoolkit/views/external_login_view.py +1 -1
  60. iatoolkit/views/forgot_password_view.py +21 -22
  61. iatoolkit/views/help_content_api_view.py +54 -0
  62. iatoolkit/views/history_api_view.py +13 -9
  63. iatoolkit/views/home_view.py +30 -39
  64. iatoolkit/views/init_context_api_view.py +16 -11
  65. iatoolkit/views/llmquery_api_view.py +38 -26
  66. iatoolkit/views/login_simulation_view.py +14 -2
  67. iatoolkit/views/login_view.py +52 -40
  68. iatoolkit/views/logout_api_view.py +26 -22
  69. iatoolkit/views/profile_api_view.py +46 -0
  70. iatoolkit/views/prompt_api_view.py +6 -6
  71. iatoolkit/views/signup_view.py +27 -27
  72. iatoolkit/views/user_feedback_api_view.py +19 -18
  73. iatoolkit/views/verify_user_view.py +29 -30
  74. {iatoolkit-0.63.1.dist-info → iatoolkit-0.69.0.dist-info}/METADATA +40 -22
  75. iatoolkit-0.69.0.dist-info/RECORD +120 -0
  76. iatoolkit-0.69.0.dist-info/licenses/LICENSE +21 -0
  77. iatoolkit/services/onboarding_service.py +0 -43
  78. iatoolkit/static/styles/chat_info.css +0 -53
  79. iatoolkit/templates/header.html +0 -31
  80. iatoolkit/templates/test.html +0 -9
  81. iatoolkit-0.63.1.dist-info/RECORD +0 -112
  82. {iatoolkit-0.63.1.dist-info → iatoolkit-0.69.0.dist-info}/WHEEL +0 -0
  83. {iatoolkit-0.63.1.dist-info → iatoolkit-0.69.0.dist-info}/top_level.txt +0 -0
@@ -1,81 +1,49 @@
1
1
  $(document).ready(function () {
2
2
  // Evento para abrir el modal de historial
3
+ const historyModal = $('#historyModal');
4
+
3
5
  $('#history-button').on('click', function() {
6
+ historyModal.modal('show');
4
7
  loadHistory();
5
- $('#historyModal').modal('show');
6
- });
7
-
8
- // Evento delegado para el icono de copiar.
9
- // Se adjunta UNA SOLA VEZ al cuerpo de la tabla y funciona para todas las filas
10
- // que se añadan dinámicamente.
11
- $('#history-table-body').on('click', '.copy-query-icon', function() {
12
- const queryText = $(this).data('query');
13
-
14
- // Copiar el texto al textarea del chat
15
- if (queryText) {
16
- $('#question').val(queryText);
17
- autoResizeTextarea($('#question')[0]);
18
- $('#send-button').removeClass('disabled');
19
-
20
- // Cerrar el modal
21
- $('#historyModal').modal('hide');
22
-
23
- // Hacer focus en el textarea
24
- $('#question').focus();
25
- }
26
8
  });
27
9
 
28
- // Variables globales para el historial
29
- let historyData = [];
30
10
 
31
11
  // Función para cargar el historial
32
12
  async function loadHistory() {
33
13
  const historyLoading = $('#history-loading');
34
- const historyError = $('#history-error');
35
14
  const historyContent = $('#history-content');
15
+ const historyTable = historyContent.find('table');
16
+ const noHistoryMessage = $('#no-history-message');
36
17
 
37
- // Mostrar loading
18
+ // prepare UI for loading
38
19
  historyLoading.show();
39
- historyError.hide();
40
20
  historyContent.hide();
21
+ historyTable.show();
22
+ noHistoryMessage.hide();
41
23
 
42
- try {
43
- const responseData = await callToolkit("/api/history", {}, "POST");
44
-
45
- if (responseData && responseData.history) {
46
- // Guardar datos globalmente
47
- historyData = responseData.history;
24
+ // cal the toolkit, handle the response and errors
25
+ const data = await callToolkit("/api/history", {}, "POST");
48
26
 
49
- // Mostrar todos los datos
50
- displayAllHistory();
51
-
52
- // Mostrar contenido
53
- historyContent.show();
54
- } else {
55
- throw new Error('La respuesta del servidor no contenía el formato esperado.');
56
- }
57
- } catch (error) {
58
- console.error("Error al cargar historial:", error);
59
-
60
- const friendlyErrorMessage = "No hemos podido cargar tu historial en este momento. Por favor, cierra esta ventana y vuelve a intentarlo en unos instantes.";
61
- const errorHtml = `
62
- <div class="text-center p-4">
63
- <i class="bi bi-exclamation-triangle text-danger" style="font-size: 2.5rem; opacity: 0.8;"></i>
64
- <h5 class="mt-3 mb-2">Ocurrió un Problema</h5>
65
- <p class="text-muted">${friendlyErrorMessage}</p>
66
- </div>
67
- `;
68
- historyError.html(errorHtml).show();
69
- } finally {
27
+ if (!data || !data.history) {
70
28
  historyLoading.hide();
29
+ toastr.error(t_js('error_loading_history'));
30
+ return;
71
31
  }
32
+
33
+ if (data.history.length === 0) {
34
+ historyTable.hide();
35
+ noHistoryMessage.show();
36
+ } else
37
+ displayAllHistory(data.history);
38
+
39
+ historyLoading.hide();
40
+ historyContent.show();
72
41
  }
73
42
 
74
43
  // Función para mostrar todo el historial
75
- function displayAllHistory() {
44
+ function displayAllHistory(historyData) {
76
45
  const historyTableBody = $('#history-table-body');
77
46
 
78
- // Limpiar tabla
79
47
  historyTableBody.empty();
80
48
 
81
49
  // Filtrar solo consultas que son strings simples
@@ -92,28 +60,24 @@ $(document).ready(function () {
92
60
  filteredHistory.forEach((item, index) => {
93
61
  const icon = $('<i>').addClass('bi bi-pencil-fill');
94
62
 
95
- const link = $('<a>')
63
+ const edit_link = $('<a>')
96
64
  .attr('href', 'javascript:void(0);')
97
- .addClass('copy-query-icon')
98
- .attr('title', 'Copiar consulta al chat')
65
+ .addClass('edit-pencil')
66
+ .attr('title', t_js('edit_query'))
99
67
  .data('query', item.query)
100
68
  .append(icon);
101
69
 
102
70
  const row = $('<tr>').append(
103
- $('<td>').text(index + 1),
104
- $('<td>').addClass('date-cell').text(formatDate(item.created_at)),
71
+ $('<td>').addClass('text-nowrap').text(formatDate(item.created_at)),
105
72
  $('<td>').text(item.query),
106
- $('<td>').addClass('text-center').append(link)
73
+ $('<td>').append(edit_link),
107
74
  );
108
-
109
75
  historyTableBody.append(row);
110
76
  });
111
77
  }
112
78
 
113
- // Función para formatear fecha
114
79
  function formatDate(dateString) {
115
80
  const date = new Date(dateString);
116
-
117
81
  const padTo2Digits = (num) => num.toString().padStart(2, '0');
118
82
 
119
83
  const day = padTo2Digits(date.getDate());
@@ -122,6 +86,25 @@ $(document).ready(function () {
122
86
  const hours = padTo2Digits(date.getHours());
123
87
  const minutes = padTo2Digits(date.getMinutes());
124
88
 
125
- return `${day}-${month}-${year} ${hours}:${minutes}`;
89
+ return `${day}-${month} ${hours}:${minutes}`;
126
90
  }
91
+
92
+ // event handler for the edit pencil icon
93
+ $('#history-table-body').on('click', '.edit-pencil', function() {
94
+ const queryText = $(this).data('query');
95
+
96
+ // copy the text to the chat input box
97
+ if (queryText) {
98
+ $('#question').val(queryText);
99
+ autoResizeTextarea($('#question')[0]);
100
+ $('#send-button').removeClass('disabled');
101
+
102
+ // Cerrar el modal
103
+ $('#historyModal').modal('hide');
104
+
105
+ // Hacer focus en el textarea
106
+ if (window.innerWidth > 768)
107
+ $('#question').focus();
108
+ }
109
+ });
127
110
  });
@@ -11,6 +11,22 @@ $(document).ready(function () {
11
11
  callToolkit(url, {'token': window.redeemToken}, "POST").catch(() => {});
12
12
  }
13
13
 
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
+
14
30
  // --- chat main event hadlers ---
15
31
  $('#send-button').on('click', handleChatMessage);
16
32
  $('#stop-button').on('click', abortCurrentRequest);
@@ -183,7 +199,6 @@ const toggleSendStopButtons = function (showStop) {
183
199
  $('#stop-button-container').toggle(showStop);
184
200
  };
185
201
 
186
-
187
202
  /**
188
203
  * Generic function to make API calls to the backend.
189
204
  * @param {string} apiPath - The API endpoint path.
@@ -214,14 +229,12 @@ const callToolkit = async function(apiPath, data, method, timeoutMs = 500000) {
214
229
 
215
230
  }
216
231
  const response = await fetch(url, fetchOptions);
217
-
218
232
  clearTimeout(timeoutId);
219
-
220
233
  if (!response.ok) {
221
234
  try {
222
235
  // Intentamos leer el error como JSON, que es el formato esperado de nuestra API.
223
236
  const errorData = await response.json();
224
- const errorMessage = errorData.error_message || 'Error desconocido del servidor.';
237
+ const errorMessage = errorData.error_message || t_js('unknown_server_error'); // <-- Translation
225
238
  const errorIcon = '<i class="bi bi-exclamation-triangle"></i>';
226
239
  const endpointError = $('<div>').addClass('error-section').html(errorIcon + `<p>${errorMessage}</p>`);
227
240
  displayBotMessage(endpointError);
@@ -229,9 +242,7 @@ const callToolkit = async function(apiPath, data, method, timeoutMs = 500000) {
229
242
  // Si response.json() falla, es porque el cuerpo no era JSON (ej. un 502 con HTML).
230
243
  // Mostramos un error genérico y más claro para el usuario.
231
244
  const errorMessage = `Error de comunicación con el servidor (${response.status}). Por favor, intente de nuevo más tarde.`;
232
- const errorIcon = '<i class="bi bi-exclamation-triangle"></i>';
233
- const infrastructureError = $('<div>').addClass('error-section').html(errorIcon + `<p>${errorMessage}</p>`);
234
- displayBotMessage(infrastructureError);
245
+ toastr.error(errorMessage);
235
246
  }
236
247
  return null;
237
248
  }
@@ -241,18 +252,7 @@ const callToolkit = async function(apiPath, data, method, timeoutMs = 500000) {
241
252
  if (error.name === 'AbortError') {
242
253
  throw error; // Re-throw to be handled by handleChatMessage
243
254
  } else {
244
- // Log detallado en consola
245
- console.error('Error de red en callToolkit:', {
246
- url,
247
- method,
248
- error,
249
- message: error?.message,
250
- stack: error?.stack,
251
- });
252
- const friendlyMessage = "Ocurrió un error de red. Por favor, inténtalo de nuevo en unos momentos.";
253
- const errorIcon = '<i class="bi bi-exclamation-triangle"></i>';
254
- const commError = $('<div>').addClass('error-section').html(errorIcon + `<p>${friendlyMessage}</p>`);
255
- displayBotMessage(commError);
255
+ toastr.error(t_js('network_error') );
256
256
  }
257
257
  return null;
258
258
  }
@@ -273,11 +273,13 @@ const displayUserMessage = function(message, isEditable, originalQuestion) {
273
273
  userMessage.append(messageText);
274
274
 
275
275
  if (isEditable) {
276
- const editIcon = $('<i>').addClass('p-2 bi bi-pencil-fill edit-icon').attr('title', 'Edit query').on('click', function () {
277
- $('#question').val(originalQuestion).focus();
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)
278
278
  autoResizeTextarea($('#question')[0]);
279
-
280
279
  $('#send-button').removeClass('disabled');
280
+
281
+ if (window.innerWidth > 768)
282
+ $('#question').focus();
281
283
  });
282
284
  userMessage.append(editIcon);
283
285
  }
@@ -310,12 +312,13 @@ const abortCurrentRequest = function () {
310
312
  const showSpinner = function () {
311
313
  if ($('#spinner').length) return;
312
314
  const accessibilityClass = (typeof bootstrap !== 'undefined') ? 'visually-hidden' : 'sr-only';
315
+ const spinnerText = t_js('loading');
313
316
  const spinner = $(`
314
317
  <div id="spinner" style="display: flex; align-items: center; justify-content: start; margin: 10px 0; padding: 10px;">
315
- <div class="spinner-border text-primary" role="status" style="width: 1.5rem; height: 1.5rem; margin-right: 15px;">
318
+ <div class="spinner-border" role="status" style="width: 1.5rem; height: 1.5rem; margin-right: 15px;">
316
319
  <span class="${accessibilityClass}">Loading...</span>
317
320
  </div>
318
- <span style="font-weight: bold; font-size: 15px;">Cargando...</span>
321
+ <span style="font-weight: bold; font-size: 15px;">${spinnerText}</span>
319
322
  </div>
320
323
  `);
321
324
  $('#chat-container').append(spinner).scrollTop($('#chat-container')[0].scrollHeight);
@@ -28,6 +28,7 @@
28
28
  const elIcon = qs(root, ui.icon);
29
29
  const elTitle = qs(root, ui.title);
30
30
  const elText = qs(root, ui.text);
31
+ const elExample = qs(root, ui.example);
31
32
  const elDots = qs(root, ui.dots);
32
33
  const elPrev = qs(root, ui.prev);
33
34
  const elNext = qs(root, ui.next);
@@ -43,6 +44,11 @@
43
44
  if (elIcon) elIcon.innerHTML = `<i class="${c.icon || 'bi bi-lightbulb'}"></i>`;
44
45
  if (elTitle) elTitle.textContent = c.title || '';
45
46
  if (elText) elText.innerHTML = c.text || '';
47
+ if (elExample && c.example) {
48
+ elExample.innerHTML = ('Ejemplo: ' + c.example) || '';
49
+ }
50
+ else
51
+ elExample.innerHTML = '';
46
52
  if (elDots) createDots(elDots, cards.length, idx);
47
53
  }
48
54
 
@@ -1,52 +1,35 @@
1
- document.addEventListener('DOMContentLoaded', function() {
2
- const reloadButton = document.getElementById('force-reload-button');
3
- if (!reloadButton) return;
1
+ $(document).ready(function () {
2
+ $('#force-reload-button').on('click', function() {
3
+ reloadButton(this);
4
+ });
4
5
 
5
- const originalIconClass = 'bi bi-arrow-clockwise';
6
- const spinnerIconClass = 'spinner-border spinner-border-sm';
6
+ async function reloadButton(button) {
7
+ const originalIconClass = 'bi bi-arrow-clockwise';
8
+ const spinnerIconClass = 'spinner-border spinner-border-sm';
7
9
 
8
- // Configuración de Toastr para que aparezca abajo a la derecha
9
- toastr.options = { "positionClass": "toast-bottom-right", "preventDuplicates": true };
10
-
11
- reloadButton.addEventListener('click', async function(event) {
12
- event.preventDefault();
13
-
14
- if (reloadButton.disabled) return; // Prevenir doble clic
10
+ // Configuración de Toastr para que aparezca abajo a la derecha
11
+ toastr.options = {"positionClass": "toast-bottom-right", "preventDuplicates": true};
15
12
 
16
13
  // 1. Deshabilitar y mostrar spinner
17
- reloadButton.disabled = true;
18
- const icon = reloadButton.querySelector('i');
14
+ button.disabled = true;
15
+ const icon = button.querySelector('i');
19
16
  icon.className = spinnerIconClass;
20
- toastr.info('Iniciando recarga de contexto en segundo plano...');
21
-
22
- try {
23
- // 2. Definir los parámetros para callToolkit
24
- const apiPath = '/api/init-context';
25
- const payload = { 'user_identifier': window.user_identifier };
26
-
27
- // 3. Hacer la llamada usando callToolkit
28
- const data = await callToolkit(apiPath, payload, 'POST');
29
-
30
- // 4. Procesar la respuesta
31
- // callToolkit devuelve null si hubo un error que ya mostró en el chat.
32
- if (data) {
33
- if (data.status === 'OK')
34
- toastr.success(data.message || 'Contexto recargado exitosamente.');
35
- else
36
- toastr.error(data.error_message || 'Ocurrió un error desconocido durante la recarga.');
37
- } else {
38
- // Si data es null, callToolkit ya manejó el error (mostrando un mensaje en el chat).
39
- // Añadimos un toast para notificar al usuario que algo falló.
40
- toastr.error('Falló la recarga del contexto. Revisa el chat para más detalles.');
41
- }
42
- } catch (error) {
43
- // Este bloque se ejecutará para errores no controlados por callToolkit (como AbortError)
44
- console.error('Error durante la recarga del contexto:', error);
45
- toastr.error(error.message || 'Error de red al intentar recargar.');
46
- } finally {
47
- // 5. Restaurar el botón en cualquier caso
48
- reloadButton.disabled = false;
49
- icon.className = originalIconClass;
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');
50
30
  }
51
- });
31
+
32
+ button.disabled = false;
33
+ icon.className = originalIconClass;
34
+ }
52
35
  });