mlrun 1.10.0rc16__py3-none-any.whl → 1.10.0rc42__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.
Potentially problematic release.
This version of mlrun might be problematic. Click here for more details.
- mlrun/__init__.py +22 -2
- mlrun/artifacts/document.py +6 -1
- mlrun/artifacts/llm_prompt.py +21 -15
- mlrun/artifacts/model.py +3 -3
- mlrun/common/constants.py +9 -0
- mlrun/common/formatters/artifact.py +1 -0
- mlrun/common/model_monitoring/helpers.py +86 -0
- mlrun/common/schemas/__init__.py +2 -0
- mlrun/common/schemas/auth.py +2 -0
- mlrun/common/schemas/function.py +10 -0
- mlrun/common/schemas/hub.py +30 -18
- mlrun/common/schemas/model_monitoring/__init__.py +2 -0
- mlrun/common/schemas/model_monitoring/constants.py +30 -6
- mlrun/common/schemas/model_monitoring/functions.py +13 -4
- mlrun/common/schemas/model_monitoring/model_endpoints.py +11 -0
- mlrun/common/schemas/pipeline.py +1 -1
- mlrun/common/schemas/serving.py +3 -0
- mlrun/common/schemas/workflow.py +1 -0
- mlrun/common/secrets.py +22 -1
- mlrun/config.py +32 -10
- mlrun/datastore/__init__.py +11 -3
- mlrun/datastore/azure_blob.py +162 -47
- mlrun/datastore/datastore.py +9 -4
- mlrun/datastore/datastore_profile.py +61 -5
- mlrun/datastore/model_provider/huggingface_provider.py +363 -0
- mlrun/datastore/model_provider/mock_model_provider.py +87 -0
- mlrun/datastore/model_provider/model_provider.py +211 -74
- mlrun/datastore/model_provider/openai_provider.py +243 -71
- mlrun/datastore/s3.py +24 -2
- mlrun/datastore/storeytargets.py +2 -3
- mlrun/datastore/utils.py +15 -3
- mlrun/db/base.py +27 -19
- mlrun/db/httpdb.py +57 -48
- mlrun/db/nopdb.py +25 -10
- mlrun/execution.py +55 -13
- mlrun/hub/__init__.py +15 -0
- mlrun/hub/module.py +181 -0
- mlrun/k8s_utils.py +105 -16
- mlrun/launcher/base.py +13 -6
- mlrun/launcher/local.py +2 -0
- mlrun/model.py +9 -3
- mlrun/model_monitoring/api.py +66 -27
- mlrun/model_monitoring/applications/__init__.py +1 -1
- mlrun/model_monitoring/applications/base.py +372 -136
- mlrun/model_monitoring/applications/context.py +2 -4
- mlrun/model_monitoring/applications/results.py +4 -7
- mlrun/model_monitoring/controller.py +239 -101
- mlrun/model_monitoring/db/_schedules.py +36 -13
- mlrun/model_monitoring/db/_stats.py +4 -3
- mlrun/model_monitoring/db/tsdb/base.py +29 -9
- mlrun/model_monitoring/db/tsdb/tdengine/schemas.py +4 -5
- mlrun/model_monitoring/db/tsdb/tdengine/tdengine_connector.py +154 -50
- mlrun/model_monitoring/db/tsdb/tdengine/writer_graph_steps.py +51 -0
- mlrun/model_monitoring/db/tsdb/v3io/stream_graph_steps.py +17 -4
- mlrun/model_monitoring/db/tsdb/v3io/v3io_connector.py +245 -51
- mlrun/model_monitoring/helpers.py +28 -5
- mlrun/model_monitoring/stream_processing.py +45 -14
- mlrun/model_monitoring/writer.py +220 -1
- mlrun/platforms/__init__.py +3 -2
- mlrun/platforms/iguazio.py +7 -3
- mlrun/projects/operations.py +6 -1
- mlrun/projects/pipelines.py +2 -2
- mlrun/projects/project.py +128 -45
- mlrun/run.py +94 -17
- mlrun/runtimes/__init__.py +18 -0
- mlrun/runtimes/base.py +14 -6
- mlrun/runtimes/daskjob.py +1 -0
- mlrun/runtimes/local.py +5 -2
- mlrun/runtimes/mounts.py +20 -2
- mlrun/runtimes/nuclio/__init__.py +1 -0
- mlrun/runtimes/nuclio/application/application.py +147 -17
- mlrun/runtimes/nuclio/function.py +70 -27
- mlrun/runtimes/nuclio/serving.py +85 -4
- mlrun/runtimes/pod.py +213 -21
- mlrun/runtimes/utils.py +49 -9
- mlrun/secrets.py +54 -13
- mlrun/serving/remote.py +79 -6
- mlrun/serving/routers.py +23 -41
- mlrun/serving/server.py +211 -40
- mlrun/serving/states.py +536 -156
- mlrun/serving/steps.py +62 -0
- mlrun/serving/system_steps.py +136 -81
- mlrun/serving/v2_serving.py +9 -10
- mlrun/utils/helpers.py +212 -82
- mlrun/utils/logger.py +3 -1
- mlrun/utils/notifications/notification/base.py +18 -0
- mlrun/utils/notifications/notification/git.py +2 -4
- mlrun/utils/notifications/notification/slack.py +2 -4
- mlrun/utils/notifications/notification/webhook.py +2 -5
- mlrun/utils/notifications/notification_pusher.py +1 -1
- mlrun/utils/version/version.json +2 -2
- {mlrun-1.10.0rc16.dist-info → mlrun-1.10.0rc42.dist-info}/METADATA +44 -45
- {mlrun-1.10.0rc16.dist-info → mlrun-1.10.0rc42.dist-info}/RECORD +97 -92
- mlrun/api/schemas/__init__.py +0 -259
- {mlrun-1.10.0rc16.dist-info → mlrun-1.10.0rc42.dist-info}/WHEEL +0 -0
- {mlrun-1.10.0rc16.dist-info → mlrun-1.10.0rc42.dist-info}/entry_points.txt +0 -0
- {mlrun-1.10.0rc16.dist-info → mlrun-1.10.0rc42.dist-info}/licenses/LICENSE +0 -0
- {mlrun-1.10.0rc16.dist-info → mlrun-1.10.0rc42.dist-info}/top_level.txt +0 -0
mlrun/db/httpdb.py
CHANGED
|
@@ -24,6 +24,7 @@ from datetime import datetime, timedelta
|
|
|
24
24
|
from os import environ, path, remove
|
|
25
25
|
from typing import Literal, Optional, Union
|
|
26
26
|
from urllib.parse import urlparse
|
|
27
|
+
from uuid import UUID
|
|
27
28
|
|
|
28
29
|
import pydantic.v1
|
|
29
30
|
import requests
|
|
@@ -44,6 +45,7 @@ import mlrun.runtimes.nuclio.api_gateway
|
|
|
44
45
|
import mlrun.runtimes.nuclio.function
|
|
45
46
|
import mlrun.utils
|
|
46
47
|
from mlrun.alerts.alert import AlertConfig
|
|
48
|
+
from mlrun.common.schemas.hub import HubSourceType
|
|
47
49
|
from mlrun.db.auth_utils import OAuthClientIDTokenProvider, StaticTokenProvider
|
|
48
50
|
from mlrun.errors import MLRunInvalidArgumentError, err_to_str
|
|
49
51
|
from mlrun.secrets import get_secret_or_env
|
|
@@ -2554,50 +2556,6 @@ class HTTPRunDB(RunDBInterface):
|
|
|
2554
2556
|
resp = self.api_call("GET", path, error_message)
|
|
2555
2557
|
return FeatureSet.from_dict(resp.json())
|
|
2556
2558
|
|
|
2557
|
-
def list_features(
|
|
2558
|
-
self,
|
|
2559
|
-
project: Optional[str] = None,
|
|
2560
|
-
name: Optional[str] = None,
|
|
2561
|
-
tag: Optional[str] = None,
|
|
2562
|
-
entities: Optional[list[str]] = None,
|
|
2563
|
-
labels: Optional[Union[str, dict[str, Optional[str]], list[str]]] = None,
|
|
2564
|
-
) -> list[dict]:
|
|
2565
|
-
"""List feature-sets which contain specific features. This function may return multiple versions of the same
|
|
2566
|
-
feature-set if a specific tag is not requested. Note that the various filters of this function actually
|
|
2567
|
-
refer to the feature-set object containing the features, not to the features themselves.
|
|
2568
|
-
|
|
2569
|
-
:param project: Project which contains these features.
|
|
2570
|
-
:param name: Name of the feature to look for. The name is used in a like query, and is not case-sensitive. For
|
|
2571
|
-
example, looking for ``feat`` will return features which are named ``MyFeature`` as well as ``defeat``.
|
|
2572
|
-
:param tag: Return feature-sets which contain the features looked for, and are tagged with the specific tag.
|
|
2573
|
-
:param entities: Return only feature-sets which contain an entity whose name is contained in this list.
|
|
2574
|
-
:param labels: Filter feature-sets by label key-value pairs or key existence. This can be provided as:
|
|
2575
|
-
- A dictionary in the format `{"label": "value"}` to match specific label key-value pairs,
|
|
2576
|
-
or `{"label": None}` to check for key existence.
|
|
2577
|
-
- A list of strings formatted as `"label=value"` to match specific label key-value pairs,
|
|
2578
|
-
or just `"label"` for key existence.
|
|
2579
|
-
- A comma-separated string formatted as `"label1=value1,label2"` to match entities with
|
|
2580
|
-
the specified key-value pairs or key existence.
|
|
2581
|
-
:returns: A list of mapping from feature to a digest of the feature-set, which contains the feature-set
|
|
2582
|
-
meta-data. Multiple entries may be returned for any specific feature due to multiple tags or versions
|
|
2583
|
-
of the feature-set.
|
|
2584
|
-
"""
|
|
2585
|
-
|
|
2586
|
-
project = project or config.active_project
|
|
2587
|
-
labels = self._parse_labels(labels)
|
|
2588
|
-
params = {
|
|
2589
|
-
"name": name,
|
|
2590
|
-
"tag": tag,
|
|
2591
|
-
"entity": entities or [],
|
|
2592
|
-
"label": labels,
|
|
2593
|
-
}
|
|
2594
|
-
|
|
2595
|
-
path = f"projects/{project}/features"
|
|
2596
|
-
|
|
2597
|
-
error_message = f"Failed listing features, project: {project}, query: {params}"
|
|
2598
|
-
resp = self.api_call("GET", path, error_message, params=params)
|
|
2599
|
-
return resp.json()["features"]
|
|
2600
|
-
|
|
2601
2559
|
def list_features_v2(
|
|
2602
2560
|
self,
|
|
2603
2561
|
project: Optional[str] = None,
|
|
@@ -3623,7 +3581,7 @@ class HTTPRunDB(RunDBInterface):
|
|
|
3623
3581
|
intersection {"intersect_metrics":[], "intersect_results":[]}
|
|
3624
3582
|
:return: A dictionary of application metrics and/or results for the model endpoints formatted by events_format.
|
|
3625
3583
|
"""
|
|
3626
|
-
path = f"projects/{project}/model-
|
|
3584
|
+
path = f"projects/{project}/model-monitoring/metrics"
|
|
3627
3585
|
params = {
|
|
3628
3586
|
"type": type,
|
|
3629
3587
|
"endpoint-id": endpoint_ids,
|
|
@@ -3813,6 +3771,9 @@ class HTTPRunDB(RunDBInterface):
|
|
|
3813
3771
|
tsdb_metrics: bool = False,
|
|
3814
3772
|
metric_list: Optional[list[str]] = None,
|
|
3815
3773
|
top_level: bool = False,
|
|
3774
|
+
modes: Optional[
|
|
3775
|
+
Union[mm_constants.EndpointMode, list[mm_constants.EndpointMode]]
|
|
3776
|
+
] = None,
|
|
3816
3777
|
uids: Optional[list[str]] = None,
|
|
3817
3778
|
latest_only: bool = False,
|
|
3818
3779
|
) -> mlrun.common.schemas.ModelEndpointList:
|
|
@@ -3833,6 +3794,8 @@ class HTTPRunDB(RunDBInterface):
|
|
|
3833
3794
|
If tsdb_metrics=False, this parameter will be ignored and no tsdb metrics
|
|
3834
3795
|
will be included.
|
|
3835
3796
|
:param top_level: Whether to return only top level model endpoints.
|
|
3797
|
+
:param modes: Specifies the modes of the model endpoints. Can be "real-time" (0), "batch" (1),
|
|
3798
|
+
"batch_legacy" (2). If set to None, all are included.
|
|
3836
3799
|
:param uids: A list of unique ids to filter by.
|
|
3837
3800
|
:param latest_only: Whether to return only the latest model endpoint version.
|
|
3838
3801
|
:return: A list of model endpoints.
|
|
@@ -3841,6 +3804,13 @@ class HTTPRunDB(RunDBInterface):
|
|
|
3841
3804
|
labels = self._parse_labels(labels)
|
|
3842
3805
|
if names and isinstance(names, str):
|
|
3843
3806
|
names = [names]
|
|
3807
|
+
if modes:
|
|
3808
|
+
# Ensure backward compatibility with Python 3.9 clients by converting IntEnum modes to integer values
|
|
3809
|
+
modes = (
|
|
3810
|
+
[modes.value]
|
|
3811
|
+
if isinstance(modes, mm_constants.EndpointMode)
|
|
3812
|
+
else [mode.value for mode in modes]
|
|
3813
|
+
)
|
|
3844
3814
|
response = self.api_call(
|
|
3845
3815
|
method=mlrun.common.types.HTTPMethod.GET,
|
|
3846
3816
|
path=path,
|
|
@@ -3856,6 +3826,7 @@ class HTTPRunDB(RunDBInterface):
|
|
|
3856
3826
|
"tsdb-metrics": tsdb_metrics,
|
|
3857
3827
|
"metric": metric_list,
|
|
3858
3828
|
"top-level": top_level,
|
|
3829
|
+
"mode": modes,
|
|
3859
3830
|
"uid": uids,
|
|
3860
3831
|
"latest-only": latest_only,
|
|
3861
3832
|
},
|
|
@@ -3964,6 +3935,13 @@ class HTTPRunDB(RunDBInterface):
|
|
|
3964
3935
|
raise MLRunInvalidArgumentError(
|
|
3965
3936
|
"Either endpoint_uid or function_name and function_tag must be provided"
|
|
3966
3937
|
)
|
|
3938
|
+
if uid:
|
|
3939
|
+
try:
|
|
3940
|
+
UUID(uid)
|
|
3941
|
+
except (ValueError, TypeError):
|
|
3942
|
+
raise MLRunInvalidArgumentError(
|
|
3943
|
+
"endpoint_id must be a valid UUID string"
|
|
3944
|
+
)
|
|
3967
3945
|
|
|
3968
3946
|
def update_model_monitoring_controller(
|
|
3969
3947
|
self,
|
|
@@ -4111,7 +4089,7 @@ class HTTPRunDB(RunDBInterface):
|
|
|
4111
4089
|
response = self.api_call(
|
|
4112
4090
|
method=mlrun.common.types.HTTPMethod.DELETE,
|
|
4113
4091
|
path=f"projects/{project}/model-monitoring/functions",
|
|
4114
|
-
params={"
|
|
4092
|
+
params={"function": functions},
|
|
4115
4093
|
)
|
|
4116
4094
|
deletion_failed = False
|
|
4117
4095
|
if response.status_code == http.HTTPStatus.ACCEPTED:
|
|
@@ -4153,6 +4131,26 @@ class HTTPRunDB(RunDBInterface):
|
|
|
4153
4131
|
params={**credentials, "replace_creds": replace_creds},
|
|
4154
4132
|
)
|
|
4155
4133
|
|
|
4134
|
+
def delete_model_monitoring_metrics(
|
|
4135
|
+
self,
|
|
4136
|
+
project: str,
|
|
4137
|
+
application_name: str,
|
|
4138
|
+
endpoint_ids: Optional[list[str]] = None,
|
|
4139
|
+
) -> None:
|
|
4140
|
+
"""
|
|
4141
|
+
Delete model endpoints metrics values.
|
|
4142
|
+
|
|
4143
|
+
:param project: The name of the project.
|
|
4144
|
+
:param application_name: The name of the application.
|
|
4145
|
+
:param endpoint_ids: The unique IDs of the model endpoints to delete metrics values from. If none is
|
|
4146
|
+
provided, the metrics values will be deleted from all project's model endpoints.
|
|
4147
|
+
"""
|
|
4148
|
+
self.api_call(
|
|
4149
|
+
method=mlrun.common.types.HTTPMethod.DELETE,
|
|
4150
|
+
path=f"projects/{project}/model-monitoring/metrics",
|
|
4151
|
+
params={"endpoint-id": endpoint_ids, "application-name": application_name},
|
|
4152
|
+
)
|
|
4153
|
+
|
|
4156
4154
|
def get_monitoring_function_summaries(
|
|
4157
4155
|
self,
|
|
4158
4156
|
project: str,
|
|
@@ -4319,6 +4317,7 @@ class HTTPRunDB(RunDBInterface):
|
|
|
4319
4317
|
item_name: Optional[str] = None,
|
|
4320
4318
|
tag: Optional[str] = None,
|
|
4321
4319
|
version: Optional[str] = None,
|
|
4320
|
+
item_type: HubSourceType = HubSourceType.functions,
|
|
4322
4321
|
) -> list[mlrun.common.schemas.hub.IndexedHubSource]:
|
|
4323
4322
|
"""
|
|
4324
4323
|
List hub sources in the MLRun DB.
|
|
@@ -4326,6 +4325,7 @@ class HTTPRunDB(RunDBInterface):
|
|
|
4326
4325
|
:param item_name: Sources contain this item will be returned, If not provided all sources will be returned.
|
|
4327
4326
|
:param tag: Item tag to filter by, supported only if item name is provided.
|
|
4328
4327
|
:param version: Item version to filter by, supported only if item name is provided and tag is not.
|
|
4328
|
+
:param item_type: Item type to filter by, supported only if item name is provided.
|
|
4329
4329
|
|
|
4330
4330
|
:returns: List of indexed hub sources.
|
|
4331
4331
|
"""
|
|
@@ -4333,6 +4333,7 @@ class HTTPRunDB(RunDBInterface):
|
|
|
4333
4333
|
params = {}
|
|
4334
4334
|
if item_name:
|
|
4335
4335
|
params["item-name"] = normalize_name(item_name)
|
|
4336
|
+
params["item-type"] = item_type
|
|
4336
4337
|
if tag:
|
|
4337
4338
|
params["tag"] = tag
|
|
4338
4339
|
if version:
|
|
@@ -4371,6 +4372,7 @@ class HTTPRunDB(RunDBInterface):
|
|
|
4371
4372
|
version: Optional[str] = None,
|
|
4372
4373
|
tag: Optional[str] = None,
|
|
4373
4374
|
force_refresh: bool = False,
|
|
4375
|
+
object_type: HubSourceType = HubSourceType.functions,
|
|
4374
4376
|
):
|
|
4375
4377
|
"""
|
|
4376
4378
|
Retrieve the item catalog for a specified hub source.
|
|
@@ -4383,6 +4385,7 @@ class HTTPRunDB(RunDBInterface):
|
|
|
4383
4385
|
rather than rely on cached information which may exist from previous get requests. For example,
|
|
4384
4386
|
if the source was re-built,
|
|
4385
4387
|
this will make the server get the updated information. Default is ``False``.
|
|
4388
|
+
:param object_type: Type of object to retrieve from the hub source (e.g: functions, modules).
|
|
4386
4389
|
:returns: :py:class:`~mlrun.common.schemas.hub.HubCatalog` object, which is essentially a list
|
|
4387
4390
|
of :py:class:`~mlrun.common.schemas.hub.HubItem` entries.
|
|
4388
4391
|
"""
|
|
@@ -4391,6 +4394,7 @@ class HTTPRunDB(RunDBInterface):
|
|
|
4391
4394
|
"version": version,
|
|
4392
4395
|
"tag": tag,
|
|
4393
4396
|
"force-refresh": force_refresh,
|
|
4397
|
+
"object_type": object_type,
|
|
4394
4398
|
}
|
|
4395
4399
|
response = self.api_call(method="GET", path=path, params=params)
|
|
4396
4400
|
return mlrun.common.schemas.HubCatalog(**response.json())
|
|
@@ -4402,6 +4406,7 @@ class HTTPRunDB(RunDBInterface):
|
|
|
4402
4406
|
version: Optional[str] = None,
|
|
4403
4407
|
tag: str = "latest",
|
|
4404
4408
|
force_refresh: bool = False,
|
|
4409
|
+
item_type: HubSourceType = HubSourceType.functions,
|
|
4405
4410
|
):
|
|
4406
4411
|
"""
|
|
4407
4412
|
Retrieve a specific hub item.
|
|
@@ -4413,6 +4418,7 @@ class HTTPRunDB(RunDBInterface):
|
|
|
4413
4418
|
:param force_refresh: Make the server fetch the information from the actual hub
|
|
4414
4419
|
source, rather than
|
|
4415
4420
|
rely on cached information. Default is ``False``.
|
|
4421
|
+
:param item_type: The type of item to retrieve from the hub source (e.g: functions, modules).
|
|
4416
4422
|
:returns: :py:class:`~mlrun.common.schemas.hub.HubItem`.
|
|
4417
4423
|
"""
|
|
4418
4424
|
path = (f"hub/sources/{source_name}/items/{item_name}",)
|
|
@@ -4420,6 +4426,7 @@ class HTTPRunDB(RunDBInterface):
|
|
|
4420
4426
|
"version": version,
|
|
4421
4427
|
"tag": tag,
|
|
4422
4428
|
"force-refresh": force_refresh,
|
|
4429
|
+
"item_type": item_type,
|
|
4423
4430
|
}
|
|
4424
4431
|
response = self.api_call(method="GET", path=path, params=params)
|
|
4425
4432
|
return mlrun.common.schemas.HubItem(**response.json())
|
|
@@ -4431,6 +4438,7 @@ class HTTPRunDB(RunDBInterface):
|
|
|
4431
4438
|
asset_name: str,
|
|
4432
4439
|
version: Optional[str] = None,
|
|
4433
4440
|
tag: str = "latest",
|
|
4441
|
+
item_type: HubSourceType = HubSourceType.functions,
|
|
4434
4442
|
):
|
|
4435
4443
|
"""
|
|
4436
4444
|
Get hub asset from item.
|
|
@@ -4440,13 +4448,14 @@ class HTTPRunDB(RunDBInterface):
|
|
|
4440
4448
|
:param asset_name: Name of the asset to retrieve.
|
|
4441
4449
|
:param version: Get a specific version of the item. Default is ``None``.
|
|
4442
4450
|
:param tag: Get a specific version of the item identified by tag. Default is ``latest``.
|
|
4443
|
-
|
|
4451
|
+
:param item_type: The type of item to retrieve from the hub source (e.g: functions, modules).
|
|
4444
4452
|
:returns: http response with the asset in the content attribute
|
|
4445
4453
|
"""
|
|
4446
4454
|
path = f"hub/sources/{source_name}/items/{item_name}/assets/{asset_name}"
|
|
4447
4455
|
params = {
|
|
4448
4456
|
"version": version,
|
|
4449
4457
|
"tag": tag,
|
|
4458
|
+
"item_type": item_type,
|
|
4450
4459
|
}
|
|
4451
4460
|
response = self.api_call(method="GET", path=path, params=params)
|
|
4452
4461
|
return response
|
|
@@ -5201,7 +5210,7 @@ class HTTPRunDB(RunDBInterface):
|
|
|
5201
5210
|
|
|
5202
5211
|
:return: A ModelEndpointDriftValues object containing the drift counts over time.
|
|
5203
5212
|
"""
|
|
5204
|
-
endpoint_path = f"projects/{project}/model-
|
|
5213
|
+
endpoint_path = f"projects/{project}/model-monitoring/drift-over-time"
|
|
5205
5214
|
error_message = f"Failed retrieving drift data for {project}"
|
|
5206
5215
|
response = self.api_call(
|
|
5207
5216
|
method="GET",
|
mlrun/db/nopdb.py
CHANGED
|
@@ -376,16 +376,6 @@ class NopDB(RunDBInterface):
|
|
|
376
376
|
) -> dict:
|
|
377
377
|
pass
|
|
378
378
|
|
|
379
|
-
def list_features(
|
|
380
|
-
self,
|
|
381
|
-
project: str,
|
|
382
|
-
name: Optional[str] = None,
|
|
383
|
-
tag: Optional[str] = None,
|
|
384
|
-
entities: Optional[list[str]] = None,
|
|
385
|
-
labels: Optional[Union[str, dict[str, Optional[str]], list[str]]] = None,
|
|
386
|
-
) -> mlrun.common.schemas.FeaturesOutput:
|
|
387
|
-
pass
|
|
388
|
-
|
|
389
379
|
def list_features_v2(
|
|
390
380
|
self,
|
|
391
381
|
project: str,
|
|
@@ -636,6 +626,9 @@ class NopDB(RunDBInterface):
|
|
|
636
626
|
tsdb_metrics: bool = False,
|
|
637
627
|
metric_list: Optional[list[str]] = None,
|
|
638
628
|
top_level: bool = False,
|
|
629
|
+
modes: Optional[
|
|
630
|
+
Union[mm_constants.EndpointMode, list[mm_constants.EndpointMode]]
|
|
631
|
+
] = None,
|
|
639
632
|
uids: Optional[list[str]] = None,
|
|
640
633
|
latest_only: bool = False,
|
|
641
634
|
) -> mlrun.common.schemas.ModelEndpointList:
|
|
@@ -682,6 +675,7 @@ class NopDB(RunDBInterface):
|
|
|
682
675
|
item_name: Optional[str] = None,
|
|
683
676
|
tag: Optional[str] = None,
|
|
684
677
|
version: Optional[str] = None,
|
|
678
|
+
item_type: mlrun.common.schemas.hub.HubSourceType = mlrun.common.schemas.hub.HubSourceType.functions,
|
|
685
679
|
):
|
|
686
680
|
pass
|
|
687
681
|
|
|
@@ -698,6 +692,7 @@ class NopDB(RunDBInterface):
|
|
|
698
692
|
version: Optional[str] = None,
|
|
699
693
|
tag: Optional[str] = None,
|
|
700
694
|
force_refresh: bool = False,
|
|
695
|
+
object_type: mlrun.common.schemas.hub.HubSourceType = mlrun.common.schemas.hub.HubSourceType.functions,
|
|
701
696
|
):
|
|
702
697
|
pass
|
|
703
698
|
|
|
@@ -709,6 +704,18 @@ class NopDB(RunDBInterface):
|
|
|
709
704
|
version: Optional[str] = None,
|
|
710
705
|
tag: str = "latest",
|
|
711
706
|
force_refresh: bool = False,
|
|
707
|
+
item_type: mlrun.common.schemas.hub.HubSourceType = mlrun.common.schemas.hub.HubSourceType.functions,
|
|
708
|
+
):
|
|
709
|
+
pass
|
|
710
|
+
|
|
711
|
+
def get_hub_asset(
|
|
712
|
+
self,
|
|
713
|
+
source_name: str,
|
|
714
|
+
item_name: str,
|
|
715
|
+
asset_name: str,
|
|
716
|
+
version: Optional[str] = None,
|
|
717
|
+
tag: str = "latest",
|
|
718
|
+
item_type: mlrun.common.schemas.hub.HubSourceType = mlrun.common.schemas.hub.HubSourceType.functions,
|
|
712
719
|
):
|
|
713
720
|
pass
|
|
714
721
|
|
|
@@ -895,6 +902,14 @@ class NopDB(RunDBInterface):
|
|
|
895
902
|
) -> None:
|
|
896
903
|
pass
|
|
897
904
|
|
|
905
|
+
def delete_model_monitoring_metrics(
|
|
906
|
+
self,
|
|
907
|
+
project: str,
|
|
908
|
+
application_name: str,
|
|
909
|
+
endpoint_ids: Optional[list[str]] = None,
|
|
910
|
+
) -> None:
|
|
911
|
+
pass
|
|
912
|
+
|
|
898
913
|
def get_monitoring_function_summaries(
|
|
899
914
|
self,
|
|
900
915
|
project: str,
|
mlrun/execution.py
CHANGED
|
@@ -917,7 +917,7 @@ class MLClientCtx:
|
|
|
917
917
|
prompt_path: Optional[str] = None,
|
|
918
918
|
prompt_legend: Optional[dict] = None,
|
|
919
919
|
model_artifact: Union[ModelArtifact, str] = None,
|
|
920
|
-
|
|
920
|
+
invocation_config: Optional[dict] = None,
|
|
921
921
|
description: Optional[str] = None,
|
|
922
922
|
target_path: Optional[str] = None,
|
|
923
923
|
artifact_path: Optional[str] = None,
|
|
@@ -934,14 +934,51 @@ class MLClientCtx:
|
|
|
934
934
|
|
|
935
935
|
Examples::
|
|
936
936
|
|
|
937
|
-
# Log an inline prompt
|
|
937
|
+
# Log directly with an inline prompt template
|
|
938
938
|
context.log_llm_prompt(
|
|
939
|
-
key="
|
|
940
|
-
prompt_template=[
|
|
939
|
+
key="customer_support_prompt",
|
|
940
|
+
prompt_template=[
|
|
941
|
+
{
|
|
942
|
+
"role": "system",
|
|
943
|
+
"content": "You are a helpful customer support assistant.",
|
|
944
|
+
},
|
|
945
|
+
{
|
|
946
|
+
"role": "user",
|
|
947
|
+
"content": "The customer reports: {issue_description}",
|
|
948
|
+
},
|
|
949
|
+
],
|
|
950
|
+
prompt_legend={
|
|
951
|
+
"issue_description": {
|
|
952
|
+
"field": "user_issue",
|
|
953
|
+
"description": "Detailed description of the customer's issue",
|
|
954
|
+
},
|
|
955
|
+
"solution": {
|
|
956
|
+
"field": "proposed_solution",
|
|
957
|
+
"description": "Suggested fix for the customer's issue",
|
|
958
|
+
},
|
|
959
|
+
},
|
|
941
960
|
model_artifact=model,
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
tag="
|
|
961
|
+
invocation_config={"temperature": 0.5, "max_tokens": 200},
|
|
962
|
+
description="Prompt for handling customer support queries",
|
|
963
|
+
tag="support-v1",
|
|
964
|
+
labels={"domain": "support"},
|
|
965
|
+
)
|
|
966
|
+
|
|
967
|
+
# Log a prompt from file
|
|
968
|
+
context.log_llm_prompt(
|
|
969
|
+
key="qa_prompt",
|
|
970
|
+
prompt_path="prompts/template.json",
|
|
971
|
+
prompt_legend={
|
|
972
|
+
"question": {
|
|
973
|
+
"field": "user_question",
|
|
974
|
+
"description": "The actual question asked by the user",
|
|
975
|
+
}
|
|
976
|
+
},
|
|
977
|
+
model_artifact=model,
|
|
978
|
+
invocation_config={"temperature": 0.7, "max_tokens": 256},
|
|
979
|
+
description="Q&A prompt template with user-provided question",
|
|
980
|
+
tag="v2",
|
|
981
|
+
labels={"task": "qa", "stage": "experiment"},
|
|
945
982
|
)
|
|
946
983
|
|
|
947
984
|
:param key: Unique name of the artifact.
|
|
@@ -950,17 +987,22 @@ class MLClientCtx:
|
|
|
950
987
|
"role": "user", "content": "I need your help with {profession}"]. only "role" and "content" keys allow in any
|
|
951
988
|
str format (upper/lower case), keys will be modified to lower case.
|
|
952
989
|
Cannot be used with `prompt_path`.
|
|
953
|
-
:param prompt_path: Path to a file containing the prompt
|
|
990
|
+
:param prompt_path: Path to a JSON file containing the prompt template.
|
|
991
|
+
Cannot be used together with `prompt_template`.
|
|
992
|
+
The file should define a list of dictionaries in the same format
|
|
993
|
+
supported by `prompt_template`.
|
|
954
994
|
:param prompt_legend: A dictionary where each key is a placeholder in the prompt (e.g., ``{user_name}``)
|
|
955
995
|
and the value is a dictionary holding two keys, "field", "description". "field" points to the field in
|
|
956
996
|
the event where the value of the place-holder inside the event, if None or not exist will be replaced
|
|
957
997
|
with the place-holder name. "description" will point to explanation of what that placeholder represents.
|
|
958
998
|
Useful for documenting and clarifying dynamic parts of the prompt.
|
|
959
999
|
:param model_artifact: Reference to the parent model (either `ModelArtifact` or model URI string).
|
|
960
|
-
:param
|
|
961
|
-
:param description:
|
|
962
|
-
:param target_path:
|
|
963
|
-
:param artifact_path:
|
|
1000
|
+
:param invocation_config: Dictionary of generation parameters (e.g., temperature, max_tokens).
|
|
1001
|
+
:param description: Optional description of the prompt.
|
|
1002
|
+
:param target_path: Absolute target path (instead of using artifact_path + local_path)
|
|
1003
|
+
:param artifact_path: Target artifact path (when not using the default)
|
|
1004
|
+
To define a subpath under the default location use:
|
|
1005
|
+
`artifact_path=context.artifact_subpath('data')`
|
|
964
1006
|
:param tag: Tag/version to assign to the prompt artifact.
|
|
965
1007
|
:param labels: Labels to tag the artifact (e.g., list or dict of key-value pairs).
|
|
966
1008
|
:param upload: Whether to upload the artifact to the store (defaults to True).
|
|
@@ -981,7 +1023,7 @@ class MLClientCtx:
|
|
|
981
1023
|
prompt_path=prompt_path,
|
|
982
1024
|
prompt_legend=prompt_legend,
|
|
983
1025
|
model_artifact=model_artifact,
|
|
984
|
-
|
|
1026
|
+
invocation_config=invocation_config,
|
|
985
1027
|
target_path=target_path,
|
|
986
1028
|
description=description,
|
|
987
1029
|
**kwargs,
|
mlrun/hub/__init__.py
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Copyright 2025 Iguazio
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
from .module import get_hub_module, import_module
|
mlrun/hub/module.py
ADDED
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
# Copyright 2025 Iguazio
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
import os
|
|
16
|
+
import subprocess
|
|
17
|
+
import sys
|
|
18
|
+
from pathlib import Path
|
|
19
|
+
from typing import Optional, Union
|
|
20
|
+
|
|
21
|
+
import yaml
|
|
22
|
+
|
|
23
|
+
import mlrun.common.types
|
|
24
|
+
import mlrun.utils
|
|
25
|
+
from mlrun.common.schemas.hub import HubModuleType, HubSourceType
|
|
26
|
+
from mlrun.run import function_to_module, get_object
|
|
27
|
+
from mlrun.utils import logger
|
|
28
|
+
|
|
29
|
+
from ..errors import MLRunBadRequestError
|
|
30
|
+
from ..model import ModelObj
|
|
31
|
+
from ..utils import extend_hub_uri_if_needed
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class HubModule(ModelObj):
|
|
35
|
+
def __init__(
|
|
36
|
+
self,
|
|
37
|
+
name: str,
|
|
38
|
+
kind: Union[HubModuleType, str],
|
|
39
|
+
version: Optional[str] = None,
|
|
40
|
+
description: Optional[str] = None,
|
|
41
|
+
categories: Optional[list] = None,
|
|
42
|
+
requirements: Optional[list] = None,
|
|
43
|
+
local_path: Optional[str] = None,
|
|
44
|
+
filename: Optional[str] = None,
|
|
45
|
+
example: Optional[str] = None,
|
|
46
|
+
url: Optional[str] = None,
|
|
47
|
+
**kwargs, # catch all for unused args
|
|
48
|
+
):
|
|
49
|
+
self.name: str = name
|
|
50
|
+
self.version: str = version
|
|
51
|
+
self.kind: HubModuleType = kind
|
|
52
|
+
self.description: str = description or ""
|
|
53
|
+
self.categories: list = categories or []
|
|
54
|
+
self.requirements: list = requirements or []
|
|
55
|
+
self.local_path: str = local_path or ""
|
|
56
|
+
self.filename: str = filename or name + ".py"
|
|
57
|
+
self.example: str = example or ""
|
|
58
|
+
self.url: str = url or ""
|
|
59
|
+
|
|
60
|
+
def module(self):
|
|
61
|
+
"""Import the module after downloading its fils to local_path"""
|
|
62
|
+
try:
|
|
63
|
+
return function_to_module(code=self.filename, workdir=self.local_path)
|
|
64
|
+
except FileNotFoundError:
|
|
65
|
+
searched_path = self.local_path or "./"
|
|
66
|
+
raise FileNotFoundError(
|
|
67
|
+
f"Module file {self.filename} not found in {searched_path}, try calling download_module_files() first"
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
def install_requirements(self) -> None:
|
|
71
|
+
"""
|
|
72
|
+
Install pip-style requirements (e.g., ["pandas>=2.0.0", "requests==2.31.0"]).
|
|
73
|
+
"""
|
|
74
|
+
for req in self.requirements:
|
|
75
|
+
logger.info(f"Installing {req} ...")
|
|
76
|
+
try:
|
|
77
|
+
subprocess.run(
|
|
78
|
+
[sys.executable, "-m", "pip", "install", req], check=True, text=True
|
|
79
|
+
)
|
|
80
|
+
logger.info(f"Installed {req}")
|
|
81
|
+
except subprocess.CalledProcessError as e:
|
|
82
|
+
logger.error(f"Failed to install {req} (exit code {e.returncode})")
|
|
83
|
+
|
|
84
|
+
def download_module_files(self, local_path=None, secrets=None):
|
|
85
|
+
"""
|
|
86
|
+
Download this hub module’s files (code file and, if available, an example notebook) to the target directory
|
|
87
|
+
specified by `local_path` (defaults to the current working directory).
|
|
88
|
+
This path will be used later to locate the code file when importing the module.
|
|
89
|
+
"""
|
|
90
|
+
self.local_path = self.verify_directory(path=local_path)
|
|
91
|
+
source_url, _ = extend_hub_uri_if_needed(
|
|
92
|
+
uri=self.url, asset_type=HubSourceType.modules, file=self.filename
|
|
93
|
+
)
|
|
94
|
+
self._download_object(
|
|
95
|
+
obj_url=source_url, target_name=self.filename, secrets=secrets
|
|
96
|
+
)
|
|
97
|
+
if self.example:
|
|
98
|
+
example_url, _ = extend_hub_uri_if_needed(
|
|
99
|
+
uri=self.url, asset_type=HubSourceType.modules, file=self.example
|
|
100
|
+
)
|
|
101
|
+
self._download_object(
|
|
102
|
+
obj_url=example_url, target_name=self.example, secrets=secrets
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
def _download_object(self, obj_url, target_name, secrets=None):
|
|
106
|
+
data = get_object(url=obj_url, secrets=secrets)
|
|
107
|
+
target_dir = self.local_path if self.local_path is not None else os.getcwd()
|
|
108
|
+
target_filepath = os.path.join(target_dir, target_name)
|
|
109
|
+
with open(target_filepath, "wb") as f:
|
|
110
|
+
f.write(data)
|
|
111
|
+
|
|
112
|
+
@staticmethod
|
|
113
|
+
def verify_directory(path: Optional[str] = None) -> Path:
|
|
114
|
+
"""
|
|
115
|
+
Validate that the given path is an existing directory.
|
|
116
|
+
If no path has been provided, returns current working directory.
|
|
117
|
+
"""
|
|
118
|
+
if path:
|
|
119
|
+
path = Path(path)
|
|
120
|
+
if not path.exists():
|
|
121
|
+
raise ValueError(f"Path does not exist: {path}")
|
|
122
|
+
if not path.is_dir():
|
|
123
|
+
raise ValueError(f"Path is not a directory: {path}")
|
|
124
|
+
return path
|
|
125
|
+
return Path(os.getcwd())
|
|
126
|
+
|
|
127
|
+
def get_module_file_path(self):
|
|
128
|
+
if not self.local_path:
|
|
129
|
+
raise MLRunBadRequestError(
|
|
130
|
+
"module files haven't been downloaded yet, try calling download_module_files() first"
|
|
131
|
+
)
|
|
132
|
+
return str(Path(self.local_path) / self.filename)
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def get_hub_module(
|
|
136
|
+
url: str = "",
|
|
137
|
+
download_files: Optional[bool] = True,
|
|
138
|
+
secrets: Optional[dict] = None,
|
|
139
|
+
local_path: Optional[str] = None,
|
|
140
|
+
) -> HubModule:
|
|
141
|
+
"""
|
|
142
|
+
Get a hub-module object containing metadata of the requested module.
|
|
143
|
+
:param url: Hub module url in the format "hub://[<source>/]<item-name>[:<tag>]"
|
|
144
|
+
:param download_files: When set to True, the module files (code file and example notebook) are downloaded
|
|
145
|
+
:param secrets: Optional, credentials dict for DB or URL (s3, v3io, ...)
|
|
146
|
+
:param local_path: Path to target directory for the module files. Ignored when download_files is set to False.
|
|
147
|
+
Defaults to the current working directory.
|
|
148
|
+
|
|
149
|
+
:return: HubModule object
|
|
150
|
+
"""
|
|
151
|
+
item_yaml_url, is_hub_uri = extend_hub_uri_if_needed(
|
|
152
|
+
uri=url, asset_type=HubSourceType.modules, file="item.yaml"
|
|
153
|
+
)
|
|
154
|
+
if not is_hub_uri:
|
|
155
|
+
raise mlrun.errors.MLRunInvalidArgumentError("Not a valid hub URL")
|
|
156
|
+
yaml_obj = get_object(url=item_yaml_url, secrets=secrets)
|
|
157
|
+
item_yaml = yaml.safe_load(yaml_obj)
|
|
158
|
+
spec = item_yaml.pop("spec", {})
|
|
159
|
+
hub_module = HubModule(**item_yaml, **spec, url=url)
|
|
160
|
+
if download_files:
|
|
161
|
+
hub_module.download_module_files(local_path=local_path, secrets=secrets)
|
|
162
|
+
return hub_module
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
def import_module(url="", install_requirements=False, secrets=None, local_path=None):
|
|
166
|
+
"""
|
|
167
|
+
Import a module from the hub to use directly.
|
|
168
|
+
:param url: hub module url in the format "hub://[<source>/]<item-name>[:<tag>]"
|
|
169
|
+
:param install_requirements: when set to True, the module's requirements are installed.
|
|
170
|
+
:param secrets: optional, credentials dict for DB or URL (s3, v3io, ...)
|
|
171
|
+
:param local_path: Path to target directory for the module files (code and example notebook).
|
|
172
|
+
Defaults to the current working directory.
|
|
173
|
+
|
|
174
|
+
:return: the module
|
|
175
|
+
"""
|
|
176
|
+
hub_module: HubModule = get_hub_module(
|
|
177
|
+
url=url, download_files=True, secrets=secrets, local_path=local_path
|
|
178
|
+
)
|
|
179
|
+
if install_requirements:
|
|
180
|
+
hub_module.install_requirements()
|
|
181
|
+
return hub_module.module()
|