ragaai-catalyst 2.0.7.2__py3-none-any.whl → 2.0.7.2b0__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.
Files changed (29) hide show
  1. ragaai_catalyst/evaluation.py +107 -153
  2. ragaai_catalyst/tracers/agentic_tracing/Untitled-1.json +660 -0
  3. ragaai_catalyst/tracers/agentic_tracing/__init__.py +3 -0
  4. ragaai_catalyst/tracers/agentic_tracing/agent_tracer.py +311 -0
  5. ragaai_catalyst/tracers/agentic_tracing/agentic_tracing.py +212 -0
  6. ragaai_catalyst/tracers/agentic_tracing/base.py +270 -0
  7. ragaai_catalyst/tracers/agentic_tracing/data_structure.py +239 -0
  8. ragaai_catalyst/tracers/agentic_tracing/llm_tracer.py +906 -0
  9. ragaai_catalyst/tracers/agentic_tracing/network_tracer.py +286 -0
  10. ragaai_catalyst/tracers/agentic_tracing/sample.py +197 -0
  11. ragaai_catalyst/tracers/agentic_tracing/tool_tracer.py +235 -0
  12. ragaai_catalyst/tracers/agentic_tracing/unique_decorator.py +221 -0
  13. ragaai_catalyst/tracers/agentic_tracing/unique_decorator_test.py +172 -0
  14. ragaai_catalyst/tracers/agentic_tracing/user_interaction_tracer.py +67 -0
  15. ragaai_catalyst/tracers/agentic_tracing/utils/__init__.py +3 -0
  16. ragaai_catalyst/tracers/agentic_tracing/utils/api_utils.py +18 -0
  17. ragaai_catalyst/tracers/agentic_tracing/utils/data_classes.py +61 -0
  18. ragaai_catalyst/tracers/agentic_tracing/utils/generic.py +32 -0
  19. ragaai_catalyst/tracers/agentic_tracing/utils/llm_utils.py +181 -0
  20. ragaai_catalyst/tracers/agentic_tracing/utils/model_costs.json +5946 -0
  21. ragaai_catalyst/tracers/agentic_tracing/utils/trace_utils.py +74 -0
  22. ragaai_catalyst/tracers/tracer.py +26 -4
  23. ragaai_catalyst/tracers/upload_traces.py +127 -0
  24. ragaai_catalyst-2.0.7.2b0.dist-info/METADATA +39 -0
  25. ragaai_catalyst-2.0.7.2b0.dist-info/RECORD +50 -0
  26. ragaai_catalyst-2.0.7.2.dist-info/METADATA +0 -386
  27. ragaai_catalyst-2.0.7.2.dist-info/RECORD +0 -29
  28. {ragaai_catalyst-2.0.7.2.dist-info → ragaai_catalyst-2.0.7.2b0.dist-info}/WHEEL +0 -0
  29. {ragaai_catalyst-2.0.7.2.dist-info → ragaai_catalyst-2.0.7.2b0.dist-info}/top_level.txt +0 -0
@@ -8,7 +8,6 @@ import pdb
8
8
 
9
9
  logger = logging.getLogger(__name__)
10
10
 
11
-
12
11
  class Evaluation:
13
12
 
14
13
  def __init__(self, project_name, dataset_name):
@@ -17,7 +16,7 @@ class Evaluation:
17
16
  self.base_url = f"{RagaAICatalyst.BASE_URL}"
18
17
  self.timeout = 10
19
18
  self.jobId = None
20
- self.num_projects = 99999
19
+ self.num_projects=99999
21
20
 
22
21
  try:
23
22
  response = requests.get(
@@ -35,11 +34,9 @@ class Evaluation:
35
34
  ]
36
35
  if project_name not in project_list:
37
36
  raise ValueError("Project not found. Please enter a valid project name")
38
-
37
+
39
38
  self.project_id = [
40
- project["id"]
41
- for project in response.json()["data"]["content"]
42
- if project["name"] == project_name
39
+ project["id"] for project in response.json()["data"]["content"] if project["name"] == project_name
43
40
  ][0]
