iatoolkit 0.59.0__tar.gz → 0.64.0__tar.gz

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 (134) hide show
  1. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/PKG-INFO +1 -1
  2. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/pyproject.toml +1 -1
  3. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/src/iatoolkit/base_company.py +3 -1
  4. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/src/iatoolkit/common/routes.py +22 -25
  5. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/src/iatoolkit/common/util.py +0 -6
  6. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/src/iatoolkit/iatoolkit.py +16 -19
  7. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/src/iatoolkit/repositories/models.py +1 -1
  8. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/src/iatoolkit/services/auth_service.py +33 -26
  9. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/src/iatoolkit/services/branding_service.py +28 -22
  10. iatoolkit-0.64.0/src/iatoolkit/services/help_content_service.py +30 -0
  11. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/src/iatoolkit/services/profile_service.py +1 -0
  12. iatoolkit-0.64.0/src/iatoolkit/services/user_feedback_service.py +103 -0
  13. iatoolkit-0.64.0/src/iatoolkit/static/js/chat_feedback_button.js +82 -0
  14. iatoolkit-0.64.0/src/iatoolkit/static/js/chat_help_content.js +124 -0
  15. iatoolkit-0.64.0/src/iatoolkit/static/js/chat_history_button.js +93 -0
  16. iatoolkit-0.64.0/src/iatoolkit/static/js/chat_logout_button.js +36 -0
  17. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/src/iatoolkit/static/js/chat_main.js +8 -162
  18. iatoolkit-0.59.0/src/iatoolkit/static/js/chat_onboarding.js → iatoolkit-0.64.0/src/iatoolkit/static/js/chat_onboarding_button.js +0 -1
  19. iatoolkit-0.64.0/src/iatoolkit/static/js/chat_prompt_manager.js +94 -0
  20. iatoolkit-0.64.0/src/iatoolkit/static/js/chat_reload_button.js +35 -0
  21. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/src/iatoolkit/static/styles/chat_iatoolkit.css +259 -141
  22. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/src/iatoolkit/static/styles/chat_modal.css +97 -91
  23. iatoolkit-0.64.0/src/iatoolkit/static/styles/landing_page.css +182 -0
  24. iatoolkit-0.64.0/src/iatoolkit/templates/_company_header.html +20 -0
  25. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/src/iatoolkit/templates/_login_widget.html +4 -6
  26. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/src/iatoolkit/templates/base.html +2 -0
  27. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/src/iatoolkit/templates/change_password.html +12 -14
  28. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/src/iatoolkit/templates/chat.html +86 -81
  29. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/src/iatoolkit/templates/chat_modals.html +91 -66
  30. iatoolkit-0.64.0/src/iatoolkit/templates/error.html +48 -0
  31. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/src/iatoolkit/templates/forgot_password.html +10 -12
  32. iatoolkit-0.64.0/src/iatoolkit/templates/index.html +142 -0
  33. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/src/iatoolkit/templates/onboarding_shell.html +1 -2
  34. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/src/iatoolkit/templates/signup.html +12 -10
  35. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/src/iatoolkit/views/change_password_view.py +8 -6
  36. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/src/iatoolkit/views/external_login_view.py +5 -11
  37. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/src/iatoolkit/views/file_store_api_view.py +7 -9
  38. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/src/iatoolkit/views/forgot_password_view.py +10 -6
  39. iatoolkit-0.64.0/src/iatoolkit/views/help_content_api_view.py +50 -0
  40. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/src/iatoolkit/views/history_api_view.py +8 -9
  41. iatoolkit-0.64.0/src/iatoolkit/views/home_view.py +67 -0
  42. iatoolkit-0.64.0/src/iatoolkit/views/index_view.py +14 -0
  43. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/src/iatoolkit/views/init_context_api_view.py +2 -6
  44. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/src/iatoolkit/views/llmquery_api_view.py +1 -3
  45. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/src/iatoolkit/views/login_view.py +14 -8
  46. iatoolkit-0.64.0/src/iatoolkit/views/logout_api_view.py +45 -0
  47. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/src/iatoolkit/views/prompt_api_view.py +5 -5
  48. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/src/iatoolkit/views/signup_view.py +10 -6
  49. iatoolkit-0.59.0/src/iatoolkit/views/tasks_view.py → iatoolkit-0.64.0/src/iatoolkit/views/tasks_api_view.py +10 -36
  50. iatoolkit-0.64.0/src/iatoolkit/views/tasks_review_api_view.py +55 -0
  51. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/src/iatoolkit/views/user_feedback_api_view.py +6 -18
  52. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/src/iatoolkit/views/verify_user_view.py +8 -3
  53. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/src/iatoolkit.egg-info/PKG-INFO +1 -1
  54. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/src/iatoolkit.egg-info/SOURCES.txt +14 -9
  55. iatoolkit-0.59.0/src/iatoolkit/services/user_feedback_service.py +0 -64
  56. iatoolkit-0.59.0/src/iatoolkit/static/js/chat_context_reload.js +0 -61
  57. iatoolkit-0.59.0/src/iatoolkit/static/js/chat_feedback.js +0 -115
  58. iatoolkit-0.59.0/src/iatoolkit/static/js/chat_history.js +0 -127
  59. iatoolkit-0.59.0/src/iatoolkit/static/styles/landing_page.css +0 -228
  60. iatoolkit-0.59.0/src/iatoolkit/templates/_branding_styles.html +0 -53
  61. iatoolkit-0.59.0/src/iatoolkit/templates/_navbar.html +0 -9
  62. iatoolkit-0.59.0/src/iatoolkit/templates/error.html +0 -15
  63. iatoolkit-0.59.0/src/iatoolkit/templates/index.html +0 -160
  64. iatoolkit-0.59.0/src/iatoolkit/views/chat_token_request_view.py +0 -98
  65. iatoolkit-0.59.0/src/iatoolkit/views/index_view.py +0 -43
  66. iatoolkit-0.59.0/src/iatoolkit/views/tasks_review_view.py +0 -83
  67. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/readme.md +0 -0
  68. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/requirements.txt +0 -0
  69. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/setup.cfg +0 -0
  70. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/src/iatoolkit/__init__.py +0 -0
  71. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/src/iatoolkit/cli_commands.py +0 -0
  72. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/src/iatoolkit/common/__init__.py +0 -0
  73. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/src/iatoolkit/common/exceptions.py +0 -0
  74. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/src/iatoolkit/common/session_manager.py +0 -0
  75. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/src/iatoolkit/company_registry.py +0 -0
  76. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/src/iatoolkit/infra/__init__.py +0 -0
  77. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/src/iatoolkit/infra/call_service.py +0 -0
  78. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/src/iatoolkit/infra/connectors/__init__.py +0 -0
  79. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/src/iatoolkit/infra/connectors/file_connector.py +0 -0
  80. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/src/iatoolkit/infra/connectors/file_connector_factory.py +0 -0
  81. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/src/iatoolkit/infra/connectors/google_cloud_storage_connector.py +0 -0
  82. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/src/iatoolkit/infra/connectors/google_drive_connector.py +0 -0
  83. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/src/iatoolkit/infra/connectors/local_file_connector.py +0 -0
  84. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/src/iatoolkit/infra/connectors/s3_connector.py +0 -0
  85. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/src/iatoolkit/infra/gemini_adapter.py +0 -0
  86. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/src/iatoolkit/infra/google_chat_app.py +0 -0
  87. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/src/iatoolkit/infra/llm_client.py +0 -0
  88. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/src/iatoolkit/infra/llm_proxy.py +0 -0
  89. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/src/iatoolkit/infra/llm_response.py +0 -0
  90. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/src/iatoolkit/infra/mail_app.py +0 -0
  91. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/src/iatoolkit/infra/openai_adapter.py +0 -0
  92. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/src/iatoolkit/infra/redis_session_manager.py +0 -0
  93. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/src/iatoolkit/repositories/__init__.py +0 -0
  94. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/src/iatoolkit/repositories/database_manager.py +0 -0
  95. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/src/iatoolkit/repositories/document_repo.py +0 -0
  96. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/src/iatoolkit/repositories/llm_query_repo.py +0 -0
  97. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/src/iatoolkit/repositories/profile_repo.py +0 -0
  98. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/src/iatoolkit/repositories/tasks_repo.py +0 -0
  99. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/src/iatoolkit/repositories/vs_repo.py +0 -0
  100. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/src/iatoolkit/services/__init__.py +0 -0
  101. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/src/iatoolkit/services/benchmark_service.py +0 -0
  102. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/src/iatoolkit/services/dispatcher_service.py +0 -0
  103. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/src/iatoolkit/services/document_service.py +0 -0
  104. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/src/iatoolkit/services/excel_service.py +0 -0
  105. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/src/iatoolkit/services/file_processor_service.py +0 -0
  106. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/src/iatoolkit/services/history_service.py +0 -0
  107. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/src/iatoolkit/services/jwt_service.py +0 -0
  108. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/src/iatoolkit/services/load_documents_service.py +0 -0
  109. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/src/iatoolkit/services/mail_service.py +0 -0
  110. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/src/iatoolkit/services/onboarding_service.py +0 -0
  111. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/src/iatoolkit/services/prompt_manager_service.py +0 -0
  112. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/src/iatoolkit/services/query_service.py +0 -0
  113. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/src/iatoolkit/services/search_service.py +0 -0
  114. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/src/iatoolkit/services/sql_service.py +0 -0
  115. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/src/iatoolkit/services/tasks_service.py +0 -0
  116. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/src/iatoolkit/services/user_session_context_service.py +0 -0
  117. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/src/iatoolkit/static/images/fernando.jpeg +0 -0
  118. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/src/iatoolkit/static/js/chat_filepond.js +0 -0
  119. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/src/iatoolkit/static/styles/chat_info.css +0 -0
  120. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/src/iatoolkit/static/styles/llm_output.css +0 -0
  121. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/src/iatoolkit/static/styles/onboarding.css +0 -0
  122. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/src/iatoolkit/system_prompts/format_styles.prompt +0 -0
  123. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/src/iatoolkit/system_prompts/query_main.prompt +0 -0
  124. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/src/iatoolkit/system_prompts/sql_rules.prompt +0 -0
  125. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/src/iatoolkit/templates/about.html +0 -0
  126. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/src/iatoolkit/templates/header.html +0 -0
  127. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/src/iatoolkit/templates/login_simulation.html +0 -0
  128. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/src/iatoolkit/templates/test.html +0 -0
  129. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/src/iatoolkit/views/__init__.py +0 -0
  130. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/src/iatoolkit/views/base_login_view.py +0 -0
  131. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/src/iatoolkit/views/login_simulation_view.py +0 -0
  132. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/src/iatoolkit.egg-info/dependency_links.txt +0 -0
  133. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/src/iatoolkit.egg-info/requires.txt +0 -0
  134. {iatoolkit-0.59.0 → iatoolkit-0.64.0}/src/iatoolkit.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: iatoolkit
