iatoolkit 0.4.2__py3-none-any.whl → 0.66.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.
- iatoolkit/__init__.py +13 -35
- iatoolkit/base_company.py +74 -8
- iatoolkit/cli_commands.py +15 -23
- iatoolkit/common/__init__.py +0 -0
- iatoolkit/common/exceptions.py +46 -0
- iatoolkit/common/routes.py +141 -0
- iatoolkit/common/session_manager.py +24 -0
- iatoolkit/common/util.py +348 -0
- iatoolkit/company_registry.py +7 -8
- iatoolkit/iatoolkit.py +169 -96
- iatoolkit/infra/__init__.py +5 -0
- iatoolkit/infra/call_service.py +140 -0
- iatoolkit/infra/connectors/__init__.py +5 -0
- iatoolkit/infra/connectors/file_connector.py +17 -0
- iatoolkit/infra/connectors/file_connector_factory.py +57 -0
- iatoolkit/infra/connectors/google_cloud_storage_connector.py +53 -0
- iatoolkit/infra/connectors/google_drive_connector.py +68 -0
- iatoolkit/infra/connectors/local_file_connector.py +46 -0
- iatoolkit/infra/connectors/s3_connector.py +33 -0
- iatoolkit/infra/gemini_adapter.py +356 -0
- iatoolkit/infra/google_chat_app.py +57 -0
- iatoolkit/infra/llm_client.py +429 -0
- iatoolkit/infra/llm_proxy.py +139 -0
- iatoolkit/infra/llm_response.py +40 -0
- iatoolkit/infra/mail_app.py +145 -0
- iatoolkit/infra/openai_adapter.py +90 -0
- iatoolkit/infra/redis_session_manager.py +122 -0
- iatoolkit/locales/en.yaml +144 -0
- iatoolkit/locales/es.yaml +140 -0
- iatoolkit/repositories/__init__.py +5 -0
- iatoolkit/repositories/database_manager.py +110 -0
- iatoolkit/repositories/document_repo.py +33 -0
- iatoolkit/repositories/llm_query_repo.py +91 -0
- iatoolkit/repositories/models.py +336 -0
- iatoolkit/repositories/profile_repo.py +123 -0
- iatoolkit/repositories/tasks_repo.py +52 -0
- iatoolkit/repositories/vs_repo.py +139 -0
- iatoolkit/services/__init__.py +5 -0
- iatoolkit/services/auth_service.py +193 -0
- {services → iatoolkit/services}/benchmark_service.py +6 -6
- iatoolkit/services/branding_service.py +149 -0
- {services → iatoolkit/services}/dispatcher_service.py +39 -99
- {services → iatoolkit/services}/document_service.py +5 -5
- {services → iatoolkit/services}/excel_service.py +27 -21
- {services → iatoolkit/services}/file_processor_service.py +5 -5
- iatoolkit/services/help_content_service.py +30 -0
- {services → iatoolkit/services}/history_service.py +8 -16
- iatoolkit/services/i18n_service.py +104 -0
- {services → iatoolkit/services}/jwt_service.py +18 -27
- iatoolkit/services/language_service.py +77 -0
- {services → iatoolkit/services}/load_documents_service.py +19 -14
- {services → iatoolkit/services}/mail_service.py +5 -5
- iatoolkit/services/onboarding_service.py +43 -0
- {services → iatoolkit/services}/profile_service.py +155 -89
- {services → iatoolkit/services}/prompt_manager_service.py +26 -11
- {services → iatoolkit/services}/query_service.py +142 -104
- {services → iatoolkit/services}/search_service.py +21 -5
- {services → iatoolkit/services}/sql_service.py +24 -6
- {services → iatoolkit/services}/tasks_service.py +10 -10
- iatoolkit/services/user_feedback_service.py +103 -0
- iatoolkit/services/user_session_context_service.py +143 -0
- iatoolkit/static/images/fernando.jpeg +0 -0
- iatoolkit/static/js/chat_feedback_button.js +80 -0
- iatoolkit/static/js/chat_filepond.js +85 -0
- iatoolkit/static/js/chat_help_content.js +124 -0
- iatoolkit/static/js/chat_history_button.js +112 -0
- iatoolkit/static/js/chat_logout_button.js +36 -0
- iatoolkit/static/js/chat_main.js +364 -0
- iatoolkit/static/js/chat_onboarding_button.js +97 -0
- iatoolkit/static/js/chat_prompt_manager.js +94 -0
- iatoolkit/static/js/chat_reload_button.js +35 -0
- iatoolkit/static/styles/chat_iatoolkit.css +592 -0
- iatoolkit/static/styles/chat_modal.css +169 -0
- iatoolkit/static/styles/chat_public.css +107 -0
- iatoolkit/static/styles/landing_page.css +182 -0
- iatoolkit/static/styles/llm_output.css +115 -0
- iatoolkit/static/styles/onboarding.css +169 -0
- iatoolkit/system_prompts/query_main.prompt +5 -15
- iatoolkit/templates/_company_header.html +20 -0
- iatoolkit/templates/_login_widget.html +42 -0
- iatoolkit/templates/about.html +13 -0
- iatoolkit/templates/base.html +65 -0
- iatoolkit/templates/change_password.html +66 -0
- iatoolkit/templates/chat.html +287 -0
- iatoolkit/templates/chat_modals.html +181 -0
- iatoolkit/templates/error.html +51 -0
- iatoolkit/templates/forgot_password.html +50 -0
- iatoolkit/templates/index.html +145 -0
- iatoolkit/templates/login_simulation.html +34 -0
- iatoolkit/templates/onboarding_shell.html +104 -0
- iatoolkit/templates/signup.html +76 -0
- iatoolkit/views/__init__.py +5 -0
- iatoolkit/views/base_login_view.py +92 -0
- iatoolkit/views/change_password_view.py +117 -0
- iatoolkit/views/external_login_view.py +73 -0
- iatoolkit/views/file_store_api_view.py +65 -0
- iatoolkit/views/forgot_password_view.py +72 -0
- iatoolkit/views/help_content_api_view.py +54 -0
- iatoolkit/views/history_api_view.py +56 -0
- iatoolkit/views/home_view.py +61 -0
- iatoolkit/views/index_view.py +14 -0
- iatoolkit/views/init_context_api_view.py +73 -0
- iatoolkit/views/llmquery_api_view.py +57 -0
- iatoolkit/views/login_simulation_view.py +81 -0
- iatoolkit/views/login_view.py +153 -0
- iatoolkit/views/logout_api_view.py +49 -0
- iatoolkit/views/profile_api_view.py +46 -0
- iatoolkit/views/prompt_api_view.py +37 -0
- iatoolkit/views/signup_view.py +94 -0
- iatoolkit/views/tasks_api_view.py +72 -0
- iatoolkit/views/tasks_review_api_view.py +55 -0
- iatoolkit/views/user_feedback_api_view.py +60 -0
- iatoolkit/views/verify_user_view.py +62 -0
- {iatoolkit-0.4.2.dist-info → iatoolkit-0.66.2.dist-info}/METADATA +2 -2
- iatoolkit-0.66.2.dist-info/RECORD +119 -0
- {iatoolkit-0.4.2.dist-info → iatoolkit-0.66.2.dist-info}/top_level.txt +0 -1
- iatoolkit/system_prompts/arquitectura.prompt +0 -32
- iatoolkit-0.4.2.dist-info/RECORD +0 -32
- services/__init__.py +0 -5
- services/api_service.py +0 -75
- services/user_feedback_service.py +0 -67
- services/user_session_context_service.py +0 -85
- {iatoolkit-0.4.2.dist-info → iatoolkit-0.66.2.dist-info}/WHEEL +0 -0
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
/* static/css/onboarding.css */
|
|
2
|
+
|
|
3
|
+
/* Fuente base para ambos contextos */
|
|
4
|
+
.ob-root {
|
|
5
|
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
/* Tarjeta */
|
|
9
|
+
.ob-card {
|
|
10
|
+
background-color: #fff;
|
|
11
|
+
border-radius: 12px;
|
|
12
|
+
box-shadow: 0 4px 20px rgba(0,0,0,0.1);
|
|
13
|
+
padding: 30px;
|
|
14
|
+
width: 90%;
|
|
15
|
+
max-width: 450px;
|
|
16
|
+
text-align: center;
|
|
17
|
+
transition: opacity 0.3s ease-in-out;
|
|
18
|
+
margin: 0 auto;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/* Contenido de tarjeta */
|
|
22
|
+
.ob-icon {
|
|
23
|
+
font-size: 40px;
|
|
24
|
+
color: var(--brand-primary-color, #FF5100);
|
|
25
|
+
margin-bottom: 15px;
|
|
26
|
+
}
|
|
27
|
+
.ob-title {
|
|
28
|
+
font-size: 1.25rem;
|
|
29
|
+
color: #333;
|
|
30
|
+
margin-bottom: 10px;
|
|
31
|
+
}
|
|
32
|
+
.ob-text {
|
|
33
|
+
font-size: 0.95rem;
|
|
34
|
+
color: #666;
|
|
35
|
+
line-height: 1.5;
|
|
36
|
+
min-height: 60px;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/* Navegación */
|
|
40
|
+
.ob-nav {
|
|
41
|
+
display: flex;
|
|
42
|
+
justify-content: space-between;
|
|
43
|
+
align-items: center;
|
|
44
|
+
margin-top: 20px;
|
|
45
|
+
}
|
|
46
|
+
.ob-btn {
|
|
47
|
+
background-color: var(--brand-secondary-color, #06326B);
|
|
48
|
+
border: none;
|
|
49
|
+
color: var(--brand-text-on-secondary, #FFFFFF);
|
|
50
|
+
border-radius: 50%;
|
|
51
|
+
width: 40px;
|
|
52
|
+
height: 40px;
|
|
53
|
+
cursor: pointer;
|
|
54
|
+
transition: opacity 0.2s;
|
|
55
|
+
display: inline-flex;
|
|
56
|
+
align-items: center;
|
|
57
|
+
justify-content: center;
|
|
58
|
+
}
|
|
59
|
+
.ob-btn:hover { opacity: 0.85; }
|
|
60
|
+
|
|
61
|
+
/* Dots */
|
|
62
|
+
.ob-dots {
|
|
63
|
+
display: flex;
|
|
64
|
+
gap: 8px;
|
|
65
|
+
}
|
|
66
|
+
.ob-dots > div {
|
|
67
|
+
width: 10px;
|
|
68
|
+
height: 10px;
|
|
69
|
+
border-radius: 50%;
|
|
70
|
+
background-color: #ddd;
|
|
71
|
+
transition: background-color 0.3s;
|
|
72
|
+
}
|
|
73
|
+
.ob-dots > div.active {
|
|
74
|
+
background-color: var(--brand-primary-color, #FF5100);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/* Encabezado reutilizable (si se usa) */
|
|
78
|
+
.ob-brand-header {
|
|
79
|
+
font-size: 2rem;
|
|
80
|
+
font-weight: 700;
|
|
81
|
+
margin-bottom: 24px;
|
|
82
|
+
color: var(--brand-secondary-color, #06326B);
|
|
83
|
+
text-align: center;
|
|
84
|
+
}
|
|
85
|
+
.ob-brand-header .brand-name {
|
|
86
|
+
color: var(--brand-primary-color, #FF5100);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/* Utilidades */
|
|
90
|
+
.ob-fade {
|
|
91
|
+
transition: opacity 0.5s ease-in-out;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/* Responsivo */
|
|
95
|
+
@media (max-width: 420px) {
|
|
96
|
+
.ob-card { padding: 24px; }
|
|
97
|
+
.ob-icon { font-size: 34px; }
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/* Overlay a pantalla completa */
|
|
101
|
+
.onboarding-shell-root {
|
|
102
|
+
position: relative;
|
|
103
|
+
height: calc(100vh - 0px);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/* Centrado vertical y horizontal del contenido del loader */
|
|
107
|
+
#loader-wrapper {
|
|
108
|
+
position: absolute; inset: 0;
|
|
109
|
+
background-color: #f4f7f6;
|
|
110
|
+
z-index: 1000;
|
|
111
|
+
display: flex; align-items: center; justify-content: center;
|
|
112
|
+
padding: 20px; box-sizing: border-box;
|
|
113
|
+
transition: opacity 0.5s ease-in-out;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/* Pila vertical: header + tarjeta + banda de carga */
|
|
117
|
+
.ob-stack {
|
|
118
|
+
width: 100%;
|
|
119
|
+
max-width: 520px; /* ligeramente más que la tarjeta para respiración */
|
|
120
|
+
display: flex;
|
|
121
|
+
flex-direction: column;
|
|
122
|
+
align-items: stretch; /* la tarjeta ocupa el ancho */
|
|
123
|
+
gap: 16px;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/* Header de marca consistente */
|
|
127
|
+
.ob-brand-header {
|
|
128
|
+
font-size: 2rem;
|
|
129
|
+
font-weight: 700;
|
|
130
|
+
margin: 0;
|
|
131
|
+
color: var(--brand-secondary-color, #06326B);
|
|
132
|
+
text-align: center;
|
|
133
|
+
}
|
|
134
|
+
.ob-brand-header .brand-name {
|
|
135
|
+
color: var(--brand-primary-color, #FF5100);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/* Banda de estado integrada visualmente con la tarjeta */
|
|
139
|
+
.ob-loading-band {
|
|
140
|
+
display: flex;
|
|
141
|
+
align-items: center;
|
|
142
|
+
justify-content: center;
|
|
143
|
+
gap: 12px;
|
|
144
|
+
padding: 12px 14px;
|
|
145
|
+
background: #ffffff;
|
|
146
|
+
border-radius: 12px;
|
|
147
|
+
box-shadow: 0 4px 20px rgba(0,0,0,0.08);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/* Spinner */
|
|
151
|
+
.spinner {
|
|
152
|
+
width: 28px; height: 28px;
|
|
153
|
+
border: 4px solid rgba(0,0,0,0.1);
|
|
154
|
+
border-top-color: var(--brand-primary-color, #FF5100);
|
|
155
|
+
border-radius: 50%;
|
|
156
|
+
animation: spin 1s linear infinite;
|
|
157
|
+
}
|
|
158
|
+
@keyframes spin { to { transform: rotate(360deg); } }
|
|
159
|
+
|
|
160
|
+
#loading-status p {
|
|
161
|
+
font-size: 0.95rem;
|
|
162
|
+
font-weight: 500;
|
|
163
|
+
color: #555;
|
|
164
|
+
margin: 0;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/* Iframe contenedor */
|
|
168
|
+
#content-container { width: 100%; height: 100%; }
|
|
169
|
+
#content-container iframe { width: 100%; height: 100%; border: none; }
|
|
@@ -1,24 +1,15 @@
|
|
|
1
1
|
Eres un asistente que responde preguntas o ejecuta tareas según el contexto de la empresa.
|
|
2
2
|
|
|
3
3
|
### **Nombre de la empresa**
|
|
4
|
-
## Nombre: {{company
|
|
4
|
+
## Nombre: {{company}}, tambien se conoce como {{ company_short_name }}
|
|
5
5
|
|
|
6
6
|
### ** Información del usuario que esta consultando este chat**
|
|
7
|
-
|
|
7
|
+
- Identificador unico de usuario: {{ user_identifier }}
|
|
8
8
|
- Nombre: {{ user_fullname }}
|
|
9
9
|
- Email: {{ user_email }}
|
|
10
10
|
- Tipo de usuario: {% if user_is_local %}Interno{% else %}Externo{% endif %}
|
|
11
|
-
-
|
|
11
|
+
- Rol de usuario: {{ user_rol }}
|
|
12
12
|
|
|
13
|
-
{% if user_name %}
|
|
14
|
-
El usuario que consulta se identifica con la variable `user_name` y tiene el
|
|
15
|
-
siguiente valor: {{ user_name }}.
|
|
16
|
-
|
|
17
|
-
Este usuario tiene el rol: {{ user_rol }} en el producto {{ user_product }}.
|
|
18
|
-
|
|
19
|
-
{% else %}
|
|
20
|
-
El usuario que consulta se identifica como: {{ user_id }}
|
|
21
|
-
{% endif %}
|
|
22
13
|
|
|
23
14
|
## Servicios de datos (function calls) disponibles en {{company.name}}:
|
|
24
15
|
{% for service in service_list %}
|
|
@@ -28,9 +19,9 @@ El usuario que consulta se identifica como: {{ user_id }}
|
|
|
28
19
|
Eres un asistente que responde preguntas sobre empresas y sus clientes.
|
|
29
20
|
|
|
30
21
|
**Reglas obligatorias de contexto:**
|
|
31
|
-
1. Cada vez que el usuario consulte por un cliente
|
|
22
|
+
1. Cada vez que el usuario consulte por un cliente,
|
|
32
23
|
debes memorizarlo y usarlo como cliente de contexto.
|
|
33
|
-
2. Si el usuario hace una pregunta **sin especificar un cliente
|
|
24
|
+
2. Si el usuario hace una pregunta **sin especificar un cliente**,
|
|
34
25
|
siempre debes asumir que la pregunta se refiere al **último cliente identificado** en la conversación.
|
|
35
26
|
3. Nunca cambies de cliente de contexto a menos que el usuario especifique uno nuevo.
|
|
36
27
|
4. Si el usuario pregunta por un cliente que no está en tus registros, responde indicando que no tienes información, pero **no borres el contexto anterior**.
|
|
@@ -38,7 +29,6 @@ siempre debes asumir que la pregunta se refiere al **último cliente identificad
|
|
|
38
29
|
6. No debes incluir explicaciones, comentarios o texto adicional.
|
|
39
30
|
|
|
40
31
|
**IMPORTANTE:**
|
|
41
|
-
Si el usuario no menciona explícitamente nombre ni RUT en la pregunta, SIEMPRE responde usando el **último cliente** del que se obtuvo información.
|
|
42
32
|
|
|
43
33
|
No respondas nunca sobre un cliente anterior si ya se identificó uno nuevo, y nunca pierdas el contexto salvo que el usuario lo cambie explícitamente.
|
|
44
34
|
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{# El div principal ahora es un contenedor y tiene los estilos y clases de alineación #}
|
|
2
|
+
<div class="custom-company-header container d-flex justify-content-between align-items-center">
|
|
3
|
+
|
|
4
|
+
{% if company_short_name and branding %}
|
|
5
|
+
<a href="{{ url_for('home', company_short_name=company_short_name) }}"
|
|
6
|
+
class="brand-name"
|
|
7
|
+
style="{{ branding.primary_text_style }}">
|
|
8
|
+
{{ branding.name }} IA
|
|
9
|
+
</a>
|
|
10
|
+
{% else %}
|
|
11
|
+
<span class="brand-name">
|
|
12
|
+
IAToolkit
|
|
13
|
+
</span>
|
|
14
|
+
{% endif %}
|
|
15
|
+
|
|
16
|
+
{# Texto "Powered by" con enlace a iatoolkit.com #}
|
|
17
|
+
<span class="powered-by">
|
|
18
|
+
Powered by <a href="{{ url_for('index') }}" rel="noopener noreferrer" class="iatoolkit-link">IAToolkit</a>
|
|
19
|
+
</span>
|
|
20
|
+
</div>
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
<div class="branded-form-container">
|
|
2
|
+
<!-- 1. Encabezado de Marketing -->
|
|
3
|
+
<div class="text-center mb-4">
|
|
4
|
+
<p class="text-muted widget-intro-text">
|
|
5
|
+
{{ t('ui.login_widget.welcome_message') }}
|
|
6
|
+
</p>
|
|
7
|
+
</div>
|
|
8
|
+
|
|
9
|
+
<!-- 2. Formulario de Inicio de Sesión -->
|
|
10
|
+
<form id="login-form"
|
|
11
|
+
action="{{ url_for('login', company_short_name=company_short_name) }}"
|
|
12
|
+
method="post">
|
|
13
|
+
<div class="mb-3">
|
|
14
|
+
<label for="email" class="form-label d-block">{{ t('ui.signup.email_label') }}</label>
|
|
15
|
+
<input type="email" id="email" name="email" class="form-control"
|
|
16
|
+
required value="{{ form_data.email if form_data is defined else '' }}">
|
|
17
|
+
</div>
|
|
18
|
+
<div class="mb-3">
|
|
19
|
+
<label for="password" class="form-label d-block">{{ t('ui.signup.password_label') }}</label>
|
|
20
|
+
<input type="password" id="password" name="password"
|
|
21
|
+
class="form-control" required>
|
|
22
|
+
</div>
|
|
23
|
+
<button type="submit" class="btn btn-branded-primary w-100 fw-bold py-2">
|
|
24
|
+
{{ t('ui.login_widget.login_button') }}
|
|
25
|
+
</button>
|
|
26
|
+
</form>
|
|
27
|
+
|
|
28
|
+
<!-- 3. Nueva Sección de Registro más Atractiva -->
|
|
29
|
+
<div class="mt-4 pt-3 text-center" style="border-top: 1px solid #e0e0e0;">
|
|
30
|
+
<span class="text-muted small">{{ t('ui.login_widget.no_account_prompt') }}</span>
|
|
31
|
+
<a href="{{ url_for('signup', company_short_name=company_short_name) }}" id="signup-link"
|
|
32
|
+
class="fw-bold ms-1 text-decoration-none" style="color: var(--brand-primary-color);">
|
|
33
|
+
{{ t('ui.login_widget.signup_link') }}</a>
|
|
34
|
+
</div>
|
|
35
|
+
|
|
36
|
+
<!-- 4. Enlace de Recuperación de Contraseña (más sutil) -->
|
|
37
|
+
<div class="text-center mt-2">
|
|
38
|
+
<a href="{{ url_for('forgot_password', company_short_name=company_short_name) }}" class="text-decoration-none text-muted" style="font-size: 0.8rem;">
|
|
39
|
+
{{ t('ui.login_widget.forgot_password_link') }}
|
|
40
|
+
</a>
|
|
41
|
+
</div>
|
|
42
|
+
</div>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<!-- templates/about.html -->
|
|
2
|
+
<!DOCTYPE html>
|
|
3
|
+
<html lang="en">
|
|
4
|
+
<head>
|
|
5
|
+
<meta charset="UTF-8">
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
7
|
+
<title>About</title>
|
|
8
|
+
</head>
|
|
9
|
+
<body>
|
|
10
|
+
<h1>AI Toolkit</h1>
|
|
11
|
+
<p>This is a static page in Flask.</p>
|
|
12
|
+
</body>
|
|
13
|
+
</html>
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>{% block title %}Chatbot{% endblock %}</title>
|
|
7
|
+
|
|
8
|
+
<!-- Bootstrap 5 CSS -->
|
|
9
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha3/dist/css/bootstrap.min.css">
|
|
10
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons/font/bootstrap-icons.css" >
|
|
11
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/filepond/dist/filepond.min.css">
|
|
12
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/sweetalert2@11/dist/sweetalert2.min.css">
|
|
13
|
+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/toastr.js/latest/toastr.min.css" />
|
|
14
|
+
<link rel="stylesheet" href="{{ url_for('static', filename='styles/chat_iatoolkit.css', _external=True) }}">
|
|
15
|
+
<link rel="stylesheet" href="{{ url_for('static', filename='styles/onboarding.css', _external=True) }}">
|
|
16
|
+
<link rel="stylesheet" href="{{ url_for('static', filename='styles/chat_modal.css', _external=True) }}">
|
|
17
|
+
<link rel="stylesheet" href="{{ url_for('static', filename='styles/llm_output.css', _external=True) }}">
|
|
18
|
+
|
|
19
|
+
{% block styles %}{% endblock %}
|
|
20
|
+
</head>
|
|
21
|
+
<body>
|
|
22
|
+
<!-- El "Ancla": Envolvemos el contenido en un div con un ID y estilo. -->
|
|
23
|
+
<div id="page-content-wrapper" style="position: relative;">
|
|
24
|
+
{% block content %}{% endblock %}
|
|
25
|
+
</div>
|
|
26
|
+
|
|
27
|
+
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha3/dist/js/bootstrap.bundle.min.js"></script>
|
|
28
|
+
<script src="https://code.jquery.com/jquery-3.6.4.min.js"></script>
|
|
29
|
+
<script src="https://cdn.jsdelivr.net/npm/filepond/dist/filepond.min.js"></script>
|
|
30
|
+
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
|
|
31
|
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/toastr.js/latest/toastr.min.js"></script>
|
|
32
|
+
|
|
33
|
+
<!-- Mostrar alertas SweetAlert2 si existe el mensaje -->
|
|
34
|
+
<script>
|
|
35
|
+
// Configuración global de Toastr
|
|
36
|
+
toastr.options = {
|
|
37
|
+
"closeButton": true,
|
|
38
|
+
"progressBar": true,
|
|
39
|
+
"positionClass": "toast-bottom-right",
|
|
40
|
+
"preventDuplicates": true,
|
|
41
|
+
"timeOut": "7000",
|
|
42
|
+
"extendedTimeOut": "1000",
|
|
43
|
+
"tapToDismiss": false,
|
|
44
|
+
"target": "#page-content-wrapper"
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
{% if flashed_messages %}
|
|
48
|
+
{% for category, message in flashed_messages %}
|
|
49
|
+
var toastClass = 'toast-info'; // default class
|
|
50
|
+
if ('{{ category }}' === 'error') {
|
|
51
|
+
toastClass = 'toast-error';
|
|
52
|
+
} else if ('{{ category }}' === 'success') {
|
|
53
|
+
toastClass = 'toast-success';
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Llama a Toastr usando la opción 'toastClass' para aplicar nuestro estilo
|
|
57
|
+
toastr.info("{{ message }}", null, { "toastClass": "toast " + toastClass });
|
|
58
|
+
|
|
59
|
+
{% endfor %}
|
|
60
|
+
{% endif %}
|
|
61
|
+
</script>
|
|
62
|
+
|
|
63
|
+
{% block scripts %}{% endblock %}
|
|
64
|
+
</body>
|
|
65
|
+
</html>
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
{% extends "base.html" %}
|
|
2
|
+
|
|
3
|
+
{% block title %}{{ t('ui.change_password.title') }} - {{ company.name }}{% endblock %}
|
|
4
|
+
|
|
5
|
+
{% block styles %}
|
|
6
|
+
<style>
|
|
7
|
+
{{ branding.css_variables | safe }}
|
|
8
|
+
</style>
|
|
9
|
+
<link rel="stylesheet" href="{{ url_for('static', filename='styles/chat_public.css') }}">
|
|
10
|
+
{% endblock %}
|
|
11
|
+
|
|
12
|
+
{% block content %}
|
|
13
|
+
<div class="container mt-4">
|
|
14
|
+
|
|
15
|
+
{% include '_company_header.html' %}
|
|
16
|
+
|
|
17
|
+
<!-- Sección contenedora para centrar el contenido -->
|
|
18
|
+
<section class="hero-section">
|
|
19
|
+
<div class="container">
|
|
20
|
+
<div class="row justify-content-center">
|
|
21
|
+
<div class="col-lg-6 col-md-8">
|
|
22
|
+
<div class="branded-form-container">
|
|
23
|
+
<h4 class="branded-form-title">{{ t('ui.change_password.title') }}</h4>
|
|
24
|
+
<p class="text-muted text-center mb-4">
|
|
25
|
+
{{ t('ui.change_password.subtitle', email=email) | safe }}
|
|
26
|
+
</p>
|
|
27
|
+
|
|
28
|
+
<form action="{{ url_for('change_password', company_short_name=company_short_name, token=token) }}" method="post">
|
|
29
|
+
|
|
30
|
+
<div class="mb-3">
|
|
31
|
+
<label for="temp_code" class="form-label text-secondary">{{ t('ui.change_password.temp_code_label') }}</label>
|
|
32
|
+
<input type="text" id="temp_code" name="temp_code" class="form-control"
|
|
33
|
+
required value="{{ form_data.temp_code if form_data else '' }}"
|
|
34
|
+
placeholder="{{ t('ui.change_password.temp_code_placeholder') }}">
|
|
35
|
+
</div>
|
|
36
|
+
|
|
37
|
+
<div class="mb-3">
|
|
38
|
+
<label for="new_password" class="form-label text-secondary">{{ t('ui.change_password.new_password_label') }}</label>
|
|
39
|
+
<input type="password" id="new_password" name="new_password" class="form-control" required>
|
|
40
|
+
<div class="d-flex align-items-start text-muted mt-2" style="font-size: 0.8rem;">
|
|
41
|
+
<i class="bi bi-info-circle me-2" style="font-size: 0.9rem; line-height: 1.4;"></i>
|
|
42
|
+
<span>{{ t('ui.change_password.password_instructions') }}</span>
|
|
43
|
+
</div>
|
|
44
|
+
</div>
|
|
45
|
+
|
|
46
|
+
<div class="mb-3">
|
|
47
|
+
<label for="confirm_password" class="form-label text-secondary">{{ t('ui.change_password.confirm_password_label') }}</label>
|
|
48
|
+
<input type="password" id="confirm_password" name="confirm_password" class="form-control" required>
|
|
49
|
+
</div>
|
|
50
|
+
|
|
51
|
+
<button type="submit" class="btn btn-branded-primary w-100 fw-bold py-2 mt-3">{{ t('ui.change_password.save_button') }}</button>
|
|
52
|
+
</form>
|
|
53
|
+
|
|
54
|
+
<div class="text-center mt-4 pt-3" style="border-top: 1px solid #e0e0e0;">
|
|
55
|
+
<a href="{{ url_for('home', company_short_name=company_short_name) }}" class="text-muted text-decoration-none fw-semibold">
|
|
56
|
+
<i class="bi bi-arrow-left me-1"></i>{{ t('ui.change_password.back_to_home') }}
|
|
57
|
+
</a>
|
|
58
|
+
</div>
|
|
59
|
+
</div>
|
|
60
|
+
</div>
|
|
61
|
+
</div>
|
|
62
|
+
</div>
|
|
63
|
+
</section>
|
|
64
|
+
</div>
|
|
65
|
+
|
|
66
|
+
{% endblock %}
|