ragaai-catalyst 2.2.1__py3-none-any.whl → 2.2.2__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.
@@ -1,15 +1,18 @@
1
- import os
2
1
  import logging
3
- import requests
4
- import time
2
+ import os
3
+ import re
5
4
  import threading
5
+ import time
6
6
  from typing import Dict, Optional, Union
7
- import re
7
+
8
+ import requests
9
+
8
10
  logger = logging.getLogger("RagaAICatalyst")
9
11
  logging_level = (
10
12
  logger.setLevel(logging.DEBUG) if os.getenv("DEBUG") == "1" else logging.INFO
11
13
  )
12
14
 
15
+
13
16
  class RagaAICatalyst:
14
17
  BASE_URL = None
15
18
  TIMEOUT = 10 # Default timeout in seconds
@@ -49,15 +52,15 @@ class RagaAICatalyst:
49
52
  "RAGAAI_CATALYST_ACCESS_KEY and RAGAAI_CATALYST_SECRET_KEY environment variables must be set"
50
53
  )
51
54
 
52
- self.access_key, self.secret_key = self._set_access_key_secret_key(
53
- access_key, secret_key
55
+ RagaAICatalyst.access_key, RagaAICatalyst.secret_key = (
56
+ self._set_access_key_secret_key(access_key, secret_key)
54
57
  )
55
58
 
56
59
  # Initialize token management
57
- self._token_expiry = None
58
- self._token_refresh_lock = threading.Lock()
59
- self._refresh_thread = None
60
-
60
+ RagaAICatalyst._token_expiry = None
61
+ RagaAICatalyst._token_refresh_lock = threading.Lock()
62
+ RagaAICatalyst._refresh_thread = None
63
+
61
64
  # Set token expiration time (convert hours to seconds)
62
65
  RagaAICatalyst.TOKEN_EXPIRY_TIME = token_expiry_time * 60 * 60
63
66
 
@@ -72,16 +75,16 @@ class RagaAICatalyst:
72
75
  if base_url:
73
76
  RagaAICatalyst.BASE_URL = self._normalize_base_url(base_url)
74
77
  try:
75
- #set the os.environ["RAGAAI_CATALYST_BASE_URL"] before getting the token as it is used in the get_token method
78
+ # set the os.environ["RAGAAI_CATALYST_BASE_URL"] before getting the token as it is used in the get_token method
76
79
  os.environ["RAGAAI_CATALYST_BASE_URL"] = RagaAICatalyst.BASE_URL
77
- self.get_token()
80
+ RagaAICatalyst.get_token(force_refresh=True)
78
81
  except requests.exceptions.RequestException:
79
82
  raise ConnectionError(
80
83
  "The provided base_url is not accessible. Please re-check the base_url."
81
84
  )
82
85
  else:
83
86
  # Get the token from the server
84
- self.get_token()
87
+ RagaAICatalyst.get_token(force_refresh=True)
85
88
 
86
89
  # Set the API keys, if available
87
90
  if self.api_keys:
@@ -89,9 +92,11 @@ class RagaAICatalyst:
89
92
 
90
93
  @staticmethod
91
94
  def _normalize_base_url(url):
92
- url = re.sub(r'(?<!:)//+', '/', url) # Ignore the `://` part of URLs and remove extra // if any
93
- url = url.rstrip("/") # To remove trailing slashes
94
- if not url.endswith("/api"): # To ensure it ends with /api
95
+ url = re.sub(
96
+ r"(?<!:)//+", "/", url
97
+ ) # Ignore the `://` part of URLs and remove extra // if any
98
+ url = url.rstrip("/") # To remove trailing slashes
99
+ if not url.endswith("/api"): # To ensure it ends with /api
95
100
  url = f"{url}/api"
96
101
  return url
97
102
 
@@ -141,7 +146,8 @@ class RagaAICatalyst:
141
146
  )
142
147
  elapsed_ms = (time.time() - start_time) * 1000
