Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix NIM selection issue #3482

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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) {
mturley marked this conversation as resolved.
Show resolved Hide resolved
// 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 @@
): { 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 @@
if (kServeEnabled) {
return { platform: ServingRuntimePlatform.SINGLE };
}
}
if (project.metadata.labels?.[KnownLabels.MODEL_SERVING_PROJECT] === 'true') {
if (nimEnabled) {

Check warning on line 322 in frontend/src/pages/modelServing/screens/projects/utils.ts

View check run for this annotation

Codecov / codecov/patch

frontend/src/pages/modelServing/screens/projects/utils.ts#L322

Added line #L322 was not covered by tests
// TODO: this is weird, it relies on KServe today... so it's never "only installed"
return { platform: ServingRuntimePlatform.SINGLE };

Check warning on line 324 in frontend/src/pages/modelServing/screens/projects/utils.ts

View check run for this annotation

Codecov / codecov/patch

frontend/src/pages/modelServing/screens/projects/utils.ts#L324

Added line #L324 was not covered by tests
}

// TODO: unreachable code unless adding a new platform? probably should throw an error
mturley marked this conversation as resolved.
Show resolved Hide resolved
} 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
Loading