@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,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
- }
@@ -1,11 +0,0 @@
1
- {
2
- "extends": "../../tsconfig-base.json",
3
- "compilerOptions": {
4
- "strict": false,
5
- "declaration": true,
6
- "module": "commonjs",
7
- "outDir": "../dist-server",
8
- "baseUrl": "./"
9
- },
10
- "include": ["./**/*"]
11
- }
@@ -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
- }