iatoolkit 0.7.9__py3-none-any.whl → 0.7.11__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.

Files changed (126) hide show
  1. iatoolkit/__init__.py +18 -14
  2. iatoolkit/base_company.py +5 -5
  3. iatoolkit/cli_commands.py +5 -3
  4. {common → iatoolkit/common}/auth.py +3 -3
  5. {common → iatoolkit/common}/routes.py +19 -19
  6. {common → iatoolkit/common}/util.py +2 -2
  7. iatoolkit/iatoolkit.py +37 -38
  8. {infra → iatoolkit/infra}/call_service.py +1 -1
  9. {infra → iatoolkit/infra}/connectors/file_connector_factory.py +5 -5
  10. {infra → iatoolkit/infra}/connectors/google_cloud_storage_connector.py +1 -1
  11. {infra → iatoolkit/infra}/connectors/google_drive_connector.py +1 -1
  12. {infra → iatoolkit/infra}/connectors/local_file_connector.py +2 -2
  13. {infra → iatoolkit/infra}/connectors/s3_connector.py +1 -1
  14. {infra → iatoolkit/infra}/gemini_adapter.py +2 -2
  15. {infra → iatoolkit/infra}/google_chat_app.py +1 -1
  16. {infra → iatoolkit/infra}/llm_client.py +7 -7
  17. {infra → iatoolkit/infra}/llm_proxy.py +6 -6
  18. {infra → iatoolkit/infra}/mail_app.py +1 -1
  19. {infra → iatoolkit/infra}/openai_adapter.py +2 -2
  20. {repositories → iatoolkit/repositories}/database_manager.py +1 -1
  21. {repositories → iatoolkit/repositories}/document_repo.py +3 -3
  22. {repositories → iatoolkit/repositories}/llm_query_repo.py +2 -2
  23. {repositories → iatoolkit/repositories}/profile_repo.py +2 -2
  24. {repositories → iatoolkit/repositories}/tasks_repo.py +2 -2
  25. {repositories → iatoolkit/repositories}/vs_repo.py +3 -3
  26. {services → iatoolkit/services}/benchmark_service.py +3 -3
  27. {services → iatoolkit/services}/dispatcher_service.py +9 -8
  28. {services → iatoolkit/services}/document_service.py +1 -1
  29. {services → iatoolkit/services}/excel_service.py +2 -2
  30. {services → iatoolkit/services}/file_processor_service.py +2 -2
  31. {services → iatoolkit/services}/history_service.py +4 -3
  32. {services → iatoolkit/services}/load_documents_service.py +11 -10
  33. {services → iatoolkit/services}/mail_service.py +2 -2
  34. {services → iatoolkit/services}/profile_service.py +6 -6
  35. {services → iatoolkit/services}/prompt_manager_service.py +5 -4
  36. {services → iatoolkit/services}/query_service.py +12 -11
  37. {services → iatoolkit/services}/search_service.py +2 -2
  38. {services → iatoolkit/services}/sql_service.py +4 -3
  39. {services → iatoolkit/services}/tasks_service.py +6 -6
  40. {services → iatoolkit/services}/user_feedback_service.py +3 -3
  41. {services → iatoolkit/services}/user_session_context_service.py +1 -1
  42. iatoolkit/static/images/arrow_up.png +0 -0
  43. iatoolkit/static/images/diagrama_iatoolkit.jpg +0 -0
  44. iatoolkit/static/images/logo_clinica.png +0 -0
  45. iatoolkit/static/images/logo_iatoolkit.png +0 -0
  46. iatoolkit/static/images/logo_maxxa.png +0 -0
  47. iatoolkit/static/images/logo_notaria.png +0 -0
  48. iatoolkit/static/images/logo_tarjeta.png +0 -0
  49. iatoolkit/static/images/logo_umayor.png +0 -0
  50. iatoolkit/static/images/upload.png +0 -0
  51. iatoolkit/static/js/chat_feedback.js +115 -0
  52. iatoolkit/static/js/chat_filepond.js +85 -0
  53. iatoolkit/static/js/chat_history.js +117 -0
  54. iatoolkit/static/js/chat_main.js +436 -0
  55. iatoolkit/static/styles/chat_iatoolkit.css +701 -0
  56. iatoolkit/static/styles/chat_info.css +53 -0
  57. iatoolkit/static/styles/chat_modal.css +136 -0
  58. iatoolkit/static/styles/llm_output.css +115 -0
  59. iatoolkit/static/temp/024f44a9-cc7e-4bde-9a3c-11903a8f5d3d.xlsx +0 -0
  60. iatoolkit/static/temp/0b97768e-79e8-43ec-b17e-ba3137f94e93.xlsx +0 -0
  61. iatoolkit/static/temp/202883ee-763e-4b40-9bb6-bfacfc5e65fe.xlsx +0 -0
  62. iatoolkit/static/temp/28287491-08b7-4863-a2a3-49fcb64a0906.xlsx +0 -0
  63. iatoolkit/static/temp/36780cac-7a46-4db4-ac98-7338a51aaf52.xlsx +0 -0
  64. iatoolkit/static/temp/5c1b66f6-d58f-4684-8a7a-df3bb1a35eaa.xlsx +0 -0
  65. iatoolkit/static/temp/5d5a3500-ec57-4e07-a554-8799a906d1ab.xlsx +0 -0
  66. iatoolkit/static/temp/65887e40-cf64-49aa-8d1f-651cb0f8cdf0.xlsx +0 -0
  67. iatoolkit/static/temp/6fa64b13-e8e5-40ad-8257-00fd1682dad8.xlsx +0 -0
  68. iatoolkit/static/temp/7ab7071f-ad9b-49e6-8e63-f08410625ce7.xlsx +0 -0
  69. iatoolkit/static/temp/824346d9-d54d-40c6-b5c2-9e1d84d0ae90.xlsx +0 -0
  70. iatoolkit/static/temp/9ca80c3d-d196-4dfc-8179-582584fae04c.xlsx +0 -0
  71. iatoolkit/static/temp/a34cb8a6-85fb-4ea8-aabe-889967cd83b5.xlsx +0 -0
  72. iatoolkit/static/temp/a7fc9c13-c509-4499-b4be-23bfa57cac31.xlsx +0 -0
  73. iatoolkit/static/temp/b83084f5-fe54-4580-885e-412b4388cbda.xlsx +0 -0
  74. iatoolkit/static/temp/c17c6864-34e1-448f-b0e9-380354256ea9.xlsx +0 -0
  75. iatoolkit/static/temp/customer_clusters.parquet +0 -0
  76. iatoolkit/static/temp/customer_clusters.xlsx +0 -0
  77. iatoolkit/static/temp/d1af98b8-18a9-4b94-b9bc-607d19a87d0d.xlsx +0 -0
  78. iatoolkit/templates/about.html +13 -0
  79. iatoolkit/templates/base.html +45 -0
  80. iatoolkit/templates/change_password.html +45 -0
  81. iatoolkit/templates/chat.html +180 -0
  82. iatoolkit/templates/chat_modals.html +115 -0
  83. iatoolkit/templates/error.html +15 -0
  84. iatoolkit/templates/forgot_password.html +33 -0
  85. iatoolkit/templates/header.html +31 -0
  86. iatoolkit/templates/home.html +201 -0
  87. iatoolkit/templates/login.html +43 -0
  88. iatoolkit/templates/signup.html +78 -0
  89. iatoolkit/templates/test.html +9 -0
  90. {views → iatoolkit/views}/change_password_view.py +1 -1
  91. {views → iatoolkit/views}/chat_token_request_view.py +2 -2
  92. {views → iatoolkit/views}/chat_view.py +3 -3
  93. {views → iatoolkit/views}/download_file_view.py +3 -3
  94. {views → iatoolkit/views}/external_chat_login_view.py +5 -5
  95. {views → iatoolkit/views}/external_login_view.py +2 -2
  96. {views → iatoolkit/views}/file_store_view.py +2 -2
  97. {views → iatoolkit/views}/forgot_password_view.py +1 -1
  98. {views → iatoolkit/views}/history_view.py +2 -2
  99. {views → iatoolkit/views}/home_view.py +1 -1
  100. {views → iatoolkit/views}/llmquery_view.py +2 -2
  101. {views → iatoolkit/views}/login_view.py +1 -1
  102. {views → iatoolkit/views}/prompt_view.py +2 -2
  103. {views → iatoolkit/views}/signup_view.py +1 -1
  104. {views → iatoolkit/views}/tasks_review_view.py +2 -2
  105. {views → iatoolkit/views}/tasks_view.py +2 -2
  106. {views → iatoolkit/views}/user_feedback_view.py +2 -2
  107. {views → iatoolkit/views}/verify_user_view.py +1 -1
  108. {iatoolkit-0.7.9.dist-info → iatoolkit-0.7.11.dist-info}/METADATA +1 -1
  109. iatoolkit-0.7.11.dist-info/RECORD +128 -0
  110. iatoolkit-0.7.11.dist-info/top_level.txt +1 -0
  111. iatoolkit-0.7.9.dist-info/RECORD +0 -80
  112. iatoolkit-0.7.9.dist-info/top_level.txt +0 -6
  113. {common → iatoolkit/common}/__init__.py +0 -0
  114. {common → iatoolkit/common}/exceptions.py +0 -0
  115. {common → iatoolkit/common}/session_manager.py +0 -0
  116. {infra → iatoolkit/infra}/__init__.py +0 -0
  117. {infra → iatoolkit/infra}/connectors/__init__.py +0 -0
  118. {infra → iatoolkit/infra}/connectors/file_connector.py +0 -0
  119. {infra → iatoolkit/infra}/llm_response.py +0 -0
  120. {infra → iatoolkit/infra}/redis_session_manager.py +0 -0
  121. {repositories → iatoolkit/repositories}/__init__.py +0 -0
  122. {repositories → iatoolkit/repositories}/models.py +0 -0
  123. {services → iatoolkit/services}/__init__.py +0 -0
  124. {services → iatoolkit/services}/jwt_service.py +0 -0
  125. {views → iatoolkit/views}/__init__.py +0 -0
  126. {iatoolkit-0.7.9.dist-info → iatoolkit-0.7.11.dist-info}/WHEEL +0 -0
