@things-factory/integration-mlflow 9.1.19 → 10.0.0-beta.2
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.
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/package.json +8 -8
- package/client/tsconfig.json +0 -11
- package/server/index.ts +0 -5
- package/server/route.ts +0 -13
- package/server/service/experiment/experiment-service.ts +0 -117
- package/server/service/index.ts +0 -17
- package/server/service/model-registry/model-registry-service.ts +0 -232
- package/server/service/run/run-service.ts +0 -177
- package/server/tsconfig.json +0 -11
- package/server/types/mlflow-types.ts +0 -235
- package/server/utils/mlflow-api-client.ts +0 -375
|
@@ -1,235 +0,0 @@
|
|
|
1
|
-
import { Field, ObjectType, InputType, Int } from 'type-graphql'
|
|
2
|
-
|
|
3
|
-
// ============================================================================
|
|
4
|
-
// Experiment Types
|
|
5
|
-
// ============================================================================
|
|
6
|
-
|
|
7
|
-
@ObjectType({ description: 'MLflow Experiment' })
|
|
8
|
-
export class MLflowExperiment {
|
|
9
|
-
@Field({ description: 'Experiment ID' })
|
|
10
|
-
experimentId: string
|
|
11
|
-
|
|
12
|
-
@Field({ description: 'Experiment name' })
|
|
13
|
-
name: string
|
|
14
|
-
|
|
15
|
-
@Field({ description: 'Artifact location' })
|
|
16
|
-
artifactLocation: string
|
|
17
|
-
|
|
18
|
-
@Field({ description: 'Lifecycle stage' })
|
|
19
|
-
lifecycleStage: string
|
|
20
|
-
|
|
21
|
-
@Field(type => String, { nullable: true, description: 'Tags as JSON string' })
|
|
22
|
-
tags?: string
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
@InputType({ description: 'Input for creating MLflow experiment' })
|
|
26
|
-
export class CreateExperimentInput {
|
|
27
|
-
@Field({ description: 'Experiment name' })
|
|
28
|
-
name: string
|
|
29
|
-
|
|
30
|
-
@Field({ nullable: true, description: 'Artifact location' })
|
|
31
|
-
artifactLocation?: string
|
|
32
|
-
|
|
33
|
-
@Field({ nullable: true, description: 'Tags as JSON string' })
|
|
34
|
-
tags?: string
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
// ============================================================================
|
|
38
|
-
// Run Types
|
|
39
|
-
// ============================================================================
|
|
40
|
-
|
|
41
|
-
@ObjectType({ description: 'MLflow Run' })
|
|
42
|
-
export class MLflowRun {
|
|
43
|
-
@Field({ description: 'Run ID' })
|
|
44
|
-
runId: string
|
|
45
|
-
|
|
46
|
-
@Field({ description: 'Experiment ID' })
|
|
47
|
-
experimentId: string
|
|
48
|
-
|
|
49
|
-
@Field({ description: 'Run status' })
|
|
50
|
-
status: string
|
|
51
|
-
|
|
52
|
-
@Field(type => Int, { description: 'Start time (Unix timestamp)' })
|
|
53
|
-
startTime: number
|
|
54
|
-
|
|
55
|
-
@Field(type => Int, { nullable: true, description: 'End time (Unix timestamp)' })
|
|
56
|
-
endTime?: number
|
|
57
|
-
|
|
58
|
-
@Field({ description: 'Artifact URI' })
|
|
59
|
-
artifactUri: string
|
|
60
|
-
|
|
61
|
-
@Field(type => String, { nullable: true, description: 'Metrics as JSON string' })
|
|
62
|
-
metrics?: string
|
|
63
|
-
|
|
64
|
-
@Field(type => String, { nullable: true, description: 'Params as JSON string' })
|
|
65
|
-
params?: string
|
|
66
|
-
|
|
67
|
-
@Field(type => String, { nullable: true, description: 'Tags as JSON string' })
|
|
68
|
-
tags?: string
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
@InputType({ description: 'Input for creating MLflow run' })
|
|
72
|
-
export class CreateRunInput {
|
|
73
|
-
@Field({ description: 'Experiment ID' })
|
|
74
|
-
experimentId: string
|
|
75
|
-
|
|
76
|
-
@Field(type => Int, { nullable: true, description: 'Start time' })
|
|
77
|
-
startTime?: number
|
|
78
|
-
|
|
79
|
-
@Field({ nullable: true, description: 'Tags as JSON string' })
|
|
80
|
-
tags?: string
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
@InputType({ description: 'Input for logging metric' })
|
|
84
|
-
export class LogMetricInput {
|
|
85
|
-
@Field({ description: 'Run ID' })
|
|
86
|
-
runId: string
|
|
87
|
-
|
|
88
|
-
@Field({ description: 'Metric key' })
|
|
89
|
-
key: string
|
|
90
|
-
|
|
91
|
-
@Field({ description: 'Metric value' })
|
|
92
|
-
value: number
|
|
93
|
-
|
|
94
|
-
@Field(type => Int, { nullable: true, description: 'Timestamp' })
|
|
95
|
-
timestamp?: number
|
|
96
|
-
|
|
97
|
-
@Field(type => Int, { nullable: true, description: 'Step' })
|
|
98
|
-
step?: number
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
@InputType({ description: 'Input for logging parameter' })
|
|
102
|
-
export class LogParamInput {
|
|
103
|
-
@Field({ description: 'Run ID' })
|
|
104
|
-
runId: string
|
|
105
|
-
|
|
106
|
-
@Field({ description: 'Parameter key' })
|
|
107
|
-
key: string
|
|
108
|
-
|
|
109
|
-
@Field({ description: 'Parameter value' })
|
|
110
|
-
value: string
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
@InputType({ description: 'Input for updating run' })
|
|
114
|
-
export class UpdateRunInput {
|
|
115
|
-
@Field({ description: 'Run ID' })
|
|
116
|
-
runId: string
|
|
117
|
-
|
|
118
|
-
@Field({ nullable: true, description: 'Status' })
|
|
119
|
-
status?: string
|
|
120
|
-
|
|
121
|
-
@Field(type => Int, { nullable: true, description: 'End time' })
|
|
122
|
-
endTime?: number
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
// ============================================================================
|
|
126
|
-
// Model Registry Types
|
|
127
|
-
// ============================================================================
|
|
128
|
-
|
|
129
|
-
@ObjectType({ description: 'MLflow Registered Model' })
|
|
130
|
-
export class MLflowRegisteredModel {
|
|
131
|
-
@Field({ description: 'Model name' })
|
|
132
|
-
name: string
|
|
133
|
-
|
|
134
|
-
@Field(type => Int, { description: 'Creation timestamp' })
|
|
135
|
-
creationTimestamp: number
|
|
136
|
-
|
|
137
|
-
@Field(type => Int, { description: 'Last updated timestamp' })
|
|
138
|
-
lastUpdatedTimestamp: number
|
|
139
|
-
|
|
140
|
-
@Field({ nullable: true, description: 'Model description' })
|
|
141
|
-
description?: string
|
|
142
|
-
|
|
143
|
-
@Field(type => String, { nullable: true, description: 'Tags as JSON string' })
|
|
144
|
-
tags?: string
|
|
145
|
-
|
|
146
|
-
@Field(type => String, { nullable: true, description: 'Latest versions as JSON string' })
|
|
147
|
-
latestVersions?: string
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
@InputType({ description: 'Input for creating registered model' })
|
|
151
|
-
export class CreateRegisteredModelInput {
|
|
152
|
-
@Field({ description: 'Model name' })
|
|
153
|
-
name: string
|
|
154
|
-
|
|
155
|
-
@Field({ nullable: true, description: 'Model description' })
|
|
156
|
-
description?: string
|
|
157
|
-
|
|
158
|
-
@Field({ nullable: true, description: 'Tags as JSON string' })
|
|
159
|
-
tags?: string
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
@ObjectType({ description: 'MLflow Model Version' })
|
|
163
|
-
export class MLflowModelVersion {
|
|
164
|
-
@Field({ description: 'Model name' })
|
|
165
|
-
name: string
|
|
166
|
-
|
|
167
|
-
@Field({ description: 'Version number' })
|
|
168
|
-
version: string
|
|
169
|
-
|
|
170
|
-
@Field(type => Int, { description: 'Creation timestamp' })
|
|
171
|
-
creationTimestamp: number
|
|
172
|
-
|
|
173
|
-
@Field({ description: 'Current stage' })
|
|
174
|
-
currentStage: string
|
|
175
|
-
|
|
176
|
-
@Field({ description: 'Model source' })
|
|
177
|
-
source: string
|
|
178
|
-
|
|
179
|
-
@Field({ description: 'Version status' })
|
|
180
|
-
status: string
|
|
181
|
-
|
|
182
|
-
@Field({ nullable: true, description: 'Run ID' })
|
|
183
|
-
runId?: string
|
|
184
|
-
|
|
185
|
-
@Field({ nullable: true, description: 'Description' })
|
|
186
|
-
description?: string
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
@InputType({ description: 'Input for creating model version' })
|
|
190
|
-
export class CreateModelVersionInput {
|
|
191
|
-
@Field({ description: 'Model name' })
|
|
192
|
-
name: string
|
|
193
|
-
|
|
194
|
-
@Field({ description: 'Model source URI' })
|
|
195
|
-
source: string
|
|
196
|
-
|
|
197
|
-
@Field({ nullable: true, description: 'Run ID' })
|
|
198
|
-
runId?: string
|
|
199
|
-
|
|
200
|
-
@Field({ nullable: true, description: 'Description' })
|
|
201
|
-
description?: string
|
|
202
|
-
|
|
203
|
-
@Field({ nullable: true, description: 'Tags as JSON string' })
|
|
204
|
-
tags?: string
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
@InputType({ description: 'Input for transitioning model version stage' })
|
|
208
|
-
export class TransitionStageInput {
|
|
209
|
-
@Field({ description: 'Model name' })
|
|
210
|
-
name: string
|
|
211
|
-
|
|
212
|
-
@Field({ description: 'Version number' })
|
|
213
|
-
version: string
|
|
214
|
-
|
|
215
|
-
@Field({ description: 'Target stage (None, Staging, Production, Archived)' })
|
|
216
|
-
stage: string
|
|
217
|
-
|
|
218
|
-
@Field({ nullable: true, description: 'Archive existing versions in target stage' })
|
|
219
|
-
archiveExistingVersions?: boolean
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
@InputType({ description: 'Input for searching runs' })
|
|
223
|
-
export class SearchRunsInput {
|
|
224
|
-
@Field(type => [String], { description: 'Experiment IDs to search' })
|
|
225
|
-
experimentIds: string[]
|
|
226
|
-
|
|
227
|
-
@Field({ nullable: true, description: 'Filter string' })
|
|
228
|
-
filter?: string
|
|
229
|
-
|
|
230
|
-
@Field(type => Int, { nullable: true, description: 'Max results' })
|
|
231
|
-
maxResults?: number
|
|
232
|
-
|
|
233
|
-
@Field(type => [String], { nullable: true, description: 'Order by' })
|
|
234
|
-
orderBy?: string[]
|
|
235
|
-
}
|
|
@@ -1,375 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* MLflow REST API Client
|
|
3
|
-
*
|
|
4
|
-
* Thin wrapper around MLflow REST API for Things-Factory integration
|
|
5
|
-
* Reference: https://mlflow.org/docs/latest/rest-api.html
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import { config } from '@things-factory/env'
|
|
9
|
-
|
|
10
|
-
const MLFLOW_TRACKING_URI = config.get('mlflowTrackingUri', process.env.MLFLOW_TRACKING_URI || 'http://localhost:5000')
|
|
11
|
-
|
|
12
|
-
interface MLflowResponse<T> {
|
|
13
|
-
data?: T
|
|
14
|
-
error?: string
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
class MLflowApiClient {
|
|
18
|
-
private baseUrl: string
|
|
19
|
-
|
|
20
|
-
constructor(baseUrl: string = MLFLOW_TRACKING_URI) {
|
|
21
|
-
this.baseUrl = baseUrl.replace(/\/$/, '') // Remove trailing slash
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Generic HTTP request wrapper
|
|
26
|
-
*/
|
|
27
|
-
private async request<T>(endpoint: string, options: RequestInit = {}): Promise<T> {
|
|
28
|
-
const url = `${this.baseUrl}${endpoint}`
|
|
29
|
-
|
|
30
|
-
const defaultHeaders = {
|
|
31
|
-
'Content-Type': 'application/json'
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
try {
|
|
35
|
-
const response = await fetch(url, {
|
|
36
|
-
...options,
|
|
37
|
-
headers: {
|
|
38
|
-
...defaultHeaders,
|
|
39
|
-
...options.headers
|
|
40
|
-
}
|
|
41
|
-
})
|
|
42
|
-
|
|
43
|
-
if (!response.ok) {
|
|
44
|
-
const errorText = await response.text()
|
|
45
|
-
throw new Error(`MLflow API error: ${response.status} - ${errorText}`)
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
return await response.json()
|
|
49
|
-
} catch (error) {
|
|
50
|
-
console.error(`MLflow API request failed: ${endpoint}`, error)
|
|
51
|
-
throw error
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
// ========================================================================
|
|
56
|
-
// Experiments API
|
|
57
|
-
// ========================================================================
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* Create a new experiment
|
|
61
|
-
*/
|
|
62
|
-
async createExperiment(params: {
|
|
63
|
-
name: string
|
|
64
|
-
artifact_location?: string
|
|
65
|
-
tags?: Array<{ key: string; value: string }>
|
|
66
|
-
}): Promise<{ experiment_id: string }> {
|
|
67
|
-
return this.request('/api/2.0/mlflow/experiments/create', {
|
|
68
|
-
method: 'POST',
|
|
69
|
-
body: JSON.stringify(params)
|
|
70
|
-
})
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* Get experiment by ID
|
|
75
|
-
*/
|
|
76
|
-
async getExperiment(experimentId: string): Promise<{
|
|
77
|
-
experiment: {
|
|
78
|
-
experiment_id: string
|
|
79
|
-
name: string
|
|
80
|
-
artifact_location: string
|
|
81
|
-
lifecycle_stage: string
|
|
82
|
-
tags?: Array<{ key: string; value: string }>
|
|
83
|
-
}
|
|
84
|
-
}> {
|
|
85
|
-
return this.request(`/api/2.0/mlflow/experiments/get?experiment_id=${experimentId}`)
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* Search experiments
|
|
90
|
-
*/
|
|
91
|
-
async searchExperiments(params?: { max_results?: number; filter?: string; order_by?: string[] }): Promise<{
|
|
92
|
-
experiments: Array<{
|
|
93
|
-
experiment_id: string
|
|
94
|
-
name: string
|
|
95
|
-
artifact_location: string
|
|
96
|
-
lifecycle_stage: string
|
|
97
|
-
tags?: Array<{ key: string; value: string }>
|
|
98
|
-
}>
|
|
99
|
-
}> {
|
|
100
|
-
const queryParams = new URLSearchParams()
|
|
101
|
-
if (params?.max_results) queryParams.append('max_results', String(params.max_results))
|
|
102
|
-
if (params?.filter) queryParams.append('filter', params.filter)
|
|
103
|
-
|
|
104
|
-
return this.request(`/api/2.0/mlflow/experiments/search?${queryParams}`)
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
/**
|
|
108
|
-
* Delete experiment
|
|
109
|
-
*/
|
|
110
|
-
async deleteExperiment(experimentId: string): Promise<void> {
|
|
111
|
-
return this.request('/api/2.0/mlflow/experiments/delete', {
|
|
112
|
-
method: 'POST',
|
|
113
|
-
body: JSON.stringify({ experiment_id: experimentId })
|
|
114
|
-
})
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
// ========================================================================
|
|
118
|
-
// Runs API
|
|
119
|
-
// ========================================================================
|
|
120
|
-
|
|
121
|
-
/**
|
|
122
|
-
* Create a new run
|
|
123
|
-
*/
|
|
124
|
-
async createRun(params: {
|
|
125
|
-
experiment_id: string
|
|
126
|
-
start_time?: number
|
|
127
|
-
tags?: Array<{ key: string; value: string }>
|
|
128
|
-
}): Promise<{
|
|
129
|
-
run: {
|
|
130
|
-
info: {
|
|
131
|
-
run_id: string
|
|
132
|
-
experiment_id: string
|
|
133
|
-
status: string
|
|
134
|
-
start_time: number
|
|
135
|
-
artifact_uri: string
|
|
136
|
-
}
|
|
137
|
-
data: any
|
|
138
|
-
}
|
|
139
|
-
}> {
|
|
140
|
-
return this.request('/api/2.0/mlflow/runs/create', {
|
|
141
|
-
method: 'POST',
|
|
142
|
-
body: JSON.stringify(params)
|
|
143
|
-
})
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
/**
|
|
147
|
-
* Get run by ID
|
|
148
|
-
*/
|
|
149
|
-
async getRun(runId: string): Promise<{
|
|
150
|
-
run: {
|
|
151
|
-
info: {
|
|
152
|
-
run_id: string
|
|
153
|
-
experiment_id: string
|
|
154
|
-
status: string
|
|
155
|
-
start_time: number
|
|
156
|
-
end_time?: number
|
|
157
|
-
artifact_uri: string
|
|
158
|
-
}
|
|
159
|
-
data: {
|
|
160
|
-
metrics: Array<{ key: string; value: number; timestamp: number; step: number }>
|
|
161
|
-
params: Array<{ key: string; value: string }>
|
|
162
|
-
tags: Array<{ key: string; value: string }>
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
}> {
|
|
166
|
-
return this.request(`/api/2.0/mlflow/runs/get?run_id=${runId}`)
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
/**
|
|
170
|
-
* Search runs
|
|
171
|
-
*/
|
|
172
|
-
async searchRuns(params: {
|
|
173
|
-
experiment_ids: string[]
|
|
174
|
-
filter?: string
|
|
175
|
-
max_results?: number
|
|
176
|
-
order_by?: string[]
|
|
177
|
-
}): Promise<{
|
|
178
|
-
runs: Array<{
|
|
179
|
-
info: {
|
|
180
|
-
run_id: string
|
|
181
|
-
experiment_id: string
|
|
182
|
-
status: string
|
|
183
|
-
start_time: number
|
|
184
|
-
end_time?: number
|
|
185
|
-
artifact_uri: string
|
|
186
|
-
}
|
|
187
|
-
data: any
|
|
188
|
-
}>
|
|
189
|
-
}> {
|
|
190
|
-
return this.request('/api/2.0/mlflow/runs/search', {
|
|
191
|
-
method: 'POST',
|
|
192
|
-
body: JSON.stringify(params)
|
|
193
|
-
})
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
/**
|
|
197
|
-
* Log metric for a run
|
|
198
|
-
*/
|
|
199
|
-
async logMetric(params: {
|
|
200
|
-
run_id: string
|
|
201
|
-
key: string
|
|
202
|
-
value: number
|
|
203
|
-
timestamp?: number
|
|
204
|
-
step?: number
|
|
205
|
-
}): Promise<void> {
|
|
206
|
-
return this.request('/api/2.0/mlflow/runs/log-metric', {
|
|
207
|
-
method: 'POST',
|
|
208
|
-
body: JSON.stringify(params)
|
|
209
|
-
})
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
/**
|
|
213
|
-
* Log parameter for a run
|
|
214
|
-
*/
|
|
215
|
-
async logParam(params: { run_id: string; key: string; value: string }): Promise<void> {
|
|
216
|
-
return this.request('/api/2.0/mlflow/runs/log-parameter', {
|
|
217
|
-
method: 'POST',
|
|
218
|
-
body: JSON.stringify(params)
|
|
219
|
-
})
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
/**
|
|
223
|
-
* Update run status
|
|
224
|
-
*/
|
|
225
|
-
async updateRun(params: {
|
|
226
|
-
run_id: string
|
|
227
|
-
status?: 'RUNNING' | 'SCHEDULED' | 'FINISHED' | 'FAILED' | 'KILLED'
|
|
228
|
-
end_time?: number
|
|
229
|
-
}): Promise<void> {
|
|
230
|
-
return this.request('/api/2.0/mlflow/runs/update', {
|
|
231
|
-
method: 'POST',
|
|
232
|
-
body: JSON.stringify(params)
|
|
233
|
-
})
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
// ========================================================================
|
|
237
|
-
// Model Registry API
|
|
238
|
-
// ========================================================================
|
|
239
|
-
|
|
240
|
-
/**
|
|
241
|
-
* Create registered model
|
|
242
|
-
*/
|
|
243
|
-
async createRegisteredModel(params: {
|
|
244
|
-
name: string
|
|
245
|
-
tags?: Array<{ key: string; value: string }>
|
|
246
|
-
description?: string
|
|
247
|
-
}): Promise<{
|
|
248
|
-
registered_model: {
|
|
249
|
-
name: string
|
|
250
|
-
creation_timestamp: number
|
|
251
|
-
last_updated_timestamp: number
|
|
252
|
-
}
|
|
253
|
-
}> {
|
|
254
|
-
return this.request('/api/2.0/mlflow/registered-models/create', {
|
|
255
|
-
method: 'POST',
|
|
256
|
-
body: JSON.stringify(params)
|
|
257
|
-
})
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
/**
|
|
261
|
-
* Get registered model
|
|
262
|
-
*/
|
|
263
|
-
async getRegisteredModel(name: string): Promise<{
|
|
264
|
-
registered_model: {
|
|
265
|
-
name: string
|
|
266
|
-
creation_timestamp: number
|
|
267
|
-
last_updated_timestamp: number
|
|
268
|
-
description?: string
|
|
269
|
-
tags?: Array<{ key: string; value: string }>
|
|
270
|
-
latest_versions?: any[]
|
|
271
|
-
}
|
|
272
|
-
}> {
|
|
273
|
-
return this.request(`/api/2.0/mlflow/registered-models/get?name=${encodeURIComponent(name)}`)
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
/**
|
|
277
|
-
* Search registered models
|
|
278
|
-
*/
|
|
279
|
-
async searchRegisteredModels(params?: { filter?: string; max_results?: number; order_by?: string[] }): Promise<{
|
|
280
|
-
registered_models: Array<{
|
|
281
|
-
name: string
|
|
282
|
-
creation_timestamp: number
|
|
283
|
-
last_updated_timestamp: number
|
|
284
|
-
description?: string
|
|
285
|
-
latest_versions?: any[]
|
|
286
|
-
}>
|
|
287
|
-
}> {
|
|
288
|
-
const queryParams = new URLSearchParams()
|
|
289
|
-
if (params?.filter) queryParams.append('filter', params.filter)
|
|
290
|
-
if (params?.max_results) queryParams.append('max_results', String(params.max_results))
|
|
291
|
-
|
|
292
|
-
return this.request(`/api/2.0/mlflow/registered-models/search?${queryParams}`)
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
/**
|
|
296
|
-
* Create model version
|
|
297
|
-
*/
|
|
298
|
-
async createModelVersion(params: {
|
|
299
|
-
name: string
|
|
300
|
-
source: string
|
|
301
|
-
run_id?: string
|
|
302
|
-
tags?: Array<{ key: string; value: string }>
|
|
303
|
-
description?: string
|
|
304
|
-
}): Promise<{
|
|
305
|
-
model_version: {
|
|
306
|
-
name: string
|
|
307
|
-
version: string
|
|
308
|
-
creation_timestamp: number
|
|
309
|
-
last_updated_timestamp: number
|
|
310
|
-
source: string
|
|
311
|
-
status: string
|
|
312
|
-
}
|
|
313
|
-
}> {
|
|
314
|
-
return this.request('/api/2.0/mlflow/model-versions/create', {
|
|
315
|
-
method: 'POST',
|
|
316
|
-
body: JSON.stringify(params)
|
|
317
|
-
})
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
/**
|
|
321
|
-
* Get model version
|
|
322
|
-
*/
|
|
323
|
-
async getModelVersion(params: { name: string; version: string }): Promise<{
|
|
324
|
-
model_version: {
|
|
325
|
-
name: string
|
|
326
|
-
version: string
|
|
327
|
-
creation_timestamp: number
|
|
328
|
-
current_stage: string
|
|
329
|
-
source: string
|
|
330
|
-
status: string
|
|
331
|
-
run_id?: string
|
|
332
|
-
}
|
|
333
|
-
}> {
|
|
334
|
-
return this.request(
|
|
335
|
-
`/api/2.0/mlflow/model-versions/get?name=${encodeURIComponent(params.name)}&version=${params.version}`
|
|
336
|
-
)
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
/**
|
|
340
|
-
* Transition model version stage
|
|
341
|
-
*/
|
|
342
|
-
async transitionModelVersionStage(params: {
|
|
343
|
-
name: string
|
|
344
|
-
version: string
|
|
345
|
-
stage: 'None' | 'Staging' | 'Production' | 'Archived'
|
|
346
|
-
archive_existing_versions?: boolean
|
|
347
|
-
}): Promise<{
|
|
348
|
-
model_version: {
|
|
349
|
-
name: string
|
|
350
|
-
version: string
|
|
351
|
-
current_stage: string
|
|
352
|
-
}
|
|
353
|
-
}> {
|
|
354
|
-
return this.request('/api/2.0/mlflow/model-versions/transition-stage', {
|
|
355
|
-
method: 'POST',
|
|
356
|
-
body: JSON.stringify(params)
|
|
357
|
-
})
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
/**
|
|
361
|
-
* Delete model version
|
|
362
|
-
*/
|
|
363
|
-
async deleteModelVersion(params: { name: string; version: string }): Promise<void> {
|
|
364
|
-
return this.request('/api/2.0/mlflow/model-versions/delete', {
|
|
365
|
-
method: 'DELETE',
|
|
366
|
-
body: JSON.stringify(params)
|
|
367
|
-
})
|
|
368
|
-
}
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
// Export singleton instance
|
|
372
|
-
export const mlflowApi = new MLflowApiClient()
|
|
373
|
-
|
|
374
|
-
// Export class for testing or custom instances
|
|
375
|
-
export { MLflowApiClient }
|