iatoolkit 0.3.9__py3-none-any.whl → 0.107.4__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 +27 -35
- iatoolkit/base_company.py +3 -35
- iatoolkit/cli_commands.py +18 -47
- iatoolkit/common/__init__.py +0 -0
- iatoolkit/common/exceptions.py +48 -0
- iatoolkit/common/interfaces/__init__.py +0 -0
- iatoolkit/common/interfaces/asset_storage.py +34 -0
- iatoolkit/common/interfaces/database_provider.py +39 -0
- iatoolkit/common/model_registry.py +159 -0
- iatoolkit/common/routes.py +138 -0
- iatoolkit/common/session_manager.py +26 -0
- iatoolkit/common/util.py +353 -0
- iatoolkit/company_registry.py +66 -29
- iatoolkit/core.py +514 -0
- iatoolkit/infra/__init__.py +5 -0
- iatoolkit/infra/brevo_mail_app.py +123 -0
- iatoolkit/infra/call_service.py +140 -0
- iatoolkit/infra/connectors/__init__.py +5 -0
- iatoolkit/infra/connectors/file_connector.py +17 -0
- iatoolkit/infra/connectors/file_connector_factory.py +57 -0
- iatoolkit/infra/connectors/google_cloud_storage_connector.py +53 -0
- iatoolkit/infra/connectors/google_drive_connector.py +68 -0
- iatoolkit/infra/connectors/local_file_connector.py +46 -0
- iatoolkit/infra/connectors/s3_connector.py +33 -0
- iatoolkit/infra/google_chat_app.py +57 -0
- iatoolkit/infra/llm_providers/__init__.py +0 -0
- iatoolkit/infra/llm_providers/deepseek_adapter.py +278 -0
- iatoolkit/infra/llm_providers/gemini_adapter.py +350 -0
- iatoolkit/infra/llm_providers/openai_adapter.py +124 -0
- iatoolkit/infra/llm_proxy.py +268 -0
- iatoolkit/infra/llm_response.py +45 -0
- iatoolkit/infra/redis_session_manager.py +122 -0
- iatoolkit/locales/en.yaml +222 -0
- iatoolkit/locales/es.yaml +225 -0
- iatoolkit/repositories/__init__.py +5 -0
- iatoolkit/repositories/database_manager.py +187 -0
- iatoolkit/repositories/document_repo.py +33 -0
- iatoolkit/repositories/filesystem_asset_repository.py +36 -0
- iatoolkit/repositories/llm_query_repo.py +105 -0
- iatoolkit/repositories/models.py +279 -0
- iatoolkit/repositories/profile_repo.py +171 -0
- iatoolkit/repositories/vs_repo.py +150 -0
- iatoolkit/services/__init__.py +5 -0
- iatoolkit/services/auth_service.py +193 -0
- {services → iatoolkit/services}/benchmark_service.py +7 -7
- iatoolkit/services/branding_service.py +153 -0
- iatoolkit/services/company_context_service.py +214 -0
- iatoolkit/services/configuration_service.py +375 -0
- iatoolkit/services/dispatcher_service.py +134 -0
- {services → iatoolkit/services}/document_service.py +20 -8
- iatoolkit/services/embedding_service.py +148 -0
- iatoolkit/services/excel_service.py +156 -0
- {services → iatoolkit/services}/file_processor_service.py +36 -21
- iatoolkit/services/history_manager_service.py +208 -0
- iatoolkit/services/i18n_service.py +104 -0
- iatoolkit/services/jwt_service.py +80 -0
- iatoolkit/services/language_service.py +89 -0
- iatoolkit/services/license_service.py +82 -0
- iatoolkit/services/llm_client_service.py +438 -0
- iatoolkit/services/load_documents_service.py +174 -0
- iatoolkit/services/mail_service.py +213 -0
- {services → iatoolkit/services}/profile_service.py +200 -101
- iatoolkit/services/prompt_service.py +303 -0
- iatoolkit/services/query_service.py +467 -0
- iatoolkit/services/search_service.py +55 -0
- iatoolkit/services/sql_service.py +169 -0
- iatoolkit/services/tool_service.py +246 -0
- iatoolkit/services/user_feedback_service.py +117 -0
- iatoolkit/services/user_session_context_service.py +213 -0
- iatoolkit/static/images/fernando.jpeg +0 -0
- iatoolkit/static/images/iatoolkit_core.png +0 -0
- iatoolkit/static/images/iatoolkit_logo.png +0 -0
- iatoolkit/static/js/chat_feedback_button.js +80 -0
- iatoolkit/static/js/chat_filepond.js +85 -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 +401 -0
- iatoolkit/static/js/chat_model_selector.js +227 -0
- iatoolkit/static/js/chat_onboarding_button.js +103 -0
- iatoolkit/static/js/chat_prompt_manager.js +94 -0
- iatoolkit/static/js/chat_reload_button.js +38 -0
- iatoolkit/static/styles/chat_iatoolkit.css +559 -0
- iatoolkit/static/styles/chat_modal.css +133 -0
- iatoolkit/static/styles/chat_public.css +135 -0
- iatoolkit/static/styles/documents.css +598 -0
- iatoolkit/static/styles/landing_page.css +398 -0
- iatoolkit/static/styles/llm_output.css +148 -0
- iatoolkit/static/styles/onboarding.css +176 -0
- iatoolkit/system_prompts/__init__.py +0 -0
- iatoolkit/system_prompts/query_main.prompt +30 -23
- iatoolkit/system_prompts/sql_rules.prompt +47 -12
- iatoolkit/templates/_company_header.html +45 -0
- iatoolkit/templates/_login_widget.html +42 -0
- iatoolkit/templates/base.html +78 -0
- iatoolkit/templates/change_password.html +66 -0
- iatoolkit/templates/chat.html +337 -0
- iatoolkit/templates/chat_modals.html +185 -0
- iatoolkit/templates/error.html +51 -0
- iatoolkit/templates/forgot_password.html +51 -0
- iatoolkit/templates/onboarding_shell.html +106 -0
- iatoolkit/templates/signup.html +79 -0
- iatoolkit/views/__init__.py +5 -0
- iatoolkit/views/base_login_view.py +96 -0
- iatoolkit/views/change_password_view.py +116 -0
- iatoolkit/views/chat_view.py +76 -0
- iatoolkit/views/embedding_api_view.py +65 -0
- iatoolkit/views/forgot_password_view.py +75 -0
- iatoolkit/views/help_content_api_view.py +54 -0
- iatoolkit/views/history_api_view.py +56 -0
- iatoolkit/views/home_view.py +63 -0
- iatoolkit/views/init_context_api_view.py +74 -0
- iatoolkit/views/llmquery_api_view.py +59 -0
- iatoolkit/views/load_company_configuration_api_view.py +49 -0
- iatoolkit/views/load_document_api_view.py +65 -0
- iatoolkit/views/login_view.py +170 -0
- iatoolkit/views/logout_api_view.py +57 -0
- iatoolkit/views/profile_api_view.py +46 -0
- iatoolkit/views/prompt_api_view.py +37 -0
- iatoolkit/views/root_redirect_view.py +22 -0
- iatoolkit/views/signup_view.py +100 -0
- iatoolkit/views/static_page_view.py +27 -0
- iatoolkit/views/user_feedback_api_view.py +60 -0
- iatoolkit/views/users_api_view.py +33 -0
- iatoolkit/views/verify_user_view.py +60 -0
- iatoolkit-0.107.4.dist-info/METADATA +268 -0
- iatoolkit-0.107.4.dist-info/RECORD +132 -0
- iatoolkit-0.107.4.dist-info/licenses/LICENSE +21 -0
- iatoolkit-0.107.4.dist-info/licenses/LICENSE_COMMUNITY.md +15 -0
- {iatoolkit-0.3.9.dist-info → iatoolkit-0.107.4.dist-info}/top_level.txt +0 -1
- iatoolkit/iatoolkit.py +0 -413
- iatoolkit/system_prompts/arquitectura.prompt +0 -32
- iatoolkit-0.3.9.dist-info/METADATA +0 -252
- iatoolkit-0.3.9.dist-info/RECORD +0 -32
- services/__init__.py +0 -5
- services/api_service.py +0 -75
- services/dispatcher_service.py +0 -351
- services/excel_service.py +0 -98
- services/history_service.py +0 -45
- services/jwt_service.py +0 -91
- services/load_documents_service.py +0 -212
- services/mail_service.py +0 -62
- services/prompt_manager_service.py +0 -172
- services/query_service.py +0 -334
- services/search_service.py +0 -32
- services/sql_service.py +0 -42
- services/tasks_service.py +0 -188
- services/user_feedback_service.py +0 -67
- services/user_session_context_service.py +0 -85
- {iatoolkit-0.3.9.dist-info → iatoolkit-0.107.4.dist-info}/WHEEL +0 -0
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
# Language: English
|
|
2
|
+
ui:
|
|
3
|
+
login_widget:
|
|
4
|
+
title: "Sign In"
|
|
5
|
+
welcome_message: "Enter your credentials or register to access this platform."
|
|
6
|
+
email_placeholder: "Email address"
|
|
7
|
+
password_placeholder: "Password"
|
|
8
|
+
login_button: "Login"
|
|
9
|
+
forgot_password_link: "Forgot your password?"
|
|
10
|
+
no_account_prompt: "Don't have an account?"
|
|
11
|
+
signup_link: "Sign Up"
|
|
12
|
+
|
|
13
|
+
signup:
|
|
14
|
+
title: "Create an Account"
|
|
15
|
+
subtitle: "Start your journey with us today."
|
|
16
|
+
first_name_label: "First Name"
|
|
17
|
+
last_name_label: "Last Name"
|
|
18
|
+
email_label: "Email Address"
|
|
19
|
+
password_label: "Password"
|
|
20
|
+
confirm_password_label: "Confirm Password"
|
|
21
|
+
signup_button: "Create Account"
|
|
22
|
+
already_have_account: "Already have an account?"
|
|
23
|
+
login_link: "Log In"
|
|
24
|
+
disclaimer: "🔒We value your privacy. Your data will be used exclusively for the operation of the platform."
|
|
25
|
+
|
|
26
|
+
forgot_password:
|
|
27
|
+
title: "Recover Password"
|
|
28
|
+
subtitle: "Enter your email address and we will send you a link to reset your password."
|
|
29
|
+
submit_button: "Send Recovery Link"
|
|
30
|
+
back_to_login: "Back to Login"
|
|
31
|
+
|
|
32
|
+
change_password:
|
|
33
|
+
title: "Create New Password"
|
|
34
|
+
subtitle: "You are changing the password for <strong>{email}</strong>."
|
|
35
|
+
temp_code_label: "Temporary Code"
|
|
36
|
+
temp_code_placeholder: "Check your email"
|
|
37
|
+
new_password_label: "New Password"
|
|
38
|
+
password_instructions: "Must contain at least 8 characters, an uppercase letter, a lowercase letter, a number, and a special character."
|
|
39
|
+
confirm_password_label: "Confirm New Password"
|
|
40
|
+
save_button: "Save Password"
|
|
41
|
+
back_to_home: "Back to home"
|
|
42
|
+
|
|
43
|
+
chat:
|
|
44
|
+
welcome_message: "Hello! How can I help you today?"
|
|
45
|
+
input_placeholder: "Type here..."
|
|
46
|
+
prompts_available: "Available prompts"
|
|
47
|
+
init_context: "Initializing the context ..."
|
|
48
|
+
|
|
49
|
+
admin:
|
|
50
|
+
resources: "Resources"
|
|
51
|
+
configuration: "Configuration"
|
|
52
|
+
prompts: "Prompts"
|
|
53
|
+
schemas: "Schemas"
|
|
54
|
+
context: "Context"
|
|
55
|
+
files: "Files"
|
|
56
|
+
users: "Users"
|
|
57
|
+
select_file: "Select a file for editing"
|
|
58
|
+
select_category: "Select a category"
|
|
59
|
+
editing: "Editing"
|
|
60
|
+
no_file_selected: "No file selected"
|
|
61
|
+
new: "New"
|
|
62
|
+
confirm: "Confirm"
|
|
63
|
+
cancel: "Cancel"
|
|
64
|
+
new_file: "New file"
|
|
65
|
+
delete_file: "Delete file"
|
|
66
|
+
save_file: "Save"
|
|
67
|
+
credentials: "Email and password required for login."
|
|
68
|
+
saved_ok: "Saved successfully"
|
|
69
|
+
deleted_ok: "Deleted successfully"
|
|
70
|
+
user_manager: "User management"
|
|
71
|
+
admin_page_title: "Admin access"
|
|
72
|
+
load_configuration: "Save configuration"
|
|
73
|
+
goto_chat: "Go to chat"
|
|
74
|
+
logout: "Close session"
|
|
75
|
+
|
|
76
|
+
tooltips:
|
|
77
|
+
history: "History of my queries"
|
|
78
|
+
reload_context: "Force Context Reload"
|
|
79
|
+
feedback: "Your feedback is very important"
|
|
80
|
+
usage_guide: "Usage Guide"
|
|
81
|
+
onboarding: "How to ask better questions"
|
|
82
|
+
logout: "Log out"
|
|
83
|
+
preferences: "Preferences"
|
|
84
|
+
use_prompt_assistant: "Use Prompt Assistant"
|
|
85
|
+
attach_files: "Attach files"
|
|
86
|
+
view_attached_files: "View attached files"
|
|
87
|
+
send: "Send"
|
|
88
|
+
stop: "Stop"
|
|
89
|
+
|
|
90
|
+
modals:
|
|
91
|
+
files_title: "Uploaded Files"
|
|
92
|
+
feedback_title: "Your Opinion is Important"
|
|
93
|
+
feedback_prompt: "How useful was the assistant's response?"
|
|
94
|
+
feedback_comment_label: "Your feedback helps us improve:"
|
|
95
|
+
feedback_comment_placeholder: "Write your opinion, suggestions, or comments here..."
|
|
96
|
+
history_title: "Query History"
|
|
97
|
+
history_table_date: "Date"
|
|
98
|
+
history_table_query: "Query"
|
|
99
|
+
loading_history: "Loading history..."
|
|
100
|
+
no_history_found: "No query history found."
|
|
101
|
+
help_title: "AI Assistant User Guide"
|
|
102
|
+
|
|
103
|
+
buttons:
|
|
104
|
+
cancel: "Close"
|
|
105
|
+
send: "Send"
|
|
106
|
+
stop: "Stop"
|
|
107
|
+
|
|
108
|
+
errors:
|
|
109
|
+
company_not_found: "The company {company_short_name} does not exist."
|
|
110
|
+
timeout: "timeout expired."
|
|
111
|
+
auth:
|
|
112
|
+
invalid_password: "The provided password is incorrect."
|
|
113
|
+
user_not_found: "A user with that email address was not found."
|
|
114
|
+
invalid_or_expired_token: "Invalid or expired token."
|
|
115
|
+
session_creation_failed: "Could not create user session."
|
|
116
|
+
authentication_required: "Authentication required. No session cookie or API Key provided."
|
|
117
|
+
invalid_api_key: "Invalid or inactive API Key."
|
|
118
|
+
no_user_identifier_api: "No user_identifier provided for API call."
|
|
119
|
+
no_company_permissions: "Do not have permissions to admin this company."
|
|
120
|
+
templates:
|
|
121
|
+
company_not_found: "Company not found."
|
|
122
|
+
home_template_not_found: "The home page template for the company '{company_short_name}' is not configured."
|
|
123
|
+
template_not_found: "Template not found: '{template_name}'."
|
|
124
|
+
processing_error: "An error occurred while processing the custom home page template: {error}"
|
|
125
|
+
general:
|
|
126
|
+
unexpected_error: "An unexpected error has occurred. Please contact support."
|
|
127
|
+
unsupported_language: "The selected language is not supported."
|
|
128
|
+
signup:
|
|
129
|
+
company_not_found: "The company {company_short_name} does not exist."
|
|
130
|
+
incorrect_password_for_existing_user: "The password for the user {email} is incorrect."
|
|
131
|
+
user_already_registered: "The user with email '{email}' already exists in this company."
|
|
132
|
+
password_mismatch: "The passwords do not match. Please try again."
|
|
133
|
+
change_password:
|
|
134
|
+
token_expired: "The password change link has expired. Please request a new one."
|
|
135
|
+
password_mismatch: "The passwords do not match. Please try again."
|
|
136
|
+
invalid_temp_code: "The temporary code is not valid. Please check it or request a new one."
|
|
137
|
+
forgot_password:
|
|
138
|
+
user_not_registered: "The user with email {email} is not registered."
|
|
139
|
+
verification:
|
|
140
|
+
token_expired: "The verification link has expired. Please contact support if you need a new one."
|
|
141
|
+
user_not_found: "The user you are trying to verify does not exist."
|
|
142
|
+
validation:
|
|
143
|
+
password_too_short: "Password must be at least 8 characters long."
|
|
144
|
+
password_no_uppercase: "Password must contain at least one uppercase letter."
|
|
145
|
+
password_no_lowercase: "Password must contain at least one lowercase letter."
|
|
146
|
+
password_no_digit: "Password must contain at least one number."
|
|
147
|
+
password_no_special_char: "Password must contain at least one special character."
|
|
148
|
+
|
|
149
|
+
services:
|
|
150
|
+
no_text_file: "The file is not text or the encoding is not UTF-8"
|
|
151
|
+
no_output_file: "Missing output file name"
|
|
152
|
+
no_data_for_excel: "Missing data or it is not a list of dictionaries"
|
|
153
|
+
no_download_directory: "Temporary directory for saving Excel files is not configured"
|
|
154
|
+
cannot_create_excel: "Could not create the Excel file"
|
|
155
|
+
invalid_filename: "Invalid filename"
|
|
156
|
+
file_not_exist: "File not found"
|
|
157
|
+
path_is_not_a_file: "The path does not correspond to a file"
|
|
158
|
+
file_validation_error: "Error validating file"
|
|
159
|
+
user_not_authorized: "user is not authorized for this company"
|
|
160
|
+
account_not_verified: "Your account has not been verified. Please check your email."
|
|
161
|
+
missing_response_id: "Can not found 'previous_response_id' for '{company_short_name}/{user_identifier}'. Reinit context"
|
|
162
|
+
context_rebuild_failed: "Company context rebuild failed."
|
|
163
|
+
cannot_read_excel: "Cannot read Excel file"
|
|
164
|
+
cannot_read_csv: "Cannot read CSV file"
|
|
165
|
+
|
|
166
|
+
api_responses:
|
|
167
|
+
context_reloaded_success: "The context has been successfully reloaded."
|
|
168
|
+
|
|
169
|
+
services:
|
|
170
|
+
mail_sent: "Email sent successfully."
|
|
171
|
+
start_query: "Hello, what can I help you with today?"
|
|
172
|
+
mail_change_password: "mail sent for password change"
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
flash_messages:
|
|
176
|
+
password_changed_success: "Your password has been successfully reset. You can now log in."
|
|
177
|
+
login_required: "Please log in to continue."
|
|
178
|
+
signup_success: "Registration successful. Please check your email to verify your account."
|
|
179
|
+
signup_success_no_verification: "Registration successful."
|
|
180
|
+
user_associated_success: "Existing user successfully associated with the new company."
|
|
181
|
+
account_verified_success: "Your account has been successfully verified. Welcome!"
|
|
182
|
+
forgot_password_success: "If your email is registered, you will receive a link to reset your password."
|
|
183
|
+
|
|
184
|
+
# Keys specifically for JavaScript
|
|
185
|
+
js_messages:
|
|
186
|
+
feedback_sent_success_title: "Feedback Sent"
|
|
187
|
+
feedback_sent_success_body: "Thank you for your feedback!"
|
|
188
|
+
feedback_sent_error: "Could not send feedback, please try again."
|
|
189
|
+
feedback_rating_error: "Please rate the assistant using the stars."
|
|
190
|
+
feedback_comment_error: "Please write your comment before sending."
|
|
191
|
+
context_reloaded: "Context has been reloaded."
|
|
192
|
+
error_loading_history: "An error occurred while loading the history."
|
|
193
|
+
request_aborted: "The response generation has been stopped."
|
|
194
|
+
processing_error: "An error occurred while processing the request."
|
|
195
|
+
server_comm_error: "Server communication error ({status}). Please try again later."
|
|
196
|
+
network_error: "A network error occurred. Please try again in a few moments."
|
|
197
|
+
unknown_server_error: "Unknown server error."
|
|
198
|
+
loading: "Loading..."
|
|
199
|
+
reload_init: "init reloading context in background..."
|
|
200
|
+
no_history_found: "No query history found."
|
|
201
|
+
example: "Example:"
|
|
202
|
+
show_reasoning: "Show reasoning"
|
|
203
|
+
unsaved: "Modified (unsaved)"
|
|
204
|
+
select_file: "Select a file from the list"
|
|
205
|
+
no_file_selected: "No file selected"
|
|
206
|
+
select_company: "Select company"
|
|
207
|
+
delete_ok: "File deleted successfully"
|
|
208
|
+
not_saved: 'Could not save'
|
|
209
|
+
saved_ok: "Saved successfully"
|
|
210
|
+
invalid_file_name: "Invalid filename. Use only letters, numbers, underscores, hyphens, and dots."
|
|
211
|
+
config_loaded: "Configuration loaded successfully."
|
|
212
|
+
config_load_error: "Error loading configuration."
|
|
213
|
+
search_placeholder: "Search users..."
|
|
214
|
+
showing: "Showing"
|
|
215
|
+
records: "Records"
|
|
216
|
+
db_user: "User"
|
|
217
|
+
db_role: "Role"
|
|
218
|
+
db_verified: "Verified"
|
|
219
|
+
db_created: "Created"
|
|
220
|
+
db_last_access: "Last access"
|
|
221
|
+
|
|
222
|
+
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
# locales/es.yaml
|
|
2
|
+
ui:
|
|
3
|
+
login_widget:
|
|
4
|
+
title: "Iniciar Sesión"
|
|
5
|
+
welcome_message: "Ingresa tus credenciales o registrate para acceder a la plataforma."
|
|
6
|
+
email_placeholder: "Correo electrónico"
|
|
7
|
+
login_button: "Acceder"
|
|
8
|
+
forgot_password_link: "¿Olvidaste tu contraseña?"
|
|
9
|
+
no_account_prompt: "¿No tienes una cuenta?"
|
|
10
|
+
signup_link: "Regístrate"
|
|
11
|
+
|
|
12
|
+
signup:
|
|
13
|
+
title: "Crear una Cuenta"
|
|
14
|
+
subtitle: "Comienza tu viaje con nosotros hoy."
|
|
15
|
+
first_name_label: "Nombre"
|
|
16
|
+
last_name_label: "Apellido"
|
|
17
|
+
email_label: "Correo Electrónico"
|
|
18
|
+
password_label: "Contraseña"
|
|
19
|
+
confirm_password_label: "Confirmar Contraseña"
|
|
20
|
+
signup_button: "Crear Cuenta"
|
|
21
|
+
already_have_account: "¿Ya tienes una cuenta?"
|
|
22
|
+
login_link: "Inicia Sesión"
|
|
23
|
+
disclaimer: "🔒 Valoramos tu privacidad. Tus datos se usarán exclusivamente para el funcionamiento de la plataforma."
|
|
24
|
+
|
|
25
|
+
forgot_password:
|
|
26
|
+
title: "Recuperar Contraseña"
|
|
27
|
+
subtitle: "Ingresa tu correo electrónico y te enviaremos un enlace para restablecer tu contraseña."
|
|
28
|
+
submit_button: "Enviar Enlace de Recuperación"
|
|
29
|
+
back_to_login: "Volver a Iniciar Sesión"
|
|
30
|
+
|
|
31
|
+
change_password:
|
|
32
|
+
title: "Crear Nueva Contraseña"
|
|
33
|
+
subtitle: "Estás cambiando la contraseña para <strong>{email}</strong>."
|
|
34
|
+
temp_code_label: "Código Temporal"
|
|
35
|
+
temp_code_placeholder: "Revisa tu correo electrónico"
|
|
36
|
+
new_password_label: "Nueva Contraseña"
|
|
37
|
+
password_instructions: "Debe contener al menos 8 caracteres, mayúscula, minúscula, número y un carácter especial."
|
|
38
|
+
confirm_password_label: "Confirmar Nueva Contraseña"
|
|
39
|
+
save_button: "Guardar Contraseña"
|
|
40
|
+
back_to_home: "Volver al inicio"
|
|
41
|
+
|
|
42
|
+
chat:
|
|
43
|
+
welcome_message: "¡Hola! ¿En qué te puedo ayudar hoy?"
|
|
44
|
+
input_placeholder: "Escribe aquí..."
|
|
45
|
+
prompts_available: "Prompts disponibles"
|
|
46
|
+
init_context: "Inicializando el contexto de la IA ..."
|
|
47
|
+
|
|
48
|
+
admin:
|
|
49
|
+
resources: "Recursos"
|
|
50
|
+
configuration: "Configuración"
|
|
51
|
+
prompts: "Prompts"
|
|
52
|
+
schemas: "Schemas"
|
|
53
|
+
context: "Contexto"
|
|
54
|
+
files: "Archivos"
|
|
55
|
+
users: "Usuarios"
|
|
56
|
+
select_file: "Seleccione un archivo a editar"
|
|
57
|
+
select_categpry: "Seleccione una categoría"
|
|
58
|
+
editing: "Editando"
|
|
59
|
+
no_file_selected: "Seleccione un archivo"
|
|
60
|
+
new: "Nuevo"
|
|
61
|
+
confirm: "Confirmar"
|
|
62
|
+
cancel: "Cancelar"
|
|
63
|
+
new_file: "Nuevo archivo"
|
|
64
|
+
delete_file: "Borrar archivo"
|
|
65
|
+
save_file: "Guardar"
|
|
66
|
+
credentials: "Email y password son requeridos."
|
|
67
|
+
saved_ok: "Guardado correctamente"
|
|
68
|
+
deleted_ok: "Eliminado correctamente"
|
|
69
|
+
company: "Empresa"
|
|
70
|
+
admin_page_title: "Acceso de administración"
|
|
71
|
+
user_manager: "Administración de usuarios"
|
|
72
|
+
load_configuration: "Guardar configuración"
|
|
73
|
+
goto_chat: "Ir al chat"
|
|
74
|
+
logout: "Cerrar sesión"
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
tooltips:
|
|
78
|
+
history: "Historial con mis consultas"
|
|
79
|
+
reload_context: "Forzar Recarga de Contexto"
|
|
80
|
+
feedback: "Tu feedback es muy importante"
|
|
81
|
+
usage_guide: "Guía de Uso"
|
|
82
|
+
onboarding: "Cómo preguntar mejor"
|
|
83
|
+
preferences: "Preferencias"
|
|
84
|
+
logout: "Cerrar sesión"
|
|
85
|
+
use_prompt_assistant: "Usar Asistente de Prompts"
|
|
86
|
+
attach_files: "Adjuntar archivos"
|
|
87
|
+
view_attached_files: "Ver archivos adjuntos"
|
|
88
|
+
modals:
|
|
89
|
+
files_title: "Archivos Cargados"
|
|
90
|
+
feedback_title: "Tu Opinión es Importante"
|
|
91
|
+
feedback_prompt: "¿Qué tan útil fue la respuesta del asistente?"
|
|
92
|
+
feedback_comment_label: "Tu comentario nos ayuda a mejorar:"
|
|
93
|
+
feedback_comment_placeholder: "Escribe aquí tu opinión, sugerencias o comentarios..."
|
|
94
|
+
history_title: "Historial de Consultas"
|
|
95
|
+
history_table_date: "Fecha"
|
|
96
|
+
history_table_query: "Consulta"
|
|
97
|
+
loading_history: "Cargando historial..."
|
|
98
|
+
no_history_found: "No se encontró historial de consultas."
|
|
99
|
+
help_title: "Guía de uso del Asistente IA"
|
|
100
|
+
|
|
101
|
+
buttons:
|
|
102
|
+
cancel: "Cerrar"
|
|
103
|
+
send: "Enviar"
|
|
104
|
+
stop: "Detener"
|
|
105
|
+
|
|
106
|
+
errors:
|
|
107
|
+
company_not_found: "La empresa {company_short_name} no existe."
|
|
108
|
+
timeout: "El tiempo de espera ha expirado."
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
auth:
|
|
112
|
+
invalid_password: "La contraseña proporcionada es incorrecta."
|
|
113
|
+
user_not_found: "No se encontró un usuario con ese correo."
|
|
114
|
+
invalid_or_expired_token: "Token inválido o expirado."
|
|
115
|
+
session_creation_failed: "No se pudo crear la sesión del usuario."
|
|
116
|
+
authentication_required: "Autenticación requerida. No se proporcionó cookie de sesión o clave de API."
|
|
117
|
+
invalid_api_key: "Clave de API inválida o inactiva."
|
|
118
|
+
no_user_identifier_api: "No se proporcionó user_identifier para la llamada a la API."
|
|
119
|
+
no_company_permissions: "No tiene permisos para administrar esta empresa."
|
|
120
|
+
|
|
121
|
+
templates:
|
|
122
|
+
company_not_found: "Empresa no encontrada."
|
|
123
|
+
home_template_not_found: "La plantilla de la página de inicio para la empresa '{company_short_name}' no está configurada."
|
|
124
|
+
processing_error: "Error al procesar el template: {error}"
|
|
125
|
+
template_not_found: "No se encontro el template: '{template_name}'."
|
|
126
|
+
|
|
127
|
+
general:
|
|
128
|
+
unexpected_error: "Ha ocurrido un error inesperado: {error}."
|
|
129
|
+
unsupported_language: "El idioma seleccionado no es válido."
|
|
130
|
+
signup:
|
|
131
|
+
company_not_found: "La empresa {company_short_name} no existe."
|
|
132
|
+
incorrect_password_for_existing_user: "La contraseña para el usuario {email} es incorrecta."
|
|
133
|
+
user_already_registered: "El usuario con email '{email}' ya existe en esta empresa."
|
|
134
|
+
password_mismatch: "Las contraseñas no coinciden. Por favor, inténtalo de nuevo."
|
|
135
|
+
change_password:
|
|
136
|
+
token_expired: "El enlace de cambio de contraseña ha expirado. Por favor, solicita uno nuevo."
|
|
137
|
+
password_mismatch: "Las contraseñas no coinciden. Por favor, inténtalo nuevamente."
|
|
138
|
+
invalid_temp_code: "El código temporal no es válido. Por favor, verifica o solicita uno nuevo."
|
|
139
|
+
forgot_password:
|
|
140
|
+
user_not_registered: "El usuario con correo {email} no está registrado."
|
|
141
|
+
verification:
|
|
142
|
+
token_expired: "El enlace de verificación ha expirado. Por favor, contacta a soporte si necesitas uno nuevo."
|
|
143
|
+
user_not_found: "El usuario que intentas verificar no existe."
|
|
144
|
+
validation:
|
|
145
|
+
password_too_short: "La contraseña debe tener al menos 8 caracteres."
|
|
146
|
+
password_no_uppercase: "La contraseña debe tener al menos una letra mayúscula."
|
|
147
|
+
password_no_lowercase: "La contraseña debe tener al menos una letra minúscula."
|
|
148
|
+
password_no_digit: "La contraseña debe tener al menos un número."
|
|
149
|
+
password_no_special_char: "La contraseña debe tener al menos un carácter especial."
|
|
150
|
+
|
|
151
|
+
services:
|
|
152
|
+
no_text_file: "El archivo no es texto o la codificación no es UTF-8"
|
|
153
|
+
no_output_file: "falta el nombre del archivo de salida"
|
|
154
|
+
no_data_for_excel: "faltan los datos o no es una lista de diccionarios"
|
|
155
|
+
no_download_directory: "no esta configurado el directorio temporal para guardar excels"
|
|
156
|
+
cannot_create_excel: "no se pudo crear el archivo excel"
|
|
157
|
+
invalid_filename: "Nombre de archivo inválido"
|
|
158
|
+
file_not_exist : "Archivo no encontrado"
|
|
159
|
+
path_is_not_a_file : "La ruta no corresponde a un archivo"
|
|
160
|
+
file_validation_error : "Error validando archivo"
|
|
161
|
+
user_not_authorized: "Usuario no esta autorizado para esta empresa"
|
|
162
|
+
account_not_verified: "Tu cuenta no ha sido verificada. Por favor, revisa tu correo."
|
|
163
|
+
missing_response_id: "No se encontró 'previous_response_id' para '{company_short_name}/{user_identifier}'. Reinicia el contexto."
|
|
164
|
+
context_rebuild_failed: "No se pudo reconstruir el contexto de la empresa."
|
|
165
|
+
cannot_read_excel: "No se pudo leer el archivo excel"
|
|
166
|
+
cannot_read_csv: "No se pudo leer el archivo CSV"
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
api_responses:
|
|
170
|
+
context_reloaded_success: "El contexto se ha recargado con éxito."
|
|
171
|
+
|
|
172
|
+
services:
|
|
173
|
+
mail_sent: "mail enviado exitosamente."
|
|
174
|
+
start_query: "Hola, cual es tu pregunta?"
|
|
175
|
+
mail_change_password: "se envio mail para cambio de clave"
|
|
176
|
+
|
|
177
|
+
flash_messages:
|
|
178
|
+
password_changed_success: "Tu contraseña ha sido restablecida exitosamente. Ahora puedes iniciar sesión."
|
|
179
|
+
signup_success: "Registro exitoso. Por favor, revisa tu correo para verificar tu cuenta."
|
|
180
|
+
signup_success_no_verification: "Registro exitoso."
|
|
181
|
+
user_associated_success: "Usuario existente asociado exitosamente a la nueva empresa."
|
|
182
|
+
account_verified_success: "Tu cuenta ha sido verificada exitosamente. ¡Bienvenido!"
|
|
183
|
+
forgot_password_success: "Si tu correo está registrado, recibirás un enlace para restablecer tu contraseña."
|
|
184
|
+
|
|
185
|
+
# Claves específicas para JavaScript
|
|
186
|
+
js_messages:
|
|
187
|
+
feedback_sent_success_title: "Feedback Enviado"
|
|
188
|
+
feedback_sent_success_body: "¡Gracias por tu comentario!"
|
|
189
|
+
feedback_sent_error: "No se pudo enviar el feedback, por favor intente nuevamente."
|
|
190
|
+
feedback_rating_error: "Por favor, califica al asistente con las estrellas."
|
|
191
|
+
feedback_comment_error: "Por favor, escribe tu comentario antes de enviar."
|
|
192
|
+
context_reloaded: "El contexto ha sido recargado."
|
|
193
|
+
error_loading_history: "Ocurrió un error al cargar el historial."
|
|
194
|
+
request_aborted: "La generación de la respuesta ha sido detenida."
|
|
195
|
+
processing_error: "Ocurrió un error al procesar la solicitud."
|
|
196
|
+
server_comm_error: "Error de comunicación con el servidor ({status}). Por favor, intente de nuevo más tarde."
|
|
197
|
+
network_error: "Ocurrió un error de red. Por favor, inténtalo de nuevo en unos momentos."
|
|
198
|
+
unknown_server_error: "Error desconocido del servidor."
|
|
199
|
+
loading: "Cargando..."
|
|
200
|
+
reload_init: "Iniciando recarga de contexto en segundo plano..."
|
|
201
|
+
no_history_found: "No existe historial de consultas."
|
|
202
|
+
example: "Ejemplo:"
|
|
203
|
+
show_reasoning: "Ver razonamiento"
|
|
204
|
+
unsaved: "Modificado (no guardado)"
|
|
205
|
+
select_file: "Seleccione un archivo de la lista"
|
|
206
|
+
no_file_selected: "No hay archivo seleccionado"
|
|
207
|
+
select_company: "Seleccione empresa"
|
|
208
|
+
delete_ok: "Archivo eliminado correctamente"
|
|
209
|
+
not_saved: 'No puede guardar'
|
|
210
|
+
invalid_file_name: "Nombre de archivo no válido. Usa solo letras, números, guiones bajos, guiones y puntos."
|
|
211
|
+
config_loaded: "Configuración cargada correctamente."
|
|
212
|
+
config_load_error: "Error cargando confguración."
|
|
213
|
+
search_placeholder: "Buscar usuarios..."
|
|
214
|
+
showing: "Mostrando"
|
|
215
|
+
records: "Registros"
|
|
216
|
+
db_user: "Usuario"
|
|
217
|
+
db_role: "Rol"
|
|
218
|
+
db_verified: "Verificado"
|
|
219
|
+
db_created: "Ingreso"
|
|
220
|
+
db_last_access: "ultimo acceso"
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
# Copyright (c) 2024 Fernando Libedinsky
|
|
2
|
+
# Product: IAToolkit
|
|
3
|
+
#
|
|
4
|
+
# IAToolkit is open source software.
|
|
5
|
+
|
|
6
|
+
# database_manager.py
|
|
7
|
+
from sqlalchemy import create_engine, event, inspect, text
|
|
8
|
+
from sqlalchemy.orm import sessionmaker, scoped_session
|
|
9
|
+
from sqlalchemy.engine.url import make_url
|
|
10
|
+
from iatoolkit.repositories.models import Base
|
|
11
|
+
from injector import inject
|
|
12
|
+
from pgvector.psycopg2 import register_vector
|
|
13
|
+
from iatoolkit.common.interfaces.database_provider import DatabaseProvider
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class DatabaseManager(DatabaseProvider):
|
|
17
|
+
@inject
|
|
18
|
+
def __init__(self,
|
|
19
|
+
database_url: str,
|
|
20
|
+
schema: str | None = None,
|
|
21
|
+
register_pgvector: bool = True):
|
|
22
|
+
"""
|
|
23
|
+
Inicializa el gestor de la base de datos.
|
|
24
|
+
:param database_url: URL de la base de datos.
|
|
25
|
+
:param schema: Esquema por defecto para la conexión (search_path).
|
|
26
|
+
:param echo: Si True, habilita logs de SQL.
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
self.schema = schema
|
|
30
|
+
|
|
31
|
+
# FIX HEROKU: replace postgres:// by postgresql:// for compatibility with SQLAlchemy 1.4+
|
|
32
|
+
if database_url and database_url.startswith("postgres://"):
|
|
33
|
+
database_url = database_url.replace("postgres://", "postgresql://", 1)
|
|
34
|
+
|
|
35
|
+
self.url = make_url(database_url)
|
|
36
|
+
|
|
37
|
+
if database_url.startswith('sqlite'):
|
|
38
|
+
self._engine = create_engine(database_url, echo=False)
|
|
39
|
+
else:
|
|
40
|
+
self._engine = create_engine(
|
|
41
|
+
database_url,
|
|
42
|
+
echo=False,
|
|
43
|
+
pool_size=10, # per worker
|
|
44
|
+
max_overflow=20,
|
|
45
|
+
pool_timeout=30,
|
|
46
|
+
pool_recycle=1800,
|
|
47
|
+
pool_pre_ping=True,
|
|
48
|
+
future=True,
|
|
49
|
+
)
|
|
50
|
+
self.SessionFactory = sessionmaker(bind=self._engine,
|
|
51
|
+
autoflush=False,
|
|
52
|
+
autocommit=False,
|
|
53
|
+
expire_on_commit=False)
|
|
54
|
+
self.scoped_session = scoped_session(self.SessionFactory)
|
|
55
|
+
|
|
56
|
+
# Register pgvector for each new connection
|
|
57
|
+
backend = self.url.get_backend_name()
|
|
58
|
+
if backend == 'postgresql' or backend == 'postgres':
|
|
59
|
+
if register_pgvector:
|
|
60
|
+
event.listen(self._engine, 'connect', self.on_connect)
|
|
61
|
+
|
|
62
|
+
# if there is a schema, configure the search_path for each connection
|
|
63
|
+
if self.schema:
|
|
64
|
+
event.listen(self._engine, 'checkout', self.set_search_path)
|
|
65
|
+
|
|
66
|
+
def set_search_path(self, dbapi_connection, connection_record, connection_proxy):
|
|
67
|
+
# Configure the search_path for this connection
|
|
68
|
+
cursor = dbapi_connection.cursor()
|
|
69
|
+
|
|
70
|
+
# The defined schema is first, and then public by default
|
|
71
|
+
try:
|
|
72
|
+
cursor.execute(f"SET search_path TO {self.schema}, public")
|
|
73
|
+
cursor.close()
|
|
74
|
+
|
|
75
|
+
# commit for persist the change in the session
|
|
76
|
+
dbapi_connection.commit()
|
|
77
|
+
except Exception:
|
|
78
|
+
# if failed, rollback to avoid invalidating the connection
|
|
79
|
+
dbapi_connection.rollback()
|
|
80
|
+
|
|
81
|
+
@staticmethod
|
|
82
|
+
def on_connect(dbapi_connection, connection_record):
|
|
83
|
+
"""
|
|
84
|
+
Esta función se ejecuta cada vez que se establece una conexión.
|
|
85
|
+
dbapi_connection es la conexión psycopg2 real.
|
|
86
|
+
"""
|
|
87
|
+
register_vector(dbapi_connection)
|
|
88
|
+
|
|
89
|
+
def get_session(self):
|
|
90
|
+
return self.scoped_session()
|
|
91
|
+
|
|
92
|
+
def get_connection(self):
|
|
93
|
+
return self._engine.connect()
|
|
94
|
+
|
|
95
|
+
def create_all(self):
|
|
96
|
+
# if there is a schema defined, make sure it exists before creating tables
|
|
97
|
+
backend = self.url.get_backend_name()
|
|
98
|
+
if self.schema and (backend == 'postgresql' or backend == 'postgres'):
|
|
99
|
+
with self._engine.begin() as conn:
|
|
100
|
+
conn.execute(text(f"CREATE SCHEMA IF NOT EXISTS {self.schema}"))
|
|
101
|
+
|
|
102
|
+
Base.metadata.create_all(self._engine)
|
|
103
|
+
|
|
104
|
+
def drop_all(self):
|
|
105
|
+
Base.metadata.drop_all(self._engine)
|
|
106
|
+
|
|
107
|
+
def remove_session(self):
|
|
108
|
+
self.scoped_session.remove()
|
|
109
|
+
|
|
110
|
+
# -- execution methods ----
|
|
111
|
+
|
|
112
|
+
def execute_query(self, query: str, commit: bool = False) -> list[dict] | dict:
|
|
113
|
+
"""
|
|
114
|
+
Implementation for Direct SQLAlchemy connection.
|
|
115
|
+
"""
|
|
116
|
+
session = self.get_session()
|
|
117
|
+
result = session.execute(text(query))
|
|
118
|
+
|
|
119
|
+
if commit:
|
|
120
|
+
session.commit()
|
|
121
|
+
|
|
122
|
+
if result.returns_rows:
|
|
123
|
+
# Convert SQLAlchemy rows to list of dicts immediately
|
|
124
|
+
cols = result.keys()
|
|
125
|
+
return [dict(zip(cols, row)) for row in result.fetchall()]
|
|
126
|
+
|
|
127
|
+
return {'rowcount': result.rowcount}
|
|
128
|
+
|
|
129
|
+
def commit(self):
|
|
130
|
+
self.get_session().commit()
|
|
131
|
+
|
|
132
|
+
def rollback(self):
|
|
133
|
+
self.get_session().rollback()
|
|
134
|
+
|
|
135
|
+
# -- schema methods ----
|
|
136
|
+
def get_all_table_names(self) -> list[str]:
|
|
137
|
+
# Returns a list of all table names in the database
|
|
138
|
+
inspector = inspect(self._engine)
|
|
139
|
+
return inspector.get_table_names(schema=self.schema)
|
|
140
|
+
|
|
141
|
+
def get_table_schema(self,
|
|
142
|
+
table_name: str,
|
|
143
|
+
db_schema: str,
|
|
144
|
+
schema_object_name: str | None = None,
|
|
145
|
+
exclude_columns: list[str] | None = None) -> str:
|
|
146
|
+
inspector = inspect(self._engine)
|
|
147
|
+
|
|
148
|
+
# search the table in the specified schema
|
|
149
|
+
if table_name not in inspector.get_table_names(schema=db_schema):
|
|
150
|
+
raise RuntimeError(f"Table '{table_name}' does not exist in database schema '{db_schema}'.")
|
|
151
|
+
|
|
152
|
+
if exclude_columns is None:
|
|
153
|
+
exclude_columns = []
|
|
154
|
+
|
|
155
|
+
# get all the table columns
|
|
156
|
+
columns = inspector.get_columns(table_name, schema=db_schema)
|
|
157
|
+
|
|
158
|
+
# construct a json dictionary with the table definition
|
|
159
|
+
json_dict = {
|
|
160
|
+
"table": table_name,
|
|
161
|
+
"description": "",
|
|
162
|
+
"fields": []
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
if schema_object_name:
|
|
166
|
+
json_dict["description"] += (
|
|
167
|
+
f"The meaning of each field in this table is detailed in the **`{schema_object_name}`** object."
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
if db_schema:
|
|
171
|
+
json_dict["schema"] = db_schema
|
|
172
|
+
json_dict["description"] += f"It belongs to the **`{db_schema}`** schema."
|
|
173
|
+
|
|
174
|
+
# now add every column to the json dictionary
|
|
175
|
+
for col in columns:
|
|
176
|
+
name = col["name"]
|
|
177
|
+
|
|
178
|
+
# omit the excluded columns.
|
|
179
|
+
if name in exclude_columns:
|
|
180
|
+
continue
|
|
181
|
+
|
|
182
|
+
json_dict["fields"].append({
|
|
183
|
+
"name": name,
|
|
184
|
+
"type": str(col["type"]),
|
|
185
|
+
})
|
|
186
|
+
|
|
187
|
+
return "\n\n" + str(json_dict)
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Copyright (c) 2024 Fernando Libedinsky
|
|
2
|
+
# Product: IAToolkit
|
|
3
|
+
#
|
|
4
|
+
# IAToolkit is open source software.
|
|
5
|
+
|
|
6
|
+
from iatoolkit.repositories.models import Document
|
|
7
|
+
from injector import inject
|
|
8
|
+
from iatoolkit.repositories.database_manager import DatabaseManager
|
|
9
|
+
from iatoolkit.common.exceptions import IAToolkitException
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class DocumentRepo:
|
|
13
|
+
@inject
|
|
14
|
+
def __init__(self, db_manager: DatabaseManager):
|
|
15
|
+
self.session = db_manager.get_session()
|
|
16
|
+
|
|
17
|
+
def insert(self,new_document: Document):
|
|
18
|
+
self.session.add(new_document)
|
|
19
|
+
self.session.commit()
|
|
20
|
+
return new_document
|
|
21
|
+
|
|
22
|
+
def get(self, company_id, filename: str ) -> Document:
|
|
23
|
+
if not company_id or not filename:
|
|
24
|
+
raise IAToolkitException(IAToolkitException.ErrorType.PARAM_NOT_FILLED,
|
|
25
|
+
'missing company_id or filename')
|
|
26
|
+
|
|
27
|
+
return self.session.query(Document).filter_by(company_id=company_id, filename=filename).first()
|
|
28
|
+
|
|
29
|
+
def get_by_id(self, document_id: int) -> Document:
|
|
30
|
+
if not document_id:
|
|
31
|
+
return None
|
|
32
|
+
|
|
33
|
+
return self.session.query(Document).filter_by(id=document_id).first()
|