@things-factory/integration-mlflow 9.2.5 → 10.0.0-beta.10

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.
@@ -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 }