Skip to content

Commit

Permalink
Fix NIM selection issue (#3482)
Browse files Browse the repository at this point in the history
* Fix NIM selection issue

* Switch back to using a numerical value
  • Loading branch information
andrewballantyne authored Nov 15, 2024
1 parent 13449c5 commit 41e1fcf
Show file tree
Hide file tree
Showing 11 changed files with 81 additions and 73 deletions.
1 change: 1 addition & 0 deletions frontend/src/concepts/areas/const.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,5 +122,6 @@ export const SupportedAreasStateMap: SupportedAreasState = {
},
[SupportedArea.NIM_MODEL]: {
featureFlags: ['disableNIMModelServing'],
reliantAreas: [SupportedArea.K_SERVE],
},
};
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,12 @@ import * as React from 'react';
import { Button } from '@patternfly/react-core';
import { useNavigate } from 'react-router-dom';
import { ModelServingContext } from '~/pages/modelServing/ModelServingContext';
import { getProjectModelServingPlatform } from '~/pages/modelServing/screens/projects/utils';
import { ServingRuntimePlatform } from '~/types';
import useServingPlatformStatuses from '~/pages/modelServing/useServingPlatformStatuses';
import EmptyDetailsView from '~/components/EmptyDetailsView';
import { ProjectObjectType, typedEmptyImage } from '~/concepts/design/utils';
import { ProjectSectionID } from '~/pages/projects/screens/detail/types';
import ServeModelButton from '~/pages/modelServing/screens/global/ServeModelButton';
import { getDisplayNameFromK8sResource } from '~/concepts/k8s/utils';
import { isProjectNIMSupported } from '~/pages/modelServing/screens/projects/nimUtils';

