chore: remove test dir
This commit is contained in:
@@ -1,7 +0,0 @@
|
|||||||
import { request } from '@umijs/max';
|
|
||||||
|
|
||||||
export const DASHBOARD_API = '/dashboard';
|
|
||||||
|
|
||||||
export async function queryDashboardData() {
|
|
||||||
return request(DASHBOARD_API);
|
|
||||||
}
|
|
||||||
@@ -1,136 +0,0 @@
|
|||||||
import PageTools from '@/components/page-tools';
|
|
||||||
import { convertFileSize } from '@/utils';
|
|
||||||
import { useIntl } from '@umijs/max';
|
|
||||||
import { Col, Row, Table } from 'antd';
|
|
||||||
import { useContext } from 'react';
|
|
||||||
import { DashboardContext } from '../config/dashboard-context';
|
|
||||||
|
|
||||||
const projectColumns = [
|
|
||||||
{
|
|
||||||
title: 'Name',
|
|
||||||
dataIndex: 'name',
|
|
||||||
key: 'name'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Token Quota',
|
|
||||||
dataIndex: 'quota',
|
|
||||||
key: 'quota',
|
|
||||||
render: (text: any, record: any) => <span>{record.quota}k</span>
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Token Utilization',
|
|
||||||
dataIndex: 'utilization',
|
|
||||||
key: 'utilization',
|
|
||||||
render: (text: any, record: any) => <span>{record.utilization}%</span>
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Members',
|
|
||||||
dataIndex: 'members',
|
|
||||||
key: 'members'
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
const projectData = [
|
|
||||||
{
|
|
||||||
id: 1,
|
|
||||||
name: 'copilot-dev',
|
|
||||||
quota: 100,
|
|
||||||
utilization: 50,
|
|
||||||
members: 4
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 2,
|
|
||||||
name: 'rag-wiki',
|
|
||||||
quota: 200,
|
|
||||||
utilization: 70,
|
|
||||||
members: 3
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 3,
|
|
||||||
name: 'smart-auto-agent',
|
|
||||||
quota: 100,
|
|
||||||
utilization: 20,
|
|
||||||
members: 5
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 4,
|
|
||||||
name: 'office-auto-docs',
|
|
||||||
quota: 100,
|
|
||||||
utilization: 25,
|
|
||||||
members: 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 5,
|
|
||||||
name: 'smart-customer-service',
|
|
||||||
quota: 100,
|
|
||||||
utilization: 46,
|
|
||||||
members: 2
|
|
||||||
}
|
|
||||||
];
|
|
||||||
const ActiveTable = () => {
|
|
||||||
const intl = useIntl();
|
|
||||||
const data = useContext(DashboardContext).active_models || [];
|
|
||||||
const modelColumns = [
|
|
||||||
{
|
|
||||||
title: intl.formatMessage({ id: 'common.table.name' }),
|
|
||||||
dataIndex: 'name',
|
|
||||||
key: 'name'
|
|
||||||
},
|
|
||||||
// {
|
|
||||||
// title: intl.formatMessage({ id: 'dashboard.gpuutilization' }),
|
|
||||||
// dataIndex: 'gpu_utilization',
|
|
||||||
// key: 'gpu_utilization',
|
|
||||||
// render: (text: any, record: any) => (
|
|
||||||
// <ProgressBar percent={_.round(text, 0)}></ProgressBar>
|
|
||||||
// )
|
|
||||||
// },
|
|
||||||
{
|
|
||||||
title: intl.formatMessage({ id: 'dashboard.allocatevram' }),
|
|
||||||
dataIndex: 'resource_claim.memory',
|
|
||||||
key: 'vram',
|
|
||||||
render: (text: any, record: any) => {
|
|
||||||
return (
|
|
||||||
<span>
|
|
||||||
{convertFileSize(record.resource_claim?.vram || 0)} /{' '}
|
|
||||||
{convertFileSize(record.resource_claim?.ram || 0)}
|
|
||||||
</span>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: intl.formatMessage({ id: 'models.form.replicas' }),
|
|
||||||
dataIndex: 'instance_count',
|
|
||||||
key: 'instance_count'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: intl.formatMessage({ id: 'dashboard.tokens' }),
|
|
||||||
dataIndex: 'token_count',
|
|
||||||
key: 'token_count'
|
|
||||||
}
|
|
||||||
];
|
|
||||||
return (
|
|
||||||
<Row gutter={[20, 0]}>
|
|
||||||
<Col xs={24} sm={24} md={24} lg={24} xl={24}>
|
|
||||||
<PageTools
|
|
||||||
style={{ margin: '26px 0px' }}
|
|
||||||
left={
|
|
||||||
<span style={{ padding: '9px 0' }}>
|
|
||||||
{intl.formatMessage({ id: 'dashboard.activeModels' })}
|
|
||||||
</span>
|
|
||||||
}
|
|
||||||
right={false}
|
|
||||||
/>
|
|
||||||
<div>
|
|
||||||
<Table
|
|
||||||
columns={modelColumns}
|
|
||||||
dataSource={data}
|
|
||||||
pagination={false}
|
|
||||||
rowKey="id"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</Col>
|
|
||||||
</Row>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default ActiveTable;
|
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
import PageTools from '@/components/page-tools';
|
|
||||||
import BaseSelect from '@/components/seal-form/base/select';
|
|
||||||
import { SyncOutlined } from '@ant-design/icons';
|
|
||||||
import { useIntl } from '@umijs/max';
|
|
||||||
import { Button, Input, Space } from 'antd';
|
|
||||||
import { memo, useCallback, useEffect, useState } from 'react';
|
|
||||||
import { queryDashboardData } from '../apis';
|
|
||||||
import DashboardContext from '../config/dashboard-context';
|
|
||||||
import { DashboardProps } from '../config/types';
|
|
||||||
import ActiveTable from './active-table';
|
|
||||||
import Overview from './over-view';
|
|
||||||
import Usage from './usage';
|
|
||||||
|
|
||||||
const Page: React.FC<{ setLoading: (loading: boolean) => void }> = ({
|
|
||||||
setLoading
|
|
||||||
}) => {
|
|
||||||
const intl = useIntl();
|
|
||||||
const [data, setData] = useState<DashboardProps>({} as DashboardProps);
|
|
||||||
|
|
||||||
const getDashboardData = useCallback(async () => {
|
|
||||||
try {
|
|
||||||
setLoading(true);
|
|
||||||
const res = await queryDashboardData();
|
|
||||||
setData(res);
|
|
||||||
setLoading(false);
|
|
||||||
} catch (error) {
|
|
||||||
setLoading(false);
|
|
||||||
setData({} as DashboardProps);
|
|
||||||
}
|
|
||||||
}, []);
|
|
||||||
useEffect(() => {
|
|
||||||
getDashboardData();
|
|
||||||
}, []);
|
|
||||||
return (
|
|
||||||
<DashboardContext.Provider value={{ ...data, fetchData: getDashboardData }}>
|
|
||||||
<Overview></Overview>
|
|
||||||
<PageTools
|
|
||||||
left={
|
|
||||||
<Space>
|
|
||||||
<Input
|
|
||||||
placeholder={intl.formatMessage({ id: 'usage.filter.user' })}
|
|
||||||
style={{ width: 200 }}
|
|
||||||
allowClear
|
|
||||||
></Input>
|
|
||||||
<BaseSelect
|
|
||||||
style={{ width: 300 }}
|
|
||||||
placeholder={intl.formatMessage({ id: 'usage.filter.model' })}
|
|
||||||
></BaseSelect>
|
|
||||||
<Button
|
|
||||||
type="text"
|
|
||||||
style={{ color: 'var(--ant-color-text-tertiary)' }}
|
|
||||||
icon={<SyncOutlined></SyncOutlined>}
|
|
||||||
></Button>
|
|
||||||
</Space>
|
|
||||||
}
|
|
||||||
></PageTools>
|
|
||||||
<Usage></Usage>
|
|
||||||
<ActiveTable></ActiveTable>
|
|
||||||
</DashboardContext.Provider>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default memo(Page);
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
:local(.card-body) {
|
|
||||||
box-shadow: none !important;
|
|
||||||
|
|
||||||
:global(.ant-card-body) {
|
|
||||||
height: 110px;
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-around;
|
|
||||||
border-radius: var(--ant-border-radius-lg);
|
|
||||||
border: 1px solid var(--ant-color-border);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
:local(.row) {
|
|
||||||
:global(.ant-col-5) {
|
|
||||||
flex: 0 0 20%;
|
|
||||||
max-width: 20%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.content {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
@@ -1,77 +0,0 @@
|
|||||||
import { useIntl } from '@umijs/max';
|
|
||||||
import { Card, Col, Row, Space } from 'antd';
|
|
||||||
import _ from 'lodash';
|
|
||||||
import React, { useContext } from 'react';
|
|
||||||
import { overviewConfigs } from '../config';
|
|
||||||
import { DashboardContext } from '../config/dashboard-context';
|
|
||||||
import '../styles/index.less';
|
|
||||||
import styles from './over-view.less';
|
|
||||||
|
|
||||||
const renderCardItem = (data: {
|
|
||||||
label: string;
|
|
||||||
value: React.ReactNode;
|
|
||||||
bgColor: string;
|
|
||||||
}) => {
|
|
||||||
const { label, value, bgColor } = data;
|
|
||||||
return (
|
|
||||||
<Card
|
|
||||||
variant="borderless"
|
|
||||||
style={{ background: bgColor }}
|
|
||||||
className={styles['card-body']}
|
|
||||||
>
|
|
||||||
<div className={styles.content}>
|
|
||||||
<div className="label">{label}</div>
|
|
||||||
<div className="value">{value}</div>
|
|
||||||
</div>
|
|
||||||
</Card>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
const Overview: React.FC = () => {
|
|
||||||
const intl = useIntl();
|
|
||||||
const data = useContext(DashboardContext).resource_counts || {};
|
|
||||||
console.log('overview===');
|
|
||||||
const renderValue = (
|
|
||||||
value:
|
|
||||||
| number
|
|
||||||
| {
|
|
||||||
healthy: number;
|
|
||||||
warning: number;
|
|
||||||
error: number;
|
|
||||||
}
|
|
||||||
) => {
|
|
||||||
if (typeof value === 'number') {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<Space className="value-box" size={20}>
|
|
||||||
<span className={'value-healthy'}>{value.healthy}</span>
|
|
||||||
<span className={'value-warning'}>{value.warning}</span>
|
|
||||||
<span className={'value-error'}>{value.error}</span>
|
|
||||||
</Space>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<Row gutter={[24, 20]} className={styles.row}>
|
|
||||||
{overviewConfigs.map((config, index) => (
|
|
||||||
<Col
|
|
||||||
xs={{ flex: '100%' }}
|
|
||||||
sm={{ flex: '50%' }}
|
|
||||||
md={{ flex: '50%' }}
|
|
||||||
lg={{ flex: '25%' }}
|
|
||||||
xl={{ flex: '25%' }}
|
|
||||||
key={config.key}
|
|
||||||
>
|
|
||||||
{renderCardItem({
|
|
||||||
label: intl.formatMessage({ id: config.label }),
|
|
||||||
value: renderValue(_.get(data, config.key, 0)),
|
|
||||||
bgColor: config.backgroundColor
|
|
||||||
})}
|
|
||||||
</Col>
|
|
||||||
))}
|
|
||||||
</Row>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Overview;
|
|
||||||
@@ -1,168 +0,0 @@
|
|||||||
import LineChart from '@/components/echarts/line-chart';
|
|
||||||
import { useIntl } from '@umijs/max';
|
|
||||||
import dayjs from 'dayjs';
|
|
||||||
import _ from 'lodash';
|
|
||||||
import { memo, useContext, useMemo } from 'react';
|
|
||||||
import { DashboardContext } from '../config/dashboard-context';
|
|
||||||
|
|
||||||
const chartColorMap = {
|
|
||||||
tickLineColor: 'rgba(217,217,217,0.5)',
|
|
||||||
axislabelColor: 'rgba(0, 0, 0, 0.4)'
|
|
||||||
};
|
|
||||||
|
|
||||||
const TypeKeyMap = {
|
|
||||||
cpu: {
|
|
||||||
label: 'CPU',
|
|
||||||
type: 'CPU',
|
|
||||||
intl: false,
|
|
||||||
color: 'rgba(250, 173, 20,.8)'
|
|
||||||
},
|
|
||||||
ram: {
|
|
||||||
label: 'dashboard.memory',
|
|
||||||
type: 'Memory',
|
|
||||||
intl: true,
|
|
||||||
color: 'rgba(114, 46, 209,.8)'
|
|
||||||
},
|
|
||||||
gpu: {
|
|
||||||
label: 'GPU',
|
|
||||||
type: 'GPU',
|
|
||||||
intl: false,
|
|
||||||
color: 'rgba(84, 204, 152,.8)'
|
|
||||||
},
|
|
||||||
vram: {
|
|
||||||
label: 'dashboard.vram',
|
|
||||||
type: 'VRAM',
|
|
||||||
intl: true,
|
|
||||||
color: 'rgba(255, 107, 179, 80%)'
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const option = {
|
|
||||||
title: {
|
|
||||||
text: ''
|
|
||||||
},
|
|
||||||
legend: {
|
|
||||||
itemWidth: 8,
|
|
||||||
itemHeight: 8,
|
|
||||||
data: []
|
|
||||||
},
|
|
||||||
grid: {
|
|
||||||
left: 0,
|
|
||||||
right: 20,
|
|
||||||
bottom: 20,
|
|
||||||
containLabel: true
|
|
||||||
},
|
|
||||||
tooltip: {
|
|
||||||
trigger: 'axis',
|
|
||||||
formatter(params: any) {
|
|
||||||
let result = `<span class="tooltip-x-name">${params[0].axisValue}</span>`;
|
|
||||||
params.forEach((item: any) => {
|
|
||||||
result += `<span class="tooltip-item">
|
|
||||||
<span class="tooltip-item-name">
|
|
||||||
<span style="display:inline-block;margin-right:5px;border-radius:8px;width:8px;height:8px;background-color:${item.color};"></span>
|
|
||||||
<span class="tooltip-title">${item.seriesName}</span>:
|
|
||||||
</span>
|
|
||||||
<span class="tooltip-value">${item.data.value}</span>
|
|
||||||
</span>`;
|
|
||||||
});
|
|
||||||
return `<div class="tooltip-wrapper">${result}</div>`;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
xAxis: {
|
|
||||||
type: 'category',
|
|
||||||
boundaryGap: true,
|
|
||||||
axisTick: {
|
|
||||||
show: true,
|
|
||||||
lineStyle: {
|
|
||||||
color: chartColorMap.tickLineColor
|
|
||||||
}
|
|
||||||
},
|
|
||||||
axisLabel: {
|
|
||||||
color: chartColorMap.axislabelColor,
|
|
||||||
// fontFamily: 'unset',
|
|
||||||
fontSize: 12
|
|
||||||
},
|
|
||||||
axisLine: {
|
|
||||||
show: false
|
|
||||||
},
|
|
||||||
data: []
|
|
||||||
},
|
|
||||||
yAxis: {
|
|
||||||
max: 100,
|
|
||||||
min: 0,
|
|
||||||
splitLine: {
|
|
||||||
show: true,
|
|
||||||
lineStyle: {
|
|
||||||
type: 'dashed'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
axisLabel: {
|
|
||||||
color: chartColorMap.axislabelColor,
|
|
||||||
// fontFamily: 'unset',
|
|
||||||
fontSize: 12
|
|
||||||
},
|
|
||||||
axisTick: {
|
|
||||||
show: false
|
|
||||||
},
|
|
||||||
type: 'value'
|
|
||||||
},
|
|
||||||
series: []
|
|
||||||
};
|
|
||||||
|
|
||||||
const UtilizationOvertime: React.FC = () => {
|
|
||||||
console.log('systemload=====================');
|
|
||||||
const intl = useIntl();
|
|
||||||
const data = useContext(DashboardContext)?.system_load?.history || {};
|
|
||||||
|
|
||||||
const typeList = ['gpu', 'cpu', 'ram', 'vram'];
|
|
||||||
|
|
||||||
const tooltipValueFormatter = (value: any) => {
|
|
||||||
return !value ? value : `${value}%`;
|
|
||||||
};
|
|
||||||
const generateData = useMemo(() => {
|
|
||||||
const legendData: string[] = [];
|
|
||||||
const xAxisData: string[] = [];
|
|
||||||
let seriesData: { value: number; time: string; type: string }[] = [];
|
|
||||||
seriesData = _.map(typeList, (item: string) => {
|
|
||||||
const itemConfig = _.get(TypeKeyMap, item, {});
|
|
||||||
const name = itemConfig.intl
|
|
||||||
? intl.formatMessage({ id: itemConfig.label })
|
|
||||||
: itemConfig.label;
|
|
||||||
legendData.push(name);
|
|
||||||
const itemDataList = _.get(data, item, []);
|
|
||||||
return {
|
|
||||||
name: name,
|
|
||||||
color: itemConfig.color,
|
|
||||||
data: _.map(itemDataList, (item: any) => {
|
|
||||||
xAxisData.push(dayjs(item.timestamp * 1000).format('HH:mm:ss'));
|
|
||||||
return {
|
|
||||||
time: dayjs(item.timestamp * 1000).format('HH:mm:ss'),
|
|
||||||
value: _.round(_.get(item, 'value', 0), 1)
|
|
||||||
};
|
|
||||||
})
|
|
||||||
};
|
|
||||||
});
|
|
||||||
return {
|
|
||||||
seriesData,
|
|
||||||
legendData,
|
|
||||||
xAxisData: _.uniq(xAxisData)
|
|
||||||
};
|
|
||||||
}, [data]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<LineChart
|
|
||||||
height={390}
|
|
||||||
seriesData={generateData.seriesData}
|
|
||||||
legendData={generateData.legendData}
|
|
||||||
xAxisData={generateData.xAxisData}
|
|
||||||
tooltipValueFormatter={tooltipValueFormatter}
|
|
||||||
smooth={true}
|
|
||||||
width="100%"
|
|
||||||
yAxisName="(%)"
|
|
||||||
></LineChart>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default memo(UtilizationOvertime);
|
|
||||||
@@ -1,119 +0,0 @@
|
|||||||
import CardWrapper from '@/components/card-wrapper';
|
|
||||||
import GaugeChart from '@/components/echarts/gauge';
|
|
||||||
import PageTools from '@/components/page-tools';
|
|
||||||
import breakpoints from '@/config/breakpoints';
|
|
||||||
import useWindowResize from '@/hooks/use-window-resize';
|
|
||||||
import { useIntl } from '@umijs/max';
|
|
||||||
import { Col, Row } from 'antd';
|
|
||||||
import dayjs from 'dayjs';
|
|
||||||
import _ from 'lodash';
|
|
||||||
import { useContext, useEffect, useState } from 'react';
|
|
||||||
import { DashboardContext } from '../config/dashboard-context';
|
|
||||||
import ResourceUtilization from './resource-utilization';
|
|
||||||
|
|
||||||
const strokeColorFunc = (percent: number) => {
|
|
||||||
if (percent <= 50) {
|
|
||||||
return 'rgb(84, 204, 152, 80%)';
|
|
||||||
}
|
|
||||||
if (percent <= 80) {
|
|
||||||
return 'rgba(250, 173, 20, 80%)';
|
|
||||||
}
|
|
||||||
return ' rgba(255, 77, 79, 80%)';
|
|
||||||
};
|
|
||||||
|
|
||||||
const SystemLoad = () => {
|
|
||||||
const intl = useIntl();
|
|
||||||
const data = useContext(DashboardContext)?.system_load?.current || {};
|
|
||||||
const { size } = useWindowResize();
|
|
||||||
const [paddingRight, setPaddingRight] = useState<string>('20px');
|
|
||||||
const [smallChartHeight, setSmallChartHeight] = useState<number>(190);
|
|
||||||
const [largeChartHeight, setLargeChartHeight] = useState<number>(400);
|
|
||||||
const thresholds = [0.5, 0.7, 1];
|
|
||||||
const height = 400;
|
|
||||||
const currentDate = dayjs().format('YYYY-MM-DD');
|
|
||||||
|
|
||||||
const handleSelectDate = (date: any) => {};
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (size.width < breakpoints.xl) {
|
|
||||||
setPaddingRight('0');
|
|
||||||
} else {
|
|
||||||
setPaddingRight('20px');
|
|
||||||
}
|
|
||||||
}, [size.width]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<div className="system-load">
|
|
||||||
<PageTools
|
|
||||||
style={{ margin: '26px 0px' }}
|
|
||||||
left={
|
|
||||||
<span>{intl.formatMessage({ id: 'dashboard.systemload' })}</span>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<Row style={{ width: '100%' }} gutter={[0, 20]}>
|
|
||||||
<Col
|
|
||||||
xs={24}
|
|
||||||
sm={24}
|
|
||||||
md={24}
|
|
||||||
lg={24}
|
|
||||||
xl={16}
|
|
||||||
style={{ paddingRight: paddingRight }}
|
|
||||||
>
|
|
||||||
<CardWrapper style={{ height: height, width: '100%' }}>
|
|
||||||
<ResourceUtilization />
|
|
||||||
</CardWrapper>
|
|
||||||
</Col>
|
|
||||||
<Col xs={24} sm={24} md={24} lg={24} xl={8}>
|
|
||||||
<CardWrapper style={{ height: largeChartHeight, width: '100%' }}>
|
|
||||||
<Row style={{ height: largeChartHeight, width: '100%' }}>
|
|
||||||
<Col span={12} style={{ height: smallChartHeight }}>
|
|
||||||
<GaugeChart
|
|
||||||
height={smallChartHeight}
|
|
||||||
value={_.round(data.gpu || 0, 1)}
|
|
||||||
color={strokeColorFunc(data.gpu)}
|
|
||||||
title={intl.formatMessage({
|
|
||||||
id: 'dashboard.gpuutilization'
|
|
||||||
})}
|
|
||||||
></GaugeChart>
|
|
||||||
</Col>
|
|
||||||
<Col span={12} style={{ height: smallChartHeight }}>
|
|
||||||
<GaugeChart
|
|
||||||
title={intl.formatMessage({
|
|
||||||
id: 'dashboard.vramutilization'
|
|
||||||
})}
|
|
||||||
height={smallChartHeight}
|
|
||||||
color={strokeColorFunc(data.vram)}
|
|
||||||
value={_.round(data.vram || 0, 1)}
|
|
||||||
></GaugeChart>
|
|
||||||
</Col>
|
|
||||||
<Col span={12} style={{ height: smallChartHeight }}>
|
|
||||||
<GaugeChart
|
|
||||||
title={intl.formatMessage({
|
|
||||||
id: 'dashboard.cpuutilization'
|
|
||||||
})}
|
|
||||||
height={smallChartHeight}
|
|
||||||
color={strokeColorFunc(data.cpu)}
|
|
||||||
value={_.round(data.cpu || 0, 1)}
|
|
||||||
></GaugeChart>
|
|
||||||
</Col>
|
|
||||||
<Col span={12} style={{ height: smallChartHeight }}>
|
|
||||||
<GaugeChart
|
|
||||||
title={intl.formatMessage({
|
|
||||||
id: 'dashboard.memoryutilization'
|
|
||||||
})}
|
|
||||||
height={smallChartHeight}
|
|
||||||
color={strokeColorFunc(data.ram)}
|
|
||||||
value={_.round(data.ram || 0, 1)}
|
|
||||||
></GaugeChart>
|
|
||||||
</Col>
|
|
||||||
</Row>
|
|
||||||
</CardWrapper>
|
|
||||||
</Col>
|
|
||||||
</Row>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default SystemLoad;
|
|
||||||
@@ -1,179 +0,0 @@
|
|||||||
import PageTools from '@/components/page-tools';
|
|
||||||
|
|
||||||
import { useIntl } from '@umijs/max';
|
|
||||||
import dayjs from 'dayjs';
|
|
||||||
import _ from 'lodash';
|
|
||||||
import { memo, useCallback, useContext } from 'react';
|
|
||||||
import { DashboardContext } from '../../config/dashboard-context';
|
|
||||||
import RequestTokenInner from './request-token-inner';
|
|
||||||
|
|
||||||
const baseColorMap = {
|
|
||||||
baseL2: 'rgba(13,171,219,0.8)',
|
|
||||||
baseL1: 'rgba(0,34,255,0.8)',
|
|
||||||
base: 'rgba(0,85,255,0.8)',
|
|
||||||
baseR1: 'rgba(0,255,233,0.8)',
|
|
||||||
baseR2: 'rgba(48,0,255,0.8)',
|
|
||||||
baseR3: 'rgba(85,167,255,0.8)'
|
|
||||||
};
|
|
||||||
|
|
||||||
const getCurrentMonthDays = () => {
|
|
||||||
const now = dayjs();
|
|
||||||
const daysInMonth = now.daysInMonth();
|
|
||||||
const year = dayjs().year();
|
|
||||||
const month = dayjs().month() + 1;
|
|
||||||
|
|
||||||
const dates = [];
|
|
||||||
for (let day = 1; day <= daysInMonth; day++) {
|
|
||||||
dates.push(dayjs(`${year}-${month}-${day}`).format('YYYY-MM-DD'));
|
|
||||||
}
|
|
||||||
return dates;
|
|
||||||
};
|
|
||||||
|
|
||||||
const UsageInner: React.FC<{ paddingRight: string }> = ({ paddingRight }) => {
|
|
||||||
const intl = useIntl();
|
|
||||||
const currentDate = dayjs();
|
|
||||||
const currentMonthDays = getCurrentMonthDays();
|
|
||||||
let requestData: {
|
|
||||||
name: string;
|
|
||||||
color: string;
|
|
||||||
areaStyle: any;
|
|
||||||
data: { time: string; value: number }[];
|
|
||||||
}[] = [];
|
|
||||||
let tokenData: { time: string; value: number }[] = [];
|
|
||||||
let userData: { name: string; value: number }[] = [];
|
|
||||||
const xAxisData: string[] = currentMonthDays;
|
|
||||||
let topUserList: string[] = [];
|
|
||||||
|
|
||||||
const { model_usage } = useContext(DashboardContext);
|
|
||||||
const data = model_usage || {};
|
|
||||||
|
|
||||||
const handleSelectDate = (date: any) => {
|
|
||||||
// fetchData?.();
|
|
||||||
};
|
|
||||||
|
|
||||||
const generateData = useCallback(() => {
|
|
||||||
const requestList: {
|
|
||||||
name: string;
|
|
||||||
color: string;
|
|
||||||
areaStyle: any;
|
|
||||||
data: { time: string; value: number }[];
|
|
||||||
} = {
|
|
||||||
name: 'API requests',
|
|
||||||
areaStyle: {},
|
|
||||||
color: baseColorMap.base,
|
|
||||||
data: []
|
|
||||||
};
|
|
||||||
|
|
||||||
const completionData: any = {
|
|
||||||
name: 'Completion tokens',
|
|
||||||
color: baseColorMap.base,
|
|
||||||
data: []
|
|
||||||
};
|
|
||||||
const prompData: any = {
|
|
||||||
name: 'Prompt tokens',
|
|
||||||
color: baseColorMap.baseR3,
|
|
||||||
data: []
|
|
||||||
};
|
|
||||||
|
|
||||||
const topUserPrompt: any = {
|
|
||||||
name: 'Prompt tokens',
|
|
||||||
color: baseColorMap.baseR3,
|
|
||||||
data: []
|
|
||||||
};
|
|
||||||
const topUserCompletion: any = {
|
|
||||||
name: 'Completion tokens',
|
|
||||||
color: baseColorMap.base,
|
|
||||||
data: []
|
|
||||||
};
|
|
||||||
|
|
||||||
_.each(xAxisData, (date: string) => {
|
|
||||||
// tokens data
|
|
||||||
const item = _.find(data.completion_token_history, (item: any) => {
|
|
||||||
return dayjs(item.timestamp * 1000).format('YYYY-MM-DD') === date;
|
|
||||||
});
|
|
||||||
if (!item) {
|
|
||||||
completionData.data.push({
|
|
||||||
titme: date,
|
|
||||||
value: 0
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
completionData.data.push({
|
|
||||||
value: item.value,
|
|
||||||
time: dayjs(item.timestamp * 1000).format('YYYY-MM-DD')
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const promptItem = _.find(data.prompt_token_history, (item: any) => {
|
|
||||||
return dayjs(item.timestamp * 1000).format('YYYY-MM-DD') === date;
|
|
||||||
});
|
|
||||||
if (!promptItem) {
|
|
||||||
prompData.data.push({
|
|
||||||
value: 0,
|
|
||||||
time: date
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
prompData.data.push({
|
|
||||||
value: promptItem.value,
|
|
||||||
time: dayjs(promptItem.timestamp * 1000).format('YYYY-MM-DD')
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// ============== api request data =================
|
|
||||||
const requestItem = _.find(data.api_request_history, (item: any) => {
|
|
||||||
return dayjs(item.timestamp * 1000).format('YYYY-MM-DD') === date;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!requestItem) {
|
|
||||||
requestList.data.push({
|
|
||||||
time: date,
|
|
||||||
value: 0
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
requestList.data.push({
|
|
||||||
time: dayjs(requestItem.timestamp * 1000).format('YYYY-MM-DD'),
|
|
||||||
value: requestItem.value
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// ========== top users ============
|
|
||||||
if (!data.top_users?.length) {
|
|
||||||
userData = [];
|
|
||||||
topUserList = [];
|
|
||||||
} else {
|
|
||||||
const users: string[] = [];
|
|
||||||
_.each(data.top_users, (item: any) => {
|
|
||||||
users.push(item.username);
|
|
||||||
topUserPrompt.data.push({
|
|
||||||
name: item.username,
|
|
||||||
value: item.prompt_token_count
|
|
||||||
});
|
|
||||||
topUserCompletion.data.push({
|
|
||||||
name: item.username,
|
|
||||||
value: item.completion_token_count
|
|
||||||
});
|
|
||||||
});
|
|
||||||
topUserList = _.uniq(users);
|
|
||||||
userData = [topUserCompletion, topUserPrompt];
|
|
||||||
}
|
|
||||||
|
|
||||||
requestData = [requestList];
|
|
||||||
tokenData = [completionData, prompData];
|
|
||||||
}, [data, xAxisData]);
|
|
||||||
|
|
||||||
generateData();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<PageTools />
|
|
||||||
<RequestTokenInner
|
|
||||||
requestData={requestData}
|
|
||||||
xAxisData={xAxisData}
|
|
||||||
tokenData={tokenData}
|
|
||||||
paddingRight={paddingRight}
|
|
||||||
></RequestTokenInner>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default memo(UsageInner);
|
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
import CardWrapper from '@/components/card-wrapper';
|
|
||||||
import BarChart from '@/components/echarts/bar-chart';
|
|
||||||
import LineChart from '@/components/echarts/line-chart';
|
|
||||||
import { useIntl } from '@umijs/max';
|
|
||||||
import { Col, Row } from 'antd';
|
|
||||||
import dayjs from 'dayjs';
|
|
||||||
import React from 'react';
|
|
||||||
|
|
||||||
interface RequestTokenInnerProps {
|
|
||||||
requestData: {
|
|
||||||
name: string;
|
|
||||||
color: string;
|
|
||||||
areaStyle: any;
|
|
||||||
data: { time: string; value: number }[];
|
|
||||||
}[];
|
|
||||||
tokenData: { time: string; value: number }[];
|
|
||||||
xAxisData: string[];
|
|
||||||
}
|
|
||||||
const RequestTokenInner: React.FC<
|
|
||||||
RequestTokenInnerProps & { paddingRight: string }
|
|
||||||
> = (props) => {
|
|
||||||
console.log('request token inner=====================');
|
|
||||||
const { requestData, tokenData, xAxisData, paddingRight } = props;
|
|
||||||
const intl = useIntl();
|
|
||||||
const labelFormatter = (v: any) => {
|
|
||||||
return dayjs(v).format('MM-DD');
|
|
||||||
};
|
|
||||||
return (
|
|
||||||
<Row style={{ width: '100%' }} gutter={[0, 20]}>
|
|
||||||
<Col
|
|
||||||
xs={24}
|
|
||||||
sm={24}
|
|
||||||
md={24}
|
|
||||||
lg={24}
|
|
||||||
xl={12}
|
|
||||||
style={{ paddingRight: paddingRight }}
|
|
||||||
>
|
|
||||||
<CardWrapper style={{ width: '100%' }}>
|
|
||||||
<LineChart
|
|
||||||
title={intl.formatMessage({ id: 'dashboard.apirequest' })}
|
|
||||||
seriesData={requestData}
|
|
||||||
xAxisData={xAxisData}
|
|
||||||
height={360}
|
|
||||||
labelFormatter={labelFormatter}
|
|
||||||
></LineChart>
|
|
||||||
</CardWrapper>
|
|
||||||
</Col>
|
|
||||||
<Col xs={24} sm={24} md={24} lg={24} xl={12}>
|
|
||||||
<CardWrapper style={{ width: '100%' }}>
|
|
||||||
<BarChart
|
|
||||||
title={intl.formatMessage({ id: 'dashboard.tokens' })}
|
|
||||||
seriesData={tokenData}
|
|
||||||
xAxisData={xAxisData}
|
|
||||||
height={360}
|
|
||||||
labelFormatter={labelFormatter}
|
|
||||||
></BarChart>
|
|
||||||
</CardWrapper>
|
|
||||||
</Col>
|
|
||||||
</Row>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default React.memo(RequestTokenInner);
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
import CardWrapper from '@/components/card-wrapper';
|
|
||||||
import HBar from '@/components/echarts/h-bar';
|
|
||||||
import { useIntl } from '@umijs/max';
|
|
||||||
import React from 'react';
|
|
||||||
|
|
||||||
interface TopUserProps {
|
|
||||||
userData: { name: string; value: number }[];
|
|
||||||
topUserList: string[];
|
|
||||||
}
|
|
||||||
const TopUser: React.FC<TopUserProps> = (props) => {
|
|
||||||
console.log('TopUser=====================');
|
|
||||||
const { userData, topUserList } = props;
|
|
||||||
const intl = useIntl();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<CardWrapper>
|
|
||||||
<HBar
|
|
||||||
title={intl.formatMessage({ id: 'dashboard.topusers' })}
|
|
||||||
seriesData={userData}
|
|
||||||
xAxisData={topUserList}
|
|
||||||
height={360}
|
|
||||||
></HBar>
|
|
||||||
</CardWrapper>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default React.memo(TopUser);
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
import breakpoints from '@/config/breakpoints';
|
|
||||||
import useWindowResize from '@/hooks/use-window-resize';
|
|
||||||
import { useEffect, useState } from 'react';
|
|
||||||
import UserInner from './usage-inner';
|
|
||||||
|
|
||||||
const Usage = () => {
|
|
||||||
const {
|
|
||||||
size: { width }
|
|
||||||
} = useWindowResize();
|
|
||||||
const [paddingRight, setPaddingRight] = useState<string>('20px');
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (width < breakpoints.xl) {
|
|
||||||
setPaddingRight('0');
|
|
||||||
} else {
|
|
||||||
setPaddingRight('20px');
|
|
||||||
}
|
|
||||||
}, [width]);
|
|
||||||
|
|
||||||
return <UserInner paddingRight={paddingRight}></UserInner>;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Usage;
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
import { createContext } from 'react';
|
|
||||||
import { DashboardProps } from './types';
|
|
||||||
|
|
||||||
export const DashboardContext = createContext<
|
|
||||||
DashboardProps & { fetchData: () => Promise<void> }
|
|
||||||
>({} as DashboardProps & { fetchData: () => Promise<void> });
|
|
||||||
|
|
||||||
export default DashboardContext;
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
export const overviewConfigs = [
|
|
||||||
{
|
|
||||||
key: 'worker_count',
|
|
||||||
label: 'dashboard.workers',
|
|
||||||
backgroundColor: 'var(--color-white-1)'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'gpu_count',
|
|
||||||
label: 'dashboard.totalgpus',
|
|
||||||
backgroundColor: 'var(--color-white-1)'
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
key: 'model_count',
|
|
||||||
label: 'dashboard.models',
|
|
||||||
backgroundColor: 'var(--color-white-1)'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'model_instance_count',
|
|
||||||
label: 'models.form.replicas',
|
|
||||||
backgroundColor: 'var(--color-white-1)'
|
|
||||||
}
|
|
||||||
];
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
export interface DashboardProps {
|
|
||||||
resource_counts: {
|
|
||||||
worker_count: number;
|
|
||||||
gpu_count: number;
|
|
||||||
model_count: number;
|
|
||||||
model_instance_count: number;
|
|
||||||
};
|
|
||||||
system_load: {
|
|
||||||
current: {
|
|
||||||
cpu: number;
|
|
||||||
ram: number;
|
|
||||||
gpu: number;
|
|
||||||
vram: number;
|
|
||||||
};
|
|
||||||
history: {
|
|
||||||
cpu: {
|
|
||||||
timestamp: number;
|
|
||||||
value: number;
|
|
||||||
}[];
|
|
||||||
ram: {
|
|
||||||
timestamp: number;
|
|
||||||
value: number;
|
|
||||||
}[];
|
|
||||||
gpu: {
|
|
||||||
timestamp: number;
|
|
||||||
value: number;
|
|
||||||
}[];
|
|
||||||
vram: {
|
|
||||||
timestamp: number;
|
|
||||||
value: number;
|
|
||||||
}[];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
model_usage: {
|
|
||||||
api_request_history: any[];
|
|
||||||
completion_token_history: any[];
|
|
||||||
prompt_token_history: any[];
|
|
||||||
top_users: {
|
|
||||||
user_id: number;
|
|
||||||
username: string;
|
|
||||||
prompt_token_count: number;
|
|
||||||
completion_token_count: number;
|
|
||||||
}[];
|
|
||||||
};
|
|
||||||
active_models: any[];
|
|
||||||
}
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
import { PageContainer } from '@ant-design/pro-components';
|
|
||||||
import { Spin } from 'antd';
|
|
||||||
import { memo, useState } from 'react';
|
|
||||||
import DashboardInner from './components/dahboard-inner';
|
|
||||||
|
|
||||||
const Dashboard: React.FC = () => {
|
|
||||||
const [loading, setLoading] = useState(false);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<PageContainer
|
|
||||||
ghost
|
|
||||||
extra={[]}
|
|
||||||
header={{
|
|
||||||
style: {
|
|
||||||
paddingInline: 'var(--layout-content-header-inlinepadding)'
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Spin spinning={loading}>
|
|
||||||
<DashboardInner setLoading={setLoading} />
|
|
||||||
</Spin>
|
|
||||||
</PageContainer>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default memo(Dashboard);
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
.value-box {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-around;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
.value-healthy {
|
|
||||||
color: var(--ant-green-6);
|
|
||||||
}
|
|
||||||
|
|
||||||
.value-warning {
|
|
||||||
color: var(--ant-gold-6);
|
|
||||||
}
|
|
||||||
|
|
||||||
.value-error {
|
|
||||||
color: var(--ant-red-6);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user