@@ -0,0 +1,115 @@
1
+ <!-- Modal para mostrar archivos cargados -->
2
+ <div class="modal fade" id="uploadedFilesModal" tabindex="-1" aria-labelledby="uploadedFilesModalLabel" aria-hidden="true">
3
+ <div class="modal-dialog">
4
+ <div class="modal-content">
5
+ <div class="modal-header">
6
+ <h5 class="modal-title" id="uploadedFilesModalLabel">Archivos Cargados</h5>
7
+ <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
8
+ </div>
9
+ <div class="modal-body">
10
+ <ul id="uploaded-files-list" class="list-group">
11
+ <!-- Los nombres de los archivos se agregarán aquí por JS -->
12
+ </ul>
13
+ </div>
14
+ <div class="modal-footer">
15
+ <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cerrar</button>
16
+ </div>
17
+ </div>
18
+ </div>
19
+ </div>
20
+
21
+ <!-- Modal para feedback -->
22
+ <div class="modal fade" id="feedbackModal" tabindex="-1" aria-labelledby="feedbackModalLabel" aria-hidden="true">
23
+ <div class="modal-dialog modal-dialog-centered">
24
+ <div class="modal-content">
25
+ <div class="modal-header">
26
+ <h5 class="modal-title" id="feedbackModalLabel">
27
+ <i class="bi bi-chat-dots me-3"></i>Tu Opinión es Importante
28
+ </h5>
29
+ <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
30
+ </div>
31
+ <div class="modal-body">
32
+ <p class="text-center mb-2"><strong>¿Qué tan útil fue la respuesta del asistente?</strong></p>
33
+
34
+ <!-- ▼▼▼ ESTE ES EL BLOQUE DE HTML QUE FALTABA ▼▼▼ -->
35
+ <div class="rating-stars mb-4">
36
+ <span class="star" data-rating="1" onclick="gfg(1)"></span>
37
+ <span class="star" data-rating="2" onclick="gfg(2)"></span>
38
+ <span class="star" data-rating="3" onclick="gfg(3)"></span>
39
+ <span class="star" data-rating="4" onclick="gfg(4)"></span>
40
+ <span class="star" data-rating="5" onclick="gfg(5)"></span>
41
+ </div>
42
+ <!-- ▲▲▲ FIN DEL BLOQUE DE HTML QUE FALTABA ▲▲▲ -->
43
+
44
+ <div class="form-group">
45
+ <label for="feedback-text" class="form-label text-muted">Tu comentario nos ayuda a mejorar:</label>
46
+ <textarea
47
+ class="form-control feedback-text"
48
+ id="feedback-text"
49
+ rows="4"
50
+ placeholder="Escribe aquí tu opinión, sugerencias o comentarios..."
51
+ style="resize: vertical; min-height: 100px;"></textarea>
52
+ </div>
53
+ </div>
54
+ <div class="modal-footer">
55
+ <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">
56
+ <i class="bi bi-x-circle me-1"></i>Cancelar
57
+ </button>
58
+ <button type="button" class="btn btn-primary" id="submit-feedback">
59
+ <i class="bi bi-send me-1"></i>Enviar
60
+ </button>
61
+ </div>
62
+ </div>
63
+ </div>
64
+ </div>
65
+
66
+ <!-- Modal para historial -->
67
+ <div class="modal fade" id="historyModal" tabindex="-1" aria-labelledby="historyModalLabel" aria-hidden="true">
68
+ <div class="modal-dialog modal-lg modal-dialog-centered">
69
+ <div class="modal-content">
70
+ <div class="modal-header">
71
+ <h5 class="modal-title" id="historyModalLabel">
72
+ <i class="bi bi-clock-history me-3"></i>Historial de Consultas
73
+ </h5>
74
+ <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
75
+ </div>
76
+ <div class="modal-body">
77
+ <div id="history-loading" style="display: none;" class="text-center p-4">
78
+ <div class="spinner-border text-primary" role="status">
79
+ <span class="visually-hidden">Cargando...</span>
80
+ </div>
81
+ <p class="mt-2">Cargando historial...</p>
82
+ </div>
83
+ <div id="history-error" style="display: none;" class="alert alert-danger">
84
+ <!-- Los errores se mostrarán aquí -->
85
+ </div>
86
+ <div id="history-content" style="display: none;">
87
+ <!-- Texto explicativo -->
88
+ <div class="alert alert-info mb-3" role="alert">
89
+ <i class="bi bi-info-circle me-2"></i>
90
+ <strong>Tip:</strong> Haz clic en cualquier pregunta del historial para copiarla automáticamente al área de texto.
91
+ </div>
92
+ <div class="table-responsive">
93
+ <table class="table table-striped table-hover">
94
+ <thead class="thead-dark">
95
+ <tr>
96
+ <th scope="col">#</th>
97
+ <th scope="col">Fecha</th>
98
+ <th scope="col">Consulta</th>
99
+ </tr>
100
+ </thead>
101
+ <tbody id="history-table-body">
102
+ <!-- Los datos se cargarán aquí -->
103
+ </tbody>
104
+ </table>
105
+ </div>
106
+ </div>
107
+ </div>
108
+ <div class="modal-footer">
109
+ <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">
110
+ <i class="bi bi-x-circle me-1"></i>Cerrar
111
+ </button>
112
+ </div>
113
+ </div>
114
+ </div>
115
+ </div>
@@ -0,0 +1,15 @@
1
+ {% extends "base.html" %}
2
+
3
+ {% block title %}Error - IAToolkit{% endblock %}
4
+
5
+ {% block content %}
6
+ <div class="container vh-100 d-flex justify-content-center align-items-center">
7
+ <div class="text-center col-11 col-md-8 col-lg-6 border rounded p-4 shadow-sm bg-light">
8
+ <h1 class="text-danger fw-bold">¡Ups! Ha ocurrido un error</h1>
9
+ <p class="mt-3 text-muted">
10
+ {{ message }}
11
+ </p>
12
+ <a href="{{ url_for('home') }}" class="btn btn-primary mt-4">Volver al Inicio</a>
13
+ </div>
14
+ </div>
15
+ {% endblock %}
@@ -0,0 +1,33 @@
1
+ {% extends "base.html" %}
2
+
3
+ {% block title %}Recuperar Contraseña{% endblock %}
4
+
5
+ {% block content %}
6
+ <div class="container d-flex justify-content-center align-items-center vh-100">
7
+ <div class="col-11 col-md-6 col-lg-4 border rounded p-3 shadow-sm">
8
+ <h4 class="text-muted fw-semibold text-start mb-3">Recuperar Contraseña</h4>
9
+
10
+ <form action="{{ url_for('forgot_password', company_short_name=company_short_name) }}" method="post">
11
+ <div class="mb-3">
12
+ <label for="email" class="form-label text-muted">Correo Electrónico</label>
13
+ <input type="email" id="email" name="email"
14
+ class="form-control text-muted"
15
+ required value="{{ form_data.email if form_data else '' }}"
16
+ style="text-align: justify;">
17
+ </div>
18
+
19
+ <button type="submit" class="btn btn-primary w-100">Enviar Contraseña</button>
20
+
21
+ <!-- Mensaje descriptivo -->
22
+ <p class="text-muted text-start mt-3" style="text-align: justify;">
23
+ Recibirás un correo con una nueva contraseña temporal junto con un código de seguridad.
24
+ Usa este código para cambiar tu contraseña de forma segura y mantener tu cuenta protegida.
25
+ </p>
26
+
27
+ <div class="text-center mt-3">
28
+ <a href="{{ url_for('login', company_short_name=company_short_name) }}" class="text-muted text-decoration-none fw-semibold">Volver al Login</a>
29
+ </div>
30
+ </form>
31
+ </div>
32
+ </div>
33
+ {% endblock %}
@@ -0,0 +1,31 @@
1
+ {% if not external_login %}
2
+ <header class="modern-header">
3
+ {% if not is_mobile or not user %}
4
+ <div class="logo-section">
5
+ <a href="{{ url_for('chat', company_short_name=company_short_name) }}" title="Ir a Inicio">
6
+ {% if company_short_name %}
7
+ <img src="{{ url_for('static', filename='images/' + company.logo_file) }}" alt="Logo de la empresa">
8
+ {% else %}
9
+ <img src="{{ url_for('static', filename='images/logo_iatoolkit.png') }}" alt="Logo predeterminado">
10
+ {% endif %}
11
+ </a>
12
+ </div>
13
+ {% endif %}
14
+ {% if user and user_company == company_short_name %}
15
+ <div class="d-flex ms-auto align-items-center">
16
+ <!-- Nombres del usuario y empresa -->
17
+ <div class="d-flex flex-column {% if not is_mobile %} align-items-end {% endif %} me-3">
18
+ <span class="text-white fw-semibold">
19
+ {{ user.email }}
20
+ </span>
21
+ </div>
22
+
23
+ <!-- Icono de cerrar sesión -->
24
+ <a href="{{ url_for('logout', company_short_name=company_short_name) }}"
25
+ | class="text-white fs-4 ms-3" title="Cerrar sesión">
26
+ <i class="bi bi-box-arrow-right"></i>
27
+ </a>
28
+ </div>
29
+ {% endif %}
30
+ </header>
31
+ {% endif %}
@@ -0,0 +1,201 @@
1
+ {% extends "base.html" %}
2
+
3
+ {% block title %}Inicio - IAToolkit{% endblock %}
4
+
5
+ {% block content %}
6
+
7
+ <!-- Contenido principal con espaciado adicional respecto al header -->
8
+ <div class="row flex-fill mt-5 flex-wrap">
9
+
10
+ {% if not user or user_company != company_short_name %}
11
+ <!-- Sección de login (se coloca primero en el HTML para mobile) -->
12
+ <div class="col-12 col-lg-5 offset-lg-1">
13
+ <div class="border rounded p-4 shadow-sm bg-light">
14
+ <h4 class="text-muted fw-semibold text-start mb-3">login integrado (IAToolkit)</h4>
15
+ <form id="login-form"
16
+ action="{{ url_for('home', company_short_name=company_short_name) }}"
17
+ method="post">
18
+ <div class="mb-3">
19
+ <label for="company_short_name" class="form-label d-block text-muted">Empresa</label>
20
+ <select id="company_short_name" name="company_short_name" class="form-select" required>
21
+ <option value="" disabled selected>Selecciona una empresa</option>
22
+ {% for company in companies %}
23
+ <option value="{{ company.short_name }}"
24
+ {% if company.short_name == company_short_name %}selected{% endif %}>
25
+ {{ company.short_name }}
26
+ </option>
27
+ {% endfor %}
28
+ </select>
29
+ </div>
30
+
31
+ <div class="mb-3">
32
+ <label for="email" class="form-label d-block text-muted">Correo Electrónico</label>
33
+ <input type="email" id="email" name="email" class="form-control" required>
34
+ </div>
35
+ <div class="mb-3">
36
+ <label for="password" class="form-label d-block text-muted">Contraseña</label>
37
+ <input type="password" id="password" name="password" class="form-control" required>
38
+ </div>
39
+ <button type="submit" class="btn btn-primary w-100">
40
+ Iniciar Sesión</button>
41
+ </form>
42
+
43
+ <div class="text-center mt-3">
44
+ <a href="{% if company_short_name %}{{ url_for('signup', company_short_name=company_short_name) }}{% else %}#{% endif %}"
45
+ id="signup-link"
46
+ class="btn btn-outline-primary w-100">Registrarse</a>
47
+ </div>
48
+ <div class="text-center mt-3">
49
+ <a href="{{ url_for('forgot_password', company_short_name=company_short_name) }}" class="text-decoration-none text-muted fw-semibold">
50
+ ¿Olvidaste tu contraseña?
51
+ </a>
52
+ </div>
53
+ </div>
54
+ </div>
55
+ {% endif %}
56
+
57
+ <!-- Sección de JWT -->
58
+ <div class="col-12 col-lg-5 offset-lg-1">
59
+ <div class="border rounded p-4 shadow-sm bg-light">
60
+ <h4 class="text-muted fw-semibold text-start mb-3">login externo (api-key)</h4>
61
+ <form id="jwt-form" method="post">
62
+ <div class="mb-3">
63
+ <label for="company_name" class="form-label d-block text-muted">Empresa</label>
64
+ <select id="company_name" name="company_short_name" class="form-select" required>
65
+ <option value="" disabled selected>Selecciona una empresa</option>
66
+ {% for company in companies %}
67
+ {% if company.allow_jwt %}
68
+ <option value="{{ company.short_name }}"> {{ company.short_name }}
69
+ </option>
70
+ {% endif %}
71
+ {% endfor %}
72
+ </select>
73
+ </div>
74
+
75
+ <div class="mb-3">
76
+ <label for="external_user_id" class="form-label d-block text-muted">External user ID</label>
77
+ <input type="text" id="external_user_id" name="external_user_id" class="form-control" required>
78
+ </div>
79
+
80
+ <button type="button"
81
+ id="initiateJwtChatButton"
82
+ class="ml-5 btn btn-primary">
83
+ <span class="spinner-border spinner-border-sm d-none" role="status" aria-hidden="true"></span>
84
+ Iniciar Sesión JWT
85
+ </button>
86
+ </form>
87
+ </div>
88
+ </div>
89
+
90
+ </div>
91
+
92
+ {% endblock %}
93
+
94
+ {% block scripts %}
95
+
96
+ <script>
97
+ // Variables pasadas desde Flask (HomeView)
98
+ const CHAT_TOKEN_REQUEST_URL = "{{ chat_token_request_url|safe }}";
99
+ const PUBLIC_CHAT_URL_TEMPLATE = "{{ public_chat_url_template|safe }}";
100
+ const API_KEY = "{{ api_key|safe }}";
101
+
102
+ $(document).ready(function () {
103
+ // Función para actualizar el enlace de "Registrarse" y el action del formulario "Iniciar Sesión"
104
+ function updateLinksAndForm() {
105
+ const selectedCompany = $('#company_short_name').val(); // Obtenemos el valor del select
106
+
107
+ // Actualizar enlace "Registrarse"
108
+ if (selectedCompany && selectedCompany.trim() !== '') {
109
+ const signupUrl = '/' + selectedCompany + '/signup';
110
+ $('#signup-link').attr('href', signupUrl); // Actualizamos el href del botón "Registrarse"
111
+ } else {
112
+ $('#signup-link').attr('href', '#'); // Enlace a "#" si no hay empresa seleccionada
113
+ }
114
+
115
+ // Actualizar action del formulario "Iniciar Sesión"
116
+ if (selectedCompany && selectedCompany.trim() !== '') {
117
+ const loginAction = '/' + selectedCompany + '/login';
118
+ $('#login-form').attr('action', loginAction); // Actualizamos la URL del form
119
+ } else {
120
+ $('#login-form').attr('action', '#'); // URL genérica si no hay selección
121
+ }
122
+ }
123
+
124
+ // Actualizamos al cargar la página
125
+ updateLinksAndForm();
126
+
127
+ // Escuchamos el evento de cambio en el dropdown para actualizar dinámicamente
128
+ $('#company_short_name').on('change', function () {
129
+ updateLinksAndForm();
130
+ });
131
+
132
+ // Interceptamos el click en "Registrarse"
133
+ $('#signup-link').on('click', function (e) {
134
+ const selectedCompany = $('#company_short_name').val();
135
+
136
+ if (!selectedCompany || selectedCompany.trim() === '') {
137
+ e.preventDefault(); // evitar navegación al #
138
+ Swal.fire({
139
+ icon: 'warning',
140
+ title: 'Empresa no seleccionada',
141
+ text: 'Por favor, selecciona una empresa antes de registrarte.'
142
+ });
143
+ }
144
+ });
145
+
146
+ // Event listener para el botón de "Abrir Chat (JWT)"
147
+ $('#initiateJwtChatButton').on('click', function() {
148
+
149
+ const selectedCompany = $('#company_name').val();
150
+ const externalUserId = $('#external_user_id').val();
151
+
152
+ if (!selectedCompany || !externalUserId.trim()) {
153
+ Swal.fire({ icon: 'warning', title: 'Campos Requeridos', text: 'Por favor, selecciona una empresa e ingresa un ID de usuario.' });
154
+ return;
155
+ }
156
+ if (!API_KEY || API_KEY.includes("defecto")) {
157
+ Swal.fire({ icon: 'error', title: 'Error de Configuración', text: 'La API Key de la aplicación no está disponible.' });
158
+ return;
159
+ }
160
+
161
+ const $button = $(this);
162
+ const $spinner = $button.find('.spinner-border');
163
+ $button.prop('disabled', true);
164
+ $spinner.removeClass('d-none');
165
+
166
+ fetch(`/${selectedCompany}/chat_login`, {
167
+ method: 'POST',
168
+ headers: {
169
+ 'Content-Type': 'application/json',
170
+ 'Authorization': `Bearer ${API_KEY}`
171
+ },
172
+ body: JSON.stringify({
173
+ external_user_id: externalUserId
174
+ })
175
+ })
176
+ .then(async response => {
177
+ if (response.ok) { // Si el status es 200, la respuesta es el HTML
178
+ return response.text();
179
+ } else { // Si hay un error, el cuerpo es JSON
180
+ const errorData = await response.json();
181
+ throw new Error(errorData.error || 'Ocurrió un error desconocido.');
182
+ }
183
+ })
184
+ .then(htmlContent => {
185
+ // Éxito: Abrimos el HTML que nos devolvió el servidor en una nueva pestaña.
186
+ const newTab = window.open();
187
+ newTab.document.write(htmlContent);
188
+ newTab.document.close();
189
+ })
190
+ .catch(error => {
191
+ Swal.fire({ icon: 'error', title: 'Error de Inicio de Sesión', text: error.message });
192
+ })
193
+ .finally(() => {
194
+ $button.prop('disabled', false);
195
+ $spinner.addClass('d-none');
196
+ });
197
+
198
+ });
199
+ });
200
+ </script>
201
+ {% endblock %}
@@ -0,0 +1,43 @@
1
+ {% extends "base.html" %}
2
+
3
+ {% block title %}Inicio de Sesión{% endblock %}
4
+
5
+ {% block content %}
6
+ <div class="container d-flex justify-content-center align-items-center vh-100">
7
+ <div class="col-11 col-md-6 col-lg-4 border rounded p-3 shadow-sm">
8
+ <h4 class="text-muted fw-semibold text-start mb-3">Iniciar Sesión - {{ company.name }}
9
+ </h4>
10
+ <form action="{{ url_for('login', company_short_name=company_short_name) }}"
11
+ method="post">
12
+ <div class="mb-3">
13
+ <label for="email" class="form-label text-muted">Correo Electrónico</label>
14
+ <input type="email" id="email" name="email"
15
+ class="form-control" required
16
+ value="{{ form_data.email if form_data else '' }}">
17
+ </div>
18
+ <div class="mb-3">
19
+ <label for="password" class="form-label">Contraseña</label>
20
+ <input type="password" id="password" name="password"
21
+ class="form-control" required
22
+ value="{{ form_data.password if form_data else '' }}">
23
+ </div>
24
+ <button type="submit" class="btn btn-primary w-100">Iniciar Sesión</button>
25
+
26
+ <p class="text-muted text-start mt-3" style="text-align: justify;">
27
+ Ingresa tus credenciales para acceder a tu cuenta. Si olvidaste tu contraseña,
28
+ puedes recuperarla fácilmente a través del siguiente enlace.
29
+ </p>
30
+ <div class="text-center mt-3">
31
+ <a href="{{ url_for('signup', company_short_name=company_short_name) }}">
32
+ ¿No tienes cuenta? Regístrate
33
+ </a>
34
+ </div>
35
+ <div class="text-center mt-3">
36
+ <a href="{{ url_for('forgot_password', company_short_name=company_short_name) }}">
37
+ ¿Olvidaste tu contraseña?
38
+ </a>
39
+ </div>
40
+ </form>
41
+ </div>
42
+ </div>
43
+ {% endblock %}
@@ -0,0 +1,78 @@
1
+ {% extends "base.html" %}
2
+
3
+ {% block title %}Registro de Usuario{% endblock %}
4
+
5
+ {% block content %}
6
+
7
+
8
+ <div class="d-flex align-items-center p-3 border-bottom border-light-subtle">
9
+ <div class="col-11 col-md-8 col-lg-5 p-3">
10
+ <h4 class="text-muted fw-semibold mb-2 text-start">Crea tu cuenta</h4>
11
+ <p class="text-muted mb-3 text-start" style="text-align: justify;">
12
+ Regístrate para acceder a todas las funcionalidades de nuestra plataforma.
13
+ </p>
14
+ <form action="{{ url_for('signup', company_short_name=company_short_name) }}" method="post" >
15
+ <div class="mb-3 ">
16
+ <label for="email" class="form-label text-secondary">Correo Electrónico</label>
17
+ <input type="email" autocomplete="off" id="email" name="email"
18
+ class="form-control" required
19
+ value="{{ form_data.email if form_data else '' }}">
20
+ </div>
21
+
22
+ {% if is_mobile %}
23
+ <!-- En móvil, cada input ocupa una fila -->
24
+ <div class="mb-3">
25
+ <label for="first_name" class="form-label text-secondary">Nombre</label>
26
+ <input type="text" id="first_name" name="first_name"
27
+ class="form-control" required
28
+ value="{{ form_data.first_name if form_data else '' }}">
29
+ </div>
30
+ <div class="mb-3">
31
+ <label for="last_name" class="form-label text-secondary">Apellido</label>
32
+ <input type="text" id="last_name" name="last_name"
33
+ class="form-control" required
34
+ value="{{ form_data.last_name if form_data else '' }}">
35
+ </div>
36
+ {% else %}
37
+ <div class="row">
38
+ <!-- En escritorio, los inputs están en la misma fila -->
39
+ <div class="col-md-6 mb-3">
40
+ <label for="first_name" class="form-label text-secondary">Nombre</label>
41
+ <input type="text" id="first_name" name="first_name"
42
+ class="form-control" required
43
+ value="{{ form_data.first_name if form_data else '' }}">
44
+ </div>
45
+ <div class="col-md-6 mb-3">
46
+ <label for="last_name" class="form-label text-secondary">Apellido</label>
47
+ <input type="text" id="last_name" name="last_name"
48
+ class="form-control" required
49
+ value="{{ form_data.last_name if form_data else '' }}">
50
+ </div>
51
+ </div>
52
+
53
+ {% endif %}
54
+
55
+ <div class="mb-3">
56
+ <label for="password" class="form-label text-secondary">Contraseña</label>
57
+ <input type="password" id="password" name="password" class="form-control" required>
58
+ <small class="form-text text-muted">
59
+ La contraseña debe contener al menos 8 caracteres, una letra mayúscula, una letra minúscula, un número y un carácter especial.
60
+ </small>
61
+
62
+ </div>
63
+ <div class="mb-3">
64
+ <label for="confirm_password" class="form-label text-secondary">Confirmar Contraseña</label>
65
+ <input type="password" id="confirm_password" name="confirm_password" class="form-control" required>
66
+ </div>
67
+ <button type="submit" class="btn btn-primary w-100">Registrarse</button>
68
+ </form>
69
+ <!-- Nota sobre privacidad -->
70
+ <p class="text-muted small mb-0 text-start mt-3" style="text-align: justify;">
71
+ 🔒 Valoramos tu privacidad. Tus datos serán utilizados exclusivamente para brindarte una mejor experiencia
72
+ y no serán compartidos con terceros sin tu consentimiento. Para más información, consulta nuestra
73
+ <a href="#" class="text-decoration-none fw-semibold">Política de Privacidad</a>.
74
+ </p>
75
+ </p>
76
+ </div>
77
+ </div>
78
+ {% endblock %}
@@ -0,0 +1,9 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Prueba</title>
5
+ </head>
6
+ <body>
7
+ <h1>Prueba Básica con Flask-Injector</h1>
8
+ </body>
9
+ </html>
@@ -5,7 +5,7 @@
5
5
 