3
- Version: 0.59.0
3
+ Version: 0.64.0
4
4
  Summary: IAToolkit
5
5
  Author: Fernando Libedinsky
6
6
  License-Expression: MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "iatoolkit"
7
- version = "0.59.0"
7
+ version = "0.64.0"
8
8
  requires-python = ">=3.12"
9
9
  description = "IAToolkit"
10
10
  readme = "readme.md"
@@ -29,11 +29,13 @@ class BaseCompany(ABC):
29
29
  def _create_company(self,
30
30
  short_name: str,
31
31
  name: str,
32
+ parameters: dict | None = None,
32
33
  branding: dict | None = None,
33
- onboarding_cards: dict | None = None
34
+ onboarding_cards: dict | None = None,
34
35
  ) -> Company:
35
36
  company_obj = Company(short_name=short_name,
36
37
  name=name,
38
+ parameters=parameters,
37
39
  branding=branding,
38
40
  onboarding_cards=onboarding_cards)
39
41
  self.company = self.profile_repo.create_company(company_obj)
@@ -3,17 +3,8 @@
3
3
  #
4
4
  # IAToolkit is open source software.
5
5
 
6
- from flask import render_template, redirect, flash, url_for,send_from_directory, current_app, abort
7
- from iatoolkit.common.session_manager import SessionManager
6
+ from flask import render_template, redirect, url_for,send_from_directory, current_app, abort
8
7
  from flask import jsonify
