-
Notifications
You must be signed in to change notification settings - Fork 163
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add deployment modal for model registry
- Loading branch information
1 parent
457d01d
commit f523086
Showing
20 changed files
with
793 additions
and
159 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
48 changes: 48 additions & 0 deletions
48
frontend/src/pages/modelRegistry/screens/RegisteredModels/useLabeledDataConnections.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
import React from 'react'; | ||
import { uriToObjectStorageFields } from '~/concepts/modelRegistry/utils'; | ||
import { LabeledDataConnection } from '~/pages/modelServing/screens/types'; | ||
import { AwsKeys } from '~/pages/projects/dataConnections/const'; | ||
import { convertAWSSecretData } from '~/pages/projects/screens/detail/data-connections/utils'; | ||
import { DataConnection } from '~/pages/projects/types'; | ||
|
||
const useLabeledDataConnections = ( | ||
modelArtifactUri: string | undefined, | ||
dataConnections: DataConnection[] = [], | ||
): { | ||
dataConnections: LabeledDataConnection[]; | ||
path: string; | ||
hasParseError?: boolean; | ||
} => | ||
React.useMemo(() => { | ||
if (!modelArtifactUri) { | ||
return { | ||
dataConnections: dataConnections.map((dataConnection) => ({ dataConnection })), | ||
path: '', | ||
}; | ||
} | ||
const storageFields = uriToObjectStorageFields(modelArtifactUri); | ||
if (!storageFields) { | ||
return { | ||
dataConnections: dataConnections.map((dataConnection) => ({ dataConnection })), | ||
path: '', | ||
hasParseError: true, | ||
}; | ||
} | ||
const labeledDataConnections = dataConnections.map((dataConnection) => { | ||
const awsData = convertAWSSecretData(dataConnection); | ||
const bucket = awsData.find((data) => data.key === AwsKeys.AWS_S3_BUCKET)?.value; | ||
const endpoint = awsData.find((data) => data.key === AwsKeys.S3_ENDPOINT)?.value; | ||
const region = awsData.find((data) => data.key === AwsKeys.DEFAULT_REGION)?.value; | ||
if ( | ||
bucket === storageFields.bucket && | ||
endpoint === storageFields.endpoint && | ||
region === storageFields.region | ||
) { | ||
return { dataConnection, isRecommended: true }; | ||
} | ||
return { dataConnection }; | ||
}); | ||
return { dataConnections: labeledDataConnections, path: storageFields.path }; | ||
}, [dataConnections, modelArtifactUri]); | ||
|
||
export default useLabeledDataConnections; |
33 changes: 33 additions & 0 deletions
33
...end/src/pages/modelRegistry/screens/RegisteredModels/useProjectErrorForRegisteredModel.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
import useServingRuntimes from '~/pages/modelServing/useServingRuntimes'; | ||
import { ServingRuntimePlatform } from '~/types'; | ||
|
||
const useProjectErrorForRegisteredModel = ( | ||
projectName?: string, | ||
platform?: ServingRuntimePlatform, | ||
): Error | undefined => { | ||
const [servingRuntimes, loaded, loadError] = useServingRuntimes(projectName); | ||
|
||
// If project is not selected, there is no error | ||
if (!projectName) { | ||
return undefined; | ||
} | ||
|
||
// If the platform is not selected | ||
if (!platform) { | ||
return new Error('Cannot deploy the model until you select a model serving platform'); | ||
} | ||
|
||
// If the platform is MULTI but it doesn't have a server | ||
if (platform === ServingRuntimePlatform.MULTI) { | ||
if (loadError) { | ||
return loadError; | ||
} | ||
if (loaded && servingRuntimes.length === 0) { | ||
return new Error('Cannot deploy the model until you configure a model server'); | ||
} | ||
} | ||
|
||
return undefined; | ||
}; | ||
|
||
export default useProjectErrorForRegisteredModel; |
37 changes: 37 additions & 0 deletions
37
frontend/src/pages/modelRegistry/screens/RegisteredModels/useRegisteredModelContext.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
import React from 'react'; | ||
import useModelArtifactsByVersionId from '~/concepts/modelRegistry/apiHooks/useModelArtifactsByVersionId'; | ||
import useRegisteredModelById from '~/concepts/modelRegistry/apiHooks/useRegisteredModelById'; | ||
import { ModelVersion } from '~/concepts/modelRegistry/types'; | ||
|
||
export type RegisteredModelContext = { | ||
modelName: string; | ||
modelFormat?: string; | ||
modelArtifactUri?: string; | ||
modelArtifactStorageKey?: string; | ||
}; | ||
|
||
const useRegisteredModelContext = (modelVersion: ModelVersion): RegisteredModelContext => { | ||
const [registeredModel] = useRegisteredModelById(modelVersion.registeredModelId); | ||
const [modelArtifactList] = useModelArtifactsByVersionId(modelVersion.id); | ||
|
||
const registeredModelContext = React.useMemo(() => { | ||
if (modelArtifactList.size === 0) { | ||
return { | ||
modelName: `${registeredModel?.name} - ${modelVersion.name}`, | ||
}; | ||
} | ||
const modelArtifact = modelArtifactList.items[0]; | ||
return { | ||
modelName: `${registeredModel?.name} - ${modelVersion.name}`, | ||
modelFormat: modelArtifact.modelFormatName | ||
? `${modelArtifact.modelFormatName} - ${modelArtifact.modelFormatVersion}` | ||
: undefined, | ||
modelArtifactUri: modelArtifact.uri, | ||
modelArtifactStorageKey: modelArtifact.storageKey, | ||
}; | ||
}, [modelArtifactList.items, modelArtifactList.size, modelVersion.name, registeredModel?.name]); | ||
|
||
return registeredModelContext; | ||
}; | ||
|
||
export default useRegisteredModelContext; |
73 changes: 73 additions & 0 deletions
73
...end/src/pages/modelRegistry/screens/RegisteredModels/useRegisteredModelContextForModal.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
import React from 'react'; | ||
import { ProjectKind } from '~/k8sTypes'; | ||
import useLabeledDataConnections from '~/pages/modelRegistry/screens/RegisteredModels/useLabeledDataConnections'; | ||
import { RegisteredModelContext } from '~/pages/modelRegistry/screens/RegisteredModels/useRegisteredModelContext'; | ||
import { | ||
CreatingInferenceServiceObject, | ||
InferenceServiceStorageType, | ||
LabeledDataConnection, | ||
} from '~/pages/modelServing/screens/types'; | ||
import { AwsKeys, EMPTY_AWS_SECRET_DATA } from '~/pages/projects/dataConnections/const'; | ||
import useDataConnections from '~/pages/projects/screens/detail/data-connections/useDataConnections'; | ||
import { DataConnection, UpdateObjectAtPropAndValue } from '~/pages/projects/types'; | ||
|
||
const useRegisteredModelContextForModal = ( | ||
projectContext: { currentProject: ProjectKind; dataConnections: DataConnection[] } | undefined, | ||
createData: CreatingInferenceServiceObject, | ||
setCreateData: UpdateObjectAtPropAndValue<CreatingInferenceServiceObject>, | ||
registeredModelContext?: RegisteredModelContext, | ||
): [LabeledDataConnection[], boolean, Error | undefined] => { | ||
const [fetchedDataConnections, dataConnectionsLoaded, dataConnectionsLoadError] = | ||
useDataConnections(projectContext ? undefined : createData.project); | ||
const allDataConnections = projectContext?.dataConnections || fetchedDataConnections; | ||
const { dataConnections, path, hasParseError } = useLabeledDataConnections( | ||
registeredModelContext?.modelArtifactUri, | ||
allDataConnections, | ||
); | ||
|
||
React.useEffect(() => { | ||
if (registeredModelContext) { | ||
setCreateData('name', registeredModelContext.modelName); | ||
const recommendedDataConnections = dataConnections.filter( | ||
(dataConnection) => dataConnection.isRecommended, | ||
); | ||
|
||
if (!registeredModelContext.modelArtifactUri || hasParseError) { | ||
setCreateData('storage', { | ||
awsData: EMPTY_AWS_SECRET_DATA, | ||
dataConnection: '', | ||
path, | ||
type: InferenceServiceStorageType.EXISTING_STORAGE, | ||
}); | ||
} else if (recommendedDataConnections.length === 0) { | ||
setCreateData('storage', { | ||
awsData: [ | ||
...EMPTY_AWS_SECRET_DATA, | ||
{ key: AwsKeys.NAME, value: registeredModelContext.modelArtifactStorageKey || '' }, | ||
], | ||
dataConnection: '', | ||
path, | ||
type: InferenceServiceStorageType.NEW_STORAGE, | ||
}); | ||
} else if (recommendedDataConnections.length === 1) { | ||
setCreateData('storage', { | ||
awsData: EMPTY_AWS_SECRET_DATA, | ||
dataConnection: recommendedDataConnections[0].dataConnection.data.metadata.name, | ||
path, | ||
type: InferenceServiceStorageType.EXISTING_STORAGE, | ||
}); | ||
} else { | ||
setCreateData('storage', { | ||
awsData: EMPTY_AWS_SECRET_DATA, | ||
dataConnection: '', | ||
path, | ||
type: InferenceServiceStorageType.EXISTING_STORAGE, | ||
}); | ||
} | ||
} | ||
}, [dataConnections, hasParseError, path, registeredModelContext, setCreateData]); | ||
|
||
return [dataConnections, dataConnectionsLoaded, dataConnectionsLoadError]; | ||
}; | ||
|
||
export default useRegisteredModelContextForModal; |
Oops, something went wrong.