iatoolkit 0.11.1__py3-none-any.whl → 0.14.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of iatoolkit might be problematic. Click here for more details.

@@ -26,9 +26,8 @@ def register_views(injector, app):
26
26
  from iatoolkit.views.tasks_view import TaskView
27
27
  from iatoolkit.views.tasks_review_view import TaskReviewView
28
28
  from iatoolkit.views.home_view import HomeView
29
- from iatoolkit.views.chat_view import ChatView
30
- from iatoolkit.views.login_view import LoginView
31
- from iatoolkit.views.external_chat_login_view import ExternalChatLoginView
29
+ from iatoolkit.views.login_view import LoginView, InitiateLoginView
30
+ from iatoolkit.views.login_external_id_view import InitiateExternalChatView, ExternalChatLoginView
32
31
  from iatoolkit.views.signup_view import SignupView
33
32
  from iatoolkit.views.verify_user_view import VerifyAccountView
34
33
  from iatoolkit.views.forgot_password_view import ForgotPasswordView
@@ -37,21 +36,22 @@ def register_views(injector, app):
37
36
  from iatoolkit.views.user_feedback_view import UserFeedbackView
38
37
  from iatoolkit.views.prompt_view import PromptView
39
38
  from iatoolkit.views.chat_token_request_view import ChatTokenRequestView
40
- from iatoolkit.views.external_login_view import ExternalLoginView
41
39
  from iatoolkit.views.download_file_view import DownloadFileView
42
40
 
43
41
  app.add_url_rule('/', view_func=HomeView.as_view('home'))
44
42
 
45
- # main chat for iatoolkit front
46
- app.add_url_rule('/<company_short_name>/chat', view_func=ChatView.as_view('chat'))
43
+ # login for external portals
44
+ app.add_url_rule('/<company_short_name>/initiate_external_chat',
45
+ view_func=InitiateExternalChatView.as_view('initiate_external_chat'))
46
+ app.add_url_rule('/<company_short_name>/external_login',
47
+ view_func=ExternalChatLoginView.as_view('external_login'))
48
+ app.add_url_rule('/auth/chat_token',
49
+ view_func=ChatTokenRequestView.as_view('chat-token'))
47
50
 
48
- # front if the company internal portal
49
- app.add_url_rule('/<company_short_name>/chat_login', view_func=ExternalChatLoginView.as_view('external_chat_login'))
50
- app.add_url_rule('/<company_short_name>/external_login/<external_user_id>', view_func=ExternalLoginView.as_view('external_login'))
51
- app.add_url_rule('/auth/chat_token', view_func=ChatTokenRequestView.as_view('chat-token'))
52
-
53
- # main pages for the iatoolkit frontend
51
+ # login for the iatoolkit integrated frontend
54
52
  app.add_url_rule('/<company_short_name>/login', view_func=LoginView.as_view('login'))
53
+ app.add_url_rule('/<company_short_name>/initiate_login', view_func=InitiateLoginView.as_view('initiate_login'))
54
+
55
55
  app.add_url_rule('/<company_short_name>/signup',view_func=SignupView.as_view('signup'))
56
56
  app.add_url_rule('/<company_short_name>/logout', 'logout', logout)
57
57
  app.add_url_rule('/logout', 'logout', logout)
iatoolkit/iatoolkit.py CHANGED
@@ -144,8 +144,13 @@ class IAToolkit:
144
144
  is_https = self._get_config_value('USE_HTTPS', 'false').lower() == 'true'
145
145
  is_dev = self._get_config_value('FLASK_ENV') == 'development'
146
146
 
147
+ # get the iatoolkit domain
148
+ parsed_url = urlparse(os.getenv('IATOOLKIT_BASE_URL'))
149
+ domain = parsed_url.netloc
150
+
147
151
  self.app.config.update({
148
152
  'VERSION': self.version,
153
+ 'SERVER_NAME': domain,
149
154
  'SECRET_KEY': self._get_config_value('FLASK_SECRET_KEY', 'iatoolkit-default-secret'),
150
155
  'SESSION_COOKIE_SAMESITE': "None" if is_https else "Lax",
151
156
  'SESSION_COOKIE_SECURE': is_https,
@@ -156,6 +161,9 @@ class IAToolkit:
156
161
  'JWT_EXPIRATION_SECONDS_CHAT': int(self._get_config_value('JWT_EXPIRATION_SECONDS_CHAT', 3600))
157
162
  })
158
163
 
164
+ if parsed_url.scheme == 'https':
165
+ self.app.config['PREFERRED_URL_SCHEME'] = 'https'
166
+
159
167
  # Configuración para tokenizers en desarrollo
160
168
  if is_dev:
161
169
  os.environ["TOKENIZERS_PARALLELISM"] = "false"
@@ -315,12 +323,8 @@ class IAToolkit:
315
323
  """Vincula las vistas después de que el injector ha sido creado"""
316
324
  from iatoolkit.views.llmquery_view import LLMQueryView
317
325
  from iatoolkit.views.home_view import HomeView
318
- from iatoolkit.views.chat_view import ChatView
319
- from iatoolkit.views.change_password_view import ChangePasswordView
320
326
 
321
327
  binder.bind(HomeView, to=HomeView)
322
- binder.bind(ChatView, to=ChatView)
323
- binder.bind(ChangePasswordView, to=ChangePasswordView)
324
328
  binder.bind(LLMQueryView, to=LLMQueryView)
325
329
 
326
330
  logging.info("✅ Views configuradas correctamente")
@@ -17,7 +17,6 @@ import secrets
17
17
  import string
18
18
  from datetime import datetime, timezone
19
19
  from iatoolkit.services.user_session_context_service import UserSessionContextService
20
- from iatoolkit.services.query_service import QueryService
21
20
 
22
21
 
