iatoolkit 0.3.7__py3-none-any.whl → 0.3.9__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.

@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: iatoolkit
3
- Version: 0.3.7
3
+ Version: 0.3.9
4
4
  Summary: IAToolkit
5
5
  Author: Fernando Libedinsky
6
6
  License-Expression: MIT
@@ -0,0 +1,32 @@
1
+ iatoolkit/__init__.py,sha256=dKjc0IsztMClwbalF5hbtz418TRtu0xE2pdb8J3iQQw,1512
2
+ iatoolkit/base_company.py,sha256=FlB-HFYH8FoTl4nbtsYgfKjkdZtizJbKwXqaosxmRqc,2009
3
+ iatoolkit/cli_commands.py,sha256=oWd5kwDYd0W1Lcpuk3N2cEnusPAVefaCrYveMQ1zDvY,3223
4
+ iatoolkit/company_registry.py,sha256=cRaez-VBo1icnUNKmkQqo_Xlr8UKWFoYEMZ70XP6Jgk,2702
5
+ iatoolkit/iatoolkit.py,sha256=OwlGujwtNLBYtfZuCpcX_yzrgB8BVo9Jfh72owM8FFc,15651
6
+ iatoolkit/system_prompts/arquitectura.prompt,sha256=2W-7NWy6P6y1Gh5_-zD1iK-BWq1Siu8TuvGCouP67bQ,1267
7
+ iatoolkit/system_prompts/format_styles.prompt,sha256=MSMe1qvR3cF_0IbFshn8R0z6Wx6VCHQq1p37rpu5wwk,3576
8
+ iatoolkit/system_prompts/query_main.prompt,sha256=Eu5VOQzUygJ45Ct1WKYGbi0JMltgI6FQIZWlGmN1bdk,3214
9
+ iatoolkit/system_prompts/sql_rules.prompt,sha256=y4nURVnb9AyFwt-lrbMNBHHtZlhk6kC9grYoOhRnrJo,59174
10
+ services/__init__.py,sha256=fSvSfIcPW1dHwTBY1hQ5dBEhaoorzk_GzR4G46gD8tY,173
11
+ services/api_service.py,sha256=InIKTc64BWcp4U4tYKHz28x4ErPxIfvR9x3ZlxJZlXs,2911
12
+ services/benchmark_service.py,sha256=g9JVrmAqIe_iI0D1DwdQ6DJ2_FJRCTndarESNSVfhbw,5907
13
+ services/dispatcher_service.py,sha256=vZbz-XCP0Aa-oE4nh5ZKeUKWlJ78VPSRYkpzMHlVFM0,14952
14
+ services/document_service.py,sha256=sm5QtbrKs2dF9hpLuSLMB-IMWYNBD7yWHv3rd80aD0o,5960
15
+ services/excel_service.py,sha256=wE9Udbyb96kGRSnZZ6KM2mbE484rKjTEhta9GKKpy-8,3630
16
+ services/file_processor_service.py,sha256=82UArWtwpr94CAMkkoRP0_nPtoqItymdKSIABS0Xkxw,2943
17
+ services/history_service.py,sha256=6fGSSWxy60nxtkwp_fodwDHoVKhpIUbHnzAzUSiNi-Y,1657
18
+ services/jwt_service.py,sha256=dC45Sn6FyzdzRiQJnzgkjN3Hy21V1imRxB0hTyWRvlA,3979
19
+ services/load_documents_service.py,sha256=_-OTUih8Zk0m4dHqAhkE7kAwU2mbz_QoMrOKnrq7ZWs,8821
20
+ services/mail_service.py,sha256=ystFit1LuYUC4ekYYebyiy1rqYQmxeL6K8h58MxEkOY,2233
21
+ services/profile_service.py,sha256=vZV0cregZQiPKYcNLaD7xjez2y6-3Mq97cDndC8NL8w,17922
22
+ services/prompt_manager_service.py,sha256=g499zeWZODqoDvqQZX6eHWmsWj7oLWkEhge7UV_y8IE,7679
23
+ services/query_service.py,sha256=zpaDzjzh2HqAG1F2Ap8WHBpfAMVtzZ_6v1JGVEguwvs,15687
24
+ services/search_service.py,sha256=oJD6WRXCJBD7WUVHWWKxexRkhR8nQSrFtcPV3pFO2KQ,1153
25
+ services/sql_service.py,sha256=H7CIPpXTcxLXLojD2fBFr_mIAD0PW1vEJhKHLfJi4Hk,1418
26
+ services/tasks_service.py,sha256=hHJDlcsSOPtEleD6_Vv3pocfxWNmthIhmZSdnoWFpEM,6861
27
+ services/user_feedback_service.py,sha256=YtCndRBekDEWYEbac431Ksn2gMO5iBrI3WqKK0xtShE,2513
28
+ services/user_session_context_service.py,sha256=5qn7fqpuiU8KgMpU4M5-iRUsETumz1raBw-EeZLuE1A,3868
29
+ iatoolkit-0.3.9.dist-info/METADATA,sha256=wLPKZh6G6AXabwamba8ywnayHiCCwHYiNWVfqH7JK9I,8801
30
+ iatoolkit-0.3.9.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
31
+ iatoolkit-0.3.9.dist-info/top_level.txt,sha256=dqlBbmgo9okD9d_WMR9uYzdup7Rxgj26yFF85jRGeu4,19
32
+ iatoolkit-0.3.9.dist-info/RECORD,,
@@ -12,6 +12,7 @@ from repositories.models import Company, Function
12
12
  from services.excel_service import ExcelService
