diff --git a/react-ui/config/config.ts b/react-ui/config/config.ts index 2e9ebf64..21474da6 100644 --- a/react-ui/config/config.ts +++ b/react-ui/config/config.ts @@ -150,9 +150,9 @@ export default defineConfig({ projectName: 'swagger', }, ], - mfsu: { - strategy: 'normal', - }, + // mfsu: { + // strategy: 'normal', + // }, requestRecord: {}, icons: {}, lessLoader: { diff --git a/react-ui/config/routes.ts b/react-ui/config/routes.ts index 3caca59f..88502bdf 100644 --- a/react-ui/config/routes.ts +++ b/react-ui/config/routes.ts @@ -220,6 +220,11 @@ export default [ path: '', component: './ModelDeployment/List', }, + { + name: '服务详情', + path: 'serverInfo/:id', + component: './ModelDeployment/Info', + }, { name: '模型部署详情', path: 'info/:id', @@ -228,6 +233,11 @@ export default [ { name: '创建推理服务', path: 'create', + component: './ModelDeployment/CreateServer', + }, + { + name: '新增服务版本', + path: 'addVersion/:id', component: './ModelDeployment/Create', }, ], diff --git a/react-ui/src/pages/ModelDeployment/CreateServer/index.less b/react-ui/src/pages/ModelDeployment/CreateServer/index.less new file mode 100644 index 00000000..f098861f --- /dev/null +++ b/react-ui/src/pages/ModelDeployment/CreateServer/index.less @@ -0,0 +1,19 @@ +.model-deployment-create { + height: 100%; + + &__content { + height: calc(100% - 60px); + margin-top: 10px; + padding: 30px 30px 10px; + overflow: auto; + color: @text-color; + font-size: @font-size-content; + background-color: white; + border-radius: 10px; + + &__type { + color: @text-color; + font-size: @font-size-input-lg; + } + } +} diff --git a/react-ui/src/pages/ModelDeployment/CreateServer/index.tsx b/react-ui/src/pages/ModelDeployment/CreateServer/index.tsx new file mode 100644 index 00000000..74072f52 --- /dev/null +++ b/react-ui/src/pages/ModelDeployment/CreateServer/index.tsx @@ -0,0 +1,212 @@ +/* + * @Author: 赵伟 + * @Date: 2024-04-16 13:58:08 + * @Description: 创建模型部署 + */ +import PageTitle from '@/components/PageTitle'; +import SubAreaTitle from '@/components/SubAreaTitle'; +import { CommonTabKeys } from '@/enums'; +import { + createModelDeploymentReq, + restartModelDeploymentReq, + updateModelDeploymentReq, +} from '@/services/modelDeployment'; +import { camelCaseToUnderscore, underscoreToCamelCase } from '@/utils'; +import { to } from '@/utils/promise'; +import { + getSessionStorageItem, + modelDeploymentInfoKey, + removeSessionStorageItem, +} from '@/utils/sessionStorage'; +import { useNavigate } from '@umijs/max'; +import { App, Button, Col, Form, Input, Row } from 'antd'; +import { pick } from 'lodash'; +import { useEffect, useState } from 'react'; +import { ModelDeploymentData, ModelDeploymentOperationType } from '../types'; +import styles from './index.less'; + +// 表单数据 +export type FormData = { + serviceName: string; // 服务名称 + serviceVersion: string; // 服务版本 + description: string; // 描述 +}; + +function ModelDeploymentCreate() { + const navigate = useNavigate(); + const [form] = Form.useForm(); + const [operationType, setOperationType] = useState(ModelDeploymentOperationType.Create); + const [modelDeploymentInfo, setModelDeploymentInfo] = useState( + undefined, + ); + const { message } = App.useApp(); + + useEffect(() => { + const res = getSessionStorageItem(modelDeploymentInfoKey, true); + if (res) { + setOperationType(res.operationType); + setModelDeploymentInfo(res); + const formData = underscoreToCamelCase(res) as FormData; + form.setFieldsValue(formData); + } + return () => { + removeSessionStorageItem(modelDeploymentInfoKey); + }; + }, []); + + // 创建 + const createModelDeployment = async (formData: FormData) => { + // 根据后台要求,修改表单数据 + const object = camelCaseToUnderscore({ + ...formData, + }); + + const params = + operationType === ModelDeploymentOperationType.Create + ? object + : { + ...pick(modelDeploymentInfo, ['service_id', 'service_ins_id']), + update_model: { + ...pick(object, ['description', 'env', 'replicas', 'resource', 'image']), + }, + }; + + let request = createModelDeploymentReq; + if (operationType === ModelDeploymentOperationType.Restart) { + request = restartModelDeploymentReq; + } else if (operationType === ModelDeploymentOperationType.Update) { + request = updateModelDeploymentReq; + } + const [res] = await to(request(params)); + if (res) { + message.success('操作成功'); + navigate(-1); + } + }; + + // 提交 + const handleSubmit = (values: FormData) => { + createModelDeployment(values); + }; + + // 取消 + const cancel = () => { + navigate(-1); + }; + + const disabled = operationType !== ModelDeploymentOperationType.Create; + let buttonText = '新建'; + if (operationType === ModelDeploymentOperationType.Update) { + buttonText = '更新'; + } else if (operationType === ModelDeploymentOperationType.Restart) { + buttonText = '重启'; + } + + return ( +
+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+ ); +} + +export default ModelDeploymentCreate; diff --git a/react-ui/src/pages/ModelDeployment/ServerInfo/index.less b/react-ui/src/pages/ModelDeployment/ServerInfo/index.less new file mode 100644 index 00000000..4dcf90d9 --- /dev/null +++ b/react-ui/src/pages/ModelDeployment/ServerInfo/index.less @@ -0,0 +1,38 @@ +.model-deployment-info { + height: 100%; + + &__content { + display: flex; + flex-direction: column; + height: calc(100% - 60px); + margin-top: 10px; + padding: 30px 30px 0; + background-color: white; + border-radius: 10px; + + &__tabs { + flex: 1; + min-height: 0; + margin-top: 20px; + padding-bottom: 10px; + + :global { + .ant-tabs { + height: 100%; + + .ant-tabs-nav { + margin-bottom: 10px; + } + + .ant-tabs-content { + height: 100%; + + .ant-tabs-tabpane { + height: 100%; + } + } + } + } + } + } +} diff --git a/react-ui/src/pages/ModelDeployment/ServerInfo/index.tsx b/react-ui/src/pages/ModelDeployment/ServerInfo/index.tsx new file mode 100644 index 00000000..4f73f46f --- /dev/null +++ b/react-ui/src/pages/ModelDeployment/ServerInfo/index.tsx @@ -0,0 +1,76 @@ +/* + * @Author: 赵伟 + * @Date: 2024-04-16 13:58:08 + * @Description: 镜像详情 + */ +import KFIcon from '@/components/KFIcon'; +import PageTitle from '@/components/PageTitle'; +import SubAreaTitle from '@/components/SubAreaTitle'; +import { useSessionStorage } from '@/hooks/sessionStorage'; +import { modelDeploymentInfoKey } from '@/utils/sessionStorage'; +import { Tabs, type TabsProps } from 'antd'; +import { useState } from 'react'; +import BasicInfo from '../components/BasicInfo'; +import ServerLog from '../components/ServerLog'; +import UserGuide from '../components/UserGuide'; +import { ModelDeploymentData } from '../types'; +import styles from './index.less'; + +export enum ModelDeploymentTabKey { + Predict = 'Predict', // 预测 + Guide = 'Guide', // 调用指南 + Log = 'Log', // 服务日志 +} + +function ModelDeploymentInfo() { + const [activeTab, setActiveTab] = useState(ModelDeploymentTabKey.Predict); + const [modelDeployementInfo] = useSessionStorage( + modelDeploymentInfoKey, + true, + undefined, + ); + + const tabItems = [ + { + key: ModelDeploymentTabKey.Predict, + label: '预测', + icon: , + }, + { + key: ModelDeploymentTabKey.Guide, + label: '调用指南', + icon: , + children: , + }, + { + key: ModelDeploymentTabKey.Log, + label: '服务日志', + icon: , + children: , + }, + ]; + + // 切换 Tab,重置数据 + const hanleTabChange: TabsProps['onChange'] = (value) => { + setActiveTab(value); + }; + + return ( +
+ +
+ + +
+ +
+
+
+ ); +} + +export default ModelDeploymentInfo;