23
22
  class ProfileService:
@@ -25,50 +24,43 @@ class ProfileService:
25
24
  def __init__(self,
26
25
  profile_repo: ProfileRepo,
27
26
  session_context_service: UserSessionContextService,
28
- query_service: QueryService,
29
27
  mail_app: MailApp):
30
28
  self.profile_repo = profile_repo
31
29
  self.session_context = session_context_service
32
- self.query_service = query_service
33
30
  self.mail_app = mail_app
34
31
  self.bcrypt = Bcrypt()
35
32
 
36
33
 
37
34
  def login(self, company_short_name: str, email: str, password: str) -> dict:
38
35
  try:
39
- # check if exits
36
+ # check if user exists
40
37
  user = self.profile_repo.get_user_by_email(email)
41
38
  if not user:
42
- return {"error": "Usuario no encontrado"}
39
+ return {'success': False, "message": "Usuario no encontrado"}
43
40
 
44
41
  # check the encrypted password
45
42
  if not check_password_hash(user.password, password):
46
- return {"error": "Contraseña inválida"}
43
+ return {'success': False, "message": "Contraseña inválida"}
47
44
 
48
45
  company = self.get_company_by_short_name(company_short_name)
49
46
  if not company:
50
- return {"error": "Empresa no encontrada"}
47
+ return {'success': False, "message": "Empresa no encontrada"}
51
48
 
52
- # check that user belongs to company
49
+ # check that user belongs to company
53
50
  if company not in user.companies:
54
- return {"error": "Usuario no esta autorizado para esta empresa"}
51
+ return {'success': False, "message": "Usuario no esta autorizado para esta empresa"}
55
52
 
56
53
  if not user.verified:
57
- return {"error": "Tu cuenta no ha sido verificada. Por favor, revisa tu correo."}
54
+ return {'success': False,
55
+ "message": "Tu cuenta no ha sido verificada. Por favor, revisa tu correo."}
58
56
 
59
- # clear history save user data into session manager
57
+ # save user data into session manager
60
58
  self.set_user_session(user=user, company=company)
61
59
 
62
- # initialize company context
63
- self.query_service.llm_init_context(
64
- company_short_name=company_short_name,
65
- local_user_id=user.id
66
- )
67
-
68
- return {"message": "Login exitoso"}
60
+ return {'success': True, "user": user, "message": "Login exitoso"}
69
61
  except Exception as e:
70
- logging.exception(f"login error: {str(e)}")
71
- return {"error": str(e)}
62
+ return {'success': False, "message": str(e)}
63
+
72
64
 
73
65
  def set_user_session(self, user: User, company: Company):
74
66
  SessionManager.set('user_id', user.id)
@@ -9,9 +9,9 @@
9
9
  <link href="https://cdn.jsdelivr.net/npm/bootstrap-icons/font/bootstrap-icons.css" rel="stylesheet">
10
10
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/filepond/dist/filepond.min.css">
11
11
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/sweetalert2@11/dist/sweetalert2.min.css">
12
- <link rel="stylesheet" href="{{ url_for('static', filename='styles/chat_iatoolkit.css') }}">
13
- <link rel="stylesheet" href="{{ url_for('static', filename='styles/chat_modal.css') }}">
14
- <link rel="stylesheet" href="{{ url_for('static', filename='styles/llm_output.css') }}">
12
+ <link rel="stylesheet" href="{{ url_for('static', filename='styles/chat_iatoolkit.css', _external=True) }}">
13
+ <link rel="stylesheet" href="{{ url_for('static', filename='styles/chat_modal.css', _external=True) }}">
14
+ <link rel="stylesheet" href="{{ url_for('static', filename='styles/llm_output.css', _external=True) }}">
15
15
  </head>
16
16
  <body class="d-flex flex-column p-3" style="min-height: 100vh;">
17
17
  <main class="d-flex flex-column flex-grow-1">
@@ -26,7 +26,7 @@
26
26
  <div class="d-flex align-items-center">
27
27
  <!-- 1. ID de Usuario -->
28
28
  <span style="{{ branding.secondary_text_style }}">
29
- {{ external_user_id or user.email }}
29
+ {{ external_user_id or user_email }}
30
30
  </span>
31
31
 
32
32
  <!-- 2. Separador Vertical -->
@@ -43,8 +43,8 @@
43
43
  </a>
44
44
 
45
45
  <!-- Icono de cerrar sesión (al final) -->
46
- {% if user.email %}
47
- <a href="{{ url_for('logout', company_short_name=company_short_name) }}"
46
+ {% if user_email %}
47
+ <a href="{{ url_for('logout', company_short_name=company_short_name, _external=True) }}"
48
48
  class="ms-3 action-icon-style" title="Cerrar sesión" style="color: {{ branding.header_text_color }} !important;">
49
49
  <i class="bi bi-box-arrow-right"></i>
50
50
  </a>
@@ -173,10 +173,10 @@
173
173
  </script>
174
174
 
175
175
  <!-- Carga de los scripts JS externos después de definir las variables globales -->
176
- <script src="{{ url_for('static', filename='js/chat_filepond.js') }}"></script>
177
- <script src="{{ url_for('static', filename='js/chat_history.js') }}"></script>
178
- <script src="{{ url_for('static', filename='js/chat_feedback.js') }}"></script>
179
- <script src="{{ url_for('static', filename='js/chat_main.js') }}"></script>
176
+ <script src="{{ url_for('static', filename='js/chat_filepond.js', _external=True) }}"></script>
177
+ <script src="{{ url_for('static', filename='js/chat_history.js', _external=True) }}"></script>
178
+ <script src="{{ url_for('static', filename='js/chat_feedback.js', _external=True) }}"></script>
179
+ <script src="{{ url_for('static', filename='js/chat_main.js', _external=True) }}"></script>
180
180
 