44
41
 
45
42
  except requests.exceptions.RequestException as e:
@@ -49,55 +46,44 @@ class Evaluation:
49
46
  try:
50
47
 
51
48
  headers = {
52
- "Content-Type": "application/json",
49
+ 'Content-Type': 'application/json',
53
50
  "Authorization": f"Bearer {os.getenv('RAGAAI_CATALYST_TOKEN')}",
54
51
  "X-Project-Id": str(self.project_id),
55
52
  }
56
- json_data = {
57
- "size": 12,
58
- "page": "0",
59
- "projectId": str(self.project_id),
60
- "search": "",
61
- }
53
+ json_data = {"size": 12, "page": "0", "projectId": str(self.project_id), "search": ""}
62
54
  response = requests.post(
63
55
  f"{self.base_url}/v2/llm/dataset",
64
56
  headers=headers,
65
57
  json=json_data,
66
58
  timeout=self.timeout,
67
59
  )
68
-
60
+
69
61
  response.raise_for_status()
70
62
  datasets_content = response.json()["data"]["content"]
71
63
  dataset_list = [dataset["name"] for dataset in datasets_content]
72
64
 
73
65
  if dataset_name not in dataset_list:
74
66
  raise ValueError("Dataset not found. Please enter a valid dataset name")
75
-
76
- self.dataset_id = [
77
- dataset["id"]
78
- for dataset in datasets_content
79
- if dataset["name"] == dataset_name
80
- ][0]
67
+
68
+ self.dataset_id = [dataset["id"] for dataset in datasets_content if dataset["name"]==dataset_name][0]
81
69
 
82
70
  except requests.exceptions.RequestException as e:
83
71
  logger.error(f"Failed to retrieve dataset list: {e}")
84
72
  raise
85
73
 
74
+
86
75
  def list_metrics(self):
87
76
  headers = {
88
77
  "Authorization": f"Bearer {os.getenv('RAGAAI_CATALYST_TOKEN')}",
89
- "X-Project-Id": str(self.project_id),
78
+ 'X-Project-Id': str(self.project_id),
90
79
  }
91
80
  try:
92
81
  response = requests.get(
93
- f"{self.base_url}/v1/llm/llm-metrics",
82
+ f'{self.base_url}/v1/llm/llm-metrics',
94
83
  headers=headers,
95
- timeout=self.timeout,
96
- )
84
+ timeout=self.timeout)
97
85
  response.raise_for_status()
98
- metric_names = [
99
- metric["name"] for metric in response.json()["data"]["metrics"]
100
- ]
86
+ metric_names = [metric["name"] for metric in response.json()["data"]["metrics"]]
101
87
  return metric_names
102
88
  except requests.exceptions.HTTPError as http_err:
103
89
  logger.error(f"HTTP error occurred: {http_err}")
@@ -114,35 +100,22 @@ class Evaluation:
114
100
  def _get_dataset_id_based_on_dataset_type(self, metric_to_evaluate):
115
101
  try:
116
102
  headers = {
117
- "Content-Type": "application/json",
103
+ 'Content-Type': 'application/json',
118
104
  "Authorization": f"Bearer {os.getenv('RAGAAI_CATALYST_TOKEN')}",
119
105
  "X-Project-Id": str(self.project_id),
120
106
  }
121
- json_data = {
122
- "size": 12,
123
- "page": "0",
124
- "projectId": str(self.project_id),
125
- "search": "",
126
- }
107
+ json_data = {"size": 12, "page": "0", "projectId": str(self.project_id), "search": ""}
127
108
  response = requests.post(
128
109
  f"{self.base_url}/v2/llm/dataset",
129
110
  headers=headers,
130
111
  json=json_data,
131
112
  timeout=self.timeout,
132
113
  )
133
-
114
+
134
115
  response.raise_for_status()
135
116
  datasets_content = response.json()["data"]["content"]
