iatoolkit 0.3.9__tar.gz → 0.4.1__tar.gz

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 (39) hide show
  1. {iatoolkit-0.3.9 → iatoolkit-0.4.1}/PKG-INFO +43 -37
  2. {iatoolkit-0.3.9 → iatoolkit-0.4.1}/pyproject.toml +1 -1
  3. iatoolkit-0.4.1/readme.md +49 -0
  4. {iatoolkit-0.3.9 → iatoolkit-0.4.1}/src/iatoolkit/__init__.py +9 -3
  5. {iatoolkit-0.3.9 → iatoolkit-0.4.1}/src/iatoolkit/cli_commands.py +2 -10
  6. {iatoolkit-0.3.9 → iatoolkit-0.4.1}/src/iatoolkit/company_registry.py +6 -8
  7. {iatoolkit-0.3.9 → iatoolkit-0.4.1}/src/iatoolkit.egg-info/PKG-INFO +43 -37
  8. {iatoolkit-0.3.9 → iatoolkit-0.4.1}/src/services/benchmark_service.py +1 -1
  9. {iatoolkit-0.3.9 → iatoolkit-0.4.1}/src/services/dispatcher_service.py +37 -23
  10. {iatoolkit-0.3.9 → iatoolkit-0.4.1}/src/services/file_processor_service.py +28 -5
  11. {iatoolkit-0.3.9 → iatoolkit-0.4.1}/src/services/load_documents_service.py +75 -22
  12. {iatoolkit-0.3.9 → iatoolkit-0.4.1}/src/services/prompt_manager_service.py +2 -1
  13. iatoolkit-0.3.9/readme.md +0 -43
  14. {iatoolkit-0.3.9 → iatoolkit-0.4.1}/requirements.txt +0 -0
  15. {iatoolkit-0.3.9 → iatoolkit-0.4.1}/setup.cfg +0 -0
  16. {iatoolkit-0.3.9 → iatoolkit-0.4.1}/src/iatoolkit/base_company.py +0 -0
  17. {iatoolkit-0.3.9 → iatoolkit-0.4.1}/src/iatoolkit/iatoolkit.py +0 -0
  18. {iatoolkit-0.3.9 → iatoolkit-0.4.1}/src/iatoolkit/system_prompts/arquitectura.prompt +0 -0
  19. {iatoolkit-0.3.9 → iatoolkit-0.4.1}/src/iatoolkit/system_prompts/format_styles.prompt +0 -0
  20. {iatoolkit-0.3.9 → iatoolkit-0.4.1}/src/iatoolkit/system_prompts/query_main.prompt +0 -0
  21. {iatoolkit-0.3.9 → iatoolkit-0.4.1}/src/iatoolkit/system_prompts/sql_rules.prompt +0 -0
  22. {iatoolkit-0.3.9 → iatoolkit-0.4.1}/src/iatoolkit.egg-info/SOURCES.txt +0 -0
  23. {iatoolkit-0.3.9 → iatoolkit-0.4.1}/src/iatoolkit.egg-info/dependency_links.txt +0 -0
  24. {iatoolkit-0.3.9 → iatoolkit-0.4.1}/src/iatoolkit.egg-info/requires.txt +0 -0
  25. {iatoolkit-0.3.9 → iatoolkit-0.4.1}/src/iatoolkit.egg-info/top_level.txt +0 -0
  26. {iatoolkit-0.3.9 → iatoolkit-0.4.1}/src/services/__init__.py +0 -0
  27. {iatoolkit-0.3.9 → iatoolkit-0.4.1}/src/services/api_service.py +0 -0
  28. {iatoolkit-0.3.9 → iatoolkit-0.4.1}/src/services/document_service.py +0 -0
  29. {iatoolkit-0.3.9 → iatoolkit-0.4.1}/src/services/excel_service.py +0 -0
  30. {iatoolkit-0.3.9 → iatoolkit-0.4.1}/src/services/history_service.py +0 -0
  31. {iatoolkit-0.3.9 → iatoolkit-0.4.1}/src/services/jwt_service.py +0 -0
  32. {iatoolkit-0.3.9 → iatoolkit-0.4.1}/src/services/mail_service.py +0 -0
  33. {iatoolkit-0.3.9 → iatoolkit-0.4.1}/src/services/profile_service.py +0 -0
  34. {iatoolkit-0.3.9 → iatoolkit-0.4.1}/src/services/query_service.py +0 -0
  35. {iatoolkit-0.3.9 → iatoolkit-0.4.1}/src/services/search_service.py +0 -0
  36. {iatoolkit-0.3.9 → iatoolkit-0.4.1}/src/services/sql_service.py +0 -0
  37. {iatoolkit-0.3.9 → iatoolkit-0.4.1}/src/services/tasks_service.py +0 -0
  38. {iatoolkit-0.3.9 → iatoolkit-0.4.1}/src/services/user_feedback_service.py +0 -0
  39. {iatoolkit-0.3.9 → iatoolkit-0.4.1}/src/services/user_session_context_service.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: iatoolkit
3
- Version: 0.3.9
3
+ Version: 0.4.1
4
4
  Summary: IAToolkit
5
5
  Author: Fernando Libedinsky
6
6
  License-Expression: MIT
@@ -207,46 +207,52 @@ Requires-Dist: yarl==1.18.3
207
207
  Requires-Dist: zipp==3.21.0
