iatoolkit 0.59.1__py3-none-any.whl → 0.67.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.

Files changed (93) hide show
  1. iatoolkit/__init__.py +2 -0
  2. iatoolkit/base_company.py +2 -19
  3. iatoolkit/common/routes.py +28 -25
  4. iatoolkit/common/session_manager.py +2 -0
  5. iatoolkit/common/util.py +17 -6
  6. iatoolkit/company_registry.py +1 -2
  7. iatoolkit/iatoolkit.py +54 -20
  8. iatoolkit/locales/en.yaml +167 -0
  9. iatoolkit/locales/es.yaml +163 -0
  10. iatoolkit/repositories/database_manager.py +3 -3
  11. iatoolkit/repositories/document_repo.py +1 -1
  12. iatoolkit/repositories/models.py +3 -4
  13. iatoolkit/repositories/profile_repo.py +0 -4
  14. iatoolkit/services/auth_service.py +44 -32
  15. iatoolkit/services/branding_service.py +35 -27
  16. iatoolkit/services/configuration_service.py +140 -0
  17. iatoolkit/services/dispatcher_service.py +20 -18
  18. iatoolkit/services/document_service.py +5 -2
  19. iatoolkit/services/excel_service.py +15 -11
  20. iatoolkit/services/file_processor_service.py +4 -12
  21. iatoolkit/services/history_service.py +8 -7
  22. iatoolkit/services/i18n_service.py +104 -0
  23. iatoolkit/services/jwt_service.py +7 -9
  24. iatoolkit/services/language_service.py +79 -0
  25. iatoolkit/services/load_documents_service.py +4 -4
  26. iatoolkit/services/mail_service.py +9 -4
  27. iatoolkit/services/onboarding_service.py +10 -4
  28. iatoolkit/services/profile_service.py +59 -38
  29. iatoolkit/services/prompt_manager_service.py +20 -16
  30. iatoolkit/services/query_service.py +15 -14
  31. iatoolkit/services/sql_service.py +6 -2
  32. iatoolkit/services/user_feedback_service.py +70 -29
  33. iatoolkit/static/js/chat_feedback_button.js +80 -0
  34. iatoolkit/static/js/chat_help_content.js +124 -0
  35. iatoolkit/static/js/chat_history_button.js +110 -0
  36. iatoolkit/static/js/chat_logout_button.js +36 -0
  37. iatoolkit/static/js/chat_main.js +32 -184
  38. iatoolkit/static/js/{chat_onboarding.js → chat_onboarding_button.js} +0 -1
  39. iatoolkit/static/js/chat_prompt_manager.js +94 -0
  40. iatoolkit/static/js/chat_reload_button.js +35 -0
  41. iatoolkit/static/styles/chat_iatoolkit.css +251 -205
  42. iatoolkit/static/styles/chat_modal.css +63 -95
  43. iatoolkit/static/styles/chat_public.css +107 -0
  44. iatoolkit/static/styles/landing_page.css +121 -167
  45. iatoolkit/templates/_company_header.html +20 -0
  46. iatoolkit/templates/_login_widget.html +10 -10
  47. iatoolkit/templates/base.html +36 -19
  48. iatoolkit/templates/change_password.html +24 -22
  49. iatoolkit/templates/chat.html +121 -93
  50. iatoolkit/templates/chat_modals.html +113 -74
  51. iatoolkit/templates/error.html +44 -8
  52. iatoolkit/templates/forgot_password.html +17 -15
  53. iatoolkit/templates/index.html +66 -81
  54. iatoolkit/templates/login_simulation.html +16 -5
  55. iatoolkit/templates/onboarding_shell.html +1 -2
  56. iatoolkit/templates/signup.html +22 -20
  57. iatoolkit/views/base_login_view.py +12 -1
  58. iatoolkit/views/change_password_view.py +50 -33
  59. iatoolkit/views/external_login_view.py +5 -11
  60. iatoolkit/views/file_store_api_view.py +7 -9
  61. iatoolkit/views/forgot_password_view.py +21 -19
  62. iatoolkit/views/help_content_api_view.py +54 -0
  63. iatoolkit/views/history_api_view.py +16 -12
  64. iatoolkit/views/home_view.py +61 -0
  65. iatoolkit/views/index_view.py +5 -34
  66. iatoolkit/views/init_context_api_view.py +16 -13
  67. iatoolkit/views/llmquery_api_view.py +38 -28
  68. iatoolkit/views/login_simulation_view.py +14 -2
  69. iatoolkit/views/login_view.py +48 -33
  70. iatoolkit/views/logout_api_view.py +49 -0
  71. iatoolkit/views/profile_api_view.py +46 -0
  72. iatoolkit/views/prompt_api_view.py +8 -8
  73. iatoolkit/views/signup_view.py +27 -25
  74. iatoolkit/views/{tasks_view.py → tasks_api_view.py} +10 -36
  75. iatoolkit/views/tasks_review_api_view.py +55 -0
  76. iatoolkit/views/user_feedback_api_view.py +21 -32
  77. iatoolkit/views/verify_user_view.py +33 -26
  78. {iatoolkit-0.59.1.dist-info → iatoolkit-0.67.0.dist-info}/METADATA +40 -22
  79. iatoolkit-0.67.0.dist-info/RECORD +120 -0
  80. iatoolkit-0.67.0.dist-info/licenses/LICENSE +21 -0
  81. iatoolkit/static/js/chat_context_reload.js +0 -54
  82. iatoolkit/static/js/chat_feedback.js +0 -115
  83. iatoolkit/static/js/chat_history.js +0 -127
  84. iatoolkit/static/styles/chat_info.css +0 -53
  85. iatoolkit/templates/_branding_styles.html +0 -53
  86. iatoolkit/templates/_navbar.html +0 -9
  87. iatoolkit/templates/header.html +0 -31
  88. iatoolkit/templates/test.html +0 -9
  89. iatoolkit/views/chat_token_request_view.py +0 -98
  90. iatoolkit/views/tasks_review_view.py +0 -83
  91. iatoolkit-0.59.1.dist-info/RECORD +0 -111
  92. {iatoolkit-0.59.1.dist-info → iatoolkit-0.67.0.dist-info}/WHEEL +0 -0
  93. {iatoolkit-0.59.1.dist-info → iatoolkit-0.67.0.dist-info}/top_level.txt +0 -0