143
148
  logger.debug(
144
- f"API Call: [POST] {endpoint} | Status: {response.status_code} | Time: {elapsed_ms:.2f}ms")
149
+ f"API Call: [POST] {endpoint} | Status: {response.status_code} | Time: {elapsed_ms:.2f}ms"
150
+ )
145
151
  if response.status_code == 200:
146
152
  print("API keys uploaded successfully")
147
153
  else:
@@ -158,43 +164,58 @@ class RagaAICatalyst:
158
164
  # Token expiration time is now configurable via the token_expiry_time parameter
159
165
  # Default is 6 hours, but can be changed to 23 hours or any other value
160
166
 
161
- def _get_credentials(self) -> tuple[str, str]:
167
+ @staticmethod
168
+ def _get_credentials() -> tuple[str, str]:
162
169
  """Get access key and secret key from instance or environment."""
163
- access_key = self.access_key or os.getenv("RAGAAI_CATALYST_ACCESS_KEY")
164
- secret_key = self.secret_key or os.getenv("RAGAAI_CATALYST_SECRET_KEY")
170
+ access_key = RagaAICatalyst.access_key or os.getenv(
171
+ "RAGAAI_CATALYST_ACCESS_KEY"
172
+ )
173
+ secret_key = RagaAICatalyst.secret_key or os.getenv(
174
+ "RAGAAI_CATALYST_SECRET_KEY"
175
+ )
165
176
  return access_key, secret_key
166
177
 
167
- def _refresh_token_async(self):
178
+ @staticmethod
179
+ def _refresh_token_async():
168
180
  """Refresh token in background thread."""
169
181
  try:
170
- self.get_token(force_refresh=True)
182
+ RagaAICatalyst.get_token(force_refresh=True)
171
183
  except Exception as e:
172
184
  logger.error(f"Background token refresh failed: {str(e)}")
173
-
174
- def _schedule_token_refresh(self):
185
+
186
+ @staticmethod
187
+ def _schedule_token_refresh():
175
188
  """Schedule a token refresh to happen 20 seconds before expiration."""
176
- if not self._token_expiry:
189
+ if not RagaAICatalyst._token_expiry:
177
190
  return
178
-
191
+
179
192
  # Calculate when to refresh (20 seconds before expiration)
180
193
  current_time = time.time()
181
- refresh_buffer = min(20, RagaAICatalyst.TOKEN_EXPIRY_TIME * 0.05) # 20 seconds or 5% of expiry time, whichever is smaller
182
- time_until_refresh = max(self._token_expiry - current_time - refresh_buffer, 1) # At least 1 second
183
-
194
+ refresh_buffer = min(
195
+ 20, RagaAICatalyst.TOKEN_EXPIRY_TIME * 0.05
196
+ ) # 20 seconds or 5% of expiry time, whichever is smaller
197
+ time_until_refresh = max(
198
+ RagaAICatalyst._token_expiry - current_time - refresh_buffer, 1
199
+ ) # At least 1 second
200
+
184
201
  def delayed_refresh():
185
202
  # Sleep until it's time to refresh
186
203
  time.sleep(time_until_refresh)
187
- logger.debug(f"Scheduled token refresh triggered")
188
- self._refresh_token_async()
189
-
204
+ logger.debug("Scheduled token refresh triggered")
205
+ RagaAICatalyst._refresh_token_async()
206
+
190
207
  # Start a new thread for the delayed refresh
191
- if not self._refresh_thread or not self._refresh_thread.is_alive():
192
- self._refresh_thread = threading.Thread(target=delayed_refresh)
193
- self._refresh_thread.daemon = True
194
- self._refresh_thread.start()
208
+ if (
209
+ not RagaAICatalyst._refresh_thread
210
+ or not RagaAICatalyst._refresh_thread.is_alive()
211
+ ):
212
+ RagaAICatalyst._refresh_thread = threading.Thread(target=delayed_refresh)
213
+ RagaAICatalyst._refresh_thread.daemon = True
214
+ RagaAICatalyst._refresh_thread.start()
195
215
  logger.debug(f"Token refresh scheduled in {time_until_refresh:.1f} seconds")
