iatoolkit 0.55.0__py3-none-any.whl → 0.55.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.

Potentially problematic release.


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

@@ -25,7 +25,7 @@ def register_views(injector, app):
25
25
  from iatoolkit.views.llmquery_api_view import LLMQueryApiView
26
26
  from iatoolkit.views.tasks_view import TaskView
27
27
  from iatoolkit.views.tasks_review_view import TaskReviewView
28
- from iatoolkit.views.login_test_view import LoginTest
28
+ from iatoolkit.views.login_simulation_view import LoginSimulationView
29
29
  from iatoolkit.views.login_view import LoginView, FinalizeContextView
30
30
  from iatoolkit.views.external_login_view import ExternalLoginView
31
31
  from iatoolkit.views.signup_view import SignupView
@@ -112,7 +112,8 @@ def register_views(injector, app):
112
112
  abort(404)
113
113
 
114
114
  # login testing (old home page)
115
- app.add_url_rule('/login_test', view_func=LoginTest.as_view('login_test'))
115
+ app.add_url_rule('/login_test/<company_short_name>/<external_user_id>',
116
+ view_func=LoginSimulationView.as_view('login_test'))
116
117
 
117
118
  app.add_url_rule(
118
119
  '/about', # URL de la ruta
iatoolkit/iatoolkit.py CHANGED
@@ -19,7 +19,7 @@ from werkzeug.middleware.proxy_fix import ProxyFix
19
19
  from injector import Binder, singleton, Injector
20
20
  from importlib.metadata import version as _pkg_version, PackageNotFoundError
21
21
 
22
- IATOOLKIT_VERSION = "0.55.0"
22
+ IATOOLKIT_VERSION = "0.55.1"
23
23
 
24
24
  # global variable for the unique instance of IAToolkit
25
25
  _iatoolkit_instance: Optional['IAToolkit'] = None
@@ -188,6 +188,15 @@ class IAToolkit:
188
188
  self.db_manager.create_all()
189
189
  logging.info("✅ Base de datos configurada correctamente")
190
190
 
191
+ @self.app.teardown_appcontext
192
+ def remove_session(exception=None):
193
+ """
194
+ Flask calls this after each request.
195
+ It ensures the SQLAlchemy session is properly closed
196
+ and the DB connection is returned to the pool.
197
+ """
198
+ self.db_manager.scoped_session.remove()
199
+
191
200
  def _setup_redis_sessions(self):
192
201
  redis_url = self._get_config_value('REDIS_URL')
193
202
  if not redis_url:
@@ -21,8 +21,20 @@ class DatabaseManager:
21
21
  :param echo: Si True, habilita logs de SQL.
22
22
  """
23
23
  self.url = make_url(database_url)
24
- self._engine = create_engine(database_url, echo=False)
25
- self.SessionFactory = sessionmaker(bind=self._engine)
24
+ self._engine = create_engine(
25
+ database_url,
26
+ echo=False,
27
+ pool_size=2, # per worker
28
+ max_overflow=3,
29
+ pool_timeout=30,
30
+ pool_recycle=1800,
31
+ pool_pre_ping=True,
32
+ future=True,
33
+ )
34
+ self.SessionFactory = sessionmaker(bind=self._engine,
35
+ autoflush=False,
36
+ autocommit=False,
37
+ expire_on_commit=False)
26
38
  self.scoped_session = scoped_session(self.SessionFactory)
27
39
 
28
40
  # REGISTRAR pgvector para cada nueva conexión solo en postgres
Binary file
@@ -4,12 +4,15 @@
4
4
 
5
5
  {% block content %}
6
6
 
7
- <style>
8
- {{ branding.css_variables | safe }}
9
- </style>
10
- <link rel="stylesheet" href="{{ url_for('static', filename='css/onboarding.css', _external=True) }}">
11
- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css">
12
- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css">
7
+ {% block styles %}
8
+ {# Movemos los estilos y los links aquí para que se rendericen en el <head> #}
9
+ <style>
10
+ {{ branding.css_variables | safe }}
11
+ </style>
12
+ <link rel="stylesheet" href="{{ url_for('static', filename='styles/onboarding.css', _external=True) }}">
13
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css">
14
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css">
15
+ {% endblock %}
13
16
 
14
17
  <!-- Sección de encabezado con el usuario conectado -->
15
18
  <div id="company-section" class="company-section d-flex justify-content-between align-items-center px-3 py-2"
@@ -59,12 +62,10 @@
59
62
  </a>
60
63
 
61
64
  <!-- Icono de cerrar sesión (al final) -->
62
- {% if user_is_local %}
63
- <a href="{{ url_for('logout', company_short_name=company_short_name, _external=True) }}"
64
- class="ms-3 action-icon-style" title="Cerrar sesión" style="color: {{ branding.header_text_color }} !important;">
65
- <i class="bi bi-box-arrow-right"></i>
66
- </a>
67
- {% endif %}
65
+ <a href="{{ url_for('logout', company_short_name=company_short_name, _external=True) }}"
66
+ class="ms-3 action-icon-style" title="Cerrar sesión" style="color: {{ branding.header_text_color }} !important;">
67
+ <i class="bi bi-box-arrow-right"></i>
68
+ </a>
68
69
  </div>
69
70
 
70
71
  </div>
@@ -136,7 +136,7 @@
136
136
  </div>
137
137
 
138
138
  <div class="modal-footer">
139
- <button id="ob-close" type="button" class="btn btn-branded-secondary" data-bs-dismiss="modal">
139
+ <button id="ob-close" type="button" class="btn btn-branded-primary" data-bs-dismiss="modal">
140
140
  Cerrar
141
141
  </button>
142
142
  </div>
@@ -1,6 +1,6 @@
1
1
  {% extends "base.html" %}
2
2
 
3
- {% block title %}IAToolkit - Acelerador de IA {% endblock %}
3
+ {% block title %}IAToolkit{% endblock %}
4
4
 
5
5
  {% block content %}
6
6
 
@@ -119,32 +119,31 @@
119
119
 
120
120
  <!-- 3.5 Sobre el Autor -->
121
121
  <section class="author-section py-5">
122
- <div class="container">
123
- <div class="row align-items-center g-4">
124
- <div class="col-md-1 d-none d-md-block text-center">
125
- <!-- Opcional: avatar (si no tienes imagen, deja el ícono) -->
126
- <div class="author-avatar mx-auto">
127
- <i class="bi bi-person-circle"></i>
128
- </div>
129
- </div>
130
- <div class="col-md-11">
131
- <div class="author-card p-4">
132
- <div class="d-flex flex-wrap align-items-center">
133
- <h5 class="mb-0 me-3" style="color: var(--brand-primary-color);">Sobre el autor</h5>
134
- <a href="https://www.linkedin.com/in/fernandolibedinsky" target="_blank" rel="noopener" class="author-linkedin ms-auto">
135
- <i class="bi bi-linkedin me-1"></i> LinkedIn
136
- </a>
122
+ <div class="container">
123
+ <div class="author-card p-4">
124
+ <div class="row align-items-center g-4">
125
+ <!-- Columna para la Imagen -->
126
+ <div class="col-md-2 text-center">
127
+ <img src="{{ url_for('static', filename='images/fernando.jpeg') }}" alt="Foto de Fernando Libedinsky" class="img-fluid rounded-circle" style="max-width: 120px;">
128
+ </div>
129
+ <!-- Columna para el Texto -->
130
+ <div class="col-md-10">
131
+ <div class="d-flex flex-wrap align-items-center mb-2">
132
+ <h5 class="mb-0 me-3" style="color: var(--brand-primary-color);">Sobre el autor</h5>
133
+ <a href="https://www.linkedin.com/in/fernandolibedinsky" target="_blank" rel="noopener" class="author-linkedin ms-auto">
134
+ <i class="bi bi-linkedin me-1"></i> LinkedIn
135
+ </a>
136
+ </div>
137
+ <p class="author-bio mb-0">
138
+ Soy <strong>Fernando Libedinsky</strong>, ingeniero de software y creador de <strong>IAToolkit</strong>.
139
+ <br>Tras una extensa trayectoria en el desarrollo de tecnología, sigo movido por la misma curiosidad que me llevó a programar por primera vez: aprender, explorar y construir cosas nuevas.
140
+ <br>IAToolkit es la continuación de ese impulso, una plataforma creada para conectar rapidamente empresas con la inteligencia artificial.
141
+ </p>
137
142
  </div>
138
- <p class="author-bio mt-2 mb-0">
139
- Soy <strong>Fernando Libedinsky</strong>, ingeniero de software y creador de <strong>IAToolkit</strong>.
140
- <br>Tras una extensa trayectoria en el desarrollo de tecnología, sigo movido por la misma curiosidad que me llevó a programar por primera vez: aprender, explorar y construir cosas nuevas.
141
- <br>IAToolkit es la continuación de ese impulso, una plataforma creada para conectar rapidamente una empresas con la IA.
142
- </p>
143
143
  </div>
144
144
  </div>
145
145
  </div>
146
- </div>
147
- </section>
146
+ </section>
148
147
 
149
148
 
150
149
  <!-- 4. Footer (sin cambios) -->
@@ -1,150 +1,118 @@
1
1
  {% extends "base.html" %}
2
2
 
3
- {% block title %}Inicio - IAToolkit{% endblock %}
3
+ {% block title %}Prueba de Login para {{ branding.name }}{% endblock %}
4
+
5
+ {% block styles %}
6
+ {# Este bloque asegura que los colores de la marca estén disponibles como variables CSS #}
7
+ {% if branding and branding.css_variables %}
8
+ <style>
9
+ {{ branding.css_variables|safe }}
10
+ /* Usa la variable de CSS para el color primario del botón */
11
+ #initiateJwtChatButton {
12
+ background-color: var(--brand-primary-color, #0d6efd);
13
+ border-color: var(--brand-primary-color, #0d6efd);
14
+ }
15
+ </style>
16
+ {% endif %}
17
+ {% endblock %}
4
18
 
5
19
  {% block content %}
6
-
7
- <!-- Contenido principal con espaciado adicional respecto al header -->
8
- <div class="row flex-fill mt-5 flex-wrap">
9
-
10
-
11
- <!-- login desde sistema externo -->
12
- <div class="col-12 col-lg-5 offset-lg-1">
13
- <div class="border rounded p-4 shadow-sm bg-light">
14
- <h3 class="text-muted fw-semibold text-start mb-3">login externo (api-key)</h3>
15
- <div class="text-center mb-4">
16
- <p class="text-muted widget-intro-text">
17
- Este formulario permite testear el acceso a IAToolkit desde un portal externo utilizando una api-key.
18
- El external user ID es el nombre del usuario ya autentificado en algún portal interno de la empresa.
19
- </p>
20
- </div>
21
- <form id="jwt-form" method="post">
22
- <div class="mb-3">
23
- <label for="company_name" class="form-label d-block">Empresa</label>
24
- <select id="company_name" name="company_short_name" class="form-select" required>
25
- <option value="" disabled selected>Selecciona una empresa</option>
26
- {% for company in companies %}
27
- {% if company.allow_jwt %}
28
- <option value="{{ company.short_name }}"> {{ company.short_name }}
29
- </option>
30
- {% endif %}
31
- {% endfor %}
32
- </select>
20
+ <div class="container-fluid">
21
+ <div class="row flex-fill mt-5 justify-content-center">
22
+ <!-- login desde sistema externo -->
23
+ <div class="col-12 col-lg-6">
24
+ <div class="border rounded p-4 p-md-5 shadow-sm bg-light">
25
+ {# El título ahora muestra dinámicamente el nombre de la empresa #}
26
+ <h3 class="text-muted fw-semibold text-start mb-3">
27
+ Login Externo para <span style="color: var(--brand-primary-color, #0d6efd);">{{ branding.name }}</span>
28
+ </h3>
29
+ <div class="text-center mb-4">
30
+ <p class="text-muted widget-intro-text">
31
+ Este formulario permite testear el acceso a IAToolkit desde un portal externo utilizando una api-key. El external user ID es el nombre del usuario ya autentificado en algún portal interno de la empresa.
32
+ </p>
33
33
  </div>
34
34
 
35
+ {# El 'action' y 'method' son manejados por JS, pero el id es crucial #}
36
+ <form id="jwt-form">
37
+
35
38
  <div class="mb-3">
36
39
  <label for="external_user_id" class="form-label d-block">External user ID</label>
37
40
  <input type="text" id="external_user_id" name="external_user_id" class="form-control" required>
38
41
  </div>
39
42
 
40
- <button type="button"
41
- id="initiateJwtChatButton"
42
- class="ml-5 btn btn-primary">
43
- <span class="spinner-border spinner-border-sm d-none" role="status" aria-hidden="true"></span>
44
- Iniciar Sesión
43
+ <button type="submit" id="initiateJwtChatButton" class="btn btn-primary">
44
+ <span class="spinner-border spinner-border-sm d-none" role="status" aria-hidden="true"></span>
45
+ Iniciar Sesión
45
46
  </button>
46
47
  </form>
47
48
  </div>
48
49
  </div>
49
-
50
50
  </div>
51
-
51
+ </div>
52
52
  {% endblock %}
53
53
 
54
54
  {% block scripts %}
55
-
56
55
  <script>
57
- // Variables pasadas desde Flask (HomeView)
58
- const API_KEY = "{{ api_key|safe }}";
59
-
60
- $(document).ready(function () {
61
- // Función para actualizar el enlace de "Registrarse" y el action del formulario "Iniciar Sesión"
62
- function updateLinksAndForm() {
63
- const selectedCompany = $('#company_short_name').val(); // Obtenemos el valor del select
64
-
65
- // Actualizar enlace "Registrarse"
66
- if (selectedCompany && selectedCompany.trim() !== '') {
67
- const signupUrl = '/' + selectedCompany + '/signup';
68
- $('#signup-link').attr('href', signupUrl); // Actualizamos el href del botón "Registrarse"
69
- } else {
70
- $('#signup-link').attr('href', '#'); // Enlace a "#" si no hay empresa seleccionada
71
- }
72
-
73
- // Actualizar action del formulario "Iniciar Sesión"
74
- if (selectedCompany && selectedCompany.trim() !== '') {
75
- const loginAction = '/' + selectedCompany + '/external_login';
76
- $('#login-form').attr('action', loginAction); // Actualizamos la URL del form
77
- } else {
78
- $('#login-form').attr('action', '#'); // URL genérica si no hay selección
79
- }
80
- }
81
-
82
- // Actualizamos al cargar la página
83
- updateLinksAndForm();
84
-
85
- // Escuchamos el evento de cambio en el dropdown para actualizar dinámicamente
86
- $('#company_short_name').on('change', function () {
87
- updateLinksAndForm();
88
- });
89
-
90
- // Interceptamos el click en "Registrarse"
91
- $('#signup-link').on('click', function (e) {
92
- const selectedCompany = $('#company_short_name').val();
93
-
94
- if (!selectedCompany || selectedCompany.trim() === '') {
95
- e.preventDefault(); // evitar navegación al #
96
- Swal.fire({
97
- icon: 'warning',
98
- title: 'Empresa no seleccionada',
99
- text: 'Por favor, selecciona una empresa antes de registrarte.'
100
- });
101
- }
102
- });
103
-
104
- // Event listener para el botón de "Abrir Chat (JWT)"
105
- $('#initiateJwtChatButton').on('click', function() {
106
-
107
- const selectedCompany = $('#company_name').val();
108
- const externalUserId = $('#external_user_id').val();
109
-
110
- if (!selectedCompany || !externalUserId.trim()) {
111
- Swal.fire({ icon: 'warning', title: 'Campos Requeridos', text: 'Por favor, selecciona una empresa e ingresa un ID de usuario.' });
112
- return;
113
- }
114
- if (!API_KEY || API_KEY.includes("defecto")) {
115
- Swal.fire({ icon: 'error', title: 'Error de Configuración', text: 'La API Key de la aplicación no está disponible.' });
116
- return;
117
- }
118
-
119
- fetch(`/${selectedCompany}/external_login`, {
120
- method: 'POST',
121
- headers: {
56
+ document.addEventListener('DOMContentLoaded', function() {
57
+ const companyShortName = "{{ company_short_name }}";
58
+ const apiKey = "{{ api_key }}";
59
+ const loginForm = document.getElementById('jwt-form');
60
+ const userIdInput = document.getElementById('external_user_id');
61
+ const submitButton = document.getElementById('initiateJwtChatButton');
62
+ const spinner = submitButton.querySelector('.spinner-border');
63
+
64
+ loginForm.addEventListener('submit', function(event) {
65
+ event.preventDefault();
66
+ const userIdentifier = userIdInput.value.trim();
67
+ if (!userIdentifier) return;
68
+
69
+ // Deshabilitar botón y mostrar spinner
70
+ submitButton.disabled = true;
71
+ spinner.classList.remove('d-none');
72
+
73
+ const newWindow = window.open('', '_blank');
74
+ const apiUrl = `/${companyShortName}/external_login`;
75
+
76
+ fetch(apiUrl, {
77
+ method: 'POST',
78
+ headers: {
122
79
  'Content-Type': 'application/json',
123
- 'Authorization': `Bearer ${API_KEY}`
80
+ 'Authorization': `Bearer ${apiKey}`
124
81
  },
125
- body: JSON.stringify({
126
- external_user_id: externalUserId
127
- })
128
- })
129
- .then(async response => {
130
- if (response.ok) { // Si el status es 200, la respuesta es el HTML
131
- return response.text();
132
- } else { // Si hay un error, el cuerpo es JSON
133
- const errorData = await response.json();
134
- throw new Error(errorData.error || 'Ocurrió un error desconocido.');
135
- }
136
- })
137
- .then(htmlContent => {
138
- // Éxito: Abrimos el HTML que nos devolvió el servidor en una nueva pestaña.
139
- const newTab = window.open();
140
- newTab.document.write(htmlContent);
141
- newTab.document.close();
142
- })
143
- .catch(error => {
144
- Swal.fire({ icon: 'error', title: 'Error de Inicio de Sesión', text: error.message });
145
- })
146
-
147
- });
82
+ body: JSON.stringify({ external_user_id: userIdentifier })
83
+ })
84
+ .then(response => response.ok ? response.text() : response.text().then(text => { throw new Error(text) }))
85
+ .then(html => {
86
+ newWindow.document.documentElement.innerHTML = html;
87
+ // Buscamos todos los scripts en el HTML inyectado y los re-ejecutamos.
88
+ const scripts = newWindow.document.querySelectorAll('script');
89
+ scripts.forEach(oldScript => {
90
+ const newScript = newWindow.document.createElement('script');
91
+
92
+ // Copiamos los atributos (como 'src' para archivos externos)
93
+ Array.from(oldScript.attributes).forEach(attr => {
94
+ newScript.setAttribute(attr.name, attr.value);
95
+ });
96
+
97
+ // Copiamos el contenido para scripts inline
98
+ newScript.appendChild(newWindow.document.createTextNode(oldScript.innerHTML));
99
+
100
+ // Reemplazamos el script viejo por el nuevo para que se ejecute.
101
+ oldScript.parentNode.replaceChild(newScript, oldScript);
102
+ });
103
+
104
+ })
105
+ .catch(error => {
106
+ console.error("Falló la prueba de login externo:", error);
107
+ const errorMessage = error.message || "Error desconocido.";
108
+ newWindow.document.body.innerHTML = `<div style="padding: 20px; font-family: monospace;"><h2>Error</h2><pre>${errorMessage}</pre></div>`;
109
+ })
110
+ .finally(() => {
111
+ // Volver a habilitar el botón y ocultar el spinner
112
+ submitButton.disabled = false;
113
+ spinner.classList.add('d-none');
114
+ });
115
+ });
148
116
  });
149
117
  </script>
150
118
  {% endblock %}
@@ -3,9 +3,20 @@
3
3
  {% block title %}Iniciando {{ branding.name | default('IAToolkit') }} IA...{% endblock %}
4
4
 
5
5
  {% block styles %}
6
+ {% endblock %}
7
+
8
+ {% block content %}
9
+
6
10
  <link rel="stylesheet" href="{{ url_for('static', filename='styles/llm_output.css', _external=True) }}?v=6">
7
- <link rel="stylesheet" href="{{ url_for('static', filename='css/onboarding.css', _external=True) }}?v=6">
11
+ <link rel="stylesheet" href="{{ url_for('static', filename='styles/onboarding.css', _external=True) }}?v=6">
12
+
8
13
  <style>
14
+ {# 1. Definimos las variables de la marca PRIMERO #}
15
+ {% if branding and branding.css_variables %}
16
+ {{ branding.css_variables|safe }}
17
+ {% endif %}
18
+
19
+ {# 2. Ahora definimos las reglas que usan esas variables #}
9
20
  .onboarding-shell-root { position: relative; height: 100vh; }
10
21
  .onboarding-shell-root #loader-wrapper { position: absolute; inset: 0; background: #f4f7f6; z-index: 1000; display:flex; align-items:center; justify-content:center; padding:20px; box-sizing:border-box; transition: opacity .5s; }
11
22
  .onboarding-shell-root .ob-stack { width:100%; max-width:520px; display:flex; flex-direction:column; gap:16px; }
@@ -22,14 +33,7 @@
22
33
  .onboarding-shell-root .ob-btn { background-color: var(--brand-secondary-color, #06326B) !important; color: var(--brand-text-on-secondary, #FFFFFF) !important; border:none !important; }
23
34
  .onboarding-shell-root .ob-dots > div.active { background-color: var(--brand-primary-color, #FF5100) !important; }
24
35
  </style>
25
- {% if branding and branding.css_variables %}
26
- <style>
27
- {{ branding.css_variables|safe }}
28
- </style>
29
- {% endif %}
30
- {% endblock %}
31
36
 
32
- {% block content %}
33
37
  <div class="onboarding-shell-root ob-root">
34
38
  <div id="loader-wrapper">
35
39
  <div class="ob-stack">
@@ -0,0 +1,60 @@
1
+ import requests
2
+ import json
3
+ import os
4
+ from flask.views import MethodView
5
+ from flask import Response, abort, request, make_response
6
+
7
+
8
+ class LoginSimulationView(MethodView):
9
+ """
10
+ Simula un portal externo que llama a la API de IAToolkit de servidor a servidor,
11
+ replicando el flujo real de `dispatch_request`.
12
+ Para usarlo, visita /login_test/<company_short_name>/<external_user_id>
13
+ """
14
+
15
+ def get(self, company_short_name: str, external_user_id: str):
16
+ api_key = os.getenv("IATOOLKIT_API_KEY")
17
+ base_url = request.host_url.rstrip('/')
18
+
19
+ if not api_key:
20
+ abort(500, "Error: IATOOLKIT_API_KEY no está configurada en el servidor de prueba.")
21
+ if not external_user_id:
22
+ abort(400, "Error: Debes proporcionar un external_user_id en la URL.")
23
+
24
+ target_url = f"{base_url}/{company_short_name}/external_login"
25
+
26
+ # --- INICIO DE LA CORRECCIÓN ---
27
+ # Usamos el formato de header 'Authorization: Bearer' como solicitaste.
28
+ headers = {
29
+ 'Content-Type': 'application/json',
30
+ 'Authorization': f'Bearer {api_key}'
31
+ }
32
+ # --- FIN DE LA CORRECCIÓN ---
33
+
34
+ payload = {'external_user_id': external_user_id}
35
+
36
+ try:
37
+ # Llamada POST interna. 'stream=True' es importante para manejar la respuesta.
38
+ internal_response = requests.post(target_url, headers=headers, data=json.dumps(payload), timeout=120,
39
+ stream=True)
40
+ internal_response.raise_for_status()
41
+
42
+ # Creamos una nueva Response de Flask para el navegador del usuario.
43
+ user_response = Response(
44
+ internal_response.iter_content(chunk_size=1024),
45
+ status=internal_response.status_code
46
+ )
47
+
48
+ # Copiamos TODAS las cabeceras de la respuesta interna a la respuesta final,
49
+ # incluyendo 'Content-Type' y, crucialmente, 'Set-Cookie'.
50
+ for key, value in internal_response.headers.items():
51
+ if key.lower() not in ['content-encoding', 'content-length', 'transfer-encoding', 'connection']:
52
+ user_response.headers[key] = value
53
+
54
+ return user_response
55
+
56
+ except requests.exceptions.HTTPError as e:
57
+ error_text = f"Error en la llamada interna a la API: {e.response.status_code}. Respuesta: {e.response.text}"
58
+ return Response(error_text, status=e.response.status_code, mimetype='text/plain')
59
+ except requests.exceptions.RequestException as e:
60
+ return Response(f'Error de conexión con el servicio de IA: {str(e)}', status=502, mimetype='text/plain')
@@ -84,7 +84,7 @@ class FinalizeContextView(MethodView):
84
84
 
85
85
  if not user_identifier:
86
86
  # This can happen if the session expires or is invalid.
87
- return redirect(url_for('login_page', company_short_name=company_short_name))
87
+ return redirect(url_for('index', company_short_name=company_short_name))
88
88
 
89
89
  company = self.profile_service.get_company_by_short_name(company_short_name)
90
90
  if not company:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: iatoolkit
3
- Version: 0.55.0
3
+ Version: 0.55.2
4
4
  Summary: IAToolkit
5
5
  Author: Fernando Libedinsky
6
6
  License-Expression: MIT
@@ -2,10 +2,10 @@ iatoolkit/__init__.py,sha256=4PWjMJjktixtrxF6BY405qyA50Sv967kEP2x-oil6qk,1120
2
2
  iatoolkit/base_company.py,sha256=uFJmy77LPAceVqkTeuJqo15-auDiq4aTwvC_bbBD0mQ,4607
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=jIIhvxu1CwCiz3dLm9B7I2SzH-4sT0QQeci_XD2_C68,17305
5
+ iatoolkit/iatoolkit.py,sha256=G_4plhotRBuf-u6OsFZhov_MoFbdvyd--u1vVc3hz18,17645
6
6
  iatoolkit/common/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
7
  iatoolkit/common/exceptions.py,sha256=EXx40n5htp7UiOM6P1xfJ9U6NMcADqm62dlFaKz7ICU,1154
8
- iatoolkit/common/routes.py,sha256=Djf8Q_b5IGkdhQ5Az_AuYIVqam6-HFA2d4ByursdARI,6030
8
+ iatoolkit/common/routes.py,sha256=LniD_xsVZ6iHx1Z2_daOChhXZ9AQwsYFtqWSuFkQVyk,6117
9
9
  iatoolkit/common/session_manager.py,sha256=UeKfD15bcEA3P5e0WSURfotLqpsiIMp3AXxAMhtgHs0,471
10
10
  iatoolkit/common/util.py,sha256=w9dTd3csK0gKtFSp-a4t7XmCPZiYDhiON92uXRbTT8A,14624
11
11
  iatoolkit/infra/__init__.py,sha256=5JqK9sZ6jBuK83zDQokUhxQ0wuJJJ9DXB8pYCLkX7X4,102
@@ -26,7 +26,7 @@ iatoolkit/infra/connectors/google_drive_connector.py,sha256=WR1AlO5-Bl3W89opdja0
26
26
  iatoolkit/infra/connectors/local_file_connector.py,sha256=hrzIgpMJOTuwTqzlQeTIU_50ZbZ6yl8lcWPv6hMnoqI,1739
27
27
  iatoolkit/infra/connectors/s3_connector.py,sha256=Nj4_YaLobjfcnbZewJf21_K2EXohgcc3mJll1Pzn4zg,1123
28
28
  iatoolkit/repositories/__init__.py,sha256=5JqK9sZ6jBuK83zDQokUhxQ0wuJJJ9DXB8pYCLkX7X4,102
29
- iatoolkit/repositories/database_manager.py,sha256=UaU7k3s7IRuXhCHTy9GoCeP9K1ad0LBdj_n1a_QjGS0,3108
29
+ iatoolkit/repositories/database_manager.py,sha256=nrBSAPuFkTYlvAht_3Kp2XeIDiqjq-mBTeqfCoMfn3A,3515
30
30
  iatoolkit/repositories/document_repo.py,sha256=Y7bF1kZB1HWJsAGjWdF7P2aVYeTYNufq9ngQXp7mDkY,1124
31
31
  iatoolkit/repositories/llm_query_repo.py,sha256=YT_t7cYGQk8rwzH_17-28aTzO-e2jUfa2rvXy8tugvA,3612
32
32
  iatoolkit/repositories/models.py,sha256=3YbIJXNMZiTkMbPyiSOiyzqUKEQF0JIfN4VSWYzwr44,13146
@@ -54,15 +54,7 @@ iatoolkit/services/sql_service.py,sha256=MIslAtpJWnTMgSD74nnqTvQj27p-lHiyRXc6OiA
54
54
  iatoolkit/services/tasks_service.py,sha256=itREO5rDnUIgsqtyCOBKDtH30QL5v1egs4qPTiBK8xU,6865
55
55
  iatoolkit/services/user_feedback_service.py,sha256=ooy750qWmYOeJi-IJQofu8pLG4svGjGU_JKpKMURZkw,2353
56
56
  iatoolkit/services/user_session_context_service.py,sha256=TeYi4xF04Xk-4Qnp6cVTmxuNzA4B1nMVUuFDjTHeiZQ,6764
57
- iatoolkit/static/images/arrow_up.png,sha256=vPcWMebWVOOt13x5U7pzsyukysoiXO0siSyErUMleHw,2781
58
- iatoolkit/static/images/diagrama_iatoolkit.jpg,sha256=GhauwUVqWjt9dWtsW53Uon_mo61j73brmC4ogQc6tkY,93527
59
- iatoolkit/static/images/logo_clinica.png,sha256=vLX6X7O9RPUHYTQHvO_Fx28sI4JulpRZsRpkuJ9XIu0,56806
60
- iatoolkit/static/images/logo_iatoolkit.png,sha256=7XSxLy8v_mGxQMM8EA0gund-MmnQoIy1RV6DkJ-eukI,185089
61
- iatoolkit/static/images/logo_maxxa.png,sha256=X4JtTu6ooe2RUHRo1stxGGquXlkiEWcTUxH5vbFdMv0,10592
62
- iatoolkit/static/images/logo_notaria.png,sha256=FLDK1mHydFpzudKLKQSqHdSqq6vbqs77a_bO0PI_yHE,105105
63
- iatoolkit/static/images/logo_tarjeta.png,sha256=HQe2lp_jHFWq5hnx3SCBEcqW5IFfvSCktv9oyN--5cQ,1700
64
- iatoolkit/static/images/logo_umayor.png,sha256=FHr1wvI8uDn1YRbRcLSRLBOc0mYusHx9Um6ZzVZUbOQ,19199
65
- iatoolkit/static/images/upload.png,sha256=zh5FiINURpaWZQF86bF_gALBX4W1c4aLp5wPQO9xGXI,296
57
+ iatoolkit/static/images/fernando.jpeg,sha256=W68TYMuo5hZVpbP-evwH6Nu4xWFv2bc8pJzSKDoLTeQ,100612
66
58
  iatoolkit/static/js/chat_feedback.js,sha256=DDT2NPgglrLnW75vtEAVXS72MNt7vlMcavzr94q80qQ,4398
67
59
  iatoolkit/static/js/chat_filepond.js,sha256=mzXafm7a506EpM37KATTK3zvAswO1E0KSUY1vKbwuRc,3163
68
60
  iatoolkit/static/js/chat_history.js,sha256=4hYNODIwYNd5vaQqkR28HZyXYIFKgSayrnmOuT_DUac,4381
@@ -83,14 +75,14 @@ iatoolkit/templates/_navbar.html,sha256=o1PvZE5ueLmVpGUAmsjtu-vS_WPROTlJc2sTXl6A
83
75
  iatoolkit/templates/about.html,sha256=ciC08grUVz5qLzdzDDqDX31xirg5PrJIRYabWpV9oA8,294
84
76
  iatoolkit/templates/base.html,sha256=hHfBqZJsPcZGlb4BxAbHvpJFcSjckLIAVTYTmoyXrz0,2323
85
77
  iatoolkit/templates/change_password.html,sha256=G5a3hYLTpz_5Q_eZ4LNcYSqLeW-CuT4NCHD8bkhAd9k,3573
86
- iatoolkit/templates/chat.html,sha256=spvypAVaVI1I22YRrYgQqzK1lXVPX5ywMp2MNixFTTY,13885
87
- iatoolkit/templates/chat_modals.html,sha256=o3BmQBCTVun4ukyy-9E0e7FuBlgyVQKbRXuDn86SVnw,6949
78
+ iatoolkit/templates/chat.html,sha256=AgVynrJzUlBr8aG334YKg3U35Nas0-RoVfzFAx9Ntfk,13961
79
+ iatoolkit/templates/chat_modals.html,sha256=NwwgPoOmVbjy4aO2eHsy1TUMXRiOfTOC5Jx_F2ehhcs,6947
88
80
  iatoolkit/templates/error.html,sha256=c3dxieMygsvdjQMiQu_sn6kqqag9zFtVu-z5FunX6so,580
89
81
  iatoolkit/templates/forgot_password.html,sha256=NRZqbNHJXSLNArF_KLbzuem-U57v07awS0ikI_DJbfM,2360
90
82
  iatoolkit/templates/header.html,sha256=179agI7rnYwP_rvJNXIiVde5E8Ec5649_XKq6eew2Hk,1263
91
- iatoolkit/templates/index.html,sha256=jBLCqZoIMmUCA1KQESW9BcEgaxE0Rjs-4-i2V0ueSMo,7654
92
- iatoolkit/templates/login_test.html,sha256=HsLgRNowhrg-G7Cyv4MFEYc6m7dJ92OpnQP6ia6eKoM,5981
93
- iatoolkit/templates/onboarding_shell.html,sha256=WA2-Or91epS2IeWf7m5vcuLYAjtpI36NBCtypcIiXAQ,4546
83
+ iatoolkit/templates/index.html,sha256=Q2wBHDv3HTBt-jURVLggye7XOqoqDY8E0LnrmLdc3SQ,7910
84
+ iatoolkit/templates/login_test.html,sha256=ApvW4l0UmcjJ9pBl3jm-0BojWwiFV6ZyCWz3caM1DN4,4722
85
+ iatoolkit/templates/onboarding_shell.html,sha256=r1ivSR2ci8GrDSm1uaD-cf78rfO1bKT5gXa-v5aHLAk,4659
94
86
  iatoolkit/templates/signup.html,sha256=9ArDvcNQgHFR2dwxy-37AXzGUOeOsT7Nz5u0y6fAB3U,4385
95
87
  iatoolkit/templates/test.html,sha256=rwNtxC83tbCl5COZFXYvmRBxxmgFJtPNuVBd_nq9KWY,133
96
88
  iatoolkit/views/__init__.py,sha256=5JqK9sZ6jBuK83zDQokUhxQ0wuJJJ9DXB8pYCLkX7X4,102
@@ -105,15 +97,15 @@ iatoolkit/views/index_view.py,sha256=P5aVdEWxsYOZGbzcXd6WFE733qZ7YXIoeqriUMAM6V8
105
97
  iatoolkit/views/init_context_api_view.py,sha256=1j8NKfODfPrffbA5YO8TPMHh-ildlLNzReIxv_qO-W4,2586
106
98
  iatoolkit/views/llmquery_api_view.py,sha256=Rh-y-VENwwtNsDrYAD_SWKwjK16fW-pFRWlEvI-OYwY,2120
107
99
  iatoolkit/views/llmquery_web_view.py,sha256=WhjlA1mfsoL8hL9tlKQfjCUcaTzT43odlp_uQKmT314,1500
108
- iatoolkit/views/login_test_view.py,sha256=7bqj9XWYCNGZulwPCgBMlk3O1DEIje_A_Hqesa58CVU,1893
109
- iatoolkit/views/login_view.py,sha256=eAsmiCWS2KSOq3czaxVGm3W9__yaXKxqB9SeuGsdnmI,4635
100
+ iatoolkit/views/login_simulation_view.py,sha256=hujduAuq84YyHXfG1iVVbypkwYOreKr9FnQNvIXBDyQ,2675
101
+ iatoolkit/views/login_view.py,sha256=3mV-I1KWrVCi4GBmSWCPmIIKj0reZEBMmyTZdBKFCFM,4630
110
102
  iatoolkit/views/prompt_api_view.py,sha256=MP0r-MiswwKcbNc_5KY7aVbHkrR218I8XCiCX1D0yTA,1244
111
103
  iatoolkit/views/signup_view.py,sha256=BCjhM2lMiDPwYrlW_eEwPl-ZLupblbFfsonWtq0E4vU,3922
112
104
  iatoolkit/views/tasks_review_view.py,sha256=keLsLCyOTTlcoIapnB_lbuSvLwrPVZVpBiFC_7ChbLg,3388
113
105
  iatoolkit/views/tasks_view.py,sha256=a3anTXrJTTvbQuc6PSpOzidLKQFL4hWa7PI2Cppcz8w,4110
114
106
  iatoolkit/views/user_feedback_api_view.py,sha256=59XB9uQLHI4Q6QA4_XhK787HzfXb-c6EY7k1Ccyr4hI,2424
115
107
  iatoolkit/views/verify_user_view.py,sha256=7XLSaxvs8LjBr3cYOUDa9B8DqW_50IGlq0IvmOQcD0Y,2340
116
- iatoolkit-0.55.0.dist-info/METADATA,sha256=thMCV6aAt67vKtHbdiK1zTVTTdW1Q-YC-SWgaSz3ywI,9301
117
- iatoolkit-0.55.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
118
- iatoolkit-0.55.0.dist-info/top_level.txt,sha256=V_w4QvDx0b1RXiy8zTCrD1Bp7AZkFe3_O0-9fMiwogg,10
119
- iatoolkit-0.55.0.dist-info/RECORD,,
108
+ iatoolkit-0.55.2.dist-info/METADATA,sha256=hR0pzM6CSYaGhZCLbwA_G4A-_85DUV3ttYIojwpDkY4,9301
109
+ iatoolkit-0.55.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
110
+ iatoolkit-0.55.2.dist-info/top_level.txt,sha256=V_w4QvDx0b1RXiy8zTCrD1Bp7AZkFe3_O0-9fMiwogg,10
111
+ iatoolkit-0.55.2.dist-info/RECORD,,
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
@@ -1,46 +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 flask import render_template, request
8
- from injector import inject
9
- from iatoolkit.services.profile_service import ProfileService
10
- from iatoolkit.services.branding_service import BrandingService
11
- from iatoolkit.services.onboarding_service import OnboardingService
12
- import os
13
-
14
-
15
- class LoginTest(MethodView):
16
- @inject
17
- def __init__(self,
18
- profile_service: ProfileService,
19
- branding_service: BrandingService,
20
- onboarding_service: OnboardingService):
21
- self.profile_service = profile_service
22
- self.branding_service = branding_service
23
- self.onboarding_service = onboarding_service
24
-
25
- def get(self):
26
- alert_message = request.args.get('alert_message', None)
27
- companies = self.profile_service.get_companies()
28
- branding_data = None
29
- onboarding_cards = {}
30
- if companies:
31
- # Obtener el branding de la primera empresa para la página de prueba
32
- first_company = companies[0]
33
- branding_data = self.branding_service.get_company_branding(first_company)
34
- onboarding_cards = self.onboarding_service.get_onboarding_cards(first_company)
35
-
36
- # Esta API_KEY para el login
37
- api_key_for_login = os.getenv("IATOOLKIT_API_KEY", "tu_api_key_por_defecto_o_error")
38
-
39
- return render_template('login_test.html',
40
- companies=companies,
41
- branding=branding_data,
42
- onboarding_cards=onboarding_cards,
43
- alert_message=alert_message,
44
- alert_icon='success' if alert_message else None,
45
- api_key=api_key_for_login
46
- )