iatoolkit 0.3.9__py3-none-any.whl → 0.107.4__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/__init__.py +27 -35
- iatoolkit/base_company.py +3 -35
- iatoolkit/cli_commands.py +18 -47
- iatoolkit/common/__init__.py +0 -0
- iatoolkit/common/exceptions.py +48 -0
- iatoolkit/common/interfaces/__init__.py +0 -0
- iatoolkit/common/interfaces/asset_storage.py +34 -0
- iatoolkit/common/interfaces/database_provider.py +39 -0
- iatoolkit/common/model_registry.py +159 -0
- iatoolkit/common/routes.py +138 -0
- iatoolkit/common/session_manager.py +26 -0
- iatoolkit/common/util.py +353 -0
- iatoolkit/company_registry.py +66 -29
- iatoolkit/core.py +514 -0
- iatoolkit/infra/__init__.py +5 -0
- iatoolkit/infra/brevo_mail_app.py +123 -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/google_chat_app.py +57 -0
- iatoolkit/infra/llm_providers/__init__.py +0 -0
- iatoolkit/infra/llm_providers/deepseek_adapter.py +278 -0
- iatoolkit/infra/llm_providers/gemini_adapter.py +350 -0
- iatoolkit/infra/llm_providers/openai_adapter.py +124 -0
- iatoolkit/infra/llm_proxy.py +268 -0
- iatoolkit/infra/llm_response.py +45 -0
- iatoolkit/infra/redis_session_manager.py +122 -0
- iatoolkit/locales/en.yaml +222 -0
- iatoolkit/locales/es.yaml +225 -0
- iatoolkit/repositories/__init__.py +5 -0
- iatoolkit/repositories/database_manager.py +187 -0
- iatoolkit/repositories/document_repo.py +33 -0
- iatoolkit/repositories/filesystem_asset_repository.py +36 -0
- iatoolkit/repositories/llm_query_repo.py +105 -0
- iatoolkit/repositories/models.py +279 -0
- iatoolkit/repositories/profile_repo.py +171 -0
- iatoolkit/repositories/vs_repo.py +150 -0
- iatoolkit/services/__init__.py +5 -0
- iatoolkit/services/auth_service.py +193 -0
- {services → iatoolkit/services}/benchmark_service.py +7 -7
- iatoolkit/services/branding_service.py +153 -0
- iatoolkit/services/company_context_service.py +214 -0
- iatoolkit/services/configuration_service.py +375 -0
- iatoolkit/services/dispatcher_service.py +134 -0
- {services → iatoolkit/services}/document_service.py +20 -8
- iatoolkit/services/embedding_service.py +148 -0
- iatoolkit/services/excel_service.py +156 -0
- {services → iatoolkit/services}/file_processor_service.py +36 -21
- iatoolkit/services/history_manager_service.py +208 -0
- iatoolkit/services/i18n_service.py +104 -0
- iatoolkit/services/jwt_service.py +80 -0
- iatoolkit/services/language_service.py +89 -0
- iatoolkit/services/license_service.py +82 -0
- iatoolkit/services/llm_client_service.py +438 -0
- iatoolkit/services/load_documents_service.py +174 -0
- iatoolkit/services/mail_service.py +213 -0
- {services → iatoolkit/services}/profile_service.py +200 -101
- iatoolkit/services/prompt_service.py +303 -0
- iatoolkit/services/query_service.py +467 -0
- iatoolkit/services/search_service.py +55 -0
- iatoolkit/services/sql_service.py +169 -0
- iatoolkit/services/tool_service.py +246 -0
- iatoolkit/services/user_feedback_service.py +117 -0
- iatoolkit/services/user_session_context_service.py +213 -0
- iatoolkit/static/images/fernando.jpeg +0 -0
- iatoolkit/static/images/iatoolkit_core.png +0 -0
- iatoolkit/static/images/iatoolkit_logo.png +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 +110 -0
- iatoolkit/static/js/chat_logout_button.js +36 -0
- iatoolkit/static/js/chat_main.js +401 -0
- iatoolkit/static/js/chat_model_selector.js +227 -0
- iatoolkit/static/js/chat_onboarding_button.js +103 -0
- iatoolkit/static/js/chat_prompt_manager.js +94 -0
- iatoolkit/static/js/chat_reload_button.js +38 -0
- iatoolkit/static/styles/chat_iatoolkit.css +559 -0
- iatoolkit/static/styles/chat_modal.css +133 -0
- iatoolkit/static/styles/chat_public.css +135 -0
- iatoolkit/static/styles/documents.css +598 -0
- iatoolkit/static/styles/landing_page.css +398 -0
- iatoolkit/static/styles/llm_output.css +148 -0
- iatoolkit/static/styles/onboarding.css +176 -0
- iatoolkit/system_prompts/__init__.py +0 -0
- iatoolkit/system_prompts/query_main.prompt +30 -23
- iatoolkit/system_prompts/sql_rules.prompt +47 -12
- iatoolkit/templates/_company_header.html +45 -0
- iatoolkit/templates/_login_widget.html +42 -0
- iatoolkit/templates/base.html +78 -0
- iatoolkit/templates/change_password.html +66 -0
- iatoolkit/templates/chat.html +337 -0
- iatoolkit/templates/chat_modals.html +185 -0
- iatoolkit/templates/error.html +51 -0
- iatoolkit/templates/forgot_password.html +51 -0
- iatoolkit/templates/onboarding_shell.html +106 -0
- iatoolkit/templates/signup.html +79 -0
- iatoolkit/views/__init__.py +5 -0
- iatoolkit/views/base_login_view.py +96 -0
- iatoolkit/views/change_password_view.py +116 -0
- iatoolkit/views/chat_view.py +76 -0
- iatoolkit/views/embedding_api_view.py +65 -0
- iatoolkit/views/forgot_password_view.py +75 -0
- iatoolkit/views/help_content_api_view.py +54 -0
- iatoolkit/views/history_api_view.py +56 -0
- iatoolkit/views/home_view.py +63 -0
- iatoolkit/views/init_context_api_view.py +74 -0
- iatoolkit/views/llmquery_api_view.py +59 -0
- iatoolkit/views/load_company_configuration_api_view.py +49 -0
- iatoolkit/views/load_document_api_view.py +65 -0
- iatoolkit/views/login_view.py +170 -0
- iatoolkit/views/logout_api_view.py +57 -0
- iatoolkit/views/profile_api_view.py +46 -0
- iatoolkit/views/prompt_api_view.py +37 -0
- iatoolkit/views/root_redirect_view.py +22 -0
- iatoolkit/views/signup_view.py +100 -0
- iatoolkit/views/static_page_view.py +27 -0
- iatoolkit/views/user_feedback_api_view.py +60 -0
- iatoolkit/views/users_api_view.py +33 -0
- iatoolkit/views/verify_user_view.py +60 -0
- iatoolkit-0.107.4.dist-info/METADATA +268 -0
- iatoolkit-0.107.4.dist-info/RECORD +132 -0
- iatoolkit-0.107.4.dist-info/licenses/LICENSE +21 -0
- iatoolkit-0.107.4.dist-info/licenses/LICENSE_COMMUNITY.md +15 -0
- {iatoolkit-0.3.9.dist-info → iatoolkit-0.107.4.dist-info}/top_level.txt +0 -1
- iatoolkit/iatoolkit.py +0 -413
- iatoolkit/system_prompts/arquitectura.prompt +0 -32
- iatoolkit-0.3.9.dist-info/METADATA +0 -252
- iatoolkit-0.3.9.dist-info/RECORD +0 -32
- services/__init__.py +0 -5
- services/api_service.py +0 -75
- services/dispatcher_service.py +0 -351
- services/excel_service.py +0 -98
- services/history_service.py +0 -45
- services/jwt_service.py +0 -91
- services/load_documents_service.py +0 -212
- services/mail_service.py +0 -62
- services/prompt_manager_service.py +0 -172
- services/query_service.py +0 -334
- services/search_service.py +0 -32
- services/sql_service.py +0 -42
- services/tasks_service.py +0 -188
- services/user_feedback_service.py +0 -67
- services/user_session_context_service.py +0 -85
- {iatoolkit-0.3.9.dist-info → iatoolkit-0.107.4.dist-info}/WHEEL +0 -0
|
@@ -1,46 +1,53 @@
|
|
|
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
|
+
## Idioma: el idioma en que debes responder inicialmente es: {{language}}
|
|
5
6
|
|
|
6
7
|
### ** Información del usuario que esta consultando este chat**
|
|
7
|
-
|
|
8
|
+
- Identificador unico de usuario: {{ user_identifier }}
|
|
8
9
|
- Nombre: {{ user_fullname }}
|
|
9
10
|
- Email: {{ user_email }}
|
|
10
11
|
- Tipo de usuario: {% if user_is_local %}Interno{% else %}Externo{% endif %}
|
|
11
|
-
-
|
|
12
|
+
- Rol de usuario: {{ user_rol }}
|
|
12
13
|
|
|
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
14
|
|
|
17
|
-
|
|
15
|
+
## 🔧 Servicios de datos disponibles en {{ company.name }}
|
|
18
16
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
{% endif %}
|
|
17
|
+
A continuación se muestran los *function calls* (tools) que puedes usar para resolver tareas relacionadas con datos.
|
|
18
|
+
Cada servicio incluye su **nombre**, **propósito** y **parámetros esperados**.
|
|
22
19
|
|
|
23
|
-
|
|
20
|
+
### 📌 LISTA DE TOOLS DISPONIBLES
|
|
24
21
|
{% for service in service_list %}
|
|
25
|
-
|
|
22
|
+
#### Tool {{ loop.index }}: `{{ service.name }}`
|
|
23
|
+
- **Descripción:** {{ service.description }}
|
|
24
|
+
- **Parámetros:** {{ service.parameters | tojson }}
|
|
26
25
|
{% endfor %}
|
|
27
26
|
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
### ⚠️ REGLAS IMPORTANTES PARA EL USO DE TOOLS
|
|
30
|
+
|
|
31
|
+
1. **Debes usar un tool cuando la tarea lo requiera.**
|
|
32
|
+
Ejemplos:
|
|
33
|
+
- Consultar bases de datos
|
|
34
|
+
- Obtener información corporativa
|
|
35
|
+
- Ejecutar SQL
|
|
36
|
+
- Cargar documentos
|
|
37
|
+
|
|
38
|
+
2. **NO inventes información** si un tool existe para obtenerla.
|
|
39
|
+
3. Si un usuario solicita datos específicos, **elige el tool cuyo propósito coincida exactamente** con la solicitud.
|
|
40
|
+
4. **Si ningún tool aplica**, responde siguiendo el estilo de un asistente normal.
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
28
44
|
Eres un asistente que responde preguntas sobre empresas y sus clientes.
|
|
29
45
|
|
|
30
46
|
**Reglas obligatorias de contexto:**
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
2. Si el usuario hace una pregunta **sin especificar un cliente** (sin RUT ni nombre),
|
|
34
|
-
siempre debes asumir que la pregunta se refiere al **último cliente identificado** en la conversación.
|
|
35
|
-
3. Nunca cambies de cliente de contexto a menos que el usuario especifique uno nuevo.
|
|
36
|
-
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**.
|
|
37
|
-
5. No respondas con “no se encontró información del cliente” salvo que nunca se haya identificado ningún cliente antes en la conversación.
|
|
38
|
-
6. No debes incluir explicaciones, comentarios o texto adicional.
|
|
47
|
+
En caso que te hagan preguntas especificas sobre un cliente, debes asumir que la pregunta se
|
|
48
|
+
refiere al **último cliente identificado** en la conversación.
|
|
39
49
|
|
|
40
50
|
**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
|
-
|
|
43
|
-
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
51
|
|
|
45
52
|
### **Instrucciones**
|
|
46
53
|
1. Devuelve siempre la respuesta en formato JSON.
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
- Muchas columnas contienen información en formato **jsonb**.
|
|
5
5
|
- Todas las consultas deben ser **sintácticamente correctas** y compatibles con PostgreSQL.
|
|
6
6
|
|
|
7
|
+
## 🔍 Uso correcto de campos JSONB
|
|
7
8
|
## 🔍 Uso correcto de campos JSONB
|
|
8
9
|
|
|
9
10
|
### Regla central: ¡NO ASUMAS QUE LAS CLAVES JSONB SON COLUMNAS!
|
|
@@ -108,32 +109,66 @@ Ejemplo incorrecto: SUM(value->>'monto')::NUMERIC
|
|
|
108
109
|
- Usa `TO_DATE(...)` para convertir el string a fecha:
|
|
109
110
|
```sql
|
|
110
111
|
TO_DATE(jsonb_credit->>'created', 'DD-MM-YYYY')
|
|
111
|
-
|
|
112
|
+
```
|
|
112
113
|
|
|
113
114
|
- antes de comparar con `CURRENT_DATE` un campo de tipo jsonb,
|
|
114
115
|
**siempre** castea explícitamente
|
|
115
116
|
|
|
116
|
-
- No utilices TO_DATE si la columna ya es de tipo DATE o TIMESTAMP.
|
|
117
|
-
Úsala solo si el campo es tipo TEXT o VARCHAR, y asegúrate de castearlo explícitamente si es necesario.
|
|
118
|
-
TO_DATE espera un string, no una fecha ya en formato DATE, y causará un error de tipo de datos.
|
|
119
|
-
|
|
120
117
|
- Si comparas fechas, asegúrate que ambos lados sean del mismo tipo.
|
|
121
118
|
ejemplo:
|
|
122
119
|
```sql
|
|
123
|
-
-- Si '
|
|
124
|
-
TO_CHAR(
|
|
125
|
-
-- Si '
|
|
126
|
-
TO_DATE(jsonb_guarantee->>'
|
|
120
|
+
-- Si 'buyer__date' es DATE:
|
|
121
|
+
TO_CHAR('buyer__date' , 'DD-MM-YYYY')
|
|
122
|
+
-- Si 'created_date' es texto en formato 'DD-MM-YYYY':
|
|
123
|
+
TO_DATE(jsonb_guarantee->>'created_date', 'DD-MM-YYYY')
|
|
127
124
|
- Evitar comparar campos de tipo DATE o TIMESTAMP con strings generados por TO_CHAR.
|
|
128
125
|
Usar funciones como date_trunc() o INTERVAL directamente.
|
|
129
126
|
|
|
127
|
+
🎯 Regla para fechas que pueden venir vacías (solo TEXT / JSONB)
|
|
128
|
+
|
|
129
|
+
- Usa `TO_DATE()` ÚNICAMENTE cuando el valor de fecha sea un string:
|
|
130
|
+
- campos de tipo TEXT o VARCHAR
|
|
131
|
+
- o valores extraídos de JSONB con `->>` (por ejemplo `jsonb_credit->>'created'`).
|
|
132
|
+
|
|
133
|
+
- Si el campo de fecha es TEXTO y puede venir vacío (`''`), utiliza este patrón:
|
|
134
|
+
TO_DATE(NULLIF(campo_texto, ''), 'DD-MM-YYYY')
|
|
135
|
+
|
|
136
|
+
donde `campo_texto` debe ser SIEMPRE:
|
|
137
|
+
- un TEXT/VARCHAR, o
|
|
138
|
+
- una expresión de JSONB como `jsonb_column->>'field'`.
|
|
139
|
+
|
|
140
|
+
- **NUNCA** uses este patrón sobre columnas que ya son de tipo DATE o TIMESTAMP.
|
|
141
|
+
Ejemplos prohibidos:
|
|
142
|
+
- TO_DATE(NULLIF(bc.init_date, ''), 'DD-MM-YYYY')
|
|
143
|
+
- TO_DATE(NULLIF(c.init_date, ''), 'DD-MM-YYYY')
|
|
144
|
+
- TO_DATE(bc.init_date, 'DD-MM-YYYY')
|
|
145
|
+
- TO_DATE(c.init_date, 'DD-MM-YYYY')
|
|
146
|
+
|
|
147
|
+
- Para columnas DATE del esquema BCU (como ejemplo):
|
|
148
|
+
- `bcu_certificate.init_date`
|
|
149
|
+
- `bcu_certificate.end_date`
|
|
150
|
+
- `bcu_tender.adjudication_date`
|
|
151
|
+
- `bcu_tender.closing_date`
|
|
152
|
+
|
|
153
|
+
**Nunca** las envuelvas en `TO_DATE()` ni en `NULLIF(columna, '')`.
|
|
154
|
+
Deben usarse directamente:
|
|
155
|
+
- ORDER BY bc.init_date DESC NULLS LAST
|
|
156
|
+
- ORDER BY t.adjudication_date DESC NULLS LAST
|
|
157
|
+
|
|
130
158
|
- Cuando necesites construir fechas a partir de valores numéricos
|
|
131
159
|
(por ejemplo, año y mes), utiliza TO_DATE() con un string en formato 'YYYY-MM-DD',
|
|
132
160
|
no uses concatenación sobre literales de tipo DATE.
|
|
133
161
|
|
|
134
|
-
-
|
|
135
|
-
|
|
136
|
-
|
|
162
|
+
- No utilices TO_DATE si la columna ya es de tipo DATE o TIMESTAMP.
|
|
163
|
+
Úsala solo si el campo es tipo TEXT o VARCHAR (por ejemplo, campos que vienen de JSONB con `->>`),
|
|
164
|
+
y siempre recuerda que TO_DATE espera un string.
|
|
165
|
+
|
|
166
|
+
- Si el campo de fecha **es texto** y puede venir vacío (`''`), usa:
|
|
167
|
+
TO_DATE(NULLIF(campo_texto, ''), 'DD-MM-YYYY')
|
|
168
|
+
Esto solo aplica cuando `campo_texto` es `TEXT`/`VARCHAR` o viene de `jsonb->>'campo'`.
|
|
169
|
+
**Nunca** uses este patrón sobre columnas que ya son DATE o TIMESTAMP
|
|
170
|
+
(en esos casos simplemente ordena o filtra con la columna tal cual, usando
|
|
171
|
+
`ORDER BY columna_fecha DESC NULLS LAST`).
|
|
137
172
|
|
|
138
173
|
### operaciones sobre campos de tipo JSONB
|
|
139
174
|
- Cuando uses SUM o alguna otra función agregada sobre un valor extraído
|
|
@@ -0,0 +1,45 @@
|
|
|
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, lang=request.args.get('lang', 'en')) }}"
|
|
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
|
+
{# Contenedor derecho: powered-by a la izquierda y selector de idioma a la derecha #}
|
|
17
|
+
<div class="d-flex align-items-center ms-auto">
|
|
18
|
+
<div class="me-3 d-flex align-items-center">
|
|
19
|
+
<span class="powered-by">
|
|
20
|
+
Powered by <a href="http://www.iatoolkit.com" rel="noopener noreferrer" class="iatoolkit-link">IAToolkit</a>
|
|
21
|
+
</span>
|
|
22
|
+
</div>
|
|
23
|
+
|
|
24
|
+
{% set current_lang = request.args.get('lang', 'en') %}
|
|
25
|
+
{% set has_endpoint = request.endpoint is not none %}
|
|
26
|
+
|
|
27
|
+
{% if has_endpoint %}
|
|
28
|
+
{% if request.view_args %}
|
|
29
|
+
{% set href_en = url_for(request.endpoint, lang='en', **request.view_args) %}
|
|
30
|
+
{% set href_es = url_for(request.endpoint, lang='es', **request.view_args) %}
|
|
31
|
+
{% else %}
|
|
32
|
+
{% set href_en = url_for(request.endpoint, lang='en') %}
|
|
33
|
+
{% set href_es = url_for(request.endpoint, lang='es') %}
|
|
34
|
+
{% endif %}
|
|
35
|
+
{% endif %}
|
|
36
|
+
|
|
37
|
+
<div class="language-switcher d-flex align-items-center">
|
|
38
|
+
<a href="{{ href_en }}" class="language-link {{ 'active' if current_lang == 'en' else '' }}">EN</a>
|
|
39
|
+
<span class="mx-1">|</span>
|
|
40
|
+
<a href="{{ href_es }}" class="language-link {{ 'active' if current_lang == 'es' else '' }}">ES</a>
|
|
41
|
+
</div>
|
|
42
|
+
</div>
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
</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, lang=request.args.get('lang', 'en')) }}"
|
|
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, lang=request.args.get('lang', 'en')) }}" 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, lang=request.args.get('lang', 'en')) }}" 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,78 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
{% if google_analytics_id %}
|
|
5
|
+
<!-- Google tag (gtag.js) -->
|
|
6
|
+
<script async src="https://www.googletagmanager.com/gtag/js?id=G-96G1XCM2CC"></script>
|
|
7
|
+
<script>
|
|
8
|
+
window.dataLayer = window.dataLayer || [];
|
|
9
|
+
function gtag(){dataLayer.push(arguments);}
|
|
10
|
+
gtag('js', new Date());
|
|
11
|
+
|
|
12
|
+
gtag('config', '{{ google_analytics_id }}');
|
|
13
|
+
</script>
|
|
14
|
+
{% endif %}
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
<meta charset="UTF-8">
|
|
18
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
19
|
+
<title>{% block title %}Chatbot{% endblock %}</title>
|
|
20
|
+
|
|
21
|
+
<!-- Bootstrap 5 CSS -->
|
|
22
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha3/dist/css/bootstrap.min.css">
|
|
23
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons/font/bootstrap-icons.css" >
|
|
24
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/filepond/dist/filepond.min.css">
|
|
25
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/sweetalert2@11/dist/sweetalert2.min.css">
|
|
26
|
+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/toastr.js/latest/toastr.min.css" />
|
|
27
|
+
<link rel="stylesheet" href="{{ url_for('static', filename='styles/chat_iatoolkit.css', _external=True) }}">
|
|
28
|
+
<link rel="stylesheet" href="{{ url_for('static', filename='styles/onboarding.css', _external=True) }}">
|
|
29
|
+
<link rel="stylesheet" href="{{ url_for('static', filename='styles/chat_modal.css', _external=True) }}">
|
|
30
|
+
<link rel="stylesheet" href="{{ url_for('static', filename='styles/llm_output.css', _external=True) }}">
|
|
31
|
+
|
|
32
|
+
{% block styles %}{% endblock %}
|
|
33
|
+
</head>
|
|
34
|
+
<body>
|
|
35
|
+
<!-- El "Ancla": Envolvemos el contenido en un div con un ID y estilo. -->
|
|
36
|
+
<div id="page-content-wrapper" style="position: relative;">
|
|
37
|
+
{% block content %}{% endblock %}
|
|
38
|
+
</div>
|
|
39
|
+
|
|
40
|
+
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha3/dist/js/bootstrap.bundle.min.js"></script>
|
|
41
|
+
<script src="https://code.jquery.com/jquery-3.6.4.min.js"></script>
|
|
42
|
+
<script src="https://cdn.jsdelivr.net/npm/filepond/dist/filepond.min.js"></script>
|
|
43
|
+
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
|
|
44
|
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/toastr.js/latest/toastr.min.js"></script>
|
|
45
|
+
|
|
46
|
+
<!-- Mostrar alertas SweetAlert2 si existe el mensaje -->
|
|
47
|
+
<script>
|
|
48
|
+
// Configuración global de Toastr
|
|
49
|
+
toastr.options = {
|
|
50
|
+
"closeButton": true,
|
|
51
|
+
"progressBar": true,
|
|
52
|
+
"positionClass": "toast-bottom-right",
|
|
53
|
+
"preventDuplicates": true,
|
|
54
|
+
"timeOut": "7000",
|
|
55
|
+
"extendedTimeOut": "1000",
|
|
56
|
+
"tapToDismiss": false,
|
|
57
|
+
"target": "#page-content-wrapper"
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
{% if flashed_messages %}
|
|
61
|
+
{% for category, message in flashed_messages %}
|
|
62
|
+
var toastClass = 'toast-info'; // default class
|
|
63
|
+
if ('{{ category }}' === 'error') {
|
|
64
|
+
toastClass = 'toast-error';
|
|
65
|
+
} else if ('{{ category }}' === 'success') {
|
|
66
|
+
toastClass = 'toast-success';
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Llama a Toastr usando la opción 'toastClass' para aplicar nuestro estilo
|
|
70
|
+
toastr.info("{{ message }}", null, { "toastClass": "toast " + toastClass });
|
|
71
|
+
|
|
72
|
+
{% endfor %}
|
|
73
|
+
{% endif %}
|
|
74
|
+
</script>
|
|
75
|
+
|
|
76
|
+
{% block scripts %}{% endblock %}
|
|
77
|
+
</body>
|
|
78
|
+
</html>
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
{% extends "base.html" %}
|
|
2
|
+
|
|
3
|
+
{% block title %}{{ t('ui.change_password.title') }} - {{ branding.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 %}
|