136
- dataset = [
137
- dataset
138
- for dataset in datasets_content
139
- if dataset["name"] == self.dataset_name
140
- ][0]
141
- if (
142
- (dataset["datasetType"] == "prompt" and metric_to_evaluate == "prompt")
143
- or (dataset["datasetType"] == "chat" and metric_to_evaluate == "chat")
144
- or dataset["datasetType"] == None
145
- ):
117
+ dataset = [dataset for dataset in datasets_content if dataset["name"]==self.dataset_name][0]
118
+ if (dataset["datasetType"]=="prompt" and metric_to_evaluate=="prompt") or (dataset["datasetType"]=="chat" and metric_to_evaluate=="chat") or dataset["datasetType"]==None:
146
119
  return dataset["id"]
147
120
  else:
148
121
  return dataset["derivedDatasetId"]
@@ -150,24 +123,28 @@ class Evaluation:
150
123
  logger.error(f"Failed to retrieve dataset list: {e}")
151
124
  raise
152
125
 
126
+
153
127
  def _get_dataset_schema(self, metric_to_evaluate=None):
154
- # this dataset_id is based on which type of metric_to_evaluate
155
- data_set_id = self._get_dataset_id_based_on_dataset_type(metric_to_evaluate)
156
- self.dataset_id = data_set_id
128
+ #this dataset_id is based on which type of metric_to_evaluate
129
+ data_set_id=self._get_dataset_id_based_on_dataset_type(metric_to_evaluate)
130
+ self.dataset_id=data_set_id
157
131
 
158
132
  headers = {
159
133
  "Authorization": f"Bearer {os.getenv('RAGAAI_CATALYST_TOKEN')}",
160
- "Content-Type": "application/json",
161
- "X-Project-Id": str(self.project_id),
134
+ 'Content-Type': 'application/json',
135
+ 'X-Project-Id': str(self.project_id),
136
+ }
137
+ data = {
138
+ "datasetId": str(data_set_id),
139
+ "fields": [],
140
+ "rowFilterList": []
162
141
  }
163
- data = {"datasetId": str(data_set_id), "fields": [], "rowFilterList": []}
164
142
  try:
165
143
  response = requests.post(
166
- f"{self.base_url}/v1/llm/docs",
144
+ f'{self.base_url}/v1/llm/docs',
167
145
  headers=headers,
168
146
  json=data,
169
- timeout=self.timeout,
170
- )
147
+ timeout=self.timeout)
171
148
  response.raise_for_status()
172
149
  if response.status_code == 200:
173
150
  return response.json()["data"]["columns"]
@@ -183,35 +160,31 @@ class Evaluation:
183
160
  logger.error(f"An unexpected error occurred: {e}")
184
161
  return {}
185
162
 
186
- def _get_variablename_from_user_schema_mapping(
187
- self, schemaName, metric_name, schema_mapping, metric_to_evaluate
188
- ):
163
+
164
+ def _get_variablename_from_user_schema_mapping(self, schemaName, metric_name, schema_mapping, metric_to_evaluate):
189
165
  user_dataset_schema = self._get_dataset_schema(metric_to_evaluate)
190
166
  user_dataset_columns = [item["displayName"] for item in user_dataset_schema]
191
167
  variableName = None
192
168
  for key, val in schema_mapping.items():
193
- if "".join(val.split("_")).lower() == schemaName:
169
+ if "".join(val.split("_")).lower()==schemaName:
194
170
  if key in user_dataset_columns:
195
- variableName = key
171
+ variableName=key
196
172
  else:
197
- raise ValueError(
198
- f"Column '{key}' is not present in '{self.dataset_name}' dataset"
199
- )
173
+ raise ValueError(f"Column '{key}' is not present in '{self.dataset_name}' dataset")
200
174
  if variableName:
201
175
  return variableName
202
176
  else:
203
- raise ValueError(
204
- f"Map '{schemaName}' column in schema_mapping for {metric_name} metric evaluation"
205
- )
177
+ raise ValueError(f"Map '{schemaName}' column in schema_mapping for {metric_name} metric evaluation")
206
178
 
207
- def _get_mapping(self, metric_name, metrics_schema, schema_mapping):
208
179
 
180
+ def _get_mapping(self, metric_name, metrics_schema, schema_mapping):
181
+
209
182
  mapping = []
