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.
Files changed (61) hide show
  1. fiddler/__init__.py +2 -0
  2. fiddler/_version.py +1 -1
  3. fiddler/api/alert_mixin.py +51 -1
  4. fiddler/api/webhooks_mixin.py +6 -8
  5. fiddler/core_objects.py +76 -26
  6. fiddler/schema/alert.py +9 -2
  7. fiddler/schemas/custom_features.py +44 -1
  8. fiddler3/__init__.py +121 -38
  9. fiddler3/configs.py +3 -0
  10. fiddler3/connection.py +68 -1
  11. fiddler3/constants/alert_rule.py +30 -0
  12. fiddler3/constants/events.py +7 -0
  13. fiddler3/constants/model.py +9 -0
  14. fiddler3/entities/__init__.py +0 -7
  15. fiddler3/entities/alert_record.py +106 -0
  16. fiddler3/entities/alert_rule.py +323 -0
  17. fiddler3/entities/base.py +2 -16
  18. fiddler3/entities/baseline.py +21 -15
  19. fiddler3/entities/dataset.py +1 -1
  20. fiddler3/entities/events.py +136 -0
  21. fiddler3/entities/file.py +162 -0
  22. fiddler3/entities/model.py +141 -24
  23. fiddler3/entities/model_artifact.py +52 -224
  24. fiddler3/entities/model_deployment.py +12 -1
  25. fiddler3/entities/project.py +2 -2
  26. fiddler3/entities/{model_surrogate.py → surrogate.py} +27 -29
  27. fiddler3/entities/webhook.py +128 -0
  28. fiddler3/entities/xai.py +271 -5
  29. fiddler3/libs/http_client.py +1 -1
  30. fiddler3/libs/json_encoder.py +1 -1
  31. fiddler3/schemas/__init__.py +0 -9
  32. fiddler3/schemas/alert_record.py +27 -0
  33. fiddler3/schemas/alert_rule.py +39 -0
  34. fiddler3/schemas/custom_features.py +68 -12
  35. fiddler3/schemas/events.py +15 -0
  36. fiddler3/schemas/file.py +23 -0
  37. fiddler3/schemas/model.py +1 -6
  38. fiddler3/schemas/model_deployment.py +5 -4
  39. fiddler3/schemas/webhook.py +23 -0
  40. fiddler3/tests/apis/test_alert_record.py +99 -0
  41. fiddler3/tests/apis/test_alert_rule.py +393 -0
  42. fiddler3/tests/apis/test_events.py +169 -0
  43. fiddler3/tests/apis/test_files.py +164 -0
  44. fiddler3/tests/apis/test_model.py +60 -9
  45. fiddler3/tests/apis/test_model_artifact.py +21 -0
  46. fiddler3/tests/apis/test_project.py +3 -3
  47. fiddler3/tests/apis/test_webhook.py +257 -0
  48. fiddler3/tests/apis/test_xai.py +233 -1
  49. fiddler3/tests/conftest.py +2 -2
  50. fiddler3/tests/constants.py +5 -0
  51. fiddler3/tests/test_connection.py +24 -1
  52. fiddler3/tests/test_json_encoder.py +2 -2
  53. fiddler3/utils/helpers.py +20 -0
  54. {fiddler_client-2.4.0.dev2.dist-info → fiddler_client-2.5.0.dev2.dist-info}/METADATA +15 -5
  55. {fiddler_client-2.4.0.dev2.dist-info → fiddler_client-2.5.0.dev2.dist-info}/RECORD +59 -44
  56. tests/fiddler/test_alert.py +95 -5
  57. fiddler3/entities/helpers.py +0 -21
  58. fiddler3/schemas/model_artifact.py +0 -6
  59. {fiddler_client-2.4.0.dev2.dist-info → fiddler_client-2.5.0.dev2.dist-info}/LICENSE.txt +0 -0
  60. {fiddler_client-2.4.0.dev2.dist-info → fiddler_client-2.5.0.dev2.dist-info}/WHEEL +0 -0
  61. {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
- raise ValueError(f'Output dir already exists {output_dir}')
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(
@@ -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)
@@ -8,5 +8,5 @@ class RequestClientJSONEncoder(JSONEncoder):
8
8
  def default(self, o: Any) -> Any:
9
9
  """Override JSONEncoder.default to support uuid serialization"""
10
10
  if isinstance(o, UUID):
11
- return o.hex
11
+ return str(o)
12
12
  return super().default(o)
@@ -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
- class CustomFeatureType(str, Enum):
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
@@ -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 Column, ModelSchema
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