196
216
 
197
- def get_token(self, force_refresh=False) -> Union[str, None]:
217
+ @staticmethod
218
+ def get_token(force_refresh=True) -> Union[str, None]:
198
219
  """
199
220
  Retrieves or refreshes a token using the provided credentials.
200
221
 
@@ -205,15 +226,20 @@ class RagaAICatalyst:
205
226
  - A string representing the token if successful.
206
227
  - None if credentials are not set or if there is an error.
207
228
  """
208
- with self._token_refresh_lock:
229
+ with RagaAICatalyst._token_refresh_lock:
209
230
  current_token = os.getenv("RAGAAI_CATALYST_TOKEN")
210
231
  current_time = time.time()
211
232
 
212
233
  # Check if we need to refresh the token
213
- if not force_refresh and current_token and self._token_expiry and current_time < self._token_expiry:
234
+ if (
235
+ not force_refresh
236
+ and current_token
237
+ and RagaAICatalyst._token_expiry
238
+ and current_time < RagaAICatalyst._token_expiry
239
+ ):
214
240
  return current_token
215
241
 
216
- access_key, secret_key = self._get_credentials()
242
+ access_key, secret_key = RagaAICatalyst._get_credentials()
217
243
  if not access_key or not secret_key:
218
244
  logger.error("Access key or secret key is not set")
219
245
  return None
@@ -222,16 +248,17 @@ class RagaAICatalyst:
222
248
  json_data = {"accessKey": access_key, "secretKey": secret_key}
223
249
 
224
250
  start_time = time.time()
225
- endpoint = f"{self.BASE_URL}/token"
251
+ endpoint = f"{RagaAICatalyst.BASE_URL}/token"
226
252
  response = requests.post(
227
253
  endpoint,
228
254
  headers=headers,
229
255
  json=json_data,
230
- timeout=self.TIMEOUT,
256
+ timeout=RagaAICatalyst.TIMEOUT,
231
257
  )
232
258
  elapsed_ms = (time.time() - start_time) * 1000
233
259
  logger.debug(
234
- f"API Call: [POST] {endpoint} | Status: {response.status_code} | Time: {elapsed_ms:.2f}ms")
260
+ f"API Call: [POST] {endpoint} | Status: {response.status_code} | Time: {elapsed_ms:.2f}ms"
261
+ )
235
262
 
236
263
  # Handle specific status codes before raising an error
237
264
  if response.status_code == 400:
@@ -254,12 +281,16 @@ class RagaAICatalyst:
254
281
  token = token_response.get("data", {}).get("token")
255
282
  if token:
256
283
  os.environ["RAGAAI_CATALYST_TOKEN"] = token
257
- self._token_expiry = time.time() + RagaAICatalyst.TOKEN_EXPIRY_TIME
258
- logger.debug(f"Token refreshed successfully. Next refresh in {RagaAICatalyst.TOKEN_EXPIRY_TIME/3600:.1f} hours")
259
-
284
+ RagaAICatalyst._token_expiry = (
285
+ time.time() + RagaAICatalyst.TOKEN_EXPIRY_TIME
286
+ )
287
+ logger.debug(
288
+ f"Token refreshed successfully. Next refresh in {RagaAICatalyst.TOKEN_EXPIRY_TIME / 3600:.1f} hours"
289
+ )
290
+
260
291
  # Schedule token refresh 20 seconds before expiration
261
- self._schedule_token_refresh()
262
-
292
+ RagaAICatalyst._schedule_token_refresh()
293
+
263
294
  return token
264
295
  else:
265
296
  logger.error("Token(s) not set")
@@ -286,14 +317,16 @@ class RagaAICatalyst:
286
317
  if not self._token_expiry or current_time >= self._token_expiry:
287
318
  logger.info("Token expired, refreshing synchronously")
