fiddler-client 2.4.0.dev2__py3-none-any.whl → 2.5.0.dev2__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.
- fiddler/__init__.py +2 -0
- fiddler/_version.py +1 -1
- fiddler/api/alert_mixin.py +51 -1
- fiddler/api/webhooks_mixin.py +6 -8
- fiddler/core_objects.py +76 -26
- fiddler/schema/alert.py +9 -2
- fiddler/schemas/custom_features.py +44 -1
- fiddler3/__init__.py +121 -38
- fiddler3/configs.py +3 -0
- fiddler3/connection.py +68 -1
- fiddler3/constants/alert_rule.py +30 -0
- fiddler3/constants/events.py +7 -0
- fiddler3/constants/model.py +9 -0
- fiddler3/entities/__init__.py +0 -7
- fiddler3/entities/alert_record.py +106 -0
- fiddler3/entities/alert_rule.py +323 -0
- fiddler3/entities/base.py +2 -16
- fiddler3/entities/baseline.py +21 -15
- fiddler3/entities/dataset.py +1 -1
- fiddler3/entities/events.py +136 -0
- fiddler3/entities/file.py +162 -0
- fiddler3/entities/model.py +141 -24
- fiddler3/entities/model_artifact.py +52 -224
- fiddler3/entities/model_deployment.py +12 -1
- fiddler3/entities/project.py +2 -2
- fiddler3/entities/{model_surrogate.py → surrogate.py} +27 -29
- fiddler3/entities/webhook.py +128 -0
- fiddler3/entities/xai.py +271 -5
- fiddler3/libs/http_client.py +1 -1
- fiddler3/libs/json_encoder.py +1 -1
- fiddler3/schemas/__init__.py +0 -9
- fiddler3/schemas/alert_record.py +27 -0
- fiddler3/schemas/alert_rule.py +39 -0
- fiddler3/schemas/custom_features.py +68 -12
- fiddler3/schemas/events.py +15 -0
- fiddler3/schemas/file.py +23 -0
- fiddler3/schemas/model.py +1 -6
- fiddler3/schemas/model_deployment.py +5 -4
- fiddler3/schemas/webhook.py +23 -0
- fiddler3/tests/apis/test_alert_record.py +99 -0
- fiddler3/tests/apis/test_alert_rule.py +393 -0
- fiddler3/tests/apis/test_events.py +169 -0
- fiddler3/tests/apis/test_files.py +164 -0
- fiddler3/tests/apis/test_model.py +60 -9
- fiddler3/tests/apis/test_model_artifact.py +21 -0
- fiddler3/tests/apis/test_project.py +3 -3
- fiddler3/tests/apis/test_webhook.py +257 -0
- fiddler3/tests/apis/test_xai.py +233 -1
- fiddler3/tests/conftest.py +2 -2
- fiddler3/tests/constants.py +5 -0
- fiddler3/tests/test_connection.py +24 -1
- fiddler3/tests/test_json_encoder.py +2 -2
- fiddler3/utils/helpers.py +20 -0
- {fiddler_client-2.4.0.dev2.dist-info → fiddler_client-2.5.0.dev2.dist-info}/METADATA +15 -5
- {fiddler_client-2.4.0.dev2.dist-info → fiddler_client-2.5.0.dev2.dist-info}/RECORD +59 -44
- tests/fiddler/test_alert.py +95 -5
- fiddler3/entities/helpers.py +0 -21
- fiddler3/schemas/model_artifact.py +0 -6
- {fiddler_client-2.4.0.dev2.dist-info → fiddler_client-2.5.0.dev2.dist-info}/LICENSE.txt +0 -0
- {fiddler_client-2.4.0.dev2.dist-info → fiddler_client-2.5.0.dev2.dist-info}/WHEEL +0 -0
- {fiddler_client-2.4.0.dev2.dist-info → fiddler_client-2.5.0.dev2.dist-info}/top_level.txt +0 -0
fiddler3/entities/xai.py
CHANGED
|
@@ -9,8 +9,11 @@ from uuid import UUID
|
|
|
9
9
|
|
|
10
10
|
import pandas as pd
|
|
11
11
|
|
|
12
|
+
from fiddler3.constants.dataset import EnvType
|
|
12
13
|
from fiddler3.constants.xai import ExplainMethod
|
|
13
14
|
from fiddler3.decorators import handle_api_error
|
|
15
|
+
from fiddler3.entities.job import Job
|
|
16
|
+
from fiddler3.schemas.job import JobCompactResp
|
|
14
17
|
from fiddler3.schemas.xai import (
|
|
15
18
|
DatasetDataSource,
|
|
16
19
|
EventIdDataSource,
|
|
@@ -18,12 +21,19 @@ from fiddler3.schemas.xai import (
|
|
|
18
21
|
SqlSliceQueryDataSource,
|
|
19
22
|
)
|
|
20
23
|
from fiddler3.utils.helpers import try_series_retype
|
|
24
|
+
from fiddler3.utils.logger import get_logger
|
|
25
|
+
|
|
26
|
+
logger = get_logger(__name__)
|
|
21
27
|
|
|
22
28
|
|
|
23
29
|
class XaiMixin:
|
|
24
30
|
id: UUID | None
|
|
25
31
|
_client: Callable
|
|
26
32
|
|
|
33
|
+
def _get_method(self, update: bool = False) -> Callable:
|
|
34
|
+
"""Get HTTP method"""
|
|
35
|
+
return self._client().put if update else self._client().post
|
|
36
|
+
|
|
27
37
|
@handle_api_error
|
|
28
38
|
def explain( # pylint: disable=too-many-arguments
|
|
29
39
|
self,
|
|
@@ -64,7 +74,7 @@ class XaiMixin:
|
|
|
64
74
|
'explanation_type': method,
|
|
65
75
|
}
|
|
66
76
|
if ref_data_source:
|
|
67
|
-
payload['ref_data_source'] = ref_data_source.dict()
|
|
77
|
+
payload['ref_data_source'] = ref_data_source.dict(exclude_none=True)
|
|
68
78
|
if num_permutations:
|
|
69
79
|
payload['num_permutations'] = num_permutations
|
|
70
80
|
if ci_level:
|
|
@@ -104,7 +114,7 @@ class XaiMixin:
|
|
|
104
114
|
|
|
105
115
|
payload: dict[str, Any] = {
|
|
106
116
|
'model_id': self.id,
|
|
107
|
-
'data_source': data_source.dict(),
|
|
117
|
+
'data_source': data_source.dict(exclude_none=True),
|
|
108
118
|
'protected_features': protected_features,
|
|
109
119
|
'positive_outcome': positive_outcome,
|
|
110
120
|
}
|
|
@@ -183,8 +193,8 @@ class XaiMixin:
|
|
|
183
193
|
"""
|
|
184
194
|
self._check_id_attributes()
|
|
185
195
|
output_dir = Path(output_dir)
|
|
186
|
-
if output_dir.exists():
|
|
187
|
-
|
|
196
|
+
if not output_dir.exists():
|
|
197
|
+
os.makedirs(output_dir)
|
|
188
198
|
payload: dict[str, Any] = {
|
|
189
199
|
'model_id': self.id,
|
|
190
200
|
'query': query,
|
|
@@ -195,7 +205,6 @@ class XaiMixin:
|
|
|
195
205
|
if columns:
|
|
196
206
|
payload['columns'] = columns
|
|
197
207
|
|
|
198
|
-
os.makedirs(output_dir)
|
|
199
208
|
file_path = os.path.join(output_dir, 'output.parquet')
|
|
200
209
|
with self._client().post(url='/v3/slice-query/download', data=payload) as resp:
|
|
201
210
|
# Download parquet file
|
|
@@ -273,6 +282,221 @@ class XaiMixin:
|
|
|
273
282
|
)
|
|
274
283
|
return pd.DataFrame(response.json()['data']['predictions'])
|
|
275
284
|
|
|
285
|
+
@handle_api_error
|
|
286
|
+
def get_feature_impact( # pylint: disable=too-many-arguments
|
|
287
|
+
self,
|
|
288
|
+
data_source: DatasetDataSource | SqlSliceQueryDataSource,
|
|
289
|
+
num_iterations: int | None = None,
|
|
290
|
+
num_refs: int | None = None,
|
|
291
|
+
ci_level: float | None = None,
|
|
292
|
+
min_support: int | None = None,
|
|
293
|
+
output_columns: list[str] | None = None,
|
|
294
|
+
) -> tuple:
|
|
295
|
+
"""
|
|
296
|
+
Get global feature impact for a model over a dataset or a slice.
|
|
297
|
+
|
|
298
|
+
:param data_source: DataSource for the input dataset to compute feature
|
|
299
|
+
impact on (DatasetDataSource or SqlSliceQueryDataSource)
|
|
300
|
+
:param num_iterations: The maximum number of ablated model inferences per feature
|
|
301
|
+
:param num_refs: The number of reference points used in the explanation
|
|
302
|
+
:param ci_level: The confidence level (between 0 and 1)
|
|
303
|
+
:param min_support: Only used for NLP (TEXT inputs) models. Specify a minimum
|
|
304
|
+
support (number of times a specific word was present in the sample data)
|
|
305
|
+
to retrieve top words. Default to 15.
|
|
306
|
+
:param output_columns: Only used for NLP (TEXT inputs) models. Output column
|
|
307
|
+
names to compute feature impact on.
|
|
308
|
+
|
|
309
|
+
:return: Feature Impact tuple
|
|
310
|
+
"""
|
|
311
|
+
|
|
312
|
+
self._check_id_attributes()
|
|
313
|
+
|
|
314
|
+
payload: dict[str, Any] = {
|
|
315
|
+
'model_id': self.id,
|
|
316
|
+
'data_source': data_source.dict(exclude_none=True),
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
if num_refs:
|
|
320
|
+
payload['num_refs'] = num_refs
|
|
321
|
+
if num_iterations:
|
|
322
|
+
payload['num_iterations'] = num_iterations
|
|
323
|
+
if ci_level:
|
|
324
|
+
payload['ci_level'] = ci_level
|
|
325
|
+
if min_support:
|
|
326
|
+
payload['min_support'] = min_support
|
|
327
|
+
if output_columns:
|
|
328
|
+
payload['output_columns'] = output_columns
|
|
329
|
+
|
|
330
|
+
response = self._client().post(
|
|
331
|
+
url='/v3/analytics/feature-impact',
|
|
332
|
+
data=payload,
|
|
333
|
+
)
|
|
334
|
+
|
|
335
|
+
return namedtuple('FeatureImpact', response.json()['data'])(
|
|
336
|
+
**response.json()['data']
|
|
337
|
+
)
|
|
338
|
+
|
|
339
|
+
@handle_api_error
|
|
340
|
+
def get_feature_importance( # pylint: disable=too-many-arguments
|
|
341
|
+
self,
|
|
342
|
+
data_source: DatasetDataSource | SqlSliceQueryDataSource,
|
|
343
|
+
num_iterations: int | None = None,
|
|
344
|
+
num_refs: int | None = None,
|
|
345
|
+
ci_level: float | None = None,
|
|
346
|
+
) -> tuple:
|
|
347
|
+
"""
|
|
348
|
+
Get global feature importance for a model over a dataset or a slice.
|
|
349
|
+
|
|
350
|
+
:param data_source: DataSource for the input dataset to compute feature
|
|
351
|
+
importance on (DatasetDataSource or SqlSliceQueryDataSource)
|
|
352
|
+
:param num_iterations: The maximum number of ablated model inferences per feature
|
|
353
|
+
:param num_refs: The number of reference points used in the explanation
|
|
354
|
+
:param ci_level: The confidence level (between 0 and 1)
|
|
355
|
+
|
|
356
|
+
:return: Feature Importance tuple
|
|
357
|
+
"""
|
|
358
|
+
|
|
359
|
+
self._check_id_attributes()
|
|
360
|
+
|
|
361
|
+
payload: dict[str, Any] = {
|
|
362
|
+
'model_id': self.id,
|
|
363
|
+
'data_source': data_source.dict(),
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
if num_refs:
|
|
367
|
+
payload['num_refs'] = num_refs
|
|
368
|
+
if num_iterations:
|
|
369
|
+
payload['num_iterations'] = num_iterations
|
|
370
|
+
if ci_level:
|
|
371
|
+
payload['ci_level'] = ci_level
|
|
372
|
+
|
|
373
|
+
response = self._client().post(
|
|
374
|
+
url='/v3/analytics/feature-importance',
|
|
375
|
+
data=payload,
|
|
376
|
+
)
|
|
377
|
+
|
|
378
|
+
return namedtuple('FeatureImportance', response.json()['data'])(
|
|
379
|
+
**response.json()['data']
|
|
380
|
+
)
|
|
381
|
+
|
|
382
|
+
@handle_api_error
|
|
383
|
+
def precompute_feature_impact( # pylint: disable=too-many-arguments
|
|
384
|
+
self,
|
|
385
|
+
dataset_id: UUID,
|
|
386
|
+
num_samples: int | None = None,
|
|
387
|
+
num_iterations: int | None = None,
|
|
388
|
+
num_refs: int | None = None,
|
|
389
|
+
ci_level: float | None = None,
|
|
390
|
+
min_support: int | None = None,
|
|
391
|
+
update: bool = False,
|
|
392
|
+
) -> Job:
|
|
393
|
+
"""Pre-compute feature impact for a model on a dataset.
|
|
394
|
+
|
|
395
|
+
This is used in various places in the UI.
|
|
396
|
+
A single feature impact can be precomputed (computed and cached) for a model.
|
|
397
|
+
|
|
398
|
+
:param dataset_id: The unique identifier of the dataset
|
|
399
|
+
:param num_samples: The number of samples used
|
|
400
|
+
:param num_iterations: The maximum number of ablated model inferences per feature
|
|
401
|
+
:param num_refs: The number of reference points used in the explanation
|
|
402
|
+
:param ci_level: The confidence level (between 0 and 1)
|
|
403
|
+
:param min_support: Only used for NLP (TEXT inputs) models. Specify a minimum
|
|
404
|
+
support (number of times a specific word was present in the sample data)
|
|
405
|
+
to retrieve top words. Default to 15.
|
|
406
|
+
:param update: Whether the precomputed feature impact should be recomputed and updated
|
|
407
|
+
|
|
408
|
+
:return: Async Job
|
|
409
|
+
"""
|
|
410
|
+
|
|
411
|
+
self._check_id_attributes()
|
|
412
|
+
|
|
413
|
+
payload: dict[str, Any] = {
|
|
414
|
+
'model_id': self.id,
|
|
415
|
+
'env_id': dataset_id,
|
|
416
|
+
'env_type': EnvType.PRE_PRODUCTION,
|
|
417
|
+
}
|
|
418
|
+
if num_samples:
|
|
419
|
+
payload['num_samples'] = num_samples
|
|
420
|
+
if num_refs:
|
|
421
|
+
payload['num_refs'] = num_refs
|
|
422
|
+
if num_iterations:
|
|
423
|
+
payload['num_iterations'] = num_iterations
|
|
424
|
+
if ci_level:
|
|
425
|
+
payload['ci_level'] = ci_level
|
|
426
|
+
if min_support:
|
|
427
|
+
payload['min_support'] = min_support
|
|
428
|
+
|
|
429
|
+
method = self._get_method(update)
|
|
430
|
+
|
|
431
|
+
response = method(
|
|
432
|
+
url='/v3/analytics/precompute-feature-impact',
|
|
433
|
+
data=payload,
|
|
434
|
+
)
|
|
435
|
+
|
|
436
|
+
job_compact = JobCompactResp(**response.json()['data']['job'])
|
|
437
|
+
logger.info(
|
|
438
|
+
'Model[%s] - Submitted job (%s) for precomputing feature impact',
|
|
439
|
+
self.id,
|
|
440
|
+
job_compact.id,
|
|
441
|
+
)
|
|
442
|
+
return Job.get(id_=job_compact.id)
|
|
443
|
+
|
|
444
|
+
@handle_api_error
|
|
445
|
+
def precompute_feature_importance( # pylint: disable=too-many-arguments
|
|
446
|
+
self,
|
|
447
|
+
dataset_id: UUID,
|
|
448
|
+
num_samples: int | None = None,
|
|
449
|
+
num_iterations: int | None = None,
|
|
450
|
+
num_refs: int | None = None,
|
|
451
|
+
ci_level: float | None = None,
|
|
452
|
+
update: bool = False,
|
|
453
|
+
) -> Job:
|
|
454
|
+
"""Pre-compute feature importance for a model on a dataset.
|
|
455
|
+
|
|
456
|
+
This is used in various places in the UI.
|
|
457
|
+
A single feature importance can be precomputed (computed and cached) for a model.
|
|
458
|
+
|
|
459
|
+
:param dataset_id: The unique identifier of the dataset
|
|
460
|
+
:param num_samples: The number of samples used
|
|
461
|
+
:param num_iterations: The maximum number of ablated model inferences per feature
|
|
462
|
+
:param num_refs: The number of reference points used in the explanation
|
|
463
|
+
:param ci_level: The confidence level (between 0 and 1)
|
|
464
|
+
:param update: Whether the precomputed feature impact should be recomputed and updated
|
|
465
|
+
|
|
466
|
+
:return: Async Job
|
|
467
|
+
"""
|
|
468
|
+
|
|
469
|
+
self._check_id_attributes()
|
|
470
|
+
|
|
471
|
+
payload: dict[str, Any] = {
|
|
472
|
+
'model_id': self.id,
|
|
473
|
+
'env_id': dataset_id,
|
|
474
|
+
'env_type': EnvType.PRE_PRODUCTION,
|
|
475
|
+
}
|
|
476
|
+
if num_samples:
|
|
477
|
+
payload['num_samples'] = num_samples
|
|
478
|
+
if num_refs:
|
|
479
|
+
payload['num_refs'] = num_refs
|
|
480
|
+
if num_iterations:
|
|
481
|
+
payload['num_iterations'] = num_iterations
|
|
482
|
+
if ci_level:
|
|
483
|
+
payload['ci_level'] = ci_level
|
|
484
|
+
|
|
485
|
+
method = self._get_method(update)
|
|
486
|
+
|
|
487
|
+
response = method(
|
|
488
|
+
url='/v3/analytics/precompute-feature-importance',
|
|
489
|
+
data=payload,
|
|
490
|
+
)
|
|
491
|
+
|
|
492
|
+
job_compact = JobCompactResp(**response.json()['data']['job'])
|
|
493
|
+
logger.info(
|
|
494
|
+
'Model[%s] - Submitted job (%s) for precomputing feature importance',
|
|
495
|
+
self.id,
|
|
496
|
+
job_compact.id,
|
|
497
|
+
)
|
|
498
|
+
return Job.get(id_=job_compact.id)
|
|
499
|
+
|
|
276
500
|
@handle_api_error
|
|
277
501
|
def get_precomputed_feature_importance(self) -> tuple:
|
|
278
502
|
"""Get precomputed feature importance for a model"""
|
|
@@ -301,6 +525,48 @@ class XaiMixin:
|
|
|
301
525
|
**response.json()['data']
|
|
302
526
|
)
|
|
303
527
|
|
|
528
|
+
@handle_api_error
|
|
529
|
+
def precompute_predictions(
|
|
530
|
+
self,
|
|
531
|
+
dataset_id: UUID,
|
|
532
|
+
chunk_size: int | None = None,
|
|
533
|
+
update: bool = False,
|
|
534
|
+
) -> Job:
|
|
535
|
+
"""
|
|
536
|
+
Pre-compute predictions for a model on a dataset
|
|
537
|
+
|
|
538
|
+
:param dataset_id: The unique identifier of the dataset
|
|
539
|
+
:param chunk_size: Chunk size for fetching predictions
|
|
540
|
+
:param update: Whether the pre-computed predictions should be re-computed and updated for this dataset
|
|
541
|
+
|
|
542
|
+
:return: Dataframe of the predictions
|
|
543
|
+
"""
|
|
544
|
+
self._check_id_attributes()
|
|
545
|
+
|
|
546
|
+
payload: dict[str, Any] = {
|
|
547
|
+
'model_id': self.id,
|
|
548
|
+
'env_id': dataset_id,
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
if chunk_size:
|
|
552
|
+
payload['batch_size'] = chunk_size
|
|
553
|
+
|
|
554
|
+
method = self._get_method(update)
|
|
555
|
+
|
|
556
|
+
response = method(
|
|
557
|
+
url='/v3/analytics/precompute-predictions',
|
|
558
|
+
data=payload,
|
|
559
|
+
)
|
|
560
|
+
|
|
561
|
+
job_compact = JobCompactResp(**response.json()['data']['job'])
|
|
562
|
+
logger.info(
|
|
563
|
+
'Model[%s] - Submitted job (%s) for precomputing predictions on dataset[%s]',
|
|
564
|
+
self.id,
|
|
565
|
+
job_compact.id,
|
|
566
|
+
dataset_id,
|
|
567
|
+
)
|
|
568
|
+
return Job.get(id_=job_compact.id)
|
|
569
|
+
|
|
304
570
|
def _check_id_attributes(self) -> None:
|
|
305
571
|
if not self.id:
|
|
306
572
|
raise AttributeError(
|
fiddler3/libs/http_client.py
CHANGED
|
@@ -78,7 +78,7 @@ class RequestClient:
|
|
|
78
78
|
request_headers.update(headers)
|
|
79
79
|
|
|
80
80
|
content_type = request_headers.get('Content-Type')
|
|
81
|
-
if data and content_type == JSON_CONTENT_TYPE:
|
|
81
|
+
if data is not None and content_type == JSON_CONTENT_TYPE:
|
|
82
82
|
data = simplejson.dumps(data, ignore_nan=True, cls=RequestClientJSONEncoder) # type: ignore
|
|
83
83
|
|
|
84
84
|
kwargs.setdefault('allow_redirects', True)
|
fiddler3/libs/json_encoder.py
CHANGED
fiddler3/schemas/__init__.py
CHANGED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
"""Initialize all schemas."""
|
|
2
|
-
from fiddler3.schemas.custom_features import * # noqa
|
|
3
|
-
from fiddler3.schemas.dataset import EnvType # noqa
|
|
4
|
-
from fiddler3.schemas.deployment_params import DeploymentParams # noqa
|
|
5
|
-
from fiddler3.schemas.model_schema import ModelSchema # noqa
|
|
6
|
-
from fiddler3.schemas.model_spec import ModelSpec # noqa
|
|
7
|
-
from fiddler3.schemas.model_task_params import ModelTaskParams # noqa
|
|
8
|
-
from fiddler3.schemas.xai import * # noqa
|
|
9
|
-
from fiddler3.schemas.xai_params import XaiParams # noqa
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
from datetime import datetime
|
|
2
|
+
from typing import Optional
|
|
3
|
+
from uuid import UUID
|
|
4
|
+
|
|
5
|
+
from pydantic import Field
|
|
6
|
+
|
|
7
|
+
from fiddler3.schemas.base import BaseModel
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class AlertRecordResp(BaseModel):
|
|
11
|
+
id: UUID = Field(alias='uuid')
|
|
12
|
+
alert_rule_id: UUID = Field(alias='alert_config_uuid')
|
|
13
|
+
alert_run_start_time: int
|
|
14
|
+
alert_time_bucket: int
|
|
15
|
+
alert_value: float
|
|
16
|
+
baseline_time_bucket: Optional[int]
|
|
17
|
+
baseline_value: Optional[float]
|
|
18
|
+
is_alert: bool
|
|
19
|
+
severity: str
|
|
20
|
+
failure_reason: str
|
|
21
|
+
message: str
|
|
22
|
+
feature_name: Optional[str]
|
|
23
|
+
alert_record_main_version: int
|
|
24
|
+
alert_record_sub_version: int
|
|
25
|
+
|
|
26
|
+
created_at: datetime
|
|
27
|
+
updated_at: datetime
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
from datetime import datetime
|
|
2
|
+
from typing import List, Optional, Union
|
|
3
|
+
from uuid import UUID
|
|
4
|
+
|
|
5
|
+
from pydantic import Field
|
|
6
|
+
|
|
7
|
+
from fiddler3.constants.alert_rule import AlertCondition, BinSize, CompareTo, Priority
|
|
8
|
+
from fiddler3.schemas.base import BaseModel
|
|
9
|
+
from fiddler3.schemas.baseline import BaselineCompactResp
|
|
10
|
+
from fiddler3.schemas.model import ModelCompactResp
|
|
11
|
+
from fiddler3.schemas.project import ProjectCompactResp
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class AlertRuleResp(BaseModel):
|
|
15
|
+
id: UUID = Field(alias='uuid')
|
|
16
|
+
name: str
|
|
17
|
+
model: ModelCompactResp
|
|
18
|
+
project: ProjectCompactResp
|
|
19
|
+
baseline: Optional[BaselineCompactResp]
|
|
20
|
+
priority: Union[str, Priority]
|
|
21
|
+
compare_to: Union[str, CompareTo]
|
|
22
|
+
metric_id: Union[str, UUID] = Field(alias='metric')
|
|
23
|
+
critical_threshold: float
|
|
24
|
+
condition: Union[str, AlertCondition]
|
|
25
|
+
bin_size: Union[str, BinSize]
|
|
26
|
+
columns: Optional[List[str]]
|
|
27
|
+
baseline_id: Optional[UUID]
|
|
28
|
+
compare_bin_delta: Optional[int]
|
|
29
|
+
warning_threshold: Optional[float]
|
|
30
|
+
|
|
31
|
+
created_at: datetime
|
|
32
|
+
updated_at: datetime = Field(alias='last_updated')
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class NotificationConfig(BaseModel):
|
|
36
|
+
emails: Optional[List[str]]
|
|
37
|
+
pagerduty_services: Optional[List[str]]
|
|
38
|
+
pagerduty_severity: Optional[str]
|
|
39
|
+
webhooks: Optional[List[UUID]]
|
|
@@ -1,19 +1,11 @@
|
|
|
1
|
-
from enum import Enum
|
|
2
1
|
from typing import Any, Dict, List, Optional, Type, TypeVar
|
|
3
2
|
|
|
4
|
-
from pydantic import BaseModel
|
|
5
|
-
|
|
6
|
-
CustomFeatureTypeVar = TypeVar('CustomFeatureTypeVar', bound='CustomFeature')
|
|
7
|
-
DEFAULT_NUM_CLUSTERS = 5
|
|
8
|
-
DEFAULT_NUM_TAGS = 5
|
|
3
|
+
from pydantic import BaseModel, validator
|
|
9
4
|
|
|
5
|
+
from fiddler3.configs import DEFAULT_NUM_CLUSTERS, DEFAULT_NUM_TAGS
|
|
6
|
+
from fiddler3.constants.model import CustomFeatureType
|
|
10
7
|
|
|
11
|
-
|
|
12
|
-
FROM_COLUMNS = 'FROM_COLUMNS'
|
|
13
|
-
FROM_VECTOR = 'FROM_VECTOR'
|
|
14
|
-
FROM_TEXT_EMBEDDING = 'FROM_TEXT_EMBEDDING'
|
|
15
|
-
FROM_IMAGE_EMBEDDING = 'FROM_IMAGE_EMBEDDING'
|
|
16
|
-
ENRICHMENT = 'ENRICHMENT'
|
|
8
|
+
CustomFeatureTypeVar = TypeVar('CustomFeatureTypeVar', bound='CustomFeature')
|
|
17
9
|
|
|
18
10
|
|
|
19
11
|
class CustomFeature(BaseModel):
|
|
@@ -22,6 +14,12 @@ class CustomFeature(BaseModel):
|
|
|
22
14
|
n_clusters: Optional[int] = DEFAULT_NUM_CLUSTERS
|
|
23
15
|
centroids: Optional[List] = None
|
|
24
16
|
|
|
17
|
+
@validator('n_clusters')
|
|
18
|
+
def validate_n_clusters(cls, value: int) -> int: # noqa: N805
|
|
19
|
+
if value < 0:
|
|
20
|
+
raise ValueError('n_clusters must be greater than 0')
|
|
21
|
+
return value
|
|
22
|
+
|
|
25
23
|
class Config:
|
|
26
24
|
allow_mutation = False
|
|
27
25
|
|
|
@@ -46,6 +44,8 @@ class CustomFeature(BaseModel):
|
|
|
46
44
|
return TextEmbedding.parse_obj(deserialized_json)
|
|
47
45
|
if feature_type == CustomFeatureType.FROM_IMAGE_EMBEDDING:
|
|
48
46
|
return ImageEmbedding.parse_obj(deserialized_json)
|
|
47
|
+
if feature_type == CustomFeatureType.ENRICHMENT:
|
|
48
|
+
return Enrichment.parse_obj(deserialized_json)
|
|
49
49
|
|
|
50
50
|
raise ValueError(f'Unsupported feature type: {feature_type}')
|
|
51
51
|
|
|
@@ -63,6 +63,10 @@ class CustomFeature(BaseModel):
|
|
|
63
63
|
return_dict['source_column'] = self.source_column
|
|
64
64
|
if isinstance(self, TextEmbedding):
|
|
65
65
|
return_dict['n_tags'] = self.n_tags
|
|
66
|
+
elif isinstance(self, Enrichment):
|
|
67
|
+
return_dict['columns'] = self.columns
|
|
68
|
+
return_dict['enrichment'] = self.enrichment
|
|
69
|
+
return_dict['config'] = self.config
|
|
66
70
|
else:
|
|
67
71
|
raise ValueError(f'Unsupported feature type: {self.type} {type(self)}')
|
|
68
72
|
|
|
@@ -74,6 +78,12 @@ class Multivariate(CustomFeature):
|
|
|
74
78
|
columns: List[str]
|
|
75
79
|
monitor_components: bool = False
|
|
76
80
|
|
|
81
|
+
@validator('columns')
|
|
82
|
+
def validate_columns(cls, value: List[str]) -> List[str]: # noqa: N805
|
|
83
|
+
if len(value) < 2:
|
|
84
|
+
raise ValueError('Multivariate columns must be greater than 1')
|
|
85
|
+
return value
|
|
86
|
+
|
|
77
87
|
|
|
78
88
|
class VectorFeature(CustomFeature):
|
|
79
89
|
type: CustomFeatureType = CustomFeatureType.FROM_VECTOR
|
|
@@ -85,6 +95,52 @@ class TextEmbedding(VectorFeature):
|
|
|
85
95
|
type: CustomFeatureType = CustomFeatureType.FROM_TEXT_EMBEDDING
|
|
86
96
|
n_tags: Optional[int] = DEFAULT_NUM_TAGS
|
|
87
97
|
|
|
98
|
+
@validator('source_column')
|
|
99
|
+
def validate_source_column(cls, value: str) -> str: # noqa: N805
|
|
100
|
+
if value is None:
|
|
101
|
+
raise ValueError('source_column must be specified')
|
|
102
|
+
return value
|
|
103
|
+
|
|
104
|
+
@validator('n_tags')
|
|
105
|
+
def validate_n_tags(cls, value: int) -> int: # noqa: N805
|
|
106
|
+
if value < 0:
|
|
107
|
+
raise ValueError('n_tags must be greater than 0')
|
|
108
|
+
return value
|
|
109
|
+
|
|
88
110
|
|
|
89
111
|
class ImageEmbedding(VectorFeature):
|
|
90
112
|
type: CustomFeatureType = CustomFeatureType.FROM_IMAGE_EMBEDDING
|
|
113
|
+
|
|
114
|
+
@validator('source_column')
|
|
115
|
+
def validate_source_column(cls, value: str) -> str: # noqa: N805
|
|
116
|
+
if value is None:
|
|
117
|
+
raise ValueError('source_column must be specified')
|
|
118
|
+
return value
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
class Enrichment(CustomFeature):
|
|
122
|
+
"""
|
|
123
|
+
Represents an enrichment feature in a data processing or machine learning context.
|
|
124
|
+
|
|
125
|
+
This class inherits from CustomFeature and is used to apply specific enrichment
|
|
126
|
+
operations to a set of columns in a dataset. The type of enrichment and its
|
|
127
|
+
configuration can be specified.
|
|
128
|
+
|
|
129
|
+
Attributes:
|
|
130
|
+
type (CustomFeatureType): The type of the custom feature, set to ENRICHMENT.
|
|
131
|
+
columns (List[str]): The list of input column names in the dataset used to generate the enrichment.
|
|
132
|
+
enrichment (str): A string identifier for the type of enrichment to be applied.
|
|
133
|
+
config (Dict[str, Any]): A dictionary containing configuration options for the enrichment.
|
|
134
|
+
"""
|
|
135
|
+
|
|
136
|
+
# Setting the feature type to ENRICHMENT
|
|
137
|
+
type: CustomFeatureType = CustomFeatureType.ENRICHMENT
|
|
138
|
+
|
|
139
|
+
# List of input column names used to generate the enrichment
|
|
140
|
+
columns: List[str]
|
|
141
|
+
|
|
142
|
+
# String identifier for the enrichment to be applied. e.g. "embedding" or "toxicity"
|
|
143
|
+
enrichment: str
|
|
144
|
+
|
|
145
|
+
# Dictionary for additional configuration options for the enrichment
|
|
146
|
+
config: Dict[str, Any] = {}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
from typing import Any, Dict, List
|
|
2
|
+
from uuid import UUID
|
|
3
|
+
|
|
4
|
+
from fiddler3.constants.events import PublishEventsSourceType
|
|
5
|
+
from fiddler3.schemas.base import BaseModel
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class FileSource(BaseModel):
|
|
9
|
+
file_id: UUID
|
|
10
|
+
type: PublishEventsSourceType = PublishEventsSourceType.FILE
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class EventsSource(BaseModel):
|
|
14
|
+
events: List[Dict[Any, Any]]
|
|
15
|
+
type: PublishEventsSourceType = PublishEventsSourceType.EVENTS
|
fiddler3/schemas/file.py
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
from datetime import datetime
|
|
2
|
+
from uuid import UUID
|
|
3
|
+
|
|
4
|
+
from pydantic import Field
|
|
5
|
+
|
|
6
|
+
from fiddler3.schemas.base import BaseModel
|
|
7
|
+
from fiddler3.schemas.user import UserCompactResp
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class FileResp(BaseModel):
|
|
11
|
+
id: UUID
|
|
12
|
+
name: str = Field(alias='filename')
|
|
13
|
+
status: str
|
|
14
|
+
type: str
|
|
15
|
+
created_at: datetime
|
|
16
|
+
updated_at: datetime
|
|
17
|
+
created_by: UserCompactResp
|
|
18
|
+
updated_by: UserCompactResp
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class FileCompactResp(BaseModel):
|
|
22
|
+
id: UUID
|
|
23
|
+
name: str
|
fiddler3/schemas/model.py
CHANGED
|
@@ -5,7 +5,7 @@ from uuid import UUID
|
|
|
5
5
|
from pydantic.fields import Field
|
|
6
6
|
|
|
7
7
|
from fiddler3.schemas.base import BaseModel
|
|
8
|
-
from fiddler3.schemas.model_schema import
|
|
8
|
+
from fiddler3.schemas.model_schema import ModelSchema
|
|
9
9
|
from fiddler3.schemas.model_spec import ModelSpec
|
|
10
10
|
from fiddler3.schemas.model_task_params import ModelTaskParams
|
|
11
11
|
from fiddler3.schemas.organization import OrganizationCompactResp
|
|
@@ -40,9 +40,4 @@ class ModelResp(BaseModel):
|
|
|
40
40
|
updated_by: UserCompactResp
|
|
41
41
|
organization: OrganizationCompactResp
|
|
42
42
|
project: ProjectCompactResp
|
|
43
|
-
input_cols: List[Column]
|
|
44
|
-
output_cols: List[Column]
|
|
45
|
-
target_cols: List[Column]
|
|
46
|
-
metadata_cols: List[Column]
|
|
47
|
-
decision_cols: List[Column]
|
|
48
43
|
is_binary_ranking_model: bool
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
from datetime import datetime
|
|
2
|
+
from typing import Optional
|
|
2
3
|
from uuid import UUID
|
|
3
4
|
|
|
4
5
|
from fiddler3.schemas.base import BaseModel
|
|
@@ -16,10 +17,10 @@ class ModelDeploymentResponse(BaseModel):
|
|
|
16
17
|
artifact_type: str
|
|
17
18
|
deployment_type: str
|
|
18
19
|
active: bool
|
|
19
|
-
image_uri: str
|
|
20
|
-
replicas: int
|
|
21
|
-
cpu: int
|
|
22
|
-
memory: int
|
|
20
|
+
image_uri: Optional[str]
|
|
21
|
+
replicas: Optional[int]
|
|
22
|
+
cpu: Optional[int]
|
|
23
|
+
memory: Optional[int]
|
|
23
24
|
created_at: datetime
|
|
24
25
|
updated_at: datetime
|
|
25
26
|
created_by: UserCompactResp
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import enum
|
|
2
|
+
from datetime import datetime
|
|
3
|
+
from uuid import UUID
|
|
4
|
+
|
|
5
|
+
from pydantic.fields import Field
|
|
6
|
+
|
|
7
|
+
from fiddler3.schemas.base import BaseModel
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@enum.unique
|
|
11
|
+
class WebhookProvider(str, enum.Enum):
|
|
12
|
+
# provider is 'SLACK' or 'OTHER' as of Aug 2023.
|
|
13
|
+
SLACK = 'SLACK'
|
|
14
|
+
OTHER = 'OTHER'
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class WebhookResp(BaseModel):
|
|
18
|
+
id: UUID = Field(alias='uuid')
|
|
19
|
+
name: str
|
|
20
|
+
url: str
|
|
21
|
+
provider: WebhookProvider
|
|
22
|
+
created_at: datetime
|
|
23
|
+
updated_at: datetime
|