210
183
  for schema in metrics_schema:
211
- if schema["name"] == metric_name:
184
+ if schema["name"]==metric_name:
212
185
  requiredFields = schema["config"]["requiredFields"]
213
186
 
214
- # this is added to check if "Chat" column is required for metric evaluation
187
+ #this is added to check if "Chat" column is required for metric evaluation
215
188
  required_variables = [_["name"].lower() for _ in requiredFields]
216
189
  if "chat" in required_variables:
217
190
  metric_to_evaluate = "chat"
@@ -220,42 +193,38 @@ class Evaluation:
220
193
 
221
194
  for field in requiredFields:
222
195
  schemaName = field["name"]
223
- variableName = self._get_variablename_from_user_schema_mapping(
224
- schemaName.lower(),
225
- metric_name,
226
- schema_mapping,
227
- metric_to_evaluate,
228
- )
229
- mapping.append(
230
- {"schemaName": schemaName, "variableName": variableName}
231
- )
196
+ variableName = self._get_variablename_from_user_schema_mapping(schemaName.lower(), metric_name, schema_mapping, metric_to_evaluate)
197
+ mapping.append({"schemaName": schemaName, "variableName": variableName})
232
198
  return mapping
233
199
 
234
200
  def _get_metricParams(self):
235
201
  return {
236
- "metricSpec": {
237
- "name": "metric_to_evaluate",
238
- "config": {
239
- "model": "null",
240
- "params": {"model": {"value": ""}},
241
- "mappings": "mappings",
202
+ "metricSpec": {
203
+ "name": "metric_to_evaluate",
204
+ "config": {
205
+ "model": "null",
206
+ "params": {
207
+ "model": {
208
+ "value": ""
209
+ }
210
+ },
211
+ "mappings": "mappings"
212
+ },
213
+ "displayName": "displayName"
242
214
  },
243
- "displayName": "displayName",
244
- },
245
- "rowFilterList": [],
246
- }
247
-
215
+ "rowFilterList": []
216
+ }
217
+
248
218
  def _get_metrics_schema_response(self):
249
219
  headers = {
250
220
  "Authorization": f"Bearer {os.getenv('RAGAAI_CATALYST_TOKEN')}",
251
- "X-Project-Id": str(self.project_id),
221
+ 'X-Project-Id': str(self.project_id),
252
222
  }
253
223
  try:
254
224
  response = requests.get(
255
- f"{self.base_url}/v1/llm/llm-metrics",
225
+ f'{self.base_url}/v1/llm/llm-metrics',
256
226
  headers=headers,
257
- timeout=self.timeout,
258
- )
227
+ timeout=self.timeout)
259
228
  response.raise_for_status()
260
229
  metrics_schema = [metric for metric in response.json()["data"]["metrics"]]
261
230
  return metrics_schema
@@ -273,49 +242,42 @@ class Evaluation:
273
242
 
274
243
  def _update_base_json(self, metrics):
275
244
  metrics_schema_response = self._get_metrics_schema_response()
276
- sub_providers = ["openai", "azure", "gemini", "groq", "anthropic", "bedrock"]
245
+ sub_providers = ["openai","azure","gemini","groq","anthropic","bedrock"]
277
246
  metricParams = []
278
247
  for metric in metrics:
279
248
  base_json = self._get_metricParams()
280
249
  base_json["metricSpec"]["name"] = metric["name"]
281
-
282
- # pasing model configuration
250
+
251
+ #pasing model configuration
283
252
  for key, value in metric["config"].items():
284
- # checking if provider is one of the allowed providers
285
- if key.lower() == "provider" and value.lower() not in sub_providers:
286
- raise ValueError(
287
- "Enter a valid provider name. The following Provider names are supported: openai, azure, gemini, groq, anthropic, bedrock"
288
- )
289
-
290
- if key.lower() == "threshold":
291
- if len(value) > 1:
292
- raise ValueError(
293
- "'threshold' can only take one argument gte/lte/eq"
294
- )
253
+ #checking if provider is one of the allowed providers
254
+ if key.lower()=="provider" and value.lower() not in sub_providers:
255
+ raise ValueError("Enter a valid provider name. The following Provider names are supported: openai, azure, gemini, groq, anthropic, bedrock")
256
+
257
+ if key.lower()=="threshold":
258
+ if len(value)>1:
259
+ raise ValueError("'threshold' can only take one argument gte/lte/eq")
295
260
  else:
296
261
  for key_thres, value_thres in value.items():
297
- base_json["metricSpec"]["config"]["params"][key] = {
298
- f"{key_thres}": value_thres
299
- }
262
+ base_json["metricSpec"]["config"]["params"][key] = {f"{key_thres}":value_thres}
300
263
  else:
301
264
  base_json["metricSpec"]["config"]["params"][key] = {"value": value}
302
265
 
266
+
303
267
  # if metric["config"]["model"]:
304
268
  # base_json["metricSpec"]["config"]["params"]["model"]["value"] = metric["config"]["model"]
305
269
  base_json["metricSpec"]["displayName"] = metric["column_name"]
306
- mappings = self._get_mapping(
307
- metric["name"], metrics_schema_response, metric["schema_mapping"]
308
- )
270
+ mappings = self._get_mapping(metric["name"], metrics_schema_response, metric["schema_mapping"])
309
271
  base_json["metricSpec"]["config"]["mappings"] = mappings
310
272
  metricParams.append(base_json)
311
- metric_schema_mapping = {"datasetId": self.dataset_id}
273
+ metric_schema_mapping = {"datasetId":self.dataset_id}
312
274
  metric_schema_mapping["metricParams"] = metricParams
313
275
  return metric_schema_mapping
314
276
 
315
277
  def _get_executed_metrics_list(self):
316
278
  headers = {
317
279
  "Authorization": f"Bearer {os.getenv('RAGAAI_CATALYST_TOKEN')}",
318
- "X-Project-Id": str(self.project_id),
280
+ 'X-Project-Id': str(self.project_id),
319
281
  }
320
282
  try:
321
283
  response = requests.get(
@@ -326,9 +288,7 @@ class Evaluation:
326
288
  response.raise_for_status()
327
289
  dataset_columns = response.json()["data"]["datasetColumnsResponses"]
328
290
  dataset_columns = [item["displayName"] for item in dataset_columns]
329
- executed_metric_list = [
330
- data for data in dataset_columns if not data.startswith("_")
331
- ]
291
+ executed_metric_list = [data for data in dataset_columns if not data.startswith('_')]
332
292
 
333
293
  return executed_metric_list
334
294
  except requests.exceptions.HTTPError as http_err:
@@ -344,7 +304,7 @@ class Evaluation:
344
304
  return []
345
305
 
346
306
  def add_metrics(self, metrics):
347
- # Handle required key if missing
307
+ #Handle required key if missing
348
308
  required_keys = {"name", "config", "column_name", "schema_mapping"}
349
309
  for metric in metrics:
350
310
  missing_keys = required_keys - metric.keys()
@@ -363,18 +323,18 @@ class Evaluation:
363
323
  raise ValueError(f"Column name '{column_name}' already exists.")
364
324
 
365
325
  headers = {
366
- "Content-Type": "application/json",
326
+ 'Content-Type': 'application/json',
367
327
  "Authorization": f"Bearer {os.getenv('RAGAAI_CATALYST_TOKEN')}",
368
- "X-Project-Id": str(self.project_id),
328
+ 'X-Project-Id': str(self.project_id),
369
329
  }
370
330
  metric_schema_mapping = self._update_base_json(metrics)
371
331
  try:
372
332
  response = requests.post(
373
- f"{self.base_url}/playground/metric-evaluation",
374
- headers=headers,
333
+ f'{self.base_url}/playground/metric-evaluation',
334
+ headers=headers,
375
335
  json=metric_schema_mapping,
376
- timeout=self.timeout,
377
- )
336
+ timeout=self.timeout
337
+ )
378
338
  if response.status_code == 400:
379
339
  raise ValueError(response.json()["message"])