@@ -4,9 +4,10 @@
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, session, redirect
7
+ from flask import render_template, request, url_for, redirect, flash
8
8
  from iatoolkit.services.profile_service import ProfileService
9
- from iatoolkit.services.branding_service import BrandingService # 1. Importar BrandingService
9
+ from iatoolkit.services.branding_service import BrandingService
10
+ from iatoolkit.services.i18n_service import I18nService
10
11
  from injector import inject
11
12
  from itsdangerous import URLSafeTimedSerializer
12
13
  import os
@@ -15,9 +16,12 @@ import os
15
16
  class SignupView(MethodView):
16
17
  @inject
17
18
  def __init__(self, profile_service: ProfileService,
18
- branding_service: BrandingService):
19
+ branding_service: BrandingService,
20
+ i18n_service: I18nService):
19
21
  self.profile_service = profile_service
20
22
  self.branding_service = branding_service # 3. Guardar la instancia
23
+ self.i18n_service = i18n_service
24
+
21
25
  self.serializer = URLSafeTimedSerializer(os.getenv("USER_VERIF_KEY"))
22
26
 
23
27
 
@@ -25,23 +29,24 @@ class SignupView(MethodView):
25
29
  # get company info
26
30
  company = self.profile_service.get_company_by_short_name(company_short_name)
27
31
  if not company:
28
- return render_template('error.html', message="Empresa no encontrada"), 404
32
+ return render_template('error.html',
33
+ message=self.i18n_service.t('errors.templates.company_not_found')), 404
29
34
 
30
- # Obtener los datos de branding
31
35
  branding_data = self.branding_service.get_company_branding(company)
32
-
33
36
  return render_template('signup.html',
34
37
  company=company,
35
38
  company_short_name=company_short_name,
36
39
  branding=branding_data)
37
40
 
38
41
  def post(self, company_short_name: str):
39
- # get company info
40
- company = self.profile_service.get_company_by_short_name(company_short_name)
41
- if not company:
42
- return render_template('error.html', message="Empresa no encontrada"), 404
43
-
44
42
  try:
43
+ company = self.profile_service.get_company_by_short_name(company_short_name)
44
+ if not company:
45
+ return render_template('error.html',
46
+ message=self.i18n_service.t('errors.templates.company_not_found')), 404
47
+
48
+ branding_data = self.branding_service.get_company_branding(company)
49
+
45
50
  first_name = request.form.get('first_name')
46
51
  last_name = request.form.get('last_name')
47
52
  email = request.form.get('email')
@@ -62,7 +67,7 @@ class SignupView(MethodView):
62
67
  verification_url=verification_url)
63
68
 
64
69
  if "error" in response:
65
- branding_data = self.branding_service.get_company_branding(company)
70
+ flash(response["error"], 'error')
66
71
  return render_template(
67
72
  'signup.html',
68
73
  company=company,
@@ -74,19 +79,16 @@ class SignupView(MethodView):
74
79
  "email": email,
75
80
  "password": password,
76
81
  "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'
82
+ }), 400
83
83
 
84
- # Redirigimos al usuario a la página de login
85
- return redirect(url_for('index', company_short_name=company_short_name))
84
+ flash(response["message"], 'success')
85
+ return redirect(url_for('home', company_short_name=company_short_name))
86
86
 
87
87
  except Exception as e:
88
- return render_template("error.html",
89
- company=company,
90
- company_short_name=company_short_name,
91
- message="Ha ocurrido un error inesperado."), 500
92
-
88
+ message = self.i18n_service.t('errors.templates.processing_error', error=str(e))
89
+ return render_template(
90
+ "error.html",
91
+ company_short_name=company_short_name,
92
+ branding=branding_data,
93
+ message=message
94
+ ), 500
@@ -7,54 +7,28 @@ from flask.views import MethodView
7
7
  from flask import request, jsonify
8
8
  from iatoolkit.services.tasks_service import TaskService
9
9
  from iatoolkit.repositories.profile_repo import ProfileRepo
10
+ from iatoolkit.services.auth_service import AuthService
10
11
  from injector import inject
11
12
  from datetime import datetime
12
13
  import logging
13
14
  from typing import Optional
14
15
 
15
16
 
16
- class TaskView(MethodView):
17
+ class TaskApiView(MethodView):
17
18
  @inject
18
- def __init__(self, task_service: TaskService, profile_repo: ProfileRepo):
19
+ def __init__(self,
20
+ auth_service: AuthService,
21
+ task_service: TaskService,
22
+ profile_repo: ProfileRepo):
23
+ self.auth_service = auth_service
19
24
  self.task_service = task_service
20
25
  self.profile_repo = profile_repo
21
26
 
22
- def _authenticate_requesting_company_via_api_key(self) -> tuple[
23
- Optional[int], Optional[str], Optional[tuple[dict, int]]]:
24
- """
25
- Autentica a la compañía usando su API Key.
26
- Retorna (company_id, company_short_name, None) en éxito.
27
- Retorna (None, None, (error_json, status_code)) en fallo.
28
- """
29
- api_key_header = request.headers.get('Authorization')
30
- if not api_key_header or not api_key_header.startswith('Bearer '):
31
- return None, None, ({"error": "API Key faltante o mal formada en el header Authorization"}, 401)
32
-
33
- api_key_value = api_key_header.split('Bearer ')[1]
34
- try:
35
- api_key_entry = self.profile_repo.get_active_api_key_entry(api_key_value)
36
- if not api_key_entry:
37
- return None, None, ({"error": "API Key inválida o inactiva"}, 401)
38
-
39
- # api_key_entry.company ya está cargado por joinedload en get_active_api_key_entry
40
- if not api_key_entry.company: # Sanity check
41
- logging.error(
42
- f"ChatTokenRequest: API Key {api_key_value[:5]}... no tiene compañía asociada a pesar de ser válida.")
43
- return None, None, ({"error": "Error interno del servidor al verificar API Key"}, 500)
44
-
45
- return api_key_entry.company_id, api_key_entry.company.short_name, None
46
-
47
- except Exception as e:
48
- logging.exception(f"ChatTokenRequest: Error interno durante validación de API Key: {e}")
49
- return None, None, ({"error": "Error interno del servidor al validar API Key"}, 500)
50
-
51
-
52
27
  def post(self):
