iatoolkit 0.59.1__py3-none-any.whl → 0.59.2__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 CHANGED
@@ -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)
iatoolkit/iatoolkit.py CHANGED
@@ -19,7 +19,7 @@ from werkzeug.middleware.proxy_fix import ProxyFix
19
19
  from injector import Binder, singleton, Injector
20
20
  from importlib.metadata import version as _pkg_version, PackageNotFoundError
21
21
 
22
- IATOOLKIT_VERSION = "0.59.1"
22
+ IATOOLKIT_VERSION = "0.59.2"
23
23
 
24
24
  # global variable for the unique instance of IAToolkit
25
25
  _iatoolkit_instance: Optional['IAToolkit'] = None
@@ -60,7 +60,7 @@ class Company(Base):
60
60
 
61
61
  branding = Column(JSON, nullable=True)
62
62
  onboarding_cards = Column(JSON, nullable=True)
63
- parameters = Column(JSON, nullable=True, default={})
63
+ parameters = Column(JSON, nullable=True)
64
64
  created_at = Column(DateTime, default=datetime.now)
65
65
  allow_jwt = Column(Boolean, default=True, nullable=True)
66
66
 
@@ -3,62 +3,101 @@
3
3
  #
4
4
  # IAToolkit is open source software.
5
5
 
6
- from iatoolkit.repositories.models import UserFeedback
6
+ from iatoolkit.repositories.models import UserFeedback, Company
7
7
  from injector import inject
8
8
  from iatoolkit.repositories.profile_repo import ProfileRepo
9
9
  from iatoolkit.infra.google_chat_app import GoogleChatApp
10
+ from iatoolkit.infra.mail_app import MailApp # <-- 1. Importar MailApp
10
11
  import logging
11
12
 
12
13
 
13
14
  class UserFeedbackService:
14
15
  @inject
15
- def __init__(self, profile_repo: ProfileRepo, google_chat_app: GoogleChatApp):
16
+ def __init__(self,
17
+ profile_repo: ProfileRepo,
18
+ google_chat_app: GoogleChatApp,
19
+ mail_app: MailApp):
16
20
  self.profile_repo = profile_repo
17
21
  self.google_chat_app = google_chat_app
22
+ self.mail_app = mail_app
23
+
24
+ def _send_google_chat_notification(self, space_name: str, message_text: str):
25
+ """Envía una notificación de feedback a un espacio de Google Chat."""
26
+ try:
27
+ chat_data = {
28
+ "type": "MESSAGE_TRIGGER",
29
+ "space": {"name": space_name},
30
+ "message": {"text": message_text}
31
+ }
32
+ chat_result = self.google_chat_app.send_message(message_data=chat_data)
33
+ if not chat_result.get('success'):
34
+ logging.warning(f"Error al enviar notificación a Google Chat: {chat_result.get('message')}")
35
+ except Exception as e:
36
+ logging.exception(f"Fallo inesperado al enviar notificación a Google Chat: {e}")
37
+
38
+ def _send_email_notification(self, destination_email: str, company_name: str, message_text: str):
39
+ """Envía una notificación de feedback por correo electrónico."""
40
+ try:
41
+ subject = f"Nuevo Feedback de {company_name}"
42
+ # Convertir el texto plano a un HTML simple para mantener los saltos de línea
43
+ html_body = message_text.replace('\n', '<br>')
44
+ self.mail_app.send_email(to=destination_email, subject=subject, body=html_body)
45
+ except Exception as e:
46
+ logging.exception(f"Fallo inesperado al enviar email de feedback: {e}")
47
+
48
+ def _handle_notification(self, company: Company, message_text: str):
49
+ """Lee la configuración de la empresa y envía la notificación al canal correspondiente."""
50
+ feedback_params = company.parameters.get('user_feedback')
51
+ if not isinstance(feedback_params, dict):
52
+ logging.warning(f"No se encontró configuración de 'user_feedback' para la empresa {company.short_name}.")
53
+ return
54
+
55
+ # get channel and destination
56
+ channel = feedback_params.get('channel')
57
+ destination = feedback_params.get('destination')
58
+ if not channel or not destination:
59
+ logging.warning(f"Configuración 'user_feedback' incompleta para {company.short_name}. Faltan 'channel' o 'destination'.")
60
+ return
61
+
62
+ if channel == 'google_chat':
63
+ self._send_google_chat_notification(space_name=destination, message_text=message_text)
64
+ elif channel == 'email':
65
+ self._send_email_notification(destination_email=destination, company_name=company.short_name, message_text=message_text)
66
+ else:
67
+ logging.warning(f"Canal de feedback '{channel}' no reconocido para la empresa {company.short_name}.")
18
68
 
