iatoolkit 0.3.3__py3-none-any.whl → 0.3.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.
- iatoolkit/__init__.py +11 -0
- iatoolkit/company_registry.py +12 -31
- iatoolkit/iatoolkit.py +41 -17
- {iatoolkit-0.3.3.dist-info → iatoolkit-0.3.4.dist-info}/METADATA +2 -2
- {iatoolkit-0.3.3.dist-info → iatoolkit-0.3.4.dist-info}/RECORD +11 -11
- services/api_service.py +56 -11
- services/dispatcher_service.py +13 -10
- services/profile_service.py +1 -1
- services/prompt_manager_service.py +8 -8
- {iatoolkit-0.3.3.dist-info → iatoolkit-0.3.4.dist-info}/WHEEL +0 -0
- {iatoolkit-0.3.3.dist-info → iatoolkit-0.3.4.dist-info}/top_level.txt +0 -0
iatoolkit/__init__.py
CHANGED
|
@@ -22,7 +22,11 @@ from services.dispatcher_service import Dispatcher
|
|
|
22
22
|
from services.document_service import DocumentService
|
|
23
23
|
from services.search_service import SearchService
|
|
24
24
|
from repositories.profile_repo import ProfileRepo
|
|
25
|
+
from repositories.llm_query_repo import LLMQueryRepo
|
|
25
26
|
from repositories.database_manager import DatabaseManager
|
|
27
|
+
from infra.call_service import CallServiceClient
|
|
28
|
+
from common.util import Utility
|
|
29
|
+
from repositories.models import Base, Company, Function, TaskType
|
|
26
30
|
|
|
27
31
|
|
|
28
32
|
__all__ = [
|
|
@@ -37,5 +41,12 @@ __all__ = [
|
|
|
37
41
|
'DocumentService',
|
|
38
42
|
'SearchService',
|
|
39
43
|
'ProfileRepo',
|
|
44
|
+
'LLMQueryRepo',
|
|
40
45
|
'DatabaseManager',
|
|
46
|
+
'CallServiceClient',
|
|
47
|
+
'Utility',
|
|
48
|
+
'Company',
|
|
49
|
+
'Function',
|
|
50
|
+
'TaskType',
|
|
51
|
+
'Base',
|
|
41
52
|
]
|
iatoolkit/company_registry.py
CHANGED
|
@@ -8,10 +8,8 @@ import logging
|
|
|
8
8
|
|
|
9
9
|
class CompanyRegistry:
|
|
10
10
|
"""
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
Permite a los clientes registrar sus clases de empresa de forma explícita
|
|
14
|
-
en lugar de usar autodiscovery.
|
|
11
|
+
Company registry with dependency injection support.
|
|
12
|
+
Allow the client to register companies and instantiate them with dependency injection.
|
|
15
13
|
"""
|
|
16
14
|
|
|
17
15
|
def __init__(self):
|
|
@@ -19,22 +17,6 @@ class CompanyRegistry:
|
|
|
19
17
|
self._company_instances: Dict[str, BaseCompany] = {}
|
|
20
18
|
self._injector = None
|
|
21
19
|
|
|
22
|
-
def register_company(self, name: str, company_class: Type[BaseCompany]) -> None:
|
|
23
|
-
"""
|
|
24
|
-
Registra una clase de empresa.
|
|
25
|
-
|
|
26
|
-
Args:
|
|
27
|
-
name: Nombre de la empresa (ej: 'maxxa')
|
|
28
|
-
company_class: Clase que hereda de BaseCompany
|
|
29
|
-
"""
|
|
30
|
-
if not issubclass(company_class, BaseCompany):
|
|
31
|
-
raise ValueError(f"La clase {company_class.__name__} debe heredar de BaseCompany")
|
|
32
|
-
|
|
33
|
-
company_key = name.lower()
|
|
34
|
-
self._company_classes[company_key] = company_class
|
|
35
|
-
|
|
36
|
-
logging.info(f"Empresa registrada: {company_key} -> {company_class.__name__}")
|
|
37
|
-
|
|
38
20
|
def set_injector(self, injector) -> None:
|
|
39
21
|
"""Establece el injector para crear instancias con dependencias"""
|
|
40
22
|
self._injector = injector
|
|
@@ -65,34 +47,33 @@ class CompanyRegistry:
|
|
|
65
47
|
return self._company_instances.copy()
|
|
66
48
|
|
|
67
49
|
def get_registered_companies(self) -> Dict[str, Type[BaseCompany]]:
|
|
68
|
-
"""Retorna las clases registradas"""
|
|
69
50
|
return self._company_classes.copy()
|
|
70
51
|
|
|
71
|
-
def get_company_instances(self) -> Dict[str, BaseCompany]:
|
|
72
|
-
"""Retorna las instancias de empresas"""
|
|
73
|
-
return self._company_instances.copy()
|
|
74
|
-
|
|
75
52
|
def clear(self) -> None:
|
|
76
53
|
"""Limpia el registro (útil para tests)"""
|
|
77
54
|
self._company_classes.clear()
|
|
78
55
|
self._company_instances.clear()
|
|
79
56
|
|
|
80
57
|
|
|
81
|
-
#
|
|
58
|
+
# global instance of the company registry
|
|
82
59
|
_company_registry = CompanyRegistry()
|
|
83
60
|
|
|
84
61
|
|
|
85
62
|
def register_company(name: str, company_class: Type[BaseCompany]) -> None:
|
|
86
63
|
"""
|
|
87
|
-
|
|
64
|
+
Public function to register a company.
|
|
88
65
|
|
|
89
66
|
Args:
|
|
90
|
-
name:
|
|
91
|
-
company_class:
|
|
67
|
+
name: Name of the company
|
|
68
|
+
company_class: Class that inherits from BaseCompany
|
|
92
69
|
"""
|
|
93
|
-
|
|
70
|
+
if not issubclass(company_class, BaseCompany):
|
|
71
|
+
raise ValueError(f"La clase {company_class.__name__} debe heredar de BaseCompany")
|
|
72
|
+
|
|
73
|
+
company_key = name.lower()
|
|
74
|
+
_company_registry._company_classes[company_key] = company_class
|
|
94
75
|
|
|
95
76
|
|
|
96
77
|
def get_company_registry() -> CompanyRegistry:
|
|
97
|
-
"""
|
|
78
|
+
"""get the global company registry instance"""
|
|
98
79
|
return _company_registry
|
iatoolkit/iatoolkit.py
CHANGED
|
@@ -19,7 +19,6 @@ import click
|
|
|
19
19
|
from typing import Optional, Dict, Any
|
|
20
20
|
from repositories.database_manager import DatabaseManager
|
|
21
21
|
from injector import Binder, singleton, Injector
|
|
22
|
-
from .toolkit_config import IAToolkitConfig
|
|
23
22
|
|
|
24
23
|
VERSION = "2.0.0"
|
|
25
24
|
|
|
@@ -51,9 +50,9 @@ class IAToolkit:
|
|
|
51
50
|
return
|
|
52
51
|
|
|
53
52
|
self.config = config or {}
|
|
54
|
-
self.app
|
|
55
|
-
self.db_manager
|
|
56
|
-
self._injector
|
|
53
|
+
self.app = None
|
|
54
|
+
self.db_manager = None
|
|
55
|
+
self._injector = None
|
|
57
56
|
|
|
58
57
|
@classmethod
|
|
59
58
|
def get_instance(cls) -> 'IAToolkit':
|
|
@@ -68,7 +67,7 @@ class IAToolkit:
|
|
|
68
67
|
def create_iatoolkit(self):
|
|
69
68
|
"""
|
|
70
69
|
Creates, configures, and returns the Flask application instance.
|
|
71
|
-
|
|
70
|
+
this is the main entry point for the application factory.
|
|
72
71
|
"""
|
|
73
72
|
self._setup_logging()
|
|
74
73
|
|
|
@@ -78,12 +77,8 @@ class IAToolkit:
|
|
|
78
77
|
# Step 2: Set up the core components that DI depends on
|
|
79
78
|
self._setup_database()
|
|
80
79
|
|
|
81
|
-
# Step 3: Create the Injector
|
|
82
|
-
|
|
83
|
-
self._injector = Injector([
|
|
84
|
-
toolkit_config_module,
|
|
85
|
-
self._configure_core_dependencies # This method binds services, repos, etc.
|
|
86
|
-
])
|
|
80
|
+
# Step 3: Create the Injector and configure all dependencies in one place
|
|
81
|
+
self._injector = Injector(self._configure_core_dependencies)
|
|
87
82
|
|
|
88
83
|
# Step 4: Register routes using the fully configured injector
|
|
89
84
|
self._register_routes()
|
|
@@ -102,7 +97,6 @@ class IAToolkit:
|
|
|
102
97
|
logging.info(f"🎉 IAToolkit v{VERSION} inicializado correctamente")
|
|
103
98
|
return self.app
|
|
104
99
|
|
|
105
|
-
|
|
106
100
|
def _get_config_value(self, key: str, default=None):
|
|
107
101
|
"""Obtiene un valor de configuración, primero del dict config, luego de env vars"""
|
|
108
102
|
return self.config.get(key, os.getenv(key, default))
|
|
@@ -228,7 +222,8 @@ class IAToolkit:
|
|
|
228
222
|
"""⚙️ Configures all system dependencies."""
|
|
229
223
|
try:
|
|
230
224
|
# Core dependencies
|
|
231
|
-
binder.bind(
|
|
225
|
+
binder.bind(Flask, to=self.app, scope=singleton)
|
|
226
|
+
binder.bind(DatabaseManager, to=self.db_manager, scope=singleton)
|
|
232
227
|
|
|
233
228
|
# Bind all application components by calling the specific methods
|
|
234
229
|
self._bind_repositories(binder)
|
|
@@ -317,16 +312,17 @@ class IAToolkit:
|
|
|
317
312
|
|
|
318
313
|
def _setup_cli_commands(self):
|
|
319
314
|
"""⌨️ Configura comandos CLI básicos"""
|
|
315
|
+
from services.dispatcher_service import Dispatcher
|
|
316
|
+
from services.profile_service import ProfileService
|
|
320
317
|
|
|
321
318
|
@self.app.cli.command("init-db")
|
|
322
319
|
def init_db():
|
|
323
320
|
"""🗄️ Inicializa la base de datos del sistema"""
|
|
324
321
|
try:
|
|
325
|
-
|
|
326
|
-
dispatcher = self._get_injector().get(Dispatcher)
|
|
322
|
+
dispatcher = self.get_injector().get(Dispatcher)
|
|
327
323
|
|
|
328
324
|
click.echo("🚀 Inicializando base de datos...")
|
|
329
|
-
dispatcher.
|
|
325
|
+
dispatcher.setup_all_companies()
|
|
330
326
|
click.echo("✅ Base de datos inicializada correctamente")
|
|
331
327
|
|
|
332
328
|
except Exception as e:
|
|
@@ -334,6 +330,34 @@ class IAToolkit:
|
|
|
334
330
|
click.echo(f"❌ Error: {e}")
|
|
335
331
|
|
|
336
332
|
|
|
333
|
+
@self.app.cli.command("setup-company")
|
|
334
|
+
@click.argument("company_short_name")
|
|
335
|
+
def setup_company(company_short_name: str):
|
|
336
|
+
"""⚙️ Ejecuta el proceso de configuración para una nueva empresa."""
|
|
337
|
+
try:
|
|
338
|
+
# step 1: init the database
|
|
339
|
+
dispatcher = self.get_injector().get(Dispatcher)
|
|
340
|
+
click.echo("🚀 step 1 of 2: init companies in the database...")
|
|
341
|
+
dispatcher.setup_all_companies()
|
|
342
|
+
click.echo("✅ database is ready.")
|
|
343
|
+
|
|
344
|
+
# step 2: generate the api key
|
|
345
|
+
profile_service = self.get_injector().get(ProfileService)
|
|
346
|
+
click.echo(f"🔑 step 2 of 2: generating api-key for use in '{company_short_name}'...")
|
|
347
|
+
result = profile_service.new_api_key(company_short_name)
|
|
348
|
+
|
|
349
|
+
if 'error' in result:
|
|
350
|
+
click.echo(f"❌ Error in step 2: {result['error']}")
|
|
351
|
+
click.echo("👉 Make sure company name is correct and it's initialized in your app.")
|
|
352
|
+
else:
|
|
353
|
+
click.echo("Configuration es ready, add this variable to your environment")
|
|
354
|
+
click.echo(f"IATOOLKIT_API_KEY={result['api-key']}")
|
|
355
|
+
|
|
356
|
+
except Exception as e:
|
|
357
|
+
logging.exception(e)
|
|
358
|
+
click.echo(f"❌ Ocurrió un error inesperado durante la configuración: {e}")
|
|
359
|
+
|
|
360
|
+
|
|
337
361
|
def _setup_context_processors(self):
|
|
338
362
|
# Configura context processors para templates
|
|
339
363
|
@self.app.context_processor
|
|
@@ -362,7 +386,7 @@ class IAToolkit:
|
|
|
362
386
|
except:
|
|
363
387
|
return 'templates'
|
|
364
388
|
|
|
365
|
-
def
|
|
389
|
+
def get_injector(self) -> Injector:
|
|
366
390
|
"""Obtiene el injector actual"""
|
|
367
391
|
if not self._injector:
|
|
368
392
|
raise IAToolkitException(
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: iatoolkit
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.4
|
|
4
4
|
Summary: IAToolkit
|
|
5
5
|
Author: Fernando Libedinsky
|
|
6
6
|
License-Expression: MIT
|
|
7
|
-
Requires-Python: >=3.
|
|
7
|
+
Requires-Python: >=3.11
|
|
8
8
|
Description-Content-Type: text/markdown
|
|
9
9
|
Requires-Dist: aiohappyeyeballs==2.4.4
|
|
10
10
|
Requires-Dist: aiohttp==3.11.9
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
iatoolkit/__init__.py,sha256=
|
|
1
|
+
iatoolkit/__init__.py,sha256=JdcXIcvFFTMy2XI9ccEws_pCklilDkPPEb7RaQNf7oY,1444
|
|
2
2
|
iatoolkit/base_company.py,sha256=VWfpNofFlmgHQQK8BCw2KSOPLd2DM9eA68lGQ3SDE7M,1639
|
|
3
|
-
iatoolkit/company_registry.py,sha256=
|
|
4
|
-
iatoolkit/iatoolkit.py,sha256=
|
|
3
|
+
iatoolkit/company_registry.py,sha256=cRaez-VBo1icnUNKmkQqo_Xlr8UKWFoYEMZ70XP6Jgk,2702
|
|
4
|
+
iatoolkit/iatoolkit.py,sha256=K7d8fKKTk-Q-sMW6Ip58oleiosRP4e-pdc3E5GSoSMw,16450
|
|
5
5
|
services/__init__.py,sha256=fSvSfIcPW1dHwTBY1hQ5dBEhaoorzk_GzR4G46gD8tY,173
|
|
6
|
-
services/api_service.py,sha256=
|
|
6
|
+
services/api_service.py,sha256=InIKTc64BWcp4U4tYKHz28x4ErPxIfvR9x3ZlxJZlXs,2911
|
|
7
7
|
services/benchmark_service.py,sha256=g9JVrmAqIe_iI0D1DwdQ6DJ2_FJRCTndarESNSVfhbw,5907
|
|
8
|
-
services/dispatcher_service.py,sha256=
|
|
8
|
+
services/dispatcher_service.py,sha256=CBslIE5FsrST46JjpKW1k_XHnIRtN9WehEr6LKadZlU,13360
|
|
9
9
|
services/document_service.py,sha256=sm5QtbrKs2dF9hpLuSLMB-IMWYNBD7yWHv3rd80aD0o,5960
|
|
10
10
|
services/excel_service.py,sha256=wE9Udbyb96kGRSnZZ6KM2mbE484rKjTEhta9GKKpy-8,3630
|
|
11
11
|
services/file_processor_service.py,sha256=82UArWtwpr94CAMkkoRP0_nPtoqItymdKSIABS0Xkxw,2943
|
|
@@ -13,15 +13,15 @@ services/history_service.py,sha256=dl-D7qgdnzpY9QhjuxJokBYZZ1AF0y59HbRzwpPet58,1
|
|
|
13
13
|
services/jwt_service.py,sha256=dC45Sn6FyzdzRiQJnzgkjN3Hy21V1imRxB0hTyWRvlA,3979
|
|
14
14
|
services/load_documents_service.py,sha256=_-OTUih8Zk0m4dHqAhkE7kAwU2mbz_QoMrOKnrq7ZWs,8821
|
|
15
15
|
services/mail_service.py,sha256=ystFit1LuYUC4ekYYebyiy1rqYQmxeL6K8h58MxEkOY,2233
|
|
16
|
-
services/profile_service.py,sha256=
|
|
17
|
-
services/prompt_manager_service.py,sha256=
|
|
16
|
+
services/profile_service.py,sha256=YtnlXofXtvud4AHOFMmPlX9VO7mhs_Fglpc1PTulExc,17861
|
|
17
|
+
services/prompt_manager_service.py,sha256=kKsqZyt2ZUWIHYTA5C6sfBk8sbXhvYF4QAUN9sOYk_s,7915
|
|
18
18
|
services/query_service.py,sha256=Fx_P1WcuoAp_TyocN5LGlv_hc_03ImzU5QdAIqQg0ek,15591
|
|
19
19
|
services/search_service.py,sha256=oJD6WRXCJBD7WUVHWWKxexRkhR8nQSrFtcPV3pFO2KQ,1153
|
|
20
20
|
services/sql_service.py,sha256=H7CIPpXTcxLXLojD2fBFr_mIAD0PW1vEJhKHLfJi4Hk,1418
|
|
21
21
|
services/tasks_service.py,sha256=hHJDlcsSOPtEleD6_Vv3pocfxWNmthIhmZSdnoWFpEM,6861
|
|
22
22
|
services/user_feedback_service.py,sha256=YtCndRBekDEWYEbac431Ksn2gMO5iBrI3WqKK0xtShE,2513
|
|
23
23
|
services/user_session_context_service.py,sha256=5qn7fqpuiU8KgMpU4M5-iRUsETumz1raBw-EeZLuE1A,3868
|
|
24
|
-
iatoolkit-0.3.
|
|
25
|
-
iatoolkit-0.3.
|
|
26
|
-
iatoolkit-0.3.
|
|
27
|
-
iatoolkit-0.3.
|
|
24
|
+
iatoolkit-0.3.4.dist-info/METADATA,sha256=fiepVsfr8K9meQEu6b5xlOFZX4KJ1npM2m9mMgC6Y9Q,8801
|
|
25
|
+
iatoolkit-0.3.4.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
26
|
+
iatoolkit-0.3.4.dist-info/top_level.txt,sha256=dqlBbmgo9okD9d_WMR9uYzdup7Rxgj26yFF85jRGeu4,19
|
|
27
|
+
iatoolkit-0.3.4.dist-info/RECORD,,
|
services/api_service.py
CHANGED
|
@@ -7,24 +7,69 @@ from infra.call_service import CallServiceClient
|
|
|
7
7
|
from injector import inject
|
|
8
8
|
from common.exceptions import IAToolkitException
|
|
9
9
|
import json
|
|
10
|
-
|
|
10
|
+
from typing import Optional, Dict, Any, Union
|
|
11
11
|
|
|
12
12
|
class ApiService:
|
|
13
13
|
@inject
|
|
14
14
|
def __init__(self, call_service: CallServiceClient):
|
|
15
15
|
self.call_service = call_service
|
|
16
16
|
|
|
17
|
-
def call_api(
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
17
|
+
def call_api(
|
|
18
|
+
self,
|
|
19
|
+
endpoint: str,
|
|
20
|
+
method: str,
|
|
21
|
+
headers: Optional[Dict[str, str]] = None,
|
|
22
|
+
params: Optional[Dict[str, Union[str, int, float, bool]]] = None,
|
|
23
|
+
body: Optional[Dict[str, Any]] = None,
|
|
24
|
+
files: Optional[Dict[str, Any]] = None,
|
|
25
|
+
timeout: Union[int, float, tuple] = 10
|
|
26
|
+
) -> str:
|
|
27
|
+
"""
|
|
28
|
+
Ejecuta una llamada HTTP genérica.
|
|
29
|
+
|
|
30
|
+
- endpoint: URL completa
|
|
31
|
+
- method: GET | POST | PUT | DELETE (case-insensitive)
|
|
32
|
+
- headers: dict opcional de cabeceras
|
|
33
|
+
- params: dict opcional de query string
|
|
34
|
+
- body: dict opcional para JSON (POST/PUT/DELETE)
|
|
35
|
+
- files: dict opcional para multipart/form-data (prioriza POST files)
|
|
36
|
+
- timeout: segundos (int/float) o tuple (connect, read)
|
|
37
|
+
"""
|
|
38
|
+
m = (method or "").strip().lower()
|
|
39
|
+
|
|
40
|
+
if m == "get":
|
|
41
|
+
response, status_code = self.call_service.get(
|
|
42
|
+
endpoint, params=params, headers=headers, timeout=timeout
|
|
43
|
+
)
|
|
44
|
+
elif m == "post":
|
|
45
|
+
# Si vienen files → multipart; si no → JSON
|
|
46
|
+
if files:
|
|
47
|
+
response, status_code = self.call_service.post_files(
|
|
48
|
+
endpoint, data=files, params=params, headers=headers, timeout=timeout
|
|
49
|
+
)
|
|
50
|
+
else:
|
|
51
|
+
response, status_code = self.call_service.post(
|
|
52
|
+
endpoint=endpoint, json_dict=body, params=params, headers=headers, timeout=timeout
|
|
53
|
+
)
|
|
54
|
+
elif m == "put":
|
|
55
|
+
response, status_code = self.call_service.put(
|
|
56
|
+
endpoint, json_dict=body, params=params, headers=headers, timeout=timeout
|
|
57
|
+
)
|
|
58
|
+
elif m == "delete":
|
|
59
|
+
response, status_code = self.call_service.delete(
|
|
60
|
+
endpoint, json_dict=body, params=params, headers=headers, timeout=timeout
|
|
61
|
+
)
|
|
22
62
|
else:
|
|
23
|
-
raise IAToolkitException(
|
|
24
|
-
|
|
63
|
+
raise IAToolkitException(
|
|
64
|
+
IAToolkitException.ErrorType.INVALID_PARAMETER,
|
|
65
|
+
f"API error: método '{method}' no soportado"
|
|
66
|
+
)
|
|
25
67
|
|
|
26
|
-
if status_code
|
|
27
|
-
raise IAToolkitException(
|
|
28
|
-
|
|
68
|
+
if status_code < 200 or status_code >= 300:
|
|
69
|
+
raise IAToolkitException(
|
|
70
|
+
IAToolkitException.ErrorType.CALL_ERROR,
|
|
71
|
+
f"API {endpoint} error: {status_code}"
|
|
72
|
+
)
|
|
29
73
|
|
|
74
|
+
# Normalizamos a string JSON (para que el LLM lo consuma consistente)
|
|
30
75
|
return json.dumps(response)
|
services/dispatcher_service.py
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
from iatoolkit import current_iatoolkit
|
|
7
7
|
from common.exceptions import IAToolkitException
|
|
8
8
|
from services.prompt_manager_service import PromptService
|
|
9
|
+
from services.api_service import ApiService
|
|
9
10
|
from repositories.llm_query_repo import LLMQueryRepo
|
|
10
11
|
from repositories.models import Company, Function
|
|
11
12
|
from services.excel_service import ExcelService
|
|
@@ -23,10 +24,12 @@ class Dispatcher:
|
|
|
23
24
|
prompt_service: PromptService,
|
|
24
25
|
llmquery_repo: LLMQueryRepo,
|
|
25
26
|
util: Utility,
|
|
27
|
+
api_service: ApiService,
|
|
26
28
|
excel_service: ExcelService,
|
|
27
29
|
mail_service: MailService):
|
|
28
30
|
self.prompt_service = prompt_service
|
|
29
31
|
self.llmquery_repo = llmquery_repo
|
|
32
|
+
self.api_service = api_service
|
|
30
33
|
self.util = util
|
|
31
34
|
self.excel_service = excel_service
|
|
32
35
|
self.mail_service = mail_service
|
|
@@ -36,41 +39,42 @@ class Dispatcher:
|
|
|
36
39
|
# Use the global registry
|
|
37
40
|
self.company_registry = get_company_registry()
|
|
38
41
|
|
|
39
|
-
#
|
|
42
|
+
# load into the dispatcher the configured companies
|
|
40
43
|
self.company_classes = {}
|
|
41
44
|
self.initialize_companies()
|
|
42
45
|
|
|
46
|
+
# run the statrtup logic for all companies
|
|
47
|
+
self.start_execution()
|
|
48
|
+
|
|
43
49
|
self.tool_handlers = {
|
|
44
50
|
"iat_generate_excel": self.excel_service.excel_generator,
|
|
45
51
|
"iat_send_email": self.mail_service.send_mail,
|
|
52
|
+
"iat_api_call": self.api_service.call_api
|
|
46
53
|
}
|
|
47
54
|
|
|
48
55
|
def initialize_companies(self):
|
|
49
56
|
"""
|
|
50
57
|
Initializes and instantiates all registered company classes.
|
|
51
|
-
This method should be called *after* the main injector is fully configured
|
|
58
|
+
This method should be called *after* the main injector is fully configured
|
|
59
|
+
and the company registry is populated.
|
|
52
60
|
"""
|
|
53
61
|
if self.company_classes: # Prevent re-initialization
|
|
54
62
|
return
|
|
55
63
|
|
|
56
64
|
# ✅ NOW it is safe to get the injector and instantiate companies.
|
|
57
|
-
injector = current_iatoolkit().
|
|
65
|
+
injector = current_iatoolkit().get_injector()
|
|
58
66
|
self.company_registry.set_injector(injector)
|
|
59
67
|
self.company_classes = self.company_registry.instantiate_companies()
|
|
60
68
|
|
|
61
69
|
def start_execution(self):
|
|
62
70
|
"""Runs the startup logic for all registered companies."""
|
|
63
|
-
# Ensure companies are initialized before starting them
|
|
64
|
-
if not self.company_classes:
|
|
65
|
-
self.initialize_companies()
|
|
66
|
-
|
|
67
71
|
for company_name, company_instance in self.company_classes.items():
|
|
68
72
|
logging.info(f'Starting execution for company: {company_name}')
|
|
69
73
|
company_instance.start_execution()
|
|
70
74
|
|
|
71
75
|
return True
|
|
72
76
|
|
|
73
|
-
def
|
|
77
|
+
def setup_all_companies(self):
|
|
74
78
|
# create system functions
|
|
75
79
|
for function in self.system_functions:
|
|
76
80
|
self.llmquery_repo.create_or_update_function(
|
|
@@ -96,10 +100,9 @@ class Dispatcher:
|
|
|
96
100
|
|
|
97
101
|
# initialize the database for every company class
|
|
98
102
|
for company in self.company_classes.values():
|
|
99
|
-
print(f'
|
|
103
|
+
print(f'company: {company.__class__.__name__}')
|
|
100
104
|
company.init_db()
|
|
101
105
|
|
|
102
|
-
|
|
103
106
|
def dispatch(self, company_name: str, action: str, **kwargs) -> str:
|
|
104
107
|
company_key = company_name.lower()
|
|
105
108
|
|
services/profile_service.py
CHANGED
|
@@ -266,7 +266,7 @@ class ProfileService:
|
|
|
266
266
|
|
|
267
267
|
api_key = ApiKey(key=key, company_id=company.id)
|
|
268
268
|
self.profile_repo.create_api_key(api_key)
|
|
269
|
-
return {"
|
|
269
|
+
return {"api-key": key}
|
|
270
270
|
|
|
271
271
|
|
|
272
272
|
def send_verification_email(self, new_user: User, company_short_name):
|
|
@@ -11,6 +11,7 @@ from collections import defaultdict
|
|
|
11
11
|
from repositories.models import Prompt, PromptCategory, Company
|
|
12
12
|
import os
|
|
13
13
|
from common.exceptions import IAToolkitException
|
|
14
|
+
from pathlib import Path
|
|
14
15
|
|
|
15
16
|
|
|
16
17
|
class PromptService:
|
|
@@ -32,7 +33,7 @@ class PromptService:
|
|
|
32
33
|
|
|
33
34
|
prompt_filename = prompt_name.lower() + '.prompt'
|
|
34
35
|
if is_system_prompt:
|
|
35
|
-
template_dir = '
|
|
36
|
+
template_dir = 'src/system_prompts'
|
|
36
37
|
else:
|
|
37
38
|
template_dir = f'companies/{company.short_name}/prompts'
|
|
38
39
|
|
|
@@ -103,16 +104,15 @@ class PromptService:
|
|
|
103
104
|
system_prompt_content = []
|
|
104
105
|
|
|
105
106
|
# get the filepaths for all system prompts
|
|
106
|
-
current_dir =
|
|
107
|
-
|
|
108
|
-
system_prompt_dir = os.path.join(src_dir, "prompts")
|
|
107
|
+
current_dir = Path(__file__).resolve().parent
|
|
108
|
+
project_root = current_dir.parent.parent
|
|
109
109
|
|
|
110
|
-
#
|
|
110
|
+
# read all the system prompts from the database
|
|
111
111
|
system_prompts = self.llm_query_repo.get_system_prompts()
|
|
112
112
|
|
|
113
113
|
for prompt in system_prompts:
|
|
114
|
-
#
|
|
115
|
-
absolute_filepath = os.path.join(
|
|
114
|
+
# build the absolute filepath for reading it
|
|
115
|
+
absolute_filepath = os.path.join(project_root, prompt.filepath)
|
|
116
116
|
if not os.path.exists(absolute_filepath):
|
|
117
117
|
logging.warning(f"El archivo para el prompt de sistema no existe: {absolute_filepath}")
|
|
118
118
|
continue
|
|
@@ -123,7 +123,7 @@ class PromptService:
|
|
|
123
123
|
raise IAToolkitException(IAToolkitException.ErrorType.FILE_IO_ERROR,
|
|
124
124
|
f"Error leyendo el archivo de prompt del sistema {absolute_filepath}: {e}")
|
|
125
125
|
|
|
126
|
-
#
|
|
126
|
+
# join the system prompts into a single string
|
|
127
127
|
return "\n".join(system_prompt_content)
|
|
128
128
|
|
|
129
129
|
except IAToolkitException:
|
|
File without changes
|
|
File without changes
|