diff --git a/config/config.ts b/config/config.ts index dfcaf3b0..e60a3b47 100644 --- a/config/config.ts +++ b/config/config.ts @@ -44,23 +44,12 @@ export default defineConfig({ minRatio: 0.8 } ]); - // config.module - // .rule('images') - // .test(/\.(png|jpe?g|gif|svg|ico)(\?.*)?$/) - // .use('url-loader') - // .loader(require.resolve('url-loader')) - // .tap((options: any) => { - // return { - // ...options, - // limit: 8192, // 小于8KB的图片会被转为base64 - // fallback: { - // loader: require.resolve('file-loader'), - // options: { - // name: 'static/[name].[hash:8].[ext]' // 将所有图片输出到 static 目录 - // } - // } - // }; - // }); + }, + terserOptions: { + compress: { + drop_console: true, + drop_debugger: true + } } } : {}), diff --git a/src/assets/styles/menu.less b/src/assets/styles/menu.less index a3ca4d4e..c86484d9 100644 --- a/src/assets/styles/menu.less +++ b/src/assets/styles/menu.less @@ -1,6 +1,5 @@ .ant-pro-layout { .ant-pro-sider { - padding: 10px; // &.ant-layout-sider { // background: var(--color-white-1); // } diff --git a/src/components/charts/column-bar.tsx b/src/components/charts/column-bar.tsx index ca3f0e8b..b85b9068 100644 --- a/src/components/charts/column-bar.tsx +++ b/src/components/charts/column-bar.tsx @@ -1,5 +1,7 @@ import { Column } from '@ant-design/plots'; +import EmptyData from './empty-data'; + interface BarChartProps { data: any[]; xField: string; @@ -99,7 +101,11 @@ const BarChart: React.FC = (props) => { return ( <> - + {data.length > 0 ? ( + + ) : ( + + )} ); }; diff --git a/src/components/charts/empty-data.tsx b/src/components/charts/empty-data.tsx new file mode 100644 index 00000000..e833600d --- /dev/null +++ b/src/components/charts/empty-data.tsx @@ -0,0 +1,32 @@ +import { Empty } from 'antd'; +import React from 'react'; + +const EmptyData: React.FC<{ + height: string | number; + title: React.ReactNode; +}> = ({ height, title }) => { + return ( +
+

+ {title} +

