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,7 +1,13 @@
|
|
1
1
|
import requests
|
2
2
|
import json
|
3
3
|
import os
|
4
|
+
import time
|
5
|
+
import logging
|
4
6
|
from datetime import datetime
|
7
|
+
from urllib.parse import urlparse, urlunparse
|
8
|
+
import re
|
9
|
+
|
10
|
+
logger = logging.getLogger(__name__)
|
5
11
|
|
6
12
|
|
7
13
|
class UploadAgenticTraces:
|
@@ -33,17 +39,41 @@ class UploadAgenticTraces:
|
|
33
39
|
}
|
34
40
|
|
35
41
|
try:
|
42
|
+
start_time = time.time()
|
43
|
+
endpoint = f"{self.base_url}/v1/llm/presigned-url"
|
36
44
|
response = requests.request("GET",
|
37
|
-
|
45
|
+
endpoint,
|
38
46
|
headers=headers,
|
39
47
|
data=payload,
|
40
48
|
timeout=self.timeout)
|
49
|
+
elapsed_ms = (time.time() - start_time) * 1000
|
50
|
+
logger.debug(
|
51
|
+
f"API Call: [GET] {endpoint} | Status: {response.status_code} | Time: {elapsed_ms:.2f}ms")
|
52
|
+
|
41
53
|
if response.status_code == 200:
|
42
|
-
|
43
|
-
|
54
|
+
presignedURLs = response.json()["data"]["presignedUrls"][0]
|
55
|
+
presignedurl = self.update_presigned_url(presignedURLs,self.base_url)
|
56
|
+
return presignedurl
|
57
|
+
|
44
58
|
except requests.exceptions.RequestException as e:
|
45
59
|
print(f"Error while getting presigned url: {e}")
|
46
60
|
return None
|
61
|
+
|
62
|
+
def update_presigned_url(self, presigned_url, base_url):
|
63
|
+
"""Replaces the domain (and port, if applicable) of the presigned URL
|
64
|
+
with that of the base URL only if the base URL contains 'localhost' or an IP address."""
|
65
|
+
#To Do: If Proxy URL has domain name how do we handle such cases
|
66
|
+
|
67
|
+
presigned_parts = urlparse(presigned_url)
|
68
|
+
base_parts = urlparse(base_url)
|
69
|
+
# Check if base_url contains localhost or an IP address
|
70
|
+
if re.match(r'^(localhost|\d{1,3}(\.\d{1,3}){3})$', base_parts.hostname):
|
71
|
+
new_netloc = base_parts.hostname # Extract domain from base_url
|
72
|
+
if base_parts.port: # Add port if present in base_url
|
73
|
+
new_netloc += f":{base_parts.port}"
|
74
|
+
updated_parts = presigned_parts._replace(netloc=new_netloc)
|
75
|
+
return urlunparse(updated_parts)
|
76
|
+
return presigned_url
|
47
77
|
|
48
78
|
def _put_presigned_url(self, presignedUrl, filename):
|
49
79
|
headers = {
|
@@ -60,11 +90,15 @@ class UploadAgenticTraces:
|
|
60
90
|
print(f"Error while reading file: {e}")
|
61
91
|
return None
|
62
92
|
try:
|
93
|
+
start_time = time.time()
|
63
94
|
response = requests.request("PUT",
|
64
95
|
presignedUrl,
|
65
96
|
headers=headers,
|
66
97
|
data=payload,
|
67
98
|
timeout=self.timeout)
|
99
|
+
elapsed_ms = (time.time() - start_time) * 1000
|
100
|
+
logger.debug(
|
101
|
+
f"API Call: [PUT] {presignedUrl} | Status: {response.status_code} | Time: {elapsed_ms:.2f}ms")
|
68
102
|
if response.status_code != 200 or response.status_code != 201:
|
69
103
|
return response, response.status_code
|
70
104
|
except requests.exceptions.RequestException as e:
|
@@ -83,11 +117,16 @@ class UploadAgenticTraces:
|
|
83
117
|
"datasetSpans": self._get_dataset_spans(), #Extra key for agentic traces
|
84
118
|
})
|
85
119
|
try:
|
120
|
+
start_time = time.time()
|
121
|
+
endpoint = f"{self.base_url}/v1/llm/insert/trace"
|
86
122
|
response = requests.request("POST",
|
87
|
-
|
123
|
+
endpoint,
|
88
124
|
headers=headers,
|
89
125
|
data=payload,
|
90
126
|
timeout=self.timeout)
|
127
|
+
elapsed_ms = (time.time() - start_time) * 1000
|
128
|
+
logger.debug(
|
129
|
+
f"API Call: [POST] {endpoint} | Status: {response.status_code} | Time: {elapsed_ms:.2f}ms")
|
91
130
|
if response.status_code != 200:
|
92
131
|
print(f"Error inserting traces: {response.json()['message']}")
|
93
132
|
return None
|
@@ -116,27 +155,43 @@ class UploadAgenticTraces:
|
|
116
155
|
"spanType": span["type"],
|
117
156
|
})
|
118
157
|
else:
|
119
|
-
datasetSpans.
|
158
|
+
datasetSpans.extend(self._get_agent_dataset_spans(span, datasetSpans))
|
159
|
+
datasetSpans = [dict(t) for t in set(tuple(sorted(d.items())) for d in datasetSpans)]
|
160
|
+
|
161
|
+
return datasetSpans
|
162
|
+
except Exception as e:
|
163
|
+
print(f"Error while reading dataset spans: {e}")
|
164
|
+
return None
|
165
|
+
|
166
|
+
def _get_agent_dataset_spans(self, span, datasetSpans):
|
167
|
+
datasetSpans.append({
|
120
168
|
"spanId": span["id"],
|
121
169
|
"spanName": span["name"],
|
122
170
|
"spanHash": span["hash_id"],
|
123
171
|
"spanType": span["type"],
|
124
172
|
})
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
173
|
+
children = span["data"]["children"]
|
174
|
+
for child in children:
|
175
|
+
if child["type"] != "agent":
|
176
|
+
existing_span = next((s for s in datasetSpans if s["spanHash"] == child["hash_id"]), None)
|
177
|
+
if existing_span is None:
|
178
|
+
datasetSpans.append({
|
179
|
+
"spanId": child["id"],
|
180
|
+
"spanName": child["name"],
|
181
|
+
"spanHash": child["hash_id"],
|
182
|
+
"spanType": child["type"],
|
183
|
+
})
|
184
|
+
else:
|
185
|
+
datasetSpans.append({
|
186
|
+
"spanId": child["id"],
|
187
|
+
"spanName": child["name"],
|
188
|
+
"spanHash": child["hash_id"],
|
189
|
+
"spanType": child["type"],
|
190
|
+
})
|
191
|
+
self._get_agent_dataset_spans(child, datasetSpans)
|
192
|
+
return datasetSpans
|
193
|
+
|
194
|
+
|
140
195
|
def upload_agentic_traces(self):
|
141
196
|
try:
|
142
197
|
presignedUrl = self._get_presigned_url()
|
@@ -2,23 +2,26 @@ from aiohttp import payload
|
|
2
2
|
import requests
|
3
3
|
import json
|
4
4
|
import os
|
5
|
+
import time
|
5
6
|
import logging
|
6
7
|
from ragaai_catalyst.ragaai_catalyst import RagaAICatalyst
|
7
8
|
logger = logging.getLogger(__name__)
|
9
|
+
from urllib.parse import urlparse, urlunparse
|
10
|
+
import re
|
8
11
|
|
9
|
-
def upload_code(hash_id, zip_path, project_name, dataset_name):
|
10
|
-
code_hashes_list = _fetch_dataset_code_hashes(project_name, dataset_name)
|
12
|
+
def upload_code(hash_id, zip_path, project_name, dataset_name, base_url=None):
|
13
|
+
code_hashes_list = _fetch_dataset_code_hashes(project_name, dataset_name, base_url)
|
11
14
|
|
12
15
|
if hash_id not in code_hashes_list:
|
13
|
-
presigned_url = _fetch_presigned_url(project_name, dataset_name)
|
16
|
+
presigned_url = _fetch_presigned_url(project_name, dataset_name, base_url)
|
14
17
|
_put_zip_presigned_url(project_name, presigned_url, zip_path)
|
15
18
|
|
16
|
-
response = _insert_code(dataset_name, hash_id, presigned_url, project_name)
|
19
|
+
response = _insert_code(dataset_name, hash_id, presigned_url, project_name, base_url)
|
17
20
|
return response
|
18
21
|
else:
|
19
22
|
return "Code already exists"
|
20
23
|
|
21
|
-
def _fetch_dataset_code_hashes(project_name, dataset_name):
|
24
|
+
def _fetch_dataset_code_hashes(project_name, dataset_name, base_url=None):
|
22
25
|
payload = {}
|
23
26
|
headers = {
|
24
27
|
"Authorization": f"Bearer {os.getenv('RAGAAI_CATALYST_TOKEN')}",
|
@@ -26,11 +29,17 @@ def _fetch_dataset_code_hashes(project_name, dataset_name):
|
|
26
29
|
}
|
27
30
|
|
28
31
|
try:
|
32
|
+
url_base = base_url if base_url is not None else RagaAICatalyst.BASE_URL
|
33
|
+
start_time = time.time()
|
34
|
+
endpoint = f"{url_base}/v2/llm/dataset/code?datasetName={dataset_name}"
|
29
35
|
response = requests.request("GET",
|
30
|
-
|
36
|
+
endpoint,
|
31
37
|
headers=headers,
|
32
38
|
data=payload,
|
33
39
|
timeout=99999)
|
40
|
+
elapsed_ms = (time.time() - start_time) * 1000
|
41
|
+
logger.debug(
|
42
|
+
f"API Call: [GET] {endpoint} | Status: {response.status_code} | Time: {elapsed_ms:.2f}ms")
|
34
43
|
|
35
44
|
if response.status_code == 200:
|
36
45
|
return response.json()["data"]["codeHashes"]
|
@@ -40,7 +49,24 @@ def _fetch_dataset_code_hashes(project_name, dataset_name):
|
|
40
49
|
logger.error(f"Failed to list datasets: {e}")
|
41
50
|
raise
|
42
51
|
|
43
|
-
|
52
|
+
|
53
|
+
def update_presigned_url(presigned_url, base_url):
|
54
|
+
"""Replaces the domain (and port, if applicable) of the presigned URL with that of the base URL."""
|
55
|
+
#To Do: If Proxy URL has domain name how do we handle such cases? Engineering Dependency.
|
56
|
+
|
57
|
+
presigned_parts = urlparse(presigned_url)
|
58
|
+
base_parts = urlparse(base_url)
|
59
|
+
# Check if base_url contains localhost or an IP address
|
60
|
+
if re.match(r'^(localhost|\d{1,3}(\.\d{1,3}){3})$', base_parts.hostname):
|
61
|
+
new_netloc = base_parts.hostname # Extract domain from base_url
|
62
|
+
if base_parts.port: # Add port if present in base_url
|
63
|
+
new_netloc += f":{base_parts.port}"
|
64
|
+
updated_parts = presigned_parts._replace(netloc=new_netloc)
|
65
|
+
return urlunparse(updated_parts)
|
66
|
+
return presigned_url
|
67
|
+
|
68
|
+
|
69
|
+
def _fetch_presigned_url(project_name, dataset_name, base_url=None):
|
44
70
|
payload = json.dumps({
|
45
71
|
"datasetName": dataset_name,
|
46
72
|
"numFiles": 1,
|
@@ -54,14 +80,22 @@ def _fetch_presigned_url(project_name, dataset_name):
|
|
54
80
|
}
|
55
81
|
|
56
82
|
try:
|
83
|
+
url_base = base_url if base_url is not None else RagaAICatalyst.BASE_URL
|
84
|
+
start_time = time.time()
|
85
|
+
endpoint = f"{url_base}/v1/llm/presigned-url"
|
57
86
|
response = requests.request("GET",
|
58
|
-
|
87
|
+
endpoint,
|
59
88
|
headers=headers,
|
60
89
|
data=payload,
|
61
90
|
timeout=99999)
|
91
|
+
elapsed_ms = (time.time() - start_time) * 1000
|
92
|
+
logger.debug(
|
93
|
+
f"API Call: [GET] {endpoint} | Status: {response.status_code} | Time: {elapsed_ms:.2f}ms")
|
62
94
|
|
63
95
|
if response.status_code == 200:
|
64
|
-
|
96
|
+
presigned_url = response.json()["data"]["presignedUrls"][0]
|
97
|
+
presigned_url = update_presigned_url(presigned_url,url_base)
|
98
|
+
return presigned_url
|
65
99
|
else:
|
66
100
|
raise Exception(f"Failed to fetch code hashes: {response.json()['message']}")
|
67
101
|
except requests.exceptions.RequestException as e:
|
@@ -80,15 +114,19 @@ def _put_zip_presigned_url(project_name, presignedUrl, filename):
|
|
80
114
|
with open(filename, 'rb') as f:
|
81
115
|
payload = f.read()
|
82
116
|
|
117
|
+
start_time = time.time()
|
83
118
|
response = requests.request("PUT",
|
84
119
|
presignedUrl,
|
85
120
|
headers=headers,
|
86
121
|
data=payload,
|
87
122
|
timeout=99999)
|
123
|
+
elapsed_ms = (time.time() - start_time) * 1000
|
124
|
+
logger.debug(
|
125
|
+
f"API Call: [PUT] {presignedUrl} | Status: {response.status_code} | Time: {elapsed_ms:.2f}ms")
|
88
126
|
if response.status_code != 200 or response.status_code != 201:
|
89
127
|
return response, response.status_code
|
90
128
|
|
91
|
-
def _insert_code(dataset_name, hash_id, presigned_url, project_name):
|
129
|
+
def _insert_code(dataset_name, hash_id, presigned_url, project_name, base_url=None):
|
92
130
|
payload = json.dumps({
|
93
131
|
"datasetName": dataset_name,
|
94
132
|
"codeHash": hash_id,
|
@@ -102,11 +140,17 @@ def _insert_code(dataset_name, hash_id, presigned_url, project_name):
|
|
102
140
|
}
|
103
141
|
|
104
142
|
try:
|
143
|
+
url_base = base_url if base_url is not None else RagaAICatalyst.BASE_URL
|
144
|
+
start_time = time.time()
|
145
|
+
endpoint = f"{url_base}/v2/llm/dataset/code"
|
105
146
|
response = requests.request("POST",
|
106
|
-
|
147
|
+
endpoint,
|
107
148
|
headers=headers,
|
108
149
|
data=payload,
|
109
150
|
timeout=99999)
|
151
|
+
elapsed_ms = (time.time() - start_time) * 1000
|
152
|
+
logger.debug(
|
153
|
+
f"API Call: [POST] {endpoint} | Status: {response.status_code} | Time: {elapsed_ms:.2f}ms")
|
110
154
|
if response.status_code == 200:
|
111
155
|
return response.json()["message"]
|
112
156
|
else:
|
@@ -3,6 +3,7 @@ import logging
|
|
3
3
|
import requests
|
4
4
|
import os
|
5
5
|
import json
|
6
|
+
import time
|
6
7
|
from ....ragaai_catalyst import RagaAICatalyst
|
7
8
|
from ..utils.get_user_trace_metrics import get_user_trace_metrics
|
8
9
|
|
@@ -14,7 +15,7 @@ logging_level = (
|
|
14
15
|
)
|
15
16
|
|
16
17
|
|
17
|
-
def upload_trace_metric(json_file_path, dataset_name, project_name):
|
18
|
+
def upload_trace_metric(json_file_path, dataset_name, project_name, base_url=None):
|
18
19
|
try:
|
19
20
|
with open(json_file_path, "r") as f:
|
20
21
|
traces = json.load(f)
|
@@ -43,11 +44,17 @@ def upload_trace_metric(json_file_path, dataset_name, project_name):
|
|
43
44
|
"datasetName": dataset_name,
|
44
45
|
"metrics": metrics
|
45
46
|
})
|
47
|
+
url_base = base_url if base_url is not None else RagaAICatalyst.BASE_URL
|
48
|
+
start_time = time.time()
|
49
|
+
endpoint = f"{url_base}/v1/llm/trace/metrics"
|
46
50
|
response = requests.request("POST",
|
47
|
-
|
51
|
+
endpoint,
|
48
52
|
headers=headers,
|
49
53
|
data=payload,
|
50
54
|
timeout=10)
|
55
|
+
elapsed_ms = (time.time() - start_time) * 1000
|
56
|
+
logger.debug(
|
57
|
+
f"API Call: [POST] {endpoint} | Status: {response.status_code} | Time: {elapsed_ms:.2f}ms")
|
51
58
|
if response.status_code != 200:
|
52
59
|
raise ValueError(f"Error inserting agentic trace metrics")
|
53
60
|
except requests.exceptions.RequestException as e:
|
@@ -4,7 +4,7 @@ import re
|
|
4
4
|
import requests
|
5
5
|
from ragaai_catalyst.tracers.agentic_tracing.tracers.base import RagaAICatalyst
|
6
6
|
|
7
|
-
def create_dataset_schema_with_trace(project_name, dataset_name):
|
7
|
+
def create_dataset_schema_with_trace(project_name, dataset_name, base_url=None):
|
8
8
|
def make_request():
|
9
9
|
headers = {
|
10
10
|
"Content-Type": "application/json",
|
@@ -15,8 +15,10 @@ def create_dataset_schema_with_trace(project_name, dataset_name):
|
|
15
15
|
"datasetName": dataset_name,
|
16
16
|
"traceFolderUrl": None,
|
17
17
|
})
|
18
|
+
# Use provided base_url or fall back to default
|
19
|
+
url_base = base_url if base_url is not None else RagaAICatalyst.BASE_URL
|
18
20
|
response = requests.request("POST",
|
19
|
-
f"{
|
21
|
+
f"{url_base}/v1/llm/dataset/logs",
|
20
22
|
headers=headers,
|
21
23
|
data=payload,
|
22
24
|
timeout=10
|
@@ -4,7 +4,7 @@ from .trace_utils import (
|
|
4
4
|
convert_usage_to_dict,
|
5
5
|
)
|
6
6
|
from importlib import resources
|
7
|
-
from litellm import model_cost
|
7
|
+
#from litellm import model_cost
|
8
8
|
import json
|
9
9
|
import os
|
10
10
|
import asyncio
|
@@ -14,6 +14,19 @@ import logging
|
|
14
14
|
|
15
15
|
logger = logging.getLogger(__name__)
|
16
16
|
|
17
|
+
def get_model_cost():
|
18
|
+
"""Load model costs from a JSON file.
|
19
|
+
Note: This file should be updated periodically or whenever a new package is created to ensure accurate cost calculations.
|
20
|
+
To Do: Implement to do this automatically.
|
21
|
+
"""
|
22
|
+
file="model_prices_and_context_window_backup.json"
|
23
|
+
d={}
|
24
|
+
with resources.open_text("ragaai_catalyst.tracers.utils", file) as f:
|
25
|
+
d= json.load(f)
|
26
|
+
return d
|
27
|
+
|
28
|
+
model_cost = get_model_cost()
|
29
|
+
|
17
30
|
def extract_model_name(args, kwargs, result):
|
18
31
|
"""Extract model name from kwargs or result"""
|
19
32
|
# First try direct model parameter
|