288
319
  return self.get_token(force_refresh=True)
289
-
320
+
290
321
  # Case 3: Token valid but approaching expiry (less than 10% of lifetime remaining)
291
322
  # Start background refresh but return current token
292
323
  token_remaining_time = self._token_expiry - current_time
293
324
  if token_remaining_time < (RagaAICatalyst.TOKEN_EXPIRY_TIME * 0.1):
294
325
  if not self._refresh_thread or not self._refresh_thread.is_alive():
295
326
  logger.info("Token approaching expiry, starting background refresh")
296
- self._refresh_thread = threading.Thread(target=self._refresh_token_async)
327
+ self._refresh_thread = threading.Thread(
328
+ target=self._refresh_token_async
329
+ )
297
330
  self._refresh_thread.daemon = True
298
331
  self._refresh_thread.start()
299
332
 
@@ -319,14 +352,11 @@ class RagaAICatalyst:
319
352
  headers = self.get_auth_header()
320
353
  start_time = time.time()
321
354
  endpoint = f"{RagaAICatalyst.BASE_URL}/v2/llm/usecase"
322
- response = requests.get(
323
- endpoint,
324
- headers=headers,
325
- timeout=self.TIMEOUT
326
- )
355
+ response = requests.get(endpoint, headers=headers, timeout=self.TIMEOUT)
327
356
  elapsed_ms = (time.time() - start_time) * 1000
328
357
  logger.debug(
329
- f"API Call: [GET] {endpoint} | Status: {response.status_code} | Time: {elapsed_ms:.2f}ms")
358
+ f"API Call: [GET] {endpoint} | Status: {response.status_code} | Time: {elapsed_ms:.2f}ms"
359
+ )
330
360
  response.raise_for_status() # Use raise_for_status to handle HTTP errors
331
361
  usecase = response.json()["data"]["usecase"]
332
362
  return usecase
@@ -349,16 +379,18 @@ class RagaAICatalyst:
349
379
  # Check if the project already exists
350
380
  existing_projects = self.list_projects()
351
381
  if project_name in existing_projects:
352
- raise ValueError(f"Project name '{project_name}' already exists. Please choose a different name.")
382
+ raise ValueError(
383
+ f"Project name '{project_name}' already exists. Please choose a different name."
384
+ )
353
385
 
354
386
  usecase_list = self.project_use_cases()
355
387
  if usecase not in usecase_list:
356
388
  raise ValueError(f"Select a valid usecase from {usecase_list}")
357
-
389
+
358
390
  json_data = {"name": project_name, "type": type, "usecase": usecase}
359
391
  headers = {
360
392
  "Content-Type": "application/json",
361
- "Authorization": f'Bearer {os.getenv("RAGAAI_CATALYST_TOKEN")}',
393
+ "Authorization": f"Bearer {os.getenv('RAGAAI_CATALYST_TOKEN')}",
362
394
  }
363
395
  try:
364
396
  start_time = time.time()
@@ -371,19 +403,20 @@ class RagaAICatalyst:
371
403
  )
372
404
  elapsed_ms = (time.time() - start_time) * 1000
373
405
  logger.debug(
374
- f"API Call: [POST] {endpoint} | Status: {response.status_code} | Time: {elapsed_ms:.2f}ms")
406
+ f"API Call: [POST] {endpoint} | Status: {response.status_code} | Time: {elapsed_ms:.2f}ms"
407
+ )
375
408
  response.raise_for_status()
376
409
  print(
377
410
  f"Project Created Successfully with name {response.json()['data']['name']} & usecase {usecase}"
378
411
  )
379
- return f'Project Created Successfully with name {response.json()["data"]["name"]} & usecase {usecase}'
412
+ return f"Project Created Successfully with name {response.json()['data']['name']} & usecase {usecase}"
380
413
 
381
414
  except requests.exceptions.HTTPError as http_err:
382
415
  if response.status_code == 401:
383
416
  logger.warning("Received 401 error. Attempting to refresh token.")
384
- self.get_token()
417
+ RagaAICatalyst.get_token(force_refresh=True)
385
418
  headers["Authorization"] = (
386
- f'Bearer {os.getenv("RAGAAI_CATALYST_TOKEN")}'
419
+ f"Bearer {os.getenv('RAGAAI_CATALYST_TOKEN')}"
387
420
  )
388
421
  try:
389
422
  response = requests.post(
@@ -397,7 +430,7 @@ class RagaAICatalyst:
397
430
  "Project Created Successfully with name %s after token refresh",
398
431
  response.json()["data"]["name"],
399
432
  )
400
- return f'Project Created Successfully with name {response.json()["data"]["name"]}'
433
+ return f"Project Created Successfully with name {response.json()['data']['name']}"
401
434
  except requests.exceptions.HTTPError as refresh_http_err:
402
435
  logger.error(
403
436
  "Failed to create project after token refresh: %s",
@@ -432,7 +465,7 @@ class RagaAICatalyst:
432
465
  list: A list of project names retrieved successfully.
433
466
  """
434
467
  headers = {
435
- "Authorization": f'Bearer {os.getenv("RAGAAI_CATALYST_TOKEN")}',
468
+ "Authorization": f"Bearer {os.getenv('RAGAAI_CATALYST_TOKEN')}",
436
469
  }
437
470
  try:
438
471
  start_time = time.time()
@@ -444,7 +477,8 @@ class RagaAICatalyst:
444
477
  )
445
478
  elapsed_ms = (time.time() - start_time) * 1000
446
479
  logger.debug(
447
- f"API Call: [GET] {endpoint} | Status: {response.status_code} | Time: {elapsed_ms:.2f}ms")
480
+ f"API Call: [GET] {endpoint} | Status: {response.status_code} | Time: {elapsed_ms:.2f}ms"
481
+ )
448
482
  response.raise_for_status()
449
483
  logger.debug("Projects list retrieved successfully")
450
484
 
@@ -456,9 +490,9 @@ class RagaAICatalyst:
456
490
  except requests.exceptions.HTTPError as http_err:
457
491
  if response.status_code == 401:
458
492
  logger.warning("Received 401 error. Attempting to refresh token.")
459
- self.get_token()
493
+ RagaAICatalyst.get_token(force_refresh=True)
460
494
  headers["Authorization"] = (
461
- f'Bearer {os.getenv("RAGAAI_CATALYST_TOKEN")}'
495
+ f"Bearer {os.getenv('RAGAAI_CATALYST_TOKEN')}"
462
496
  )
463
497
  try:
464
498
  response = requests.get(
@@ -466,17 +500,19 @@ class RagaAICatalyst:
466
500
  headers=headers,
467
501
  timeout=self.TIMEOUT,
468
502
  )
469
- response.raise_for_status()
503
+ elapsed_ms = (time.time() - start_time) * 1000
470
504
  logger.debug(
471
- "Projects list retrieved successfully after token refresh"
505
+ f"API Call:[GET] {endpoint} | Status: {response.status_code} | Time: {elapsed_ms:.2f}ms"
472
506
  )
473
- project_df = pd.DataFrame(
474
- [
475
- {"project": project["name"]}
476
- for project in response.json()["data"]["content"]
477
- ]
478
- )
479
- return project_df
507
+ response.raise_for_status()
508
+ logger.debug("Projects list retrieved successfully")
509
+
510
+ project_list = [
511
+ project["name"]
512
+ for project in response.json()["data"]["content"]
513
+ ]
514
+
515
+ return project_list
480
516
 
481
517
  except requests.exceptions.HTTPError as refresh_http_err:
482
518
  logger.error(
@@ -505,7 +541,7 @@ class RagaAICatalyst:
505
541
  def list_metrics():
506
542
  headers = {
507
543
  "Content-Type": "application/json",
508
- "Authorization": f'Bearer {os.getenv("RAGAAI_CATALYST_TOKEN")}',
544
+ "Authorization": f"Bearer {os.getenv('RAGAAI_CATALYST_TOKEN')}",
509
545
  }
510
546
  try:
511
547
  start_time = time.time()
@@ -517,7 +553,8 @@ class RagaAICatalyst:
517
553
  )
518
554
  elapsed_ms = (time.time() - start_time) * 1000
519
555
  logger.debug(
520
- f"API Call: [GET] {endpoint} | Status: {response.status_code} | Time: {elapsed_ms:.2f}ms")
556
+ f"API Call: [GET] {endpoint} | Status: {response.status_code} | Time: {elapsed_ms:.2f}ms"
557
+ )
521
558
  response.raise_for_status()
522
559
  logger.debug("Metrics list retrieved successfully")
523
560
 
@@ -529,15 +566,15 @@ class RagaAICatalyst:
529
566
  except requests.exceptions.HTTPError as http_err:
530
567
  if response.status_code == 401:
531
568
  logger.warning("Received 401 error. Attempting to refresh token.")
532
- self.get_token()
569
+ RagaAICatalyst.get_token(force_refresh=True)
533
570
  headers["Authorization"] = (
534
- f'Bearer {os.getenv("RAGAAI_CATALYST_TOKEN")}'
571
+ f"Bearer {os.getenv('RAGAAI_CATALYST_TOKEN')}"
535
572
  )
536
573
  try:
537
574
  response = requests.get(
538
575
  f"{RagaAICatalyst.BASE_URL}/v1/llm/llm-metrics",
539
576
  headers=headers,
540
- timeout=self.TIMEOUT,
577
+ timeout=RagaAICatalyst.TIMEOUT,
541
578
  )
542
579
  response.raise_for_status()
543
580
  logger.debug(
@@ -2,23 +2,17 @@
2
2
  trace_uploader.py - A dedicated process for handling trace uploads
3
3
  """
4
4
 
5
- import os
6
- import sys
5
+ import argparse
6
+ import atexit
7
+ import concurrent.futures
7
8
  import json
8
- import time
9
- import signal
10
9
  import logging
11
- import argparse
10
+ import os
12
11
  import tempfile
13
- from pathlib import Path
14
- import multiprocessing
15
- import queue
12
+ import time
16
13
  from datetime import datetime
17
- import atexit
18
- import glob
19
14
  from logging.handlers import RotatingFileHandler
20
- import concurrent.futures
21
- from typing import Dict, Any, Optional
15
+ from typing import Any, Dict
22
16
 
23
17
  # Set up logging
24
18
  log_dir = os.path.join(tempfile.gettempdir(), "ragaai_logs")
@@ -43,11 +37,16 @@ logging.basicConfig(
43
37
  logger = logging.getLogger("trace_uploader")
44
38
 
45
39
  try:
46
- from ragaai_catalyst.tracers.agentic_tracing.upload.upload_agentic_traces import UploadAgenticTraces
40
+ from ragaai_catalyst import RagaAICatalyst
41
+ from ragaai_catalyst.tracers.agentic_tracing.upload.upload_agentic_traces import (
42
+ UploadAgenticTraces,
43
+ )
47
44
  from ragaai_catalyst.tracers.agentic_tracing.upload.upload_code import upload_code
45
+
48
46
  # from ragaai_catalyst.tracers.agentic_tracing.upload.upload_trace_metric import upload_trace_metric
49
- from ragaai_catalyst.tracers.agentic_tracing.utils.create_dataset_schema import create_dataset_schema_with_trace
50
- from ragaai_catalyst import RagaAICatalyst
47
+ from ragaai_catalyst.tracers.agentic_tracing.utils.create_dataset_schema import (
48
+ create_dataset_schema_with_trace,
49
+ )
51
50
  IMPORTS_AVAILABLE = True
52
51
  except ImportError:
53
52
  logger.warning("RagaAI Catalyst imports not available - running in test mode")