6
6
  from flask.views import MethodView
7
7
  from flask import render_template, request
8
- from services.profile_service import ProfileService
8
+ from iatoolkit.services.profile_service import ProfileService
9
9
  from itsdangerous import URLSafeTimedSerializer, SignatureExpired
10
10
  from flask_bcrypt import Bcrypt
11
11
  from injector import inject
@@ -7,8 +7,8 @@ from flask import request, jsonify, current_app
7
7
  from flask.views import MethodView
8
8
  from injector import inject
9
9
  import logging
10
- from repositories.profile_repo import ProfileRepo
11
- from services.jwt_service import JWTService
10
+ from iatoolkit.repositories.profile_repo import ProfileRepo
11
+ from iatoolkit.services.jwt_service import JWTService
12
12
  from typing import Optional
13
13
 
14
14
 
@@ -4,12 +4,12 @@
4
4
  # IAToolkit is open source software.
5
5
 
6
6
  from flask import render_template, request, jsonify
7
- from services.profile_service import ProfileService
7
+ from iatoolkit.services.profile_service import ProfileService
8
8
  from flask.views import MethodView
9
9
  from injector import inject
10
10
  import os
11
- from common.auth import IAuthentication
12
- from services.prompt_manager_service import PromptService
11
+ from iatoolkit.common.auth import IAuthentication
12
+ from iatoolkit.services.prompt_manager_service import PromptService
13
13
 
