iatoolkit 0.3.9__py3-none-any.whl → 0.107.4__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of iatoolkit might be problematic. Click here for more details.
- iatoolkit/__init__.py +27 -35
- iatoolkit/base_company.py +3 -35
- iatoolkit/cli_commands.py +18 -47
- iatoolkit/common/__init__.py +0 -0
- iatoolkit/common/exceptions.py +48 -0
- iatoolkit/common/interfaces/__init__.py +0 -0
- iatoolkit/common/interfaces/asset_storage.py +34 -0
- iatoolkit/common/interfaces/database_provider.py +39 -0
- iatoolkit/common/model_registry.py +159 -0
- iatoolkit/common/routes.py +138 -0
- iatoolkit/common/session_manager.py +26 -0
- iatoolkit/common/util.py +353 -0
- iatoolkit/company_registry.py +66 -29
- iatoolkit/core.py +514 -0
- iatoolkit/infra/__init__.py +5 -0
- iatoolkit/infra/brevo_mail_app.py +123 -0
- iatoolkit/infra/call_service.py +140 -0
- iatoolkit/infra/connectors/__init__.py +5 -0
- iatoolkit/infra/connectors/file_connector.py +17 -0
- iatoolkit/infra/connectors/file_connector_factory.py +57 -0
- iatoolkit/infra/connectors/google_cloud_storage_connector.py +53 -0
- iatoolkit/infra/connectors/google_drive_connector.py +68 -0
- iatoolkit/infra/connectors/local_file_connector.py +46 -0
- iatoolkit/infra/connectors/s3_connector.py +33 -0
- iatoolkit/infra/google_chat_app.py +57 -0
- iatoolkit/infra/llm_providers/__init__.py +0 -0
- iatoolkit/infra/llm_providers/deepseek_adapter.py +278 -0
- iatoolkit/infra/llm_providers/gemini_adapter.py +350 -0
- iatoolkit/infra/llm_providers/openai_adapter.py +124 -0
- iatoolkit/infra/llm_proxy.py +268 -0
- iatoolkit/infra/llm_response.py +45 -0
- iatoolkit/infra/redis_session_manager.py +122 -0
- iatoolkit/locales/en.yaml +222 -0
- iatoolkit/locales/es.yaml +225 -0
- iatoolkit/repositories/__init__.py +5 -0
- iatoolkit/repositories/database_manager.py +187 -0
- iatoolkit/repositories/document_repo.py +33 -0
- iatoolkit/repositories/filesystem_asset_repository.py +36 -0
- iatoolkit/repositories/llm_query_repo.py +105 -0
- iatoolkit/repositories/models.py +279 -0
- iatoolkit/repositories/profile_repo.py +171 -0
- iatoolkit/repositories/vs_repo.py +150 -0
- iatoolkit/services/__init__.py +5 -0
- iatoolkit/services/auth_service.py +193 -0
- {services → iatoolkit/services}/benchmark_service.py +7 -7
- iatoolkit/services/branding_service.py +153 -0
- iatoolkit/services/company_context_service.py +214 -0
- iatoolkit/services/configuration_service.py +375 -0
- iatoolkit/services/dispatcher_service.py +134 -0
- {services → iatoolkit/services}/document_service.py +20 -8
- iatoolkit/services/embedding_service.py +148 -0
- iatoolkit/services/excel_service.py +156 -0
- {services → iatoolkit/services}/file_processor_service.py +36 -21
- iatoolkit/services/history_manager_service.py +208 -0
- iatoolkit/services/i18n_service.py +104 -0
- iatoolkit/services/jwt_service.py +80 -0
- iatoolkit/services/language_service.py +89 -0
- iatoolkit/services/license_service.py +82 -0
- iatoolkit/services/llm_client_service.py +438 -0
- iatoolkit/services/load_documents_service.py +174 -0
- iatoolkit/services/mail_service.py +213 -0
- {services → iatoolkit/services}/profile_service.py +200 -101
- iatoolkit/services/prompt_service.py +303 -0
- iatoolkit/services/query_service.py +467 -0
- iatoolkit/services/search_service.py +55 -0
- iatoolkit/services/sql_service.py +169 -0
- iatoolkit/services/tool_service.py +246 -0
- iatoolkit/services/user_feedback_service.py +117 -0
- iatoolkit/services/user_session_context_service.py +213 -0
- iatoolkit/static/images/fernando.jpeg +0 -0
- iatoolkit/static/images/iatoolkit_core.png +0 -0
- iatoolkit/static/images/iatoolkit_logo.png +0 -0
- iatoolkit/static/js/chat_feedback_button.js +80 -0
- iatoolkit/static/js/chat_filepond.js +85 -0
- iatoolkit/static/js/chat_help_content.js +124 -0
- iatoolkit/static/js/chat_history_button.js +110 -0
- iatoolkit/static/js/chat_logout_button.js +36 -0
- iatoolkit/static/js/chat_main.js +401 -0
- iatoolkit/static/js/chat_model_selector.js +227 -0
- iatoolkit/static/js/chat_onboarding_button.js +103 -0
- iatoolkit/static/js/chat_prompt_manager.js +94 -0
- iatoolkit/static/js/chat_reload_button.js +38 -0
- iatoolkit/static/styles/chat_iatoolkit.css +559 -0
- iatoolkit/static/styles/chat_modal.css +133 -0
- iatoolkit/static/styles/chat_public.css +135 -0
- iatoolkit/static/styles/documents.css +598 -0
- iatoolkit/static/styles/landing_page.css +398 -0
- iatoolkit/static/styles/llm_output.css +148 -0
- iatoolkit/static/styles/onboarding.css +176 -0
- iatoolkit/system_prompts/__init__.py +0 -0
- iatoolkit/system_prompts/query_main.prompt +30 -23
- iatoolkit/system_prompts/sql_rules.prompt +47 -12
- iatoolkit/templates/_company_header.html +45 -0
- iatoolkit/templates/_login_widget.html +42 -0
- iatoolkit/templates/base.html +78 -0
- iatoolkit/templates/change_password.html +66 -0
- iatoolkit/templates/chat.html +337 -0
- iatoolkit/templates/chat_modals.html +185 -0
- iatoolkit/templates/error.html +51 -0
- iatoolkit/templates/forgot_password.html +51 -0
- iatoolkit/templates/onboarding_shell.html +106 -0
- iatoolkit/templates/signup.html +79 -0
- iatoolkit/views/__init__.py +5 -0
- iatoolkit/views/base_login_view.py +96 -0
- iatoolkit/views/change_password_view.py +116 -0
- iatoolkit/views/chat_view.py +76 -0
- iatoolkit/views/embedding_api_view.py +65 -0
- iatoolkit/views/forgot_password_view.py +75 -0
- iatoolkit/views/help_content_api_view.py +54 -0
- iatoolkit/views/history_api_view.py +56 -0
- iatoolkit/views/home_view.py +63 -0
- iatoolkit/views/init_context_api_view.py +74 -0
- iatoolkit/views/llmquery_api_view.py +59 -0
- iatoolkit/views/load_company_configuration_api_view.py +49 -0
- iatoolkit/views/load_document_api_view.py +65 -0
- iatoolkit/views/login_view.py +170 -0
- iatoolkit/views/logout_api_view.py +57 -0
- iatoolkit/views/profile_api_view.py +46 -0
- iatoolkit/views/prompt_api_view.py +37 -0
- iatoolkit/views/root_redirect_view.py +22 -0
- iatoolkit/views/signup_view.py +100 -0
- iatoolkit/views/static_page_view.py +27 -0
- iatoolkit/views/user_feedback_api_view.py +60 -0
- iatoolkit/views/users_api_view.py +33 -0
- iatoolkit/views/verify_user_view.py +60 -0
- iatoolkit-0.107.4.dist-info/METADATA +268 -0
- iatoolkit-0.107.4.dist-info/RECORD +132 -0
- iatoolkit-0.107.4.dist-info/licenses/LICENSE +21 -0
- iatoolkit-0.107.4.dist-info/licenses/LICENSE_COMMUNITY.md +15 -0
- {iatoolkit-0.3.9.dist-info → iatoolkit-0.107.4.dist-info}/top_level.txt +0 -1
- iatoolkit/iatoolkit.py +0 -413
- iatoolkit/system_prompts/arquitectura.prompt +0 -32
- iatoolkit-0.3.9.dist-info/METADATA +0 -252
- iatoolkit-0.3.9.dist-info/RECORD +0 -32
- services/__init__.py +0 -5
- services/api_service.py +0 -75
- services/dispatcher_service.py +0 -351
- services/excel_service.py +0 -98
- services/history_service.py +0 -45
- services/jwt_service.py +0 -91
- services/load_documents_service.py +0 -212
- services/mail_service.py +0 -62
- services/prompt_manager_service.py +0 -172
- services/query_service.py +0 -334
- services/search_service.py +0 -32
- services/sql_service.py +0 -42
- services/tasks_service.py +0 -188
- services/user_feedback_service.py +0 -67
- services/user_session_context_service.py +0 -85
- {iatoolkit-0.3.9.dist-info → iatoolkit-0.107.4.dist-info}/WHEEL +0 -0
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# iatoolkit/views/profile_api_view.py
|
|
2
|
+
from flask import request, jsonify
|
|
3
|
+
from flask.views import MethodView
|
|
4
|
+
from injector import inject
|
|
5
|
+
from iatoolkit.services.auth_service import AuthService
|
|
6
|
+
from iatoolkit.services.profile_service import ProfileService
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class UserLanguageApiView(MethodView):
|
|
10
|
+
"""
|
|
11
|
+
API endpoint for managing user language preferences.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
@inject
|
|
15
|
+
def __init__(self,
|
|
16
|
+
auth_service: AuthService,
|
|
17
|
+
profile_service: ProfileService):
|
|
18
|
+
self.auth_service = auth_service
|
|
19
|
+
self.profile_service = profile_service
|
|
20
|
+
|
|
21
|
+
def post(self):
|
|
22
|
+
"""
|
|
23
|
+
Handles POST requests to update the user's preferred language.
|
|
24
|
+
Expects a JSON body with a 'language' key, e.g., {"language": "en"}.
|
|
25
|
+
"""
|
|
26
|
+
# 1. Authenticate the user from the current session.
|
|
27
|
+
auth_result = self.auth_service.verify()
|
|
28
|
+
if not auth_result.get("success"):
|
|
29
|
+
return jsonify(auth_result), auth_result.get("status_code")
|
|
30
|
+
|
|
31
|
+
user_identifier = auth_result.get('user_identifier')
|
|
32
|
+
|
|
33
|
+
# 2. Validate request body
|
|
34
|
+
data = request.get_json()
|
|
35
|
+
if not data or 'language' not in data:
|
|
36
|
+
return jsonify({"error_message": "Missing 'language' field in request body"}), 400
|
|
37
|
+
|
|
38
|
+
new_lang = data.get('language')
|
|
39
|
+
|
|
40
|
+
# 3. Call the service to perform the update
|
|
41
|
+
update_result = self.profile_service.update_user_language(user_identifier, new_lang)
|
|
42
|
+
|
|
43
|
+
if not update_result.get('success'):
|
|
44
|
+
return jsonify(update_result), 400
|
|
45
|
+
|
|
46
|
+
return jsonify({"message": "Language preference updated successfully"}), 200
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Copyright (c) 2024 Fernando Libedinsky
|
|
2
|
+
# Product: IAToolkit
|
|
3
|
+
#
|
|
4
|
+
# IAToolkit is open source software.
|
|
5
|
+
|
|
6
|
+
from flask import jsonify
|
|
7
|
+
from flask.views import MethodView
|
|
8
|
+
from iatoolkit.services.prompt_service import PromptService
|
|
9
|
+
from iatoolkit.services.auth_service import AuthService
|
|
10
|
+
from injector import inject
|
|
11
|
+
import logging
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class PromptApiView(MethodView):
|
|
15
|
+
@inject
|
|
16
|
+
def __init__(self,
|
|
17
|
+
auth_service: AuthService,
|
|
18
|
+
prompt_service: PromptService ):
|
|
19
|
+
self.auth_service = auth_service
|
|
20
|
+
self.prompt_service = prompt_service
|
|
21
|
+
|
|
22
|
+
def get(self, company_short_name):
|
|
23
|
+
try:
|
|
24
|
+
# get access credentials
|
|
25
|
+
auth_result = self.auth_service.verify(anonymous=True)
|
|
26
|
+
if not auth_result.get("success"):
|
|
27
|
+
return jsonify(auth_result), auth_result.get('status_code')
|
|
28
|
+
|
|
29
|
+
response = self.prompt_service.get_user_prompts(company_short_name)
|
|
30
|
+
if "error" in response:
|
|
31
|
+
return {'error_message': response["error"]}, 402
|
|
32
|
+
|
|
33
|
+
return response, 200
|
|
34
|
+
except Exception as e:
|
|
35
|
+
logging.exception(
|
|
36
|
+
f"unexpected error getting company prompts: {e}")
|
|
37
|
+
return jsonify({"error_message": str(e)}), 500
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
from flask import redirect, url_for
|
|
2
|
+
from flask.views import MethodView
|
|
3
|
+
from iatoolkit.company_registry import get_company_registry
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class RootRedirectView(MethodView):
|
|
7
|
+
"""
|
|
8
|
+
Vista que redirige la raíz '/' al home de la primera compañía disponible.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
def get(self):
|
|
12
|
+
registry = get_company_registry()
|
|
13
|
+
companies = registry.get_all_company_instances()
|
|
14
|
+
|
|
15
|
+
if companies:
|
|
16
|
+
# Obtener el short_name de la primera compañía registrada.
|
|
17
|
+
# En Python 3.7+, los diccionarios mantienen el orden de inserción.
|
|
18
|
+
first_company_short_name = next(iter(companies))
|
|
19
|
+
return redirect(url_for('home', company_short_name=first_company_short_name))
|
|
20
|
+
|
|
21
|
+
# Fallback: Si no hay compañías, ir al index genérico (o a un 404)
|
|
22
|
+
return redirect(url_for('index'))
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# Copyright (c) 2024 Fernando Libedinsky
|
|
2
|
+
# Product: IAToolkit
|
|
3
|
+
#
|
|
4
|
+
# IAToolkit is open source software.
|
|
5
|
+
|
|
6
|
+
from flask.views import MethodView
|
|
7
|
+
from flask import render_template, request, url_for, redirect, flash
|
|
8
|
+
from iatoolkit.services.profile_service import ProfileService
|
|
9
|
+
from iatoolkit.services.branding_service import BrandingService
|
|
10
|
+
from iatoolkit.services.i18n_service import I18nService
|
|
11
|
+
from injector import inject
|
|
12
|
+
from itsdangerous import URLSafeTimedSerializer
|
|
13
|
+
import os
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class SignupView(MethodView):
|
|
17
|
+
@inject
|
|
18
|
+
def __init__(self, profile_service: ProfileService,
|
|
19
|
+
branding_service: BrandingService,
|
|
20
|
+
i18n_service: I18nService):
|
|
21
|
+
self.profile_service = profile_service
|
|
22
|
+
self.branding_service = branding_service # 3. Guardar la instancia
|
|
23
|
+
self.i18n_service = i18n_service
|
|
24
|
+
|
|
25
|
+
self.serializer = URLSafeTimedSerializer(os.getenv("IATOOLKIT_SECRET_KEY"))
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def get(self, company_short_name: str):
|
|
29
|
+
# get company info
|
|
30
|
+
company = self.profile_service.get_company_by_short_name(company_short_name)
|
|
31
|
+
if not company:
|
|
32
|
+
return render_template('error.html',
|
|
33
|
+
message=self.i18n_service.t('errors.templates.company_not_found')), 404
|
|
34
|
+
|
|
35
|
+
branding_data = self.branding_service.get_company_branding(company_short_name)
|
|
36
|
+
current_lang = request.args.get("lang") or "en"
|
|
37
|
+
|
|
38
|
+
return render_template('signup.html',
|
|
39
|
+
company_short_name=company_short_name,
|
|
40
|
+
branding=branding_data,
|
|
41
|
+
lang=current_lang)
|
|
42
|
+
|
|
43
|
+
def post(self, company_short_name: str):
|
|
44
|
+
try:
|
|
45
|
+
company = self.profile_service.get_company_by_short_name(company_short_name)
|
|
46
|
+
if not company:
|
|
47
|
+
return render_template('error.html',
|
|
48
|
+
message=self.i18n_service.t('errors.templates.company_not_found')), 404
|
|
49
|
+
|
|
50
|
+
branding_data = self.branding_service.get_company_branding(company_short_name)
|
|
51
|
+
|
|
52
|
+
first_name = request.form.get('first_name')
|
|
53
|
+
last_name = request.form.get('last_name')
|
|
54
|
+
email = request.form.get('email')
|
|
55
|
+
password = request.form.get('password')
|
|
56
|
+
confirm_password = request.form.get('confirm_password')
|
|
57
|
+
|
|
58
|
+
# get the language from the form, then query
|
|
59
|
+
current_lang = request.form.get("lang") or request.args.get("lang")
|
|
60
|
+
|
|
61
|
+
# create verification token and url for verification
|
|
62
|
+
token = self.serializer.dumps(email, salt='email-confirm')
|
|
63
|
+
verification_url = url_for('verify_account',
|
|
64
|
+
company_short_name=company_short_name,
|
|
65
|
+
token=token, _external=True)
|
|
66
|
+
|
|
67
|
+
response = self.profile_service.signup(
|
|
68
|
+
company_short_name=company_short_name,
|
|
69
|
+
email=email,
|
|
70
|
+
first_name=first_name, last_name=last_name,
|
|
71
|
+
password=password, confirm_password=confirm_password,
|
|
72
|
+
verification_url=verification_url)
|
|
73
|
+
|
|
74
|
+
if "error" in response:
|
|
75
|
+
flash(response["error"], 'error')
|
|
76
|
+
return render_template(
|
|
77
|
+
'signup.html',
|
|
78
|
+
company_short_name=company_short_name,
|
|
79
|
+
branding=branding_data,
|
|
80
|
+
lang=current_lang,
|
|
81
|
+
form_data={
|
|
82
|
+
"first_name": first_name,
|
|
83
|
+
"last_name": last_name,
|
|
84
|
+
"email": email,
|
|
85
|
+
"password": password,
|
|
86
|
+
"confirm_password": confirm_password
|
|
87
|
+
}), 400
|
|
88
|
+
|
|
89
|
+
flash(response["message"], 'success')
|
|
90
|
+
return redirect(url_for('home', company_short_name=company_short_name, lang=current_lang))
|
|
91
|
+
|
|
92
|
+
except Exception as e:
|
|
93
|
+
message = self.i18n_service.t('errors.templates.processing_error', error=str(e))
|
|
94
|
+
return render_template(
|
|
95
|
+
"error.html",
|
|
96
|
+
company_short_name=company_short_name,
|
|
97
|
+
branding=branding_data,
|
|
98
|
+
message=message,
|
|
99
|
+
lang=current_lang
|
|
100
|
+
), 500
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
from flask import render_template
|
|
2
|
+
from flask.views import MethodView
|
|
3
|
+
from injector import inject
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class StaticPageView(MethodView):
|
|
7
|
+
"""
|
|
8
|
+
View genérica para servir páginas estáticas simples (sin lógica de negocio compleja).
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
@inject
|
|
12
|
+
def __init__(self):
|
|
13
|
+
pass
|
|
14
|
+
|
|
15
|
+
def get(self, page_name: str):
|
|
16
|
+
# Mapeo seguro de nombres de página a plantillas
|
|
17
|
+
# Esto evita que se intente cargar cualquier archivo arbitrario
|
|
18
|
+
valid_pages = {
|
|
19
|
+
'foundation': 'docs/foundation.html',
|
|
20
|
+
'mini_project': 'docs/mini_project.html'
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if page_name not in valid_pages:
|
|
24
|
+
# Si la página no existe, podríamos retornar un 404 o redirigir al index
|
|
25
|
+
return render_template('error.html', message=f"Página no encontrada: {page_name}"), 404
|
|
26
|
+
|
|
27
|
+
return render_template(valid_pages[page_name])
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# Copyright (c) 2024 Fernando Libedinsky
|
|
2
|
+
# Product: IAToolkit
|
|
3
|
+
#
|
|
4
|
+
# IAToolkit is open source software.
|
|
5
|
+
|
|
6
|
+
from flask import request, jsonify
|
|
7
|
+
from flask.views import MethodView
|
|
8
|
+
from iatoolkit.services.user_feedback_service import UserFeedbackService
|
|
9
|
+
from iatoolkit.services.auth_service import AuthService
|
|
10
|
+
from injector import inject
|
|
11
|
+
import logging
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class UserFeedbackApiView(MethodView):
|
|
15
|
+
@inject
|
|
16
|
+
def __init__(self,
|
|
17
|
+
auth_service: AuthService,
|
|
18
|
+
user_feedback_service: UserFeedbackService ):
|
|
19
|
+
self.auth_service = auth_service
|
|
20
|
+
self.user_feedback_service = user_feedback_service
|
|
21
|
+
|
|
22
|
+
def post(self, company_short_name):
|
|
23
|
+
try:
|
|
24
|
+
# get access credentials
|
|
25
|
+
auth_result = self.auth_service.verify()
|
|
26
|
+
if not auth_result.get("success"):
|
|
27
|
+
return jsonify(auth_result), auth_result.get("status_code")
|
|
28
|
+
|
|
29
|
+
user_identifier = auth_result.get('user_identifier')
|
|
30
|
+
|
|
31
|
+
data = request.get_json()
|
|
32
|
+
if not data:
|
|
33
|
+
return jsonify({"error_message": "invalid json body"}), 402
|
|
34
|
+
|
|
35
|
+
# these validations are performed also in the frontend
|
|
36
|
+
# the are localized in the front
|
|
37
|
+
message = data.get("message")
|
|
38
|
+
if not message:
|
|
39
|
+
return jsonify({"error_message": "missing feedback message"}), 400
|
|
40
|
+
|
|
41
|
+
rating = data.get("rating")
|
|
42
|
+
if not rating:
|
|
43
|
+
return jsonify({"error_message": "missing rating"}), 400
|
|
44
|
+
|
|
45
|
+
response = self.user_feedback_service.new_feedback(
|
|
46
|
+
company_short_name=company_short_name,
|
|
47
|
+
message=message,
|
|
48
|
+
user_identifier=user_identifier,
|
|
49
|
+
rating=rating
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
if "error" in response:
|
|
53
|
+
return {'error_message': response["error"]}, 402
|
|
54
|
+
|
|
55
|
+
return response, 200
|
|
56
|
+
except Exception as e:
|
|
57
|
+
logging.exception(
|
|
58
|
+
f"unexpected error processing feedback for {company_short_name}: {e}")
|
|
59
|
+
return jsonify({"error_message": str(e)}), 500
|
|
60
|
+
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
from flask.views import MethodView
|
|
2
|
+
from flask import jsonify
|
|
3
|
+
from injector import inject
|
|
4
|
+
from iatoolkit.services.auth_service import AuthService
|
|
5
|
+
from iatoolkit.services.profile_service import ProfileService
|
|
6
|
+
import logging
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class UsersApiView(MethodView):
|
|
10
|
+
"""
|
|
11
|
+
list company users and their roles
|
|
12
|
+
"""
|
|
13
|
+
@inject
|
|
14
|
+
def __init__(self,
|
|
15
|
+
auth_service: AuthService,
|
|
16
|
+
profile_service: ProfileService):
|
|
17
|
+
self.auth_service = auth_service
|
|
18
|
+
self.profile_service = profile_service
|
|
19
|
+
|
|
20
|
+
def get(self, company_short_name: str):
|
|
21
|
+
try:
|
|
22
|
+
auth_result = self.auth_service.verify(anonymous=True)
|
|
23
|
+
if not auth_result.get("success"):
|
|
24
|
+
return jsonify(auth_result), auth_result.get("status_code", 401)
|
|
25
|
+
|
|
26
|
+
# get users of the company
|
|
27
|
+
users = self.profile_service.get_company_users(company_short_name)
|
|
28
|
+
|
|
29
|
+
return jsonify(users), 200
|
|
30
|
+
|
|
31
|
+
except Exception as e:
|
|
32
|
+
logging.exception(f"Error fetching users for {company_short_name}: {e}")
|
|
33
|
+
return jsonify({"error": "Unexpected error", "details": str(e)}), 500
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# Copyright (c) 2024 Fernando Libedinsky
|
|
2
|
+
# Product: IAToolkit
|
|
3
|
+
#
|
|
4
|
+
# IAToolkit is open source software.
|
|
5
|
+
|
|
6
|
+
from flask.views import MethodView
|
|
7
|
+
from flask import render_template, url_for, redirect, session, flash
|
|
8
|
+
from iatoolkit.services.profile_service import ProfileService
|
|
9
|
+
from itsdangerous import URLSafeTimedSerializer, SignatureExpired
|
|
10
|
+
from iatoolkit.services.branding_service import BrandingService
|
|
11
|
+
from iatoolkit.services.i18n_service import I18nService
|
|
12
|
+
from injector import inject
|
|
13
|
+
import os
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class VerifyAccountView(MethodView):
|
|
17
|
+
@inject
|
|
18
|
+
def __init__(self,
|
|
19
|
+
profile_service: ProfileService,
|
|
20
|
+
branding_service: BrandingService,
|
|
21
|
+
i18n_service: I18nService):
|
|
22
|
+
self.profile_service = profile_service
|
|
23
|
+
self.branding_service = branding_service
|
|
24
|
+
self.i18n_service = i18n_service
|
|
25
|
+
self.serializer = URLSafeTimedSerializer(os.getenv("IATOOLKIT_SECRET_KEY"))
|
|
26
|
+
|
|
27
|
+
def get(self, company_short_name: str, token: str):
|
|
28
|
+
try:
|
|
29
|
+
# get company info
|
|
30
|
+
company = self.profile_service.get_company_by_short_name(company_short_name)
|
|
31
|
+
if not company:
|
|
32
|
+
return render_template('error.html',
|
|
33
|
+
message=self.i18n_service.t('errors.templates.company_not_found')), 404
|
|
34
|
+
|
|
35
|
+
branding_data = self.branding_service.get_company_branding(company_short_name)
|
|
36
|
+
try:
|
|
37
|
+
# decode the token from the URL
|
|
38
|
+
email = self.serializer.loads(token, salt='email-confirm', max_age=3600*5)
|
|
39
|
+
except SignatureExpired:
|
|
40
|
+
flash(self.i18n_service.t('errors.verification.token_expired'), 'error')
|
|
41
|
+
return render_template('signup.html',
|
|
42
|
+
company_short_name=company_short_name,
|
|
43
|
+
branding=branding_data,
|
|
44
|
+
token=token), 400
|
|
45
|
+
|
|
46
|
+
response = self.profile_service.verify_account(email)
|
|
47
|
+
if "error" in response:
|
|
48
|
+
flash(response["error"], 'error')
|
|
49
|
+
return render_template(
|
|
50
|
+
'signup.html',
|
|
51
|
+
company_short_name=company_short_name,
|
|
52
|
+
branding=branding_data,
|
|
53
|
+
token=token), 400
|
|
54
|
+
|
|
55
|
+
flash(response['message'], 'success')
|
|
56
|
+
return redirect(url_for('home', company_short_name=company_short_name))
|
|
57
|
+
|
|
58
|
+
except Exception as e:
|
|
59
|
+
flash(self.i18n_service.t('errors.general.unexpected_error', error=str(e)), 'error')
|
|
60
|
+
return redirect(url_for('home', company_short_name=company_short_name))
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: iatoolkit
|
|
3
|
+
Version: 0.107.4
|
|
4
|
+
Summary: IAToolkit
|
|
5
|
+
Author: Fernando Libedinsky
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Requires-Python: >=3.12
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
License-File: LICENSE_COMMUNITY.md
|
|
11
|
+
Requires-Dist: bcrypt==4.2.1
|
|
12
|
+
Requires-Dist: boto3==1.36.22
|
|
13
|
+
Requires-Dist: botocore==1.36.22
|
|
14
|
+
Requires-Dist: build==1.2.2.post1
|
|
15
|
+
Requires-Dist: click==8.1.8
|
|
16
|
+
Requires-Dist: cryptography==44.0.3
|
|
17
|
+
Requires-Dist: Flask==3.1.0
|
|
18
|
+
Requires-Dist: Flask-Bcrypt==1.0.1
|
|
19
|
+
Requires-Dist: flask-cors==6.0.0
|
|
20
|
+
Requires-Dist: Flask-Injector==0.15.0
|
|
21
|
+
Requires-Dist: Flask-Session==0.8.0
|
|
22
|
+
Requires-Dist: flatbuffers==24.3.25
|
|
23
|
+
Requires-Dist: google-ai-generativelanguage==0.6.15
|
|
24
|
+
Requires-Dist: google-api-core==2.24.1
|
|
25
|
+
Requires-Dist: google-api-python-client==2.161.0
|
|
26
|
+
Requires-Dist: google-auth==2.37.0
|
|
27
|
+
Requires-Dist: google-auth-httplib2==0.2.0
|
|
28
|
+
Requires-Dist: google-auth-oauthlib==1.2.1
|
|
29
|
+
Requires-Dist: google-cloud-core==2.4.1
|
|
30
|
+
Requires-Dist: google-cloud-storage==3.0.0
|
|
31
|
+
Requires-Dist: google-crc32c==1.6.0
|
|
32
|
+
Requires-Dist: google-generativeai==0.8.5
|
|
33
|
+
Requires-Dist: google-resumable-media==2.7.2
|
|
34
|
+
Requires-Dist: googleapis-common-protos==1.66.0
|
|
35
|
+
Requires-Dist: gunicorn==23.0.0
|
|
36
|
+
Requires-Dist: h11==0.14.0
|
|
37
|
+
Requires-Dist: httpcore==1.0.7
|
|
38
|
+
Requires-Dist: httplib2==0.22.0
|
|
39
|
+
Requires-Dist: httptools==0.6.4
|
|
40
|
+
Requires-Dist: httpx==0.28.0
|
|
41
|
+
Requires-Dist: httpx-sse==0.4.0
|
|
42
|
+
Requires-Dist: huggingface-hub==0.31.4
|
|
43
|
+
Requires-Dist: humanfriendly==10.0
|
|
44
|
+
Requires-Dist: idna==3.10
|
|
45
|
+
Requires-Dist: injector==0.22.0
|
|
46
|
+
Requires-Dist: Jinja2==3.1.5
|
|
47
|
+
Requires-Dist: langchain==0.3.19
|
|
48
|
+
Requires-Dist: langchain-core==0.3.35
|
|
49
|
+
Requires-Dist: langchain-text-splitters==0.3.6
|
|
50
|
+
Requires-Dist: markdown2==2.5.3
|
|
51
|
+
Requires-Dist: openai==2.8.1
|
|
52
|
+
Requires-Dist: openpyxl==3.1.5
|
|
53
|
+
Requires-Dist: pandas==2.3.1
|
|
54
|
+
Requires-Dist: pgvector==0.3.6
|
|
55
|
+
Requires-Dist: pillow==11.0.0
|
|
56
|
+
Requires-Dist: psutil==7.0.0
|
|
57
|
+
Requires-Dist: psycopg2-binary==2.9.10
|
|
58
|
+
Requires-Dist: PyJWT==2.10.1
|
|
59
|
+
Requires-Dist: PyMuPDF==1.25.0
|
|
60
|
+
Requires-Dist: python-dotenv==1.0.1
|
|
61
|
+
Requires-Dist: pytest==8.3.4
|
|
62
|
+
Requires-Dist: pytest-cov==5.0.0
|
|
63
|
+
Requires-Dist: pytest-mock==3.14.0
|
|
64
|
+
Requires-Dist: python-dateutil==2.9.0.post0
|
|
65
|
+
Requires-Dist: python-docx==1.1.2
|
|
66
|
+
Requires-Dist: pytesseract==0.3.13
|
|
67
|
+
Requires-Dist: pytz==2025.2
|
|
68
|
+
Requires-Dist: PyYAML==6.0.2
|
|
69
|
+
Requires-Dist: redis==5.2.1
|
|
70
|
+
Requires-Dist: regex==2024.11.6
|
|
71
|
+
Requires-Dist: requests==2.32.3
|
|
72
|
+
Requires-Dist: requests-oauthlib==2.0.0
|
|
73
|
+
Requires-Dist: requests-toolbelt==1.0.0
|
|
74
|
+
Requires-Dist: s3transfer==0.11.2
|
|
75
|
+
Requires-Dist: sib-api-v3-sdk==7.6.0
|
|
76
|
+
Requires-Dist: SQLAlchemy==2.0.36
|
|
77
|
+
Requires-Dist: tiktoken==0.8.0
|
|
78
|
+
Requires-Dist: tokenizers==0.21.0
|
|
79
|
+
Requires-Dist: websocket-client==1.8.0
|
|
80
|
+
Requires-Dist: websockets==14.1
|
|
81
|
+
Requires-Dist: Werkzeug==3.1.3
|
|
82
|
+
Requires-Dist: pyjwt[crypto]>=2.8.0
|
|
83
|
+
Dynamic: license-file
|
|
84
|
+
|
|
85
|
+
# 🧠 IAToolkit — Open-Source Framework for Real-World AI Assistants
|
|
86
|
+
|
|
87
|
+
Build private, production-grade AI assistants that run entirely inside your environment and speak the language of your business.
|
|
88
|
+
|
|
89
|
+
IAToolkit is not a demo wrapper or a prompt playground — it is a **full architecture** for implementing intelligent systems that combine LLMs, SQL data, internal documents, tools, workflows, and multi-tenant business logic.
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
## 🚀 Why IAToolkit?
|
|
94
|
+
|
|
95
|
+
Modern AI development is fragmented: LangChain handles chains, LlamaIndex handles documents,
|
|
96
|
+
your backend handles SQL, your frontend handles chats, and your devs glue everything together.
|
|
97
|
+
|
|
98
|
+
**IAToolkit brings all of this into one unified, production-ready framework.**
|
|
99
|
+
|
|
100
|
+
It focuses on:
|
|
101
|
+
|
|
102
|
+
- **real-world data** (SQL + documents)
|
|
103
|
+
- **real workflows** (LLM tools + python services)
|
|
104
|
+
- **real multi-tenant architecture** (1 company → many companies)
|
|
105
|
+
- **real constraints** (security, reproducibility, governance)
|
|
106
|
+
- **real deployment** (your servers, your infrastructure)
|
|
107
|
+
|
|
108
|
+
IAToolkit lets you build the assistant that *your* organization needs — not a generic chatbot.
|
|
109
|
+
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
## 🧩 Architecture in a Nutshell
|
|
113
|
+
|
|
114
|
+
IAToolkit is a structured, layered framework:
|
|
115
|
+
|
|
116
|
+
Interfaces (Web & API)
|
|
117
|
+
↓
|
|
118
|
+
Intelligence Layer (prompts, tools, SQL orchestration, RAG)
|
|
119
|
+
↓
|
|
120
|
+
Execution Layer (services, workflows, validation)
|
|
121
|
+
↓
|
|
122
|
+
Data Access (SQLAlchemy, connectors)
|
|
123
|
+
↓
|
|
124
|
+
Company Modules (company.yaml + custom tools)
|
|
125
|
+
|
|
126
|
+
### ✔ Interfaces
|
|
127
|
+
Chat UI, REST API, auth, sessions, JSON/HTML responses.
|
|
128
|
+
|
|
129
|
+
### ✔ Intelligence Layer
|
|
130
|
+
Core logic: prompt rendering, SQL orchestration, RAG, LLM tool dispatching.
|
|
131
|
+
|
|
132
|
+
### ✔ Execution Layer
|
|
133
|
+
Python services that implement real workflows: querying data, generating reports, retrieving documents, executing business logic.
|
|
134
|
+
|
|
135
|
+
### ✔ Data Access
|
|
136
|
+
A clean repository pattern using SQLAlchemy.
|
|
137
|
+
|
|
138
|
+
### ✔ Company Modules
|
|
139
|
+
Each company has:
|
|
140
|
+
|
|
141
|
+
- its own `company.yaml`
|
|
142
|
+
- its own prompts
|
|
143
|
+
- its own tools
|
|
144
|
+
- its own services
|
|
145
|
+
- its own vector store & SQL context
|
|
146
|
+
|
|
147
|
+
This modularity allows **true multi-tenancy**.
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
## 🔌 Connect to Anything
|
|
152
|
+
|
|
153
|
+
IAToolkit integrates naturally with:
|
|
154
|
+
|
|
155
|
+
- **SQL databases** (PostgreSQL, MySQL, SQL Server, etc.)
|
|
156
|
+
- **Document retrieval** (PDF, text, embeddings)
|
|
157
|
+
- **External APIs**
|
|
158
|
+
- **Internal microservices**
|
|
159
|
+
- **Custom Python tools**
|
|
160
|
+
|
|
161
|
+
It also includes a **production-grade RAG pipeline**, combining:
|
|
162
|
+
|
|
163
|
+
- embeddings
|
|
164
|
+
- chunking
|
|
165
|
+
- hybrid search
|
|
166
|
+
- SQL queries + document retrieval
|
|
167
|
+
- tool execution
|
|
168
|
+
|
|
169
|
+
Everything orchestrated through the Intelligence Layer.
|
|
170
|
+
|
|
171
|
+
---
|
|
172
|
+
|
|
173
|
+
## 🏢 Multi-Tenant Architecture
|
|
174
|
+
|
|
175
|
+
A single installation of IAToolkit can power assistants for multiple companies, departments, or customers.
|
|
176
|
+
```text
|
|
177
|
+
companies/
|
|
178
|
+
company_a
|
|
179
|
+
company_b
|
|
180
|
+
company_c
|
|
181
|
+
```
|
|
182
|
+
Each Company is fully isolated:
|
|
183
|
+
|
|
184
|
+
- prompts
|
|
185
|
+
- tools
|
|
186
|
+
- credentials
|
|
187
|
+
- documents
|
|
188
|
+
- SQL contexts
|
|
189
|
+
- business rules
|
|
190
|
+
|
|
191
|
+
This makes IAToolkit ideal for SaaS products, agencies, consultancies, and organizations with multiple business units.
|
|
192
|
+
|
|
193
|
+
---
|
|
194
|
+
|
|
195
|
+
## 🆓 Community Edition vs Enterprise Edition
|
|
196
|
+
|
|
197
|
+
IAToolkit follows a modern **open-core** model:
|
|
198
|
+
|
|
199
|
+
### 🟦 Community Edition (MIT License)
|
|
200
|
+
- Full Open-Source Core
|
|
201
|
+
- SQL + Basic RAG
|
|
202
|
+
- One Company
|
|
203
|
+
- Custom Python tools
|
|
204
|
+
- Self-managed deployment
|
|
205
|
+
|
|
206
|
+
Perfect for developers, small teams, single-business use cases, and experimentation.
|
|
207
|
+
|
|
208
|
+
### 🟥 Enterprise Edition (Commercial License)
|
|
209
|
+
- Unlimited Companies (multi-tenant)
|
|
210
|
+
- Payment services integration
|
|
211
|
+
- Enterprise Agent Workflows
|
|
212
|
+
- SSO integration
|
|
213
|
+
- Priority support & continuous updates
|
|
214
|
+
- Activation via **License Key**
|
|
215
|
+
|
|
216
|
+
👉 Licensing information:
|
|
217
|
+
- [Community Edition (MIT)](LICENSE_COMMUNITY.md)
|
|
218
|
+
- [Enterprise License](ENTERPRISE_LICENSE.md)
|
|
219
|
+
|
|
220
|
+
---
|
|
221
|
+
|
|
222
|
+
## 🧩 Who Is IAToolkit For?
|
|
223
|
+
|
|
224
|
+
- Companies building internal “ChatGPT for the business”
|
|
225
|
+
- SaaS products adding AI assistants for multiple customers
|
|
226
|
+
- AI teams that need reproducible prompts and controlled tools
|
|
227
|
+
- Developers who want real workflows, not toy demos
|
|
228
|
+
- Organizations requiring privacy, security, and self-hosting
|
|
229
|
+
- Teams working with SQL-heavy business logic
|
|
230
|
+
- Consultancies deploying AI for multiple clients
|
|
231
|
+
|
|
232
|
+
---
|
|
233
|
+
|
|
234
|
+
## ⭐ Key Differentiators
|
|
235
|
+
|
|
236
|
+
- prioritizes **architecture-first design**, not chains or wrappers
|
|
237
|
+
- supports **multi-company** out of the box
|
|
238
|
+
- integrates **SQL, RAG, and tools** into a single intelligence layer
|
|
239
|
+
- keeps **business logic isolated** inside Company modules
|
|
240
|
+
- runs entirely **on your own infrastructure**
|
|
241
|
+
- ships with a **full web chat**, and API.
|
|
242
|
+
- is built for **production**, not prototypes
|
|
243
|
+
|
|
244
|
+
---
|
|
245
|
+
|
|
246
|
+
## 📚 Documentation
|
|
247
|
+
|
|
248
|
+
- 🚀 **[Quickstart](docs/quickstart.md)** – Set up your environment and run the project
|
|
249
|
+
- ☁️ **[Deployment Guide](docs/deployment_guide.md)** – Production deployment instructions
|
|
250
|
+
- 🏗️ **[Companies & Components](docs/companies_and_components.md)** – how Company modules work
|
|
251
|
+
- 🧠 **[Programming Guide](docs/programming_guide.md)** – services, intelligence layer, dispatching
|
|
252
|
+
- 🗃️ **[Database Guide](docs/database_guide.md)** – internal schema overview
|
|
253
|
+
- 🌱 **[Foundation Article](https://iatoolkit.com/pages/foundation)** – the “Why” behind the architecture
|
|
254
|
+
- 📘 **[Mini-Project (3 months)](https://iatoolkit.com/pages/mini_project)** – how to deploy a corporate AI assistant
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
---
|
|
258
|
+
|
|
259
|
+
## 🤝 Contributing
|
|
260
|
+
|
|
261
|
+
IAToolkit is open-source and community-friendly.
|
|
262
|
+
PRs, issues, ideas, and feedback are always welcome.
|
|
263
|
+
|
|
264
|
+
---
|
|
265
|
+
|
|
266
|
+
## ⭐ Support the Project
|
|
267
|
+
|
|
268
|
+
If you find IAToolkit useful, please **star the GitHub repo** — it helps visibility and adoption.
|