9
- from iatoolkit.views.history_api_view import HistoryApiView
10
- import os
11
-
12
-
13
- def logout(company_short_name: str):
14
- SessionManager.clear()
15
- flash("Has cerrado sesión correctamente", "info")
16
- return redirect(url_for('index', company_short_name=company_short_name))
17
8
 
18
9
 
19
10
  # this function register all the views
@@ -22,8 +13,8 @@ def register_views(injector, app):
22
13
  from iatoolkit.views.index_view import IndexView
23
14
  from iatoolkit.views.init_context_api_view import InitContextApiView
24
15
  from iatoolkit.views.llmquery_api_view import LLMQueryApiView
25
- from iatoolkit.views.tasks_view import TaskView
26
- from iatoolkit.views.tasks_review_view import TaskReviewView
16
+ from iatoolkit.views.tasks_api_view import TaskApiView
17
+ from iatoolkit.views.tasks_review_api_view import TaskReviewApiView
27
18
  from iatoolkit.views.login_simulation_view import LoginSimulationView
28
19
  from iatoolkit.views.signup_view import SignupView
29
20
  from iatoolkit.views.verify_user_view import VerifyAccountView
@@ -32,12 +23,19 @@ def register_views(injector, app):
32
23
  from iatoolkit.views.file_store_api_view import FileStoreApiView
33
24
  from iatoolkit.views.user_feedback_api_view import UserFeedbackApiView
34
25
  from iatoolkit.views.prompt_api_view import PromptApiView
35
- from iatoolkit.views.chat_token_request_view import ChatTokenRequestView
26
+ from iatoolkit.views.history_api_view import HistoryApiView
27
+ from iatoolkit.views.help_content_api_view import HelpContentApiView
28
+
36
29
  from iatoolkit.views.login_view import LoginView, FinalizeContextView
37
30
  from iatoolkit.views.external_login_view import ExternalLoginView, RedeemTokenApiView
31
+ from iatoolkit.views.logout_api_view import LogoutApiView
32
+ from iatoolkit.views.home_view import HomeView
38
33
 
39
34
  # iatoolkit home page
40
- app.add_url_rule('/<company_short_name>', view_func=IndexView.as_view('index'))
35
+ app.add_url_rule('/', view_func=IndexView.as_view('index'))
36
+
37
+ # company home view
38
+ app.add_url_rule('/<company_short_name>/home', view_func=HomeView.as_view('home'))
41
39
 
42
40
  # login for the iatoolkit integrated frontend
43
41
  app.add_url_rule('/<company_short_name>/login', view_func=LoginView.as_view('login'))
@@ -57,23 +55,21 @@ def register_views(injector, app):
57
55
  view_func=FinalizeContextView.as_view('finalize_with_token')
58
56
  )
59
57
 
58
+ # logout
59
+ app.add_url_rule('/<company_short_name>/api/logout',
60
+ view_func=LogoutApiView.as_view('logout'))
61
+
60
62
  # this endpoint is called by the JS for changing the token for a session
61
63
  app.add_url_rule('/<string:company_short_name>/api/redeem_token',
62
64
  view_func = RedeemTokenApiView.as_view('redeem_token'))
63
65
 
64
- # this endpoint is for requesting a chat token for external users
65
- app.add_url_rule('/auth/chat_token',
66
- view_func=ChatTokenRequestView.as_view('chat-token'))
67
-
68
- # init (reset) the company context (with api-key)
66
+ # init (reset) the company context
69
67
  app.add_url_rule('/<company_short_name>/api/init-context',
70
68
  view_func=InitContextApiView.as_view('init-context'),
71
69
  methods=['POST', 'OPTIONS'])
