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

@@ -22,6 +22,7 @@ def logout(company_short_name: str):
22
22
  # this function register all the views
23
23
  def register_views(injector, app):
24
24
 
25
+ from iatoolkit.views.index_view import IndexView
25
26
  from iatoolkit.views.llmquery_view import LLMQueryView
26
27
  from iatoolkit.views.tasks_view import TaskView
27
28
  from iatoolkit.views.tasks_review_view import TaskReviewView
@@ -38,7 +39,11 @@ def register_views(injector, app):
38
39
  from iatoolkit.views.chat_token_request_view import ChatTokenRequestView
39
40
  from iatoolkit.views.download_file_view import DownloadFileView
40
41
 
41
- app.add_url_rule('/', view_func=HomeView.as_view('home'))
42
+ # landing page
43
+ app.add_url_rule('/<company_short_name>', view_func=IndexView.as_view('index'))
44
+
45
+ # login testing /login_testing
46
+ app.add_url_rule('/login_testing', view_func=HomeView.as_view('home'))
42
47
 
43
48
  # login for external portals
44
49
  app.add_url_rule('/<company_short_name>/initiate_external_chat',
@@ -99,3 +104,9 @@ def register_views(injector, app):
99
104
  except FileNotFoundError:
100
105
  abort(404)
101
106
 
107
+ # Redirección opcional: hacer que la raíz '/' vaya a la landing de sample_company
108
+ @app.route('/')
109
+ def root_redirect():
110
+ return redirect(url_for('index', company_short_name='sample_company'))
111
+
112
+
iatoolkit/iatoolkit.py CHANGED
@@ -153,7 +153,6 @@ class IAToolkit:
153
153
  except PackageNotFoundError:
154
154
  pass
155
155
 
156
- self.app.wsgi_app = ProxyFix(self.app.wsgi_app, x_proto=1)
157
156
 
158
157
  self.app.config.update({
159
158
  'VERSION': self.version,
@@ -171,6 +170,9 @@ class IAToolkit:
171
170
  if parsed_url.scheme == 'https':
172
171
  self.app.config['PREFERRED_URL_SCHEME'] = 'https'
173
172
 
173
+ # 2. ProxyFix para no tener problemas con iframes y rutas
174
+ self.app.wsgi_app = ProxyFix(self.app.wsgi_app, x_proto=1)
175
+
174
176
  # Configuración para tokenizers en desarrollo
175
177
  if is_dev:
176
178
  os.environ["TOKENIZERS_PARALLELISM"] = "false"
@@ -379,6 +381,7 @@ class IAToolkit:
379
381
  'app_name': 'IAToolkit',
380
382
  'user': SessionManager.get('user'),
381
383
  'user_company': SessionManager.get('company_short_name'),
384
+ 'iatoolkit_base_url': os.environ.get('IATOOLKIT_BASE_URL', ''),
382
385
  }
383
386
 
384
387
  def _get_default_static_folder(self) -> str:
@@ -71,6 +71,14 @@ class BrandingService:
71
71
  if company and company.branding:
72
72
  final_branding_values.update(company.branding)
73
73
 
74
+ # Función para convertir HEX a RGB
75
+ def hex_to_rgb(hex_color):
76
+ hex_color = hex_color.lstrip('#')
77
+ return tuple(int(hex_color[i:i + 2], 16) for i in (0, 2, 4))
78
+
79
+ primary_rgb = hex_to_rgb(final_branding_values['brand_primary_color'])
80
+ secondary_rgb = hex_to_rgb(final_branding_values['brand_secondary_color'])
81
+
74
82
  # --- CONSTRUCCIÓN DE ESTILOS Y VARIABLES CSS ---
75
83
  header_style = (
76
84
  f"background-color: {final_branding_values['header_background_color']}; "
@@ -95,6 +103,8 @@ class BrandingService:
95
103
  :root {{
96
104
  --brand-primary-color: {final_branding_values['brand_primary_color']};
97
105
  --brand-secondary-color: {final_branding_values['brand_secondary_color']};
106
+ --brand-primary-color-rgb: {', '.join(map(str, primary_rgb))};
107
+ --brand-secondary-color-rgb: {', '.join(map(str, secondary_rgb))};
98
108
  --brand-text-on-primary: {final_branding_values['brand_text_on_primary']};
99
109
  --brand-text-on-secondary: {final_branding_values['brand_text_on_secondary']};
100
110
  --brand-modal-header-bg: {final_branding_values['header_background_color']};
@@ -12,7 +12,7 @@ $(document).ready(function () {
12
12
  const queryText = $(this).data('query');
13
13
 
14
14
  // Copiar el texto al textarea del chat
15
- if (queryText) { // Buena práctica: Asegurarse de que el dato no es indefinido
15
+ if (queryText) {
16
16
  $('#question').val(queryText);
17
17
  autoResizeTextarea($('#question')[0]);
18
18
  $('#send-button').removeClass('disabled');
@@ -92,7 +92,7 @@ $(document).ready(function () {
92
92
  }
93
93
  });
94
94
 
95
- // Poblar tabla con un método más seguro
95
+ // Poblar la tabla
96
96
  filteredHistory.forEach((item, index) => {
97
97
  const icon = $('<i>').addClass('bi bi-pencil-fill');
98
98
 
@@ -100,23 +100,21 @@ $(document).ready(function () {
100
100
  .attr('href', 'javascript:void(0);')
101
101
  .addClass('copy-query-icon')
102
102
  .attr('title', 'Copiar consulta al chat')
103
- .data('query', item.query) // Usar .data() es más seguro que un atributo de string
103
+ .data('query', item.query)
104
104
  .append(icon);
105
105
 
106
106
  const row = $('<tr>').append(
107
107
  $('<td>').text(index + 1),
108
108
  $('<td>').addClass('date-cell').text(formatDate(item.created_at)),
109
- $('<td>').text(item.query), // Usar .text() para evitar inyección de HTML
109
+ $('<td>').text(item.query),
110
110
  $('<td>').addClass('text-center').append(link)
111
111
  );
112
112
 
113
113
  historyTableBody.append(row);
114
114
  });
115
-
116
- // El event handler ya no se adjunta aquí.
117
115
  }
118
116
 
119
- // Función para formatear fecha (sin cambios)
117
+ // Función para formatear fecha
120
118
  function formatDate(dateString) {
121
119
  const date = new Date(dateString);
122
120
 
@@ -403,7 +403,7 @@ const showSpinner = function () {
403
403
  <div class="spinner-border text-primary" role="status" style="width: 1.5rem; height: 1.5rem; margin-right: 15px;">
404
404
  <span class="${accessibilityClass}">Loading...</span>
405
405
  </div>
406
- <span style="font-weight: bold; font-size: 15px;">Loading...</span>
406
+ <span style="font-weight: bold; font-size: 15px;">Cargando...</span>
407
407
  </div>
408
408
  `);
409
409
  $('#chat-container').append(spinner).scrollTop($('#chat-container')[0].scrollHeight);
@@ -185,6 +185,11 @@
185
185
  box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);
186
186
  }
187
187
 
188
+ /* Aplica el color secundario de la marca al icono de ver archivos */
189
+ #view-files-button i {
190
+ color: var(--brand-secondary-color, #6c757d);
191
+ }
192
+
188
193
  /* Estilo para mensajes sutiles del sistema (ej. abortado) */
189
194
  .system-message {
190
195
  color: var(--brand-secondary-color, #6c757d); /* Usa el color secundario o un gris por defecto */
@@ -0,0 +1,30 @@
1
+ <style>
2
+ {{ branding.css_variables | safe }}
3
+
4
+ /* Clases de botón reutilizables basadas en el branding */
5
+ .btn-branded-primary {
6
+ background-color: var(--brand-primary-color);
7
+ color: var(--brand-text-on-primary);
8
+ border-color: var(--brand-primary-color);
9
+ transition: all 0.2s ease-in-out;
10
+ }
11
+ .btn-branded-primary:hover {
12
+ background-color: #e9ecef;
13
+ color: var(--brand-primary-color);
14
+ border-color: var(--brand-primary-color);
15
+ }
16
+ .btn-branded-secondary {
17
+ background-color: var(--brand-secondary-color);
18
+ color: var(--brand-text-on-secondary);
19
+ border-color: var(--brand-secondary-color);
20
+ transition: all 0.2s ease-in-out;
21
+ }
22
+ .btn-branded-secondary:hover {
23
+ background-color: #e9ecef;
24
+ color: var(--brand-secondary-color);
25
+ border-color: var(--brand-secondary-color);
26
+ }
27
+ .form-title {
28
+ color: var(--brand-primary-color);
29
+ }
30
+ </style>
@@ -0,0 +1,41 @@
1
+ <!-- templates/_login_widget.html -->
2
+ <div class="border rounded p-4 shadow-sm bg-light">
3
+ <!-- 1. Nuevo Encabezado de Marketing -->
4
+ <div class="text-center mb-4">
5
+ <h4 class="form-title fw-bold">Acceso a la Plataforma</h4>
6
+ <!-- Párrafo modificado con nuevo texto y nueva clase CSS -->
7
+ <p class="text-muted widget-intro-text">
8
+ Ingresa a la plataforma o regístrate y prueba una demo interactiva con nuestra empresa de ejemplo.
9
+ </p>
10
+ </div>
11
+
12
+ <!-- 2. Formulario de Inicio de Sesión -->
13
+ <form id="login-form"
14
+ action="{{ url_for('initiate_login', company_short_name=company_short_name) }}"
15
+ method="post">
16
+ <div class="mb-3">
17
+ <label for="email" class="form-label d-block text-muted">Correo Electrónico</label>
18
+ <input type="email" id="email" name="email" class="form-control" required>
19
+ </div>
20
+ <div class="mb-3">
21
+ <label for="password" class="form-label d-block text-muted">Contraseña</label>
22
+ <input type="password" id="password" name="password" class="form-control" required>
23
+ </div>
24
+ <button type="submit" class="btn btn-branded-primary w-100 fw-bold py-2">
25
+ Ingresar
26
+ </button>
27
+ </form>
28
+
29
+ <!-- 3. Nueva Sección de Registro más Atractiva -->
30
+ <div class="mt-4 pt-3 text-center" style="border-top: 1px solid #e0e0e0;">
31
+ <span class="text-muted small">¿Eres nuevo aquí?</span>
32
+ <a href="{{ url_for('signup', company_short_name=company_short_name) }}" id="signup-link" class="fw-bold ms-1 text-decoration-none">Crea una cuenta gratis</a>
33
+ </div>
34
+
35
+ <!-- 4. Enlace de Recuperación de Contraseña (más sutil) -->
36
+ <div class="text-center mt-2">
37
+ <a href="{{ url_for('forgot_password', company_short_name=company_short_name) }}" class="text-decoration-none text-muted" style="font-size: 0.8rem;">
38
+ ¿Olvidaste tu contraseña?
39
+ </a>
40
+ </div>
41
+ </div>
@@ -0,0 +1,9 @@
1
+ <!-- templates/_navbar.html -->
2
+ <nav class="navbar landing-navbar">
3
+ <div class="container-fluid">
4
+ <!-- Convertido en un enlace a la landing page de la compañía actual -->
5
+ <a class="navbar-brand text-decoration-none" href="{{ url_for('index', company_short_name=company_short_name) }}">
6
+ IAToolkit
7
+ </a>
8
+ </div>
9
+ </nav>
@@ -14,10 +14,12 @@
14
14
  <link rel="stylesheet" href="{{ url_for('static', filename='styles/llm_output.css', _external=True) }}">
15
15
  </head>
16
16
  <body class="d-flex flex-column p-3" style="min-height: 100vh;">
17
+
17
18
  <main class="d-flex flex-column flex-grow-1">
18
19
  {% block content %}{% endblock %}
19
20
  </main>
20
21
 
22
+
21
23
  <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha3/dist/js/bootstrap.bundle.min.js"></script>
22
24
  <script src="https://code.jquery.com/jquery-3.6.4.min.js"></script>
23
25
  <script src="https://cdn.jsdelivr.net/npm/filepond/dist/filepond.min.js"></script>
@@ -118,8 +118,9 @@
118
118
  <div id="chat-input-bar" class="chat-input-bar d-flex align-items-center">
119
119
  <!-- Iconos de la izquierda -->
120
120
  <div class="d-flex align-items-center">
121
- <!-- BOTÓN PARA CONTROLAR EL COLLAPSE -->
122
- <a class="p-2" href="#prompt-assistant-collapse" data-bs-toggle="collapse" role="button" aria-expanded="false" aria-controls="prompt-assistant-collapse" title="Usar Asistente de Prompts">
121
+ <!-- varita magica -->
122
+ <a class="p-2" href="#prompt-assistant-collapse" data-bs-toggle="collapse" role="button"
123
+ aria-expanded="false" aria-controls="prompt-assistant-collapse" title="Usar Asistente de Prompts">
123
124
  <i class="bi bi-magic"></i>
124
125
  </a>
125
126
  <a class="p-2" href="javascript:void(0);" id="paperclip-button" title="Adjuntar archivos">
@@ -1,33 +1,48 @@
1
1
  {% extends "base.html" %}
2
2
 
3
- {% block title %}Recuperar Contraseña{% endblock %}
3
+ {% block title %}Recuperar Contraseña - {{ company.name }}{% endblock %}
4
4
 
5
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>
6
+ <!-- 1. Incluimos los estilos de branding reutilizables -->
7
+ {% include '_branding_styles.html' %}
8
+
9
+ <!-- Enlazamos la hoja de estilos de la landing page para reutilizar estilos -->
10
+ <link rel="stylesheet" href="{{ iatoolkit_base_url }}/static/styles/landing_page.css">
11
+
12
+ <!-- 2. Incluimos la barra de navegación reutilizable -->
13
+ {% include '_navbar.html' %}
14
+
15
+ <!-- 3. Sección contenedora para centrar el contenido -->
16
+ <section class="hero-section">
17
+ <div class="container">
18
+ <div class="row justify-content-center">
19
+ <div class="col-lg-6 col-md-8">
20
+ <div class="border rounded p-4 p-md-5 shadow-sm bg-light">
21
+ <h4 class="form-title fw-bold mb-3 text-center">Recuperar Contraseña</h4>
22
+
23
+ <p class="text-muted text-center mb-4">
24
+ Ingresa tu correo electrónico y te enviaremos un enlace para restablecer tu contraseña.
25
+ </p>
18
26
 
19
- <button type="submit" class="btn btn-primary w-100">Enviar Contraseña</button>
27
+ <form action="{{ url_for('forgot_password', company_short_name=company_short_name) }}" method="post">
28
+ <div class="mb-3">
29
+ <label for="email" class="form-label text-secondary">Correo Electrónico</label>
30
+ <input type="email" id="email" name="email"
31
+ class="form-control"
32
+ required value="{{ form_data.email if form_data else '' }}">
33
+ </div>
20
34
 
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>
35
+ <button type="submit" class="btn btn-branded-primary w-100 fw-bold py-2 mt-3">Enviar Enlace</button>
36
+ </form>
26
37
 
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>
38
+ <div class="text-center mt-4 pt-3" style="border-top: 1px solid #e0e0e0;">
39
+ <a href="{{ url_for('index', company_short_name=company_short_name) }}" class="text-muted text-decoration-none fw-semibold">
40
+ <i class="bi bi-arrow-left me-1"></i>Volver al inicio
41
+ </a>
42
+ </div>
43
+ </div>
44
+ </div>
29
45
  </div>
30
- </form>
31
- </div>
32
- </div>
46
+ </div>
47
+ </section>
33
48
  {% endblock %}
@@ -0,0 +1,126 @@
1
+ {% extends "base.html" %}
2
+
3
+ {% block title %}IAToolkit - Acelerador de IA para tu Empresa{% endblock %}
4
+
5
+ {% block content %}
6
+
7
+ <!-- Incluimos los estilos de branding reutilizables -->
8
+ {% include '_branding_styles.html' %}
9
+
10
+ <!-- Enlazamos la hoja de estilos de la landing page -->
11
+ <link rel="stylesheet" href="{{ iatoolkit_base_url }}/static/styles/landing_page.css">
12
+
13
+ <!-- 1. Barra de Navegación (sin cambios) -->
14
+ <nav class="navbar landing-navbar">
15
+ <div class="container-fluid">
16
+ <span class="navbar-brand">IAToolkit</span>
17
+ </div>
18
+ </nav>
19
+
20
+ <!-- 2. Sección Principal (sin cambios) -->
21
+ <section class="hero-section">
22
+ <div class="container">
23
+ <div class="row align-items-center">
24
+ <div class="col-lg-7">
25
+ <div class="value-proposition">
26
+ <h1 class="hero-title">El <span class="hero-accelerator">Acelerador</span> de IA para tu Empresa</h1>
27
+ <p class="hero-subtitle">IAToolkit es la plataforma de código abierto que conecta de forma segura tus
28
+ datos internos —bases de datos, documentos y sistemas— para crear un asistente de IA
29
+ que entiende tu negocio desde el primer día.</p>
30
+ <p class="hero-subtitle">
31
+ Es un producto para ingenieros de software que quieren construir aplicaciones de IA
32
+ a gran velocidad. Proveemos la infraestructura fundamental y extensible construida en Python
33
+ para que tú te puedas enfocar en conectar tus datos y crear la lógica de negocio.</p>
34
+ </div>
35
+ </div>
36
+ <div class="col-lg-5">
37
+ {% include '_login_widget.html' %}
38
+ </div>
39
+ </div>
40
+ </div>
41
+ </section>
42
+
43
+ <!-- 3. Sección de Características con 6 recuadros -->
44
+ <section class="features-section">
45
+ <div class="container">
46
+ <!-- Primera Fila de Características -->
47
+ <div class="row g-4">
48
+ <!-- Feature 1: GitHub / Open Source -->
49
+ <div class="col-lg-4 d-flex align-items-stretch">
50
+ <div class="opensource-box">
51
+ <div>
52
+ <div class="opensource-icon"><i class="bi bi-github"></i></div>
53
+ <div class="opensource-content">
54
+ <h3>100% Open Source</h3>
55
+ <p>Construido en Python, IAToolkit te da control total. Audita el código, adáptalo y contribuye a una comunidad en crecimiento.</p>
56
+ <a href="https://github.com/tu-usuario/iatoolkit" target="_blank" class="btn btn-light"><i class="bi bi-github me-2"></i>Ir a GitHub</a>
57
+ </div>
58
+ </div>
59
+
60
+ </div>
61
+ </div>
62
+
63
+ <!-- Feature 4: Conectividad -->
64
+ <div class="col-lg-4 d-flex align-items-stretch">
65
+ <div class="feature-item">
66
+ <div class="feature-icon"><i class="bi bi-hdd-stack"></i></div>
67
+ <h3>Conecta tus Datos</h3>
68
+ <p>Integra tus bases de datos SQL, documentos (PDFs, TXT) y otros sistemas para que el asistente tenga un contexto real de tu negocio.</p>
69
+ </div>
70
+ </div>
71
+
72
+ <!-- Feature 2: Multi-LLM -->
73
+ <div class="col-lg-4 d-flex align-items-stretch">
74
+ <div class="feature-item">
75
+ <div class="feature-icon"><i class="bi bi-gem"></i></div>
76
+ <h3>Multi-LLM</h3>
77
+ <p>No te ates a un solo proveedor. IAToolkit está diseñado para funcionar con diferentes modelos, incluyendo Gemini y OpenAI (GPT).</p>
78
+ </div>
79
+ </div>
80
+
81
+ </div>
82
+
83
+ <!-- Segunda Fila de Características -->
84
+ <div class="row g-4 mt-4">
85
+ <div class="col-lg-4 d-flex align-items-stretch">
86
+ <div class="feature-item">
87
+ <div class="feature-icon"><i class="bi bi-magic"></i></div>
88
+ <h3>Prompt Manager</h3>
89
+ <p>Crea, gestiona y comparte una librería de prompts personalizados para tu empresa, optimizando las tareas repetitivas.</p>
90
+ </div>
91
+ </div>
92
+ <!-- Feature 6: Personalización -->
93
+ <div class="col-lg-4 d-flex align-items-stretch">
94
+ <div class="feature-item">
95
+ <div class="feature-icon"><i class="bi bi-palette"></i></div>
96
+ <h3>100% Personalizable</h3>
97
+ <p>Desde la apariencia visual hasta las capacidades y herramientas del asistente,
98
+ adapta cada aspecto para que se alinee con la identidad de tu marca.</p>
99
+ </div>
100
+ </div>
101
+
102
+ <!-- Feature 5: Seguridad -->
103
+ <div class="col-lg-4 d-flex align-items-stretch">
104
+ <div class="feature-item">
105
+ <div class="feature-icon"><i class="bi bi-shield-lock"></i></div>
106
+ <h3>Privacidad Primero</h3>
107
+ <p>Despliega IAToolkit en tus propios servidores. Tus datos y consultas nunca son compartidos con terceros, garantizando la máxima confidencialidad.</p>
108
+ </div>
109
+ </div>
110
+
111
+ </div>
112
+ </div>
113
+ </section>
114
+
115
+ <!-- 4. Footer (sin cambios) -->
116
+ <footer class="landing-footer">
117
+ <div class="container">
118
+ &copy; IAToolkit - Proyecto Open Source
119
+ </div>
120
+ </footer>
121
+
122
+ {% endblock %}
123
+
124
+ {% block scripts %}
125
+ <!-- No se necesita JavaScript aquí para la funcionalidad de la página -->
126
+ {% endblock %}
@@ -95,7 +95,7 @@
95
95
  <!-- MEJORADO: Texto de estado ahora junto al spinner -->
96
96
  <div id="loading-status">
97
97
  <div class="spinner"></div>
98
- <p>Inicializando el contexto de Maxxa para la IA...</p>
98
+ <p>Inicializando el contexto de {{ branding.name }} para la IA...</p>
99
99
  </div>
100
100
 
101
101
  </div>
@@ -1,78 +1,74 @@
1
1
  {% extends "base.html" %}
2
2
 
3
- {% block title %}Registro de Usuario{% endblock %}
3
+ {% block title %}Registro de Usuario - {{ company.name }}{% endblock %}
4
4
 
5
5
  {% block content %}
6
+ <!-- 1. Incluimos los estilos de branding reutilizables -->
7
+ {% include '_branding_styles.html' %}
6
8
 
9
+ <!-- Enlazamos la hoja de estilos de la landing page para reutilizar estilos -->
10
+ <link rel="stylesheet" href="{{ iatoolkit_base_url }}/static/styles/landing_page.css">
7
11
 
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>
12
+ <!-- 2. Incluimos la barra de navegación reutilizable -->
13
+ {% include '_navbar.html' %}
21
14
 
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>
15
+ <!-- 3. Sección contenedora para centrar el contenido -->
16
+ <section class="hero-section">
17
+ <div class="container">
18
+ <div class="row justify-content-center">
19
+ <!-- Se ha reducido el ancho de la columna a lg-6 y md-8 -->
20
+ <div class="col-lg-6 col-md-8">
21
+ <div class="border rounded p-4 p-md-5 shadow-sm bg-light">
22
+ <h4 class="form-title fw-bold mb-3 text-center">Crea tu cuenta en {{ company.name }}</h4>
23
+ <form action="{{ url_for('signup', company_short_name=company_short_name) }}" method="post">
24
+ <div class="mb-3">
25
+ <label for="email" class="form-label text-secondary">Correo Electrónico</label>
26
+ <input type="email" autocomplete="off" id="email" name="email"
27
+ class="form-control" required
28
+ value="{{ form_data.email if form_data else '' }}">
29
+ </div>
52
30
 
53
- {% endif %}
31
+ <div class="row">
32
+ <div class="col-md-6 mb-3">
33
+ <label for="first_name" class="form-label text-secondary">Nombre</label>
34
+ <input type="text" id="first_name" name="first_name"
35
+ class="form-control" required
36
+ value="{{ form_data.first_name if form_data else '' }}">
37
+ </div>
38
+ <div class="col-md-6 mb-3">
39
+ <label for="last_name" class="form-label text-secondary">Apellido</label>
40
+ <input type="text" id="last_name" name="last_name"
41
+ class="form-control" required
42
+ value="{{ form_data.last_name if form_data else '' }}">
43
+ </div>
44
+ </div>
54
45
 
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>
46
+ <div class="mb-3">
47
+ <label for="password" class="form-label text-secondary">Contraseña</label>
48
+ <input type="password" id="password" name="password" class="form-control" required>
49
+ <!-- Bloque de ayuda para la contraseña mejorado -->
50
+ <div class="d-flex align-items-start text-muted mt-2" style="font-size: 0.8rem;">
51
+ <i class="bi bi-info-circle me-2" style="font-size: 0.9rem; line-height: 1.4;"></i>
52
+ <span>Debe contener al menos 8 caracteres, mayúscula, minúscula, número y un carácter especial.</span>
53
+ </div>
54
+ </div>
61
55
 
56
+ <div class="mb-3">
57
+ <label for="confirm_password" class="form-label text-secondary">Confirmar Contraseña</label>
58
+ <input type="password" id="confirm_password" name="confirm_password" class="form-control" required>
59
+ </div>
60
+
61
+ <!-- Botón actualizado con la clase de branding -->
62
+ <button type="submit" class="btn btn-branded-primary w-100 fw-bold py-2 mt-3">Registrarse</button>
63
+ </form>
64
+ <!-- Nota de privacidad -->
65
+ <p class="text-muted small mb-0 text-center mt-4">
66
+ 🔒 Valoramos tu privacidad. Tus datos se usarán exclusivamente para el funcionamiento de la plataforma.
67
+ </p>
68
+ </div>
69
+ </div>
62
70
  </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>
71
+ </div>
72
+ </section>
73
+
78
74
  {% endblock %}
@@ -4,16 +4,19 @@
4
4
  # IAToolkit is open source software.
5
5
 
6
6
  from flask.views import MethodView
7
- from flask import render_template, request, url_for
7
+ from flask import render_template, request, url_for, flash, redirect, session
8
8
  from injector import inject
9
9
  from iatoolkit.services.profile_service import ProfileService
10
+ from iatoolkit.services.branding_service import BrandingService
10
11
  from itsdangerous import URLSafeTimedSerializer
11
12
  import os
12
13
 
13
14
  class ForgotPasswordView(MethodView):
14
15
  @inject
15
- def __init__(self, profile_service: ProfileService):
16
+ def __init__(self, profile_service: ProfileService,
17
+ branding_service: BrandingService):
16
18
  self.profile_service = profile_service
19
+ self.branding_service = branding_service # 3. Guardar la instancia
17
20
  self.serializer = URLSafeTimedSerializer(os.getenv("PASS_RESET_KEY"))
18
21
 
19
22
  def get(self, company_short_name: str):
@@ -22,9 +25,11 @@ class ForgotPasswordView(MethodView):
22
25
  if not company:
23
26
  return render_template('error.html', message="Empresa no encontrada"), 404
24
27
 
28
+ branding_data = self.branding_service.get_company_branding(company)
25
29
  return render_template('forgot_password.html',
26
30
  company=company,
27
- company_short_name=company_short_name
31
+ company_short_name=company_short_name,
32
+ branding=branding_data
28
33
  )
29
34
 
30
35
  def post(self, company_short_name: str):
@@ -43,19 +48,20 @@ class ForgotPasswordView(MethodView):
43
48
 
44
49
  response = self.profile_service.forgot_password(email=email, reset_url=reset_url)
45
50
  if "error" in response:
51
+ branding_data = self.branding_service.get_company_branding(company)
46
52
  return render_template(
47
53
  'forgot_password.html',
48
54
  company=company,
49
55
  company_short_name=company_short_name,
50
- form_data={"email": email },
56
+ branding=branding_data,
57
+ form_data={"email": email},
51
58
  alert_message=response["error"]), 400
52
59
 
60
+ # Guardamos el mensaje y el icono en la sesión manualmente
61
+ session['alert_message'] = "Si tu correo está registrado, recibirás un enlace para restablecer tu contraseña."
62
+ session['alert_icon'] = "success"
63
+ return redirect(url_for('index', company_short_name=company_short_name))
53
64
 
54
- return render_template('login.html',
55
- company=company,
56
- company_short_name=company_short_name,
57
- alert_icon='success',
58
- alert_message="Hemos enviado un enlace a tu correo para restablecer la contraseña.")
59
65
  except Exception as e:
60
66
  return render_template("error.html",
61
67
  company=company,
@@ -0,0 +1,43 @@
1
+ # iatoolkit/views/index_view.py
2
+
3
+ from flask import render_template, abort, session
4
+ from flask.views import MethodView
5
+ from injector import inject
6
+ from iatoolkit.services.profile_service import ProfileService
7
+ from iatoolkit.services.branding_service import BrandingService
8
+
9
+
10
+ class IndexView(MethodView):
11
+ """
12
+ Handles the rendering of the company-specific landing page.
13
+ """
14
+
15
+ @inject
16
+ def __init__(self,
17
+ profile_service: ProfileService,
18
+ branding_service: BrandingService):
19
+ self.profile_service = profile_service
20
+ self.branding_service = branding_service
21
+
22
+ def get(self, company_short_name: str):
23
+ # La vista ahora recibe el company_short_name desde la URL
24
+ company = self.profile_service.get_company_by_short_name(company_short_name)
25
+
26
+ if not company:
27
+ abort(404, description=f"La empresa '{company_short_name}' no fue encontrada.")
28
+
29
+ # Obtenemos los datos de branding para la plantilla
30
+ branding_data = self.branding_service.get_company_branding(company)
31
+
32
+ alert_message = session.pop('alert_message', None)
33
+ alert_icon = session.pop('alert_icon', 'error')
34
+
35
+ # 2. Pasamos las variables a la plantilla. Si no hay mensaje, serán None.
36
+ return render_template(
37
+ 'index.html',
38
+ company=company,
39
+ company_short_name=company_short_name,
40
+ branding=branding_data,
41
+ alert_message=alert_message,
42
+ alert_icon=alert_icon
43
+ )
@@ -4,18 +4,20 @@
4
4
  # IAToolkit is open source software.
5
5
 
6
6
  from flask.views import MethodView
7
- from flask import render_template
7
+ from flask import render_template, request, url_for, session, redirect
8
8
  from iatoolkit.services.profile_service import ProfileService
9
+ from iatoolkit.services.branding_service import BrandingService # 1. Importar BrandingService
9
10
  from injector import inject
10
11
  from itsdangerous import URLSafeTimedSerializer
11
- from flask import url_for, request
12
12
  import os
13
13
 
14
14
 
15
15
  class SignupView(MethodView):
16
16
  @inject
17
- def __init__(self, profile_service: ProfileService):
17
+ def __init__(self, profile_service: ProfileService,
18
+ branding_service: BrandingService):
18
19
  self.profile_service = profile_service
20
+ self.branding_service = branding_service # 3. Guardar la instancia
19
21
  self.serializer = URLSafeTimedSerializer(os.getenv("USER_VERIF_KEY"))
20
22
 
21
23
 
@@ -25,12 +27,13 @@ class SignupView(MethodView):
25
27
  if not company:
26
28
  return render_template('error.html', message="Empresa no encontrada"), 404
27
29
 
28
- user_agent = request.user_agent
29
- is_mobile = user_agent.platform in ["android", "iphone", "ipad"] or "mobile" in user_agent.string.lower()
30
+ # Obtener los datos de branding
31
+ branding_data = self.branding_service.get_company_branding(company)
32
+
30
33
  return render_template('signup.html',
31
34
  company=company,
32
35
  company_short_name=company_short_name,
33
- is_mobile=is_mobile)
36
+ branding=branding_data)
34
37
 
35
38
  def post(self, company_short_name: str):
36
39
  # get company info
@@ -59,26 +62,28 @@ class SignupView(MethodView):
59
62
  verification_url=verification_url)
60
63
 
61
64
  if "error" in response:
65
+ branding_data = self.branding_service.get_company_branding(company)
62
66
  return render_template(
63
- 'signup.html',
64
- company=company,
65
- company_short_name=company_short_name,
66
- form_data={
67
- "first_name": first_name,
68
- "last_name": last_name,
69
- "email": email,
70
- "password": password,
71
- "confirm_password": confirm_password
72
- },
73
- alert_message=response["error"]), 400
74
-
75
- # all is OK
76
- return render_template(
77
- 'login.html',
78
- company=company,
79
- company_short_name=company_short_name,
80
- alert_icon='success',
81
- alert_message=response["message"]), 200
67
+ 'signup.html',
68
+ company=company,
69
+ company_short_name=company_short_name,
70
+ branding=branding_data,
71
+ form_data={
72
+ "first_name": first_name,
73
+ "last_name": last_name,
74
+ "email": email,
75
+ "password": password,
76
+ "confirm_password": confirm_password
77
+ },
78
+ alert_message=response["error"]), 400
79
+
80
+ # Guardamos el mensaje de éxito en la sesión
81
+ session['alert_message'] = response["message"]
82
+ session['alert_icon'] = 'success'
83
+
84
+ # Redirigimos al usuario a la página de login
85
+ return redirect(url_for('index', company_short_name=company_short_name))
86
+
82
87
  except Exception as e:
83
88
  return render_template("error.html",
84
89
  company=company,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: iatoolkit
3
- Version: 0.18.0
3
+ Version: 0.19.0
4
4
  Summary: IAToolkit
5
5
  Author: Fernando Libedinsky
6
6
  License-Expression: MIT
@@ -2,11 +2,11 @@ iatoolkit/__init__.py,sha256=4PWjMJjktixtrxF6BY405qyA50Sv967kEP2x-oil6qk,1120
2
2
  iatoolkit/base_company.py,sha256=GacYVVujoxAwUhofRn5eZcR-s1bHtSQXLD-0SRnWSC0,4595
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=AfuumoVKH2wk8Kg2w-m0iPOgKK5ZxePn_xZJ0a5rcrg,17174
5
+ iatoolkit/iatoolkit.py,sha256=7VR04Pl5HsgcrLHfFaxiFJTqF2NZj3eeOgz5EiZIDyY,17321
6
6
  iatoolkit/common/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
7
  iatoolkit/common/auth.py,sha256=83WsyHF7TdjPYfAA-da-waizlWLIqSTx-2z4pI4LAnw,8471
8
8
  iatoolkit/common/exceptions.py,sha256=EXx40n5htp7UiOM6P1xfJ9U6NMcADqm62dlFaKz7ICU,1154
9
- iatoolkit/common/routes.py,sha256=ZCJyeVaGsCPaEWEgj2ZKh3RzuFcyEx_dnrlKdAbcOao,4930
9
+ iatoolkit/common/routes.py,sha256=F7jKOgiXNxbnh1nwhiZ-_wOTJo2HMVwN0JL708J8o6s,5349
10
10
  iatoolkit/common/session_manager.py,sha256=7D_RuJs60w-1zDr3fOGEz9JW7IZlSXuUHgUT87CzaUo,472
11
11
  iatoolkit/common/util.py,sha256=08js3KLJTXICOd5sgwDp2u_kDaZO_0xG4BIuzWZnLo8,15535
12
12
  iatoolkit/infra/__init__.py,sha256=5JqK9sZ6jBuK83zDQokUhxQ0wuJJJ9DXB8pYCLkX7X4,102
@@ -36,7 +36,7 @@ iatoolkit/repositories/tasks_repo.py,sha256=icVO_r2oPagGnnBhwVFzznnvEEU2EAx-2dlW
36
36
  iatoolkit/repositories/vs_repo.py,sha256=UkpmQQiocgM5IwRBmmWhw3HHzHP6zK1nN3J3TcQgjhc,5300
37
37
  iatoolkit/services/__init__.py,sha256=5JqK9sZ6jBuK83zDQokUhxQ0wuJJJ9DXB8pYCLkX7X4,102
38
38
  iatoolkit/services/benchmark_service.py,sha256=CdbFYyS3FHFhNzWQEa9ZNjUlmON10DT1nKNbZQ1EUi8,5880
39
- iatoolkit/services/branding_service.py,sha256=gjGKMkCfW9kQJ3Zwzf4XNhrOinfjSo43uD9iG07QlFg,6981
39
+ iatoolkit/services/branding_service.py,sha256=gXj9Lj6EIFNIHT6wAHia5lr4_2a2sD-ExMbewno5YD8,7505
40
40
  iatoolkit/services/dispatcher_service.py,sha256=ykR1ye6McyCCuaBgwH6r3-PqcLAr4v4ApkPazMSBzbs,14040
41
41
  iatoolkit/services/document_service.py,sha256=nMXrNtbHQuc9pSaten0LvKY0kT8_WngBDmZJUP3jNPw,5936
42
42
  iatoolkit/services/excel_service.py,sha256=CJGhu7cQl9J6y_ZWSJ-M63Xm-RXR9Zs66oOR2NJErZQ,3868
@@ -65,27 +65,31 @@ iatoolkit/static/images/logo_umayor.png,sha256=FHr1wvI8uDn1YRbRcLSRLBOc0mYusHx9U
65
65
  iatoolkit/static/images/upload.png,sha256=zh5FiINURpaWZQF86bF_gALBX4W1c4aLp5wPQO9xGXI,296
66
66
  iatoolkit/static/js/chat_feedback.js,sha256=_izl49hFEUZYREcJoaPukpTs0YjDgJYUu-QfPt5Ll2s,4398
67
67
  iatoolkit/static/js/chat_filepond.js,sha256=mzXafm7a506EpM37KATTK3zvAswO1E0KSUY1vKbwuRc,3163
68
- iatoolkit/static/js/chat_history.js,sha256=79xI8lRdb7Ja4c1qqhv-ZVyJnViZWFPhX6BK3CwLbbI,4736
69
- iatoolkit/static/js/chat_main.js,sha256=mJH3mWn_-4xeBhGdHiQFDDp7l2_OdWhXc7r1v_A22pE,17313
70
- iatoolkit/static/styles/chat_iatoolkit.css,sha256=36987PwwNc_H86zCHZMllLT8SPAo7v2b60jC8p0LFEM,11271
68
+ iatoolkit/static/js/chat_history.js,sha256=1iLTsfC_SfcdhSYIzVvfPGmrVnzb0HMpPQyZXFnUbbY,4478
69
+ iatoolkit/static/js/chat_main.js,sha256=lpTM_E2HBJMdh1d43nT6niecCDrLbACKkPLcQbBIRyU,17314
70
+ iatoolkit/static/styles/chat_iatoolkit.css,sha256=WgzKKyFRuQU8SozX1sWSN7b66SxVoKIHDwpK6V-xL6g,11417
71
71
  iatoolkit/static/styles/chat_info.css,sha256=17DbgoNYE21VYWfb5L9-QLCpD2R1idK4imKRLwXtJLY,1058
72
72
  iatoolkit/static/styles/chat_modal.css,sha256=mdfjrJtmUn3O9rKwIGjJc-oSNmJGnzUY1aAJqEfPh38,4301
73
73
  iatoolkit/static/styles/llm_output.css,sha256=AlxgRSOleeCk2dLAqFWVaQ-jwZiJjcpC5rHuUv3T6VU,2312
74
74
  iatoolkit/system_prompts/format_styles.prompt,sha256=MSMe1qvR3cF_0IbFshn8R0z6Wx6VCHQq1p37rpu5wwk,3576
75
75
  iatoolkit/system_prompts/query_main.prompt,sha256=w_9ybgWgiQH4V_RbAXqsvz0M7oOuiyhxcwf-D0CgfA4,3017
76
76
  iatoolkit/system_prompts/sql_rules.prompt,sha256=y4nURVnb9AyFwt-lrbMNBHHtZlhk6kC9grYoOhRnrJo,59174
77
+ iatoolkit/templates/_branding_styles.html,sha256=LWNEdNzsD9oJeUFkGiE1CumfIcXDcdbvpYJN_JZs698,984
78
+ iatoolkit/templates/_login_widget.html,sha256=nPNbPKSLN8OulXab9m-sCJpKhmkR6N9LEEoZy2QFp_8,1949
79
+ iatoolkit/templates/_navbar.html,sha256=o1PvZE5ueLmVpGUAmsjtu-vS_WPROTlJc2sTXl6AS4Y,360
77
80
  iatoolkit/templates/about.html,sha256=ciC08grUVz5qLzdzDDqDX31xirg5PrJIRYabWpV9oA8,294
78
- iatoolkit/templates/base.html,sha256=TojvSnVvXkTe7Kpt_BBWoXFfZN6dveKD0VqQjUOXdgU,2212
81
+ iatoolkit/templates/base.html,sha256=Bd_dBk_wiAhX0DPQHJAdPtCBBq2xK1J1Z2b9p3Wn0e8,2214
79
82
  iatoolkit/templates/change_password.html,sha256=DFfQSFcZ2YJZNFis2IXfzEKStxTf4i9f4eQ_6GiyNs8,2342
80
- iatoolkit/templates/chat.html,sha256=HpQxZHqlPN6iOuMaWQPOlrqyC7Aib3AYpboRAokLHZk,9491
83
+ iatoolkit/templates/chat.html,sha256=UeVY2K2DIgK5N5MR-8HcAK97reMdSYE-wL2Xrg3JgUA,9485
81
84
  iatoolkit/templates/chat_modals.html,sha256=ngKk0L8qnWteBDLAqCKv8-55LWNH3-HwVyk2of6ylWo,5510
82
85
  iatoolkit/templates/error.html,sha256=BNF-7z8AYL5vF4ZMUFMrOBt8c85kCFrm9qSHn9EiHWg,540
83
- iatoolkit/templates/forgot_password.html,sha256=1lUbKg9CKnQdnySplceY_pibwYne1-mOlM38fqI1kW8,1563
86
+ iatoolkit/templates/forgot_password.html,sha256=NRZqbNHJXSLNArF_KLbzuem-U57v07awS0ikI_DJbfM,2360
84
87
  iatoolkit/templates/header.html,sha256=179agI7rnYwP_rvJNXIiVde5E8Ec5649_XKq6eew2Hk,1263
85
88
  iatoolkit/templates/home.html,sha256=Bq4wSWrd9E2VRFQ4Br_nqbhipYxZTJfRMiD0hjaSNsM,7942
89
+ iatoolkit/templates/index.html,sha256=S0fraGK1zgygbCPRi4BlDgduNcOJZDmwqJVmYuh8hF0,6029
86
90
  iatoolkit/templates/login.html,sha256=r4hy7MsQkfDqi6pBRNkkRiFr3GPSoHCT89R5lQLUWZc,1991
87
- iatoolkit/templates/onboarding_shell.html,sha256=iIYEe0O3RQ5FgjPigGh8SfC3bFYcJjtd2HeoibyDFLM,7463
88
- iatoolkit/templates/signup.html,sha256=J8wOjUhUe_KozyThDTWHjXpSJ1ubR2IDVobThtkSRuo,3819
91
+ iatoolkit/templates/onboarding_shell.html,sha256=at7VXh9vQmDiWu2mJbc6NkzEVlu8I8Xgn6_31JltrW0,7477
92
+ iatoolkit/templates/signup.html,sha256=9ArDvcNQgHFR2dwxy-37AXzGUOeOsT7Nz5u0y6fAB3U,4385
89
93
  iatoolkit/templates/test.html,sha256=rwNtxC83tbCl5COZFXYvmRBxxmgFJtPNuVBd_nq9KWY,133
90
94
  iatoolkit/views/__init__.py,sha256=5JqK9sZ6jBuK83zDQokUhxQ0wuJJJ9DXB8pYCLkX7X4,102
91
95
  iatoolkit/views/change_password_view.py,sha256=rSebwecI1zwBgR2yvAhcfMwWpGDa4QbVAIllgtSOo9k,3940
@@ -93,18 +97,19 @@ iatoolkit/views/chat_token_request_view.py,sha256=wf32_A2Sq8NHYWshCwL10Tovd1znLo
93
97
  iatoolkit/views/download_file_view.py,sha256=1gZ0ipqeCn39sTrJFo1-tlewlcSF7s_YNTvE4qd0HOw,2010
94
98
  iatoolkit/views/external_login_view.py,sha256=VyDrncAbtowZ_gOmk1kXoWhNw78xHGaz4LijIRmtWY8,6562
95
99
  iatoolkit/views/file_store_view.py,sha256=hUm5wX4E5oqJJEPEAObEj-nPiRp5EJIICULSfAWmHCs,1933
96
- iatoolkit/views/forgot_password_view.py,sha256=Rk8Qbe9Fz7Wlgje1rt29I15gFM-a089EBi2at4FT7kA,2715
100
+ iatoolkit/views/forgot_password_view.py,sha256=CjMIW5LblPAyTZ3uqL1_mqRTXCYTT1O8qCyVhztm5HY,3166
97
101
  iatoolkit/views/history_view.py,sha256=fzZrnC-RySa7ngcPe2Hmf9_s3imx6VB6MKROMcNpjoU,2064
98
102
  iatoolkit/views/home_view.py,sha256=TihO2flkelJa9j6a0FKCMVhD-2X7BhemonB7LTne4x8,1248
103
+ iatoolkit/views/index_view.py,sha256=P5aVdEWxsYOZGbzcXd6WFE733qZ7YXIoeqriUMAM6V8,1527
99
104
  iatoolkit/views/llmquery_view.py,sha256=rv2i3oeXlNc3Sv7Qu3DZGf37r-bMSa4N25FzG7_kPAI,2432
100
105
  iatoolkit/views/login_view.py,sha256=tSJiSTT7gKHediAAD2IGdVTUfkTNI1aWMt-d9J-S4lk,5562
101
106
  iatoolkit/views/prompt_view.py,sha256=l8KHlLmkSgSLK43VbhwKED7mCN9YyfeHHh4zvx0pT0E,1257
102
- iatoolkit/views/signup_view.py,sha256=NTx_2w8F6Np88FKEpDvBvJXU-bISKpDMdhhT4XFAVfk,3805
107
+ iatoolkit/views/signup_view.py,sha256=BCjhM2lMiDPwYrlW_eEwPl-ZLupblbFfsonWtq0E4vU,3922
103
108
  iatoolkit/views/tasks_review_view.py,sha256=keLsLCyOTTlcoIapnB_lbuSvLwrPVZVpBiFC_7ChbLg,3388
104
109
  iatoolkit/views/tasks_view.py,sha256=a3anTXrJTTvbQuc6PSpOzidLKQFL4hWa7PI2Cppcz8w,4110
105
110
  iatoolkit/views/user_feedback_view.py,sha256=G37zmP8P4LvZrSymNJ5iFXhLZg1A3BEwRfTpH1Iam5w,2652
106
111
  iatoolkit/views/verify_user_view.py,sha256=a3q4wHJ8mKAEmgbNTOcnX4rMikROjOR3mHvCr30qGGA,2351
107
- iatoolkit-0.18.0.dist-info/METADATA,sha256=LhMtK3T52D0dc1QeV-mRyfnpNhQRHDDAwlvz3zrEXiQ,9301
108
- iatoolkit-0.18.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
109
- iatoolkit-0.18.0.dist-info/top_level.txt,sha256=V_w4QvDx0b1RXiy8zTCrD1Bp7AZkFe3_O0-9fMiwogg,10
110
- iatoolkit-0.18.0.dist-info/RECORD,,
112
+ iatoolkit-0.19.0.dist-info/METADATA,sha256=su7PqytEmn9LgAOYFOmZ9-fbqX8v33jE7KmjZK_9Jqk,9301
113
+ iatoolkit-0.19.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
114
+ iatoolkit-0.19.0.dist-info/top_level.txt,sha256=V_w4QvDx0b1RXiy8zTCrD1Bp7AZkFe3_O0-9fMiwogg,10
115
+ iatoolkit-0.19.0.dist-info/RECORD,,