iatoolkit 0.14.0__py3-none-any.whl → 0.16.1__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/base_company.py +8 -2
- iatoolkit/common/routes.py +1 -1
- iatoolkit/repositories/models.py +1 -0
- iatoolkit/repositories/profile_repo.py +1 -0
- iatoolkit/services/branding_service.py +24 -0
- iatoolkit/services/onboarding_service.py +43 -0
- iatoolkit/static/styles/chat_iatoolkit.css +22 -8
- iatoolkit/templates/home.html +1 -1
- iatoolkit/templates/{login_shell.html → onboarding_shell.html} +6 -24
- iatoolkit/views/{login_external_id_view.py → external_login_view.py} +45 -19
- iatoolkit/views/login_view.py +37 -36
- {iatoolkit-0.14.0.dist-info → iatoolkit-0.16.1.dist-info}/METADATA +1 -1
- {iatoolkit-0.14.0.dist-info → iatoolkit-0.16.1.dist-info}/RECORD +15 -14
- {iatoolkit-0.14.0.dist-info → iatoolkit-0.16.1.dist-info}/WHEEL +0 -0
- {iatoolkit-0.14.0.dist-info → iatoolkit-0.16.1.dist-info}/top_level.txt +0 -0
iatoolkit/base_company.py
CHANGED
|
@@ -26,10 +26,16 @@ class BaseCompany(ABC):
|
|
|
26
26
|
self.company = self.profile_repo.get_company_by_short_name(short_name)
|
|
27
27
|
return self.company
|
|
28
28
|
|
|
29
|
-
def _create_company(self,
|
|
29
|
+
def _create_company(self,
|
|
30
|
+
short_name: str,
|
|
31
|
+
name: str,
|
|
32
|
+
branding: dict | None = None,
|
|
33
|
+
onboarding_cards: dict | None = None
|
|
34
|
+
) -> Company:
|
|
30
35
|
company_obj = Company(short_name=short_name,
|
|
31
36
|
name=name,
|
|
32
|
-
branding=branding
|
|
37
|
+
branding=branding,
|
|
38
|
+
onboarding_cards=onboarding_cards)
|
|
33
39
|
self.company = self.profile_repo.create_company(company_obj)
|
|
34
40
|
return self.company
|
|
35
41
|
|
iatoolkit/common/routes.py
CHANGED
|
@@ -27,7 +27,7 @@ def register_views(injector, app):
|
|
|
27
27
|
from iatoolkit.views.tasks_review_view import TaskReviewView
|
|
28
28
|
from iatoolkit.views.home_view import HomeView
|
|
29
29
|
from iatoolkit.views.login_view import LoginView, InitiateLoginView
|
|
30
|
-
from iatoolkit.views.
|
|
30
|
+
from iatoolkit.views.external_login_view import InitiateExternalChatView, ExternalChatLoginView
|
|
31
31
|
from iatoolkit.views.signup_view import SignupView
|
|
32
32
|
from iatoolkit.views.verify_user_view import VerifyAccountView
|
|
33
33
|
from iatoolkit.views.forgot_password_view import ForgotPasswordView
|
iatoolkit/repositories/models.py
CHANGED
|
@@ -58,6 +58,7 @@ class Company(Base):
|
|
|
58
58
|
gemini_api_key = Column(String, nullable=True)
|
|
59
59
|
|
|
60
60
|
branding = Column(JSON, nullable=True)
|
|
61
|
+
onboarding_cards = Column(JSON, nullable=True)
|
|
61
62
|
parameters = Column(JSON, nullable=True, default={})
|
|
62
63
|
created_at = Column(DateTime, default=datetime.now)
|
|
63
64
|
allow_jwt = Column(Boolean, default=True, nullable=True)
|
|
@@ -44,6 +44,19 @@ class BrandingService:
|
|
|
44
44
|
"brand_info_text": "#055160", # Texto azul oscuro
|
|
45
45
|
"brand_info_border": "#b6effb",
|
|
46
46
|
|
|
47
|
+
# Estilos para el Asistente de Prompts ---
|
|
48
|
+
"prompt_assistant_bg": "#f8f9fa",
|
|
49
|
+
"prompt_assistant_border": "#dee2e6",
|
|
50
|
+
"prompt_assistant_icon_color": "#6c757d",
|
|
51
|
+
"prompt_assistant_button_bg": "#FFFFFF",
|
|
52
|
+
"prompt_assistant_button_text": "#495057",
|
|
53
|
+
"prompt_assistant_button_border": "#ced4da",
|
|
54
|
+
"prompt_assistant_dropdown_bg": "#f8f9fa",
|
|
55
|
+
"prompt_assistant_header_bg": "#e9ecef",
|
|
56
|
+
"prompt_assistant_header_text": "#495057",
|
|
57
|
+
"prompt_assistant_item_hover_bg": None, # Usará el primario por defecto
|
|
58
|
+
"prompt_assistant_item_hover_text": None, # Usará el texto sobre primario
|
|
59
|
+
|
|
47
60
|
# Color para el botón de Enviar ---
|
|
48
61
|
"send_button_color": "#212529" # Gris oscuro/casi negro por defecto
|
|
49
62
|
}
|
|
@@ -93,6 +106,17 @@ class BrandingService:
|
|
|
93
106
|
--brand-info-bg: {final_branding_values['brand_info_bg']};
|
|
94
107
|
--brand-info-text: {final_branding_values['brand_info_text']};
|
|
95
108
|
--brand-info-border: {final_branding_values['brand_info_border']};
|
|
109
|
+
--brand-prompt-assistant-bg: {final_branding_values['prompt_assistant_bg']};
|
|
110
|
+
--brand-prompt-assistant-border: {final_branding_values['prompt_assistant_border']};
|
|
111
|
+
--brand-prompt-assistant-icon-color: {final_branding_values['prompt_assistant_icon_color']};
|
|
112
|
+
--brand-prompt-assistant-button-bg: {final_branding_values['prompt_assistant_button_bg']};
|
|
113
|
+
--brand-prompt-assistant-button-text: {final_branding_values['prompt_assistant_button_text']};
|
|
114
|
+
--brand-prompt-assistant-button-border: {final_branding_values['prompt_assistant_button_border']};
|
|
115
|
+
--brand-prompt-assistant-dropdown-bg: {final_branding_values['prompt_assistant_dropdown_bg']};
|
|
116
|
+
--brand-prompt-assistant-header-bg: {final_branding_values['prompt_assistant_header_bg']};
|
|
117
|
+
--brand-prompt-assistant-header-text: {final_branding_values['prompt_assistant_header_text']};
|
|
118
|
+
--brand-prompt-assistant-item-hover-bg: {final_branding_values['prompt_assistant_item_hover_bg'] or final_branding_values['brand_primary_color']};
|
|
119
|
+
--brand-prompt-assistant-item-hover-text: {final_branding_values['prompt_assistant_item_hover_text'] or final_branding_values['brand_text_on_primary']};
|
|
96
120
|
|
|
97
121
|
}}
|
|
98
122
|
"""
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Copyright (c) 2024 Fernando Libedinsky
|
|
2
|
+
# Product: IAToolkit
|
|
3
|
+
#
|
|
4
|
+
# IAToolkit is open source software.
|
|
5
|
+
|
|
6
|
+
from iatoolkit.repositories.models import Company
|
|
7
|
+
from typing import List, Dict, Any
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class OnboardingService:
|
|
11
|
+
"""
|
|
12
|
+
Servicio para gestionar las tarjetas de contenido que se muestran
|
|
13
|
+
durante la pantalla de carga (onboarding).
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
def __init__(self):
|
|
17
|
+
"""
|
|
18
|
+
Define el conjunto de tarjetas de onboarding por defecto.
|
|
19
|
+
"""
|
|
20
|
+
self._default_cards = [
|
|
21
|
+
{'icon': 'fas fa-users', 'title': 'Clientes',
|
|
22
|
+
'text': 'Conozco en detalle a nuestros clientes: antigüedad, contactos, historial de operaciones.<br><br><strong>Ejemplo:</strong> ¿cuántos clientes nuevos se incorporaron a mi cartera este año?'},
|
|
23
|
+
{'icon': 'fas fa-cubes', 'title': 'Productos',
|
|
24
|
+
'text': 'Productos: características, condiciones, historial.'},
|
|
25
|
+
|
|
26
|
+
{'icon': 'fas fa-cogs', 'title': 'Personaliza tus Prompts',
|
|
27
|
+
'text': 'Utiliza la varita mágica y podrás explorar los prompts predefinidos que he preparado para ti.'},
|
|
28
|
+
{'icon': 'fas fa-table', 'title': 'Tablas y Excel',
|
|
29
|
+
'text': 'Puedes pedirme la respuesta en formato de tablas o excel.<br><br><strong>Ejemplo:</strong> dame una tabla con los 10 certificados más grandes este año.'},
|
|
30
|
+
{'icon': 'fas fa-shield-alt', 'title': 'Seguridad y Confidencialidad',
|
|
31
|
+
'text': 'Toda tu información es procesada de forma segura y confidencial dentro de nuestro entorno protegido.'}
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
def get_onboarding_cards(self, company: Company | None) -> List[Dict[str, Any]]:
|
|
35
|
+
"""
|
|
36
|
+
Retorna la lista de tarjetas de onboarding para una compañía.
|
|
37
|
+
Si la compañía tiene tarjetas personalizadas, las devuelve.
|
|
38
|
+
De lo contrario, devuelve las tarjetas por defecto.
|
|
39
|
+
"""
|
|
40
|
+
if company and company.onboarding_cards:
|
|
41
|
+
return company.onboarding_cards
|
|
42
|
+
|
|
43
|
+
return self._default_cards
|
|
@@ -168,7 +168,7 @@
|
|
|
168
168
|
|
|
169
169
|
/* 1. La caja principal que envuelve toda el área de entrada */
|
|
170
170
|
.input-area {
|
|
171
|
-
background-color: #f8f9fa;
|
|
171
|
+
background-color: var(--brand-prompt-assistant-bg, #f8f9fa);
|
|
172
172
|
}
|
|
173
173
|
|
|
174
174
|
/* 2. La barra "cápsula" que envuelve el texto y los iconos */
|
|
@@ -202,7 +202,7 @@
|
|
|
202
202
|
|
|
203
203
|
#prompt-assistant-collapse .card {
|
|
204
204
|
border-radius: 1.5rem; /* Mismo radio que el chat-input-bar */
|
|
205
|
-
border: 1px solid #dee2e6; /* Mismo borde que el chat-input-bar */
|
|
205
|
+
border: 1px solid var(--brand-prompt-assistant-border, #dee2e6); /* Mismo borde que el chat-input-bar */
|
|
206
206
|
box-shadow: none; /* Eliminamos la sombra por defecto del card */
|
|
207
207
|
}
|
|
208
208
|
|
|
@@ -241,6 +241,12 @@
|
|
|
241
241
|
color: #6c757d;
|
|
242
242
|
transition: color 0.2s ease-in-out;
|
|
243
243
|
}
|
|
244
|
+
|
|
245
|
+
/* Anulación específica para el icono de la varita mágica */
|
|
246
|
+
.chat-input-bar a[href="#prompt-assistant-collapse"] i {
|
|
247
|
+
color: var(--brand-prompt-assistant-icon-color, #6c757d);
|
|
248
|
+
}
|
|
249
|
+
|
|
244
250
|
.chat-input-bar .d-flex a:hover i {
|
|
245
251
|
color: #343a40;
|
|
246
252
|
}
|
|
@@ -302,8 +308,8 @@
|
|
|
302
308
|
}
|
|
303
309
|
|
|
304
310
|
.dropdown-menu-soft {
|
|
305
|
-
background-color: #f8f9fa;
|
|
306
|
-
border-color: #dee2e6;
|
|
311
|
+
background-color: var(--brand-prompt-assistant-dropdown-bg, #f8f9fa);
|
|
312
|
+
border-color: var(--brand-prompt-assistant-border, #dee2e6);
|
|
307
313
|
}
|
|
308
314
|
|
|
309
315
|
.dropdown-menu-soft .dropdown-item {
|
|
@@ -312,15 +318,15 @@
|
|
|
312
318
|
|
|
313
319
|
.dropdown-menu-soft .dropdown-item:hover,
|
|
314
320
|
.dropdown-menu-soft .dropdown-item:focus {
|
|
315
|
-
color: #ffffff;
|
|
316
|
-
background-color: #495057;
|
|
321
|
+
color: var(--brand-prompt-assistant-item-hover-text, #ffffff);
|
|
322
|
+
background-color: var(--brand-prompt-assistant-item-hover-bg, #495057);
|
|
317
323
|
padding-left: 1.5rem;
|
|
318
324
|
transition: all 0.15s ease-in-out;
|
|
319
325
|
}
|
|
320
326
|
|
|
321
327
|
.dropdown-menu-soft .dropdown-header {
|
|
322
|
-
background-color: #495057;
|
|
323
|
-
color: #ffffff;
|
|
328
|
+
background-color: var(--brand-prompt-assistant-header-bg, #495057);
|
|
329
|
+
color: var(--brand-prompt-assistant-header-text, #ffffff);
|
|
324
330
|
font-weight: 600;
|
|
325
331
|
margin: 4px;
|
|
326
332
|
padding: 0.4rem 1rem;
|
|
@@ -331,6 +337,14 @@
|
|
|
331
337
|
border-bottom: none;
|
|
332
338
|
}
|
|
333
339
|
|
|
340
|
+
/* Estilo para el botón principal del asistente de prompts */
|
|
341
|
+
#prompt-select-button {
|
|
342
|
+
background-color: var(--brand-prompt-assistant-button-bg, #FFFFFF);
|
|
343
|
+
color: var(--brand-prompt-assistant-button-text, #495057);
|
|
344
|
+
border-color: var(--brand-prompt-assistant-button-border, #ced4da);
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
|
|
334
348
|
#clear-selection-button {
|
|
335
349
|
position: absolute;
|
|
336
350
|
top: 50%;
|
iatoolkit/templates/home.html
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
<div class="border rounded p-4 shadow-sm bg-light">
|
|
14
14
|
<h4 class="text-muted fw-semibold text-start mb-3">login integrado (IAToolkit)</h4>
|
|
15
15
|
<form id="login-form"
|
|
16
|
-
action="{{ url_for('initiate_login', company_short_name=company_short_name) }}"
|
|
16
|
+
action="{{ url_for('initiate_login', company_short_name=company_short_name, external_login=True) }}"
|
|
17
17
|
method="post">
|
|
18
18
|
<div class="mb-3">
|
|
19
19
|
<label for="company_short_name" class="form-label d-block text-muted">Empresa</label>
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
|
|
1
|
+
|
|
2
2
|
<!DOCTYPE html>
|
|
3
3
|
<html lang="es">
|
|
4
4
|
<head>
|
|
5
5
|
<meta charset="UTF-8">
|
|
6
|
-
<title>Iniciando
|
|
6
|
+
<title>Iniciando {{ branding.name | default('IAToolkit') }} IA...</title>
|
|
7
7
|
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
|
|
8
8
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css">
|
|
9
9
|
|
|
@@ -78,11 +78,9 @@
|
|
|
78
78
|
<div id="loader-wrapper">
|
|
79
79
|
|
|
80
80
|
<h1 id="brand-header">
|
|
81
|
-
<span class="brand-name">
|
|
81
|
+
<span class="brand-name">{{ branding.name | default('IAToolkit') }}</span> <span>IA</span>
|
|
82
82
|
</h1>
|
|
83
83
|
|
|
84
|
-
<!-- ELIMINADO: El subtítulo de carga que estaba aquí -->
|
|
85
|
-
|
|
86
84
|
<div id="card-container">
|
|
87
85
|
<div id="card-icon" class="icon"><i class="fas fa-lightbulb"></i></div>
|
|
88
86
|
<h3 id="card-title">Título de la Tarjeta</h3>
|
|
@@ -106,24 +104,8 @@
|
|
|
106
104
|
|
|
107
105
|
<script>
|
|
108
106
|
$(function() {
|
|
109
|
-
const cardsData =
|
|
110
|
-
|
|
111
|
-
text: 'Conozco en detalle a los clientes de Maxxa: antiguedad, contactos, apoderados, historial de operaciones.<br><br><strong>Ejemplo:</strong> cuantos clientes nuevos de garantia se incorporaron a mi cartera este año?' },
|
|
112
|
-
{ icon: 'fas fa-cubes', title: 'Productos',
|
|
113
|
-
text: 'Productos contratados por los clientes: garantias, credito en cuotas, software.<br><br><strong>Ejemplo:</strong> Cuantos clientes de software tengo en cartera?' },
|
|
114
|
-
{ icon: 'fas fa-exchange-alt', title: 'Operaciones',
|
|
115
|
-
text: 'Operaciones de garantia y créditos: tasas, comisiones, acredores, fondos, cobranza, etc.<br><br><strong>Ejemplo:</strong> Dame una tabla con los clientes de mi cartera han emitido mas de 20 garantias este año? columnas: rut, nombre, #garantias, monto, comisión' },
|
|
116
|
-
{ icon: 'fas fa-landmark', title: 'Chilecompra',
|
|
117
|
-
text: 'Historial completo de la participacion en chilecompra de un cliente. <br><br><strong>Ejemplo:</strong> Que porcentaje de garantias FC adjudicadas en los últimos 12 meses por el cliente 1234567-8 las compro en Maxxa.' },
|
|
118
|
-
{ icon: 'fas fa-comments', title: 'Equipos Comerciales',
|
|
119
|
-
text: 'Conozco los equipos comerciales de crédito y garantia. <br><br><strong>Ejemplo:</strong> dime las 10 licitaciones mas grandes que han ganado clientes de mi cartera este año.' },
|
|
120
|
-
{ icon: 'fas fa-cogs', title: 'Personaliza tus Prompts',
|
|
121
|
-
text: 'Utiliza la varita magica y podras explorar los prompts predefinidos que he preparado para ti.' },
|
|
122
|
-
{ icon: 'fas fa-table', title: 'Tablas y Excel',
|
|
123
|
-
text: 'Puedes pedirme la respuesta en formato de tablas o excel. <br><br><strong>Ejemplo:</strong> dame una tabla con los 10 certificados mas grande este año, columnas: rut, cliente, fecha, monto, tasa, comision, acreedor...' },
|
|
124
|
-
{ icon: 'fas fa-shield-alt', title: 'Seguridad y Confidencialidad',
|
|
125
|
-
text: 'Toda tu información es procesada de forma segura y confidencial dentro de nuestro entorno protegido.' }
|
|
126
|
-
];
|
|
107
|
+
const cardsData = {{ onboarding_cards | tojson }};
|
|
108
|
+
|
|
127
109
|
let currentCardIndex = 0, autoRotateInterval;
|
|
128
110
|
const $cardContainer = $('#card-container'), $cardIcon = $('#card-icon'), $cardTitle = $('#card-title'), $cardText = $('#card-text'), $progressDots = $('#progress-dots');
|
|
129
111
|
function displayCard(index) {
|
|
@@ -152,7 +134,7 @@
|
|
|
152
134
|
clearInterval(autoRotateInterval); startAutoRotate();
|
|
153
135
|
});
|
|
154
136
|
|
|
155
|
-
|
|
137
|
+
const $loader = $('#loader-wrapper');
|
|
156
138
|
const $container = $('#content-container');
|
|
157
139
|
|
|
158
140
|
// URL para el iframe, pasada desde la vista InitiateExternalChatView
|
|
@@ -14,17 +14,24 @@ from iatoolkit.services.query_service import QueryService
|
|
|
14
14
|
from iatoolkit.services.prompt_manager_service import PromptService
|
|
15
15
|
from iatoolkit.services.jwt_service import JWTService
|
|
16
16
|
from iatoolkit.services.branding_service import BrandingService
|
|
17
|
+
from iatoolkit.services.onboarding_service import OnboardingService
|
|
18
|
+
from iatoolkit.services.jwt_service import JWTService
|
|
19
|
+
|
|
17
20
|
|
|
18
21
|
class InitiateExternalChatView(MethodView):
|
|
19
22
|
@inject
|
|
20
23
|
def __init__(self,
|
|
21
24
|
iauthentication: IAuthentication,
|
|
22
25
|
branding_service: BrandingService,
|
|
23
|
-
profile_service: ProfileService
|
|
26
|
+
profile_service: ProfileService,
|
|
27
|
+
onboarding_service: OnboardingService,
|
|
28
|
+
jwt_service: JWTService
|
|
24
29
|
):
|
|
25
30
|
self.iauthentication = iauthentication
|
|
26
31
|
self.branding_service = branding_service
|
|
27
32
|
self.profile_service = profile_service
|
|
33
|
+
self.onboarding_service = onboarding_service
|
|
34
|
+
self.jwt_service = jwt_service
|
|
28
35
|
|
|
29
36
|
def post(self, company_short_name: str):
|
|
30
37
|
data = request.get_json()
|
|
@@ -45,19 +52,29 @@ class InitiateExternalChatView(MethodView):
|
|
|
45
52
|
if not iaut.get("success"):
|
|
46
53
|
return jsonify(iaut), 401
|
|
47
54
|
|
|
48
|
-
# 2.
|
|
55
|
+
# 2. Generate a short-lived initiation token.
|
|
56
|
+
initiation_token = self.jwt_service.generate_chat_jwt(
|
|
57
|
+
company_id=company.id,
|
|
58
|
+
company_short_name=company.short_name,
|
|
59
|
+
external_user_id=external_user_id,
|
|
60
|
+
expires_delta_seconds=180
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
# 2. Get branding and onboarding data for the shell page
|
|
49
64
|
branding_data = self.branding_service.get_company_branding(company)
|
|
65
|
+
onboarding_cards = self.onboarding_service.get_onboarding_cards(company)
|
|
50
66
|
|
|
51
|
-
#
|
|
52
|
-
target_url = url_for('external_login',
|
|
67
|
+
# 4. Generate the URL for the iframe's SRC, now with the secure token.
|
|
68
|
+
target_url = url_for('external_login',
|
|
53
69
|
company_short_name=company_short_name,
|
|
54
|
-
|
|
70
|
+
init_token=initiation_token,
|
|
55
71
|
_external=True)
|
|
56
72
|
|
|
57
|
-
#
|
|
58
|
-
return render_template("
|
|
59
|
-
iframe_src_url=target_url,
|
|
60
|
-
branding=branding_data
|
|
73
|
+
# 5. Render the shell.
|
|
74
|
+
return render_template("onboarding_shell.html",
|
|
75
|
+
iframe_src_url=target_url,
|
|
76
|
+
branding=branding_data,
|
|
77
|
+
onboarding_cards=onboarding_cards
|
|
61
78
|
)
|
|
62
79
|
|
|
63
80
|
class ExternalChatLoginView(MethodView):
|
|
@@ -78,10 +95,20 @@ class ExternalChatLoginView(MethodView):
|
|
|
78
95
|
self.branding_service = branding_service
|
|
79
96
|
|
|
80
97
|
def get(self, company_short_name: str):
|
|
81
|
-
#
|
|
82
|
-
|
|
98
|
+
# 1. Validate the initiation token from the URL
|
|
99
|
+
init_token = request.args.get('init_token')
|
|
100
|
+
if not init_token:
|
|
101
|
+
return "Falta el token de iniciación.", 401
|
|
102
|
+
|
|
103
|
+
# Reutilizamos el validador de JWT, ya que el token tiene la misma estructura
|
|
104
|
+
payload = self.jwt_service.validate_chat_jwt(init_token, company_short_name)
|
|
105
|
+
if not payload:
|
|
106
|
+
return "Token de iniciación inválido o expirado.", 401
|
|
107
|
+
|
|
108
|
+
# 2. Extract user ID securely from the validated token
|
|
109
|
+
external_user_id = payload.get('external_user_id')
|
|
83
110
|
if not external_user_id:
|
|
84
|
-
return "
|
|
111
|
+
return "Token con formato incorrecto.", 400
|
|
85
112
|
|
|
86
113
|
company = self.profile_service.get_company_by_short_name(company_short_name)
|
|
87
114
|
if not company:
|
|
@@ -89,8 +116,7 @@ class ExternalChatLoginView(MethodView):
|
|
|
89
116
|
return jsonify({"error": "Empresa no encontrada"}), 404
|
|
90
117
|
|
|
91
118
|
try:
|
|
92
|
-
|
|
93
|
-
# 1. generate a new JWT, our secure access token.
|
|
119
|
+
# 3. Generate a new long-lived session JWT.
|
|
94
120
|
token = self.jwt_service.generate_chat_jwt(
|
|
95
121
|
company_id=company.id,
|
|
96
122
|
company_short_name=company.short_name,
|
|
@@ -100,19 +126,19 @@ class ExternalChatLoginView(MethodView):
|
|
|
100
126
|
if not token:
|
|
101
127
|
raise Exception("No se pudo generar el token de sesión (JWT).")
|
|
102
128
|
|
|
103
|
-
#
|
|
129
|
+
# 4. Init the company/user LLM context.
|
|
104
130
|
self.query_service.llm_init_context(
|
|
105
131
|
company_short_name=company_short_name,
|
|
106
132
|
external_user_id=external_user_id
|
|
107
133
|
)
|
|
108
134
|
|
|
109
|
-
#
|
|
135
|
+
# 5. get the prompt list from backend
|
|
110
136
|
prompts = self.prompt_service.get_user_prompts(company_short_name)
|
|
111
137
|
|
|
112
|
-
#
|
|
138
|
+
# 6. get the branding data
|
|
113
139
|
branding_data = self.branding_service.get_company_branding(company)
|
|
114
140
|
|
|
115
|
-
#
|
|
141
|
+
# 7. render the chat page with the company/user information.
|
|
116
142
|
return render_template("chat.html",
|
|
117
143
|
company_short_name=company_short_name,
|
|
118
144
|
auth_method='jwt',
|
|
@@ -125,4 +151,4 @@ class ExternalChatLoginView(MethodView):
|
|
|
125
151
|
|
|
126
152
|
except Exception as e:
|
|
127
153
|
logging.exception(f"Error al inicializar el chat para {company_short_name}/{external_user_id}: {e}")
|
|
128
|
-
return jsonify({"error": "Error interno al iniciar el chat"}), 500
|
|
154
|
+
return jsonify({"error": f"Error interno al iniciar el chat. {str(e)}"}), 500
|
iatoolkit/views/login_view.py
CHANGED
|
@@ -6,14 +6,13 @@
|
|
|
6
6
|
from flask.views import MethodView
|
|
7
7
|
from flask import request, redirect, render_template, url_for
|
|
8
8
|
from injector import inject
|
|
9
|
-
from iatoolkit.repositories.models import User
|
|
10
9
|
from iatoolkit.services.profile_service import ProfileService
|
|
11
10
|
from iatoolkit.services.prompt_manager_service import PromptService
|
|
12
|
-
from iatoolkit.services.branding_service import BrandingService
|
|
13
11
|
from iatoolkit.services.query_service import QueryService
|
|
14
12
|
import os
|
|
15
13
|
from iatoolkit.common.session_manager import SessionManager
|
|
16
14
|
from iatoolkit.services.branding_service import BrandingService
|
|
15
|
+
from iatoolkit.services.onboarding_service import OnboardingService
|
|
17
16
|
|
|
18
17
|
class InitiateLoginView(MethodView):
|
|
19
18
|
"""
|
|
@@ -24,9 +23,11 @@ class InitiateLoginView(MethodView):
|
|
|
24
23
|
@inject
|
|
25
24
|
def __init__(self,
|
|
26
25
|
profile_service: ProfileService,
|
|
27
|
-
branding_service: BrandingService,
|
|
26
|
+
branding_service: BrandingService,
|
|
27
|
+
onboarding_service: OnboardingService):
|
|
28
28
|
self.profile_service = profile_service
|
|
29
29
|
self.branding_service = branding_service
|
|
30
|
+
self.onboarding_service = onboarding_service
|
|
30
31
|
|
|
31
32
|
def post(self, company_short_name: str):
|
|
32
33
|
# get company info
|
|
@@ -56,18 +57,22 @@ class InitiateLoginView(MethodView):
|
|
|
56
57
|
},
|
|
57
58
|
alert_message=response["error"]), 400
|
|
58
59
|
|
|
59
|
-
# 2. Get branding data for the shell page
|
|
60
|
+
# 2. Get branding and onboarding data for the shell page
|
|
60
61
|
branding_data = self.branding_service.get_company_branding(company)
|
|
62
|
+
onboarding_cards = self.onboarding_service.get_onboarding_cards(company)
|
|
63
|
+
|
|
64
|
+
target_url = url_for('login',
|
|
65
|
+
company_short_name=company_short_name,
|
|
66
|
+
_external=True)
|
|
61
67
|
|
|
62
68
|
# 3. Render the shell page, passing the URL for the heavy lifting
|
|
63
69
|
# The shell's AJAX call will now be authenticated via the session cookie.
|
|
64
70
|
return render_template(
|
|
65
|
-
"
|
|
66
|
-
|
|
67
|
-
company_short_name=company_short_name,
|
|
68
|
-
_external=True),
|
|
71
|
+
"onboarding_shell.html",
|
|
72
|
+
iframe_src_url=target_url,
|
|
69
73
|
external_user_id='',
|
|
70
74
|
branding=branding_data,
|
|
75
|
+
onboarding_cards=onboarding_cards
|
|
71
76
|
)
|
|
72
77
|
|
|
73
78
|
|
|
@@ -84,52 +89,48 @@ class LoginView(MethodView):
|
|
|
84
89
|
self.branding_service = branding_service
|
|
85
90
|
|
|
86
91
|
def get(self, company_short_name: str):
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
return render_template('login.html',
|
|
93
|
-
company=company,
|
|
94
|
-
company_short_name=company_short_name)
|
|
95
|
-
|
|
96
|
-
def post(self, company_short_name: str):
|
|
97
|
-
company = self.profile_service.get_company_by_short_name(company_short_name)
|
|
98
|
-
|
|
99
|
-
# 1. The user is already authenticated by the session cookie set by InitiateLoginView.
|
|
100
|
-
# We just retrieve the user and company IDs from the session.
|
|
92
|
+
"""
|
|
93
|
+
Handles the heavy-lifting part of the login, triggered by the iframe.
|
|
94
|
+
The user is already authenticated via the session cookie.
|
|
95
|
+
"""
|
|
96
|
+
# 1. Retrieve user and company info from the session.
|
|
101
97
|
user_id = SessionManager.get('user_id')
|
|
102
98
|
if not user_id:
|
|
103
|
-
|
|
99
|
+
# This can happen if the session expires or is invalid.
|
|
100
|
+
# Redirecting to home is a safe fallback.
|
|
101
|
+
return redirect(url_for('home', company_short_name=company_short_name))
|
|
104
102
|
|
|
105
103
|
user_email = SessionManager.get('user')['email']
|
|
104
|
+
company = self.profile_service.get_company_by_short_name(company_short_name)
|
|
105
|
+
if not company:
|
|
106
|
+
return render_template('error.html', message="Empresa no encontrada"), 404
|
|
106
107
|
|
|
107
108
|
try:
|
|
108
|
-
# 2.
|
|
109
|
+
# 2. Init the company/user LLM context (the long-running task).
|
|
109
110
|
self.query_service.llm_init_context(
|
|
110
111
|
company_short_name=company_short_name,
|
|
111
112
|
local_user_id=user_id
|
|
112
113
|
)
|
|
113
114
|
|
|
114
|
-
# 3.
|
|
115
|
+
# 3. Get the prompt list from backend.
|
|
115
116
|
prompts = self.prompt_service.get_user_prompts(company_short_name)
|
|
116
117
|
|
|
117
|
-
# 4.
|
|
118
|
+
# 4. Get the branding data.
|
|
118
119
|
branding_data = self.branding_service.get_company_branding(company)
|
|
119
120
|
|
|
121
|
+
# 5. Render the final chat page.
|
|
120
122
|
return render_template("chat.html",
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
123
|
+
company_short_name=company_short_name,
|
|
124
|
+
auth_method="Session",
|
|
125
|
+
session_jwt=None, # No JWT in this flow
|
|
126
|
+
user_email=user_email,
|
|
127
|
+
branding=branding_data,
|
|
128
|
+
prompts=prompts,
|
|
129
|
+
iatoolkit_base_url=os.getenv('IATOOLKIT_BASE_URL'),
|
|
130
|
+
), 200
|
|
129
131
|
|
|
130
132
|
except Exception as e:
|
|
131
133
|
return render_template("error.html",
|
|
132
134
|
company=company,
|
|
133
135
|
company_short_name=company_short_name,
|
|
134
|
-
message="Ha ocurrido un error inesperado."), 500
|
|
135
|
-
|
|
136
|
+
message="Ha ocurrido un error inesperado."), 500
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
iatoolkit/__init__.py,sha256=4PWjMJjktixtrxF6BY405qyA50Sv967kEP2x-oil6qk,1120
|
|
2
|
-
iatoolkit/base_company.py,sha256=
|
|
2
|
+
iatoolkit/base_company.py,sha256=GacYVVujoxAwUhofRn5eZcR-s1bHtSQXLD-0SRnWSC0,4595
|
|
3
3
|
iatoolkit/cli_commands.py,sha256=G5L9xQXZ0lVFXQWBaE_KEZHyfuiT6PL1nTQRoSdnBzc,2302
|
|
4
4
|
iatoolkit/company_registry.py,sha256=tduqt3oV8iDX_IB1eA7KIgvIxE4edTcy-3qZIXh3Lzw,2549
|
|
5
5
|
iatoolkit/iatoolkit.py,sha256=9OIBCsHGAQGGIzExP95KFxND1bxaRuYQ08oHkbxv8WM,16996
|
|
6
6
|
iatoolkit/common/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
7
7
|
iatoolkit/common/auth.py,sha256=8NH6MQXfddLQd1GxrO2op3IYrrP4SMQKoKzj1o1jZmc,8486
|
|
8
8
|
iatoolkit/common/exceptions.py,sha256=EXx40n5htp7UiOM6P1xfJ9U6NMcADqm62dlFaKz7ICU,1154
|
|
9
|
-
iatoolkit/common/routes.py,sha256=
|
|
9
|
+
iatoolkit/common/routes.py,sha256=c3T4YlkYHSLD2OifSI7pfIKy4rgz9xgo5ECcGHbAHNA,4901
|
|
10
10
|
iatoolkit/common/session_manager.py,sha256=7D_RuJs60w-1zDr3fOGEz9JW7IZlSXuUHgUT87CzaUo,472
|
|
11
11
|
iatoolkit/common/util.py,sha256=08js3KLJTXICOd5sgwDp2u_kDaZO_0xG4BIuzWZnLo8,15535
|
|
12
12
|
iatoolkit/infra/__init__.py,sha256=5JqK9sZ6jBuK83zDQokUhxQ0wuJJJ9DXB8pYCLkX7X4,102
|
|
@@ -30,13 +30,13 @@ iatoolkit/repositories/__init__.py,sha256=5JqK9sZ6jBuK83zDQokUhxQ0wuJJJ9DXB8pYCL
|
|
|
30
30
|
iatoolkit/repositories/database_manager.py,sha256=UaU7k3s7IRuXhCHTy9GoCeP9K1ad0LBdj_n1a_QjGS0,3108
|
|
31
31
|
iatoolkit/repositories/document_repo.py,sha256=Y7bF1kZB1HWJsAGjWdF7P2aVYeTYNufq9ngQXp7mDkY,1124
|
|
32
32
|
iatoolkit/repositories/llm_query_repo.py,sha256=YT_t7cYGQk8rwzH_17-28aTzO-e2jUfa2rvXy8tugvA,3612
|
|
33
|
-
iatoolkit/repositories/models.py,sha256=
|
|
34
|
-
iatoolkit/repositories/profile_repo.py,sha256=
|
|
33
|
+
iatoolkit/repositories/models.py,sha256=DVmFYncVF-JKiE7SZjN8SmsDOsEx1ADlF1PpVnnfASM,13209
|
|
34
|
+
iatoolkit/repositories/profile_repo.py,sha256=vwDuVec9IDUCSyM7ecf790oqdpV36cpM2bgqP8POkHQ,4128
|
|
35
35
|
iatoolkit/repositories/tasks_repo.py,sha256=icVO_r2oPagGnnBhwVFzznnvEEU2EAx-2dlWuWvoDC4,1745
|
|
36
36
|
iatoolkit/repositories/vs_repo.py,sha256=UkpmQQiocgM5IwRBmmWhw3HHzHP6zK1nN3J3TcQgjhc,5300
|
|
37
37
|
iatoolkit/services/__init__.py,sha256=5JqK9sZ6jBuK83zDQokUhxQ0wuJJJ9DXB8pYCLkX7X4,102
|
|
38
38
|
iatoolkit/services/benchmark_service.py,sha256=CdbFYyS3FHFhNzWQEa9ZNjUlmON10DT1nKNbZQ1EUi8,5880
|
|
39
|
-
iatoolkit/services/branding_service.py,sha256=
|
|
39
|
+
iatoolkit/services/branding_service.py,sha256=gjGKMkCfW9kQJ3Zwzf4XNhrOinfjSo43uD9iG07QlFg,6981
|
|
40
40
|
iatoolkit/services/dispatcher_service.py,sha256=ykR1ye6McyCCuaBgwH6r3-PqcLAr4v4ApkPazMSBzbs,14040
|
|
41
41
|
iatoolkit/services/document_service.py,sha256=nMXrNtbHQuc9pSaten0LvKY0kT8_WngBDmZJUP3jNPw,5936
|
|
42
42
|
iatoolkit/services/excel_service.py,sha256=CJGhu7cQl9J6y_ZWSJ-M63Xm-RXR9Zs66oOR2NJErZQ,3868
|
|
@@ -45,6 +45,7 @@ iatoolkit/services/history_service.py,sha256=ZlYfaSHOcCxxc6ICTnqflaGBlzctpJdNUwX
|
|
|
45
45
|
iatoolkit/services/jwt_service.py,sha256=YoZ9h7_o9xBko-arNQv4MbcwnxoSWVNj4VbZmMo_QGY,3908
|
|
46
46
|
iatoolkit/services/load_documents_service.py,sha256=ZpB0BZ3qX1fGJGBtZtMLbFdWWx0hkPoeCS3OqJKwCTs,7291
|
|
47
47
|
iatoolkit/services/mail_service.py,sha256=2h-fcF3swZDya_o7IpgXkmuj3iEVHVCiHi7oVxU99sQ,2182
|
|
48
|
+
iatoolkit/services/onboarding_service.py,sha256=cMO2Ho1-G3wAeVNl-j25LwCMJjRwj3yKHpYKnZUFLDE,2001
|
|
48
49
|
iatoolkit/services/profile_service.py,sha256=Mxt_Hdz-SyYDuwWVu10hZnb00dKaOeONX8zp1TzpQt4,17387
|
|
49
50
|
iatoolkit/services/prompt_manager_service.py,sha256=U-XmSpkeXvv1KRN4dytdMxSYBMRSB7y-UHcb18mk0nA,8342
|
|
50
51
|
iatoolkit/services/query_service.py,sha256=CI_LUBdqolvsuh7TjY23oaQcc8s6rmmr4LqnjE81ZJc,15394
|
|
@@ -66,7 +67,7 @@ iatoolkit/static/js/chat_feedback.js,sha256=_izl49hFEUZYREcJoaPukpTs0YjDgJYUu-Qf
|
|
|
66
67
|
iatoolkit/static/js/chat_filepond.js,sha256=mzXafm7a506EpM37KATTK3zvAswO1E0KSUY1vKbwuRc,3163
|
|
67
68
|
iatoolkit/static/js/chat_history.js,sha256=G01rKSXOpLpIavycGPbfpfYg5vmPrLhkHYbCLhY3_zs,3964
|
|
68
69
|
iatoolkit/static/js/chat_main.js,sha256=BLKN5a3xP2uu0z6iF6qmgIpT1vClaZf3apcAVQBhU0g,16229
|
|
69
|
-
iatoolkit/static/styles/chat_iatoolkit.css,sha256=
|
|
70
|
+
iatoolkit/static/styles/chat_iatoolkit.css,sha256=TbdviimueZjOKVH5FFSjfIqJvLJJt1XGFRwUJgsIP5M,10887
|
|
70
71
|
iatoolkit/static/styles/chat_info.css,sha256=17DbgoNYE21VYWfb5L9-QLCpD2R1idK4imKRLwXtJLY,1058
|
|
71
72
|
iatoolkit/static/styles/chat_modal.css,sha256=pE7JY5D63Ds_d2FKdmxym4sevvg-2Mf7yo-gB7KA9vE,3730
|
|
72
73
|
iatoolkit/static/styles/llm_output.css,sha256=AlxgRSOleeCk2dLAqFWVaQ-jwZiJjcpC5rHuUv3T6VU,2312
|
|
@@ -81,29 +82,29 @@ iatoolkit/templates/chat_modals.html,sha256=3CQ430bwhebq6rAJ6Bk12PQDjt9YenqNXm5t
|
|
|
81
82
|
iatoolkit/templates/error.html,sha256=BNF-7z8AYL5vF4ZMUFMrOBt8c85kCFrm9qSHn9EiHWg,540
|
|
82
83
|
iatoolkit/templates/forgot_password.html,sha256=1lUbKg9CKnQdnySplceY_pibwYne1-mOlM38fqI1kW8,1563
|
|
83
84
|
iatoolkit/templates/header.html,sha256=179agI7rnYwP_rvJNXIiVde5E8Ec5649_XKq6eew2Hk,1263
|
|
84
|
-
iatoolkit/templates/home.html,sha256=
|
|
85
|
+
iatoolkit/templates/home.html,sha256=Bq4wSWrd9E2VRFQ4Br_nqbhipYxZTJfRMiD0hjaSNsM,7942
|
|
85
86
|
iatoolkit/templates/login.html,sha256=r4hy7MsQkfDqi6pBRNkkRiFr3GPSoHCT89R5lQLUWZc,1991
|
|
86
|
-
iatoolkit/templates/
|
|
87
|
+
iatoolkit/templates/onboarding_shell.html,sha256=iIYEe0O3RQ5FgjPigGh8SfC3bFYcJjtd2HeoibyDFLM,7463
|
|
87
88
|
iatoolkit/templates/signup.html,sha256=J8wOjUhUe_KozyThDTWHjXpSJ1ubR2IDVobThtkSRuo,3819
|
|
88
89
|
iatoolkit/templates/test.html,sha256=rwNtxC83tbCl5COZFXYvmRBxxmgFJtPNuVBd_nq9KWY,133
|
|
89
90
|
iatoolkit/views/__init__.py,sha256=5JqK9sZ6jBuK83zDQokUhxQ0wuJJJ9DXB8pYCLkX7X4,102
|
|
90
91
|
iatoolkit/views/change_password_view.py,sha256=rSebwecI1zwBgR2yvAhcfMwWpGDa4QbVAIllgtSOo9k,3940
|
|
91
92
|
iatoolkit/views/chat_token_request_view.py,sha256=wf32_A2Sq8NHYWshCwL10Tovd1znLoD0jQjzutR3sVE,4408
|
|
92
93
|
iatoolkit/views/download_file_view.py,sha256=1gZ0ipqeCn39sTrJFo1-tlewlcSF7s_YNTvE4qd0HOw,2010
|
|
94
|
+
iatoolkit/views/external_login_view.py,sha256=VyDrncAbtowZ_gOmk1kXoWhNw78xHGaz4LijIRmtWY8,6562
|
|
93
95
|
iatoolkit/views/file_store_view.py,sha256=hUm5wX4E5oqJJEPEAObEj-nPiRp5EJIICULSfAWmHCs,1933
|
|
94
96
|
iatoolkit/views/forgot_password_view.py,sha256=Rk8Qbe9Fz7Wlgje1rt29I15gFM-a089EBi2at4FT7kA,2715
|
|
95
97
|
iatoolkit/views/history_view.py,sha256=fzZrnC-RySa7ngcPe2Hmf9_s3imx6VB6MKROMcNpjoU,2064
|
|
96
98
|
iatoolkit/views/home_view.py,sha256=TihO2flkelJa9j6a0FKCMVhD-2X7BhemonB7LTne4x8,1248
|
|
97
99
|
iatoolkit/views/llmquery_view.py,sha256=rv2i3oeXlNc3Sv7Qu3DZGf37r-bMSa4N25FzG7_kPAI,2432
|
|
98
|
-
iatoolkit/views/
|
|
99
|
-
iatoolkit/views/login_view.py,sha256=mmJ-VMnT_VvQy5GkTGM8dDdG7yNjqpW-7YQgzkQmhQI,5396
|
|
100
|
+
iatoolkit/views/login_view.py,sha256=tSJiSTT7gKHediAAD2IGdVTUfkTNI1aWMt-d9J-S4lk,5562
|
|
100
101
|
iatoolkit/views/prompt_view.py,sha256=l8KHlLmkSgSLK43VbhwKED7mCN9YyfeHHh4zvx0pT0E,1257
|
|
101
102
|
iatoolkit/views/signup_view.py,sha256=NTx_2w8F6Np88FKEpDvBvJXU-bISKpDMdhhT4XFAVfk,3805
|
|
102
103
|
iatoolkit/views/tasks_review_view.py,sha256=keLsLCyOTTlcoIapnB_lbuSvLwrPVZVpBiFC_7ChbLg,3388
|
|
103
104
|
iatoolkit/views/tasks_view.py,sha256=a3anTXrJTTvbQuc6PSpOzidLKQFL4hWa7PI2Cppcz8w,4110
|
|
104
105
|
iatoolkit/views/user_feedback_view.py,sha256=G37zmP8P4LvZrSymNJ5iFXhLZg1A3BEwRfTpH1Iam5w,2652
|
|
105
106
|
iatoolkit/views/verify_user_view.py,sha256=a3q4wHJ8mKAEmgbNTOcnX4rMikROjOR3mHvCr30qGGA,2351
|
|
106
|
-
iatoolkit-0.
|
|
107
|
-
iatoolkit-0.
|
|
108
|
-
iatoolkit-0.
|
|
109
|
-
iatoolkit-0.
|
|
107
|
+
iatoolkit-0.16.1.dist-info/METADATA,sha256=ut9KzzgbvimOPWvU9sIYZuHHg0KZJW3-512ny2VSz_E,9301
|
|
108
|
+
iatoolkit-0.16.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
109
|
+
iatoolkit-0.16.1.dist-info/top_level.txt,sha256=V_w4QvDx0b1RXiy8zTCrD1Bp7AZkFe3_O0-9fMiwogg,10
|
|
110
|
+
iatoolkit-0.16.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|