chore: profile config
This commit is contained in:
Vendored
+1
-1
@@ -56,7 +56,7 @@ declare namespace Global {
|
||||
currentUser?: UserInfo;
|
||||
}
|
||||
|
||||
type SearchParams = Pagination & { search?: string };
|
||||
type SearchParams = Pagination & { search?: string; [key: string]: any };
|
||||
|
||||
type MessageType = 'transition' | 'warning' | 'danger' | 'success' | 'info';
|
||||
|
||||
|
||||
@@ -1,10 +1,15 @@
|
||||
import { request } from '@umijs/max';
|
||||
import { CancelToken } from 'axios';
|
||||
import { BenchmarkMetricsFormData } from '../config/detail-types';
|
||||
import { BenchmarkListItem, DatasetListItem, FormData } from '../config/types';
|
||||
import {
|
||||
BenchmarkListItem,
|
||||
DatasetListItem,
|
||||
FormData,
|
||||
ProfileOption
|
||||
} from '../config/types';
|
||||
|
||||
export const BENCHMARKS_API = '/benchmarks';
|
||||
export const DATASETS_API = '/datasets';
|
||||
export const PROFILES_CONFIG_API = '/benchmark-profiles/default-config';
|
||||
|
||||
export async function queryBenchmarkList(
|
||||
params: Global.SearchParams,
|
||||
@@ -83,18 +88,18 @@ export async function queryDatasetList(
|
||||
});
|
||||
}
|
||||
|
||||
export async function queryBenchmarkMetrics(
|
||||
export async function queryProfiles(
|
||||
params: {
|
||||
id: number;
|
||||
data: BenchmarkMetricsFormData;
|
||||
id?: number | string;
|
||||
},
|
||||
options?: {
|
||||
token?: CancelToken;
|
||||
}
|
||||
) {
|
||||
return request<any>(`${BENCHMARKS_API}/${params.id}/metrics`, {
|
||||
method: 'POST',
|
||||
data: params.data,
|
||||
return request<{
|
||||
profiles: ProfileOption[];
|
||||
}>(`${PROFILES_CONFIG_API}`, {
|
||||
method: 'get',
|
||||
cancelToken: options?.token
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
import { Descriptions, DescriptionsProps } from 'antd';
|
||||
import React from 'react';
|
||||
import { useDetailContext } from '../../config/detail-context';
|
||||
import Section from '../summary/section';
|
||||
|
||||
const Benchmark: React.FC = () => {
|
||||
const { detailData } = useDetailContext();
|
||||
|
||||
const items: DescriptionsProps['items'] = [
|
||||
{
|
||||
key: '1',
|
||||
label: 'Profile',
|
||||
children: detailData?.profile || '-'
|
||||
},
|
||||
{
|
||||
key: '2',
|
||||
label: 'Dataset',
|
||||
children: detailData?.dataset_name || '-'
|
||||
},
|
||||
{
|
||||
key: '3',
|
||||
label: 'Token Length (In/Out)',
|
||||
children: (
|
||||
<span>
|
||||
{detailData?.dataset_input_tokens || '-'} /{' '}
|
||||
{detailData?.dataset_output_tokens || '-'}
|
||||
</span>
|
||||
)
|
||||
},
|
||||
{
|
||||
key: '5',
|
||||
label: 'Seed',
|
||||
children: detailData?.seed || '-'
|
||||
},
|
||||
{
|
||||
key: '6',
|
||||
label: 'Request Rate',
|
||||
children: detailData?.request_rate || '-'
|
||||
},
|
||||
{
|
||||
key: '7',
|
||||
label: 'Total Requests',
|
||||
children: detailData?.total_requests || '-'
|
||||
}
|
||||
];
|
||||
|
||||
return (
|
||||
<Section title="Benchmark Parameters">
|
||||
<Descriptions
|
||||
items={items}
|
||||
colon={false}
|
||||
column={3}
|
||||
layout="vertical"
|
||||
styles={{
|
||||
content: {
|
||||
justifyContent: 'flex-start'
|
||||
}
|
||||
}}
|
||||
></Descriptions>
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
export default Benchmark;
|
||||
@@ -1,9 +1,23 @@
|
||||
import React from 'react';
|
||||
import styled from 'styled-components';
|
||||
import { useDetailContext } from '../../config/detail-context';
|
||||
import Benchmark from './benchmark';
|
||||
import Instance from './instance';
|
||||
|
||||
const Container = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
`;
|
||||
|
||||
const Configure: React.FC = () => {
|
||||
const { detailData } = useDetailContext();
|
||||
return <div>Configure Content</div>;
|
||||
return (
|
||||
<Container>
|
||||
<Instance />
|
||||
<Benchmark />
|
||||
</Container>
|
||||
);
|
||||
};
|
||||
|
||||
export default Configure;
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
import StatusTag from '@/components/status-tag';
|
||||
import { InstanceStatusMapValue, status } from '@/pages/llmodels/config';
|
||||
import { convertFileSize } from '@/utils';
|
||||
import { Descriptions } from 'antd';
|
||||
import _ from 'lodash';
|
||||
import React, { useMemo } from 'react';
|
||||
import { useDetailContext } from '../../config/detail-context';
|
||||
import Section from '../summary/section';
|
||||
|
||||
const calcTotalVram = (vram: Record<string, number>) => {
|
||||
return _.sum(_.values(vram));
|
||||
};
|
||||
|
||||
const Instance: React.FC = () => {
|
||||
const { detailData } = useDetailContext();
|
||||
|
||||
const items = useMemo(() => {
|
||||
const { snapshot } = detailData;
|
||||
const [instanceName, instanceData] =
|
||||
Object.entries(snapshot.instances || {})[0] || [];
|
||||
return [
|
||||
{
|
||||
key: '1',
|
||||
label: 'Instance Name',
|
||||
children: (
|
||||
<div className="flex-center gap-8">
|
||||
<span>{instanceName}</span>
|
||||
<StatusTag
|
||||
statusValue={{
|
||||
status: status[instanceData.state],
|
||||
text: InstanceStatusMapValue[instanceData.state],
|
||||
message: detailData.state_message || undefined
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
},
|
||||
{
|
||||
key: '2',
|
||||
label: 'Worker',
|
||||
children: instanceData?.worker_name || '-'
|
||||
// children:
|
||||
// instanceData?.ports?.length > 0
|
||||
// ? `${instanceData.worker_ip}:${instanceData.ports[0]}`
|
||||
// : instanceData.worker_ip || '-'
|
||||
},
|
||||
{
|
||||
key: '3',
|
||||
label: 'GPU Indexes',
|
||||
children:
|
||||
_.join(
|
||||
instanceData.gpu_indexes?.sort?.((a, b) => a - b),
|
||||
','
|
||||
) || '-'
|
||||
},
|
||||
{
|
||||
key: '6',
|
||||
label: 'GPU Type',
|
||||
children: instanceData?.gpu_type || '-'
|
||||
},
|
||||
{
|
||||
key: '4',
|
||||
label: 'Allocated VRAM',
|
||||
children:
|
||||
convertFileSize(
|
||||
instanceData.computed_resource_claim?.vram
|
||||
? calcTotalVram(instanceData.computed_resource_claim?.vram)
|
||||
: 0,
|
||||
1
|
||||
) || '-'
|
||||
},
|
||||
{
|
||||
key: '5',
|
||||
label: 'Backend',
|
||||
children: `${instanceData?.backend || '-'} ${
|
||||
instanceData.backend_version
|
||||
? `(${instanceData.backend_version})`
|
||||
: ''
|
||||
}`
|
||||
}
|
||||
];
|
||||
}, [detailData]);
|
||||
|
||||
return (
|
||||
<Section title="Model Instance">
|
||||
<Descriptions
|
||||
items={items}
|
||||
colon={false}
|
||||
column={3}
|
||||
layout="vertical"
|
||||
styles={{
|
||||
content: {
|
||||
justifyContent: 'flex-start'
|
||||
}
|
||||
}}
|
||||
></Descriptions>
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
export default Instance;
|
||||
@@ -1,16 +1,28 @@
|
||||
import AutoTooltip from '@/components/auto-tooltip';
|
||||
import { convertFileSize } from '@/utils';
|
||||
import { Descriptions, DescriptionsProps } from 'antd';
|
||||
import React from 'react';
|
||||
import styled from 'styled-components';
|
||||
import { GPUData } from '../../config/detail-types';
|
||||
import Section from '../summary/section';
|
||||
|
||||
const Content = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
align-items: flex-start;
|
||||
.name {
|
||||
font-weight: 500;
|
||||
}
|
||||
`;
|
||||
|
||||
const Environment: React.FC<GPUData> = (props) => {
|
||||
const items: DescriptionsProps['items'] = [
|
||||
{
|
||||
key: '4',
|
||||
label: 'Name',
|
||||
children: props.name
|
||||
},
|
||||
// {
|
||||
// key: '4',
|
||||
// label: 'Name',
|
||||
// children: <AutoTooltip ghost>{props.name}</AutoTooltip>
|
||||
// },
|
||||
{
|
||||
key: '1',
|
||||
label: 'VRAM',
|
||||
@@ -18,12 +30,12 @@ const Environment: React.FC<GPUData> = (props) => {
|
||||
},
|
||||
{
|
||||
key: '3',
|
||||
label: 'Driver Version',
|
||||
label: 'Driver',
|
||||
children: props.driver_version
|
||||
},
|
||||
{
|
||||
key: '2',
|
||||
label: 'Runtime Version',
|
||||
label: 'Runtime',
|
||||
children: props.runtime_version
|
||||
},
|
||||
{
|
||||
@@ -35,21 +47,36 @@ const Environment: React.FC<GPUData> = (props) => {
|
||||
key: '5',
|
||||
label: 'Vendor',
|
||||
children: props.vendor
|
||||
},
|
||||
{
|
||||
key: '7',
|
||||
label: 'GPU Type',
|
||||
children: props.type
|
||||
}
|
||||
];
|
||||
return (
|
||||
<Section title={`GPU ${props.index}`}>
|
||||
<Descriptions
|
||||
items={items}
|
||||
colon={false}
|
||||
column={3}
|
||||
layout="vertical"
|
||||
styles={{
|
||||
content: {
|
||||
justifyContent: 'flex-start'
|
||||
}
|
||||
}}
|
||||
></Descriptions>
|
||||
<Section
|
||||
title={
|
||||
<span style={{ color: 'var(--ant-color-text-tertiary)' }}>
|
||||
GPU {props.index}
|
||||
</span>
|
||||
}
|
||||
>
|
||||
<Content>
|
||||
<div className="name">
|
||||
<AutoTooltip ghost>{props.name}</AutoTooltip>
|
||||
</div>
|
||||
<Descriptions
|
||||
items={items}
|
||||
colon={true}
|
||||
column={3}
|
||||
styles={{
|
||||
content: {
|
||||
justifyContent: 'flex-start'
|
||||
}
|
||||
}}
|
||||
></Descriptions>
|
||||
</Content>
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -63,7 +63,14 @@ const Environment: React.FC = () => {
|
||||
gpuData={mainWorker.gpuData}
|
||||
title={
|
||||
<div className="flex-center gap-8">
|
||||
<Tag color="geekblue">Sub</Tag>
|
||||
<Tag
|
||||
style={{
|
||||
backgroundColor: 'var(--ant-color-fill-secondary)',
|
||||
color: 'var(--ant-color-text-tertiary)'
|
||||
}}
|
||||
>
|
||||
Sub
|
||||
</Tag>
|
||||
<span>{mainWorker?.workerData?.name}</span>
|
||||
</div>
|
||||
}
|
||||
|
||||
@@ -31,6 +31,10 @@ const Environment: React.FC<{
|
||||
<Section
|
||||
title={title}
|
||||
styles={{
|
||||
wraper: {
|
||||
border: 'none',
|
||||
overflow: 'unset'
|
||||
},
|
||||
container: {
|
||||
border: 'none',
|
||||
paddingInline: 16,
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import BaseSelect from '@/components/seal-form/base/select';
|
||||
import { SearchOutlined, SyncOutlined } from '@ant-design/icons';
|
||||
import { useIntl } from '@umijs/max';
|
||||
import { Button, Input, Space } from 'antd';
|
||||
@@ -6,11 +7,19 @@ import React from 'react';
|
||||
export interface RightActionsProps {
|
||||
handleInputChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
|
||||
handleSearch: () => void;
|
||||
handleQueryChange: (value: any, option?: any) => void;
|
||||
modelList?: Global.BaseOption<number>[];
|
||||
datasetList?: Global.BaseOption<string>[];
|
||||
gpuVendorList?: Global.BaseOption<string>[];
|
||||
}
|
||||
|
||||
const RightActions: React.FC<RightActionsProps> = ({
|
||||
handleInputChange,
|
||||
handleSearch
|
||||
handleSearch,
|
||||
handleQueryChange,
|
||||
modelList,
|
||||
datasetList,
|
||||
gpuVendorList
|
||||
}) => {
|
||||
const intl = useIntl();
|
||||
|
||||
@@ -29,7 +38,42 @@ const RightActions: React.FC<RightActionsProps> = ({
|
||||
allowClear
|
||||
onChange={handleInputChange}
|
||||
></Input>
|
||||
{/* <CompareConditions></CompareConditions> */}
|
||||
<BaseSelect
|
||||
allowClear
|
||||
placeholder="Filter by model"
|
||||
style={{ width: 150 }}
|
||||
options={modelList}
|
||||
onChange={(value, option) =>
|
||||
handleQueryChange({
|
||||
model_name: value,
|
||||
page: 1
|
||||
})
|
||||
}
|
||||
></BaseSelect>
|
||||
<BaseSelect
|
||||
allowClear
|
||||
placeholder="Filter by dataset"
|
||||
style={{ width: 150 }}
|
||||
options={datasetList}
|
||||
onChange={(value, option) =>
|
||||
handleQueryChange({
|
||||
dataset_name: value,
|
||||
page: 1
|
||||
})
|
||||
}
|
||||
></BaseSelect>
|
||||
<BaseSelect
|
||||
allowClear
|
||||
placeholder="Filter by GPU vendor"
|
||||
onChange={(value, option) =>
|
||||
handleQueryChange({
|
||||
gpu_summary: value,
|
||||
page: 1
|
||||
})
|
||||
}
|
||||
style={{ width: 180 }}
|
||||
options={gpuVendorList}
|
||||
></BaseSelect>
|
||||
<Button
|
||||
type="text"
|
||||
style={{ color: 'var(--ant-color-text-tertiary)' }}
|
||||
|
||||
@@ -12,6 +12,7 @@ export interface RightActionsProps {
|
||||
handleDeleteByBatch: () => void;
|
||||
handleClickPrimary?: () => void;
|
||||
handleSettingFields?: () => void;
|
||||
handleExport?: () => void;
|
||||
settingButton?: React.ReactNode;
|
||||
buttonText?: string;
|
||||
rowSelection: {
|
||||
@@ -23,6 +24,7 @@ const RightActions: React.FC<RightActionsProps> = ({
|
||||
handleDeleteByBatch,
|
||||
handleClickPrimary,
|
||||
handleSettingFields,
|
||||
handleExport,
|
||||
settingButton,
|
||||
buttonText,
|
||||
rowSelection
|
||||
@@ -36,7 +38,7 @@ const RightActions: React.FC<RightActionsProps> = ({
|
||||
},
|
||||
{
|
||||
label: 'common.button.delete',
|
||||
key: 'start',
|
||||
key: 'delete',
|
||||
props: {
|
||||
danger: true
|
||||
},
|
||||
@@ -44,7 +46,13 @@ const RightActions: React.FC<RightActionsProps> = ({
|
||||
}
|
||||
];
|
||||
|
||||
const handleActionSelect = (val: string) => {};
|
||||
const handleActionSelect = (val: string) => {
|
||||
if (val === 'delete') {
|
||||
handleDeleteByBatch();
|
||||
} else if (val === 'export') {
|
||||
handleExport?.();
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Space size={16}>
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
import AutoTooltip from '@/components/auto-tooltip';
|
||||
import StatusTag from '@/components/status-tag';
|
||||
import { useIntl } from '@umijs/max';
|
||||
import { Col, Descriptions, DescriptionsProps, Row, Statistic } from 'antd';
|
||||
import dayjs from 'dayjs';
|
||||
import { round } from 'lodash';
|
||||
import React from 'react';
|
||||
import styled from 'styled-components';
|
||||
import { BenchmarkStatus, BenchmarkStatusLabelMap } from '../../config';
|
||||
import { useDetailContext } from '../../config/detail-context';
|
||||
import PercentileResult from './percentile-result';
|
||||
import Section from './section';
|
||||
@@ -158,7 +156,7 @@ const Summary: React.FC = () => {
|
||||
<Container>
|
||||
<Row gutter={16}>
|
||||
{cardFields.map((field) => (
|
||||
<Col span={8} key={field.key} style={{ padding: '8px' }}>
|
||||
<Col span={4} key={field.key} style={{ padding: '8px' }}>
|
||||
<Card>
|
||||
<Statistic
|
||||
title={field.label}
|
||||
@@ -180,17 +178,7 @@ const Summary: React.FC = () => {
|
||||
</Col>
|
||||
))}
|
||||
</Row>
|
||||
<Section>
|
||||
<div className="flex-center section-title gap-8">
|
||||
<span>{detailData.model_instance_name}</span>
|
||||
<StatusTag
|
||||
statusValue={{
|
||||
status: BenchmarkStatus[detailData.state],
|
||||
text: BenchmarkStatusLabelMap[detailData.state],
|
||||
message: detailData.state_message || undefined
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<Section title="Metadata">
|
||||
<Descriptions
|
||||
items={items}
|
||||
colon={false}
|
||||
@@ -205,10 +193,7 @@ const Summary: React.FC = () => {
|
||||
</Section>
|
||||
|
||||
<Box>
|
||||
<Section>
|
||||
<div className="flex-center section-title gap-8">
|
||||
<span>Throughput</span>
|
||||
</div>
|
||||
<Section title="Throughput">
|
||||
<Descriptions
|
||||
items={throughputFields}
|
||||
colon={true}
|
||||
@@ -220,10 +205,7 @@ const Summary: React.FC = () => {
|
||||
}}
|
||||
></Descriptions>
|
||||
</Section>
|
||||
<Section>
|
||||
<div className="flex-center section-title gap-8">
|
||||
<span>Latency</span>
|
||||
</div>
|
||||
<Section title="Latency">
|
||||
<Descriptions
|
||||
items={latencyFields}
|
||||
colon={true}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import _ from 'lodash';
|
||||
import React, { useEffect } from 'react';
|
||||
import React from 'react';
|
||||
import { useDetailContext } from '../../config/detail-context';
|
||||
import useQueryMtrics from '../../services/use-query-metrics';
|
||||
|
||||
const fields = [
|
||||
'requests_per_second_mean',
|
||||
@@ -15,25 +13,7 @@ const fields = [
|
||||
];
|
||||
|
||||
const Summary: React.FC = () => {
|
||||
const { detailData, id } = useDetailContext();
|
||||
const {
|
||||
detailData: metricsData,
|
||||
fetchData,
|
||||
cancelRequest
|
||||
} = useQueryMtrics();
|
||||
|
||||
useEffect(() => {
|
||||
if (id) {
|
||||
fetchData({
|
||||
id: id,
|
||||
data: {
|
||||
..._.pick(detailData, fields)
|
||||
}
|
||||
});
|
||||
} else {
|
||||
cancelRequest();
|
||||
}
|
||||
}, [id]);
|
||||
const { detailData } = useDetailContext();
|
||||
return <div></div>;
|
||||
};
|
||||
|
||||
|
||||
@@ -1,8 +1,14 @@
|
||||
import styled from 'styled-components';
|
||||
|
||||
const Wrapper = styled.div`
|
||||
border: 1px solid var(--ant-color-border);
|
||||
border-radius: var(--ant-border-radius);
|
||||
overflow: hidden;
|
||||
`;
|
||||
|
||||
const Container = styled.div`
|
||||
padding: 16px;
|
||||
border: 1px solid var(--ant-color-border);
|
||||
// border: 1px solid var(--ant-color-border);
|
||||
border-radius: 4px;
|
||||
.section-title {
|
||||
font-weight: 500;
|
||||
@@ -17,25 +23,29 @@ const Container = styled.div`
|
||||
const Title = styled.div`
|
||||
display: flex;
|
||||
font-weight: 500;
|
||||
margin-bottom: 12px;
|
||||
// margin-bottom: 12px;
|
||||
font-size: 14px;
|
||||
gap: 8px;
|
||||
padding: 12px 16px;
|
||||
align-items: center;
|
||||
background-color: var(--ant-color-fill-tertiary);
|
||||
border-radius: 4px 4px 0 0;
|
||||
`;
|
||||
|
||||
const DetailSection: React.FC<{
|
||||
children: React.ReactNode;
|
||||
title?: React.ReactNode;
|
||||
styles?: {
|
||||
wraper?: React.CSSProperties;
|
||||
container?: React.CSSProperties;
|
||||
title?: React.CSSProperties;
|
||||
};
|
||||
}> = ({ children, title, styles }) => {
|
||||
return (
|
||||
<Container style={styles?.container}>
|
||||
<Wrapper style={styles?.wraper}>
|
||||
{title && <Title style={styles?.title}>{title}</Title>}
|
||||
{children}
|
||||
</Container>
|
||||
<Container style={styles?.container}>{children}</Container>
|
||||
</Wrapper>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -28,26 +28,46 @@ export const BenchmarkStatus: Record<string, StatusType> = {
|
||||
[BenchmarkStatusValueMap.Unreachable]: StatusMaps.error
|
||||
};
|
||||
|
||||
export const ProfileValueMap = {
|
||||
LatencyShort: 'latency_short',
|
||||
ThroughputMedium: 'throughput_medium',
|
||||
LongContextStress: 'long_context_stress',
|
||||
GenerationHeavy: 'generation_heavy',
|
||||
Custom: 'Custom'
|
||||
};
|
||||
|
||||
export const ProfileLabelMap = {
|
||||
[ProfileValueMap.LatencyShort]: 'benchmark.form.profile.latency',
|
||||
[ProfileValueMap.ThroughputMedium]: 'benchmark.form.profile.throughput',
|
||||
[ProfileValueMap.LongContextStress]: 'benchmark.form.profile.longContext',
|
||||
[ProfileValueMap.GenerationHeavy]: 'benchmark.form.profile.heavy',
|
||||
[ProfileValueMap.Custom]: 'benchmark.form.profile.custom'
|
||||
};
|
||||
|
||||
export const profileOptions = [
|
||||
{
|
||||
label: 'benchmark.form.profile.latency',
|
||||
value: 'latency_short',
|
||||
value: ProfileValueMap.LatencyShort,
|
||||
locale: true
|
||||
},
|
||||
{
|
||||
label: 'benchmark.form.profile.throughput',
|
||||
value: 'throughput_medium',
|
||||
value: ProfileValueMap.ThroughputMedium,
|
||||
locale: true
|
||||
},
|
||||
{
|
||||
label: 'benchmark.form.profile.longContext',
|
||||
value: 'long_context_stress',
|
||||
value: ProfileValueMap.LongContextStress,
|
||||
locale: true
|
||||
},
|
||||
{
|
||||
label: 'benchmark.form.profile.heavy',
|
||||
value: 'generation_heavy',
|
||||
value: ProfileValueMap.GenerationHeavy,
|
||||
locale: true
|
||||
},
|
||||
{ label: 'benchmark.form.profile.custom', value: 'custom', locale: true }
|
||||
{
|
||||
label: 'benchmark.form.profile.custom',
|
||||
value: ProfileValueMap.Custom,
|
||||
locale: true
|
||||
}
|
||||
];
|
||||
|
||||
@@ -87,6 +87,7 @@ export interface FormData {
|
||||
state_message: string;
|
||||
worker_id: number;
|
||||
gpu_summary: string;
|
||||
seed: number;
|
||||
gpu_vendor_summary: string;
|
||||
}
|
||||
|
||||
@@ -101,4 +102,16 @@ export interface DatasetListItem {
|
||||
source: string;
|
||||
prompt_tokens: number;
|
||||
output_tokens: number;
|
||||
id: number;
|
||||
}
|
||||
|
||||
export interface ProfileOption {
|
||||
name: string;
|
||||
description: string;
|
||||
dataset_name: string;
|
||||
dataset_source: string;
|
||||
dataset_prompt_tokens: number;
|
||||
dataset_output_tokens: number;
|
||||
request_rate: number;
|
||||
total_requests: number;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useIntl, useNavigate, useSearchParams } from '@umijs/max';
|
||||
import React from 'react';
|
||||
import React, { useEffect } from 'react';
|
||||
import { PageContainerInner } from '../_components/page-box';
|
||||
import PageBreadcrumb from '../_components/page-breadcrumb';
|
||||
import DetailContent from './components/detail-content';
|
||||
@@ -19,6 +19,11 @@ const Details: React.FC = () => {
|
||||
title: name
|
||||
}
|
||||
];
|
||||
|
||||
useEffect(() => {
|
||||
document.title = `${intl.formatMessage({ id: 'benchmark.title' })} - ${name}`;
|
||||
}, [name, intl]);
|
||||
|
||||
return (
|
||||
<PageContainerInner
|
||||
header={{
|
||||
|
||||
@@ -5,6 +5,10 @@ import { PageAction } from '@/config';
|
||||
import useAppUtils from '@/hooks/use-app-utils';
|
||||
import { ClusterStatusValueMap } from '@/pages/cluster-management/config';
|
||||
import { useQueryClusterList } from '@/pages/cluster-management/services/use-query-cluster-list';
|
||||
import {
|
||||
InstanceStatusMap,
|
||||
InstanceStatusMapValue
|
||||
} from '@/pages/llmodels/config';
|
||||
import { useQueryModelInstancesList } from '@/pages/llmodels/services/use-query-model-instances';
|
||||
import { useQueryModelList } from '@/pages/llmodels/services/use-query-model-list';
|
||||
import { useIntl } from '@umijs/max';
|
||||
@@ -28,9 +32,9 @@ const BasicForm: React.FC = () => {
|
||||
} = useQueryClusterList();
|
||||
const {
|
||||
loading: modelLoading,
|
||||
fetchModelList,
|
||||
fetchData: fetchModelList,
|
||||
cancelRequest: cancelModelRequest,
|
||||
modelList
|
||||
dataList: modelList
|
||||
} = useQueryModelList();
|
||||
const {
|
||||
loading: instanceLoading,
|
||||
@@ -65,6 +69,15 @@ const BasicForm: React.FC = () => {
|
||||
form.setFieldValue('model_id', option?.id);
|
||||
};
|
||||
|
||||
const optionRender = (option: any) => {
|
||||
return (
|
||||
<span className="flex-center">
|
||||
{option.label}
|
||||
<span className="text-tertiary m-l-4">{`[${InstanceStatusMapValue[option.data?.state]}]`}</span>
|
||||
</span>
|
||||
);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const initClusterId = (list: any[]) => {
|
||||
// Find default cluster
|
||||
@@ -163,7 +176,11 @@ const BasicForm: React.FC = () => {
|
||||
>
|
||||
<SealSelect
|
||||
loading={instanceLoading}
|
||||
options={instanceList}
|
||||
options={instanceList.map((item) => ({
|
||||
...item,
|
||||
disabled: item.state !== InstanceStatusMap.Running
|
||||
}))}
|
||||
optionRender={optionRender}
|
||||
onOpenChange={onInstanceOpenChange}
|
||||
label={intl.formatMessage({ id: 'benchmark.table.instance' })}
|
||||
required
|
||||
|
||||
@@ -1,40 +1,129 @@
|
||||
import AutoComplete from '@/components/seal-form/auto-complete';
|
||||
import SealInputNumber from '@/components/seal-form/input-number';
|
||||
import SealInput from '@/components/seal-form/seal-input';
|
||||
import SealSelect from '@/components/seal-form/seal-select';
|
||||
import useAppUtils from '@/hooks/use-app-utils';
|
||||
import { useIntl } from '@umijs/max';
|
||||
import { Form } from 'antd';
|
||||
import _ from 'lodash';
|
||||
import React, { useEffect } from 'react';
|
||||
import { profileOptions } from '../config';
|
||||
import { ProfileValueMap } from '../config';
|
||||
import { useFormContext } from '../config/form-context';
|
||||
import { FormData } from '../config/types';
|
||||
import useQueryDataset from '../services/use-query-dataset';
|
||||
import useQueryProfiles from '../services/use-query-profiles';
|
||||
import RandomSettingsForm from './random-settings';
|
||||
|
||||
const profileFields = [
|
||||
'dataset_prompt_tokens',
|
||||
'dataset_output_tokens',
|
||||
'request_rate',
|
||||
'total_requests'
|
||||
];
|
||||
|
||||
const DatasetForm: React.FC = () => {
|
||||
const intl = useIntl();
|
||||
const form = Form.useFormInstance();
|
||||
const { getRuleMessage } = useAppUtils();
|
||||
const { action, open } = useFormContext();
|
||||
const {
|
||||
dataList: datasetList,
|
||||
datasetList,
|
||||
loading: datasetLoading,
|
||||
fetchData,
|
||||
fetchDatasetData,
|
||||
cancelRequest: cancelDatasetRequest
|
||||
} = useQueryDataset();
|
||||
const {
|
||||
profilesOptions,
|
||||
fetchProfilesData,
|
||||
cancelRequest: cancelProfilesRequest
|
||||
} = useQueryProfiles();
|
||||
const profileConfigCache = React.useRef<{ [key: string]: any }>({});
|
||||
|
||||
const handleOnDataSetChange = (value: any, option: any) => {
|
||||
form.setFieldValue('dataset_id', option?.data?.id);
|
||||
if (value === 'Custom') {
|
||||
form.setFieldsValue({
|
||||
profile: ProfileValueMap.Custom,
|
||||
dataset_id: null,
|
||||
dataset_prompt_tokens: null,
|
||||
dataset_output_tokens: null,
|
||||
request_rate: null,
|
||||
total_requests: null
|
||||
});
|
||||
} else {
|
||||
form.setFieldsValue({
|
||||
profile: ProfileValueMap.Custom,
|
||||
dataset_id: option?.data?.id,
|
||||
dataset_prompt_tokens: option?.prompt_tokens,
|
||||
dataset_output_tokens: option?.output_tokens,
|
||||
request_rate: null,
|
||||
total_requests: null
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const handleOnDatasetOpenChange = async (open: boolean) => {
|
||||
if (!datasetList.length && open) {
|
||||
await fetchData({ page: -1 });
|
||||
const setCustomProfileValues = () => {
|
||||
form.setFieldsValue({
|
||||
dataset_name: 'Custom',
|
||||
dataset_id: null,
|
||||
dataset_prompt_tokens: null,
|
||||
dataset_output_tokens: null,
|
||||
request_rate: null,
|
||||
total_requests: null
|
||||
});
|
||||
};
|
||||
|
||||
const handleProfileChange = (value: string, option: any) => {
|
||||
if (value === ProfileValueMap.Custom) {
|
||||
setCustomProfileValues();
|
||||
profileConfigCache.current = {};
|
||||
} else {
|
||||
const dataset_id = datasetList.find(
|
||||
(item) => item.label === option.config?.dataset_name
|
||||
)?.value;
|
||||
|
||||
form.setFieldsValue({
|
||||
dataset_id: dataset_id,
|
||||
..._.omit(option?.config, ['description', 'dataset_source'])
|
||||
});
|
||||
|
||||
profileConfigCache.current = {
|
||||
profile: value,
|
||||
config: {
|
||||
dataset_id: dataset_id,
|
||||
..._.omit(option?.config, ['description', 'dataset_source'])
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
const handleOnProfileConfigChange = async () => {
|
||||
const values = form.getFieldsValue(profileFields);
|
||||
if (
|
||||
_.isEqual(values, {
|
||||
..._.pick(profileConfigCache.current.config, profileFields)
|
||||
})
|
||||
) {
|
||||
form.setFieldsValue({
|
||||
profile: profileConfigCache.current.profile,
|
||||
...profileConfigCache.current.config
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
form.setFieldsValue({
|
||||
profile: 'Custom',
|
||||
dataset_name: 'Custom'
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!open) {
|
||||
cancelDatasetRequest();
|
||||
cancelProfilesRequest();
|
||||
}
|
||||
if (open) {
|
||||
fetchProfilesData();
|
||||
fetchDatasetData();
|
||||
}
|
||||
}, [open]);
|
||||
|
||||
@@ -51,7 +140,8 @@ const DatasetForm: React.FC = () => {
|
||||
]}
|
||||
>
|
||||
<SealSelect
|
||||
options={profileOptions}
|
||||
onChange={handleProfileChange}
|
||||
options={profilesOptions}
|
||||
label={intl.formatMessage({ id: 'benchmark.form.profile' })}
|
||||
required
|
||||
></SealSelect>
|
||||
@@ -65,51 +155,55 @@ const DatasetForm: React.FC = () => {
|
||||
}
|
||||
]}
|
||||
>
|
||||
<SealSelect
|
||||
<AutoComplete
|
||||
options={datasetList.map((item) => ({
|
||||
label: item.name,
|
||||
value: item.name
|
||||
...item,
|
||||
label: item.label,
|
||||
value: item.label
|
||||
}))}
|
||||
loading={datasetLoading}
|
||||
onChange={handleOnDataSetChange}
|
||||
onOpenChange={handleOnDatasetOpenChange}
|
||||
label={intl.formatMessage({ id: 'benchmark.table.dataset' })}
|
||||
required
|
||||
></SealSelect>
|
||||
></AutoComplete>
|
||||
</Form.Item>
|
||||
<Form.Item<FormData> hidden name="dataset_id">
|
||||
<SealInput.Input></SealInput.Input>
|
||||
</Form.Item>
|
||||
<RandomSettingsForm></RandomSettingsForm>
|
||||
<RandomSettingsForm
|
||||
onValueChange={handleOnProfileConfigChange}
|
||||
></RandomSettingsForm>
|
||||
<Form.Item<FormData>
|
||||
name="request_rate"
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: getRuleMessage('select', 'benchmark.table.requestRate')
|
||||
message: getRuleMessage('input', 'benchmark.table.requestRate')
|
||||
}
|
||||
]}
|
||||
>
|
||||
<SealSelect
|
||||
options={[]}
|
||||
<SealInputNumber
|
||||
min={0}
|
||||
onChange={handleOnProfileConfigChange}
|
||||
label={intl.formatMessage({ id: 'benchmark.table.requestRate' })}
|
||||
required
|
||||
></SealSelect>
|
||||
></SealInputNumber>
|
||||
</Form.Item>
|
||||
<Form.Item<FormData>
|
||||
name="total_requests"
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: getRuleMessage('select', 'benchmark.form.totalRequests')
|
||||
message: getRuleMessage('input', 'benchmark.form.totalRequests')
|
||||
}
|
||||
]}
|
||||
>
|
||||
<SealSelect
|
||||
options={[]}
|
||||
<SealInputNumber
|
||||
min={0}
|
||||
onChange={handleOnProfileConfigChange}
|
||||
label={intl.formatMessage({ id: 'benchmark.form.totalRequests' })}
|
||||
required
|
||||
></SealSelect>
|
||||
></SealInputNumber>
|
||||
</Form.Item>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -99,7 +99,17 @@ const ProviderForm: React.FC<ProviderFormProps> = forwardRef((props, ref) => {
|
||||
open
|
||||
}}
|
||||
>
|
||||
<Form form={form} onFinish={onFinish} initialValues={{}}>
|
||||
<Form
|
||||
form={form}
|
||||
onFinish={onFinish}
|
||||
initialValues={{
|
||||
dataset_prompt_tokens: null,
|
||||
dataset_output_tokens: null,
|
||||
total_requests: null,
|
||||
request_rate: null,
|
||||
seed: null
|
||||
}}
|
||||
>
|
||||
<Basic />
|
||||
<CollapsePanel
|
||||
activeKey={activeKey}
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import SealInputNumber from '@/components/seal-form/input-number';
|
||||
import SealSelect from '@/components/seal-form/seal-select';
|
||||
import useAppUtils from '@/hooks/use-app-utils';
|
||||
import { useIntl } from '@umijs/max';
|
||||
import { Form } from 'antd';
|
||||
import React from 'react';
|
||||
import { FormData } from '../config/types';
|
||||
|
||||
const DatasetForm: React.FC = () => {
|
||||
const DatasetForm: React.FC<{
|
||||
onValueChange?: (value: any) => void;
|
||||
}> = ({ onValueChange }) => {
|
||||
const intl = useIntl();
|
||||
const form = Form.useFormInstance();
|
||||
const { getRuleMessage } = useAppUtils();
|
||||
@@ -18,27 +19,16 @@ const DatasetForm: React.FC = () => {
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: getRuleMessage(
|
||||
'select',
|
||||
'benchmark.table.inputTokenLength'
|
||||
)
|
||||
message: getRuleMessage('input', 'benchmark.table.inputTokenLength')
|
||||
}
|
||||
]}
|
||||
>
|
||||
<SealSelect
|
||||
options={[
|
||||
{
|
||||
label: '100',
|
||||
value: 100
|
||||
},
|
||||
{
|
||||
label: '128',
|
||||
value: 128
|
||||
}
|
||||
]}
|
||||
<SealInputNumber
|
||||
min={0}
|
||||
label={intl.formatMessage({ id: 'benchmark.table.inputTokenLength' })}
|
||||
required
|
||||
></SealSelect>
|
||||
onChange={onValueChange}
|
||||
></SealInputNumber>
|
||||
</Form.Item>
|
||||
<Form.Item<FormData>
|
||||
name="dataset_output_tokens"
|
||||
@@ -46,33 +36,28 @@ const DatasetForm: React.FC = () => {
|
||||
{
|
||||
required: true,
|
||||
message: getRuleMessage(
|
||||
'select',
|
||||
'input',
|
||||
'benchmark.table.outputTokenLength'
|
||||
)
|
||||
}
|
||||
]}
|
||||
>
|
||||
<SealSelect
|
||||
options={[
|
||||
{
|
||||
label: '4',
|
||||
value: 4
|
||||
},
|
||||
{
|
||||
label: '8',
|
||||
value: 8
|
||||
}
|
||||
]}
|
||||
<SealInputNumber
|
||||
min={0}
|
||||
label={intl.formatMessage({
|
||||
id: 'benchmark.table.outputTokenLength'
|
||||
})}
|
||||
required
|
||||
></SealSelect>
|
||||
onChange={onValueChange}
|
||||
></SealInputNumber>
|
||||
</Form.Item>
|
||||
<Form.Item<FormData> name="seed">
|
||||
<Form.Item<FormData>
|
||||
name="seed"
|
||||
getValueProps={(value) => ({ value: value || null })}
|
||||
>
|
||||
<SealInputNumber
|
||||
min={0}
|
||||
label={intl.formatMessage({ id: 'playground.image.params.seed' })}
|
||||
required
|
||||
></SealInputNumber>
|
||||
</Form.Item>
|
||||
</>
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
import { exportJsonToExcel } from '@/utils/excel-reader';
|
||||
|
||||
const useExportData = (params: { columns: any[] }) => {
|
||||
const { columns } = params;
|
||||
const colIndexMap = columns.reduce(
|
||||
(map, col) => {
|
||||
if (col.dataIndex !== 'operations') {
|
||||
map[col.dataIndex] = col.title;
|
||||
}
|
||||
return map;
|
||||
},
|
||||
{} as Record<string, any>
|
||||
);
|
||||
|
||||
const exportData = (dataList: any[]) => {
|
||||
const fileName = `benchmark.xlsx`;
|
||||
exportJsonToExcel({
|
||||
jsonData: dataList || [],
|
||||
fileName: fileName,
|
||||
fields: Object.keys(colIndexMap),
|
||||
fieldLabels: colIndexMap,
|
||||
formatMap: {}
|
||||
});
|
||||
};
|
||||
return { exportData };
|
||||
};
|
||||
|
||||
export default useExportData;
|
||||
@@ -4,12 +4,15 @@ import { FilterBar } from '@/components/page-tools';
|
||||
import { PageAction } from '@/config';
|
||||
import { TABLE_SORT_DIRECTIONS } from '@/config/settings';
|
||||
import useTableFetch from '@/hooks/use-table-fetch';
|
||||
import { useQueryModelList } from '@/pages/llmodels/services/use-query-model-list';
|
||||
import { useIntl, useNavigate } from '@umijs/max';
|
||||
import { useMemoizedFn } from 'ahooks';
|
||||
import { ConfigProvider, Table, message } from 'antd';
|
||||
import _ from 'lodash';
|
||||
import { useEffect, useState } from 'react';
|
||||
import NoResult from '../_components/no-result';
|
||||
import PageBox from '../_components/page-box';
|
||||
import useQueryGPUs from '../resources/services/use-query-gpus';
|
||||
import {
|
||||
createBenchmark,
|
||||
deleteBenchmark,
|
||||
@@ -24,6 +27,7 @@ import { FormData, BenchmarkListItem as ListItem } from './config/types';
|
||||
import useBenchmarkColumns from './hooks/use-benchmark-columns';
|
||||
import useColumnSettings from './hooks/use-column-settings';
|
||||
import useCreateBenchmark from './hooks/use-create-benchmark';
|
||||
import useExportData from './hooks/use-export-data';
|
||||
import useViewDetail from './hooks/use-view-detail';
|
||||
|
||||
const Benchmark: React.FC = () => {
|
||||
@@ -38,6 +42,7 @@ const Benchmark: React.FC = () => {
|
||||
fetchData,
|
||||
handlePageChange,
|
||||
handleTableChange,
|
||||
handleQueryChange,
|
||||
handleSearch,
|
||||
handleNameChange
|
||||
} = useTableFetch<ListItem>({
|
||||
@@ -54,7 +59,26 @@ const Benchmark: React.FC = () => {
|
||||
closeViewDetailModal,
|
||||
openViewDetailModalStatus
|
||||
} = useViewDetail();
|
||||
const { dataList: modelList, fetchData: fetchModelList } = useQueryModelList({
|
||||
getValue: (item: any) => item.name
|
||||
});
|
||||
const { fetchData: fetchGpuList } = useQueryGPUs();
|
||||
const { SettingsButton, selectedColumns } = useColumnSettings();
|
||||
const [gpuVendorList, setGpuVendorList] = useState<
|
||||
Global.BaseOption<string>[]
|
||||
>([]);
|
||||
|
||||
useEffect(() => {
|
||||
fetchModelList({ page: -1 });
|
||||
fetchGpuList({ page: -1 }).then((list) => {
|
||||
const vendors = _.uniq(list.map((gpu) => gpu.vendor).filter((v) => !!v));
|
||||
const vendorOptions = vendors.map((vendor: string) => ({
|
||||
label: vendor,
|
||||
value: vendor
|
||||
}));
|
||||
setGpuVendorList(vendorOptions);
|
||||
});
|
||||
}, []);
|
||||
|
||||
const handleAddBenchmark = () => {
|
||||
openBenchmarkModal(PageAction.CREATE, 'Add Benchmark');
|
||||
@@ -137,6 +161,15 @@ const Benchmark: React.FC = () => {
|
||||
handleOnCellClick
|
||||
);
|
||||
|
||||
const { exportData } = useExportData({ columns: columns });
|
||||
|
||||
const handleExportData = () => {
|
||||
const list = dataSource.dataList.filter((item) =>
|
||||
rowSelection.selectedRowKeys.includes(item.id)
|
||||
);
|
||||
exportData(list);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<PageBox>
|
||||
@@ -150,7 +183,10 @@ const Benchmark: React.FC = () => {
|
||||
widths={{ input: 300 }}
|
||||
left={
|
||||
<LeftActions
|
||||
modelList={modelList}
|
||||
gpuVendorList={gpuVendorList}
|
||||
handleSearch={handleSearch}
|
||||
handleQueryChange={handleQueryChange}
|
||||
handleInputChange={handleNameChange}
|
||||
></LeftActions>
|
||||
}
|
||||
@@ -159,6 +195,7 @@ const Benchmark: React.FC = () => {
|
||||
settingButton={SettingsButton}
|
||||
handleDeleteByBatch={handleDeleteBatch}
|
||||
handleClickPrimary={handleAddBenchmark}
|
||||
handleExport={handleExportData}
|
||||
buttonText={intl.formatMessage({
|
||||
id: 'benchmark.button.add'
|
||||
})}
|
||||
@@ -176,6 +213,7 @@ const Benchmark: React.FC = () => {
|
||||
sortDirections={TABLE_SORT_DIRECTIONS}
|
||||
showSorterTooltip={false}
|
||||
rowKey="id"
|
||||
scroll={{ x: 1200 }}
|
||||
onChange={handleTableChange}
|
||||
pagination={{
|
||||
showSizeChanger: true,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { useQueryDataList } from '@/hooks/use-query-data-list';
|
||||
import { useState } from 'react';
|
||||
import { queryDatasetList } from '../apis';
|
||||
import { DatasetListItem } from '../config/types';
|
||||
|
||||
@@ -11,10 +12,34 @@ const useQueryDataset = () => {
|
||||
fetchList: queryDatasetList
|
||||
});
|
||||
|
||||
const [datasetList, setDatasetList] = useState<
|
||||
Global.BaseOption<number | string>[]
|
||||
>([]);
|
||||
|
||||
const fetchDatasetData = async () => {
|
||||
const items = await fetchData({
|
||||
page: -1
|
||||
});
|
||||
const list =
|
||||
items?.map((item) => ({
|
||||
...item,
|
||||
label: item.name,
|
||||
value: item.id
|
||||
})) || [];
|
||||
|
||||
setDatasetList([
|
||||
...list,
|
||||
{
|
||||
label: 'Custom',
|
||||
value: 'Custom'
|
||||
}
|
||||
]);
|
||||
};
|
||||
|
||||
return {
|
||||
dataList,
|
||||
datasetList,
|
||||
loading,
|
||||
fetchData,
|
||||
fetchDatasetData,
|
||||
cancelRequest
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
import { useQueryData } from '@/hooks/use-query-data-list';
|
||||
import { queryBenchmarkMetrics } from '../apis';
|
||||
import { BenchmarkMetricsFormData } from '../config/detail-types';
|
||||
|
||||
export default function useQueryBenchmarkMetrics() {
|
||||
const { detailData, loading, cancelRequest, fetchData } = useQueryData<
|
||||
any,
|
||||
{
|
||||
id: number;
|
||||
data: BenchmarkMetricsFormData;
|
||||
}
|
||||
>({
|
||||
fetchDetail: queryBenchmarkMetrics,
|
||||
key: 'benchmarkMetrics'
|
||||
});
|
||||
return {
|
||||
detailData,
|
||||
loading,
|
||||
cancelRequest,
|
||||
fetchData
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
import { useQueryData } from '@/hooks/use-query-data-list';
|
||||
import _ from 'lodash';
|
||||
import { useState } from 'react';
|
||||
import { queryProfiles } from '../apis';
|
||||
import { ProfileOption } from '../config/types';
|
||||
|
||||
export default function useQueryProfiles() {
|
||||
const { detailData, loading, cancelRequest, fetchData } = useQueryData<{
|
||||
profiles: ProfileOption[];
|
||||
}>({
|
||||
fetchDetail: queryProfiles,
|
||||
key: 'profiles'
|
||||
});
|
||||
const [profilesOptions, setProfilesOptions] = useState<
|
||||
{
|
||||
label: string;
|
||||
value: string;
|
||||
config: Partial<ProfileOption>;
|
||||
}[]
|
||||
>([]);
|
||||
|
||||
const fetchProfilesData = async () => {
|
||||
const res = await fetchData({});
|
||||
const list =
|
||||
res?.profiles?.map((item) => {
|
||||
return {
|
||||
label: item.name,
|
||||
value: item.name,
|
||||
config: {
|
||||
..._.omit(item, 'name')
|
||||
}
|
||||
};
|
||||
}) || [];
|
||||
|
||||
setProfilesOptions([
|
||||
...list,
|
||||
{
|
||||
label: 'Custom',
|
||||
value: 'Custom',
|
||||
config: {
|
||||
dataset_name: '',
|
||||
dataset_prompt_tokens: null,
|
||||
dataset_output_tokens: null,
|
||||
request_rate: null,
|
||||
total_requests: null
|
||||
}
|
||||
}
|
||||
]);
|
||||
};
|
||||
|
||||
return {
|
||||
profilesOptions,
|
||||
loading,
|
||||
cancelRequest,
|
||||
fetchProfilesData
|
||||
};
|
||||
}
|
||||
@@ -1,67 +1,25 @@
|
||||
import { createAxiosToken } from '@/hooks/use-chunk-request';
|
||||
import { useRequest } from 'ahooks';
|
||||
import { message } from 'antd';
|
||||
import { CancelTokenSource } from 'axios';
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import { useQueryDataList } from '@/hooks/use-query-data-list';
|
||||
import { queryModelsList } from '../apis';
|
||||
import { ListItem } from '../config/types';
|
||||
|
||||
/**
|
||||
*
|
||||
* @returns loading, fetch, dataList
|
||||
*/
|
||||
export const useQueryModelList = () => {
|
||||
const axiosTokenRef = useRef<CancelTokenSource | null>(null);
|
||||
const [dataList, setDataList] = useState<
|
||||
Array<Partial<ListItem> & { label: string; value: number }>
|
||||
>([]);
|
||||
|
||||
const {
|
||||
runAsync: fetchData,
|
||||
loading,
|
||||
cancel
|
||||
} = useRequest(
|
||||
async (params: { page: number; perPage?: number; cluster_id?: number }) => {
|
||||
axiosTokenRef.current?.cancel();
|
||||
axiosTokenRef.current = createAxiosToken();
|
||||
const res = await queryModelsList(params, {
|
||||
token: axiosTokenRef.current.token
|
||||
});
|
||||
setDataList(
|
||||
res.items?.map((item: ListItem) => ({
|
||||
...item,
|
||||
label: item.name,
|
||||
value: item.id
|
||||
})) || []
|
||||
);
|
||||
return res.items || [];
|
||||
},
|
||||
{
|
||||
manual: true,
|
||||
onSuccess: (response) => {},
|
||||
onError: (error) => {
|
||||
message.error(error?.message || 'Failed to fetch model list');
|
||||
setDataList([]);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
const cancelRequest = () => {
|
||||
cancel();
|
||||
axiosTokenRef.current?.cancel();
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
cancel();
|
||||
axiosTokenRef.current?.cancel();
|
||||
};
|
||||
}, []);
|
||||
export const useQueryModelList = (optons?: {
|
||||
getLabel?: (item: ListItem) => string;
|
||||
getValue?: (item: ListItem) => any;
|
||||
}) => {
|
||||
const { dataList, loading, fetchData, cancelRequest } = useQueryDataList<
|
||||
ListItem,
|
||||
Global.SearchParams
|
||||
>({
|
||||
key: 'modelList',
|
||||
fetchList: queryModelsList
|
||||
});
|
||||
|
||||
return {
|
||||
dataList,
|
||||
loading,
|
||||
modelList: dataList,
|
||||
cancelRequest,
|
||||
fetchModelList: fetchData
|
||||
fetchData,
|
||||
cancelRequest
|
||||
};
|
||||
};
|
||||
|
||||
export default useQueryModelList;
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
import { useQueryDataList } from '@/hooks/use-query-data-list';
|
||||
import { queryGpuDevicesList } from '../apis';
|
||||
import { GPUDeviceItem as ListItem } from '../config/types';
|
||||
|
||||
export const useQueryGPUs = (optons?: {
|
||||
getLabel?: (item: ListItem) => string;
|
||||
getValue?: (item: ListItem) => any;
|
||||
}) => {
|
||||
const { dataList, loading, fetchData, cancelRequest } = useQueryDataList<
|
||||
ListItem,
|
||||
Global.SearchParams
|
||||
>({
|
||||
key: 'gpuList',
|
||||
fetchList: queryGpuDevicesList
|
||||
});
|
||||
|
||||
return {
|
||||
dataList,
|
||||
loading,
|
||||
fetchData,
|
||||
cancelRequest
|
||||
};
|
||||
};
|
||||
|
||||
export default useQueryGPUs;
|
||||
Reference in New Issue
Block a user