72
70
 
73
71
  # register new user, account verification and forgot password
74
72
  app.add_url_rule('/<company_short_name>/signup',view_func=SignupView.as_view('signup'))
75
- app.add_url_rule('/<company_short_name>/logout', 'logout', logout)
76
- app.add_url_rule('/logout', 'logout', logout)
77
73
  app.add_url_rule('/<company_short_name>/verify/<token>', view_func=VerifyAccountView.as_view('verify_account'))
78
74
  app.add_url_rule('/<company_short_name>/forgot-password', view_func=ForgotPasswordView.as_view('forgot_password'))
79
75
  app.add_url_rule('/<company_short_name>/change-password/<token>', view_func=ChangePasswordView.as_view('change_password'))
@@ -85,13 +81,14 @@ def register_views(injector, app):
85
81
  # open the promt directory
86
82
  app.add_url_rule('/<company_short_name>/api/prompts', view_func=PromptApiView.as_view('prompt'))
87
83
 
88
- # feedback and history
84
+ # toolbar buttons
89
85
  app.add_url_rule('/<company_short_name>/api/feedback', view_func=UserFeedbackApiView.as_view('feedback'))
90
86
  app.add_url_rule('/<company_short_name>/api/history', view_func=HistoryApiView.as_view('history'))
87
+ app.add_url_rule('/<company_short_name>/api/help-content', view_func=HelpContentApiView.as_view('help-content'))
91
88
 
92
89
  # tasks management endpoints: create task, and review answer
93
- app.add_url_rule('/tasks', view_func=TaskView.as_view('tasks'))
94
- app.add_url_rule('/tasks/review/<int:task_id>', view_func=TaskReviewView.as_view('tasks-review'))
90
+ app.add_url_rule('/tasks', view_func=TaskApiView.as_view('tasks'))
91
+ app.add_url_rule('/tasks/review/<int:task_id>', view_func=TaskReviewApiView.as_view('tasks-review'))
95
92
 
96
93
  # this endpoint is for upload documents into the vector store (api-key)
97
94
  app.add_url_rule('/api/load', view_func=FileStoreApiView.as_view('load_api'))
@@ -133,6 +130,6 @@ def register_views(injector, app):
133
130
  # hacer que la raíz '/' vaya al home de iatoolkit
134
131
  @app.route('/')
135
132
  def root_redirect():
136
- return redirect(url_for('index', company_short_name='sample_company'))
133
+ return redirect(url_for('index'))
137
134
 
138
135
 
@@ -21,10 +21,8 @@ class Utility:
21
21
  def __init__(self):
22
22
  self.encryption_key = os.getenv('FERNET_KEY')
23
23
 
24
-
25
24
  def render_prompt_from_template(self,
26
25
  template_pathname: str,
27
- query: str = None,
28
26
  client_data: dict = {},
29
27
  **kwargs) -> str:
30
28
 
@@ -37,8 +35,6 @@ class Utility:
37
35
  env = Environment(loader=FileSystemLoader(template_dir))
38
36
  template = env.get_template(template_file)
39
37
 
40
- kwargs["query"] = query
41
-
42
38
  # add all the keys in client_data to kwargs
43
39
  kwargs.update(client_data)
44
40
 
@@ -53,7 +49,6 @@ class Utility:
53
49
  def render_prompt_from_string(self,
54
50
  template_string: str,
55
51
  searchpath: str | list[str] = None,
56
- query: str = None,
57
52
  client_data: dict = {},
58
53
  **kwargs) -> str:
59
54
  """
@@ -76,7 +71,6 @@ class Utility:
76
71
  env = Environment(loader=loader)
77
72
  template = env.from_string(template_string)
78
73
 
79
- kwargs["query"] = query
80
74
  kwargs.update(client_data)
81
75
 
82
76
  prompt = template.render(**kwargs)
@@ -16,10 +16,10 @@ import os
16
16
  from typing import Optional, Dict, Any
17
17
  from iatoolkit.repositories.database_manager import DatabaseManager
18
18
  from werkzeug.middleware.proxy_fix import ProxyFix
19
- from injector import Binder, singleton, Injector
19
+ from injector import Binder, Injector, singleton
20
20
  from importlib.metadata import version as _pkg_version, PackageNotFoundError
21
21
 
22
- IATOOLKIT_VERSION = "0.59.0"
22
+ IATOOLKIT_VERSION = "0.64.0"
23
23
 
24
24
  # global variable for the unique instance of IAToolkit
25
25
  _iatoolkit_instance: Optional['IAToolkit'] = None
@@ -52,7 +52,7 @@ class IAToolkit:
52
52
  self.app = None
53
53
  self.db_manager = None
54
54
  self._injector = None
55
- self.version = IATOOLKIT_VERSION
55
+ self.version = IATOOLKIT_VERSION # default version
56
56
 
57
57
  @classmethod
58
58
  def get_instance(cls) -> 'IAToolkit':
@@ -88,7 +88,7 @@ class IAToolkit:
88
88
  # and other integrations, as views are handled manually.
89
89
  FlaskInjector(app=self.app, injector=self._injector)
90
90
 
91
- # Step 6: initialize dispatcher and registered compaies
91
+ # Step 6: initialize dispatcher and registered companies
92
92
  self._init_dispatcher_and_company_instances()
93
93
 
94
94
  # Step 7: Finalize setup within the application context
@@ -101,8 +101,6 @@ class IAToolkit:
101
101
  # Step 8: define the download_dir for excel's
102
102
  self._setup_download_dir()
103
103
 
104
-
105
-
106
104
  logging.info(f"🎉 IAToolkit v{self.version} inicializado correctamente")
107
105
  self._initialized = True
108
106
  return self.app
@@ -117,7 +115,7 @@ class IAToolkit:
117
115
  log_level = getattr(logging, log_level_name, logging.INFO)
118
116
 
119
117
  logging.basicConfig(
120
- level=logging.INFO, # log_level,
118
+ level=log_level,
121
119
  format="%(asctime)s - IATOOLKIT - %(name)s - %(levelname)s - %(message)s",
122
120
  handlers=[logging.StreamHandler()],
123
121
  force=True
@@ -226,20 +224,19 @@ class IAToolkit:
226
224
 
227
225
  def _setup_cors(self):
228
226
  """🌐 Configura CORS"""
229
- # Origins por defecto para desarrollo
227
+ from iatoolkit.company_registry import get_company_registry
228
+
229
+ # default CORS origin
230
230
  default_origins = [
231
- "http://localhost:5001",
232
- "http://127.0.0.1:5001",
233
- "https://portal-interno.maxxa.cl",
234
231
  os.getenv('IATOOLKIT_BASE_URL')
235
232
  ]
236
233
 
237
- # Obtener origins adicionales desde configuración/env
234
+ # Iterate through the registered company names
238
235
  extra_origins = []
239
- for i in range(1, 11): # Soporte para CORS_ORIGIN_1 a CORS_ORIGIN_10
240
- origin = self._get_config_value(f'CORS_ORIGIN_{i}')
241
- if origin:
242
- extra_origins.append(origin)
236
+ all_company_instances = get_company_registry().get_all_company_instances()
237
+ for company_name, company_instance in all_company_instances.items():
238
+ cors_origin = company_instance.company.parameters.get('cors_origin', [])
239
+ extra_origins += cors_origin
243
240
 
244
241
  all_origins = default_origins + extra_origins
245
242
 
@@ -254,7 +251,6 @@ class IAToolkit:
254
251
 
255
252
  logging.info(f"✅ CORS configurado para: {all_origins}")
256
253
 
257
-
258
254
  def _configure_core_dependencies(self, binder: Binder):
259
255
  """⚙️ Configures all system dependencies."""
260
256
  try:
@@ -325,8 +321,8 @@ class IAToolkit:
325
321
  from iatoolkit.services.auth_service import AuthService
326
322
  from iatoolkit.common.util import Utility
327
323
 
328
- binder.bind(LLMProxy, to=LLMProxy, scope=singleton)
329
- binder.bind(llmClient, to=llmClient, scope=singleton)
324
+ binder.bind(LLMProxy, to=LLMProxy)
325
+ binder.bind(llmClient, to=llmClient)
330
326
  binder.bind(GoogleChatApp, to=GoogleChatApp)
331
327
  binder.bind(MailApp, to=MailApp)
332
328
  binder.bind(AuthService, to=AuthService)
@@ -385,6 +381,7 @@ class IAToolkit:
385
381
  'iatoolkit_base_url': os.environ.get('IATOOLKIT_BASE_URL', ''),
386
382
  }
387
383
 
384
+
388
385
  def _get_default_static_folder(self) -> str:
389
386
  try:
390
387
  current_dir = os.path.dirname(os.path.abspath(__file__)) # .../src/iatoolkit
@@ -60,7 +60,7 @@ class Company(Base):
60
60
 
61
61
  branding = Column(JSON, nullable=True)
62
62
  onboarding_cards = Column(JSON, nullable=True)
63
- parameters = Column(JSON, nullable=True, default={})
63
+ parameters = Column(JSON, nullable=True)
64
64
  created_at = Column(DateTime, default=datetime.now)
65
65
  allow_jwt = Column(Boolean, default=True, nullable=True)
66
66
 
@@ -91,9 +91,10 @@ class AuthService:
91
91
  )
92
92
  return {'success': False, 'error': 'No se pudo crear la sesión del usuario'}
93
93
 
94
- def verify(self) -> dict:
94
+ def verify(self, anonymous: bool = False) -> dict:
95
95
  """
96
96
  Verifies the current request and identifies the user.
97
+ If anonymous is True the non-presence of use_identifier is ignored
97
98
 
98
99
  Returns a dictionary with:
99
100
  - success: bool
@@ -109,7 +110,7 @@ class AuthService:
109
110
  return {
110
111
  "success": True,
111
112
  "company_short_name": session_info['company_short_name'],
112
- "user_identifier": session_info['user_identifier']
113
+ "user_identifier": session_info['user_identifier'],
113
114
  }
114
115
 
115
116
  # --- Priority 2: Check for a valid API Key in headers ---
@@ -118,31 +119,37 @@ class AuthService:
118
119
  if isinstance(auth, str) and auth.lower().startswith('bearer '):
119
120
  api_key = auth.split(' ', 1)[1].strip()
120
121
 
