iatoolkit 0.71.4__py3-none-any.whl → 0.91.1__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.
- iatoolkit/__init__.py +15 -5
- iatoolkit/base_company.py +4 -58
- iatoolkit/cli_commands.py +6 -7
- iatoolkit/common/exceptions.py +1 -0
- iatoolkit/common/routes.py +12 -28
- iatoolkit/common/util.py +7 -1
- iatoolkit/company_registry.py +50 -14
- iatoolkit/{iatoolkit.py → core.py} +54 -55
- iatoolkit/infra/{mail_app.py → brevo_mail_app.py} +15 -37
- iatoolkit/infra/llm_client.py +9 -5
- iatoolkit/locales/en.yaml +10 -2
- iatoolkit/locales/es.yaml +171 -162
- iatoolkit/repositories/database_manager.py +59 -14
- iatoolkit/repositories/llm_query_repo.py +34 -22
- iatoolkit/repositories/models.py +16 -18
- iatoolkit/repositories/profile_repo.py +5 -10
- iatoolkit/repositories/vs_repo.py +9 -4
- iatoolkit/services/auth_service.py +1 -1
- iatoolkit/services/branding_service.py +1 -1
- iatoolkit/services/company_context_service.py +19 -11
- iatoolkit/services/configuration_service.py +219 -46
- iatoolkit/services/dispatcher_service.py +31 -225
- iatoolkit/services/document_service.py +10 -1
- iatoolkit/services/embedding_service.py +9 -6
- iatoolkit/services/excel_service.py +50 -2
- iatoolkit/services/history_manager_service.py +189 -0
- iatoolkit/services/jwt_service.py +1 -1
- iatoolkit/services/language_service.py +8 -2
- iatoolkit/services/license_service.py +82 -0
- iatoolkit/services/mail_service.py +171 -25
- iatoolkit/services/profile_service.py +37 -32
- iatoolkit/services/{prompt_manager_service.py → prompt_service.py} +110 -1
- iatoolkit/services/query_service.py +192 -191
- iatoolkit/services/sql_service.py +63 -12
- iatoolkit/services/tool_service.py +231 -0
- iatoolkit/services/user_feedback_service.py +18 -6
- iatoolkit/services/user_session_context_service.py +18 -0
- iatoolkit/static/images/iatoolkit_core.png +0 -0
- iatoolkit/static/images/iatoolkit_logo.png +0 -0
- iatoolkit/static/js/chat_feedback_button.js +1 -1
- iatoolkit/static/js/chat_help_content.js +4 -4
- iatoolkit/static/js/chat_main.js +17 -5
- iatoolkit/static/js/chat_onboarding_button.js +1 -1
- iatoolkit/static/styles/chat_iatoolkit.css +1 -1
- iatoolkit/static/styles/chat_public.css +28 -0
- iatoolkit/static/styles/documents.css +598 -0
- iatoolkit/static/styles/landing_page.css +223 -7
- iatoolkit/system_prompts/__init__.py +0 -0
- iatoolkit/system_prompts/query_main.prompt +2 -1
- iatoolkit/system_prompts/sql_rules.prompt +47 -12
- iatoolkit/templates/_company_header.html +30 -5
- iatoolkit/templates/_login_widget.html +3 -3
- iatoolkit/templates/chat.html +1 -1
- iatoolkit/templates/forgot_password.html +3 -2
- iatoolkit/templates/onboarding_shell.html +1 -1
- iatoolkit/templates/signup.html +3 -0
- iatoolkit/views/base_login_view.py +1 -1
- iatoolkit/views/change_password_view.py +1 -1
- iatoolkit/views/forgot_password_view.py +9 -4
- iatoolkit/views/history_api_view.py +3 -3
- iatoolkit/views/home_view.py +4 -2
- iatoolkit/views/init_context_api_view.py +1 -1
- iatoolkit/views/llmquery_api_view.py +4 -3
- iatoolkit/views/{file_store_api_view.py → load_document_api_view.py} +1 -1
- iatoolkit/views/login_view.py +17 -5
- iatoolkit/views/logout_api_view.py +10 -2
- iatoolkit/views/prompt_api_view.py +1 -1
- iatoolkit/views/root_redirect_view.py +22 -0
- iatoolkit/views/signup_view.py +12 -4
- iatoolkit/views/static_page_view.py +27 -0
- iatoolkit/views/verify_user_view.py +1 -1
- iatoolkit-0.91.1.dist-info/METADATA +268 -0
- iatoolkit-0.91.1.dist-info/RECORD +125 -0
- iatoolkit-0.91.1.dist-info/licenses/LICENSE_COMMUNITY.md +15 -0
- iatoolkit/services/history_service.py +0 -37
- iatoolkit/templates/about.html +0 -13
- iatoolkit/templates/index.html +0 -145
- iatoolkit/templates/login_simulation.html +0 -45
- iatoolkit/views/external_login_view.py +0 -73
- iatoolkit/views/index_view.py +0 -14
- iatoolkit/views/login_simulation_view.py +0 -93
- iatoolkit-0.71.4.dist-info/METADATA +0 -276
- iatoolkit-0.71.4.dist-info/RECORD +0 -122
- {iatoolkit-0.71.4.dist-info → iatoolkit-0.91.1.dist-info}/WHEEL +0 -0
- {iatoolkit-0.71.4.dist-info → iatoolkit-0.91.1.dist-info}/licenses/LICENSE +0 -0
- {iatoolkit-0.71.4.dist-info → iatoolkit-0.91.1.dist-info}/top_level.txt +0 -0
|
@@ -3,28 +3,26 @@
|
|
|
3
3
|
#
|
|
4
4
|
# IAToolkit is open source software.
|
|
5
5
|
|
|
6
|
-
from flask import Flask, url_for, get_flashed_messages
|
|
6
|
+
from flask import Flask, url_for, get_flashed_messages, request
|
|
7
7
|
from flask_session import Session
|
|
8
8
|
from flask_injector import FlaskInjector
|
|
9
9
|
from flask_bcrypt import Bcrypt
|
|
10
10
|
from flask_cors import CORS
|
|
11
11
|
from iatoolkit.common.exceptions import IAToolkitException
|
|
12
|
-
from urllib.parse import urlparse
|
|
13
|
-
import redis
|
|
14
|
-
import logging
|
|
15
|
-
import os
|
|
16
12
|
from typing import Optional, Dict, Any
|
|
17
13
|
from iatoolkit.repositories.database_manager import DatabaseManager
|
|
18
14
|
from werkzeug.middleware.proxy_fix import ProxyFix
|
|
19
15
|
from injector import Binder, Injector, singleton
|
|
20
|
-
from
|
|
16
|
+
from urllib.parse import urlparse
|
|
17
|
+
import redis
|
|
18
|
+
import logging
|
|
19
|
+
import os
|
|
21
20
|
|
|
22
|
-
|
|
21
|
+
from iatoolkit import __version__ as IATOOLKIT_VERSION
|
|
23
22
|
|
|
24
23
|
# global variable for the unique instance of IAToolkit
|
|
25
24
|
_iatoolkit_instance: Optional['IAToolkit'] = None
|
|
26
25
|
|
|
27
|
-
|
|
28
26
|
class IAToolkit:
|
|
29
27
|
"""
|
|
30
28
|
IAToolkit main class
|
|
@@ -53,6 +51,7 @@ class IAToolkit:
|
|
|
53
51
|
self.db_manager = None
|
|
54
52
|
self._injector = None
|
|
55
53
|
self.version = IATOOLKIT_VERSION # default version
|
|
54
|
+
self.license = "Community Edition"
|
|
56
55
|
|
|
57
56
|
@classmethod
|
|
58
57
|
def get_instance(cls) -> 'IAToolkit':
|
|
@@ -88,13 +87,16 @@ class IAToolkit:
|
|
|
88
87
|
# and other integrations, as views are handled manually.
|
|
89
88
|
FlaskInjector(app=self.app, injector=self._injector)
|
|
90
89
|
|
|
91
|
-
# Step 6: initialize
|
|
92
|
-
self.
|
|
90
|
+
# Step 6: initialize registered companies
|
|
91
|
+
self._instantiate_company_instances()
|
|
93
92
|
|
|
94
93
|
# Re-apply logging configuration in case it was modified by company-specific code
|
|
95
94
|
self._setup_logging()
|
|
96
95
|
|
|
97
|
-
# Step 7:
|
|
96
|
+
# Step 7: load company configuration file
|
|
97
|
+
self._load_company_configuration()
|
|
98
|
+
|
|
99
|
+
# Step 8: Finalize setup within the application context
|
|
98
100
|
self._setup_redis_sessions()
|
|
99
101
|
self._setup_cors()
|
|
100
102
|
self._setup_additional_services()
|
|
@@ -102,11 +104,12 @@ class IAToolkit:
|
|
|
102
104
|
self._setup_request_globals()
|
|
103
105
|
self._setup_context_processors()
|
|
104
106
|
|
|
105
|
-
# Step
|
|
107
|
+
# Step 9: define the download_dir
|
|
106
108
|
self._setup_download_dir()
|
|
107
109
|
|
|
108
|
-
logging.info(f"🎉 IAToolkit
|
|
110
|
+
logging.info(f"🎉 IAToolkit {self.license} version {self.version} correctly initialized.")
|
|
109
111
|
self._initialized = True
|
|
112
|
+
|
|
110
113
|
return self.app
|
|
111
114
|
|
|
112
115
|
def _get_config_value(self, key: str, default=None):
|
|
@@ -141,14 +144,15 @@ class IAToolkit:
|
|
|
141
144
|
force=True
|
|
142
145
|
)
|
|
143
146
|
|
|
147
|
+
logging.getLogger("httpx").setLevel(logging.WARNING)
|
|
148
|
+
|
|
144
149
|
def _register_routes(self):
|
|
145
150
|
"""Registers routes by passing the configured injector."""
|
|
146
151
|
from iatoolkit.common.routes import register_views
|
|
147
152
|
|
|
148
153
|
# Pass the injector to the view registration function
|
|
149
|
-
register_views(self.
|
|
150
|
-
|
|
151
|
-
logging.info("✅ Routes registered.")
|
|
154
|
+
register_views(self.app)
|
|
155
|
+
logging.info("✅ Community routes registered.")
|
|
152
156
|
|
|
153
157
|
def _create_flask_instance(self):
|
|
154
158
|
static_folder = self._get_config_value('STATIC_FOLDER') or self._get_default_static_folder()
|
|
@@ -158,12 +162,6 @@ class IAToolkit:
|
|
|
158
162
|
static_folder=static_folder,
|
|
159
163
|
template_folder=template_folder)
|
|
160
164
|
|
|
161
|
-
# get the IATOOLKIT_VERSION from the package metadata
|
|
162
|
-
try:
|
|
163
|
-
self.version = _pkg_version("iatoolkit")
|
|
164
|
-
except PackageNotFoundError:
|
|
165
|
-
pass
|
|
166
|
-
|
|
167
165
|
self.app.config.update({
|
|
168
166
|
'VERSION': self.version,
|
|
169
167
|
'SECRET_KEY': self._get_config_value('FLASK_SECRET_KEY', 'iatoolkit-default-secret'),
|
|
@@ -171,15 +169,10 @@ class IAToolkit:
|
|
|
171
169
|
'SESSION_COOKIE_SECURE': True,
|
|
172
170
|
'SESSION_PERMANENT': False,
|
|
173
171
|
'SESSION_USE_SIGNER': True,
|
|
174
|
-
'
|
|
172
|
+
'IATOOLKIT_SECRET_KEY': self._get_config_value('IATOOLKIT_SECRET_KEY', 'iatoolkit-jwt-secret'),
|
|
175
173
|
'JWT_ALGORITHM': 'HS256',
|
|
176
|
-
'JWT_EXPIRATION_SECONDS_CHAT': int(self._get_config_value('JWT_EXPIRATION_SECONDS_CHAT', 3600))
|
|
177
174
|
})
|
|
178
175
|
|
|
179
|
-
parsed_url = urlparse(os.getenv('IATOOLKIT_BASE_URL'))
|
|
180
|
-
if parsed_url.scheme == 'https':
|
|
181
|
-
self.app.config['PREFERRED_URL_SCHEME'] = 'https'
|
|
182
|
-
|
|
183
176
|
# 2. ProxyFix para no tener problemas con iframes y rutas
|
|
184
177
|
self.app.wsgi_app = ProxyFix(self.app.wsgi_app, x_proto=1)
|
|
185
178
|
|
|
@@ -192,12 +185,12 @@ class IAToolkit:
|
|
|
192
185
|
if not database_uri:
|
|
193
186
|
raise IAToolkitException(
|
|
194
187
|
IAToolkitException.ErrorType.CONFIG_ERROR,
|
|
195
|
-
"DATABASE_URI
|
|
188
|
+
"DATABASE_URI is requires (config dict or env. variable)"
|
|
196
189
|
)
|
|
197
190
|
|
|
198
|
-
self.db_manager = DatabaseManager(database_uri)
|
|
191
|
+
self.db_manager = DatabaseManager(database_url=database_uri, schema='iatoolkit')
|
|
199
192
|
self.db_manager.create_all()
|
|
200
|
-
logging.info("✅
|
|
193
|
+
logging.info("✅ Database configured successfully")
|
|
201
194
|
|
|
202
195
|
@self.app.teardown_appcontext
|
|
203
196
|
def remove_session(exception=None):
|
|
@@ -211,7 +204,7 @@ class IAToolkit:
|
|
|
211
204
|
def _setup_redis_sessions(self):
|
|
212
205
|
redis_url = self._get_config_value('REDIS_URL')
|
|
213
206
|
if not redis_url:
|
|
214
|
-
logging.warning("⚠️ REDIS_URL
|
|
207
|
+
logging.warning("⚠️ REDIS_URL not configured, will use memory sessions")
|
|
215
208
|
return
|
|
216
209
|
|
|
217
210
|
try:
|
|
@@ -230,20 +223,18 @@ class IAToolkit:
|
|
|
230
223
|
})
|
|
231
224
|
|
|
232
225
|
Session(self.app)
|
|
233
|
-
logging.info("✅ Redis
|
|
226
|
+
logging.info("✅ Redis and sessions configured successfully")
|
|
234
227
|
|
|
235
228
|
except Exception as e:
|
|
236
|
-
logging.error(f"❌ Error
|
|
237
|
-
|
|
229
|
+
logging.error(f"❌ Error configuring Redis: {e}")
|
|
230
|
+
raise e
|
|
238
231
|
|
|
239
232
|
def _setup_cors(self):
|
|
240
233
|
"""🌐 Configura CORS"""
|
|
241
234
|
from iatoolkit.company_registry import get_company_registry
|
|
242
235
|
|
|
243
236
|
# default CORS origin
|
|
244
|
-
default_origins = [
|
|
245
|
-
os.getenv('IATOOLKIT_BASE_URL')
|
|
246
|
-
]
|
|
237
|
+
default_origins = []
|
|
247
238
|
|
|
248
239
|
# Iterate through the registered company names
|
|
249
240
|
extra_origins = []
|
|
@@ -263,7 +254,7 @@ class IAToolkit:
|
|
|
263
254
|
],
|
|
264
255
|
methods=["GET", "POST", "PUT", "DELETE", "OPTIONS"])
|
|
265
256
|
|
|
266
|
-
logging.info(f"✅ CORS
|
|
257
|
+
logging.info(f"✅ CORS configured for: {all_origins}")
|
|
267
258
|
|
|
268
259
|
def _configure_core_dependencies(self, binder: Binder):
|
|
269
260
|
"""⚙️ Configures all system dependencies."""
|
|
@@ -277,13 +268,13 @@ class IAToolkit:
|
|
|
277
268
|
self._bind_services(binder)
|
|
278
269
|
self._bind_infrastructure(binder)
|
|
279
270
|
|
|
280
|
-
logging.info("✅
|
|
271
|
+
logging.info("✅ Dependencies configured successfully")
|
|
281
272
|
|
|
282
273
|
except Exception as e:
|
|
283
|
-
logging.error(f"❌ Error
|
|
274
|
+
logging.error(f"❌ Error configuring dependencies: {e}")
|
|
284
275
|
raise IAToolkitException(
|
|
285
276
|
IAToolkitException.ErrorType.CONFIG_ERROR,
|
|
286
|
-
f"❌ Error
|
|
277
|
+
f"❌ Error configuring dependencies: {e}"
|
|
287
278
|
)
|
|
288
279
|
|
|
289
280
|
def _bind_repositories(self, binder: Binder):
|
|
@@ -304,7 +295,7 @@ class IAToolkit:
|
|
|
304
295
|
from iatoolkit.services.tasks_service import TaskService
|
|
305
296
|
from iatoolkit.services.benchmark_service import BenchmarkService
|
|
306
297
|
from iatoolkit.services.document_service import DocumentService
|
|
307
|
-
from iatoolkit.services.
|
|
298
|
+
from iatoolkit.services.prompt_service import PromptService
|
|
308
299
|
from iatoolkit.services.excel_service import ExcelService
|
|
309
300
|
from iatoolkit.services.mail_service import MailService
|
|
310
301
|
from iatoolkit.services.load_documents_service import LoadDocumentsService
|
|
@@ -316,6 +307,8 @@ class IAToolkit:
|
|
|
316
307
|
from iatoolkit.services.language_service import LanguageService
|
|
317
308
|
from iatoolkit.services.configuration_service import ConfigurationService
|
|
318
309
|
from iatoolkit.services.embedding_service import EmbeddingService
|
|
310
|
+
from iatoolkit.services.history_manager_service import HistoryManagerService
|
|
311
|
+
from iatoolkit.services.tool_service import ToolService
|
|
319
312
|
|
|
320
313
|
binder.bind(QueryService, to=QueryService)
|
|
321
314
|
binder.bind(TaskService, to=TaskService)
|
|
@@ -333,32 +326,36 @@ class IAToolkit:
|
|
|
333
326
|
binder.bind(LanguageService, to=LanguageService)
|
|
334
327
|
binder.bind(ConfigurationService, to=ConfigurationService)
|
|
335
328
|
binder.bind(EmbeddingService, to=EmbeddingService)
|
|
329
|
+
binder.bind(HistoryManagerService, to=HistoryManagerService)
|
|
330
|
+
binder.bind(ToolService, to=ToolService)
|
|
336
331
|
|
|
337
332
|
def _bind_infrastructure(self, binder: Binder):
|
|
338
333
|
from iatoolkit.infra.llm_client import llmClient
|
|
339
334
|
from iatoolkit.infra.llm_proxy import LLMProxy
|
|
340
335
|
from iatoolkit.infra.google_chat_app import GoogleChatApp
|
|
341
|
-
from iatoolkit.infra.
|
|
336
|
+
from iatoolkit.infra.brevo_mail_app import BrevoMailApp
|
|
342
337
|
from iatoolkit.services.auth_service import AuthService
|
|
343
338
|
from iatoolkit.common.util import Utility
|
|
344
339
|
|
|
345
340
|
binder.bind(LLMProxy, to=LLMProxy)
|
|
346
341
|
binder.bind(llmClient, to=llmClient)
|
|
347
342
|
binder.bind(GoogleChatApp, to=GoogleChatApp)
|
|
348
|
-
binder.bind(
|
|
343
|
+
binder.bind(BrevoMailApp, to=BrevoMailApp)
|
|
349
344
|
binder.bind(AuthService, to=AuthService)
|
|
350
345
|
binder.bind(Utility, to=Utility)
|
|
351
346
|
|
|
352
347
|
def _setup_additional_services(self):
|
|
353
348
|
Bcrypt(self.app)
|
|
354
349
|
|
|
355
|
-
def
|
|
350
|
+
def _instantiate_company_instances(self):
|
|
356
351
|
from iatoolkit.company_registry import get_company_registry
|
|
357
|
-
from iatoolkit.services.dispatcher_service import Dispatcher
|
|
358
352
|
|
|
359
353
|
# instantiate all the registered companies
|
|
360
354
|
get_company_registry().instantiate_companies(self._injector)
|
|
361
355
|
|
|
356
|
+
def _load_company_configuration(self):
|
|
357
|
+
from iatoolkit.services.dispatcher_service import Dispatcher
|
|
358
|
+
|
|
362
359
|
# use the dispatcher to load the company config.yaml file and prepare the execution
|
|
363
360
|
dispatcher = self._injector.get(Dispatcher)
|
|
364
361
|
dispatcher.load_company_configs()
|
|
@@ -369,17 +366,18 @@ class IAToolkit:
|
|
|
369
366
|
|
|
370
367
|
# 1. Register core commands
|
|
371
368
|
register_core_commands(self.app)
|
|
372
|
-
logging.info("✅
|
|
369
|
+
logging.info("✅ Core CLI commands registered.")
|
|
373
370
|
|
|
374
371
|
# 2. Register company-specific commands
|
|
375
372
|
try:
|
|
376
373
|
# Iterate through the registered company names
|
|
377
374
|
all_company_instances = get_company_registry().get_all_company_instances()
|
|
378
375
|
for company_name, company_instance in all_company_instances.items():
|
|
379
|
-
company_instance
|
|
376
|
+
if hasattr(company_instance, "register_cli_commands"):
|
|
377
|
+
company_instance.register_cli_commands(self.app)
|
|
380
378
|
|
|
381
379
|
except Exception as e:
|
|
382
|
-
logging.error(f"❌
|
|
380
|
+
logging.error(f"❌ error while registering company commands: {e}")
|
|
383
381
|
|
|
384
382
|
def _setup_context_processors(self):
|
|
385
383
|
# Configura context processors para templates
|
|
@@ -403,13 +401,14 @@ class IAToolkit:
|
|
|
403
401
|
|
|
404
402
|
return {
|
|
405
403
|
'url_for': url_for,
|
|
406
|
-
'iatoolkit_version': self.version,
|
|
404
|
+
'iatoolkit_version': f'{self.version}',
|
|
405
|
+
'license': self.license,
|
|
407
406
|
'app_name': 'IAToolkit',
|
|
408
407
|
'user_identifier': SessionManager.get('user_identifier'),
|
|
409
408
|
'company_short_name': SessionManager.get('company_short_name'),
|
|
410
409
|
'user_is_local': user_profile.get('user_is_local'),
|
|
411
410
|
'user_email': user_profile.get('user_email'),
|
|
412
|
-
'iatoolkit_base_url':
|
|
411
|
+
'iatoolkit_base_url': request.url_root,
|
|
413
412
|
'flashed_messages': get_flashed_messages(with_categories=True),
|
|
414
413
|
't': translate_for_template
|
|
415
414
|
}
|
|
@@ -442,7 +441,7 @@ class IAToolkit:
|
|
|
442
441
|
if not self._injector:
|
|
443
442
|
raise IAToolkitException(
|
|
444
443
|
IAToolkitException.ErrorType.CONFIG_ERROR,
|
|
445
|
-
"App no
|
|
444
|
+
"App no initialized. Call create_app() first"
|
|
446
445
|
)
|
|
447
446
|
return self._injector.get(Dispatcher)
|
|
448
447
|
|
|
@@ -450,7 +449,7 @@ class IAToolkit:
|
|
|
450
449
|
if not self.db_manager:
|
|
451
450
|
raise IAToolkitException(
|
|
452
451
|
IAToolkitException.ErrorType.CONFIG_ERROR,
|
|
453
|
-
"Database manager
|
|
452
|
+
"Database manager not initialized."
|
|
454
453
|
)
|
|
455
454
|
return self.db_manager
|
|
456
455
|
|
|
@@ -459,7 +458,7 @@ class IAToolkit:
|
|
|
459
458
|
default_download_dir = os.path.join(os.getcwd(), 'iatoolkit-downloads')
|
|
460
459
|
|
|
461
460
|
# 3. if user specified one, use it
|
|
462
|
-
download_dir = self.
|
|
461
|
+
download_dir = self._get_config_value('IATOOLKIT_DOWNLOAD_DIR', default_download_dir)
|
|
463
462
|
|
|
464
463
|
# 3. save it in the app config
|
|
465
464
|
self.app.config['IATOOLKIT_DOWNLOAD_DIR'] = download_dir
|
|
@@ -13,12 +13,13 @@ import logging
|
|
|
13
13
|
MAX_ATTACH_BYTES = int(os.getenv("BREVO_MAX_ATTACH_BYTES", str(5 * 1024 * 1024))) # 5MB seguro
|
|
14
14
|
|
|
15
15
|
|
|
16
|
-
class
|
|
17
|
-
def
|
|
16
|
+
class BrevoMailApp:
|
|
17
|
+
def _init_brevo(self, provider_config: dict, sender: dict = None):
|
|
18
|
+
# config and init the brevo client
|
|
18
19
|
self.configuration = sib_api_v3_sdk.Configuration()
|
|
19
|
-
self.configuration.api_key['api-key'] =
|
|
20
|
+
self.configuration.api_key['api-key'] = provider_config.get("api_key")
|
|
20
21
|
self.mail_api = sib_api_v3_sdk.TransactionalEmailsApi(sib_api_v3_sdk.ApiClient(self.configuration))
|
|
21
|
-
|
|
22
|
+
|
|
22
23
|
|
|
23
24
|
@staticmethod
|
|
24
25
|
def _strip_data_url_prefix(b64: str) -> str:
|
|
@@ -73,13 +74,20 @@ class MailApp:
|
|
|
73
74
|
|
|
74
75
|
|
|
75
76
|
def send_email(self,
|
|
77
|
+
provider_config: dict,
|
|
76
78
|
to: str,
|
|
77
79
|
subject: str,
|
|
78
80
|
body: str,
|
|
79
|
-
sender: dict
|
|
81
|
+
sender: dict,
|
|
80
82
|
attachments: list[dict] = None):
|
|
81
|
-
|
|
82
|
-
|
|
83
|
+
|
|
84
|
+
if not provider_config.get("api_key"):
|
|
85
|
+
logging.error(f'Try to send brevo_mail without api_key in provider_config')
|
|
86
|
+
raise IAToolkitException(IAToolkitException.ErrorType.MAIL_ERROR,
|
|
87
|
+
f"Invalid mail configuration for Brevo: missing api-key")
|
|
88
|
+
|
|
89
|
+
# init the Brevo client
|
|
90
|
+
self._init_brevo(provider_config)
|
|
83
91
|
|
|
84
92
|
try:
|
|
85
93
|
sdk_attachments = self._normalize_attachments(attachments)
|
|
@@ -112,34 +120,4 @@ class MailApp:
|
|
|
112
120
|
logging.exception("MAIL ERROR: %s", str(e))
|
|
113
121
|
raise IAToolkitException(IAToolkitException.ErrorType.MAIL_ERROR,
|
|
114
122
|
f"No se pudo enviar correo: {str(e)}") from e
|
|
115
|
-
''''
|
|
116
|
-
def send_template_email(self,
|
|
117
|
-
subject: str,
|
|
118
|
-
recipients: list,
|
|
119
|
-
template_name: str,
|
|
120
|
-
context: dict,
|
|
121
|
-
sender=None):
|
|
122
|
-
try:
|
|
123
|
-
# Renderiza el template con el contexto proporcionado
|
|
124
|
-
with self.app.app_context():
|
|
125
|
-
html_message = render_template(template_name, **context)
|
|
126
123
|
|
|
127
|
-
# Crea el mensaje
|
|
128
|
-
msg = Message(
|
|
129
|
-
subject=subject,
|
|
130
|
-
recipients=recipients,
|
|
131
|
-
html=html_message,
|
|
132
|
-
sender=sender or self.app.config.get('MAIL_DEFAULT_SENDER')
|
|
133
|
-
)
|
|
134
|
-
|
|
135
|
-
# Envía el correo
|
|
136
|
-
# self.send_brevo_email(msg)
|
|
137
|
-
pass
|
|
138
|
-
except jinja2.exceptions.TemplateNotFound:
|
|
139
|
-
raise IAToolkitException(IAToolkitException.ErrorType.MAIL_ERROR,
|
|
140
|
-
f"Error: No se encontró el template '{template_name}'.")
|
|
141
|
-
except Exception as e:
|
|
142
|
-
raise IAToolkitException(IAToolkitException.ErrorType.MAIL_ERROR,
|
|
143
|
-
f'No se pudo enviar correo: {str(e)}') from e
|
|
144
|
-
|
|
145
|
-
'''
|
iatoolkit/infra/llm_client.py
CHANGED
|
@@ -75,9 +75,12 @@ class llmClient:
|
|
|
75
75
|
force_tool_name = None
|
|
76
76
|
reasoning = {}
|
|
77
77
|
|
|
78
|
-
if 'gpt-5'
|
|
78
|
+
if model in ('gpt-5', 'gpt-5-mini'):
|
|
79
79
|
text['verbosity'] = "low"
|
|
80
80
|
reasoning = {"effort": 'minimal'}
|
|
81
|
+
elif model == 'gpt-5.1':
|
|
82
|
+
text['verbosity'] = "low"
|
|
83
|
+
reasoning = {"effort": 'low'}
|
|
81
84
|
|
|
82
85
|
try:
|
|
83
86
|
start_time = time.time()
|
|
@@ -86,7 +89,7 @@ class llmClient:
|
|
|
86
89
|
# get the proxy for the company
|
|
87
90
|
llm_proxy = self.llm_proxy_factory.create_for_company(company)
|
|
88
91
|
|
|
89
|
-
#
|
|
92
|
+
# this is the first call to the LLM on the iteration
|
|
90
93
|
try:
|
|
91
94
|
input_messages = [{
|
|
92
95
|
"role": "user",
|
|
@@ -132,7 +135,7 @@ class llmClient:
|
|
|
132
135
|
try:
|
|
133
136
|
result = self.dispatcher.dispatch(
|
|
134
137
|
company_short_name=company.short_name,
|
|
135
|
-
|
|
138
|
+
function_name=function_name,
|
|
136
139
|
**args
|
|
137
140
|
)
|
|
138
141
|
force_tool_name = None
|
|
@@ -170,10 +173,10 @@ class llmClient:
|
|
|
170
173
|
f_calls.append(f_call_identity)
|
|
171
174
|
f_call_time += elapsed
|
|
172
175
|
|
|
173
|
-
logging.info(f"end execution {function_name} in {elapsed:.1f} secs.")
|
|
176
|
+
logging.info(f"[{company.short_name}] Tool end execution: {function_name} in {elapsed:.1f} secs.")
|
|
174
177
|
|
|
175
178
|
if not function_calls:
|
|
176
|
-
break # no function
|
|
179
|
+
break # no more function calls, the answer to send back to llm
|
|
177
180
|
|
|
178
181
|
# send results back to the LLM
|
|
179
182
|
tool_choice_value = "auto"
|
|
@@ -226,6 +229,7 @@ class llmClient:
|
|
|
226
229
|
'aditional_data': decoded_response.get('aditional_data', {}),
|
|
227
230
|
'response_id': response.id,
|
|
228
231
|
'query_id': query.id,
|
|
232
|
+
'model': model,
|
|
229
233
|
}
|
|
230
234
|
except SQLAlchemyError as db_error:
|
|
231
235
|
# rollback
|
iatoolkit/locales/en.yaml
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
ui:
|
|
3
3
|
login_widget:
|
|
4
4
|
title: "Sign In"
|
|
5
|
-
welcome_message: "Enter your credentials or register to access
|
|
5
|
+
welcome_message: "Enter your credentials or register to access this platform."
|
|
6
6
|
email_placeholder: "Email address"
|
|
7
7
|
password_placeholder: "Password"
|
|
8
8
|
login_button: "Login"
|
|
@@ -42,8 +42,9 @@ ui:
|
|
|
42
42
|
|
|
43
43
|
chat:
|
|
44
44
|
welcome_message: "Hello! How can I help you today?"
|
|
45
|
-
input_placeholder: "Type
|
|
45
|
+
input_placeholder: "Type here..."
|
|
46
46
|
prompts_available: "Available prompts"
|
|
47
|
+
init_context: "Initializing the context ..."
|
|
47
48
|
|
|
48
49
|
tooltips:
|
|
49
50
|
history: "History of my queries"
|
|
@@ -130,6 +131,9 @@ errors:
|
|
|
130
131
|
user_not_authorized: "user is not authorized for this company"
|
|
131
132
|
account_not_verified: "Your account has not been verified. Please check your email."
|
|
132
133
|
missing_response_id: "Can not found 'previous_response_id' for '{company_short_name}/{user_identifier}'. Reinit context"
|
|
134
|
+
context_rebuild_failed: "Company context rebuild failed."
|
|
135
|
+
cannot_read_excel: "Cannot read Excel file"
|
|
136
|
+
cannot_read_csv: "Cannot read CSV file"
|
|
133
137
|
|
|
134
138
|
|
|
135
139
|
api_responses:
|
|
@@ -138,12 +142,14 @@ api_responses:
|
|
|
138
142
|
services:
|
|
139
143
|
mail_sent: "Email sent successfully."
|
|
140
144
|
start_query: "Hello, what can I help you with today?"
|
|
145
|
+
mail_change_password: "mail sent for password change"
|
|
141
146
|
|
|
142
147
|
|
|
143
148
|
flash_messages:
|
|
144
149
|
password_changed_success: "Your password has been successfully reset. You can now log in."
|
|
145
150
|
login_required: "Please log in to continue."
|
|
146
151
|
signup_success: "Registration successful. Please check your email to verify your account."
|
|
152
|
+
signup_success_no_verification: "Registration successful."
|
|
147
153
|
user_associated_success: "Existing user successfully associated with the new company."
|
|
148
154
|
account_verified_success: "Your account has been successfully verified. Welcome!"
|
|
149
155
|
forgot_password_success: "If your email is registered, you will receive a link to reset your password."
|
|
@@ -165,3 +171,5 @@ js_messages:
|
|
|
165
171
|
loading: "Loading..."
|
|
166
172
|
reload_init: "init reloading context in background..."
|
|
167
173
|
no_history_found: "No query history found."
|
|
174
|
+
example: "Example:"
|
|
175
|
+
|