14
14
 
15
15
  class ChatView(MethodView):
@@ -10,9 +10,9 @@ from flask import current_app, jsonify, send_from_directory
10
10
  from flask.views import MethodView
11
11
  from injector import inject
12
12
 
13
- from common.auth import IAuthentication
14
- from services.excel_service import ExcelService
15
- from services.profile_service import ProfileService
13
+ from iatoolkit.common.auth import IAuthentication
14
+ from iatoolkit.services.excel_service import ExcelService
15
+ from iatoolkit.services.profile_service import ProfileService
16
16
 
17
17
 
18
18
  class DownloadFileView(MethodView):
@@ -8,11 +8,11 @@ import logging
8
8
  from flask import request, jsonify, render_template
9
9
  from flask.views import MethodView
10
10
  from injector import inject
11
- from common.auth import IAuthentication
12
- from services.profile_service import ProfileService
13
- from services.query_service import QueryService
14
- from services.prompt_manager_service import PromptService
15
- from services.jwt_service import JWTService
11
+ from iatoolkit.common.auth import IAuthentication
12
+ from iatoolkit.services.profile_service import ProfileService
13
+ from iatoolkit.services.query_service import QueryService
14
+ from iatoolkit.services.prompt_manager_service import PromptService
15
+ from iatoolkit.services.jwt_service import JWTService
16
16
 