13
13
  from services.mail_service import MailService
14
14
  from iatoolkit.company_registry import get_company_registry
15
+ from common.session_manager import SessionManager
15
16
  from common.util import Utility
16
17
  from injector import inject
17
18
  import logging
@@ -98,10 +99,9 @@ class Dispatcher:
98
99
  )
99
100
  i += 1
100
101
 
101
- # initialize the database for every company class
102
+ # register in the database every company class
102
103
  for company in self.company_classes.values():
103
- print(f'company: {company.__class__.__name__}')
104
- company.init_db()
104
+ company.register_company()
105
105
 
106
106
  def dispatch(self, company_name: str, action: str, **kwargs) -> str:
107
107
  company_key = company_name.lower()
@@ -179,19 +179,51 @@ class Dispatcher:
179
179
  tools.append(ai_tool)
180
180
  return tools
181
181
 
182
- def get_user_info(self, company_name: str, **kwargs) -> dict:
182
+ def get_user_info(self, company_name: str, user_identifier: str, is_local_user: bool) -> dict:
183
183
  if company_name not in self.company_classes:
184
184
  raise IAToolkitException(IAToolkitException.ErrorType.EXTERNAL_SOURCE_ERROR,
185
- f"Empresa no configurada: {company_name}")
185
+ f"Empresa no configurada: {company_name}")
186
+
187
+ raw_user_data = {}
188
+ if is_local_user:
189
+ # source 1: local user login into IAToolkit
190
+ raw_user_data = SessionManager.get('user', {})
191
+ else:
192
+ # source 2: external company user
193
+ company_instance = self.company_classes[company_name]
194
+ try:
195
+ raw_user_data = company_instance.get_user_info(user_identifier)
196
+ except Exception as e:
197
+ logging.exception(e)
198
+ raise IAToolkitException(IAToolkitException.ErrorType.EXTERNAL_SOURCE_ERROR,
199
+ f"Error en get_user_info de {company_name}: {str(e)}") from e
200
+
201
+ # always normalize the data for consistent structure
202
+ return self._normalize_user_data(raw_user_data, is_local_user)
203
+
204
+ def _normalize_user_data(self, raw_data: dict, is_local: bool) -> dict:
205
+ """
206
+ Asegura que los datos del usuario siempre tengan una estructura consistente.
207
+ """
208
+ # Valores por defecto para un perfil robusto
209
+ normalized_user = {
210
+ "id": raw_data.get("id", 0),
211
+ "user_email": raw_data.get("email", ""),
212
+ "user_fullname": raw_data.get("user_fullname", ""),
213
+ "super_user": raw_data.get("super_user", False),
214
+ "company_id": raw_data.get("company_id", 0),
215
+ "company_name": raw_data.get("company", ""),
216
+ "company_short_name": raw_data.get("company_short_name", ""),
217
+ "is_local": is_local,
218
+ "extras": raw_data.get("extras", {})
219
+ }
186
220
 
187
- company_instance = self.company_classes[company_name]
188
- try:
189
- return company_instance.get_user_info(**kwargs)
190
- except Exception as e:
191
- logging.exception(e)
192
- raise IAToolkitException(IAToolkitException.ErrorType.EXTERNAL_SOURCE_ERROR,
193
- f"Error en get_user_info de {company_name}: {str(e)}") from e
221
+ # get the extras from the raw data, if any
222
+ extras = raw_data.get("extras", {})
223
+ if isinstance(extras, dict):
224
+ normalized_user.update(extras)
194
225
 
