iatoolkit 0.3.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.

Potentially problematic release.


This version of iatoolkit might be problematic. Click here for more details.

@@ -0,0 +1,252 @@
1
+ Metadata-Version: 2.4
2
+ Name: iatoolkit
3
+ Version: 0.3.1
4
+ Summary: IAToolkit
5
+ Author: Fernando Libedinsky
6
+ License-Expression: MIT
7
+ Requires-Python: >=3.10
8
+ Description-Content-Type: text/markdown
9
+ Requires-Dist: aiohappyeyeballs==2.4.4
10
+ Requires-Dist: aiohttp==3.11.9
11
+ Requires-Dist: aiosignal==1.3.1
12
+ Requires-Dist: annotated-types==0.7.0
13
+ Requires-Dist: anyio==4.6.2.post1
14
+ Requires-Dist: asgiref==3.8.1
15
+ Requires-Dist: async-timeout==4.0.3
16
+ Requires-Dist: attrs==24.3.0
17
+ Requires-Dist: backoff==2.2.1
18
+ Requires-Dist: bcrypt==4.2.1
19
+ Requires-Dist: beautifulsoup4==4.12.3
20
+ Requires-Dist: blinker==1.9.0
21
+ Requires-Dist: boto3==1.36.22
22
+ Requires-Dist: botocore==1.36.22
23
+ Requires-Dist: build==1.2.2.post1
24
+ Requires-Dist: cachelib==0.13.0
25
+ Requires-Dist: cachetools==5.5.0
26
+ Requires-Dist: certifi==2024.12.14
27
+ Requires-Dist: cffi==1.17.1
28
+ Requires-Dist: charset-normalizer==3.4.0
29
+ Requires-Dist: click==8.1.8
30
+ Requires-Dist: coloredlogs==15.0.1
31
+ Requires-Dist: contourpy==1.3.3
32
+ Requires-Dist: coverage==7.6.10
33
+ Requires-Dist: cryptography==44.0.3
34
+ Requires-Dist: cycler==0.12.1
35
+ Requires-Dist: dataclasses-json==0.6.7
36
+ Requires-Dist: Deprecated==1.2.15
37
+ Requires-Dist: distro==1.9.0
38
+ Requires-Dist: durationpy==0.9
39
+ Requires-Dist: ecs-logging==2.2.0
40
+ Requires-Dist: elastic-apm==6.23.0
41
+ Requires-Dist: et_xmlfile==2.0.0
42
+ Requires-Dist: exceptiongroup==1.2.2
43
+ Requires-Dist: fastapi==0.115.6
44
+ Requires-Dist: filelock==3.16.1
45
+ Requires-Dist: Flask==3.1.0
46
+ Requires-Dist: Flask-Bcrypt==1.0.1
47
+ Requires-Dist: flask-cors==6.0.0
48
+ Requires-Dist: Flask-Injector==0.15.0
49
+ Requires-Dist: Flask-Session==0.8.0
50
+ Requires-Dist: flatbuffers==24.3.25
51
+ Requires-Dist: fonttools==4.59.2
52
+ Requires-Dist: frozenlist==1.5.0
53
+ Requires-Dist: fsspec==2024.10.0
54
+ Requires-Dist: google-ai-generativelanguage==0.6.15
55
+ Requires-Dist: google-api-core==2.24.1
56
+ Requires-Dist: google-api-python-client==2.161.0
57
+ Requires-Dist: google-auth==2.37.0
58
+ Requires-Dist: google-auth-httplib2==0.2.0
59
+ Requires-Dist: google-auth-oauthlib==1.2.1
60
+ Requires-Dist: google-cloud-core==2.4.1
61
+ Requires-Dist: google-cloud-storage==3.0.0
62
+ Requires-Dist: google-crc32c==1.6.0
63
+ Requires-Dist: google-generativeai==0.8.5
64
+ Requires-Dist: google-resumable-media==2.7.2
65
+ Requires-Dist: googleapis-common-protos==1.66.0
66
+ Requires-Dist: grpcio==1.74.0
67
+ Requires-Dist: grpcio-status==1.71.2
68
+ Requires-Dist: gunicorn==23.0.0
69
+ Requires-Dist: h11==0.14.0
70
+ Requires-Dist: httpcore==1.0.7
71
+ Requires-Dist: httplib2==0.22.0
72
+ Requires-Dist: httptools==0.6.4
73
+ Requires-Dist: httpx==0.28.0
74
+ Requires-Dist: httpx-sse==0.4.0
75
+ Requires-Dist: huggingface-hub==0.31.4
76
+ Requires-Dist: humanfriendly==10.0
77
+ Requires-Dist: idna==3.10
78
+ Requires-Dist: importlib_metadata==8.5.0
79
+ Requires-Dist: importlib_resources==6.4.5
80
+ Requires-Dist: iniconfig==2.0.0
81
+ Requires-Dist: injector==0.22.0
82
+ Requires-Dist: itsdangerous==2.2.0
83
+ Requires-Dist: Jinja2==3.1.5
84
+ Requires-Dist: jiter==0.8.0
85
+ Requires-Dist: jmespath==1.0.1
86
+ Requires-Dist: joblib==1.4.2
87
+ Requires-Dist: jsonpatch==1.33
88
+ Requires-Dist: jsonpointer==3.0.0
89
+ Requires-Dist: kiwisolver==1.4.9
90
+ Requires-Dist: kubernetes==31.0.0
91
+ Requires-Dist: langchain==0.3.19
92
+ Requires-Dist: langchain-core==0.3.35
93
+ Requires-Dist: langchain-text-splitters==0.3.6
94
+ Requires-Dist: langsmith==0.3.8
95
+ Requires-Dist: lxml==5.3.0
96
+ Requires-Dist: markdown-it-py==3.0.0
97
+ Requires-Dist: markdown2==2.5.3
98
+ Requires-Dist: MarkupSafe==3.0.2
99
+ Requires-Dist: marshmallow==3.23.1
100
+ Requires-Dist: matplotlib==3.10.6
101
+ Requires-Dist: mdurl==0.1.2
102
+ Requires-Dist: mmh3==5.0.1
103
+ Requires-Dist: monotonic==1.6
104
+ Requires-Dist: mpmath==1.3.0
105
+ Requires-Dist: msgspec==0.19.0
106
+ Requires-Dist: multidict==6.1.0
107
+ Requires-Dist: mypy-extensions==1.0.0
108
+ Requires-Dist: narwhals==2.3.0
109
+ Requires-Dist: networkx==3.4.2
110
+ Requires-Dist: numpy==2.2.3
111
+ Requires-Dist: oauth2client==4.1.3
112
+ Requires-Dist: oauthlib==3.2.2
113
+ Requires-Dist: onnxruntime==1.19.2
114
+ Requires-Dist: openai==1.79.0
115
+ Requires-Dist: openpyxl==3.1.5
116
+ Requires-Dist: opentelemetry-api==1.28.2
117
+ Requires-Dist: opentelemetry-exporter-otlp-proto-common==1.28.2
118
+ Requires-Dist: opentelemetry-exporter-otlp-proto-grpc==1.28.2
119
+ Requires-Dist: opentelemetry-instrumentation==0.49b2
120
+ Requires-Dist: opentelemetry-instrumentation-asgi==0.49b2
121
+ Requires-Dist: opentelemetry-instrumentation-fastapi==0.49b2
122
+ Requires-Dist: opentelemetry-proto==1.28.2
123
+ Requires-Dist: opentelemetry-sdk==1.28.2
124
+ Requires-Dist: opentelemetry-semantic-conventions==0.49b2
125
+ Requires-Dist: opentelemetry-util-http==0.49b2
126
+ Requires-Dist: orjson==3.10.12
127
+ Requires-Dist: overrides==7.7.0
128
+ Requires-Dist: packaging==24.2
129
+ Requires-Dist: pandas==2.3.1
130
+ Requires-Dist: pgvector==0.3.6
131
+ Requires-Dist: pillow==11.0.0
132
+ Requires-Dist: plotly==6.3.0
133
+ Requires-Dist: pluggy==1.5.0
134
+ Requires-Dist: posthog==3.7.4
135
+ Requires-Dist: propcache==0.2.1
136
+ Requires-Dist: proto-plus==1.26.0
137
+ Requires-Dist: protobuf==5.29.1
138
+ Requires-Dist: psutil==7.0.0
139
+ Requires-Dist: psycopg2-binary==2.9.10
140
+ Requires-Dist: pyarrow==21.0.0
141
+ Requires-Dist: pyasn1==0.6.1
142
+ Requires-Dist: pyasn1_modules==0.4.1
143
+ Requires-Dist: pycparser==2.22
144
+ Requires-Dist: pydantic==2.10.2
145
+ Requires-Dist: pydantic-settings==2.6.1
146
+ Requires-Dist: pydantic_core==2.27.1
147
+ Requires-Dist: PyDrive==1.3.1
148
+ Requires-Dist: Pygments==2.18.0
149
+ Requires-Dist: PyJWT==2.10.1
150
+ Requires-Dist: PyMuPDF==1.25.0
151
+ Requires-Dist: pyparsing==3.2.1
152
+ Requires-Dist: pypdf==5.1.0
153
+ Requires-Dist: PyPika==0.48.9
154
+ Requires-Dist: pyproject_hooks==1.2.0
155
+ Requires-Dist: pytesseract==0.3.13
156
+ Requires-Dist: pytest==8.3.4
157
+ Requires-Dist: pytest-cov==5.0.0
158
+ Requires-Dist: pytest-mock==3.14.0
159
+ Requires-Dist: python-dateutil==2.9.0.post0
160
+ Requires-Dist: python-docx==1.1.2
161
+ Requires-Dist: python-dotenv==1.0.1
162
+ Requires-Dist: pytz==2025.2
163
+ Requires-Dist: PyYAML==6.0.2
164
+ Requires-Dist: redis==5.2.1
165
+ Requires-Dist: regex==2024.11.6
166
+ Requires-Dist: requests==2.32.3
167
+ Requires-Dist: requests-oauthlib==2.0.0
168
+ Requires-Dist: requests-toolbelt==1.0.0
169
+ Requires-Dist: rich==13.9.4
170
+ Requires-Dist: rsa==4.9
171
+ Requires-Dist: s3transfer==0.11.2
172
+ Requires-Dist: safetensors==0.5.2
173
+ Requires-Dist: scikit-learn==1.7.1
174
+ Requires-Dist: scipy==1.15.1
175
+ Requires-Dist: seaborn==0.13.2
176
+ Requires-Dist: setuptools==75.8.0
177
+ Requires-Dist: shellingham==1.5.4
178
+ Requires-Dist: sib-api-v3-sdk==7.6.0
179
+ Requires-Dist: six==1.17.0
180
+ Requires-Dist: sniffio==1.3.1
181
+ Requires-Dist: soupsieve==2.6
182
+ Requires-Dist: SQLAlchemy==2.0.36
183
+ Requires-Dist: starlette==0.41.3
184
+ Requires-Dist: sympy==1.13.1
185
+ Requires-Dist: tenacity==9.0.0
186
+ Requires-Dist: threadpoolctl==3.5.0
187
+ Requires-Dist: tiktoken==0.8.0
188
+ Requires-Dist: tokenizers==0.21.0
189
+ Requires-Dist: tomli==2.2.1
190
+ Requires-Dist: tqdm==4.67.1
191
+ Requires-Dist: typer==0.15.1
192
+ Requires-Dist: typing-inspect==0.9.0
193
+ Requires-Dist: typing_extensions==4.12.2
194
+ Requires-Dist: tzdata==2025.2
195
+ Requires-Dist: uritemplate==4.1.1
196
+ Requires-Dist: urllib3==2.3.0
197
+ Requires-Dist: uvicorn==0.32.1
198
+ Requires-Dist: uvloop==0.21.0
199
+ Requires-Dist: watchfiles==1.0.0
200
+ Requires-Dist: websocket-client==1.8.0
201
+ Requires-Dist: websockets==14.1
202
+ Requires-Dist: Werkzeug==3.1.3
203
+ Requires-Dist: whitenoise==6.8.2
204
+ Requires-Dist: wikipedia==1.4.0
205
+ Requires-Dist: wrapt==1.17.0
206
+ Requires-Dist: yarl==1.18.3
207
+ Requires-Dist: zipp==3.21.0
208
+ Requires-Dist: zstandard==0.23.0
209
+
210
+ # iatoolkit
211
+
212
+ IAToolkit is a comprehensive, open-source framework designed for building enterprise-grade
213
+ AI chatbots and conversational applications.
214
+ Built on Flask with dependency injection, it provides a robust foundation for scalable AI solutions.
215
+
216
+ ## 🚀 Key Features
217
+ - **Universal LLM Integration**: OpenAI GPT, Google Gemini
218
+ - **Template System**: Jinja2-powered prompt templates with variables
219
+ - **Context Management**: Maintain conversation context across sessions
220
+
221
+ ### 🔒 **Enterprise Security**
222
+ - **JWT Authentication**: Secure token-based authentication
223
+ - **Session Management**: Redis-backed secure sessions
224
+ - **CORS Configuration**: Flexible cross-origin resource sharing
225
+
226
+ ### 🛠 **Function Calling & Tools**
227
+ - **Native Function Calls**: Direct integration with LLM function calling
228
+ - **Custom Tools**: Build and register custom tools for your chatbot
229
+ - **SQL Query Generation**: Natural language to SQL conversion
230
+ - **API Integrations**: Connect to external services and APIs
231
+
232
+ ### 🗄 **Database & Storage**
233
+ - **Multi-Database Support**: PostgreSQL, MySQL, SQLite via SQLAlchemy
234
+ - **Vector Store Integration**: Semantic search and retrieval
235
+ - **Document Processing**: PDF, Word, Excel, and text file handling
236
+
237
+ ### 📊 **Analytics & Monitoring**
238
+ - **Query Logging**: Track all LLM interactions
239
+ - **Performance Metrics**: Response times, token usage, costs
240
+ - **Benchmarking**: Compare model performance
241
+ - **Task Management**: Async task processing with status tracking
242
+
243
+ ### 🔧 **Developer Experience**
244
+ - **Dependency Injection**: Clean, testable architecture
245
+ - **CLI Tools**: Command-line interface for common tasks
246
+ - **Hot Reloading**: Development-friendly configuration
247
+ - **Comprehensive Logging**: Debug and monitor easily
248
+
249
+ ## License
250
+ MIT License
251
+
252
+
@@ -0,0 +1,28 @@
1
+ iatoolkit/__init__.py,sha256=Yu9XbQmEjs0gA1HBnqiaORL7HUfoKuEElUIs8scg4IQ,1125
2
+ iatoolkit/base_company.py,sha256=VWfpNofFlmgHQQK8BCw2KSOPLd2DM9eA68lGQ3SDE7M,1639
3
+ iatoolkit/company_registry.py,sha256=saOf5JxsEtvAs-JqkNp-UfOIQvtVCXyujvv6G5_zi5k,3332
4
+ iatoolkit/iatoolkit.py,sha256=YX5Oh-WWBKX0DDrzeOeaNoBrPLm0O7t4ttntYC_rk-8,15186
5
+ iatoolkit/toolkit_config.py,sha256=y4y6DV_HvHbEHCKC3v5FtX9zZyuYR5qOoULPNuiNfXI,492
6
+ services/__init__.py,sha256=fSvSfIcPW1dHwTBY1hQ5dBEhaoorzk_GzR4G46gD8tY,173
7
+ services/api_service.py,sha256=VTM5OfKF7-eCT-dpl46ZnZ3ptbTxLUDH2IxnbS4T3jA,1113
8
+ services/benchmark_service.py,sha256=g9JVrmAqIe_iI0D1DwdQ6DJ2_FJRCTndarESNSVfhbw,5907
9
+ services/dispatcher_service.py,sha256=iNu_gUZS_AgbwmCxtLBk0A33-jxsnMGYAKI5ScaJ-yE,13207
10
+ services/document_service.py,sha256=sm5QtbrKs2dF9hpLuSLMB-IMWYNBD7yWHv3rd80aD0o,5960
11
+ services/excel_service.py,sha256=wE9Udbyb96kGRSnZZ6KM2mbE484rKjTEhta9GKKpy-8,3630
12
+ services/file_processor_service.py,sha256=82UArWtwpr94CAMkkoRP0_nPtoqItymdKSIABS0Xkxw,2943
13
+ services/history_service.py,sha256=dl-D7qgdnzpY9QhjuxJokBYZZ1AF0y59HbRzwpPet58,1654
14
+ services/jwt_service.py,sha256=dC45Sn6FyzdzRiQJnzgkjN3Hy21V1imRxB0hTyWRvlA,3979
15
+ services/load_documents_service.py,sha256=_-OTUih8Zk0m4dHqAhkE7kAwU2mbz_QoMrOKnrq7ZWs,8821
16
+ services/mail_service.py,sha256=ystFit1LuYUC4ekYYebyiy1rqYQmxeL6K8h58MxEkOY,2233
17
+ services/profile_service.py,sha256=z1dSX45HDv8VJE4w8-ucpb3kBpE2fkyOdtgnrHc9vuE,17918
18
+ services/prompt_manager_service.py,sha256=nnr_iNIFeJzOY_1fbuu5-reyJS04RvGx5JW_d3YFUbk,7966
19
+ services/query_service.py,sha256=Fx_P1WcuoAp_TyocN5LGlv_hc_03ImzU5QdAIqQg0ek,15591
20
+ services/search_service.py,sha256=oJD6WRXCJBD7WUVHWWKxexRkhR8nQSrFtcPV3pFO2KQ,1153
21
+ services/sql_service.py,sha256=H7CIPpXTcxLXLojD2fBFr_mIAD0PW1vEJhKHLfJi4Hk,1418
22
+ services/tasks_service.py,sha256=hHJDlcsSOPtEleD6_Vv3pocfxWNmthIhmZSdnoWFpEM,6861
23
+ services/user_feedback_service.py,sha256=YtCndRBekDEWYEbac431Ksn2gMO5iBrI3WqKK0xtShE,2513
24
+ services/user_session_context_service.py,sha256=5qn7fqpuiU8KgMpU4M5-iRUsETumz1raBw-EeZLuE1A,3868
25
+ iatoolkit-0.3.1.dist-info/METADATA,sha256=fhcbOmNc0NQoNP0HA_QpNc0Y7VIqgPfLWV14fz7e_IQ,8801
26
+ iatoolkit-0.3.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
27
+ iatoolkit-0.3.1.dist-info/top_level.txt,sha256=dqlBbmgo9okD9d_WMR9uYzdup7Rxgj26yFF85jRGeu4,19
28
+ iatoolkit-0.3.1.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (80.9.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ iatoolkit
2
+ services
services/__init__.py ADDED
@@ -0,0 +1,5 @@
1
+ # Copyright (c) 2024 Fernando Libedinsky
2
+ # Producto: IAToolkit
3
+ # Todos los derechos reservados.
4
+ # En trámite de registro en el Registro de Propiedad Intelectual de Chile.
5
+
@@ -0,0 +1,30 @@
1
+ # Copyright (c) 2024 Fernando Libedinsky
2
+ # Producto: IAToolkit
3
+ # Todos los derechos reservados.
4
+ # En trámite de registro en el Registro de Propiedad Intelectual de Chile.
5
+
6
+ from infra.call_service import CallServiceClient
7
+ from injector import inject
8
+ from common.exceptions import IAToolkitException
9
+ import json
10
+
11
+
12
+ class ApiService:
13
+ @inject
14
+ def __init__(self, call_service: CallServiceClient):
15
+ self.call_service = call_service
16
+
17
+ def call_api(self, endpoint: str, method: str, **kwargs):
18
+ if method == 'get':
19
+ response, status_code = self.call_service.get(endpoint)
20
+ elif method == 'post':
21
+ response, status_code = self.call_service.post(endpoint=endpoint, json_dict=kwargs)
22
+ else:
23
+ raise IAToolkitException(IAToolkitException.ErrorType.INVALID_PARAMETER,
24
+ f'API error, {method} not supported')
25
+
26
+ if status_code != 200:
27
+ raise IAToolkitException(IAToolkitException.ErrorType.CALL_ERROR,
28
+ f'API {endpoint} error: {status_code}')
29
+
30
+ return json.dumps(response)
@@ -0,0 +1,139 @@
1
+ # Copyright (c) 2024 Fernando Libedinsky
2
+ # Producto: IAToolkit
3
+ # Todos los derechos reservados.
4
+ # En trámite de registro en el Registro de Propiedad Intelectual de Chile.
5
+
6
+ import pandas as pd
7
+ import time
8
+ import logging
9
+ from injector import inject
10
+ from services.query_service import QueryService
11
+ from repositories.profile_repo import ProfileRepo
12
+ from common.exceptions import IAToolkitException
13
+
14
+
15
+ class BenchmarkService:
16
+ @inject
17
+ def __init__(self, query_service: QueryService, profile_repo: ProfileRepo):
18
+ self.query_service = query_service
19
+ self.profile_repo = profile_repo
20
+
21
+ def _update_results_row(self, df: pd.DataFrame, index: int,
22
+ status: str,
23
+ context_time: float,
24
+ gpt_time: float,
25
+ answer: str,
26
+ error_msg: str,
27
+ query_id: int,
28
+ stats: dict):
29
+ df.at[index, 'status'] = status
30
+ df.at[index, 'context_time'] = round(context_time, 2)
31
+ df.at[index, 'gpt_time'] = round(gpt_time, 2)
32
+ df.at[index, 'answer'] = answer
33
+ df.at[index, 'error_message'] = error_msg[:512]
34
+ df.at[index, 'query_id'] = query_id
35
+ df.at[index, 'in_tokens'] = stats.get('input_tokens', 0)
36
+ df.at[index, 'out_tokens'] = stats.get('output_tokens', 0)
37
+ df.at[index, 'retry'] = stats.get('sql_retry_count', 0)
38
+
39
+ def run(self, company_short_name: str, file_path: str):
40
+ if not file_path.endswith('.xlsx'):
41
+ raise IAToolkitException(IAToolkitException.ErrorType.INVALID_PARAMETER,
42
+ f"solo se leer archivos .xlsx")
43
+
44
+ try:
45
+ df = pd.read_excel(file_path, keep_default_na=False)
46
+ except FileNotFoundError:
47
+ raise IAToolkitException(IAToolkitException.ErrorType.INVALID_NAME,
48
+ f"El archivo no fue encontrado en: {file_path}")
49
+
50
+ required_columns = ['username', 'client_identity', 'prompt_name', 'question', 'model']
51
+ if not all(col in df.columns for col in required_columns):
52
+ raise IAToolkitException(IAToolkitException.ErrorType.INVALID_PARAMETER,
53
+ f"La planilla debe contener las columnas: {required_columns}")
54
+
55
+ # Añadir columnas para los resultados
56
+ df['status'] = 'pending'
57
+ df['context_time'] = 0.0
58
+ df['gpt_time'] = 0.0
59
+ df['answer'] = ''
60
+ df['error_message'] = ''
61
+ df['query_id'] = 0
62
+ df['in_tokens'] = 0
63
+ df['out_tokens'] = 0
64
+ df['retry'] = 0
65
+
66
+ company = self.profile_repo.get_company_by_short_name(company_short_name)
67
+ if not company:
68
+ raise IAToolkitException(IAToolkitException.ErrorType.CONFIG_ERROR, "Compañía 'maxxa' no encontrada.")
69
+
70
+ total_rows = len(df)
71
+ logging.info(f"Iniciando benchmark para {total_rows} casos de prueba desde el archivo: {file_path}")
72
+
73
+ for index, row in df.iterrows():
74
+ status = 'OK'
75
+ error_msg = ''
76
+ answer = ''
77
+ stats = {}
78
+
79
+ try:
80
+ username = str(row['username'])
81
+ client_identity = str(row['client_identity'])
82
+ prompt_name = str(row['prompt_name'])
83
+ question = str(row['question'])
84
+ model = str(row['model'])
85
+
86
+ logging.info(
87
+ f"*** Procesando caso {index + 1}/{total_rows}: client_rut='{client_identity}', prompt='{prompt_name}'")
88
+
89
+ # 1. init context with user executing the test
90
+ start_time = time.time()
91
+ self.query_service.llm_init_context(company.short_name,
92
+ external_user_id=username,
93
+ model=model)
94
+ context_time = time.time() - start_time
95
+
96
+ # 2. prepare client data.
97
+ client_data = {'client_identity': client_identity}
98
+
99
+ # 3. execute the query
100
+ start_time = time.time()
101
+ response = self.query_service.llm_query(
102
+ company_short_name=company.short_name,
103
+ prompt_name=prompt_name,
104
+ question=question,
105
+ external_user_id=username,
106
+ client_data=client_data
107
+ )
108
+ gpt_time = time.time() - start_time
109
+
110
+ # 4. process the response
111
+ if response.get('error') or not response.get('valid_response'):
112
+ status = 'FAILED'
113
+ error_msg = response.get('error_message', 'Error desconocido en la respuesta.')
114
+ else:
115
+ answer = response.get('answer', '')
116
+ stats = response.get('stats', {})
117
+
118
+ query_id = response.get('query_id', 0)
119
+
120
+ except Exception as e:
121
+ status = 'FAILED'
122
+ error_msg = f"Excepción durante la ejecución: {type(e).__name__} - {str(e)}"
123
+ logging.error(f"Fallo en el caso {index + 1}: {error_msg}")
124
+
125
+ finally:
126
+ self._update_results_row(df, index,
127
+ status=status,
128
+ context_time=context_time,
129
+ gpt_time=gpt_time,
130
+ answer=answer,
131
+ error_msg=error_msg,
132
+ stats=stats,
133
+ query_id=query_id)
134
+
135
+ output_filename = file_path.replace('.xlsx', '_results.xlsx')
136
+ df.to_excel(output_filename, index=False)
137
+ logging.info(f"Benchmark finalizado. Resultados guardados en: {output_filename}")
138
+
139
+ return output_filename