208
208
  Requires-Dist: zstandard==0.23.0
209
209
 
210
- # iatoolkit
210
+
211
+ <div align="center">
212
+ <h1>IAToolkit</h1>
213
+ <p><strong>The Open-Source Framework for Building AI Chatbots on Your Private Data.</strong></p>
214
+ </div>
211
215
 
212
216
  IAToolkit is a comprehensive, open-source framework designed for building enterprise-grade
213
217
  AI chatbots and conversational applications.
214
- Built on Flask with dependency injection, it provides a robust foundation for scalable AI solutions.
218
+ With IAToolkit, you can build production-ready, context-aware chatbots and agents that
219
+ can query relational databases, perform semantic searches on documents,
220
+ and connect to your internal APIs in minutes.
221
+
222
+ IAToolkit bridges the gap between powerful LLMs and your company's data.
223
+
215
224
 
216
225
  ## 🚀 Key Features
217
- - **Universal LLM Integration**: OpenAI GPT, Google Gemini
218
- - **Template System**: Jinja2-powered prompt templates with variables
219
- - **Context Management**: Maintain conversation context across sessions
220
-
221
- ### 🔒 **Enterprise Security**
222
- - **JWT Authentication**: Secure token-based authentication
223
- - **Session Management**: Redis-backed secure sessions
224
- - **CORS Configuration**: Flexible cross-origin resource sharing
225
-
226
- ### 🛠 **Function Calling & Tools**
227
- - **Native Function Calls**: Direct integration with LLM function calling
228
- - **Custom Tools**: Build and register custom tools for your chatbot
229
- - **SQL Query Generation**: Natural language to SQL conversion
230
- - **API Integrations**: Connect to external services and APIs
231
-
232
- ### 🗄 **Database & Storage**
233
- - **Multi-Database Support**: PostgreSQL, MySQL, SQLite via SQLAlchemy
234
- - **Vector Store Integration**: Semantic search and retrieval
235
- - **Document Processing**: PDF, Word, Excel, and text file handling
236
-
237
- ### 📊 **Analytics & Monitoring**
238
- - **Query Logging**: Track all LLM interactions
239
- - **Performance Metrics**: Response times, token usage, costs
240
- - **Benchmarking**: Compare model performance
241
- - **Task Management**: Async task processing with status tracking
242
-
243
- ### 🔧 **Developer Experience**
244
- - **Dependency Injection**: Clean, testable architecture
245
- - **CLI Tools**: Command-line interface for common tasks
246
- - **Hot Reloading**: Development-friendly configuration
247
- - **Comprehensive Logging**: Debug and monitor easily
248
-
249
- ## License
250
- MIT License
251
226
 
227
+ * **🔗 Unified Data Connection**:
228
+ * **Natural Language to SQL**: Let your chatbot query relational databases (PostgreSQL, MySQL, SQLite) using everyday language.
229
+ * **Semantic Document Search**: Automatically chunk, embed, and search across your private documents (PDFs, Word, etc.) to provide contextually accurate answers.
230
+
231
+ * **🏢 Enterprise-Ready Multi-Tenancy**:
232
+ * Deploy isolated "Company" modules, each with its own data, tools, and context. Perfect for SaaS products or internal departmental agents.
233
+
234
+ * **🧠 LLM Agnostic**:
235
+ * Switch between **OpenAI (GPT-*)** and **Google (Gemini-*)** with a single line change in your configuration. No code refactoring needed.
236
+
237
+ * **🛠️ Developer-First Experience**:
238
+ * Built with a clean, **Dependency Injection** architecture.
239
+ * High-quality code base with **90%+ test coverage**.
240
+ * Powerful Flask-based **CLI** for database setup, API key generation, and more.
241
+
242
+ * **🔒 Security & Observability Built-In**:
243
+ * Comes with JWT-based authentication, user management, and secure session handling out of the box.
244
+ * Full traceability with detailed logging of all queries, function calls, token usage, and costs.
245
+
246
+ ## ⚡ Quick Start: Create a Custom Tool in 30 Seconds
247
+
248
+ See how easy it is to give your AI a new skill. Just define a method inside your Company class and describe it.
249
+ IAToolkit handles the rest.
250
+
251
+ ## 🤝 Contributing
252
+
253
+ We welcome contributions! Whether it's adding a new feature, improving documentation, or fixing a bug,
254
+ please feel free to open a pull request.
255
+
256
+ ## 📄 License
252
257
 
258
+ IAToolkit is open-source and licensed under the [MIT License](LICENSE).
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "iatoolkit"
7
- version = "0.3.9"
7
+ version = "0.4.1"
8
8
  requires-python = ">=3.11"
9
9
  description = "IAToolkit"
10
10
  readme = "readme.md"