53
28
  try:
54
- # only requests with valid api-key are allowed
55
- auth_company_id, auth_company_short_name, error = self._authenticate_requesting_company_via_api_key()
56
- if error:
57
- return jsonify(error[0]), error[1]
29
+ auth_result = self.auth_service.verify(anonymous=True)
30
+ if not auth_result.get("success"):
31
+ return jsonify(auth_result), auth_result.get("status_code")
58
32
 
59
33
  req_data = request.get_json()
60
34
  files = request.files.getlist('files')
@@ -0,0 +1,55 @@
1
+ # Copyright (c) 2024 Fernando Libedinsky
2
+ # Product: IAToolkit
3
+ #
4
+ # IAToolkit is open source software.
5
+
6
+ from flask.views import MethodView
7
+ from flask import request, jsonify
8
+ from iatoolkit.services.tasks_service import TaskService
9
+ from iatoolkit.repositories.profile_repo import ProfileRepo
10
+ from iatoolkit.services.auth_service import AuthService
11
+ from injector import inject
12
+ import logging
13
+ from typing import Optional
14
+
15
+
16
+ class TaskReviewApiView(MethodView):
17
+ @inject
18
+ def __init__(self,
19
+ auth_service: AuthService,
20
+ task_service: TaskService,
21
+ profile_repo: ProfileRepo):
22
+ self.auth_service = auth_service
23
+ self.task_service = task_service
24
+ self.profile_repo = profile_repo
25
+
26
+ def post(self, task_id: int):
27
+ auth_result = self.auth_service.verify(anonymous=True)
28
+ if not auth_result.get("success"):
29
+ return jsonify(auth_result), auth_result.get("status_code")
30
+
31
+ try:
32
+ req_data = request.get_json()
33
+ required_fields = ['review_user', 'approved']
34
+ for field in required_fields:
35
+ if field not in req_data:
36
+ return jsonify({"error": f"El campo {field} es requerido"}), 400
37
+
38
+ review_user = req_data.get('review_user', '')
39
+ approved = req_data.get('approved', False)
40
+ comment = req_data.get('comment', '')
41
+
42
+ new_task = self.task_service.review_task(
43
+ task_id=task_id,
44
+ review_user=review_user,
45
+ approved=approved,
46
+ comment=comment)
47
+
48
+ return jsonify({
49
+ "task_id": new_task.id,
50
+ "status": new_task.status.name
51
+ }), 200
52
+
53
+ except Exception as e:
54
+ logging.exception("Error al revisar la tarea: %s", str(e))
55
+ return jsonify({"error": str(e)}), 500
@@ -14,48 +14,38 @@ import logging
14
14
  class UserFeedbackApiView(MethodView):
15
15
  @inject
16
16
  def __init__(self,
17
- iauthentication: AuthService,
17
+ auth_service: AuthService,
18
18
  user_feedback_service: UserFeedbackService ):
19
- self.iauthentication = iauthentication
19
+ self.auth_service = auth_service
20
20
  self.user_feedback_service = user_feedback_service
21
21
 
22
22
  def post(self, company_short_name):
23
- # get access credentials
24
- iaut = self.iauthentication.verify()
25
- if not iaut.get("success"):
26
- return jsonify(iaut), 401
23
+ try:
24
+ # get access credentials
25
+ auth_result = self.auth_service.verify()
26
+ if not auth_result.get("success"):
27
+ return jsonify(auth_result), auth_result.get("status_code")
27
28
 
28
- user_identifier = iaut.get('user_identifier')
29
- if not user_identifier:
30
- return jsonify({"error": "Could not identify user from session or payload"}), 400
29
+ user_identifier = auth_result.get('user_identifier')
31
30
 
32
- data = request.get_json()
33
- if not data:
34
- return jsonify({"error_message": "Cuerpo de la solicitud JSON inválido o faltante"}), 402
31
+ data = request.get_json()
32
+ if not data:
33
+ return jsonify({"error_message": "invalid json body"}), 402
35
34
 
36
- message = data.get("message")
37
- if not message:
38
- return jsonify({"error_message": "Falta el mensaje de feedback"}), 400
39
-
40
- space = data.get("space")
41
- if not space:
42
- return jsonify({"error_message": "Falta el espacio de Google Chat"}), 400
43
-
44
- type = data.get("type")
45
- if not type:
46
- return jsonify({"error_message": "Falta el tipo de feedback"}), 400
47
-
48
- rating = data.get("rating")
49
- if not rating:
50
- return jsonify({"error_message": "Falta la calificación"}), 400
35
+ # these validations are performed also in the frontend
36
+ # the are localized in the front
37
+ message = data.get("message")
38
+ if not message:
39
+ return jsonify({"error_message": "missing feedback message"}), 400
40
+
41
+ rating = data.get("rating")
42
+ if not rating:
43
+ return jsonify({"error_message": "missing rating"}), 400
51
44
 
52
- try:
53
45
  response = self.user_feedback_service.new_feedback(
54
46
  company_short_name=company_short_name,
55
47
  message=message,
56
48
  user_identifier=user_identifier,
57
- space=space,
58
- type=type,
59
49
  rating=rating
60
50
  )
61
51
 
@@ -65,7 +55,6 @@ class UserFeedbackApiView(MethodView):
65
55
  return response, 200
66
56
  except Exception as e:
67
57
  logging.exception(
68
- f"Error inesperado al procesar feedback para company {company_short_name}: {e}")
69
-
58
+ f"unexpected error processing feedback for {company_short_name}: {e}")
70
59
  return jsonify({"error_message": str(e)}), 500
71
60
 
