iatoolkit 0.71.4__py3-none-any.whl → 1.4.2__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.
- iatoolkit/__init__.py +19 -7
- iatoolkit/base_company.py +1 -71
- iatoolkit/cli_commands.py +9 -21
- iatoolkit/common/exceptions.py +2 -0
- iatoolkit/common/interfaces/__init__.py +0 -0
- iatoolkit/common/interfaces/asset_storage.py +34 -0
- iatoolkit/common/interfaces/database_provider.py +38 -0
- iatoolkit/common/model_registry.py +159 -0
- iatoolkit/common/routes.py +53 -32
- iatoolkit/common/util.py +17 -12
- iatoolkit/company_registry.py +55 -14
- iatoolkit/{iatoolkit.py → core.py} +102 -72
- iatoolkit/infra/{mail_app.py → brevo_mail_app.py} +15 -37
- iatoolkit/infra/llm_providers/__init__.py +0 -0
- iatoolkit/infra/llm_providers/deepseek_adapter.py +278 -0
- iatoolkit/infra/{gemini_adapter.py → llm_providers/gemini_adapter.py} +11 -17
- iatoolkit/infra/{openai_adapter.py → llm_providers/openai_adapter.py} +41 -7
- iatoolkit/infra/llm_proxy.py +235 -134
- iatoolkit/infra/llm_response.py +5 -0
- iatoolkit/locales/en.yaml +134 -4
- iatoolkit/locales/es.yaml +293 -162
- iatoolkit/repositories/database_manager.py +92 -22
- iatoolkit/repositories/document_repo.py +7 -0
- iatoolkit/repositories/filesystem_asset_repository.py +36 -0
- iatoolkit/repositories/llm_query_repo.py +36 -22
- iatoolkit/repositories/models.py +86 -95
- iatoolkit/repositories/profile_repo.py +64 -13
- iatoolkit/repositories/vs_repo.py +31 -28
- iatoolkit/services/auth_service.py +1 -1
- iatoolkit/services/branding_service.py +1 -1
- iatoolkit/services/company_context_service.py +96 -39
- iatoolkit/services/configuration_service.py +329 -67
- iatoolkit/services/dispatcher_service.py +51 -227
- iatoolkit/services/document_service.py +10 -1
- iatoolkit/services/embedding_service.py +9 -6
- iatoolkit/services/excel_service.py +50 -2
- iatoolkit/services/file_processor_service.py +0 -5
- iatoolkit/services/history_manager_service.py +208 -0
- iatoolkit/services/jwt_service.py +1 -1
- iatoolkit/services/knowledge_base_service.py +412 -0
- iatoolkit/services/language_service.py +8 -2
- iatoolkit/services/license_service.py +82 -0
- iatoolkit/{infra/llm_client.py → services/llm_client_service.py} +42 -29
- iatoolkit/services/load_documents_service.py +18 -47
- iatoolkit/services/mail_service.py +171 -25
- iatoolkit/services/profile_service.py +69 -36
- iatoolkit/services/{prompt_manager_service.py → prompt_service.py} +136 -25
- iatoolkit/services/query_service.py +229 -203
- iatoolkit/services/sql_service.py +116 -34
- iatoolkit/services/tool_service.py +246 -0
- iatoolkit/services/user_feedback_service.py +18 -6
- iatoolkit/services/user_session_context_service.py +121 -51
- iatoolkit/static/images/iatoolkit_core.png +0 -0
- iatoolkit/static/images/iatoolkit_logo.png +0 -0
- iatoolkit/static/js/chat_feedback_button.js +1 -1
- iatoolkit/static/js/chat_help_content.js +4 -4
- iatoolkit/static/js/chat_main.js +61 -9
- iatoolkit/static/js/chat_model_selector.js +227 -0
- iatoolkit/static/js/chat_onboarding_button.js +1 -1
- iatoolkit/static/js/chat_reload_button.js +4 -1
- iatoolkit/static/styles/chat_iatoolkit.css +59 -3
- iatoolkit/static/styles/chat_public.css +28 -0
- iatoolkit/static/styles/documents.css +598 -0
- iatoolkit/static/styles/landing_page.css +223 -7
- iatoolkit/static/styles/llm_output.css +34 -1
- iatoolkit/system_prompts/__init__.py +0 -0
- iatoolkit/system_prompts/query_main.prompt +28 -3
- iatoolkit/system_prompts/sql_rules.prompt +47 -12
- iatoolkit/templates/_company_header.html +30 -5
- iatoolkit/templates/_login_widget.html +3 -3
- iatoolkit/templates/base.html +13 -0
- iatoolkit/templates/chat.html +45 -3
- iatoolkit/templates/forgot_password.html +3 -2
- iatoolkit/templates/onboarding_shell.html +1 -2
- iatoolkit/templates/signup.html +3 -0
- iatoolkit/views/base_login_view.py +8 -3
- iatoolkit/views/change_password_view.py +1 -1
- iatoolkit/views/chat_view.py +76 -0
- iatoolkit/views/forgot_password_view.py +9 -4
- iatoolkit/views/history_api_view.py +3 -3
- iatoolkit/views/home_view.py +4 -2
- iatoolkit/views/init_context_api_view.py +1 -1
- iatoolkit/views/llmquery_api_view.py +4 -3
- iatoolkit/views/load_company_configuration_api_view.py +49 -0
- iatoolkit/views/{file_store_api_view.py → load_document_api_view.py} +15 -11
- iatoolkit/views/login_view.py +25 -8
- iatoolkit/views/logout_api_view.py +10 -2
- iatoolkit/views/prompt_api_view.py +1 -1
- iatoolkit/views/rag_api_view.py +216 -0
- iatoolkit/views/root_redirect_view.py +22 -0
- iatoolkit/views/signup_view.py +12 -4
- iatoolkit/views/static_page_view.py +27 -0
- iatoolkit/views/users_api_view.py +33 -0
- iatoolkit/views/verify_user_view.py +1 -1
- iatoolkit-1.4.2.dist-info/METADATA +268 -0
- iatoolkit-1.4.2.dist-info/RECORD +133 -0
- iatoolkit-1.4.2.dist-info/licenses/LICENSE_COMMUNITY.md +15 -0
- iatoolkit/repositories/tasks_repo.py +0 -52
- iatoolkit/services/history_service.py +0 -37
- iatoolkit/services/search_service.py +0 -55
- iatoolkit/services/tasks_service.py +0 -188
- iatoolkit/templates/about.html +0 -13
- iatoolkit/templates/index.html +0 -145
- iatoolkit/templates/login_simulation.html +0 -45
- iatoolkit/views/external_login_view.py +0 -73
- iatoolkit/views/index_view.py +0 -14
- iatoolkit/views/login_simulation_view.py +0 -93
- iatoolkit/views/tasks_api_view.py +0 -72
- iatoolkit/views/tasks_review_api_view.py +0 -55
- iatoolkit-0.71.4.dist-info/METADATA +0 -276
- iatoolkit-0.71.4.dist-info/RECORD +0 -122
- {iatoolkit-0.71.4.dist-info → iatoolkit-1.4.2.dist-info}/WHEEL +0 -0
- {iatoolkit-0.71.4.dist-info → iatoolkit-1.4.2.dist-info}/licenses/LICENSE +0 -0
- {iatoolkit-0.71.4.dist-info → iatoolkit-1.4.2.dist-info}/top_level.txt +0 -0
|
@@ -36,9 +36,16 @@ body {
|
|
|
36
36
|
color: #ffffff;
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
+
/* --- Header & Link Styles --- */
|
|
40
|
+
.website-header .website-brand,
|
|
41
|
+
.website-header a.website-brand,
|
|
42
|
+
.website-header a.website-brand:hover {
|
|
43
|
+
text-decoration: none; /* Elimina el subrayado de los enlaces */
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
|
|
39
47
|
/* --- Sección Principal (Hero) --- */
|
|
40
48
|
.hero-section {
|
|
41
|
-
padding: 2rem 0 1rem; /* Ajustado: 5rem arriba, 0 a los lados, 2.5rem abajo */
|
|
42
49
|
}
|
|
43
50
|
|
|
44
51
|
.hero-title {
|
|
@@ -54,21 +61,29 @@ body {
|
|
|
54
61
|
background-clip: text;
|
|
55
62
|
text-fill-color: transparent;
|
|
56
63
|
}
|
|
64
|
+
|
|
57
65
|
.hero-bullets {
|
|
58
66
|
list-style: none;
|
|
59
67
|
padding-left: 0;
|
|
60
|
-
font-size: 1.
|
|
68
|
+
font-size: 1.25rem;
|
|
69
|
+
line-height: 1.5;
|
|
70
|
+
margin-top: 1.5rem;
|
|
61
71
|
}
|
|
72
|
+
|
|
62
73
|
.hero-bullets li {
|
|
63
74
|
display: flex;
|
|
64
|
-
align-items:
|
|
65
|
-
gap:
|
|
66
|
-
margin-bottom:
|
|
75
|
+
align-items: flex-start; /* necesario para alinear texto superior */
|
|
76
|
+
gap: 1rem;
|
|
77
|
+
margin-bottom: 1.4rem;
|
|
67
78
|
color: var(--website-muted-text);
|
|
68
79
|
}
|
|
80
|
+
|
|
69
81
|
.hero-bullets .bi {
|
|
82
|
+
font-size: 2rem;
|
|
70
83
|
color: var(--website-primary-color);
|
|
71
|
-
|
|
84
|
+
flex-shrink: 0;
|
|
85
|
+
line-height: 1; /* evita que el ícono genere espacio extra */
|
|
86
|
+
margin-top: 0.35rem; /* ESTE valor alinea perfecto el ícono con el texto */
|
|
72
87
|
}
|
|
73
88
|
|
|
74
89
|
/* --- Botón de Llamada a la Acción (CTA) --- */
|
|
@@ -87,7 +102,7 @@ body {
|
|
|
87
102
|
}
|
|
88
103
|
|
|
89
104
|
.features-section {
|
|
90
|
-
padding:
|
|
105
|
+
padding: 2rem 1rem;
|
|
91
106
|
background-color: var(--website-light-bg);
|
|
92
107
|
}
|
|
93
108
|
.feature-item {
|
|
@@ -144,6 +159,12 @@ body {
|
|
|
144
159
|
margin-bottom: 1.5rem;
|
|
145
160
|
}
|
|
146
161
|
|
|
162
|
+
.article-footer {
|
|
163
|
+
margin-top: 4rem;
|
|
164
|
+
padding-top: 2rem;
|
|
165
|
+
border-top: 1px solid #e9ecef; /* Separador visual */
|
|
166
|
+
}
|
|
167
|
+
|
|
147
168
|
/* --- Sección del Autor --- */
|
|
148
169
|
.author-section {
|
|
149
170
|
background-color: #fff;
|
|
@@ -170,6 +191,61 @@ body {
|
|
|
170
191
|
.author-linkedin:hover {
|
|
171
192
|
opacity: 0.8;
|
|
172
193
|
}
|
|
194
|
+
.author-box {
|
|
195
|
+
display: flex;
|
|
196
|
+
align-items: center;
|
|
197
|
+
gap: 25px;
|
|
198
|
+
background-color: #f8f9fa;
|
|
199
|
+
padding: 25px;
|
|
200
|
+
border-radius: 12px;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
.author-avatar img {
|
|
204
|
+
width: 90px;
|
|
205
|
+
height: 90px;
|
|
206
|
+
border-radius: 50%;
|
|
207
|
+
object-fit: cover;
|
|
208
|
+
border: 3px solid #fff;
|
|
209
|
+
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
.author-details {
|
|
213
|
+
line-height: 1.4; /* Reduce el espacio entre líneas */
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
.author-details p {
|
|
217
|
+
margin: 0; /* Elimina los márgenes por defecto de los párrafos */
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
.author-name {
|
|
221
|
+
font-weight: 600;
|
|
222
|
+
font-size: 1.25rem;
|
|
223
|
+
color: #212529;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
.author-title {
|
|
227
|
+
font-size: 1rem;
|
|
228
|
+
color: #6c757d;
|
|
229
|
+
margin-top: 2px; /* Pequeño espacio después del nombre */
|
|
230
|
+
font-style: normal;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
.author-social-link {
|
|
234
|
+
display: inline-block;
|
|
235
|
+
margin-top: 8px; /* Espacio reducido antes del enlace */
|
|
236
|
+
font-size: 0.95rem;
|
|
237
|
+
color: #007bff;
|
|
238
|
+
text-decoration: none;
|
|
239
|
+
font-weight: 500;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
.author-social-link:hover {
|
|
243
|
+
text-decoration: underline;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
.author-social-link i {
|
|
247
|
+
margin-right: 5px;
|
|
248
|
+
}
|
|
173
249
|
|
|
174
250
|
/* --- Footer --- */
|
|
175
251
|
.landing-footer {
|
|
@@ -179,4 +255,144 @@ body {
|
|
|
179
255
|
text-align: center;
|
|
180
256
|
margin-top: 4rem;
|
|
181
257
|
border-top: 1px solid #e9ecef;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
/* Language Switcher within header */
|
|
262
|
+
.language-switcher {
|
|
263
|
+
display: flex;
|
|
264
|
+
align-items: center;
|
|
265
|
+
font-size: 0.9rem;
|
|
266
|
+
/* margen izquierdo auto no es necesario si usas justify-content-between,
|
|
267
|
+
pero no molesta si el header cambia en el futuro */
|
|
268
|
+
margin-left: auto;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/* Links de idioma sobre fondo azul */
|
|
272
|
+
.language-link {
|
|
273
|
+
text-decoration: none;
|
|
274
|
+
color: #ffffff; /* texto blanco */
|
|
275
|
+
padding: 2px 8px;
|
|
276
|
+
font-weight: 500;
|
|
277
|
+
border-radius: 4px;
|
|
278
|
+
transition: background-color 0.2s ease;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/* Separador | puede heredar color blanco */
|
|
282
|
+
.language-switcher .mx-1 {
|
|
283
|
+
color: #ffffff;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/* Hover: blanco translúcido encima del azul */
|
|
287
|
+
.language-link:hover {
|
|
288
|
+
background-color: rgba(255, 255, 255, 0.25);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/* Idioma activo: un poco más marcado */
|
|
292
|
+
.language-link.active {
|
|
293
|
+
background-color: rgba(255, 255, 255, 0.35);
|
|
294
|
+
font-weight: 700;
|
|
295
|
+
color: #ffffff;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
.btn-outline-website {
|
|
299
|
+
border: 2px solid var(--website-primary-color);
|
|
300
|
+
color: var(--website-primary-color);
|
|
301
|
+
background-color: transparent;
|
|
302
|
+
font-weight: 600;
|
|
303
|
+
transition: 0.2s ease-in-out;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
.btn-outline-website:hover {
|
|
307
|
+
background-color: var(--website-primary-color);
|
|
308
|
+
color: #fff;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
/* ------- Editions Section (Community vs Enterprise) ------- */
|
|
312
|
+
.edition-box {
|
|
313
|
+
background: #ffffff;
|
|
314
|
+
border: 1px solid rgba(0,0,0,0.08);
|
|
315
|
+
border-radius: 12px;
|
|
316
|
+
padding: 2rem;
|
|
317
|
+
text-align: left;
|
|
318
|
+
box-shadow: 0 4px 12px rgba(0,0,0,0.04);
|
|
319
|
+
transition: transform 0.2s ease, box-shadow 0.2s ease;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
.edition-box h3 {
|
|
323
|
+
font-weight: 600;
|
|
324
|
+
font-size: 1.4rem;
|
|
325
|
+
margin-bottom: 0.5rem;
|
|
326
|
+
color: var(--website-primary-color);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
.edition-box p {
|
|
330
|
+
margin-bottom: 1.2rem;
|
|
331
|
+
color: var(--website-muted-text);
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
.edition-box ul {
|
|
335
|
+
padding-left: 0;
|
|
336
|
+
list-style: none;
|
|
337
|
+
margin: 0;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
.edition-box ul li {
|
|
341
|
+
margin-bottom: 0.4rem;
|
|
342
|
+
font-size: 1rem;
|
|
343
|
+
display: flex;
|
|
344
|
+
align-items: center;
|
|
345
|
+
gap: 0.5rem;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
.edition-box ul li::before {
|
|
349
|
+
content: "✔";
|
|
350
|
+
font-weight: bold;
|
|
351
|
+
color: var(--website-primary-color);
|
|
352
|
+
font-size: 1rem;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
/* Hover effect (solo desktop) */
|
|
356
|
+
@media (hover: hover) {
|
|
357
|
+
.edition-box:hover {
|
|
358
|
+
transform: translateY(-6px);
|
|
359
|
+
box-shadow: 0 8px 20px rgba(0,0,0,0.08);
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
/* Enterprise highlighting */
|
|
364
|
+
.edition-box.enterprise {
|
|
365
|
+
background: var(--website-light-bg);
|
|
366
|
+
border: 1px solid rgba(0,0,0,0.12);
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
/* Section title & spacing */
|
|
370
|
+
.editions-section h2 {
|
|
371
|
+
color: var(--website-dark-text);
|
|
372
|
+
font-weight: 700;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
.editions-section .edition-box {
|
|
376
|
+
min-height: 100%;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
.trusted-subtitle {
|
|
380
|
+
font-size: 0.9rem;
|
|
381
|
+
font-weight: 500;
|
|
382
|
+
color: var(--website-primary-color-dark);
|
|
383
|
+
opacity: 0.8;
|
|
384
|
+
text-align: center;
|
|
385
|
+
margin-top: -0.5rem;
|
|
386
|
+
margin-bottom: 1.2rem;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
/* Estilo del link dentro del badge */
|
|
390
|
+
.trusted-link {
|
|
391
|
+
color: var(--website-primary-color-dark);
|
|
392
|
+
text-decoration: none;
|
|
393
|
+
font-weight: 600;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
.trusted-link:hover {
|
|
397
|
+
text-decoration: underline;
|
|
182
398
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/* BLOQUE GENERAL */
|
|
2
2
|
.llm-output {
|
|
3
3
|
margin: 0;
|
|
4
|
-
padding:
|
|
4
|
+
padding: 14px;
|
|
5
5
|
font-family: Arial, sans-serif;
|
|
6
6
|
font-size: 16px;
|
|
7
7
|
line-height: 1.5;
|
|
@@ -113,3 +113,36 @@
|
|
|
113
113
|
.nowrap {
|
|
114
114
|
white-space: nowrap;
|
|
115
115
|
}
|
|
116
|
+
|
|
117
|
+
/* =========================================================
|
|
118
|
+
REASONING BLOCK (LLM)
|
|
119
|
+
========================================================= */
|
|
120
|
+
|
|
121
|
+
.reasoning-block {
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/* Botón de mostrar razonamiento */
|
|
125
|
+
.reasoning-toggle {
|
|
126
|
+
font-size: 13px;
|
|
127
|
+
color: #6c757d; /* text-secondary */
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
.reasoning-toggle:hover {
|
|
131
|
+
color: #495057;
|
|
132
|
+
text-decoration: underline;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/* Contenedor del reasoning */
|
|
136
|
+
.reasoning-card {
|
|
137
|
+
background-color: #f8f9fa; /* bg-light */
|
|
138
|
+
border-left: 3px solid #6c757d; /* border-secondary */
|
|
139
|
+
padding: 10px 14px;
|
|
140
|
+
font-size: 14px; /* consistente con llm-output */
|
|
141
|
+
line-height: 1.5;
|
|
142
|
+
color: #555;
|
|
143
|
+
white-space: pre-wrap;
|
|
144
|
+
max-height: 300px;
|
|
145
|
+
overflow-y: auto;
|
|
146
|
+
font-family: inherit; /* 👈 clave: usa la misma fuente base */
|
|
147
|
+
}
|
|
148
|
+
|
|
File without changes
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
Eres un asistente que responde preguntas o ejecuta tareas según el contexto de la empresa.
|
|
2
2
|
|
|
3
3
|
### **Nombre de la empresa**
|
|
4
|
-
## Nombre: {{company}}, tambien se conoce como {{ company_short_name }}
|
|
4
|
+
## Nombre: {{company}}, tambien se conoce como **{{ company_short_name }}**
|
|
5
|
+
## Idioma: el idioma en que debes responder inicialmente es: {{language}}
|
|
5
6
|
|
|
6
7
|
### ** Información del usuario que esta consultando este chat**
|
|
7
8
|
- Identificador unico de usuario: {{ user_identifier }}
|
|
@@ -11,11 +12,35 @@ Eres un asistente que responde preguntas o ejecuta tareas según el contexto de
|
|
|
11
12
|
- Rol de usuario: {{ user_rol }}
|
|
12
13
|
|
|
13
14
|
|
|
14
|
-
## Servicios de datos
|
|
15
|
+
## 🔧 Servicios de datos disponibles en {{ company.name }}
|
|
16
|
+
|
|
17
|
+
A continuación se muestran los *function calls* (tools) que puedes usar para resolver tareas relacionadas con datos.
|
|
18
|
+
Cada servicio incluye su **nombre**, **propósito** y **parámetros esperados**.
|
|
19
|
+
|
|
20
|
+
### 📌 LISTA DE TOOLS DISPONIBLES
|
|
15
21
|
{% for service in service_list %}
|
|
16
|
-
|
|
22
|
+
#### Tool {{ loop.index }}: `{{ service.name }}`
|
|
23
|
+
- **Descripción:** {{ service.description }}
|
|
24
|
+
- **Parámetros:** {{ service.parameters | tojson }}
|
|
17
25
|
{% endfor %}
|
|
18
26
|
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
### ⚠️ REGLAS IMPORTANTES PARA EL USO DE TOOLS
|
|
30
|
+
|
|
31
|
+
1. **Debes usar un tool cuando la tarea lo requiera.**
|
|
32
|
+
Ejemplos:
|
|
33
|
+
- Consultar bases de datos
|
|
34
|
+
- Obtener información corporativa
|
|
35
|
+
- Ejecutar SQL
|
|
36
|
+
- Cargar documentos
|
|
37
|
+
|
|
38
|
+
2. **NO inventes información** si un tool existe para obtenerla.
|
|
39
|
+
3. Si un usuario solicita datos específicos, **elige el tool cuyo propósito coincida exactamente** con la solicitud.
|
|
40
|
+
4. **Si ningún tool aplica**, responde siguiendo el estilo de un asistente normal.
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
19
44
|
Eres un asistente que responde preguntas sobre empresas y sus clientes.
|
|
20
45
|
|
|
21
46
|
**Reglas obligatorias de contexto:**
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
- Muchas columnas contienen información en formato **jsonb**.
|
|
5
5
|
- Todas las consultas deben ser **sintácticamente correctas** y compatibles con PostgreSQL.
|
|
6
6
|
|
|
7
|
+
## 🔍 Uso correcto de campos JSONB
|
|
7
8
|
## 🔍 Uso correcto de campos JSONB
|
|
8
9
|
|
|
9
10
|
### Regla central: ¡NO ASUMAS QUE LAS CLAVES JSONB SON COLUMNAS!
|
|
@@ -108,32 +109,66 @@ Ejemplo incorrecto: SUM(value->>'monto')::NUMERIC
|
|
|
108
109
|
- Usa `TO_DATE(...)` para convertir el string a fecha:
|
|
109
110
|
```sql
|
|
110
111
|
TO_DATE(jsonb_credit->>'created', 'DD-MM-YYYY')
|
|
111
|
-
|
|
112
|
+
```
|
|
112
113
|
|
|
113
114
|
- antes de comparar con `CURRENT_DATE` un campo de tipo jsonb,
|
|
114
115
|
**siempre** castea explícitamente
|
|
115
116
|
|
|
116
|
-
- No utilices TO_DATE si la columna ya es de tipo DATE o TIMESTAMP.
|
|
117
|
-
Úsala solo si el campo es tipo TEXT o VARCHAR, y asegúrate de castearlo explícitamente si es necesario.
|
|
118
|
-
TO_DATE espera un string, no una fecha ya en formato DATE, y causará un error de tipo de datos.
|
|
119
|
-
|
|
120
117
|
- Si comparas fechas, asegúrate que ambos lados sean del mismo tipo.
|
|
121
118
|
ejemplo:
|
|
122
119
|
```sql
|
|
123
|
-
-- Si '
|
|
124
|
-
TO_CHAR(
|
|
125
|
-
-- Si '
|
|
126
|
-
TO_DATE(jsonb_guarantee->>'
|
|
120
|
+
-- Si 'buyer__date' es DATE:
|
|
121
|
+
TO_CHAR('buyer__date' , 'DD-MM-YYYY')
|
|
122
|
+
-- Si 'created_date' es texto en formato 'DD-MM-YYYY':
|
|
123
|
+
TO_DATE(jsonb_guarantee->>'created_date', 'DD-MM-YYYY')
|
|
127
124
|
- Evitar comparar campos de tipo DATE o TIMESTAMP con strings generados por TO_CHAR.
|
|
128
125
|
Usar funciones como date_trunc() o INTERVAL directamente.
|
|
129
126
|
|
|
127
|
+
🎯 Regla para fechas que pueden venir vacías (solo TEXT / JSONB)
|
|
128
|
+
|
|
129
|
+
- Usa `TO_DATE()` ÚNICAMENTE cuando el valor de fecha sea un string:
|
|
130
|
+
- campos de tipo TEXT o VARCHAR
|
|
131
|
+
- o valores extraídos de JSONB con `->>` (por ejemplo `jsonb_credit->>'created'`).
|
|
132
|
+
|
|
133
|
+
- Si el campo de fecha es TEXTO y puede venir vacío (`''`), utiliza este patrón:
|
|
134
|
+
TO_DATE(NULLIF(campo_texto, ''), 'DD-MM-YYYY')
|
|
135
|
+
|
|
136
|
+
donde `campo_texto` debe ser SIEMPRE:
|
|
137
|
+
- un TEXT/VARCHAR, o
|
|
138
|
+
- una expresión de JSONB como `jsonb_column->>'field'`.
|
|
139
|
+
|
|
140
|
+
- **NUNCA** uses este patrón sobre columnas que ya son de tipo DATE o TIMESTAMP.
|
|
141
|
+
Ejemplos prohibidos:
|
|
142
|
+
- TO_DATE(NULLIF(bc.init_date, ''), 'DD-MM-YYYY')
|
|
143
|
+
- TO_DATE(NULLIF(c.init_date, ''), 'DD-MM-YYYY')
|
|
144
|
+
- TO_DATE(bc.init_date, 'DD-MM-YYYY')
|
|
145
|
+
- TO_DATE(c.init_date, 'DD-MM-YYYY')
|
|
146
|
+
|
|
147
|
+
- Para columnas DATE del esquema BCU (como ejemplo):
|
|
148
|
+
- `bcu_certificate.init_date`
|
|
149
|
+
- `bcu_certificate.end_date`
|
|
150
|
+
- `bcu_tender.adjudication_date`
|
|
151
|
+
- `bcu_tender.closing_date`
|
|
152
|
+
|
|
153
|
+
**Nunca** las envuelvas en `TO_DATE()` ni en `NULLIF(columna, '')`.
|
|
154
|
+
Deben usarse directamente:
|
|
155
|
+
- ORDER BY bc.init_date DESC NULLS LAST
|
|
156
|
+
- ORDER BY t.adjudication_date DESC NULLS LAST
|
|
157
|
+
|
|
130
158
|
- Cuando necesites construir fechas a partir de valores numéricos
|
|
131
159
|
(por ejemplo, año y mes), utiliza TO_DATE() con un string en formato 'YYYY-MM-DD',
|
|
132
160
|
no uses concatenación sobre literales de tipo DATE.
|
|
133
161
|
|
|
134
|
-
-
|
|
135
|
-
|
|
136
|
-
|
|
162
|
+
- No utilices TO_DATE si la columna ya es de tipo DATE o TIMESTAMP.
|
|
163
|
+
Úsala solo si el campo es tipo TEXT o VARCHAR (por ejemplo, campos que vienen de JSONB con `->>`),
|
|
164
|
+
y siempre recuerda que TO_DATE espera un string.
|
|
165
|
+
|
|
166
|
+
- Si el campo de fecha **es texto** y puede venir vacío (`''`), usa:
|
|
167
|
+
TO_DATE(NULLIF(campo_texto, ''), 'DD-MM-YYYY')
|
|
168
|
+
Esto solo aplica cuando `campo_texto` es `TEXT`/`VARCHAR` o viene de `jsonb->>'campo'`.
|
|
169
|
+
**Nunca** uses este patrón sobre columnas que ya son DATE o TIMESTAMP
|
|
170
|
+
(en esos casos simplemente ordena o filtra con la columna tal cual, usando
|
|
171
|
+
`ORDER BY columna_fecha DESC NULLS LAST`).
|
|
137
172
|
|
|
138
173
|
### operaciones sobre campos de tipo JSONB
|
|
139
174
|
- Cuando uses SUM o alguna otra función agregada sobre un valor extraído
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
<div class="custom-company-header container d-flex justify-content-between align-items-center">
|
|
3
3
|
|
|
4
4
|
{% if company_short_name and branding %}
|
|
5
|
-
<a href="{{ url_for('home', company_short_name=company_short_name) }}"
|
|
5
|
+
<a href="{{ url_for('home', company_short_name=company_short_name, lang=request.args.get('lang', 'en')) }}"
|
|
6
6
|
class="brand-name"
|
|
7
7
|
style="{{ branding.primary_text_style }}">
|
|
8
8
|
{{ branding.name }} IA
|
|
@@ -13,8 +13,33 @@
|
|
|
13
13
|
</span>
|
|
14
14
|
{% endif %}
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
<
|
|
18
|
-
|
|
19
|
-
|
|
16
|
+
{# Contenedor derecho: powered-by a la izquierda y selector de idioma a la derecha #}
|
|
17
|
+
<div class="d-flex align-items-center ms-auto">
|
|
18
|
+
<div class="me-3 d-flex align-items-center">
|
|
19
|
+
<span class="powered-by">
|
|
20
|
+
Powered by <a href="http://www.iatoolkit.com" rel="noopener noreferrer" class="iatoolkit-link">IAToolkit</a>
|
|
21
|
+
</span>
|
|
22
|
+
</div>
|
|
23
|
+
|
|
24
|
+
{% set current_lang = request.args.get('lang', 'en') %}
|
|
25
|
+
{% set has_endpoint = request.endpoint is not none %}
|
|
26
|
+
|
|
27
|
+
{% if has_endpoint %}
|
|
28
|
+
{% if request.view_args %}
|
|
29
|
+
{% set href_en = url_for(request.endpoint, lang='en', **request.view_args) %}
|
|
30
|
+
{% set href_es = url_for(request.endpoint, lang='es', **request.view_args) %}
|
|
31
|
+
{% else %}
|
|
32
|
+
{% set href_en = url_for(request.endpoint, lang='en') %}
|
|
33
|
+
{% set href_es = url_for(request.endpoint, lang='es') %}
|
|
34
|
+
{% endif %}
|
|
35
|
+
{% endif %}
|
|
36
|
+
|
|
37
|
+
<div class="language-switcher d-flex align-items-center">
|
|
38
|
+
<a href="{{ href_en }}" class="language-link {{ 'active' if current_lang == 'en' else '' }}">EN</a>
|
|
39
|
+
<span class="mx-1">|</span>
|
|
40
|
+
<a href="{{ href_es }}" class="language-link {{ 'active' if current_lang == 'es' else '' }}">ES</a>
|
|
41
|
+
</div>
|
|
42
|
+
</div>
|
|
43
|
+
|
|
44
|
+
|
|
20
45
|
</div>
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
<!-- 2. Formulario de Inicio de Sesión -->
|
|
10
10
|
<form id="login-form"
|
|
11
|
-
action="{{ url_for('login', company_short_name=company_short_name) }}"
|
|
11
|
+
action="{{ url_for('login', company_short_name=company_short_name, lang=request.args.get('lang', 'en')) }}"
|
|
12
12
|
method="post">
|
|
13
13
|
<div class="mb-3">
|
|
14
14
|
<label for="email" class="form-label d-block">{{ t('ui.signup.email_label') }}</label>
|
|
@@ -28,14 +28,14 @@
|
|
|
28
28
|
<!-- 3. Nueva Sección de Registro más Atractiva -->
|
|
29
29
|
<div class="mt-4 pt-3 text-center" style="border-top: 1px solid #e0e0e0;">
|
|
30
30
|
<span class="text-muted small">{{ t('ui.login_widget.no_account_prompt') }}</span>
|
|
31
|
-
<a href="{{ url_for('signup', company_short_name=company_short_name) }}" id="signup-link"
|
|
31
|
+
<a href="{{ url_for('signup', company_short_name=company_short_name, lang=request.args.get('lang', 'en')) }}" id="signup-link"
|
|
32
32
|
class="fw-bold ms-1 text-decoration-none" style="color: var(--brand-primary-color);">
|
|
33
33
|
{{ t('ui.login_widget.signup_link') }}</a>
|
|
34
34
|
</div>
|
|
35
35
|
|
|
36
36
|
<!-- 4. Enlace de Recuperación de Contraseña (más sutil) -->
|
|
37
37
|
<div class="text-center mt-2">
|
|
38
|
-
<a href="{{ url_for('forgot_password', company_short_name=company_short_name) }}" class="text-decoration-none text-muted" style="font-size: 0.8rem;">
|
|
38
|
+
<a href="{{ url_for('forgot_password', company_short_name=company_short_name, lang=request.args.get('lang', 'en')) }}" class="text-decoration-none text-muted" style="font-size: 0.8rem;">
|
|
39
39
|
{{ t('ui.login_widget.forgot_password_link') }}
|
|
40
40
|
</a>
|
|
41
41
|
</div>
|
iatoolkit/templates/base.html
CHANGED
|
@@ -1,6 +1,19 @@
|
|
|
1
1
|
<!DOCTYPE html>
|
|
2
2
|
<html lang="en">
|
|
3
3
|
<head>
|
|
4
|
+
{% if google_analytics_id %}
|
|
5
|
+
<!-- Google tag (gtag.js) -->
|
|
6
|
+
<script async src="https://www.googletagmanager.com/gtag/js?id=G-96G1XCM2CC"></script>
|
|
7
|
+
<script>
|
|
8
|
+
window.dataLayer = window.dataLayer || [];
|
|
9
|
+
function gtag(){dataLayer.push(arguments);}
|
|
10
|
+
gtag('js', new Date());
|
|
11
|
+
|
|
12
|
+
gtag('config', '{{ google_analytics_id }}');
|
|
13
|
+
</script>
|
|
14
|
+
{% endif %}
|
|
15
|
+
|
|
16
|
+
|
|
4
17
|
<meta charset="UTF-8">
|
|
5
18
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
19
|
<title>{% block title %}Chatbot{% endblock %}</title>
|
iatoolkit/templates/chat.html
CHANGED
|
@@ -25,10 +25,11 @@
|
|
|
25
25
|
{{ branding.name }}
|
|
26
26
|
</span>
|
|
27
27
|
<span class="ms-2" data-bs-toggle="tooltip" data-bs-placement="bottom"
|
|
28
|
-
title="Powered by IAToolkit
|
|
28
|
+
title="Powered by IAToolkit {{ license }} ver. {{ iatoolkit_version }}">
|
|
29
29
|
<i class="bi bi-info-circle" style="color: {{ branding.header_text_color }}; opacity: 0.7; font-size: 0.9rem;"></i>
|
|
30
30
|
</span>
|
|
31
|
-
|
|
31
|
+
|
|
32
|
+
</div>
|
|
32
33
|
|
|
33
34
|
<!-- Contenedor para la derecha que agrupa ID de usuario y botones -->
|
|
34
35
|
<div class="d-flex flex-column flex-md-row align-items-center">
|
|
@@ -38,14 +39,39 @@
|
|
|
38
39
|
{{ user_identifier }}
|
|
39
40
|
</span>
|
|
40
41
|
|
|
42
|
+
|
|
41
43
|
<!-- Separador Vertical (Solo visible en Desktop) -->
|
|
42
44
|
<div class="vr mx-3 d-none d-md-block"></div>
|
|
43
45
|
|
|
44
46
|
<!-- Fila 3 (Móvil) / Parte 2 de la Columna Derecha (Desktop): Iconos de Acción -->
|
|
45
47
|
<div class="d-flex align-items-center">
|
|
48
|
+
<!-- Selector de modelo LLM -->
|
|
49
|
+
<button type="button"
|
|
50
|
+
id="llm-model-button"
|
|
51
|
+
class="btn btn-sm py-1 px-3"
|
|
52
|
+
style="border-radius: 0.4rem; border: 1px solid rgba(255,255,255,0.7); background: rgba(0,0,0,0.08); color: {{ branding.header_text_color }};">
|
|
53
|
+
<i class="bi bi-cpu me-1"></i>
|
|
54
|
+
<span id="llm-model-button-label">
|
|
55
|
+
{{ (llm_available_models[0].label if llm_available_models and llm_available_models[0].label else llm_default_model) or 'Modelo IA' }}
|
|
56
|
+
</span>
|
|
57
|
+
</button>
|
|
58
|
+
<!-- Popup simple para selección de modelo -->
|
|
59
|
+
<div id="llm-model-popup"
|
|
60
|
+
class="card shadow-sm llm-model-popup"
|
|
61
|
+
style="position: absolute; z-index: 9999; display: none; min-width: 260px;">
|
|
62
|
+
<div class="card-body py-2">
|
|
63
|
+
<div class="small mb-1 fw-bold">Modelo de IA</div>
|
|
64
|
+
<div class="small mb-2 llm-model-subtitle">
|
|
65
|
+
Este modelo se usará en las próximas consultas.
|
|
66
|
+
</div>
|
|
67
|
+
<div id="llm-model-list" class="list-group list-group-flush">
|
|
68
|
+
{# El contenido se inyecta vía JavaScript con window.availableLlmModels #}
|
|
69
|
+
</div>
|
|
70
|
+
</div>
|
|
71
|
+
</div>
|
|
46
72
|
<a href="javascript:void(0);"
|
|
47
73
|
id="history-button"
|
|
48
|
-
class="action-icon-style" title="{{ t('ui.tooltips.history') }}"
|
|
74
|
+
class="ms-3 action-icon-style" title="{{ t('ui.tooltips.history') }}"
|
|
49
75
|
style="color: {{ branding.header_text_color }};">
|
|
50
76
|
<i class="bi bi-clock-history"></i>
|
|
51
77
|
</a>
|
|
@@ -77,7 +103,17 @@
|
|
|
77
103
|
title="{{ t('ui.tooltips.usage_guide') }}"
|
|
78
104
|
style="color: {{ branding.header_text_color }};">
|
|
79
105
|
<i class="bi bi-question-circle-fill"></i>
|
|
106
|
+
</a>
|
|
107
|
+
{% if user_role == "admin" and license == 'enterprise' %}
|
|
108
|
+
<a href="/{{ company_short_name }}/admin/dashboard"
|
|
109
|
+
target="_blank"
|
|
110
|
+
id="preferences-button"
|
|
111
|
+
class="ms-3 action-icon-style"
|
|
112
|
+
title="{{ t('ui.tooltips.preferences') }}"
|
|
113
|
+
style="color: {{ branding.header_text_color }};">
|
|
114
|
+
<i class="bi bi-gear"></i>
|
|
80
115
|
</a>
|
|
116
|
+
{% endif %}
|
|
81
117
|
<a href="javascript:void(0);"
|
|
82
118
|
id="logout-button"
|
|
83
119
|
class="ms-3 action-icon-style"
|
|
@@ -220,6 +256,11 @@
|
|
|
220
256
|
window.onboardingCards = {{ onboarding_cards | tojson }};
|
|
221
257
|
window.sendButtonColor = "{{ branding.send_button_color }}";
|
|
222
258
|
|
|
259
|
+
// LLM configuration from backend
|
|
260
|
+
window.defaultLlmModel = {{ llm_default_model | tojson }};
|
|
261
|
+
window.availableLlmModels = {{ llm_available_models | tojson }};
|
|
262
|
+
|
|
263
|
+
|
|
223
264
|
// JS translations helper
|
|
224
265
|
window.i18n = {{ js_translations | tojson }};
|
|
225
266
|
function t_js(key) {
|
|
@@ -238,6 +279,7 @@
|
|
|
238
279
|
<script src="{{ url_for('static', filename='js/chat_logout_button.js', _external=True) }}"></script>
|
|
239
280
|
<script src="{{ url_for('static', filename='js/chat_prompt_manager.js', _external=True) }}"></script>
|
|
240
281
|
<script src="{{ url_for('static', filename='js/chat_filepond.js', _external=True) }}"></script>
|
|
282
|
+
<script src="{{ url_for('static', filename='js/chat_model_selector.js', _external=True) }}"></script>
|
|
241
283
|
<script src="{{ url_for('static', filename='js/chat_main.js', _external=True) }}"></script>
|
|
242
284
|
|
|
243
285
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
|
|
@@ -24,7 +24,8 @@
|
|
|
24
24
|
{{ t('ui.forgot_password.subtitle') }}
|
|
25
25
|
</p>
|
|
26
26
|
|
|
27
|
-
<form action="{{ url_for('forgot_password', company_short_name=company_short_name) }}" method="post">
|
|
27
|
+
<form action="{{ url_for('forgot_password', company_short_name=company_short_name, lang=lang) }}" method="post">
|
|
28
|
+
<input type="hidden" name="lang" value="{{ lang }}">
|
|
28
29
|
<div class="mb-3">
|
|
29
30
|
<label for="email" class="form-label text-secondary">{{ t('ui.signup.email_label') }}</label>
|
|
30
31
|
<input type="email" id="email" name="email"
|
|
@@ -36,7 +37,7 @@
|
|
|
36
37
|
</form>
|
|
37
38
|
|
|
38
39
|
<div class="text-center mt-4 pt-3" style="border-top: 1px solid #e0e0e0;">
|
|
39
|
-
<a href="{{ url_for('home', company_short_name=company_short_name) }}" class="text-muted text-decoration-none fw-semibold">
|
|
40
|
+
<a href="{{ url_for('home', company_short_name=company_short_name, lang=request.args.get('lang', 'en')) }}" class="text-muted text-decoration-none fw-semibold">
|
|
40
41
|
<i class="bi bi-arrow-left me-1"></i>{{ t('ui.forgot_password.back_to_login') }}
|
|
41
42
|
</a>
|
|
42
43
|
</div>
|