17
17
  class ExternalChatLoginView(MethodView):
18
18
  @inject
@@ -5,8 +5,8 @@
5
5
 
6
6
  from flask.views import MethodView
7
7
  from injector import inject
8
- from common.auth import IAuthentication
9
- from services.query_service import QueryService
8
+ from iatoolkit.common.auth import IAuthentication
9
+ from iatoolkit.services.query_service import QueryService
10
10
  from flask import jsonify
11
11
  import logging
12
12
 
@@ -5,8 +5,8 @@
5
5
 
6
6
  from flask.views import MethodView
7
7
  from flask import request, jsonify
8
- from services.load_documents_service import LoadDocumentsService
9
- from repositories.profile_repo import ProfileRepo
8
+ from iatoolkit.services.load_documents_service import LoadDocumentsService
9
+ from iatoolkit.repositories.profile_repo import ProfileRepo
10
10
  from injector import inject
11
11
  import base64
12
12
 
@@ -6,7 +6,7 @@
6
6
  from flask.views import MethodView
7
7
  from flask import render_template, request, url_for
8
8
  from injector import inject
9
- from services.profile_service import ProfileService
9
+ from iatoolkit.services.profile_service import ProfileService
10
10
  from itsdangerous import URLSafeTimedSerializer
11
11
  import os
12
12
 
@@ -5,8 +5,8 @@
5
5
 
6
6
  from flask import request, jsonify, render_template
7
7
  from flask.views import MethodView
8
- from services.history_service import HistoryService
9
- from common.auth import IAuthentication
8
+ from iatoolkit.services.history_service import HistoryService
9
+ from iatoolkit.common.auth import IAuthentication
10
10
  from injector import inject
11
11
  import logging
12
12