19
69
  def new_feedback(self,
20
70
  company_short_name: str,
21
71
  message: str,
22
72
  user_identifier: str,
23
- space: str = None,
24
- type: str = None,
25
73
  rating: int = None) -> dict:
26
74
  try:
27
- # validate company
75
+ # 1. Validar empresa
28
76
  company = self.profile_repo.get_company_by_short_name(company_short_name)
29
77
  if not company:
30
78
  return {'error': f'No existe la empresa: {company_short_name}'}
31
79
 
32
- # send notification to Google Chat
33
- chat_message = f"*Nuevo feedback de {company_short_name}*:\n*Usuario:* {user_identifier}\n*Mensaje:* {message}\n*Calificación:* {rating}"
34
-
35
- # TO DO: get the space and type from the input data
36
- chat_data = {
37
- "type": type,
38
- "space": {
39
- "name": space
40
- },
41
- "message": {
42
- "text": chat_message
43
- }
44
- }
45
-
46
- chat_result = self.google_chat_app.send_message(message_data=chat_data)
47
- if not chat_result.get('success'):
48
- logging.warning(f"Error al enviar notificación a Google Chat: {chat_result.get('message')}")
80
+ # 2. Enviar notificación según la configuración de la empresa
81
+ notification_text = (f"*Nuevo feedback de {company_short_name}*:\n"
82
+ f"*Usuario:* {user_identifier}\n"
83
+ f"*Mensaje:* {message}\n"
84
+ f"*Calificación:* {rating if rating is not None else 'N/A'}")
85
+ self._handle_notification(company, notification_text)
49
86
 
