1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
|
# frozen_string_literal: true
require 'mime/types'
module API
# MLFlow integration API, replicating the Rest API https://www.mlflow.org/docs/latest/rest-api.html#rest-api
module Ml
module Mlflow
class RegisteredModels < ::API::Base
feature_category :mlops
before do
check_api_read!
check_api_model_registry_read!
check_api_write! if route.settings.dig(:api, :write)
check_api_model_registry_write! if route.settings.dig(:model_registry, :write)
end
resource 'registered-models' do
desc 'Creates a Registered Model.' do
success Entities::Ml::Mlflow::RegisteredModel
detail 'MLFlow Registered Models map to GitLab Models. https://mlflow.org/docs/2.6.0/rest-api.html#create-registeredmodel'
end
route_setting :api, write: true
route_setting :model_registry, write: true
params do
requires :name, type: String,
desc: 'Register models under this name.'
optional :description, type: String,
desc: 'Optional description for registered model.'
optional :tags, type: Array, desc: 'Additional metadata for registered model.'
end
post 'create', urgency: :low do
model = ::Ml::CreateModelService.new(
user_project,
params[:name],
current_user,
params[:description],
params[:tags]
).execute
resource_already_exists! unless model.persisted?
present model,
with: Entities::Ml::Mlflow::RegisteredModel,
root: :registered_model
rescue ActiveRecord::RecordInvalid
resource_already_exists!
end
desc 'Fetch a Registered Model by Name' do
success Entities::Ml::Mlflow::RegisteredModel
detail 'https://www.mlflow.org/docs/1.28.0/rest-api.html#get-registeredmodel'
end
params do
# The name param is actually required, however it is listed as optional here
# we can send a custom error response required by MLFlow
optional :name, type: String, default: '',
desc: 'Registered model unique name identifier, in reference to the project'
end
get 'get', urgency: :low do
present find_model(user_project, params[:name]), with: Entities::Ml::Mlflow::RegisteredModel,
root: :registered_model
end
desc 'Update a Registered Model by Name' do
success Entities::Ml::Mlflow::RegisteredModel
detail 'https://mlflow.org/docs/2.6.0/rest-api.html#update-registeredmodel'
end
route_setting :api, write: true
route_setting :model_registry, write: true
params do
# The name param is actually required, however it is listed as optional here
# we can send a custom error response required by MLFlow
optional :name, type: String,
desc: 'Registered model unique name identifier, in reference to the project'
optional :description, type: String,
desc: 'Optional description for registered model.'
end
patch 'update', urgency: :low do
present ::Ml::UpdateModelService.new(find_model(user_project, params[:name]), params[:description]).execute,
with: Entities::Ml::Mlflow::RegisteredModel, root: :registered_model
end
desc 'Fetch the latest Model Version for the given Registered Model Name' do
success Entities::Ml::Mlflow::ModelVersion
detail 'https://mlflow.org/docs/2.6.0/rest-api.html#get-latest-modelversions'
end
params do
# The name param is actually required, however it is listed as optional here
# we can send a custom error response required by MLFlow
optional :name, type: String,
desc: 'Registered model unique name identifier, in reference to the project'
end
post 'get-latest-versions', urgency: :low do
model = find_model(user_project, params[:name])
present [model.latest_version], with: Entities::Ml::Mlflow::ModelVersion,
root: :model_versions
end
desc 'Delete a Registered Model by Name' do
success Entities::Ml::Mlflow::RegisteredModel
detail 'https://mlflow.org/docs/2.6.0/rest-api.html#delete-registeredmodel'
end
route_setting :api, write: true
route_setting :model_registry, write: true
params do
# The name param is actually required, however it is listed as optional here
# we can send a custom error response required by MLFlow
optional :name, type: String,
desc: 'Registered model unique name identifier, in reference to the project'
end
delete 'delete', urgency: :low do
resource_not_found! unless params[:name]
model = ::Ml::FindModelService.new(user_project, params[:name]).execute
resource_not_found! unless model
if ::Ml::DestroyModelService.new(model, current_user).execute
present({})
else
render_api_error!('Model could not be deleted', 400)
end
end
desc 'Search Registered Models within a project' do
success Entities::Ml::Mlflow::RegisteredModel
detail 'https://mlflow.org/docs/2.6.0/rest-api.html#search-registeredmodels'
end
params do
optional :filter,
type: String,
desc: "Filter to search models. must be in the format `name='value'`. Only filtering by name is supported"
optional :max_results,
type: Integer,
desc: 'Maximum number of models desired. Default is 200. Max threshold is 1000.',
default: 200
optional :order_by,
type: String,
desc: 'Order criteria. Can be by name or last_updated_timestamp, with optional DESC or ASC (default)' \
'Valid examples: `name`, `name DESC`, `last_updated_timestamp DESC`' \
'Sorting by model metadata is not supported.',
default: 'name ASC'
optional :page_token,
type: String,
desc: 'Token for pagination'
end
get 'search', urgency: :low do
max_results = [params[:max_results], 1000].min
finder_params = model_order_params(params)
filter_params = model_filter_params(params)
if !params[:filter].nil? && !filter_params.key?(:name)
invalid_parameter!("Invalid attribute key specified. Valid keys are '{'name'}'")
end
finder = ::Projects::Ml::ModelFinder.new(user_project, finder_params.merge(filter_params))
paginator = finder.execute.keyset_paginate(cursor: params[:page_token], per_page: max_results)
result = {
registered_models: paginator.records,
next_page_token: paginator.cursor_for_next_page
}
present result, with: Entities::Ml::Mlflow::ListRegisteredModels
end
end
end
end
end
end
|