+
+ +
+
+ ); +}; + +export default EmptyData; diff --git a/src/components/charts/h-bar.tsx b/src/components/charts/h-bar.tsx index dc3422d0..da8a3f49 100644 --- a/src/components/charts/h-bar.tsx +++ b/src/components/charts/h-bar.tsx @@ -1,4 +1,5 @@ import { Bar } from '@ant-design/plots'; +import EmptyData from './empty-data'; interface BarChartProps { data: any[]; @@ -11,6 +12,7 @@ interface BarChartProps { seriesField?: string; stack?: boolean; legend?: any; + showYAxis?: boolean; } const BarChart: React.FC = (props) => { const { @@ -23,6 +25,7 @@ const BarChart: React.FC = (props) => { colorField, seriesField, stack, + showYAxis = true, legend = undefined } = props; const config = { @@ -57,9 +60,11 @@ const BarChart: React.FC = (props) => { xAxis: true, tick: false }, - y: { - tick: false - } + y: showYAxis + ? { + tick: false + } + : null }, title: { title, @@ -94,7 +99,11 @@ const BarChart: React.FC = (props) => { return ( <> - + {data.length === 0 ? ( + + ) : ( + + )} ); }; diff --git a/src/components/charts/line-chart.tsx b/src/components/charts/line-chart.tsx index 98422b9b..6738ae3a 100644 --- a/src/components/charts/line-chart.tsx +++ b/src/components/charts/line-chart.tsx @@ -7,12 +7,22 @@ interface LineChartProps { color?: string[]; xField?: string; yField?: string; + locale: string; labelFormatter?: (v: any) => string; slider?: any; } const LineChart: React.FC = (props) => { - const { data, title, color, xField, yField, slider, height, labelFormatter } = - props; + const { + data, + title, + color, + xField, + locale, + yField, + slider, + height, + labelFormatter + } = props; const config = { title, height, @@ -56,6 +66,7 @@ const LineChart: React.FC = (props) => { color: { layout: { justifyContent: 'center' } }, + size: { itemLabelFontSize: 14, itemLabelFontWeight: 500 diff --git a/src/components/util-bar/index.tsx b/src/components/util-bar/index.tsx index 14f8b287..93868f23 100644 --- a/src/components/util-bar/index.tsx +++ b/src/components/util-bar/index.tsx @@ -16,7 +16,7 @@ const UitilBar: React.FC = (props) => { percent, steps = 10, gapDegree = 170, - strokeWidth = 12, + strokeWidth = 10, title, size = 160, strokeColor, diff --git a/src/locales/en-US.ts b/src/locales/en-US.ts index b611c962..6e6483f7 100644 --- a/src/locales/en-US.ts +++ b/src/locales/en-US.ts @@ -1,5 +1,6 @@ import apikeys from './en-US/apikeys'; import common from './en-US/common'; +import dashboard from './en-US/dashboard'; import menu from './en-US/menu'; import models from './en-US/models'; import playground from './en-US/playground'; @@ -13,5 +14,6 @@ export default { ...playground, ...resources, ...apikeys, - ...users + ...users, + ...dashboard }; diff --git a/src/locales/en-US/dashboard.ts b/src/locales/en-US/dashboard.ts new file mode 100644 index 00000000..bb317cdd --- /dev/null +++ b/src/locales/en-US/dashboard.ts @@ -0,0 +1,24 @@ +export default { + 'dashboard.title': 'Dashboard', + 'dashboard.workers': 'Workers', + 'dashboard.models': 'Models', + 'dashboard.totalgpus': 'Total GPUs', + 'dashboard.allocategpus': 'Allocated GPUs', + 'dashboard.instances': 'Instances', + 'dashboard.systemload': 'System Load', + 'dashboard.memory': 'Memory', + 'dashboard.disk': 'Storage', + 'dashboard.vram': 'VRAM', + 'dashboard.cpuutilization': 'CPU Utilization', + 'dashboard.memoryutilization': 'Memory Utilization', + 'dashboard.diskutilization': 'Storage Utilization', + 'dashboard.vramutilization': 'VRAM Utilization', + 'dashboard.gpuutilization': 'GPU Utilization', + 'dashboard.usage': 'Usage', + 'dashboard.apirequest': 'API Request', + 'dashboard.tokens': 'Tokens', + 'dashboard.topusers': 'Top Users', + 'dashboard.activeModels': 'Active Models', + 'dashboard.runninginstances': 'Running Instances', + 'dashboard.activeModels.name': 'Model Name' +}; diff --git a/src/locales/en-US/resources.ts b/src/locales/en-US/resources.ts index fc74c9c3..7cc6894c 100644 --- a/src/locales/en-US/resources.ts +++ b/src/locales/en-US/resources.ts @@ -7,5 +7,12 @@ export default { 'resources.table.memory': 'Memory', 'resources.table.gpu': 'GPU', 'resources.table.disk': 'Storage', - 'resources.table.vram': 'VRAM' + 'resources.table.vram': 'VRAM', + 'resources.table.index': 'Index', + 'resources.table.workername': 'Wroker Name', + 'resources.table.vender': 'Vender', + 'resources.table.temperature': 'Temperature', + 'resources.table.core': 'Core', + 'resources.table.gpuutilization': 'GPU Utilization', + 'resources.table.vramutilization': 'VRAM Utilization' }; diff --git a/src/locales/zh-CN.ts b/src/locales/zh-CN.ts index f37c36b4..80926799 100644 --- a/src/locales/zh-CN.ts +++ b/src/locales/zh-CN.ts @@ -1,5 +1,6 @@ import apikeys from './zh-CN/apikeys'; import common from './zh-CN/common'; +import dashboard from './zh-CN/dashboard'; import menu from './zh-CN/menu'; import models from './zh-CN/models'; import playground from './zh-CN/playground'; @@ -13,5 +14,6 @@ export default { ...playground, ...resources, ...apikeys, - ...users + ...users, + ...dashboard }; diff --git a/src/locales/zh-CN/dashboard.ts b/src/locales/zh-CN/dashboard.ts new file mode 100644 index 00000000..c7e62a87 --- /dev/null +++ b/src/locales/zh-CN/dashboard.ts @@ -0,0 +1,24 @@ +export default { + 'dashboard.title': '概览', + 'dashboard.workers': '节点', + 'dashboard.models': '模型', + 'dashboard.totalgpus': '总 GPU 数量', + 'dashboard.allocategpus': '已分配 GPU 数量', + 'dashboard.instances': '实例', + 'dashboard.systemload': '系统负载', + 'dashboard.memory': '内存', + 'dashboard.disk': '磁盘', + 'dashboard.vram': '显存', + 'dashboard.cpuutilization': 'CPU 利用率', + 'dashboard.memoryutilization': '内存利用率', + 'dashboard.diskutilization': '磁盘利用率', + 'dashboard.vramutilization': '显存利用率', + 'dashboard.gpuutilization': 'GPU 利用率', + 'dashboard.usage': '使用量', + 'dashboard.apirequest': 'API 请求', + 'dashboard.tokens': 'Tokens', + 'dashboard.topusers': '用户排行', + 'dashboard.activeModels': '活跃模型', + 'dashboard.activeModels.name': '模型名称', + 'dashboard.runninginstances': '运行实例' +}; diff --git a/src/locales/zh-CN/resources.ts b/src/locales/zh-CN/resources.ts index c33c8258..68c25d0c 100644 --- a/src/locales/zh-CN/resources.ts +++ b/src/locales/zh-CN/resources.ts @@ -7,5 +7,12 @@ export default { 'resources.table.memory': '内存', 'resources.table.gpu': 'GPU', 'resources.table.disk': '磁盘', - 'resources.table.vram': '显存' + 'resources.table.vram': '显存', + 'resources.table.index': '序号', + 'resources.table.workername': '节点名称', + 'resources.table.vender': '厂商', + 'resources.table.temperature': '温度', + 'resources.table.core': '核数', + 'resources.table.gpuutilization': 'GPU 利用率', + 'resources.table.vramutilization': '显存利用率' }; diff --git a/src/pages/dashboard/components/active-table.tsx b/src/pages/dashboard/components/active-table.tsx index d815eecd..71ea39cc 100644 --- a/src/pages/dashboard/components/active-table.tsx +++ b/src/pages/dashboard/components/active-table.tsx @@ -1,44 +1,11 @@ import PageTools from '@/components/page-tools'; import ProgressBar from '@/components/progress-bar'; +import { useIntl } from '@umijs/max'; import { Col, Row, Table } from 'antd'; import _ from 'lodash'; import { useContext } from 'react'; import { DashboardContext } from '../config/dashboard-context'; -const modelColumns = [ - { - title: 'Name', - dataIndex: 'name', - key: 'name' - }, - { - title: 'GPU Utilization', - dataIndex: 'gpu_utilization', - key: 'gpu_utilization', - render: (text: any, record: any) => ( - - ) - }, - { - title: 'VRAM Utilization', - dataIndex: 'gpu_memory_utilization', - key: 'gpu_memory_utilization', - render: (text: any, record: any) => ( - - ) - }, - { - title: 'Running Instances', - dataIndex: 'instance_count', - key: 'instance_count' - }, - { - title: 'Tokens', - dataIndex: 'token_count', - key: 'token_count' - } -]; - const projectColumns = [ { title: 'Name', @@ -102,7 +69,41 @@ const projectData = [ } ]; const ActiveTable = () => { + const intl = useIntl(); const data = useContext(DashboardContext).active_models || []; + const modelColumns = [ + { + title: intl.formatMessage({ id: 'dashboard.activeModels.name' }), + dataIndex: 'name', + key: 'name' + }, + { + title: intl.formatMessage({ id: 'dashboard.gpuutilization' }), + dataIndex: 'gpu_utilization', + key: 'gpu_utilization', + render: (text: any, record: any) => ( + + ) + }, + { + title: intl.formatMessage({ id: 'dashboard.vramutilization' }), + dataIndex: 'gpu_memory_utilization', + key: 'gpu_memory_utilization', + render: (text: any, record: any) => ( + + ) + }, + { + title: intl.formatMessage({ id: 'dashboard.runninginstances' }), + dataIndex: 'instance_count', + key: 'instance_count' + }, + { + title: 'Tokens', + dataIndex: 'token_count', + key: 'token_count' + } + ]; return ( @@ -112,7 +113,7 @@ const ActiveTable = () => { - Active Models + {intl.formatMessage({ id: 'dashboard.activeModels' })} } right={false} diff --git a/src/pages/dashboard/components/over-view.tsx b/src/pages/dashboard/components/over-view.tsx index 46cf5de0..10289e26 100644 --- a/src/pages/dashboard/components/over-view.tsx +++ b/src/pages/dashboard/components/over-view.tsx @@ -1,3 +1,4 @@ +import { useIntl } from '@umijs/max'; import { Card, Col, Row, Space } from 'antd'; import _ from 'lodash'; import React, { useContext } from 'react'; @@ -26,6 +27,7 @@ const renderCardItem = (data: { ); }; const Overview: React.FC = () => { + const intl = useIntl(); const data = useContext(DashboardContext).resource_counts || {}; const renderValue = ( @@ -61,7 +63,7 @@ const Overview: React.FC = () => { key={config.key} > {renderCardItem({ - label: config.label, + label: intl.formatMessage({ id: config.label }), value: renderValue(_.get(data, config.key, 0)), bgColor: config.backgroundColor })} diff --git a/src/pages/dashboard/components/resource-utilization.tsx b/src/pages/dashboard/components/resource-utilization.tsx index d402501d..345f5bfb 100644 --- a/src/pages/dashboard/components/resource-utilization.tsx +++ b/src/pages/dashboard/components/resource-utilization.tsx @@ -1,32 +1,43 @@ import LineChart from '@/components/charts/line-chart'; +import { getLocale, useIntl } from '@umijs/max'; import dayjs from 'dayjs'; import _ from 'lodash'; -import { useContext, useEffect, useState } from 'react'; +import { useCallback, useContext, useEffect, useState } from 'react'; import { DashboardContext } from '../config/dashboard-context'; const TypeKeyMap = { cpu: { label: 'CPU', + type: 'CPU', + intl: false, color: 'linear-gradient(90deg,rgba(84, 204, 152,0.8) 0%,rgba(0, 168, 143,.7) 100%)' }, memory: { - label: 'Memory', + label: 'dashboard.memory', + type: 'Memory', + intl: true, color: 'linear-gradient(90deg,rgba(249, 248, 113,.8) 0%,rgba(255, 199, 92,0.7) 100%)' }, gpu: { label: 'GPU', + type: 'GPU', + intl: false, color: 'rgba(84, 204, 152,0.8)' }, gpu_memory: { - label: 'VRAM', + label: 'dashboard.vram', + type: 'VRAM', + intl: true, color: 'linear-gradient(90deg,rgba(84, 204, 152,0.8) 0%,rgba(0, 168, 143,.7) 100%)' } }; const UtilizationOvertime: React.FC = () => { + const intl = useIntl(); + const locale = getLocale(); const data = useContext(DashboardContext)?.system_load?.history || {}; const [result, setResult] = useState< { time: string; value: number; type: string }[] @@ -52,30 +63,38 @@ const UtilizationOvertime: React.FC = () => { const labelFormatter = (value: any) => { return `${value}%`; }; - const generateData = () => { + const generateData = useCallback(() => { const list: { value: number; time: string; type: string }[] = []; _.each(typeList, (type: any) => { const dataList = _.map(_.get(data, type, []), (item: any) => { + const value = _.get(item, 'value', 0); + const time = dayjs(item.timestamp * 1000).format('HH:mm:ss'); + const itemtype = _.get(TypeKeyMap, [type, 'intl'], false) + ? intl.formatMessage({ + id: _.get(TypeKeyMap, [type, 'label'], '') + }) + : _.get(TypeKeyMap, [type, 'label'], ''); return { - value: _.round(item.value, 2) || 0, - time: dayjs(item.timestamp * 1000).format('HH:mm:ss'), - type: _.get(TypeKeyMap, [type, 'label'], ''), + value, + time, + type: itemtype, color: 'red' }; }); list.push(...dataList); }); setResult(list); - }; + }, [data, locale]); useEffect(() => { generateData(); - }, [data]); + }, [data, locale]); return ( <> diff --git a/src/pages/dashboard/components/system-load.tsx b/src/pages/dashboard/components/system-load.tsx index 81c5434d..0ea4f3a2 100644 --- a/src/pages/dashboard/components/system-load.tsx +++ b/src/pages/dashboard/components/system-load.tsx @@ -2,6 +2,7 @@ import CardWrapper from '@/components/card-wrapper'; 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, DatePicker, Row } from 'antd'; import _ from 'lodash'; import { useContext, useEffect, useState } from 'react'; @@ -15,6 +16,7 @@ const SystemLoad = () => { 'linear-gradient(90deg, rgba(255, 214, 102,.8) 0%, rgba(255, 214, 102,0.5) 50%, rgba(255, 214, 102,.8) 100%)', 'linear-gradient(90deg, rgba(255, 120, 117,.8) 0%, rgba(255, 120, 117,0.5) 50%, rgba(255, 120, 117,.8) 100%)' ]; + const intl = useIntl(); const data = useContext(DashboardContext)?.system_load?.current || {}; const { size } = useWindowResize(); const [paddingRight, setPaddingRight] = useState('20px'); @@ -40,7 +42,7 @@ const SystemLoad = () => { style={{ margin: '32px 8px' }} left={ - System Load + {intl.formatMessage({ id: 'dashboard.systemload' })} } right={ @@ -65,25 +67,33 @@ const SystemLoad = () => { diff --git a/src/pages/dashboard/components/usage.tsx b/src/pages/dashboard/components/usage.tsx index cd607050..5607dabd 100644 --- a/src/pages/dashboard/components/usage.tsx +++ b/src/pages/dashboard/components/usage.tsx @@ -5,6 +5,7 @@ import PageTools from '@/components/page-tools'; import breakpoints from '@/config/breakpoints'; import useWindowResize from '@/hooks/use-window-resize'; import { generateRandomArray } from '@/utils'; +import { useIntl } from '@umijs/max'; import { Col, DatePicker, Row } from 'antd'; import dayjs from 'dayjs'; import _ from 'lodash'; @@ -93,6 +94,7 @@ const tokenUsage = TokensData.map((val, i) => { }); const Usage = () => { + const intl = useIntl(); const { size } = useWindowResize(); const [paddingRight, setPaddingRight] = useState('20px'); const [requestData, setRequestData] = useState< @@ -125,14 +127,14 @@ const Usage = () => { _.each(data.api_request_history, (item: any) => { requestList.push({ - time: dayjs(item.timestamp * 1000).format('YYYY-MM-DD'), + time: dayjs(item.timestamp * 1000).format('YYYY-MM'), value: item.value }); }); _.each(data.completion_token_history, (item: any) => { tokenList.push({ - time: dayjs(item.timestamp * 1000).format('YYYY-MM-DD'), + time: dayjs(item.timestamp * 1000).format('YYYY-MM'), name: 'completion_token', color: 'rgba(84, 204, 152,0.8)', value: item.value @@ -140,7 +142,7 @@ const Usage = () => { }); _.each(data.prompt_token_history, (item: any) => { tokenList.push({ - time: dayjs(item.timestamp * 1000).format('YYYY-MM-DD'), + time: dayjs(item.timestamp * 1000).format('YYYY-MM'), name: 'prompt_token', color: 'rgba(0, 170, 173, 0.8)', value: item.value @@ -183,7 +185,11 @@ const Usage = () => { <> Usage} + left={ + + {intl.formatMessage({ id: 'dashboard.usage' })} + + } right={ } @@ -201,7 +207,7 @@ const Usage = () => { { { { useEffect(() => { fetchData(); - setTimeout(() => { - createModelsChunkRequest(); - }, 1000); - + createModelsChunkRequest(); return () => { chunkRequedtRef.current?.current?.cancel?.(); }; diff --git a/src/pages/login/components/password-form.tsx b/src/pages/login/components/password-form.tsx index f1d325e2..a168a2fe 100644 --- a/src/pages/login/components/password-form.tsx +++ b/src/pages/login/components/password-form.tsx @@ -76,10 +76,9 @@ const PasswordForm: React.FC = () => { { required: true, pattern: PasswordReg, - message: intl.formatMessage( - { id: 'common.form.rule.input' }, - { name: intl.formatMessage({ id: 'users.form.newpassword' }) } - ) + message: intl.formatMessage({ + id: 'users.form.rule.password' + }) } ]} > diff --git a/src/pages/resources/components/gpus.tsx b/src/pages/resources/components/gpus.tsx index 0a28dba4..e7605e55 100644 --- a/src/pages/resources/components/gpus.tsx +++ b/src/pages/resources/components/gpus.tsx @@ -12,97 +12,6 @@ import { queryGpuDevicesList } from '../apis'; import { GPUDeviceItem } from '../config/types'; const { Column } = Table; -const dataSource: GPUDeviceItem[] = [ - { - id: 1, - name: 'bj-web-service-1', - address: '183.14.31.136', - hostname: 'bj-web-service-1', - labels: {}, - resources: { - capacity: { - cpu: 4, - gpu: 2, - memory: '64 GiB', - gram: '24 Gib' - }, - allocable: { - cpu: 2.5, - gpu: 1.6, - memory: '64', - gram: '24 Gib' - } - }, - state: 'ACTIVE' - }, - { - id: 2, - name: 'bj-db-service-2', - address: '172.24.1.36', - hostname: 'bj-db-service-2', - labels: {}, - resources: { - capacity: { - cpu: 4, - gpu: 2, - memory: '64 GiB', - gram: '24 Gib' - }, - allocable: { - cpu: 2, - gpu: 1.5, - memory: '32 GiB', - gram: '12 Gib' - } - }, - state: 'ACTIVE' - }, - { - id: 3, - name: 'guangzhou-computed-node-2', - address: '170.10.2.10', - hostname: 'guangzhou-computed-node-2', - labels: {}, - resources: { - capacity: { - cpu: 8, - gpu: 4, - memory: '64 GiB', - gram: '24 Gib' - }, - allocable: { - cpu: 2, - gpu: 1.5, - memory: '32 GiB', - gram: '12 Gib' - } - }, - state: 'ACTIVE' - }, - { - id: 4, - name: 'hangzhou-cache-node-1', - address: '115.2.21.10', - hostname: 'hangzhou-cache-node-1', - labels: {}, - resources: { - capacity: { - cpu: 8, - gpu: 4, - memory: '64 GiB', - gram: '24 Gib' - }, - allocable: { - cpu: 4, - gpu: 2.5, - memory: '40 GiB', - gram: '16 Gib' - } - }, - state: 'ACTIVE' - } -]; - const Models: React.FC = () => { const intl = useIntl(); const rowSelection = useTableRowSelection(); @@ -205,20 +114,32 @@ const Models: React.FC = () => { onChange: handlePageChange }} > - + { return {record.index}; }} /> - - + + { @@ -226,7 +147,7 @@ const Models: React.FC = () => { }} /> { @@ -234,7 +155,7 @@ const Models: React.FC = () => { }} /> { @@ -247,8 +168,8 @@ const Models: React.FC = () => { /> { return ( diff --git a/src/request-config.ts b/src/request-config.ts index 42b9604e..30f36911 100644 --- a/src/request-config.ts +++ b/src/request-config.ts @@ -13,7 +13,7 @@ export const requestConfig: RequestConfig = { errorHandler: (error: any, opts: any) => { const { message: errorMessage, response } = error; const errMsg = response?.data?.message || errorMessage; - if (!opts?.skipErrorHandler) { + if (!opts?.skipErrorHandler && response?.status) { message.error(errMsg); } console.log('errorHandler+++++++++++++++', error, opts);