@@ -4,52 +4,59 @@
4
4
  # IAToolkit is open source software.
5
5
 
6
6
  from flask.views import MethodView
7
- from flask import render_template, url_for, redirect, session
7
+ from flask import render_template, url_for, redirect, session, flash
8
8
  from iatoolkit.services.profile_service import ProfileService
9
9
  from itsdangerous import URLSafeTimedSerializer, SignatureExpired
10
+ from iatoolkit.services.branding_service import BrandingService
11
+ from iatoolkit.services.i18n_service import I18nService
10
12
  from injector import inject
11
13
  import os
12
14
 
13
15
 
14
16
  class VerifyAccountView(MethodView):
15
17
  @inject
16
- def __init__(self, profile_service: ProfileService):
18
+ def __init__(self,
19
+ profile_service: ProfileService,
20
+ branding_service: BrandingService,
21
+ i18n_service: I18nService):
17
22
  self.profile_service = profile_service
23
+ self.branding_service = branding_service
24
+ self.i18n_service = i18n_service
18
25
  self.serializer = URLSafeTimedSerializer(os.getenv("USER_VERIF_KEY"))
19
26
 
20
27
  def get(self, company_short_name: str, token: str):
21
- # get company info
22
- company = self.profile_service.get_company_by_short_name(company_short_name)
23
- if not company:
24
- return render_template('error.html', message="Empresa no encontrada"), 404
25
-
26
28
  try:
27
- # decode the token from the URL
28
- email = self.serializer.loads(token, salt='email-confirm', max_age=3600*5)
29
- except SignatureExpired:
30
- return render_template('signup.html',
31
- company=company,
32
- company_short_name=company_short_name,
33
- token=token,
34
- alert_message="El enlace de verificación ha expirado. Por favor, solicita uno nuevo."), 400
29
+ # get company info
30
+ company = self.profile_service.get_company_by_short_name(company_short_name)
31
+ if not company:
32
+ return render_template('error.html',
33
+ message=self.i18n_service.t('errors.templates.company_not_found')), 404
34
+
35
+ branding_data = self.branding_service.get_company_branding(company)
36
+ try:
37
+ # decode the token from the URL
38
+ email = self.serializer.loads(token, salt='email-confirm', max_age=3600*5)
39
+ except SignatureExpired:
40
+ flash(self.i18n_service.t('errors.verification.token_expired'), 'error')
41
+ return render_template('signup.html',
42
+ company=company,
43
+ company_short_name=company_short_name,
44
+ branding=branding_data,
45
+ token=token), 400
35
46
 
36
- try:
37
47
  response = self.profile_service.verify_account(email)
38
48
  if "error" in response:
49
+ flash(response["error"], 'error')
39
50
  return render_template(
40
51
  'signup.html',
41
52
  company=company,
42
53
  company_short_name=company_short_name,
43
- token=token,
44
- alert_message=response["error"]), 400
54
+ branding=branding_data,
55
+ token=token), 400
45
56
 
46
- # Guardamos el mensaje y el icono en la sesión manualmente
47
- session['alert_message'] = response['message']
48
- session['alert_icon'] = "success"
49
- return redirect(url_for('index', company_short_name=company_short_name))
57
+ flash(response['message'], 'success')
58
+ return redirect(url_for('home', company_short_name=company_short_name))
50
59
 
51
60
  except Exception as e:
52
- return render_template("error.html",
53
- company=company,
54
- company_short_name=company_short_name,
55
- message="Ha ocurrido un error inesperado."), 500
61
+ flash(self.i18n_service.t('errors.general.unexpected_error', error=str(e)), 'error')
62
+ return redirect(url_for('home', company_short_name=company_short_name))
@@ -1,11 +1,12 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: iatoolkit
3
- Version: 0.59.1
3
+ Version: 0.67.0
4
4
  Summary: IAToolkit
5
5
  Author: Fernando Libedinsky
6
6
  License-Expression: MIT
7
7
  Requires-Python: >=3.12
8
8
  Description-Content-Type: text/markdown
9
+ License-File: LICENSE
9
10
  Requires-Dist: aiohappyeyeballs==2.4.4
10
11
  Requires-Dist: aiohttp==3.11.9
11
12
  Requires-Dist: aiosignal==1.3.1
@@ -206,47 +207,64 @@ Requires-Dist: wrapt==1.17.0
206
207
  Requires-Dist: yarl==1.18.3
207
208
  Requires-Dist: zipp==3.21.0
208
209
  Requires-Dist: zstandard==0.23.0
210
+ Dynamic: license-file
209
211
 
210
212
 
211
213
  <div align="center">
212
- <h1>IAToolkit</h1>
214
+ <h1>
215
+ IAToolkit
216
+ </h1>
217
+
213
218
  <p><strong>The Open-Source Framework for Building AI Chatbots on Your Private Data.</strong></p>
219
+ <h4>
220
+ <a href="https://www.iatoolkit.com" target="_blank" style="text-decoration: none; color: inherit;">
221
+ www.iatoolkit.com
222
+ </a>
223
+ </h4>
214
224
  </div>
215
225
 
216
- IAToolkit is a comprehensive, open-source framework designed for building enterprise-grade
217
- AI chatbots and conversational applications.
226
+ IAToolkit is a comprehensive, Python open-source framework designed for building enterprise-grade
227
+ AI chatbots and conversational applications. It bridges the gap between the power of
228
+ Large Language Models (LLMs) and the valuable,
229
+ private data locked within your organization's databases and documents.
230
+
218
231
  With IAToolkit, you can build production-ready, context-aware chatbots and agents that
219
232
  can query relational databases, perform semantic searches on documents,
220
233
  and connect to your internal APIs in minutes.
221
234
 
222
- IAToolkit bridges the gap between powerful LLMs and your company's data.
235
+ Create secure, branded chat interfaces that can reason over your data, answer questions, and execute custom business logic,
236
+ all powered by leading models from OpenAI, Google Gemini, and more.
223
237
 
224
238
 
225
239
  ## 🚀 Key Features
226
240
 
