build: output files to dir

This commit is contained in:
jialin
2024-06-17 13:03:41 +08:00
parent 2352c316c0
commit 9fa61b9849
20 changed files with 776 additions and 245 deletions
@@ -161,7 +161,7 @@ const ModelBills: React.FC = () => {
<PageTools
marginBottom={10}
marginTop={0}
left={<span>Bills by model</span>}
left={false}
right={
<Space>
<Select
+50 -11
View File
@@ -1,12 +1,15 @@
import { Card, Col, Row } from 'antd';
import { Card, Col, Row, Space } from 'antd';
import React from 'react';
import { overviewConfigs } from '../config';
import '../styles/index.less';
import styles from './over-view.less';
const CardItem: React.FC<{ label: string; value: number; bgColor: string }> = ({
label,
value,
bgColor
const renderCardItem = (data: {
label: string;
value: React.ReactNode;
bgColor: string;
}) => {
const { label, value, bgColor } = data;
return (
<Card
bordered={false}
@@ -21,16 +24,52 @@ const CardItem: React.FC<{ label: string; value: number; bgColor: string }> = ({
);
};
const Overview: React.FC = (props) => {
const { data = {} } = props;
// const { data = {} } = props;
const data = {
workers: 8,
models: {
healthy: 10,
warning: 2,
error: 1
},
gpus: 30,
allocatedGpus: 12,
instances: {
healthy: 32,
warning: 3,
error: 2
}
};
const renderValue = (
value:
| number
| {
healthy: number;
warning: number;
error: number;
}
) => {
if (typeof value === 'number') {
return value;
}
return (
<Space className="value-box">
<span className={'value-healthy'}>{value.healthy}</span>
<span className={'value-warning'}>{value.warning}</span>
<span className={'value-error'}>{value.error}</span>
</Space>
);
};
return (
<Row gutter={[20, 20]} className={styles.row}>
{overviewConfigs.map((config, index) => (
<Col span={5} key={config.key}>
<CardItem
label={config.label}
value={data[config.key] || 0}
bgColor={config.backgroundColor}
/>
{renderCardItem({
label: config.label,
value: renderValue(data[config.key] || 0),
bgColor: config.backgroundColor
})}
</Col>
))}
</Row>
@@ -1,15 +1,21 @@
import PageTools from '@/components/page-tools';
import { generateRandomArray } from '@/utils';
import { Line } from '@ant-design/plots';
import { DatePicker } from 'antd';
import _ from 'lodash';
const mockData = {
GPU: generateRandomArray(),
CPU: generateRandomArray(),
Memory: generateRandomArray(),
VRAM: generateRandomArray()
};
const UtilizationOvertime: React.FC = () => {
const timeList = [
'01:00:00',
'02:00:00',
'03:00:00',
'04:00:00',
'05:00:00',
// '01:00:00',
// '02:00:00',
// '03:00:00',
// '04:00:00',
// '05:00:00',
'06:00:00',
'07:00:00',
'08:00:00',
@@ -21,7 +27,7 @@ const UtilizationOvertime: React.FC = () => {
'14:00:00',
'15:00:00'
];
const typeList = ['GPU', 'CPU', 'Memory'];
const typeList = ['GPU', 'CPU', 'Memory', 'VRAM'];
const generateData = () => {
const data = [];
for (let i = 0; i < timeList.length; i++) {
@@ -29,7 +35,7 @@ const UtilizationOvertime: React.FC = () => {
data.push({
time: timeList[i],
type: typeList[j],
value: _.round(Math.random(), 3)
value: _.get(mockData, typeList[j])[i]
});
}
}
@@ -41,10 +47,12 @@ const UtilizationOvertime: React.FC = () => {
console.log('dateString============', date);
};
const config = {
// title: 'Resource Utilization',
xField: 'time',
yField: 'value',
color: ['red', 'blue', 'green'],
colorField: 'type',
autoFit: true,
slider: false,
shapeField: 'smooth',
axis: {
@@ -69,21 +77,15 @@ const UtilizationOvertime: React.FC = () => {
tooltip: {
title: 'time',
items: [{ channel: 'y' }]
},
label: {
autoRotate: true
}
// label: {
// autoRotate: true
// }
};
// <DatePicker onChange={handleSelectDate} style={{ width: 300 }} />
return (
<>
<PageTools
marginBottom={10}
marginTop={0}
left={<span>Utilization Over Time</span>}
right={
<DatePicker onChange={handleSelectDate} style={{ width: 300 }} />
}
/>
<PageTools marginBottom={10} marginTop={0} left={false} right={false} />
<Line height={400} data={data} {...config} />
</>
);
+14 -14
View File
@@ -1,13 +1,7 @@
export const overviewConfigs = [
{
key: 'models',
label: 'Models',
backgroundColor:
'linear-gradient(180deg, rgba(0,188,203,.2) 0%, rgba(40,207,181,.2) 100%)'
},
{
key: 'nodes',
label: 'Nodes',
key: 'workers',
label: 'Workers',
backgroundColor:
'linear-gradient(180deg, rgba(0,188,203,.2) 0%, rgba(40,207,181,.2) 100%)'
},
@@ -17,16 +11,22 @@ export const overviewConfigs = [
backgroundColor:
'linear-gradient(180deg, rgba(0,188,203,.2) 0%, rgba(40,207,181,.2) 100%)'
},
{
key: 'idleGpus',
label: 'Idle GPUs',
backgroundColor:
'linear-gradient(180deg, rgba(0,188,203,.2) 0%, rgba(40,207,181,.2) 100%)'
},
{
key: 'allocatedGpus',
label: 'Allocated GPUs',
backgroundColor:
'linear-gradient(180deg, rgba(0,188,203,.2) 0%, rgba(40,207,181,.2) 100%)'
},
{
key: 'models',
label: 'Models',
backgroundColor:
'linear-gradient(180deg, rgba(0,188,203,.2) 0%, rgba(40,207,181,.2) 100%)'
},
{
key: 'instances',
label: 'Instances',
backgroundColor:
'linear-gradient(180deg, rgba(0,188,203,.2) 0%, rgba(40,207,181,.2) 100%)'
}
];
+133 -11
View File
@@ -1,11 +1,94 @@
import BarChart from '@/components/bar-chart';
import HBar from '@/components/bar-chart/h-bar';
import ContentWrapper from '@/components/content-wrapper';
import DividerLine from '@/components/divider-line';
import PageTools from '@/components/page-tools';
import { generateRandomArray } from '@/utils';
import { PageContainer } from '@ant-design/pro-components';
import { Col, Row } from 'antd';
import GPUUtilization from './components/gpu-utilization';
import Overview from './components/over-view';
import UtilizationOvertime from './components/utilization-overtime';
const times = [
'june 1',
'june 2',
'june 3',
'june 4',
'june 5',
'june 6',
'june 7'
];
const users = ['Jim', 'Lucy', 'Lily', 'Tom', 'Jack', 'Rose', 'Jerry'];
const projects = [
'copilot-dev',
'rag-wiki',
'smart-auto-agent',
'office-auto-docs',
'smart-customer-service'
];
const APIRequestData = generateRandomArray({
length: times.length,
max: 100,
min: 0,
offset: 10
});
const TokensData = generateRandomArray({
length: times.length,
max: 2000,
min: 200,
offset: 200
});
const usersData = generateRandomArray({
length: users.length,
max: 100,
min: 0,
offset: 10
});
const projectsData = generateRandomArray({
length: projects.length,
max: 100,
min: 0,
offset: 10
});
const userDataList = usersData
.map((val, i) => {
return {
time: users[i],
value: val
};
})
.sort((a, b) => b.value - a.value);
const projectDataList = projectsData
.map((val, i) => {
return {
time: projects[i],
value: val
};
})
.sort((a, b) => b.value - a.value);
const dataList = APIRequestData.map((val, i) => {
console.log('val', val);
return {
time: times[i],
value: val
};
});
const tokenUsage = TokensData.map((val, i) => {
console.log('val', val);
return {
time: times[i],
value: val
};
});
const Dashboard: React.FC = () => {
return (
<>
@@ -13,6 +96,10 @@ const Dashboard: React.FC = () => {
<Overview></Overview>
</PageContainer>
<DividerLine></DividerLine>
<PageContainer ghost title="System Load">
<UtilizationOvertime></UtilizationOvertime>
</PageContainer>
<DividerLine></DividerLine>
<PageContainer ghost title={false}>
<Row gutter={20} style={{ marginTop: '0px' }}>
<Col span={12}>
@@ -54,18 +141,53 @@ const Dashboard: React.FC = () => {
</Col>
</Row>
</PageContainer>
{/* <DividerLine></DividerLine>
<PageContainer ghost title={false}>
<div style={{ marginTop: '0px' }}>
<ModelBills></ModelBills>
</div>
</PageContainer> */}
<DividerLine></DividerLine>
<PageContainer ghost title={false}>
<div style={{ marginTop: '0px' }}>
<UtilizationOvertime></UtilizationOvertime>
</div>
</PageContainer>
<Row gutter={10}>
<Col span={12}>
<ContentWrapper
contentStyle={{ paddingRight: 0 }}
title={<span style={{ lineHeight: '48px' }}>API Request</span>}
>
<BarChart data={dataList} xField="time" yField="value"></BarChart>
</ContentWrapper>
</Col>
<Col span={12}>
<ContentWrapper
contentStyle={{ paddingRight: 0 }}
title={<span style={{ lineHeight: '48px' }}>Tokens</span>}
>
<BarChart data={tokenUsage} xField="time" yField="value"></BarChart>
</ContentWrapper>
</Col>
</Row>
<Row gutter={10}>
<Col span={12}>
<ContentWrapper
contentStyle={{ paddingRight: 0 }}
title={<span style={{ lineHeight: '48px' }}>Top Users</span>}
>
<HBar
data={userDataList}
xField="time"
yField="value"
height={360}
></HBar>
</ContentWrapper>
</Col>
<Col span={12}>
<ContentWrapper
contentStyle={{ paddingRight: 0 }}
title={<span style={{ lineHeight: '48px' }}>Top Projects</span>}
>
<HBar
data={projectDataList}
xField="time"
yField="value"
height={300}
></HBar>
</ContentWrapper>
</Col>
</Row>
</>
);
};
+17
View File
@@ -0,0 +1,17 @@
.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-danger {
color: var(--ant-red-6);
}
}
+2 -5
View File
@@ -129,6 +129,7 @@ const AddModal: React.FC<AddModalProps> = (props) => {
onChange={handleInputRepoChange}
onSearch={debounceSearch}
options={repoOptions}
description="Only .gguf format is supported"
></SealAutoComplete>
</Form.Item>
<Form.Item<FormData>
@@ -210,11 +211,7 @@ const AddModal: React.FC<AddModalProps> = (props) => {
>
<Form name="addModalForm" form={form} onFinish={onOk} preserve={false}>
<Form.Item<FormData> name="name" rules={[{ required: true }]}>
<SealInput.Input
label="Name"
required
description="description info"
></SealInput.Input>
<SealInput.Input label="Name" required></SealInput.Input>
</Form.Item>
<Form.Item<FormData> name="source" rules={[{ required: true }]}>
<SealSelect
+24 -12
View File
@@ -16,14 +16,21 @@ import ViewCodeModal from './view-code-modal';
interface MessageProps {
parameters: any;
}
interface MessageItemProps {
role: string;
content: string;
uid: number;
}
const MessageList: React.FC<MessageProps> = (props) => {
const { parameters } = props;
const [messageList, setMessageList] = useState<
{ role: string; content: string }[]
>([
const messageId = useRef<number>(0);
const [messageList, setMessageList] = useState<MessageItemProps[]>([
{
role: 'user',
content: ''
content: '',
uid: messageId.current
}
]);
@@ -37,11 +44,17 @@ const MessageList: React.FC<MessageProps> = (props) => {
const handleSystemMessageChange = (e: any) => {
setSystemMessage(e.target.value);
};
const setMessageId = () => {
messageId.current = messageId.current + 1;
};
const handleNewMessage = () => {
messageList.push({
role: 'user',
content: ''
content: '',
uid: messageId.current + 1
});
setMessageId();
setMessageList([...messageList]);
setActiveIndex(messageList.length - 1);
};
@@ -71,9 +84,11 @@ const MessageList: React.FC<MessageProps> = (props) => {
...messageList,
{
role: Roles.Assistant,
content: assistant.content
content: assistant.content,
uid: messageId.current + 1
}
]);
setMessageId();
setLoading(false);
} catch (error) {
setLoading(false);
@@ -101,10 +116,7 @@ const MessageList: React.FC<MessageProps> = (props) => {
setMessageList([...messageList]);
};
const handleUpdateMessage = (
index: number,
message: { role: string; content: string }
) => {
const handleUpdateMessage = (index: number, message: MessageItemProps) => {
messageList[index] = message;
console.log('updatemessage========', index, message);
setMessageList([...messageList]);
@@ -143,12 +155,12 @@ const MessageList: React.FC<MessageProps> = (props) => {
{messageList.map((item, index) => {
return (
<MessageItem
key={index}
key={item.uid}
isFocus={index === activeIndex}
islast={index === messageList.length - 1}
loading={loading}
onDelete={() => handleDelete(index)}
updateMessage={(message: { role: string; content: string }) =>
updateMessage={(message: MessageItemProps) =>
handleUpdateMessage(index, message)
}
message={item}
@@ -4,18 +4,20 @@ import _ from 'lodash';
import { memo, useEffect, useRef, useState } from 'react';
import { Roles } from '../config';
import '../style/message-item.less';
interface MessageItemProps {
role: string;
content: string;
uid: number;
}
const MessageItem: React.FC<{
message: {
role: string;
content: string;
};
message: MessageItemProps;
loading?: boolean;
islast?: boolean;
updateMessage: (message: { role: string; content: string }) => void;
updateMessage: (message: MessageItemProps) => void;
isFocus: boolean;
onDelete: () => void;
}> = ({ message, isFocus, onDelete, updateMessage, loading, islast }) => {
}> = ({ message, isFocus, onDelete, updateMessage }) => {
const [roleType, setRoleType] = useState(message.role);
const [isTyping, setIsTyping] = useState(false);
const [messageContent, setMessageContent] = useState(message.content);
@@ -51,7 +53,11 @@ const MessageItem: React.FC<{
useEffect(() => {
if (!isAnimating && !isInitialRender.current) {
updateMessage({ role: roleType, content: messageContent });
updateMessage({
role: roleType,
content: messageContent,
uid: message.uid
});
} else {
isInitialRender.current = false;
}