121
- if api_key:
122
- api_key_entry = self.profile_service.get_active_api_key_entry(api_key)
123
- if not api_key_entry:
124
- logging.info(f"Invalid or inactive API Key {api_key}")
125
- return {"success": False, "error_message": "Invalid or inactive API Key", "status_code": 401}
122
+ if not api_key:
123
+ # --- Failure: No valid credentials found ---
124
+ logging.info(f"Authentication required. No session cookie or API Key provided.")
125
+ return {"success": False,
126
+ "error_message": "Authentication required. No session cookie or API Key provided.",
127
+ "status_code": 401}
128
+
129
+ # check if the api-key is valid and active
130
+ api_key_entry = self.profile_service.get_active_api_key_entry(api_key)
131
+ if not api_key_entry:
132
+ logging.info(f"Invalid or inactive API Key {api_key}")
133
+ return {"success": False, "error_message": "Invalid or inactive API Key",
134
+ "status_code": 402}
135
+
136
+ # get the company from the api_key_entry
137
+ company = api_key_entry.company
138
+
139
+ # For API calls, the external_user_id must be provided in the request.
140
+ data = request.get_json(silent=True) or {}
141
+ user_identifier = data.get('user_identifier', '')
142
+ if not anonymous and not user_identifier:
143
+ logging.info(f"No user_identifier provided for API call.")
144
+ return {"success": False, "error_message": "No user_identifier provided for API call.",
145
+ "status_code": 403}
146
+
147
+ return {
148
+ "success": True,
149
+ "company_short_name": company.short_name,
150
+ "user_identifier": user_identifier
151
+ }
126
152
 
127
- # obtain the company from the api_key_entry
128
- company = api_key_entry.company
129
-
130
- # For API calls, the external_user_id must be provided in the request.
131
- user_identifier = ''
132
- if request.is_json:
133
- data = request.get_json() or {}
134
- user_identifier = data.get('user_identifier', '')
135
-
136
- return {
137
- "success": True,
138
- "company_short_name": company.short_name,
139
- "user_identifier": user_identifier
140
- }
141
-
142
- # --- Failure: No valid credentials found ---
143
- logging.info(f"Authentication required. No session cookie or API Key provided.")
144
- return {"success": False, "error_message": "Authentication required. No session cookie or API Key provided.",
145
- "status_code": 402}
146
153
 
147
154
  def log_access(self,
148
155
  company_short_name: str,
@@ -4,6 +4,7 @@
4
4
  # IAToolkit is open source software.
5
5
 
6
6
  from iatoolkit.repositories.models import Company
7
+ from injector import inject
7
8
 
8
9
 
9
10
  class BrandingService:
@@ -11,6 +12,7 @@ class BrandingService:
11
12
  Servicio centralizado que gestiona la configuración de branding.
12
13
  """
13
14
 
15
+ @inject
14
16
  def __init__(self):
15
17
  """
16
18
  Define los estilos de branding por defecto para la aplicación.
@@ -19,13 +21,16 @@ class BrandingService:
19
21
  # --- Estilos del Encabezado Principal ---
20
22
  "header_background_color": "#FFFFFF",
21
23
  "header_text_color": "#6C757D",
22
- "primary_font_weight": "bold",
23
- "primary_font_size": "1rem",
24
- "secondary_font_weight": "600",
25
- "secondary_font_size": "0.875rem",
26
- "tertiary_font_weight": "normal",
27
- "tertiary_font_size": "0.75rem",
28
- "tertiary_opacity": "0.8",
24
+ "primary_font_weight": "600",
25
+ "primary_font_size": "1.2rem",
26
+ "secondary_font_weight": "400",
27
+ "secondary_font_size": "0.9rem",
28
+ "tertiary_font_weight": "300",
29
+ "tertiary_font_size": "0.8rem",
30
+ "tertiary_opacity": "0.7",
31
+
32
+ # headings
33
+ "brand_text_heading_color": "#334155", # Gris pizarra por defecto
29
34
 
30
35
  # Estilos Globales de la Marca ---
31
36
  "brand_primary_color": "#0d6efd", # Azul de Bootstrap por defecto
@@ -40,25 +45,27 @@ class BrandingService:
40
45
  "brand_danger_border": "#f5c2c7", # Borde rojo intermedio
41
46
 
42
47
  # Estilos para Alertas Informativas ---
43
- "brand_info_bg": "#cff4fc", # Fondo celeste pálido
44
- "brand_info_text": "#055160", # Texto azul oscuro
45
- "brand_info_border": "#b6effb",
48
+ "brand_info_bg": "#F0F4F8", # Un fondo de gris azulado muy pálido
49
+ "brand_info_text": "#0d6efd", # Texto en el color primario
50
+ "brand_info_border": "#D9E2EC", # Borde de gris azulado pálido
46
51
 
47
52
  # Estilos para el Asistente de Prompts ---
48
53
  "prompt_assistant_bg": "#f8f9fa",
49
54
  "prompt_assistant_border": "#dee2e6",
50
- "prompt_assistant_icon_color": "#6c757d",
51
55
  "prompt_assistant_button_bg": "#FFFFFF",
52
56
  "prompt_assistant_button_text": "#495057",
53
57
  "prompt_assistant_button_border": "#ced4da",
54
58
  "prompt_assistant_dropdown_bg": "#f8f9fa",
55
59
  "prompt_assistant_header_bg": "#e9ecef",
56
60
  "prompt_assistant_header_text": "#495057",
57
- "prompt_assistant_item_hover_bg": None, # Usará el primario por defecto
58
- "prompt_assistant_item_hover_text": None, # Usará el texto sobre primario
61
+
62
+ # this use the primary by default
63
+ "prompt_assistant_icon_color": None,
64
+ "prompt_assistant_item_hover_bg": None,
65
+ "prompt_assistant_item_hover_text": None,
59
66
 
60
67
  # Color para el botón de Enviar ---
61
- "send_button_color": "#212529" # Gris oscuro/casi negro por defecto
68
+ "send_button_color": "#212529" # Gris oscuro/casi negro por defecto
62
69
  }
