iatoolkit 0.66.2__py3-none-any.whl → 0.71.2__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 +2 -6
- iatoolkit/base_company.py +3 -31
- iatoolkit/cli_commands.py +1 -1
- iatoolkit/common/routes.py +5 -1
- iatoolkit/common/session_manager.py +2 -0
- iatoolkit/company_registry.py +1 -2
- iatoolkit/iatoolkit.py +13 -13
- iatoolkit/infra/llm_client.py +8 -12
- iatoolkit/infra/llm_proxy.py +38 -10
- iatoolkit/locales/en.yaml +25 -2
- iatoolkit/locales/es.yaml +27 -4
- iatoolkit/repositories/database_manager.py +8 -3
- iatoolkit/repositories/document_repo.py +1 -1
- iatoolkit/repositories/models.py +6 -8
- iatoolkit/repositories/profile_repo.py +0 -4
- iatoolkit/repositories/vs_repo.py +26 -20
- iatoolkit/services/auth_service.py +2 -2
- iatoolkit/services/branding_service.py +11 -7
- iatoolkit/services/company_context_service.py +155 -0
- iatoolkit/services/configuration_service.py +133 -0
- iatoolkit/services/dispatcher_service.py +75 -70
- iatoolkit/services/document_service.py +5 -2
- iatoolkit/services/embedding_service.py +146 -0
- iatoolkit/services/excel_service.py +15 -11
- iatoolkit/services/file_processor_service.py +4 -12
- iatoolkit/services/history_service.py +7 -7
- iatoolkit/services/i18n_service.py +4 -4
- iatoolkit/services/jwt_service.py +7 -9
- iatoolkit/services/language_service.py +29 -23
- iatoolkit/services/load_documents_service.py +100 -113
- iatoolkit/services/mail_service.py +9 -4
- iatoolkit/services/profile_service.py +10 -7
- iatoolkit/services/prompt_manager_service.py +20 -16
- iatoolkit/services/query_service.py +112 -43
- iatoolkit/services/search_service.py +11 -4
- iatoolkit/services/sql_service.py +57 -25
- iatoolkit/services/user_feedback_service.py +15 -13
- iatoolkit/static/js/chat_history_button.js +3 -5
- iatoolkit/static/js/chat_main.js +2 -17
- iatoolkit/static/js/chat_onboarding_button.js +6 -0
- iatoolkit/static/styles/chat_iatoolkit.css +69 -158
- iatoolkit/static/styles/chat_modal.css +1 -37
- iatoolkit/static/styles/onboarding.css +7 -0
- iatoolkit/system_prompts/query_main.prompt +2 -10
- iatoolkit/templates/change_password.html +1 -1
- iatoolkit/templates/chat.html +12 -4
- iatoolkit/templates/chat_modals.html +4 -0
- iatoolkit/templates/error.html +1 -1
- iatoolkit/templates/login_simulation.html +17 -6
- iatoolkit/templates/onboarding_shell.html +4 -1
- iatoolkit/views/base_login_view.py +7 -8
- iatoolkit/views/change_password_view.py +2 -3
- iatoolkit/views/embedding_api_view.py +65 -0
- iatoolkit/views/external_login_view.py +1 -1
- iatoolkit/views/file_store_api_view.py +1 -1
- iatoolkit/views/forgot_password_view.py +2 -4
- iatoolkit/views/help_content_api_view.py +9 -9
- iatoolkit/views/history_api_view.py +1 -1
- iatoolkit/views/home_view.py +2 -2
- iatoolkit/views/init_context_api_view.py +18 -17
- iatoolkit/views/llmquery_api_view.py +3 -2
- iatoolkit/views/login_simulation_view.py +14 -2
- iatoolkit/views/login_view.py +9 -9
- iatoolkit/views/signup_view.py +2 -4
- iatoolkit/views/verify_user_view.py +2 -4
- {iatoolkit-0.66.2.dist-info → iatoolkit-0.71.2.dist-info}/METADATA +40 -22
- iatoolkit-0.71.2.dist-info/RECORD +122 -0
- iatoolkit-0.71.2.dist-info/licenses/LICENSE +21 -0
- iatoolkit/services/help_content_service.py +0 -30
- iatoolkit/services/onboarding_service.py +0 -43
- iatoolkit-0.66.2.dist-info/RECORD +0 -119
- {iatoolkit-0.66.2.dist-info → iatoolkit-0.71.2.dist-info}/WHEEL +0 -0
- {iatoolkit-0.66.2.dist-info → iatoolkit-0.71.2.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# iatoolkit/views/embedding_api_view.py
|
|
2
|
+
# Copyright (c) 2024 Fernando Libedinsky
|
|
3
|
+
# Product: IAToolkit
|
|
4
|
+
#
|
|
5
|
+
# IAToolkit is open source software.
|
|
6
|
+
|
|
7
|
+
from flask import request, jsonify
|
|
8
|
+
from flask.views import MethodView
|
|
9
|
+
from iatoolkit.services.embedding_service import EmbeddingService
|
|
10
|
+
from iatoolkit.services.auth_service import AuthService
|
|
11
|
+
from injector import inject
|
|
12
|
+
import logging
|
|
13
|
+
|
|
14
|
+
class EmbeddingApiView(MethodView):
|
|
15
|
+
"""
|
|
16
|
+
Handles API requests to generate an embedding for a given text.
|
|
17
|
+
Authentication is based on the active Flask session.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
@inject
|
|
21
|
+
def __init__(self,
|
|
22
|
+
auth_service: AuthService,
|
|
23
|
+
embedding_service: EmbeddingService):
|
|
24
|
+
self.auth_service = auth_service
|
|
25
|
+
self.embedding_service = embedding_service
|
|
26
|
+
|
|
27
|
+
def post(self, company_short_name: str):
|
|
28
|
+
"""
|
|
29
|
+
Generates an embedding for the text provided in the request body.
|
|
30
|
+
Expects a JSON payload with a "text" key.
|
|
31
|
+
"""
|
|
32
|
+
try:
|
|
33
|
+
# 1. Authenticate the user from the current session
|
|
34
|
+
auth_result = self.auth_service.verify(anonymous=True)
|
|
35
|
+
if not auth_result.get("success"):
|
|
36
|
+
return jsonify(auth_result), auth_result.get("status_code", 401)
|
|
37
|
+
|
|
38
|
+
# 2. Validate incoming request data
|
|
39
|
+
if not request.is_json:
|
|
40
|
+
return jsonify({"error": "Request must be JSON"}), 400
|
|
41
|
+
|
|
42
|
+
data = request.get_json()
|
|
43
|
+
text = data.get('text')
|
|
44
|
+
|
|
45
|
+
if not text:
|
|
46
|
+
return jsonify({"error": "The 'text' key is required."}), 400
|
|
47
|
+
|
|
48
|
+
# 3. Call the embedding service, now passing the company_short_name
|
|
49
|
+
embedding_b64 = self.embedding_service.embed_text(
|
|
50
|
+
company_short_name=company_short_name,
|
|
51
|
+
text=text,
|
|
52
|
+
to_base64=True
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
model_name = self.embedding_service.get_model_name(company_short_name)
|
|
56
|
+
response = {
|
|
57
|
+
"embedding": embedding_b64,
|
|
58
|
+
"model": model_name
|
|
59
|
+
}
|
|
60
|
+
return jsonify(response), 200
|
|
61
|
+
|
|
62
|
+
except Exception as e:
|
|
63
|
+
logging.exception(f"Unexpected error in EmbeddingApiView: {e}")
|
|
64
|
+
# Return a generic error message to the client
|
|
65
|
+
return jsonify({"error": "An internal error occurred while generating the embedding."}), 500
|
|
@@ -47,7 +47,7 @@ class ExternalLoginView(BaseLoginView):
|
|
|
47
47
|
|
|
48
48
|
# 5. Delegate the path decision to the centralized logic.
|
|
49
49
|
try:
|
|
50
|
-
return self._handle_login_path(
|
|
50
|
+
return self._handle_login_path(company_short_name, user_identifier, target_url, redeem_token)
|
|
51
51
|
except Exception as e:
|
|
52
52
|
logging.exception(f"Error processing external login path for {company_short_name}/{user_identifier}: {e}")
|
|
53
53
|
return jsonify({"error": f"Internal server error while starting chat. {str(e)}"}), 500
|
|
@@ -48,7 +48,7 @@ class FileStoreApiView(MethodView):
|
|
|
48
48
|
# get the file content from base64
|
|
49
49
|
content = base64.b64decode(base64_content)
|
|
50
50
|
|
|
51
|
-
new_document = self.doc_service.
|
|
51
|
+
new_document = self.doc_service._file_processing_callback(
|
|
52
52
|
filename=filename,
|
|
53
53
|
content=content,
|
|
54
54
|
company=company,
|
|
@@ -30,9 +30,8 @@ class ForgotPasswordView(MethodView):
|
|
|
30
30
|
return render_template('error.html',
|
|
31
31
|
message=self.i18n_service.t('errors.templates.company_not_found')), 404
|
|
32
32
|
|
|
33
|
-
branding_data = self.branding_service.get_company_branding(
|
|
33
|
+
branding_data = self.branding_service.get_company_branding(company_short_name)
|
|
34
34
|
return render_template('forgot_password.html',
|
|
35
|
-
company=company,
|
|
36
35
|
company_short_name=company_short_name,
|
|
37
36
|
branding=branding_data
|
|
38
37
|
)
|
|
@@ -45,7 +44,7 @@ class ForgotPasswordView(MethodView):
|
|
|
45
44
|
return render_template('error.html',
|
|
46
45
|
message=self.i18n_service.t('errors.templates.company_not_found')), 404
|
|
47
46
|
|
|
48
|
-
branding_data = self.branding_service.get_company_branding(
|
|
47
|
+
branding_data = self.branding_service.get_company_branding(company_short_name)
|
|
49
48
|
email = request.form.get('email')
|
|
50
49
|
|
|
51
50
|
# create a safe token and url for it
|
|
@@ -59,7 +58,6 @@ class ForgotPasswordView(MethodView):
|
|
|
59
58
|
flash(response["error"], 'error')
|
|
60
59
|
return render_template(
|
|
61
60
|
'forgot_password.html',
|
|
62
|
-
company=company,
|
|
63
61
|
company_short_name=company_short_name,
|
|
64
62
|
branding=branding_data,
|
|
65
63
|
form_data={"email": email}), 400
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
from flask import request, jsonify
|
|
7
7
|
from flask.views import MethodView
|
|
8
|
-
from iatoolkit.services.
|
|
8
|
+
from iatoolkit.services.configuration_service import ConfigurationService
|
|
9
9
|
from iatoolkit.services.i18n_service import I18nService
|
|
10
10
|
from iatoolkit.services.auth_service import AuthService
|
|
11
11
|
from injector import inject
|
|
@@ -21,10 +21,10 @@ class HelpContentApiView(MethodView):
|
|
|
21
21
|
@inject
|
|
22
22
|
def __init__(self,
|
|
23
23
|
auth_service: AuthService,
|
|
24
|
-
|
|
24
|
+
config_service: ConfigurationService,
|
|
25
25
|
i18n_service: I18nService):
|
|
26
26
|
self.auth_service = auth_service
|
|
27
|
-
self.
|
|
27
|
+
self.config_service = config_service
|
|
28
28
|
self.i18n_service = i18n_service
|
|
29
29
|
|
|
30
30
|
def post(self, company_short_name: str):
|
|
@@ -36,10 +36,10 @@ class HelpContentApiView(MethodView):
|
|
|
36
36
|
|
|
37
37
|
user_identifier = auth_result.get('user_identifier')
|
|
38
38
|
|
|
39
|
-
# 2. Call the
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
39
|
+
# 2. Call the config service with the unified identifier.
|
|
40
|
+
response = self.config_service.get_configuration(
|
|
41
|
+
company_short_name=company_short_name,
|
|
42
|
+
content_key='help_content' # specific key for this service
|
|
43
43
|
)
|
|
44
44
|
|
|
45
45
|
if "error" in response:
|
|
@@ -50,5 +50,5 @@ class HelpContentApiView(MethodView):
|
|
|
50
50
|
|
|
51
51
|
except Exception as e:
|
|
52
52
|
logging.exception(
|
|
53
|
-
f"Unexpected error fetching help_content for {company_short_name}
|
|
54
|
-
return jsonify({"error_message": self.i18n_service.t('errors.general.unexpected_error')}), 500
|
|
53
|
+
f"Unexpected error fetching help_content for {company_short_name}: {e}")
|
|
54
|
+
return jsonify({"error_message": self.i18n_service.t('errors.general.unexpected_error', error=str(e))}), 500
|
|
@@ -53,4 +53,4 @@ class HistoryApiView(MethodView):
|
|
|
53
53
|
except Exception as e:
|
|
54
54
|
logging.exception(
|
|
55
55
|
f"Unexpected error: {e}")
|
|
56
|
-
return jsonify({"error_message": self.i18n_service.t('errors.general.unexpected_error')}), 500
|
|
56
|
+
return jsonify({"error_message": self.i18n_service.t('errors.general.unexpected_error', error=str(e))}), 500
|
iatoolkit/views/home_view.py
CHANGED
|
@@ -25,13 +25,14 @@ class HomeView(MethodView):
|
|
|
25
25
|
self.util = utility
|
|
26
26
|
|
|
27
27
|
def get(self, company_short_name: str):
|
|
28
|
+
branding_data = {}
|
|
28
29
|
try:
|
|
29
30
|
company = self.profile_service.get_company_by_short_name(company_short_name)
|
|
30
31
|
if not company:
|
|
31
32
|
return render_template('error.html',
|
|
32
33
|
message=self.i18n_service.t('errors.templates.company_not_found')), 404
|
|
33
34
|
|
|
34
|
-
branding_data = self.branding_service.get_company_branding(
|
|
35
|
+
branding_data = self.branding_service.get_company_branding(company_short_name)
|
|
35
36
|
home_template = self.util.get_company_template(company_short_name, "home.html")
|
|
36
37
|
|
|
37
38
|
# 2. Verificamos si el archivo de plantilla personalizado no existe.
|
|
@@ -47,7 +48,6 @@ class HomeView(MethodView):
|
|
|
47
48
|
# 3. Si el archivo existe, intentamos leerlo y renderizarlo.
|
|
48
49
|
return render_template_string(
|
|
49
50
|
home_template,
|
|
50
|
-
company=company,
|
|
51
51
|
company_short_name=company_short_name,
|
|
52
52
|
branding=branding_data,
|
|
53
53
|
)
|
|
@@ -4,7 +4,7 @@ from iatoolkit.services.query_service import QueryService
|
|
|
4
4
|
from iatoolkit.services.profile_service import ProfileService
|
|
5
5
|
from iatoolkit.services.auth_service import AuthService
|
|
6
6
|
from iatoolkit.services.i18n_service import I18nService
|
|
7
|
-
from flask import jsonify
|
|
7
|
+
from flask import jsonify, request
|
|
8
8
|
import logging
|
|
9
9
|
|
|
10
10
|
|
|
@@ -39,29 +39,30 @@ class InitContextApiView(MethodView):
|
|
|
39
39
|
|
|
40
40
|
user_identifier = auth_result.get('user_identifier')
|
|
41
41
|
|
|
42
|
-
#
|
|
43
|
-
|
|
44
|
-
|
|
42
|
+
# check if model was sent as a parameter
|
|
43
|
+
data = request.get_json(silent=True) or {}
|
|
44
|
+
model = data.get('model', '')
|
|
45
45
|
|
|
46
|
-
# LLM context
|
|
47
|
-
self.query_service.
|
|
46
|
+
# reinit the LLM context
|
|
47
|
+
response = self.query_service.init_context(
|
|
48
48
|
company_short_name=company_short_name,
|
|
49
|
-
user_identifier=user_identifier
|
|
50
|
-
|
|
49
|
+
user_identifier=user_identifier,
|
|
50
|
+
model=model)
|
|
51
51
|
|
|
52
|
-
|
|
53
|
-
company_short_name=company_short_name,
|
|
54
|
-
user_identifier=user_identifier
|
|
55
|
-
)
|
|
56
|
-
|
|
57
|
-
# 3. Respond with JSON, as this is an API endpoint.
|
|
52
|
+
# Respond with JSON, as this is an API endpoint.
|
|
58
53
|
success_message = self.i18n_service.t('api_responses.context_reloaded_success')
|
|
59
|
-
|
|
54
|
+
response_message = {'status': 'OK', 'message': success_message}
|
|
55
|
+
|
|
56
|
+
# if received a response ID with the context, return it
|
|
57
|
+
if response.get('response_id'):
|
|
58
|
+
response_message['response_id'] = response['response_id']
|
|
59
|
+
|
|
60
|
+
return jsonify(response_message), 200
|
|
60
61
|
|
|
61
62
|
except Exception as e:
|
|
62
63
|
logging.exception(f"errors while reloading context: {e}")
|
|
63
|
-
error_message = self.i18n_service.t('errors.general.unexpected_error')
|
|
64
|
-
return jsonify({"error_message": error_message}),
|
|
64
|
+
error_message = self.i18n_service.t('errors.general.unexpected_error', error=str(e))
|
|
65
|
+
return jsonify({"error_message": error_message}), 406
|
|
65
66
|
|
|
66
67
|
def options(self, company_short_name):
|
|
67
68
|
"""
|
|
@@ -44,14 +44,15 @@ class LLMQueryApiView(MethodView):
|
|
|
44
44
|
question=data.get('question', ''),
|
|
45
45
|
prompt_name=data.get('prompt_name'),
|
|
46
46
|
client_data=data.get('client_data', {}),
|
|
47
|
+
response_id = data.get('response_id'),
|
|
47
48
|
files=data.get('files', [])
|
|
48
49
|
)
|
|
49
50
|
if 'error' in result:
|
|
50
|
-
return jsonify(result),
|
|
51
|
+
return jsonify(result), 407
|
|
51
52
|
|
|
52
53
|
return jsonify(result), 200
|
|
53
54
|
|
|
54
55
|
except Exception as e:
|
|
55
56
|
logging.exception(
|
|
56
57
|
f"Unexpected error: {e}")
|
|
57
|
-
return jsonify({"error_message": self.i18n_service.t('errors.general.unexpected_error')}), 500
|
|
58
|
+
return jsonify({"error_message": self.i18n_service.t('errors.general.unexpected_error', error=str(e))}), 500
|
|
@@ -10,17 +10,29 @@ from flask.views import MethodView
|
|
|
10
10
|
from flask import render_template, request, Response
|
|
11
11
|
from injector import inject
|
|
12
12
|
from iatoolkit.services.profile_service import ProfileService
|
|
13
|
+
from iatoolkit.services.branding_service import BrandingService
|
|
13
14
|
|
|
14
15
|
|
|
15
16
|
class LoginSimulationView(MethodView):
|
|
16
17
|
@inject
|
|
17
18
|
def __init__(self,
|
|
18
|
-
profile_service: ProfileService
|
|
19
|
+
profile_service: ProfileService,
|
|
20
|
+
branding_service: BrandingService):
|
|
19
21
|
self.profile_service = profile_service
|
|
22
|
+
self.branding_service = branding_service
|
|
23
|
+
|
|
20
24
|
|
|
21
25
|
def get(self, company_short_name: str = None):
|
|
22
|
-
|
|
26
|
+
company = self.profile_service.get_company_by_short_name(company_short_name)
|
|
27
|
+
if not company:
|
|
28
|
+
return render_template('error.html',
|
|
29
|
+
company_short_name=company_short_name,
|
|
30
|
+
message="Empresa no encontrada"), 404
|
|
31
|
+
|
|
32
|
+
branding_data = self.branding_service.get_company_branding(company_short_name)
|
|
33
|
+
|
|
23
34
|
return render_template('login_simulation.html',
|
|
35
|
+
branding=branding_data,
|
|
24
36
|
company_short_name=company_short_name
|
|
25
37
|
)
|
|
26
38
|
|
iatoolkit/views/login_view.py
CHANGED
|
@@ -12,7 +12,7 @@ from iatoolkit.services.jwt_service import JWTService
|
|
|
12
12
|
from iatoolkit.services.query_service import QueryService
|
|
13
13
|
from iatoolkit.services.prompt_manager_service import PromptService
|
|
14
14
|
from iatoolkit.services.branding_service import BrandingService
|
|
15
|
-
from iatoolkit.services.
|
|
15
|
+
from iatoolkit.services.configuration_service import ConfigurationService
|
|
16
16
|
from iatoolkit.services.i18n_service import I18nService
|
|
17
17
|
from iatoolkit.views.base_login_view import BaseLoginView
|
|
18
18
|
import logging
|
|
@@ -29,7 +29,7 @@ class LoginView(BaseLoginView):
|
|
|
29
29
|
return render_template('error.html',
|
|
30
30
|
message=self.i18n_service.t('errors.templates.company_not_found')), 404
|
|
31
31
|
|
|
32
|
-
branding_data = self.branding_service.get_company_branding(
|
|
32
|
+
branding_data = self.branding_service.get_company_branding(company_short_name)
|
|
33
33
|
email = request.form.get('email')
|
|
34
34
|
password = request.form.get('password')
|
|
35
35
|
|
|
@@ -61,7 +61,7 @@ class LoginView(BaseLoginView):
|
|
|
61
61
|
|
|
62
62
|
# 2. Delegate the path decision to the centralized logic.
|
|
63
63
|
try:
|
|
64
|
-
return self._handle_login_path(
|
|
64
|
+
return self._handle_login_path(company_short_name, user_identifier, target_url)
|
|
65
65
|
except Exception as e:
|
|
66
66
|
message = self.i18n_service.t('errors.templates.processing_error', error=str(e))
|
|
67
67
|
return render_template(
|
|
@@ -83,7 +83,7 @@ class FinalizeContextView(MethodView):
|
|
|
83
83
|
query_service: QueryService,
|
|
84
84
|
prompt_service: PromptService,
|
|
85
85
|
branding_service: BrandingService,
|
|
86
|
-
|
|
86
|
+
config_service: ConfigurationService,
|
|
87
87
|
jwt_service: JWTService,
|
|
88
88
|
i18n_service: I18nService
|
|
89
89
|
):
|
|
@@ -92,7 +92,7 @@ class FinalizeContextView(MethodView):
|
|
|
92
92
|
self.query_service = query_service
|
|
93
93
|
self.prompt_service = prompt_service
|
|
94
94
|
self.branding_service = branding_service
|
|
95
|
-
self.
|
|
95
|
+
self.config_service = config_service
|
|
96
96
|
self.i18n_service = i18n_service
|
|
97
97
|
|
|
98
98
|
def get(self, company_short_name: str, token: str = None):
|
|
@@ -111,7 +111,7 @@ class FinalizeContextView(MethodView):
|
|
|
111
111
|
|
|
112
112
|
user_identifier = payload.get('user_identifier')
|
|
113
113
|
else:
|
|
114
|
-
logging.
|
|
114
|
+
logging.error("missing session information or auth token")
|
|
115
115
|
return redirect(url_for('home', company_short_name=company_short_name))
|
|
116
116
|
|
|
117
117
|
company = self.profile_service.get_company_by_short_name(company_short_name)
|
|
@@ -119,17 +119,17 @@ class FinalizeContextView(MethodView):
|
|
|
119
119
|
return render_template('error.html',
|
|
120
120
|
company_short_name=company_short_name,
|
|
121
121
|
message="Empresa no encontrada"), 404
|
|
122
|
-
branding_data = self.branding_service.get_company_branding(
|
|
122
|
+
branding_data = self.branding_service.get_company_branding(company_short_name)
|
|
123
123
|
|
|
124
124
|
# 2. Finalize the context rebuild (the heavy task).
|
|
125
|
-
self.query_service.
|
|
125
|
+
self.query_service.set_context_for_llm(
|
|
126
126
|
company_short_name=company_short_name,
|
|
127
127
|
user_identifier=user_identifier
|
|
128
128
|
)
|
|
129
129
|
|
|
130
130
|
# 3. render the chat page.
|
|
131
131
|
prompts = self.prompt_service.get_user_prompts(company_short_name)
|
|
132
|
-
onboarding_cards = self.
|
|
132
|
+
onboarding_cards = self.config_service.get_configuration(company_short_name, 'onboarding_cards')
|
|
133
133
|
|
|
134
134
|
# Get the entire 'js_messages' block in the correct language.
|
|
135
135
|
js_translations = self.i18n_service.get_translation_block('js_messages')
|
iatoolkit/views/signup_view.py
CHANGED
|
@@ -32,9 +32,8 @@ class SignupView(MethodView):
|
|
|
32
32
|
return render_template('error.html',
|
|
33
33
|
message=self.i18n_service.t('errors.templates.company_not_found')), 404
|
|
34
34
|
|
|
35
|
-
branding_data = self.branding_service.get_company_branding(
|
|
35
|
+
branding_data = self.branding_service.get_company_branding(company_short_name)
|
|
36
36
|
return render_template('signup.html',
|
|
37
|
-
company=company,
|
|
38
37
|
company_short_name=company_short_name,
|
|
39
38
|
branding=branding_data)
|
|
40
39
|
|
|
@@ -45,7 +44,7 @@ class SignupView(MethodView):
|
|
|
45
44
|
return render_template('error.html',
|
|
46
45
|
message=self.i18n_service.t('errors.templates.company_not_found')), 404
|
|
47
46
|
|
|
48
|
-
branding_data = self.branding_service.get_company_branding(
|
|
47
|
+
branding_data = self.branding_service.get_company_branding(company_short_name)
|
|
49
48
|
|
|
50
49
|
first_name = request.form.get('first_name')
|
|
51
50
|
last_name = request.form.get('last_name')
|
|
@@ -70,7 +69,6 @@ class SignupView(MethodView):
|
|
|
70
69
|
flash(response["error"], 'error')
|
|
71
70
|
return render_template(
|
|
72
71
|
'signup.html',
|
|
73
|
-
company=company,
|
|
74
72
|
company_short_name=company_short_name,
|
|
75
73
|
branding=branding_data,
|
|
76
74
|
form_data={
|
|
@@ -32,14 +32,13 @@ class VerifyAccountView(MethodView):
|
|
|
32
32
|
return render_template('error.html',
|
|
33
33
|
message=self.i18n_service.t('errors.templates.company_not_found')), 404
|
|
34
34
|
|
|
35
|
-
branding_data = self.branding_service.get_company_branding(
|
|
35
|
+
branding_data = self.branding_service.get_company_branding(company_short_name)
|
|
36
36
|
try:
|
|
37
37
|
# decode the token from the URL
|
|
38
38
|
email = self.serializer.loads(token, salt='email-confirm', max_age=3600*5)
|
|
39
39
|
except SignatureExpired:
|
|
40
40
|
flash(self.i18n_service.t('errors.verification.token_expired'), 'error')
|
|
41
41
|
return render_template('signup.html',
|
|
42
|
-
company=company,
|
|
43
42
|
company_short_name=company_short_name,
|
|
44
43
|
branding=branding_data,
|
|
45
44
|
token=token), 400
|
|
@@ -49,7 +48,6 @@ class VerifyAccountView(MethodView):
|
|
|
49
48
|
flash(response["error"], 'error')
|
|
50
49
|
return render_template(
|
|
51
50
|
'signup.html',
|
|
52
|
-
company=company,
|
|
53
51
|
company_short_name=company_short_name,
|
|
54
52
|
branding=branding_data,
|
|
55
53
|
token=token), 400
|
|
@@ -58,5 +56,5 @@ class VerifyAccountView(MethodView):
|
|
|
58
56
|
return redirect(url_for('home', company_short_name=company_short_name))
|
|
59
57
|
|
|
60
58
|
except Exception as e:
|
|
61
|
-
flash(self.i18n_service.t('errors.general.unexpected_error'), 'error')
|
|
59
|
+
flash(self.i18n_service.t('errors.general.unexpected_error', error=str(e)), 'error')
|
|
62
60
|
return redirect(url_for('home', company_short_name=company_short_name))
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: iatoolkit
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.71.2
|
|
4
4
|
Summary: IAToolkit
|
|
5
5
|
Author: Fernando Libedinsky
|
|
6
6
|
License-Expression: MIT
|
|
7
7
|
Requires-Python: >=3.12
|
|
8
8
|
Description-Content-Type: text/markdown
|
|
9
|
+
License-File: LICENSE
|
|
9
10
|
Requires-Dist: aiohappyeyeballs==2.4.4
|
|
10
11
|
Requires-Dist: aiohttp==3.11.9
|
|
11
12
|
Requires-Dist: aiosignal==1.3.1
|
|
@@ -206,47 +207,64 @@ Requires-Dist: wrapt==1.17.0
|
|
|
206
207
|
Requires-Dist: yarl==1.18.3
|
|
207
208
|
Requires-Dist: zipp==3.21.0
|
|
208
209
|
Requires-Dist: zstandard==0.23.0
|
|
210
|
+
Dynamic: license-file
|
|
209
211
|
|
|
210
212
|
|
|
211
213
|
<div align="center">
|
|
212
|
-
|
|
214
|
+
<h1>
|
|
215
|
+
IAToolkit
|
|
216
|
+
</h1>
|
|
217
|
+
|
|
213
218
|
<p><strong>The Open-Source Framework for Building AI Chatbots on Your Private Data.</strong></p>
|
|
219
|
+
<h4>
|
|
220
|
+
<a href="https://www.iatoolkit.com" target="_blank" style="text-decoration: none; color: inherit;">
|
|
221
|
+
www.iatoolkit.com
|
|
222
|
+
</a>
|
|
223
|
+
</h4>
|
|
214
224
|
</div>
|
|
215
225
|
|
|
216
|
-
IAToolkit is a comprehensive, open-source framework designed for building enterprise-grade
|
|
217
|
-
AI chatbots and conversational applications.
|
|
226
|
+
IAToolkit is a comprehensive, Python open-source framework designed for building enterprise-grade
|
|
227
|
+
AI chatbots and conversational applications. It bridges the gap between the power of
|
|
228
|
+
Large Language Models (LLMs) and the valuable,
|
|
229
|
+
private data locked within your organization's databases and documents.
|
|
230
|
+
|
|
218
231
|
With IAToolkit, you can build production-ready, context-aware chatbots and agents that
|
|
219
232
|
can query relational databases, perform semantic searches on documents,
|
|
220
233
|
and connect to your internal APIs in minutes.
|
|
221
234
|
|
|
222
|
-
|
|
235
|
+
Create secure, branded chat interfaces that can reason over your data, answer questions, and execute custom business logic,
|
|
236
|
+
all powered by leading models from OpenAI, Google Gemini, and more.
|
|
223
237
|
|
|
224
238
|
|
|
225
239
|
## 🚀 Key Features
|
|
226
240
|
|
|
227
|
-
*
|
|
228
|
-
*
|
|
229
|
-
*
|
|
241
|
+
* **🔗 Unified Data Connection**
|
|
242
|
+
* **Natural Language to SQL**: Let your chatbot query relational databases (PostgreSQL, MySQL, SQLite) using everyday language.
|
|
243
|
+
* **Semantic Document Search**: Automatically chunk, embed, and search across your private documents (PDFs, Word, etc.) to provide contextually accurate answers.
|
|
230
244
|
|
|
231
|
-
*
|
|
232
|
-
*
|
|
245
|
+
* **🏢 Enterprise-Ready Multi-Tenancy**
|
|
246
|
+
* Deploy isolated "Company" modules, each with its own data, tools, and context.
|
|
247
|
+
* Perfect for SaaS products or internal departmental agents.
|
|
233
248
|
|
|
234
|
-
*
|
|
235
|
-
*
|
|
249
|
+
* **🎨 Fully Brandable UI**
|
|
250
|
+
* Customize the look and feel for each "Company" with its own logos, colors, and even language settings (i18n).
|
|
251
|
+
* Provides a white-labeled experience for your users.
|
|
236
252
|
|
|
237
|
-
*
|
|
238
|
-
*
|
|
239
|
-
*
|
|
240
|
-
* Powerful Flask-based **CLI** for database setup, API key generation, and more.
|
|
253
|
+
* **🧠 LLM Agnostic**
|
|
254
|
+
* Switch between **OpenAI (GPT-*)** and **Google (Gemini-*)** with a single line change in your configuration.
|
|
255
|
+
* No code refactoring needed.
|
|
241
256
|
|
|
242
|
-
*
|
|
243
|
-
*
|
|
244
|
-
*
|
|
257
|
+
* **🛠️ Developer-First Experience**
|
|
258
|
+
* Built with a clean **Dependency Injection** architecture.
|
|
259
|
+
* High-quality code base with **90%+ test coverage**.
|
|
245
260
|
|
|
246
|
-
|
|
261
|
+
* **🔒 Security & Observability Built-In**
|
|
262
|
+
* Comes with integrated user authentication, API keys, and secure session handling out of the box.
|
|
263
|
+
* Full traceability with detailed logging of all queries, function calls, token usage, and costs.
|
|
264
|
+
## ⚡ Quick Start: Try our 'hello world' example
|
|
247
265
|
|
|
248
|
-
|
|
249
|
-
|
|
266
|
+
Ready to see it in action? Our Quickstart Guide will walk you through downloading, configuring, and launching your first AI assistant in just a few minutes.
|
|
267
|
+
It's the best way to experience the toolkit's capabilities firsthand.
|
|
250
268
|
|
|
251
269
|
## 🤝 Contributing
|
|
252
270
|
|