iatoolkit 0.22.1__tar.gz → 0.64.1__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.
- {iatoolkit-0.22.1 → iatoolkit-0.64.1}/PKG-INFO +2 -2
- {iatoolkit-0.22.1 → iatoolkit-0.64.1}/pyproject.toml +3 -3
- {iatoolkit-0.22.1 → iatoolkit-0.64.1}/src/iatoolkit/base_company.py +4 -2
- iatoolkit-0.64.1/src/iatoolkit/common/routes.py +135 -0
- {iatoolkit-0.22.1 → iatoolkit-0.64.1}/src/iatoolkit/common/session_manager.py +0 -1
- {iatoolkit-0.22.1 → iatoolkit-0.64.1}/src/iatoolkit/common/util.py +0 -27
- {iatoolkit-0.22.1 → iatoolkit-0.64.1}/src/iatoolkit/iatoolkit.py +37 -38
- {iatoolkit-0.22.1 → iatoolkit-0.64.1}/src/iatoolkit/infra/llm_client.py +4 -6
- {iatoolkit-0.22.1 → iatoolkit-0.64.1}/src/iatoolkit/infra/openai_adapter.py +1 -1
- {iatoolkit-0.22.1 → iatoolkit-0.64.1}/src/iatoolkit/infra/redis_session_manager.py +48 -2
- {iatoolkit-0.22.1 → iatoolkit-0.64.1}/src/iatoolkit/repositories/database_manager.py +17 -2
- {iatoolkit-0.22.1 → iatoolkit-0.64.1}/src/iatoolkit/repositories/models.py +28 -4
- {iatoolkit-0.22.1 → iatoolkit-0.64.1}/src/iatoolkit/repositories/profile_repo.py +7 -3
- iatoolkit-0.64.1/src/iatoolkit/services/auth_service.py +188 -0
- {iatoolkit-0.22.1 → iatoolkit-0.64.1}/src/iatoolkit/services/branding_service.py +28 -22
- {iatoolkit-0.22.1 → iatoolkit-0.64.1}/src/iatoolkit/services/dispatcher_service.py +10 -41
- {iatoolkit-0.22.1 → iatoolkit-0.64.1}/src/iatoolkit/services/excel_service.py +15 -15
- iatoolkit-0.64.1/src/iatoolkit/services/help_content_service.py +30 -0
- {iatoolkit-0.22.1 → iatoolkit-0.64.1}/src/iatoolkit/services/history_service.py +2 -11
- {iatoolkit-0.22.1 → iatoolkit-0.64.1}/src/iatoolkit/services/jwt_service.py +15 -24
- {iatoolkit-0.22.1 → iatoolkit-0.64.1}/src/iatoolkit/services/profile_service.py +88 -27
- {iatoolkit-0.22.1 → iatoolkit-0.64.1}/src/iatoolkit/services/query_service.py +124 -81
- {iatoolkit-0.22.1 → iatoolkit-0.64.1}/src/iatoolkit/services/tasks_service.py +1 -1
- iatoolkit-0.64.1/src/iatoolkit/services/user_feedback_service.py +103 -0
- iatoolkit-0.64.1/src/iatoolkit/services/user_session_context_service.py +143 -0
- iatoolkit-0.64.1/src/iatoolkit/static/images/fernando.jpeg +0 -0
- iatoolkit-0.64.1/src/iatoolkit/static/js/chat_feedback_button.js +82 -0
- iatoolkit-0.64.1/src/iatoolkit/static/js/chat_help_content.js +124 -0
- iatoolkit-0.64.1/src/iatoolkit/static/js/chat_history_button.js +93 -0
- iatoolkit-0.64.1/src/iatoolkit/static/js/chat_logout_button.js +36 -0
- {iatoolkit-0.22.1 → iatoolkit-0.64.1}/src/iatoolkit/static/js/chat_main.js +40 -168
- iatoolkit-0.64.1/src/iatoolkit/static/js/chat_onboarding_button.js +97 -0
- iatoolkit-0.64.1/src/iatoolkit/static/js/chat_prompt_manager.js +94 -0
- iatoolkit-0.64.1/src/iatoolkit/static/js/chat_reload_button.js +35 -0
- {iatoolkit-0.22.1 → iatoolkit-0.64.1}/src/iatoolkit/static/styles/chat_iatoolkit.css +258 -141
- {iatoolkit-0.22.1 → iatoolkit-0.64.1}/src/iatoolkit/static/styles/chat_modal.css +95 -91
- iatoolkit-0.64.1/src/iatoolkit/static/styles/landing_page.css +182 -0
- iatoolkit-0.64.1/src/iatoolkit/static/styles/onboarding.css +169 -0
- {iatoolkit-0.22.1 → iatoolkit-0.64.1}/src/iatoolkit/system_prompts/query_main.prompt +3 -12
- iatoolkit-0.64.1/src/iatoolkit/templates/_company_header.html +20 -0
- {iatoolkit-0.22.1 → iatoolkit-0.64.1}/src/iatoolkit/templates/_login_widget.html +10 -13
- {iatoolkit-0.22.1 → iatoolkit-0.64.1}/src/iatoolkit/templates/base.html +3 -0
- {iatoolkit-0.22.1 → iatoolkit-0.64.1}/src/iatoolkit/templates/change_password.html +12 -14
- iatoolkit-0.64.1/src/iatoolkit/templates/chat.html +271 -0
- {iatoolkit-0.22.1 → iatoolkit-0.64.1}/src/iatoolkit/templates/chat_modals.html +116 -58
- iatoolkit-0.64.1/src/iatoolkit/templates/error.html +48 -0
- {iatoolkit-0.22.1 → iatoolkit-0.64.1}/src/iatoolkit/templates/forgot_password.html +10 -12
- iatoolkit-0.64.1/src/iatoolkit/templates/index.html +142 -0
- iatoolkit-0.64.1/src/iatoolkit/templates/login_simulation.html +34 -0
- iatoolkit-0.64.1/src/iatoolkit/templates/onboarding_shell.html +104 -0
- {iatoolkit-0.22.1 → iatoolkit-0.64.1}/src/iatoolkit/templates/signup.html +12 -10
- iatoolkit-0.64.1/src/iatoolkit/views/base_login_view.py +81 -0
- {iatoolkit-0.22.1 → iatoolkit-0.64.1}/src/iatoolkit/views/change_password_view.py +8 -6
- iatoolkit-0.64.1/src/iatoolkit/views/external_login_view.py +73 -0
- iatoolkit-0.22.1/src/iatoolkit/views/file_store_view.py → iatoolkit-0.64.1/src/iatoolkit/views/file_store_api_view.py +9 -11
- {iatoolkit-0.22.1 → iatoolkit-0.64.1}/src/iatoolkit/views/forgot_password_view.py +10 -6
- iatoolkit-0.64.1/src/iatoolkit/views/help_content_api_view.py +50 -0
- iatoolkit-0.64.1/src/iatoolkit/views/history_api_view.py +51 -0
- iatoolkit-0.64.1/src/iatoolkit/views/home_view.py +67 -0
- iatoolkit-0.64.1/src/iatoolkit/views/index_view.py +14 -0
- iatoolkit-0.64.1/src/iatoolkit/views/init_context_api_view.py +68 -0
- iatoolkit-0.64.1/src/iatoolkit/views/llmquery_api_view.py +45 -0
- iatoolkit-0.64.1/src/iatoolkit/views/login_simulation_view.py +81 -0
- iatoolkit-0.64.1/src/iatoolkit/views/login_view.py +144 -0
- iatoolkit-0.64.1/src/iatoolkit/views/logout_api_view.py +45 -0
- iatoolkit-0.22.1/src/iatoolkit/views/prompt_view.py → iatoolkit-0.64.1/src/iatoolkit/views/prompt_api_view.py +7 -7
- {iatoolkit-0.22.1 → iatoolkit-0.64.1}/src/iatoolkit/views/signup_view.py +10 -6
- iatoolkit-0.22.1/src/iatoolkit/views/tasks_view.py → iatoolkit-0.64.1/src/iatoolkit/views/tasks_api_view.py +10 -36
- iatoolkit-0.64.1/src/iatoolkit/views/tasks_review_api_view.py +55 -0
- iatoolkit-0.22.1/src/iatoolkit/views/user_feedback_view.py → iatoolkit-0.64.1/src/iatoolkit/views/user_feedback_api_view.py +16 -31
- {iatoolkit-0.22.1 → iatoolkit-0.64.1}/src/iatoolkit/views/verify_user_view.py +8 -3
- {iatoolkit-0.22.1 → iatoolkit-0.64.1}/src/iatoolkit.egg-info/PKG-INFO +2 -2
- {iatoolkit-0.22.1 → iatoolkit-0.64.1}/src/iatoolkit.egg-info/SOURCES.txt +25 -26
- iatoolkit-0.22.1/src/iatoolkit/common/auth.py +0 -200
- iatoolkit-0.22.1/src/iatoolkit/common/routes.py +0 -130
- iatoolkit-0.22.1/src/iatoolkit/services/user_feedback_service.py +0 -67
- iatoolkit-0.22.1/src/iatoolkit/services/user_session_context_service.py +0 -85
- iatoolkit-0.22.1/src/iatoolkit/static/images/arrow_up.png +0 -0
- iatoolkit-0.22.1/src/iatoolkit/static/images/diagrama_iatoolkit.jpg +0 -0
- iatoolkit-0.22.1/src/iatoolkit/static/images/logo_clinica.png +0 -0
- iatoolkit-0.22.1/src/iatoolkit/static/images/logo_iatoolkit.png +0 -0
- iatoolkit-0.22.1/src/iatoolkit/static/images/logo_maxxa.png +0 -0
- iatoolkit-0.22.1/src/iatoolkit/static/images/logo_notaria.png +0 -0
- iatoolkit-0.22.1/src/iatoolkit/static/images/logo_tarjeta.png +0 -0
- iatoolkit-0.22.1/src/iatoolkit/static/images/logo_umayor.png +0 -0
- iatoolkit-0.22.1/src/iatoolkit/static/images/upload.png +0 -0
- iatoolkit-0.22.1/src/iatoolkit/static/js/chat_feedback.js +0 -115
- iatoolkit-0.22.1/src/iatoolkit/static/js/chat_history.js +0 -131
- iatoolkit-0.22.1/src/iatoolkit/static/styles/landing_page.css +0 -168
- iatoolkit-0.22.1/src/iatoolkit/templates/_branding_styles.html +0 -53
- iatoolkit-0.22.1/src/iatoolkit/templates/_navbar.html +0 -9
- iatoolkit-0.22.1/src/iatoolkit/templates/chat.html +0 -204
- iatoolkit-0.22.1/src/iatoolkit/templates/error.html +0 -15
- iatoolkit-0.22.1/src/iatoolkit/templates/home.html +0 -190
- iatoolkit-0.22.1/src/iatoolkit/templates/index.html +0 -134
- iatoolkit-0.22.1/src/iatoolkit/templates/login.html +0 -43
- iatoolkit-0.22.1/src/iatoolkit/templates/onboarding_shell.html +0 -167
- iatoolkit-0.22.1/src/iatoolkit/views/chat_token_request_view.py +0 -98
- iatoolkit-0.22.1/src/iatoolkit/views/download_file_view.py +0 -58
- iatoolkit-0.22.1/src/iatoolkit/views/external_login_view.py +0 -154
- iatoolkit-0.22.1/src/iatoolkit/views/history_view.py +0 -57
- iatoolkit-0.22.1/src/iatoolkit/views/home_view.py +0 -34
- iatoolkit-0.22.1/src/iatoolkit/views/index_view.py +0 -43
- iatoolkit-0.22.1/src/iatoolkit/views/init_context_view.py +0 -35
- iatoolkit-0.22.1/src/iatoolkit/views/llmquery_view.py +0 -65
- iatoolkit-0.22.1/src/iatoolkit/views/login_view.py +0 -136
- iatoolkit-0.22.1/src/iatoolkit/views/tasks_review_view.py +0 -83
- {iatoolkit-0.22.1 → iatoolkit-0.64.1}/readme.md +0 -0
- {iatoolkit-0.22.1 → iatoolkit-0.64.1}/requirements.txt +0 -0
- {iatoolkit-0.22.1 → iatoolkit-0.64.1}/setup.cfg +0 -0
- {iatoolkit-0.22.1 → iatoolkit-0.64.1}/src/iatoolkit/__init__.py +0 -0
- {iatoolkit-0.22.1 → iatoolkit-0.64.1}/src/iatoolkit/cli_commands.py +0 -0
- {iatoolkit-0.22.1 → iatoolkit-0.64.1}/src/iatoolkit/common/__init__.py +0 -0
- {iatoolkit-0.22.1 → iatoolkit-0.64.1}/src/iatoolkit/common/exceptions.py +0 -0
- {iatoolkit-0.22.1 → iatoolkit-0.64.1}/src/iatoolkit/company_registry.py +0 -0
- {iatoolkit-0.22.1 → iatoolkit-0.64.1}/src/iatoolkit/infra/__init__.py +0 -0
- {iatoolkit-0.22.1 → iatoolkit-0.64.1}/src/iatoolkit/infra/call_service.py +0 -0
- {iatoolkit-0.22.1 → iatoolkit-0.64.1}/src/iatoolkit/infra/connectors/__init__.py +0 -0
- {iatoolkit-0.22.1 → iatoolkit-0.64.1}/src/iatoolkit/infra/connectors/file_connector.py +0 -0
- {iatoolkit-0.22.1 → iatoolkit-0.64.1}/src/iatoolkit/infra/connectors/file_connector_factory.py +0 -0
- {iatoolkit-0.22.1 → iatoolkit-0.64.1}/src/iatoolkit/infra/connectors/google_cloud_storage_connector.py +0 -0
- {iatoolkit-0.22.1 → iatoolkit-0.64.1}/src/iatoolkit/infra/connectors/google_drive_connector.py +0 -0
- {iatoolkit-0.22.1 → iatoolkit-0.64.1}/src/iatoolkit/infra/connectors/local_file_connector.py +0 -0
- {iatoolkit-0.22.1 → iatoolkit-0.64.1}/src/iatoolkit/infra/connectors/s3_connector.py +0 -0
- {iatoolkit-0.22.1 → iatoolkit-0.64.1}/src/iatoolkit/infra/gemini_adapter.py +0 -0
- {iatoolkit-0.22.1 → iatoolkit-0.64.1}/src/iatoolkit/infra/google_chat_app.py +0 -0
- {iatoolkit-0.22.1 → iatoolkit-0.64.1}/src/iatoolkit/infra/llm_proxy.py +0 -0
- {iatoolkit-0.22.1 → iatoolkit-0.64.1}/src/iatoolkit/infra/llm_response.py +0 -0
- {iatoolkit-0.22.1 → iatoolkit-0.64.1}/src/iatoolkit/infra/mail_app.py +0 -0
- {iatoolkit-0.22.1 → iatoolkit-0.64.1}/src/iatoolkit/repositories/__init__.py +0 -0
- {iatoolkit-0.22.1 → iatoolkit-0.64.1}/src/iatoolkit/repositories/document_repo.py +0 -0
- {iatoolkit-0.22.1 → iatoolkit-0.64.1}/src/iatoolkit/repositories/llm_query_repo.py +0 -0
- {iatoolkit-0.22.1 → iatoolkit-0.64.1}/src/iatoolkit/repositories/tasks_repo.py +0 -0
- {iatoolkit-0.22.1 → iatoolkit-0.64.1}/src/iatoolkit/repositories/vs_repo.py +0 -0
- {iatoolkit-0.22.1 → iatoolkit-0.64.1}/src/iatoolkit/services/__init__.py +0 -0
- {iatoolkit-0.22.1 → iatoolkit-0.64.1}/src/iatoolkit/services/benchmark_service.py +0 -0
- {iatoolkit-0.22.1 → iatoolkit-0.64.1}/src/iatoolkit/services/document_service.py +0 -0
- {iatoolkit-0.22.1 → iatoolkit-0.64.1}/src/iatoolkit/services/file_processor_service.py +0 -0
- {iatoolkit-0.22.1 → iatoolkit-0.64.1}/src/iatoolkit/services/load_documents_service.py +0 -0
- {iatoolkit-0.22.1 → iatoolkit-0.64.1}/src/iatoolkit/services/mail_service.py +0 -0
- {iatoolkit-0.22.1 → iatoolkit-0.64.1}/src/iatoolkit/services/onboarding_service.py +0 -0
- {iatoolkit-0.22.1 → iatoolkit-0.64.1}/src/iatoolkit/services/prompt_manager_service.py +0 -0
- {iatoolkit-0.22.1 → iatoolkit-0.64.1}/src/iatoolkit/services/search_service.py +0 -0
- {iatoolkit-0.22.1 → iatoolkit-0.64.1}/src/iatoolkit/services/sql_service.py +0 -0
- {iatoolkit-0.22.1 → iatoolkit-0.64.1}/src/iatoolkit/static/js/chat_filepond.js +0 -0
- {iatoolkit-0.22.1 → iatoolkit-0.64.1}/src/iatoolkit/static/styles/chat_info.css +0 -0
- {iatoolkit-0.22.1 → iatoolkit-0.64.1}/src/iatoolkit/static/styles/llm_output.css +0 -0
- {iatoolkit-0.22.1 → iatoolkit-0.64.1}/src/iatoolkit/system_prompts/format_styles.prompt +0 -0
- {iatoolkit-0.22.1 → iatoolkit-0.64.1}/src/iatoolkit/system_prompts/sql_rules.prompt +0 -0
- {iatoolkit-0.22.1 → iatoolkit-0.64.1}/src/iatoolkit/templates/about.html +0 -0
- {iatoolkit-0.22.1 → iatoolkit-0.64.1}/src/iatoolkit/templates/header.html +0 -0
- {iatoolkit-0.22.1 → iatoolkit-0.64.1}/src/iatoolkit/templates/test.html +0 -0
- {iatoolkit-0.22.1 → iatoolkit-0.64.1}/src/iatoolkit/views/__init__.py +0 -0
- {iatoolkit-0.22.1 → iatoolkit-0.64.1}/src/iatoolkit.egg-info/dependency_links.txt +0 -0
- {iatoolkit-0.22.1 → iatoolkit-0.64.1}/src/iatoolkit.egg-info/requires.txt +0 -0
- {iatoolkit-0.22.1 → iatoolkit-0.64.1}/src/iatoolkit.egg-info/top_level.txt +0 -0
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: iatoolkit
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.64.1
|
|
4
4
|
Summary: IAToolkit
|
|
5
5
|
Author: Fernando Libedinsky
|
|
6
6
|
License-Expression: MIT
|
|
7
|
-
Requires-Python: >=3.
|
|
7
|
+
Requires-Python: >=3.12
|
|
8
8
|
Description-Content-Type: text/markdown
|
|
9
9
|
Requires-Dist: aiohappyeyeballs==2.4.4
|
|
10
10
|
Requires-Dist: aiohttp==3.11.9
|
|
@@ -4,8 +4,8 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "iatoolkit"
|
|
7
|
-
version = "0.
|
|
8
|
-
requires-python = ">=3.
|
|
7
|
+
version = "0.64.1"
|
|
8
|
+
requires-python = ">=3.12"
|
|
9
9
|
description = "IAToolkit"
|
|
10
10
|
readme = "readme.md"
|
|
11
11
|
license = "MIT"
|
|
@@ -19,7 +19,7 @@ package-dir = {"" = "src"}
|
|
|
19
19
|
|
|
20
20
|
[tool.setuptools.packages.find]
|
|
21
21
|
where = ["src"]
|
|
22
|
-
exclude = ["tests*"]
|
|
22
|
+
exclude = ["tests*", "*/tests*"]
|
|
23
23
|
|
|
24
24
|
|
|
25
25
|
[tool.setuptools.dynamic]
|
|
@@ -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)
|
|
@@ -88,7 +90,7 @@ class BaseCompany(ABC):
|
|
|
88
90
|
|
|
89
91
|
@abstractmethod
|
|
90
92
|
# get context specific for this company
|
|
91
|
-
def get_user_info(self, user_identifier: str) ->
|
|
93
|
+
def get_user_info(self, user_identifier: str) -> dict:
|
|
92
94
|
raise NotImplementedError("La subclase debe implementar el método get_user_info()")
|
|
93
95
|
|
|
94
96
|
@abstractmethod
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
# Copyright (c) 2024 Fernando Libedinsky
|
|
2
|
+
# Product: IAToolkit
|
|
3
|
+
#
|
|
4
|
+
# IAToolkit is open source software.
|
|
5
|
+
|
|
6
|
+
from flask import render_template, redirect, url_for,send_from_directory, current_app, abort
|
|
7
|
+
from flask import jsonify
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
# this function register all the views
|
|
11
|
+
def register_views(injector, app):
|
|
12
|
+
|
|
13
|
+
from iatoolkit.views.index_view import IndexView
|
|
14
|
+
from iatoolkit.views.init_context_api_view import InitContextApiView
|
|
15
|
+
from iatoolkit.views.llmquery_api_view import LLMQueryApiView
|
|
16
|
+
from iatoolkit.views.tasks_api_view import TaskApiView
|
|
17
|
+
from iatoolkit.views.tasks_review_api_view import TaskReviewApiView
|
|
18
|
+
from iatoolkit.views.login_simulation_view import LoginSimulationView
|
|
19
|
+
from iatoolkit.views.signup_view import SignupView
|
|
20
|
+
from iatoolkit.views.verify_user_view import VerifyAccountView
|
|
21
|
+
from iatoolkit.views.forgot_password_view import ForgotPasswordView
|
|
22
|
+
from iatoolkit.views.change_password_view import ChangePasswordView
|
|
23
|
+
from iatoolkit.views.file_store_api_view import FileStoreApiView
|
|
24
|
+
from iatoolkit.views.user_feedback_api_view import UserFeedbackApiView
|
|
25
|
+
from iatoolkit.views.prompt_api_view import PromptApiView
|
|
26
|
+
from iatoolkit.views.history_api_view import HistoryApiView
|
|
27
|
+
from iatoolkit.views.help_content_api_view import HelpContentApiView
|
|
28
|
+
|
|
29
|
+
from iatoolkit.views.login_view import LoginView, FinalizeContextView
|
|
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
|
|
33
|
+
|
|
34
|
+
# iatoolkit home page
|
|
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'))
|
|
39
|
+
|
|
40
|
+
# login for the iatoolkit integrated frontend
|
|
41
|
+
app.add_url_rule('/<company_short_name>/login', view_func=LoginView.as_view('login'))
|
|
42
|
+
|
|
43
|
+
# this is the login for external users
|
|
44
|
+
app.add_url_rule('/<company_short_name>/external_login',
|
|
45
|
+
view_func=ExternalLoginView.as_view('external_login'))
|
|
46
|
+
|
|
47
|
+
# this endpoint is called when onboarding_shell finish the context load
|
|
48
|
+
app.add_url_rule(
|
|
49
|
+
'/<company_short_name>/finalize',
|
|
50
|
+
view_func=FinalizeContextView.as_view('finalize_no_token')
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
app.add_url_rule(
|
|
54
|
+
'/<company_short_name>/finalize/<token>',
|
|
55
|
+
view_func=FinalizeContextView.as_view('finalize_with_token')
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
# logout
|
|
59
|
+
app.add_url_rule('/<company_short_name>/api/logout',
|
|
60
|
+
view_func=LogoutApiView.as_view('logout'))
|
|
61
|
+
|
|
62
|
+
# this endpoint is called by the JS for changing the token for a session
|
|
63
|
+
app.add_url_rule('/<string:company_short_name>/api/redeem_token',
|
|
64
|
+
view_func = RedeemTokenApiView.as_view('redeem_token'))
|
|
65
|
+
|
|
66
|
+
# init (reset) the company context
|
|
67
|
+
app.add_url_rule('/<company_short_name>/api/init-context',
|
|
68
|
+
view_func=InitContextApiView.as_view('init-context'),
|
|
69
|
+
methods=['POST', 'OPTIONS'])
|
|
70
|
+
|
|
71
|
+
# register new user, account verification and forgot password
|
|
72
|
+
app.add_url_rule('/<company_short_name>/signup',view_func=SignupView.as_view('signup'))
|
|
73
|
+
app.add_url_rule('/<company_short_name>/verify/<token>', view_func=VerifyAccountView.as_view('verify_account'))
|
|
74
|
+
app.add_url_rule('/<company_short_name>/forgot-password', view_func=ForgotPasswordView.as_view('forgot_password'))
|
|
75
|
+
app.add_url_rule('/<company_short_name>/change-password/<token>', view_func=ChangePasswordView.as_view('change_password'))
|
|
76
|
+
|
|
77
|
+
# main chat query, used by the JS in the browser (with credentials)
|
|
78
|
+
# can be used also for executing iatoolkit prompts
|
|
79
|
+
app.add_url_rule('/<company_short_name>/api/llm_query', view_func=LLMQueryApiView.as_view('llm_query_api'))
|
|
80
|
+
|
|
81
|
+
# open the promt directory
|
|
82
|
+
app.add_url_rule('/<company_short_name>/api/prompts', view_func=PromptApiView.as_view('prompt'))
|
|
83
|
+
|
|
84
|
+
# toolbar buttons
|
|
85
|
+
app.add_url_rule('/<company_short_name>/api/feedback', view_func=UserFeedbackApiView.as_view('feedback'))
|
|
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'))
|
|
88
|
+
|
|
89
|
+
# tasks management endpoints: create task, and review answer
|
|
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'))
|
|
92
|
+
|
|
93
|
+
# this endpoint is for upload documents into the vector store (api-key)
|
|
94
|
+
app.add_url_rule('/api/load', view_func=FileStoreApiView.as_view('load_api'))
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
@app.route('/download/<path:filename>')
|
|
98
|
+
def download_file(filename):
|
|
99
|
+
"""
|
|
100
|
+
Esta vista sirve un archivo previamente generado desde el directorio
|
|
101
|
+
configurado en IATOOLKIT_DOWNLOAD_DIR.
|
|
102
|
+
"""
|
|
103
|
+
# Valida que la configuración exista
|
|
104
|
+
if 'IATOOLKIT_DOWNLOAD_DIR' not in current_app.config:
|
|
105
|
+
abort(500, "Error de configuración: IATOOLKIT_DOWNLOAD_DIR no está definido.")
|
|
106
|
+
|
|
107
|
+
download_dir = current_app.config['IATOOLKIT_DOWNLOAD_DIR']
|
|
108
|
+
|
|
109
|
+
try:
|
|
110
|
+
return send_from_directory(
|
|
111
|
+
download_dir,
|
|
112
|
+
filename,
|
|
113
|
+
as_attachment=True # Fuerza la descarga en lugar de la visualización
|
|
114
|
+
)
|
|
115
|
+
except FileNotFoundError:
|
|
116
|
+
abort(404)
|
|
117
|
+
|
|
118
|
+
# login testing
|
|
119
|
+
app.add_url_rule('/<company_short_name>/login_test',
|
|
120
|
+
view_func=LoginSimulationView.as_view('login_test'))
|
|
121
|
+
|
|
122
|
+
app.add_url_rule(
|
|
123
|
+
'/about', # URL de la ruta
|
|
124
|
+
view_func=lambda: render_template('about.html'))
|
|
125
|
+
|
|
126
|
+
app.add_url_rule('/version', 'version',
|
|
127
|
+
lambda: jsonify({"iatoolkit_version": current_app.config.get('VERSION', 'N/A')}))
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
# hacer que la raíz '/' vaya al home de iatoolkit
|
|
131
|
+
@app.route('/')
|
|
132
|
+
def root_redirect():
|
|
133
|
+
return redirect(url_for('index'))
|
|
134
|
+
|
|
135
|
+
|
|
@@ -9,7 +9,6 @@ from iatoolkit.common.exceptions import IAToolkitException
|
|
|
9
9
|
from injector import inject
|
|
10
10
|
import os
|
|
11
11
|
from jinja2 import Environment, FileSystemLoader
|
|
12
|
-
from iatoolkit.common.session_manager import SessionManager
|
|
13
12
|
from datetime import datetime, date
|
|
14
13
|
from decimal import Decimal
|
|
15
14
|
import yaml
|
|
@@ -22,30 +21,8 @@ class Utility:
|
|
|
22
21
|
def __init__(self):
|
|
23
22
|
self.encryption_key = os.getenv('FERNET_KEY')
|
|
24
23
|
|
|
25
|
-
@staticmethod
|
|
26
|
-
def resolve_user_identifier(external_user_id: str = None, local_user_id: int = 0) -> tuple[str, bool]:
|
|
27
|
-
"""
|
|
28
|
-
Resuelve un identificador único de usuario desde external_user_id o local_user_id.
|
|
29
|
-
|
|
30
|
-
Lógica:
|
|
31
|
-
- Si external_user_id existe y no está vacío: usar external_user_id
|
|
32
|
-
- Si no, y local_user_id > 0: obtener email de la sesión actual y retornarlo como ID
|
|
33
|
-
- Si ninguno: retornar string vacío
|
|
34
|
-
|
|
35
|
-
"""
|
|
36
|
-
if external_user_id and external_user_id.strip():
|
|
37
|
-
return external_user_id.strip(), False
|
|
38
|
-
elif local_user_id and local_user_id > 0:
|
|
39
|
-
# get the user information from the session
|
|
40
|
-
user_data = SessionManager.get('user')
|
|
41
|
-
if user_data:
|
|
42
|
-
return user_data.get('email', ''), True
|
|
43
|
-
|
|
44
|
-
return "", False
|
|
45
|
-
|
|
46
24
|
def render_prompt_from_template(self,
|
|
47
25
|
template_pathname: str,
|
|
48
|
-
query: str = None,
|
|
49
26
|
client_data: dict = {},
|
|
50
27
|
**kwargs) -> str:
|
|
51
28
|
|
|
@@ -58,8 +35,6 @@ class Utility:
|
|
|
58
35
|
env = Environment(loader=FileSystemLoader(template_dir))
|
|
59
36
|
template = env.get_template(template_file)
|
|
60
37
|
|
|
61
|
-
kwargs["query"] = query
|
|
62
|
-
|
|
63
38
|
# add all the keys in client_data to kwargs
|
|
64
39
|
kwargs.update(client_data)
|
|
65
40
|
|
|
@@ -74,7 +49,6 @@ class Utility:
|
|
|
74
49
|
def render_prompt_from_string(self,
|
|
75
50
|
template_string: str,
|
|
76
51
|
searchpath: str | list[str] = None,
|
|
77
|
-
query: str = None,
|
|
78
52
|
client_data: dict = {},
|
|
79
53
|
**kwargs) -> str:
|
|
80
54
|
"""
|
|
@@ -97,7 +71,6 @@ class Utility:
|
|
|
97
71
|
env = Environment(loader=loader)
|
|
98
72
|
template = env.from_string(template_string)
|
|
99
73
|
|
|
100
|
-
kwargs["query"] = query
|
|
101
74
|
kwargs.update(client_data)
|
|
102
75
|
|
|
103
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,
|
|
19
|
+
from injector import Binder, Injector, singleton
|
|
20
20
|
from importlib.metadata import version as _pkg_version, PackageNotFoundError
|
|
21
21
|
|
|
22
|
-
IATOOLKIT_VERSION = "0.
|
|
22
|
+
IATOOLKIT_VERSION = "0.64.1"
|
|
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
|
|
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
|
|
@@ -155,10 +153,9 @@ class IAToolkit:
|
|
|
155
153
|
|
|
156
154
|
self.app.config.update({
|
|
157
155
|
'VERSION': self.version,
|
|
158
|
-
'SERVER_NAME': domain,
|
|
159
156
|
'SECRET_KEY': self._get_config_value('FLASK_SECRET_KEY', 'iatoolkit-default-secret'),
|
|
160
|
-
'SESSION_COOKIE_SAMESITE': "None"
|
|
161
|
-
'SESSION_COOKIE_SECURE':
|
|
157
|
+
'SESSION_COOKIE_SAMESITE': "None",
|
|
158
|
+
'SESSION_COOKIE_SECURE': True,
|
|
162
159
|
'SESSION_PERMANENT': False,
|
|
163
160
|
'SESSION_USE_SIGNER': True,
|
|
164
161
|
'JWT_SECRET_KEY': self._get_config_value('JWT_SECRET_KEY', 'iatoolkit-jwt-secret'),
|
|
@@ -188,6 +185,15 @@ class IAToolkit:
|
|
|
188
185
|
self.db_manager.create_all()
|
|
189
186
|
logging.info("✅ Base de datos configurada correctamente")
|
|
190
187
|
|
|
188
|
+
@self.app.teardown_appcontext
|
|
189
|
+
def remove_session(exception=None):
|
|
190
|
+
"""
|
|
191
|
+
Flask calls this after each request.
|
|
192
|
+
It ensures the SQLAlchemy session is properly closed
|
|
193
|
+
and the DB connection is returned to the pool.
|
|
194
|
+
"""
|
|
195
|
+
self.db_manager.scoped_session.remove()
|
|
196
|
+
|
|
191
197
|
def _setup_redis_sessions(self):
|
|
192
198
|
redis_url = self._get_config_value('REDIS_URL')
|
|
193
199
|
if not redis_url:
|
|
@@ -218,19 +224,19 @@ class IAToolkit:
|
|
|
218
224
|
|
|
219
225
|
def _setup_cors(self):
|
|
220
226
|
"""🌐 Configura CORS"""
|
|
221
|
-
|
|
227
|
+
from iatoolkit.company_registry import get_company_registry
|
|
228
|
+
|
|
229
|
+
# default CORS origin
|
|
222
230
|
default_origins = [
|
|
223
|
-
"http://localhost:5001",
|
|
224
|
-
"http://127.0.0.1:5001",
|
|
225
231
|
os.getenv('IATOOLKIT_BASE_URL')
|
|
226
232
|
]
|
|
227
233
|
|
|
228
|
-
#
|
|
234
|
+
# Iterate through the registered company names
|
|
229
235
|
extra_origins = []
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
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
|
|
234
240
|
|
|
235
241
|
all_origins = default_origins + extra_origins
|
|
236
242
|
|
|
@@ -245,7 +251,6 @@ class IAToolkit:
|
|
|
245
251
|
|
|
246
252
|
logging.info(f"✅ CORS configurado para: {all_origins}")
|
|
247
253
|
|
|
248
|
-
|
|
249
254
|
def _configure_core_dependencies(self, binder: Binder):
|
|
250
255
|
"""⚙️ Configures all system dependencies."""
|
|
251
256
|
try:
|
|
@@ -257,7 +262,6 @@ class IAToolkit:
|
|
|
257
262
|
self._bind_repositories(binder)
|
|
258
263
|
self._bind_services(binder)
|
|
259
264
|
self._bind_infrastructure(binder)
|
|
260
|
-
self._bind_views(binder)
|
|
261
265
|
|
|
262
266
|
logging.info("✅ Dependencias configuradas correctamente")
|
|
263
267
|
|
|
@@ -309,34 +313,21 @@ class IAToolkit:
|
|
|
309
313
|
binder.bind(Dispatcher, to=Dispatcher)
|
|
310
314
|
binder.bind(BrandingService, to=BrandingService)
|
|
311
315
|
|
|
312
|
-
|
|
313
316
|
def _bind_infrastructure(self, binder: Binder):
|
|
314
317
|
from iatoolkit.infra.llm_client import llmClient
|
|
315
318
|
from iatoolkit.infra.llm_proxy import LLMProxy
|
|
316
319
|
from iatoolkit.infra.google_chat_app import GoogleChatApp
|
|
317
320
|
from iatoolkit.infra.mail_app import MailApp
|
|
318
|
-
from iatoolkit.
|
|
321
|
+
from iatoolkit.services.auth_service import AuthService
|
|
319
322
|
from iatoolkit.common.util import Utility
|
|
320
323
|
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
binder.bind(LLMProxy, to=LLMProxy, scope=singleton)
|
|
324
|
-
binder.bind(llmClient, to=llmClient, scope=singleton)
|
|
324
|
+
binder.bind(LLMProxy, to=LLMProxy)
|
|
325
|
+
binder.bind(llmClient, to=llmClient)
|
|
325
326
|
binder.bind(GoogleChatApp, to=GoogleChatApp)
|
|
326
327
|
binder.bind(MailApp, to=MailApp)
|
|
327
|
-
binder.bind(
|
|
328
|
+
binder.bind(AuthService, to=AuthService)
|
|
328
329
|
binder.bind(Utility, to=Utility)
|
|
329
330
|
|
|
330
|
-
def _bind_views(self, binder: Binder):
|
|
331
|
-
"""Vincula las vistas después de que el injector ha sido creado"""
|
|
332
|
-
from iatoolkit.views.llmquery_view import LLMQueryView
|
|
333
|
-
from iatoolkit.views.home_view import HomeView
|
|
334
|
-
|
|
335
|
-
binder.bind(HomeView, to=HomeView)
|
|
336
|
-
binder.bind(LLMQueryView, to=LLMQueryView)
|
|
337
|
-
|
|
338
|
-
logging.info("✅ Views configuradas correctamente")
|
|
339
|
-
|
|
340
331
|
def _setup_additional_services(self):
|
|
341
332
|
Bcrypt(self.app)
|
|
342
333
|
|
|
@@ -374,15 +365,23 @@ class IAToolkit:
|
|
|
374
365
|
@self.app.context_processor
|
|
375
366
|
def inject_globals():
|
|
376
367
|
from iatoolkit.common.session_manager import SessionManager
|
|
368
|
+
from iatoolkit.services.profile_service import ProfileService
|
|
369
|
+
|
|
370
|
+
profile_service = self._injector.get(ProfileService)
|
|
371
|
+
user_profile = profile_service.get_current_session_info().get('profile', {})
|
|
372
|
+
|
|
377
373
|
return {
|
|
378
374
|
'url_for': url_for,
|
|
379
375
|
'iatoolkit_version': self.version,
|
|
380
376
|
'app_name': 'IAToolkit',
|
|
381
|
-
'
|
|
382
|
-
'
|
|
377
|
+
'user_identifier': SessionManager.get('user_identifier'),
|
|
378
|
+
'company_short_name': SessionManager.get('company_short_name'),
|
|
379
|
+
'user_is_local': user_profile.get('user_is_local'),
|
|
380
|
+
'user_email': user_profile.get('user_email'),
|
|
383
381
|
'iatoolkit_base_url': os.environ.get('IATOOLKIT_BASE_URL', ''),
|
|
384
382
|
}
|
|
385
383
|
|
|
384
|
+
|
|
386
385
|
def _get_default_static_folder(self) -> str:
|
|
387
386
|
try:
|
|
388
387
|
current_dir = os.path.dirname(os.path.abspath(__file__)) # .../src/iatoolkit
|
|
@@ -21,7 +21,7 @@ import tiktoken
|
|
|
21
21
|
from typing import Dict, Optional, List
|
|
22
22
|
from iatoolkit.services.dispatcher_service import Dispatcher
|
|
23
23
|
|
|
24
|
-
CONTEXT_ERROR_MESSAGE = 'Tu consulta supera el límite de contexto,
|
|
24
|
+
CONTEXT_ERROR_MESSAGE = 'Tu consulta supera el límite de contexto, utiliza el boton de recarga de contexto.'
|
|
25
25
|
|
|
26
26
|
class llmClient:
|
|
27
27
|
_llm_clients_cache = {} # class attribute, for the clients cache
|
|
@@ -266,16 +266,14 @@ class llmClient:
|
|
|
266
266
|
def set_company_context(self,
|
|
267
267
|
company: Company,
|
|
268
268
|
company_base_context: str,
|
|
269
|
-
model
|
|
269
|
+
model) -> str:
|
|
270
270
|
|
|
271
|
-
|
|
272
|
-
self.model = model
|
|
273
|
-
logging.info(f"initializing model '{self.model}' with company context: {self.count_tokens(company_base_context)} tokens...")
|
|
271
|
+
logging.info(f"initializing model '{model}' with company context: {self.count_tokens(company_base_context)} tokens...")
|
|
274
272
|
|
|
275
273
|
llm_proxy = self.llm_proxy_factory.create_for_company(company)
|
|
276
274
|
try:
|
|
277
275
|
response = llm_proxy.create_response(
|
|
278
|
-
model=
|
|
276
|
+
model=model,
|
|
279
277
|
input=[{
|
|
280
278
|
"role": "system",
|
|
281
279
|
"content": company_base_context
|
|
@@ -55,7 +55,7 @@ class OpenAIAdapter:
|
|
|
55
55
|
|
|
56
56
|
# En caso de error de contexto
|
|
57
57
|
if "context_length_exceeded" in str(e):
|
|
58
|
-
error_message = 'Tu consulta supera el limite de contexto
|
|
58
|
+
error_message = 'Tu consulta supera el limite de contexto. Reinicia el contexto con el boton de la barra superior.'
|
|
59
59
|
|
|
60
60
|
raise IAToolkitException(IAToolkitException.ErrorType.LLM_ERROR, error_message)
|
|
61
61
|
|
|
@@ -37,9 +37,14 @@ class RedisSessionManager:
|
|
|
37
37
|
return cls._client
|
|
38
38
|
|
|
39
39
|
@classmethod
|
|
40
|
-
def set(cls, key: str, value: str,
|
|
40
|
+
def set(cls, key: str, value: str, **kwargs):
|
|
41
|
+
"""
|
|
42
|
+
Método set flexible que pasa argumentos opcionales (como ex, nx)
|
|
43
|
+
directamente al cliente de redis.
|
|
44
|
+
"""
|
|
41
45
|
client = cls._get_client()
|
|
42
|
-
|
|
46
|
+
# Pasa todos los argumentos de palabra clave adicionales al cliente real
|
|
47
|
+
result = client.set(key, value, **kwargs)
|
|
43
48
|
return result
|
|
44
49
|
|
|
45
50
|
@classmethod
|
|
@@ -49,12 +54,53 @@ class RedisSessionManager:
|
|
|
49
54
|
result = value if value is not None else default
|
|
50
55
|
return result
|
|
51
56
|
|
|
57
|
+
@classmethod
|
|
58
|
+
def hset(cls, key: str, field: str, value: str):
|
|
59
|
+
"""
|
|
60
|
+
Establece un campo en un Hash de Redis.
|
|
61
|
+
"""
|
|
62
|
+
client = cls._get_client()
|
|
63
|
+
return client.hset(key, field, value)
|
|
64
|
+
|
|
65
|
+
@classmethod
|
|
66
|
+
def hget(cls, key: str, field: str):
|
|
67
|
+
"""
|
|
68
|
+
Obtiene el valor de un campo de un Hash de Redis.
|
|
69
|
+
Devuelve None si la clave o el campo no existen.
|
|
70
|
+
"""
|
|
71
|
+
client = cls._get_client()
|
|
72
|
+
return client.hget(key, field)
|
|
73
|
+
|
|
74
|
+
@classmethod
|
|
75
|
+
def hdel(cls, key: str, *fields):
|
|
76
|
+
"""
|
|
77
|
+
Elimina uno o más campos de un Hash de Redis.
|
|
78
|
+
"""
|
|
79
|
+
client = cls._get_client()
|
|
80
|
+
return client.hdel(key, *fields)
|
|
81
|
+
|
|
82
|
+
@classmethod
|
|
83
|
+
def pipeline(cls):
|
|
84
|
+
"""
|
|
85
|
+
Inicia una transacción (pipeline) de Redis.
|
|
86
|
+
"""
|
|
87
|
+
client = cls._get_client()
|
|
88
|
+
return client.pipeline()
|
|
89
|
+
|
|
90
|
+
|
|
52
91
|
@classmethod
|
|
53
92
|
def remove(cls, key: str):
|
|
54
93
|
client = cls._get_client()
|
|
55
94
|
result = client.delete(key)
|
|
56
95
|
return result
|
|
57
96
|
|
|
97
|
+
@classmethod
|
|
98
|
+
def exists(cls, key: str) -> bool:
|
|
99
|
+
"""Verifica si una clave existe en Redis."""
|
|
100
|
+
client = cls._get_client()
|
|
101
|
+
# El comando EXISTS de Redis devuelve un entero (0 o 1). Lo convertimos a booleano.
|
|
102
|
+
return bool(client.exists(key))
|
|
103
|
+
|
|
58
104
|
@classmethod
|
|
59
105
|
def set_json(cls, key: str, value: dict, ex: int = None):
|
|
60
106
|
json_str = json.dumps(value)
|
|
@@ -21,8 +21,23 @@ class DatabaseManager:
|
|
|
21
21
|
:param echo: Si True, habilita logs de SQL.
|
|
22
22
|
"""
|
|
23
23
|
self.url = make_url(database_url)
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
if database_url.startswith('sqlite'): # for tests
|
|
25
|
+
self._engine = create_engine(database_url, echo=False)
|
|
26
|
+
else:
|
|
27
|
+
self._engine = create_engine(
|
|
28
|
+
database_url,
|
|
29
|
+
echo=False,
|
|
30
|
+
pool_size=2, # per worker
|
|
31
|
+
max_overflow=3,
|
|
32
|
+
pool_timeout=30,
|
|
33
|
+
pool_recycle=1800,
|
|
34
|
+
pool_pre_ping=True,
|
|
35
|
+
future=True,
|
|
36
|
+
)
|
|
37
|
+
self.SessionFactory = sessionmaker(bind=self._engine,
|
|
38
|
+
autoflush=False,
|
|
39
|
+
autocommit=False,
|
|
40
|
+
expire_on_commit=False)
|
|
26
41
|
self.scoped_session = scoped_session(self.SessionFactory)
|
|
27
42
|
|
|
28
43
|
# REGISTRAR pgvector para cada nueva conexión solo en postgres
|
|
@@ -3,9 +3,10 @@
|
|
|
3
3
|
#
|
|
4
4
|
# IAToolkit is open source software.
|
|
5
5
|
|
|
6
|
-
from sqlalchemy import Column, Integer, String, DateTime, Enum, Text, JSON, Boolean, ForeignKey, Table
|
|
6
|
+
from sqlalchemy import Column, Integer, BigInteger, String, DateTime, Enum, Text, JSON, Boolean, ForeignKey, Table
|
|
7
7
|
from sqlalchemy.orm import DeclarativeBase
|
|
8
8
|
from sqlalchemy.orm import relationship, class_mapper, declarative_base
|
|
9
|
+
from sqlalchemy.sql import func
|
|
9
10
|
from datetime import datetime
|
|
10
11
|
from pgvector.sqlalchemy import Vector
|
|
11
12
|
from enum import Enum as PyEnum
|
|
@@ -59,7 +60,7 @@ class Company(Base):
|
|
|
59
60
|
|
|
60
61
|
branding = Column(JSON, nullable=True)
|
|
61
62
|
onboarding_cards = Column(JSON, nullable=True)
|
|
62
|
-
parameters = Column(JSON, nullable=True
|
|
63
|
+
parameters = Column(JSON, nullable=True)
|
|
63
64
|
created_at = Column(DateTime, default=datetime.now)
|
|
64
65
|
allow_jwt = Column(Boolean, default=True, nullable=True)
|
|
65
66
|
|
|
@@ -265,8 +266,7 @@ class UserFeedback(Base):
|
|
|
265
266
|
id = Column(Integer, primary_key=True)
|
|
266
267
|
company_id = Column(Integer, ForeignKey('iat_companies.id',
|
|
267
268
|
ondelete='CASCADE'), nullable=False)
|
|
268
|
-
|
|
269
|
-
external_user_id = Column(String(128), default='', nullable=True)
|
|
269
|
+
user_identifier = Column(String(128), default='', nullable=True)
|
|
270
270
|
message = Column(Text, nullable=False)
|
|
271
271
|
rating = Column(Integer, nullable=False)
|
|
272
272
|
created_at = Column(DateTime, default=datetime.now)
|
|
@@ -308,3 +308,27 @@ class Prompt(Base):
|
|
|
308
308
|
|
|
309
309
|
company = relationship("Company", back_populates="prompts")
|
|
310
310
|
category = relationship("PromptCategory", back_populates="prompts")
|
|
311
|
+
|
|
312
|
+
class AccessLog(Base):
|
|
313
|
+
# Modelo ORM para registrar cada intento de acceso a la plataforma.
|
|
314
|
+
__tablename__ = 'iat_access_log'
|
|
315
|
+
|
|
316
|
+
id = Column(BigInteger, primary_key=True)
|
|
317
|
+
|
|
318
|
+
timestamp = Column(DateTime(timezone=True), server_default=func.now(), nullable=False, index=True)
|
|
319
|
+
company_short_name = Column(String(100), nullable=False, index=True)
|
|
320
|
+
user_identifier = Column(String(255), index=True)
|
|
321
|
+
|
|
322
|
+
# Cómo y el Resultado
|
|
323
|
+
auth_type = Column(String(20), nullable=False) # 'local', 'external_api', 'redeem_token', etc.
|
|
324
|
+
outcome = Column(String(10), nullable=False) # 'success' o 'failure'
|
|
325
|
+
reason_code = Column(String(50)) # Causa de fallo, ej: 'INVALID_CREDENTIALS'
|
|
326
|
+
|
|
327
|
+
# Contexto de la Petición
|
|
328
|
+
source_ip = Column(String(45), nullable=False)
|
|
329
|
+
user_agent_hash = Column(String(16)) # Hash corto del User-Agent
|
|
330
|
+
request_path = Column(String(255), nullable=False)
|
|
331
|
+
|
|
332
|
+
def __repr__(self):
|
|
333
|
+
return (f"<AccessLog(id={self.id}, company='{self.company_short_name}', "
|
|
334
|
+
f"user='{self.user_identifier}', outcome='{self.outcome}')>")
|
|
@@ -72,10 +72,14 @@ class ProfileRepo:
|
|
|
72
72
|
def create_company(self, new_company: Company):
|
|
73
73
|
company = self.session.query(Company).filter_by(name=new_company.name).first()
|
|
74
74
|
if company:
|
|
75
|
-
company.parameters
|
|
76
|
-
|
|
77
|
-
company.
|
|
75
|
+
if company.parameters != new_company.parameters:
|
|
76
|
+
company.parameters = new_company.parameters
|
|
77
|
+
if company.branding != new_company.branding:
|
|
78
|
+
company.branding = new_company.branding
|
|
79
|
+
if company.onboarding_cards != new_company.onboarding_cards:
|
|
80
|
+
company.onboarding_cards = new_company.onboarding_cards
|
|
78
81
|
else:
|
|
82
|
+
# Si la compañía no existe, la añade a la sesión.
|
|
79
83
|
self.session.add(new_company)
|
|
80
84
|
company = new_company
|
|
81
85
|
|