226
+ return normalized_user
195
227
 
196
228
  def get_metadata_from_filename(self, company_name: str, filename: str) -> dict:
197
229
  if company_name not in self.company_classes:
@@ -206,6 +238,10 @@ class Dispatcher:
206
238
  raise IAToolkitException(IAToolkitException.ErrorType.EXTERNAL_SOURCE_ERROR,
207
239
  f"Error en get_metadata_from_filename de {company_name}: {str(e)}") from e
208
240
 
241
+ def get_company_instance(self, company_name: str):
242
+ """Returns the instance for a given company name."""
243
+ return self.company_classes.get(company_name)
244
+
209
245
  def get_registered_companies(self) -> dict:
210
246
  """Obtiene todas las empresas registradas (para debugging/admin)"""
211
247
  return {
@@ -23,7 +23,7 @@ class HistoryService:
23
23
  external_user_id: str = None,
24
24
  local_user_id: int = 0) -> dict:
25
25
  try:
26
- user_identifier = self.util.resolve_user_identifier(external_user_id, local_user_id)
26
+ user_identifier, _ = self.util.resolve_user_identifier(external_user_id, local_user_id)
27
27
  if not user_identifier:
28
28
  return {'error': "No se pudo resolver el identificador del usuario"}
29
29
 
@@ -79,13 +79,13 @@ class ProfileService:
79
79
  user_data = {
80
80
  "id": user.id,
81
81
  "email": user.email,
82
- "first_name": user.first_name,
83
- "last_name": user.last_name,
82
+ "user_fullname": f'{user.first_name} {user.last_name}',
84
83
  "super_user": user.super_user,
85
84
  "company_id": company.id,
86
85
  "company": company.name,
87
86
  "company_short_name": company.short_name,
88
- "company_logo": company.logo_file
87
+ "user_is_local": True, # origin of data
88
+ "extras": {} # company specific data
89
89
  }
90
90
  SessionManager.set('user', user_data)
91
91
 
@@ -12,6 +12,7 @@ from repositories.models import Prompt, PromptCategory, Company
12
12
  import os
13
13
  from common.exceptions import IAToolkitException
14
14
  from pathlib import Path
15
+ import importlib.resources
15
16
 
16
17
 
17
18
  class PromptService:
@@ -33,18 +34,16 @@ class PromptService:
33
34
 
34
35
  prompt_filename = prompt_name.lower() + '.prompt'
35
36
  if is_system_prompt:
36
- template_dir = 'src/system_prompts'
37
+ if not importlib.resources.files('iatoolkit.system_prompts').joinpath(prompt_filename).is_file():
38
+ raise IAToolkitException(IAToolkitException.ErrorType.INVALID_NAME,
39
+ f'No existe el archivo de prompt de sistemas: {prompt_filename}')
37
40
  else:
38
41
  template_dir = f'companies/{company.short_name}/prompts'
39
42
 
40
- # Guardar el filepath como una ruta relativa
41
- relative_prompt_path = os.path.join(template_dir, prompt_filename)
42
-
43
- # Validar la existencia del archivo usando la ruta absoluta
44
- absolute_prompt_path = os.path.join(os.getcwd(), relative_prompt_path)
45
- if not os.path.exists(absolute_prompt_path):
46
- raise IAToolkitException(IAToolkitException.ErrorType.INVALID_NAME,
47
- f'No existe el archivo de prompt: {absolute_prompt_path}')
43
+ relative_prompt_path = os.path.join(template_dir, prompt_filename)
44
+ if not os.path.exists(relative_prompt_path):
45
+ raise IAToolkitException(IAToolkitException.ErrorType.INVALID_NAME,
46
+ f'No existe el archivo de prompt: {relative_prompt_path}')
48
47
 
49
48
  prompt = Prompt(
50
49
  company_id=company.id if company else None,
@@ -53,7 +52,7 @@ class PromptService:
53
52
  order=order,
54
53
  category_id=category.id if category and not is_system_prompt else None,
55
54
  active=active,
56
- filepath=relative_prompt_path,
55
+ filename=prompt_filename,
57
56
  is_system_prompt=is_system_prompt,
58
57
  parameters=params
59
58
  )