227
- * **🔗 Unified Data Connection**:
228
- * **Natural Language to SQL**: Let your chatbot query relational databases (PostgreSQL, MySQL, SQLite) using everyday language.
229
- * **Semantic Document Search**: Automatically chunk, embed, and search across your private documents (PDFs, Word, etc.) to provide contextually accurate answers.
241
+ * **🔗 Unified Data Connection**
242
+ * **Natural Language to SQL**: Let your chatbot query relational databases (PostgreSQL, MySQL, SQLite) using everyday language.
243
+ * **Semantic Document Search**: Automatically chunk, embed, and search across your private documents (PDFs, Word, etc.) to provide contextually accurate answers.
230
244
 
231
- * **🏢 Enterprise-Ready Multi-Tenancy**:
232
- * Deploy isolated "Company" modules, each with its own data, tools, and context. Perfect for SaaS products or internal departmental agents.
245
+ * **🏢 Enterprise-Ready Multi-Tenancy**
246
+ * Deploy isolated "Company" modules, each with its own data, tools, and context.
247
+ * Perfect for SaaS products or internal departmental agents.
233
248
 
234
- * **🧠 LLM Agnostic**:
235
- * Switch between **OpenAI (GPT-*)** and **Google (Gemini-*)** with a single line change in your configuration. No code refactoring needed.
249
+ * **🎨 Fully Brandable UI**
250
+ * Customize the look and feel for each "Company" with its own logos, colors, and even language settings (i18n).
251
+ * Provides a white-labeled experience for your users.
236
252
 
237
- * **🛠️ Developer-First Experience**:
238
- * Built with a clean, **Dependency Injection** architecture.
239
- * High-quality code base with **90%+ test coverage**.
240
- * Powerful Flask-based **CLI** for database setup, API key generation, and more.
253
+ * **🧠 LLM Agnostic**
254
+ * Switch between **OpenAI (GPT-*)** and **Google (Gemini-*)** with a single line change in your configuration.
255
+ * No code refactoring needed.
241
256
 
242
- * **🔒 Security & Observability Built-In**:
243
- * Comes with JWT-based authentication, user management, and secure session handling out of the box.
244
- * Full traceability with detailed logging of all queries, function calls, token usage, and costs.
257
+ * **🛠️ Developer-First Experience**
258
+ * Built with a clean **Dependency Injection** architecture.
259
+ * High-quality code base with **90%+ test coverage**.
245
260
 
246
- ## Quick Start: Create a Custom Tool in 30 Seconds
261
+ * **🔒 Security & Observability Built-In**
262
+ * Comes with integrated user authentication, API keys, and secure session handling out of the box.
263
+ * Full traceability with detailed logging of all queries, function calls, token usage, and costs.
264
+ ## ⚡ Quick Start: Try our 'hello world' example
247
265
 
248
- See how easy it is to give your AI a new skill. Just define a method inside your Company class and describe it.
249
- IAToolkit handles the rest.
266
+ Ready to see it in action? Our Quickstart Guide will walk you through downloading, configuring, and launching your first AI assistant in just a few minutes.
267
+ It's the best way to experience the toolkit's capabilities firsthand.
250
268
 
251
269
  ## 🤝 Contributing
252
270
 