@@ -0,0 +1,49 @@
1
+
2
+ <div align="center">
3
+ <h1>IAToolkit</h1>
4
+ <p><strong>The Open-Source Framework for Building AI Chatbots on Your Private Data.</strong></p>
5
+ </div>
6
+
7
+ IAToolkit is a comprehensive, open-source framework designed for building enterprise-grade
8
+ AI chatbots and conversational applications.
9
+ With IAToolkit, you can build production-ready, context-aware chatbots and agents that
10
+ can query relational databases, perform semantic searches on documents,
11
+ and connect to your internal APIs in minutes.
12
+
13
+ IAToolkit bridges the gap between powerful LLMs and your company's data.
14
+
15
+
16
+ ## 🚀 Key Features
17
+
18
+ * **🔗 Unified Data Connection**:
19
+ * **Natural Language to SQL**: Let your chatbot query relational databases (PostgreSQL, MySQL, SQLite) using everyday language.
20
+ * **Semantic Document Search**: Automatically chunk, embed, and search across your private documents (PDFs, Word, etc.) to provide contextually accurate answers.
21
+
22
+ * **🏢 Enterprise-Ready Multi-Tenancy**:
23
+ * Deploy isolated "Company" modules, each with its own data, tools, and context. Perfect for SaaS products or internal departmental agents.
24
+
25
+ * **🧠 LLM Agnostic**:
26
+ * Switch between **OpenAI (GPT-*)** and **Google (Gemini-*)** with a single line change in your configuration. No code refactoring needed.
27
+
28
+ * **🛠️ Developer-First Experience**:
29
+ * Built with a clean, **Dependency Injection** architecture.
30
+ * High-quality code base with **90%+ test coverage**.
31
+ * Powerful Flask-based **CLI** for database setup, API key generation, and more.
32
+
33
+ * **🔒 Security & Observability Built-In**:
34
+ * Comes with JWT-based authentication, user management, and secure session handling out of the box.
35
+ * Full traceability with detailed logging of all queries, function calls, token usage, and costs.
36
+
37
+ ## ⚡ Quick Start: Create a Custom Tool in 30 Seconds
38
+
39
+ See how easy it is to give your AI a new skill. Just define a method inside your Company class and describe it.
40
+ IAToolkit handles the rest.
41
+
42
+ ## 🤝 Contributing
43
+
44
+ We welcome contributions! Whether it's adding a new feature, improving documentation, or fixing a bug,
45
+ please feel free to open a pull request.
46
+
47
+ ## 📄 License
48
+
49
+ IAToolkit is open-source and licensed under the [MIT License](LICENSE).
@@ -21,13 +21,15 @@ from services.excel_service import ExcelService
21
21
  from services.dispatcher_service import Dispatcher
22
22
  from services.document_service import DocumentService
23
23
  from services.search_service import SearchService
24
- from services.query_service import QueryService
24
+ from services.load_documents_service import LoadDocumentsService
25
25
  from repositories.profile_repo import ProfileRepo
26
26
  from repositories.llm_query_repo import LLMQueryRepo
27
+ from services.query_service import QueryService
28
+ from services.prompt_manager_service import PromptService
27
29
  from repositories.database_manager import DatabaseManager
28
30
  from infra.call_service import CallServiceClient
29
31
  from common.util import Utility
30
- from repositories.models import Base, Company, Function, TaskType
32
+ from repositories.models import Base, Company, Function, TaskType, Prompt, PromptCategory
31
33
 
32
34
 
