iatoolkit 0.7.5__py3-none-any.whl → 0.7.6__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.

Files changed (49) hide show
  1. {iatoolkit-0.7.5.dist-info → iatoolkit-0.7.6.dist-info}/METADATA +1 -1
  2. iatoolkit-0.7.6.dist-info/RECORD +80 -0
  3. {iatoolkit-0.7.5.dist-info → iatoolkit-0.7.6.dist-info}/top_level.txt +3 -0
  4. infra/__init__.py +5 -0
  5. infra/call_service.py +140 -0
  6. infra/connectors/__init__.py +5 -0
  7. infra/connectors/file_connector.py +17 -0
  8. infra/connectors/file_connector_factory.py +57 -0
  9. infra/connectors/google_cloud_storage_connector.py +53 -0
  10. infra/connectors/google_drive_connector.py +68 -0
  11. infra/connectors/local_file_connector.py +46 -0
  12. infra/connectors/s3_connector.py +33 -0
  13. infra/gemini_adapter.py +356 -0
  14. infra/google_chat_app.py +57 -0
  15. infra/llm_client.py +430 -0
  16. infra/llm_proxy.py +139 -0
  17. infra/llm_response.py +40 -0
  18. infra/mail_app.py +145 -0
  19. infra/openai_adapter.py +90 -0
  20. infra/redis_session_manager.py +76 -0
  21. repositories/__init__.py +5 -0
  22. repositories/database_manager.py +95 -0
  23. repositories/document_repo.py +33 -0
  24. repositories/llm_query_repo.py +91 -0
  25. repositories/models.py +309 -0
  26. repositories/profile_repo.py +118 -0
  27. repositories/tasks_repo.py +52 -0
  28. repositories/vs_repo.py +139 -0
  29. views/__init__.py +5 -0
  30. views/change_password_view.py +91 -0
  31. views/chat_token_request_view.py +98 -0
  32. views/chat_view.py +51 -0
  33. views/download_file_view.py +58 -0
  34. views/external_chat_login_view.py +88 -0
  35. views/external_login_view.py +40 -0
  36. views/file_store_view.py +58 -0
  37. views/forgot_password_view.py +64 -0
  38. views/history_view.py +57 -0
  39. views/home_view.py +34 -0
  40. views/llmquery_view.py +65 -0
  41. views/login_view.py +60 -0
  42. views/prompt_view.py +37 -0
  43. views/signup_view.py +87 -0
  44. views/tasks_review_view.py +83 -0
  45. views/tasks_view.py +98 -0
  46. views/user_feedback_view.py +74 -0
  47. views/verify_user_view.py +55 -0
  48. iatoolkit-0.7.5.dist-info/RECORD +0 -36
  49. {iatoolkit-0.7.5.dist-info → iatoolkit-0.7.6.dist-info}/WHEEL +0 -0
