feat: models filter by state
This commit is contained in:
@@ -216,8 +216,8 @@ export default {
|
||||
'models.form.gpusAllocationType.custom.tips':
|
||||
'You can specify the exact number of GPUs per replica.',
|
||||
'models.mymodels.status.inactive': 'Stopped',
|
||||
'models.mymodels.status.degrade': 'Abnormal',
|
||||
'models.mymodels.status.active': 'Active',
|
||||
'models.mymodels.status.degrade': 'Not Ready',
|
||||
'models.mymodels.status.active': 'Ready',
|
||||
'models.form.kvCache.tips':
|
||||
'Extended KV cache and speculative decoding are only available with built-in backends (vLLM / SGLang), Please switch the backend in the <span class="bold-text">Advanced</span> settings to enable them.',
|
||||
'models.form.kvCache.tips2':
|
||||
|
||||
@@ -216,8 +216,8 @@ export default {
|
||||
'models.form.gpusAllocationType.custom.tips':
|
||||
'You can specify the exact number of GPUs per replica.',
|
||||
'models.mymodels.status.inactive': 'Stopped',
|
||||
'models.mymodels.status.degrade': 'Abnormal',
|
||||
'models.mymodels.status.active': 'Active',
|
||||
'models.mymodels.status.degrade': 'Not Ready',
|
||||
'models.mymodels.status.active': 'Ready',
|
||||
'models.form.kvCache.tips':
|
||||
'Extended KV cache and speculative decoding are only available with built-in backends (vLLM / SGLang), Please switch the backend in the <span class="bold-text">Advanced</span> settings to enable them.',
|
||||
'models.form.kvCache.tips2':
|
||||
@@ -313,8 +313,8 @@ export default {
|
||||
// 37. 'models.form.gpusAllocationType.auto.tips': 'The system automatically calculates the GPU count per replica, using powers of two by default and capped by the selected GPUs.',
|
||||
// 38. 'models.form.gpusAllocationType.custom.tips': 'You can specify the exact number of GPUs per replica.',
|
||||
// 39. 'models.mymodels.status.inactive': 'Stopped',
|
||||
// 41. 'models.mymodels.status.degrade': 'Abnormal',
|
||||
// 42. 'models.mymodels.status.active': 'Active'
|
||||
// 41. 'models.mymodels.status.degrade': 'Not Ready',
|
||||
// 42. 'models.mymodels.status.active': 'Ready',
|
||||
// 43. 'models.form.remoteURL.tips': 'Refer to the <a href="https://docs.lmcache.ai/api_reference/configurations.html" target="_blank">configuration documentation</a> for details.',
|
||||
// 44. 'models.form.kvCache.tips': 'Extended KV cache and speculative decoding are only available with built-in backends (vLLM / SGLang), Please switch the backend in the <span class="bold-text">Advanced</span> settings to enable them.',
|
||||
// 45. 'models.form.kvCache.tips2': 'Only supported when using built-in inference backends (vLLM or SGLang).',
|
||||
|
||||
@@ -220,8 +220,8 @@ export default {
|
||||
'models.form.gpusAllocationType.custom.tips':
|
||||
'Вы можете указать точное количество GPU на реплику.',
|
||||
'models.mymodels.status.inactive': 'Остановлен',
|
||||
'models.mymodels.status.degrade': 'Аномальный',
|
||||
'models.mymodels.status.active': 'Активен',
|
||||
'models.mymodels.status.degrade': 'Не готов',
|
||||
'models.mymodels.status.active': 'Готов',
|
||||
'models.form.kvCache.tips':
|
||||
'Расширенный KV-кэш и спекулятивное декодирование доступны только со встроенными бэкендами (vLLM / SGLang). Переключите бэкенд в <span class="bold-text">Расширенных</span> настройках, чтобы включить их.',
|
||||
'models.form.kvCache.tips2':
|
||||
|
||||
@@ -161,21 +161,6 @@ const ModelItem: React.FC<{
|
||||
return _.round(max_tokens / 1024);
|
||||
}, [model]);
|
||||
|
||||
const status = useMemo(() => {
|
||||
if (!model.replicas && !model.ready_replicas) {
|
||||
return MyModelsStatusValueMap.Inactive;
|
||||
}
|
||||
|
||||
if (model.replicas > 0 && !model.ready_replicas) {
|
||||
return MyModelsStatusValueMap.Degrade;
|
||||
}
|
||||
|
||||
if (model.replicas === model.ready_replicas && model.replicas > 0) {
|
||||
return MyModelsStatusValueMap.Active;
|
||||
}
|
||||
return MyModelsStatusValueMap.Degrade;
|
||||
}, [model]);
|
||||
|
||||
return (
|
||||
<CardWrapper>
|
||||
<Card
|
||||
@@ -198,7 +183,7 @@ const ModelItem: React.FC<{
|
||||
statusValue={{
|
||||
status: MyModelsStatusMap[model.status],
|
||||
text: intl.formatMessage({
|
||||
id: MyModelsStatusLabelMap[model.status]
|
||||
id: MyModelsStatusLabelMap[model.status] || ''
|
||||
}),
|
||||
message: model.state_message
|
||||
}}
|
||||
|
||||
@@ -56,6 +56,7 @@ import {
|
||||
ModelInstanceListItem,
|
||||
SourceType
|
||||
} from '../config/types';
|
||||
import useFilterStatus from '../hooks/use-filter-status';
|
||||
import useFormInitialValues from '../hooks/use-form-initial-values';
|
||||
import useModelsColumns from '../hooks/use-models-columns';
|
||||
import AccessControlModal from './access-control-modal';
|
||||
@@ -78,6 +79,7 @@ interface ModelsProps {
|
||||
onStop?: (ids: number[]) => void;
|
||||
onStart?: () => void;
|
||||
onTableSort?: (order: TableOrder | Array<TableOrder>) => void;
|
||||
onStatusChange: (value?: any) => void;
|
||||
sortOrder: string[];
|
||||
queryParams: {
|
||||
page: number;
|
||||
@@ -119,6 +121,7 @@ const Models: React.FC<ModelsProps> = ({
|
||||
onStop,
|
||||
onStart,
|
||||
onTableSort,
|
||||
onStatusChange,
|
||||
sortOrder,
|
||||
deleteIds,
|
||||
dataSource,
|
||||
@@ -154,6 +157,10 @@ const Models: React.FC<ModelsProps> = ({
|
||||
removeExpandedRowKey,
|
||||
expandedRowKeys
|
||||
} = useExpandedRowKeys(expandAtom);
|
||||
const { labelRender, optionRender, handleStatusChange, statusOptions } =
|
||||
useFilterStatus({
|
||||
onStatusChange: onStatusChange
|
||||
});
|
||||
|
||||
const [apiAccessInfo, setAPIAccessInfo] = useState<any>({
|
||||
show: false,
|
||||
@@ -663,6 +670,18 @@ const Models: React.FC<ModelsProps> = ({
|
||||
onChange={handleClusterChange}
|
||||
options={clusterList}
|
||||
></BaseSelect>
|
||||
<BaseSelect
|
||||
allowClear
|
||||
showSearch={false}
|
||||
placeholder={intl.formatMessage({ id: 'common.filter.status' })}
|
||||
style={{ width: 180 }}
|
||||
size="large"
|
||||
maxTagCount={1}
|
||||
optionRender={optionRender}
|
||||
labelRender={labelRender}
|
||||
options={statusOptions}
|
||||
onChange={handleStatusChange}
|
||||
></BaseSelect>
|
||||
<Button
|
||||
type="text"
|
||||
style={{ color: 'var(--ant-color-text-tertiary)' }}
|
||||
|
||||
@@ -196,9 +196,9 @@ export const status: any = {
|
||||
};
|
||||
|
||||
export const MyModelsStatusValueMap = {
|
||||
Inactive: 'Inactive',
|
||||
Degrade: 'Degrade',
|
||||
Active: 'Active'
|
||||
Inactive: 'stopped',
|
||||
Degrade: 'not_ready',
|
||||
Active: 'ready'
|
||||
};
|
||||
|
||||
export const MyModelsStatusMap = {
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
import { useIntl } from '@umijs/max';
|
||||
import { MyModelsStatusValueMap } from '../config';
|
||||
|
||||
const Dot = ({ color }: { color: string }) => {
|
||||
return (
|
||||
<span
|
||||
style={{
|
||||
backgroundColor: color,
|
||||
borderRadius: '50%',
|
||||
height: 8,
|
||||
width: 8,
|
||||
display: 'flex'
|
||||
}}
|
||||
></span>
|
||||
);
|
||||
};
|
||||
|
||||
const useFilterStatus = (options: {
|
||||
onStatusChange: (value?: any) => void;
|
||||
}) => {
|
||||
const { onStatusChange } = options;
|
||||
const intl = useIntl();
|
||||
|
||||
const statusOptions = [
|
||||
{
|
||||
value: MyModelsStatusValueMap.Active,
|
||||
color: 'var(--ant-color-success)',
|
||||
label: intl.formatMessage({
|
||||
id: 'models.mymodels.status.active'
|
||||
})
|
||||
},
|
||||
{
|
||||
value: MyModelsStatusValueMap.Inactive,
|
||||
color: 'var(--ant-color-fill)',
|
||||
label: intl.formatMessage({
|
||||
id: 'models.mymodels.status.inactive'
|
||||
})
|
||||
},
|
||||
{
|
||||
value: MyModelsStatusValueMap.Degrade,
|
||||
color: 'var(--ant-color-error)',
|
||||
label: intl.formatMessage({
|
||||
id: 'models.mymodels.status.degrade'
|
||||
})
|
||||
}
|
||||
];
|
||||
|
||||
const labelRender = (item: any) => {
|
||||
const current = statusOptions.find((option) => option.value === item.value);
|
||||
return (
|
||||
<span className="flex-center gap-8">
|
||||
<Dot color={current!.color}></Dot>
|
||||
{item.label}
|
||||
</span>
|
||||
);
|
||||
};
|
||||
|
||||
const optionRender = (item: any) => {
|
||||
return (
|
||||
<span className="flex-center gap-8">
|
||||
<Dot color={item.data?.color}></Dot>
|
||||
{item.label}
|
||||
</span>
|
||||
);
|
||||
};
|
||||
|
||||
const handleStatusChange = (value: string | undefined) => {
|
||||
onStatusChange(value);
|
||||
};
|
||||
|
||||
return {
|
||||
statusOptions,
|
||||
labelRender,
|
||||
optionRender,
|
||||
handleStatusChange
|
||||
};
|
||||
};
|
||||
|
||||
export default useFilterStatus;
|
||||
@@ -47,6 +47,7 @@ const Models: React.FC = () => {
|
||||
search: '',
|
||||
cluster_id: 0,
|
||||
categories: [],
|
||||
state: '',
|
||||
sort_by: '-created_at'
|
||||
});
|
||||
|
||||
@@ -197,6 +198,7 @@ const Models: React.FC = () => {
|
||||
search: string;
|
||||
categories: any[];
|
||||
cluster_id: number;
|
||||
state?: string;
|
||||
}) => {
|
||||
const search = params?.search || queryParams.search;
|
||||
const categories = params?.categories || queryParams.categories;
|
||||
@@ -287,6 +289,19 @@ const Models: React.FC = () => {
|
||||
});
|
||||
};
|
||||
|
||||
const handleOnStatusChange = async (value: string | undefined) => {
|
||||
handleQueryChange({
|
||||
page: 1,
|
||||
state: value
|
||||
});
|
||||
createModelsChunkRequest({
|
||||
search: queryParams.search,
|
||||
categories: queryParams.categories,
|
||||
cluster_id: queryParams.cluster_id || 0,
|
||||
state: value
|
||||
});
|
||||
};
|
||||
|
||||
const handleClusterChange = async (value: number) => {
|
||||
handleQueryChange({
|
||||
page: 1,
|
||||
@@ -408,6 +423,7 @@ const Models: React.FC = () => {
|
||||
>
|
||||
<TableList
|
||||
dataSource={dataSource.dataList}
|
||||
onStatusChange={handleOnStatusChange}
|
||||
handleNameChange={handleNameChange}
|
||||
handleCategoryChange={handleCategoryChange}
|
||||
handleClusterChange={handleClusterChange}
|
||||
|
||||
@@ -62,7 +62,6 @@ const UserModels: React.FC = () => {
|
||||
}
|
||||
});
|
||||
const intl = useIntl();
|
||||
const [status, setStatus] = React.useState<string | undefined>(undefined);
|
||||
|
||||
const statusOptions = useMemo(() => {
|
||||
return [
|
||||
@@ -131,7 +130,9 @@ const UserModels: React.FC = () => {
|
||||
});
|
||||
|
||||
const handleStatusChange = (value: string) => {
|
||||
setStatus(value);
|
||||
handleQueryChange({
|
||||
state: value
|
||||
});
|
||||
};
|
||||
|
||||
const labelRender = (item: any) => {
|
||||
@@ -166,9 +167,8 @@ const UserModels: React.FC = () => {
|
||||
status: getStatus(item)
|
||||
};
|
||||
});
|
||||
if (!status) return result;
|
||||
return result.filter((item) => item.status === status);
|
||||
}, [dataSource.dataList, status]);
|
||||
return result;
|
||||
}, [dataSource.dataList]);
|
||||
|
||||
return (
|
||||
<PageBox>
|
||||
@@ -242,7 +242,7 @@ const UserModels: React.FC = () => {
|
||||
loadend={dataSource.loadend}
|
||||
dataSource={dataList}
|
||||
image={<IconFont type="icon-models" />}
|
||||
filters={{ ...queryParams, status: status }}
|
||||
filters={{ ...queryParams }}
|
||||
noFoundText={intl.formatMessage({
|
||||
id: 'noresult.mymodels.nofound'
|
||||
})}
|
||||
|
||||
Reference in New Issue
Block a user