iatoolkit 0.55.1__py3-none-any.whl → 0.55.3__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/common/routes.py +2 -2
- iatoolkit/iatoolkit.py +10 -1
- iatoolkit/repositories/database_manager.py +17 -2
- iatoolkit/services/profile_service.py +3 -3
- iatoolkit/services/query_service.py +0 -4
- iatoolkit/static/images/fernando.jpeg +0 -0
- iatoolkit/templates/index.html +22 -23
- iatoolkit/templates/login_simulation.html +91 -0
- iatoolkit/views/external_login_view.py +8 -8
- iatoolkit/views/login_simulation_view.py +20 -53
- {iatoolkit-0.55.1.dist-info → iatoolkit-0.55.3.dist-info}/METADATA +1 -1
- {iatoolkit-0.55.1.dist-info → iatoolkit-0.55.3.dist-info}/RECORD +14 -22
- iatoolkit/static/images/arrow_up.png +0 -0
- iatoolkit/static/images/diagrama_iatoolkit.jpg +0 -0
- iatoolkit/static/images/logo_clinica.png +0 -0
- iatoolkit/static/images/logo_iatoolkit.png +0 -0
- iatoolkit/static/images/logo_maxxa.png +0 -0
- iatoolkit/static/images/logo_notaria.png +0 -0
- iatoolkit/static/images/logo_tarjeta.png +0 -0
- iatoolkit/static/images/logo_umayor.png +0 -0
- iatoolkit/static/images/upload.png +0 -0
- iatoolkit/templates/login_test.html +0 -118
- {iatoolkit-0.55.1.dist-info → iatoolkit-0.55.3.dist-info}/WHEEL +0 -0
- {iatoolkit-0.55.1.dist-info → iatoolkit-0.55.3.dist-info}/top_level.txt +0 -0
iatoolkit/common/routes.py
CHANGED
|
@@ -111,8 +111,8 @@ def register_views(injector, app):
|
|
|
111
111
|
except FileNotFoundError:
|
|
112
112
|
abort(404)
|
|
113
113
|
|
|
114
|
-
# login testing
|
|
115
|
-
app.add_url_rule('
|
|
114
|
+
# login testing
|
|
115
|
+
app.add_url_rule('/<company_short_name>/login_test',
|
|
116
116
|
view_func=LoginSimulationView.as_view('login_test'))
|
|
117
117
|
|
|
118
118
|
app.add_url_rule(
|
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.
|
|
22
|
+
IATOOLKIT_VERSION = "0.55.3"
|
|
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,23 @@ class DatabaseManager:
|
|
|
21
21
|
:param echo: Si True, habilita logs de SQL.
|
|
22
22
|
"""
|
|
23
23
|
self.url = make_url(database_url)
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
if database_url.startswith('sqlite'): # for tests
|
|
25
|
+
self._engine = create_engine(database_url, echo=False)
|
|
26
|
+
else:
|
|
27
|
+
self._engine = create_engine(
|
|
28
|
+
database_url,
|
|
29
|
+
echo=False,
|
|
30
|
+
pool_size=2, # per worker
|
|
31
|
+
max_overflow=3,
|
|
32
|
+
pool_timeout=30,
|
|
33
|
+
pool_recycle=1800,
|
|
34
|
+
pool_pre_ping=True,
|
|
35
|
+
future=True,
|
|
36
|
+
)
|
|
37
|
+
self.SessionFactory = sessionmaker(bind=self._engine,
|
|
38
|
+
autoflush=False,
|
|
39
|
+
autocommit=False,
|
|
40
|
+
expire_on_commit=False)
|
|
26
41
|
self.scoped_session = scoped_session(self.SessionFactory)
|
|
27
42
|
|
|
28
43
|
# REGISTRAR pgvector para cada nueva conexión solo en postgres
|
|
@@ -74,20 +74,20 @@ class ProfileService:
|
|
|
74
74
|
except Exception as e:
|
|
75
75
|
return {'success': False, "message": str(e)}
|
|
76
76
|
|
|
77
|
-
def create_external_user_session(self, company: Company,
|
|
77
|
+
def create_external_user_session(self, company: Company, user_identifier: str):
|
|
78
78
|
"""
|
|
79
79
|
Public method for views to create a web session for an external user.
|
|
80
80
|
"""
|
|
81
81
|
# 1. Fetch the profile from the external system via Dispatcher.
|
|
82
82
|
user_profile = self.dispatcher.get_user_info(
|
|
83
83
|
company_name=company.short_name,
|
|
84
|
-
user_identifier=
|
|
84
|
+
user_identifier=user_identifier
|
|
85
85
|
)
|
|
86
86
|
|
|
87
87
|
# 2. Call the session creation helper with external_user_id as user_identifier
|
|
88
88
|
self.create_web_session(
|
|
89
89
|
company=company,
|
|
90
|
-
user_identifier=
|
|
90
|
+
user_identifier=user_identifier,
|
|
91
91
|
user_profile=user_profile)
|
|
92
92
|
|
|
93
93
|
def create_web_session(self, company: Company, user_identifier: str, user_profile: dict):
|
|
@@ -114,10 +114,6 @@ class QueryService:
|
|
|
114
114
|
self._has_valid_cached_context(company_short_name, user_identifier))
|
|
115
115
|
|
|
116
116
|
if rebuild_is_needed:
|
|
117
|
-
logging.info(
|
|
118
|
-
f"Se necesita reconstrucción de contexto para {company_short_name}/{user_identifier}. Preparando...")
|
|
119
|
-
|
|
120
|
-
|
|
121
117
|
# Guardar el contexto preparado y su versión para que `finalize_context_rebuild` los use.
|
|
122
118
|
self.session_context.save_prepared_context(company_short_name, user_identifier, final_system_context,
|
|
123
119
|
current_version)
|
|
Binary file
|
iatoolkit/templates/index.html
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{% extends "base.html" %}
|
|
2
2
|
|
|
3
|
-
{% block title %}IAToolkit
|
|
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
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
</
|
|
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
|
-
</
|
|
147
|
-
</section>
|
|
146
|
+
</section>
|
|
148
147
|
|
|
149
148
|
|
|
150
149
|
<!-- 4. Footer (sin cambios) -->
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
{% extends "base.html" %}
|
|
2
|
+
|
|
3
|
+
{% block title %}Prueba de Login para {{ company_short_name }}{% endblock %}
|
|
4
|
+
|
|
5
|
+
{% block content %}
|
|
6
|
+
|
|
7
|
+
<div class="container-fluid">
|
|
8
|
+
<div class="row flex-fill mt-5 justify-content-center">
|
|
9
|
+
<!-- login desde sistema externo -->
|
|
10
|
+
<div class="col-12 col-lg-6">
|
|
11
|
+
<div class="border rounded p-4 p-md-5 shadow-sm bg-light">
|
|
12
|
+
{# El título ahora muestra dinámicamente el nombre de la empresa #}
|
|
13
|
+
<h3 class="text-muted fw-semibold text-start mb-3">
|
|
14
|
+
Login Externo para <span style="color:#0d6efd;">{{ company_short_name }}</span>
|
|
15
|
+
</h3>
|
|
16
|
+
<div class="text-center mb-4">
|
|
17
|
+
<p class="text-muted widget-intro-text">
|
|
18
|
+
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.
|
|
19
|
+
</p>
|
|
20
|
+
</div>
|
|
21
|
+
|
|
22
|
+
{# El 'action' y 'method' son manejados por JS, pero el id es crucial #}
|
|
23
|
+
<form id="external-login">
|
|
24
|
+
|
|
25
|
+
<div class="mb-3">
|
|
26
|
+
<label for="external_user_id" class="form-label d-block">External user ID</label>
|
|
27
|
+
<input type="text" id="external_user_id" name="external_user_id" class="form-control" required>
|
|
28
|
+
</div>
|
|
29
|
+
|
|
30
|
+
<button type="submit" id="loginButton" class="btn btn-primary">
|
|
31
|
+
Iniciar Sesión
|
|
32
|
+
</button>
|
|
33
|
+
</form>
|
|
34
|
+
</div>
|
|
35
|
+
</div>
|
|
36
|
+
</div>
|
|
37
|
+
</div>
|
|
38
|
+
{% endblock %}
|
|
39
|
+
|
|
40
|
+
{% block scripts %}
|
|
41
|
+
<script>
|
|
42
|
+
document.addEventListener('DOMContentLoaded', function() {
|
|
43
|
+
const companyShortName = "{{ company_short_name }}";
|
|
44
|
+
const apiKey = "{{ api_key }}";
|
|
45
|
+
const loginForm = document.getElementById('external-login');
|
|
46
|
+
const userIdInput = document.getElementById('external_user_id');
|
|
47
|
+
|
|
48
|
+
loginForm.addEventListener('submit', function(event) {
|
|
49
|
+
event.preventDefault();
|
|
50
|
+
const userIdentifier = userIdInput.value.trim();
|
|
51
|
+
if (!userIdentifier) return;
|
|
52
|
+
|
|
53
|
+
// 1. Reemplazamos la página actual con un mensaje de carga.
|
|
54
|
+
document.body.innerHTML = '<div style="display:flex; align-items:center; justify-content:center; height:100vh; font-family:sans-serif;">Iniciando sesión, por favor espera...</div>';
|
|
55
|
+
|
|
56
|
+
const apiUrl = `/${companyShortName}/external_login`;
|
|
57
|
+
|
|
58
|
+
fetch(apiUrl, {
|
|
59
|
+
method: 'POST',
|
|
60
|
+
headers: {
|
|
61
|
+
'Content-Type': 'application/json',
|
|
62
|
+
'Authorization': `Bearer ${apiKey}`
|
|
63
|
+
},
|
|
64
|
+
body: JSON.stringify({
|
|
65
|
+
// Usamos 'userIdentifier' como el valor para el campo 'external_user_id'
|
|
66
|
+
user_identifier: userIdentifier
|
|
67
|
+
})
|
|
68
|
+
})
|
|
69
|
+
.then(async response => {
|
|
70
|
+
if (response.ok) {
|
|
71
|
+
return response.text();
|
|
72
|
+
} else {
|
|
73
|
+
const errorText = await response.text();
|
|
74
|
+
throw new Error(errorText || `Error ${response.status}`);
|
|
75
|
+
}
|
|
76
|
+
})
|
|
77
|
+
.then(htmlContent => {
|
|
78
|
+
// 2. Reemplazamos todo el documento con el nuevo HTML recibido.
|
|
79
|
+
// Esto asegura que todos los scripts y estilos del nuevo HTML se carguen correctamente.
|
|
80
|
+
document.open();
|
|
81
|
+
document.write(htmlContent);
|
|
82
|
+
document.close();
|
|
83
|
+
})
|
|
84
|
+
.catch(error => {
|
|
85
|
+
// Si hay un error, lo mostramos en la página.
|
|
86
|
+
document.body.innerHTML = `<div style="padding:20px; font-family:monospace; color:red;"><h2>Error</h2><pre>${error.message}</pre></div>`;
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
</script>
|
|
91
|
+
{% endblock %}
|
|
@@ -43,16 +43,16 @@ class ExternalLoginView(BaseLoginView):
|
|
|
43
43
|
|
|
44
44
|
def post(self, company_short_name: str):
|
|
45
45
|
data = request.get_json()
|
|
46
|
-
if not data or '
|
|
47
|
-
return jsonify({"error": "Falta
|
|
46
|
+
if not data or 'user_identifier' not in data:
|
|
47
|
+
return jsonify({"error": "Falta user_identifier"}), 400
|
|
48
48
|
|
|
49
49
|
company = self.profile_service.get_company_by_short_name(company_short_name)
|
|
50
50
|
if not company:
|
|
51
51
|
return jsonify({"error": "Empresa no encontrada"}), 404
|
|
52
52
|
|
|
53
|
-
|
|
54
|
-
if not
|
|
55
|
-
return jsonify({"error": "missing
|
|
53
|
+
user_identifier = data.get('user_identifier')
|
|
54
|
+
if not user_identifier:
|
|
55
|
+
return jsonify({"error": "missing user_identifier"}), 404
|
|
56
56
|
|
|
57
57
|
# 1. Authenticate the API call.
|
|
58
58
|
iaut = self.iauthentication.verify()
|
|
@@ -60,11 +60,11 @@ class ExternalLoginView(BaseLoginView):
|
|
|
60
60
|
return jsonify(iaut), 401
|
|
61
61
|
|
|
62
62
|
# 2. Create the external user session.
|
|
63
|
-
self.profile_service.create_external_user_session(company,
|
|
63
|
+
self.profile_service.create_external_user_session(company, user_identifier)
|
|
64
64
|
|
|
65
65
|
# 3. Delegate the path decision to the centralized logic.
|
|
66
66
|
try:
|
|
67
|
-
return self._handle_login_path(company_short_name,
|
|
67
|
+
return self._handle_login_path(company_short_name, user_identifier, company)
|
|
68
68
|
except Exception as e:
|
|
69
|
-
logging.exception(f"Error processing external login path for {company_short_name}/{
|
|
69
|
+
logging.exception(f"Error processing external login path for {company_short_name}/{user_identifier}: {e}")
|
|
70
70
|
return jsonify({"error": f"Internal server error while starting chat. {str(e)}"}), 500
|
|
@@ -1,60 +1,27 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
# Copyright (c) 2024 Fernando Libedinsky
|
|
2
|
+
# Product: IAToolkit
|
|
3
|
+
#
|
|
4
|
+
# IAToolkit is open source software.
|
|
5
|
+
|
|
4
6
|
from flask.views import MethodView
|
|
5
|
-
from flask import
|
|
7
|
+
from flask import render_template, request
|
|
8
|
+
from injector import inject
|
|
9
|
+
from iatoolkit.services.profile_service import ProfileService
|
|
10
|
+
import os
|
|
6
11
|
|
|
7
12
|
|
|
8
13
|
class LoginSimulationView(MethodView):
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
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
|
-
)
|
|
14
|
+
@inject
|
|
15
|
+
def __init__(self,
|
|
16
|
+
profile_service: ProfileService):
|
|
17
|
+
self.profile_service = profile_service
|
|
47
18
|
|
|
48
|
-
|
|
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
|
|
19
|
+
def get(self, company_short_name: str = None):
|
|
53
20
|
|
|
54
|
-
|
|
21
|
+
# Esta API_KEY para el login
|
|
22
|
+
api_key_for_login = os.getenv("IATOOLKIT_API_KEY", "tu_api_key_por_defecto_o_error")
|
|
55
23
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
return Response(f'Error de conexión con el servicio de IA: {str(e)}', status=502, mimetype='text/plain')
|
|
24
|
+
return render_template('login_simulation.html',
|
|
25
|
+
company_short_name=company_short_name,
|
|
26
|
+
api_key=api_key_for_login
|
|
27
|
+
)
|
|
@@ -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=
|
|
5
|
+
iatoolkit/iatoolkit.py,sha256=1Uo619dvzhZzMwgycUFLb0iH3eIJiBw-FuDZbQmMsGE,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=
|
|
8
|
+
iatoolkit/common/routes.py,sha256=EcfJXJ3e3sQX_jRiMRKambcYoAaLnnjMuKS9H7NqkDM,6082
|
|
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=
|
|
29
|
+
iatoolkit/repositories/database_manager.py,sha256=QgV8hNnVv9RmeOvUdomdj_mfk0bf3Rl8Ti41a-5zIAY,3700
|
|
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
|
|
@@ -46,23 +46,15 @@ iatoolkit/services/jwt_service.py,sha256=YoZ9h7_o9xBko-arNQv4MbcwnxoSWVNj4VbZmMo
|
|
|
46
46
|
iatoolkit/services/load_documents_service.py,sha256=ZpB0BZ3qX1fGJGBtZtMLbFdWWx0hkPoeCS3OqJKwCTs,7291
|
|
47
47
|
iatoolkit/services/mail_service.py,sha256=2h-fcF3swZDya_o7IpgXkmuj3iEVHVCiHi7oVxU99sQ,2182
|
|
48
48
|
iatoolkit/services/onboarding_service.py,sha256=cMO2Ho1-G3wAeVNl-j25LwCMJjRwj3yKHpYKnZUFLDE,2001
|
|
49
|
-
iatoolkit/services/profile_service.py,sha256=
|
|
49
|
+
iatoolkit/services/profile_service.py,sha256=w4ZhMuhZMH5_UHbDgvKeZHXNNecEIiExtuKI8fKZL-k,20232
|
|
50
50
|
iatoolkit/services/prompt_manager_service.py,sha256=U-XmSpkeXvv1KRN4dytdMxSYBMRSB7y-UHcb18mk0nA,8342
|
|
51
|
-
iatoolkit/services/query_service.py,sha256=
|
|
51
|
+
iatoolkit/services/query_service.py,sha256=J42KzthYIIsUX8cUS2E7vcXA6IZOJ28Y8I637m-9za4,17649
|
|
52
52
|
iatoolkit/services/search_service.py,sha256=i1xGWu7ORKIIDH0aAQBkF86dVVbLQ0Yrooz5TiZ6aGo,1823
|
|
53
53
|
iatoolkit/services/sql_service.py,sha256=MIslAtpJWnTMgSD74nnqTvQj27p-lHiyRXc6OiA2C_c,2172
|
|
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/
|
|
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
|
|
@@ -88,8 +80,8 @@ iatoolkit/templates/chat_modals.html,sha256=NwwgPoOmVbjy4aO2eHsy1TUMXRiOfTOC5Jx_
|
|
|
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=
|
|
92
|
-
iatoolkit/templates/
|
|
83
|
+
iatoolkit/templates/index.html,sha256=Q2wBHDv3HTBt-jURVLggye7XOqoqDY8E0LnrmLdc3SQ,7910
|
|
84
|
+
iatoolkit/templates/login_simulation.html,sha256=DqzH0ygJzkGHjdQcoITdONe8GJmv4u_rgoAw1TizYeo,3513
|
|
93
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
|
|
@@ -97,7 +89,7 @@ iatoolkit/views/__init__.py,sha256=5JqK9sZ6jBuK83zDQokUhxQ0wuJJJ9DXB8pYCLkX7X4,1
|
|
|
97
89
|
iatoolkit/views/base_login_view.py,sha256=6IWJXEg_6K9cPYoKnG_-Kpt_hIdYnv5ZNC5anIrytXk,2819
|
|
98
90
|
iatoolkit/views/change_password_view.py,sha256=tM0woZyKdhY4XYjS_YXg2sKq3RYkXGfcq_eVAKrNvNM,4498
|
|
99
91
|
iatoolkit/views/chat_token_request_view.py,sha256=wf32_A2Sq8NHYWshCwL10Tovd1znLoD0jQjzutR3sVE,4408
|
|
100
|
-
iatoolkit/views/external_login_view.py,sha256=
|
|
92
|
+
iatoolkit/views/external_login_view.py,sha256=IC3X0IZYAfTjHfWSzCwrjqlnBin3Ky7hJZzj3AGk8ZI,2884
|
|
101
93
|
iatoolkit/views/file_store_api_view.py,sha256=Uz9f6sey3_F5K8zuyQz6SwYRKAalCjD1ekf-Mkl_Kfo,2326
|
|
102
94
|
iatoolkit/views/forgot_password_view.py,sha256=-qKJeeOBqJFdvDUk7rCNg1E1cDQnJQkozPpb0T0FgwA,3159
|
|
103
95
|
iatoolkit/views/history_api_view.py,sha256=x-tZhB8UzqrD2n-WDIfmHK9iVhGZ9f0yncsGs9mxwt0,1953
|
|
@@ -105,7 +97,7 @@ 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_simulation_view.py,sha256=
|
|
100
|
+
iatoolkit/views/login_simulation_view.py,sha256=GFKtrHXzU_bPRgtPO1quoPknV_GeI-fUHq9YVPqNrJs,854
|
|
109
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
|
|
@@ -113,7 +105,7 @@ iatoolkit/views/tasks_review_view.py,sha256=keLsLCyOTTlcoIapnB_lbuSvLwrPVZVpBiFC
|
|
|
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.
|
|
117
|
-
iatoolkit-0.55.
|
|
118
|
-
iatoolkit-0.55.
|
|
119
|
-
iatoolkit-0.55.
|
|
108
|
+
iatoolkit-0.55.3.dist-info/METADATA,sha256=JYdzDOAsjbP7j9lAd6wtdNf6Lj2LjJEBpbqIPpCLt6Y,9301
|
|
109
|
+
iatoolkit-0.55.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
110
|
+
iatoolkit-0.55.3.dist-info/top_level.txt,sha256=V_w4QvDx0b1RXiy8zTCrD1Bp7AZkFe3_O0-9fMiwogg,10
|
|
111
|
+
iatoolkit-0.55.3.dist-info/RECORD,,
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
{% extends "base.html" %}
|
|
2
|
-
|
|
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 %}
|
|
18
|
-
|
|
19
|
-
{% block content %}
|
|
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
|
-
</div>
|
|
34
|
-
|
|
35
|
-
{# El 'action' y 'method' son manejados por JS, pero el id es crucial #}
|
|
36
|
-
<form id="jwt-form">
|
|
37
|
-
|
|
38
|
-
<div class="mb-3">
|
|
39
|
-
<label for="external_user_id" class="form-label d-block">External user ID</label>
|
|
40
|
-
<input type="text" id="external_user_id" name="external_user_id" class="form-control" required>
|
|
41
|
-
</div>
|
|
42
|
-
|
|
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
|
|
46
|
-
</button>
|
|
47
|
-
</form>
|
|
48
|
-
</div>
|
|
49
|
-
</div>
|
|
50
|
-
</div>
|
|
51
|
-
</div>
|
|
52
|
-
{% endblock %}
|
|
53
|
-
|
|
54
|
-
{% block scripts %}
|
|
55
|
-
<script>
|
|
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: {
|
|
79
|
-
'Content-Type': 'application/json',
|
|
80
|
-
'Authorization': `Bearer ${apiKey}`
|
|
81
|
-
},
|
|
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
|
-
});
|
|
116
|
-
});
|
|
117
|
-
</script>
|
|
118
|
-
{% endblock %}
|
|
File without changes
|
|
File without changes
|