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

Files changed (150) hide show
  1. iatoolkit/__init__.py +27 -35
  2. iatoolkit/base_company.py +3 -35
  3. iatoolkit/cli_commands.py +18 -47
  4. iatoolkit/common/__init__.py +0 -0
  5. iatoolkit/common/exceptions.py +48 -0
  6. iatoolkit/common/interfaces/__init__.py +0 -0
  7. iatoolkit/common/interfaces/asset_storage.py +34 -0
  8. iatoolkit/common/interfaces/database_provider.py +39 -0
  9. iatoolkit/common/model_registry.py +159 -0
  10. iatoolkit/common/routes.py +138 -0
  11. iatoolkit/common/session_manager.py +26 -0
  12. iatoolkit/common/util.py +353 -0
  13. iatoolkit/company_registry.py +66 -29
  14. iatoolkit/core.py +514 -0
  15. iatoolkit/infra/__init__.py +5 -0
  16. iatoolkit/infra/brevo_mail_app.py +123 -0
  17. iatoolkit/infra/call_service.py +140 -0
  18. iatoolkit/infra/connectors/__init__.py +5 -0
  19. iatoolkit/infra/connectors/file_connector.py +17 -0
  20. iatoolkit/infra/connectors/file_connector_factory.py +57 -0
  21. iatoolkit/infra/connectors/google_cloud_storage_connector.py +53 -0
  22. iatoolkit/infra/connectors/google_drive_connector.py +68 -0
  23. iatoolkit/infra/connectors/local_file_connector.py +46 -0
  24. iatoolkit/infra/connectors/s3_connector.py +33 -0
  25. iatoolkit/infra/google_chat_app.py +57 -0
  26. iatoolkit/infra/llm_providers/__init__.py +0 -0
  27. iatoolkit/infra/llm_providers/deepseek_adapter.py +278 -0
  28. iatoolkit/infra/llm_providers/gemini_adapter.py +350 -0
  29. iatoolkit/infra/llm_providers/openai_adapter.py +124 -0
  30. iatoolkit/infra/llm_proxy.py +268 -0
  31. iatoolkit/infra/llm_response.py +45 -0
  32. iatoolkit/infra/redis_session_manager.py +122 -0
  33. iatoolkit/locales/en.yaml +222 -0
  34. iatoolkit/locales/es.yaml +225 -0
  35. iatoolkit/repositories/__init__.py +5 -0
  36. iatoolkit/repositories/database_manager.py +187 -0
  37. iatoolkit/repositories/document_repo.py +33 -0
  38. iatoolkit/repositories/filesystem_asset_repository.py +36 -0
  39. iatoolkit/repositories/llm_query_repo.py +105 -0
  40. iatoolkit/repositories/models.py +279 -0
  41. iatoolkit/repositories/profile_repo.py +171 -0
  42. iatoolkit/repositories/vs_repo.py +150 -0
  43. iatoolkit/services/__init__.py +5 -0
  44. iatoolkit/services/auth_service.py +193 -0
  45. {services → iatoolkit/services}/benchmark_service.py +7 -7
  46. iatoolkit/services/branding_service.py +153 -0
  47. iatoolkit/services/company_context_service.py +214 -0
  48. iatoolkit/services/configuration_service.py +375 -0
  49. iatoolkit/services/dispatcher_service.py +134 -0
  50. {services → iatoolkit/services}/document_service.py +20 -8
  51. iatoolkit/services/embedding_service.py +148 -0
  52. iatoolkit/services/excel_service.py +156 -0
  53. {services → iatoolkit/services}/file_processor_service.py +36 -21
  54. iatoolkit/services/history_manager_service.py +208 -0
  55. iatoolkit/services/i18n_service.py +104 -0
  56. iatoolkit/services/jwt_service.py +80 -0
  57. iatoolkit/services/language_service.py +89 -0
  58. iatoolkit/services/license_service.py +82 -0
  59. iatoolkit/services/llm_client_service.py +438 -0
  60. iatoolkit/services/load_documents_service.py +174 -0
  61. iatoolkit/services/mail_service.py +213 -0
  62. {services → iatoolkit/services}/profile_service.py +200 -101
  63. iatoolkit/services/prompt_service.py +303 -0
  64. iatoolkit/services/query_service.py +467 -0
  65. iatoolkit/services/search_service.py +55 -0
  66. iatoolkit/services/sql_service.py +169 -0
  67. iatoolkit/services/tool_service.py +246 -0
  68. iatoolkit/services/user_feedback_service.py +117 -0
  69. iatoolkit/services/user_session_context_service.py +213 -0
  70. iatoolkit/static/images/fernando.jpeg +0 -0
  71. iatoolkit/static/images/iatoolkit_core.png +0 -0
  72. iatoolkit/static/images/iatoolkit_logo.png +0 -0
  73. iatoolkit/static/js/chat_feedback_button.js +80 -0
  74. iatoolkit/static/js/chat_filepond.js +85 -0
  75. iatoolkit/static/js/chat_help_content.js +124 -0
  76. iatoolkit/static/js/chat_history_button.js +110 -0
  77. iatoolkit/static/js/chat_logout_button.js +36 -0
  78. iatoolkit/static/js/chat_main.js +401 -0
  79. iatoolkit/static/js/chat_model_selector.js +227 -0
  80. iatoolkit/static/js/chat_onboarding_button.js +103 -0
  81. iatoolkit/static/js/chat_prompt_manager.js +94 -0
  82. iatoolkit/static/js/chat_reload_button.js +38 -0
  83. iatoolkit/static/styles/chat_iatoolkit.css +559 -0
  84. iatoolkit/static/styles/chat_modal.css +133 -0
  85. iatoolkit/static/styles/chat_public.css +135 -0
  86. iatoolkit/static/styles/documents.css +598 -0
  87. iatoolkit/static/styles/landing_page.css +398 -0
  88. iatoolkit/static/styles/llm_output.css +148 -0
  89. iatoolkit/static/styles/onboarding.css +176 -0
  90. iatoolkit/system_prompts/__init__.py +0 -0
  91. iatoolkit/system_prompts/query_main.prompt +30 -23
  92. iatoolkit/system_prompts/sql_rules.prompt +47 -12
  93. iatoolkit/templates/_company_header.html +45 -0
  94. iatoolkit/templates/_login_widget.html +42 -0
  95. iatoolkit/templates/base.html +78 -0
  96. iatoolkit/templates/change_password.html +66 -0
  97. iatoolkit/templates/chat.html +337 -0
  98. iatoolkit/templates/chat_modals.html +185 -0
  99. iatoolkit/templates/error.html +51 -0
  100. iatoolkit/templates/forgot_password.html +51 -0
  101. iatoolkit/templates/onboarding_shell.html +106 -0
  102. iatoolkit/templates/signup.html +79 -0
  103. iatoolkit/views/__init__.py +5 -0
  104. iatoolkit/views/base_login_view.py +96 -0
  105. iatoolkit/views/change_password_view.py +116 -0
  106. iatoolkit/views/chat_view.py +76 -0
  107. iatoolkit/views/embedding_api_view.py +65 -0
  108. iatoolkit/views/forgot_password_view.py +75 -0
  109. iatoolkit/views/help_content_api_view.py +54 -0
  110. iatoolkit/views/history_api_view.py +56 -0
  111. iatoolkit/views/home_view.py +63 -0
  112. iatoolkit/views/init_context_api_view.py +74 -0
  113. iatoolkit/views/llmquery_api_view.py +59 -0
  114. iatoolkit/views/load_company_configuration_api_view.py +49 -0
  115. iatoolkit/views/load_document_api_view.py +65 -0
  116. iatoolkit/views/login_view.py +170 -0
  117. iatoolkit/views/logout_api_view.py +57 -0
  118. iatoolkit/views/profile_api_view.py +46 -0
  119. iatoolkit/views/prompt_api_view.py +37 -0
  120. iatoolkit/views/root_redirect_view.py +22 -0
  121. iatoolkit/views/signup_view.py +100 -0
  122. iatoolkit/views/static_page_view.py +27 -0
  123. iatoolkit/views/user_feedback_api_view.py +60 -0
  124. iatoolkit/views/users_api_view.py +33 -0
  125. iatoolkit/views/verify_user_view.py +60 -0
  126. iatoolkit-0.107.4.dist-info/METADATA +268 -0
  127. iatoolkit-0.107.4.dist-info/RECORD +132 -0
  128. iatoolkit-0.107.4.dist-info/licenses/LICENSE +21 -0
  129. iatoolkit-0.107.4.dist-info/licenses/LICENSE_COMMUNITY.md +15 -0
  130. {iatoolkit-0.3.9.dist-info → iatoolkit-0.107.4.dist-info}/top_level.txt +0 -1
  131. iatoolkit/iatoolkit.py +0 -413
  132. iatoolkit/system_prompts/arquitectura.prompt +0 -32
  133. iatoolkit-0.3.9.dist-info/METADATA +0 -252
  134. iatoolkit-0.3.9.dist-info/RECORD +0 -32
  135. services/__init__.py +0 -5
  136. services/api_service.py +0 -75
  137. services/dispatcher_service.py +0 -351
  138. services/excel_service.py +0 -98
  139. services/history_service.py +0 -45
  140. services/jwt_service.py +0 -91
  141. services/load_documents_service.py +0 -212
  142. services/mail_service.py +0 -62
  143. services/prompt_manager_service.py +0 -172
  144. services/query_service.py +0 -334
  145. services/search_service.py +0 -32
  146. services/sql_service.py +0 -42
  147. services/tasks_service.py +0 -188
  148. services/user_feedback_service.py +0 -67
  149. services/user_session_context_service.py +0 -85
  150. {iatoolkit-0.3.9.dist-info → iatoolkit-0.107.4.dist-info}/WHEEL +0 -0
