ragaai-catalyst 2.1.5b32__py3-none-any.whl → 2.1.5b34__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.
- ragaai_catalyst/ragaai_catalyst.py +40 -7
- ragaai_catalyst/tracers/agentic_tracing/tracers/base.py +283 -95
- ragaai_catalyst/tracers/agentic_tracing/tracers/llm_tracer.py +3 -3
- ragaai_catalyst/tracers/agentic_tracing/upload/trace_uploader.py +684 -0
- ragaai_catalyst/tracers/agentic_tracing/upload/upload_agentic_traces.py +75 -20
- ragaai_catalyst/tracers/agentic_tracing/upload/upload_code.py +55 -11
- ragaai_catalyst/tracers/agentic_tracing/upload/upload_trace_metric.py +9 -2
- ragaai_catalyst/tracers/agentic_tracing/utils/create_dataset_schema.py +4 -2
- ragaai_catalyst/tracers/agentic_tracing/utils/llm_utils.py +14 -1
- ragaai_catalyst/tracers/utils/model_prices_and_context_window_backup.json +9365 -0
- {ragaai_catalyst-2.1.5b32.dist-info → ragaai_catalyst-2.1.5b34.dist-info}/METADATA +1 -1
- {ragaai_catalyst-2.1.5b32.dist-info → ragaai_catalyst-2.1.5b34.dist-info}/RECORD +15 -13
- {ragaai_catalyst-2.1.5b32.dist-info → ragaai_catalyst-2.1.5b34.dist-info}/WHEEL +1 -1
- {ragaai_catalyst-2.1.5b32.dist-info → ragaai_catalyst-2.1.5b34.dist-info}/LICENSE +0 -0
- {ragaai_catalyst-2.1.5b32.dist-info → ragaai_catalyst-2.1.5b34.dist-info}/top_level.txt +0 -0
@@ -1,10 +1,13 @@
|
|
1
1
|
import os
|
2
2
|
import logging
|
3
3
|
import requests
|
4
|
+
import time
|
4
5
|
from typing import Dict, Optional, Union
|
5
6
|
import re
|
6
7
|
logger = logging.getLogger("RagaAICatalyst")
|
7
|
-
|
8
|
+
logging_level = (
|
9
|
+
logger.setLevel(logging.DEBUG) if os.getenv("DEBUG") == "1" else logging.INFO
|
10
|
+
)
|
8
11
|
|
9
12
|
class RagaAICatalyst:
|
10
13
|
BASE_URL = None
|
@@ -116,12 +119,17 @@ class RagaAICatalyst:
|
|
116
119
|
for service, key in self.api_keys.items()
|
117
120
|
]
|
118
121
|
json_data = {"secrets": secrets}
|
122
|
+
start_time = time.time()
|
123
|
+
endpoint = f"{RagaAICatalyst.BASE_URL}/v1/llm/secrets/upload"
|
119
124
|
response = requests.post(
|
120
|
-
|
125
|
+
endpoint,
|
121
126
|
headers=headers,
|
122
127
|
json=json_data,
|
123
128
|
timeout=RagaAICatalyst.TIMEOUT,
|
124
129
|
)
|
130
|
+
elapsed_ms = (time.time() - start_time) * 1000
|
131
|
+
logger.debug(
|
132
|
+
f"API Call: [POST] {endpoint} | Status: {response.status_code} | Time: {elapsed_ms:.2f}ms")
|
125
133
|
if response.status_code == 200:
|
126
134
|
print("API keys uploaded successfully")
|
127
135
|
else:
|
@@ -162,12 +170,17 @@ class RagaAICatalyst:
|
|
162
170
|
headers = {"Content-Type": "application/json"}
|
163
171
|
json_data = {"accessKey": access_key, "secretKey": secret_key}
|
164
172
|
|
173
|
+
start_time = time.time()
|
174
|
+
endpoint = f"{RagaAICatalyst.BASE_URL}/token"
|
165
175
|
response = requests.post(
|
166
|
-
|
176
|
+
endpoint,
|
167
177
|
headers=headers,
|
168
178
|
json=json_data,
|
169
179
|
timeout=RagaAICatalyst.TIMEOUT,
|
170
180
|
)
|
181
|
+
elapsed_ms = (time.time() - start_time) * 1000
|
182
|
+
logger.debug(
|
183
|
+
f"API Call: [POST] {endpoint} | Status: {response.status_code} | Time: {elapsed_ms:.2f}ms")
|
171
184
|
|
172
185
|
# Handle specific status codes before raising an error
|
173
186
|
if response.status_code == 400:
|
@@ -202,11 +215,16 @@ class RagaAICatalyst:
|
|
202
215
|
headers = {
|
203
216
|
"Authorization": f'Bearer {os.getenv("RAGAAI_CATALYST_TOKEN")}',
|
204
217
|
}
|
218
|
+
start_time = time.time()
|
219
|
+
endpoint = f"{RagaAICatalyst.BASE_URL}/v2/llm/usecase"
|
205
220
|
response = requests.get(
|
206
|
-
|
221
|
+
endpoint,
|
207
222
|
headers=headers,
|
208
223
|
timeout=self.TIMEOUT
|
209
224
|
)
|
225
|
+
elapsed_ms = (time.time() - start_time) * 1000
|
226
|
+
logger.debug(
|
227
|
+
f"API Call: [GET] {endpoint} | Status: {response.status_code} | Time: {elapsed_ms:.2f}ms")
|
210
228
|
response.raise_for_status() # Use raise_for_status to handle HTTP errors
|
211
229
|
usecase = response.json()["data"]["usecase"]
|
212
230
|
return usecase
|
@@ -241,12 +259,17 @@ class RagaAICatalyst:
|
|
241
259
|
"Authorization": f'Bearer {os.getenv("RAGAAI_CATALYST_TOKEN")}',
|
242
260
|
}
|
243
261
|
try:
|
262
|
+
start_time = time.time()
|
263
|
+
endpoint = f"{RagaAICatalyst.BASE_URL}/v2/llm/project"
|
244
264
|
response = requests.post(
|
245
|
-
|
265
|
+
endpoint,
|
246
266
|
headers=headers,
|
247
267
|
json=json_data,
|
248
268
|
timeout=self.TIMEOUT,
|
249
269
|
)
|
270
|
+
elapsed_ms = (time.time() - start_time) * 1000
|
271
|
+
logger.debug(
|
272
|
+
f"API Call: [POST] {endpoint} | Status: {response.status_code} | Time: {elapsed_ms:.2f}ms")
|
250
273
|
response.raise_for_status()
|
251
274
|
print(
|
252
275
|
f"Project Created Successfully with name {response.json()['data']['name']} & usecase {usecase}"
|
@@ -310,11 +333,16 @@ class RagaAICatalyst:
|
|
310
333
|
"Authorization": f'Bearer {os.getenv("RAGAAI_CATALYST_TOKEN")}',
|
311
334
|
}
|
312
335
|
try:
|
336
|
+
start_time = time.time()
|
337
|
+
endpoint = f"{RagaAICatalyst.BASE_URL}/v2/llm/projects?size={num_projects}"
|
313
338
|
response = requests.get(
|
314
|
-
|
339
|
+
endpoint,
|
315
340
|
headers=headers,
|
316
341
|
timeout=self.TIMEOUT,
|
317
342
|
)
|
343
|
+
elapsed_ms = (time.time() - start_time) * 1000
|
344
|
+
logger.debug(
|
345
|
+
f"API Call: [GET] {endpoint} | Status: {response.status_code} | Time: {elapsed_ms:.2f}ms")
|
318
346
|
response.raise_for_status()
|
319
347
|
logger.debug("Projects list retrieved successfully")
|
320
348
|
|
@@ -378,11 +406,16 @@ class RagaAICatalyst:
|
|
378
406
|
"Authorization": f'Bearer {os.getenv("RAGAAI_CATALYST_TOKEN")}',
|
379
407
|
}
|
380
408
|
try:
|
409
|
+
start_time = time.time()
|
410
|
+
endpoint = f"{RagaAICatalyst.BASE_URL}/v1/llm/llm-metrics"
|
381
411
|
response = requests.get(
|
382
|
-
|
412
|
+
endpoint,
|
383
413
|
headers=headers,
|
384
414
|
timeout=RagaAICatalyst.TIMEOUT,
|
385
415
|
)
|
416
|
+
elapsed_ms = (time.time() - start_time) * 1000
|
417
|
+
logger.debug(
|
418
|
+
f"API Call: [GET] {endpoint} | Status: {response.status_code} | Time: {elapsed_ms:.2f}ms")
|
386
419
|
response.raise_for_status()
|
387
420
|
logger.debug("Metrics list retrieved successfully")
|
388
421
|
|
@@ -18,14 +18,11 @@ from ragaai_catalyst.tracers.agentic_tracing.data.data_structure import (
|
|
18
18
|
Resources,
|
19
19
|
Component,
|
20
20
|
)
|
21
|
-
from ragaai_catalyst.tracers.agentic_tracing.upload.upload_agentic_traces import UploadAgenticTraces
|
22
|
-
from ragaai_catalyst.tracers.agentic_tracing.upload.upload_code import upload_code
|
23
|
-
from ragaai_catalyst.tracers.agentic_tracing.upload.upload_trace_metric import upload_trace_metric
|
24
21
|
from ragaai_catalyst.tracers.agentic_tracing.utils.file_name_tracker import TrackName
|
25
22
|
from ragaai_catalyst.tracers.agentic_tracing.utils.zip_list_of_unique_files import zip_list_of_unique_files
|
26
23
|
from ragaai_catalyst.tracers.agentic_tracing.utils.span_attributes import SpanAttributes
|
27
|
-
from ragaai_catalyst.tracers.agentic_tracing.utils.create_dataset_schema import create_dataset_schema_with_trace
|
28
24
|
from ragaai_catalyst.tracers.agentic_tracing.utils.system_monitor import SystemMonitor
|
25
|
+
from ragaai_catalyst.tracers.agentic_tracing.upload.trace_uploader import submit_upload_task, get_task_status, ensure_uploader_running
|
29
26
|
|
30
27
|
import logging
|
31
28
|
|
@@ -67,6 +64,7 @@ class BaseTracer:
|
|
67
64
|
self.dataset_name = self.user_details["dataset_name"]
|
68
65
|
self.project_id = self.user_details["project_id"]
|
69
66
|
self.trace_name = self.user_details["trace_name"]
|
67
|
+
self.base_url = self.user_details.get("base_url", RagaAICatalyst.BASE_URL) # Get base_url from user_details or fallback to default
|
70
68
|
self.visited_metrics = []
|
71
69
|
self.trace_metrics = []
|
72
70
|
|
@@ -87,6 +85,14 @@ class BaseTracer:
|
|
87
85
|
self.system_monitor = None
|
88
86
|
self.gt = None
|
89
87
|
|
88
|
+
# For upload tracking
|
89
|
+
self.upload_task_id = None
|
90
|
+
|
91
|
+
# For backward compatibility
|
92
|
+
self._upload_tasks = []
|
93
|
+
self._is_uploading = False
|
94
|
+
self._upload_completed_callback = None
|
95
|
+
|
90
96
|
def _get_system_info(self) -> SystemInfo:
|
91
97
|
return self.system_monitor.get_system_info()
|
92
98
|
|
@@ -178,135 +184,221 @@ class BaseTracer:
|
|
178
184
|
metrics=[] # Initialize empty metrics list
|
179
185
|
)
|
180
186
|
|
187
|
+
def on_upload_completed(self, callback_fn):
|
188
|
+
"""
|
189
|
+
Register a callback function to be called when all uploads are completed.
|
190
|
+
For backward compatibility - simulates the old callback mechanism.
|
191
|
+
|
192
|
+
Args:
|
193
|
+
callback_fn: A function that takes a single argument (the tracer instance)
|
194
|
+
"""
|
195
|
+
self._upload_completed_callback = callback_fn
|
196
|
+
|
197
|
+
# Check for status periodically and call callback when complete
|
198
|
+
def check_status_and_callback():
|
199
|
+
if self.upload_task_id:
|
200
|
+
status = self.get_upload_status()
|
201
|
+
if status.get("status") in ["completed", "failed"]:
|
202
|
+
self._is_uploading = False
|
203
|
+
# Execute callback
|
204
|
+
try:
|
205
|
+
if self._upload_completed_callback:
|
206
|
+
self._upload_completed_callback(self)
|
207
|
+
except Exception as e:
|
208
|
+
logger.error(f"Error in upload completion callback: {e}")
|
209
|
+
return
|
210
|
+
|
211
|
+
# Schedule next check
|
212
|
+
threading.Timer(5.0, check_status_and_callback).start()
|
213
|
+
|
214
|
+
# Start status checking if we already have a task
|
215
|
+
if self.upload_task_id:
|
216
|
+
threading.Timer(5.0, check_status_and_callback).start()
|
217
|
+
|
218
|
+
return self
|
219
|
+
|
220
|
+
def wait_for_uploads(self, timeout=None):
|
221
|
+
"""
|
222
|
+
Wait for all async uploads to complete.
|
223
|
+
This provides backward compatibility with the old API.
|
224
|
+
|
225
|
+
Args:
|
226
|
+
timeout: Maximum time to wait in seconds (None means wait indefinitely)
|
227
|
+
|
228
|
+
Returns:
|
229
|
+
True if all uploads completed successfully, False otherwise
|
230
|
+
"""
|
231
|
+
if not self.upload_task_id:
|
232
|
+
return True
|
233
|
+
|
234
|
+
start_time = time.time()
|
235
|
+
while True:
|
236
|
+
# Check if timeout expired
|
237
|
+
if timeout is not None and time.time() - start_time > timeout:
|
238
|
+
logger.warning(f"Upload wait timed out after {timeout} seconds")
|
239
|
+
return False
|
240
|
+
|
241
|
+
# Get current status
|
242
|
+
status = self.get_upload_status()
|
243
|
+
if status.get("status") == "completed":
|
244
|
+
return True
|
245
|
+
elif status.get("status") == "failed":
|
246
|
+
logger.error(f"Upload failed: {status.get('error')}")
|
247
|
+
return False
|
248
|
+
elif status.get("status") == "unknown":
|
249
|
+
logger.warning("Upload task not found, assuming completed")
|
250
|
+
return True
|
251
|
+
|
252
|
+
# Sleep before checking again
|
253
|
+
time.sleep(1.0)
|
254
|
+
|
181
255
|
def stop(self):
|
182
|
-
"""Stop the trace and save to JSON file"""
|
256
|
+
"""Stop the trace and save to JSON file, then submit to background uploader"""
|
183
257
|
if hasattr(self, "trace"):
|
258
|
+
# Set end times
|
184
259
|
self.trace.data[0]["end_time"] = datetime.now().astimezone().isoformat()
|
185
260
|
self.trace.end_time = datetime.now().astimezone().isoformat()
|
186
261
|
|
187
|
-
#
|
262
|
+
# Stop tracking metrics
|
188
263
|
self.tracking = False
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
# track network and disk usage
|
195
|
-
network_uploads, network_downloads = 0, 0
|
196
|
-
disk_read, disk_write = 0, 0
|
197
|
-
|
198
|
-
# Handle cases where lists might have different lengths
|
199
|
-
min_len = min(len(self.network_usage_list), len(self.disk_usage_list))
|
200
|
-
for i in range(min_len):
|
201
|
-
network_usage = self.network_usage_list[i]
|
202
|
-
disk_usage = self.disk_usage_list[i]
|
203
|
-
|
204
|
-
# Safely get network usage values with defaults of 0
|
205
|
-
network_uploads += network_usage.get('uploads', 0) or 0
|
206
|
-
network_downloads += network_usage.get('downloads', 0) or 0
|
207
|
-
|
208
|
-
# Safely get disk usage values with defaults of 0
|
209
|
-
disk_read += disk_usage.get('disk_read', 0) or 0
|
210
|
-
disk_write += disk_usage.get('disk_write', 0) or 0
|
211
|
-
|
212
|
-
# track disk usage
|
213
|
-
disk_list_len = len(self.disk_usage_list)
|
214
|
-
self.trace.metadata.resources.disk.read = [disk_read / disk_list_len if disk_list_len > 0 else 0]
|
215
|
-
self.trace.metadata.resources.disk.write = [disk_write / disk_list_len if disk_list_len > 0 else 0]
|
216
|
-
|
217
|
-
# track network usage
|
218
|
-
network_list_len = len(self.network_usage_list)
|
219
|
-
self.trace.metadata.resources.network.uploads = [
|
220
|
-
network_uploads / network_list_len if network_list_len > 0 else 0]
|
221
|
-
self.trace.metadata.resources.network.downloads = [
|
222
|
-
network_downloads / network_list_len if network_list_len > 0 else 0]
|
223
|
-
|
224
|
-
# update interval time
|
225
|
-
self.trace.metadata.resources.cpu.interval = float(self.interval_time)
|
226
|
-
self.trace.metadata.resources.memory.interval = float(self.interval_time)
|
227
|
-
self.trace.metadata.resources.disk.interval = float(self.interval_time)
|
228
|
-
self.trace.metadata.resources.network.interval = float(self.interval_time)
|
229
|
-
|
230
|
-
# Change span ids to int
|
264
|
+
|
265
|
+
# Process and aggregate metrics
|
266
|
+
self._process_resource_metrics()
|
267
|
+
|
268
|
+
# Process trace spans
|
231
269
|
self.trace = self._change_span_ids_to_int(self.trace)
|
232
270
|
self.trace = self._change_agent_input_output(self.trace)
|
233
271
|
self.trace = self._extract_cost_tokens(self.trace)
|
234
272
|
|
235
|
-
# Create traces directory
|
273
|
+
# Create traces directory and prepare file paths
|
236
274
|
self.traces_dir = tempfile.gettempdir()
|
237
275
|
filename = self.trace.id + ".json"
|
238
276
|
filepath = f"{self.traces_dir}/{filename}"
|
239
277
|
|
240
|
-
#
|
278
|
+
# Process source files
|
241
279
|
list_of_unique_files = self.file_tracker.get_unique_files()
|
242
280
|
hash_id, zip_path = zip_list_of_unique_files(
|
243
281
|
list_of_unique_files, output_dir=self.traces_dir
|
244
282
|
)
|
245
|
-
|
246
|
-
# replace source code with zip_path
|
247
283
|
self.trace.metadata.system_info.source_code = hash_id
|
248
284
|
|
249
|
-
#
|
285
|
+
# Prepare trace data for saving
|
250
286
|
trace_data = self.trace.to_dict()
|
251
287
|
trace_data["metrics"] = self.trace_metrics
|
252
|
-
|
253
|
-
# Clean up trace_data before saving
|
254
288
|
cleaned_trace_data = self._clean_trace(trace_data)
|
255
|
-
|
256
|
-
#
|
289
|
+
|
290
|
+
# Add interactions
|
257
291
|
interactions = self.format_interactions()
|
258
|
-
# trace_data["workflow"] = interactions["workflow"]
|
259
292
|
cleaned_trace_data["workflow"] = interactions["workflow"]
|
260
293
|
|
294
|
+
# Save trace data to file
|
261
295
|
with open(filepath, "w") as f:
|
262
296
|
json.dump(cleaned_trace_data, f, cls=TracerJSONEncoder, indent=2)
|
263
297
|
|
264
|
-
logger.info("
|
298
|
+
logger.info("Traces saved successfully.")
|
265
299
|
logger.debug(f"Trace saved to {filepath}")
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
project_name = self.project_name
|
270
|
-
project_id = self.project_id
|
271
|
-
dataset_name = self.dataset_name
|
272
|
-
user_detail = self.user_details
|
273
|
-
base_url = RagaAICatalyst.BASE_URL
|
274
|
-
|
275
|
-
## create dataset schema
|
276
|
-
response = create_dataset_schema_with_trace(
|
277
|
-
dataset_name=dataset_name, project_name=project_name
|
278
|
-
)
|
279
|
-
|
280
|
-
##Upload trace metrics
|
281
|
-
response = upload_trace_metric(
|
282
|
-
json_file_path=json_file_path,
|
283
|
-
dataset_name=self.dataset_name,
|
284
|
-
project_name=self.project_name,
|
285
|
-
)
|
286
|
-
|
287
|
-
upload_traces = UploadAgenticTraces(
|
288
|
-
json_file_path=json_file_path,
|
289
|
-
project_name=project_name,
|
290
|
-
project_id=project_id,
|
291
|
-
dataset_name=dataset_name,
|
292
|
-
user_detail=user_detail,
|
293
|
-
base_url=base_url,
|
294
|
-
)
|
295
|
-
upload_traces.upload_agentic_traces()
|
300
|
+
|
301
|
+
# Make sure uploader process is available
|
302
|
+
ensure_uploader_running()
|
296
303
|
|
297
|
-
|
298
|
-
|
304
|
+
logger.debug("Base URL used for uploading: {}".format(self.base_url))
|
305
|
+
|
306
|
+
# Submit to background process for uploading
|
307
|
+
self.upload_task_id = submit_upload_task(
|
308
|
+
filepath=filepath,
|
299
309
|
hash_id=hash_id,
|
300
310
|
zip_path=zip_path,
|
301
|
-
project_name=project_name,
|
302
|
-
|
311
|
+
project_name=self.project_name,
|
312
|
+
project_id=self.project_id,
|
313
|
+
dataset_name=self.dataset_name,
|
314
|
+
user_details=self.user_details,
|
315
|
+
base_url=self.base_url
|
303
316
|
)
|
304
|
-
|
317
|
+
|
318
|
+
# # For backward compatibility
|
319
|
+
# self._is_uploading = True
|
320
|
+
|
321
|
+
# # Start checking for completion if a callback is registered
|
322
|
+
# if self._upload_completed_callback:
|
323
|
+
# # Start a thread to check status and call callback when complete
|
324
|
+
# def check_status_and_callback():
|
325
|
+
# status = self.get_upload_status()
|
326
|
+
# if status.get("status") in ["completed", "failed"]:
|
327
|
+
# self._is_uploading = False
|
328
|
+
# # Execute callback
|
329
|
+
# try:
|
330
|
+
# self._upload_completed_callback(self)
|
331
|
+
# except Exception as e:
|
332
|
+
# logger.error(f"Error in upload completion callback: {e}")
|
333
|
+
# return
|
334
|
+
|
335
|
+
# # Check again after a delay
|
336
|
+
# threading.Timer(5.0, check_status_and_callback).start()
|
337
|
+
|
338
|
+
# # Start checking
|
339
|
+
# threading.Timer(5.0, check_status_and_callback).start()
|
340
|
+
|
341
|
+
logger.info(f"Submitted upload task with ID: {self.upload_task_id}")
|
305
342
|
|
306
|
-
# Cleanup
|
343
|
+
# Cleanup local resources
|
307
344
|
self.components = []
|
308
345
|
self.file_tracker.reset()
|
346
|
+
|
347
|
+
def get_upload_status(self):
|
348
|
+
"""
|
349
|
+
Get the status of the upload task.
|
350
|
+
|
351
|
+
Returns:
|
352
|
+
dict: Status information
|
353
|
+
"""
|
354
|
+
if not self.upload_task_id:
|
355
|
+
return {"status": "not_started", "message": "No upload has been initiated"}
|
356
|
+
|
357
|
+
return get_task_status(self.upload_task_id)
|
309
358
|
|
359
|
+
def _process_resource_metrics(self):
|
360
|
+
"""Process and aggregate all resource metrics"""
|
361
|
+
# Process memory metrics
|
362
|
+
self.trace.metadata.resources.memory.values = self.memory_usage_list
|
363
|
+
|
364
|
+
# Process CPU metrics
|
365
|
+
self.trace.metadata.resources.cpu.values = self.cpu_usage_list
|
366
|
+
|
367
|
+
# Process network and disk metrics
|
368
|
+
network_uploads, network_downloads = 0, 0
|
369
|
+
disk_read, disk_write = 0, 0
|
370
|
+
|
371
|
+
# Handle cases where lists might have different lengths
|
372
|
+
min_len = min(len(self.network_usage_list), len(self.disk_usage_list)) if self.network_usage_list and self.disk_usage_list else 0
|
373
|
+
for i in range(min_len):
|
374
|
+
network_usage = self.network_usage_list[i]
|
375
|
+
disk_usage = self.disk_usage_list[i]
|
376
|
+
|
377
|
+
# Safely get network usage values with defaults of 0
|
378
|
+
network_uploads += network_usage.get('uploads', 0) or 0
|
379
|
+
network_downloads += network_usage.get('downloads', 0) or 0
|
380
|
+
|
381
|
+
# Safely get disk usage values with defaults of 0
|
382
|
+
disk_read += disk_usage.get('disk_read', 0) or 0
|
383
|
+
disk_write += disk_usage.get('disk_write', 0) or 0
|
384
|
+
|
385
|
+
# Set aggregate values
|
386
|
+
disk_list_len = len(self.disk_usage_list)
|
387
|
+
self.trace.metadata.resources.disk.read = [disk_read / disk_list_len if disk_list_len > 0 else 0]
|
388
|
+
self.trace.metadata.resources.disk.write = [disk_write / disk_list_len if disk_list_len > 0 else 0]
|
389
|
+
|
390
|
+
network_list_len = len(self.network_usage_list)
|
391
|
+
self.trace.metadata.resources.network.uploads = [
|
392
|
+
network_uploads / network_list_len if network_list_len > 0 else 0]
|
393
|
+
self.trace.metadata.resources.network.downloads = [
|
394
|
+
network_downloads / network_list_len if network_list_len > 0 else 0]
|
395
|
+
|
396
|
+
# Set interval times
|
397
|
+
self.trace.metadata.resources.cpu.interval = float(self.interval_time)
|
398
|
+
self.trace.metadata.resources.memory.interval = float(self.interval_time)
|
399
|
+
self.trace.metadata.resources.disk.interval = float(self.interval_time)
|
400
|
+
self.trace.metadata.resources.network.interval = float(self.interval_time)
|
401
|
+
|
310
402
|
def add_component(self, component: Component):
|
311
403
|
"""Add a component to the trace"""
|
312
404
|
self.components.append(component)
|
@@ -1107,3 +1199,99 @@ class BaseTracer:
|
|
1107
1199
|
|
1108
1200
|
return local_metrics_results
|
1109
1201
|
|
1202
|
+
|
1203
|
+
def upload_directly(self):
|
1204
|
+
"""Upload trace directly without using the background process"""
|
1205
|
+
# Check if we have necessary details
|
1206
|
+
if not hasattr(self, 'trace') or not self.trace_id:
|
1207
|
+
print("No trace to upload")
|
1208
|
+
return False
|
1209
|
+
|
1210
|
+
# Get the filepath from the last trace
|
1211
|
+
trace_dir = tempfile.gettempdir()
|
1212
|
+
trace_file = os.path.join(trace_dir, f"{self.trace_id}.json")
|
1213
|
+
|
1214
|
+
# If filepath wasn't saved from previous stop() call, try to find it
|
1215
|
+
if not os.path.exists(trace_file):
|
1216
|
+
print(f"Looking for trace file for {self.trace_id}")
|
1217
|
+
# Try to find the trace file by pattern
|
1218
|
+
for file in os.listdir(trace_dir):
|
1219
|
+
if file.endswith(".json") and self.trace_id in file:
|
1220
|
+
trace_file = os.path.join(trace_dir, file)
|
1221
|
+
print(f"Found trace file: {trace_file}")
|
1222
|
+
break
|
1223
|
+
|
1224
|
+
if not os.path.exists(trace_file):
|
1225
|
+
print(f"Trace file not found for ID {self.trace_id}")
|
1226
|
+
return False
|
1227
|
+
|
1228
|
+
print(f"Starting direct upload of {trace_file}")
|
1229
|
+
|
1230
|
+
try:
|
1231
|
+
# 1. Create the dataset schema
|
1232
|
+
print("Creating dataset schema...")
|
1233
|
+
from ragaai_catalyst.tracers.agentic_tracing.utils.create_dataset_schema import create_dataset_schema_with_trace
|
1234
|
+
response = create_dataset_schema_with_trace(
|
1235
|
+
dataset_name=self.dataset_name,
|
1236
|
+
project_name=self.project_name
|
1237
|
+
)
|
1238
|
+
print(f"Schema created: {response}")
|
1239
|
+
|
1240
|
+
# 2. Upload trace metrics
|
1241
|
+
print("Uploading trace metrics...")
|
1242
|
+
from ragaai_catalyst.tracers.agentic_tracing.upload.upload_trace_metric import upload_trace_metric
|
1243
|
+
response = upload_trace_metric(
|
1244
|
+
json_file_path=trace_file,
|
1245
|
+
dataset_name=self.dataset_name,
|
1246
|
+
project_name=self.project_name,
|
1247
|
+
)
|
1248
|
+
print(f"Metrics uploaded: {response}")
|
1249
|
+
|
1250
|
+
# 3. Get code hash and zip path if available
|
1251
|
+
code_hash = None
|
1252
|
+
zip_path = None
|
1253
|
+
try:
|
1254
|
+
with open(trace_file, 'r') as f:
|
1255
|
+
data = json.load(f)
|
1256
|
+
code_hash = data.get("metadata", {}).get("system_info", {}).get("source_code")
|
1257
|
+
if code_hash:
|
1258
|
+
zip_path = os.path.join(trace_dir, f"{code_hash}.zip")
|
1259
|
+
print(f"Found code hash: {code_hash}")
|
1260
|
+
print(f"Zip path: {zip_path}")
|
1261
|
+
except Exception as e:
|
1262
|
+
print(f"Error getting code hash: {e}")
|
1263
|
+
|
1264
|
+
# 4. Upload agentic traces
|
1265
|
+
print("Uploading agentic traces...")
|
1266
|
+
from ragaai_catalyst.tracers.agentic_tracing.upload.upload_agentic_traces import UploadAgenticTraces
|
1267
|
+
from ragaai_catalyst import RagaAICatalyst
|
1268
|
+
upload_traces = UploadAgenticTraces(
|
1269
|
+
json_file_path=trace_file,
|
1270
|
+
project_name=self.project_name,
|
1271
|
+
project_id=self.project_id,
|
1272
|
+
dataset_name=self.dataset_name,
|
1273
|
+
user_detail=self.user_details,
|
1274
|
+
base_url=RagaAICatalyst.BASE_URL,
|
1275
|
+
)
|
1276
|
+
upload_traces.upload_agentic_traces()
|
1277
|
+
print("Agentic traces uploaded successfully")
|
1278
|
+
|
1279
|
+
# 5. Upload code hash if available
|
1280
|
+
if code_hash and zip_path and os.path.exists(zip_path):
|
1281
|
+
print(f"Uploading code hash: {code_hash}")
|
1282
|
+
from ragaai_catalyst.tracers.agentic_tracing.upload.upload_code import upload_code
|
1283
|
+
response = upload_code(
|
1284
|
+
hash_id=code_hash,
|
1285
|
+
zip_path=zip_path,
|
1286
|
+
project_name=self.project_name,
|
1287
|
+
dataset_name=self.dataset_name,
|
1288
|
+
)
|
1289
|
+
print(f"Code uploaded: {response}")
|
1290
|
+
|
1291
|
+
print("Upload completed successfully - check UI now")
|
1292
|
+
return True
|
1293
|
+
except Exception as e:
|
1294
|
+
print(f"Error during direct upload: {e}")
|
1295
|
+
import traceback
|
1296
|
+
traceback.print_exc()
|
1297
|
+
return False
|
@@ -12,7 +12,6 @@ import contextvars
|
|
12
12
|
import traceback
|
13
13
|
import importlib
|
14
14
|
import sys
|
15
|
-
from litellm import model_cost
|
16
15
|
import logging
|
17
16
|
|
18
17
|
try:
|
@@ -29,7 +28,8 @@ from ..utils.llm_utils import (
|
|
29
28
|
sanitize_api_keys,
|
30
29
|
sanitize_input,
|
31
30
|
extract_llm_output,
|
32
|
-
num_tokens_from_messages
|
31
|
+
num_tokens_from_messages,
|
32
|
+
get_model_cost
|
33
33
|
)
|
34
34
|
from ..utils.unique_decorator import generate_unique_hash
|
35
35
|
from ..utils.file_name_tracker import TrackName
|
@@ -49,7 +49,7 @@ class LLMTracerMixin:
|
|
49
49
|
self.file_tracker = TrackName()
|
50
50
|
self.patches = []
|
51
51
|
try:
|
52
|
-
self.model_costs =
|
52
|
+
self.model_costs = get_model_cost()
|
53
53
|
except Exception as e:
|
54
54
|
self.model_costs = {
|
55
55
|
"default": {"input_cost_per_token": 0.0, "output_cost_per_token": 0.0}
|