mlrun 1.8.0rc12__py3-none-any.whl → 1.8.0rc13__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/artifacts/document.py +32 -6
- mlrun/common/formatters/artifact.py +1 -1
- mlrun/common/schemas/partition.py +23 -18
- mlrun/datastore/vectorstore.py +69 -26
- mlrun/db/base.py +13 -1
- mlrun/db/httpdb.py +42 -7
- mlrun/db/nopdb.py +12 -1
- mlrun/execution.py +43 -11
- mlrun/model_monitoring/applications/_application_steps.py +1 -1
- mlrun/model_monitoring/applications/base.py +2 -3
- mlrun/model_monitoring/applications/context.py +94 -71
- mlrun/projects/pipelines.py +6 -3
- mlrun/projects/project.py +77 -1
- mlrun/runtimes/nuclio/function.py +2 -1
- mlrun/runtimes/nuclio/serving.py +10 -5
- mlrun/serving/routers.py +16 -7
- mlrun/serving/states.py +14 -6
- mlrun/serving/v2_serving.py +11 -6
- mlrun/utils/notifications/notification/base.py +1 -1
- mlrun/utils/notifications/notification/webhook.py +13 -12
- mlrun/utils/notifications/notification_pusher.py +18 -23
- mlrun/utils/version/version.json +2 -2
- {mlrun-1.8.0rc12.dist-info → mlrun-1.8.0rc13.dist-info}/METADATA +2 -2
- {mlrun-1.8.0rc12.dist-info → mlrun-1.8.0rc13.dist-info}/RECORD +28 -28
- {mlrun-1.8.0rc12.dist-info → mlrun-1.8.0rc13.dist-info}/LICENSE +0 -0
- {mlrun-1.8.0rc12.dist-info → mlrun-1.8.0rc13.dist-info}/WHEEL +0 -0
- {mlrun-1.8.0rc12.dist-info → mlrun-1.8.0rc13.dist-info}/entry_points.txt +0 -0
- {mlrun-1.8.0rc12.dist-info → mlrun-1.8.0rc13.dist-info}/top_level.txt +0 -0
mlrun/artifacts/document.py
CHANGED
|
@@ -89,12 +89,17 @@ class MLRunLoader:
|
|
|
89
89
|
A factory class for creating instances of a dynamically defined document loader.
|
|
90
90
|
|
|
91
91
|
Args:
|
|
92
|
-
artifact_key (str): The key for the artifact to be logged.
|
|
93
|
-
|
|
92
|
+
artifact_key (str, optional): The key for the artifact to be logged. Special characters and symbols
|
|
93
|
+
not valid in artifact names will be encoded as their hexadecimal representation. The '%%' pattern
|
|
94
|
+
in the key will be replaced by the hex-encoded version of the source path. Defaults to "doc%%".
|
|
94
95
|
local_path (str): The source path of the document to be loaded.
|
|
95
96
|
loader_spec (DocumentLoaderSpec): Specification for the document loader.
|
|
96
|
-
producer (Optional[Union[MlrunProject, str, MLClientCtx]], optional): The producer of the document
|
|
97
|
+
producer (Optional[Union[MlrunProject, str, MLClientCtx]], optional): The producer of the document.
|
|
98
|
+
If not specified, will try to get the current MLRun context or project.
|
|
99
|
+
Defaults to None.
|
|
97
100
|
upload (bool, optional): Flag indicating whether to upload the document.
|
|
101
|
+
labels (Optional[Dict[str, str]], optional): Key-value labels to attach to the artifact. Defaults to None.
|
|
102
|
+
tag (str, optional): Version tag for the artifact. Defaults to "".
|
|
98
103
|
|
|
99
104
|
Returns:
|
|
100
105
|
DynamicDocumentLoader: An instance of a dynamically defined subclass of BaseLoader.
|
|
@@ -146,6 +151,8 @@ class MLRunLoader:
|
|
|
146
151
|
artifact_key="doc%%",
|
|
147
152
|
producer: Optional[Union["MlrunProject", str, "MLClientCtx"]] = None, # noqa: F821
|
|
148
153
|
upload: bool = False,
|
|
154
|
+
tag: str = "",
|
|
155
|
+
labels: Optional[dict[str, str]] = None,
|
|
149
156
|
):
|
|
150
157
|
# Dynamically import BaseLoader
|
|
151
158
|
from langchain_community.document_loaders.base import BaseLoader
|
|
@@ -158,6 +165,8 @@ class MLRunLoader:
|
|
|
158
165
|
artifact_key,
|
|
159
166
|
producer,
|
|
160
167
|
upload,
|
|
168
|
+
tag,
|
|
169
|
+
labels,
|
|
161
170
|
):
|
|
162
171
|
self.producer = producer
|
|
163
172
|
self.artifact_key = (
|
|
@@ -168,6 +177,8 @@ class MLRunLoader:
|
|
|
168
177
|
self.loader_spec = loader_spec
|
|
169
178
|
self.local_path = local_path
|
|
170
179
|
self.upload = upload
|
|
180
|
+
self.tag = tag
|
|
181
|
+
self.labels = labels
|
|
171
182
|
|
|
172
183
|
# Resolve the producer
|
|
173
184
|
if not self.producer:
|
|
@@ -181,9 +192,11 @@ class MLRunLoader:
|
|
|
181
192
|
document_loader_spec=self.loader_spec,
|
|
182
193
|
local_path=self.local_path,
|
|
183
194
|
upload=self.upload,
|
|
195
|
+
labels=self.labels,
|
|
196
|
+
tag=self.tag,
|
|
184
197
|
)
|
|
185
198
|
res = artifact.to_langchain_documents()
|
|
186
|
-
|
|
199
|
+
return res
|
|
187
200
|
|
|
188
201
|
# Return an instance of the dynamically defined subclass
|
|
189
202
|
instance = DynamicDocumentLoader(
|
|
@@ -192,6 +205,8 @@ class MLRunLoader:
|
|
|
192
205
|
loader_spec=loader_spec,
|
|
193
206
|
producer=producer,
|
|
194
207
|
upload=upload,
|
|
208
|
+
tag=tag,
|
|
209
|
+
labels=labels,
|
|
195
210
|
)
|
|
196
211
|
return instance
|
|
197
212
|
|
|
@@ -257,6 +272,9 @@ class DocumentArtifact(Artifact):
|
|
|
257
272
|
METADATA_CHUNK_KEY = "mlrun_chunk"
|
|
258
273
|
METADATA_ARTIFACT_URI_KEY = "mlrun_object_uri"
|
|
259
274
|
METADATA_ARTIFACT_TARGET_PATH_KEY = "mlrun_target_path"
|
|
275
|
+
METADATA_ARTIFACT_TAG = "mlrun_tag"
|
|
276
|
+
METADATA_ARTIFACT_KEY = "mlrun_key"
|
|
277
|
+
METADATA_ARTIFACT_PROJECT = "mlrun_project"
|
|
260
278
|
|
|
261
279
|
def __init__(
|
|
262
280
|
self,
|
|
@@ -331,6 +349,10 @@ class DocumentArtifact(Artifact):
|
|
|
331
349
|
metadata[self.METADATA_ORIGINAL_SOURCE_KEY] = self.spec.original_source
|
|
332
350
|
metadata[self.METADATA_SOURCE_KEY] = self.get_source()
|
|
333
351
|
metadata[self.METADATA_ARTIFACT_URI_KEY] = self.uri
|
|
352
|
+
metadata[self.METADATA_ARTIFACT_TAG] = self.tag or "latest"
|
|
353
|
+
metadata[self.METADATA_ARTIFACT_KEY] = self.key
|
|
354
|
+
metadata[self.METADATA_ARTIFACT_PROJECT] = self.metadata.project
|
|
355
|
+
|
|
334
356
|
if self.get_target_path():
|
|
335
357
|
metadata[self.METADATA_ARTIFACT_TARGET_PATH_KEY] = (
|
|
336
358
|
self.get_target_path()
|
|
@@ -346,7 +368,7 @@ class DocumentArtifact(Artifact):
|
|
|
346
368
|
idx = idx + 1
|
|
347
369
|
return results
|
|
348
370
|
|
|
349
|
-
def collection_add(self, collection_id: str) ->
|
|
371
|
+
def collection_add(self, collection_id: str) -> bool:
|
|
350
372
|
"""
|
|
351
373
|
Add a collection ID to the artifact's collection list.
|
|
352
374
|
|
|
@@ -361,8 +383,10 @@ class DocumentArtifact(Artifact):
|
|
|
361
383
|
"""
|
|
362
384
|
if collection_id not in self.spec.collections:
|
|
363
385
|
self.spec.collections[collection_id] = "1"
|
|
386
|
+
return True
|
|
387
|
+
return False
|
|
364
388
|
|
|
365
|
-
def collection_remove(self, collection_id: str) ->
|
|
389
|
+
def collection_remove(self, collection_id: str) -> bool:
|
|
366
390
|
"""
|
|
367
391
|
Remove a collection ID from the artifact's collection list.
|
|
368
392
|
|
|
@@ -376,3 +400,5 @@ class DocumentArtifact(Artifact):
|
|
|
376
400
|
"""
|
|
377
401
|
if collection_id in self.spec.collections:
|
|
378
402
|
self.spec.collections.pop(collection_id)
|
|
403
|
+
return True
|
|
404
|
+
return False
|
|
@@ -46,24 +46,23 @@ class PartitionInterval(StrEnum):
|
|
|
46
46
|
return timedelta(weeks=1)
|
|
47
47
|
|
|
48
48
|
@classmethod
|
|
49
|
-
def
|
|
49
|
+
def from_expression(cls, partition_expression: str):
|
|
50
50
|
"""
|
|
51
|
-
Returns the corresponding PartitionInterval for a given partition
|
|
51
|
+
Returns the corresponding PartitionInterval for a given partition expression,
|
|
52
52
|
or None if the function is not mapped.
|
|
53
53
|
|
|
54
|
-
:param
|
|
55
|
-
:return: PartitionInterval corresponding to the
|
|
54
|
+
:param partition_expression: The partition expression to map to an interval.
|
|
55
|
+
:return: PartitionInterval corresponding to the expression, or `month` if no match is found.
|
|
56
56
|
"""
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
return cls
|
|
66
|
-
raise KeyError(f"Partition function: {partition_function} isn't supported")
|
|
57
|
+
|
|
58
|
+
# Match the provided function string to the correct interval
|
|
59
|
+
partition_expression = partition_expression.upper()
|
|
60
|
+
if "YEARWEEK" in partition_expression:
|
|
61
|
+
return cls.YEARWEEK
|
|
62
|
+
elif "DAYOFMONTH" in partition_expression:
|
|
63
|
+
return cls.DAY
|
|
64
|
+
else:
|
|
65
|
+
return cls.MONTH
|
|
67
66
|
|
|
68
67
|
def get_partition_info(
|
|
69
68
|
self,
|
|
@@ -120,11 +119,17 @@ class PartitionInterval(StrEnum):
|
|
|
120
119
|
year, week, _ = current_datetime.isocalendar()
|
|
121
120
|
return f"{year}{week:02d}"
|
|
122
121
|
|
|
123
|
-
def get_partition_expression(self):
|
|
122
|
+
def get_partition_expression(self, column_name: str):
|
|
124
123
|
if self == PartitionInterval.YEARWEEK:
|
|
125
|
-
return "YEARWEEK(
|
|
126
|
-
|
|
127
|
-
|
|
124
|
+
return f"YEARWEEK({column_name}, 1)"
|
|
125
|
+
elif self == PartitionInterval.DAY:
|
|
126
|
+
# generates value in format %Y%m%d in mysql
|
|
127
|
+
# mysql query example: `select YEAR(NOW())*10000 + MONTH(NOW())*100 + DAY(NOW());`
|
|
128
|
+
return f"YEAR({column_name}) * 10000 + MONTH({column_name}) * 100 + DAY({column_name})"
|
|
129
|
+
elif self == PartitionInterval.MONTH:
|
|
130
|
+
# generates value in format %Y%m in mysql
|
|
131
|
+
# mysql query example: `select YEAR(NOW())*100 + MONTH(NOW());`
|
|
132
|
+
return f"YEAR({column_name}) * 100 + MONTH({column_name})"
|
|
128
133
|
|
|
129
134
|
def get_number_of_partitions(self, days: int) -> int:
|
|
130
135
|
# Calculate the number partitions based on given number of days
|
mlrun/datastore/vectorstore.py
CHANGED
|
@@ -19,19 +19,42 @@ from typing import Optional, Union
|
|
|
19
19
|
from mlrun.artifacts import DocumentArtifact
|
|
20
20
|
|
|
21
21
|
|
|
22
|
-
def
|
|
23
|
-
#
|
|
24
|
-
|
|
22
|
+
def find_existing_attribute(obj, base_name="name", parent_name="collection"):
|
|
23
|
+
# Define all possible patterns
|
|
24
|
+
|
|
25
|
+
return None
|
|
26
|
+
|
|
25
27
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
28
|
+
def _extract_collection_name(vectorstore: "VectorStore") -> str: # noqa: F821
|
|
29
|
+
patterns = [
|
|
30
|
+
"collection.name",
|
|
31
|
+
"collection._name",
|
|
32
|
+
"_collection.name",
|
|
33
|
+
"_collection._name",
|
|
34
|
+
"collection_name",
|
|
35
|
+
"_collection_name",
|
|
36
|
+
]
|
|
37
|
+
|
|
38
|
+
def resolve_attribute(obj, pattern):
|
|
39
|
+
if "." in pattern:
|
|
40
|
+
parts = pattern.split(".")
|
|
41
|
+
current = vectorstore
|
|
42
|
+
for part in parts:
|
|
43
|
+
if hasattr(current, part):
|
|
44
|
+
current = getattr(current, part)
|
|
45
|
+
else:
|
|
46
|
+
return None
|
|
47
|
+
return current
|
|
48
|
+
else:
|
|
49
|
+
return getattr(obj, pattern, None)
|
|
31
50
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
51
|
+
for pattern in patterns:
|
|
52
|
+
try:
|
|
53
|
+
value = resolve_attribute(vectorstore, pattern)
|
|
54
|
+
if value is not None:
|
|
55
|
+
return value
|
|
56
|
+
except (AttributeError, TypeError):
|
|
57
|
+
continue
|
|
35
58
|
|
|
36
59
|
# If we get here, we couldn't find a valid collection name
|
|
37
60
|
raise ValueError(
|
|
@@ -82,6 +105,19 @@ class VectorStoreCollection:
|
|
|
82
105
|
# Forward the attribute setting to _collection_impl
|
|
83
106
|
setattr(self._collection_impl, name, value)
|
|
84
107
|
|
|
108
|
+
def _get_mlrun_project_name(self):
|
|
109
|
+
import mlrun
|
|
110
|
+
|
|
111
|
+
if self._mlrun_context and isinstance(
|
|
112
|
+
self._mlrun_context, mlrun.projects.MlrunProject
|
|
113
|
+
):
|
|
114
|
+
return self._mlrun_context.name
|
|
115
|
+
if self._mlrun_context and isinstance(
|
|
116
|
+
self._mlrun_context, mlrun.execution.MLClientCtx
|
|
117
|
+
):
|
|
118
|
+
return self._mlrun_context.get_project_object().name
|
|
119
|
+
return None
|
|
120
|
+
|
|
85
121
|
def delete(self, *args, **kwargs):
|
|
86
122
|
self._collection_impl.delete(*args, **kwargs)
|
|
87
123
|
|
|
@@ -106,13 +142,22 @@ class VectorStoreCollection:
|
|
|
106
142
|
"""
|
|
107
143
|
if self._mlrun_context:
|
|
108
144
|
for document in documents:
|
|
109
|
-
|
|
110
|
-
DocumentArtifact.
|
|
145
|
+
mlrun_key = document.metadata.get(
|
|
146
|
+
DocumentArtifact.METADATA_ARTIFACT_KEY, None
|
|
147
|
+
)
|
|
148
|
+
mlrun_project = document.metadata.get(
|
|
149
|
+
DocumentArtifact.METADATA_ARTIFACT_PROJECT, None
|
|
111
150
|
)
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
151
|
+
|
|
152
|
+
if mlrun_key and mlrun_project == self._get_mlrun_project_name():
|
|
153
|
+
mlrun_tag = document.metadata.get(
|
|
154
|
+
DocumentArtifact.METADATA_ARTIFACT_TAG, None
|
|
155
|
+
)
|
|
156
|
+
artifact = self._mlrun_context.get_artifact(
|
|
157
|
+
key=mlrun_key, tag=mlrun_tag
|
|
158
|
+
)
|
|
159
|
+
if artifact.collection_add(self.collection_name):
|
|
160
|
+
self._mlrun_context.update_artifact(artifact)
|
|
116
161
|
|
|
117
162
|
return self._collection_impl.add_documents(documents, **kwargs)
|
|
118
163
|
|
|
@@ -159,8 +204,7 @@ class VectorStoreCollection:
|
|
|
159
204
|
)
|
|
160
205
|
for index, artifact in enumerate(artifacts):
|
|
161
206
|
documents = artifact.to_langchain_documents(splitter)
|
|
162
|
-
artifact.collection_add(self.collection_name)
|
|
163
|
-
if self._mlrun_context:
|
|
207
|
+
if artifact.collection_add(self.collection_name) and self._mlrun_context:
|
|
164
208
|
self._mlrun_context.update_artifact(artifact)
|
|
165
209
|
if user_ids:
|
|
166
210
|
num_of_documents = len(documents)
|
|
@@ -182,8 +226,8 @@ class VectorStoreCollection:
|
|
|
182
226
|
Args:
|
|
183
227
|
artifact (DocumentArtifact): The artifact from which the current object should be removed.
|
|
184
228
|
"""
|
|
185
|
-
|
|
186
|
-
if self._mlrun_context:
|
|
229
|
+
|
|
230
|
+
if artifact.collection_remove(self.collection_name) and self._mlrun_context:
|
|
187
231
|
self._mlrun_context.update_artifact(artifact)
|
|
188
232
|
|
|
189
233
|
def delete_artifacts(self, artifacts: list[DocumentArtifact]):
|
|
@@ -201,16 +245,15 @@ class VectorStoreCollection:
|
|
|
201
245
|
"""
|
|
202
246
|
store_class = self._collection_impl.__class__.__name__.lower()
|
|
203
247
|
for artifact in artifacts:
|
|
204
|
-
artifact.collection_remove(self.collection_name)
|
|
205
|
-
if self._mlrun_context:
|
|
248
|
+
if artifact.collection_remove(self.collection_name) and self._mlrun_context:
|
|
206
249
|
self._mlrun_context.update_artifact(artifact)
|
|
207
250
|
|
|
208
251
|
if store_class == "milvus":
|
|
209
252
|
expr = f"{DocumentArtifact.METADATA_SOURCE_KEY} == '{artifact.get_source()}'"
|
|
210
|
-
|
|
253
|
+
self._collection_impl.delete(expr=expr)
|
|
211
254
|
elif store_class == "chroma":
|
|
212
255
|
where = {DocumentArtifact.METADATA_SOURCE_KEY: artifact.get_source()}
|
|
213
|
-
|
|
256
|
+
self._collection_impl.delete(where=where)
|
|
214
257
|
|
|
215
258
|
elif (
|
|
216
259
|
hasattr(self._collection_impl, "delete")
|
|
@@ -222,7 +265,7 @@ class VectorStoreCollection:
|
|
|
222
265
|
DocumentArtifact.METADATA_SOURCE_KEY: artifact.get_source()
|
|
223
266
|
}
|
|
224
267
|
}
|
|
225
|
-
|
|
268
|
+
self._collection_impl.delete(filter=filter)
|
|
226
269
|
else:
|
|
227
270
|
raise NotImplementedError(
|
|
228
271
|
f"delete_artifacts() operation not supported for {store_class}"
|
mlrun/db/base.py
CHANGED
|
@@ -23,6 +23,7 @@ import mlrun.common
|
|
|
23
23
|
import mlrun.common.formatters
|
|
24
24
|
import mlrun.common.runtimes.constants
|
|
25
25
|
import mlrun.common.schemas
|
|
26
|
+
import mlrun.common.schemas.model_monitoring.constants as mm_constants
|
|
26
27
|
import mlrun.common.schemas.model_monitoring.model_endpoints as mm_endpoints
|
|
27
28
|
import mlrun.model_monitoring
|
|
28
29
|
|
|
@@ -58,6 +59,15 @@ class RunDBInterface(ABC):
|
|
|
58
59
|
def abort_run(self, uid, project="", iter=0, timeout=45, status_text=""):
|
|
59
60
|
pass
|
|
60
61
|
|
|
62
|
+
@abstractmethod
|
|
63
|
+
def push_run_notifications(
|
|
64
|
+
self,
|
|
65
|
+
uid,
|
|
66
|
+
project="",
|
|
67
|
+
timeout=45,
|
|
68
|
+
):
|
|
69
|
+
pass
|
|
70
|
+
|
|
61
71
|
@abstractmethod
|
|
62
72
|
def read_run(
|
|
63
73
|
self,
|
|
@@ -666,7 +676,9 @@ class RunDBInterface(ABC):
|
|
|
666
676
|
def create_model_endpoint(
|
|
667
677
|
self,
|
|
668
678
|
model_endpoint: mlrun.common.schemas.ModelEndpoint,
|
|
669
|
-
creation_strategy:
|
|
679
|
+
creation_strategy: Optional[
|
|
680
|
+
mm_constants.ModelEndpointCreationStrategy
|
|
681
|
+
] = mm_constants.ModelEndpointCreationStrategy.INPLACE,
|
|
670
682
|
) -> mlrun.common.schemas.ModelEndpoint:
|
|
671
683
|
pass
|
|
672
684
|
|
mlrun/db/httpdb.py
CHANGED
|
@@ -35,6 +35,7 @@ import mlrun.common.constants
|
|
|
35
35
|
import mlrun.common.formatters
|
|
36
36
|
import mlrun.common.runtimes
|
|
37
37
|
import mlrun.common.schemas
|
|
38
|
+
import mlrun.common.schemas.model_monitoring.constants as mm_constants
|
|
38
39
|
import mlrun.common.schemas.model_monitoring.model_endpoints as mm_endpoints
|
|
39
40
|
import mlrun.common.types
|
|
40
41
|
import mlrun.platforms
|
|
@@ -755,6 +756,34 @@ class HTTPRunDB(RunDBInterface):
|
|
|
755
756
|
)
|
|
756
757
|
return None
|
|
757
758
|
|
|
759
|
+
def push_run_notifications(
|
|
760
|
+
self,
|
|
761
|
+
uid,
|
|
762
|
+
project="",
|
|
763
|
+
timeout=45,
|
|
764
|
+
):
|
|
765
|
+
"""
|
|
766
|
+
Push notifications for a run.
|
|
767
|
+
|
|
768
|
+
:param uid: Unique ID of the run.
|
|
769
|
+
:param project: Project that the run belongs to.
|
|
770
|
+
:returns: :py:class:`~mlrun.common.schemas.BackgroundTask`.
|
|
771
|
+
"""
|
|
772
|
+
project = project or config.default_project
|
|
773
|
+
|
|
774
|
+
response = self.api_call(
|
|
775
|
+
"POST",
|
|
776
|
+
path=f"projects/{project}/runs/{uid}/push_notifications",
|
|
777
|
+
error="Failed push notifications",
|
|
778
|
+
timeout=timeout,
|
|
779
|
+
)
|
|
780
|
+
if response.status_code == http.HTTPStatus.ACCEPTED:
|
|
781
|
+
background_task = mlrun.common.schemas.BackgroundTask(**response.json())
|
|
782
|
+
return self._wait_for_background_task_to_reach_terminal_state(
|
|
783
|
+
background_task.metadata.name, project=project
|
|
784
|
+
)
|
|
785
|
+
return None
|
|
786
|
+
|
|
758
787
|
def read_run(
|
|
759
788
|
self,
|
|
760
789
|
uid,
|
|
@@ -3582,18 +3611,24 @@ class HTTPRunDB(RunDBInterface):
|
|
|
3582
3611
|
def create_model_endpoint(
|
|
3583
3612
|
self,
|
|
3584
3613
|
model_endpoint: mlrun.common.schemas.ModelEndpoint,
|
|
3585
|
-
creation_strategy:
|
|
3614
|
+
creation_strategy: Optional[
|
|
3615
|
+
mm_constants.ModelEndpointCreationStrategy
|
|
3616
|
+
] = mm_constants.ModelEndpointCreationStrategy.INPLACE,
|
|
3586
3617
|
) -> mlrun.common.schemas.ModelEndpoint:
|
|
3587
3618
|
"""
|
|
3588
3619
|
Creates a DB record with the given model_endpoint record.
|
|
3589
3620
|
|
|
3590
3621
|
:param model_endpoint: An object representing the model endpoint.
|
|
3591
|
-
:param creation_strategy:
|
|
3592
|
-
|
|
3593
|
-
|
|
3594
|
-
|
|
3595
|
-
|
|
3596
|
-
|
|
3622
|
+
:param creation_strategy: Strategy for creating or updating the model endpoint:
|
|
3623
|
+
* **overwrite**:
|
|
3624
|
+
1. If model endpoints with the same name exist, delete the `latest` one.
|
|
3625
|
+
2. Create a new model endpoint entry and set it as `latest`.
|
|
3626
|
+
* **inplace** (default):
|
|
3627
|
+
1. If model endpoints with the same name exist, update the `latest` entry.
|
|
3628
|
+
2. Otherwise, create a new entry.
|
|
3629
|
+
* **archive**:
|
|
3630
|
+
1. If model endpoints with the same name exist, preserve them.
|
|
3631
|
+
2. Create a new model endpoint with the same name and set it to `latest`.
|
|
3597
3632
|
:return: The created model endpoint object.
|
|
3598
3633
|
"""
|
|
3599
3634
|
|
mlrun/db/nopdb.py
CHANGED
|
@@ -20,6 +20,7 @@ import mlrun.alerts
|
|
|
20
20
|
import mlrun.common.formatters
|
|
21
21
|
import mlrun.common.runtimes.constants
|
|
22
22
|
import mlrun.common.schemas
|
|
23
|
+
import mlrun.common.schemas.model_monitoring.constants as mm_constants
|
|
23
24
|
import mlrun.errors
|
|
24
25
|
import mlrun.lists
|
|
25
26
|
import mlrun.model_monitoring
|
|
@@ -75,6 +76,14 @@ class NopDB(RunDBInterface):
|
|
|
75
76
|
def abort_run(self, uid, project="", iter=0, timeout=45, status_text=""):
|
|
76
77
|
pass
|
|
77
78
|
|
|
79
|
+
def push_run_notifications(
|
|
80
|
+
self,
|
|
81
|
+
uid,
|
|
82
|
+
project="",
|
|
83
|
+
timeout=45,
|
|
84
|
+
):
|
|
85
|
+
pass
|
|
86
|
+
|
|
78
87
|
def list_runtime_resources(
|
|
79
88
|
self,
|
|
80
89
|
project: Optional[str] = None,
|
|
@@ -575,7 +584,9 @@ class NopDB(RunDBInterface):
|
|
|
575
584
|
def create_model_endpoint(
|
|
576
585
|
self,
|
|
577
586
|
model_endpoint: mlrun.common.schemas.ModelEndpoint,
|
|
578
|
-
creation_strategy:
|
|
587
|
+
creation_strategy: Optional[
|
|
588
|
+
mm_constants.ModelEndpointCreationStrategy
|
|
589
|
+
] = mm_constants.ModelEndpointCreationStrategy.INPLACE,
|
|
579
590
|
) -> mlrun.common.schemas.ModelEndpoint:
|
|
580
591
|
pass
|
|
581
592
|
|
mlrun/execution.py
CHANGED
|
@@ -880,7 +880,7 @@ class MLClientCtx:
|
|
|
880
880
|
tag: str = "",
|
|
881
881
|
local_path: str = "",
|
|
882
882
|
artifact_path: Optional[str] = None,
|
|
883
|
-
|
|
883
|
+
document_loader_spec: DocumentLoaderSpec = DocumentLoaderSpec(),
|
|
884
884
|
upload: Optional[bool] = False,
|
|
885
885
|
labels: Optional[dict[str, str]] = None,
|
|
886
886
|
target_path: Optional[str] = None,
|
|
@@ -891,22 +891,48 @@ class MLClientCtx:
|
|
|
891
891
|
|
|
892
892
|
:param key: Artifact key
|
|
893
893
|
:param tag: Version tag
|
|
894
|
-
:param local_path:
|
|
895
|
-
|
|
896
|
-
:param artifact_path:
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
:param
|
|
894
|
+
:param local_path: path to the local file we upload, will also be use
|
|
895
|
+
as the destination subpath (under "artifact_path")
|
|
896
|
+
:param artifact_path: Target artifact path (when not using the default)
|
|
897
|
+
to define a subpath under the default location use:
|
|
898
|
+
`artifact_path=context.artifact_subpath('data')`
|
|
899
|
+
:param document_loader_spec: Spec to use to load the artifact as langchain document.
|
|
900
|
+
|
|
901
|
+
By default, uses DocumentLoaderSpec() which initializes with:
|
|
902
|
+
|
|
903
|
+
* loader_class_name="langchain_community.document_loaders.TextLoader"
|
|
904
|
+
* src_name="file_path"
|
|
905
|
+
* kwargs=None
|
|
906
|
+
|
|
907
|
+
Can be customized for different document types, e.g.::
|
|
908
|
+
|
|
909
|
+
DocumentLoaderSpec(
|
|
910
|
+
loader_class_name="langchain_community.document_loaders.PDFLoader",
|
|
911
|
+
src_name="file_path",
|
|
912
|
+
kwargs={"extract_images": True}
|
|
913
|
+
)
|
|
900
914
|
:param upload: Whether to upload the artifact
|
|
901
915
|
:param labels: Key-value labels
|
|
902
916
|
:param target_path: Path to the local file
|
|
903
917
|
:param kwargs: Additional keyword arguments
|
|
904
918
|
:return: DocumentArtifact object
|
|
919
|
+
|
|
920
|
+
Example:
|
|
921
|
+
>>> # Log a PDF document with custom loader
|
|
922
|
+
>>> project.log_document(
|
|
923
|
+
... key="my_doc",
|
|
924
|
+
... local_path="path/to/doc.pdf",
|
|
925
|
+
... document_loader_spec=DocumentLoaderSpec(
|
|
926
|
+
... loader_class_name="langchain_community.document_loaders.PDFLoader",
|
|
927
|
+
... src_name="file_path",
|
|
928
|
+
... kwargs={"extract_images": True},
|
|
929
|
+
... ),
|
|
930
|
+
... )
|
|
905
931
|
"""
|
|
906
932
|
doc_artifact = DocumentArtifact(
|
|
907
933
|
key=key,
|
|
908
934
|
original_source=local_path or target_path,
|
|
909
|
-
|
|
935
|
+
document_loader_spec=document_loader_spec,
|
|
910
936
|
**kwargs,
|
|
911
937
|
)
|
|
912
938
|
|
|
@@ -929,9 +955,15 @@ class MLClientCtx:
|
|
|
929
955
|
)
|
|
930
956
|
return self.get_artifact(key)
|
|
931
957
|
|
|
932
|
-
def get_artifact(
|
|
933
|
-
|
|
934
|
-
|
|
958
|
+
def get_artifact(
|
|
959
|
+
self, key, tag=None, iter=None, tree=None, uid=None
|
|
960
|
+
) -> Optional[Artifact]:
|
|
961
|
+
if tag or iter or tree or uid:
|
|
962
|
+
project = self.get_project_object()
|
|
963
|
+
return project.get_artifact(key=key, tag=tag, iter=iter, tree=tree, uid=uid)
|
|
964
|
+
else:
|
|
965
|
+
artifact_uri = self._artifacts_manager.artifact_uris[key]
|
|
966
|
+
return self.get_store_resource(artifact_uri)
|
|
935
967
|
|
|
936
968
|
def update_artifact(self, artifact_object: Artifact):
|
|
937
969
|
"""Update an artifact object in the DB and the cached uri"""
|
|
@@ -136,7 +136,7 @@ class _PrepareMonitoringEvent(StepToDict):
|
|
|
136
136
|
:param event: Application event.
|
|
137
137
|
:return: Application context.
|
|
138
138
|
"""
|
|
139
|
-
application_context = MonitoringApplicationContext(
|
|
139
|
+
application_context = MonitoringApplicationContext._from_graph_ctx(
|
|
140
140
|
application_name=self.application_name,
|
|
141
141
|
event=event,
|
|
142
142
|
model_endpoint_dict=self.model_endpoints,
|
|
@@ -112,11 +112,10 @@ class ModelMonitoringApplicationBase(MonitoringApplicationToDict, ABC):
|
|
|
112
112
|
def call_do_tracking(event: Optional[dict] = None):
|
|
113
113
|
if event is None:
|
|
114
114
|
event = {}
|
|
115
|
-
monitoring_context = mm_context.MonitoringApplicationContext(
|
|
115
|
+
monitoring_context = mm_context.MonitoringApplicationContext._from_ml_ctx(
|
|
116
116
|
event=event,
|
|
117
117
|
application_name=self.__class__.__name__,
|
|
118
|
-
|
|
119
|
-
artifacts_logger=context,
|
|
118
|
+
context=context,
|
|
120
119
|
sample_df=sample_data,
|
|
121
120
|
feature_stats=feature_stats,
|
|
122
121
|
)
|