@@ -1,212 +0,0 @@
1
- # Copyright (c) 2024 Fernando Libedinsky
2
- # Producto: IAToolkit
3
- # Todos los derechos reservados.
4
- # En trámite de registro en el Registro de Propiedad Intelectual de Chile.
5
-
6
- from repositories.vs_repo import VSRepo
7
- from repositories.document_repo import DocumentRepo
8
- from repositories.profile_repo import ProfileRepo
9
- from repositories.llm_query_repo import LLMQueryRepo
10
- from repositories.models import Document, VSDoc, Company
11
- from services.document_service import DocumentService
12
- from langchain.text_splitter import RecursiveCharacterTextSplitter
13
- from infra.connectors.file_connector_factory import FileConnectorFactory
14
- from services.file_processor_service import FileProcessorConfig, FileProcessor
15
- from services.dispatcher_service import Dispatcher
16
- from common.exceptions import IAToolkitException
17
- import logging
18
- import base64
19
- from injector import inject
20
- from typing import Dict
21
-
22
-
23
- class LoadDocumentsService:
24
- @inject
25
- def __init__(self,
26
- file_connector_factory: FileConnectorFactory,
27
- doc_service: DocumentService,
28
- doc_repo: DocumentRepo,
29
- vector_store: VSRepo,
30
- profile_repo: ProfileRepo,
31
- dispatcher: Dispatcher,
32
- llm_query_repo: LLMQueryRepo
33
- ):
34
- self.doc_service = doc_service
35
- self.doc_repo = doc_repo
36
- self.profile_repo = profile_repo
37
- self.llm_query_repo = llm_query_repo
38
- self.vector_store = vector_store
39
- self.file_connector_factory = file_connector_factory
40
- self.dispatcher = dispatcher
41
- self.company = None
42
-
43
- # lower warnings
44
- logging.getLogger().setLevel(logging.ERROR)
45
-
46
- self.splitter = RecursiveCharacterTextSplitter(
47
- chunk_size=1000,
48
- chunk_overlap=100,
49
- separators=["\n\n", "\n", "."]
50
- )
51
-
52
- # load the files for all of the companies.
53
- def load(self, doc_type: str = None):
54
- # doc_type: an optional document_type for loading
55
- files_loaded = 0
56
- companies = self.profile_repo.get_companies()
57
-
58
- for company in companies:
59
- load_config = company.parameters.get('load', {})
60
- if not load_config:
61
- continue
62
-
63
- print(f"Cargando datos de ** {company.short_name} **")
64
- self.company = company
65
-
66
- # Si hay configuraciones de tipos de documento específicos
67
- doc_types_config = load_config.get('document_types', {})
68
-
69
- if doc_types_config and len(doc_types_config) > 0:
70
- # Si se especificó un tipo de documento, cargar solo ese tipo
71
- if doc_type and doc_type in doc_types_config:
72
- files_loaded += self._load_document_type(company, doc_type, doc_types_config[doc_type])
73
- # Si no se especificó, cargar todos los tipos configurados
74
- elif not doc_type:
75
- for type_name, type_config in doc_types_config.items():
76
- files_loaded += self._load_document_type(company, type_name, type_config)
77
- else:
78
- # Comportamiento anterior: usar la configuración general
79
- connector = load_config.get('connector', {})
80
- if not connector:
81
- raise IAToolkitException(IAToolkitException.ErrorType.MISSING_PARAMETER,
82
- f"Falta configurar conector en empresa {company.short_name}")
83
-
84
- files_loaded += self.load_data_source(connector)
85
-
86
- return {'message': f'{files_loaded} files processed'}
87
-
88
- def _load_document_type(self, company: Company, doc_type_name: str, type_config: Dict) -> int:
89
- # load specific document_types for a company
90
- connector = type_config.get('connector')
91
- if not connector:
92
- logging.warning(f"Falta configurar conector para tipo {doc_type_name} en empresa {company.short_name}")
93
- raise IAToolkitException(IAToolkitException.ErrorType.MISSING_PARAMETER,
94
- f"Falta configurar conector para tipo {doc_type_name} en empresa {company.short_name}")
95
-
96
- # get the metadata for this connector
97
- predefined_metadata = type_config.get('metadata', {})
98
-
99
- # config specific filters
100
- filters = type_config.get('filters', {"filename_contains": ".pdf"})
101
-
102
- return self.load_data_source(connector, predefined_metadata, filters)
103
-
104
- def load_data_source(self, connector_config: Dict, predefined_metadata: Dict = None, filters: Dict = None):
105
- """
106
- Carga archivos desde una fuente de datos usando un conector.
107
-
108
- Args:
109
- connector_config: Configuración del conector
110
- predefined_metadata: Metadatos predefinidos para todos los documentos de esta fuente
111
- filters: Filtros específicos para esta carga
112
-
113
- Returns:
114
- int o dict: Número de archivos procesados o diccionario de error
115
- """
116
- try:
117
- # Si no se proporcionaron filtros, usar el predeterminado
118
- if not filters:
119
- filters = {"filename_contains": ".pdf"}
120
-
121
- # Pasar metadata predefinida como parte del contexto al procesador
122
- # para que esté disponible en la función load_file
123
- extra_context = {}
124
- if predefined_metadata:
125
- extra_context['metadata'] = predefined_metadata
126
-
127
- # config the processor
128
- processor_config = FileProcessorConfig(
129
- context=extra_context,
130
- filters=filters,
131
- action=self.load_file,
132
- continue_on_error=True,
133
- echo=True
134
- )
135
-
136
- connector = self.file_connector_factory.create(connector_config)
137
- processor = FileProcessor(connector, processor_config)
138
-
139
- # process the files
140
- processor.process_files()
141
-
142
- return processor.processed_files
143
- except Exception as e:
144
- logging.exception("Loading files error: %s", str(e))
145
- return {"error": str(e)}
146
-
147
- # load an individual filename
148
- # this method is set up on the FileProcessorConfig object
149
- def load_file(self, filename: str, content: bytes, context: dict = {}, company: Company = None):
150
- if not company:
151
- company = self.company
152
-
153
- # check if file exist in repositories
154
- if self.doc_repo.get(company=company,filename=filename):
155
- return
156
-
157
- try:
158
- # extract text from the document
159
- document_content = self.doc_service.file_to_txt(filename, content)
160
- content_base64 = base64.b64encode(content).decode('utf-8')
161
-
162
- # generate metada based on the filename structure
163
- dynamic_metadata = self.dispatcher.get_metadata_from_filename(company_name=company.short_name, filename=filename)
164
-
165
- # Obtener metadatos del contexto si existen
166
- context_metadata = context.get('metadata', {}).copy() if context else {}
167
-
168
- # Fusionar los metadatos. El orden de prioridad es:
169
- # 1. dynamic_metadata (tiene mayor prioridad)
170
- # 2. context_metadata (del parámetro context)
171
- # Los valores en dynamic_metadata tendrán precedencia sobre los de context_metadata
172
- final_meta = {**context_metadata, **dynamic_metadata}
173
-
174
- # save the file in the document repositories
175
- new_document = Document(
176
- company_id=company.id,
177
- filename=filename,
178
- content=document_content,
179
- content_b64=content_base64,
180
- meta=final_meta
181
- )
182
-
183
- # insert the document into the Database (without commit)
184
- session = self.doc_repo.session
185
- session.add(new_document)
186
- session.flush() # get the ID without commit
187
-
188
- # split the content, and create the chunk list
189
- splitted_content = self.splitter.split_text(document_content)
190
- chunk_list = [
191
- VSDoc(
192
- company_id=company.id,
193
- document_id=new_document.id,
194
- text=text
195
- )
196
- for text in splitted_content
197
- ]
198
-
199
- # save to vector store
200
- self.vector_store.add_document(chunk_list)
201
-
202
- # confirm the transaction
203
- session.commit()
204
-
205
- return new_document
206
- except Exception as e:
207
- self.doc_repo.session.rollback()
208
-
209
- # if something fails, throw exception
210
- logging.exception("Error procesando el archivo %s: %s", filename, str(e))
211
- raise IAToolkitException(IAToolkitException.ErrorType.LOAD_DOCUMENT_ERROR,
212
- f"Error al procesar el archivo {filename}")
services/mail_service.py DELETED
@@ -1,62 +0,0 @@
1
- # Copyright (c) 2024 Fernando Libedinsky
2
- # Producto: IAToolkit
3
- # Todos los derechos reservados.
4
- # En trámite de registro en el Registro de Propiedad Intelectual de Chile.
5
-
6
- from infra.mail_app import MailApp
7
- from injector import inject
8
- from pathlib import Path
9
- from common.exceptions import IAToolkitException
10
- import base64
11
-
12
- TEMP_DIR = Path("static/temp")
13
-
14
- class MailService:
15
- @inject
16
- def __init__(self, mail_app: MailApp):
17
- self.mail_app = mail_app
18
-
19
- def _read_token_bytes(self, token: str) -> bytes:
20
- # Defensa simple contra path traversal
21
- if not token or "/" in token or "\\" in token or token.startswith("."):
22
- raise IAToolkitException(IAToolkitException.ErrorType.MAIL_ERROR,
23
- "attachment_token inválido")
24
- path = TEMP_DIR / token
25
- if not path.is_file():
26
- raise IAToolkitException(IAToolkitException.ErrorType.MAIL_ERROR,
27
- f"Adjunto no encontrado: {token}")
28
- return path.read_bytes()
29
-
30
- def send_mail(self, **kwargs):
31
- from_email = kwargs.get('from_email', 'iatoolkit@iatoolkit.com')
32
- recipient = kwargs.get('recipient')
33
- subject = kwargs.get('subject')
34
- body = kwargs.get('body')
35
- attachments = kwargs.get('attachments')
36
-
37
- # Normalizar a payload de MailApp (name + base64 content)
38
- norm_attachments = []
39
- for a in attachments or []:
40
- if a.get("attachment_token"):
41
- raw = self._read_token_bytes(a["attachment_token"])
42
- norm_attachments.append({
43
- "filename": a["filename"],
44
- "content": base64.b64encode(raw).decode("utf-8"),
45
- })
46
- else:
47
- # asumo que ya viene un base64
48
- norm_attachments.append({
49
- "filename": a["filename"],
50
- "content": a["content"]
51
- })
52
-
53
- self.sender = {"email": from_email, "name": "IAToolkit"}
54
-
55
- response = self.mail_app.send_email(
56
- sender=self.sender,
57
- to=recipient,
58
- subject=subject,
59
- body=body,
60
- attachments=norm_attachments)
61
-
62
- return 'mail enviado'
@@ -1,172 +0,0 @@
1
- # Copyright (c) 2024 Fernando Libedinsky
2
- # Producto: IAToolkit
3
- # Todos los derechos reservados.
4
- # En trámite de registro en el Registro de Propiedad Intelectual de Chile.
5
-
6
- from injector import inject
7
- from repositories.llm_query_repo import LLMQueryRepo
8
- import logging
9
- from repositories.profile_repo import ProfileRepo
10
- from collections import defaultdict
11
- from repositories.models import Prompt, PromptCategory, Company
12
- import os
13
- from common.exceptions import IAToolkitException
14
- from pathlib import Path
15
- import importlib.resources
16
-
17
-
18
- class PromptService:
19
- @inject
20
- def __init__(self, llm_query_repo: LLMQueryRepo, profile_repo: ProfileRepo):
21
- self.llm_query_repo = llm_query_repo
22
- self.profile_repo = profile_repo
23
-
24
- def create_prompt(self,
25
- prompt_name: str,
26
- description: str,
27
- order: int,
28
- company: Company = None,
29
- category: PromptCategory = None,
30
- active: bool = True,
31
- is_system_prompt: bool = False,
32
- params: dict = {}
33
- ):
34
-
35
- prompt_filename = prompt_name.lower() + '.prompt'
36
- if is_system_prompt:
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}')
40
- else:
41
- template_dir = f'companies/{company.short_name}/prompts'
42
-
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}')
47
-
48
- prompt = Prompt(
49
- company_id=company.id if company else None,
50
- name=prompt_name,
51
- description=description,
52
- order=order,
53
- category_id=category.id if category and not is_system_prompt else None,
54
- active=active,
55
- filename=prompt_filename,
56
- is_system_prompt=is_system_prompt,
57
- parameters=params
58
- )
59
-
60
- try:
61
- self.llm_query_repo.create_or_update_prompt(prompt)
62
- except Exception as e:
63
- raise IAToolkitException(IAToolkitException.ErrorType.DATABASE_ERROR,
64
- f'error creating prompt "{prompt_name}": {str(e)}')
65
-
66
- def get_prompt_content(self, company: Company, prompt_name: str):
67
- try:
68
- user_prompt_content = []
69
- execution_dir = os.getcwd()
70
-
71
- # get the user prompt
72
- user_prompt = self.llm_query_repo.get_prompt_by_name(company, prompt_name)
73
- if not user_prompt:
74
- raise IAToolkitException(IAToolkitException.ErrorType.DOCUMENT_NOT_FOUND,
75
- f"No se encontró el prompt '{prompt_name}' para la empresa '{company.short_name}'")
76
-
77
- absolute_filepath = os.path.join(execution_dir, user_prompt.filename)
78
- if not os.path.exists(absolute_filepath):
79
- raise IAToolkitException(IAToolkitException.ErrorType.FILE_IO_ERROR,
80
- f"El archivo para el prompt '{prompt_name}' no existe: {absolute_filepath}")
81
-
82
- try:
83
- with open(absolute_filepath, 'r', encoding='utf-8') as f:
84
- user_prompt_content = f.read()
85
- except Exception as e:
86
- raise IAToolkitException(IAToolkitException.ErrorType.FILE_IO_ERROR,
87
- f"Error leyendo el archivo de prompt '{prompt_name}' en {absolute_filepath}: {e}")
88
-
89
- return user_prompt_content
90
-
91
- except IAToolkitException:
92
- # Vuelve a lanzar las IAToolkitException que ya hemos manejado
93
- # para que no sean capturadas por el siguiente bloque.
94
- raise
95
- except Exception as e:
96
- logging.exception(
97
- f"Error al obtener el contenido del prompt para la empresa '{company.short_name}' y prompt '{prompt_name}': {e}")
98
- raise IAToolkitException(IAToolkitException.ErrorType.PROMPT_ERROR,
99
- f'Error al obtener el contenido del prompt "{prompt_name}" para la empresa {company.short_name}: {str(e)}')
100
-
101
- def get_system_prompt(self):
102
- try:
103
- system_prompt_content = []
104
-
105
- # read all the system prompts from the database
106
- system_prompts = self.llm_query_repo.get_system_prompts()
107
-
108
- for prompt in system_prompts:
109
- try:
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}")
114
- except Exception as e:
115
- raise IAToolkitException(IAToolkitException.ErrorType.FILE_IO_ERROR,
116
- f"Error leyendo el archivo de prompt del sistema '{prompt.filename}': {e}")
117
-
118
- # join the system prompts into a single string
119
- return "\n".join(system_prompt_content)
120
-
121
- except IAToolkitException:
122
- raise
123
- except Exception as e:
124
- logging.exception(
125
- f"Error al obtener el contenido del prompt de sistema: {e}")
126
- raise IAToolkitException(IAToolkitException.ErrorType.PROMPT_ERROR,
127
- f'Error al obtener el contenido de los prompts de sistema": {str(e)}')
128
-
129
- def get_user_prompts(self, company_short_name: str) -> dict:
130
- try:
131
- # validate company
132
- company = self.profile_repo.get_company_by_short_name(company_short_name)
133
- if not company:
134
- return {'error': f'No existe la empresa: {company_short_name}'}
135
-
136
- # get all the prompts
137
- all_prompts = self.llm_query_repo.get_prompts(company)
138
-
139
- # Agrupar prompts por categoría
140
- prompts_by_category = defaultdict(list)
141
- for prompt in all_prompts:
142
- if prompt.active:
143
- if prompt.category:
144
- cat_key = (prompt.category.order, prompt.category.name)
145
- prompts_by_category[cat_key].append(prompt)
146
-
147
- # Ordenar los prompts dentro de cada categoría
148
- for cat_key in prompts_by_category:
149
- prompts_by_category[cat_key].sort(key=lambda p: p.order)
150
-
151
- # Crear la estructura de respuesta final, ordenada por la categoría
152
- categorized_prompts = []
153
-
154
- # Ordenar las categorías por su 'order'
155
- sorted_categories = sorted(prompts_by_category.items(), key=lambda item: item[0][0])
156
-
157
- for (cat_order, cat_name), prompts in sorted_categories:
158
- categorized_prompts.append({
159
- 'category_name': cat_name,
160
- 'category_order': cat_order,
161
- 'prompts': [
162
- {'prompt': p.name, 'description': p.description, 'order': p.order}
163
- for p in prompts
164
- ]
165
- })
166
-
167
- return {'message': categorized_prompts}
168
-
169
- except Exception as e:
170
- logging.error(f"Error en get_prompts: {e}")
171
- return {'error': str(e)}
172
-