lexsi-sdk 0.1.16__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.
- lexsi_sdk/__init__.py +5 -0
- lexsi_sdk/client/__init__.py +0 -0
- lexsi_sdk/client/client.py +176 -0
- lexsi_sdk/common/__init__.py +0 -0
- lexsi_sdk/common/config/.env.prod +3 -0
- lexsi_sdk/common/constants.py +143 -0
- lexsi_sdk/common/enums.py +8 -0
- lexsi_sdk/common/environment.py +49 -0
- lexsi_sdk/common/monitoring.py +81 -0
- lexsi_sdk/common/trigger.py +75 -0
- lexsi_sdk/common/types.py +122 -0
- lexsi_sdk/common/utils.py +93 -0
- lexsi_sdk/common/validation.py +110 -0
- lexsi_sdk/common/xai_uris.py +197 -0
- lexsi_sdk/core/__init__.py +0 -0
- lexsi_sdk/core/agent.py +62 -0
- lexsi_sdk/core/alert.py +56 -0
- lexsi_sdk/core/case.py +618 -0
- lexsi_sdk/core/dashboard.py +131 -0
- lexsi_sdk/core/guardrails/__init__.py +0 -0
- lexsi_sdk/core/guardrails/guard_template.py +299 -0
- lexsi_sdk/core/guardrails/guardrail_autogen.py +554 -0
- lexsi_sdk/core/guardrails/guardrails_langgraph.py +525 -0
- lexsi_sdk/core/guardrails/guardrails_openai.py +541 -0
- lexsi_sdk/core/guardrails/openai_runner.py +1328 -0
- lexsi_sdk/core/model_summary.py +110 -0
- lexsi_sdk/core/organization.py +549 -0
- lexsi_sdk/core/project.py +5131 -0
- lexsi_sdk/core/synthetic.py +387 -0
- lexsi_sdk/core/text.py +595 -0
- lexsi_sdk/core/tracer.py +208 -0
- lexsi_sdk/core/utils.py +36 -0
- lexsi_sdk/core/workspace.py +325 -0
- lexsi_sdk/core/wrapper.py +766 -0
- lexsi_sdk/core/xai.py +306 -0
- lexsi_sdk/version.py +34 -0
- lexsi_sdk-0.1.16.dist-info/METADATA +100 -0
- lexsi_sdk-0.1.16.dist-info/RECORD +40 -0
- lexsi_sdk-0.1.16.dist-info/WHEEL +5 -0
- lexsi_sdk-0.1.16.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
import os
|
|
3
|
+
from typing import Any
|
|
4
|
+
from pydantic import BaseModel
|
|
5
|
+
import json
|
|
6
|
+
from IPython.display import IFrame, display, HTML
|
|
7
|
+
from lexsi_sdk.common.xai_uris import XAI_APP_URI
|
|
8
|
+
|
|
9
|
+
DASHBOARD_TYPES = [
|
|
10
|
+
"data_drift",
|
|
11
|
+
"target_drift",
|
|
12
|
+
"performance",
|
|
13
|
+
"biasmonitoring",
|
|
14
|
+
"image_property_drift",
|
|
15
|
+
"label_drift",
|
|
16
|
+
"property_label_correlation",
|
|
17
|
+
"image_dataset_drift",
|
|
18
|
+
]
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class Dashboard(BaseModel):
|
|
22
|
+
"""Client-side wrapper for visualizing generated dashboards."""
|
|
23
|
+
config: dict
|
|
24
|
+
query_params: str
|
|
25
|
+
raw_data: dict | list | str
|
|
26
|
+
|
|
27
|
+
def __init__(self, **kwargs):
|
|
28
|
+
"""Print configuration then render the dashboard frame."""
|
|
29
|
+
super().__init__(**kwargs)
|
|
30
|
+
|
|
31
|
+
self.print_config()
|
|
32
|
+
self.plot()
|
|
33
|
+
|
|
34
|
+
def plot(self, width: int = "100%", height: int = 800):
|
|
35
|
+
"""plot the dashboard by remote url
|
|
36
|
+
|
|
37
|
+
:param width: Width of the embedded frame.
|
|
38
|
+
:param height: Height of the embedded frame.
|
|
39
|
+
"""
|
|
40
|
+
if isinstance(self.raw_data, str) and "</html>" in self.raw_data:
|
|
41
|
+
display(HTML(self.raw_data))
|
|
42
|
+
else:
|
|
43
|
+
uri = os.environ.get("XAI_APP_URL", XAI_APP_URI)
|
|
44
|
+
url = f"{uri}/sdk/dashboard{self.query_params}"
|
|
45
|
+
display(IFrame(src=f"{url}", width=width, height=height))
|
|
46
|
+
|
|
47
|
+
def get_config(self) -> dict:
|
|
48
|
+
"""
|
|
49
|
+
get the dashboard config
|
|
50
|
+
"""
|
|
51
|
+
config_copy = {**self.config}
|
|
52
|
+
config_copy.pop("metadata", None)
|
|
53
|
+
return config_copy
|
|
54
|
+
|
|
55
|
+
def get_raw_data(self) -> dict:
|
|
56
|
+
"""
|
|
57
|
+
get the dashboard raw data
|
|
58
|
+
"""
|
|
59
|
+
raw_data = {"created_at": self.config.get("created_at")}
|
|
60
|
+
|
|
61
|
+
if self.config["type"] == "data_drift":
|
|
62
|
+
data_drift_table = next(
|
|
63
|
+
filter(
|
|
64
|
+
lambda data: data["metric"] == "DataDriftTable",
|
|
65
|
+
self.raw_data.get("metrics"),
|
|
66
|
+
),
|
|
67
|
+
None,
|
|
68
|
+
)
|
|
69
|
+
if data_drift_table:
|
|
70
|
+
for item in data_drift_table["result"].get("drift_by_columns"):
|
|
71
|
+
item.pop("current_small_distribution", None)
|
|
72
|
+
item.pop("reference_small_distribution", None)
|
|
73
|
+
item.pop("current_big_distribution", None)
|
|
74
|
+
item.pop("reference_big_distribution", None)
|
|
75
|
+
item.pop("current_mean", None)
|
|
76
|
+
item.pop("reference_std", None)
|
|
77
|
+
raw_data.update(data_drift_table["result"])
|
|
78
|
+
|
|
79
|
+
if self.config["type"] == "target_drift":
|
|
80
|
+
column_drift_metric = next(
|
|
81
|
+
filter(
|
|
82
|
+
lambda data: data["metric"] == "ColumnDriftMetric",
|
|
83
|
+
self.raw_data.get("metrics"),
|
|
84
|
+
),
|
|
85
|
+
None,
|
|
86
|
+
)
|
|
87
|
+
if column_drift_metric:
|
|
88
|
+
column_drift_metric["result"].pop("data", None)
|
|
89
|
+
|
|
90
|
+
raw_data.update(column_drift_metric["result"])
|
|
91
|
+
|
|
92
|
+
if self.config["type"] == "performance":
|
|
93
|
+
classification_quality_metric = next(
|
|
94
|
+
filter(
|
|
95
|
+
lambda data: data["metric"] == "ClassificationQualityMetric",
|
|
96
|
+
self.raw_data.get("metrics"),
|
|
97
|
+
),
|
|
98
|
+
None,
|
|
99
|
+
)
|
|
100
|
+
if classification_quality_metric:
|
|
101
|
+
for curr_ref in ["current", "reference"]:
|
|
102
|
+
classification_quality_metric["result"][curr_ref].pop(
|
|
103
|
+
"rate_plots_data", None
|
|
104
|
+
)
|
|
105
|
+
classification_quality_metric["result"][curr_ref].pop(
|
|
106
|
+
"plot_data", None
|
|
107
|
+
)
|
|
108
|
+
raw_data.update(classification_quality_metric["result"])
|
|
109
|
+
|
|
110
|
+
return raw_data
|
|
111
|
+
|
|
112
|
+
def print_config(self):
|
|
113
|
+
"""
|
|
114
|
+
pretty print the cdashboard config
|
|
115
|
+
"""
|
|
116
|
+
config = {k: v for k, v in self.config.items() if v is not None}
|
|
117
|
+
config.pop("metadata", None)
|
|
118
|
+
print("Using config: ", end="")
|
|
119
|
+
print(json.dumps(config, indent=4))
|
|
120
|
+
|
|
121
|
+
def __print__(self) -> str:
|
|
122
|
+
"""User-friendly string representation."""
|
|
123
|
+
return f"Dashboard(config='{self.get_config()}')"
|
|
124
|
+
|
|
125
|
+
def __str__(self) -> str:
|
|
126
|
+
"""Return printable representation."""
|
|
127
|
+
return self.__print__()
|
|
128
|
+
|
|
129
|
+
def __repr__(self) -> str:
|
|
130
|
+
"""Return developer-friendly representation."""
|
|
131
|
+
return self.__print__()
|
|
File without changes
|
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
from typing import Any, Callable, Dict, List, Optional, Tuple, TypedDict, Union
|
|
2
|
+
|
|
3
|
+
class Guard:
|
|
4
|
+
"""Predefined guardrail configurations for common use cases"""
|
|
5
|
+
|
|
6
|
+
@staticmethod
|
|
7
|
+
def detect_pii(entities: List[str] = None) -> Dict[str, Any]:
|
|
8
|
+
"""Template for PII detection guardrail
|
|
9
|
+
|
|
10
|
+
:param entities: List of PII entity types to detect.
|
|
11
|
+
"""
|
|
12
|
+
if entities is None:
|
|
13
|
+
entities = ["EMAIL_ADDRESS", "PHONE_NUMBER", "PERSON", "ADDRESS"]
|
|
14
|
+
|
|
15
|
+
return {
|
|
16
|
+
"name": "Detect PII",
|
|
17
|
+
"config": {
|
|
18
|
+
"pii_entities": entities
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
@staticmethod
|
|
23
|
+
def nsfw_text(threshold: float = 0.8, validation_method: str = "sentence") -> Dict[str, Any]:
|
|
24
|
+
"""Template for NSFW text detection guardrail
|
|
25
|
+
|
|
26
|
+
:param threshold: Confidence threshold for detection (0.0-1.0).
|
|
27
|
+
:param validation_method: Validation scope: "sentence", "paragraph", or "document".
|
|
28
|
+
"""
|
|
29
|
+
return {
|
|
30
|
+
"name": "NSFW Text",
|
|
31
|
+
"config": {
|
|
32
|
+
"threshold": threshold,
|
|
33
|
+
"validation_method": validation_method
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
@staticmethod
|
|
37
|
+
def ban_list(banned_words: List[str]) -> Dict[str, Any]:
|
|
38
|
+
"""Template for banned words guardrail"""
|
|
39
|
+
return {
|
|
40
|
+
"name": "Ban List",
|
|
41
|
+
"config": {
|
|
42
|
+
"banned_words": banned_words
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
@staticmethod
|
|
46
|
+
def bias_check(threshold: float = 0.9) -> Dict[str, Any]:
|
|
47
|
+
"""Template for bias check guardrail"""
|
|
48
|
+
return {
|
|
49
|
+
"name": "Bias Check",
|
|
50
|
+
"config": {
|
|
51
|
+
"threshold": threshold
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
@staticmethod
|
|
56
|
+
def competitor_check(competitors: List[str]) -> Dict[str, Any]:
|
|
57
|
+
"""Template for competitor guardrail"""
|
|
58
|
+
return {
|
|
59
|
+
"name": "Competitor Check",
|
|
60
|
+
"config": {
|
|
61
|
+
"competitors": competitors
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
@staticmethod
|
|
66
|
+
def correct_language(expected_language_iso: str = "en", threshold: float = 0.75) -> Dict[str, Any]:
|
|
67
|
+
"""Template for correct language guardrail"""
|
|
68
|
+
return {
|
|
69
|
+
"name": "Correct Language",
|
|
70
|
+
"config": {
|
|
71
|
+
"expected_language_iso": expected_language_iso,
|
|
72
|
+
"threshold": threshold
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
@staticmethod
|
|
77
|
+
def gibberish_text(threshold: float = 0.5, validation_method: str = "sentence") -> Dict[str, Any]:
|
|
78
|
+
"""Template for gibberish text guardrail"""
|
|
79
|
+
return {
|
|
80
|
+
"name": "Gibberish Text",
|
|
81
|
+
"config": {
|
|
82
|
+
"threshold": threshold,
|
|
83
|
+
"validation_method": validation_method
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
@staticmethod
|
|
88
|
+
def profanity_free() -> Dict[str, Any]:
|
|
89
|
+
"""Template for profanity free guardrail"""
|
|
90
|
+
return {
|
|
91
|
+
"name": "Profanity Free",
|
|
92
|
+
"config": {}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
@staticmethod
|
|
96
|
+
def secrets_present() -> Dict[str, Any]:
|
|
97
|
+
"""Template for secrets present guardrail"""
|
|
98
|
+
return {
|
|
99
|
+
"name": "Secrets Present",
|
|
100
|
+
"config": {}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
@staticmethod
|
|
104
|
+
def toxic_language(threshold: float = 0.5, validation_method: str = "sentence") -> Dict[str, Any]:
|
|
105
|
+
"""Template for toxic language guardrail"""
|
|
106
|
+
return {
|
|
107
|
+
"name": "Toxic Language",
|
|
108
|
+
"config": {
|
|
109
|
+
"threshold": threshold,
|
|
110
|
+
"validation_method": validation_method
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
@staticmethod
|
|
115
|
+
def contains_string(substring: str) -> Dict[str, Any]:
|
|
116
|
+
"""Template for contains string guardrail"""
|
|
117
|
+
return {
|
|
118
|
+
"name": "Contains String",
|
|
119
|
+
"config": {
|
|
120
|
+
"substring": substring
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
@staticmethod
|
|
125
|
+
def detect_jailbreak(threshold: float = 0.0) -> Dict[str, Any]:
|
|
126
|
+
"""Template for detect jailbreak guardrail"""
|
|
127
|
+
return {
|
|
128
|
+
"name": "Detect Jailbreak",
|
|
129
|
+
"config": {
|
|
130
|
+
"threshold": threshold
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
@staticmethod
|
|
135
|
+
def endpoint_is_reachable() -> Dict[str, Any]:
|
|
136
|
+
"""Template for endpoint is reachable guardrail"""
|
|
137
|
+
return {
|
|
138
|
+
"name": "Endpoint Is Reachable",
|
|
139
|
+
"config": {}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
@staticmethod
|
|
143
|
+
def ends_with(end: str) -> Dict[str, Any]:
|
|
144
|
+
"""Template for ends with guardrail"""
|
|
145
|
+
return {
|
|
146
|
+
"name": "Ends With",
|
|
147
|
+
"config": {
|
|
148
|
+
"end": end
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
@staticmethod
|
|
153
|
+
def has_url() -> Dict[str, Any]:
|
|
154
|
+
"""Template for has url guardrail"""
|
|
155
|
+
return {
|
|
156
|
+
"name": "Has Url",
|
|
157
|
+
"config": {}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
@staticmethod
|
|
161
|
+
def lower_case() -> Dict[str, Any]:
|
|
162
|
+
"""Template for lower case guardrail"""
|
|
163
|
+
return {
|
|
164
|
+
"name": "Lower Case",
|
|
165
|
+
"config": {}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
@staticmethod
|
|
169
|
+
def mentions_drugs() -> Dict[str, Any]:
|
|
170
|
+
"""Template for mentions drugs guardrail"""
|
|
171
|
+
return {
|
|
172
|
+
"name": "Mentions Drugs",
|
|
173
|
+
"config": {}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
@staticmethod
|
|
177
|
+
def one_line() -> Dict[str, Any]:
|
|
178
|
+
"""Template for one line guardrail"""
|
|
179
|
+
return {
|
|
180
|
+
"name": "One Line",
|
|
181
|
+
"config": {}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
@staticmethod
|
|
185
|
+
def reading_time(reading_time: float) -> Dict[str, Any]:
|
|
186
|
+
"""Template for reading time guardrail"""
|
|
187
|
+
return {
|
|
188
|
+
"name": "Reading Time",
|
|
189
|
+
"config": {
|
|
190
|
+
"reading_time": reading_time
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
@staticmethod
|
|
195
|
+
def redundant_sentences(threshold: int = 70) -> Dict[str, Any]:
|
|
196
|
+
"""Template for redundant sentences guardrail"""
|
|
197
|
+
return {
|
|
198
|
+
"name": "Redundant Sentences",
|
|
199
|
+
"config": {
|
|
200
|
+
"threshold": threshold
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
@staticmethod
|
|
205
|
+
def regex_match(regex: str, match_type: str = "search") -> Dict[str, Any]:
|
|
206
|
+
"""Template for regex match guardrail"""
|
|
207
|
+
return {
|
|
208
|
+
"name": "Regex Match",
|
|
209
|
+
"config": {
|
|
210
|
+
"regex": regex,
|
|
211
|
+
"match_type": match_type
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
@staticmethod
|
|
216
|
+
def sql_column_presence(cols: List[str]) -> Dict[str, Any]:
|
|
217
|
+
"""Template for SQL column presence guardrail"""
|
|
218
|
+
return {
|
|
219
|
+
"name": "Sql Column Presence",
|
|
220
|
+
"config": {
|
|
221
|
+
"cols": cols
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
@staticmethod
|
|
226
|
+
def two_words() -> Dict[str, Any]:
|
|
227
|
+
"""Template for two words guardrail"""
|
|
228
|
+
return {
|
|
229
|
+
"name": "Two Words",
|
|
230
|
+
"config": {}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
@staticmethod
|
|
234
|
+
def upper_case() -> Dict[str, Any]:
|
|
235
|
+
"""Template for upper case guardrail"""
|
|
236
|
+
return {
|
|
237
|
+
"name": "Upper Case",
|
|
238
|
+
"config": {}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
@staticmethod
|
|
242
|
+
def valid_choices(choices: List[str]) -> Dict[str, Any]:
|
|
243
|
+
"""Template for valid choices guardrail"""
|
|
244
|
+
return {
|
|
245
|
+
"name": "Valid Choices",
|
|
246
|
+
"config": {
|
|
247
|
+
"choices": choices
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
@staticmethod
|
|
252
|
+
def valid_json() -> Dict[str, Any]:
|
|
253
|
+
"""Template for valid json guardrail"""
|
|
254
|
+
return {
|
|
255
|
+
"name": "Valid Json",
|
|
256
|
+
"config": {}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
@staticmethod
|
|
260
|
+
def valid_length(min: Optional[int] = None, max: Optional[int] = None) -> Dict[str, Any]:
|
|
261
|
+
"""Template for valid length guardrail"""
|
|
262
|
+
config = {}
|
|
263
|
+
if min is not None:
|
|
264
|
+
config['min'] = min
|
|
265
|
+
if max is not None:
|
|
266
|
+
config['max'] = max
|
|
267
|
+
return {
|
|
268
|
+
"name": "Valid Length",
|
|
269
|
+
"config": config
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
@staticmethod
|
|
273
|
+
def valid_range(min: Optional[int] = None, max: Optional[int] = None) -> Dict[str, Any]:
|
|
274
|
+
"""Template for valid range guardrail"""
|
|
275
|
+
config = {}
|
|
276
|
+
if min is not None:
|
|
277
|
+
config['min'] = min
|
|
278
|
+
if max is not None:
|
|
279
|
+
config['max'] = max
|
|
280
|
+
return {
|
|
281
|
+
"name": "Valid Range",
|
|
282
|
+
"config": config
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
@staticmethod
|
|
286
|
+
def valid_url() -> Dict[str, Any]:
|
|
287
|
+
"""Template for valid url guardrail"""
|
|
288
|
+
return {
|
|
289
|
+
"name": "Valid URL",
|
|
290
|
+
"config": {}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
@staticmethod
|
|
294
|
+
def web_sanitization() -> Dict[str, Any]:
|
|
295
|
+
"""Template for web sanitization guardrail"""
|
|
296
|
+
return {
|
|
297
|
+
"name": "Web Sanitization",
|
|
298
|
+
"config": {}
|
|
299
|
+
}
|