@things-factory/integration-mlflow 9.1.19 → 10.0.0-beta.1
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
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@things-factory/integration-mlflow",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "10.0.0-beta.1",
|
|
4
4
|
"main": "dist-server/index.js",
|
|
5
5
|
"browser": "dist-client/index.js",
|
|
6
6
|
"things-factory": true,
|
|
@@ -26,12 +26,12 @@
|
|
|
26
26
|
"clean": "npm run clean:server && npm run clean:client"
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@operato/graphql": "^
|
|
30
|
-
"@operato/layout": "^
|
|
31
|
-
"@things-factory/auth-base": "^
|
|
32
|
-
"@things-factory/env": "^
|
|
33
|
-
"@things-factory/menu-base": "^
|
|
34
|
-
"@things-factory/shell": "^
|
|
29
|
+
"@operato/graphql": "^10.0.0-beta.1",
|
|
30
|
+
"@operato/layout": "^10.0.0-beta.1",
|
|
31
|
+
"@things-factory/auth-base": "^10.0.0-beta.1",
|
|
32
|
+
"@things-factory/env": "^10.0.0-beta.1",
|
|
33
|
+
"@things-factory/menu-base": "^10.0.0-beta.1",
|
|
34
|
+
"@things-factory/shell": "^10.0.0-beta.1"
|
|
35
35
|
},
|
|
36
36
|
"keywords": [
|
|
37
37
|
"things-factory",
|
|
@@ -41,5 +41,5 @@
|
|
|
41
41
|
"model-registry",
|
|
42
42
|
"machine-learning"
|
|
43
43
|
],
|
|
44
|
-
"gitHead": "
|
|
44
|
+
"gitHead": "90f40bf160fa25edf4560d7893cfd576cf474411"
|
|
45
45
|
}
|
package/client/tsconfig.json
DELETED
package/server/index.ts
DELETED
package/server/route.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* MLflow Integration Routes
|
|
3
|
-
*
|
|
4
|
-
* Register additional routes if needed (beyond GraphQL)
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
// Example: Proxy to MLflow UI, webhooks, etc.
|
|
8
|
-
// import Koa from 'koa'
|
|
9
|
-
// import Router from 'koa-router'
|
|
10
|
-
|
|
11
|
-
// process.on('bootstrap-module-domain-private-route', (app: Koa, router: Router) => {
|
|
12
|
-
// // Add custom routes here
|
|
13
|
-
// })
|
|
@@ -1,117 +0,0 @@
|
|
|
1
|
-
import { Resolver, Query, Mutation, Arg, Ctx, Directive } from 'type-graphql'
|
|
2
|
-
import { mlflowApi } from '../../utils/mlflow-api-client'
|
|
3
|
-
import {
|
|
4
|
-
MLflowExperiment,
|
|
5
|
-
CreateExperimentInput
|
|
6
|
-
} from '../../types/mlflow-types'
|
|
7
|
-
|
|
8
|
-
@Resolver()
|
|
9
|
-
export class ExperimentService {
|
|
10
|
-
/**
|
|
11
|
-
* Get all experiments
|
|
12
|
-
*/
|
|
13
|
-
@Query(returns => [MLflowExperiment], {
|
|
14
|
-
description: 'Get all MLflow experiments'
|
|
15
|
-
})
|
|
16
|
-
@Directive('@privilege(category: "mlflow", privilege: "query")')
|
|
17
|
-
async mlflowExperiments(@Ctx() context: ResolverContext): Promise<MLflowExperiment[]> {
|
|
18
|
-
try {
|
|
19
|
-
const response = await mlflowApi.searchExperiments()
|
|
20
|
-
|
|
21
|
-
return response.experiments.map(exp => ({
|
|
22
|
-
experimentId: exp.experiment_id,
|
|
23
|
-
name: exp.name,
|
|
24
|
-
artifactLocation: exp.artifact_location,
|
|
25
|
-
lifecycleStage: exp.lifecycle_stage,
|
|
26
|
-
tags: exp.tags ? JSON.stringify(exp.tags) : undefined
|
|
27
|
-
}))
|
|
28
|
-
} catch (error) {
|
|
29
|
-
console.error('Failed to fetch MLflow experiments:', error)
|
|
30
|
-
throw new Error(`Failed to fetch experiments: ${error.message}`)
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* Get experiment by ID
|
|
36
|
-
*/
|
|
37
|
-
@Query(returns => MLflowExperiment, {
|
|
38
|
-
description: 'Get MLflow experiment by ID',
|
|
39
|
-
nullable: true
|
|
40
|
-
})
|
|
41
|
-
@Directive('@privilege(category: "mlflow", privilege: "query")')
|
|
42
|
-
async mlflowExperiment(
|
|
43
|
-
@Arg('experimentId') experimentId: string,
|
|
44
|
-
@Ctx() context: ResolverContext
|
|
45
|
-
): Promise<MLflowExperiment | null> {
|
|
46
|
-
try {
|
|
47
|
-
const response = await mlflowApi.getExperiment(experimentId)
|
|
48
|
-
|
|
49
|
-
return {
|
|
50
|
-
experimentId: response.experiment.experiment_id,
|
|
51
|
-
name: response.experiment.name,
|
|
52
|
-
artifactLocation: response.experiment.artifact_location,
|
|
53
|
-
lifecycleStage: response.experiment.lifecycle_stage,
|
|
54
|
-
tags: response.experiment.tags ? JSON.stringify(response.experiment.tags) : undefined
|
|
55
|
-
}
|
|
56
|
-
} catch (error) {
|
|
57
|
-
console.error(`Failed to fetch experiment ${experimentId}:`, error)
|
|
58
|
-
return null
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* Create new experiment
|
|
64
|
-
*/
|
|
65
|
-
@Mutation(returns => MLflowExperiment, {
|
|
66
|
-
description: 'Create new MLflow experiment'
|
|
67
|
-
})
|
|
68
|
-
@Directive('@privilege(category: "mlflow", privilege: "mutation")')
|
|
69
|
-
async createMLflowExperiment(
|
|
70
|
-
@Arg('input') input: CreateExperimentInput,
|
|
71
|
-
@Ctx() context: ResolverContext
|
|
72
|
-
): Promise<MLflowExperiment> {
|
|
73
|
-
try {
|
|
74
|
-
const tags = input.tags ? JSON.parse(input.tags) : undefined
|
|
75
|
-
|
|
76
|
-
const response = await mlflowApi.createExperiment({
|
|
77
|
-
name: input.name,
|
|
78
|
-
artifact_location: input.artifactLocation,
|
|
79
|
-
tags
|
|
80
|
-
})
|
|
81
|
-
|
|
82
|
-
// Fetch created experiment
|
|
83
|
-
const experiment = await mlflowApi.getExperiment(response.experiment_id)
|
|
84
|
-
|
|
85
|
-
return {
|
|
86
|
-
experimentId: experiment.experiment.experiment_id,
|
|
87
|
-
name: experiment.experiment.name,
|
|
88
|
-
artifactLocation: experiment.experiment.artifact_location,
|
|
89
|
-
lifecycleStage: experiment.experiment.lifecycle_stage,
|
|
90
|
-
tags: experiment.experiment.tags ? JSON.stringify(experiment.experiment.tags) : undefined
|
|
91
|
-
}
|
|
92
|
-
} catch (error) {
|
|
93
|
-
console.error('Failed to create MLflow experiment:', error)
|
|
94
|
-
throw new Error(`Failed to create experiment: ${error.message}`)
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
/**
|
|
99
|
-
* Delete experiment
|
|
100
|
-
*/
|
|
101
|
-
@Mutation(returns => Boolean, {
|
|
102
|
-
description: 'Delete MLflow experiment'
|
|
103
|
-
})
|
|
104
|
-
@Directive('@privilege(category: "mlflow", privilege: "mutation")')
|
|
105
|
-
async deleteMLflowExperiment(
|
|
106
|
-
@Arg('experimentId') experimentId: string,
|
|
107
|
-
@Ctx() context: ResolverContext
|
|
108
|
-
): Promise<boolean> {
|
|
109
|
-
try {
|
|
110
|
-
await mlflowApi.deleteExperiment(experimentId)
|
|
111
|
-
return true
|
|
112
|
-
} catch (error) {
|
|
113
|
-
console.error(`Failed to delete experiment ${experimentId}:`, error)
|
|
114
|
-
throw new Error(`Failed to delete experiment: ${error.message}`)
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
}
|
package/server/service/index.ts
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { ExperimentService } from './experiment/experiment-service'
|
|
2
|
-
import { RunService } from './run/run-service'
|
|
3
|
-
import { ModelRegistryService } from './model-registry/model-registry-service'
|
|
4
|
-
|
|
5
|
-
export const entities = []
|
|
6
|
-
|
|
7
|
-
export const schema = {
|
|
8
|
-
resolverClasses: [
|
|
9
|
-
ExperimentService,
|
|
10
|
-
RunService,
|
|
11
|
-
ModelRegistryService
|
|
12
|
-
]
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export * from './experiment/experiment-service'
|
|
16
|
-
export * from './run/run-service'
|
|
17
|
-
export * from './model-registry/model-registry-service'
|
|
@@ -1,232 +0,0 @@
|
|
|
1
|
-
import { Resolver, Query, Mutation, Arg, Ctx, Directive } from 'type-graphql'
|
|
2
|
-
import { mlflowApi } from '../../utils/mlflow-api-client'
|
|
3
|
-
import {
|
|
4
|
-
MLflowRegisteredModel,
|
|
5
|
-
MLflowModelVersion,
|
|
6
|
-
CreateRegisteredModelInput,
|
|
7
|
-
CreateModelVersionInput,
|
|
8
|
-
TransitionStageInput
|
|
9
|
-
} from '../../types/mlflow-types'
|
|
10
|
-
|
|
11
|
-
@Resolver()
|
|
12
|
-
export class ModelRegistryService {
|
|
13
|
-
/**
|
|
14
|
-
* Get all registered models
|
|
15
|
-
*/
|
|
16
|
-
@Query(returns => [MLflowRegisteredModel], {
|
|
17
|
-
description: 'Get all registered models in MLflow'
|
|
18
|
-
})
|
|
19
|
-
@Directive('@privilege(category: "mlflow", privilege: "query")')
|
|
20
|
-
async mlflowRegisteredModels(@Ctx() context: ResolverContext): Promise<MLflowRegisteredModel[]> {
|
|
21
|
-
try {
|
|
22
|
-
const response = await mlflowApi.searchRegisteredModels()
|
|
23
|
-
|
|
24
|
-
return response.registered_models.map(model => ({
|
|
25
|
-
name: model.name,
|
|
26
|
-
creationTimestamp: model.creation_timestamp,
|
|
27
|
-
lastUpdatedTimestamp: model.last_updated_timestamp,
|
|
28
|
-
description: model.description,
|
|
29
|
-
tags: undefined,
|
|
30
|
-
latestVersions: model.latest_versions ? JSON.stringify(model.latest_versions) : undefined
|
|
31
|
-
}))
|
|
32
|
-
} catch (error) {
|
|
33
|
-
console.error('Failed to fetch registered models:', error)
|
|
34
|
-
throw new Error(`Failed to fetch registered models: ${error.message}`)
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Get registered model by name
|
|
40
|
-
*/
|
|
41
|
-
@Query(returns => MLflowRegisteredModel, {
|
|
42
|
-
description: 'Get registered model by name',
|
|
43
|
-
nullable: true
|
|
44
|
-
})
|
|
45
|
-
@Directive('@privilege(category: "mlflow", privilege: "query")')
|
|
46
|
-
async mlflowRegisteredModel(
|
|
47
|
-
@Arg('name') name: string,
|
|
48
|
-
@Ctx() context: ResolverContext
|
|
49
|
-
): Promise<MLflowRegisteredModel | null> {
|
|
50
|
-
try {
|
|
51
|
-
const response = await mlflowApi.getRegisteredModel(name)
|
|
52
|
-
|
|
53
|
-
return {
|
|
54
|
-
name: response.registered_model.name,
|
|
55
|
-
creationTimestamp: response.registered_model.creation_timestamp,
|
|
56
|
-
lastUpdatedTimestamp: response.registered_model.last_updated_timestamp,
|
|
57
|
-
description: response.registered_model.description,
|
|
58
|
-
tags: response.registered_model.tags ? JSON.stringify(response.registered_model.tags) : undefined,
|
|
59
|
-
latestVersions: response.registered_model.latest_versions ? JSON.stringify(response.registered_model.latest_versions) : undefined
|
|
60
|
-
}
|
|
61
|
-
} catch (error) {
|
|
62
|
-
console.error(`Failed to fetch model ${name}:`, error)
|
|
63
|
-
return null
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* Create registered model
|
|
69
|
-
*/
|
|
70
|
-
@Mutation(returns => MLflowRegisteredModel, {
|
|
71
|
-
description: 'Create new registered model'
|
|
72
|
-
})
|
|
73
|
-
@Directive('@privilege(category: "mlflow", privilege: "mutation")')
|
|
74
|
-
async createMLflowRegisteredModel(
|
|
75
|
-
@Arg('input') input: CreateRegisteredModelInput,
|
|
76
|
-
@Ctx() context: ResolverContext
|
|
77
|
-
): Promise<MLflowRegisteredModel> {
|
|
78
|
-
try {
|
|
79
|
-
const tags = input.tags ? JSON.parse(input.tags) : undefined
|
|
80
|
-
|
|
81
|
-
const response = await mlflowApi.createRegisteredModel({
|
|
82
|
-
name: input.name,
|
|
83
|
-
description: input.description,
|
|
84
|
-
tags
|
|
85
|
-
})
|
|
86
|
-
|
|
87
|
-
return {
|
|
88
|
-
name: response.registered_model.name,
|
|
89
|
-
creationTimestamp: response.registered_model.creation_timestamp,
|
|
90
|
-
lastUpdatedTimestamp: response.registered_model.last_updated_timestamp,
|
|
91
|
-
description: input.description,
|
|
92
|
-
tags: input.tags,
|
|
93
|
-
latestVersions: undefined
|
|
94
|
-
}
|
|
95
|
-
} catch (error) {
|
|
96
|
-
console.error('Failed to create registered model:', error)
|
|
97
|
-
throw new Error(`Failed to create registered model: ${error.message}`)
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
/**
|
|
102
|
-
* Get model version
|
|
103
|
-
*/
|
|
104
|
-
@Query(returns => MLflowModelVersion, {
|
|
105
|
-
description: 'Get model version',
|
|
106
|
-
nullable: true
|
|
107
|
-
})
|
|
108
|
-
@Directive('@privilege(category: "mlflow", privilege: "query")')
|
|
109
|
-
async mlflowModelVersion(
|
|
110
|
-
@Arg('name') name: string,
|
|
111
|
-
@Arg('version') version: string,
|
|
112
|
-
@Ctx() context: ResolverContext
|
|
113
|
-
): Promise<MLflowModelVersion | null> {
|
|
114
|
-
try {
|
|
115
|
-
const response = await mlflowApi.getModelVersion({ name, version })
|
|
116
|
-
|
|
117
|
-
return {
|
|
118
|
-
name: response.model_version.name,
|
|
119
|
-
version: response.model_version.version,
|
|
120
|
-
creationTimestamp: response.model_version.creation_timestamp,
|
|
121
|
-
currentStage: response.model_version.current_stage,
|
|
122
|
-
source: response.model_version.source,
|
|
123
|
-
status: response.model_version.status,
|
|
124
|
-
runId: response.model_version.run_id,
|
|
125
|
-
description: undefined
|
|
126
|
-
}
|
|
127
|
-
} catch (error) {
|
|
128
|
-
console.error(`Failed to fetch model version ${name}/${version}:`, error)
|
|
129
|
-
return null
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
/**
|
|
134
|
-
* Create model version
|
|
135
|
-
*/
|
|
136
|
-
@Mutation(returns => MLflowModelVersion, {
|
|
137
|
-
description: 'Create new model version'
|
|
138
|
-
})
|
|
139
|
-
@Directive('@privilege(category: "mlflow", privilege: "mutation")')
|
|
140
|
-
async createMLflowModelVersion(
|
|
141
|
-
@Arg('input') input: CreateModelVersionInput,
|
|
142
|
-
@Ctx() context: ResolverContext
|
|
143
|
-
): Promise<MLflowModelVersion> {
|
|
144
|
-
try {
|
|
145
|
-
const tags = input.tags ? JSON.parse(input.tags) : undefined
|
|
146
|
-
|
|
147
|
-
const response = await mlflowApi.createModelVersion({
|
|
148
|
-
name: input.name,
|
|
149
|
-
source: input.source,
|
|
150
|
-
run_id: input.runId,
|
|
151
|
-
description: input.description,
|
|
152
|
-
tags
|
|
153
|
-
})
|
|
154
|
-
|
|
155
|
-
return {
|
|
156
|
-
name: response.model_version.name,
|
|
157
|
-
version: response.model_version.version,
|
|
158
|
-
creationTimestamp: response.model_version.creation_timestamp,
|
|
159
|
-
currentStage: response.model_version.status,
|
|
160
|
-
source: response.model_version.source,
|
|
161
|
-
status: response.model_version.status,
|
|
162
|
-
runId: input.runId,
|
|
163
|
-
description: input.description
|
|
164
|
-
}
|
|
165
|
-
} catch (error) {
|
|
166
|
-
console.error('Failed to create model version:', error)
|
|
167
|
-
throw new Error(`Failed to create model version: ${error.message}`)
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
/**
|
|
172
|
-
* Transition model version stage
|
|
173
|
-
*/
|
|
174
|
-
@Mutation(returns => MLflowModelVersion, {
|
|
175
|
-
description: 'Transition model version to target stage (None, Staging, Production, Archived)'
|
|
176
|
-
})
|
|
177
|
-
@Directive('@privilege(category: "mlflow", privilege: "mutation")')
|
|
178
|
-
async transitionMLflowModelStage(
|
|
179
|
-
@Arg('input') input: TransitionStageInput,
|
|
180
|
-
@Ctx() context: ResolverContext
|
|
181
|
-
): Promise<MLflowModelVersion> {
|
|
182
|
-
try {
|
|
183
|
-
const response = await mlflowApi.transitionModelVersionStage({
|
|
184
|
-
name: input.name,
|
|
185
|
-
version: input.version,
|
|
186
|
-
stage: input.stage as any,
|
|
187
|
-
archive_existing_versions: input.archiveExistingVersions
|
|
188
|
-
})
|
|
189
|
-
|
|
190
|
-
// Fetch updated version
|
|
191
|
-
const version = await mlflowApi.getModelVersion({
|
|
192
|
-
name: input.name,
|
|
193
|
-
version: input.version
|
|
194
|
-
})
|
|
195
|
-
|
|
196
|
-
return {
|
|
197
|
-
name: version.model_version.name,
|
|
198
|
-
version: version.model_version.version,
|
|
199
|
-
creationTimestamp: version.model_version.creation_timestamp,
|
|
200
|
-
currentStage: version.model_version.current_stage,
|
|
201
|
-
source: version.model_version.source,
|
|
202
|
-
status: version.model_version.status,
|
|
203
|
-
runId: version.model_version.run_id,
|
|
204
|
-
description: undefined
|
|
205
|
-
}
|
|
206
|
-
} catch (error) {
|
|
207
|
-
console.error('Failed to transition model stage:', error)
|
|
208
|
-
throw new Error(`Failed to transition model stage: ${error.message}`)
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
/**
|
|
213
|
-
* Delete model version
|
|
214
|
-
*/
|
|
215
|
-
@Mutation(returns => Boolean, {
|
|
216
|
-
description: 'Delete model version'
|
|
217
|
-
})
|
|
218
|
-
@Directive('@privilege(category: "mlflow", privilege: "mutation")')
|
|
219
|
-
async deleteMLflowModelVersion(
|
|
220
|
-
@Arg('name') name: string,
|
|
221
|
-
@Arg('version') version: string,
|
|
222
|
-
@Ctx() context: ResolverContext
|
|
223
|
-
): Promise<boolean> {
|
|
224
|
-
try {
|
|
225
|
-
await mlflowApi.deleteModelVersion({ name, version })
|
|
226
|
-
return true
|
|
227
|
-
} catch (error) {
|
|
228
|
-
console.error(`Failed to delete model version ${name}/${version}:`, error)
|
|
229
|
-
throw new Error(`Failed to delete model version: ${error.message}`)
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
}
|
|
@@ -1,177 +0,0 @@
|
|
|
1
|
-
import { Resolver, Query, Mutation, Arg, Ctx, Directive } from 'type-graphql'
|
|
2
|
-
import { User } from '@things-factory/auth-base'
|
|
3
|
-
import { mlflowApi } from '../../utils/mlflow-api-client'
|
|
4
|
-
import {
|
|
5
|
-
MLflowRun,
|
|
6
|
-
CreateRunInput,
|
|
7
|
-
LogMetricInput,
|
|
8
|
-
LogParamInput,
|
|
9
|
-
UpdateRunInput,
|
|
10
|
-
SearchRunsInput
|
|
11
|
-
} from '../../types/mlflow-types'
|
|
12
|
-
|
|
13
|
-
@Resolver()
|
|
14
|
-
export class RunService {
|
|
15
|
-
/**
|
|
16
|
-
* Get run by ID
|
|
17
|
-
*/
|
|
18
|
-
@Query(returns => MLflowRun, {
|
|
19
|
-
description: 'Get MLflow run by ID',
|
|
20
|
-
nullable: true
|
|
21
|
-
})
|
|
22
|
-
@Directive('@privilege(category: "mlflow", privilege: "query")')
|
|
23
|
-
async mlflowRun(@Arg('runId') runId: string, @Ctx() context: ResolverContext): Promise<MLflowRun | null> {
|
|
24
|
-
try {
|
|
25
|
-
const response = await mlflowApi.getRun(runId)
|
|
26
|
-
const run = response.run
|
|
27
|
-
|
|
28
|
-
return {
|
|
29
|
-
runId: run.info.run_id,
|
|
30
|
-
experimentId: run.info.experiment_id,
|
|
31
|
-
status: run.info.status,
|
|
32
|
-
startTime: run.info.start_time,
|
|
33
|
-
endTime: run.info.end_time,
|
|
34
|
-
artifactUri: run.info.artifact_uri,
|
|
35
|
-
metrics: run.data.metrics ? JSON.stringify(run.data.metrics) : undefined,
|
|
36
|
-
params: run.data.params ? JSON.stringify(run.data.params) : undefined,
|
|
37
|
-
tags: run.data.tags ? JSON.stringify(run.data.tags) : undefined
|
|
38
|
-
}
|
|
39
|
-
} catch (error) {
|
|
40
|
-
console.error(`Failed to fetch run ${runId}:`, error)
|
|
41
|
-
return null
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Search runs
|
|
47
|
-
*/
|
|
48
|
-
@Query(returns => [MLflowRun], {
|
|
49
|
-
description: 'Search MLflow runs'
|
|
50
|
-
})
|
|
51
|
-
@Directive('@privilege(category: "mlflow", privilege: "query")')
|
|
52
|
-
async searchMLflowRuns(@Arg('input') input: SearchRunsInput, @Ctx() context: ResolverContext): Promise<MLflowRun[]> {
|
|
53
|
-
try {
|
|
54
|
-
const response = await mlflowApi.searchRuns({
|
|
55
|
-
experiment_ids: input.experimentIds,
|
|
56
|
-
filter: input.filter,
|
|
57
|
-
max_results: input.maxResults,
|
|
58
|
-
order_by: input.orderBy
|
|
59
|
-
})
|
|
60
|
-
|
|
61
|
-
return response.runs.map(run => ({
|
|
62
|
-
runId: run.info.run_id,
|
|
63
|
-
experimentId: run.info.experiment_id,
|
|
64
|
-
status: run.info.status,
|
|
65
|
-
startTime: run.info.start_time,
|
|
66
|
-
endTime: run.info.end_time,
|
|
67
|
-
artifactUri: run.info.artifact_uri,
|
|
68
|
-
metrics: run.data.metrics ? JSON.stringify(run.data.metrics) : undefined,
|
|
69
|
-
params: run.data.params ? JSON.stringify(run.data.params) : undefined,
|
|
70
|
-
tags: run.data.tags ? JSON.stringify(run.data.tags) : undefined
|
|
71
|
-
}))
|
|
72
|
-
} catch (error) {
|
|
73
|
-
console.error('Failed to search runs:', error)
|
|
74
|
-
throw new Error(`Failed to search runs: ${error.message}`)
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* Create new run
|
|
80
|
-
*/
|
|
81
|
-
@Mutation(returns => MLflowRun, {
|
|
82
|
-
description: 'Create new MLflow run'
|
|
83
|
-
})
|
|
84
|
-
@Directive('@privilege(category: "mlflow", privilege: "mutation")')
|
|
85
|
-
async createMLflowRun(@Arg('input') input: CreateRunInput, @Ctx() context: ResolverContext): Promise<MLflowRun> {
|
|
86
|
-
try {
|
|
87
|
-
const tags = input.tags ? JSON.parse(input.tags) : undefined
|
|
88
|
-
|
|
89
|
-
const response = await mlflowApi.createRun({
|
|
90
|
-
experiment_id: input.experimentId,
|
|
91
|
-
start_time: input.startTime,
|
|
92
|
-
tags
|
|
93
|
-
})
|
|
94
|
-
|
|
95
|
-
const run = response.run
|
|
96
|
-
|
|
97
|
-
return {
|
|
98
|
-
runId: run.info.run_id,
|
|
99
|
-
experimentId: run.info.experiment_id,
|
|
100
|
-
status: run.info.status,
|
|
101
|
-
startTime: run.info.start_time,
|
|
102
|
-
artifactUri: run.info.artifact_uri,
|
|
103
|
-
metrics: run.data.metrics ? JSON.stringify(run.data.metrics) : undefined,
|
|
104
|
-
params: run.data.params ? JSON.stringify(run.data.params) : undefined,
|
|
105
|
-
tags: run.data.tags ? JSON.stringify(run.data.tags) : undefined
|
|
106
|
-
}
|
|
107
|
-
} catch (error) {
|
|
108
|
-
console.error('Failed to create run:', error)
|
|
109
|
-
throw new Error(`Failed to create run: ${error.message}`)
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
/**
|
|
114
|
-
* Log metric
|
|
115
|
-
*/
|
|
116
|
-
@Mutation(returns => Boolean, {
|
|
117
|
-
description: 'Log metric to MLflow run'
|
|
118
|
-
})
|
|
119
|
-
@Directive('@privilege(category: "mlflow", privilege: "mutation")')
|
|
120
|
-
async logMLflowMetric(@Arg('input') input: LogMetricInput, @Ctx() context: ResolverContext): Promise<boolean> {
|
|
121
|
-
try {
|
|
122
|
-
await mlflowApi.logMetric({
|
|
123
|
-
run_id: input.runId,
|
|
124
|
-
key: input.key,
|
|
125
|
-
value: input.value,
|
|
126
|
-
timestamp: input.timestamp,
|
|
127
|
-
step: input.step
|
|
128
|
-
})
|
|
129
|
-
return true
|
|
130
|
-
} catch (error) {
|
|
131
|
-
console.error('Failed to log metric:', error)
|
|
132
|
-
throw new Error(`Failed to log metric: ${error.message}`)
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
/**
|
|
137
|
-
* Log parameter
|
|
138
|
-
*/
|
|
139
|
-
@Mutation(returns => Boolean, {
|
|
140
|
-
description: 'Log parameter to MLflow run'
|
|
141
|
-
})
|
|
142
|
-
@Directive('@privilege(category: "mlflow", privilege: "mutation")')
|
|
143
|
-
async logMLflowParam(@Arg('input') input: LogParamInput, @Ctx() context: ResolverContext): Promise<boolean> {
|
|
144
|
-
try {
|
|
145
|
-
await mlflowApi.logParam({
|
|
146
|
-
run_id: input.runId,
|
|
147
|
-
key: input.key,
|
|
148
|
-
value: input.value
|
|
149
|
-
})
|
|
150
|
-
return true
|
|
151
|
-
} catch (error) {
|
|
152
|
-
console.error('Failed to log parameter:', error)
|
|
153
|
-
throw new Error(`Failed to log parameter: ${error.message}`)
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
/**
|
|
158
|
-
* Update run
|
|
159
|
-
*/
|
|
160
|
-
@Mutation(returns => Boolean, {
|
|
161
|
-
description: 'Update MLflow run status'
|
|
162
|
-
})
|
|
163
|
-
@Directive('@privilege(category: "mlflow", privilege: "mutation")')
|
|
164
|
-
async updateMLflowRun(@Arg('input') input: UpdateRunInput, @Ctx() context: ResolverContext): Promise<boolean> {
|
|
165
|
-
try {
|
|
166
|
-
await mlflowApi.updateRun({
|
|
167
|
-
run_id: input.runId,
|
|
168
|
-
status: input.status as any,
|
|
169
|
-
end_time: input.endTime
|
|
170
|
-
})
|
|
171
|
-
return true
|
|
172
|
-
} catch (error) {
|
|
173
|
-
console.error('Failed to update run:', error)
|
|
174
|
-
throw new Error(`Failed to update run: ${error.message}`)
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
}
|