diff --git a/src/locales/en-US/benchmark.ts b/src/locales/en-US/benchmark.ts
index f515d968..ff47730d 100644
--- a/src/locales/en-US/benchmark.ts
+++ b/src/locales/en-US/benchmark.ts
@@ -21,7 +21,7 @@ export default {
'benchmark.form.profile.longContext': 'Long Context',
'benchmark.form.profile.heavy': 'Generation Heavy',
'benchmark.form.profile.custom': 'Custom',
- 'benchmark.table.inputTokenLength': 'Input Token Length',
+ 'benchmark.table.inputTokenLength': 'Prompt Token Length',
'benchmark.table.outputTokenLength': 'Output Token Length',
'benchmark.detail.summary.title': 'Summary',
'benchmark.detail.configure.title': 'Configure',
diff --git a/src/locales/ja-JP/benchmark.ts b/src/locales/ja-JP/benchmark.ts
index f515d968..ff47730d 100644
--- a/src/locales/ja-JP/benchmark.ts
+++ b/src/locales/ja-JP/benchmark.ts
@@ -21,7 +21,7 @@ export default {
'benchmark.form.profile.longContext': 'Long Context',
'benchmark.form.profile.heavy': 'Generation Heavy',
'benchmark.form.profile.custom': 'Custom',
- 'benchmark.table.inputTokenLength': 'Input Token Length',
+ 'benchmark.table.inputTokenLength': 'Prompt Token Length',
'benchmark.table.outputTokenLength': 'Output Token Length',
'benchmark.detail.summary.title': 'Summary',
'benchmark.detail.configure.title': 'Configure',
diff --git a/src/locales/ru-RU/benchmark.ts b/src/locales/ru-RU/benchmark.ts
index f515d968..ff47730d 100644
--- a/src/locales/ru-RU/benchmark.ts
+++ b/src/locales/ru-RU/benchmark.ts
@@ -21,7 +21,7 @@ export default {
'benchmark.form.profile.longContext': 'Long Context',
'benchmark.form.profile.heavy': 'Generation Heavy',
'benchmark.form.profile.custom': 'Custom',
- 'benchmark.table.inputTokenLength': 'Input Token Length',
+ 'benchmark.table.inputTokenLength': 'Prompt Token Length',
'benchmark.table.outputTokenLength': 'Output Token Length',
'benchmark.detail.summary.title': 'Summary',
'benchmark.detail.configure.title': 'Configure',
diff --git a/src/locales/zh-CN/benchmark.ts b/src/locales/zh-CN/benchmark.ts
index 5860e71d..da26b9ec 100644
--- a/src/locales/zh-CN/benchmark.ts
+++ b/src/locales/zh-CN/benchmark.ts
@@ -21,7 +21,7 @@ export default {
'benchmark.form.profile.longContext': '长上下文',
'benchmark.form.profile.heavy': '高生成量',
'benchmark.form.profile.custom': '自定义',
- 'benchmark.table.inputTokenLength': '输入 Token 长度',
+ 'benchmark.table.inputTokenLength': '提示词 Token 长度',
'benchmark.table.outputTokenLength': '输出 Token 长度',
'benchmark.detail.summary.title': '摘要',
'benchmark.detail.configure.title': '配置',
diff --git a/src/pages/benchmark/apis/index.ts b/src/pages/benchmark/apis/index.ts
index c6ea7d96..791b7ac6 100644
--- a/src/pages/benchmark/apis/index.ts
+++ b/src/pages/benchmark/apis/index.ts
@@ -10,6 +10,7 @@ import {
export const BENCHMARKS_API = '/benchmarks';
export const DATASETS_API = '/datasets';
export const PROFILES_CONFIG_API = '/benchmark-profiles/default-config';
+export const EXPORT_BENCHMARK_LIST = '/benchmarks/export';
export async function queryBenchmarkList(
params: Global.SearchParams,
@@ -103,3 +104,19 @@ export async function queryProfiles(
cancelToken: options?.token
});
}
+
+export async function exportBenchmarkList(
+ params: {
+ ids?: number[];
+ },
+ options?: {
+ token?: CancelToken;
+ }
+) {
+ return request(`${BENCHMARKS_API}/export`, {
+ method: 'POST',
+ data: params.ids,
+ responseType: 'blob',
+ cancelToken: options?.token
+ });
+}
diff --git a/src/pages/benchmark/components/environment/index.tsx b/src/pages/benchmark/components/environment/index.tsx
index d416ea75..26b5e525 100644
--- a/src/pages/benchmark/components/environment/index.tsx
+++ b/src/pages/benchmark/components/environment/index.tsx
@@ -4,7 +4,8 @@ import SealTable from '@/components/seal-table/index';
import useExpandedRowKeys from '@/hooks/use-expanded-row-keys';
import { convertFileSize } from '@/utils';
import useMemoizedFn from 'ahooks/lib/useMemoizedFn';
-import { Col, Row } from 'antd';
+import { Col, Row, Tag } from 'antd';
+import _ from 'lodash';
import React, { useMemo } from 'react';
import styled from 'styled-components';
import { useDetailContext } from '../../config/detail-context';
@@ -32,30 +33,31 @@ const Environment: React.FC = () => {
return {
...workerInfo,
+ ..._.pick(gpuData?.[0], ['driver_version', 'runtime_version']),
isMain: true,
children: gpuData
};
}, [snapshot]);
- // const subWorkers = useMemo(() => {
- // const [[mainWorkerName, mainWorkerInfo]] = Object.entries(snapshot.workers);
+ const subWorkers = useMemo(() => {
+ const [[mainWorkerName, mainWorkerInfo]] = Object.entries(snapshot.workers);
- // const subOrdinaryWorkers = Object.values(snapshot.instances).filter(
- // (instance) => instance.worker_name === mainWorkerName
- // );
+ const subOrdinaryWorkers = Object.values(snapshot.instances).filter(
+ (instance) => instance.worker_name === mainWorkerName
+ );
- // return subOrdinaryWorkers.map((worker) => {
- // const gpuData = Object.values(snapshot.gpus).filter(
- // (gpu) => gpu.worker_name === worker.worker_name
- // );
+ return subOrdinaryWorkers.map((worker) => {
+ const gpuData = Object.values(snapshot.gpus).filter(
+ (gpu) => gpu.worker_name === worker.worker_name
+ );
- // return {
- // ...worker,
- // isMain: false,
- // children: gpuData
- // };
- // });
- // }, [snapshot, mainWorker]);
+ return {
+ ...worker,
+ isMain: false,
+ children: gpuData
+ };
+ });
+ }, [snapshot, mainWorker]);
const GPUColumns = [
{
@@ -68,19 +70,26 @@ const Environment: React.FC = () => {
{value}
)
},
+ {
+ title: 'Index',
+ dataIndex: 'index',
+ key: 'index',
+ span: 4,
+ colStyle: { paddingLeft: 48 }
+ },
{
title: 'Vendor',
dataIndex: 'vendor',
key: 'vendor',
- span: 4,
- colStyle: { paddingLeft: 46 }
+ span: 6,
+ colStyle: { paddingLeft: 110 }
},
{
title: 'VRAM',
dataIndex: 'memory_total',
key: 'memory_total',
label: 'VRAM',
- span: 3,
+ span: 4,
render: (value: number, record: any) => convertFileSize(value)
},
{
@@ -88,20 +97,8 @@ const Environment: React.FC = () => {
dataIndex: 'core_total',
key: 'core_total',
label: 'Cores',
- span: 3
- },
- {
- title: 'Runtime Version',
- dataIndex: 'runtime_version',
- key: 'runtime_version',
- span: 4
- },
- {
- title: 'Driver Version',
- dataIndex: 'driver_version',
- key: 'driver_version',
span: 4,
- colStyle: { paddingLeft: 35 }
+ colStyle: { paddingLeft: 36 }
}
];
@@ -110,31 +107,56 @@ const Environment: React.FC = () => {
title: 'Worker Name',
dataIndex: 'name',
key: 'name',
- span: 6
+ span: 6,
+ render: (value: string, record: any) => {
+ return (
+ <>
+ {value}
+ {record.isMain && (
+
+ Main
+
+ )}
+ >
+ );
+ }
},
{
title: 'System',
dataIndex: 'os',
key: 'system',
- span: 4,
+ span: 5,
render: (os: { name: string; version: string }, record: any) => {
- return `${record.os.name}`;
+ return (
+ {`${record.os.name} (${record.os.version})`}
+ );
}
},
{
- title: 'Version',
- dataIndex: 'version',
- key: 'version',
- span: 6,
+ title: 'Runtime Version',
+ dataIndex: 'runtime_version',
+ key: 'runtime_version',
+ span: 3,
render: (val: any, record: any) => {
- return {record.os.version};
+ return {record.runtime_version};
+ }
+ },
+ {
+ title: 'Driver Version',
+ dataIndex: 'driver_version',
+ key: 'driver_version',
+ span: 3,
+ render: (val: any, record: any) => {
+ return {record.driver_version};
}
},
{
title: 'CPU Count',
dataIndex: 'cpu_total',
key: 'cpu_total',
- span: 4
+ span: 3
},
{
title: 'Memory',
@@ -146,8 +168,8 @@ const Environment: React.FC = () => {
];
const dataList = useMemo(() => {
- return [mainWorker];
- }, [mainWorker]);
+ return [mainWorker, ...subWorkers];
+ }, [mainWorker, subWorkers]);
const handleToggleExpandAll = useMemoizedFn((expanded: boolean) => {
const keys = dataList?.map((item) => item.id);
@@ -161,6 +183,29 @@ const Environment: React.FC = () => {
const renderChildren = useMemoizedFn((list: any[]) => {
return (
+
+ {GPUColumns.map((col) => (
+
+
+
+ {col.title}
+
+
+
+ ))}
+
{list.map((gpu) => (
@@ -174,14 +219,6 @@ const Environment: React.FC = () => {
flexDirection: 'column'
}}
>
-
- {col.title}
-
{col.render
? col.render((gpu as any)[col.dataIndex], gpu)
: (gpu as any)[col.dataIndex]}
diff --git a/src/pages/benchmark/components/summary/benchmark.tsx b/src/pages/benchmark/components/summary/benchmark.tsx
index b18b6bd5..f9b940fd 100644
--- a/src/pages/benchmark/components/summary/benchmark.tsx
+++ b/src/pages/benchmark/components/summary/benchmark.tsx
@@ -1,7 +1,7 @@
import { Descriptions, DescriptionsProps } from 'antd';
import React from 'react';
import { useDetailContext } from '../../config/detail-context';
-import Section from './section';
+import Title from './title';
const Benchmark: React.FC = () => {
const { detailData } = useDetailContext();
@@ -19,7 +19,7 @@ const Benchmark: React.FC = () => {
},
{
key: '3',
- label: 'Token Length (Prompt/Out)',
+ label: 'Token Length (Prompt/Output)',
children: (
{detailData?.dataset_prompt_tokens || '-'} /{' '}
@@ -45,19 +45,19 @@ const Benchmark: React.FC = () => {
];
return (
-
+
+
Parameters
-
+
);
};
diff --git a/src/pages/benchmark/components/summary/index.tsx b/src/pages/benchmark/components/summary/index.tsx
index 816ff6cc..59d10078 100644
--- a/src/pages/benchmark/components/summary/index.tsx
+++ b/src/pages/benchmark/components/summary/index.tsx
@@ -1,9 +1,11 @@
+import { Divider } from 'antd';
import React from 'react';
import styled from 'styled-components';
import BenchMark from './benchmark';
import Instance from './instance';
import MetricsResult from './metrics-result';
import PercentileResult from './percentile-result';
+import Section from './section';
const Container = styled.div`
display: flex;
@@ -14,10 +16,16 @@ const Container = styled.div`
const Summary: React.FC = () => {
return (
-
-
-
-
+
+
);
};
diff --git a/src/pages/benchmark/components/summary/instance.tsx b/src/pages/benchmark/components/summary/instance.tsx
index 49bf4c5c..31a23687 100644
--- a/src/pages/benchmark/components/summary/instance.tsx
+++ b/src/pages/benchmark/components/summary/instance.tsx
@@ -1,8 +1,9 @@
+import AutoTooltip from '@/components/auto-tooltip';
import { Descriptions, Flex, Tag } from 'antd';
import _ from 'lodash';
import React, { useMemo } from 'react';
import { useDetailContext } from '../../config/detail-context';
-import Section from './section';
+import Title from './title';
const calcTotalVram = (vram: Record) => {
return _.sum(_.values(vram));
@@ -10,6 +11,8 @@ const calcTotalVram = (vram: Record) => {
const Instance: React.FC = () => {
const { detailData } = useDetailContext();
+ const [, instanceData] =
+ Object.entries(detailData?.snapshot?.instances || {})[0] || [];
const items = useMemo(() => {
const { snapshot } = detailData;
@@ -18,25 +21,21 @@ const Instance: React.FC = () => {
return [
{
key: '1',
- label: 'Instance Name',
+ label: 'Model Name',
children: (
-
-
- {detailData?.model_name}/{detailData?.model_instance_name}
-
-
+ {detailData?.model_name || '-'}
)
},
{
key: '2',
- label: 'Worker',
- children: instanceData?.worker_name || '-'
- },
- {
- key: '6',
- label: 'GPU Type',
- children: instanceData?.gpu_type || '-'
+ label: 'Instance Name',
+ children: (
+
+ {detailData?.model_instance_name || '-'}
+
+ )
},
+
{
key: '5',
label: 'Backend',
@@ -45,6 +44,13 @@ const Instance: React.FC = () => {
? `(${instanceData?.backend_version})`
: ''
}`
+ },
+ {
+ key: '6',
+ label: 'Model File',
+ children: (
+ {instanceData?.resolved_path || '-'}
+ )
}
];
}, [detailData]);
@@ -144,7 +150,8 @@ const Instance: React.FC = () => {
}, [detailData]);
return (
-
+
+
Instance
{
}
}}
>
-
+
);
};
diff --git a/src/pages/benchmark/components/summary/metrics-result.tsx b/src/pages/benchmark/components/summary/metrics-result.tsx
index ba313909..f1d5bc15 100644
--- a/src/pages/benchmark/components/summary/metrics-result.tsx
+++ b/src/pages/benchmark/components/summary/metrics-result.tsx
@@ -1,25 +1,46 @@
import { Descriptions } from 'antd';
import _, { round } from 'lodash';
import React from 'react';
+import styled from 'styled-components';
import { useDetailContext } from '../../config/detail-context';
-import Section from './section';
+import Title from './title';
+
+const Card = styled.div`
+ height: 78px;
+ padding: 12px 16px;
+ border: 1px solid var(--ant-color-border);
+ border-radius: var(--ant-border-radius);
+ background-color: var(--ant-color-bg-container);
+`;
+
+const Box = styled.div`
+ display: grid;
+ grid-template-columns: 1fr 1fr 1fr;
+ gap: 16px;
+`;
+
+const DescWrapper = styled.div`
+ display: grid;
+ grid-template-columns: 1fr 1fr 1fr;
+ gap: 24px;
+`;
const columns = [
- {
- title: 'Duration (s)',
- dataIndex: 'duration',
- path: ['raw_metrics', 'benchmarks', '0', 'duration'],
- unit: 's',
- render: (value: number) => round(value, 2)
- },
+ // {
+ // title: 'Duration',
+ // dataIndex: 'duration',
+ // path: ['raw_metrics', 'benchmarks', '0', 'duration'],
+ // unit: 's',
+ // render: (value: number) => round(value, 2)
+ // },
- {
- title: 'Total Requests',
- dataIndex: 'total_requests',
- path: 'total_requests',
- unit: '',
- render: (value: number) => round(value, 0)
- },
+ // {
+ // title: 'Total Requests',
+ // dataIndex: 'total_requests',
+ // path: 'total_requests',
+ // unit: '',
+ // render: (value: number) => round(value, 0)
+ // },
{
title: 'Total token throughput',
dataIndex: 'tokens_per_second_mean',
@@ -28,18 +49,25 @@ const columns = [
render: (value: number) => round(value, 2)
},
{
- title: 'Success Requests',
- dataIndex: 'successful_requests',
- path: ['raw_metrics', 'benchmarks', '0'],
- unit: '',
- render: (value: number) => {
- return (
-
- {_.get(value, 'metrics.request_totals.successful')}
-
- );
- }
+ title: 'Prompt token throughput ',
+ dataIndex: 'prompt_tokens_per_second_mean',
+ path: 'prompt_tokens_per_second_mean',
+ unit: 'Tokens/s',
+ render: (value: number) => round(value, 2)
},
+ // {
+ // title: 'Success Requests',
+ // dataIndex: 'successful_requests',
+ // path: ['raw_metrics', 'benchmarks', '0'],
+ // unit: '',
+ // render: (value: number) => {
+ // return (
+ //
+ // {_.get(value, 'metrics.request_totals.successful')}
+ //
+ // );
+ // }
+ // },
{
title: 'Output token throughput',
@@ -51,65 +79,103 @@ const columns = [
];
const columnsSub = [
+ // {
+ // title: 'Failed Requests',
+ // dataIndex: 'failed_requests',
+ // path: ['raw_metrics', 'benchmarks', '0'],
+ // unit: '',
+ // render: (value: number) => {
+ // return (
+ //
+ // {_.get(value, 'metrics.request_totals.errored')}
+ //
+ // );
+ // }
+ // },
+ // {
+ // title: 'Concurrency',
+ // dataIndex: 'request_concurrency',
+ // path: ['raw_metrics', 'benchmarks', '0'],
+ // unit: '',
+ // render: (value: number) => {
+ // return round(
+ // _.get(value, 'metrics.request_concurrency.successful.mean'),
+ // 0
+ // );
+ // }
+ // },
+
{
- title: 'Failed Requests',
- dataIndex: 'failed_requests',
- path: ['raw_metrics', 'benchmarks', '0'],
- unit: '',
- render: (value: number) => {
- return (
-
- {_.get(value, 'metrics.request_totals.errored')}
-
- );
- }
- },
- {
- title: 'Concurrency',
- dataIndex: 'request_concurrency',
- path: ['raw_metrics', 'benchmarks', '0'],
- unit: '',
- render: (value: number) => {
- return round(
- _.get(value, 'metrics.request_concurrency.successful.mean'),
- 0
- );
- }
- },
- {
- title: 'Request token throughput ',
- dataIndex: 'prompt_tokens_per_second_mean',
- path: 'prompt_tokens_per_second_mean',
- unit: 'Tokens/s',
- render: (value: number) => round(value, 2)
- },
- {
- title: 'Average Request Latency (ms)',
+ title: 'Average Request Latency',
dataIndex: 'request_latency_mean',
path: 'request_latency_mean',
unit: 'ms',
render: (value: number) => round(value, 2)
},
{
- title: 'Average Time To First Token (ms)',
+ title: 'Average Time To First Token',
dataIndex: 'time_to_first_token_mean',
path: 'time_to_first_token_mean',
unit: 'ms',
render: (value: number) => round(value, 2)
},
{
- title: 'Average Time Per Output Token (ms)',
+ title: 'Average Time Per Output Token',
dataIndex: 'time_per_output_token_mean',
path: 'time_per_output_token_mean',
unit: 'ms',
render: (value: number) => round(value, 2)
},
{
- title: '',
- dataIndex: '',
- path: '',
- unit: '',
- render: (_: number) => ''
+ title: 'Average Inter Token Latency',
+ dataIndex: 'inter_token_latency_mean',
+ path: 'inter_token_latency_mean',
+ unit: 'ms',
+ render: (value: number) => round(value, 2)
+ }
+];
+
+const requestFields = [
+ {
+ label: 'Total Requests',
+ key: 'total_requests',
+ dataIndex: 'total_requests',
+ path: 'total_requests',
+ precision: 0,
+ render: (value: number) => round(value, 0),
+ unit: ''
+ },
+ {
+ label: 'Success Requests',
+ key: 'total_requests',
+ dataIndex: 'successful_requests',
+ path: ['raw_metrics', 'benchmarks', '0'],
+ render: (value: number) =>
+ round(_.get(value, ['metrics', 'request_totals', 'successful']), 0),
+ precision: 0,
+ color: 'var(--ant-color-success)',
+ unit: ''
+ },
+ {
+ label: 'Failed Requests',
+ key: 'total_requests',
+ dataIndex: 'failed_requests',
+ path: ['raw_metrics', 'benchmarks', '0'],
+ render: (value: number) =>
+ round(_.get(value, ['metrics', 'request_totals', 'errored']), 0),
+ precision: 0,
+ color: 'var(--ant-color-error)',
+ unit: ''
+ },
+ {
+ label: 'Concurrency',
+ key: 'request_concurrency',
+ dataIndex: 'request_concurrency',
+ path: ['raw_metrics', 'benchmarks', '0'],
+ render: (value: number) =>
+ round(_.get(value, 'metrics.request_concurrency.successful.mean'), 0),
+ precision: 0,
+ unit: ''
}
];
@@ -148,39 +214,94 @@ const PercentileResult: React.FC = () => {
})
);
+ const throughputItems = columns.map(
+ ({ title, dataIndex, path, render, unit }) => ({
+ key: dataIndex,
+ label: title,
+ children: unit ? (
+
+ {render(_.get(detailData, path) ?? 0)}{' '}
+ ({unit})
+
+ ) : (
+ render(_.get(detailData, path) ?? 0)
+ )
+ })
+ );
+
+ const latencyItems = columnsSub.map(
+ ({ title, dataIndex, path, render, unit }) => ({
+ key: dataIndex,
+ label: title,
+ children: unit ? (
+
+ {render(_.get(detailData, path) ?? 0)}{' '}
+ ({unit})
+
+ ) : (
+ render(_.get(detailData, path) ?? 0)
+ )
+ })
+ );
+
+ const requestItems = requestFields.map(
+ ({ label, dataIndex, path, render, unit, color }) => ({
+ key: dataIndex,
+ label: label,
+ children: unit ? (
+
+ {render(_.get(detailData, path) ?? 0)}{' '}
+ ({unit})
+
+ ) : (
+
+ {render(_.get(detailData, path) ?? 0)}
+
+ )
+ })
+ );
+
+ const descriptionStyles = {
+ header: {
+ marginBottom: 8
+ },
+ title: {
+ fontWeight: 500,
+ color: 'var(--ant-color-text-secondary)',
+ fontSize: 14
+ },
+ content: {
+ justifyContent: 'flex-start'
+ }
+ };
+
return (
-
+
+
Metrics
+
+
+
+
+
+
);
};
diff --git a/src/pages/benchmark/components/summary/percentile-result.tsx b/src/pages/benchmark/components/summary/percentile-result.tsx
index 93505327..0b1b64e3 100644
--- a/src/pages/benchmark/components/summary/percentile-result.tsx
+++ b/src/pages/benchmark/components/summary/percentile-result.tsx
@@ -2,7 +2,7 @@ import { Table } from 'antd';
import { round } from 'lodash';
import React from 'react';
import { useDetailContext } from '../../config/detail-context';
-import Section from './section';
+import Title from './title';
const columns = [
{
@@ -76,13 +76,17 @@ const PercentileResult: React.FC = () => {
};
return (
-
+
+
Percentile
(
+ {value}
+ )
},
...columns
]}
@@ -90,17 +94,15 @@ const PercentileResult: React.FC = () => {
rowKey="percentile"
pagination={false}
styles={{
- // header: {
- // row: {
- // background: 'none',
- // borderBottom: '1px solid var(--ant-color-split)'
- // },
- // cell: {
- // background: 'none',
- // paddingBottom: 0,
- // borderBottom: '1px solid var(--ant-color-split)'
- // }
- // },
+ header: {
+ row: {
+ backgroundColor: 'transparent'
+ },
+ cell: {
+ fontWeight: 400,
+ borderBottom: '1px solid var(--ant-color-split)'
+ }
+ },
body: {
cell: {
height: 54
@@ -108,7 +110,7 @@ const PercentileResult: React.FC = () => {
}
}}
>
-
+
);
};
diff --git a/src/pages/benchmark/components/summary/title.tsx b/src/pages/benchmark/components/summary/title.tsx
new file mode 100644
index 00000000..4e4f5dad
--- /dev/null
+++ b/src/pages/benchmark/components/summary/title.tsx
@@ -0,0 +1,21 @@
+import { BulbOutlined } from '@ant-design/icons';
+import styled from 'styled-components';
+
+const Content = styled.div`
+ font-weight: 500;
+ font-size: 14px;
+ margin-bottom: 16px;
+`;
+
+const Title: React.FC<{ children: React.ReactNode }> = ({ children }) => {
+ return (
+
+
+ {children}
+
+ );
+};
+
+export default Title;
diff --git a/src/pages/benchmark/config/index.ts b/src/pages/benchmark/config/index.ts
index 2c5bbcea..f3155ffb 100644
--- a/src/pages/benchmark/config/index.ts
+++ b/src/pages/benchmark/config/index.ts
@@ -7,6 +7,7 @@ export const BenchmarkStatusValueMap = {
Running: 'running',
Completed: 'completed',
Error: 'error',
+ Stopped: 'stopped',
Unreachable: 'unreachable'
};
@@ -16,6 +17,7 @@ export const BenchmarkStatusLabelMap = {
[BenchmarkStatusValueMap.Running]: 'Running',
[BenchmarkStatusValueMap.Completed]: 'Completed',
[BenchmarkStatusValueMap.Error]: 'Error',
+ [BenchmarkStatusValueMap.Stopped]: 'Stopped',
[BenchmarkStatusValueMap.Unreachable]: 'Unreachable'
};
@@ -25,7 +27,8 @@ export const BenchmarkStatus: Record = {
[BenchmarkStatusValueMap.Running]: StatusMaps.success,
[BenchmarkStatusValueMap.Completed]: StatusMaps.success,
[BenchmarkStatusValueMap.Error]: StatusMaps.error,
- [BenchmarkStatusValueMap.Unreachable]: StatusMaps.error
+ [BenchmarkStatusValueMap.Unreachable]: StatusMaps.error,
+ [BenchmarkStatusValueMap.Stopped]: StatusMaps.warning
};
export const ProfileValueMap = {
diff --git a/src/pages/benchmark/config/types.ts b/src/pages/benchmark/config/types.ts
index bdd5b1e5..0654ea0d 100644
--- a/src/pages/benchmark/config/types.ts
+++ b/src/pages/benchmark/config/types.ts
@@ -91,6 +91,7 @@ export interface BenchmarkListItem extends FormData {
updated_at: string;
state: string;
state_message: string;
+ progress: number;
instance_snapshot: InstanceSnapshot;
gpu_snapshot: GPUSnapshot[];
}
diff --git a/src/pages/benchmark/forms/basic.tsx b/src/pages/benchmark/forms/basic.tsx
index 7addb16e..513e5f10 100644
--- a/src/pages/benchmark/forms/basic.tsx
+++ b/src/pages/benchmark/forms/basic.tsx
@@ -77,6 +77,7 @@ const BasicForm: React.FC = () => {
]}
>
{
hidden name="dataset_id">
- {profile === 'Custom' && (
-
- )}
+
>
);
};
diff --git a/src/pages/benchmark/forms/index.tsx b/src/pages/benchmark/forms/index.tsx
index 20ff6b40..061fb728 100644
--- a/src/pages/benchmark/forms/index.tsx
+++ b/src/pages/benchmark/forms/index.tsx
@@ -17,7 +17,6 @@ import FormContext from '../config/form-context';
import { FormData, BenchmarkListItem as ListItem } from '../config/types';
import Basic from './basic';
import DatasetForm from './dataset';
-import RandomSettingsForm from './random-settings';
interface ProviderFormProps {
ref?: any;
@@ -90,16 +89,16 @@ const ProviderForm: React.FC = forwardRef((props, ref) => {
}
}, [showAdvanced, activeKey]);
- const advancedItems = showAdvanced
- ? [
- {
- key: TABKeysMap.ADVANCED,
- label: intl.formatMessage({ id: 'resources.form.advanced' }),
- forceRender: true,
- children:
- }
- ]
- : [];
+ // const advancedItems = showAdvanced
+ // ? [
+ // {
+ // key: TABKeysMap.ADVANCED,
+ // label: intl.formatMessage({ id: 'resources.form.advanced' }),
+ // forceRender: true,
+ // children:
+ // }
+ // ]
+ // : [];
console.log('render form with profile:', showAdvanced);
@@ -144,8 +143,7 @@ const ProviderForm: React.FC = forwardRef((props, ref) => {
label: intl.formatMessage({ id: 'common.title.config' }),
forceRender: true,
children:
- },
- ...advancedItems
+ }
]}
>
diff --git a/src/pages/benchmark/hooks/use-benchmark-columns.tsx b/src/pages/benchmark/hooks/use-benchmark-columns.tsx
index 00f18ad6..442e1f7f 100644
--- a/src/pages/benchmark/hooks/use-benchmark-columns.tsx
+++ b/src/pages/benchmark/hooks/use-benchmark-columns.tsx
@@ -3,7 +3,7 @@ import AutoTooltip from '@/components/auto-tooltip';
import StatusTag from '@/components/status-tag';
import { tableSorter } from '@/config/settings';
import { useIntl } from '@umijs/max';
-import { Typography } from 'antd';
+import { Progress, Typography } from 'antd';
import { ColumnsType } from 'antd/es/table';
import _ from 'lodash';
import { useMemo } from 'react';
@@ -58,15 +58,24 @@ const useBenchmarkColumns = (
ellipsis: {
showTitle: false
},
- width: 100,
+ width: 120,
render: (value: number, record: ListItem) => (
-
+
+
+ {record.progress !== undefined && record.progress < 100 && (
+
+ )}
+
)
},
// {
diff --git a/src/pages/benchmark/index.tsx b/src/pages/benchmark/index.tsx
index 4e24dce1..7c4f5728 100644
--- a/src/pages/benchmark/index.tsx
+++ b/src/pages/benchmark/index.tsx
@@ -27,8 +27,8 @@ 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 useViewLogs from './hooks/use-view-logs';
+import { useExportBenchmark } from './services/use-export-benchmark';
import useQueryDataset from './services/use-query-dataset';
const Benchmark: React.FC = () => {
@@ -65,6 +65,7 @@ const Benchmark: React.FC = () => {
const { SettingsButton, selectedColumns } = useColumnSettings();
const { datasetList, fetchDatasetData } = useQueryDataset();
+ const { exportData } = useExportBenchmark();
useEffect(() => {
fetchModelList({ page: -1 });
@@ -154,13 +155,8 @@ 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);
+ exportData(rowSelection.selectedRowKeys);
};
return (
diff --git a/src/pages/benchmark/services/use-export-benchmark.ts b/src/pages/benchmark/services/use-export-benchmark.ts
new file mode 100644
index 00000000..dd066a02
--- /dev/null
+++ b/src/pages/benchmark/services/use-export-benchmark.ts
@@ -0,0 +1,45 @@
+import { GPUSTACK_API_BASE_URL } from '@/config/settings';
+import { downloadFile } from '@/utils/download-stream';
+import { message } from 'antd';
+import { EXPORT_BENCHMARK_LIST } from '../apis';
+
+const matchFilename = (disposition: string | null): string | undefined => {
+ if (!disposition) return '';
+
+ const match = disposition.match(/filename="?([^"]+)"?/);
+ const filename = match ? match[1] : '';
+ return filename;
+};
+
+export function useExportBenchmark() {
+ const exportData = async (data: any[]) => {
+ try {
+ const res = await fetch(
+ `${GPUSTACK_API_BASE_URL}${EXPORT_BENCHMARK_LIST}`,
+ {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json'
+ },
+ body: JSON.stringify(data)
+ }
+ );
+ // header
+ const contentDispostion = res.headers.get('content-Disposition');
+ const filename =
+ matchFilename(contentDispostion) || `benchmark-export.yml`;
+ if (res.ok) {
+ const blob = await res.blob();
+ downloadFile(blob, filename);
+ } else {
+ message.error('Download failed');
+ }
+ } catch (error) {
+ message.error('Download failed');
+ }
+ };
+
+ return {
+ exportData
+ };
+}
diff --git a/src/pages/login/components/local-user-form.tsx b/src/pages/login/components/local-user-form.tsx
index ed35920f..edd919c2 100644
--- a/src/pages/login/components/local-user-form.tsx
+++ b/src/pages/login/components/local-user-form.tsx
@@ -36,6 +36,7 @@ const useStyles = createStyles(({ token, css }) => {
interface LocalUserFormProps {
handleLogin: (values: any) => void;
form: FormInstance;
+ loading?: boolean;
loginOption: {
saml: boolean;
oidc: boolean;
@@ -144,6 +145,7 @@ const LocalUserForm: React.FC = (props) => {
htmlType="submit"
type="primary"
block
+ loading={props.loading}
style={{ height: '48px', fontSize: '14px' }}
>
{intl.formatMessage({ id: 'common.button.login' })}
diff --git a/src/pages/login/components/login-form.tsx b/src/pages/login/components/login-form.tsx
index ed4d6144..ac3cde04 100644
--- a/src/pages/login/components/login-form.tsx
+++ b/src/pages/login/components/login-form.tsx
@@ -148,7 +148,7 @@ const LoginForm = () => {
};
// local user authentication
- const { handleLogin } = useLocalAuth({
+ const { handleLogin, submitLoading } = useLocalAuth({
fetchUserInfo,
form,
onSuccess: async (userInfo) => {
@@ -254,6 +254,7 @@ const LoginForm = () => {
)}
diff --git a/src/pages/login/hooks/use-local-auth.ts b/src/pages/login/hooks/use-local-auth.ts
index d6fa3412..58e9794b 100644
--- a/src/pages/login/hooks/use-local-auth.ts
+++ b/src/pages/login/hooks/use-local-auth.ts
@@ -10,7 +10,7 @@ import {
import { FormInstance } from 'antd';
import CryptoJS from 'crypto-js';
import { useAtom } from 'jotai';
-import { useEffect } from 'react';
+import { useEffect, useState } from 'react';
import { login } from '../apis';
interface UseLocalAuthOptions {
@@ -27,6 +27,7 @@ export const useLocalAuth = ({
form
}: UseLocalAuthOptions) => {
const [initialPassword, setInitialPassword] = useAtom(initialPasswordAtom);
+ const [submitLoading, setSubmitLoading] = useState(false);
// Encrypt password before storing
const encryptPassword = (password: string) => {
@@ -66,6 +67,7 @@ export const useLocalAuth = ({
// click login button
const handleLogin = async (values: any) => {
+ setSubmitLoading(true);
try {
await login({
username: values.username,
@@ -86,6 +88,8 @@ export const useLocalAuth = ({
onSuccess?.(userInfo);
} catch (error: any) {
onError?.(error);
+ } finally {
+ setSubmitLoading(false);
}
};
@@ -94,6 +98,7 @@ export const useLocalAuth = ({
}, []);
return {
- handleLogin
+ handleLogin,
+ submitLoading
};
};