views/llmquery_view.py ADDED
@@ -0,0 +1,65 @@
1
+ # Copyright (c) 2024 Fernando Libedinsky
2
+ # Product: IAToolkit
3
+ #
4
+ # IAToolkit is open source software.
5
+
6
+ from flask import request, jsonify, render_template
7
+ from flask.views import MethodView
8
+ from services.query_service import QueryService
9
+ from common.auth import IAuthentication
10
+ from injector import inject
11
+ import logging
12
+
13
+
14
+ class LLMQueryView(MethodView):
15
+ @inject
16
+ def __init__(self,
17
+ iauthentication: IAuthentication,
18
+ query_service: QueryService,
19
+ ):
20
+ self.iauthentication = iauthentication
21
+ self.query_service = query_service
22
+
23
+ def post(self, company_short_name):
24
+ data = request.get_json()
25
+ if not data:
26
+ return jsonify({"error_message": "Cuerpo de la solicitud JSON inválido o faltante"}), 400
27
+
28
+ # get access credentials
29
+ iaut = self.iauthentication.verify(company_short_name, data.get("external_user_id"))
30
+ if not iaut.get("success"):
31
+ return jsonify(iaut), 401
32
+
33
+ company_id = iaut.get("company_id")
34
+ external_user_id = iaut.get("external_user_id")
35
+ local_user_id = iaut.get("local_user_id")
36
+
37
+ # now check the form
38
+ question = data.get("question")
39
+ files = data.get("files", [])
40
+ client_data = data.get("client_data", {})
41
+ prompt_name = data.get("prompt_name")
42
+ if not question and not prompt_name:
43
+ return jsonify({"error_message": "Falta la consulta o el prompt_name"}), 400
44
+
45
+ try:
46
+ response = self.query_service.llm_query(
47
+ company_short_name=company_short_name,
48
+ external_user_id=external_user_id,
49
+ local_user_id=local_user_id,
50
+ question=question,
51
+ prompt_name=prompt_name,
52
+ client_data=client_data,
53
+ files=files)
54
+ if "error" in response:
55
+ return {'error_message': response.get("error_message", '')}, 401
56
+
57
+ return response, 200
58
+ except Exception as e:
59
+ logging.exception(
60
+ f"Error inesperado al procesar llm_query para company {company_short_name}: {e}")
61
+ if local_user_id:
62
+ return render_template("error.html",
63
+ message="Ha ocurrido un error inesperado."), 500
64
+ else:
65
+ return jsonify({"error_message": str(e)}), 500
views/login_view.py ADDED
@@ -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 request, redirect, render_template, url_for
8
+ from injector import inject
9
+ from services.profile_service import ProfileService
10
+
11
+ class LoginView(MethodView):
12
+ @inject
13
+ def __init__(self, profile_service: ProfileService):
14
+ self.profile_service = profile_service
15
+
16
+ def get(self, company_short_name: str):
17
+ # get company info
18
+ company = self.profile_service.get_company_by_short_name(company_short_name)
19
+ if not company:
20
+ return render_template('error.html', message="Empresa no encontrada"), 404
21
+
22
+ return render_template('login.html',
23
+ company=company,
24
+ company_short_name=company_short_name)
25
+
26
+ def post(self, company_short_name: str):
27
+ # get company info
28
+ company = self.profile_service.get_company_by_short_name(company_short_name)
29
+ if not company:
30
+ return render_template('error.html', message="Empresa no encontrada"), 404
31
+
32
+ email = request.form.get('email')
33
+ try:
34
+ password = request.form.get('password')
35
+
36
+ response = self.profile_service.login(
37
+ company_short_name=company_short_name,
38
+ email=email,
39
+ password=password
40
+ )
41
+
42
+ if "error" in response:
43
+ return render_template(
44
+ 'login.html',
45
+ company_short_name=company_short_name,
46
+ company=company,
47
+ form_data={
48
+ "email": email,
49
+ "password": password,
50
+ },
51
+ alert_message=response["error"]), 400
52
+
53
+ return redirect(url_for('chat', company_short_name=company_short_name))
54
+
55
+ except Exception as e:
56
+ return render_template("error.html",
57
+ company=company,
58
+ company_short_name=company_short_name,
59
+ message="Ha ocurrido un error inesperado."), 500
60
+
views/prompt_view.py ADDED
@@ -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 services.prompt_manager_service import PromptService
9
+ from common.auth import IAuthentication
10
+ from injector import inject
11
+ import logging
12
+
13
+
14
+ class PromptView(MethodView):
15
+ @inject
16
+ def __init__(self,
17
+ iauthentication: IAuthentication,
18
+ prompt_service: PromptService ):
19
+ self.iauthentication = iauthentication
20
+ self.prompt_service = prompt_service
21
+
22
+ def get(self, company_short_name):
23
+ # get access credentials
24
+ iaut = self.iauthentication.verify(company_short_name)
25
+ if not iaut.get("success"):
26
+ return jsonify(iaut), 401
27
+
28
+ try:
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"Error inesperado al obtener el historial de consultas para company {company_short_name}: {e}")
37
+ return jsonify({"error_message": str(e)}), 500
views/signup_view.py ADDED
@@ -0,0 +1,87 @@
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
8
+ from services.profile_service import ProfileService
9
+ from injector import inject
10
+ from itsdangerous import URLSafeTimedSerializer
11
+ from flask import url_for, request
12
+ import os
13
+
14
+
15
+ class SignupView(MethodView):
16
+ @inject
17
+ def __init__(self, profile_service: ProfileService):
18
+ self.profile_service = profile_service
19
+ self.serializer = URLSafeTimedSerializer(os.getenv("USER_VERIF_KEY"))
20
+
21
+
22
+ def get(self, company_short_name: str):
23
+ # get company info
24
+ company = self.profile_service.get_company_by_short_name(company_short_name)
25
+ if not company:
26
+ return render_template('error.html', message="Empresa no encontrada"), 404
27
+
28
+ user_agent = request.user_agent
29
+ is_mobile = user_agent.platform in ["android", "iphone", "ipad"] or "mobile" in user_agent.string.lower()
30
+ return render_template('signup.html',
31
+ company=company,
32
+ company_short_name=company_short_name,
33
+ is_mobile=is_mobile)
34
+
35
+ def post(self, company_short_name: str):
36
+ # get company info
37
+ company = self.profile_service.get_company_by_short_name(company_short_name)
38
+ if not company:
39
+ return render_template('error.html', message="Empresa no encontrada"), 404
40
+
41
+ try:
42
+ first_name = request.form.get('first_name')
43
+ last_name = request.form.get('last_name')
44
+ email = request.form.get('email')
45
+ password = request.form.get('password')
46
+ confirm_password = request.form.get('confirm_password')
47
+
48
+ # create verification token and url for verification
49
+ token = self.serializer.dumps(email, salt='email-confirm')
50
+ verification_url = url_for('verify_account',
51
+ company_short_name=company_short_name,
52
+ token=token, _external=True)
53
+
54
+ response = self.profile_service.signup(
55
+ company_short_name=company_short_name,
56
+ email=email,
57
+ first_name=first_name, last_name=last_name,
58
+ password=password, confirm_password=confirm_password,
59
+ verification_url=verification_url)
60
+
61
+ if "error" in response:
62
+ return render_template(
63
+ 'signup.html',
64
+ company=company,
65
+ company_short_name=company_short_name,
66
+ form_data={
67
+ "first_name": first_name,
68
+ "last_name": last_name,
69
+ "email": email,
70
+ "password": password,
71
+ "confirm_password": confirm_password
72
+ },
73
+ alert_message=response["error"]), 400
74
+
75
+ # all is OK
76
+ return render_template(
77
+ 'login.html',
78
+ company=company,
79
+ company_short_name=company_short_name,
80
+ alert_icon='success',
81
+ alert_message=response["message"]), 200
82
+ except Exception as e:
83
+ return render_template("error.html",
84
+ company=company,
85
+ company_short_name=company_short_name,
86
+ message="Ha ocurrido un error inesperado."), 500
87
+
@@ -0,0 +1,83 @@
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 request, jsonify
8
+ from services.tasks_service import TaskService
9
+ from repositories.profile_repo import ProfileRepo
10
+ from injector import inject
11
+ import logging
12
+ from typing import Optional
13
+
14
+
15
+ class TaskReviewView(MethodView):
16
+ @inject
17
+ def __init__(self, task_service: TaskService, profile_repo: ProfileRepo):
18
+ self.task_service = task_service
19
+ self.profile_repo = profile_repo
20
+
21
+
22
+ def _authenticate_requesting_company_via_api_key(self) -> tuple[
23
+ Optional[int], Optional[str], Optional[tuple[dict, int]]]:
24
+ """
25
+ Autentica a la compañía usando su API Key.
26
+ Retorna (company_id, company_short_name, None) en éxito.
27
+ Retorna (None, None, (error_json, status_code)) en fallo.
28
+ """
29
+ api_key_header = request.headers.get('Authorization')
30
+ if not api_key_header or not api_key_header.startswith('Bearer '):
31
+ return None, None, ({"error": "API Key faltante o mal formada en el header Authorization"}, 401)
32
+
33
+ api_key_value = api_key_header.split('Bearer ')[1]
34
+ try:
35
+ api_key_entry = self.profile_repo.get_active_api_key_entry(api_key_value)
36
+ if not api_key_entry:
37
+ return None, None, ({"error": "API Key inválida o inactiva"}, 401)
38
+
39
+ # api_key_entry.company ya está cargado por joinedload en get_active_api_key_entry
40
+ if not api_key_entry.company: # Sanity check
41
+ logging.error(
42
+ f"ChatTokenRequest: API Key {api_key_value[:5]}... no tiene compañía asociada a pesar de ser válida.")
43
+ return None, None, ({"error": "Error interno del servidor al verificar API Key"}, 500)
44
+
45
+ return api_key_entry.company_id, api_key_entry.company.short_name, None
46
+
47
+ except Exception as e:
48
+ logging.exception(f"ChatTokenRequest: Error interno durante validación de API Key: {e}")
49
+ return None, None, ({"error": "Error interno del servidor al validar API Key"}, 500)
50
+
51
+
52
+ def post(self, task_id: int):
53
+ try:
54
+ # only requests with valid api-key are allowed
55
+ auth_company_id, auth_company_short_name, error = self._authenticate_requesting_company_via_api_key()
56
+ if error:
57
+ return jsonify(error[0]), error[1]
58
+
59
+ req_data = request.get_json()
60
+
61
+ required_fields = ['review_user', 'approved']
62
+ for field in required_fields:
63
+ if field not in req_data:
64
+ return jsonify({"error": f"El campo {field} es requerido"}), 400
65
+
66
+ review_user = req_data.get('review_user', '')
67
+ approved = req_data.get('approved', False)
68
+ comment = req_data.get('comment', '')
69
+
70
+ new_task = self.task_service.review_task(
71
+ task_id=task_id,
72
+ review_user=review_user,
73
+ approved=approved,
74
+ comment=comment)
75
+
76
+ return jsonify({
77
+ "task_id": new_task.id,
78
+ "status": new_task.status.name
79
+ }), 200
80
+
81
+ except Exception as e:
82
+ logging.exception("Error al revisar la tarea: %s", str(e))
83
+ return jsonify({"error": str(e)}), 500
views/tasks_view.py ADDED
@@ -0,0 +1,98 @@
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 request, jsonify
8
+ from services.tasks_service import TaskService
9
+ from repositories.profile_repo import ProfileRepo
10
+ from injector import inject
11
+ from datetime import datetime
12
+ import logging
13
+ from typing import Optional
14
+
15
+
16
+ class TaskView(MethodView):
17
+ @inject
18
+ def __init__(self, task_service: TaskService, profile_repo: ProfileRepo):
19
+ self.task_service = task_service
20
+ self.profile_repo = profile_repo
21
+
22
+ def _authenticate_requesting_company_via_api_key(self) -> tuple[
23
+ Optional[int], Optional[str], Optional[tuple[dict, int]]]:
24
+ """
25
+ Autentica a la compañía usando su API Key.
26
+ Retorna (company_id, company_short_name, None) en éxito.
27
+ Retorna (None, None, (error_json, status_code)) en fallo.
28
+ """
29
+ api_key_header = request.headers.get('Authorization')
30
+ if not api_key_header or not api_key_header.startswith('Bearer '):
31
+ return None, None, ({"error": "API Key faltante o mal formada en el header Authorization"}, 401)
32
+
33
+ api_key_value = api_key_header.split('Bearer ')[1]
34
+ try:
35
+ api_key_entry = self.profile_repo.get_active_api_key_entry(api_key_value)
36
+ if not api_key_entry:
37
+ return None, None, ({"error": "API Key inválida o inactiva"}, 401)
38
+
39
+ # api_key_entry.company ya está cargado por joinedload en get_active_api_key_entry
40
+ if not api_key_entry.company: # Sanity check
41
+ logging.error(
42
+ f"ChatTokenRequest: API Key {api_key_value[:5]}... no tiene compañía asociada a pesar de ser válida.")
43
+ return None, None, ({"error": "Error interno del servidor al verificar API Key"}, 500)
44
+
45
+ return api_key_entry.company_id, api_key_entry.company.short_name, None
46
+
47
+ except Exception as e:
48
+ logging.exception(f"ChatTokenRequest: Error interno durante validación de API Key: {e}")
49
+ return None, None, ({"error": "Error interno del servidor al validar API Key"}, 500)
50
+
51
+
52
+ def post(self):
53
+ try:
54
+ # only requests with valid api-key are allowed
55
+ auth_company_id, auth_company_short_name, error = self._authenticate_requesting_company_via_api_key()
56
+ if error:
57
+ return jsonify(error[0]), error[1]
58
+
59
+ req_data = request.get_json()
60
+ files = request.files.getlist('files')
61
+
62
+ required_fields = ['company', 'task_type', 'client_data']
63
+ for field in required_fields:
64
+ if field not in req_data:
65
+ return jsonify({"error": f"El campo {field} es requerido"}), 400
66
+
67
+ company_short_name = req_data.get('company', '')
68
+ task_type = req_data.get('task_type', '')
69
+ client_data = req_data.get('client_data', {})
70
+ company_task_id = req_data.get('company_task_id', 0)
71
+ execute_at = req_data.get('execute_at', None)
72
+
73
+ # validate date format is parameter is present
74
+ if execute_at:
75
+ try:
76
+ # date in iso format
77
+ execute_at = datetime.fromisoformat(execute_at)
78
+ except ValueError:
79
+ return jsonify({
80
+ "error": "El formato de execute_at debe ser YYYY-MM-DD HH:MM:SS"
81
+ }), 400
82
+
83
+ new_task = self.task_service.create_task(
84
+ company_short_name=company_short_name,
85
+ task_type_name=task_type,
86
+ client_data=client_data,
87
+ company_task_id=company_task_id,
88
+ execute_at=execute_at,
89
+ files=files)
90
+
91
+ return jsonify({
92
+ "task_id": new_task.id,
93
+ "status": new_task.status.name
94
+ }), 201
95
+
96
+ except Exception as e:
97
+ logging.exception("Error al crear la tarea: %s", str(e))
98
+ return jsonify({"error": str(e)}), 500
@@ -0,0 +1,74 @@
1
+ # Copyright (c) 2024 Fernando Libedinsky
2
+ # Product: IAToolkit
3
+ #
4
+ # IAToolkit is open source software.
5
+
6
+ from flask import request, jsonify, render_template
7
+ from flask.views import MethodView
8
+ from services.user_feedback_service import UserFeedbackService
9
+ from common.auth import IAuthentication
10
+ from injector import inject
11
+ import logging
12
+
13
+
14
+ class UserFeedbackView(MethodView):
15
+ @inject
16
+ def __init__(self,
17
+ iauthentication: IAuthentication,
18
+ user_feedback_service: UserFeedbackService ):
19
+ self.iauthentication = iauthentication
20
+ self.user_feedback_service = user_feedback_service
21
+
22
+ def post(self, company_short_name):
23
+ data = request.get_json()
24
+ if not data:
25
+ return jsonify({"error_message": "Cuerpo de la solicitud JSON inválido o faltante"}), 400
26
+
27
+ # get access credentials
28
+ iaut = self.iauthentication.verify(company_short_name, data.get("external_user_id"))
29
+ if not iaut.get("success"):
30
+ return jsonify(iaut), 401
31
+
32
+ message = data.get("message")
33
+ if not message:
34
+ return jsonify({"error_message": "Falta el mensaje de feedback"}), 400
35
+
36
+ space = data.get("space")
37
+ if not space:
38
+ return jsonify({"error_message": "Falta el espacio de Google Chat"}), 400
39
+
40
+ type = data.get("type")
41
+ if not type:
42
+ return jsonify({"error_message": "Falta el tipo de feedback"}), 400
43
+
44
+ rating = data.get("rating")
45
+ if not rating:
46
+ return jsonify({"error_message": "Falta la calificación"}), 400
47
+
48
+ external_user_id = data.get("external_user_id")
49
+ local_user_id = data.get("local_user_id", 0)
50
+
51
+ try:
52
+ response = self.user_feedback_service.new_feedback(
53
+ company_short_name=company_short_name,
54
+ message=message,
55
+ external_user_id=external_user_id,
56
+ local_user_id=local_user_id,
57
+ space=space,
58
+ type=type,
59
+ rating=rating
60
+ )
61
+
62
+ if "error" in response:
63
+ return {'error_message': response["error"]}, 402
64
+
65
+ return response, 200
66
+ except Exception as e:
67
+ logging.exception(
68
+ f"Error inesperado al procesar feedback para company {company_short_name}: {e}")
69
+ if local_user_id:
70
+ return render_template("error.html",
71
+ message="Ha ocurrido un error inesperado."), 500
72
+ else:
73
+ return jsonify({"error_message": str(e)}), 500
74
+
@@ -0,0 +1,55 @@
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
8
+ from services.profile_service import ProfileService
9
+ from itsdangerous import URLSafeTimedSerializer, SignatureExpired
10
+ from injector import inject
11
+ import os
12
+
13
+
14
+ class VerifyAccountView(MethodView):
15
+ @inject
16
+ def __init__(self, profile_service: ProfileService):
17
+ self.profile_service = profile_service
18
+ self.serializer = URLSafeTimedSerializer(os.getenv("USER_VERIF_KEY"))
19
+
20
+ def get(self, company_short_name: str, token: str):
21
+ # get company info
22
+ company = self.profile_service.get_company_by_short_name(company_short_name)
23
+ if not company:
24
+ return render_template('error.html', message="Empresa no encontrada"), 404
25
+
26
+ try:
27
+ # decode the token from the URL
28
+ email = self.serializer.loads(token, salt='email-confirm', max_age=3600*5)
29
+ except SignatureExpired:
30
+ return render_template('signup.html',
31
+ company=company,
32
+ company_short_name=company_short_name,
33
+ token=token,
34
+ alert_message="El enlace de verificación ha expirado. Por favor, solicita uno nuevo."), 400
35
+
36
+ try:
37
+ response = self.profile_service.verify_account(email)
38
+ if "error" in response:
39
+ return render_template(
40
+ 'signup.html',
41
+ company=company,
42
+ company_short_name=company_short_name,
43
+ token=token,
44
+ alert_message=response["error"]), 400
45
+
46
+ return render_template('login.html',
47
+ company=company,
48
+ company_short_name=company_short_name,
49
+ alert_icon='success',
50
+ alert_message=response['message'])
51
+ except Exception as e:
52
+ return render_template("error.html",
53
+ company=company,
54
+ company_short_name=company_short_name,
55
+ message="Ha ocurrido un error inesperado."), 500
@@ -1,36 +0,0 @@
1
- common/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- common/auth.py,sha256=kKBvZoIm8RPpPFZ6KEm1oowHJfJwSO0mf10Yac8SG9k,8456
3
- common/exceptions.py,sha256=EXx40n5htp7UiOM6P1xfJ9U6NMcADqm62dlFaKz7ICU,1154
4
- common/routes.py,sha256=_1ywiXorwEeJ8IAamQwSxU9z8jlAAL_U64tMb01-zFg,4188
5
- common/session_manager.py,sha256=7D_RuJs60w-1zDr3fOGEz9JW7IZlSXuUHgUT87CzaUo,472
6
- common/util.py,sha256=5zw1wL_FdPBibGJbQAl1kozgTjUpsOZlPqT3tbWsHp4,15515
7
- iatoolkit/__init__.py,sha256=GkFxAQHKPifz4Kd8M73Rc8TWRVIxjxkl1N0nsPvb_sU,1743
8
- iatoolkit/base_company.py,sha256=WmD4o0qFC1n5DW5eRsRsuNfaGot9nxGFcJe3LmibSuE,4259
9
- iatoolkit/cli_commands.py,sha256=BGuThg19eoSssrBJIqzBNaWpMmyy7u4yRUz0JA7d-vc,2270
10
- iatoolkit/company_registry.py,sha256=tduqt3oV8iDX_IB1eA7KIgvIxE4edTcy-3qZIXh3Lzw,2549
11
- iatoolkit/iatoolkit.py,sha256=bbwLkLS_xZGNS0Dki3zX73RhAYMS32IshXDIdr_RVXg,15776
12
- iatoolkit/system_prompts/format_styles.prompt,sha256=MSMe1qvR3cF_0IbFshn8R0z6Wx6VCHQq1p37rpu5wwk,3576
13
- iatoolkit/system_prompts/query_main.prompt,sha256=w_9ybgWgiQH4V_RbAXqsvz0M7oOuiyhxcwf-D0CgfA4,3017
14
- iatoolkit/system_prompts/sql_rules.prompt,sha256=y4nURVnb9AyFwt-lrbMNBHHtZlhk6kC9grYoOhRnrJo,59174
15
- services/__init__.py,sha256=5JqK9sZ6jBuK83zDQokUhxQ0wuJJJ9DXB8pYCLkX7X4,102
16
- services/benchmark_service.py,sha256=_ruKh9YzrTLtR0ZKrRNxqJQW0HdbwWuFz1gfLzJ9owA,5850
17
- services/dispatcher_service.py,sha256=y2J-TfrkoCcsOESr3E6E3q5bleJfRibT4ONxs9AxUSg,13959
18
- services/document_service.py,sha256=8MsJz0pihM9E9Z92PrPqDgQnpMAmpFrbogXr5HscMWM,5926
19
- services/excel_service.py,sha256=ATPaeAvkLwQAkPZ3AKIUpO73RVyRg0D8c6i37_mcql0,3559
20
- services/file_processor_service.py,sha256=98yWYF7nIq1nm7nh6IzMmTKaOMTIeqCFWYwXVtV-ZJI,4102
21
- services/history_service.py,sha256=j0QCqcIIyw7DBy3GrZrEZNk0I4m-uuRoG5g0Z2RCcOE,1586
22
- services/jwt_service.py,sha256=YoZ9h7_o9xBko-arNQv4MbcwnxoSWVNj4VbZmMo_QGY,3908
23
- services/load_documents_service.py,sha256=UGfomYz7seWFXawbDuk2t6CyoEr1vggR8vmrCUAeLBg,7190
24
- services/mail_service.py,sha256=_67pctxZO46DHnWBip51ayuYtWd4bEoS1kg29ACO7_I,2162
25
- services/profile_service.py,sha256=vTK9TvH_2AFdqgL3sGjhck9LyLGIbvdC2USoaRx82G8,17561
26
- services/prompt_manager_service.py,sha256=7SMC6N_T4BP4m5-ZNYAL3Y2YWHwl1bytXSgnEqu5bWI,8301
27
- services/query_service.py,sha256=gvUnq0Vpn4gv5ycQk8-fklh7NDFIXpO1Vt1lT2ugO6Q,15283
28
- services/search_service.py,sha256=bB3FWFxJi1iYsOdBxyu9tzIO406nQxcyeQzEowpmpjY,1803
29
- services/sql_service.py,sha256=s84K1ADlvMtum949wgMh8jsmqlOUeL-m_SWfAM4Wsv4,2141
30
- services/tasks_service.py,sha256=1DdbERlAxIkCpGEylnHDKC-KAsXRJugbaRSzRbPfL58,6790
31
- services/user_feedback_service.py,sha256=_LeNBYz4hHFapXfYTQVfkkD34gE8j2UeKnyOZ8H0nWo,2442
32
- services/user_session_context_service.py,sha256=GluNSgqP6W_hFke4oslSnfGnU_b-ph28BHH6jf3EIm0,3797
33
- iatoolkit-0.7.5.dist-info/METADATA,sha256=LPCUPFDxvY1hpeWfbGx5Whlxh2baz1XoUwMAZv0NjYk,9300
34
- iatoolkit-0.7.5.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
35
- iatoolkit-0.7.5.dist-info/top_level.txt,sha256=iJOJr1k6nTgm_uuxyeWodC3pMsTebfQ2qEUz3rkbpB4,26
36
- iatoolkit-0.7.5.dist-info/RECORD,,