@@ -75,7 +74,7 @@ class PromptService:
75
74
  raise IAToolkitException(IAToolkitException.ErrorType.DOCUMENT_NOT_FOUND,
76
75
  f"No se encontró el prompt '{prompt_name}' para la empresa '{company.short_name}'")
77
76
 
78
- absolute_filepath = os.path.join(execution_dir, user_prompt.filepath)
77
+ absolute_filepath = os.path.join(execution_dir, user_prompt.filename)
79
78
  if not os.path.exists(absolute_filepath):
80
79
  raise IAToolkitException(IAToolkitException.ErrorType.FILE_IO_ERROR,
81
80
  f"El archivo para el prompt '{prompt_name}' no existe: {absolute_filepath}")
@@ -103,25 +102,18 @@ class PromptService:
103
102
  try:
104
103
  system_prompt_content = []
105
104
 
106
- # get the filepaths for all system prompts
107
- current_dir = Path(__file__).resolve().parent
108
- project_root = current_dir.parent.parent
109
-
110
105
  # read all the system prompts from the database
111
106
  system_prompts = self.llm_query_repo.get_system_prompts()
112
107
 
113
108
  for prompt in system_prompts:
114
- # build the absolute filepath for reading it
115
- absolute_filepath = os.path.join(project_root, prompt.filepath)
116
- if not os.path.exists(absolute_filepath):
117
- logging.warning(f"El archivo para el prompt de sistema no existe: {absolute_filepath}")
118
- continue
119
109
  try:
120
- with open(absolute_filepath, 'r', encoding='utf-8') as f:
121
- system_prompt_content.append(f.read())
110
+ content = importlib.resources.read_text('iatoolkit.system_prompts', prompt.filename)
111
+ system_prompt_content.append(content)
112
+ except FileNotFoundError:
113
+ logging.warning(f"El archivo para el prompt de sistema no existe en el paquete: {prompt.filename}")
122
114
  except Exception as e:
123
115
  raise IAToolkitException(IAToolkitException.ErrorType.FILE_IO_ERROR,
124
- f"Error leyendo el archivo de prompt del sistema {absolute_filepath}: {e}")
116
+ f"Error leyendo el archivo de prompt del sistema '{prompt.filename}': {e}")
125
117
 
126
118
  # join the system prompts into a single string
127
119
  return "\n".join(system_prompt_content)
services/query_service.py CHANGED
@@ -65,7 +65,7 @@ class QueryService:
65
65
  model = self.model
66
66
 
67
67
  # Validate the user and company
68
- user_identifier = self.util.resolve_user_identifier(external_user_id, local_user_id)
68
+ user_identifier, is_local_user = self.util.resolve_user_identifier(external_user_id, local_user_id)
69
69
  if not user_identifier:
70
70
  raise IAToolkitException(IAToolkitException.ErrorType.INVALID_USER,
71
71
  "No se pudo resolver el identificador del usuario")
@@ -85,23 +85,25 @@ class QueryService:
85
85
 
86
86
  # 2. get dictionary with user information from company DB
87
87
  # user roles are read at this point from company db
88
- user_info = self.dispatcher.get_user_info(
88
+ user_profile = self.dispatcher.get_user_info(
89
89
  company_name=company_short_name,
90
- user_id=user_identifier
90
+ user_identifier=user_identifier,
91
+ is_local_user=is_local_user
91
92
  )
93
+
92
94
  # add the user logged in to the user_info dictionary
93
- user_info['user_id'] = user_identifier
95
+ user_profile['user_id'] = user_identifier
94
96
 
95
97
  # save the user information in the session context
96
98
  # it's needed for the jinja predefined prompts (filtering)
97
- self.session_context.save_user_session_data(company_short_name, user_identifier, user_info)
99
+ self.session_context.save_user_session_data(company_short_name, user_identifier, user_profile)
98
100
 
99
101
  # 3. render the iatoolkit main system prompt with the company/user information
100
102
  system_prompt_template = self.prompt_service.get_system_prompt()
101
103
  rendered_system_prompt = self.util.render_prompt_from_string(
102
104
  template_string=system_prompt_template,
103
105
  question=None,
104
- client_data=user_info,
106
+ client_data=user_profile,
105
107
  company=company,
106
108
  service_list=self.dispatcher.get_company_services(company)
107
109
  )
@@ -148,7 +150,7 @@ class QueryService:
148
150
  client_data: dict = {},
149
151
  files: list = []) -> dict:
150
152
  try:
151
- user_identifier = self.util.resolve_user_identifier(external_user_id, local_user_id)
153
+ user_identifier, is_local_user = self.util.resolve_user_identifier(external_user_id, local_user_id)
152
154
  if not user_identifier:
153
155
  return {"error": True,
154
156
  "error_message": "No se pudo identificar al usuario"}
@@ -1,27 +0,0 @@
1
- iatoolkit/__init__.py,sha256=JdcXIcvFFTMy2XI9ccEws_pCklilDkPPEb7RaQNf7oY,1444
2
- iatoolkit/base_company.py,sha256=VWfpNofFlmgHQQK8BCw2KSOPLd2DM9eA68lGQ3SDE7M,1639
3
- iatoolkit/company_registry.py,sha256=cRaez-VBo1icnUNKmkQqo_Xlr8UKWFoYEMZ70XP6Jgk,2702
4
- iatoolkit/iatoolkit.py,sha256=SHuCY9SAThT91qs9StTBwI4U-1ttYbVfRoma1j_7E8g,16793
5
- services/__init__.py,sha256=fSvSfIcPW1dHwTBY1hQ5dBEhaoorzk_GzR4G46gD8tY,173
6
- services/api_service.py,sha256=InIKTc64BWcp4U4tYKHz28x4ErPxIfvR9x3ZlxJZlXs,2911
7
- services/benchmark_service.py,sha256=g9JVrmAqIe_iI0D1DwdQ6DJ2_FJRCTndarESNSVfhbw,5907
8
- services/dispatcher_service.py,sha256=CBslIE5FsrST46JjpKW1k_XHnIRtN9WehEr6LKadZlU,13360
9
- services/document_service.py,sha256=sm5QtbrKs2dF9hpLuSLMB-IMWYNBD7yWHv3rd80aD0o,5960
10
- services/excel_service.py,sha256=wE9Udbyb96kGRSnZZ6KM2mbE484rKjTEhta9GKKpy-8,3630
11
- services/file_processor_service.py,sha256=82UArWtwpr94CAMkkoRP0_nPtoqItymdKSIABS0Xkxw,2943
12
- services/history_service.py,sha256=dl-D7qgdnzpY9QhjuxJokBYZZ1AF0y59HbRzwpPet58,1654
13
- services/jwt_service.py,sha256=dC45Sn6FyzdzRiQJnzgkjN3Hy21V1imRxB0hTyWRvlA,3979
14
- services/load_documents_service.py,sha256=_-OTUih8Zk0m4dHqAhkE7kAwU2mbz_QoMrOKnrq7ZWs,8821
15
- services/mail_service.py,sha256=ystFit1LuYUC4ekYYebyiy1rqYQmxeL6K8h58MxEkOY,2233
16
- services/profile_service.py,sha256=YtnlXofXtvud4AHOFMmPlX9VO7mhs_Fglpc1PTulExc,17861
17
- services/prompt_manager_service.py,sha256=kKsqZyt2ZUWIHYTA5C6sfBk8sbXhvYF4QAUN9sOYk_s,7915
18
- services/query_service.py,sha256=Fx_P1WcuoAp_TyocN5LGlv_hc_03ImzU5QdAIqQg0ek,15591
19
- services/search_service.py,sha256=oJD6WRXCJBD7WUVHWWKxexRkhR8nQSrFtcPV3pFO2KQ,1153
20
- services/sql_service.py,sha256=H7CIPpXTcxLXLojD2fBFr_mIAD0PW1vEJhKHLfJi4Hk,1418
21
- services/tasks_service.py,sha256=hHJDlcsSOPtEleD6_Vv3pocfxWNmthIhmZSdnoWFpEM,6861
22
- services/user_feedback_service.py,sha256=YtCndRBekDEWYEbac431Ksn2gMO5iBrI3WqKK0xtShE,2513
23
- services/user_session_context_service.py,sha256=5qn7fqpuiU8KgMpU4M5-iRUsETumz1raBw-EeZLuE1A,3868
24
- iatoolkit-0.3.7.dist-info/METADATA,sha256=9veR_--w5S2gN0OyGvai1N0BX7XVDwzaLmwT88IFmRU,8801
25
- iatoolkit-0.3.7.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
26
- iatoolkit-0.3.7.dist-info/top_level.txt,sha256=dqlBbmgo9okD9d_WMR9uYzdup7Rxgj26yFF85jRGeu4,19
27
- iatoolkit-0.3.7.dist-info/RECORD,,