iatoolkit 0.66.2__tar.gz → 0.66.4__tar.gz
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.
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/PKG-INFO +1 -1
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/pyproject.toml +1 -1
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/common/session_manager.py +2 -0
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/iatoolkit.py +1 -1
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/locales/en.yaml +23 -0
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/locales/es.yaml +25 -2
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/repositories/database_manager.py +1 -1
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/repositories/document_repo.py +1 -1
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/services/auth_service.py +2 -2
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/services/branding_service.py +1 -2
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/services/dispatcher_service.py +8 -9
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/services/document_service.py +5 -2
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/services/excel_service.py +15 -11
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/services/file_processor_service.py +4 -12
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/services/help_content_service.py +1 -1
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/services/history_service.py +8 -7
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/services/i18n_service.py +2 -2
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/services/jwt_service.py +7 -9
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/services/load_documents_service.py +4 -4
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/services/mail_service.py +9 -4
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/services/profile_service.py +5 -5
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/services/prompt_manager_service.py +20 -16
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/services/query_service.py +15 -14
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/services/sql_service.py +6 -2
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/services/user_feedback_service.py +15 -13
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/static/js/chat_history_button.js +3 -5
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/static/js/chat_main.js +2 -17
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/static/styles/chat_iatoolkit.css +35 -114
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/static/styles/chat_modal.css +1 -37
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/templates/chat_modals.html +3 -0
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/templates/login_simulation.html +16 -5
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/views/help_content_api_view.py +1 -1
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/views/history_api_view.py +1 -1
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/views/init_context_api_view.py +1 -1
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/views/llmquery_api_view.py +1 -1
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/views/login_simulation_view.py +14 -2
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/views/verify_user_view.py +1 -1
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit.egg-info/PKG-INFO +1 -1
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/readme.md +0 -0
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/requirements.txt +0 -0
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/setup.cfg +0 -0
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/__init__.py +0 -0
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/base_company.py +0 -0
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/cli_commands.py +0 -0
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/common/__init__.py +0 -0
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/common/exceptions.py +0 -0
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/common/routes.py +0 -0
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/common/util.py +0 -0
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/company_registry.py +0 -0
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/infra/__init__.py +0 -0
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/infra/call_service.py +0 -0
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/infra/connectors/__init__.py +0 -0
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/infra/connectors/file_connector.py +0 -0
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/infra/connectors/file_connector_factory.py +0 -0
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/infra/connectors/google_cloud_storage_connector.py +0 -0
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/infra/connectors/google_drive_connector.py +0 -0
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/infra/connectors/local_file_connector.py +0 -0
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/infra/connectors/s3_connector.py +0 -0
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/infra/gemini_adapter.py +0 -0
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/infra/google_chat_app.py +0 -0
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/infra/llm_client.py +0 -0
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/infra/llm_proxy.py +0 -0
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/infra/llm_response.py +0 -0
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/infra/mail_app.py +0 -0
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/infra/openai_adapter.py +0 -0
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/infra/redis_session_manager.py +0 -0
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/repositories/__init__.py +0 -0
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/repositories/llm_query_repo.py +0 -0
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/repositories/models.py +0 -0
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/repositories/profile_repo.py +0 -0
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/repositories/tasks_repo.py +0 -0
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/repositories/vs_repo.py +0 -0
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/services/__init__.py +0 -0
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/services/benchmark_service.py +0 -0
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/services/language_service.py +0 -0
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/services/onboarding_service.py +0 -0
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/services/search_service.py +0 -0
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/services/tasks_service.py +0 -0
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/services/user_session_context_service.py +0 -0
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/static/images/fernando.jpeg +0 -0
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/static/js/chat_feedback_button.js +0 -0
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/static/js/chat_filepond.js +0 -0
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/static/js/chat_help_content.js +0 -0
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/static/js/chat_logout_button.js +0 -0
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/static/js/chat_onboarding_button.js +0 -0
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/static/js/chat_prompt_manager.js +0 -0
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/static/js/chat_reload_button.js +0 -0
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/static/styles/chat_public.css +0 -0
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/static/styles/landing_page.css +0 -0
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/static/styles/llm_output.css +0 -0
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/static/styles/onboarding.css +0 -0
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/system_prompts/format_styles.prompt +0 -0
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/system_prompts/query_main.prompt +0 -0
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/system_prompts/sql_rules.prompt +0 -0
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/templates/_company_header.html +0 -0
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/templates/_login_widget.html +0 -0
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/templates/about.html +0 -0
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/templates/base.html +0 -0
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/templates/change_password.html +0 -0
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/templates/chat.html +0 -0
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/templates/error.html +0 -0
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/templates/forgot_password.html +0 -0
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/templates/index.html +0 -0
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/templates/onboarding_shell.html +0 -0
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/templates/signup.html +0 -0
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/views/__init__.py +0 -0
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/views/base_login_view.py +0 -0
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/views/change_password_view.py +0 -0
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/views/external_login_view.py +0 -0
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/views/file_store_api_view.py +0 -0
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/views/forgot_password_view.py +0 -0
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/views/home_view.py +0 -0
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/views/index_view.py +0 -0
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/views/login_view.py +0 -0
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/views/logout_api_view.py +0 -0
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/views/profile_api_view.py +0 -0
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/views/prompt_api_view.py +0 -0
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/views/signup_view.py +0 -0
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/views/tasks_api_view.py +0 -0
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/views/tasks_review_api_view.py +0 -0
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit/views/user_feedback_api_view.py +0 -0
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit.egg-info/SOURCES.txt +0 -0
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit.egg-info/dependency_links.txt +0 -0
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit.egg-info/requires.txt +0 -0
- {iatoolkit-0.66.2 → iatoolkit-0.66.4}/src/iatoolkit.egg-info/top_level.txt +0 -0
|
@@ -19,7 +19,7 @@ from werkzeug.middleware.proxy_fix import ProxyFix
|
|
|
19
19
|
from injector import Binder, Injector, singleton
|
|
20
20
|
from importlib.metadata import version as _pkg_version, PackageNotFoundError
|
|
21
21
|
|
|
22
|
-
IATOOLKIT_VERSION = "0.66.
|
|
22
|
+
IATOOLKIT_VERSION = "0.66.4"
|
|
23
23
|
|
|
24
24
|
# global variable for the unique instance of IAToolkit
|
|
25
25
|
_iatoolkit_instance: Optional['IAToolkit'] = None
|
|
@@ -77,6 +77,8 @@ ui:
|
|
|
77
77
|
stop: "Stop"
|
|
78
78
|
|
|
79
79
|
errors:
|
|
80
|
+
company_not_found: "The company {company_short_name} does not exist."
|
|
81
|
+
timeout: "timeout expired."
|
|
80
82
|
auth:
|
|
81
83
|
invalid_password: "The provided password is incorrect."
|
|
82
84
|
user_not_found: "A user with that email address was not found."
|
|
@@ -115,9 +117,29 @@ errors:
|
|
|
115
117
|
password_no_digit: "Password must contain at least one number."
|
|
116
118
|
password_no_special_char: "Password must contain at least one special character."
|
|
117
119
|
|
|
120
|
+
services:
|
|
121
|
+
no_text_file: "The file is not text or the encoding is not UTF-8"
|
|
122
|
+
no_output_file: "Missing output file name"
|
|
123
|
+
no_data_for_excel: "Missing data or it is not a list of dictionaries"
|
|
124
|
+
no_download_directory: "Temporary directory for saving Excel files is not configured"
|
|
125
|
+
cannot_create_excel: "Could not create the Excel file"
|
|
126
|
+
invalid_filename: "Invalid filename"
|
|
127
|
+
file_not_exist: "File not found"
|
|
128
|
+
path_is_not_a_file: "The path does not correspond to a file"
|
|
129
|
+
file_validation_error: "Error validating file"
|
|
130
|
+
user_not_authorized: "user is not authorized for this company"
|
|
131
|
+
account_not_verified: "Your account has not been verified. Please check your email."
|
|
132
|
+
missing_response_id: "Can not found 'previous_response_id' for '{company_short_name}/{user_identifier}'. Reinit context"
|
|
133
|
+
|
|
134
|
+
|
|
118
135
|
api_responses:
|
|
119
136
|
context_reloaded_success: "The context has been successfully reloaded."
|
|
120
137
|
|
|
138
|
+
services:
|
|
139
|
+
mail_sent: "Email sent successfully."
|
|
140
|
+
start_query: "Hello, what can I help you with today?"
|
|
141
|
+
|
|
142
|
+
|
|
121
143
|
flash_messages:
|
|
122
144
|
password_changed_success: "Your password has been successfully reset. You can now log in."
|
|
123
145
|
login_required: "Please log in to continue."
|
|
@@ -142,3 +164,4 @@ js_messages:
|
|
|
142
164
|
unknown_server_error: "Unknown server error."
|
|
143
165
|
loading: "Loading..."
|
|
144
166
|
reload_init: "init reloading context in background..."
|
|
167
|
+
no_history_found: "No query history found."
|
|
@@ -73,6 +73,10 @@
|
|
|
73
73
|
stop: "Detener"
|
|
74
74
|
|
|
75
75
|
errors:
|
|
76
|
+
company_not_found: "La empresa {company_short_name} no existe."
|
|
77
|
+
timeout: "El tiempo de espera ha expirado."
|
|
78
|
+
|
|
79
|
+
|
|
76
80
|
auth:
|
|
77
81
|
invalid_password: "La contraseña proporcionada es incorrecta."
|
|
78
82
|
user_not_found: "No se encontró un usuario con ese correo."
|
|
@@ -84,11 +88,11 @@
|
|
|
84
88
|
templates:
|
|
85
89
|
company_not_found: "Empresa no encontrada."
|
|
86
90
|
home_template_not_found: "La plantilla de la página de inicio para la empresa '{company_name}' no está configurada."
|
|
91
|
+
processing_error: "Error al procesar el template: {error}"
|
|
87
92
|
template_not_found: "No se encontro el template: '{template_name}'."
|
|
88
|
-
processing_error: "Ocurrió un error al procesar la plantilla personalizada de la página de inicio: {error}"
|
|
89
93
|
|
|
90
94
|
general:
|
|
91
|
-
unexpected_error: "Ha ocurrido un error inesperado
|
|
95
|
+
unexpected_error: "Ha ocurrido un error inesperado: {error}."
|
|
92
96
|
unsupported_language: "El idioma seleccionado no es válido."
|
|
93
97
|
signup:
|
|
94
98
|
company_not_found: "La empresa {company_name} no existe."
|
|
@@ -111,9 +115,27 @@
|
|
|
111
115
|
password_no_digit: "La contraseña debe tener al menos un número."
|
|
112
116
|
password_no_special_char: "La contraseña debe tener al menos un carácter especial."
|
|
113
117
|
|
|
118
|
+
services:
|
|
119
|
+
no_text_file: "El archivo no es texto o la codificación no es UTF-8"
|
|
120
|
+
no_output_file: "falta el nombre del archivo de salida"
|
|
121
|
+
no_data_for_excel: "faltan los datos o no es una lista de diccionarios"
|
|
122
|
+
no_download_directory: "no esta configurado el directorio temporal para guardar excels"
|
|
123
|
+
cannot_create_excel: "no se pudo crear el archivo excel"
|
|
124
|
+
invalid_filename: "Nombre de archivo inválido"
|
|
125
|
+
file_not_exist : "Archivo no encontrado"
|
|
126
|
+
path_is_not_a_file : "La ruta no corresponde a un archivo"
|
|
127
|
+
file_validation_error : "Error validando archivo"
|
|
128
|
+
user_not_authorized: "Usuario no esta autorizado para esta empresa"
|
|
129
|
+
account_not_verified: "Tu cuenta no ha sido verificada. Por favor, revisa tu correo."
|
|
130
|
+
missing_response_id: "No se encontró 'previous_response_id' para '{company_short_name}/{user_identifier}'. Reinicia el contexto."
|
|
131
|
+
|
|
114
132
|
api_responses:
|
|
115
133
|
context_reloaded_success: "El contexto se ha recargado con éxito."
|
|
116
134
|
|
|
135
|
+
services:
|
|
136
|
+
mail_sent: "mail enviado exitosamente."
|
|
137
|
+
start_query: "Hola, cual es tu pregunta?"
|
|
138
|
+
|
|
117
139
|
flash_messages:
|
|
118
140
|
password_changed_success: "Tu contraseña ha sido restablecida exitosamente. Ahora puedes iniciar sesión."
|
|
119
141
|
signup_success: "Registro exitoso. Por favor, revisa tu correo para verificar tu cuenta."
|
|
@@ -137,4 +159,5 @@
|
|
|
137
159
|
unknown_server_error: "Error desconocido del servidor."
|
|
138
160
|
loading: "Cargando..."
|
|
139
161
|
reload_init: "Iniciando recarga de contexto en segundo plano..."
|
|
162
|
+
no_history_found: "No existe historial de consultas."
|
|
140
163
|
|
|
@@ -77,7 +77,7 @@ class DatabaseManager:
|
|
|
77
77
|
inspector = inspect(self._engine)
|
|
78
78
|
|
|
79
79
|
if table_name not in inspector.get_table_names():
|
|
80
|
-
raise RuntimeError(f"
|
|
80
|
+
raise RuntimeError(f"Table '{table_name}' does not exist.")
|
|
81
81
|
|
|
82
82
|
if exclude_columns is None:
|
|
83
83
|
exclude_columns = []
|
|
@@ -22,7 +22,7 @@ class DocumentRepo:
|
|
|
22
22
|
def get(self, company_id, filename: str ) -> Document:
|
|
23
23
|
if not company_id or not filename:
|
|
24
24
|
raise IAToolkitException(IAToolkitException.ErrorType.PARAM_NOT_FILLED,
|
|
25
|
-
'
|
|
25
|
+
'missing company_id or filename')
|
|
26
26
|
|
|
27
27
|
return self.session.query(Document).filter_by(company_id=company_id, filename=filename).first()
|
|
28
28
|
|
|
@@ -84,7 +84,7 @@ class AuthService:
|
|
|
84
84
|
)
|
|
85
85
|
return {'success': True, 'user_identifier': user_identifier}
|
|
86
86
|
except Exception as e:
|
|
87
|
-
logging.error(f"
|
|
87
|
+
logging.error(f"error creeating session for Token of {user_identifier}: {e}")
|
|
88
88
|
self.log_access(
|
|
89
89
|
company_short_name=company_short_name,
|
|
90
90
|
auth_type='redeem_token',
|
|
@@ -189,5 +189,5 @@ class AuthService:
|
|
|
189
189
|
session.commit()
|
|
190
190
|
|
|
191
191
|
except Exception as e:
|
|
192
|
-
logging.error(f"
|
|
192
|
+
logging.error(f"error writting to AccessLog: {e}", exc_info=False)
|
|
193
193
|
session.rollback()
|
|
@@ -149,7 +149,7 @@ class Dispatcher:
|
|
|
149
149
|
except Exception as e:
|
|
150
150
|
logging.exception(e)
|
|
151
151
|
raise IAToolkitException(IAToolkitException.ErrorType.EXTERNAL_SOURCE_ERROR,
|
|
152
|
-
f"Error
|
|
152
|
+
f"Error getting company context of: {company_name}: {str(e)}") from e
|
|
153
153
|
|
|
154
154
|
def get_company_services(self, company: Company) -> list[dict]:
|
|
155
155
|
# create the syntax with openai response syntax, for the company function list
|
|
@@ -173,7 +173,7 @@ class Dispatcher:
|
|
|
173
173
|
def get_user_info(self, company_name: str, user_identifier: str) -> dict:
|
|
174
174
|
if company_name not in self.company_instances:
|
|
175
175
|
raise IAToolkitException(IAToolkitException.ErrorType.EXTERNAL_SOURCE_ERROR,
|
|
176
|
-
f"
|
|
176
|
+
f"company not configured: {company_name}")
|
|
177
177
|
|
|
178
178
|
# source 2: external company user
|
|
179
179
|
company_instance = self.company_instances[company_name]
|
|
@@ -182,14 +182,14 @@ class Dispatcher:
|
|
|
182
182
|
except Exception as e:
|
|
183
183
|
logging.exception(e)
|
|
184
184
|
raise IAToolkitException(IAToolkitException.ErrorType.EXTERNAL_SOURCE_ERROR,
|
|
185
|
-
f"Error
|
|
185
|
+
f"Error in get_user_info: {company_name}: {str(e)}") from e
|
|
186
186
|
|
|
187
187
|
return external_user_profile
|
|
188
188
|
|
|
189
189
|
def get_metadata_from_filename(self, company_name: str, filename: str) -> dict:
|
|
190
190
|
if company_name not in self.company_instances:
|
|
191
191
|
raise IAToolkitException(IAToolkitException.ErrorType.EXTERNAL_SOURCE_ERROR,
|
|
192
|
-
f"
|
|
192
|
+
f"company not configured: {company_name}")
|
|
193
193
|
|
|
194
194
|
company_instance = self.company_instances[company_name]
|
|
195
195
|
try:
|
|
@@ -197,7 +197,7 @@ class Dispatcher:
|
|
|
197
197
|
except Exception as e:
|
|
198
198
|
logging.exception(e)
|
|
199
199
|
raise IAToolkitException(IAToolkitException.ErrorType.EXTERNAL_SOURCE_ERROR,
|
|
200
|
-
f"Error
|
|
200
|
+
f"Error in get_metadata_from_filename: {company_name}: {str(e)}") from e
|
|
201
201
|
|
|
202
202
|
def get_company_instance(self, company_name: str):
|
|
203
203
|
"""Returns the instance for a given company name."""
|
|
@@ -207,12 +207,11 @@ class Dispatcher:
|
|
|
207
207
|
|
|
208
208
|
# iatoolkit system prompts
|
|
209
209
|
_SYSTEM_PROMPT = [
|
|
210
|
-
{'name': 'query_main', 'description':'main prompt
|
|
211
|
-
{'name': 'format_styles', 'description':'
|
|
212
|
-
{'name': 'sql_rules', 'description':'
|
|
210
|
+
{'name': 'query_main', 'description':'iatoolkit main prompt'},
|
|
211
|
+
{'name': 'format_styles', 'description':'output format styles'},
|
|
212
|
+
{'name': 'sql_rules', 'description':'instructions for SQL queries'}
|
|
213
213
|
]
|
|
214
214
|
|
|
215
|
-
|
|
216
215
|
# iatoolkit function calls
|
|
217
216
|
_FUNCTION_LIST = [
|
|
218
217
|
{
|
|
@@ -11,10 +11,13 @@ import os
|
|
|
11
11
|
import pytesseract
|
|
12
12
|
from injector import inject
|
|
13
13
|
from iatoolkit.common.exceptions import IAToolkitException
|
|
14
|
+
from iatoolkit.services.i18n_service import I18nService
|
|
14
15
|
|
|
15
16
|
class DocumentService:
|
|
16
17
|
@inject
|
|
17
|
-
def __init__(self):
|
|
18
|
+
def __init__(self, i18n_service: I18nService):
|
|
19
|
+
self.i18n_service = i18n_service
|
|
20
|
+
|
|
18
21
|
# max number of pages to load
|
|
19
22
|
self.max_doc_pages = int(os.getenv("MAX_DOC_PAGES", "200"))
|
|
20
23
|
|
|
@@ -29,7 +32,7 @@ class DocumentService:
|
|
|
29
32
|
file_content = file_content.decode('utf-8')
|
|
30
33
|
except UnicodeDecodeError:
|
|
31
34
|
raise IAToolkitException(IAToolkitException.ErrorType.FILE_FORMAT_ERROR,
|
|
32
|
-
|
|
35
|
+
self.i18n_service.t('errors.services.no_text_file'))
|
|
33
36
|
|
|
34
37
|
return file_content
|
|
35
38
|
elif filename.lower().endswith('.pdf'):
|
|
@@ -8,6 +8,7 @@ import pandas as pd
|
|
|
8
8
|
from uuid import uuid4
|
|
9
9
|
from pathlib import Path
|
|
10
10
|
from iatoolkit.common.exceptions import IAToolkitException
|
|
11
|
+
from iatoolkit.services.i18n_service import I18nService
|
|
11
12
|
from injector import inject
|
|
12
13
|
import os
|
|
13
14
|
import logging
|
|
@@ -18,8 +19,11 @@ EXCEL_MIME = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
|
|
|
18
19
|
|
|
19
20
|
class ExcelService:
|
|
20
21
|
@inject
|
|
21
|
-
def __init__(self,
|
|
22
|
+
def __init__(self,
|
|
23
|
+
util: Utility,
|
|
24
|
+
i18n_service: I18nService):
|
|
22
25
|
self.util = util
|
|
26
|
+
self.i18n_service = i18n_service
|
|
23
27
|
|
|
24
28
|
def excel_generator(self, **kwargs) -> str:
|
|
25
29
|
"""
|
|
@@ -42,11 +46,11 @@ class ExcelService:
|
|
|
42
46
|
# get the parameters
|
|
43
47
|
fname = kwargs.get('filename')
|
|
44
48
|
if not fname:
|
|
45
|
-
return '
|
|
49
|
+
return self.i18n_service.t('errors.services.no_output_file')
|
|
46
50
|
|
|
47
51
|
data = kwargs.get('data')
|
|
48
52
|
if not data or not isinstance(data, list):
|
|
49
|
-
return '
|
|
53
|
+
return self.i18n_service.t('errors.services.no_data_for_excel')
|
|
50
54
|
|
|
51
55
|
sheet_name = kwargs.get('sheet_name', 'hoja 1')
|
|
52
56
|
|
|
@@ -58,7 +62,7 @@ class ExcelService:
|
|
|
58
62
|
|
|
59
63
|
# 4. check that download directory is configured
|
|
60
64
|
if 'IATOOLKIT_DOWNLOAD_DIR' not in current_app.config:
|
|
61
|
-
return '
|
|
65
|
+
return self.i18n_service.t('errors.services.no_download_directory')
|
|
62
66
|
|
|
63
67
|
download_dir = current_app.config['IATOOLKIT_DOWNLOAD_DIR']
|
|
64
68
|
filepath = Path(download_dir) / token
|
|
@@ -77,28 +81,28 @@ class ExcelService:
|
|
|
77
81
|
|
|
78
82
|
except Exception as e:
|
|
79
83
|
raise IAToolkitException(IAToolkitException.ErrorType.CALL_ERROR,
|
|
80
|
-
'
|
|
84
|
+
self.i18n_service.t('errors.services.cannot_create_excel')) from e
|
|
81
85
|
|
|
82
86
|
def validate_file_access(self, filename):
|
|
83
87
|
try:
|
|
84
88
|
if not filename:
|
|
85
|
-
return jsonify({"error":
|
|
89
|
+
return jsonify({"error": self.i18n_service.t('errors.services.invalid_filename')})
|
|
86
90
|
# Prevent path traversal attacks
|
|
87
91
|
if '..' in filename or filename.startswith('/') or '\\' in filename:
|
|
88
|
-
return jsonify({"error":
|
|
92
|
+
return jsonify({"error": self.i18n_service.t('errors.services.invalid_filename')})
|
|
89
93
|
|
|
90
94
|
temp_dir = os.path.join(current_app.root_path, 'static', 'temp')
|
|
91
95
|
file_path = os.path.join(temp_dir, filename)
|
|
92
96
|
|
|
93
97
|
if not os.path.exists(file_path):
|
|
94
|
-
return jsonify({"error":
|
|
98
|
+
return jsonify({"error": self.i18n_service.t('errors.services.file_not_exist')})
|
|
95
99
|
|
|
96
100
|
if not os.path.isfile(file_path):
|
|
97
|
-
return jsonify({"error":
|
|
101
|
+
return jsonify({"error": self.i18n_service.t('errors.services.path_is_not_a_file')})
|
|
98
102
|
|
|
99
103
|
return None
|
|
100
104
|
|
|
101
105
|
except Exception as e:
|
|
102
|
-
error_msg = f"
|
|
106
|
+
error_msg = f"File validation error {filename}: {str(e)}"
|
|
103
107
|
logging.error(error_msg)
|
|
104
|
-
return jsonify({"error":
|
|
108
|
+
return jsonify({"error": self.i18n_service.t('errors.services.file_validation_error')})
|
|
@@ -52,27 +52,19 @@ class FileProcessor:
|
|
|
52
52
|
logger: Optional[logging.Logger] = None):
|
|
53
53
|
self.connector = connector
|
|
54
54
|
self.config = config
|
|
55
|
-
self.logger = logger or self._setup_logger()
|
|
56
55
|
self.processed_files = 0
|
|
57
56
|
|
|
58
|
-
def _setup_logger(self):
|
|
59
|
-
logging.basicConfig(
|
|
60
|
-
filename=self.config.log_file,
|
|
61
|
-
level=logging.INFO,
|
|
62
|
-
format='%(asctime)s - %(levelname)s - %(message)s'
|
|
63
|
-
)
|
|
64
|
-
return logging.getLogger(__name__)
|
|
65
57
|
|
|
66
58
|
def process_files(self):
|
|
67
59
|
# Fetches files from the connector, filters them, and processes them.
|
|
68
60
|
try:
|
|
69
61
|
files = self.connector.list_files()
|
|
70
62
|
except Exception as e:
|
|
71
|
-
|
|
63
|
+
logging.error(f"Error fetching files: {e}")
|
|
72
64
|
return False
|
|
73
65
|
|
|
74
66
|
if self.config.echo:
|
|
75
|
-
print(f'
|
|
67
|
+
print(f'loading {len(files)} files')
|
|
76
68
|
|
|
77
69
|
for file_info in files:
|
|
78
70
|
file_path = file_info['path']
|
|
@@ -95,10 +87,10 @@ class FileProcessor:
|
|
|
95
87
|
context=self.config.context)
|
|
96
88
|
self.processed_files += 1
|
|
97
89
|
|
|
98
|
-
|
|
90
|
+
logging.info(f"Successfully processed file: {file_path}")
|
|
99
91
|
|
|
100
92
|
except Exception as e:
|
|
101
|
-
|
|
93
|
+
logging.error(f"Error processing {file_path}: {e}")
|
|
102
94
|
if not self.config.continue_on_error:
|
|
103
95
|
raise e
|
|
104
96
|
|
|
@@ -27,4 +27,4 @@ class HelpContentService:
|
|
|
27
27
|
except Exception as e:
|
|
28
28
|
logging.exception(e)
|
|
29
29
|
raise IAToolkitException(IAToolkitException.ErrorType.CONFIG_ERROR,
|
|
30
|
-
f"Error
|
|
30
|
+
f"Error getting help file for {company_short_name}: {str(e)}") from e
|
|
@@ -6,32 +6,33 @@
|
|
|
6
6
|
from injector import inject
|
|
7
7
|
from iatoolkit.repositories.llm_query_repo import LLMQueryRepo
|
|
8
8
|
from iatoolkit.repositories.profile_repo import ProfileRepo
|
|
9
|
+
from iatoolkit.services.i18n_service import I18nService
|
|
10
|
+
|
|
9
11
|
|
|
10
12
|
|
|
11
13
|
class HistoryService:
|
|
12
14
|
@inject
|
|
13
15
|
def __init__(self, llm_query_repo: LLMQueryRepo,
|
|
14
|
-
profile_repo: ProfileRepo
|
|
16
|
+
profile_repo: ProfileRepo,
|
|
17
|
+
i18n_service: I18nService):
|
|
15
18
|
self.llm_query_repo = llm_query_repo
|
|
16
19
|
self.profile_repo = profile_repo
|
|
20
|
+
self.i18n_service = i18n_service
|
|
17
21
|
|
|
18
22
|
def get_history(self,
|
|
19
23
|
company_short_name: str,
|
|
20
24
|
user_identifier: str) -> dict:
|
|
21
25
|
try:
|
|
22
|
-
# validate company
|
|
23
26
|
company = self.profile_repo.get_company_by_short_name(company_short_name)
|
|
24
27
|
if not company:
|
|
25
|
-
return {
|
|
28
|
+
return {"error": self.i18n_service.t('errors.company_not_found', company_short_name=company_short_name)}
|
|
26
29
|
|
|
27
30
|
history = self.llm_query_repo.get_history(company, user_identifier)
|
|
28
|
-
|
|
29
31
|
if not history:
|
|
30
|
-
return {'message': '
|
|
32
|
+
return {'message': 'empty history', 'history': []}
|
|
31
33
|
|
|
32
34
|
history_list = [query.to_dict() for query in history]
|
|
33
|
-
|
|
34
|
-
return {'message': 'Historial obtenido correctamente', 'history': history_list}
|
|
35
|
+
return {'message': 'history loaded ok', 'history': history_list}
|
|
35
36
|
|
|
36
37
|
except Exception as e:
|
|
37
38
|
return {'error': str(e)}
|
|
@@ -27,7 +27,7 @@ class I18nService:
|
|
|
27
27
|
"""
|
|
28
28
|
locales_dir = os.path.join(os.path.dirname(__file__), '..', 'locales')
|
|
29
29
|
if not os.path.exists(locales_dir):
|
|
30
|
-
logging.error("
|
|
30
|
+
logging.error("Directory 'locales' not found.")
|
|
31
31
|
return
|
|
32
32
|
|
|
33
33
|
for filename in os.listdir(locales_dir):
|
|
@@ -37,7 +37,7 @@ class I18nService:
|
|
|
37
37
|
try:
|
|
38
38
|
self.translations[lang_code] = self.util.load_schema_from_yaml(filepath)
|
|
39
39
|
except Exception as e:
|
|
40
|
-
logging.error(f"
|
|
40
|
+
logging.error(f"Error while loading the translation file {filepath}: {e}")
|
|
41
41
|
|
|
42
42
|
def _get_nested_key(self, lang: str, key: str):
|
|
43
43
|
"""
|
|
@@ -20,8 +20,8 @@ class JWTService:
|
|
|
20
20
|
self.secret_key = app.config['JWT_SECRET_KEY']
|
|
21
21
|
self.algorithm = app.config['JWT_ALGORITHM']
|
|
22
22
|
except KeyError as e:
|
|
23
|
-
logging.error(f"
|
|
24
|
-
raise RuntimeError(f"
|
|
23
|
+
logging.error(f"missing JWT configuration: {e}.")
|
|
24
|
+
raise RuntimeError(f"missing JWT configuration variables: {e}")
|
|
25
25
|
|
|
26
26
|
def generate_chat_jwt(self,
|
|
27
27
|
company_short_name: str,
|
|
@@ -58,25 +58,23 @@ class JWTService:
|
|
|
58
58
|
|
|
59
59
|
# Validaciones adicionales
|
|
60
60
|
if payload.get('type') != 'chat_session':
|
|
61
|
-
logging.warning(f"
|
|
61
|
+
logging.warning(f"Invalid JWT type '{payload.get('type')}'")
|
|
62
62
|
return None
|
|
63
63
|
|
|
64
64
|
# user_identifier debe estar presente
|
|
65
65
|
if not payload.get('user_identifier'):
|
|
66
|
-
logging.warning(f"
|
|
66
|
+
logging.warning(f"missing user_identifier in JWT payload.")
|
|
67
67
|
return None
|
|
68
68
|
|
|
69
69
|
if not payload.get('company_short_name'):
|
|
70
|
-
logging.warning(f"
|
|
70
|
+
logging.warning(f"missing company_short_name in JWT payload.")
|
|
71
71
|
return None
|
|
72
72
|
|
|
73
|
-
logging.debug(
|
|
74
|
-
f"JWT validado exitosamente para company: {payload.get('company_short_name')}, user: {payload.get('external_user_id')}")
|
|
75
73
|
return payload
|
|
76
74
|
|
|
77
75
|
except jwt.InvalidTokenError as e:
|
|
78
|
-
logging.warning(f"
|
|
76
|
+
logging.warning(f"Invalid JWT token:: {e}")
|
|
79
77
|
return None
|
|
80
78
|
except Exception as e:
|
|
81
|
-
logging.error(f"
|
|
79
|
+
logging.error(f"unexpected error during JWT validation: {e}")
|
|
82
80
|
return None
|
|
@@ -72,7 +72,7 @@ class LoadDocumentsService:
|
|
|
72
72
|
"""
|
|
73
73
|
if not connector_config:
|
|
74
74
|
raise IAToolkitException(IAToolkitException.ErrorType.MISSING_PARAMETER,
|
|
75
|
-
f"
|
|
75
|
+
f"Missing connector config")
|
|
76
76
|
|
|
77
77
|
try:
|
|
78
78
|
if not filters:
|
|
@@ -123,7 +123,7 @@ class LoadDocumentsService:
|
|
|
123
123
|
|
|
124
124
|
if not company:
|
|
125
125
|
raise IAToolkitException(IAToolkitException.ErrorType.MISSING_PARAMETER,
|
|
126
|
-
f"
|
|
126
|
+
f"missing company")
|
|
127
127
|
|
|
128
128
|
# check if file exist in repositories
|
|
129
129
|
if self.doc_repo.get(company_id=company.id,filename=filename):
|
|
@@ -182,6 +182,6 @@ class LoadDocumentsService:
|
|
|
182
182
|
self.doc_repo.session.rollback()
|
|
183
183
|
|
|
184
184
|
# if something fails, throw exception
|
|
185
|
-
logging.exception("Error
|
|
185
|
+
logging.exception("Error processing file %s: %s", filename, str(e))
|
|
186
186
|
raise IAToolkitException(IAToolkitException.ErrorType.LOAD_DOCUMENT_ERROR,
|
|
187
|
-
f"Error
|
|
187
|
+
f"Error while processing file: {filename}")
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
# IAToolkit is open source software.
|
|
5
5
|
|
|
6
6
|
from iatoolkit.infra.mail_app import MailApp
|
|
7
|
+
from iatoolkit.services.i18n_service import I18nService
|
|
7
8
|
from injector import inject
|
|
8
9
|
from pathlib import Path
|
|
9
10
|
from iatoolkit.common.exceptions import IAToolkitException
|
|
@@ -13,18 +14,22 @@ TEMP_DIR = Path("static/temp")
|
|
|
13
14
|
|
|
14
15
|
class MailService:
|
|
15
16
|
@inject
|
|
16
|
-
def __init__(self,
|
|
17
|
+
def __init__(self,
|
|
18
|
+
mail_app: MailApp,
|
|
19
|
+
i18n_service: I18nService):
|
|
17
20
|
self.mail_app = mail_app
|
|
21
|
+
self.i18n_service = i18n_service
|
|
22
|
+
|
|
18
23
|
|
|
19
24
|
def _read_token_bytes(self, token: str) -> bytes:
|
|
20
25
|
# Defensa simple contra path traversal
|
|
21
26
|
if not token or "/" in token or "\\" in token or token.startswith("."):
|
|
22
27
|
raise IAToolkitException(IAToolkitException.ErrorType.MAIL_ERROR,
|
|
23
|
-
"attachment_token
|
|
28
|
+
"attachment_token invalid")
|
|
24
29
|
path = TEMP_DIR / token
|
|
25
30
|
if not path.is_file():
|
|
26
31
|
raise IAToolkitException(IAToolkitException.ErrorType.MAIL_ERROR,
|
|
27
|
-
f"
|
|
32
|
+
f"attach file not found: {token}")
|
|
28
33
|
return path.read_bytes()
|
|
29
34
|
|
|
30
35
|
def send_mail(self, **kwargs):
|
|
@@ -59,4 +64,4 @@ class MailService:
|
|
|
59
64
|
body=body,
|
|
60
65
|
attachments=norm_attachments)
|
|
61
66
|
|
|
62
|
-
return '
|
|
67
|
+
return self.i18n_service.t('services.mail_sent')
|
|
@@ -49,15 +49,15 @@ class ProfileService:
|
|
|
49
49
|
|
|
50
50
|
company = self.profile_repo.get_company_by_short_name(company_short_name)
|
|
51
51
|
if not company:
|
|
52
|
-
return {'success': False, "message": "
|
|
52
|
+
return {'success': False, "message": "missing company"}
|
|
53
53
|
|
|
54
54
|
# check that user belongs to company
|
|
55
55
|
if company not in user.companies:
|
|
56
|
-
return {'success': False, "message":
|
|
56
|
+
return {'success': False, "message": self.i18n_service.t('errors.services.user_not_authorized')}
|
|
57
57
|
|
|
58
58
|
if not user.verified:
|
|
59
59
|
return {'success': False,
|
|
60
|
-
"message":
|
|
60
|
+
"message": self.i18n_service.t('errors.services.account_not_verified')}
|
|
61
61
|
|
|
62
62
|
# 1. Build the local user profile dictionary here.
|
|
63
63
|
# the user_profile variables are used on the LLM templates also (see in query_main.prompt)
|
|
@@ -74,7 +74,7 @@ class ProfileService:
|
|
|
74
74
|
|
|
75
75
|
# 3. create the web session
|
|
76
76
|
self.set_session_for_user(company.short_name, user_identifier)
|
|
77
|
-
return {'success': True, "user_identifier": user_identifier, "message": "Login
|
|
77
|
+
return {'success': True, "user_identifier": user_identifier, "message": "Login ok"}
|
|
78
78
|
except Exception as e:
|
|
79
79
|
logging.error(f"Error in login: {e}")
|
|
80
80
|
return {'success': False, "message": str(e)}
|
|
@@ -324,7 +324,7 @@ class ProfileService:
|
|
|
324
324
|
def new_api_key(self, company_short_name: str):
|
|
325
325
|
company = self.get_company_by_short_name(company_short_name)
|
|
326
326
|
if not company:
|
|
327
|
-
return {"error":
|
|
327
|
+
return {"error": self.i18n_service.t('errors.company_not_found', company_short_name=company_short_name)}
|
|
328
328
|
|
|
329
329
|
length = 40 # lenght of the api key
|
|
330
330
|
alphabet = string.ascii_letters + string.digits
|