63
70
 
64
71
  def get_company_branding(self, company: Company | None) -> dict:
@@ -80,10 +87,6 @@ class BrandingService:
80
87
  secondary_rgb = hex_to_rgb(final_branding_values['brand_secondary_color'])
81
88
 
82
89
  # --- CONSTRUCCIÓN DE ESTILOS Y VARIABLES CSS ---
83
- header_style = (
84
- f"background-color: {final_branding_values['header_background_color']}; "
85
- f"color: {final_branding_values['header_text_color']};"
86
- )
87
90
  primary_text_style = (
88
91
  f"font-weight: {final_branding_values['primary_font_weight']}; "
89
92
  f"font-size: {final_branding_values['primary_font_size']};"
@@ -103,6 +106,10 @@ class BrandingService:
103
106
  :root {{
104
107
  --brand-primary-color: {final_branding_values['brand_primary_color']};
105
108
  --brand-secondary-color: {final_branding_values['brand_secondary_color']};
109
+ --brand-header-bg: {final_branding_values['header_background_color']};
110
+ --brand-header-text: {final_branding_values['header_text_color']};
111
+ --brand-text-heading-color: {final_branding_values['brand_text_heading_color']};
112
+
106
113
  --brand-primary-color-rgb: {', '.join(map(str, primary_rgb))};
107
114
  --brand-secondary-color-rgb: {', '.join(map(str, secondary_rgb))};
108
115
  --brand-text-on-primary: {final_branding_values['brand_text_on_primary']};
@@ -114,11 +121,11 @@ class BrandingService:
114
121
  --brand-danger-text: {final_branding_values['brand_danger_text']};
115
122
  --brand-danger-border: {final_branding_values['brand_danger_border']};
116
123
  --brand-info-bg: {final_branding_values['brand_info_bg']};
117
- --brand-info-text: {final_branding_values['brand_info_text']};
124
+ --brand-info-text: {final_branding_values['brand_info_text'] or final_branding_values['brand_primary_color']};
118
125
  --brand-info-border: {final_branding_values['brand_info_border']};
119
126
  --brand-prompt-assistant-bg: {final_branding_values['prompt_assistant_bg']};
120
127
  --brand-prompt-assistant-border: {final_branding_values['prompt_assistant_border']};
121
- --brand-prompt-assistant-icon-color: {final_branding_values['prompt_assistant_icon_color']};
128
+ --brand-prompt-assistant-icon-color: {final_branding_values['prompt_assistant_icon_color'] or final_branding_values['brand_primary_color']};
122
129
  --brand-prompt-assistant-button-bg: {final_branding_values['prompt_assistant_button_bg']};
123
130
  --brand-prompt-assistant-button-text: {final_branding_values['prompt_assistant_button_text']};
124
131
  --brand-prompt-assistant-button-border: {final_branding_values['prompt_assistant_button_border']};
@@ -133,11 +140,10 @@ class BrandingService:
133
140
 
134
141
  return {
135
142
  "name": company.name if company else "IAToolkit",
136
- "header_style": header_style,
137
143
  "primary_text_style": primary_text_style,
138
144
  "secondary_text_style": secondary_text_style,
139
145
  "tertiary_text_style": tertiary_text_style,
140
146
  "header_text_color": final_branding_values['header_text_color'],
141
147
  "css_variables": css_variables,
142
- "send_button_color": final_branding_values['send_button_color']
148
+ "send_button_color": final_branding_values['brand_primary_color']
143
149
  }
@@ -0,0 +1,30 @@
1
+ # Copyright (c) 2024 Fernando Libedinsky
2
+ # Product: IAToolkit
3
+ #
4
+ # IAToolkit is open source software.
5
+
6
+ from iatoolkit.common.util import Utility
7
+ from iatoolkit.common.exceptions import IAToolkitException
8
+ import os
9
+ from injector import inject
10
+ import logging
11
+
12
+
13
+ class HelpContentService:
14
+ @inject
15
+ def __init__(self, util: Utility):
16
+ self.util = util
17
+
18
+ def get_content(self, company_short_name: str | None) -> dict:
19
+ filepath = f'companies/{company_short_name}/help_content.yaml'
20
+ if not os.path.exists(filepath):
21
+ return {}
22
+
23
+ # read the file
24
+ try:
25
+ help_content = self.util.load_schema_from_yaml(filepath)
26
+ return help_content
27
+ except Exception as e:
28
+ logging.exception(e)
29
+ raise IAToolkitException(IAToolkitException.ErrorType.CONFIG_ERROR,
30
+ f"Error obteniendo help de {company_short_name}: {str(e)}") from e
@@ -131,6 +131,7 @@ class ProfileService:
131
131
  "profile": profile
132
132
  }
133
133
 
134
+
134
135
  def get_profile_by_identifier(self, company_short_name: str, user_identifier: str) -> dict:
135
136
  """
136
137
  Fetches a user profile directly by their identifier, bypassing the Flask session.
@@ -0,0 +1,103 @@
1
+ # Copyright (c) 2024 Fernando Libedinsky
2
+ # Product: IAToolkit
3
+ #
4
+ # IAToolkit is open source software.
5
+
6
+ from iatoolkit.repositories.models import UserFeedback, Company
7
+ from injector import inject
8
+ from iatoolkit.repositories.profile_repo import ProfileRepo
9
+ from iatoolkit.infra.google_chat_app import GoogleChatApp
10
+ from iatoolkit.infra.mail_app import MailApp # <-- 1. Importar MailApp
11
+ import logging
12
+
13
+
14
+ class UserFeedbackService:
15
+ @inject
16
+ def __init__(self,
17
+ profile_repo: ProfileRepo,
18
+ google_chat_app: GoogleChatApp,
19
+ mail_app: MailApp):
20
+ self.profile_repo = profile_repo
21
+ self.google_chat_app = google_chat_app
22
+ self.mail_app = mail_app
23
+
24
+ def _send_google_chat_notification(self, space_name: str, message_text: str):
25
+ """Envía una notificación de feedback a un espacio de Google Chat."""
26
+ try:
27
+ chat_data = {
28
+ "type": "MESSAGE_TRIGGER",
29
+ "space": {"name": space_name},
30
+ "message": {"text": message_text}
31
+ }
32
+ chat_result = self.google_chat_app.send_message(message_data=chat_data)
33
+ if not chat_result.get('success'):
34
+ logging.warning(f"Error al enviar notificación a Google Chat: {chat_result.get('message')}")
35
+ except Exception as e:
36
+ logging.exception(f"Fallo inesperado al enviar notificación a Google Chat: {e}")
37
+
38
+ def _send_email_notification(self, destination_email: str, company_name: str, message_text: str):
39
+ """Envía una notificación de feedback por correo electrónico."""
40
+ try:
41
+ subject = f"Nuevo Feedback de {company_name}"
42
+ # Convertir el texto plano a un HTML simple para mantener los saltos de línea
43
+ html_body = message_text.replace('\n', '<br>')
44
+ self.mail_app.send_email(to=destination_email, subject=subject, body=html_body)
45
+ except Exception as e:
46
+ logging.exception(f"Fallo inesperado al enviar email de feedback: {e}")
47
+
48
+ def _handle_notification(self, company: Company, message_text: str):
49
+ """Lee la configuración de la empresa y envía la notificación al canal correspondiente."""
50
+ feedback_params = company.parameters.get('user_feedback')
51
+ if not isinstance(feedback_params, dict):
52
+ logging.warning(f"No se encontró configuración de 'user_feedback' para la empresa {company.short_name}.")
53
+ return
54
+
55
+ # get channel and destination
56
+ channel = feedback_params.get('channel')
57
+ destination = feedback_params.get('destination')
58
+ if not channel or not destination:
59
+ logging.warning(f"Configuración 'user_feedback' incompleta para {company.short_name}. Faltan 'channel' o 'destination'.")
60
+ return
61
+
62
+ if channel == 'google_chat':
63
+ self._send_google_chat_notification(space_name=destination, message_text=message_text)
64
+ elif channel == 'email':
65
+ self._send_email_notification(destination_email=destination, company_name=company.short_name, message_text=message_text)
66
+ else:
67
+ logging.warning(f"Canal de feedback '{channel}' no reconocido para la empresa {company.short_name}.")
68
+
69
+ def new_feedback(self,
70
+ company_short_name: str,
71
+ message: str,
72
+ user_identifier: str,
73
+ rating: int = None) -> dict:
74
+ try:
75
+ # 1. Validar empresa
76
+ company = self.profile_repo.get_company_by_short_name(company_short_name)
77
+ if not company:
78
+ return {'error': f'No existe la empresa: {company_short_name}'}
79
+
80
+ # 2. Enviar notificación según la configuración de la empresa
81
+ notification_text = (f"*Nuevo feedback de {company_short_name}*:\n"
82
+ f"*Usuario:* {user_identifier}\n"
83
+ f"*Mensaje:* {message}\n"
84
+ f"*Calificación:* {rating if rating is not None else 'N/A'}")
85
+ self._handle_notification(company, notification_text)
86
+
87
+ # 3. Guardar el feedback en la base de datos (independientemente del éxito de la notificación)
88
+ new_feedback_obj = UserFeedback(
89
+ company_id=company.id,
90
+ message=message,
91
+ user_identifier=user_identifier,
92
+ rating=rating
93
+ )
94
+ saved_feedback = self.profile_repo.save_feedback(new_feedback_obj)
95
+ if not saved_feedback:
96
+ logging.error(f"No se pudo guardar el feedback para el usuario {user_identifier} en la empresa {company_short_name}")
97
+ return {'error': 'No se pudo guardar el feedback'}
98
+
99
+ return {'success': True, 'message': 'Feedback guardado correctamente'}
100
+
101
+ except Exception as e:
102
+ logging.exception(f"Error crítico en el servicio de feedback: {e}")
103
+ return {'error': str(e)}