ragaai-catalyst 2.0.4__py3-none-any.whl → 2.0.6__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/__init__.py +3 -1
- ragaai_catalyst/dataset.py +50 -61
- ragaai_catalyst/evaluation.py +80 -47
- ragaai_catalyst/guard_executor.py +97 -0
- ragaai_catalyst/guardrails_manager.py +259 -0
- ragaai_catalyst/internal_api_completion.py +83 -0
- ragaai_catalyst/prompt_manager.py +1 -1
- ragaai_catalyst/proxy_call.py +1 -1
- ragaai_catalyst/ragaai_catalyst.py +1 -1
- ragaai_catalyst/synthetic_data_generation.py +206 -77
- ragaai_catalyst/tracers/llamaindex_callback.py +361 -0
- ragaai_catalyst/tracers/tracer.py +62 -28
- ragaai_catalyst-2.0.6.dist-info/METADATA +386 -0
- ragaai_catalyst-2.0.6.dist-info/RECORD +29 -0
- {ragaai_catalyst-2.0.4.dist-info → ragaai_catalyst-2.0.6.dist-info}/WHEEL +1 -1
- ragaai_catalyst-2.0.4.dist-info/METADATA +0 -228
- ragaai_catalyst-2.0.4.dist-info/RECORD +0 -25
- {ragaai_catalyst-2.0.4.dist-info → ragaai_catalyst-2.0.6.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,259 @@
|
|
1
|
+
import requests
|
2
|
+
import json
|
3
|
+
import os
|
4
|
+
from .ragaai_catalyst import RagaAICatalyst
|
5
|
+
|
6
|
+
|
7
|
+
class GuardrailsManager:
|
8
|
+
def __init__(self, project_name):
|
9
|
+
"""
|
10
|
+
Initialize the GuardrailsManager with the given project name.
|
11
|
+
|
12
|
+
:param project_name: The name of the project to manage guardrails for.
|
13
|
+
"""
|
14
|
+
self.project_name = project_name
|
15
|
+
self.timeout = 10
|
16
|
+
self.num_projects = 99999
|
17
|
+
self.deployment_name = "NA"
|
18
|
+
self.deployment_id = "NA"
|
19
|
+
self.base_url = f"{RagaAICatalyst.BASE_URL}"
|
20
|
+
list_projects, project_name_with_id = self._get_project_list()
|
21
|
+
if project_name not in list_projects:
|
22
|
+
raise ValueError(f"Project '{self.project_name}' does not exists")
|
23
|
+
|
24
|
+
self.project_id = [_["id"] for _ in project_name_with_id if _["name"]==self.project_name][0]
|
25
|
+
|
26
|
+
|
27
|
+
def _get_project_list(self):
|
28
|
+
"""
|
29
|
+
Retrieve the list of projects and their IDs from the API.
|
30
|
+
|
31
|
+
:return: A tuple containing a list of project names and a list of dictionaries with project IDs and names.
|
32
|
+
"""
|
33
|
+
headers = {'Authorization': f'Bearer {os.getenv("RAGAAI_CATALYST_TOKEN")}'}
|
34
|
+
response = requests.request("GET", f"{self.base_url}/v2/llm/projects?size={self.num_projects}", headers=headers, timeout=self.timeout)
|
35
|
+
project_content = response.json()["data"]["content"]
|
36
|
+
list_project = [_["name"] for _ in project_content]
|
37
|
+
project_name_with_id = [{"id": _["id"], "name": _["name"]} for _ in project_content]
|
38
|
+
return list_project, project_name_with_id
|
39
|
+
|
40
|
+
|
41
|
+
def list_deployment_ids(self):
|
42
|
+
"""
|
43
|
+
List all deployment IDs and their names for the current project.
|
44
|
+
|
45
|
+
:return: A list of dictionaries containing deployment IDs and names.
|
46
|
+
"""
|
47
|
+
payload = {}
|
48
|
+
headers = {
|
49
|
+
'Authorization': f'Bearer {os.getenv("RAGAAI_CATALYST_TOKEN")}',
|
50
|
+
'X-Project-Id': str(self.project_id)
|
51
|
+
}
|
52
|
+
response = requests.request("GET", f"{self.base_url}/guardrail/deployment?size={self.num_projects}&page=0&sort=lastUsedAt,desc", headers=headers, data=payload, timeout=self.timeout)
|
53
|
+
deployment_ids_content = response.json()["data"]["content"]
|
54
|
+
deployment_ids_content = [{"id": _["id"], "name": _["name"]} for _ in deployment_ids_content]
|
55
|
+
return deployment_ids_content
|
56
|
+
|
57
|
+
|
58
|
+
def get_deployment(self, deployment_id):
|
59
|
+
"""
|
60
|
+
Get details of a specific deployment ID, including its name and guardrails.
|
61
|
+
|
62
|
+
:param deployment_id: The ID of the deployment to retrieve details for.
|
63
|
+
:return: A dictionary containing the deployment name and a list of guardrails.
|
64
|
+
"""
|
65
|
+
payload = {}
|
66
|
+
headers = {
|
67
|
+
'Authorization': f'Bearer {os.getenv("RAGAAI_CATALYST_TOKEN")}',
|
68
|
+
'X-Project-Id': str(self.project_id)
|
69
|
+
}
|
70
|
+
response = requests.request("GET", f"{self.base_url}/guardrail/deployment/{deployment_id}", headers=headers, data=payload, timeout=self.timeout)
|
71
|
+
if response.json()['success']:
|
72
|
+
return response.json()
|
73
|
+
else:
|
74
|
+
print('Error in retrieving deployment details:',response.json()['message'])
|
75
|
+
return None
|
76
|
+
|
77
|
+
|
78
|
+
def list_guardrails(self):
|
79
|
+
"""
|
80
|
+
List all available guardrails for the current project.
|
81
|
+
|
82
|
+
:return: A list of guardrail names.
|
83
|
+
"""
|
84
|
+
payload = {}
|
85
|
+
headers = {
|
86
|
+
'Authorization': f'Bearer {os.getenv("RAGAAI_CATALYST_TOKEN")}',
|
87
|
+
'X-Project-Id': str(self.project_id)
|
88
|
+
}
|
89
|
+
response = requests.request("GET", f"{self.base_url}/v1/llm/llm-metrics?category=Guardrail", headers=headers, data=payload, timeout=self.timeout)
|
90
|
+
list_guardrails_content = response.json()["data"]["metrics"]
|
91
|
+
list_guardrails = [_["name"] for _ in list_guardrails_content]
|
92
|
+
return list_guardrails
|
93
|
+
|
94
|
+
|
95
|
+
def list_fail_condition(self):
|
96
|
+
"""
|
97
|
+
List all fail conditions for the current project's deployments.
|
98
|
+
|
99
|
+
:return: A list of fail conditions.
|
100
|
+
"""
|
101
|
+
payload = {}
|
102
|
+
headers = {
|
103
|
+
'Authorization': f'Bearer {os.getenv("RAGAAI_CATALYST_TOKEN")}',
|
104
|
+
'X-Project-Id': str(self.project_id)
|
105
|
+
}
|
106
|
+
response = requests.request("GET", f"{self.base_url}/guardrail/deployment/configurations", headers=headers, data=payload, timeout=self.timeout)
|
107
|
+
return response.json()["data"]
|
108
|
+
|
109
|
+
|
110
|
+
def create_deployment(self, deployment_name):
|
111
|
+
"""
|
112
|
+
Create a new deployment ID with the given name.
|
113
|
+
|
114
|
+
:param deployment_name: The name of the new deployment.
|
115
|
+
:raises ValueError: If a deployment with the given name already exists.
|
116
|
+
"""
|
117
|
+
self.deployment_name = deployment_name
|
118
|
+
list_deployment_ids = self.list_deployment_ids()
|
119
|
+
list_deployment_names = [_["name"] for _ in list_deployment_ids]
|
120
|
+
if deployment_name in list_deployment_names:
|
121
|
+
raise ValueError(f"Deployment with '{deployment_name}' already exists, choose a unique name")
|
122
|
+
|
123
|
+
payload = json.dumps({"name": str(deployment_name)})
|
124
|
+
headers = {
|
125
|
+
'Authorization': f'Bearer {os.getenv("RAGAAI_CATALYST_TOKEN")}',
|
126
|
+
'Content-Type': 'application/json',
|
127
|
+
'X-Project-Id': str(self.project_id)
|
128
|
+
}
|
129
|
+
response = requests.request("POST", f"{self.base_url}/guardrail/deployment", headers=headers, data=payload, timeout=self.timeout)
|
130
|
+
if response.status_code == 409:
|
131
|
+
raise ValueError(f"Data with '{deployment_name}' already exists, choose a unique name")
|
132
|
+
if response.json()["success"]:
|
133
|
+
print(response.json()["message"])
|
134
|
+
deployment_ids = self.list_deployment_ids()
|
135
|
+
self.deployment_id = [_["id"] for _ in deployment_ids if _["name"]==self.deployment_name][0]
|
136
|
+
return self.deployment_id
|
137
|
+
else:
|
138
|
+
print(response)
|
139
|
+
|
140
|
+
|
141
|
+
def add_guardrails(self, deployment_id, guardrails, guardrails_config={}):
|
142
|
+
"""
|
143
|
+
Add guardrails to the current deployment.
|
144
|
+
|
145
|
+
:param guardrails: A list of guardrails to add.
|
146
|
+
:param guardrails_config: Configuration settings for the guardrails.
|
147
|
+
:raises ValueError: If a guardrail name or type is invalid.
|
148
|
+
"""
|
149
|
+
# Checking if guardrails names given already exist or not
|
150
|
+
self.deployment_id = deployment_id
|
151
|
+
deployment_details = self.get_deployment(self.deployment_id)
|
152
|
+
if not deployment_details:
|
153
|
+
return None
|
154
|
+
deployment_id_name = deployment_details["data"]["name"]
|
155
|
+
deployment_id_guardrails = deployment_details["data"]["guardrailsResponse"]
|
156
|
+
guardrails_type_name_exists = [{_['metricSpec']["name"]:_['metricSpec']["displayName"]} for _ in deployment_id_guardrails]
|
157
|
+
guardrails_type_name_exists = [list(d.values())[0] for d in guardrails_type_name_exists]
|
158
|
+
user_guardrails_name_list = [_["name"] for _ in guardrails]
|
159
|
+
for g_name in user_guardrails_name_list:
|
160
|
+
if g_name in guardrails_type_name_exists:
|
161
|
+
raise ValueError(f"Guardrail with '{g_name} already exists, choose a unique name'")
|
162
|
+
# Checking if guardrails type is correct or not
|
163
|
+
available_guardrails_list = self.list_guardrails()
|
164
|
+
user_guardrails_type_list = [_["name"] for _ in guardrails]
|
165
|
+
for g_type in user_guardrails_type_list:
|
166
|
+
if g_type not in available_guardrails_list:
|
167
|
+
raise ValueError(f"Guardrail type '{g_type} does not exists, choose a correct type'")
|
168
|
+
|
169
|
+
payload = self._get_guardrail_config_payload(guardrails_config)
|
170
|
+
payload["guardrails"] = self._get_guardrail_list_payload(guardrails)
|
171
|
+
payload = json.dumps(payload)
|
172
|
+
headers = {
|
173
|
+
'Authorization': f'Bearer {os.getenv("RAGAAI_CATALYST_TOKEN")}',
|
174
|
+
'Content-Type': 'application/json',
|
175
|
+
'X-Project-Id': str(self.project_id)
|
176
|
+
}
|
177
|
+
response = requests.request("POST", f"{self.base_url}/guardrail/deployment/{str(self.deployment_id)}/configure", headers=headers, data=payload)
|
178
|
+
if response.json()["success"]:
|
179
|
+
print(response.json()["message"])
|
180
|
+
else:
|
181
|
+
print('Error updating guardrail ',response.json()['message'])
|
182
|
+
|
183
|
+
def _get_guardrail_config_payload(self, guardrails_config):
|
184
|
+
"""
|
185
|
+
Construct the payload for guardrail configuration.
|
186
|
+
|
187
|
+
:param guardrails_config: Configuration settings for the guardrails.
|
188
|
+
:return: A dictionary representing the guardrail configuration payload.
|
189
|
+
"""
|
190
|
+
data = {
|
191
|
+
"isActive": guardrails_config.get("isActive",False),
|
192
|
+
"guardrailFailConditions": guardrails_config.get("guardrailFailConditions",["FAIL"]),
|
193
|
+
"deploymentFailCondition": guardrails_config.get("deploymentFailCondition","ONE_FAIL"),
|
194
|
+
"failAction": {
|
195
|
+
"action": "ALTERNATE_RESPONSE",
|
196
|
+
"args": f'{{\"alternateResponse\": \"{guardrails_config.get("alternateResponse","This is the Alternate Response")}\"}}'
|
197
|
+
},
|
198
|
+
"guardrails" : []
|
199
|
+
}
|
200
|
+
return data
|
201
|
+
|
202
|
+
def _get_guardrail_list_payload(self, guardrails):
|
203
|
+
"""
|
204
|
+
Construct the payload for a list of guardrails.
|
205
|
+
|
206
|
+
:param guardrails: A list of guardrails to include in the payload.
|
207
|
+
:return: A list of dictionaries representing each guardrail's data.
|
208
|
+
"""
|
209
|
+
guardrails_list_payload = []
|
210
|
+
for guardrail in guardrails:
|
211
|
+
guardrails_list_payload.append(self._get_one_guardrail_data(guardrail))
|
212
|
+
return guardrails_list_payload
|
213
|
+
|
214
|
+
def _get_one_guardrail_data(self, guardrail):
|
215
|
+
"""
|
216
|
+
Construct the data for a single guardrail.
|
217
|
+
|
218
|
+
:param guardrail: A dictionary containing the guardrail's attributes.
|
219
|
+
:return: A dictionary representing the guardrail's data.
|
220
|
+
"""
|
221
|
+
if 'config' in guardrail:
|
222
|
+
if 'mappings' in guardrail.get('config'):
|
223
|
+
for mapping in guardrail.get('config',{}).get('mappings',{}):
|
224
|
+
if mapping['schemaName'] not in ['Text','Prompt','Context','Response']:
|
225
|
+
raise(ValueError('Invalid schemaName in guardrail mapping schema'))
|
226
|
+
if mapping['variableName'] not in ['Instruction','Prompt','Context','Response']:
|
227
|
+
raise(ValueError('Invalid variableName in guardrail mapping schema'))
|
228
|
+
if 'model' in guardrail.get('config'):
|
229
|
+
if guardrail.get('config',{}).get('model','') not in ['gpt-4o-mini','gpt-4o','gpt-4-turbo']:
|
230
|
+
raise(ValueError('Invalid model name in guardrail model schema'))
|
231
|
+
if 'params' not in guardrail.get('config'):
|
232
|
+
guardrail['config']['params'] = {
|
233
|
+
"isActive": {"value": False},
|
234
|
+
"isHighRisk": {"value": False},
|
235
|
+
"threshold": {"lt": 1}
|
236
|
+
}
|
237
|
+
|
238
|
+
|
239
|
+
data = {
|
240
|
+
"displayName": guardrail["displayName"],
|
241
|
+
"name": guardrail["name"],
|
242
|
+
"config": guardrail.get("config", {})
|
243
|
+
}
|
244
|
+
'''
|
245
|
+
if "lte" in guardrail["threshold"]:
|
246
|
+
data["threshold"]["lte"] = guardrail["threshold"]["lte"]
|
247
|
+
elif "gte" in guardrail["threshold"]:
|
248
|
+
data["threshold"]["gte"] = guardrail["threshold"]["gte"]
|
249
|
+
elif "eq" in guardrail["threshold"]:
|
250
|
+
data["threshold"]["eq"] = guardrail["threshold"]["eq"]
|
251
|
+
else:
|
252
|
+
data["threshold"]["gte"] = 0.0'''
|
253
|
+
return data
|
254
|
+
|
255
|
+
|
256
|
+
def _run(self, **kwargs):
|
257
|
+
"""
|
258
|
+
Execute the guardrail checks with the provided variables.
|
259
|
+
"""
|
@@ -0,0 +1,83 @@
|
|
1
|
+
import requests
|
2
|
+
import json
|
3
|
+
import subprocess
|
4
|
+
import logging
|
5
|
+
import traceback
|
6
|
+
import pandas as pd
|
7
|
+
|
8
|
+
logger = logging.getLogger(__name__)
|
9
|
+
|
10
|
+
def api_completion(messages, model_config, kwargs):
|
11
|
+
attempts = 0
|
12
|
+
while attempts < 3:
|
13
|
+
|
14
|
+
user_id = kwargs.get('user_id', '1')
|
15
|
+
internal_llm_proxy = kwargs.get('internal_llm_proxy', -1)
|
16
|
+
|
17
|
+
|
18
|
+
job_id = model_config.get('job_id',-1)
|
19
|
+
converted_message = convert_input(messages,model_config, user_id)
|
20
|
+
payload = json.dumps(converted_message)
|
21
|
+
headers = {
|
22
|
+
'Content-Type': 'application/json',
|
23
|
+
# 'Wd-PCA-Feature-Key':f'your_feature_key, $(whoami)'
|
24
|
+
}
|
25
|
+
try:
|
26
|
+
response = requests.request("POST", internal_llm_proxy, headers=headers, data=payload)
|
27
|
+
if model_config.get('log_level','')=='debug':
|
28
|
+
logger.info(f'Model response Job ID {job_id} {response.text}')
|
29
|
+
if response.status_code!=200:
|
30
|
+
# logger.error(f'Error in model response Job ID {job_id}:',str(response.text))
|
31
|
+
raise ValueError(str(response.text))
|
32
|
+
|
33
|
+
if response.status_code==200:
|
34
|
+
response = response.json()
|
35
|
+
if "error" in response:
|
36
|
+
raise ValueError(response["error"]["message"])
|
37
|
+
else:
|
38
|
+
result= response["choices"][0]["message"]["content"]
|
39
|
+
response1 = result.replace('\n', '')
|
40
|
+
try:
|
41
|
+
json_data = json.loads(response1)
|
42
|
+
df = pd.DataFrame(json_data)
|
43
|
+
return(df)
|
44
|
+
except json.JSONDecodeError:
|
45
|
+
attempts += 1 # Increment attempts if JSON parsing fails
|
46
|
+
if attempts == 3:
|
47
|
+
raise Exception("Failed to generate a valid response after multiple attempts.")
|
48
|
+
|
49
|
+
except Exception as e:
|
50
|
+
raise ValueError(f"{e}")
|
51
|
+
|
52
|
+
|
53
|
+
def get_username():
|
54
|
+
result = subprocess.run(['whoami'], capture_output=True, text=True)
|
55
|
+
result = result.stdout
|
56
|
+
return result
|
57
|
+
|
58
|
+
|
59
|
+
def convert_input(messages, model_config, user_id):
|
60
|
+
doc_input = {
|
61
|
+
"model": model_config.get('model'),
|
62
|
+
**model_config,
|
63
|
+
"messages": messages,
|
64
|
+
"user_id": user_id
|
65
|
+
}
|
66
|
+
return doc_input
|
67
|
+
|
68
|
+
|
69
|
+
if __name__=='__main__':
|
70
|
+
messages = [
|
71
|
+
{
|
72
|
+
"role": "system",
|
73
|
+
"content": "you are a poet well versed in shakespeare literature"
|
74
|
+
},
|
75
|
+
{
|
76
|
+
"role": "user",
|
77
|
+
"content": "write a poem on pirates and penguins"
|
78
|
+
}
|
79
|
+
]
|
80
|
+
kwargs = {"internal_llm_proxy": "http://13.200.11.66:4000/chat/completions", "user_id": 1}
|
81
|
+
model_config = {"model": "workday_gateway", "provider":"openai", "max_tokens": 10}
|
82
|
+
answer = api_completion(messages, model_config, kwargs)
|
83
|
+
print(answer)
|
@@ -23,7 +23,7 @@ class PromptManager:
|
|
23
23
|
self.project_name = project_name
|
24
24
|
self.base_url = f"{RagaAICatalyst.BASE_URL}/playground/prompt"
|
25
25
|
self.timeout = 10
|
26
|
-
self.size =
|
26
|
+
self.size = 99999 #Number of projects to fetch
|
27
27
|
|
28
28
|
try:
|
29
29
|
response = requests.get(
|
ragaai_catalyst/proxy_call.py
CHANGED
@@ -23,7 +23,7 @@ def api_completion(model,messages, api_base='http://127.0.0.1:8000',
|
|
23
23
|
if model_config.get('log_level','')=='debug':
|
24
24
|
logger.info(f'Model response Job ID {job_id} {response.text}')
|
25
25
|
if response.status_code!=200:
|
26
|
-
logger.error(f'Error in model response Job ID {job_id}:',str(response.text))
|
26
|
+
# logger.error(f'Error in model response Job ID {job_id}:',str(response.text))
|
27
27
|
raise ValueError(str(response.text))
|
28
28
|
except Exception as e:
|
29
29
|
logger.error(f'Error in calling api Job ID {job_id}:',str(e))
|
@@ -287,7 +287,7 @@ class RagaAICatalyst:
|
|
287
287
|
def get_project_id(self, project_name):
|
288
288
|
pass
|
289
289
|
|
290
|
-
def list_projects(self, num_projects=
|
290
|
+
def list_projects(self, num_projects=99999):
|
291
291
|
"""
|
292
292
|
Retrieves a list of projects with the specified number of projects.
|
293
293
|
|