33
35
  __all__ = [
@@ -40,10 +42,12 @@ __all__ = [
40
42
  'ExcelService',
41
43
  'Dispatcher',
42
44
  'DocumentService',
43
- 'QueryService',
44
45
  'SearchService',
46
+ 'QueryService',
47
+ 'LoadDocumentsService',
45
48
  'ProfileRepo',
46
49
  'LLMQueryRepo',
50
+ 'PromptService',
47
51
  'DatabaseManager',
48
52
  'CallServiceClient',
49
53
  'Utility',
@@ -51,4 +55,6 @@ __all__ = [
51
55
  'Function',
52
56
  'TaskType',
53
57
  'Base',
58
+ 'Prompt',
59
+ 'PromptCategory'
54
60
  ]
@@ -24,6 +24,8 @@ def register_core_commands(app):
24
24
  def setup_company(company_short_name: str):
25
25
  """⚙️ Genera una nueva API key para una compañía ya registrada."""
26
26
  try:
27
+ dispatcher = IAToolkit.get_instance().get_injector().get(Dispatcher)
28
+ dispatcher.setup_all_companies()
27
29
  profile_service = IAToolkit.get_instance().get_injector().get(ProfileService)
28
30
  click.echo(f"🔑 Generando API key para '{company_short_name}'...")
29
31
  result = profile_service.new_api_key(company_short_name)
@@ -64,14 +66,4 @@ def register_core_commands(app):
64
66
  logging.exception(e)
65
67
  click.echo(f"Error: {str(e)}")
66
68
 
67
- @app.cli.command("load")
68
- def load_documents():
69
- from services.load_documents_service import LoadDocumentsService
70
69
 
71
- load_documents_service = IAToolkit.get_instance().get_injector().get(LoadDocumentsService)
72
- try:
73
- result = load_documents_service.load()
74
- click.echo(result['message'])
75
- except Exception as e:
76
- logging.exception(e)
77
- click.echo(f"Error: {str(e)}")
@@ -15,27 +15,21 @@ class CompanyRegistry:
15
15
  def __init__(self):
16
16
  self._company_classes: Dict[str, Type[BaseCompany]] = {}
17
17
  self._company_instances: Dict[str, BaseCompany] = {}
18
- self._injector = None
19
18
 
20
- def set_injector(self, injector) -> None:
21
- """Establece el injector para crear instancias con dependencias"""
22
- self._injector = injector
23
19
 
24
- def instantiate_companies(self) -> Dict[str, BaseCompany]:
20
+ def instantiate_companies(self, injector) -> Dict[str, BaseCompany]:
25
21
  """
26
22
  Instancia todas las empresas registradas con inyección de dependencias.
27
23
 
28
24
  Returns:
29
25
  Dict con instancias de empresas {name: instance}
30
26
  """
31
- if not self._injector:
32
- raise RuntimeError("Injector no configurado. Llame a set_injector() primero.")
33
27
 
34
28
  for company_key, company_class in self._company_classes.items():
35
29
  if company_key not in self._company_instances:
36
30
  try:
37
31
  # use de injector to create the instance
38
- company_instance = self._injector.get(company_class)
32
+ company_instance = injector.get(company_class)
39
33
  self._company_instances[company_key] = company_instance
40
34
  logging.info(f"company '{company_key}' created in dispatcher")
41
35
 
@@ -46,6 +40,10 @@ class CompanyRegistry:
46
40
 
47
41
  return self._company_instances.copy()
48
42
 
43
+ def get_all_company_instances(self) -> Dict[str, BaseCompany]:
44
+ """Devuelve un diccionario con todas las instancias de empresas creadas."""
45
+ return self._company_instances.copy()
46
+
49
47
  def get_registered_companies(self) -> Dict[str, Type[BaseCompany]]:
50
48
  return self._company_classes.copy()
51
49
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: iatoolkit
3
- Version: 0.3.9
3
+ Version: 0.4.1
4
4
  Summary: IAToolkit
5
5
  Author: Fernando Libedinsky
6
6
  License-Expression: MIT
@@ -207,46 +207,52 @@ Requires-Dist: yarl==1.18.3
207
207
  Requires-Dist: zipp==3.21.0
208
208
  Requires-Dist: zstandard==0.23.0
209
209
 
210
- # iatoolkit
210
+
211
+ <div align="center">
212
+ <h1>IAToolkit</h1>
213
+ <p><strong>The Open-Source Framework for Building AI Chatbots on Your Private Data.</strong></p>
214
+ </div>
211
215
 
212
216
  IAToolkit is a comprehensive, open-source framework designed for building enterprise-grade
213
217
  AI chatbots and conversational applications.
214
- Built on Flask with dependency injection, it provides a robust foundation for scalable AI solutions.
218
+ With IAToolkit, you can build production-ready, context-aware chatbots and agents that
219
+ can query relational databases, perform semantic searches on documents,
220
+ and connect to your internal APIs in minutes.
221
+
222
+ IAToolkit bridges the gap between powerful LLMs and your company's data.
223
+
215
224
 
216
225
  ## 🚀 Key Features
217
- - **Universal LLM Integration**: OpenAI GPT, Google Gemini
218
- - **Template System**: Jinja2-powered prompt templates with variables
219
- - **Context Management**: Maintain conversation context across sessions
220
-
221
- ### 🔒 **Enterprise Security**
222
- - **JWT Authentication**: Secure token-based authentication
223
- - **Session Management**: Redis-backed secure sessions
224
- - **CORS Configuration**: Flexible cross-origin resource sharing
225
-
226
- ### 🛠 **Function Calling & Tools**
227
- - **Native Function Calls**: Direct integration with LLM function calling
228
- - **Custom Tools**: Build and register custom tools for your chatbot
229
- - **SQL Query Generation**: Natural language to SQL conversion
230
- - **API Integrations**: Connect to external services and APIs
231
-
232
- ### 🗄 **Database & Storage**
233
- - **Multi-Database Support**: PostgreSQL, MySQL, SQLite via SQLAlchemy
234
- - **Vector Store Integration**: Semantic search and retrieval
235
- - **Document Processing**: PDF, Word, Excel, and text file handling
236
-
237
- ### 📊 **Analytics & Monitoring**
238
- - **Query Logging**: Track all LLM interactions
239
- - **Performance Metrics**: Response times, token usage, costs
240
- - **Benchmarking**: Compare model performance
241
- - **Task Management**: Async task processing with status tracking
242
-
243
- ### 🔧 **Developer Experience**
244
- - **Dependency Injection**: Clean, testable architecture
245
- - **CLI Tools**: Command-line interface for common tasks
246
- - **Hot Reloading**: Development-friendly configuration
247
- - **Comprehensive Logging**: Debug and monitor easily
248
-
249
- ## License
250
- MIT License
251
226
 
227
+ * **🔗 Unified Data Connection**:
228
+ * **Natural Language to SQL**: Let your chatbot query relational databases (PostgreSQL, MySQL, SQLite) using everyday language.
229
+ * **Semantic Document Search**: Automatically chunk, embed, and search across your private documents (PDFs, Word, etc.) to provide contextually accurate answers.
230
+
231
+ * **🏢 Enterprise-Ready Multi-Tenancy**:
232
+ * Deploy isolated "Company" modules, each with its own data, tools, and context. Perfect for SaaS products or internal departmental agents.
233
+
234
+ * **🧠 LLM Agnostic**:
235
+ * Switch between **OpenAI (GPT-*)** and **Google (Gemini-*)** with a single line change in your configuration. No code refactoring needed.
236
+
237
+ * **🛠️ Developer-First Experience**:
238
+ * Built with a clean, **Dependency Injection** architecture.
239
+ * High-quality code base with **90%+ test coverage**.
240
+ * Powerful Flask-based **CLI** for database setup, API key generation, and more.
241
+
242
+ * **🔒 Security & Observability Built-In**:
243
+ * Comes with JWT-based authentication, user management, and secure session handling out of the box.
244
+ * Full traceability with detailed logging of all queries, function calls, token usage, and costs.
245
+
246
+ ## ⚡ Quick Start: Create a Custom Tool in 30 Seconds
247
+
248
+ See how easy it is to give your AI a new skill. Just define a method inside your Company class and describe it.
249
+ IAToolkit handles the rest.
250
+
251
+ ## 🤝 Contributing
252
+
253
+ We welcome contributions! Whether it's adding a new feature, improving documentation, or fixing a bug,
254
+ please feel free to open a pull request.
255
+
256
+ ## 📄 License
252
257
 
258
+ IAToolkit is open-source and licensed under the [MIT License](LICENSE).
@@ -65,7 +65,7 @@ class BenchmarkService:
65
65
 
66
66
  company = self.profile_repo.get_company_by_short_name(company_short_name)
67
67
  if not company:
68
- raise IAToolkitException(IAToolkitException.ErrorType.CONFIG_ERROR, "Compañía 'maxxa' no encontrada.")
68
+ raise IAToolkitException(IAToolkitException.ErrorType.CONFIG_ERROR, f"Compañía {company_short_name} no encontrada.")
69
69
 
70
70
  total_rows = len(df)
71
71
  logging.info(f"Iniciando benchmark para {total_rows} casos de prueba desde el archivo: {file_path}")
@@ -3,7 +3,6 @@
3
3
  # Todos los derechos reservados.
4
4
  # En trámite de registro en el Registro de Propiedad Intelectual de Chile.
5
5
 
6
- from iatoolkit import current_iatoolkit
7
6
  from common.exceptions import IAToolkitException
8
7
  from services.prompt_manager_service import PromptService
9
8
  from services.api_service import ApiService
@@ -11,10 +10,10 @@ from repositories.llm_query_repo import LLMQueryRepo
11
10
  from repositories.models import Company, Function
12
11
  from services.excel_service import ExcelService
13
12
  from services.mail_service import MailService
14
- from iatoolkit.company_registry import get_company_registry
15
13
  from common.session_manager import SessionManager
16
14
  from common.util import Utility
17
15
  from injector import inject
16
+ from typing import Dict
18
17
  import logging
19
18
  import os
20
19
 
@@ -37,11 +36,10 @@ class Dispatcher:
37
36
  self.system_functions = _FUNCTION_LIST
38
37
  self.system_prompts = _SYSTEM_PROMPT
39
38
 
40
- # Use the global registry
41
- self.company_registry = get_company_registry()
39
+ self._company_registry = None
40
+ self._company_instances = None
42
41
 
43
42
  # load into the dispatcher the configured companies
44
- self.company_classes = {}
45
43
  self.initialize_companies()
46
44
 
47
45
  # run the statrtup logic for all companies
@@ -53,23 +51,39 @@ class Dispatcher:
53
51
  "iat_api_call": self.api_service.call_api
54
52
  }
55
53
 
54
+ @property
55
+ def company_registry(self):
56
+ """Lazy-loads and returns the CompanyRegistry instance."""
57
+ if self._company_registry is None:
58
+ from iatoolkit.company_registry import get_company_registry
59
+ self._company_registry = get_company_registry()
60
+ return self._company_registry
61
+
62
+ @property
63
+ def company_instances(self):
64
+ """Lazy-loads and returns the instantiated company classes."""
65
+ if self._company_instances is None:
66
+ self._company_instances = self.company_registry.get_all_company_instances()
67
+ return self._company_instances
68
+
56
69
  def initialize_companies(self):
70
+ from iatoolkit import current_iatoolkit
57
71
  """
58
72
  Initializes and instantiates all registered company classes.
59
73
  This method should be called *after* the main injector is fully configured
60
74
  and the company registry is populated.
61
75
  """
62
- if self.company_classes: # Prevent re-initialization
76
+ if self.company_registry.get_all_company_instances(): # Check if already instantiated
63
77
  return
64
78
 
65
79
  # ✅ NOW it is safe to get the injector and instantiate companies.
66
80
  injector = current_iatoolkit().get_injector()
67
- self.company_registry.set_injector(injector)
68
- self.company_classes = self.company_registry.instantiate_companies()
81
+ self.company_registry.instantiate_companies(injector)
82
+
69
83
 
70
84
  def start_execution(self):
71
85
  """Runs the startup logic for all registered companies."""
72
- for company_name, company_instance in self.company_classes.items():
86
+ for company_name, company_instance in self.company_instances.items():
73
87
  logging.info(f'Starting execution for company: {company_name}')
74
88
  company_instance.start_execution()
75
89
 
@@ -100,14 +114,14 @@ class Dispatcher:
100
114
  i += 1
101
115
 
102
116
  # register in the database every company class
103
- for company in self.company_classes.values():
117
+ for company in self.company_instances.values():
104
118
  company.register_company()
105
119
 
106
120
  def dispatch(self, company_name: str, action: str, **kwargs) -> str:
107
121
  company_key = company_name.lower()
108
122
 
109
- if company_key not in self.company_classes:
110
- available_companies = list(self.company_classes.keys())
123
+ if company_key not in self.company_instances:
124
+ available_companies = list(self.company_instances.keys())
111
125
  raise IAToolkitException(
112
126
  IAToolkitException.ErrorType.EXTERNAL_SOURCE_ERROR,
113
127
  f"Empresa '{company_name}' no configurada. Empresas disponibles: {available_companies}"
@@ -117,7 +131,7 @@ class Dispatcher:
117
131
  if action in self.tool_handlers:
118
132
  return self.tool_handlers[action](**kwargs)
119
133
 
120
- company_instance = self.company_classes[company_name]
134
+ company_instance = self.company_instances[company_name]
121
135
  try:
122
136
  return company_instance.handle_request(action, **kwargs)
123
137
  except IAToolkitException as e:
@@ -130,7 +144,7 @@ class Dispatcher:
130
144
  f"Error en function call '{action}': {str(e)}") from e
131
145
 
132
146
  def get_company_context(self, company_name: str, **kwargs) -> str:
133
- if company_name not in self.company_classes:
147
+ if company_name not in self.company_instances:
134
148
  raise IAToolkitException(IAToolkitException.ErrorType.EXTERNAL_SOURCE_ERROR,
135
149
  f"Empresa no configurada: {company_name}")
136
150
 
@@ -152,7 +166,7 @@ class Dispatcher:
152
166
  filepath = os.path.join(schema_dir, file)
153
167
  company_context += self.util.generate_context_for_schema(schema_name, filepath)
154
168
 
155
- company_instance = self.company_classes[company_name]
169
+ company_instance = self.company_instances[company_name]
156
170
  try:
157
171
  return company_context + company_instance.get_company_context(**kwargs)
158
172
  except Exception as e:
@@ -180,7 +194,7 @@ class Dispatcher:
180
194
  return tools
181
195
 
182
196
  def get_user_info(self, company_name: str, user_identifier: str, is_local_user: bool) -> dict:
183
- if company_name not in self.company_classes:
197
+ if company_name not in self.company_instances:
184
198
  raise IAToolkitException(IAToolkitException.ErrorType.EXTERNAL_SOURCE_ERROR,
185
199
  f"Empresa no configurada: {company_name}")
186
200
 
@@ -190,7 +204,7 @@ class Dispatcher:
190
204
  raw_user_data = SessionManager.get('user', {})
191
205
  else:
192
206
  # source 2: external company user
193
- company_instance = self.company_classes[company_name]
207
+ company_instance = self.company_instances[company_name]
194
208
  try:
195
209
  raw_user_data = company_instance.get_user_info(user_identifier)
196
210
  except Exception as e:
@@ -226,11 +240,11 @@ class Dispatcher:
226
240
  return normalized_user
227
241
 
228
242
  def get_metadata_from_filename(self, company_name: str, filename: str) -> dict:
229
- if company_name not in self.company_classes:
243
+ if company_name not in self.company_instances:
230
244
  raise IAToolkitException(IAToolkitException.ErrorType.EXTERNAL_SOURCE_ERROR,
231
245
  f"Empresa no configurada: {company_name}")
232
246
 
233
- company_instance = self.company_classes[company_name]
247
+ company_instance = self.company_instances[company_name]
234
248
  try:
235
249
  return company_instance.get_metadata_from_filename(filename)
236
250
  except Exception as e:
@@ -240,14 +254,14 @@ class Dispatcher:
240
254
 
241
255
  def get_company_instance(self, company_name: str):
242
256
  """Returns the instance for a given company name."""
243
- return self.company_classes.get(company_name)
257
+ return self.company_instances.get(company_name)
244
258
 
245
259
  def get_registered_companies(self) -> dict:
246
- """Obtiene todas las empresas registradas (para debugging/admin)"""
260
+ """Gets all registered companies (for debugging/admin purposes)"""
247
261
  return {
248
262
  "registered_classes": list(self.company_registry.get_registered_companies().keys()),
249
- "instantiated": list(self.company_classes.keys()),
250
- "count": len(self.company_classes)
263
+ "instantiated": list(self.company_instances.keys()),
264
+ "count": len(self.company_instances)
251
265
  }
252
266
 
253
267
 
@@ -7,26 +7,45 @@ from infra.connectors.file_connector import FileConnector
7
7
  import logging
8
8
  import os
9
9
  from typing import Optional, Callable, Dict
10
+ from repositories.models import Company
10
11
 
11
12
 
12
13
  class FileProcessorConfig:
14
+ """Configuration class for the FileProcessor."""
13
15
  def __init__(
14
16
  self,
15
17
  filters: Dict,
16
- action: Callable[[str, bytes], None],
18
+ callback: Callable[[Company, str, bytes, dict], None],
17
19
  continue_on_error: bool = True,
18
20
  log_file: str = 'file_processor.log',
19
21
  echo: bool = False,
20
- context: dict = None,
22
+ context: dict = None
21
23
  ):
24
+ """
25
+ Initializes the FileProcessor configuration.
26
+
27
+ Args:
28
+ filters (Dict): A dictionary of filters to apply to file names.
29
+ Example: {'filename_contains': '.pdf'}
30
+ action (Callable): The function to execute for each processed file.
31
+ It receives filename (str), content (bytes), and context (dict).
32
+ continue_on_error (bool): If True, continues processing other files upon an error.
33
+ log_file (str): The path to the log file.
34
+ echo (bool): If True, prints progress to the console.
35
+ context (dict): A context dictionary passed to the action function.
36
+ """
22
37
  self.filters = filters
23
- self.action = action
38
+ self.callback = callback
24
39
  self.continue_on_error = continue_on_error
25
40
  self.log_file = log_file
26
41
  self.echo = echo
27
42
  self.context = context or {}
28
43
 
29
44
  class FileProcessor:
45
+ """
46
+ A generic service to process files from a given data source (connector).
47
+ It lists files, applies filters, and executes a specific action for each one.
48
+ """
30
49
  def __init__(self,
31
50
  connector: FileConnector,
32
51
  config: FileProcessorConfig,
@@ -45,6 +64,7 @@ class FileProcessor:
45
64
  return logging.getLogger(__name__)
46
65
 
47
66
  def process_files(self):
67
+ # Fetches files from the connector, filters them, and processes them.
48
68
  try:
49
69
  files = self.connector.list_files()
50
70
  except Exception as e:
@@ -67,9 +87,12 @@ class FileProcessor:
67
87
 
68
88
  content = self.connector.get_file_content(file_path)
69
89
 
70
- # execute the action defined
90
+ # execute the callback function
71
91
  filename = os.path.basename(file_name)
72
- self.config.action(filename, content, self.config.context)
92
+ self.config.callback(company=self.config.context.get('company'),
93
+ filename=filename,
94
+ content=content,
95
+ context=self.config.context)
73
96
  self.processed_files += 1
74
97
 
75
98
  self.logger.info(f"Successfully processed file: {file_path}")
@@ -21,6 +21,10 @@ from typing import Dict
21
21
 
22
22
 
23
23
  class LoadDocumentsService:
24
+ """
25
+ Orchestrates the process of loading, processing, and storing documents
26
+ from various sources for different companies.
27
+ """
24
28
  @inject
25
29
  def __init__(self,
26
30
  file_connector_factory: FileConnectorFactory,
@@ -38,7 +42,6 @@ class LoadDocumentsService:
38
42
  self.vector_store = vector_store
39
43
  self.file_connector_factory = file_connector_factory
40
44
  self.dispatcher = dispatcher
41
- self.company = None
42
45
 
43
46
  # lower warnings
44
47
  logging.getLogger().setLevel(logging.ERROR)
@@ -51,6 +54,17 @@ class LoadDocumentsService:
51
54
 
52
55
  # load the files for all of the companies.
53
56
  def load(self, doc_type: str = None):
57
+ """
58
+ Loads documents for all companies based on their configuration.
59
+ It can load all document types or a specific one if provided.
60
+
61
+ Args:
62
+ doc_type (str, optional): A specific document type to load.
63
+ If None, all configured types are loaded.
64
+
65
+ Returns:
66
+ Dict: A dictionary with a summary message.
67
+ """
54
68
  # doc_type: an optional document_type for loading
55
69
  files_loaded = 0
56
70
  companies = self.profile_repo.get_companies()
@@ -61,7 +75,6 @@ class LoadDocumentsService:
61
75
  continue
62
76
 
63
77
  print(f"Cargando datos de ** {company.short_name} **")
64
- self.company = company
65
78
 
66
79
  # Si hay configuraciones de tipos de documento específicos
67
80
  doc_types_config = load_config.get('document_types', {})
@@ -81,7 +94,34 @@ class LoadDocumentsService:
81
94
  raise IAToolkitException(IAToolkitException.ErrorType.MISSING_PARAMETER,
82
95
  f"Falta configurar conector en empresa {company.short_name}")
83
96
 
84
- files_loaded += self.load_data_source(connector)
97
+ files_loaded += self.load_data_source(company=company,
98
+ connector_config=connector)
99
+
100
+ return {'message': f'{files_loaded} files processed'}
101
+
102
+ def load_company_files(self, company: Company,
103
+ connector: dict,
104
+ predefined_metadata: Dict = None,
105
+ filters: Dict = None):
106
+ """
107
+ Loads all files for a specific company using a given connector.
108
+
109
+ Args:
110
+ company (Company): The company to load files for.
111
+ connector (dict): The connector configuration.
112
+
113
+ Returns:
114
+ Dict: A dictionary with a summary message.
115
+ """
116
+ if not connector:
117
+ raise IAToolkitException(IAToolkitException.ErrorType.MISSING_PARAMETER,
118
+ f"Falta configurar conector")
119
+
120
+ files_loaded = self.load_data_source(
121
+ company=company,
122
+ connector_config=connector,
123
+ predefined_metadata=predefined_metadata,
124
+ filters=filters)
85
125
 
86
126
  return {'message': f'{files_loaded} files processed'}
87
127
 
@@ -99,36 +139,42 @@ class LoadDocumentsService:
99
139
  # config specific filters
100
140
  filters = type_config.get('filters', {"filename_contains": ".pdf"})
101
141
 
102
- return self.load_data_source(connector, predefined_metadata, filters)
142
+ return self.load_data_source(company=company,
143
+ connector_config=connector,
144
+ predefined_metadata=predefined_metadata,
145
+ filters=filters)
103
146
 
104
- def load_data_source(self, connector_config: Dict, predefined_metadata: Dict = None, filters: Dict = None):
147
+ def load_data_source(self, company: Company, connector_config: Dict, predefined_metadata: Dict = None, filters: Dict = None):
105
148
  """
106
- Carga archivos desde una fuente de datos usando un conector.
149
+ Loads files from a data source using a connector and a FileProcessor.
107
150
 
108
151
  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
152
+ connector_config (Dict): The configuration for the file connector.
153
+ predefined_metadata (Dict, optional): Metadata to be added to all documents from this source.
154
+ filters (Dict, optional): Filters to apply to the files.
112
155
 
113
156
  Returns:
114
- int o dict: Número de archivos procesados o diccionario de error
157
+ int: The number of processed files.
115
158
  """
116
159
  try:
117
- # Si no se proporcionaron filtros, usar el predeterminado
118
160
  if not filters:
119
161
  filters = {"filename_contains": ".pdf"}
120
162
 
121
163
  # Pasar metadata predefinida como parte del contexto al procesador
122
- # para que esté disponible en la función load_file
123
- extra_context = {}
164
+ # para que esté disponible en la función load_file_callback
165
+ context = {
166
+ 'company': company,
167
+ 'metadata': {}
168
+ }
169
+
124
170
  if predefined_metadata:
125
- extra_context['metadata'] = predefined_metadata
171
+ context['metadata'] = predefined_metadata
126
172
 
127
173
  # config the processor
128
174
  processor_config = FileProcessorConfig(
129
- context=extra_context,
175
+ callback=self.load_file_callback,
176
+ context=context,
130
177
  filters=filters,
131
- action=self.load_file,
132
178
  continue_on_error=True,
133
179
  echo=True
134
180
  )
@@ -144,14 +190,21 @@ class LoadDocumentsService:
144
190
  logging.exception("Loading files error: %s", str(e))
145
191
  return {"error": str(e)}
146
192
 
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
193
+ def load_file_callback(self, company: Company, filename: str, content: bytes, context: dict = {}):
194
+ """
195
+ Processes a single file: extracts text, generates metadata, and saves it
196
+ to the relational database and the vector store.
197
+ This method is intended to be used as the 'action' for FileProcessor.
198
+
199
+ Args:
200
+ company (Company): The company associated with the file.
201
+ filename (str): The name of the file.
202
+ content (bytes): The binary content of the file.
203
+ context (dict, optional): A context dictionary, may contain predefined metadata.
204
+ """
152
205
 
153
206
  # check if file exist in repositories
154
- if self.doc_repo.get(company=company,filename=filename):
207
+ if self.doc_repo.get(company_id=company.id,filename=filename):
155
208
  return
156
209
 
157
210
  try:
@@ -74,7 +74,8 @@ class PromptService:
74
74
  raise IAToolkitException(IAToolkitException.ErrorType.DOCUMENT_NOT_FOUND,
75
75
  f"No se encontró el prompt '{prompt_name}' para la empresa '{company.short_name}'")
76
76
 
77
- absolute_filepath = os.path.join(execution_dir, user_prompt.filename)
77
+ prompt_file = f'companies/{company.short_name}/prompts/{user_prompt.filename}'
78
+ absolute_filepath = os.path.join(execution_dir, prompt_file)
78
79
  if not os.path.exists(absolute_filepath):
79
80
  raise IAToolkitException(IAToolkitException.ErrorType.FILE_IO_ERROR,
80
81
  f"El archivo para el prompt '{prompt_name}' no existe: {absolute_filepath}")
iatoolkit-0.3.9/readme.md DELETED
@@ -1,43 +0,0 @@
1
- # iatoolkit
2
-
3
- IAToolkit is a comprehensive, open-source framework designed for building enterprise-grade
4
- AI chatbots and conversational applications.
5
- Built on Flask with dependency injection, it provides a robust foundation for scalable AI solutions.
6
-
7
- ## 🚀 Key Features
8
- - **Universal LLM Integration**: OpenAI GPT, Google Gemini
9
- - **Template System**: Jinja2-powered prompt templates with variables
10
- - **Context Management**: Maintain conversation context across sessions
11
-
12
- ### 🔒 **Enterprise Security**
13
- - **JWT Authentication**: Secure token-based authentication
14
- - **Session Management**: Redis-backed secure sessions
15
- - **CORS Configuration**: Flexible cross-origin resource sharing
16
-
17
- ### 🛠 **Function Calling & Tools**
18
- - **Native Function Calls**: Direct integration with LLM function calling
19
- - **Custom Tools**: Build and register custom tools for your chatbot
20
- - **SQL Query Generation**: Natural language to SQL conversion
21
- - **API Integrations**: Connect to external services and APIs
22
-
23
- ### 🗄 **Database & Storage**
24
- - **Multi-Database Support**: PostgreSQL, MySQL, SQLite via SQLAlchemy
25
- - **Vector Store Integration**: Semantic search and retrieval
26
- - **Document Processing**: PDF, Word, Excel, and text file handling
27
-
28
- ### 📊 **Analytics & Monitoring**
29
- - **Query Logging**: Track all LLM interactions
30
- - **Performance Metrics**: Response times, token usage, costs
31
- - **Benchmarking**: Compare model performance
32
- - **Task Management**: Async task processing with status tracking
33
-
34
- ### 🔧 **Developer Experience**
35
- - **Dependency Injection**: Clean, testable architecture
36
- - **CLI Tools**: Command-line interface for common tasks
37
- - **Hot Reloading**: Development-friendly configuration
38
- - **Comprehensive Logging**: Debug and monitor easily
39
-
40
- ## License
41
- MIT License
42
-
43
-
File without changes
File without changes