380
340
  response.raise_for_status()
@@ -395,31 +355,24 @@ class Evaluation:
395
355
 
396
356
  def get_status(self):
397
357
  headers = {
398
- "Content-Type": "application/json",
358
+ 'Content-Type': 'application/json',
399
359
  "Authorization": f"Bearer {os.getenv('RAGAAI_CATALYST_TOKEN')}",
400
- "X-Project-Id": str(self.project_id),
360
+ 'X-Project-Id': str(self.project_id),
401
361
  }
402
362
  try:
403
363
  response = requests.get(
404
- f"{self.base_url}/job/status", headers=headers, timeout=self.timeout
405
- )
364
+ f'{self.base_url}/job/status',
365
+ headers=headers,
366
+ timeout=self.timeout)
406
367
  response.raise_for_status()
407
368
  if response.json()["success"]:
408
- status_json = [
409
- item["status"]
410
- for item in response.json()["data"]["content"]
411
- if item["id"] == self.jobId
412
- ][0]
369
+ status_json = [item["status"] for item in response.json()["data"]["content"] if item["id"]==self.jobId][0]
413
370
  if status_json == "Failed":
414
371
  return print("Job failed. No results to fetch.")
415
372
  elif status_json == "In Progress":
416
- return print(
417
- f"Job in progress. Please wait while the job completes.\nVisit Job Status: {self.base_url.removesuffix('/api')}/projects/job-status?projectId={self.project_id} to track"
418
- )
373
+ return print(f"Job in progress. Please wait while the job completes.\nVisit Job Status: {self.base_url.removesuffix('/api')}/projects/job-status?projectId={self.project_id} to track")
419
374
  elif status_json == "Completed":
420
- print(
421
- f"Job completed. Fetching results.\nVisit Job Status: {self.base_url.removesuffix('/api')}/projects/job-status?projectId={self.project_id} to check"
422
- )
375
+ print(f"Job completed. Fetching results.\nVisit Job Status: {self.base_url.removesuffix('/api')}/projects/job-status?projectId={self.project_id} to check")
423
376
  except requests.exceptions.HTTPError as http_err:
424
377
  logger.error(f"HTTP error occurred: {http_err}")
425
378
  except requests.exceptions.ConnectionError as conn_err:
@@ -435,24 +388,25 @@ class Evaluation:
435
388
 
436
389
  def get_presignedUrl():
437
390
  headers = {
438
- "Content-Type": "application/json",
391
+ 'Content-Type': 'application/json',
439
392
  "Authorization": f"Bearer {os.getenv('RAGAAI_CATALYST_TOKEN')}",
440
- "X-Project-Id": str(self.project_id),
441
- }
442
-
393
+ 'X-Project-Id': str(self.project_id),
394
+ }
395
+
443
396
  data = {
444
- "fields": ["*"],
397
+ "fields": [
398
+ "*"
399
+ ],
445
400
  "datasetId": str(self.dataset_id),
446
401
  "rowFilterList": [],
447
- "export": True,
448
- }
449
- try:
402
+ "export": True
403
+ }
404
+ try:
450
405
  response = requests.post(
451
- f"{self.base_url}/v1/llm/docs",
452
- headers=headers,
406
+ f'{self.base_url}/v1/llm/docs',
407
+ headers=headers,
453
408
  json=data,
454
- timeout=self.timeout,
455
- )
409
+ timeout=self.timeout)
456
410
  response.raise_for_status()
457
411
  return response.json()
458
412
  except requests.exceptions.HTTPError as http_err:
@@ -491,8 +445,8 @@ class Evaluation:
491
445
  df = pd.read_csv(io.StringIO(response_text))
492
446
 
493
447
  column_list = df.columns.to_list()
494
- column_list = [col for col in column_list if not col.startswith("_")]
495
- column_list = [col for col in column_list if "." not in col]
448
+ column_list = [col for col in column_list if not col.startswith('_')]
449
+ column_list = [col for col in column_list if '.' not in col]
496
450
  return df[column_list]
497
451
  else:
498
452
  return pd.DataFrame()