const EmptyModelServing: React.FC = () => {
const navigate = useNavigate();
Expand All @@ -19,14 +16,9 @@ const EmptyModelServing: React.FC = () => {
project,
} = React.useContext(ModelServingContext);
const servingPlatformStatuses = useServingPlatformStatuses();
const isKServeNIMEnabled = project ? isProjectNIMSupported(project) : false;

if (
(getProjectModelServingPlatform(project, servingPlatformStatuses).platform !==
ServingRuntimePlatform.SINGLE ||
isKServeNIMEnabled) &&
servingRuntimes.length === 0
) {
if (servingPlatformStatuses.modelMesh.enabled && servingRuntimes.length === 0) {
// Server needed -- must deploy from the project
return (
<EmptyDetailsView
title="No deployed models"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,12 +63,9 @@ const ModelServingPlatform: React.FC = () => {
const deployingFromRegistry = !!(modelRegistryName && registeredModelId && modelVersionId);

const servingPlatformStatuses = useServingPlatformStatuses();
const {
kServe: { enabled: kServeEnabled },
modelMesh: { enabled: modelMeshEnabled },
nim: { available: isNIMAvailable },
numServingPlatformsAvailable,
} = servingPlatformStatuses;
const kServeEnabled = servingPlatformStatuses.kServe.enabled;
const isNIMAvailable = servingPlatformStatuses.kServeNIM.enabled;
const modelMeshEnabled = servingPlatformStatuses.modelMesh.enabled;

const {
servingRuntimes: {
Expand Down Expand Up @@ -100,8 +97,7 @@ const ModelServingPlatform: React.FC = () => {
getProjectModelServingPlatform(currentProject, servingPlatformStatuses);

const shouldShowPlatformSelection =
((kServeEnabled && modelMeshEnabled) || (!kServeEnabled && !modelMeshEnabled)) &&
!currentProjectServingPlatform;
servingPlatformStatuses.platformEnabledCount !== 1 && !currentProjectServingPlatform;

const isProjectModelMesh = currentProjectServingPlatform === ServingRuntimePlatform.MULTI;

Expand Down Expand Up @@ -259,7 +255,7 @@ const ModelServingPlatform: React.FC = () => {
isEmpty={shouldShowPlatformSelection}
loadError={platformError || servingRuntimeError || templateError}
emptyState={
kServeEnabled && modelMeshEnabled ? (
servingPlatformStatuses.platformEnabledCount > 1 ? (
<Flex alignItems={{ default: 'alignItemsCenter' }} gap={{ default: 'gapLg' }}>
<FlexItem
flex={{ default: 'flex_1' }}
Expand All @@ -281,16 +277,20 @@ const ModelServingPlatform: React.FC = () => {
</StackItem>
<StackItem>
<Gallery hasGutter>
<GalleryItem>
<EmptySingleModelServingCard
setErrorSelectingPlatform={setErrorSelectingPlatform}
/>
</GalleryItem>
<GalleryItem>
<EmptyMultiModelServingCard
setErrorSelectingPlatform={setErrorSelectingPlatform}
/>
</GalleryItem>
{kServeEnabled && (
<GalleryItem>
<EmptySingleModelServingCard
setErrorSelectingPlatform={setErrorSelectingPlatform}
/>
</GalleryItem>
)}
{modelMeshEnabled && (
<GalleryItem>
<EmptyMultiModelServingCard
setErrorSelectingPlatform={setErrorSelectingPlatform}
/>
</GalleryItem>
)}
{isNIMAvailable && (
<GalleryItem>
<EmptyNIMModelServingCard
Expand Down Expand Up @@ -330,7 +330,7 @@ const ModelServingPlatform: React.FC = () => {
? 'Multi-model serving enabled'
: 'Single-model serving enabled'}
</Label>
{emptyModelServer && numServingPlatformsAvailable > 1 && (
{emptyModelServer && servingPlatformStatuses.platformEnabledCount > 1 && (
<ModelServingPlatformSelectButton
namespace={currentProject.metadata.name}
servingPlatform={NamespaceApplicationCase.RESET_MODEL_SERVING_PLATFORM}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,21 +67,22 @@ const getMockServingPlatformStatuses = ({
kServeInstalled = true,
modelMeshEnabled = true,
modelMeshInstalled = true,
nimAvailable = true,
nimEnabled = false,
nimInstalled = false,
}): ServingPlatformStatuses => ({
kServe: {
enabled: kServeEnabled,
installed: kServeInstalled,
},
kServeNIM: {
enabled: nimEnabled,
installed: nimInstalled,
},
modelMesh: {
enabled: modelMeshEnabled,
installed: modelMeshInstalled,
},
nim: {
available: nimAvailable,
},
numServingPlatformsAvailable: [kServeEnabled, modelMeshEnabled, nimAvailable].filter(Boolean)
.length,
platformEnabledCount: [kServeEnabled, nimEnabled, modelMeshEnabled].filter(Boolean).length,
});

describe('getProjectModelServingPlatform', () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { useEffect, useState } from 'react';
import { SupportedArea, useIsAreaAvailable } from '~/concepts/areas';
import { isNIMServingRuntimeTemplateAvailable } from '~/pages/modelServing/screens/projects/nimUtils';
import { useDashboardNamespace } from '~/redux/selectors';

export const useIsNIMAvailable = (dashboardNamespace: string): boolean => {
export const useIsNIMAvailable = (): boolean => {
const { dashboardNamespace } = useDashboardNamespace();
const [isNIMAvailable, setIsNIMAvailable] = useState<boolean>(false);
const isNIMModelServingAvailable = useIsAreaAvailable(SupportedArea.NIM_MODEL).status;

Expand Down
20 changes: 17 additions & 3 deletions frontend/src/pages/modelServing/screens/projects/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -298,13 +298,19 @@ export const getProjectModelServingPlatform = (
): { platform?: ServingRuntimePlatform; error?: Error } => {
const {
kServe: { enabled: kServeEnabled, installed: kServeInstalled },
kServeNIM: { enabled: nimEnabled },
modelMesh: { enabled: modelMeshEnabled, installed: modelMeshInstalled },
platformEnabledCount,
} = platformStatuses;

if (!project) {
// Likely temporary or a bad usage of the hook
return {};
}

if (project.metadata.labels?.[KnownLabels.MODEL_SERVING_PROJECT] === undefined) {
if ((kServeEnabled && modelMeshEnabled) || (!kServeEnabled && !modelMeshEnabled)) {
// Auto-select logic
if (platformEnabledCount !== 1) {
return {};
}
if (modelMeshEnabled) {
Expand All @@ -313,13 +319,21 @@ export const getProjectModelServingPlatform = (
if (kServeEnabled) {
return { platform: ServingRuntimePlatform.SINGLE };
}
}
if (project.metadata.labels?.[KnownLabels.MODEL_SERVING_PROJECT] === 'true') {
if (nimEnabled) {
// TODO: this is weird, it relies on KServe today... so it's never "only installed"
return { platform: ServingRuntimePlatform.SINGLE };
}

// TODO: unreachable code unless adding a new platform? probably should throw an error
} else if (project.metadata.labels[KnownLabels.MODEL_SERVING_PROJECT] === 'true') {
// Model mesh logic
return {
platform: ServingRuntimePlatform.MULTI,
error: modelMeshInstalled ? undefined : new Error('Multi-model platform is not installed'),
};
}

// KServe logic
return {
platform: ServingRuntimePlatform.SINGLE,
error: kServeInstalled ? undefined : new Error('Single-model platform is not installed'),
Expand Down
20 changes: 8 additions & 12 deletions frontend/src/pages/modelServing/screens/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,19 +108,15 @@ export type ServingRuntimeEditInfo = {
secrets: SecretKind[];
};

type PlatformStatus = {
enabled: boolean;
installed: boolean;
};
export type ServingPlatformStatuses = {
kServe: {
enabled: boolean;
installed: boolean;
};
modelMesh: {
enabled: boolean;
installed: boolean;
};
nim: {
available: boolean;
};
numServingPlatformsAvailable: number;
kServe: PlatformStatus;
kServeNIM: PlatformStatus;
modelMesh: PlatformStatus;
platformEnabledCount: number;
};

export type LabeledDataConnection = {
Expand Down
16 changes: 7 additions & 9 deletions frontend/src/pages/modelServing/useServingPlatformStatuses.ts
Original file line number Diff line number Diff line change
@@ -1,33 +1,31 @@
import { StackComponent, SupportedArea, useIsAreaAvailable } from '~/concepts/areas';
import { ServingPlatformStatuses } from '~/pages/modelServing/screens/types';
import { useDashboardNamespace } from '~/redux/selectors';
import { useIsNIMAvailable } from '~/pages/modelServing/screens/projects/useIsNIMAvailable';

const useServingPlatformStatuses = (): ServingPlatformStatuses => {
const { dashboardNamespace } = useDashboardNamespace();

const kServeStatus = useIsAreaAvailable(SupportedArea.K_SERVE);
const modelMeshStatus = useIsAreaAvailable(SupportedArea.MODEL_MESH);
const kServeEnabled = kServeStatus.status;
const modelMeshEnabled = modelMeshStatus.status;
const kServeInstalled = !!kServeStatus.requiredComponents?.[StackComponent.K_SERVE];
const modelMeshInstalled = !!modelMeshStatus.requiredComponents?.[StackComponent.MODEL_MESH];
const isNIMAvailable = useIsNIMAvailable(dashboardNamespace);

const isNIMAvailable = useIsNIMAvailable();

return {
kServe: {
enabled: kServeEnabled,
installed: kServeInstalled,
},
kServeNIM: {
enabled: isNIMAvailable,
installed: kServeInstalled,
},
modelMesh: {
enabled: modelMeshEnabled,
installed: modelMeshInstalled,
},
nim: {
available: isNIMAvailable,
},
numServingPlatformsAvailable: [kServeEnabled, modelMeshEnabled, isNIMAvailable].filter(Boolean)
.length,
platformEnabledCount: [kServeEnabled, isNIMAvailable, modelMeshEnabled].filter(Boolean).length,
};
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,12 @@ const PlatformSelectSection: React.FC = () => {
const [errorSelectingPlatform, setErrorSelectingPlatform] = React.useState<Error>();

const servingPlatformStatuses = useServingPlatformStatuses();
const {
nim: { available: isNIMAvailable },
} = servingPlatformStatuses;
const kServeEnabled = servingPlatformStatuses.kServe.enabled;
const isNIMAvailable = servingPlatformStatuses.kServeNIM.enabled;
const modelMeshEnabled = servingPlatformStatuses.modelMesh.enabled;

const galleryWidths = isNIMAvailable
const threeEnabled = [kServeEnabled, modelMeshEnabled, isNIMAvailable].every((v) => v);
const galleryWidths = threeEnabled
? {
minWidths: { default: '100%', lg: 'calc(33.33% - 1rem / 3 * 2)' },
maxWidths: { default: '100%', lg: 'calc(33.33% - 1rem / 3 * 2)' },
Expand All @@ -38,8 +39,12 @@ const PlatformSelectSection: React.FC = () => {
</Text>
</TextContent>
<Gallery hasGutter {...galleryWidths}>
<SelectSingleModelCard setErrorSelectingPlatform={setErrorSelectingPlatform} />
<SelectMultiModelCard setErrorSelectingPlatform={setErrorSelectingPlatform} />
{kServeEnabled && (
<SelectSingleModelCard setErrorSelectingPlatform={setErrorSelectingPlatform} />
)}
{modelMeshEnabled && (
<SelectMultiModelCard setErrorSelectingPlatform={setErrorSelectingPlatform} />
)}
{isNIMAvailable && (
<SelectNIMCard setErrorSelectingPlatform={setErrorSelectingPlatform} />
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ import DeployedModelsSection from './deployedModels/DeployedModelsSection';
const ServeModelsSection: React.FC = () => {
const servingPlatformStatuses = useServingPlatformStatuses();
const {
numServingPlatformsAvailable,
modelMesh: { enabled: modelMeshEnabled },
platformEnabledCount,
} = servingPlatformStatuses;

const { currentProject } = React.useContext(ProjectDetailsContext);
Expand All @@ -21,11 +21,11 @@ const ServeModelsSection: React.FC = () => {
servingPlatformStatuses,
);

if (numServingPlatformsAvailable > 1 && !currentProjectServingPlatform) {
if (platformEnabledCount > 1 && !currentProjectServingPlatform) {
return <PlatformSelectSection />;
}

if (numServingPlatformsAvailable === 0) {
if (platformEnabledCount === 0) {
return <NoProjectServingEnabledSection />;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ const DeployedModelsSection: React.FC<DeployedModelsSectionProps> = ({ isMultiPl
} = React.useContext(ProjectDetailsContext);

const servingPlatformStatuses = useServingPlatformStatuses();
const { numServingPlatformsAvailable } = servingPlatformStatuses;
const { error: platformError } = getProjectModelServingPlatform(
currentProject,
servingPlatformStatuses,
Expand Down Expand Up @@ -130,7 +129,7 @@ const DeployedModelsSection: React.FC<DeployedModelsSectionProps> = ({ isMultiPl
headerInfo={
<Flex gap={{ default: 'gapSm' }}>
<Label>Multi-model serving enabled</Label>
{numServingPlatformsAvailable > 1 && (
{servingPlatformStatuses.platformEnabledCount > 1 && (
<ModelServingPlatformSelectButton
namespace={currentProject.metadata.name}
servingPlatform={NamespaceApplicationCase.RESET_MODEL_SERVING_PLATFORM}
Expand Down Expand Up @@ -194,7 +193,7 @@ const DeployedModelsSection: React.FC<DeployedModelsSectionProps> = ({ isMultiPl
<Label>
{isMultiPlatform ? 'Multi-model serving enabled' : 'Single-model serving enabled'}
</Label>
{numServingPlatformsAvailable > 1 && (
{servingPlatformStatuses.platformEnabledCount > 1 && (
<ModelServingPlatformSelectButton
namespace={currentProject.metadata.name}
servingPlatform={NamespaceApplicationCase.RESET_MODEL_SERVING_PLATFORM}
Expand Down

0 comments on commit 41e1fcf

Please sign in to comment.