50
- # create the UserFeedback object
51
- new_feedback = UserFeedback(
87
+ # 3. Guardar el feedback en la base de datos (independientemente del éxito de la notificación)
88
+ new_feedback_obj = UserFeedback(
52
89
  company_id=company.id,
53
90
  message=message,
54
91
  user_identifier=user_identifier,
55
92
  rating=rating
56
93
  )
57
- new_feedback = self.profile_repo.save_feedback(new_feedback)
58
- if not new_feedback:
94
+ saved_feedback = self.profile_repo.save_feedback(new_feedback_obj)
95
+ if not saved_feedback:
96
+ logging.error(f"No se pudo guardar el feedback para el usuario {user_identifier} en la empresa {company_short_name}")
59
97
  return {'error': 'No se pudo guardar el feedback'}
60
98
 
61
99
  return {'message': 'Feedback guardado correctamente'}
62
100
 
63
101
  except Exception as e:
102
+ logging.exception(f"Error crítico en el servicio de feedback: {e}")
64
103
  return {'error': str(e)}
@@ -101,12 +101,10 @@ const sendFeedback = async function(message) {
101
101
  "user_identifier": window.user_identifier,
102
102
  "message": message,
103
103
  "rating": activeStars,
104
- "space": "spaces/AAQAupQldd4", // Este valor podría necesitar ser dinámico
105
- "type": "MESSAGE_TRIGGER"
106
104
  };
107
105
  try {
108
106
  // Asumiendo que callLLMAPI está definido globalmente en otro archivo (ej. chat_main.js)
109
- const responseData = await callToolkit('/feedback', data, "POST");
107
+ const responseData = await callToolkit('/api/feedback', data, "POST");
110
108
  return responseData;
111
109
  } catch (error) {
112
110
  console.error("Error al enviar feedback:", error);
@@ -37,14 +37,6 @@ class UserFeedbackApiView(MethodView):
37
37
  if not message:
38
38
  return jsonify({"error_message": "Falta el mensaje de feedback"}), 400
39
39
 
40
- space = data.get("space")
41
- if not space:
42
- return jsonify({"error_message": "Falta el espacio de Google Chat"}), 400
43
-
44
- type = data.get("type")
45
- if not type:
46
- return jsonify({"error_message": "Falta el tipo de feedback"}), 400
47
-
48
40
  rating = data.get("rating")
49
41
  if not rating:
50
42
  return jsonify({"error_message": "Falta la calificación"}), 400
@@ -54,8 +46,6 @@ class UserFeedbackApiView(MethodView):
54
46
  company_short_name=company_short_name,
55
47
  message=message,
56
48
  user_identifier=user_identifier,
57
- space=space,
58
- type=type,
59
49
  rating=rating
60
50
  )
61
51
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: iatoolkit
3
- Version: 0.59.1
3
+ Version: 0.59.2
4
4
  Summary: IAToolkit
5
5
  Author: Fernando Libedinsky
6
6
  License-Expression: MIT
@@ -1,8 +1,8 @@
1
1
  iatoolkit/__init__.py,sha256=4PWjMJjktixtrxF6BY405qyA50Sv967kEP2x-oil6qk,1120
2
- iatoolkit/base_company.py,sha256=nfF-G0h63jy3Qh9kCnvx8Ozx76IjG2p7a34HpweWhOk,4608
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=gaO37He8WhL0K0MItvOxxIq38PIaEtaumJ294lesqbA,17583
5
+ iatoolkit/iatoolkit.py,sha256=N922fz-tHZYZSpu5_PupW8p4x1yi66wnRq7UUgpPCfs,17583
6
6
  iatoolkit/common/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
7
  iatoolkit/common/exceptions.py,sha256=EXx40n5htp7UiOM6P1xfJ9U6NMcADqm62dlFaKz7ICU,1154
8
8
  iatoolkit/common/routes.py,sha256=en9LNxQ3oj7wPUA19okmauGVqdA1yIB_YjPo_-CV-UQ,6195
@@ -29,7 +29,7 @@ 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=qM95kiKm_92JoPNXiwMT4HTjr5BjalnrDiatG3Rte-M,14300
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
@@ -52,11 +52,11 @@ iatoolkit/services/query_service.py,sha256=gtMEAQ7IRVrFAMq4h_Pc_lHlMlXFI6heLSuBY
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=ooy750qWmYOeJi-IJQofu8pLG4svGjGU_JKpKMURZkw,2353
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
58
  iatoolkit/static/js/chat_context_reload.js,sha256=DCOGEf7-t_YLw9wuqkP-kFpiFHt3UyaesFfePp9Cs_k,2512
59
- iatoolkit/static/js/chat_feedback.js,sha256=zlLEDQfEocGK7RKG2baqI-9fyQlqe6hVuAHOKTPmWek,4399
59
+ iatoolkit/static/js/chat_feedback.js,sha256=j2LieutME4RrtMmHbyi3ptfRLefcxechule2NLxzCm8,4284
60
60
  iatoolkit/static/js/chat_filepond.js,sha256=mzXafm7a506EpM37KATTK3zvAswO1E0KSUY1vKbwuRc,3163
61
61
  iatoolkit/static/js/chat_history.js,sha256=4h6ldU7cDvgkW84fMKB8JReoxCX0NKSQAir_4CzAF9I,4382
62
62
  iatoolkit/static/js/chat_main.js,sha256=o1ZNkeaBgGG9d07e5BxTL9OI0aJ26z1bvca1lGoQ-Uo,18535
@@ -103,9 +103,9 @@ iatoolkit/views/prompt_api_view.py,sha256=MP0r-MiswwKcbNc_5KY7aVbHkrR218I8XCiCX1
103
103
  iatoolkit/views/signup_view.py,sha256=BCjhM2lMiDPwYrlW_eEwPl-ZLupblbFfsonWtq0E4vU,3922
104
104
  iatoolkit/views/tasks_review_view.py,sha256=keLsLCyOTTlcoIapnB_lbuSvLwrPVZVpBiFC_7ChbLg,3388
105
105
  iatoolkit/views/tasks_view.py,sha256=a3anTXrJTTvbQuc6PSpOzidLKQFL4hWa7PI2Cppcz8w,4110
106
- iatoolkit/views/user_feedback_api_view.py,sha256=59XB9uQLHI4Q6QA4_XhK787HzfXb-c6EY7k1Ccyr4hI,2424
106
+ iatoolkit/views/user_feedback_api_view.py,sha256=PNtXs3G26COw3QeZ9WlX14lYizualGMZ4wVfv77IUoU,2075
107
107
  iatoolkit/views/verify_user_view.py,sha256=7XLSaxvs8LjBr3cYOUDa9B8DqW_50IGlq0IvmOQcD0Y,2340
108
- iatoolkit-0.59.1.dist-info/METADATA,sha256=0XpfjEJK6gmLoXv1_MF0E2ttfqygFrIwy9pK5PngYZM,9301
109
- iatoolkit-0.59.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
110
- iatoolkit-0.59.1.dist-info/top_level.txt,sha256=V_w4QvDx0b1RXiy8zTCrD1Bp7AZkFe3_O0-9fMiwogg,10
111
- iatoolkit-0.59.1.dist-info/RECORD,,
108
+ iatoolkit-0.59.2.dist-info/METADATA,sha256=XUACxsD5jRzps23Y-avo13tfLAXlF23w7v2jrq-Pr4Q,9301
109
+ iatoolkit-0.59.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
110
+ iatoolkit-0.59.2.dist-info/top_level.txt,sha256=V_w4QvDx0b1RXiy8zTCrD1Bp7AZkFe3_O0-9fMiwogg,10
111
+ iatoolkit-0.59.2.dist-info/RECORD,,