181
181
  <script>
182
182
  document.addEventListener('DOMContentLoaded', function() {
@@ -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('home', company_short_name=company_short_name) }}"
16
+ action="{{ url_for('initiate_login', company_short_name=company_short_name) }}"
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>
@@ -112,7 +112,7 @@
112
112
 
113
113
  // Actualizar action del formulario "Iniciar Sesión"
114
114
  if (selectedCompany && selectedCompany.trim() !== '') {
115
- const loginAction = '/' + selectedCompany + '/login';
115
+ const loginAction = '/' + selectedCompany + '/initiate_login';
116
116
  $('#login-form').attr('action', loginAction); // Actualizamos la URL del form
117
117
  } else {
118
118
  $('#login-form').attr('action', '#'); // URL genérica si no hay selección
@@ -156,12 +156,7 @@
156
156
  return;
157
157
  }
158
158
 
159
- const $button = $(this);
160
- const $spinner = $button.find('.spinner-border');
161
- $button.prop('disabled', true);
162
- $spinner.removeClass('d-none');
163
-
164
- fetch(`/${selectedCompany}/chat_login`, {
159
+ fetch(`/${selectedCompany}/initiate_external_chat`, {
165
160
  method: 'POST',
166
161
  headers: {
167
162
  'Content-Type': 'application/json',
@@ -188,10 +183,6 @@
188
183
  .catch(error => {
189
184
  Swal.fire({ icon: 'error', title: 'Error de Inicio de Sesión', text: error.message });
190
185
  })
191
- .finally(() => {
192
- $button.prop('disabled', false);
193
- $spinner.addClass('d-none');
194
- });
195
186
 
196
187
  });
197
188
  });
@@ -0,0 +1,185 @@
1
+ <!-- templates/iatoolkit/shell.html -->
2
+ <!DOCTYPE html>
3
+ <html lang="es">
4
+ <head>
5
+ <meta charset="UTF-8">
6
+ <title>Iniciando Maxxa IA...</title>
7
+ <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
8
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css">
9
+
10
+ <!-- Inyecta las variables CSS de la marca -->
11
+ {% if branding and branding.css_variables %}
12
+ <style>
13
+ {{ branding.css_variables|safe }}
14
+ </style>
15
+ {% endif %}
16
+
17
+ <style>
18
+ /* --- Estilos Generales --- */
19
+ body, html { margin: 0; padding: 0; height: 100%; overflow: hidden; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; }
20
+
21
+ #loader-wrapper {
22
+ position: fixed; top: 0; left: 0; width: 100%; height: 100%;
23
+ background-color: #f4f7f6;
24
+ z-index: 1000;
25
+ display: flex;
26
+ justify-content: center;
27
+ align-items: center;
28
+ flex-direction: column;
29
+ padding: 20px;
30
+ box-sizing: border-box;
31
+ transition: opacity 0.5s ease-in-out;
32
+ }
33
+
34
+ /* --- Estilos de Branding --- */
35
+ #brand-header {
36
+ font-size: 2.5rem;
37
+ font-weight: 700;
38
+ margin: 0 0 30px 0; /* Aumentamos el margen inferior para dar espacio */
39
+ color: var(--brand-secondary-color, #06326B);
40
+ }
41
+ #brand-header .brand-name {
42
+ color: var(--brand-primary-color, #FF5100);
43
+ }
44
+
45
+
46
+ /* --- Estilos de la Tarjeta (Sin cambios) --- */
47
+ #card-container {
48
+ background-color: #fff; border-radius: 12px; box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
49
+ padding: 30px; width: 90%; max-width: 450px; text-align: center; transition: opacity 0.3s ease-in-out;
50
+ }
51
+ #card-container .icon { font-size: 40px; color: var(--brand-primary-color, #FF5100); margin-bottom: 15px; }
52
+ #card-container h3 { font-size: 1.25rem; color: #333; margin-bottom: 10px; }
53
+ #card-container p { font-size: 0.95rem; color: #666; line-height: 1.5; min-height: 60px; }
54
+ .card-nav { display: flex; justify-content: space-between; align-items: center; margin-top: 20px; }
55
+ .card-nav button { background-color: var(--brand-secondary-color, #06326B); border: none; color: var(--brand-text-on-secondary, #FFFFFF); border-radius: 50%; width: 40px; height: 40px; cursor: pointer; transition: opacity 0.2s; }
56
+ .card-nav button:hover { opacity: 0.85; }
57
+ #progress-dots { display: flex; gap: 8px; }
58
+ .dot { width: 10px; height: 10px; border-radius: 50%; background-color: #ddd; transition: background-color 0.3s; }
59
+ .dot.active { background-color: var(--brand-primary-color, #FF5100); }
60
+
61
+ /* --- ESTILOS MEJORADOS: SPINNER DE CARGA --- */
62
+ #loading-status { margin-top: 30px; display: flex; align-items: center; gap: 15px; }
63
+ .spinner {
64
+ width: 30px; height: 30px; border: 4px solid rgba(0, 0, 0, 0.1);
65
+ border-top-color: var(--brand-primary-color, #FF5100);
66
+ border-radius: 50%;
67
+ animation: spin 1s linear infinite;
68
+ }
69
+ #loading-status p { font-size: 1rem; font-weight: 500; color: #555; margin: 0; }
70
+ @keyframes spin { to { transform: rotate(360deg); } }
71
+
72
+ /* --- Iframe (Sin cambios) --- */
73
+ #content-container { width: 100%; height: 100%; }
74
+ iframe { width: 100%; height: 100%; border: none; }
75
+ </style>
76
+ </head>
77
+ <body>
78
+ <div id="loader-wrapper">
79
+
80
+ <h1 id="brand-header">
81
+ <span class="brand-name">Maxxa</span><span>IA</span>
82
+ </h1>
83
+
84
+ <!-- ELIMINADO: El subtítulo de carga que estaba aquí -->
85
+
86
+ <div id="card-container">
87
+ <div id="card-icon" class="icon"><i class="fas fa-lightbulb"></i></div>
88
+ <h3 id="card-title">Título de la Tarjeta</h3>
89
+ <p id="card-text">Descripción de la tarjeta de capacitación.</p>
90
+ <div class="card-nav">
91
+ <button id="prev-card" aria-label="Anterior"><i class="fas fa-chevron-left"></i></button>
92
+ <div id="progress-dots"></div>
93
+ <button id="next-card" aria-label="Siguiente"><i class="fas fa-chevron-right"></i></button>
94
+ </div>
95
+ </div>
96
+
97
+ <!-- MEJORADO: Texto de estado ahora junto al spinner -->
98
+ <div id="loading-status">
99
+ <div class="spinner"></div>
100
+ <p>Inicializando el contexto de Maxxa para la IA...</p>
101
+ </div>
102
+
103
+ </div>
104
+
105
+ <div id="content-container"></div>
106
+
107
+ <script>
108
+ $(function() {
109
+ const cardsData = [
110
+ { icon: 'fas fa-users', title: 'Clientes',
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
+ ];
127
+ let currentCardIndex = 0, autoRotateInterval;
128
+ const $cardContainer = $('#card-container'), $cardIcon = $('#card-icon'), $cardTitle = $('#card-title'), $cardText = $('#card-text'), $progressDots = $('#progress-dots');
129
+ function displayCard(index) {
130
+ $cardContainer.css('opacity', 0);
131
+ setTimeout(() => {
132
+ const card = cardsData[index];
133
+ $cardIcon.html(`<i class="${card.icon}"></i>`);
134
+ $cardTitle.text(card.title);
135
+ $cardText.html(card.text);
136
+ $progressDots.find('.dot').removeClass('active').eq(index).addClass('active');
137
+ $cardContainer.css('opacity', 1);
138
+ }, 300);
139
+ }
140
+ function startAutoRotate() { autoRotateInterval = setInterval(() => $('#next-card').click(), 5000); }
141
+ cardsData.forEach(() => $progressDots.append('<div class="dot"></div>'));
142
+ displayCard(currentCardIndex);
143
+ startAutoRotate();
144
+ $('#next-card').on('click', function() {
145
+ currentCardIndex = (currentCardIndex + 1) % cardsData.length;
146
+ displayCard(currentCardIndex);
147
+ clearInterval(autoRotateInterval); startAutoRotate();
148
+ });
149
+ $('#prev-card').on('click', function() {
150
+ currentCardIndex = (currentCardIndex - 1 + cardsData.length) % cardsData.length;
151
+ displayCard(currentCardIndex);
152
+ clearInterval(autoRotateInterval); startAutoRotate();
153
+ });
154
+
155
+ const $loader = $('#loader-wrapper');
156
+ const $container = $('#content-container');
157
+
158
+ // URL para el iframe, pasada desde la vista InitiateExternalChatView
159
+ const iframeSrc = "{{ iframe_src_url }}";
160
+
161
+ // Creamos el elemento iframe
162
+ const iframe = document.createElement('iframe');
163
+ iframe.src = iframeSrc;
164
+
165
+ // Estilos para que ocupe toda la pantalla
166
+ iframe.style.width = '100%';
167
+ iframe.style.height = '100%';
168
+ iframe.style.border = 'none';
169
+ iframe.style.display = 'none'; // Empezamos oculto
170
+
171
+ // Evento que se dispara cuando el iframe ha terminado de cargar su contenido
172
+ iframe.onload = function() {
173
+ // Mostramos el iframe
174
+ iframe.style.display = 'block';
175
+ // Ocultamos la animación de carga con una transición suave
176
+ $loader.css('opacity', 0);
177
+ setTimeout(() => $loader.hide(), 500); // Lo eliminamos del DOM después de la transición
178
+ };
179
+
180
+ // Añadimos el iframe al contenedor en el DOM
181
+ $container.append(iframe);
182
+ });
183
+ </script>
184
+ </body>
185
+ </html>
@@ -34,7 +34,7 @@ class HistoryView(MethodView):
34
34
  return jsonify(iaut), 401
35
35
 
36
36
  external_user_id = data.get("external_user_id")
37
- local_user_id = data.get("local_user_id", 0)
37
+ local_user_id = iaut.get("local_user_id", 0)
38
38
 
39
39
  try:
40
40
  response = self.history_service.get_history(
@@ -5,7 +5,7 @@
5
5
 
6
6
  import os
7
7
  import logging
8
- from flask import request, jsonify, render_template
8
+ from flask import request, jsonify, render_template, url_for, session
9
9
  from flask.views import MethodView
10
10
  from injector import inject
11
11
  from iatoolkit.common.auth import IAuthentication
@@ -15,22 +15,16 @@ 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
17
 
18
- class ExternalChatLoginView(MethodView):
18
+ class InitiateExternalChatView(MethodView):
19
19
  @inject
20
20
  def __init__(self,
21
- profile_service: ProfileService,
22
- query_service: QueryService,
23
- prompt_service: PromptService,
24
21
  iauthentication: IAuthentication,
25
- jwt_service: JWTService,
26
- branding_service: BrandingService
22
+ branding_service: BrandingService,
23
+ profile_service: ProfileService
27
24
  ):
28
- self.profile_service = profile_service
29
- self.query_service = query_service
30
- self.prompt_service = prompt_service
31
25
  self.iauthentication = iauthentication
32
- self.jwt_service = jwt_service
33
26
  self.branding_service = branding_service
27
+ self.profile_service = profile_service
34
28
 
35
29
  def post(self, company_short_name: str):
36
30
  data = request.get_json()
@@ -39,7 +33,11 @@ class ExternalChatLoginView(MethodView):
39
33
 
40
34
  external_user_id = data['external_user_id']
41
35
 
42
- # 1. get access credentials
36
+ company = self.profile_service.get_company_by_short_name(company_short_name)
37
+ if not company:
38
+ return jsonify({"error": "Empresa no encontrada"}), 404
39
+
40
+ # 1. verify access credentials quickly
43
41
  iaut = self.iauthentication.verify(
44
42
  company_short_name,
45
43
  body_external_user_id=external_user_id
@@ -47,11 +45,51 @@ class ExternalChatLoginView(MethodView):
47
45
  if not iaut.get("success"):
48
46
  return jsonify(iaut), 401
49
47
 
48
+ # 2. Get branding data for the shell page
49
+ branding_data = self.branding_service.get_company_branding(company)
50
+
51
+ # Generamos la URL para el SRC del iframe, añadiendo el usuario como un query parameter.
52
+ target_url = url_for('external_login', # Apunta a la vista del chat
53
+ company_short_name=company_short_name,
54
+ external_user_id=external_user_id, # Se añadirá como ?external_user_id=...
55
+ _external=True)
56
+
57
+ # Renderizamos el shell para un iframe.
58
+ return render_template("login_shell.html",
59
+ iframe_src_url=target_url, # Le cambiamos el nombre para más claridad
60
+ branding=branding_data
61
+ )
62
+
63
+ class ExternalChatLoginView(MethodView):
64
+ @inject
65
+ def __init__(self,
66
+ profile_service: ProfileService,
67
+ query_service: QueryService,
68
+ prompt_service: PromptService,
69
+ iauthentication: IAuthentication,
70
+ jwt_service: JWTService,
71
+ branding_service: BrandingService
72
+ ):
73
+ self.profile_service = profile_service
74
+ self.query_service = query_service
75
+ self.prompt_service = prompt_service
76
+ self.iauthentication = iauthentication
77
+ self.jwt_service = jwt_service
78
+ self.branding_service = branding_service
79
+
80
+ def get(self, company_short_name: str):
81
+ # Leemos el user_id desde los parámetros de la URL (?external_user_id=...)
82
+ external_user_id = request.args.get('external_user_id')
83
+ if not external_user_id:
84
+ return "Falta el parámetro external_user_id en la URL", 400
85
+
50
86
  company = self.profile_service.get_company_by_short_name(company_short_name)
51
87
  if not company:
88
+ logging.error(f'Company {company_short_name} not found')
52
89
  return jsonify({"error": "Empresa no encontrada"}), 404
53
90
 
54
91
  try:
92
+
55
93
  # 1. generate a new JWT, our secure access token.
56
94
  token = self.jwt_service.generate_chat_jwt(
57
95
  company_id=company.id,
@@ -75,20 +113,15 @@ class ExternalChatLoginView(MethodView):
75
113
  branding_data = self.branding_service.get_company_branding(company)
76
114
 
77
115
  # 5. render the chat page with the company/user information.
78
- user_agent = request.user_agent
79
- is_mobile = user_agent.platform in ["android", "iphone", "ipad"] or "mobile" in user_agent.string.lower()
80
-
81
- chat_html = render_template("chat.html",
116
+ return render_template("chat.html",
82
117
  company_short_name=company_short_name,
83
- branding=branding_data,
118
+ auth_method='jwt',
119
+ session_jwt=token,
84
120
  external_user_id=external_user_id,
85
- is_mobile=is_mobile,
86
- auth_method='jwt', # login method is JWT
87
- session_jwt=token, # pass the token to the front-end
88
- iatoolkit_base_url=os.getenv('IATOOLKIT_BASE_URL'),
121
+ branding=branding_data,
89
122
  prompts=prompts,
90
- external_login=True)
91
- return chat_html, 200
123
+ iatoolkit_base_url=os.getenv('IATOOLKIT_BASE_URL'),
124
+ ), 200
92
125
 
93
126
  except Exception as e:
94
127
  logging.exception(f"Error al inicializar el chat para {company_short_name}/{external_user_id}: {e}")
@@ -6,12 +6,82 @@
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
9
10
  from iatoolkit.services.profile_service import ProfileService
11
+ from iatoolkit.services.prompt_manager_service import PromptService
12
+ from iatoolkit.services.branding_service import BrandingService
13
+ from iatoolkit.services.query_service import QueryService
14
+ import os
15
+ from iatoolkit.common.session_manager import SessionManager
16
+ from iatoolkit.services.branding_service import BrandingService
17
+
18
+ class InitiateLoginView(MethodView):
19
+ """
20
+ Handles the initial, fast part of the standard login process.
21
+ Authenticates user credentials, sets up the server-side session,
22
+ and immediately returns the loading shell page.
23
+ """
24
+ @inject
25
+ def __init__(self,
26
+ profile_service: ProfileService,
27
+ branding_service: BrandingService,):
28
+ self.profile_service = profile_service
29
+ self.branding_service = branding_service
30
+
31
+ def post(self, company_short_name: str):
32
+ # get company info
33
+ company = self.profile_service.get_company_by_short_name(company_short_name)
34
+ if not company:
35
+ return render_template('error.html',
36
+ message="Empresa no encontrada"), 404
37
+
38
+ email = request.form.get('email')
39
+ password = request.form.get('password')
40
+
41
+ # 1. authenticate the user
42
+ response = self.profile_service.login(
43
+ company_short_name=company_short_name,
44
+ email=email,
45
+ password=password
46
+ )
47
+
48
+ if not response['success']:
49
+ return render_template(
50
+ 'login.html',
51
+ company_short_name=company_short_name,
52
+ company=company,
53
+ form_data={
54
+ "email": email,
55
+ "password": password,
56
+ },
57
+ alert_message=response["error"]), 400
58
+
59
+ # 2. Get branding data for the shell page
60
+ branding_data = self.branding_service.get_company_branding(company)
61
+
62
+ # 3. Render the shell page, passing the URL for the heavy lifting
63
+ # The shell's AJAX call will now be authenticated via the session cookie.
64
+ return render_template(
65
+ "login_shell.html",
66
+ data_source_url=url_for('login',
67
+ company_short_name=company_short_name,
68
+ _external=True),
69
+ external_user_id='',
70
+ branding=branding_data,
71
+ )
72
+
10
73
 
11
74
  class LoginView(MethodView):
12
75
  @inject
13
- def __init__(self, profile_service: ProfileService):
76
+ def __init__(self,
77
+ profile_service: ProfileService,
78
+ query_service: QueryService,
79
+ prompt_service: PromptService,
80
+ branding_service: BrandingService):
14
81
  self.profile_service = profile_service
82
+ self.query_service = query_service
83
+ self.prompt_service = prompt_service
84
+ self.branding_service = branding_service
15
85
 
16
86
  def get(self, company_short_name: str):
17
87
  # get company info
@@ -24,33 +94,38 @@ class LoginView(MethodView):
24
94
  company_short_name=company_short_name)
25
95
 
26
96
  def post(self, company_short_name: str):
27
- # get company info
28
97
  company = self.profile_service.get_company_by_short_name(company_short_name)
29
- if not company:
30
- return render_template('error.html', message="Empresa no encontrada"), 404
31
98
 
32
- email = request.form.get('email')
33
- try:
34
- password = request.form.get('password')
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.
101
+ user_id = SessionManager.get('user_id')
102
+ if not user_id:
103
+ return render_template('error.html', message="Usuario no encontrado"), 404
104
+
105
+ user_email = SessionManager.get('user')['email']
35
106
 
36
- response = self.profile_service.login(
107
+ try:
108
+ # 2. init the company/user LLM context.
109
+ self.query_service.llm_init_context(
37
110
  company_short_name=company_short_name,
38
- email=email,
39
- password=password
40
- )
111
+ local_user_id=user_id
112
+ )
41
113
 
42
- if "error" in response:
43
- return render_template(
44
- 'login.html',
114
+ # 3. get the prompt list from backend
115
+ prompts = self.prompt_service.get_user_prompts(company_short_name)
116
+
117
+ # 4. get the branding data
118
+ branding_data = self.branding_service.get_company_branding(company)
119
+
120
+ return render_template("chat.html",
45
121
  company_short_name=company_short_name,
46
- company=company,
47
- form_data={
48
- "email": email,
49
- "password": password,
50
- },
51
- alert_message=response["error"]), 400
52
-
53
- return redirect(url_for('chat', company_short_name=company_short_name))
122
+ auth_method="Session",
123
+ session_jwt=None, # No JWT in this flow
124
+ user_email=user_email,
125
+ branding=branding_data,
126
+ prompts=prompts,
127
+ iatoolkit_base_url=os.getenv('IATOOLKIT_BASE_URL'),
128
+ ), 200
54
129
 
55
130
  except Exception as e:
56
131
  return render_template("error.html",
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: iatoolkit
3
- Version: 0.11.1
3
+ Version: 0.14.0
4
4
  Summary: IAToolkit
5
5
  Author: Fernando Libedinsky
6
6
  License-Expression: MIT
@@ -2,11 +2,11 @@ iatoolkit/__init__.py,sha256=4PWjMJjktixtrxF6BY405qyA50Sv967kEP2x-oil6qk,1120
2
2
  iatoolkit/base_company.py,sha256=4usUdOC57Nk1XsawAEyC7mlzb0jROadu64YcYf6poiM,4371
3
3
  iatoolkit/cli_commands.py,sha256=G5L9xQXZ0lVFXQWBaE_KEZHyfuiT6PL1nTQRoSdnBzc,2302
4
4
  iatoolkit/company_registry.py,sha256=tduqt3oV8iDX_IB1eA7KIgvIxE4edTcy-3qZIXh3Lzw,2549
5
- iatoolkit/iatoolkit.py,sha256=EXmHQEgLCqbBP7Cwq6-O1NPj7O3M_2Cg9JLp5xa41ig,16960
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=8_wvrFiB5w5Sq-5gZfIDz9JVPROd9JED5oxkX1N87gY,4923
9
+ iatoolkit/common/routes.py,sha256=mzbljACSZeJmJ6S9BZvTTRujTRnrEU-VKTqNdmfW3hs,4904
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
@@ -45,7 +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/profile_service.py,sha256=azaCQtRJwQayg-3NV6k0lX97SFiF12emhz60S4CWv-M,17621
48
+ iatoolkit/services/profile_service.py,sha256=Mxt_Hdz-SyYDuwWVu10hZnb00dKaOeONX8zp1TzpQt4,17387
49
49
  iatoolkit/services/prompt_manager_service.py,sha256=U-XmSpkeXvv1KRN4dytdMxSYBMRSB7y-UHcb18mk0nA,8342
50
50
  iatoolkit/services/query_service.py,sha256=CI_LUBdqolvsuh7TjY23oaQcc8s6rmmr4LqnjE81ZJc,15394
51
51
  iatoolkit/services/search_service.py,sha256=i1xGWu7ORKIIDH0aAQBkF86dVVbLQ0Yrooz5TiZ6aGo,1823
@@ -74,37 +74,36 @@ iatoolkit/system_prompts/format_styles.prompt,sha256=MSMe1qvR3cF_0IbFshn8R0z6Wx6
74
74
  iatoolkit/system_prompts/query_main.prompt,sha256=w_9ybgWgiQH4V_RbAXqsvz0M7oOuiyhxcwf-D0CgfA4,3017
75
75
  iatoolkit/system_prompts/sql_rules.prompt,sha256=y4nURVnb9AyFwt-lrbMNBHHtZlhk6kC9grYoOhRnrJo,59174
76
76
  iatoolkit/templates/about.html,sha256=ciC08grUVz5qLzdzDDqDX31xirg5PrJIRYabWpV9oA8,294
77
- iatoolkit/templates/base.html,sha256=LXXB8oPrcBFkf2pLfOSyAaSh66kHbs4SEujpFL3h9Nw,2163
77
+ iatoolkit/templates/base.html,sha256=TojvSnVvXkTe7Kpt_BBWoXFfZN6dveKD0VqQjUOXdgU,2212
78
78
  iatoolkit/templates/change_password.html,sha256=DFfQSFcZ2YJZNFis2IXfzEKStxTf4i9f4eQ_6GiyNs8,2342
79
- iatoolkit/templates/chat.html,sha256=xaQk5McHRO8VF2LCBbr4vT0d2fFNy2GW61DwCYht-_M,9371
79
+ iatoolkit/templates/chat.html,sha256=pQm1vDikaSsvleJK0LglL1BAeoLbwPLe4FYtLIsW4T8,9451
80
80
  iatoolkit/templates/chat_modals.html,sha256=3CQ430bwhebq6rAJ6Bk12PQDjt9YenqNXm5thC5WP2Y,5771
81
81
  iatoolkit/templates/error.html,sha256=BNF-7z8AYL5vF4ZMUFMrOBt8c85kCFrm9qSHn9EiHWg,540
82
82
  iatoolkit/templates/forgot_password.html,sha256=1lUbKg9CKnQdnySplceY_pibwYne1-mOlM38fqI1kW8,1563
83
83
  iatoolkit/templates/header.html,sha256=179agI7rnYwP_rvJNXIiVde5E8Ec5649_XKq6eew2Hk,1263
84
- iatoolkit/templates/home.html,sha256=HpJmz0rCMBt3XYd83hecBCESvMg85n56PV5XvE_8Q_g,8201
84
+ iatoolkit/templates/home.html,sha256=UWtAn19_S-k6e8_UoWBFeeELbMhJRxXLwxNH7AC4Lf0,7921
85
85
  iatoolkit/templates/login.html,sha256=r4hy7MsQkfDqi6pBRNkkRiFr3GPSoHCT89R5lQLUWZc,1991
86
+ iatoolkit/templates/login_shell.html,sha256=d_dAgbZ2JqCc96FDX_kA6sRofAZ_qc7D1N6Zyto9ZJ8,9727
86
87
  iatoolkit/templates/signup.html,sha256=J8wOjUhUe_KozyThDTWHjXpSJ1ubR2IDVobThtkSRuo,3819
87
88
  iatoolkit/templates/test.html,sha256=rwNtxC83tbCl5COZFXYvmRBxxmgFJtPNuVBd_nq9KWY,133
88
89
  iatoolkit/views/__init__.py,sha256=5JqK9sZ6jBuK83zDQokUhxQ0wuJJJ9DXB8pYCLkX7X4,102
89
90
  iatoolkit/views/change_password_view.py,sha256=rSebwecI1zwBgR2yvAhcfMwWpGDa4QbVAIllgtSOo9k,3940
90
91
  iatoolkit/views/chat_token_request_view.py,sha256=wf32_A2Sq8NHYWshCwL10Tovd1znLoD0jQjzutR3sVE,4408
91
- iatoolkit/views/chat_view.py,sha256=BD1N-Jo9IOoS6baX1bzdM7DKa2zepVHZnJIxiF0vNc8,2381
92
92
  iatoolkit/views/download_file_view.py,sha256=1gZ0ipqeCn39sTrJFo1-tlewlcSF7s_YNTvE4qd0HOw,2010
93
- iatoolkit/views/external_chat_login_view.py,sha256=h-Xr7UkQM7QxLZIDQ0fXb-BUfPbABQ1gjiP--FrXnpc,4075
94
- iatoolkit/views/external_login_view.py,sha256=EHxN2omqTDkWyMp0FVCNDFt-JJ2hpg8LvprKanGR1gY,1355
95
93
  iatoolkit/views/file_store_view.py,sha256=hUm5wX4E5oqJJEPEAObEj-nPiRp5EJIICULSfAWmHCs,1933
96
94
  iatoolkit/views/forgot_password_view.py,sha256=Rk8Qbe9Fz7Wlgje1rt29I15gFM-a089EBi2at4FT7kA,2715
97
- iatoolkit/views/history_view.py,sha256=8sqc9i8hN5bbRs3mSjurqKEZaXKANTQqATfwVAS4qSM,2064
95
+ iatoolkit/views/history_view.py,sha256=fzZrnC-RySa7ngcPe2Hmf9_s3imx6VB6MKROMcNpjoU,2064
98
96
  iatoolkit/views/home_view.py,sha256=TihO2flkelJa9j6a0FKCMVhD-2X7BhemonB7LTne4x8,1248
99
97
  iatoolkit/views/llmquery_view.py,sha256=rv2i3oeXlNc3Sv7Qu3DZGf37r-bMSa4N25FzG7_kPAI,2432
100
- iatoolkit/views/login_view.py,sha256=MI87rGB1QpxEVxWy-tR2q7s9ms9pcFLIW8ZmNQh1EFE,2332
98
+ iatoolkit/views/login_external_id_view.py,sha256=bkpsGFLxg9MPhRyLdvtfzlOIQFZgQVzNKPIJbnsHTPY,5524
99
+ iatoolkit/views/login_view.py,sha256=mmJ-VMnT_VvQy5GkTGM8dDdG7yNjqpW-7YQgzkQmhQI,5396
101
100
  iatoolkit/views/prompt_view.py,sha256=l8KHlLmkSgSLK43VbhwKED7mCN9YyfeHHh4zvx0pT0E,1257
102
101
  iatoolkit/views/signup_view.py,sha256=NTx_2w8F6Np88FKEpDvBvJXU-bISKpDMdhhT4XFAVfk,3805
103
102
  iatoolkit/views/tasks_review_view.py,sha256=keLsLCyOTTlcoIapnB_lbuSvLwrPVZVpBiFC_7ChbLg,3388
104
103
  iatoolkit/views/tasks_view.py,sha256=a3anTXrJTTvbQuc6PSpOzidLKQFL4hWa7PI2Cppcz8w,4110
105
104
  iatoolkit/views/user_feedback_view.py,sha256=G37zmP8P4LvZrSymNJ5iFXhLZg1A3BEwRfTpH1Iam5w,2652
106
105
  iatoolkit/views/verify_user_view.py,sha256=a3q4wHJ8mKAEmgbNTOcnX4rMikROjOR3mHvCr30qGGA,2351
107
- iatoolkit-0.11.1.dist-info/METADATA,sha256=5vmAxDm05jysqCbNZe1lJqpc3N--YhpxBizGrQ1-CJ8,9301
108
- iatoolkit-0.11.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
109
- iatoolkit-0.11.1.dist-info/top_level.txt,sha256=V_w4QvDx0b1RXiy8zTCrD1Bp7AZkFe3_O0-9fMiwogg,10
110
- iatoolkit-0.11.1.dist-info/RECORD,,
106
+ iatoolkit-0.14.0.dist-info/METADATA,sha256=VYEM96_CE62ebzB8ScujIwbcjnC5T6qEzzr8hQep0Xw,9301
107
+ iatoolkit-0.14.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
108
+ iatoolkit-0.14.0.dist-info/top_level.txt,sha256=V_w4QvDx0b1RXiy8zTCrD1Bp7AZkFe3_O0-9fMiwogg,10
109
+ iatoolkit-0.14.0.dist-info/RECORD,,
@@ -1,58 +0,0 @@
1
- # Copyright (c) 2024 Fernando Libedinsky
2
- # Product: IAToolkit
3
- #
4
- # IAToolkit is open source software.
5
-
6
- from flask import render_template, request, jsonify
7
- from iatoolkit.services.profile_service import ProfileService
8
- from flask.views import MethodView
9
- from injector import inject
10
- import os
11
- from iatoolkit.common.auth import IAuthentication
12
- from iatoolkit.services.prompt_manager_service import PromptService
13
- from iatoolkit.services.branding_service import BrandingService
14
-
15
-
16
- class ChatView(MethodView):
17
- @inject
18
- def __init__(self,
19
- iauthentication: IAuthentication,
20
- prompt_service: PromptService,
21
- profile_service: ProfileService,
22
- branding_service: BrandingService
23
- ):
24
- self.iauthentication = iauthentication
25
- self.profile_service = profile_service
26
- self.prompt_service = prompt_service
27
- self.branding_service = branding_service
28
-
29
- def get(self, company_short_name: str):
30
- # get access credentials
31
- iaut = self.iauthentication.verify(company_short_name)
32
- if not iaut.get("success"):
33
- return jsonify(iaut), 401
34
-
35
- user_agent = request.user_agent
36
- is_mobile = user_agent.platform in ["android", "iphone", "ipad"] or "mobile" in user_agent.string.lower()
37
- alert_message = request.args.get('alert_message', None)
38
-
39
- # 1. get company info
40
- company = self.profile_service.get_company_by_short_name(company_short_name)
41
- if not company:
42
- return render_template('error.html', message="Empresa no encontrada"), 404
43
-
44
- # 2. get the company prompts
45
- prompts = self.prompt_service.get_user_prompts(company_short_name)
46
-
47
- # 3. get the branding data
48
- branding_data = self.branding_service.get_company_branding(company)
49
-
50
- return render_template("chat.html",
51
- branding=branding_data,
52
- company_short_name=company_short_name,
53
- is_mobile=is_mobile,
54
- alert_message=alert_message,
55
- alert_icon='success' if alert_message else None,
56
- iatoolkit_base_url=os.getenv('IATOOLKIT_BASE_URL', 'http://localhost:5000'),
57
- prompts=prompts
58
- )
@@ -1,40 +0,0 @@
1
- # Copyright (c) 2024 Fernando Libedinsky
2
- # Product: IAToolkit
3
- #
4
- # IAToolkit is open source software.
5
-
6
- from flask.views import MethodView
7
- from injector import inject
8
- from iatoolkit.common.auth import IAuthentication
9
- from iatoolkit.services.query_service import QueryService
10
- from flask import jsonify
11
- import logging
12
-
13
- class ExternalLoginView(MethodView):
14
-
15
- @inject
16
- def __init__(self,
17
- iauthentication: IAuthentication,
18
- query_service: QueryService
19
- ):
20
- self.iauthentication = iauthentication
21
- self.query_service = query_service
22
-
23
- def get(self, company_short_name: str, external_user_id: str):
24
- # 1. get access credentials
25
- iaut = self.iauthentication.verify(company_short_name, external_user_id)
26
- if not iaut.get("success"):
27
- return jsonify(iaut), 401
28
-
29
- try:
30
- # initialize the context
31
- self.query_service.llm_init_context(
32
- company_short_name=company_short_name,
33
- external_user_id=external_user_id
34
- )
35
-
36
- return {'status': 'OK'}, 200
37
- except Exception as e:
38
- logging.exception(
39
- f"Error inesperado al inicializar el contexto durante el login para company {company_short_name}: {e}")
40
- return jsonify({"error_message": str(e)}), 500