@@ -0,0 +1,120 @@
1
+ iatoolkit/__init__.py,sha256=P2gSaiW8Bh3bgWbTOe09XIv6WCjS5z8AxLL7IlB9qaw,1222
2
+ iatoolkit/base_company.py,sha256=f545DR8pJpkHMhkeqJzSof_81jru65P7xmBewVLvzu4,3924
3
+ iatoolkit/cli_commands.py,sha256=G5L9xQXZ0lVFXQWBaE_KEZHyfuiT6PL1nTQRoSdnBzc,2302
4
+ iatoolkit/company_registry.py,sha256=NAsrCJyvgkdG8yGfqA7EdPUTHDzzcPzKu0PKXniub50,2490
5
+ iatoolkit/iatoolkit.py,sha256=GrYmS3eL8OAxXxBacwh9V1MWcQTACo3pA8uYr09D8tQ,19430
6
+ iatoolkit/common/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
+ iatoolkit/common/exceptions.py,sha256=EXx40n5htp7UiOM6P1xfJ9U6NMcADqm62dlFaKz7ICU,1154
8
+ iatoolkit/common/routes.py,sha256=sYkW9mLIh8IUh8v_CyLxwR9wELiPJdZqjt07DVyozeU,6261
9
+ iatoolkit/common/session_manager.py,sha256=OUYMzT8hN1U-NCUidR5tUAXB1drd8nYTOpo60rUNYeY,532
10
+ iatoolkit/common/util.py,sha256=lwMhQ2gT1DPzJ3mmL9xw3uobWJFIapAw50ks6mCvV60,15028
11
+ iatoolkit/infra/__init__.py,sha256=5JqK9sZ6jBuK83zDQokUhxQ0wuJJJ9DXB8pYCLkX7X4,102
12
+ iatoolkit/infra/call_service.py,sha256=iRk9VxbXaAwlLIl8fUzGDWIAdzwfsbs1MtP84YeENxg,4929
13
+ iatoolkit/infra/gemini_adapter.py,sha256=kXV-t5i9GmWBafUPX2kAyiqvcT7GPoxHylcCUWG_c_U,15051
14
+ iatoolkit/infra/google_chat_app.py,sha256=_uKWxeacHH6C5a4FVx0YZjBn1tL-x_MIQV9gqgWGAjo,1937
15
+ iatoolkit/infra/llm_client.py,sha256=clTYqV_0a2VD2vVH3j6AWqd1gVUmeg-fU3_myizmjQc,18543
16
+ iatoolkit/infra/llm_proxy.py,sha256=cHyNxUpVE4UDoWUfvSGfGCrIUFPTrpWZOixELQTsGFY,5744
17
+ iatoolkit/infra/llm_response.py,sha256=YUUQPBHzmP3Ce6-t0kKMRIpowvh7de1odSoefEByIvI,904
18
+ iatoolkit/infra/mail_app.py,sha256=PLGZdEs7LQ_9bmMRRxz0iqQdNa4xToAFyf9tg75wK8U,6103
19
+ iatoolkit/infra/openai_adapter.py,sha256=tbzd8aPAH5cQOJT-sD4ypqq2fWB6WiEIGuGesUDnQNk,3550
20
+ iatoolkit/infra/redis_session_manager.py,sha256=EPr3E_g7LHxn6U4SV5lT_L8WQsAwg8VzA_WIEZ3TwOw,3667
21
+ iatoolkit/infra/connectors/__init__.py,sha256=5JqK9sZ6jBuK83zDQokUhxQ0wuJJJ9DXB8pYCLkX7X4,102
22
+ iatoolkit/infra/connectors/file_connector.py,sha256=HOjRTFd-WfDOcFyvHncAhnGNZuFgChIwC-P6osPo9ZM,352
23
+ iatoolkit/infra/connectors/file_connector_factory.py,sha256=3qvyfH4ZHKuiMxJFkawOxhW2-TGKKtsBYHgoPpZMuKU,2118
24
+ iatoolkit/infra/connectors/google_cloud_storage_connector.py,sha256=IXpL3HTo7Ft4EQsYiQq5wXRRQK854jzOEB7ZdWjLa4U,2050
25
+ iatoolkit/infra/connectors/google_drive_connector.py,sha256=WR1AlO5-Bl3W89opdja0kKgHTJzVOjTsy3H4SlIvwVg,2537
26
+ iatoolkit/infra/connectors/local_file_connector.py,sha256=hrzIgpMJOTuwTqzlQeTIU_50ZbZ6yl8lcWPv6hMnoqI,1739
27
+ iatoolkit/infra/connectors/s3_connector.py,sha256=Nj4_YaLobjfcnbZewJf21_K2EXohgcc3mJll1Pzn4zg,1123
28
+ iatoolkit/locales/en.yaml,sha256=goGwTZsQo5-PnGTdAZCTduAPaFwggkLsu0WWvtWj9bw,7662
29
+ iatoolkit/locales/es.yaml,sha256=ZIOCUSaRmtJImdZw9zpzbY9SmNzLu88SZEmCRIWYur4,8678
30
+ iatoolkit/repositories/__init__.py,sha256=5JqK9sZ6jBuK83zDQokUhxQ0wuJJJ9DXB8pYCLkX7X4,102
31
+ iatoolkit/repositories/database_manager.py,sha256=5L8hZm58_PYuXxecF2XSdiJR2n1gC34V8wTt0LNsHAg,3695
32
+ iatoolkit/repositories/document_repo.py,sha256=vhFc0hu9GK6yoKJHs2dLaAoQ9ZJaf9GEOsD2yWuVuNw,1130
33
+ iatoolkit/repositories/llm_query_repo.py,sha256=YT_t7cYGQk8rwzH_17-28aTzO-e2jUfa2rvXy8tugvA,3612
34
+ iatoolkit/repositories/models.py,sha256=NlI3Glz2bXppCCvblqd6D8NJp39KkWIl4x3IWyzty5w,14322
35
+ iatoolkit/repositories/profile_repo.py,sha256=zM68DvI3J3aSFt8yMuOpqy3v9_xJ2j86cmspD87gLK8,4139
36
+ iatoolkit/repositories/tasks_repo.py,sha256=icVO_r2oPagGnnBhwVFzznnvEEU2EAx-2dlWuWvoDC4,1745
37
+ iatoolkit/repositories/vs_repo.py,sha256=UkpmQQiocgM5IwRBmmWhw3HHzHP6zK1nN3J3TcQgjhc,5300
38
+ iatoolkit/services/__init__.py,sha256=5JqK9sZ6jBuK83zDQokUhxQ0wuJJJ9DXB8pYCLkX7X4,102
39
+ iatoolkit/services/auth_service.py,sha256=ErP0CC2MpGJthIOMuYBbRdFsQQKpEQQ0Uu9_wT90yJI,7744
40
+ iatoolkit/services/benchmark_service.py,sha256=CdbFYyS3FHFhNzWQEa9ZNjUlmON10DT1nKNbZQ1EUi8,5880
41
+ iatoolkit/services/branding_service.py,sha256=Rko_iSbtARUoo_y1jjgBaG3O1wNPcFaEIT31zYjpUGc,8035
42
+ iatoolkit/services/configuration_service.py,sha256=Gga9UhoCwSB5WhVnyQFUj1wUqVsAp03EMiIcxiJhM44,6103
43
+ iatoolkit/services/dispatcher_service.py,sha256=V__pRmT0vBqGt-KHM-fr1iMPhbKaC5mfCNwZv0a4Qs8,13029
44
+ iatoolkit/services/document_service.py,sha256=whW3B9g7lCaNOqezYmoHkSAov0K7EH90u-KVANO0mPg,6057
45
+ iatoolkit/services/excel_service.py,sha256=MGVFjSo1NOL8PL7_hVgEEFzvXfA4NmF-JFEr8FBSjOA,4090
46
+ iatoolkit/services/file_processor_service.py,sha256=h8Tg2Xwvjv_HOIUo51Rnu5H4tUmkJ8W9tKvmFfgKPms,3792
47
+ iatoolkit/services/history_service.py,sha256=a7FbBWsfe7_5dstCCsPqkg8nYWrMzXBVcFbO_FXVhNc,1376
48
+ iatoolkit/services/i18n_service.py,sha256=mR4pS0z56NgZLeSnEvDXiMvVBeOCl5CkUWdYBTVEhyM,3941
49
+ iatoolkit/services/jwt_service.py,sha256=EXpc1cZAak2nQ3cXIopm5nFTqevzINToWRYk22gJNjo,2933
50
+ iatoolkit/services/language_service.py,sha256=kFBO12EPhQPcFqPOiAciAxeGIFkfRah3JKljb9HxKIw,3134
51
+ iatoolkit/services/load_documents_service.py,sha256=fbgDhKjX7LnKzrVJJVfrlL3vrzbUD07LqOLhPJNNr-w,7275
52
+ iatoolkit/services/mail_service.py,sha256=R_5zOSXMGOdn3pSCyUFCOUmQumXoiKEgmg78H_rxcP8,2366
53
+ iatoolkit/services/onboarding_service.py,sha256=ljvN_Myz1Ey-vF2_VREVe7fhEBkEXEps5PVbFkf5SI0,2273
54
+ iatoolkit/services/profile_service.py,sha256=blRTmQ7QCIlXWPyhwSNJxMitsagrWHxW6e6QrkO031Y,21887
55
+ iatoolkit/services/prompt_manager_service.py,sha256=o0SBO3k_VHaPxPcaM5oeq7Y2rOlFr7FCp_cIcpcU8qY,8415
56
+ iatoolkit/services/query_service.py,sha256=-UxbH8bNth2Cy4vbRoAtC1U_pN69rLtd4QxUhNBxYgA,17458
57
+ iatoolkit/services/search_service.py,sha256=i1xGWu7ORKIIDH0aAQBkF86dVVbLQ0Yrooz5TiZ6aGo,1823
58
+ iatoolkit/services/sql_service.py,sha256=NPXQR3M-JUnJb2g6QIUmI2QDPpevxuKLC8UQJIbyVS4,2318
59
+ iatoolkit/services/tasks_service.py,sha256=itREO5rDnUIgsqtyCOBKDtH30QL5v1egs4qPTiBK8xU,6865
60
+ iatoolkit/services/user_feedback_service.py,sha256=4hftNzE69kiaJYjhxgPmiDAVu3399DiIgCbzg6DQ7Rc,4966
61
+ iatoolkit/services/user_session_context_service.py,sha256=vYF_vWM37tPB_ZyPBJ6f6WTJVjT2j-4L8JfZbqbI93k,6775
62
+ iatoolkit/static/images/fernando.jpeg,sha256=W68TYMuo5hZVpbP-evwH6Nu4xWFv2bc8pJzSKDoLTeQ,100612
63
+ iatoolkit/static/js/chat_feedback_button.js,sha256=Wzb2l3jmpZNwY2KYQQDuBmFKS4oU9WteB9s4U-bEqb4,2429
64
+ iatoolkit/static/js/chat_filepond.js,sha256=mzXafm7a506EpM37KATTK3zvAswO1E0KSUY1vKbwuRc,3163
65
+ iatoolkit/static/js/chat_help_content.js,sha256=N9APsdNoPWWyC1aMLjfq-xFfFYZ5g8ZefUGTkYt75DY,5211
66
+ iatoolkit/static/js/chat_history_button.js,sha256=i9EBAWWW2XyQnAuj1b-c8102EG_gDkQ2ElbA8_Nu0yo,3491
67
+ iatoolkit/static/js/chat_logout_button.js,sha256=Of9H6IbAboSBmeqRaurEVW6_dL752L0UeDcDLNBD5Z0,1335
68
+ iatoolkit/static/js/chat_main.js,sha256=MmoagngCFqzjWVUewq9ZOE2RgATKoyuy351aQ0ezVco,12504
69
+ iatoolkit/static/js/chat_onboarding_button.js,sha256=vjvEloJ9PA9D7jOGca0QjS3J_7bU97R71L7kSyY3wOI,3153
70
+ iatoolkit/static/js/chat_prompt_manager.js,sha256=QYki28CpyM2Chn82dnOP2eH6FObxH8eChGFyUxukv1M,3319
71
+ iatoolkit/static/js/chat_reload_button.js,sha256=FHMm5sLdn2HuWDq66wphNuRcltjLG-aADp0yTwEbnQw,1256
72
+ iatoolkit/static/styles/chat_iatoolkit.css,sha256=b25ahyuEKRLQArOhyIgnMxWAxy2vATk8-iVlebl6PrY,13808
73
+ iatoolkit/static/styles/chat_modal.css,sha256=9rwWrzL4Vq7AsdiGb3qczyOUf2PJEgLjSLCkSns8dQA,3031
74
+ iatoolkit/static/styles/chat_public.css,sha256=4EHN_VvURQYlooCmNB-UHIhvMsn4GFm7tKtr4VKpCNE,3830
75
+ iatoolkit/static/styles/landing_page.css,sha256=E6VRI5dko_naloH_FmNAHpjzxz4NZbrbzKwYLw4fYJA,4297
76
+ iatoolkit/static/styles/llm_output.css,sha256=AlxgRSOleeCk2dLAqFWVaQ-jwZiJjcpC5rHuUv3T6VU,2312
77
+ iatoolkit/static/styles/onboarding.css,sha256=Bo0hd8ngVy404_a-gtNFi-hzljhIAnpE-1oQJGnj0F0,3655
78
+ iatoolkit/system_prompts/format_styles.prompt,sha256=MSMe1qvR3cF_0IbFshn8R0z6Wx6VCHQq1p37rpu5wwk,3576
79
+ iatoolkit/system_prompts/query_main.prompt,sha256=D2Wjf0uunQIQsQiJVrY-BTQz6PemM5En6ftmw_c5t4E,2808
80
+ iatoolkit/system_prompts/sql_rules.prompt,sha256=y4nURVnb9AyFwt-lrbMNBHHtZlhk6kC9grYoOhRnrJo,59174
81
+ iatoolkit/templates/_company_header.html,sha256=wrwDftsSVu1uMPchsweAPLupsPkmLIPQBQ0xpIIyxjA,747
82
+ iatoolkit/templates/_login_widget.html,sha256=mheHpa_mcGK7UYSYdzxyD_n97MnJXJE19IcFxxUQYTY,1952
83
+ iatoolkit/templates/about.html,sha256=ciC08grUVz5qLzdzDDqDX31xirg5PrJIRYabWpV9oA8,294
84
+ iatoolkit/templates/base.html,sha256=xOox6JJEd6dHBlw6DBrFDJTXtAKCaXZc3Ffrufa-GDk,3042
85
+ iatoolkit/templates/change_password.html,sha256=rvB4R7lO3y__umQRvkcK1FaOYYvvHn4oKCdrUzvIvf8,3483
86
+ iatoolkit/templates/chat.html,sha256=BkODBkMRZjoFLkWurZznFrluE9CZyqXWQwvpnaIUujM,13251
87
+ iatoolkit/templates/chat_modals.html,sha256=awjPV-JD-Y6Xm_HSgwFAr_2UAIKI6ydgvQfhy9YhuhY,8442
88
+ iatoolkit/templates/error.html,sha256=IdswYbZYp5cHZjPdKBOR44OBwL1GRVR--UTpSKYSwTU,1779
89
+ iatoolkit/templates/forgot_password.html,sha256=RPV_fDCzEdSQpA0qM8RNSCsNlhUhgp9sRGUHpMMBQ10,2247
90
+ iatoolkit/templates/index.html,sha256=mOuHePAmQ5PaMwqkJf7HU5oIL_lh8iKBKFng6d-QVzA,8017
91
+ iatoolkit/templates/login_simulation.html,sha256=gahHUP-ifHyuH2Nl-8n7_GfsHWlGeHWKq0bHNHRuXCQ,1472
92
+ iatoolkit/templates/onboarding_shell.html,sha256=3Kb7R9AytkztJpxoTCi4zNZRZxxQ3mZsAId44BR5PaU,4611
93
+ iatoolkit/templates/signup.html,sha256=u2wiahk_d_BfooknSCcgcgAaQqIfas2aj6fe0cG3jzE,4174
94
+ iatoolkit/views/__init__.py,sha256=5JqK9sZ6jBuK83zDQokUhxQ0wuJJJ9DXB8pYCLkX7X4,102
95
+ iatoolkit/views/base_login_view.py,sha256=wwPcB2LE0FwyE-Any-KPkAJPYtzUw5_9E6q2sxO5Ryo,3700
96
+ iatoolkit/views/change_password_view.py,sha256=JfFcJgqIbsDaMgt9OB70GsWmzR8er6vmLi-fm-gPU1A,4966
97
+ iatoolkit/views/external_login_view.py,sha256=d4gUQbxFsThGbbAUdtFn7AMgPJjeb7_8KFFoH3vspVA,2853
98
+ iatoolkit/views/file_store_api_view.py,sha256=UvtZWOG-rLQMLfs8igOIYoQ-tkkEg5baMjqCJdKxaRQ,2300
99
+ iatoolkit/views/forgot_password_view.py,sha256=k200mbuzL6CZ-P8NfovpBYKAkzK0FNvZawD8kjGUWGA,3184
100
+ iatoolkit/views/help_content_api_view.py,sha256=QiGtscTnj5E2jY-FrcFiLImI913SOlIVEVdMXBbF3cE,2013
101
+ iatoolkit/views/history_api_view.py,sha256=CrfHmdIx4pB41KC_mbvEpv33zkPeKuBmlfGI2kc1ZvM,1988
102
+ iatoolkit/views/home_view.py,sha256=zKR-8bzOrS2OKy9Ka-j3Tsg3MHDzUurJQQ0LOfVF8P4,2574
103
+ iatoolkit/views/index_view.py,sha256=OsykSlXLB-TpFAPkDlsMna6bi3Ie5PXL303Hsg3WwUM,329
104
+ iatoolkit/views/init_context_api_view.py,sha256=jdX-D3LVOHvpsoFCpzlPmILpYlq_zp0_IoNBxukBw3k,3014
105
+ iatoolkit/views/llmquery_api_view.py,sha256=unaKeiPj6cKpiwdxvKlzJpvSkH1szvu7CQY7oUSKhYY,2178
106
+ iatoolkit/views/login_simulation_view.py,sha256=TP85TjdtbEBZlVLUMr0KrQ0Wrjrv8rpAlgQ9QUZE4rU,4023
107
+ iatoolkit/views/login_view.py,sha256=3C356H9UfI8VHcMwg8K8_5F3ZlFqeDD3s4pIaEfPUKw,6412
108
+ iatoolkit/views/logout_api_view.py,sha256=tvk4sCCXOFsk6qfGsrwY-pDKHL4ET30tL7ncTG-PT8A,1733
109
+ iatoolkit/views/profile_api_view.py,sha256=qhlmhyygIs5h-OyNDwq1uGUS8S-GxB2zOYY51Hs5prY,1645
110
+ iatoolkit/views/prompt_api_view.py,sha256=zumYnC_LWq_IeLraoL24YrY87U6a7iC6maY1PN-IP6U,1263
111
+ iatoolkit/views/signup_view.py,sha256=aAY5R4iH2Bi6qzfTNpyHvD-Vx6jC8oSKXlwQNOrQqw4,3980
112
+ iatoolkit/views/tasks_api_view.py,sha256=wGnuwuuL83ByQ1Yre6ytRVztA0OGQjGrwMjB1_G830U,2630
113
+ iatoolkit/views/tasks_review_api_view.py,sha256=wsCpzqyRyUdCXWAhyGlBe3eNZZ6A1DQG7TblN_GZNfM,1894
114
+ iatoolkit/views/user_feedback_api_view.py,sha256=QOTBtpNqYAmewXDgVAoaIprnVjvf1xM0ExWxSFp3ICI,2098
115
+ iatoolkit/views/verify_user_view.py,sha256=RzemgRpiQwjIz2Z43aIupE3uMeyFLTjqgAPPDcCb63Y,2735
116
+ iatoolkit-0.67.0.dist-info/licenses/LICENSE,sha256=5tOLQdjoCvSXEx_7Lr4bSab3ha4NSwzamvua0fwCXi8,1075
117
+ iatoolkit-0.67.0.dist-info/METADATA,sha256=C4yG5NkBoGa9SRFozeBChMebS2T_2YUru0PqeN42Fc0,9963
118
+ iatoolkit-0.67.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
119
+ iatoolkit-0.67.0.dist-info/top_level.txt,sha256=V_w4QvDx0b1RXiy8zTCrD1Bp7AZkFe3_O0-9fMiwogg,10
120
+ iatoolkit-0.67.0.dist-info/RECORD,,
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Fernando Libedinsky
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.