iatoolkit 0.59.1__py3-none-any.whl → 0.60.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/base_company.py +3 -1
- iatoolkit/common/routes.py +12 -21
- iatoolkit/iatoolkit.py +5 -5
- iatoolkit/repositories/models.py +1 -1
- iatoolkit/services/auth_service.py +32 -25
- iatoolkit/services/profile_service.py +1 -0
- iatoolkit/services/user_feedback_service.py +65 -26
- iatoolkit/static/js/{chat_feedback.js → chat_feedback_button.js} +5 -10
- iatoolkit/static/js/chat_main.js +0 -8
- iatoolkit/static/js/{chat_onboarding.js → chat_onboarding_button.js} +0 -1
- iatoolkit/static/js/{chat_context_reload.js → chat_reload_button.js} +2 -4
- iatoolkit/static/styles/chat_iatoolkit.css +44 -0
- iatoolkit/templates/chat.html +18 -10
- iatoolkit/templates/onboarding_shell.html +1 -1
- iatoolkit/views/change_password_view.py +2 -2
- iatoolkit/views/external_login_view.py +5 -11
- iatoolkit/views/file_store_api_view.py +7 -9
- iatoolkit/views/history_api_view.py +8 -8
- iatoolkit/views/init_context_api_view.py +2 -4
- iatoolkit/views/llmquery_api_view.py +1 -3
- iatoolkit/views/logout_api_view.py +45 -0
- iatoolkit/views/prompt_api_view.py +5 -5
- 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 +6 -18
- {iatoolkit-0.59.1.dist-info → iatoolkit-0.60.0.dist-info}/METADATA +1 -1
- {iatoolkit-0.59.1.dist-info → iatoolkit-0.60.0.dist-info}/RECORD +30 -30
- iatoolkit/views/chat_token_request_view.py +0 -98
- iatoolkit/views/tasks_review_view.py +0 -83
- /iatoolkit/static/js/{chat_history.js → chat_history_button.js} +0 -0
- {iatoolkit-0.59.1.dist-info → iatoolkit-0.60.0.dist-info}/WHEEL +0 -0
- {iatoolkit-0.59.1.dist-info → iatoolkit-0.60.0.dist-info}/top_level.txt +0 -0
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
from flask import request, jsonify
|
|
7
7
|
from flask.views import MethodView
|
|
8
8
|
from iatoolkit.services.history_service import HistoryService
|
|
9
|
-
from iatoolkit.services.
|
|
9
|
+
from iatoolkit.services.auth_service import AuthService
|
|
10
10
|
from injector import inject
|
|
11
11
|
import logging
|
|
12
12
|
|
|
@@ -19,18 +19,18 @@ class HistoryApiView(MethodView):
|
|
|
19
19
|
|
|
20
20
|
@inject
|
|
21
21
|
def __init__(self,
|
|
22
|
-
|
|
22
|
+
auth_service: AuthService,
|
|
23
23
|
history_service: HistoryService):
|
|
24
|
-
self.
|
|
24
|
+
self.auth_service = auth_service
|
|
25
25
|
self.history_service = history_service
|
|
26
26
|
|
|
27
27
|
def post(self, company_short_name: str):
|
|
28
|
-
# 1. Get the authenticated user's
|
|
29
|
-
|
|
30
|
-
|
|
28
|
+
# 1. Get the authenticated user's
|
|
29
|
+
auth_result = self.auth_service.verify()
|
|
30
|
+
if not auth_result.get("success"):
|
|
31
|
+
return jsonify(auth_result), auth_result.get("status_code")
|
|
31
32
|
|
|
32
|
-
|
|
33
|
-
return jsonify({'error_message': 'Usuario no autenticado o sesión inválida'}), 401
|
|
33
|
+
user_identifier = auth_result.get('user_identifier')
|
|
34
34
|
|
|
35
35
|
try:
|
|
36
36
|
# 2. Call the history service with the unified identifier.
|
|
@@ -31,11 +31,9 @@ class InitContextApiView(MethodView):
|
|
|
31
31
|
# 1. Authenticate the request. This handles both session and API Key.
|
|
32
32
|
auth_result = self.auth_service.verify()
|
|
33
33
|
if not auth_result.get("success"):
|
|
34
|
-
return jsonify(
|
|
34
|
+
return jsonify(auth_result), auth_result.get("status_code")
|
|
35
35
|
|
|
36
36
|
user_identifier = auth_result.get('user_identifier')
|
|
37
|
-
if not user_identifier:
|
|
38
|
-
return jsonify({"error": "Could not identify user from session or payload"}), 400
|
|
39
37
|
|
|
40
38
|
try:
|
|
41
39
|
# 2. Execute the forced rebuild sequence using the unified identifier.
|
|
@@ -54,7 +52,7 @@ class InitContextApiView(MethodView):
|
|
|
54
52
|
)
|
|
55
53
|
|
|
56
54
|
# 3. Respond with JSON, as this is an API endpoint.
|
|
57
|
-
return jsonify({'status': 'OK', 'message': 'El
|
|
55
|
+
return jsonify({'status': 'OK', 'message': 'El contexto se ha recargado con éxito.'}), 200
|
|
58
56
|
|
|
59
57
|
except Exception as e:
|
|
60
58
|
logging.exception(f"Error durante la recarga de contexto {user_identifier}: {e}")
|
|
@@ -21,12 +21,10 @@ class LLMQueryApiView(MethodView):
|
|
|
21
21
|
# 1. Authenticate the API request.
|
|
22
22
|
auth_result = self.auth_service.verify()
|
|
23
23
|
if not auth_result.get("success"):
|
|
24
|
-
return jsonify(
|
|
24
|
+
return jsonify(auth_result), auth_result.get("status_code")
|
|
25
25
|
|
|
26
26
|
# 2. Get the user identifier from the payload.
|
|
27
27
|
user_identifier = auth_result.get('user_identifier')
|
|
28
|
-
if not user_identifier:
|
|
29
|
-
return jsonify({"error": "Payload must include 'user_identifier'"}), 400
|
|
30
28
|
|
|
31
29
|
data = request.get_json()
|
|
32
30
|
if not data:
|
|
@@ -0,0 +1,45 @@
|
|
|
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
|
+
|
|
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
|
+
# 1. Get the authenticated user's
|
|
24
|
+
auth_result = self.auth_service.verify(anonymous=True)
|
|
25
|
+
if not auth_result.get("success"):
|
|
26
|
+
return jsonify(auth_result), auth_result.get("status_code", 401)
|
|
27
|
+
|
|
28
|
+
company = self.profile_service.get_company_by_short_name(company_short_name)
|
|
29
|
+
if not company:
|
|
30
|
+
return jsonify({"error": "Empresa no encontrada"}), 404
|
|
31
|
+
|
|
32
|
+
# get URL for redirection
|
|
33
|
+
url_for_redirect = company.parameters.get('external_urls', {}).get('logout_url')
|
|
34
|
+
if not url_for_redirect:
|
|
35
|
+
url_for_redirect = url_for('index', company_short_name=company_short_name)
|
|
36
|
+
|
|
37
|
+
# clear de session cookie
|
|
38
|
+
SessionManager.clear()
|
|
39
|
+
|
|
40
|
+
return {
|
|
41
|
+
'status': 'success',
|
|
42
|
+
'url': url_for_redirect,
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
|
|
@@ -14,16 +14,16 @@ 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
23
|
# get access credentials
|
|
24
|
-
|
|
25
|
-
if not
|
|
26
|
-
return jsonify(
|
|
24
|
+
auth_result = self.auth_service.verify(anonymous=True)
|
|
25
|
+
if not auth_result.get("success"):
|
|
26
|
+
return jsonify(auth_result), auth_result.get('status_code')
|
|
27
27
|
|
|
28
28
|
try:
|
|
29
29
|
response = self.prompt_service.get_user_prompts(company_short_name)
|
|
@@ -7,54 +7,28 @@ from flask.views import MethodView
|
|
|
7
7
|
from flask import request, jsonify
|
|
8
8
|
from iatoolkit.services.tasks_service import TaskService
|
|
9
9
|
from iatoolkit.repositories.profile_repo import ProfileRepo
|
|
10
|
+
from iatoolkit.services.auth_service import AuthService
|
|
10
11
|
from injector import inject
|
|
11
12
|
from datetime import datetime
|
|
12
13
|
import logging
|
|
13
14
|
from typing import Optional
|
|
14
15
|
|
|
15
16
|
|
|
16
|
-
class
|
|
17
|
+
class TaskApiView(MethodView):
|
|
17
18
|
@inject
|
|
18
|
-
def __init__(self,
|
|
19
|
+
def __init__(self,
|
|
20
|
+
auth_service: AuthService,
|
|
21
|
+
task_service: TaskService,
|
|
22
|
+
profile_repo: ProfileRepo):
|
|
23
|
+
self.auth_service = auth_service
|
|
19
24
|
self.task_service = task_service
|
|
20
25
|
self.profile_repo = profile_repo
|
|
21
26
|
|
|
22
|
-
def _authenticate_requesting_company_via_api_key(self) -> tuple[
|
|
23
|
-
Optional[int], Optional[str], Optional[tuple[dict, int]]]:
|
|
24
|
-
"""
|
|
25
|
-
Autentica a la compañía usando su API Key.
|
|
26
|
-
Retorna (company_id, company_short_name, None) en éxito.
|
|
27
|
-
Retorna (None, None, (error_json, status_code)) en fallo.
|
|
28
|
-
"""
|
|
29
|
-
api_key_header = request.headers.get('Authorization')
|
|
30
|
-
if not api_key_header or not api_key_header.startswith('Bearer '):
|
|
31
|
-
return None, None, ({"error": "API Key faltante o mal formada en el header Authorization"}, 401)
|
|
32
|
-
|
|
33
|
-
api_key_value = api_key_header.split('Bearer ')[1]
|
|
34
|
-
try:
|
|
35
|
-
api_key_entry = self.profile_repo.get_active_api_key_entry(api_key_value)
|
|
36
|
-
if not api_key_entry:
|
|
37
|
-
return None, None, ({"error": "API Key inválida o inactiva"}, 401)
|
|
38
|
-
|
|
39
|
-
# api_key_entry.company ya está cargado por joinedload en get_active_api_key_entry
|
|
40
|
-
if not api_key_entry.company: # Sanity check
|
|
41
|
-
logging.error(
|
|
42
|
-
f"ChatTokenRequest: API Key {api_key_value[:5]}... no tiene compañía asociada a pesar de ser válida.")
|
|
43
|
-
return None, None, ({"error": "Error interno del servidor al verificar API Key"}, 500)
|
|
44
|
-
|
|
45
|
-
return api_key_entry.company_id, api_key_entry.company.short_name, None
|
|
46
|
-
|
|
47
|
-
except Exception as e:
|
|
48
|
-
logging.exception(f"ChatTokenRequest: Error interno durante validación de API Key: {e}")
|
|
49
|
-
return None, None, ({"error": "Error interno del servidor al validar API Key"}, 500)
|
|
50
|
-
|
|
51
|
-
|
|
52
27
|
def post(self):
|
|
53
28
|
try:
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
return jsonify(error[0]), error[1]
|
|
29
|
+
auth_result = self.auth_service.verify(anonymous=True)
|
|
30
|
+
if not auth_result.get("success"):
|
|
31
|
+
return jsonify(auth_result), auth_result.get("status_code")
|
|
58
32
|
|
|
59
33
|
req_data = request.get_json()
|
|
60
34
|
files = request.files.getlist('files')
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# Copyright (c) 2024 Fernando Libedinsky
|
|
2
|
+
# Product: IAToolkit
|
|
3
|
+
#
|
|
4
|
+
# IAToolkit is open source software.
|
|
5
|
+
|
|
6
|
+
from flask.views import MethodView
|
|
7
|
+
from flask import request, jsonify
|
|
8
|
+
from iatoolkit.services.tasks_service import TaskService
|
|
9
|
+
from iatoolkit.repositories.profile_repo import ProfileRepo
|
|
10
|
+
from iatoolkit.services.auth_service import AuthService
|
|
11
|
+
from injector import inject
|
|
12
|
+
import logging
|
|
13
|
+
from typing import Optional
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class TaskReviewApiView(MethodView):
|
|
17
|
+
@inject
|
|
18
|
+
def __init__(self,
|
|
19
|
+
auth_service: AuthService,
|
|
20
|
+
task_service: TaskService,
|
|
21
|
+
profile_repo: ProfileRepo):
|
|
22
|
+
self.auth_service = auth_service
|
|
23
|
+
self.task_service = task_service
|
|
24
|
+
self.profile_repo = profile_repo
|
|
25
|
+
|
|
26
|
+
def post(self, task_id: int):
|
|
27
|
+
auth_result = self.auth_service.verify(anonymous=True)
|
|
28
|
+
if not auth_result.get("success"):
|
|
29
|
+
return jsonify(auth_result), auth_result.get("status_code")
|
|
30
|
+
|
|
31
|
+
try:
|
|
32
|
+
req_data = request.get_json()
|
|
33
|
+
required_fields = ['review_user', 'approved']
|
|
34
|
+
for field in required_fields:
|
|
35
|
+
if field not in req_data:
|
|
36
|
+
return jsonify({"error": f"El campo {field} es requerido"}), 400
|
|
37
|
+
|
|
38
|
+
review_user = req_data.get('review_user', '')
|
|
39
|
+
approved = req_data.get('approved', False)
|
|
40
|
+
comment = req_data.get('comment', '')
|
|
41
|
+
|
|
42
|
+
new_task = self.task_service.review_task(
|
|
43
|
+
task_id=task_id,
|
|
44
|
+
review_user=review_user,
|
|
45
|
+
approved=approved,
|
|
46
|
+
comment=comment)
|
|
47
|
+
|
|
48
|
+
return jsonify({
|
|
49
|
+
"task_id": new_task.id,
|
|
50
|
+
"status": new_task.status.name
|
|
51
|
+
}), 200
|
|
52
|
+
|
|
53
|
+
except Exception as e:
|
|
54
|
+
logging.exception("Error al revisar la tarea: %s", str(e))
|
|
55
|
+
return jsonify({"error": str(e)}), 500
|
|
@@ -14,20 +14,18 @@ import logging
|
|
|
14
14
|
class UserFeedbackApiView(MethodView):
|
|
15
15
|
@inject
|
|
16
16
|
def __init__(self,
|
|
17
|
-
|
|
17
|
+
auth_service: AuthService,
|
|
18
18
|
user_feedback_service: UserFeedbackService ):
|
|
19
|
-
self.
|
|
19
|
+
self.auth_service = auth_service
|
|
20
20
|
self.user_feedback_service = user_feedback_service
|
|
21
21
|
|
|
22
22
|
def post(self, company_short_name):
|
|
23
23
|
# get access credentials
|
|
24
|
-
|
|
25
|
-
if not
|
|
26
|
-
return jsonify(
|
|
24
|
+
auth_result = self.auth_service.verify()
|
|
25
|
+
if not auth_result.get("success"):
|
|
26
|
+
return jsonify(auth_result), auth_result.get("status_code")
|
|
27
27
|
|
|
28
|
-
user_identifier =
|
|
29
|
-
if not user_identifier:
|
|
30
|
-
return jsonify({"error": "Could not identify user from session or payload"}), 400
|
|
28
|
+
user_identifier = auth_result.get('user_identifier')
|
|
31
29
|
|
|
32
30
|
data = request.get_json()
|
|
33
31
|
if not data:
|
|
@@ -37,14 +35,6 @@ class UserFeedbackApiView(MethodView):
|
|
|
37
35
|
if not message:
|
|
38
36
|
return jsonify({"error_message": "Falta el mensaje de feedback"}), 400
|
|
39
37
|
|
|
40
|
-
space = data.get("space")
|
|
41
|
-
if not space:
|
|
42
|
-
return jsonify({"error_message": "Falta el espacio de Google Chat"}), 400
|
|
43
|
-
|
|
44
|
-
type = data.get("type")
|
|
45
|
-
if not type:
|
|
46
|
-
return jsonify({"error_message": "Falta el tipo de feedback"}), 400
|
|
47
|
-
|
|
48
38
|
rating = data.get("rating")
|
|
49
39
|
if not rating:
|
|
50
40
|
return jsonify({"error_message": "Falta la calificación"}), 400
|
|
@@ -54,8 +44,6 @@ class UserFeedbackApiView(MethodView):
|
|
|
54
44
|
company_short_name=company_short_name,
|
|
55
45
|
message=message,
|
|
56
46
|
user_identifier=user_identifier,
|
|
57
|
-
space=space,
|
|
58
|
-
type=type,
|
|
59
47
|
rating=rating
|
|
60
48
|
)
|
|
61
49
|
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
iatoolkit/__init__.py,sha256=4PWjMJjktixtrxF6BY405qyA50Sv967kEP2x-oil6qk,1120
|
|
2
|
-
iatoolkit/base_company.py,sha256=
|
|
2
|
+
iatoolkit/base_company.py,sha256=vU4ki-wB3PWIn3_Bvehfh0TfBH_XNC614tRBKNmEd84,4718
|
|
3
3
|
iatoolkit/cli_commands.py,sha256=G5L9xQXZ0lVFXQWBaE_KEZHyfuiT6PL1nTQRoSdnBzc,2302
|
|
4
4
|
iatoolkit/company_registry.py,sha256=tduqt3oV8iDX_IB1eA7KIgvIxE4edTcy-3qZIXh3Lzw,2549
|
|
5
|
-
iatoolkit/iatoolkit.py,sha256=
|
|
5
|
+
iatoolkit/iatoolkit.py,sha256=FCFi1qcaTEMh3ZKqBB3LJTkjxc-JCvcGf79LYfYukKM,17570
|
|
6
6
|
iatoolkit/common/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
7
7
|
iatoolkit/common/exceptions.py,sha256=EXx40n5htp7UiOM6P1xfJ9U6NMcADqm62dlFaKz7ICU,1154
|
|
8
|
-
iatoolkit/common/routes.py,sha256=
|
|
8
|
+
iatoolkit/common/routes.py,sha256=L8UTwbE-cNSYl5s09mMckO2J9on0N1F6p8ZXMFbjrDM,5738
|
|
9
9
|
iatoolkit/common/session_manager.py,sha256=UeKfD15bcEA3P5e0WSURfotLqpsiIMp3AXxAMhtgHs0,471
|
|
10
10
|
iatoolkit/common/util.py,sha256=w9dTd3csK0gKtFSp-a4t7XmCPZiYDhiON92uXRbTT8A,14624
|
|
11
11
|
iatoolkit/infra/__init__.py,sha256=5JqK9sZ6jBuK83zDQokUhxQ0wuJJJ9DXB8pYCLkX7X4,102
|
|
@@ -29,12 +29,12 @@ iatoolkit/repositories/__init__.py,sha256=5JqK9sZ6jBuK83zDQokUhxQ0wuJJJ9DXB8pYCL
|
|
|
29
29
|
iatoolkit/repositories/database_manager.py,sha256=QgV8hNnVv9RmeOvUdomdj_mfk0bf3Rl8Ti41a-5zIAY,3700
|
|
30
30
|
iatoolkit/repositories/document_repo.py,sha256=Y7bF1kZB1HWJsAGjWdF7P2aVYeTYNufq9ngQXp7mDkY,1124
|
|
31
31
|
iatoolkit/repositories/llm_query_repo.py,sha256=YT_t7cYGQk8rwzH_17-28aTzO-e2jUfa2rvXy8tugvA,3612
|
|
32
|
-
iatoolkit/repositories/models.py,sha256=
|
|
32
|
+
iatoolkit/repositories/models.py,sha256=6KQpyCtp2l-ExfbeoPmoqc2V5qlTmSmEbzHYISZtu6g,14288
|
|
33
33
|
iatoolkit/repositories/profile_repo.py,sha256=21am3GP7XCG0nq6i3pArQ7mfGsrRn8rdcWT98fsdwlU,4397
|
|
34
34
|
iatoolkit/repositories/tasks_repo.py,sha256=icVO_r2oPagGnnBhwVFzznnvEEU2EAx-2dlWuWvoDC4,1745
|
|
35
35
|
iatoolkit/repositories/vs_repo.py,sha256=UkpmQQiocgM5IwRBmmWhw3HHzHP6zK1nN3J3TcQgjhc,5300
|
|
36
36
|
iatoolkit/services/__init__.py,sha256=5JqK9sZ6jBuK83zDQokUhxQ0wuJJJ9DXB8pYCLkX7X4,102
|
|
37
|
-
iatoolkit/services/auth_service.py,sha256=
|
|
37
|
+
iatoolkit/services/auth_service.py,sha256=PPaa_zB0L2i574O6VQzKvTmzHbmzlWK3vvMQl2TYjOA,7494
|
|
38
38
|
iatoolkit/services/benchmark_service.py,sha256=CdbFYyS3FHFhNzWQEa9ZNjUlmON10DT1nKNbZQ1EUi8,5880
|
|
39
39
|
iatoolkit/services/branding_service.py,sha256=gXj9Lj6EIFNIHT6wAHia5lr4_2a2sD-ExMbewno5YD8,7505
|
|
40
40
|
iatoolkit/services/dispatcher_service.py,sha256=Qdn2x4cozpgpKg2448sUxkhO6tuplzb8xPWUxdTTFBE,12772
|
|
@@ -46,22 +46,22 @@ iatoolkit/services/jwt_service.py,sha256=W2kQVNQheQSLkNLS7RZ4jd3hmySBPLbHAS5hvBr
|
|
|
46
46
|
iatoolkit/services/load_documents_service.py,sha256=ZpB0BZ3qX1fGJGBtZtMLbFdWWx0hkPoeCS3OqJKwCTs,7291
|
|
47
47
|
iatoolkit/services/mail_service.py,sha256=2h-fcF3swZDya_o7IpgXkmuj3iEVHVCiHi7oVxU99sQ,2182
|
|
48
48
|
iatoolkit/services/onboarding_service.py,sha256=cMO2Ho1-G3wAeVNl-j25LwCMJjRwj3yKHpYKnZUFLDE,2001
|
|
49
|
-
iatoolkit/services/profile_service.py,sha256=
|
|
49
|
+
iatoolkit/services/profile_service.py,sha256=cOjGJvrH9f3DRoXrhs4vZEqG7dzwrl_GnOcwxyaSX18,20301
|
|
50
50
|
iatoolkit/services/prompt_manager_service.py,sha256=U-XmSpkeXvv1KRN4dytdMxSYBMRSB7y-UHcb18mk0nA,8342
|
|
51
51
|
iatoolkit/services/query_service.py,sha256=gtMEAQ7IRVrFAMq4h_Pc_lHlMlXFI6heLSuBYHenkfs,17502
|
|
52
52
|
iatoolkit/services/search_service.py,sha256=i1xGWu7ORKIIDH0aAQBkF86dVVbLQ0Yrooz5TiZ6aGo,1823
|
|
53
53
|
iatoolkit/services/sql_service.py,sha256=MIslAtpJWnTMgSD74nnqTvQj27p-lHiyRXc6OiA2C_c,2172
|
|
54
54
|
iatoolkit/services/tasks_service.py,sha256=itREO5rDnUIgsqtyCOBKDtH30QL5v1egs4qPTiBK8xU,6865
|
|
55
|
-
iatoolkit/services/user_feedback_service.py,sha256=
|
|
55
|
+
iatoolkit/services/user_feedback_service.py,sha256=Bb6PVWcxzoQ3awev_k4MI0BQhkMh6iLPGC8_CK02t5g,4986
|
|
56
56
|
iatoolkit/services/user_session_context_service.py,sha256=vYF_vWM37tPB_ZyPBJ6f6WTJVjT2j-4L8JfZbqbI93k,6775
|
|
57
57
|
iatoolkit/static/images/fernando.jpeg,sha256=W68TYMuo5hZVpbP-evwH6Nu4xWFv2bc8pJzSKDoLTeQ,100612
|
|
58
|
-
iatoolkit/static/js/
|
|
59
|
-
iatoolkit/static/js/chat_feedback.js,sha256=zlLEDQfEocGK7RKG2baqI-9fyQlqe6hVuAHOKTPmWek,4399
|
|
58
|
+
iatoolkit/static/js/chat_feedback_button.js,sha256=j3BIyxcgyDuDDBn3vxxe0DV4evQabj3xb6XF28OWwCs,4220
|
|
60
59
|
iatoolkit/static/js/chat_filepond.js,sha256=mzXafm7a506EpM37KATTK3zvAswO1E0KSUY1vKbwuRc,3163
|
|
61
|
-
iatoolkit/static/js/
|
|
62
|
-
iatoolkit/static/js/chat_main.js,sha256=
|
|
63
|
-
iatoolkit/static/js/
|
|
64
|
-
iatoolkit/static/
|
|
60
|
+
iatoolkit/static/js/chat_history_button.js,sha256=4h6ldU7cDvgkW84fMKB8JReoxCX0NKSQAir_4CzAF9I,4382
|
|
61
|
+
iatoolkit/static/js/chat_main.js,sha256=GPPM3euqT_cGcrmsb7DGr0Aa6BpeQRTpuf2zW2VEvMM,18118
|
|
62
|
+
iatoolkit/static/js/chat_onboarding_button.js,sha256=vjvEloJ9PA9D7jOGca0QjS3J_7bU97R71L7kSyY3wOI,3153
|
|
63
|
+
iatoolkit/static/js/chat_reload_button.js,sha256=f8f_qRnZTNr_DwbcmafTHIuBLmiCoypYAKGQc472AOs,2393
|
|
64
|
+
iatoolkit/static/styles/chat_iatoolkit.css,sha256=w9O_4slQuls3R5UH30oUrgA5BetA5BVctzSPpelMN4Y,12934
|
|
65
65
|
iatoolkit/static/styles/chat_info.css,sha256=17DbgoNYE21VYWfb5L9-QLCpD2R1idK4imKRLwXtJLY,1058
|
|
66
66
|
iatoolkit/static/styles/chat_modal.css,sha256=mdfjrJtmUn3O9rKwIGjJc-oSNmJGnzUY1aAJqEfPh38,4301
|
|
67
67
|
iatoolkit/static/styles/landing_page.css,sha256=5MHlXkmgZVv9uHE7rZTGYzZeynya3ONY4hp7e2uPXwk,4898
|
|
@@ -76,36 +76,36 @@ iatoolkit/templates/_navbar.html,sha256=o1PvZE5ueLmVpGUAmsjtu-vS_WPROTlJc2sTXl6A
|
|
|
76
76
|
iatoolkit/templates/about.html,sha256=ciC08grUVz5qLzdzDDqDX31xirg5PrJIRYabWpV9oA8,294
|
|
77
77
|
iatoolkit/templates/base.html,sha256=hHfBqZJsPcZGlb4BxAbHvpJFcSjckLIAVTYTmoyXrz0,2323
|
|
78
78
|
iatoolkit/templates/change_password.html,sha256=G5a3hYLTpz_5Q_eZ4LNcYSqLeW-CuT4NCHD8bkhAd9k,3573
|
|
79
|
-
iatoolkit/templates/chat.html,sha256=
|
|
79
|
+
iatoolkit/templates/chat.html,sha256=kq9juQ1LhXxG-uERr8FdK80KtwI43DABmSS3z66qNfQ,12182
|
|
80
80
|
iatoolkit/templates/chat_modals.html,sha256=NwwgPoOmVbjy4aO2eHsy1TUMXRiOfTOC5Jx_F2ehhcs,6947
|
|
81
81
|
iatoolkit/templates/error.html,sha256=c3dxieMygsvdjQMiQu_sn6kqqag9zFtVu-z5FunX6so,580
|
|
82
82
|
iatoolkit/templates/forgot_password.html,sha256=NRZqbNHJXSLNArF_KLbzuem-U57v07awS0ikI_DJbfM,2360
|
|
83
83
|
iatoolkit/templates/header.html,sha256=179agI7rnYwP_rvJNXIiVde5E8Ec5649_XKq6eew2Hk,1263
|
|
84
84
|
iatoolkit/templates/index.html,sha256=ZeDBmZGZ_GlxQ8p_NA2Fdf4syTU5kXrJBO6q2P77wKY,7907
|
|
85
85
|
iatoolkit/templates/login_simulation.html,sha256=1svwCBPrJ3Gy6bD9WMuz25NBSdFgZt4j8_sC7HE6MFU,1270
|
|
86
|
-
iatoolkit/templates/onboarding_shell.html,sha256=
|
|
86
|
+
iatoolkit/templates/onboarding_shell.html,sha256=exSGckoPeE-ID9ym3B4TLh5hULpR7N1X6LeuSNmiUL0,4666
|
|
87
87
|
iatoolkit/templates/signup.html,sha256=9ArDvcNQgHFR2dwxy-37AXzGUOeOsT7Nz5u0y6fAB3U,4385
|
|
88
88
|
iatoolkit/templates/test.html,sha256=rwNtxC83tbCl5COZFXYvmRBxxmgFJtPNuVBd_nq9KWY,133
|
|
89
89
|
iatoolkit/views/__init__.py,sha256=5JqK9sZ6jBuK83zDQokUhxQ0wuJJJ9DXB8pYCLkX7X4,102
|
|
90
90
|
iatoolkit/views/base_login_view.py,sha256=qoMMrAezCJvzjcfNzIbd2vwHhksALIQfNK8f_9E8m0o,3241
|
|
91
|
-
iatoolkit/views/change_password_view.py,sha256=
|
|
92
|
-
iatoolkit/views/
|
|
93
|
-
iatoolkit/views/
|
|
94
|
-
iatoolkit/views/file_store_api_view.py,sha256=Uz9f6sey3_F5K8zuyQz6SwYRKAalCjD1ekf-Mkl_Kfo,2326
|
|
91
|
+
iatoolkit/views/change_password_view.py,sha256=DRfyvD-zgX-zidoIrvYnWg6V0LOeeugCZTxgk7wNntM,4503
|
|
92
|
+
iatoolkit/views/external_login_view.py,sha256=d4gUQbxFsThGbbAUdtFn7AMgPJjeb7_8KFFoH3vspVA,2853
|
|
93
|
+
iatoolkit/views/file_store_api_view.py,sha256=UvtZWOG-rLQMLfs8igOIYoQ-tkkEg5baMjqCJdKxaRQ,2300
|
|
95
94
|
iatoolkit/views/forgot_password_view.py,sha256=-qKJeeOBqJFdvDUk7rCNg1E1cDQnJQkozPpb0T0FgwA,3159
|
|
96
|
-
iatoolkit/views/history_api_view.py,sha256=
|
|
95
|
+
iatoolkit/views/history_api_view.py,sha256=0YChbss0ae05KHzni2p3d4bGS2_yKAbjALk1OBeQk50,1867
|
|
97
96
|
iatoolkit/views/index_view.py,sha256=P5aVdEWxsYOZGbzcXd6WFE733qZ7YXIoeqriUMAM6V8,1527
|
|
98
|
-
iatoolkit/views/init_context_api_view.py,sha256=
|
|
99
|
-
iatoolkit/views/llmquery_api_view.py,sha256=
|
|
97
|
+
iatoolkit/views/init_context_api_view.py,sha256=YTjpT4xdtm1knUhelDj-VbV4EK6o_qGAgwwDhFmIOlg,2716
|
|
98
|
+
iatoolkit/views/llmquery_api_view.py,sha256=v_KxR6w-TrCVR2fMFHZCz3_v4o42CXb1Yvd-R1hSJHg,1662
|
|
100
99
|
iatoolkit/views/login_simulation_view.py,sha256=0Qt-puRnltI2HZxlfdyJmOf26-hQp3xjknGV_jkwV7E,3484
|
|
101
100
|
iatoolkit/views/login_view.py,sha256=ESJLKHGUKQw71STHK2AoxugQUJmxnPYlI13n7ZawLLg,5663
|
|
102
|
-
iatoolkit/views/
|
|
101
|
+
iatoolkit/views/logout_api_view.py,sha256=V1HkfUfTQr_IrHFqjmeA0-qN2qugk3bmtLRHtZd7VE8,1506
|
|
102
|
+
iatoolkit/views/prompt_api_view.py,sha256=S_4-qAD5knh8Esae1AczEYGdXy_AuU7LMOmnUPej4jQ,1294
|
|
103
103
|
iatoolkit/views/signup_view.py,sha256=BCjhM2lMiDPwYrlW_eEwPl-ZLupblbFfsonWtq0E4vU,3922
|
|
104
|
-
iatoolkit/views/
|
|
105
|
-
iatoolkit/views/
|
|
106
|
-
iatoolkit/views/user_feedback_api_view.py,sha256
|
|
104
|
+
iatoolkit/views/tasks_api_view.py,sha256=wGnuwuuL83ByQ1Yre6ytRVztA0OGQjGrwMjB1_G830U,2630
|
|
105
|
+
iatoolkit/views/tasks_review_api_view.py,sha256=wsCpzqyRyUdCXWAhyGlBe3eNZZ6A1DQG7TblN_GZNfM,1894
|
|
106
|
+
iatoolkit/views/user_feedback_api_view.py,sha256=-Ngex8SPf0mPvPNqwE_GUcRErLpOL49yJ43o5Y4Qhqo,1992
|
|
107
107
|
iatoolkit/views/verify_user_view.py,sha256=7XLSaxvs8LjBr3cYOUDa9B8DqW_50IGlq0IvmOQcD0Y,2340
|
|
108
|
-
iatoolkit-0.
|
|
109
|
-
iatoolkit-0.
|
|
110
|
-
iatoolkit-0.
|
|
111
|
-
iatoolkit-0.
|
|
108
|
+
iatoolkit-0.60.0.dist-info/METADATA,sha256=OHgf546tocA5arbQL9wnzreenlXGvfD52xko9xBi9kM,9301
|
|
109
|
+
iatoolkit-0.60.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
110
|
+
iatoolkit-0.60.0.dist-info/top_level.txt,sha256=V_w4QvDx0b1RXiy8zTCrD1Bp7AZkFe3_O0-9fMiwogg,10
|
|
111
|
+
iatoolkit-0.60.0.dist-info/RECORD,,
|
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
# Copyright (c) 2024 Fernando Libedinsky
|
|
2
|
-
# Product: IAToolkit
|
|
3
|
-
#
|
|
4
|
-
# IAToolkit is open source software.
|
|
5
|
-
|
|
6
|
-
from flask import request, jsonify, current_app
|
|
7
|
-
from flask.views import MethodView
|
|
8
|
-
from injector import inject
|
|
9
|
-
import logging
|
|
10
|
-
from iatoolkit.repositories.profile_repo import ProfileRepo
|
|
11
|
-
from iatoolkit.services.jwt_service import JWTService
|
|
12
|
-
from typing import Optional
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
# Necesitaremos JWT_EXPIRATION_SECONDS_CHAT de la configuración de la app
|
|
16
|
-
# Se podría inyectar o acceder globalmente.
|
|
17
|
-
|
|
18
|
-
class ChatTokenRequestView(MethodView):
|
|
19
|
-
@inject
|
|
20
|
-
def __init__(self, profile_repo: ProfileRepo, jwt_service: JWTService):
|
|
21
|
-
self.profile_repo = profile_repo
|
|
22
|
-
self.jwt_service = jwt_service
|
|
23
|
-
|
|
24
|
-
def _authenticate_requesting_company_via_api_key(self) -> tuple[
|
|
25
|
-
Optional[int], Optional[str], Optional[tuple[dict, int]]]:
|
|
26
|
-
"""
|
|
27
|
-
Autentica a la compañía que solicita el token JWT usando su API Key.
|
|
28
|
-
Retorna (company_id, company_short_name, None) en éxito.
|
|
29
|
-
Retorna (None, None, (error_json, status_code)) en fallo.
|
|
30
|
-
"""
|
|
31
|
-
api_key_header = request.headers.get('Authorization')
|
|
32
|
-
if not api_key_header or not api_key_header.startswith('Bearer '):
|
|
33
|
-
return None, None, ({"error": "API Key faltante o mal formada en el header Authorization"}, 401)
|
|
34
|
-
|
|
35
|
-
api_key_value = api_key_header.split('Bearer ')[1]
|
|
36
|
-
try:
|
|
37
|
-
api_key_entry = self.profile_repo.get_active_api_key_entry(api_key_value)
|
|
38
|
-
if not api_key_entry:
|
|
39
|
-
return None, None, ({"error": "API Key inválida o inactiva"}, 401)
|
|
40
|
-
|
|
41
|
-
# api_key_entry.company ya está cargado por joinedload en get_active_api_key_entry
|
|
42
|
-
if not api_key_entry.company: # Sanity check
|
|
43
|
-
logging.error(
|
|
44
|
-
f"ChatTokenRequest: API Key {api_key_value[:5]}... no tiene compañía asociada a pesar de ser válida.")
|
|
45
|
-
return None, None, ({"error": "Error interno del servidor al verificar API Key"}, 500)
|
|
46
|
-
|
|
47
|
-
return api_key_entry.company_id, api_key_entry.company.short_name, None
|
|
48
|
-
|
|
49
|
-
except Exception as e:
|
|
50
|
-
logging.exception(f"ChatTokenRequest: Error interno durante validación de API Key: {e}")
|
|
51
|
-
return None, None, ({"error": "Error interno del servidor al validar API Key"}, 500)
|
|
52
|
-
|
|
53
|
-
def post(self):
|
|
54
|
-
"""
|
|
55
|
-
Genera un JWT para una sesión de chat.
|
|
56
|
-
Autenticado por API Key de la empresa.
|
|
57
|
-
Requiere JSON body:
|
|
58
|
-
{"company_short_name": "target_company_name",
|
|
59
|
-
"external_user_id": "user_abc"
|
|
60
|
-
}
|
|
61
|
-
"""
|
|
62
|
-
# only requests with valid api-key are allowed
|
|
63
|
-
auth_company_id, auth_company_short_name, error = self._authenticate_requesting_company_via_api_key()
|
|
64
|
-
if error:
|
|
65
|
-
return jsonify(error[0]), error[1]
|
|
66
|
-
|
|
67
|
-
# get the json fields from the request body
|
|
68
|
-
data = request.get_json()
|
|
69
|
-
if not data:
|
|
70
|
-
return jsonify({"error": "Cuerpo de la solicitud JSON faltante"}), 400
|
|
71
|
-
|
|
72
|
-
target_company_short_name = data.get('company_short_name')
|
|
73
|
-
external_user_id = data.get('external_user_id')
|
|
74
|
-
|
|
75
|
-
if not target_company_short_name or not external_user_id:
|
|
76
|
-
return jsonify(
|
|
77
|
-
{"error": "Faltan 'company_short_name' o 'external_user_id' en el cuerpo de la solicitud"}), 401
|
|
78
|
-
|
|
79
|
-
# Verificar que la API Key usada pertenezca a la empresa para la cual se solicita el token
|
|
80
|
-
if auth_company_short_name != target_company_short_name:
|
|
81
|
-
return jsonify({
|
|
82
|
-
"error": f"API Key no autorizada para generar tokens para la compañía '{target_company_short_name}'"}), 403
|
|
83
|
-
|
|
84
|
-
jwt_expiration_seconds = current_app.config.get('JWT_EXPIRATION_SECONDS_CHAT', 3600)
|
|
85
|
-
|
|
86
|
-
# Aquí, auth_company_id es el ID de la compañía para la que se generará el token.
|
|
87
|
-
# auth_company_short_name es su nombre corto.
|
|
88
|
-
token = self.jwt_service.generate_chat_jwt(
|
|
89
|
-
company_id=auth_company_id,
|
|
90
|
-
company_short_name=auth_company_short_name, # Usamos el short_name autenticado
|
|
91
|
-
external_user_id=external_user_id,
|
|
92
|
-
expires_delta_seconds=jwt_expiration_seconds
|
|
93
|
-
)
|
|
94
|
-
|
|
95
|
-
if token:
|
|
96
|
-
return jsonify({"chat_jwt": token}), 200
|
|
97
|
-
else:
|
|
98
|
-
return jsonify({"error": "No se pudo generar el token de chat"}), 500
|
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
# Copyright (c) 2024 Fernando Libedinsky
|
|
2
|
-
# Product: IAToolkit
|
|
3
|
-
#
|
|
4
|
-
# IAToolkit is open source software.
|
|
5
|
-
|
|
6
|
-
from flask.views import MethodView
|
|
7
|
-
from flask import request, jsonify
|
|
8
|
-
from iatoolkit.services.tasks_service import TaskService
|
|
9
|
-
from iatoolkit.repositories.profile_repo import ProfileRepo
|
|
10
|
-
from injector import inject
|
|
11
|
-
import logging
|
|
12
|
-
from typing import Optional
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
class TaskReviewView(MethodView):
|
|
16
|
-
@inject
|
|
17
|
-
def __init__(self, task_service: TaskService, profile_repo: ProfileRepo):
|
|
18
|
-
self.task_service = task_service
|
|
19
|
-
self.profile_repo = profile_repo
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
def _authenticate_requesting_company_via_api_key(self) -> tuple[
|
|
23
|
-
Optional[int], Optional[str], Optional[tuple[dict, int]]]:
|
|
24
|
-
"""
|
|
25
|
-
Autentica a la compañía usando su API Key.
|
|
26
|
-
Retorna (company_id, company_short_name, None) en éxito.
|
|
27
|
-
Retorna (None, None, (error_json, status_code)) en fallo.
|
|
28
|
-
"""
|
|
29
|
-
api_key_header = request.headers.get('Authorization')
|
|
30
|
-
if not api_key_header or not api_key_header.startswith('Bearer '):
|
|
31
|
-
return None, None, ({"error": "API Key faltante o mal formada en el header Authorization"}, 401)
|
|
32
|
-
|
|
33
|
-
api_key_value = api_key_header.split('Bearer ')[1]
|
|
34
|
-
try:
|
|
35
|
-
api_key_entry = self.profile_repo.get_active_api_key_entry(api_key_value)
|
|
36
|
-
if not api_key_entry:
|
|
37
|
-
return None, None, ({"error": "API Key inválida o inactiva"}, 401)
|
|
38
|
-
|
|
39
|
-
# api_key_entry.company ya está cargado por joinedload en get_active_api_key_entry
|
|
40
|
-
if not api_key_entry.company: # Sanity check
|
|
41
|
-
logging.error(
|
|
42
|
-
f"ChatTokenRequest: API Key {api_key_value[:5]}... no tiene compañía asociada a pesar de ser válida.")
|
|
43
|
-
return None, None, ({"error": "Error interno del servidor al verificar API Key"}, 500)
|
|
44
|
-
|
|
45
|
-
return api_key_entry.company_id, api_key_entry.company.short_name, None
|
|
46
|
-
|
|
47
|
-
except Exception as e:
|
|
48
|
-
logging.exception(f"ChatTokenRequest: Error interno durante validación de API Key: {e}")
|
|
49
|
-
return None, None, ({"error": "Error interno del servidor al validar API Key"}, 500)
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
def post(self, task_id: int):
|
|
53
|
-
try:
|
|
54
|
-
# only requests with valid api-key are allowed
|
|
55
|
-
auth_company_id, auth_company_short_name, error = self._authenticate_requesting_company_via_api_key()
|
|
56
|
-
if error:
|
|
57
|
-
return jsonify(error[0]), error[1]
|
|
58
|
-
|
|
59
|
-
req_data = request.get_json()
|
|
60
|
-
|
|
61
|
-
required_fields = ['review_user', 'approved']
|
|
62
|
-
for field in required_fields:
|
|
63
|
-
if field not in req_data:
|
|
64
|
-
return jsonify({"error": f"El campo {field} es requerido"}), 400
|
|
65
|
-
|
|
66
|
-
review_user = req_data.get('review_user', '')
|
|
67
|
-
approved = req_data.get('approved', False)
|
|
68
|
-
comment = req_data.get('comment', '')
|
|
69
|
-
|
|
70
|
-
new_task = self.task_service.review_task(
|
|
71
|
-
task_id=task_id,
|
|
72
|
-
review_user=review_user,
|
|
73
|
-
approved=approved,
|
|
74
|
-
comment=comment)
|
|
75
|
-
|
|
76
|
-
return jsonify({
|
|
77
|
-
"task_id": new_task.id,
|
|
78
|
-
"status": new_task.status.name
|
|
79
|
-
}), 200
|
|
80
|
-
|
|
81
|
-
except Exception as e:
|
|
82
|
-
logging.exception("Error al revisar la tarea: %s", str(e))
|
|
83
|
-
return jsonify({"error": str(e)}), 500
|
|
File without changes
|
|
File without changes
|
|
File without changes
|