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.
- iatoolkit/__init__.py +2 -0
- iatoolkit/base_company.py +2 -19
- iatoolkit/common/routes.py +28 -25
- iatoolkit/common/session_manager.py +2 -0
- iatoolkit/common/util.py +17 -6
- iatoolkit/company_registry.py +1 -2
- iatoolkit/iatoolkit.py +54 -20
- iatoolkit/locales/en.yaml +167 -0
- iatoolkit/locales/es.yaml +163 -0
- iatoolkit/repositories/database_manager.py +3 -3
- iatoolkit/repositories/document_repo.py +1 -1
- iatoolkit/repositories/models.py +3 -4
- iatoolkit/repositories/profile_repo.py +0 -4
- iatoolkit/services/auth_service.py +44 -32
- iatoolkit/services/branding_service.py +35 -27
- iatoolkit/services/configuration_service.py +140 -0
- iatoolkit/services/dispatcher_service.py +20 -18
- iatoolkit/services/document_service.py +5 -2
- iatoolkit/services/excel_service.py +15 -11
- iatoolkit/services/file_processor_service.py +4 -12
- iatoolkit/services/history_service.py +8 -7
- iatoolkit/services/i18n_service.py +104 -0
- iatoolkit/services/jwt_service.py +7 -9
- iatoolkit/services/language_service.py +79 -0
- iatoolkit/services/load_documents_service.py +4 -4
- iatoolkit/services/mail_service.py +9 -4
- iatoolkit/services/onboarding_service.py +10 -4
- iatoolkit/services/profile_service.py +59 -38
- iatoolkit/services/prompt_manager_service.py +20 -16
- iatoolkit/services/query_service.py +15 -14
- iatoolkit/services/sql_service.py +6 -2
- iatoolkit/services/user_feedback_service.py +70 -29
- iatoolkit/static/js/chat_feedback_button.js +80 -0
- iatoolkit/static/js/chat_help_content.js +124 -0
- iatoolkit/static/js/chat_history_button.js +110 -0
- iatoolkit/static/js/chat_logout_button.js +36 -0
- iatoolkit/static/js/chat_main.js +32 -184
- iatoolkit/static/js/{chat_onboarding.js → chat_onboarding_button.js} +0 -1
- iatoolkit/static/js/chat_prompt_manager.js +94 -0
- iatoolkit/static/js/chat_reload_button.js +35 -0
- iatoolkit/static/styles/chat_iatoolkit.css +251 -205
- iatoolkit/static/styles/chat_modal.css +63 -95
- iatoolkit/static/styles/chat_public.css +107 -0
- iatoolkit/static/styles/landing_page.css +121 -167
- iatoolkit/templates/_company_header.html +20 -0
- iatoolkit/templates/_login_widget.html +10 -10
- iatoolkit/templates/base.html +36 -19
- iatoolkit/templates/change_password.html +24 -22
- iatoolkit/templates/chat.html +121 -93
- iatoolkit/templates/chat_modals.html +113 -74
- iatoolkit/templates/error.html +44 -8
- iatoolkit/templates/forgot_password.html +17 -15
- iatoolkit/templates/index.html +66 -81
- iatoolkit/templates/login_simulation.html +16 -5
- iatoolkit/templates/onboarding_shell.html +1 -2
- iatoolkit/templates/signup.html +22 -20
- iatoolkit/views/base_login_view.py +12 -1
- iatoolkit/views/change_password_view.py +50 -33
- iatoolkit/views/external_login_view.py +5 -11
- iatoolkit/views/file_store_api_view.py +7 -9
- iatoolkit/views/forgot_password_view.py +21 -19
- iatoolkit/views/help_content_api_view.py +54 -0
- iatoolkit/views/history_api_view.py +16 -12
- iatoolkit/views/home_view.py +61 -0
- iatoolkit/views/index_view.py +5 -34
- iatoolkit/views/init_context_api_view.py +16 -13
- iatoolkit/views/llmquery_api_view.py +38 -28
- iatoolkit/views/login_simulation_view.py +14 -2
- iatoolkit/views/login_view.py +48 -33
- iatoolkit/views/logout_api_view.py +49 -0
- iatoolkit/views/profile_api_view.py +46 -0
- iatoolkit/views/prompt_api_view.py +8 -8
- iatoolkit/views/signup_view.py +27 -25
- iatoolkit/views/{tasks_view.py → tasks_api_view.py} +10 -36
- iatoolkit/views/tasks_review_api_view.py +55 -0
- iatoolkit/views/user_feedback_api_view.py +21 -32
- iatoolkit/views/verify_user_view.py +33 -26
- {iatoolkit-0.59.1.dist-info → iatoolkit-0.67.0.dist-info}/METADATA +40 -22
- iatoolkit-0.67.0.dist-info/RECORD +120 -0
- iatoolkit-0.67.0.dist-info/licenses/LICENSE +21 -0
- iatoolkit/static/js/chat_context_reload.js +0 -54
- iatoolkit/static/js/chat_feedback.js +0 -115
- iatoolkit/static/js/chat_history.js +0 -127
- iatoolkit/static/styles/chat_info.css +0 -53
- iatoolkit/templates/_branding_styles.html +0 -53
- iatoolkit/templates/_navbar.html +0 -9
- iatoolkit/templates/header.html +0 -31
- iatoolkit/templates/test.html +0 -9
- iatoolkit/views/chat_token_request_view.py +0 -98
- iatoolkit/views/tasks_review_view.py +0 -83
- iatoolkit-0.59.1.dist-info/RECORD +0 -111
- {iatoolkit-0.59.1.dist-info → iatoolkit-0.67.0.dist-info}/WHEEL +0 -0
- {iatoolkit-0.59.1.dist-info → iatoolkit-0.67.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# iatoolkit/views/home_view.py
|
|
2
|
+
from flask import render_template, render_template_string
|
|
3
|
+
from flask.views import MethodView
|
|
4
|
+
from injector import inject
|
|
5
|
+
from iatoolkit.services.profile_service import ProfileService
|
|
6
|
+
from iatoolkit.services.branding_service import BrandingService
|
|
7
|
+
from iatoolkit.services.i18n_service import I18nService
|
|
8
|
+
from iatoolkit.common.util import Utility
|
|
9
|
+
|
|
10
|
+
class HomeView(MethodView):
|
|
11
|
+
"""
|
|
12
|
+
Handles the rendering of the company-specific home page with a login widget.
|
|
13
|
+
If the custom template is not found or fails, it renders an error page.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
@inject
|
|
17
|
+
def __init__(self,
|
|
18
|
+
profile_service: ProfileService,
|
|
19
|
+
branding_service: BrandingService,
|
|
20
|
+
i18n_service: I18nService,
|
|
21
|
+
utility: Utility):
|
|
22
|
+
self.profile_service = profile_service
|
|
23
|
+
self.branding_service = branding_service
|
|
24
|
+
self.i18n_service = i18n_service
|
|
25
|
+
self.util = utility
|
|
26
|
+
|
|
27
|
+
def get(self, company_short_name: str):
|
|
28
|
+
try:
|
|
29
|
+
company = self.profile_service.get_company_by_short_name(company_short_name)
|
|
30
|
+
if not company:
|
|
31
|
+
return render_template('error.html',
|
|
32
|
+
message=self.i18n_service.t('errors.templates.company_not_found')), 404
|
|
33
|
+
|
|
34
|
+
branding_data = self.branding_service.get_company_branding(company)
|
|
35
|
+
home_template = self.util.get_company_template(company_short_name, "home.html")
|
|
36
|
+
|
|
37
|
+
# 2. Verificamos si el archivo de plantilla personalizado no existe.
|
|
38
|
+
if not home_template:
|
|
39
|
+
message = self.i18n_service.t('errors.templates.home_template_not_found', company_name=company_short_name)
|
|
40
|
+
return render_template(
|
|
41
|
+
"error.html",
|
|
42
|
+
company_short_name=company_short_name,
|
|
43
|
+
branding=branding_data,
|
|
44
|
+
message=message
|
|
45
|
+
), 500
|
|
46
|
+
|
|
47
|
+
# 3. Si el archivo existe, intentamos leerlo y renderizarlo.
|
|
48
|
+
return render_template_string(
|
|
49
|
+
home_template,
|
|
50
|
+
company=company,
|
|
51
|
+
company_short_name=company_short_name,
|
|
52
|
+
branding=branding_data,
|
|
53
|
+
)
|
|
54
|
+
except Exception as e:
|
|
55
|
+
message = self.i18n_service.t('errors.templates.processing_error', error=str(e))
|
|
56
|
+
return render_template(
|
|
57
|
+
"error.html",
|
|
58
|
+
company_short_name=company_short_name,
|
|
59
|
+
branding=branding_data,
|
|
60
|
+
message=message
|
|
61
|
+
), 500
|
iatoolkit/views/index_view.py
CHANGED
|
@@ -1,43 +1,14 @@
|
|
|
1
1
|
# iatoolkit/views/index_view.py
|
|
2
2
|
|
|
3
|
-
from flask import render_template,
|
|
3
|
+
from flask import render_template, session
|
|
4
4
|
from flask.views import MethodView
|
|
5
|
-
from injector import inject
|
|
6
|
-
from iatoolkit.services.profile_service import ProfileService
|
|
7
|
-
from iatoolkit.services.branding_service import BrandingService
|
|
8
5
|
|
|
9
6
|
|
|
10
7
|
class IndexView(MethodView):
|
|
11
8
|
"""
|
|
12
|
-
Handles the rendering of the
|
|
9
|
+
Handles the rendering of the generic landing page, which no longer depends
|
|
10
|
+
on a specific company.
|
|
13
11
|
"""
|
|
14
12
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
profile_service: ProfileService,
|
|
18
|
-
branding_service: BrandingService):
|
|
19
|
-
self.profile_service = profile_service
|
|
20
|
-
self.branding_service = branding_service
|
|
21
|
-
|
|
22
|
-
def get(self, company_short_name: str):
|
|
23
|
-
# La vista ahora recibe el company_short_name desde la URL
|
|
24
|
-
company = self.profile_service.get_company_by_short_name(company_short_name)
|
|
25
|
-
|
|
26
|
-
if not company:
|
|
27
|
-
abort(404, description=f"La empresa '{company_short_name}' no fue encontrada.")
|
|
28
|
-
|
|
29
|
-
# Obtenemos los datos de branding para la plantilla
|
|
30
|
-
branding_data = self.branding_service.get_company_branding(company)
|
|
31
|
-
|
|
32
|
-
alert_message = session.pop('alert_message', None)
|
|
33
|
-
alert_icon = session.pop('alert_icon', 'error')
|
|
34
|
-
|
|
35
|
-
# 2. Pasamos las variables a la plantilla. Si no hay mensaje, serán None.
|
|
36
|
-
return render_template(
|
|
37
|
-
'index.html',
|
|
38
|
-
company=company,
|
|
39
|
-
company_short_name=company_short_name,
|
|
40
|
-
branding=branding_data,
|
|
41
|
-
alert_message=alert_message,
|
|
42
|
-
alert_icon=alert_icon
|
|
43
|
-
)
|
|
13
|
+
def get(self):
|
|
14
|
+
return render_template('index.html')
|
|
@@ -3,7 +3,8 @@ from injector import inject
|
|
|
3
3
|
from iatoolkit.services.query_service import QueryService
|
|
4
4
|
from iatoolkit.services.profile_service import ProfileService
|
|
5
5
|
from iatoolkit.services.auth_service import AuthService
|
|
6
|
-
from
|
|
6
|
+
from iatoolkit.services.i18n_service import I18nService
|
|
7
|
+
from flask import jsonify
|
|
7
8
|
import logging
|
|
8
9
|
|
|
9
10
|
|
|
@@ -17,10 +18,12 @@ class InitContextApiView(MethodView):
|
|
|
17
18
|
def __init__(self,
|
|
18
19
|
auth_service: AuthService,
|
|
19
20
|
query_service: QueryService,
|
|
20
|
-
profile_service: ProfileService
|
|
21
|
+
profile_service: ProfileService,
|
|
22
|
+
i18n_service: I18nService):
|
|
21
23
|
self.auth_service = auth_service
|
|
22
24
|
self.query_service = query_service
|
|
23
25
|
self.profile_service = profile_service
|
|
26
|
+
self.i18n_service = i18n_service
|
|
24
27
|
|
|
25
28
|
def post(self, company_short_name: str):
|
|
26
29
|
"""
|
|
@@ -28,16 +31,14 @@ class InitContextApiView(MethodView):
|
|
|
28
31
|
an active web session or by the external_user_id in the JSON payload
|
|
29
32
|
for API calls.
|
|
30
33
|
"""
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
34
|
+
try:
|
|
35
|
+
# 1. Authenticate the request. This handles both session and API Key.
|
|
36
|
+
auth_result = self.auth_service.verify()
|
|
37
|
+
if not auth_result.get("success"):
|
|
38
|
+
return jsonify(auth_result), auth_result.get("status_code")
|
|
35
39
|
|
|
36
|
-
|
|
37
|
-
if not user_identifier:
|
|
38
|
-
return jsonify({"error": "Could not identify user from session or payload"}), 400
|
|
40
|
+
user_identifier = auth_result.get('user_identifier')
|
|
39
41
|
|
|
40
|
-
try:
|
|
41
42
|
# 2. Execute the forced rebuild sequence using the unified identifier.
|
|
42
43
|
self.query_service.session_context.clear_all_context(company_short_name, user_identifier)
|
|
43
44
|
logging.info(f"Context for {company_short_name}/{user_identifier} has been cleared.")
|
|
@@ -54,11 +55,13 @@ class InitContextApiView(MethodView):
|
|
|
54
55
|
)
|
|
55
56
|
|
|
56
57
|
# 3. Respond with JSON, as this is an API endpoint.
|
|
57
|
-
|
|
58
|
+
success_message = self.i18n_service.t('api_responses.context_reloaded_success')
|
|
59
|
+
return jsonify({'status': 'OK', 'message': success_message}), 200
|
|
58
60
|
|
|
59
61
|
except Exception as e:
|
|
60
|
-
logging.exception(f"
|
|
61
|
-
|
|
62
|
+
logging.exception(f"errors while reloading context: {e}")
|
|
63
|
+
error_message = self.i18n_service.t('errors.general.unexpected_error', error=str(e))
|
|
64
|
+
return jsonify({"error_message": error_message}), 500
|
|
62
65
|
|
|
63
66
|
def options(self, company_short_name):
|
|
64
67
|
"""
|
|
@@ -4,6 +4,7 @@ from injector import inject
|
|
|
4
4
|
from iatoolkit.services.query_service import QueryService
|
|
5
5
|
from iatoolkit.services.auth_service import AuthService
|
|
6
6
|
from iatoolkit.services.profile_service import ProfileService
|
|
7
|
+
from iatoolkit.services.i18n_service import I18nService
|
|
7
8
|
import logging
|
|
8
9
|
|
|
9
10
|
class LLMQueryApiView(MethodView):
|
|
@@ -12,36 +13,45 @@ class LLMQueryApiView(MethodView):
|
|
|
12
13
|
"""
|
|
13
14
|
|
|
14
15
|
@inject
|
|
15
|
-
def __init__(self,
|
|
16
|
+
def __init__(self,
|
|
17
|
+
auth_service: AuthService,
|
|
18
|
+
query_service: QueryService,
|
|
19
|
+
profile_service: ProfileService,
|
|
20
|
+
i18n_service: I18nService):
|
|
16
21
|
self.auth_service = auth_service
|
|
17
22
|
self.query_service = query_service
|
|
18
23
|
self.profile_service = profile_service
|
|
24
|
+
self.i18n_service = i18n_service
|
|
19
25
|
|
|
20
26
|
def post(self, company_short_name: str):
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
27
|
+
try:
|
|
28
|
+
# 1. Authenticate the API request.
|
|
29
|
+
auth_result = self.auth_service.verify()
|
|
30
|
+
if not auth_result.get("success"):
|
|
31
|
+
return jsonify(auth_result), auth_result.get("status_code")
|
|
32
|
+
|
|
33
|
+
# 2. Get the user identifier from the payload.
|
|
34
|
+
user_identifier = auth_result.get('user_identifier')
|
|
35
|
+
|
|
36
|
+
data = request.get_json()
|
|
37
|
+
if not data:
|
|
38
|
+
return jsonify({"error": "Invalid JSON body"}), 400
|
|
39
|
+
|
|
40
|
+
# 4. Call the unified query service method.
|
|
41
|
+
result = self.query_service.llm_query(
|
|
42
|
+
company_short_name=company_short_name,
|
|
43
|
+
user_identifier=user_identifier,
|
|
44
|
+
question=data.get('question', ''),
|
|
45
|
+
prompt_name=data.get('prompt_name'),
|
|
46
|
+
client_data=data.get('client_data', {}),
|
|
47
|
+
files=data.get('files', [])
|
|
48
|
+
)
|
|
49
|
+
if 'error' in result:
|
|
50
|
+
return jsonify(result), 400
|
|
51
|
+
|
|
52
|
+
return jsonify(result), 200
|
|
53
|
+
|
|
54
|
+
except Exception as e:
|
|
55
|
+
logging.exception(
|
|
56
|
+
f"Unexpected error: {e}")
|
|
57
|
+
return jsonify({"error_message": self.i18n_service.t('errors.general.unexpected_error', error=str(e))}), 500
|
|
@@ -10,17 +10,29 @@ from flask.views import MethodView
|
|
|
10
10
|
from flask import render_template, request, Response
|
|
11
11
|
from injector import inject
|
|
12
12
|
from iatoolkit.services.profile_service import ProfileService
|
|
13
|
+
from iatoolkit.services.branding_service import BrandingService
|
|
13
14
|
|
|
14
15
|
|
|
15
16
|
class LoginSimulationView(MethodView):
|
|
16
17
|
@inject
|
|
17
18
|
def __init__(self,
|
|
18
|
-
profile_service: ProfileService
|
|
19
|
+
profile_service: ProfileService,
|
|
20
|
+
branding_service: BrandingService):
|
|
19
21
|
self.profile_service = profile_service
|
|
22
|
+
self.branding_service = branding_service
|
|
23
|
+
|
|
20
24
|
|
|
21
25
|
def get(self, company_short_name: str = None):
|
|
22
|
-
|
|
26
|
+
company = self.profile_service.get_company_by_short_name(company_short_name)
|
|
27
|
+
if not company:
|
|
28
|
+
return render_template('error.html',
|
|
29
|
+
company_short_name=company_short_name,
|
|
30
|
+
message="Empresa no encontrada"), 404
|
|
31
|
+
|
|
32
|
+
branding_data = self.branding_service.get_company_branding(company)
|
|
33
|
+
|
|
23
34
|
return render_template('login_simulation.html',
|
|
35
|
+
branding=branding_data,
|
|
24
36
|
company_short_name=company_short_name
|
|
25
37
|
)
|
|
26
38
|
|
iatoolkit/views/login_view.py
CHANGED
|
@@ -4,15 +4,16 @@
|
|
|
4
4
|
# IAToolkit is open source software.
|
|
5
5
|
|
|
6
6
|
from flask.views import MethodView
|
|
7
|
-
from flask import request, redirect, render_template, url_for
|
|
7
|
+
from flask import (request, redirect, render_template, url_for,
|
|
8
|
+
render_template_string, flash)
|
|
8
9
|
from injector import inject
|
|
9
10
|
from iatoolkit.services.profile_service import ProfileService
|
|
10
|
-
from iatoolkit.services.auth_service import AuthService
|
|
11
11
|
from iatoolkit.services.jwt_service import JWTService
|
|
12
12
|
from iatoolkit.services.query_service import QueryService
|
|
13
13
|
from iatoolkit.services.prompt_manager_service import PromptService
|
|
14
14
|
from iatoolkit.services.branding_service import BrandingService
|
|
15
15
|
from iatoolkit.services.onboarding_service import OnboardingService
|
|
16
|
+
from iatoolkit.services.i18n_service import I18nService
|
|
16
17
|
from iatoolkit.views.base_login_view import BaseLoginView
|
|
17
18
|
import logging
|
|
18
19
|
|
|
@@ -25,8 +26,10 @@ class LoginView(BaseLoginView):
|
|
|
25
26
|
def post(self, company_short_name: str):
|
|
26
27
|
company = self.profile_service.get_company_by_short_name(company_short_name)
|
|
27
28
|
if not company:
|
|
28
|
-
return render_template('error.html',
|
|
29
|
+
return render_template('error.html',
|
|
30
|
+
message=self.i18n_service.t('errors.templates.company_not_found')), 404
|
|
29
31
|
|
|
32
|
+
branding_data = self.branding_service.get_company_branding(company)
|
|
30
33
|
email = request.form.get('email')
|
|
31
34
|
password = request.form.get('password')
|
|
32
35
|
|
|
@@ -38,15 +41,15 @@ class LoginView(BaseLoginView):
|
|
|
38
41
|
)
|
|
39
42
|
|
|
40
43
|
if not auth_response['success']:
|
|
41
|
-
|
|
44
|
+
flash(auth_response["message"], 'error')
|
|
45
|
+
home_template = self.utility.get_company_template(company_short_name, "home.html")
|
|
42
46
|
|
|
43
|
-
return
|
|
44
|
-
|
|
47
|
+
return render_template_string(
|
|
48
|
+
home_template,
|
|
45
49
|
company_short_name=company_short_name,
|
|
46
50
|
company=company,
|
|
47
51
|
branding=branding_data,
|
|
48
52
|
form_data={"email": email},
|
|
49
|
-
alert_message=auth_response["message"]
|
|
50
53
|
), 400
|
|
51
54
|
|
|
52
55
|
user_identifier = auth_response['user_identifier']
|
|
@@ -60,8 +63,13 @@ class LoginView(BaseLoginView):
|
|
|
60
63
|
try:
|
|
61
64
|
return self._handle_login_path(company, user_identifier, target_url)
|
|
62
65
|
except Exception as e:
|
|
63
|
-
|
|
64
|
-
|
|
66
|
+
message = self.i18n_service.t('errors.templates.processing_error', error=str(e))
|
|
67
|
+
return render_template(
|
|
68
|
+
"error.html",
|
|
69
|
+
company_short_name=company_short_name,
|
|
70
|
+
branding=branding_data,
|
|
71
|
+
message=message
|
|
72
|
+
), 500
|
|
65
73
|
|
|
66
74
|
|
|
67
75
|
class FinalizeContextView(MethodView):
|
|
@@ -72,12 +80,12 @@ class FinalizeContextView(MethodView):
|
|
|
72
80
|
@inject
|
|
73
81
|
def __init__(self,
|
|
74
82
|
profile_service: ProfileService,
|
|
75
|
-
auth_service: AuthService,
|
|
76
83
|
query_service: QueryService,
|
|
77
84
|
prompt_service: PromptService,
|
|
78
85
|
branding_service: BrandingService,
|
|
79
86
|
onboarding_service: OnboardingService,
|
|
80
87
|
jwt_service: JWTService,
|
|
88
|
+
i18n_service: I18nService
|
|
81
89
|
):
|
|
82
90
|
self.profile_service = profile_service
|
|
83
91
|
self.jwt_service = jwt_service
|
|
@@ -85,30 +93,34 @@ class FinalizeContextView(MethodView):
|
|
|
85
93
|
self.prompt_service = prompt_service
|
|
86
94
|
self.branding_service = branding_service
|
|
87
95
|
self.onboarding_service = onboarding_service
|
|
96
|
+
self.i18n_service = i18n_service
|
|
88
97
|
|
|
89
98
|
def get(self, company_short_name: str, token: str = None):
|
|
90
|
-
session_info = self.profile_service.get_current_session_info()
|
|
91
|
-
if session_info:
|
|
92
|
-
# session exists, internal user
|
|
93
|
-
user_identifier = session_info.get('user_identifier')
|
|
94
|
-
token = ''
|
|
95
|
-
elif token:
|
|
96
|
-
# user identified by api-key
|
|
97
|
-
payload = self.jwt_service.validate_chat_jwt(token)
|
|
98
|
-
if not payload:
|
|
99
|
-
logging.warning("Fallo crítico: No se pudo leer el auth token.")
|
|
100
|
-
return redirect(url_for('index', company_short_name=company_short_name))
|
|
101
|
-
|
|
102
|
-
user_identifier = payload.get('user_identifier')
|
|
103
|
-
else:
|
|
104
|
-
logging.warning("Fallo crítico: missing session information or auth token")
|
|
105
|
-
return redirect(url_for('index', company_short_name=company_short_name))
|
|
106
|
-
|
|
107
|
-
company = self.profile_service.get_company_by_short_name(company_short_name)
|
|
108
|
-
if not company:
|
|
109
|
-
return render_template('error.html', message="Empresa no encontrada"), 404
|
|
110
|
-
|
|
111
99
|
try:
|
|
100
|
+
session_info = self.profile_service.get_current_session_info()
|
|
101
|
+
if session_info:
|
|
102
|
+
# session exists, internal user
|
|
103
|
+
user_identifier = session_info.get('user_identifier')
|
|
104
|
+
token = ''
|
|
105
|
+
elif token:
|
|
106
|
+
# user identified by api-key
|
|
107
|
+
payload = self.jwt_service.validate_chat_jwt(token)
|
|
108
|
+
if not payload:
|
|
109
|
+
logging.warning("Fallo crítico: No se pudo leer el auth token.")
|
|
110
|
+
return redirect(url_for('home', company_short_name=company_short_name))
|
|
111
|
+
|
|
112
|
+
user_identifier = payload.get('user_identifier')
|
|
113
|
+
else:
|
|
114
|
+
logging.warning("Fallo crítico: missing session information or auth token")
|
|
115
|
+
return redirect(url_for('home', company_short_name=company_short_name))
|
|
116
|
+
|
|
117
|
+
company = self.profile_service.get_company_by_short_name(company_short_name)
|
|
118
|
+
if not company:
|
|
119
|
+
return render_template('error.html',
|
|
120
|
+
company_short_name=company_short_name,
|
|
121
|
+
message="Empresa no encontrada"), 404
|
|
122
|
+
branding_data = self.branding_service.get_company_branding(company)
|
|
123
|
+
|
|
112
124
|
# 2. Finalize the context rebuild (the heavy task).
|
|
113
125
|
self.query_service.finalize_context_rebuild(
|
|
114
126
|
company_short_name=company_short_name,
|
|
@@ -117,9 +129,11 @@ class FinalizeContextView(MethodView):
|
|
|
117
129
|
|
|
118
130
|
# 3. render the chat page.
|
|
119
131
|
prompts = self.prompt_service.get_user_prompts(company_short_name)
|
|
120
|
-
branding_data = self.branding_service.get_company_branding(company)
|
|
121
132
|
onboarding_cards = self.onboarding_service.get_onboarding_cards(company)
|
|
122
133
|
|
|
134
|
+
# Get the entire 'js_messages' block in the correct language.
|
|
135
|
+
js_translations = self.i18n_service.get_translation_block('js_messages')
|
|
136
|
+
|
|
123
137
|
return render_template(
|
|
124
138
|
"chat.html",
|
|
125
139
|
company_short_name=company_short_name,
|
|
@@ -127,12 +141,13 @@ class FinalizeContextView(MethodView):
|
|
|
127
141
|
branding=branding_data,
|
|
128
142
|
prompts=prompts,
|
|
129
143
|
onboarding_cards=onboarding_cards,
|
|
144
|
+
js_translations=js_translations,
|
|
130
145
|
redeem_token=token
|
|
131
146
|
)
|
|
132
147
|
|
|
133
148
|
except Exception as e:
|
|
134
149
|
return render_template("error.html",
|
|
135
|
-
company=company,
|
|
136
150
|
company_short_name=company_short_name,
|
|
151
|
+
branding=branding_data,
|
|
137
152
|
message=f"An unexpected error occurred during context loading: {str(e)}"), 500
|
|
138
153
|
|
|
@@ -0,0 +1,49 @@
|
|
|
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 redirect, url_for, jsonify
|
|
8
|
+
from injector import inject
|
|
9
|
+
from iatoolkit.services.auth_service import AuthService
|
|
10
|
+
from iatoolkit.services.profile_service import ProfileService
|
|
11
|
+
from iatoolkit.common.session_manager import SessionManager
|
|
12
|
+
import logging
|
|
13
|
+
|
|
14
|
+
class LogoutApiView(MethodView):
|
|
15
|
+
@inject
|
|
16
|
+
def __init__(self,
|
|
17
|
+
profile_service: ProfileService,
|
|
18
|
+
auth_service: AuthService):
|
|
19
|
+
self.profile_service = profile_service
|
|
20
|
+
self.auth_service = auth_service
|
|
21
|
+
|
|
22
|
+
def get(self, company_short_name: str = None):
|
|
23
|
+
try:
|
|
24
|
+
# 1. Get the authenticated user's
|
|
25
|
+
auth_result = self.auth_service.verify(anonymous=True)
|
|
26
|
+
if not auth_result.get("success"):
|
|
27
|
+
return jsonify(auth_result), auth_result.get("status_code", 401)
|
|
28
|
+
|
|
29
|
+
company = self.profile_service.get_company_by_short_name(company_short_name)
|
|
30
|
+
if not company:
|
|
31
|
+
return jsonify({"error": "company not found."}), 404
|
|
32
|
+
|
|
33
|
+
# get URL for redirection
|
|
34
|
+
url_for_redirect = company.parameters.get('external_urls', {}).get('logout_url')
|
|
35
|
+
if not url_for_redirect:
|
|
36
|
+
url_for_redirect = url_for('home', company_short_name=company_short_name)
|
|
37
|
+
|
|
38
|
+
# clear de session cookie
|
|
39
|
+
SessionManager.clear()
|
|
40
|
+
|
|
41
|
+
return {
|
|
42
|
+
'status': 'success',
|
|
43
|
+
'url': url_for_redirect,
|
|
44
|
+
}, 200
|
|
45
|
+
except Exception as e:
|
|
46
|
+
logging.exception(f"Unexpected error: {e}")
|
|
47
|
+
return {'status': 'error'}, 500
|
|
48
|
+
|
|
49
|
+
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# iatoolkit/views/profile_api_view.py
|
|
2
|
+
from flask import request, jsonify
|
|
3
|
+
from flask.views import MethodView
|
|
4
|
+
from injector import inject
|
|
5
|
+
from iatoolkit.services.auth_service import AuthService
|
|
6
|
+
from iatoolkit.services.profile_service import ProfileService
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class UserLanguageApiView(MethodView):
|
|
10
|
+
"""
|
|
11
|
+
API endpoint for managing user language preferences.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
@inject
|
|
15
|
+
def __init__(self,
|
|
16
|
+
auth_service: AuthService,
|
|
17
|
+
profile_service: ProfileService):
|
|
18
|
+
self.auth_service = auth_service
|
|
19
|
+
self.profile_service = profile_service
|
|
20
|
+
|
|
21
|
+
def post(self):
|
|
22
|
+
"""
|
|
23
|
+
Handles POST requests to update the user's preferred language.
|
|
24
|
+
Expects a JSON body with a 'language' key, e.g., {"language": "en"}.
|
|
25
|
+
"""
|
|
26
|
+
# 1. Authenticate the user from the current session.
|
|
27
|
+
auth_result = self.auth_service.verify()
|
|
28
|
+
if not auth_result.get("success"):
|
|
29
|
+
return jsonify(auth_result), auth_result.get("status_code")
|
|
30
|
+
|
|
31
|
+
user_identifier = auth_result.get('user_identifier')
|
|
32
|
+
|
|
33
|
+
# 2. Validate request body
|
|
34
|
+
data = request.get_json()
|
|
35
|
+
if not data or 'language' not in data:
|
|
36
|
+
return jsonify({"error_message": "Missing 'language' field in request body"}), 400
|
|
37
|
+
|
|
38
|
+
new_lang = data.get('language')
|
|
39
|
+
|
|
40
|
+
# 3. Call the service to perform the update
|
|
41
|
+
update_result = self.profile_service.update_user_language(user_identifier, new_lang)
|
|
42
|
+
|
|
43
|
+
if not update_result.get('success'):
|
|
44
|
+
return jsonify(update_result), 400
|
|
45
|
+
|
|
46
|
+
return jsonify({"message": "Language preference updated successfully"}), 200
|
|
@@ -14,18 +14,18 @@ import logging
|
|
|
14
14
|
class PromptApiView(MethodView):
|
|
15
15
|
@inject
|
|
16
16
|
def __init__(self,
|
|
17
|
-
|
|
17
|
+
auth_service: AuthService,
|
|
18
18
|
prompt_service: PromptService ):
|
|
19
|
-
self.
|
|
19
|
+
self.auth_service = auth_service
|
|
20
20
|
self.prompt_service = prompt_service
|
|
21
21
|
|
|
22
22
|
def get(self, company_short_name):
|
|
23
|
-
# get access credentials
|
|
24
|
-
iaut = self.iauthentication.verify()
|
|
25
|
-
if not iaut.get("success"):
|
|
26
|
-
return jsonify(iaut), 401
|
|
27
|
-
|
|
28
23
|
try:
|
|
24
|
+
# get access credentials
|
|
25
|
+
auth_result = self.auth_service.verify(anonymous=True)
|
|
26
|
+
if not auth_result.get("success"):
|
|
27
|
+
return jsonify(auth_result), auth_result.get('status_code')
|
|
28
|
+
|
|
29
29
|
response = self.prompt_service.get_user_prompts(company_short_name)
|
|
30
30
|
if "error" in response:
|
|
31
31
|
return {'error_message': response["error"]}, 402
|
|
@@ -33,5 +33,5 @@ class PromptApiView(MethodView):
|
|
|
33
33
|
return response, 200
|
|
34
34
|
except Exception as e:
|
|
35
35
|
logging.exception(
|
|
36
|
-
f"
|
|
36
|
+
f"unexpected error getting company prompts: {e}")
|
|
37
37
|
return jsonify({"error_message": str(e)}), 500
|