| @@ -20,13 +20,13 @@ export default { | |||||
| // localhost:8000/api/** -> https://preview.pro.ant.design/api/** | // localhost:8000/api/** -> https://preview.pro.ant.design/api/** | ||||
| '/api/': { | '/api/': { | ||||
| // 要代理的地址 | // 要代理的地址 | ||||
| target: 'http://172.20.32.181:31213', // 开发环境 | |||||
| // target: 'http://172.20.32.98:8082', | |||||
| // target: 'http://172.20.32.181:31213', // 开发环境 | |||||
| target: 'http://172.168.15.80:8082', | |||||
| // target: 'http://172.20.32.150:8082', | // target: 'http://172.20.32.150:8082', | ||||
| // 配置了这个可以从 http 代理到 https | // 配置了这个可以从 http 代理到 https | ||||
| // 依赖 origin 的功能可能需要这个,比如 cookie | // 依赖 origin 的功能可能需要这个,比如 cookie | ||||
| changeOrigin: true, | changeOrigin: true, | ||||
| // pathRewrite: { '^/api': '' }, | |||||
| pathRewrite: { '^/api': '' }, | |||||
| }, | }, | ||||
| '/profile/avatar/': { | '/profile/avatar/': { | ||||
| target: 'http://172.20.32.185:31213', | target: 'http://172.20.32.185:31213', | ||||
| @@ -181,7 +181,7 @@ export default [ | |||||
| }, | }, | ||||
| { | { | ||||
| name: '实验实例详情', | name: '实验实例详情', | ||||
| path: 'instance/:autoMLId/:id', | |||||
| path: 'instance/:experimentId/:id', | |||||
| component: './AutoML/Instance/index', | component: './AutoML/Instance/index', | ||||
| }, | }, | ||||
| ], | ], | ||||
| @@ -217,11 +217,47 @@ export default [ | |||||
| }, | }, | ||||
| { | { | ||||
| name: '实验实例详情', | name: '实验实例详情', | ||||
| path: 'instance/:autoMLId/:id', | |||||
| path: 'instance/:experimentId/:id', | |||||
| component: './HyperParameter/Instance/index', | component: './HyperParameter/Instance/index', | ||||
| }, | }, | ||||
| ], | ], | ||||
| }, | }, | ||||
| { | |||||
| name: '主动学习', | |||||
| path: 'active-learn', | |||||
| routes: [ | |||||
| { | |||||
| name: '超参数寻优', | |||||
| path: '', | |||||
| component: './ActiveLearn/List/index', | |||||
| }, | |||||
| { | |||||
| name: '实验详情', | |||||
| path: 'info/:id', | |||||
| component: './ActiveLearn/Info/index', | |||||
| }, | |||||
| { | |||||
| name: '创建实验', | |||||
| path: 'create', | |||||
| component: './ActiveLearn/Create/index', | |||||
| }, | |||||
| { | |||||
| name: '编辑实验', | |||||
| path: 'edit/:id', | |||||
| component: './ActiveLearn/Create/index', | |||||
| }, | |||||
| { | |||||
| name: '复制实验', | |||||
| path: 'copy/:id', | |||||
| component: './ActiveLearn/Create/index', | |||||
| }, | |||||
| { | |||||
| name: '实验实例详情', | |||||
| path: 'instance/:experimentId/:id', | |||||
| component: './ActiveLearn/Instance/index', | |||||
| }, | |||||
| ], | |||||
| }, | |||||
| ], | ], | ||||
| }, | }, | ||||
| { | { | ||||
| @@ -525,6 +561,18 @@ export default [ | |||||
| }, | }, | ||||
| ], | ], | ||||
| }, | }, | ||||
| { | |||||
| name: '知识图谱', | |||||
| path: '/knowledge', | |||||
| routes: [ | |||||
| { | |||||
| name: '知识图谱', | |||||
| path: '', | |||||
| key: 'knowledge', | |||||
| component: './Knowledge/index', | |||||
| }, | |||||
| ], | |||||
| }, | |||||
| { | { | ||||
| path: '*', | path: '*', | ||||
| layout: false, | layout: false, | ||||
| @@ -140,7 +140,7 @@ | |||||
| "umi-presets-pro": "^2.0.0" | "umi-presets-pro": "^2.0.0" | ||||
| }, | }, | ||||
| "engines": { | "engines": { | ||||
| "node": ">=16.14.0" | |||||
| "node": ">=18.18.0" | |||||
| }, | }, | ||||
| "create-umi": { | "create-umi": { | ||||
| "ignoreScript": [ | "ignoreScript": [ | ||||
| @@ -25,7 +25,7 @@ export { requestConfig as request } from './requestConfig'; | |||||
| /** | /** | ||||
| * @see https://umijs.org/zh-CN/plugins/plugin-initial-state | * @see https://umijs.org/zh-CN/plugins/plugin-initial-state | ||||
| * */ | |||||
| */ | |||||
| export async function getInitialState(): Promise<GlobalInitialState> { | export async function getInitialState(): Promise<GlobalInitialState> { | ||||
| const fetchUserInfo = async () => { | const fetchUserInfo = async () => { | ||||
| try { | try { | ||||
| @@ -15,6 +15,7 @@ export enum IframePageType { | |||||
| DevEnv = 'DevEnv', // 开发环境 | DevEnv = 'DevEnv', // 开发环境 | ||||
| GitLink = 'GitLink', // git link | GitLink = 'GitLink', // git link | ||||
| Aim = 'Aim', // 实验对比 | Aim = 'Aim', // 实验对比 | ||||
| Knowledge = 'Knowledge', // 知识图谱 | |||||
| } | } | ||||
| const getRequestAPI = (type: IframePageType): (() => Promise<any>) => { | const getRequestAPI = (type: IframePageType): (() => Promise<any>) => { | ||||
| @@ -37,6 +38,10 @@ const getRequestAPI = (type: IframePageType): (() => Promise<any>) => { | |||||
| code: 200, | code: 200, | ||||
| data: SessionStorage.getItem(SessionStorage.aimUrlKey) || '', | data: SessionStorage.getItem(SessionStorage.aimUrlKey) || '', | ||||
| }); | }); | ||||
| case IframePageType.Knowledge: { // 知识图谱 | |||||
| const { origin } = location; | |||||
| return () => Promise.resolve({ code: 200, data: `http://${origin}:32701` }); | |||||
| } | |||||
| } | } | ||||
| }; | }; | ||||
| @@ -58,9 +63,12 @@ function IframePage({ type, openInTab = false, className, style }: IframePagePro | |||||
| useEffect(() => { | useEffect(() => { | ||||
| const requestIframeUrl = async () => { | const requestIframeUrl = async () => { | ||||
| setLoading(true); | |||||
| const [res] = await to(getRequestAPI(type)()); | const [res] = await to(getRequestAPI(type)()); | ||||
| if (res && res.data) { | if (res && res.data) { | ||||
| setIframeUrl(res.data); | setIframeUrl(res.data); | ||||
| } else { | |||||
| setLoading(false); | |||||
| } | } | ||||
| }; | }; | ||||
| @@ -4,7 +4,7 @@ | |||||
| right: 0; | right: 0; | ||||
| bottom: 0; | bottom: 0; | ||||
| left: 0; | left: 0; | ||||
| z-index: 1001; | |||||
| z-index: 1001; // 设置大于 Modal 的 z-index | |||||
| display: flex; | display: flex; | ||||
| flex-direction: column; | flex-direction: column; | ||||
| align-items: center; | align-items: center; | ||||
| @@ -7,4 +7,25 @@ | |||||
| background-repeat: no-repeat; | background-repeat: no-repeat; | ||||
| background-position: top center; | background-position: top center; | ||||
| background-size: 100% 100%; | background-size: 100% 100%; | ||||
| &__tips { | |||||
| position: relative; | |||||
| margin-left: 18px; | |||||
| padding: 3px 15px; | |||||
| color: @primary-color; | |||||
| background: .addAlpha(@primary-color, 0.1) []; | |||||
| border-radius: 4px; | |||||
| &::before { | |||||
| position: absolute; | |||||
| top: 10px; | |||||
| left: -6px; | |||||
| width: 0; | |||||
| height: 0; | |||||
| border-top: 4px solid transparent; | |||||
| border-right: 6px solid .addAlpha(@primary-color, 0.1) []; | |||||
| border-bottom: 4px solid transparent; | |||||
| content: ''; | |||||
| } | |||||
| } | |||||
| } | } | ||||
| @@ -3,6 +3,7 @@ | |||||
| * @Date: 2024-04-17 14:01:46 | * @Date: 2024-04-17 14:01:46 | ||||
| * @Description: 页面标题 | * @Description: 页面标题 | ||||
| */ | */ | ||||
| import KFIcon from '@/components/KFIcon'; | |||||
| import classNames from 'classnames'; | import classNames from 'classnames'; | ||||
| import React from 'react'; | import React from 'react'; | ||||
| import './index.less'; | import './index.less'; | ||||
| @@ -10,19 +11,29 @@ import './index.less'; | |||||
| type PageTitleProps = { | type PageTitleProps = { | ||||
| /** 标题 */ | /** 标题 */ | ||||
| title: React.ReactNode; | title: React.ReactNode; | ||||
| /** 图标 */ | |||||
| tooltip?: string; | |||||
| /** 自定义类名 */ | /** 自定义类名 */ | ||||
| className?: string; | className?: string; | ||||
| /** 自定义样式 */ | /** 自定义样式 */ | ||||
| style?: React.CSSProperties; | style?: React.CSSProperties; | ||||
| /** 自定义标题 */ | |||||
| titleRender?: () => React.ReactNode; | |||||
| }; | }; | ||||
| /** | /** | ||||
| * 页面标题 | * 页面标题 | ||||
| */ | */ | ||||
| function PageTitle({ title, style, className = '' }: PageTitleProps) { | |||||
| function PageTitle({ title, style, className, tooltip }: PageTitleProps) { | |||||
| return ( | return ( | ||||
| <div className={classNames('kf-page-title', className)} style={style}> | <div className={classNames('kf-page-title', className)} style={style}> | ||||
| {title} | |||||
| <div>{title}</div> | |||||
| {tooltip && ( | |||||
| <div className="kf-page-title__tips"> | |||||
| <KFIcon type="icon-tishi" font={14} /> | |||||
| <span style={{ marginLeft: '8px', fontSize: '14px' }}>{tooltip}</span> | |||||
| </div> | |||||
| )} | |||||
| </div> | </div> | ||||
| ); | ); | ||||
| } | } | ||||
| @@ -26,6 +26,12 @@ | |||||
| border: 1px solid rgba(22, 100, 255, 0.3); | border: 1px solid rgba(22, 100, 255, 0.3); | ||||
| border-radius: 8px; | border-radius: 8px; | ||||
| :global { | |||||
| .ant-tree-list-holder { | |||||
| overflow-x: hidden; | |||||
| } | |||||
| } | |||||
| &__search { | &__search { | ||||
| margin-bottom: 14px; | margin-bottom: 14px; | ||||
| padding-left: 0; | padding-left: 0; | ||||
| @@ -2,6 +2,7 @@ import { clearSessionToken } from '@/access'; | |||||
| import { setRemoteMenu } from '@/services/session'; | import { setRemoteMenu } from '@/services/session'; | ||||
| import { logout } from '@/services/system/auth'; | import { logout } from '@/services/system/auth'; | ||||
| import { ClientInfo } from '@/types'; | import { ClientInfo } from '@/types'; | ||||
| import { sleep } from '@/utils/promise'; | |||||
| import SessionStorage from '@/utils/sessionStorage'; | import SessionStorage from '@/utils/sessionStorage'; | ||||
| import { gotoLoginPage, oauthLogout } from '@/utils/ui'; | import { gotoLoginPage, oauthLogout } from '@/utils/ui'; | ||||
| import { LogoutOutlined, UserOutlined } from '@ant-design/icons'; | import { LogoutOutlined, UserOutlined } from '@ant-design/icons'; | ||||
| @@ -63,7 +64,8 @@ const AvatarDropdown: React.FC<GlobalHeaderRightProps> = ({ menu }) => { | |||||
| */ | */ | ||||
| const loginOut = async () => { | const loginOut = async () => { | ||||
| oauthLogout('http://172.20.32.197:31209/oauth/logout'); | oauthLogout('http://172.20.32.197:31209/oauth/logout'); | ||||
| await logout(); | |||||
| // 至少 1 秒后跳转,希望子系统能完成注销 | |||||
| await Promise.all([logout(), sleep(1000)]); | |||||
| clearSessionToken(); | clearSessionToken(); | ||||
| setRemoteMenu(null); | setRemoteMenu(null); | ||||
| gotoLoginPage(); | gotoLoginPage(); | ||||
| @@ -0,0 +1,55 @@ | |||||
| .create-hyperparameter { | |||||
| 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; | |||||
| } | |||||
| :global { | |||||
| .ant-input-number { | |||||
| width: 100%; | |||||
| } | |||||
| .ant-form-item { | |||||
| margin-bottom: 20px; | |||||
| } | |||||
| .image-url { | |||||
| margin-top: -15px; | |||||
| .ant-form-item-label > label::after { | |||||
| content: ''; | |||||
| } | |||||
| } | |||||
| .ant-btn-variant-text:disabled { | |||||
| color: @text-disabled-color; | |||||
| } | |||||
| .ant-btn-variant-text { | |||||
| color: #565658; | |||||
| } | |||||
| .ant-btn.ant-btn-icon-only .anticon { | |||||
| font-size: 20px; | |||||
| } | |||||
| .anticon-question-circle { | |||||
| margin-top: -12px; | |||||
| margin-left: 1px !important; | |||||
| color: @text-color-tertiary !important; | |||||
| font-size: 12px !important; | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,142 @@ | |||||
| /* | |||||
| * @Author: 赵伟 | |||||
| * @Date: 2024-04-16 13:58:08 | |||||
| * @Description: 创建实验 | |||||
| */ | |||||
| import PageTitle from '@/components/PageTitle'; | |||||
| import { AutoMLTaskType } from '@/enums'; | |||||
| import { | |||||
| addActiveLearnReq, | |||||
| getActiveLearnInfoReq, | |||||
| updateActiveLearnReq, | |||||
| } from '@/services/activeLearn'; | |||||
| import { safeInvoke } from '@/utils/functional'; | |||||
| import { to } from '@/utils/promise'; | |||||
| import { useLocation, useNavigate, useParams } from '@umijs/max'; | |||||
| import { App, Button, Form } from 'antd'; | |||||
| import { useEffect } from 'react'; | |||||
| import BasicConfig from '../components/CreateForm/BasicConfig'; | |||||
| import ExecuteConfig from '../components/CreateForm/ExecuteConfig'; | |||||
| import { ActiveLearnData, FormData } from '../types'; | |||||
| import styles from './index.less'; | |||||
| function CreateActiveLearn() { | |||||
| const navigate = useNavigate(); | |||||
| const [form] = Form.useForm(); | |||||
| const { message } = App.useApp(); | |||||
| const params = useParams(); | |||||
| const id = safeInvoke(Number)(params.id); | |||||
| const { pathname } = useLocation(); | |||||
| const isCopy = pathname.includes('copy'); | |||||
| useEffect(() => { | |||||
| // 编辑,复制 | |||||
| if (id && !Number.isNaN(id)) { | |||||
| getActiveLearnInfo(id); | |||||
| } | |||||
| }, [id]); | |||||
| // 获取服务详情 | |||||
| const getActiveLearnInfo = async (id: number) => { | |||||
| const [res] = await to(getActiveLearnInfoReq({ id })); | |||||
| if (res && res.data) { | |||||
| const info: ActiveLearnData = res.data; | |||||
| const { name: name_str, ...rest } = info; | |||||
| const name = isCopy ? `${name_str}-copy` : name_str; | |||||
| const formData = { | |||||
| ...rest, | |||||
| name, | |||||
| }; | |||||
| form.setFieldsValue(formData); | |||||
| } | |||||
| }; | |||||
| // 创建、更新、复制实验 | |||||
| const createExperiment = async (formData: FormData) => { | |||||
| // 根据后台要求,修改表单数据 | |||||
| const object = { | |||||
| ...formData, | |||||
| }; | |||||
| const params = | |||||
| id && !isCopy | |||||
| ? { | |||||
| id: id, | |||||
| ...object, | |||||
| } | |||||
| : object; | |||||
| const request = id && !isCopy ? updateActiveLearnReq : addActiveLearnReq; | |||||
| const [res] = await to(request(params)); | |||||
| if (res) { | |||||
| message.success('操作成功'); | |||||
| navigate(-1); | |||||
| } | |||||
| }; | |||||
| // 提交 | |||||
| const handleSubmit = (values: FormData) => { | |||||
| createExperiment(values); | |||||
| }; | |||||
| // 取消 | |||||
| const cancel = () => { | |||||
| navigate(-1); | |||||
| }; | |||||
| let buttonText = '新建'; | |||||
| let title = '新建实验'; | |||||
| if (id) { | |||||
| if (isCopy) { | |||||
| title = '复制实验'; | |||||
| buttonText = '确定'; | |||||
| } else { | |||||
| title = '编辑实验'; | |||||
| buttonText = '更新'; | |||||
| } | |||||
| } | |||||
| return ( | |||||
| <div className={styles['create-hyperparameter']}> | |||||
| <PageTitle title={title}></PageTitle> | |||||
| <div className={styles['create-hyperparameter__content']}> | |||||
| <div> | |||||
| <Form | |||||
| name="create-active-learn" | |||||
| labelCol={{ flex: '160px' }} | |||||
| labelAlign="left" | |||||
| form={form} | |||||
| onFinish={handleSubmit} | |||||
| size="large" | |||||
| autoComplete="off" | |||||
| scrollToFirstError | |||||
| initialValues={{ | |||||
| task_type: AutoMLTaskType.Classification, | |||||
| shuffle: false, | |||||
| }} | |||||
| > | |||||
| <BasicConfig /> | |||||
| <ExecuteConfig /> | |||||
| <Form.Item wrapperCol={{ offset: 0, span: 16 }} style={{ marginTop: '40px' }}> | |||||
| <Button type="primary" htmlType="submit"> | |||||
| {buttonText} | |||||
| </Button> | |||||
| <Button | |||||
| type="default" | |||||
| htmlType="button" | |||||
| onClick={cancel} | |||||
| style={{ marginLeft: '20px' }} | |||||
| > | |||||
| 取消 | |||||
| </Button> | |||||
| </Form.Item> | |||||
| </Form> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| ); | |||||
| } | |||||
| export default CreateActiveLearn; | |||||
| @@ -0,0 +1,40 @@ | |||||
| .auto-ml-info { | |||||
| position: relative; | |||||
| height: 100%; | |||||
| &__tabs { | |||||
| height: 50px; | |||||
| padding-left: 25px; | |||||
| background-image: url(@/assets/img/page-title-bg.png); | |||||
| background-repeat: no-repeat; | |||||
| background-position: top center; | |||||
| background-size: 100% 100%; | |||||
| } | |||||
| &__content { | |||||
| height: calc(100% - 60px); | |||||
| margin-top: 10px; | |||||
| } | |||||
| &__tips { | |||||
| position: absolute; | |||||
| top: 11px; | |||||
| left: 256px; | |||||
| padding: 3px 12px; | |||||
| color: #565658; | |||||
| font-size: @font-size-content; | |||||
| background: .addAlpha(@primary-color, 0.09) []; | |||||
| border-radius: 4px; | |||||
| &::before { | |||||
| position: absolute; | |||||
| top: 10px; | |||||
| left: -6px; | |||||
| width: 0; | |||||
| height: 0; | |||||
| border-top: 4px solid transparent; | |||||
| border-right: 6px solid .addAlpha(@primary-color, 0.09) []; | |||||
| border-bottom: 4px solid transparent; | |||||
| content: ''; | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,45 @@ | |||||
| /* | |||||
| * @Author: 赵伟 | |||||
| * @Date: 2024-04-16 13:58:08 | |||||
| * @Description: 主动学习实验详情 | |||||
| */ | |||||
| import PageTitle from '@/components/PageTitle'; | |||||
| import { getActiveLearnInfoReq } from '@/services/activeLearn'; | |||||
| import { safeInvoke } from '@/utils/functional'; | |||||
| import { to } from '@/utils/promise'; | |||||
| import { useParams } from '@umijs/max'; | |||||
| import { useEffect, useState } from 'react'; | |||||
| import ActiveLearnBasic from '../components/ActiveLearnBasic'; | |||||
| import { ActiveLearnData } from '../types'; | |||||
| import styles from './index.less'; | |||||
| function ActiveLearnInfo() { | |||||
| const params = useParams(); | |||||
| const id = safeInvoke(Number)(params.id); | |||||
| const [info, setInfo] = useState<ActiveLearnData | undefined>(undefined); | |||||
| useEffect(() => { | |||||
| if (id) { | |||||
| getActiveLearnInfo(); | |||||
| } | |||||
| }, []); | |||||
| // 获取详情 | |||||
| const getActiveLearnInfo = async () => { | |||||
| const [res] = await to(getActiveLearnInfoReq({ id: id })); | |||||
| if (res && res.data) { | |||||
| setInfo(res.data); | |||||
| } | |||||
| }; | |||||
| return ( | |||||
| <div className={styles['auto-ml-info']}> | |||||
| <PageTitle title="实验详情"></PageTitle> | |||||
| <div className={styles['auto-ml-info__content']}> | |||||
| <ActiveLearnBasic info={info} /> | |||||
| </div> | |||||
| </div> | |||||
| ); | |||||
| } | |||||
| export default ActiveLearnInfo; | |||||
| @@ -0,0 +1,42 @@ | |||||
| .active-learn-instance { | |||||
| height: 100%; | |||||
| &__tabs { | |||||
| height: 100%; | |||||
| :global { | |||||
| .ant-tabs-nav-list { | |||||
| width: 100%; | |||||
| height: 50px; | |||||
| padding-left: 15px; | |||||
| background-image: url(@/assets/img/page-title-bg.png); | |||||
| background-repeat: no-repeat; | |||||
| background-position: top center; | |||||
| background-size: 100% 100%; | |||||
| } | |||||
| .ant-tabs-content-holder { | |||||
| height: calc(100% - 50px); | |||||
| .ant-tabs-content { | |||||
| height: 100%; | |||||
| .ant-tabs-tabpane { | |||||
| height: 100%; | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| &__basic { | |||||
| height: calc(100% - 10px); | |||||
| margin-top: 10px; | |||||
| } | |||||
| &__log { | |||||
| height: calc(100% - 10px); | |||||
| margin-top: 10px; | |||||
| padding: 20px calc(@content-padding - 8px); | |||||
| overflow-y: visible; | |||||
| background-color: white; | |||||
| border-radius: 10px; | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,194 @@ | |||||
| import KFIcon from '@/components/KFIcon'; | |||||
| import { ExperimentStatus } from '@/enums'; | |||||
| import { getActiveLearnInsReq } from '@/services/activeLearn'; | |||||
| import { NodeStatus } from '@/types'; | |||||
| import { parseJsonText } from '@/utils'; | |||||
| import { safeInvoke } from '@/utils/functional'; | |||||
| import { to } from '@/utils/promise'; | |||||
| import { useParams } from '@umijs/max'; | |||||
| import { Tabs } from 'antd'; | |||||
| import { useEffect, useRef, useState } from 'react'; | |||||
| import ActiveLearnBasic from '../components/ActiveLearnBasic'; | |||||
| import ExperimentHistory from '../components/ExperimentHistory'; | |||||
| import ExperimentLog from '../components/ExperimentLog'; | |||||
| import ExperimentResult from '../components/ExperimentResult'; | |||||
| import { ActiveLearnData, ActiveLearnInstanceData } from '../types'; | |||||
| import styles from './index.less'; | |||||
| enum TabKeys { | |||||
| Params = 'params', | |||||
| Log = 'log', | |||||
| Result = 'result', | |||||
| History = 'history', | |||||
| } | |||||
| const NodePrefix = 'workflow'; | |||||
| function ActiveLearnInstance() { | |||||
| const [experimentInfo, setExperimentInfo] = useState<ActiveLearnData | undefined>(undefined); | |||||
| const [instanceInfo, setInstanceInfo] = useState<ActiveLearnInstanceData | undefined>(undefined); | |||||
| // 超参数寻优运行有3个节点,运行状态取工作流状态,而不是 auto-hpo 节点状态 | |||||
| const [workflowStatus, setWorkflowStatus] = useState<NodeStatus | undefined>(undefined); | |||||
| const [nodes, setNodes] = useState<Record<string, NodeStatus> | undefined>(undefined); | |||||
| const params = useParams(); | |||||
| const instanceId = safeInvoke(Number)(params.id); | |||||
| const evtSourceRef = useRef<EventSource | null>(null); | |||||
| useEffect(() => { | |||||
| if (instanceId) { | |||||
| getExperimentInsInfo(false); | |||||
| } | |||||
| return () => { | |||||
| closeSSE(); | |||||
| }; | |||||
| // eslint-disable-next-line react-hooks/exhaustive-deps | |||||
| }, [instanceId]); | |||||
| // 获取实验实例详情 | |||||
| const getExperimentInsInfo = async (isStatusDetermined: boolean) => { | |||||
| const [res] = await to(getActiveLearnInsReq(instanceId)); | |||||
| if (res && res.data) { | |||||
| const info = res.data as ActiveLearnInstanceData; | |||||
| const { param, node_status, argo_ins_name, argo_ins_ns, status } = info; | |||||
| // 解析配置参数 | |||||
| const paramJson = parseJsonText(param); | |||||
| if (paramJson) { | |||||
| setExperimentInfo(paramJson.data); | |||||
| } | |||||
| setInstanceInfo(info); | |||||
| // 这个接口返回的状态有延时,SSE 返回的状态是最新的 | |||||
| // SSE 调用时,不需要解析 node_status,也不要重新建立 SSE | |||||
| if (isStatusDetermined) { | |||||
| return; | |||||
| } | |||||
| // 进行节点状态 | |||||
| const nodeStatusJson = parseJsonText(node_status); | |||||
| if (nodeStatusJson) { | |||||
| setNodes(nodeStatusJson); | |||||
| Object.keys(nodeStatusJson).some((key) => { | |||||
| if (key.startsWith(NodePrefix)) { | |||||
| const workflowStatus = nodeStatusJson[key]; | |||||
| setWorkflowStatus(workflowStatus); | |||||
| return true; | |||||
| } | |||||
| return false; | |||||
| }); | |||||
| } | |||||
| // 运行中或者等待中,开启 SSE | |||||
| if (status === ExperimentStatus.Pending || status === ExperimentStatus.Running) { | |||||
| setupSSE(argo_ins_name, argo_ins_ns); | |||||
| } | |||||
| } | |||||
| }; | |||||
| const setupSSE = (name: string, namespace: string) => { | |||||
| const { origin } = location; | |||||
| const params = encodeURIComponent(`metadata.namespace=${namespace},metadata.name=${name}`); | |||||
| const evtSource = new EventSource( | |||||
| `${origin}/api/v1/realtimeStatus?listOptions.fieldSelector=${params}`, | |||||
| { withCredentials: false }, | |||||
| ); | |||||
| evtSource.onmessage = (event) => { | |||||
| const data = event?.data; | |||||
| if (!data) { | |||||
| return; | |||||
| } | |||||
| const dataJson = parseJsonText(data); | |||||
| if (dataJson) { | |||||
| const nodes = dataJson?.result?.object?.status?.nodes; | |||||
| if (nodes) { | |||||
| const workflowStatus = Object.values(nodes).find((node: any) => | |||||
| node.displayName.startsWith(NodePrefix), | |||||
| ) as NodeStatus; | |||||
| // 节点 | |||||
| setNodes(nodes); | |||||
| // 设置工作流状态 | |||||
| if (workflowStatus) { | |||||
| setWorkflowStatus(workflowStatus); | |||||
| // 实验结束,关闭 SSE | |||||
| if ( | |||||
| workflowStatus.phase !== ExperimentStatus.Pending && | |||||
| workflowStatus.phase !== ExperimentStatus.Running | |||||
| ) { | |||||
| closeSSE(); | |||||
| getExperimentInsInfo(true); | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| }; | |||||
| evtSource.onerror = (error) => { | |||||
| console.error('SSE error: ', error); | |||||
| }; | |||||
| evtSourceRef.current = evtSource; | |||||
| }; | |||||
| const closeSSE = () => { | |||||
| if (evtSourceRef.current) { | |||||
| evtSourceRef.current.close(); | |||||
| evtSourceRef.current = null; | |||||
| } | |||||
| }; | |||||
| const basicTabItems = [ | |||||
| { | |||||
| key: TabKeys.Params, | |||||
| label: '基本信息', | |||||
| icon: <KFIcon type="icon-jibenxinxi" />, | |||||
| children: ( | |||||
| <ActiveLearnBasic | |||||
| className={styles['active-learn-instance__basic']} | |||||
| info={experimentInfo} | |||||
| runStatus={workflowStatus} | |||||
| isInstance | |||||
| /> | |||||
| ), | |||||
| }, | |||||
| { | |||||
| key: TabKeys.Log, | |||||
| label: '日志', | |||||
| icon: <KFIcon type="icon-rizhi1" />, | |||||
| children: ( | |||||
| <div className={styles['active-learn-instance__log']}> | |||||
| {instanceInfo && nodes && <ExperimentLog instanceInfo={instanceInfo} nodes={nodes} />} | |||||
| </div> | |||||
| ), | |||||
| }, | |||||
| ]; | |||||
| const resultTabItems = [ | |||||
| { | |||||
| key: TabKeys.Result, | |||||
| label: '实验结果', | |||||
| icon: <KFIcon type="icon-shiyanjieguo1" />, | |||||
| children: <ExperimentResult fileUrl={instanceInfo?.result_txt} />, | |||||
| }, | |||||
| { | |||||
| key: TabKeys.History, | |||||
| label: '寻优列表', | |||||
| icon: <KFIcon type="icon-Trialliebiao" />, | |||||
| children: <ExperimentHistory trialList={instanceInfo?.trial_list ?? []} />, | |||||
| }, | |||||
| ]; | |||||
| const tabItems = | |||||
| instanceInfo?.status === ExperimentStatus.Succeeded | |||||
| ? [...basicTabItems, ...resultTabItems] | |||||
| : basicTabItems; | |||||
| return ( | |||||
| <div className={styles['active-learn-instance']}> | |||||
| <Tabs className={styles['active-learn-instance__tabs']} items={tabItems} /> | |||||
| </div> | |||||
| ); | |||||
| } | |||||
| export default ActiveLearnInstance; | |||||
| @@ -0,0 +1,13 @@ | |||||
| /* | |||||
| * @Author: 赵伟 | |||||
| * @Date: 2024-04-16 13:58:08 | |||||
| * @Description: 超参数自动寻优 | |||||
| */ | |||||
| import ExperimentList, { ExperimentListType } from '@/pages/AutoML/components/ExperimentList'; | |||||
| function ActiveLearn() { | |||||
| return <ExperimentList type={ExperimentListType.ActiveLearn} />; | |||||
| } | |||||
| export default ActiveLearn; | |||||
| @@ -0,0 +1,13 @@ | |||||
| .active-learn-basic { | |||||
| height: 100%; | |||||
| padding: 20px @content-padding; | |||||
| overflow-y: auto; | |||||
| background-color: white; | |||||
| border-radius: 10px; | |||||
| :global { | |||||
| .kf-basic-info__item__value__text { | |||||
| white-space: pre; | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,278 @@ | |||||
| import ConfigInfo, { type BasicInfoData } from '@/components/ConfigInfo'; | |||||
| import { AutoMLTaskType, autoMLTaskTypeOptions } from '@/enums'; | |||||
| import { useComputingResource } from '@/hooks/useComputingResource'; | |||||
| import { | |||||
| classifierAlgorithms, | |||||
| FrameworkType, | |||||
| frameworkTypeOptions, | |||||
| queryStrategies, | |||||
| regressorAlgorithms, | |||||
| } from '@/pages/ActiveLearn/components/CreateForm/utils'; | |||||
| import { ActiveLearnData } from '@/pages/ActiveLearn/types'; | |||||
| import { experimentStatusInfo } from '@/pages/Experiment/status'; | |||||
| import { type NodeStatus } from '@/types'; | |||||
| import { elapsedTime } from '@/utils/date'; | |||||
| import { | |||||
| formatBoolean, | |||||
| formatCodeConfig, | |||||
| formatDataset, | |||||
| formatDate, | |||||
| formatEnum, | |||||
| formatMirror, | |||||
| formatModel, | |||||
| } from '@/utils/format'; | |||||
| import { Flex } from 'antd'; | |||||
| import classNames from 'classnames'; | |||||
| import { useMemo } from 'react'; | |||||
| import styles from './index.less'; | |||||
| type BasicInfoProps = { | |||||
| info?: ActiveLearnData; | |||||
| className?: string; | |||||
| isInstance?: boolean; | |||||
| runStatus?: NodeStatus; | |||||
| }; | |||||
| function BasicInfo({ info, className, runStatus, isInstance = false }: BasicInfoProps) { | |||||
| const getResourceDescription = useComputingResource()[1]; | |||||
| const basicDatas: BasicInfoData[] = useMemo(() => { | |||||
| if (!info) { | |||||
| return []; | |||||
| } | |||||
| return [ | |||||
| { | |||||
| label: '实验名称', | |||||
| value: info.name, | |||||
| }, | |||||
| { | |||||
| label: '实验描述', | |||||
| value: info.description, | |||||
| }, | |||||
| { | |||||
| label: '创建人', | |||||
| value: info.create_by, | |||||
| }, | |||||
| { | |||||
| label: '创建时间', | |||||
| value: info.create_time, | |||||
| format: formatDate, | |||||
| }, | |||||
| { | |||||
| label: '更新时间', | |||||
| value: info.update_time, | |||||
| format: formatDate, | |||||
| }, | |||||
| ]; | |||||
| }, [info]); | |||||
| const configDatas: BasicInfoData[] = useMemo(() => { | |||||
| if (!info) { | |||||
| return []; | |||||
| } | |||||
| const modelInfo = [ | |||||
| { | |||||
| label: '预训练模型', | |||||
| value: info.model, | |||||
| format: formatModel, | |||||
| }, | |||||
| { | |||||
| label: '模型文件路径', | |||||
| value: info.model_py, | |||||
| }, | |||||
| { | |||||
| label: '模型类名称', | |||||
| value: info.model_class_name, | |||||
| }, | |||||
| { | |||||
| label: 'epochs', | |||||
| value: info.epochs, | |||||
| }, | |||||
| ]; | |||||
| const lossInfo = [ | |||||
| { | |||||
| label: 'loss文件路径', | |||||
| value: info.loss_py, | |||||
| }, | |||||
| { | |||||
| label: 'loss类名', | |||||
| value: info.loss_class_name, | |||||
| }, | |||||
| { | |||||
| label: '学习率', | |||||
| value: info.lr, | |||||
| }, | |||||
| ]; | |||||
| const algorithmInfo = [ | |||||
| { | |||||
| label: info.task_type === AutoMLTaskType.Regression ? '回归算法' : '分类算法', | |||||
| value: | |||||
| info.task_type === AutoMLTaskType.Regression ? info.regressor_alg : info.classifier_alg, | |||||
| format: formatEnum( | |||||
| info.task_type === AutoMLTaskType.Regression ? regressorAlgorithms : classifierAlgorithms, | |||||
| ), | |||||
| }, | |||||
| ]; | |||||
| const diffInfo = | |||||
| info.framework_type === FrameworkType.Pytorch | |||||
| ? [...modelInfo, ...lossInfo] | |||||
| : info.framework_type === FrameworkType.Keras | |||||
| ? modelInfo | |||||
| : algorithmInfo; | |||||
| return [ | |||||
| { | |||||
| label: '任务类型', | |||||
| value: info.task_type, | |||||
| format: formatEnum(autoMLTaskTypeOptions), | |||||
| }, | |||||
| { | |||||
| label: '框架类型', | |||||
| value: info.framework_type, | |||||
| format: formatEnum(frameworkTypeOptions), | |||||
| }, | |||||
| ...diffInfo, | |||||
| { | |||||
| label: '代码配置', | |||||
| value: info.code_config, | |||||
| format: formatCodeConfig, | |||||
| }, | |||||
| { | |||||
| label: '数据集', | |||||
| value: info.dataset, | |||||
| format: formatDataset, | |||||
| }, | |||||
| { | |||||
| label: '数据集处理文件路径', | |||||
| value: info.dataset_py, | |||||
| }, | |||||
| { | |||||
| label: '数据集类名', | |||||
| value: info.dataset_class_name, | |||||
| }, | |||||
| { | |||||
| label: '镜像', | |||||
| value: info.image, | |||||
| format: formatMirror, | |||||
| }, | |||||
| { | |||||
| label: '资源规格', | |||||
| value: info.computing_resource_id, | |||||
| format: getResourceDescription, | |||||
| }, | |||||
| { | |||||
| label: '是否打乱', | |||||
| value: info.shuffle, | |||||
| format: formatBoolean, | |||||
| }, | |||||
| { | |||||
| label: '数据量', | |||||
| value: info.data_size, | |||||
| }, | |||||
| { | |||||
| label: '训练集数据量', | |||||
| value: info.train_size, | |||||
| }, | |||||
| { | |||||
| label: '初始训练数据量', | |||||
| value: info.initial_num, | |||||
| }, | |||||
| { | |||||
| label: '查询次数', | |||||
| value: info.queries_num, | |||||
| }, | |||||
| { | |||||
| label: '每次查询数据量', | |||||
| value: info.instances_num, | |||||
| }, | |||||
| { | |||||
| label: '查询策略', | |||||
| value: info.query_strategy, | |||||
| format: formatEnum(queryStrategies), | |||||
| }, | |||||
| { | |||||
| label: '检查点轮数', | |||||
| value: info.checkpoint_num, | |||||
| }, | |||||
| { | |||||
| label: 'batch_size', | |||||
| value: info.batch_size, | |||||
| }, | |||||
| ]; | |||||
| }, [info, getResourceDescription]); | |||||
| const instanceDatas = useMemo(() => { | |||||
| if (!runStatus) { | |||||
| return []; | |||||
| } | |||||
| return [ | |||||
| { | |||||
| label: '启动时间', | |||||
| value: formatDate(runStatus.startedAt), | |||||
| ellipsis: true, | |||||
| }, | |||||
| { | |||||
| label: '执行时长', | |||||
| value: elapsedTime(runStatus.startedAt, runStatus.finishedAt), | |||||
| ellipsis: true, | |||||
| }, | |||||
| { | |||||
| label: '状态', | |||||
| value: ( | |||||
| <Flex align="center"> | |||||
| <img | |||||
| style={{ width: '17px', marginRight: '7px' }} | |||||
| src={experimentStatusInfo[runStatus.phase]?.icon} | |||||
| draggable={false} | |||||
| alt="" | |||||
| /> | |||||
| <div | |||||
| style={{ | |||||
| color: experimentStatusInfo[runStatus?.phase]?.color, | |||||
| fontSize: '15px', | |||||
| lineHeight: 1.6, | |||||
| }} | |||||
| > | |||||
| {experimentStatusInfo[runStatus?.phase]?.label} | |||||
| </div> | |||||
| </Flex> | |||||
| ), | |||||
| ellipsis: true, | |||||
| }, | |||||
| ]; | |||||
| }, [runStatus]); | |||||
| return ( | |||||
| <div className={classNames(styles['active-learn-basic'], className)}> | |||||
| {isInstance && runStatus && ( | |||||
| <ConfigInfo | |||||
| title="运行信息" | |||||
| datas={instanceDatas} | |||||
| labelWidth={70} | |||||
| style={{ marginBottom: '20px' }} | |||||
| /> | |||||
| )} | |||||
| {!isInstance && ( | |||||
| <ConfigInfo | |||||
| title="基本信息" | |||||
| datas={basicDatas} | |||||
| labelWidth={70} | |||||
| style={{ marginBottom: '20px' }} | |||||
| /> | |||||
| )} | |||||
| <ConfigInfo | |||||
| title="配置信息" | |||||
| datas={configDatas} | |||||
| labelWidth={120} | |||||
| style={{ marginBottom: '20px' }} | |||||
| ></ConfigInfo> | |||||
| </div> | |||||
| ); | |||||
| } | |||||
| export default BasicInfo; | |||||
| @@ -0,0 +1,54 @@ | |||||
| import SubAreaTitle from '@/components/SubAreaTitle'; | |||||
| import { Col, Form, Input, Row } from 'antd'; | |||||
| function BasicConfig() { | |||||
| return ( | |||||
| <> | |||||
| <SubAreaTitle | |||||
| title="基本信息" | |||||
| image={require('@/assets/img/mirror-basic.png')} | |||||
| style={{ marginBottom: '26px' }} | |||||
| ></SubAreaTitle> | |||||
| <Row gutter={8}> | |||||
| <Col span={10}> | |||||
| <Form.Item | |||||
| label="实验名称" | |||||
| name="name" | |||||
| rules={[ | |||||
| { | |||||
| required: true, | |||||
| message: '请输入实验名称', | |||||
| }, | |||||
| ]} | |||||
| > | |||||
| <Input placeholder="请输入实验名称" maxLength={64} showCount allowClear /> | |||||
| </Form.Item> | |||||
| </Col> | |||||
| </Row> | |||||
| <Row gutter={8}> | |||||
| <Col span={20}> | |||||
| <Form.Item | |||||
| label="实验描述" | |||||
| name="description" | |||||
| rules={[ | |||||
| { | |||||
| required: true, | |||||
| message: '请输入实验描述', | |||||
| }, | |||||
| ]} | |||||
| > | |||||
| <Input.TextArea | |||||
| autoSize={{ minRows: 2, maxRows: 6 }} | |||||
| placeholder="请输入实验描述" | |||||
| maxLength={256} | |||||
| showCount | |||||
| allowClear | |||||
| /> | |||||
| </Form.Item> | |||||
| </Col> | |||||
| </Row> | |||||
| </> | |||||
| ); | |||||
| } | |||||
| export default BasicConfig; | |||||
| @@ -0,0 +1,518 @@ | |||||
| import CodeSelect from '@/components/CodeSelect'; | |||||
| import ParameterSelect from '@/components/ParameterSelect'; | |||||
| import ResourceSelect, { | |||||
| requiredValidator, | |||||
| ResourceSelectorType, | |||||
| } from '@/components/ResourceSelect'; | |||||
| import SubAreaTitle from '@/components/SubAreaTitle'; | |||||
| import { AutoMLTaskType, autoMLTaskTypeOptions } from '@/enums'; | |||||
| import { Col, Form, Input, InputNumber, Radio, Row, Select, Switch } from 'antd'; | |||||
| import { | |||||
| classifierAlgorithms, | |||||
| FrameworkType, | |||||
| frameworkTypeOptions, | |||||
| queryStrategies, | |||||
| regressorAlgorithms, | |||||
| } from './utils'; | |||||
| function ExecuteConfig() { | |||||
| const form = Form.useFormInstance(); | |||||
| return ( | |||||
| <> | |||||
| <SubAreaTitle | |||||
| title="配置信息" | |||||
| image={require('@/assets/img/model-deployment.png')} | |||||
| style={{ marginTop: '20px', marginBottom: '24px' }} | |||||
| ></SubAreaTitle> | |||||
| <Row gutter={8}> | |||||
| <Col span={10}> | |||||
| <Form.Item | |||||
| label="任务类型" | |||||
| name="task_type" | |||||
| rules={[{ required: true, message: '请选择任务类型' }]} | |||||
| > | |||||
| <Radio.Group | |||||
| options={autoMLTaskTypeOptions} | |||||
| onChange={() => form.resetFields(['metrics'])} | |||||
| ></Radio.Group> | |||||
| </Form.Item> | |||||
| </Col> | |||||
| </Row> | |||||
| <Row gutter={8}> | |||||
| <Col span={10}> | |||||
| <Form.Item | |||||
| label="框架类型" | |||||
| name="framework_type" | |||||
| rules={[ | |||||
| { | |||||
| required: true, | |||||
| message: '请选择框架类型', | |||||
| }, | |||||
| ]} | |||||
| > | |||||
| <Select | |||||
| placeholder="请选择框架类型" | |||||
| options={frameworkTypeOptions} | |||||
| showSearch | |||||
| allowClear | |||||
| /> | |||||
| </Form.Item> | |||||
| </Col> | |||||
| </Row> | |||||
| <Form.Item dependencies={['task_type', 'framework_type']} noStyle> | |||||
| {({ getFieldValue }) => { | |||||
| const taskType = getFieldValue('task_type'); | |||||
| const frameworkType = getFieldValue('framework_type'); | |||||
| if (frameworkType === FrameworkType.Keras || frameworkType === FrameworkType.Pytorch) { | |||||
| return ( | |||||
| <> | |||||
| <Row gutter={8}> | |||||
| <Col span={10}> | |||||
| <Form.Item label="预训练模型" name="model"> | |||||
| <ResourceSelect | |||||
| type={ResourceSelectorType.Model} | |||||
| placeholder="请选择模型" | |||||
| canInput={false} | |||||
| size="large" | |||||
| /> | |||||
| </Form.Item> | |||||
| </Col> | |||||
| </Row> | |||||
| <Row gutter={8}> | |||||
| <Col span={10}> | |||||
| <Form.Item | |||||
| label="模型文件路径" | |||||
| name="model_py" | |||||
| rules={[ | |||||
| { | |||||
| required: true, | |||||
| message: '请输入模型文件路径', | |||||
| }, | |||||
| ]} | |||||
| > | |||||
| <Input placeholder="请输入模型文件路径" maxLength={64} showCount allowClear /> | |||||
| </Form.Item> | |||||
| </Col> | |||||
| </Row> | |||||
| <Row gutter={8}> | |||||
| <Col span={10}> | |||||
| <Form.Item | |||||
| label="模型类名称" | |||||
| name="model_class_name" | |||||
| rules={[ | |||||
| { | |||||
| required: true, | |||||
| message: '请输入模型类名称', | |||||
| }, | |||||
| ]} | |||||
| > | |||||
| <Input placeholder="请输入模型类名称" maxLength={64} showCount allowClear /> | |||||
| </Form.Item> | |||||
| </Col> | |||||
| </Row> | |||||
| <Row gutter={8}> | |||||
| <Col span={10}> | |||||
| <Form.Item | |||||
| label="epochs" | |||||
| name="epochs" | |||||
| rules={[ | |||||
| { | |||||
| required: true, | |||||
| message: '请输入epochs', | |||||
| }, | |||||
| ]} | |||||
| > | |||||
| <InputNumber placeholder="请输入epochs" min={0} precision={0} /> | |||||
| </Form.Item> | |||||
| </Col> | |||||
| </Row> | |||||
| {frameworkType === FrameworkType.Pytorch ? ( | |||||
| <> | |||||
| <Row gutter={8}> | |||||
| <Col span={10}> | |||||
| <Form.Item | |||||
| label="loss 文件路径" | |||||
| name="loss_py" | |||||
| rules={[ | |||||
| { | |||||
| required: true, | |||||
| message: '请输入 loss 文件路径', | |||||
| }, | |||||
| ]} | |||||
| > | |||||
| <Input | |||||
| placeholder="请输入 loss 文件路径" | |||||
| maxLength={64} | |||||
| showCount | |||||
| allowClear | |||||
| /> | |||||
| </Form.Item> | |||||
| </Col> | |||||
| </Row> | |||||
| <Row gutter={8}> | |||||
| <Col span={10}> | |||||
| <Form.Item | |||||
| label="loss 类名" | |||||
| name="loss_class_name" | |||||
| rules={[ | |||||
| { | |||||
| required: true, | |||||
| message: '请输入 loss 类名', | |||||
| }, | |||||
| ]} | |||||
| > | |||||
| <Input | |||||
| placeholder="请输入 loss 类名" | |||||
| maxLength={64} | |||||
| showCount | |||||
| allowClear | |||||
| /> | |||||
| </Form.Item> | |||||
| </Col> | |||||
| </Row> | |||||
| <Row gutter={8}> | |||||
| <Col span={10}> | |||||
| <Form.Item | |||||
| label="学习率" | |||||
| name="lr" | |||||
| rules={[ | |||||
| { | |||||
| required: true, | |||||
| message: '请输入学习率', | |||||
| }, | |||||
| ]} | |||||
| > | |||||
| <InputNumber placeholder="请输入学习率" min={0} /> | |||||
| </Form.Item> | |||||
| </Col> | |||||
| </Row> | |||||
| </> | |||||
| ) : null} | |||||
| </> | |||||
| ); | |||||
| } else if (frameworkType === FrameworkType.Sklearn) { | |||||
| if (taskType === AutoMLTaskType.Classification) { | |||||
| return ( | |||||
| <> | |||||
| <Row gutter={8}> | |||||
| <Col span={10}> | |||||
| <Form.Item | |||||
| label="分类算法" | |||||
| name="classifier_alg" | |||||
| rules={[ | |||||
| { | |||||
| required: true, | |||||
| message: '请选择分类算法', | |||||
| }, | |||||
| ]} | |||||
| > | |||||
| <Select | |||||
| placeholder="请选择分类算法" | |||||
| options={classifierAlgorithms} | |||||
| showSearch | |||||
| allowClear | |||||
| /> | |||||
| </Form.Item> | |||||
| </Col> | |||||
| </Row> | |||||
| </> | |||||
| ); | |||||
| } else { | |||||
| return ( | |||||
| <> | |||||
| <Row gutter={8}> | |||||
| <Col span={10}> | |||||
| <Form.Item | |||||
| label="回归算法" | |||||
| name="regressor_alg" | |||||
| rules={[ | |||||
| { | |||||
| required: true, | |||||
| message: '请选择回归算法', | |||||
| }, | |||||
| ]} | |||||
| > | |||||
| <Select | |||||
| placeholder="请选择回归算法" | |||||
| options={regressorAlgorithms} | |||||
| showSearch | |||||
| allowClear | |||||
| /> | |||||
| </Form.Item> | |||||
| </Col> | |||||
| </Row> | |||||
| </> | |||||
| ); | |||||
| } | |||||
| } else { | |||||
| return null; | |||||
| } | |||||
| }} | |||||
| </Form.Item> | |||||
| <Row gutter={8}> | |||||
| <Col span={10}> | |||||
| <Form.Item | |||||
| label="代码配置" | |||||
| name="code_config" | |||||
| rules={[ | |||||
| { | |||||
| validator: requiredValidator, | |||||
| message: '请选择代码配置', | |||||
| }, | |||||
| ]} | |||||
| required | |||||
| > | |||||
| <CodeSelect placeholder="请选择代码配置" canInput={false} size="large" /> | |||||
| </Form.Item> | |||||
| </Col> | |||||
| </Row> | |||||
| <Row gutter={8}> | |||||
| <Col span={10}> | |||||
| <Form.Item | |||||
| label="数据集" | |||||
| name="dataset" | |||||
| rules={[ | |||||
| { | |||||
| validator: requiredValidator, | |||||
| message: '请选择数据集', | |||||
| }, | |||||
| ]} | |||||
| required | |||||
| > | |||||
| <ResourceSelect | |||||
| type={ResourceSelectorType.Dataset} | |||||
| placeholder="请选择数据集" | |||||
| canInput={false} | |||||
| size="large" | |||||
| /> | |||||
| </Form.Item> | |||||
| </Col> | |||||
| </Row> | |||||
| <Row gutter={8}> | |||||
| <Col span={10}> | |||||
| <Form.Item | |||||
| label="数据集处理文件路径" | |||||
| name="dataset_py" | |||||
| rules={[ | |||||
| { | |||||
| required: true, | |||||
| message: '请输入数据集处理文件路径', | |||||
| }, | |||||
| ]} | |||||
| > | |||||
| <Input placeholder="请输入数据集处理文件路径" maxLength={64} showCount allowClear /> | |||||
| </Form.Item> | |||||
| </Col> | |||||
| </Row> | |||||
| <Row gutter={8}> | |||||
| <Col span={10}> | |||||
| <Form.Item | |||||
| label="数据集类名" | |||||
| name="dataset_class_name" | |||||
| rules={[ | |||||
| { | |||||
| required: true, | |||||
| message: '请输入数据集类名', | |||||
| }, | |||||
| ]} | |||||
| > | |||||
| <Input placeholder="请输入数据集类名" maxLength={64} showCount allowClear /> | |||||
| </Form.Item> | |||||
| </Col> | |||||
| </Row> | |||||
| <Row gutter={8}> | |||||
| <Col span={10}> | |||||
| <Form.Item | |||||
| label="数据量" | |||||
| name="data_size" | |||||
| rules={[ | |||||
| { | |||||
| required: true, | |||||
| message: '请输入数据量', | |||||
| }, | |||||
| ]} | |||||
| > | |||||
| <InputNumber placeholder="请输入数据量" min={0} precision={0} /> | |||||
| </Form.Item> | |||||
| </Col> | |||||
| </Row> | |||||
| <Row gutter={8}> | |||||
| <Col span={10}> | |||||
| <Form.Item | |||||
| label="镜像" | |||||
| name="image" | |||||
| rules={[ | |||||
| { | |||||
| validator: requiredValidator, | |||||
| message: '请选择镜像', | |||||
| }, | |||||
| ]} | |||||
| required | |||||
| > | |||||
| <ResourceSelect | |||||
| type={ResourceSelectorType.Mirror} | |||||
| placeholder="请选择镜像" | |||||
| canInput={false} | |||||
| /> | |||||
| </Form.Item> | |||||
| </Col> | |||||
| </Row> | |||||
| <Row gutter={8}> | |||||
| <Col span={10}> | |||||
| <Form.Item | |||||
| label="资源规格" | |||||
| name="computing_resource_id" | |||||
| rules={[ | |||||
| { | |||||
| required: true, | |||||
| message: '请选择资源规格', | |||||
| }, | |||||
| ]} | |||||
| > | |||||
| <ParameterSelect dataType="resource" placeholder="请选择资源规格" /> | |||||
| </Form.Item> | |||||
| </Col> | |||||
| </Row> | |||||
| <Row gutter={8}> | |||||
| <Col span={10}> | |||||
| <Form.Item label="是否随机打乱" name="shuffle" valuePropName="checked"> | |||||
| <Switch /> | |||||
| </Form.Item> | |||||
| </Col> | |||||
| </Row> | |||||
| <Row gutter={8}> | |||||
| <Col span={10}> | |||||
| <Form.Item | |||||
| label="训练集数据量" | |||||
| name="train_size" | |||||
| rules={[ | |||||
| { | |||||
| required: true, | |||||
| message: '请输入训练集数据量', | |||||
| }, | |||||
| ]} | |||||
| > | |||||
| <InputNumber placeholder="请输入训练集数据量" min={0} precision={0} /> | |||||
| </Form.Item> | |||||
| </Col> | |||||
| </Row> | |||||
| <Row gutter={8}> | |||||
| <Col span={10}> | |||||
| <Form.Item | |||||
| label="初始训练数据量" | |||||
| name="initial_num" | |||||
| rules={[ | |||||
| { | |||||
| required: true, | |||||
| message: '请输入初始训练数据量', | |||||
| }, | |||||
| ]} | |||||
| > | |||||
| <InputNumber placeholder="请输入初始训练数据量" min={0} precision={0} /> | |||||
| </Form.Item> | |||||
| </Col> | |||||
| </Row> | |||||
| <Row gutter={8}> | |||||
| <Col span={10}> | |||||
| <Form.Item | |||||
| label="查询次数" | |||||
| name="queries_num" | |||||
| rules={[ | |||||
| { | |||||
| required: true, | |||||
| message: '请输入查询次数量', | |||||
| }, | |||||
| ]} | |||||
| > | |||||
| <InputNumber placeholder="请输入查询次数" min={0} precision={0} /> | |||||
| </Form.Item> | |||||
| </Col> | |||||
| </Row> | |||||
| <Row gutter={8}> | |||||
| <Col span={10}> | |||||
| <Form.Item | |||||
| label="每次查询数据量" | |||||
| name="instances_num" | |||||
| rules={[ | |||||
| { | |||||
| required: true, | |||||
| message: '请输入每次查询数据量', | |||||
| }, | |||||
| ]} | |||||
| > | |||||
| <InputNumber placeholder="请输入每次查询数据量" min={0} precision={0} /> | |||||
| </Form.Item> | |||||
| </Col> | |||||
| </Row> | |||||
| <Row gutter={8}> | |||||
| <Col span={10}> | |||||
| <Form.Item | |||||
| label="查询策略" | |||||
| name="query_strategy" | |||||
| rules={[ | |||||
| { | |||||
| required: true, | |||||
| message: '请选择查询策略', | |||||
| }, | |||||
| ]} | |||||
| > | |||||
| <Select placeholder="请选择查询策略" options={queryStrategies} showSearch allowClear /> | |||||
| </Form.Item> | |||||
| </Col> | |||||
| </Row> | |||||
| <Row gutter={8}> | |||||
| <Col span={10}> | |||||
| <Form.Item | |||||
| label="检查点轮数" | |||||
| name="checkpoint_num" | |||||
| rules={[ | |||||
| { | |||||
| required: true, | |||||
| message: '请输入检查点轮数', | |||||
| }, | |||||
| ]} | |||||
| tooltip="多少轮查询保存一次模型参数" | |||||
| > | |||||
| <InputNumber placeholder="请输入检查点轮数" min={0} precision={0} /> | |||||
| </Form.Item> | |||||
| </Col> | |||||
| </Row> | |||||
| <Row gutter={8}> | |||||
| <Col span={10}> | |||||
| <Form.Item | |||||
| label="batch_size" | |||||
| name="batch_size" | |||||
| rules={[ | |||||
| { | |||||
| required: true, | |||||
| message: '请输入 batch_size', | |||||
| }, | |||||
| ]} | |||||
| > | |||||
| <InputNumber placeholder="请输入 batch_size" min={0} precision={0} /> | |||||
| </Form.Item> | |||||
| </Col> | |||||
| </Row> | |||||
| </> | |||||
| ); | |||||
| } | |||||
| export default ExecuteConfig; | |||||
| @@ -0,0 +1,92 @@ | |||||
| // 分类算法 | |||||
| export const classifierAlgorithms = [ | |||||
| { | |||||
| label: 'logistic_regression(逻辑回归)', | |||||
| value: 'logistic_regression', | |||||
| }, | |||||
| { | |||||
| label: 'decision_tree(决策树)', | |||||
| value: 'decision_tree', | |||||
| }, | |||||
| { | |||||
| label: 'random_forest(随机森林)', | |||||
| value: 'random_forest', | |||||
| }, | |||||
| { | |||||
| label: 'SVM(支持向量机)', | |||||
| value: 'SVM', | |||||
| }, | |||||
| { | |||||
| label: 'naive_bayes(朴素贝叶斯)', | |||||
| value: 'naive_bayes', | |||||
| }, | |||||
| { | |||||
| label: 'GBM(梯度提升树)', | |||||
| value: 'GBM', | |||||
| }, | |||||
| ]; | |||||
| // 回归算法 | |||||
| export const regressorAlgorithms = [ | |||||
| { | |||||
| label: 'bayesian_ridge(岭回归)', | |||||
| value: 'bayesian_ridge', | |||||
| }, | |||||
| { | |||||
| label: 'ARD_regression(自动相关性确定回归)', | |||||
| value: 'ARD_regression', | |||||
| }, | |||||
| { | |||||
| label: 'gaussian_process(高斯回归)', | |||||
| value: 'gaussian_process', | |||||
| } | |||||
| ]; | |||||
| // 框架类型 | |||||
| export enum FrameworkType { | |||||
| Sklearn = 'sklearn', | |||||
| Keras = 'keras', | |||||
| Pytorch = 'pytorch', | |||||
| } | |||||
| // 框架类型选项 | |||||
| export const frameworkTypeOptions = [ | |||||
| { | |||||
| label: FrameworkType.Sklearn, | |||||
| value: FrameworkType.Sklearn, | |||||
| }, | |||||
| { | |||||
| label: FrameworkType.Keras, | |||||
| value: FrameworkType.Keras, | |||||
| }, | |||||
| { | |||||
| label: FrameworkType.Pytorch, | |||||
| value: FrameworkType.Pytorch, | |||||
| }, | |||||
| ]; | |||||
| // 查询策略 | |||||
| export const queryStrategies = [ | |||||
| { | |||||
| label: 'uncertainty_sampling', | |||||
| value: 'uncertainty_sampling', | |||||
| }, | |||||
| { | |||||
| label: 'uncertainty_batch_sampling', | |||||
| value: 'uncertainty_batch_sampling', | |||||
| }, | |||||
| { | |||||
| label: 'max_std_sampling', | |||||
| value: 'max_std_sampling', | |||||
| }, | |||||
| { | |||||
| label: 'expected_improvement', | |||||
| value: 'expected_improvement', | |||||
| }, | |||||
| { | |||||
| label: 'upper_confidence_bound', | |||||
| value: 'upper_confidence_bound', | |||||
| } | |||||
| ]; | |||||
| @@ -0,0 +1,14 @@ | |||||
| .experiment-history { | |||||
| height: calc(100% - 10px); | |||||
| margin-top: 10px; | |||||
| &__content { | |||||
| height: 100%; | |||||
| padding: 20px @content-padding; | |||||
| background-color: white; | |||||
| border-radius: 10px; | |||||
| &__table { | |||||
| height: 100%; | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,132 @@ | |||||
| import { getFileReq } from '@/services/file'; | |||||
| import { to } from '@/utils/promise'; | |||||
| import tableCellRender from '@/utils/table'; | |||||
| import { Table, type TableProps } from 'antd'; | |||||
| import classNames from 'classnames'; | |||||
| import { useEffect, useState } from 'react'; | |||||
| import styles from './index.less'; | |||||
| type ExperimentHistoryProps = { | |||||
| fileUrl?: string; | |||||
| isClassification: boolean; | |||||
| }; | |||||
| type TableData = { | |||||
| id?: string; | |||||
| accuracy?: number; | |||||
| duration?: number; | |||||
| train_loss?: number; | |||||
| status?: string; | |||||
| feature?: string; | |||||
| althorithm?: string; | |||||
| }; | |||||
| function ExperimentHistory({ fileUrl, isClassification }: ExperimentHistoryProps) { | |||||
| const [tableData, setTableData] = useState<TableData[]>([]); | |||||
| useEffect(() => { | |||||
| if (fileUrl) { | |||||
| getHistoryFile(); | |||||
| } | |||||
| }, [fileUrl]); | |||||
| // 获取实验运行历史记录 | |||||
| const getHistoryFile = async () => { | |||||
| const [res] = await to(getFileReq(fileUrl)); | |||||
| if (res) { | |||||
| const data: any[] = res.data; | |||||
| const list: TableData[] = data.map((item) => { | |||||
| return { | |||||
| id: item[0]?.[0], | |||||
| accuracy: item[1]?.[5]?.accuracy, | |||||
| duration: item[1]?.[5]?.duration, | |||||
| train_loss: item[1]?.[5]?.train_loss, | |||||
| status: item[1]?.[2]?.['__enum__']?.split('.')?.[1], | |||||
| }; | |||||
| }); | |||||
| list.forEach((item) => { | |||||
| if (!item.id) return; | |||||
| const config = (res as any).configs?.[item.id]; | |||||
| item.feature = config?.['feature_preprocessor:__choice__']; | |||||
| item.althorithm = isClassification | |||||
| ? config?.['classifier:__choice__'] | |||||
| : config?.['regressor:__choice__']; | |||||
| }); | |||||
| setTableData(list); | |||||
| } | |||||
| }; | |||||
| const columns: TableProps<TableData>['columns'] = [ | |||||
| { | |||||
| title: 'ID', | |||||
| dataIndex: 'id', | |||||
| key: 'id', | |||||
| width: 80, | |||||
| render: tableCellRender(false), | |||||
| }, | |||||
| { | |||||
| title: '准确率', | |||||
| dataIndex: 'accuracy', | |||||
| key: 'accuracy', | |||||
| render: tableCellRender(true), | |||||
| ellipsis: { showTitle: false }, | |||||
| }, | |||||
| { | |||||
| title: '耗时', | |||||
| dataIndex: 'duration', | |||||
| key: 'duration', | |||||
| render: tableCellRender(true), | |||||
| ellipsis: { showTitle: false }, | |||||
| }, | |||||
| { | |||||
| title: '训练损失', | |||||
| dataIndex: 'train_loss', | |||||
| key: 'train_loss', | |||||
| render: tableCellRender(true), | |||||
| ellipsis: { showTitle: false }, | |||||
| }, | |||||
| { | |||||
| title: '特征处理', | |||||
| dataIndex: 'feature', | |||||
| key: 'feature', | |||||
| render: tableCellRender(true), | |||||
| ellipsis: { showTitle: false }, | |||||
| }, | |||||
| { | |||||
| title: '算法', | |||||
| dataIndex: 'althorithm', | |||||
| key: 'althorithm', | |||||
| render: tableCellRender(true), | |||||
| ellipsis: { showTitle: false }, | |||||
| }, | |||||
| { | |||||
| title: '状态', | |||||
| dataIndex: 'status', | |||||
| key: 'status', | |||||
| width: 120, | |||||
| render: tableCellRender(false), | |||||
| }, | |||||
| ]; | |||||
| return ( | |||||
| <div className={styles['experiment-history']}> | |||||
| <div className={styles['experiment-history__content']}> | |||||
| <div | |||||
| className={classNames( | |||||
| 'vertical-scroll-table-no-page', | |||||
| styles['experiment-history__content__table'], | |||||
| )} | |||||
| > | |||||
| <Table | |||||
| dataSource={tableData} | |||||
| columns={columns} | |||||
| pagination={false} | |||||
| scroll={{ y: 'calc(100% - 55px)' }} | |||||
| rowKey="id" | |||||
| /> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| ); | |||||
| } | |||||
| export default ExperimentHistory; | |||||
| @@ -0,0 +1,16 @@ | |||||
| .experiment-log { | |||||
| height: 100%; | |||||
| &__tabs { | |||||
| height: 100%; | |||||
| :global { | |||||
| .ant-tabs-nav-list { | |||||
| padding-left: 0 !important; | |||||
| background: none !important; | |||||
| } | |||||
| } | |||||
| &__log { | |||||
| height: 100%; | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,106 @@ | |||||
| import { ExperimentStatus } from '@/enums'; | |||||
| import { ActiveLearnInstanceData } from '@/pages/ActiveLearn/types'; | |||||
| import LogList from '@/pages/Experiment/components/LogList'; | |||||
| import { NodeStatus } from '@/types'; | |||||
| import { Tabs } from 'antd'; | |||||
| import styles from './index.less'; | |||||
| type ExperimentLogProps = { | |||||
| instanceInfo: ActiveLearnInstanceData; | |||||
| nodes: Record<string, NodeStatus>; | |||||
| }; | |||||
| function ExperimentLog({ instanceInfo, nodes }: ExperimentLogProps) { | |||||
| let hpoNodeStatus: NodeStatus | undefined; | |||||
| let frameworkCloneNodeStatus: NodeStatus | undefined; | |||||
| let trainCloneNodeStatus: NodeStatus | undefined; | |||||
| Object.keys(nodes) | |||||
| .sort((key1, key2) => { | |||||
| const node1 = nodes[key1]; | |||||
| const node2 = nodes[key2]; | |||||
| return new Date(node1.startedAt).getTime() - new Date(node2.startedAt).getTime(); | |||||
| }) | |||||
| .forEach((key) => { | |||||
| const node = nodes[key]; | |||||
| if (node.displayName.startsWith('active-learn')) { | |||||
| hpoNodeStatus = node; | |||||
| } else if (node.displayName.startsWith('git-clone') && !frameworkCloneNodeStatus) { | |||||
| frameworkCloneNodeStatus = node; | |||||
| } else if ( | |||||
| node.displayName.startsWith('git-clone') && | |||||
| frameworkCloneNodeStatus && | |||||
| node.displayName !== frameworkCloneNodeStatus?.displayName | |||||
| ) { | |||||
| trainCloneNodeStatus = node; | |||||
| } | |||||
| }); | |||||
| const tabItems = [ | |||||
| // { | |||||
| // key: 'git-clone-framework', | |||||
| // label: '框架代码日志', | |||||
| // // icon: <KFIcon type="icon-rizhi1" />, | |||||
| // children: ( | |||||
| // <div className={styles['experiment-log__tabs__log']}> | |||||
| // {frameworkCloneNodeStatus && ( | |||||
| // <LogList | |||||
| // instanceName={instanceInfo.argo_ins_name} | |||||
| // instanceNamespace={instanceInfo.argo_ins_ns} | |||||
| // pipelineNodeId={frameworkCloneNodeStatus.displayName} | |||||
| // workflowId={frameworkCloneNodeStatus.id} | |||||
| // instanceNodeStartTime={frameworkCloneNodeStatus.startedAt} | |||||
| // instanceNodeStatus={frameworkCloneNodeStatus.phase as ExperimentStatus} | |||||
| // ></LogList> | |||||
| // )} | |||||
| // </div> | |||||
| // ), | |||||
| // }, | |||||
| { | |||||
| key: 'git-clone-train', | |||||
| label: '系统日志', | |||||
| // icon: <KFIcon type="icon-rizhi1" />, | |||||
| children: ( | |||||
| <div className={styles['experiment-log__tabs__log']}> | |||||
| {trainCloneNodeStatus && ( | |||||
| <LogList | |||||
| instanceName={instanceInfo.argo_ins_name} | |||||
| instanceNamespace={instanceInfo.argo_ins_ns} | |||||
| pipelineNodeId={trainCloneNodeStatus.displayName} | |||||
| workflowId={trainCloneNodeStatus.id} | |||||
| instanceNodeStartTime={trainCloneNodeStatus.startedAt} | |||||
| instanceNodeStatus={trainCloneNodeStatus.phase as ExperimentStatus} | |||||
| ></LogList> | |||||
| )} | |||||
| </div> | |||||
| ), | |||||
| }, | |||||
| { | |||||
| key: 'active-learn', | |||||
| label: '主动学习日志', | |||||
| // icon: <KFIcon type="icon-rizhi1" />, | |||||
| children: ( | |||||
| <div className={styles['experiment-log__tabs__log']}> | |||||
| {hpoNodeStatus && ( | |||||
| <LogList | |||||
| instanceName={instanceInfo.argo_ins_name} | |||||
| instanceNamespace={instanceInfo.argo_ins_ns} | |||||
| pipelineNodeId={hpoNodeStatus.displayName} | |||||
| workflowId={hpoNodeStatus.id} | |||||
| instanceNodeStartTime={hpoNodeStatus.startedAt} | |||||
| instanceNodeStatus={hpoNodeStatus.phase as ExperimentStatus} | |||||
| ></LogList> | |||||
| )} | |||||
| </div> | |||||
| ), | |||||
| }, | |||||
| ]; | |||||
| return ( | |||||
| <div className={styles['experiment-log']}> | |||||
| <Tabs className={styles['experiment-log__tabs']} items={tabItems} /> | |||||
| </div> | |||||
| ); | |||||
| } | |||||
| export default ExperimentLog; | |||||
| @@ -0,0 +1,52 @@ | |||||
| .experiment-result { | |||||
| height: calc(100% - 10px); | |||||
| margin-top: 10px; | |||||
| padding: 20px @content-padding; | |||||
| overflow-y: auto; | |||||
| background-color: white; | |||||
| border-radius: 10px; | |||||
| &__download { | |||||
| padding-top: 16px; | |||||
| padding-bottom: 16px; | |||||
| padding-left: @content-padding; | |||||
| color: @text-color; | |||||
| font-size: 13px; | |||||
| background-color: #f8f8f9; | |||||
| border-radius: 4px; | |||||
| &__btn { | |||||
| display: block; | |||||
| height: 36px; | |||||
| margin-top: 15px; | |||||
| font-size: 14px; | |||||
| } | |||||
| } | |||||
| &__text { | |||||
| white-space: pre-wrap; | |||||
| } | |||||
| &__images { | |||||
| display: flex; | |||||
| align-items: flex-start; | |||||
| width: 100%; | |||||
| overflow-x: auto; | |||||
| :global { | |||||
| .ant-image { | |||||
| margin-right: 20px; | |||||
| &:last-child { | |||||
| margin-right: 0; | |||||
| } | |||||
| } | |||||
| } | |||||
| &__item { | |||||
| height: 248px; | |||||
| border: 1px solid rgba(96, 107, 122, 0.3); | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,83 @@ | |||||
| import InfoGroup from '@/components/InfoGroup'; | |||||
| import { getFileReq } from '@/services/file'; | |||||
| import { to } from '@/utils/promise'; | |||||
| import { Button, Image } from 'antd'; | |||||
| import { useEffect, useMemo, useState } from 'react'; | |||||
| import styles from './index.less'; | |||||
| type ExperimentResultProps = { | |||||
| fileUrl?: string; | |||||
| imageUrl?: string; | |||||
| modelPath?: string; | |||||
| }; | |||||
| function ExperimentResult({ fileUrl, imageUrl, modelPath }: ExperimentResultProps) { | |||||
| const [result, setResult] = useState<string | undefined>(''); | |||||
| const images = useMemo(() => { | |||||
| if (imageUrl) { | |||||
| return imageUrl.split(',').map((item) => item.trim()); | |||||
| } | |||||
| return []; | |||||
| }, [imageUrl]); | |||||
| useEffect(() => { | |||||
| if (fileUrl) { | |||||
| getResultFile(); | |||||
| } | |||||
| }, [fileUrl]); | |||||
| // 获取实验运行历史记录 | |||||
| const getResultFile = async () => { | |||||
| const [res] = await to(getFileReq(fileUrl)); | |||||
| if (res) { | |||||
| setResult(res as any as string); | |||||
| } | |||||
| }; | |||||
| return ( | |||||
| <div className={styles['experiment-result']}> | |||||
| <InfoGroup title="实验结果" height={420} width="100%"> | |||||
| <div className={styles['experiment-result__text']}>{result}</div> | |||||
| </InfoGroup> | |||||
| <InfoGroup title="可视化结果" style={{ margin: '16px 0' }}> | |||||
| <div className={styles['experiment-result__images']}> | |||||
| <Image.PreviewGroup | |||||
| preview={{ | |||||
| onChange: (current, prev) => | |||||
| console.log(`current index: ${current}, prev index: ${prev}`), | |||||
| }} | |||||
| > | |||||
| {images.map((item) => ( | |||||
| <Image | |||||
| key={item} | |||||
| className={styles['experiment-result__images__item']} | |||||
| src={item} | |||||
| height={248} | |||||
| draggable={false} | |||||
| alt="" | |||||
| /> | |||||
| ))} | |||||
| </Image.PreviewGroup> | |||||
| </div> | |||||
| </InfoGroup> | |||||
| {modelPath && ( | |||||
| <div className={styles['experiment-result__download']}> | |||||
| <span style={{ marginRight: '12px', color: '#606b7a' }}>文件名</span> | |||||
| <span>save_model.joblib</span> | |||||
| <Button | |||||
| type="primary" | |||||
| className={styles['experiment-result__download__btn']} | |||||
| onClick={() => { | |||||
| window.location.href = modelPath; | |||||
| }} | |||||
| > | |||||
| 模型下载 | |||||
| </Button> | |||||
| </div> | |||||
| )} | |||||
| </div> | |||||
| ); | |||||
| } | |||||
| export default ExperimentResult; | |||||
| @@ -0,0 +1,120 @@ | |||||
| { | |||||
| "workflow-xwnb8": { | |||||
| "id": "workflow-xwnb8", | |||||
| "name": "workflow-xwnb8", | |||||
| "type": "DAG", | |||||
| "phase": "Failed", | |||||
| "children": [ | |||||
| "workflow-xwnb8-1083129199" | |||||
| ], | |||||
| "progress": "2/3", | |||||
| "startedAt": "2025-04-18T06:56:18Z", | |||||
| "finishedAt": "2025-04-18T06:57:32Z", | |||||
| "displayName": "workflow-xwnb8", | |||||
| "templateName": "ml-workflow", | |||||
| "outboundNodes": [ | |||||
| "workflow-xwnb8-1355608520" | |||||
| ], | |||||
| "templateScope": "local/workflow-xwnb8", | |||||
| "resourcesDuration": { | |||||
| "cpu": 42, | |||||
| "memory": 851, | |||||
| "nvidia.com/gpu": 10 | |||||
| } | |||||
| }, | |||||
| "git-clone-9d0c5965": { | |||||
| "id": "workflow-xwnb8-514970004", | |||||
| "name": "workflow-xwnb8.git-clone-9d0c5965", | |||||
| "type": "Pod", | |||||
| "phase": "Succeeded", | |||||
| "outputs": { | |||||
| "exitCode": "0", | |||||
| "artifacts": [ | |||||
| { | |||||
| "s3": { | |||||
| "key": "workflow-xwnb8/workflow-xwnb8-git-clone-9d0c5965-514970004/main.log" | |||||
| }, | |||||
| "name": "main-logs" | |||||
| } | |||||
| ] | |||||
| }, | |||||
| "children": [ | |||||
| "workflow-xwnb8-1355608520" | |||||
| ], | |||||
| "progress": "1/1", | |||||
| "startedAt": "2025-04-18T06:56:38Z", | |||||
| "boundaryID": "workflow-xwnb8", | |||||
| "finishedAt": "2025-04-18T06:56:49Z", | |||||
| "displayName": "git-clone-9d0c5965", | |||||
| "hostNodeName": "k8s-node01", | |||||
| "templateName": "git-clone-9d0c5965", | |||||
| "templateScope": "local/workflow-xwnb8", | |||||
| "resourcesDuration": { | |||||
| "cpu": 1, | |||||
| "memory": 11 | |||||
| } | |||||
| }, | |||||
| "git-clone-e28c560c": { | |||||
| "id": "workflow-xwnb8-1083129199", | |||||
| "name": "workflow-xwnb8.git-clone-e28c560c", | |||||
| "type": "Pod", | |||||
| "phase": "Succeeded", | |||||
| "outputs": { | |||||
| "exitCode": "0", | |||||
| "artifacts": [ | |||||
| { | |||||
| "s3": { | |||||
| "key": "workflow-xwnb8/workflow-xwnb8-git-clone-e28c560c-1083129199/main.log" | |||||
| }, | |||||
| "name": "main-logs" | |||||
| } | |||||
| ] | |||||
| }, | |||||
| "children": [ | |||||
| "workflow-xwnb8-514970004" | |||||
| ], | |||||
| "progress": "1/1", | |||||
| "startedAt": "2025-04-18T06:56:18Z", | |||||
| "boundaryID": "workflow-xwnb8", | |||||
| "finishedAt": "2025-04-18T06:56:27Z", | |||||
| "displayName": "git-clone-e28c560c", | |||||
| "hostNodeName": "k8s-node01", | |||||
| "templateName": "git-clone-e28c560c", | |||||
| "templateScope": "local/workflow-xwnb8", | |||||
| "resourcesDuration": { | |||||
| "cpu": 1, | |||||
| "memory": 11 | |||||
| } | |||||
| }, | |||||
| "active-learn-b708ed0b": { | |||||
| "id": "workflow-xwnb8-1355608520", | |||||
| "name": "workflow-xwnb8.active-learn-b708ed0b", | |||||
| "type": "Pod", | |||||
| "phase": "Failed", | |||||
| "message": "Error (exit code 1)", | |||||
| "outputs": { | |||||
| "exitCode": "1", | |||||
| "artifacts": [ | |||||
| { | |||||
| "s3": { | |||||
| "key": "workflow-xwnb8/workflow-xwnb8-active-learn-b708ed0b-1355608520/main.log" | |||||
| }, | |||||
| "name": "main-logs" | |||||
| } | |||||
| ] | |||||
| }, | |||||
| "progress": "0/1", | |||||
| "startedAt": "2025-04-18T06:57:00Z", | |||||
| "boundaryID": "workflow-xwnb8", | |||||
| "finishedAt": "2025-04-18T06:57:27Z", | |||||
| "displayName": "active-learn-b708ed0b", | |||||
| "hostNodeName": "k8s-node01", | |||||
| "templateName": "active-learn-b708ed0b", | |||||
| "templateScope": "local/workflow-xwnb8", | |||||
| "resourcesDuration": { | |||||
| "cpu": 40, | |||||
| "memory": 829, | |||||
| "nvidia.com/gpu": 10 | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,85 @@ | |||||
| /* | |||||
| * @Author: error: error: git config user.name & please set dead value or install git && error: git config user.email & please set dead value or install git & please set dead value or install git | |||||
| * @Date: 2025-04-18 08:40:03 | |||||
| * @LastEditors: error: error: git config user.name & please set dead value or install git && error: git config user.email & please set dead value or install git & please set dead value or install git | |||||
| * @LastEditTime: 2025-04-18 11:30:21 | |||||
| * @FilePath: \ci4s\react-ui\src\pages\ActiveLearn\types.ts | |||||
| * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE | |||||
| */ | |||||
| import { type ParameterInputObject } from '@/components/ResourceSelect'; | |||||
| import { type NodeStatus } from '@/types'; | |||||
| import { AutoMLTaskType } from '@/enums'; | |||||
| // 操作类型 | |||||
| export enum OperationType { | |||||
| Create = 'Create', // 创建 | |||||
| Update = 'Update', // 更新 | |||||
| } | |||||
| // 表单数据 | |||||
| export type FormData = { | |||||
| name: string; // 实验名称 | |||||
| description: string; // 实验描述 | |||||
| task_type: AutoMLTaskType; // 任务类型 | |||||
| framework_type: string; // 框架类型 | |||||
| code_config: ParameterInputObject; // 代码配置 | |||||
| model?: ParameterInputObject; // 模型 | |||||
| model_py?: string; // 模型文件路径 | |||||
| model_class_name?: string; // 模型类名称 | |||||
| loss_py?: string; // loss文件路径 | |||||
| loss_class_name?: string; // loss类名 | |||||
| classifier_alg?: string; // 分类算法 | |||||
| regressor_alg?: string; // 回归算法 | |||||
| dataset: ParameterInputObject; // 数据集 | |||||
| dataset_py: string; // dataset处理文件路径 | |||||
| dataset_class_name: string; // dataset类名 | |||||
| data_size: number; // 数据量 | |||||
| train_size: number; // 训练集数据量 | |||||
| initial_num: number; // 初始训练数据量 | |||||
| queries_num: number; // 查询次数 | |||||
| instances_num: number; // 每次查询数据量 | |||||
| computing_resource_id: number; // 资源规格 | |||||
| image: ParameterInputObject; // 镜像 | |||||
| shuffle: boolean; // 是否随机打乱 | |||||
| query_strategy: string; // 查询策略 | |||||
| checkpoint_num: number; // 多少轮查询保存一次模型参数 | |||||
| batch_size: number; // batch_size | |||||
| epochs: number; // epochs | |||||
| lr: number; // 学习率 | |||||
| }; | |||||
| // 主动学习 | |||||
| export type ActiveLearnData = { | |||||
| id: number; | |||||
| progress: number; | |||||
| run_state: string; | |||||
| state: number; | |||||
| create_by?: string; | |||||
| create_time?: string; | |||||
| update_by?: string; | |||||
| update_time?: string; | |||||
| status_list: string; // 最近五次运行状态 | |||||
| } & FormData; | |||||
| // 主动学习实验实例 | |||||
| export type ActiveLearnInstanceData = { | |||||
| id: number; | |||||
| auto_ml_id: number; | |||||
| result_path: string; | |||||
| model_path: string; | |||||
| img_path: string; | |||||
| run_history_path: string; | |||||
| state: number; | |||||
| status: string; | |||||
| node_status: string; | |||||
| node_result: string; | |||||
| param: string; | |||||
| source: string | null; | |||||
| argo_ins_name: string; | |||||
| argo_ins_ns: string; | |||||
| create_time: string; | |||||
| update_time: string; | |||||
| finish_time: string; | |||||
| nodeStatus?: NodeStatus; | |||||
| }; | |||||
| @@ -4,6 +4,15 @@ | |||||
| * @Description: 实验列表组件配置 | * @Description: 实验列表组件配置 | ||||
| */ | */ | ||||
| import { | |||||
| batchDeleteActiveLearnInsReq, | |||||
| deleteActiveLearnInsReq, | |||||
| deleteActiveLearnReq, | |||||
| getActiveLearnInsListReq, | |||||
| getActiveLearnListReq, | |||||
| runActiveLearnReq, | |||||
| stopActiveLearnInsReq, | |||||
| } from '@/services/activeLearn'; | |||||
| import { | import { | ||||
| batchDeleteExperimentInsReq, | batchDeleteExperimentInsReq, | ||||
| deleteAutoMLReq, | deleteAutoMLReq, | ||||
| @@ -26,6 +35,7 @@ import { | |||||
| export enum ExperimentListType { | export enum ExperimentListType { | ||||
| AutoML = 'AutoML', | AutoML = 'AutoML', | ||||
| HyperParameter = 'HyperParameter', | HyperParameter = 'HyperParameter', | ||||
| ActiveLearn = 'ActiveLearn', | |||||
| } | } | ||||
| type ExperimentListInfo = { | type ExperimentListInfo = { | ||||
| @@ -72,4 +82,18 @@ export const experimentListConfig: Record<ExperimentListType, ExperimentListInfo | |||||
| descProperty: 'description', | descProperty: 'description', | ||||
| idProperty: 'rayId', | idProperty: 'rayId', | ||||
| }, | }, | ||||
| [ExperimentListType.ActiveLearn]: { | |||||
| getListReq: getActiveLearnListReq, | |||||
| getInsListReq: getActiveLearnInsListReq, | |||||
| deleteRecordReq: deleteActiveLearnReq, | |||||
| runRecordReq: runActiveLearnReq, | |||||
| deleteInsReq: deleteActiveLearnInsReq, | |||||
| batchDeleteInsReq: batchDeleteActiveLearnInsReq, | |||||
| stopInsReq: stopActiveLearnInsReq, | |||||
| title: '自动学习', | |||||
| pathPrefix: 'active-learn', | |||||
| nameProperty: 'name', | |||||
| descProperty: 'description', | |||||
| idProperty: 'activeLearnId', | |||||
| }, | |||||
| }; | }; | ||||
| @@ -63,7 +63,7 @@ function ExperimentList({ type }: ExperimentListProps) { | |||||
| const params: Record<string, any> = { | const params: Record<string, any> = { | ||||
| page: pagination.current! - 1, | page: pagination.current! - 1, | ||||
| size: pagination.pageSize, | size: pagination.pageSize, | ||||
| ml_name: searchText || undefined, | |||||
| [config.nameProperty]: searchText || undefined, | |||||
| }; | }; | ||||
| const request = config.getListReq; | const request = config.getListReq; | ||||
| const [res] = await to(request(params)); | const [res] = await to(request(params)); | ||||
| @@ -248,7 +248,7 @@ function ExperimentList({ type }: ExperimentListProps) { | |||||
| { | { | ||||
| title: '实验名称', | title: '实验名称', | ||||
| dataIndex: config.nameProperty, | dataIndex: config.nameProperty, | ||||
| key: 'ml_name', | |||||
| key: 'name', | |||||
| width: '16%', | width: '16%', | ||||
| render: tableCellRender(false, TableCellValueType.Link, { | render: tableCellRender(false, TableCellValueType.Link, { | ||||
| onClick: gotoDetail, | onClick: gotoDetail, | ||||
| @@ -257,7 +257,7 @@ function ExperimentList({ type }: ExperimentListProps) { | |||||
| { | { | ||||
| title: '实验描述', | title: '实验描述', | ||||
| dataIndex: config.descProperty, | dataIndex: config.descProperty, | ||||
| key: 'ml_description', | |||||
| key: 'description', | |||||
| render: tableCellRender(true), | render: tableCellRender(true), | ||||
| }, | }, | ||||
| { | { | ||||
| @@ -55,12 +55,10 @@ function EditorCreate() { | |||||
| // 创建编辑器 | // 创建编辑器 | ||||
| const createEditor = async (formData: FormData) => { | const createEditor = async (formData: FormData) => { | ||||
| // 根据后台要求,修改表单数据 | // 根据后台要求,修改表单数据 | ||||
| const image = formData['image']; | |||||
| const model = formData['model']; | const model = formData['model']; | ||||
| const dataset = formData['dataset']; | const dataset = formData['dataset']; | ||||
| const params = { | const params = { | ||||
| ...omit(formData, ['image', 'model', 'dataset']), | |||||
| image: image.value, | |||||
| ...omit(formData, ['model', 'dataset']), | |||||
| model: model && pick(model, ['id', 'version', 'path', 'showValue']), | model: model && pick(model, ['id', 'version', 'path', 'showValue']), | ||||
| dataset: dataset && pick(dataset, ['id', 'version', 'path', 'showValue']), | dataset: dataset && pick(dataset, ['id', 'version', 'path', 'showValue']), | ||||
| }; | }; | ||||
| @@ -77,6 +77,7 @@ function EditorList() { | |||||
| content.forEach((item: EditorData) => { | content.forEach((item: EditorData) => { | ||||
| item.dataset = typeof item.dataset === 'string' ? parseJsonText(item.dataset) : null; | item.dataset = typeof item.dataset === 'string' ? parseJsonText(item.dataset) : null; | ||||
| item.model = typeof item.model === 'string' ? parseJsonText(item.model) : null; | item.model = typeof item.model === 'string' ? parseJsonText(item.model) : null; | ||||
| item.image = typeof item.image === 'string' ? parseJsonText(item.image) : null; | |||||
| }); | }); | ||||
| setTableData(content); | setTableData(content); | ||||
| setTotal(totalElements); | setTotal(totalElements); | ||||
| @@ -224,7 +225,7 @@ function EditorList() { | |||||
| }, | }, | ||||
| { | { | ||||
| title: '镜像', | title: '镜像', | ||||
| dataIndex: ['image'], | |||||
| dataIndex: ['image', 'showValue'], | |||||
| key: 'image', | key: 'image', | ||||
| width: '15%', | width: '15%', | ||||
| render: tableCellRender(true), | render: tableCellRender(true), | ||||
| @@ -54,10 +54,7 @@ function LogGroup({ | |||||
| useEffect(() => { | useEffect(() => { | ||||
| // 建立 socket 连接 | // 建立 socket 连接 | ||||
| const setupSockect = () => { | const setupSockect = () => { | ||||
| let { host } = location; | |||||
| if (process.env.NODE_ENV === 'development') { | |||||
| host = '172.20.32.197:31213'; | |||||
| } | |||||
| const { host } = location; | |||||
| const socket = new WebSocket( | const socket = new WebSocket( | ||||
| `ws://${host}/newlog/realtimeLog?start=${start_time}&query={pod="${pod_name}"}`, | `ws://${host}/newlog/realtimeLog?start=${start_time}&query={pod="${pod_name}"}`, | ||||
| ); | ); | ||||
| @@ -20,7 +20,7 @@ function HyperparameterInfo() { | |||||
| undefined, | undefined, | ||||
| ); | ); | ||||
| // 获取自动机器学习详情 | |||||
| // 获取详情 | |||||
| const getHyperparameterInfo = useCallback(async () => { | const getHyperparameterInfo = useCallback(async () => { | ||||
| const [res] = await to(getRayInfoReq({ id: hyperparameterId })); | const [res] = await to(getRayInfoReq({ id: hyperparameterId })); | ||||
| if (res && res.data) { | if (res && res.data) { | ||||
| @@ -3,7 +3,6 @@ import LogList from '@/pages/Experiment/components/LogList'; | |||||
| import { HyperParameterInstanceData } from '@/pages/HyperParameter/types'; | import { HyperParameterInstanceData } from '@/pages/HyperParameter/types'; | ||||
| import { NodeStatus } from '@/types'; | import { NodeStatus } from '@/types'; | ||||
| import { Tabs } from 'antd'; | import { Tabs } from 'antd'; | ||||
| import { useEffect } from 'react'; | |||||
| import styles from './index.less'; | import styles from './index.less'; | ||||
| type ExperimentLogProps = { | type ExperimentLogProps = { | ||||
| @@ -97,8 +96,6 @@ function ExperimentLog({ instanceInfo, nodes }: ExperimentLogProps) { | |||||
| }, | }, | ||||
| ]; | ]; | ||||
| useEffect(() => {}, []); | |||||
| return ( | return ( | ||||
| <div className={styles['experiment-log']}> | <div className={styles['experiment-log']}> | ||||
| <Tabs className={styles['experiment-log__tabs']} items={tabItems} /> | <Tabs className={styles['experiment-log__tabs']} items={tabItems} /> | ||||
| @@ -41,7 +41,7 @@ export type HyperParameterData = { | |||||
| status_list: string; // 最近五次运行状态 | status_list: string; // 最近五次运行状态 | ||||
| } & FormData; | } & FormData; | ||||
| // 自动机器学习实验实例 | |||||
| // 实验实例 | |||||
| export type HyperParameterInstanceData = { | export type HyperParameterInstanceData = { | ||||
| id: number; | id: number; | ||||
| ray_id: number; | ray_id: number; | ||||
| @@ -0,0 +1,12 @@ | |||||
| /* | |||||
| * @Author: 赵伟 | |||||
| * @Date: 2025-04-21 16:38:59 | |||||
| * @Description: 知识图谱 | |||||
| */ | |||||
| import IframePage, { IframePageType } from '@/components/IFramePage'; | |||||
| function KnowledgePage() { | |||||
| return <IframePage type={IframePageType.Knowledge}></IframePage>; | |||||
| } | |||||
| export default KnowledgePage; | |||||
| @@ -117,7 +117,6 @@ function CreateServiceVersion() { | |||||
| // 创建版本 | // 创建版本 | ||||
| const createServiceVersion = async (formData: FormData) => { | const createServiceVersion = async (formData: FormData) => { | ||||
| const envList = formData['env_variables']; | const envList = formData['env_variables']; | ||||
| const image = formData['image']; | |||||
| const model = formData['model']; | const model = formData['model']; | ||||
| const codeConfig = formData['code_config']; | const codeConfig = formData['code_config']; | ||||
| const envVariables = envList?.reduce((acc, cur) => { | const envVariables = envList?.reduce((acc, cur) => { | ||||
| @@ -127,10 +126,9 @@ function CreateServiceVersion() { | |||||
| // 根据后台要求,修改表单数据 | // 根据后台要求,修改表单数据 | ||||
| const object = { | const object = { | ||||
| ...omit(formData, ['replicas', 'env_variables', 'image', 'model', 'code_config']), | |||||
| ...omit(formData, ['replicas', 'env_variables', 'model', 'code_config']), | |||||
| replicas: Number(formData.replicas), | replicas: Number(formData.replicas), | ||||
| env_variables: envVariables, | env_variables: envVariables, | ||||
| image: image.value, | |||||
| model: changePropertyName( | model: changePropertyName( | ||||
| pick(model, ['id', 'name', 'version', 'path', 'identifier', 'owner', 'showValue']), | pick(model, ['id', 'name', 'version', 'path', 'identifier', 'owner', 'showValue']), | ||||
| { showValue: 'show_value' }, | { showValue: 'show_value' }, | ||||
| @@ -292,7 +292,7 @@ function ServiceInfo() { | |||||
| }, | }, | ||||
| { | { | ||||
| title: '版本镜像', | title: '版本镜像', | ||||
| dataIndex: 'image', | |||||
| dataIndex: ['image', 'showValue'], | |||||
| key: 'image', | key: 'image', | ||||
| width: '20%', | width: '20%', | ||||
| render: tableCellRender(true), | render: tableCellRender(true), | ||||
| @@ -11,7 +11,7 @@ | |||||
| &__top { | &__top { | ||||
| display: flex; | display: flex; | ||||
| align-items: center; | align-items: center; | ||||
| justify-content: end; | |||||
| justify-content: flex-end; | |||||
| width: 100%; | width: 100%; | ||||
| height: 52px; | height: 52px; | ||||
| padding: 0 20px; | padding: 0 20px; | ||||
| @@ -0,0 +1,93 @@ | |||||
| /* | |||||
| * @Author: 赵伟 | |||||
| * @Date: 2024-11-18 10:18:27 | |||||
| * @Description: 主动学习 | |||||
| */ | |||||
| import { request } from '@umijs/max'; | |||||
| // 分页查询超参数自动寻优 | |||||
| export function getActiveLearnListReq(params) { | |||||
| return request(`/api/mmp/activeLearn`, { | |||||
| method: 'GET', | |||||
| params, | |||||
| }); | |||||
| } | |||||
| // 查询超参数自动寻优详情 | |||||
| export function getActiveLearnInfoReq(params) { | |||||
| return request(`/api/mmp/activeLearn/getActiveLearnDetail`, { | |||||
| method: 'GET', | |||||
| params, | |||||
| }); | |||||
| } | |||||
| // 新增超参数自动寻优 | |||||
| export function addActiveLearnReq(data) { | |||||
| return request(`/api/mmp/activeLearn`, { | |||||
| method: 'POST', | |||||
| data, | |||||
| }); | |||||
| } | |||||
| // 编辑超参数自动寻优 | |||||
| export function updateActiveLearnReq(data) { | |||||
| return request(`/api/mmp/activeLearn`, { | |||||
| method: 'PUT', | |||||
| data, | |||||
| }); | |||||
| } | |||||
| // 删除超参数自动寻优 | |||||
| export function deleteActiveLearnReq(id) { | |||||
| return request(`/api/mmp/activeLearn/${id}`, { | |||||
| method: 'DELETE', | |||||
| }); | |||||
| } | |||||
| // 运行超参数自动寻优 | |||||
| export function runActiveLearnReq(id) { | |||||
| return request(`/api/mmp/activeLearn/run/${id}`, { | |||||
| method: 'POST', | |||||
| }); | |||||
| } | |||||
| // ----------------------- 实验实例 ----------------------- | |||||
| // 获取实验实例列表 | |||||
| export function getActiveLearnInsListReq(params) { | |||||
| return request(`/api/mmp/activeLearnIns`, { | |||||
| method: 'GET', | |||||
| params, | |||||
| }); | |||||
| } | |||||
| // 查询实验实例详情 | |||||
| export function getActiveLearnInsReq(id) { | |||||
| return request(`/api/mmp/activeLearnIns/${id}`, { | |||||
| method: 'GET', | |||||
| }); | |||||
| } | |||||
| // 停止实验实例 | |||||
| export function stopActiveLearnInsReq(id) { | |||||
| return request(`/api/mmp/activeLearnIns/${id}`, { | |||||
| method: 'PUT', | |||||
| }); | |||||
| } | |||||
| // 删除实验实例 | |||||
| export function deleteActiveLearnInsReq(id) { | |||||
| return request(`/api/mmp/activeLearnIns/${id}`, { | |||||
| method: 'DELETE', | |||||
| }); | |||||
| } | |||||
| // 批量删除实验实例 | |||||
| export function batchDeleteActiveLearnInsReq(data) { | |||||
| return request(`/api/mmp/activeLearnIns/batchDelete`, { | |||||
| method: 'DELETE', | |||||
| data | |||||
| }); | |||||
| } | |||||
| @@ -1,5 +1,6 @@ | |||||
| import PageTitle from '@/components/PageTitle'; | import PageTitle from '@/components/PageTitle'; | ||||
| import type { Meta, StoryObj } from '@storybook/react'; | import type { Meta, StoryObj } from '@storybook/react'; | ||||
| import { Tabs } from 'antd'; | |||||
| // More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export | // More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export | ||||
| const meta = { | const meta = { | ||||
| @@ -28,3 +29,25 @@ export const Primary: Story = { | |||||
| title: '数据集列表', | title: '数据集列表', | ||||
| }, | }, | ||||
| }; | }; | ||||
| /* 带有提示信息 */ | |||||
| export const WithTooltip: Story = { | |||||
| args: { | |||||
| title: '数据集列表', | |||||
| tooltip: '其它提示', | |||||
| }, | |||||
| }; | |||||
| /* Title 可以是 ReactNode */ | |||||
| export const Custom: Story = { | |||||
| args: { | |||||
| title: ( | |||||
| <Tabs | |||||
| items={[ | |||||
| { label: 'Tab 1', key: '1' }, | |||||
| { label: 'Tab 2', key: '2' }, | |||||
| ]} | |||||
| ></Tabs> | |||||
| ), | |||||
| }, | |||||
| }; | |||||
| @@ -20,7 +20,7 @@ export const elapsedTime = (begin?: string | null, end?: string | null): string | |||||
| const timestamp = endDate.valueOf() - beginDate.valueOf(); | const timestamp = endDate.valueOf() - beginDate.valueOf(); | ||||
| if (timestamp < 0) { | if (timestamp < 0) { | ||||
| return '时间有误'; | |||||
| return '0秒'; | |||||
| } | } | ||||
| const duration = dayjs.duration(timestamp); | const duration = dayjs.duration(timestamp); | ||||
| const years = duration.years(); | const years = duration.years(); | ||||
| @@ -13,3 +13,16 @@ export async function to<T, U = any>(promise: Promise<T>): Promise<[T, null] | [ | |||||
| } | } | ||||
| export default to; | export default to; | ||||
| /** | |||||
| * 休眠 | |||||
| * @param ms - The number of milliseconds to sleep. | |||||
| * @return A promise that resolves after the specified amount of time. | |||||
| */ | |||||
| export function sleep(ms: number) { | |||||
| return new Promise((resolve) => { | |||||
| setTimeout(() => { | |||||
| resolve(true); | |||||
| }, ms); | |||||
| }); | |||||
| } | |||||
| @@ -87,7 +87,7 @@ function formatArray(property?: string): TableCellFormatter { | |||||
| * @param ellipsis - 是否省略 | * @param ellipsis - 是否省略 | ||||
| * @param type - 类型 | * @param type - 类型 | ||||
| * @param options - 选项 | * @param options - 选项 | ||||
| * @returns React 节点 | |||||
| * @returns Ant Design Table 的 render | |||||
| */ | */ | ||||
| function tableCellRender<T>( | function tableCellRender<T>( | ||||
| ellipsis: boolean | TooltipProps | 'auto' = false, | ellipsis: boolean | TooltipProps | 'auto' = false, | ||||
| @@ -39,6 +39,10 @@ public class Constant { | |||||
| public final static String Init = "Init"; | public final static String Init = "Init"; | ||||
| public final static String Stopped = "Stopped"; | public final static String Stopped = "Stopped"; | ||||
| public final static String Succeeded = "Succeeded"; | public final static String Succeeded = "Succeeded"; | ||||
| public final static String Error = "Error"; | |||||
| public final static String Unknown = "Unknown"; | |||||
| public final static String Available = "available"; | |||||
| public final static String Type_Train = "train"; | public final static String Type_Train = "train"; | ||||
| public final static String Type_Evaluate = "evaluate"; | public final static String Type_Evaluate = "evaluate"; | ||||
| @@ -0,0 +1,62 @@ | |||||
| package com.ruoyi.platform.controller.activeLearn; | |||||
| import com.ruoyi.common.core.web.controller.BaseController; | |||||
| import com.ruoyi.common.core.web.domain.GenericsAjaxResult; | |||||
| import com.ruoyi.platform.domain.ActiveLearn; | |||||
| import com.ruoyi.platform.service.ActiveLearnService; | |||||
| import com.ruoyi.platform.vo.ActiveLearnVo; | |||||
| import io.swagger.annotations.Api; | |||||
| import io.swagger.annotations.ApiOperation; | |||||
| import org.springframework.web.bind.annotation.*; | |||||
| import org.springframework.data.domain.Page; | |||||
| import org.springframework.data.domain.PageRequest; | |||||
| import javax.annotation.Resource; | |||||
| import java.io.IOException; | |||||
| @RestController | |||||
| @RequestMapping("activeLearn") | |||||
| @Api("主动学习") | |||||
| public class ActiveLearnController extends BaseController { | |||||
| @Resource | |||||
| private ActiveLearnService activeLearnService; | |||||
| @GetMapping | |||||
| @ApiOperation("分页查询") | |||||
| public GenericsAjaxResult<Page<ActiveLearn>> queryByPage(@RequestParam("page") int page, | |||||
| @RequestParam("size") int size, | |||||
| @RequestParam(value = "name", required = false) String name) { | |||||
| PageRequest pageRequest = PageRequest.of(page, size); | |||||
| return genericsSuccess(this.activeLearnService.queryByPage(name, pageRequest)); | |||||
| } | |||||
| @PostMapping | |||||
| @ApiOperation("新增主动学习") | |||||
| public GenericsAjaxResult<ActiveLearn> addActiveLearn(@RequestBody ActiveLearnVo activeLearnVo) throws Exception { | |||||
| return genericsSuccess(this.activeLearnService.save(activeLearnVo)); | |||||
| } | |||||
| @PutMapping | |||||
| @ApiOperation("编辑主动学习") | |||||
| public GenericsAjaxResult<String> editActiveLearn(@RequestBody ActiveLearnVo activeLearnVo) throws Exception { | |||||
| return genericsSuccess(this.activeLearnService.edit(activeLearnVo)); | |||||
| } | |||||
| @GetMapping("/getActiveLearnDetail") | |||||
| @ApiOperation("获取主动学习详细信息") | |||||
| public GenericsAjaxResult<ActiveLearnVo> getActiveLearnDetail(@RequestParam("id") Long id) throws IOException { | |||||
| return genericsSuccess(this.activeLearnService.getActiveLearnDetail(id)); | |||||
| } | |||||
| @DeleteMapping("{id}") | |||||
| @ApiOperation("删除主动学习") | |||||
| public GenericsAjaxResult<String> deleteActiveLearn(@PathVariable("id") Long id) { | |||||
| return genericsSuccess(this.activeLearnService.delete(id)); | |||||
| } | |||||
| @PostMapping("/run/{id}") | |||||
| @ApiOperation("运行主动学习实验") | |||||
| public GenericsAjaxResult<String> runActiveLearn(@PathVariable("id") Long id) throws Exception { | |||||
| return genericsSuccess(this.activeLearnService.runActiveLearnIns(id)); | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,60 @@ | |||||
| package com.ruoyi.platform.controller.activeLearn; | |||||
| import com.ruoyi.common.core.web.controller.BaseController; | |||||
| import com.ruoyi.common.core.web.domain.GenericsAjaxResult; | |||||
| import com.ruoyi.platform.domain.ActiveLearnIns; | |||||
| import com.ruoyi.platform.service.ActiveLearnInsService; | |||||
| import io.swagger.annotations.Api; | |||||
| import io.swagger.annotations.ApiOperation; | |||||
| import org.springframework.data.domain.PageRequest; | |||||
| import org.springframework.web.bind.annotation.*; | |||||
| import org.springframework.data.domain.Page; | |||||
| import javax.annotation.Resource; | |||||
| import java.io.IOException; | |||||
| import java.util.List; | |||||
| @RestController | |||||
| @RequestMapping("activeLearnIns") | |||||
| @Api("主动学习实验实例") | |||||
| public class ActiveLearnInsController extends BaseController { | |||||
| @Resource | |||||
| private ActiveLearnInsService activeLearnInsService; | |||||
| @GetMapping | |||||
| @ApiOperation("分页查询") | |||||
| public GenericsAjaxResult<Page<ActiveLearnIns>> queryByPage(Long activeLearnId, int page, int size) throws IOException { | |||||
| PageRequest pageRequest = PageRequest.of(page, size); | |||||
| return genericsSuccess(this.activeLearnInsService.queryByPage(activeLearnId, pageRequest)); | |||||
| } | |||||
| @PostMapping | |||||
| @ApiOperation("新增实验实例") | |||||
| public GenericsAjaxResult<ActiveLearnIns> add(@RequestBody ActiveLearnIns activeLearnIns) { | |||||
| return genericsSuccess(this.activeLearnInsService.insert(activeLearnIns)); | |||||
| } | |||||
| @DeleteMapping("{id}") | |||||
| @ApiOperation("删除实验实例") | |||||
| public GenericsAjaxResult<String> deleteById(@PathVariable("id") Long id) { | |||||
| return genericsSuccess(this.activeLearnInsService.deleteById(id)); | |||||
| } | |||||
| @DeleteMapping("batchDelete") | |||||
| @ApiOperation("批量删除实验实例") | |||||
| public GenericsAjaxResult<String> batchDelete(@RequestBody List<Long> ids) { | |||||
| return genericsSuccess(this.activeLearnInsService.batchDelete(ids)); | |||||
| } | |||||
| @PutMapping("{id}") | |||||
| @ApiOperation("终止实验实例") | |||||
| public GenericsAjaxResult<Boolean> terminateActiveLearnIns(@PathVariable("id") Long id) throws Exception { | |||||
| return genericsSuccess(this.activeLearnInsService.terminateActiveLearnIns(id)); | |||||
| } | |||||
| @GetMapping("{id}") | |||||
| @ApiOperation("查看实验实例详情") | |||||
| public GenericsAjaxResult<ActiveLearnIns> getDetailById(@PathVariable("id") Long id) throws Exception { | |||||
| return genericsSuccess(this.activeLearnInsService.getDetailById(id)); | |||||
| } | |||||
| } | |||||
| @@ -115,6 +115,7 @@ public class ImageController extends BaseController { | |||||
| * @return 删除是否成功 | * @return 删除是否成功 | ||||
| */ | */ | ||||
| @DeleteMapping("{id}") | @DeleteMapping("{id}") | ||||
| @ApiOperation("删除镜像") | |||||
| public GenericsAjaxResult<String> deleteById(@PathVariable("id") Integer id) throws Exception { | public GenericsAjaxResult<String> deleteById(@PathVariable("id") Integer id) throws Exception { | ||||
| return genericsSuccess(this.imageService.removeById(id)); | return genericsSuccess(this.imageService.removeById(id)); | ||||
| } | } | ||||
| @@ -50,7 +50,7 @@ public class RayController extends BaseController { | |||||
| @DeleteMapping("{id}") | @DeleteMapping("{id}") | ||||
| @ApiOperation("删除自动超参数寻优") | @ApiOperation("删除自动超参数寻优") | ||||
| public GenericsAjaxResult<String> deleteRay(@PathVariable("id") Long id) { | |||||
| public GenericsAjaxResult<String> deleteRay(@PathVariable("id") Long id) { | |||||
| return genericsSuccess(this.rayService.delete(id)); | return genericsSuccess(this.rayService.delete(id)); | ||||
| } | } | ||||
| @@ -85,13 +85,13 @@ public class ServiceController extends BaseController { | |||||
| @GetMapping("/serviceVersionDetail/{id}") | @GetMapping("/serviceVersionDetail/{id}") | ||||
| @ApiOperation("查询服务版本详细信息") | @ApiOperation("查询服务版本详细信息") | ||||
| public GenericsAjaxResult<ServiceVersionVo> getServiceVersion(@PathVariable("id") Long id) { | |||||
| public GenericsAjaxResult<ServiceVersionVo> getServiceVersion(@PathVariable("id") Long id) throws IOException { | |||||
| return genericsSuccess(serviceService.getServiceVersion(id)); | return genericsSuccess(serviceService.getServiceVersion(id)); | ||||
| } | } | ||||
| @GetMapping("serviceVersionCompare") | @GetMapping("serviceVersionCompare") | ||||
| @ApiOperation("服务版本版本对比") | @ApiOperation("服务版本版本对比") | ||||
| public GenericsAjaxResult<Map<String, Object>> serviceVersionCompare(@RequestParam("id1") Long id1, @RequestParam("id2") Long id2) throws IllegalAccessException { | |||||
| public GenericsAjaxResult<Map<String, Object>> serviceVersionCompare(@RequestParam("id1") Long id1, @RequestParam("id2") Long id2) throws IllegalAccessException, IOException { | |||||
| return genericsSuccess(serviceService.serviceVersionCompare(id1, id2)); | return genericsSuccess(serviceService.serviceVersionCompare(id1, id2)); | ||||
| } | } | ||||
| @@ -0,0 +1,113 @@ | |||||
| package com.ruoyi.platform.domain; | |||||
| import com.fasterxml.jackson.databind.PropertyNamingStrategy; | |||||
| import com.fasterxml.jackson.databind.annotation.JsonNaming; | |||||
| import io.swagger.annotations.ApiModel; | |||||
| import io.swagger.annotations.ApiModelProperty; | |||||
| import lombok.Data; | |||||
| import java.util.Date; | |||||
| @Data | |||||
| @JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class) | |||||
| @ApiModel(description = "主动学习") | |||||
| public class ActiveLearn { | |||||
| private Long id; | |||||
| @ApiModelProperty(value = "实验名称") | |||||
| private String name; | |||||
| @ApiModelProperty(value = "实验描述") | |||||
| private String description; | |||||
| @ApiModelProperty(value = "任务类型:classification或regression") | |||||
| private String taskType; | |||||
| @ApiModelProperty(value = "框架类型: sklearn, keras, pytorch") | |||||
| private String frameworkType; | |||||
| @ApiModelProperty(value = "代码配置") | |||||
| private String codeConfig; | |||||
| @ApiModelProperty(value = "预训练的模型") | |||||
| private String model; | |||||
| @ApiModelProperty(value = "模型文件路径") | |||||
| private String modelPy; | |||||
| @ApiModelProperty(value = "模型类名称") | |||||
| private String modelClassName; | |||||
| @ApiModelProperty(value = "分类算法") | |||||
| private String classifierAlg; | |||||
| @ApiModelProperty(value = "回归算法") | |||||
| private String regressorAlg; | |||||
| @ApiModelProperty(value = "dataset处理文件路径") | |||||
| private String datasetPy; | |||||
| @ApiModelProperty(value = "dataset类名") | |||||
| private String datasetClassName; | |||||
| @ApiModelProperty(value = "数据集") | |||||
| private String dataset; | |||||
| @ApiModelProperty(value = "数据量") | |||||
| private Integer dataSize; | |||||
| @ApiModelProperty(value = "镜像") | |||||
| private String image; | |||||
| @ApiModelProperty(value = "计算资源id") | |||||
| private Integer computingResourceId; | |||||
| @ApiModelProperty(value = "是否随机打乱") | |||||
| private Boolean shuffle; | |||||
| @ApiModelProperty(value = "训练集数据量") | |||||
| private Integer trainSize; | |||||
| @ApiModelProperty(value = "初始训练数据量") | |||||
| private Integer initialNum; | |||||
| @ApiModelProperty(value = "查询次数") | |||||
| private Integer queriesNum; | |||||
| @ApiModelProperty(value = "每次查询数据量") | |||||
| private Integer instancesNum; | |||||
| @ApiModelProperty(value = "查询策略:uncertainty_sampling, uncertainty_batch_sampling, max_std_sampling, expected_improvement, upper_confidence_bound") | |||||
| private String queryStrategy; | |||||
| @ApiModelProperty(value = "loss文件路径") | |||||
| private String lossPy; | |||||
| @ApiModelProperty(value = "loss类名") | |||||
| private String lossClassName; | |||||
| @ApiModelProperty(value = "多少轮查询保存一次模型参数") | |||||
| private Integer checkpointNum; | |||||
| @ApiModelProperty(value = "batch_size") | |||||
| private Integer batchSize; | |||||
| @ApiModelProperty(value = "epochs") | |||||
| private Integer epochs; | |||||
| @ApiModelProperty(value = "学习率") | |||||
| private Float lr; | |||||
| private String createBy; | |||||
| private String updateBy; | |||||
| private Date createTime; | |||||
| private Date updateTime; | |||||
| private Integer state; | |||||
| @ApiModelProperty(value = "状态列表") | |||||
| private String statusList; | |||||
| } | |||||
| @@ -0,0 +1,39 @@ | |||||
| package com.ruoyi.platform.domain; | |||||
| import com.fasterxml.jackson.databind.PropertyNamingStrategy; | |||||
| import com.fasterxml.jackson.databind.annotation.JsonNaming; | |||||
| import io.swagger.annotations.ApiModel; | |||||
| import lombok.Data; | |||||
| import java.util.Date; | |||||
| @Data | |||||
| @JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class) | |||||
| @ApiModel(description = "主动学习实验实例") | |||||
| public class ActiveLearnIns { | |||||
| private Long id; | |||||
| private Long activeLearnId; | |||||
| private Integer state; | |||||
| private String status; | |||||
| private String param; | |||||
| private Date createTime; | |||||
| private Date updateTime; | |||||
| private Date finishTime; | |||||
| private String argoInsName; | |||||
| private String argoInsNs; | |||||
| private String resultPath; | |||||
| private String nodeStatus; | |||||
| private String nodeResult; | |||||
| } | |||||
| @@ -49,9 +49,12 @@ public class ResourceOccupy { | |||||
| @ApiModelProperty("流水线id") | @ApiModelProperty("流水线id") | ||||
| private Long workflowId; | private Long workflowId; | ||||
| @ApiModelProperty("流水线节点id") | |||||
| private String nodeId; | |||||
| @ApiModelProperty("任务名称") | @ApiModelProperty("任务名称") | ||||
| private String taskName; | private String taskName; | ||||
| @ApiModelProperty("流水线节点id") | |||||
| private String nodeId; | |||||
| @ApiModelProperty("任务状态") | |||||
| private Integer taskState; | |||||
| } | } | ||||
| @@ -0,0 +1,29 @@ | |||||
| package com.ruoyi.platform.mapper; | |||||
| import com.ruoyi.platform.domain.ActiveLearn; | |||||
| import org.apache.ibatis.annotations.Param; | |||||
| import org.springframework.data.domain.PageRequest; | |||||
| import java.util.List; | |||||
| public interface ActiveLearnDao { | |||||
| long count(@Param("name") String name); | |||||
| List<ActiveLearn> queryByPage(@Param("name") String name, @Param("pageable") PageRequest pageRequest); | |||||
| ActiveLearn getActiveLearnByName(@Param("name") String name); | |||||
| int save(@Param("activeLearn") ActiveLearn activeLearn); | |||||
| int edit(@Param("activeLearn") ActiveLearn activeLearn); | |||||
| ActiveLearn getActiveLearnById(@Param("id") Long id); | |||||
| List<ActiveLearn> queryByDatasetId(@Param("datasetId") String datasetId); | |||||
| List<ActiveLearn> queryByModelId(@Param("modelId") String modelId); | |||||
| List<ActiveLearn> queryByImageId(@Param("imageId") String imageId); | |||||
| List<ActiveLearn> queryByCodeConfig(@Param("codeConfig") String codeConfig); | |||||
| } | |||||
| @@ -0,0 +1,23 @@ | |||||
| package com.ruoyi.platform.mapper; | |||||
| import com.ruoyi.platform.domain.ActiveLearnIns; | |||||
| import org.apache.ibatis.annotations.Param; | |||||
| import org.springframework.data.domain.Pageable; | |||||
| import java.util.List; | |||||
| public interface ActiveLearnInsDao { | |||||
| long count(@Param("activeLearnId") Long activeLearnId); | |||||
| List<ActiveLearnIns> queryAllByLimit(@Param("activeLearnId") Long activeLearnId, @Param("pageable") Pageable pageable); | |||||
| int insert(@Param("activeLearnIns") ActiveLearnIns activeLearnIns); | |||||
| int update(@Param("activeLearnIns") ActiveLearnIns activeLearnIns); | |||||
| ActiveLearnIns queryById(@Param("id") Long id); | |||||
| List<ActiveLearnIns> getByActiveLearnId(@Param("activeLearnId") Long activeLearnId); | |||||
| List<ActiveLearnIns> queryActiveLearnInsIsNotTerminated(); | |||||
| } | |||||
| @@ -62,6 +62,14 @@ public interface DevEnvironmentDao { | |||||
| */ | */ | ||||
| int deleteById(Integer id); | int deleteById(Integer id); | ||||
| DevEnvironment getByName(@Param("name") String name); | |||||
| List<DevEnvironment> getRunning(); | List<DevEnvironment> getRunning(); | ||||
| List<DevEnvironment> queryByDatasetId(@Param("datasetId") String datasetId); | |||||
| List<DevEnvironment> queryByModelId(@Param("modelId") String modelId); | |||||
| List<DevEnvironment> queryByImageId(@Param("imageId") String imageId); | |||||
| } | } | ||||
| @@ -14,7 +14,7 @@ public interface ResourceOccupyDao { | |||||
| int edit(@Param("resourceOccupy") ResourceOccupy resourceOccupy); | int edit(@Param("resourceOccupy") ResourceOccupy resourceOccupy); | ||||
| List<ResourceOccupy> getResourceOccupyByTask(@Param("taskType") String taskType, @Param("taskId") Long taskId, @Param("taskInsId") Long taskInsId, @Param("nodeId") String nodeId); | |||||
| List<ResourceOccupy> getResourceOccupyByTask(@Param("taskType") String taskType, @Param("taskId") Long taskId, @Param("taskInsId") Long taskInsId, @Param("nodeId") String nodeId); | |||||
| int deduceCredit(@Param("credit") Double credit, @Param("userId") Long userId); | int deduceCredit(@Param("credit") Double credit, @Param("userId") Long userId); | ||||
| @@ -29,4 +29,6 @@ public interface ResourceOccupyDao { | |||||
| Double getUserCredit(@Param("userId") Long userId); | Double getUserCredit(@Param("userId") Long userId); | ||||
| Double getDeduceCredit(@Param("userId") Long userId); | Double getDeduceCredit(@Param("userId") Long userId); | ||||
| int deleteTaskState(@Param("taskType") String taskType, @Param("taskId") Long taskId, @Param("taskInsId") Long taskInsId); | |||||
| } | } | ||||
| @@ -38,4 +38,10 @@ public interface ServiceDao { | |||||
| ServiceVersion getSvByVersion(@Param("version") String version, @Param("serviceId") Long serviceId); | ServiceVersion getSvByVersion(@Param("version") String version, @Param("serviceId") Long serviceId); | ||||
| List<ServiceVersion> getRunning(); | List<ServiceVersion> getRunning(); | ||||
| List<String> queryByModelId(@Param("modelId") String modelId); | |||||
| List<String> queryByImageId(@Param("imageId") String imageId); | |||||
| List<String> queryByCodeConfig(@Param("codeConfig") String codeConfig); | |||||
| } | } | ||||
| @@ -0,0 +1,116 @@ | |||||
| package com.ruoyi.platform.scheduling; | |||||
| import com.ruoyi.platform.domain.ActiveLearn; | |||||
| import com.ruoyi.platform.domain.ActiveLearnIns; | |||||
| import com.ruoyi.platform.mapper.ActiveLearnDao; | |||||
| import com.ruoyi.platform.mapper.ActiveLearnInsDao; | |||||
| import com.ruoyi.platform.mapper.ResourceOccupyDao; | |||||
| import com.ruoyi.platform.service.ActiveLearnInsService; | |||||
| import com.ruoyi.platform.service.ResourceOccupyService; | |||||
| import com.ruoyi.system.api.constant.Constant; | |||||
| import org.apache.commons.lang3.StringUtils; | |||||
| import org.springframework.scheduling.annotation.Scheduled; | |||||
| import org.springframework.stereotype.Component; | |||||
| import javax.annotation.Resource; | |||||
| import java.util.ArrayList; | |||||
| import java.util.Iterator; | |||||
| import java.util.List; | |||||
| @Component() | |||||
| public class ActiveLearnInsStatusTask { | |||||
| @Resource | |||||
| private ActiveLearnInsService activeLearnInsService; | |||||
| @Resource | |||||
| private ActiveLearnInsDao activeLearnInsDao; | |||||
| @Resource | |||||
| private ActiveLearnDao activeLearnDao; | |||||
| @Resource | |||||
| private ResourceOccupyDao resourceOccupyDao; | |||||
| @Resource | |||||
| private ResourceOccupyService resourceOccupyService; | |||||
| private List<Long> activeLearnIds = new ArrayList<>(); | |||||
| @Scheduled(cron = "0/30 * * * * ?") // 每30S执行一次 | |||||
| public void executeActiveLearnInsStatus() { | |||||
| List<ActiveLearnIns> activeLearnInsList = activeLearnInsService.queryActiveLearnInsIsNotTerminated(); | |||||
| // 去argo查询状态 | |||||
| List<ActiveLearnIns> updateList = new ArrayList<>(); | |||||
| if (activeLearnInsList != null && activeLearnInsList.size() > 0) { | |||||
| for (ActiveLearnIns activeLearnIns : activeLearnInsList) { | |||||
| //当原本状态为null或非终止态时才调用argo接口 | |||||
| try { | |||||
| Long userId = resourceOccupyDao.getResourceOccupyByTask(Constant.TaskType_ActiveLearn, activeLearnIns.getActiveLearnId(), activeLearnIns.getId(), null).get(0).getUserId(); | |||||
| if (resourceOccupyDao.getUserCredit(userId) <= 0) { | |||||
| activeLearnIns.setStatus(Constant.Failed); | |||||
| activeLearnInsService.terminateActiveLearnIns(activeLearnIns.getId()); | |||||
| } else { | |||||
| activeLearnIns = activeLearnInsService.queryStatusFromArgo(activeLearnIns); | |||||
| // 扣除积分 | |||||
| if (Constant.Running.equals(activeLearnIns.getStatus())) { | |||||
| resourceOccupyService.deducing(Constant.TaskType_ActiveLearn, null, activeLearnIns.getId(), null, null); | |||||
| } else if (Constant.Failed.equals(activeLearnIns.getStatus()) || Constant.Terminated.equals(activeLearnIns.getStatus()) | |||||
| || Constant.Succeeded.equals(activeLearnIns.getStatus())) { | |||||
| resourceOccupyService.endDeduce(Constant.TaskType_ActiveLearn, null, activeLearnIns.getId(), null, null); | |||||
| } | |||||
| } | |||||
| } catch (Exception e) { | |||||
| activeLearnIns.setStatus(Constant.Failed); | |||||
| // 结束扣除积分 | |||||
| resourceOccupyService.endDeduce(Constant.TaskType_ActiveLearn, null, activeLearnIns.getId(), null, null); | |||||
| } | |||||
| // 线程安全的添加操作 | |||||
| synchronized (activeLearnIds) { | |||||
| activeLearnIds.add(activeLearnIns.getActiveLearnId()); | |||||
| } | |||||
| updateList.add(activeLearnIns); | |||||
| } | |||||
| if (updateList.size() > 0) { | |||||
| for (ActiveLearnIns activeLearnIns : updateList) { | |||||
| activeLearnInsDao.update(activeLearnIns); | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| @Scheduled(cron = "0/30 * * * * ?") // / 每30S执行一次 | |||||
| public void executeActiveLearnStatus() { | |||||
| if (activeLearnIds.size() == 0) { | |||||
| return; | |||||
| } | |||||
| // 存储需要更新的实验对象列表 | |||||
| List<ActiveLearn> updateActiveLearns = new ArrayList<>(); | |||||
| for (Long activeLearnId : activeLearnIds) { | |||||
| // 获取当前实验的所有实例列表 | |||||
| List<ActiveLearnIns> insList = activeLearnInsDao.getByActiveLearnId(activeLearnId); | |||||
| List<String> statusList = new ArrayList<>(); | |||||
| // 更新实验状态列表 | |||||
| for (int i = 0; i < insList.size(); i++) { | |||||
| statusList.add(insList.get(i).getStatus()); | |||||
| } | |||||
| String subStatus = statusList.toString().substring(1, statusList.toString().length() - 1); | |||||
| ActiveLearn activeLearn = activeLearnDao.getActiveLearnById(activeLearnId); | |||||
| if (!StringUtils.equals(activeLearn.getStatusList(), subStatus)) { | |||||
| activeLearn.setStatusList(subStatus); | |||||
| updateActiveLearns.add(activeLearn); | |||||
| activeLearnDao.edit(activeLearn); | |||||
| } | |||||
| } | |||||
| if (!updateActiveLearns.isEmpty()) { | |||||
| // 使用Iterator进行安全的删除操作 | |||||
| Iterator<Long> iterator = activeLearnIds.iterator(); | |||||
| while (iterator.hasNext()) { | |||||
| Long activeLearnId = iterator.next(); | |||||
| for (ActiveLearn activeLearn : updateActiveLearns) { | |||||
| if (activeLearn.getId().equals(activeLearnId)) { | |||||
| iterator.remove(); | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,28 @@ | |||||
| package com.ruoyi.platform.service; | |||||
| import com.ruoyi.platform.domain.ActiveLearnIns; | |||||
| import org.springframework.data.domain.Page; | |||||
| import org.springframework.data.domain.PageRequest; | |||||
| import java.io.IOException; | |||||
| import java.util.List; | |||||
| public interface ActiveLearnInsService { | |||||
| Page<ActiveLearnIns> queryByPage(Long activeLearnId, PageRequest pageRequest) throws IOException; | |||||
| ActiveLearnIns insert(ActiveLearnIns activeLearnIns); | |||||
| String deleteById(Long id); | |||||
| String batchDelete(List<Long> ids); | |||||
| boolean terminateActiveLearnIns(Long id) throws Exception; | |||||
| ActiveLearnIns getDetailById(Long id) throws Exception; | |||||
| void updateActiveLearnStatus(Long activeLearnId); | |||||
| ActiveLearnIns queryStatusFromArgo(ActiveLearnIns ins); | |||||
| List<ActiveLearnIns> queryActiveLearnInsIsNotTerminated(); | |||||
| } | |||||
| @@ -0,0 +1,22 @@ | |||||
| package com.ruoyi.platform.service; | |||||
| import com.ruoyi.platform.domain.ActiveLearn; | |||||
| import com.ruoyi.platform.vo.ActiveLearnVo; | |||||
| import org.springframework.data.domain.PageRequest; | |||||
| import org.springframework.data.domain.Page; | |||||
| import java.io.IOException; | |||||
| public interface ActiveLearnService { | |||||
| Page<ActiveLearn> queryByPage(String name, PageRequest pageRequest); | |||||
| ActiveLearn save(ActiveLearnVo activeLearnVo) throws Exception; | |||||
| String edit(ActiveLearnVo activeLearnVo) throws Exception; | |||||
| ActiveLearnVo getActiveLearnDetail(Long id) throws IOException; | |||||
| String delete(Long id); | |||||
| String runActiveLearnIns (Long id) throws Exception; | |||||
| } | |||||
| @@ -4,6 +4,7 @@ import org.springframework.data.domain.PageRequest; | |||||
| import com.ruoyi.platform.domain.RayIns; | import com.ruoyi.platform.domain.RayIns; | ||||
| import java.io.IOException; | import java.io.IOException; | ||||
| import java.util.List; | import java.util.List; | ||||
| public interface RayInsService { | public interface RayInsService { | ||||
| Page<RayIns> queryByPage(Long rayId, PageRequest pageRequest) throws IOException; | Page<RayIns> queryByPage(Long rayId, PageRequest pageRequest) throws IOException; | ||||
| @@ -22,4 +22,6 @@ public interface ResourceOccupyService { | |||||
| Map<String, Double> queryCredit(); | Map<String, Double> queryCredit(); | ||||
| void update(String taskType, Long taskId, Long taskInsId, Integer computingResourceId, Integer replicas); | void update(String taskType, Long taskId, Long taskInsId, Integer computingResourceId, Integer replicas); | ||||
| void deleteTaskState(String taskType, Long taskId, Long taskInsId); | |||||
| } | } | ||||
| @@ -26,9 +26,9 @@ public interface ServiceService { | |||||
| Service getService(Long id); | Service getService(Long id); | ||||
| ServiceVersionVo getServiceVersion(Long id); | |||||
| ServiceVersionVo getServiceVersion(Long id) throws IOException; | |||||
| Map<String, Object> serviceVersionCompare(Long id1, Long id2) throws IllegalAccessException; | |||||
| Map<String, Object> serviceVersionCompare(Long id1, Long id2) throws IllegalAccessException, IOException; | |||||
| String deleteService(Long id) throws Exception; | String deleteService(Long id) throws Exception; | ||||
| @@ -0,0 +1,263 @@ | |||||
| package com.ruoyi.platform.service.impl; | |||||
| import com.ruoyi.platform.domain.ActiveLearn; | |||||
| import com.ruoyi.platform.domain.ActiveLearnIns; | |||||
| import com.ruoyi.platform.mapper.ActiveLearnDao; | |||||
| import com.ruoyi.platform.mapper.ActiveLearnInsDao; | |||||
| import com.ruoyi.platform.service.ActiveLearnInsService; | |||||
| import com.ruoyi.platform.service.ResourceOccupyService; | |||||
| import com.ruoyi.platform.utils.DateUtils; | |||||
| import com.ruoyi.platform.utils.HttpUtils; | |||||
| import com.ruoyi.platform.utils.JsonUtils; | |||||
| import com.ruoyi.system.api.constant.Constant; | |||||
| import org.apache.commons.lang3.StringUtils; | |||||
| import org.springframework.beans.factory.annotation.Value; | |||||
| import org.springframework.data.domain.Page; | |||||
| import org.springframework.data.domain.PageImpl; | |||||
| import org.springframework.data.domain.PageRequest; | |||||
| import org.springframework.stereotype.Service; | |||||
| import org.springframework.transaction.annotation.Transactional; | |||||
| import javax.annotation.Resource; | |||||
| import java.io.IOException; | |||||
| import java.util.*; | |||||
| @Service | |||||
| public class ActiveLearnInsServiceImpl implements ActiveLearnInsService { | |||||
| @Value("${argo.url}") | |||||
| private String argoUrl; | |||||
| @Value("${argo.workflowStatus}") | |||||
| private String argoWorkflowStatus; | |||||
| @Value("${argo.workflowTermination}") | |||||
| private String argoWorkflowTermination; | |||||
| @Resource | |||||
| private ActiveLearnInsDao activeLearnInsDao; | |||||
| @Resource | |||||
| private ActiveLearnDao activeLearnDao; | |||||
| @Resource | |||||
| private ResourceOccupyService resourceOccupyService; | |||||
| @Override | |||||
| public Page<ActiveLearnIns> queryByPage(Long activeLearnId, PageRequest pageRequest) throws IOException { | |||||
| long total = this.activeLearnInsDao.count(activeLearnId); | |||||
| List<ActiveLearnIns> activeLearnInsList = activeLearnInsDao.queryAllByLimit(activeLearnId, pageRequest); | |||||
| return new PageImpl<>(activeLearnInsList, pageRequest, total); | |||||
| } | |||||
| @Override | |||||
| public ActiveLearnIns insert(ActiveLearnIns activeLearnIns) { | |||||
| activeLearnInsDao.insert(activeLearnIns); | |||||
| return activeLearnIns; | |||||
| } | |||||
| @Override | |||||
| @Transactional | |||||
| public String deleteById(Long id) { | |||||
| ActiveLearnIns activeLearnIns = activeLearnInsDao.queryById(id); | |||||
| if (activeLearnIns == null) { | |||||
| return "实验实例不存在"; | |||||
| } | |||||
| if (StringUtils.isEmpty(activeLearnIns.getStatus())) { | |||||
| activeLearnIns = queryStatusFromArgo(activeLearnIns); | |||||
| } | |||||
| if (StringUtils.equals(activeLearnIns.getStatus(), Constant.Running)) { | |||||
| return "实验实例正在运行,不可删除"; | |||||
| } | |||||
| activeLearnIns.setState(Constant.State_invalid); | |||||
| int update = activeLearnInsDao.update(activeLearnIns); | |||||
| if (update > 0) { | |||||
| resourceOccupyService.deleteTaskState(Constant.TaskType_ActiveLearn, activeLearnIns.getActiveLearnId(), id); | |||||
| updateActiveLearnStatus(activeLearnIns.getActiveLearnId()); | |||||
| return "删除成功"; | |||||
| } else { | |||||
| return "删除失败"; | |||||
| } | |||||
| } | |||||
| @Override | |||||
| public String batchDelete(List<Long> ids) { | |||||
| for (Long id : ids) { | |||||
| String result = deleteById(id); | |||||
| if (!"删除成功".equals(result)) { | |||||
| return result; | |||||
| } | |||||
| } | |||||
| return "删除成功"; | |||||
| } | |||||
| @Override | |||||
| public boolean terminateActiveLearnIns(Long id) throws Exception { | |||||
| ActiveLearnIns activeLearnIns = activeLearnInsDao.queryById(id); | |||||
| if (activeLearnIns == null) { | |||||
| throw new IllegalStateException("实验实例未查询到,id: " + id); | |||||
| } | |||||
| String currentStatus = activeLearnIns.getStatus(); | |||||
| String name = activeLearnIns.getArgoInsName(); | |||||
| String namespace = activeLearnIns.getArgoInsNs(); | |||||
| // 获取当前状态,如果为空,则从Argo查询 | |||||
| if (StringUtils.isEmpty(currentStatus)) { | |||||
| currentStatus = queryStatusFromArgo(activeLearnIns).getStatus(); | |||||
| } | |||||
| // 只有状态是"Running"时才能终止实例 | |||||
| if (!currentStatus.equalsIgnoreCase(Constant.Running)) { | |||||
| throw new Exception("终止错误,只有运行状态的实例才能终止"); // 如果不是"Running"状态,则不执行终止操作 | |||||
| } | |||||
| // 创建请求数据map | |||||
| Map<String, Object> requestData = new HashMap<>(); | |||||
| requestData.put("namespace", namespace); | |||||
| requestData.put("name", name); | |||||
| // 创建发送数据map,将请求数据作为"data"键的值 | |||||
| Map<String, Object> res = new HashMap<>(); | |||||
| res.put("data", requestData); | |||||
| try { | |||||
| // 发送POST请求到Argo工作流状态查询接口,并将请求数据转换为JSON | |||||
| String req = HttpUtils.sendPost(argoUrl + argoWorkflowTermination, null, JsonUtils.mapToJson(res)); | |||||
| // 检查响应是否为空或无内容 | |||||
| if (StringUtils.isEmpty(req)) { | |||||
| throw new RuntimeException("终止响应内容为空。"); | |||||
| } | |||||
| // 将响应的JSON字符串转换为Map对象 | |||||
| Map<String, Object> runResMap = JsonUtils.jsonToMap(req); | |||||
| // 从响应Map中直接获取"errCode"的值 | |||||
| Integer errCode = (Integer) runResMap.get("errCode"); | |||||
| if (errCode != null && errCode == 0) { | |||||
| //更新autoMlIns,确保状态更新被保存到数据库 | |||||
| ActiveLearnIns ins = queryStatusFromArgo(activeLearnIns); | |||||
| String nodeStatus = ins.getNodeStatus(); | |||||
| Map<String, Object> nodeMap = JsonUtils.jsonToMap(nodeStatus); | |||||
| // 遍历 map | |||||
| for (Map.Entry<String, Object> entry : nodeMap.entrySet()) { | |||||
| // 获取每个 Map 中的值并强制转换为 Map | |||||
| Map<String, Object> innerMap = (Map<String, Object>) entry.getValue(); | |||||
| // 检查 phase 的值 | |||||
| if (innerMap.containsKey("phase")) { | |||||
| String phaseValue = (String) innerMap.get("phase"); | |||||
| // 如果值不等于 Succeeded,则赋值为 Failed | |||||
| if (!StringUtils.equals(Constant.Succeeded, phaseValue)) { | |||||
| innerMap.put("phase", Constant.Failed); | |||||
| } | |||||
| } | |||||
| } | |||||
| ins.setNodeStatus(JsonUtils.mapToJson(nodeMap)); | |||||
| ins.setStatus(Constant.Terminated); | |||||
| ins.setUpdateTime(new Date()); | |||||
| activeLearnInsDao.update(ins); | |||||
| updateActiveLearnStatus(ins.getActiveLearnId()); | |||||
| // 结束扣积分 | |||||
| resourceOccupyService.endDeduce(Constant.TaskType_ActiveLearn, null, id, null, null); | |||||
| return true; | |||||
| } else { | |||||
| return false; | |||||
| } | |||||
| } catch (Exception e) { | |||||
| throw new RuntimeException("终止实例错误: " + e.getMessage(), e); | |||||
| } | |||||
| } | |||||
| @Override | |||||
| public ActiveLearnIns getDetailById(Long id) throws Exception { | |||||
| ActiveLearnIns activeLearnIns = activeLearnInsDao.queryById(id); | |||||
| if (Constant.Running.equals(activeLearnIns.getStatus()) || Constant.Pending.equals(activeLearnIns.getStatus())) { | |||||
| activeLearnIns = queryStatusFromArgo(activeLearnIns); | |||||
| } | |||||
| return activeLearnIns; | |||||
| } | |||||
| @Override | |||||
| public void updateActiveLearnStatus(Long activeLearnId) { | |||||
| List<ActiveLearnIns> insList = activeLearnInsDao.getByActiveLearnId(activeLearnId); | |||||
| List<String> statusList = new ArrayList<>(); | |||||
| // 更新实验状态列表 | |||||
| for (int i = 0; i < insList.size(); i++) { | |||||
| statusList.add(insList.get(i).getStatus()); | |||||
| } | |||||
| String subStatus = statusList.toString().substring(1, statusList.toString().length() - 1); | |||||
| ActiveLearn activeLearn = activeLearnDao.getActiveLearnById(activeLearnId); | |||||
| if (!StringUtils.equals(activeLearn.getStatusList(), subStatus)) { | |||||
| activeLearn.setStatusList(subStatus); | |||||
| activeLearnDao.edit(activeLearn); | |||||
| } | |||||
| } | |||||
| @Override | |||||
| public ActiveLearnIns queryStatusFromArgo(ActiveLearnIns ins) { | |||||
| String namespace = ins.getArgoInsNs(); | |||||
| String name = ins.getArgoInsName(); | |||||
| // 创建请求数据map | |||||
| Map<String, Object> requestData = new HashMap<>(); | |||||
| requestData.put("namespace", namespace); | |||||
| requestData.put("name", name); | |||||
| // 创建发送数据map,将请求数据作为"data"键的值 | |||||
| Map<String, Object> res = new HashMap<>(); | |||||
| res.put("data", requestData); | |||||
| try { | |||||
| // 发送POST请求到Argo工作流状态查询接口,并将请求数据转换为JSON | |||||
| String req = HttpUtils.sendPost(argoUrl + argoWorkflowStatus, null, JsonUtils.mapToJson(res)); | |||||
| // 检查响应是否为空或无内容 | |||||
| if (req == null || StringUtils.isEmpty(req)) { | |||||
| throw new RuntimeException("工作流状态响应为空。"); | |||||
| } | |||||
| // 将响应的JSON字符串转换为Map对象 | |||||
| Map<String, Object> runResMap = JsonUtils.jsonToMap(req); | |||||
| // 从响应Map中获取"data"部分 | |||||
| Map<String, Object> data = (Map<String, Object>) runResMap.get("data"); | |||||
| if (data == null || data.isEmpty()) { | |||||
| throw new RuntimeException("工作流数据为空."); | |||||
| } | |||||
| // 从"data"中获取"status"部分,并返回"phase"的值 | |||||
| Map<String, Object> status = (Map<String, Object>) data.get("status"); | |||||
| if (status == null || status.isEmpty()) { | |||||
| throw new RuntimeException("工作流状态为空。"); | |||||
| } | |||||
| //解析流水线结束时间 | |||||
| String finishedAtString = (String) status.get("finishedAt"); | |||||
| if (finishedAtString != null && !finishedAtString.isEmpty()) { | |||||
| Date finishTime = DateUtils.convertUTCtoShanghaiDate(finishedAtString); | |||||
| ins.setFinishTime(finishTime); | |||||
| } | |||||
| // 解析nodes字段,提取节点状态并转换为JSON字符串 | |||||
| Map<String, Object> nodes = (Map<String, Object>) status.get("nodes"); | |||||
| Map<String, Object> modifiedNodes = new LinkedHashMap<>(); | |||||
| if (nodes != null) { | |||||
| for (Map.Entry<String, Object> nodeEntry : nodes.entrySet()) { | |||||
| Map<String, Object> nodeDetails = (Map<String, Object>) nodeEntry.getValue(); | |||||
| String templateName = (String) nodeDetails.get("displayName"); | |||||
| modifiedNodes.put(templateName, nodeDetails); | |||||
| } | |||||
| } | |||||
| String nodeStatusJson = JsonUtils.mapToJson(modifiedNodes); | |||||
| ins.setNodeStatus(nodeStatusJson); | |||||
| //终止态为终止不改 | |||||
| if (!StringUtils.equals(ins.getStatus(), Constant.Terminated)) { | |||||
| ins.setStatus(StringUtils.isNotEmpty((String) status.get("phase")) ? (String) status.get("phase") : Constant.Pending); | |||||
| } | |||||
| if (StringUtils.equals(ins.getStatus(), Constant.Error)) { | |||||
| ins.setStatus(Constant.Failed); | |||||
| } | |||||
| return ins; | |||||
| } catch (Exception e) { | |||||
| throw new RuntimeException("查询状态失败: " + e.getMessage(), e); | |||||
| } | |||||
| } | |||||
| @Override | |||||
| public List<ActiveLearnIns> queryActiveLearnInsIsNotTerminated() { | |||||
| return activeLearnInsDao.queryActiveLearnInsIsNotTerminated(); | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,201 @@ | |||||
| package com.ruoyi.platform.service.impl; | |||||
| import com.ruoyi.common.security.utils.SecurityUtils; | |||||
| import com.ruoyi.platform.domain.ActiveLearn; | |||||
| import com.ruoyi.platform.domain.ActiveLearnIns; | |||||
| import com.ruoyi.platform.mapper.ActiveLearnDao; | |||||
| import com.ruoyi.platform.mapper.ActiveLearnInsDao; | |||||
| import com.ruoyi.platform.service.ActiveLearnInsService; | |||||
| import com.ruoyi.platform.service.ActiveLearnService; | |||||
| import com.ruoyi.platform.service.ResourceOccupyService; | |||||
| import com.ruoyi.platform.utils.HttpUtils; | |||||
| import com.ruoyi.platform.utils.JacksonUtil; | |||||
| import com.ruoyi.platform.utils.JsonUtils; | |||||
| import com.ruoyi.platform.vo.ActiveLearnParamVo; | |||||
| import com.ruoyi.platform.vo.ActiveLearnVo; | |||||
| import com.ruoyi.system.api.constant.Constant; | |||||
| import org.apache.commons.collections4.MapUtils; | |||||
| import org.apache.commons.lang3.StringUtils; | |||||
| import org.springframework.beans.BeanUtils; | |||||
| import org.springframework.beans.factory.annotation.Value; | |||||
| import org.springframework.data.domain.Page; | |||||
| import org.springframework.data.domain.PageImpl; | |||||
| import org.springframework.data.domain.PageRequest; | |||||
| import org.springframework.stereotype.Service; | |||||
| import org.springframework.transaction.annotation.Transactional; | |||||
| import javax.annotation.Resource; | |||||
| import java.io.IOException; | |||||
| import java.util.ArrayList; | |||||
| import java.util.HashMap; | |||||
| import java.util.List; | |||||
| import java.util.Map; | |||||
| @Service | |||||
| public class ActiveLearnServiceImpl implements ActiveLearnService { | |||||
| @Value("${argo.url}") | |||||
| private String argoUrl; | |||||
| @Value("${argo.workflowRun}") | |||||
| private String argoWorkflowRun; | |||||
| @Value("${argo.convertActiveLearn}") | |||||
| String convertActiveLearn; | |||||
| @Resource | |||||
| private ResourceOccupyService resourceOccupyService; | |||||
| @Resource | |||||
| private ActiveLearnDao activeLearnDao; | |||||
| @Resource | |||||
| private ActiveLearnInsDao activeLearnInsDao; | |||||
| @Resource | |||||
| private ActiveLearnInsService activeLearnInsService; | |||||
| @Override | |||||
| public Page<ActiveLearn> queryByPage(String name, PageRequest pageRequest) { | |||||
| long total = activeLearnDao.count(name); | |||||
| List<ActiveLearn> activeLearns = activeLearnDao.queryByPage(name, pageRequest); | |||||
| return new PageImpl<>(activeLearns, pageRequest, total); | |||||
| } | |||||
| @Override | |||||
| public ActiveLearn save(ActiveLearnVo activeLearnVo) throws Exception { | |||||
| ActiveLearn activeLearnByName = activeLearnDao.getActiveLearnByName(activeLearnVo.getName()); | |||||
| if (activeLearnByName != null) { | |||||
| throw new RuntimeException("实验名称已存在"); | |||||
| } | |||||
| ActiveLearn activeLearn = new ActiveLearn(); | |||||
| BeanUtils.copyProperties(activeLearnVo, activeLearn); | |||||
| String username = SecurityUtils.getLoginUser().getUsername(); | |||||
| activeLearn.setCreateBy(username); | |||||
| activeLearn.setUpdateBy(username); | |||||
| activeLearn.setDataset(JacksonUtil.toJSONString(activeLearnVo.getDataset())); | |||||
| activeLearn.setCodeConfig(JacksonUtil.toJSONString(activeLearnVo.getCodeConfig())); | |||||
| activeLearn.setModel(JacksonUtil.toJSONString(activeLearnVo.getModel())); | |||||
| activeLearn.setImage(JacksonUtil.toJSONString(activeLearnVo.getImage())); | |||||
| activeLearnDao.save(activeLearn); | |||||
| return activeLearn; | |||||
| } | |||||
| @Override | |||||
| public String edit(ActiveLearnVo activeLearnVo) throws Exception { | |||||
| ActiveLearn oldActiveLearn = activeLearnDao.getActiveLearnByName(activeLearnVo.getName()); | |||||
| if (oldActiveLearn != null && !oldActiveLearn.getId().equals(activeLearnVo.getId())) { | |||||
| throw new RuntimeException("实验名称已存在"); | |||||
| } | |||||
| ActiveLearn activeLearn = new ActiveLearn(); | |||||
| BeanUtils.copyProperties(activeLearnVo, activeLearn); | |||||
| activeLearn.setUpdateBy(SecurityUtils.getLoginUser().getUsername()); | |||||
| activeLearn.setDataset(JacksonUtil.toJSONString(activeLearnVo.getDataset())); | |||||
| activeLearn.setCodeConfig(JacksonUtil.toJSONString(activeLearnVo.getCodeConfig())); | |||||
| activeLearn.setModel(JacksonUtil.toJSONString(activeLearnVo.getModel())); | |||||
| activeLearn.setImage(JacksonUtil.toJSONString(activeLearnVo.getImage())); | |||||
| activeLearnDao.edit(activeLearn); | |||||
| return "修改成功"; | |||||
| } | |||||
| @Override | |||||
| public ActiveLearnVo getActiveLearnDetail(Long id) throws IOException { | |||||
| ActiveLearn activeLearn = activeLearnDao.getActiveLearnById(id); | |||||
| ActiveLearnVo activeLearnVo = new ActiveLearnVo(); | |||||
| BeanUtils.copyProperties(activeLearn, activeLearnVo); | |||||
| if (StringUtils.isNotEmpty(activeLearn.getDataset())) { | |||||
| activeLearnVo.setDataset(JsonUtils.jsonToMap(activeLearn.getDataset())); | |||||
| } | |||||
| if (StringUtils.isNotEmpty(activeLearn.getCodeConfig())) { | |||||
| activeLearnVo.setCodeConfig(JsonUtils.jsonToMap(activeLearn.getCodeConfig())); | |||||
| } | |||||
| if (StringUtils.isNotEmpty(activeLearn.getModel())) { | |||||
| activeLearnVo.setModel(JsonUtils.jsonToMap(activeLearn.getModel())); | |||||
| } | |||||
| if (StringUtils.isNotEmpty(activeLearn.getImage())) { | |||||
| activeLearnVo.setImage(JsonUtils.jsonToMap(activeLearn.getImage())); | |||||
| } | |||||
| return activeLearnVo; | |||||
| } | |||||
| @Override | |||||
| @Transactional | |||||
| public String delete(Long id) { | |||||
| ActiveLearn activeLearn = activeLearnDao.getActiveLearnById(id); | |||||
| if (activeLearn == null) { | |||||
| throw new RuntimeException("实验不存在"); | |||||
| } | |||||
| String username = SecurityUtils.getLoginUser().getUsername(); | |||||
| String createBy = activeLearn.getCreateBy(); | |||||
| if (!(StringUtils.equals(username, "admin") || StringUtils.equals(username, createBy))) { | |||||
| throw new RuntimeException("无权限删除该实验"); | |||||
| } | |||||
| activeLearn.setState(Constant.State_invalid); | |||||
| resourceOccupyService.deleteTaskState(Constant.TaskType_ActiveLearn, id, null); | |||||
| return activeLearnDao.edit(activeLearn) > 0 ? "删除成功" : "删除失败"; | |||||
| } | |||||
| @Override | |||||
| public String runActiveLearnIns(Long id) throws Exception { | |||||
| ActiveLearn activeLearn = activeLearnDao.getActiveLearnById(id); | |||||
| if (activeLearn == null) { | |||||
| throw new Exception("主动学习配置不存在"); | |||||
| } | |||||
| // 记录开始扣积分 | |||||
| if (resourceOccupyService.haveResource(activeLearn.getComputingResourceId(), 1)) { | |||||
| ActiveLearnParamVo activeLearnParamVo = new ActiveLearnParamVo(); | |||||
| BeanUtils.copyProperties(activeLearn, activeLearnParamVo); | |||||
| activeLearnParamVo.setCodeConfig(JsonUtils.jsonToMap(activeLearn.getCodeConfig())); | |||||
| activeLearnParamVo.setDataset(JsonUtils.jsonToMap(activeLearn.getDataset())); | |||||
| activeLearnParamVo.setModel(JsonUtils.jsonToMap(activeLearn.getModel())); | |||||
| activeLearnParamVo.setImage(JsonUtils.jsonToMap(activeLearn.getImage())); | |||||
| String param = JsonUtils.getConvertParam(activeLearnParamVo); | |||||
| // 调argo转换接口 | |||||
| try { | |||||
| String convertRes = HttpUtils.sendPost(argoUrl + convertActiveLearn, param); | |||||
| if (convertRes == null || StringUtils.isEmpty(convertRes)) { | |||||
| throw new RuntimeException("转换流水线失败"); | |||||
| } | |||||
| Map<String, Object> converMap = JsonUtils.jsonToMap(convertRes); | |||||
| // 组装运行接口json | |||||
| Map<String, Object> output = (Map<String, Object>) converMap.get("output"); | |||||
| Map<String, Object> runReqMap = new HashMap<>(); | |||||
| runReqMap.put("data", converMap.get("data")); | |||||
| // 调argo运行接口 | |||||
| String runRes = HttpUtils.sendPost(argoUrl + argoWorkflowRun, JsonUtils.mapToJson(runReqMap)); | |||||
| if (runRes == null || StringUtils.isEmpty(runRes)) { | |||||
| throw new RuntimeException("运行失败"); | |||||
| } | |||||
| Map<String, Object> runResMap = JsonUtils.jsonToMap(runRes); | |||||
| Map<String, Object> data = (Map<String, Object>) runResMap.get("data"); | |||||
| //判断data为空 | |||||
| if (data == null || MapUtils.isEmpty(data)) { | |||||
| throw new RuntimeException("运行失败"); | |||||
| } | |||||
| Map<String, Object> metadata = (Map<String, Object>) data.get("metadata"); | |||||
| // 插入记录到实验实例表 | |||||
| ActiveLearnIns activeLearnIns = new ActiveLearnIns(); | |||||
| activeLearnIns.setActiveLearnId(id); | |||||
| activeLearnIns.setArgoInsNs((String) metadata.get("namespace")); | |||||
| activeLearnIns.setArgoInsName((String) metadata.get("name")); | |||||
| activeLearnIns.setParam(param); | |||||
| activeLearnIns.setStatus(Constant.Pending); | |||||
| //替换argoInsName | |||||
| String outputString = JsonUtils.mapToJson(output); | |||||
| activeLearnIns.setNodeResult(outputString.replace("{{workflow.name}}", (String) metadata.get("name"))); | |||||
| Map<String, Object> param_output = (Map<String, Object>) output.get("param_output"); | |||||
| List output1 = (ArrayList) param_output.values().toArray()[0]; | |||||
| Map<String, String> output2 = (Map<String, String>) output1.get(0); | |||||
| String outputPath = output2.get("path").replace("{{workflow.name}}", (String) metadata.get("name")) + "/hpo"; | |||||
| activeLearnIns.setResultPath(outputPath); | |||||
| activeLearnInsDao.insert(activeLearnIns); | |||||
| activeLearnInsService.updateActiveLearnStatus(id); | |||||
| // 记录开始扣除积分 | |||||
| resourceOccupyService.startDeduce(activeLearn.getComputingResourceId(), 1, Constant.TaskType_ActiveLearn, id, activeLearnIns.getId(), null, activeLearn.getName(), null, null); | |||||
| } catch (Exception e) { | |||||
| throw new RuntimeException(e); | |||||
| } | |||||
| } | |||||
| return "执行成功"; | |||||
| } | |||||
| } | |||||
| @@ -146,7 +146,7 @@ public class AutoMlInsServiceImpl implements AutoMlInsService { | |||||
| if (!StringUtils.equals(ins.getStatus(), Constant.Terminated)) { | if (!StringUtils.equals(ins.getStatus(), Constant.Terminated)) { | ||||
| ins.setStatus(StringUtils.isNotEmpty((String) status.get("phase")) ? (String) status.get("phase") : Constant.Pending); | ins.setStatus(StringUtils.isNotEmpty((String) status.get("phase")) ? (String) status.get("phase") : Constant.Pending); | ||||
| } | } | ||||
| if (StringUtils.equals(ins.getStatus(), "Error")) { | |||||
| if (StringUtils.equals(ins.getStatus(), Constant.Error)) { | |||||
| ins.setStatus(Constant.Failed); | ins.setStatus(Constant.Failed); | ||||
| } | } | ||||
| return ins; | return ins; | ||||
| @@ -2,11 +2,11 @@ package com.ruoyi.platform.service.impl; | |||||
| import com.alibaba.fastjson2.JSON; | import com.alibaba.fastjson2.JSON; | ||||
| import com.ruoyi.common.security.utils.SecurityUtils; | import com.ruoyi.common.security.utils.SecurityUtils; | ||||
| import com.ruoyi.platform.domain.ActiveLearn; | |||||
| import com.ruoyi.platform.mapper.*; | |||||
| import com.ruoyi.system.api.constant.Constant; | import com.ruoyi.system.api.constant.Constant; | ||||
| import com.ruoyi.platform.domain.AssetWorkflow; | import com.ruoyi.platform.domain.AssetWorkflow; | ||||
| import com.ruoyi.platform.domain.CodeConfig; | import com.ruoyi.platform.domain.CodeConfig; | ||||
| import com.ruoyi.platform.mapper.AssetWorkflowDao; | |||||
| import com.ruoyi.platform.mapper.CodeConfigDao; | |||||
| import com.ruoyi.platform.service.CodeConfigService; | import com.ruoyi.platform.service.CodeConfigService; | ||||
| import com.ruoyi.system.api.model.LoginUser; | import com.ruoyi.system.api.model.LoginUser; | ||||
| import org.apache.commons.lang3.StringUtils; | import org.apache.commons.lang3.StringUtils; | ||||
| @@ -15,7 +15,6 @@ import org.springframework.data.domain.PageImpl; | |||||
| import org.springframework.data.domain.PageRequest; | import org.springframework.data.domain.PageRequest; | ||||
| import org.springframework.stereotype.Service; | import org.springframework.stereotype.Service; | ||||
| import com.ruoyi.platform.domain.Ray; | import com.ruoyi.platform.domain.Ray; | ||||
| import com.ruoyi.platform.mapper.RayDao; | |||||
| import javax.annotation.Resource; | import javax.annotation.Resource; | ||||
| import java.util.Date; | import java.util.Date; | ||||
| @@ -32,6 +31,10 @@ public class CodeConfigServiceImpl implements CodeConfigService { | |||||
| private AssetWorkflowDao assetWorkflowDao; | private AssetWorkflowDao assetWorkflowDao; | ||||
| @Resource | @Resource | ||||
| private RayDao rayDao; | private RayDao rayDao; | ||||
| @Resource | |||||
| private ActiveLearnDao activeLearnDao; | |||||
| @Resource | |||||
| private ServiceDao serviceDao; | |||||
| @Override | @Override | ||||
| public Page<CodeConfig> queryByPage(CodeConfig codeConfig, PageRequest pageRequest) { | public Page<CodeConfig> queryByPage(CodeConfig codeConfig, PageRequest pageRequest) { | ||||
| @@ -102,6 +105,18 @@ public class CodeConfigServiceImpl implements CodeConfigService { | |||||
| throw new Exception("该代码配置被超参数自动寻优:" + rays + "使用,不能删除,请先删除超参数自动寻优。"); | throw new Exception("该代码配置被超参数自动寻优:" + rays + "使用,不能删除,请先删除超参数自动寻优。"); | ||||
| } | } | ||||
| List<ActiveLearn> activeLearnList = activeLearnDao.queryByCodeConfig(JSON.toJSONString(map)); | |||||
| if (activeLearnList != null && !activeLearnList.isEmpty()) { | |||||
| String activeLearns = String.join(",", activeLearnList.stream().map(ActiveLearn::getName).collect(Collectors.toSet())); | |||||
| throw new Exception("该代码配置被主动学习:" + activeLearns + "使用,不能删除,请先删除主动学习。"); | |||||
| } | |||||
| List<String> serviceVersionList = serviceDao.queryByCodeConfig(JSON.toJSONString(map)); | |||||
| if (serviceVersionList != null && !serviceVersionList.isEmpty()) { | |||||
| String serviceVersions = String.join(",", serviceVersionList.stream().collect(Collectors.toSet())); | |||||
| throw new Exception("该代码配置被服务版本:" + serviceVersions + "使用,不能删除,请先删除服务版本。"); | |||||
| } | |||||
| LoginUser loginUser = SecurityUtils.getLoginUser(); | LoginUser loginUser = SecurityUtils.getLoginUser(); | ||||
| String username = loginUser.getUsername(); | String username = loginUser.getUsername(); | ||||
| String createBy = codeConfig.getCreateBy(); | String createBy = codeConfig.getCreateBy(); | ||||
| @@ -6,9 +6,11 @@ import com.ruoyi.platform.domain.PodStatus; | |||||
| import com.ruoyi.platform.mapper.DevEnvironmentDao; | import com.ruoyi.platform.mapper.DevEnvironmentDao; | ||||
| import com.ruoyi.platform.service.DevEnvironmentService; | import com.ruoyi.platform.service.DevEnvironmentService; | ||||
| import com.ruoyi.platform.service.JupyterService; | import com.ruoyi.platform.service.JupyterService; | ||||
| import com.ruoyi.platform.service.ResourceOccupyService; | |||||
| import com.ruoyi.platform.utils.JacksonUtil; | import com.ruoyi.platform.utils.JacksonUtil; | ||||
| import com.ruoyi.platform.vo.DevEnvironmentVo; | import com.ruoyi.platform.vo.DevEnvironmentVo; | ||||
| import com.ruoyi.platform.vo.PodStatusVo; | import com.ruoyi.platform.vo.PodStatusVo; | ||||
| import com.ruoyi.system.api.constant.Constant; | |||||
| import com.ruoyi.system.api.model.LoginUser; | import com.ruoyi.system.api.model.LoginUser; | ||||
| import org.apache.commons.lang3.StringUtils; | import org.apache.commons.lang3.StringUtils; | ||||
| import org.springframework.context.annotation.Lazy; | import org.springframework.context.annotation.Lazy; | ||||
| @@ -16,6 +18,7 @@ import org.springframework.data.domain.Page; | |||||
| import org.springframework.data.domain.PageImpl; | import org.springframework.data.domain.PageImpl; | ||||
| import org.springframework.data.domain.PageRequest; | import org.springframework.data.domain.PageRequest; | ||||
| import org.springframework.stereotype.Service; | import org.springframework.stereotype.Service; | ||||
| import org.springframework.transaction.annotation.Transactional; | |||||
| import javax.annotation.Resource; | import javax.annotation.Resource; | ||||
| import java.util.Date; | import java.util.Date; | ||||
| @@ -35,6 +38,8 @@ public class DevEnvironmentServiceImpl implements DevEnvironmentService { | |||||
| @Resource | @Resource | ||||
| @Lazy | @Lazy | ||||
| private JupyterService jupyterService; | private JupyterService jupyterService; | ||||
| @Resource | |||||
| private ResourceOccupyService resourceOccupyService; | |||||
| /** | /** | ||||
| * 通过ID查询单条数据 | * 通过ID查询单条数据 | ||||
| @@ -89,27 +94,28 @@ public class DevEnvironmentServiceImpl implements DevEnvironmentService { | |||||
| */ | */ | ||||
| @Override | @Override | ||||
| public DevEnvironment insert(DevEnvironmentVo devEnvironmentVo) throws Exception { | public DevEnvironment insert(DevEnvironmentVo devEnvironmentVo) throws Exception { | ||||
| DevEnvironment devByName = devEnvironmentDao.getByName(devEnvironmentVo.getName()); | |||||
| if (devByName != null) { | |||||
| throw new RuntimeException("开发环境名称已存在"); | |||||
| } | |||||
| //插入预备,此时不需要判断版本重复 | //插入预备,此时不需要判断版本重复 | ||||
| DevEnvironment devEnvironment = new DevEnvironment(); | DevEnvironment devEnvironment = new DevEnvironment(); | ||||
| LoginUser loginUser = SecurityUtils.getLoginUser(); | LoginUser loginUser = SecurityUtils.getLoginUser(); | ||||
| devEnvironment.setName(devEnvironmentVo.getName()); | devEnvironment.setName(devEnvironmentVo.getName()); | ||||
| //状态先设为未知 | //状态先设为未知 | ||||
| devEnvironment.setStatus("Unknown"); | |||||
| devEnvironment.setStatus(Constant.Unknown); | |||||
| devEnvironment.setComputingResource(devEnvironmentVo.getComputingResource()); | devEnvironment.setComputingResource(devEnvironmentVo.getComputingResource()); | ||||
| devEnvironment.setComputingResourceId(devEnvironmentVo.getComputingResourceId()); | devEnvironment.setComputingResourceId(devEnvironmentVo.getComputingResourceId()); | ||||
| devEnvironment.setStandard(devEnvironmentVo.getStandard()); | devEnvironment.setStandard(devEnvironmentVo.getStandard()); | ||||
| devEnvironment.setEnvVariable(devEnvironmentVo.getEnvVariable()); | devEnvironment.setEnvVariable(devEnvironmentVo.getEnvVariable()); | ||||
| devEnvironment.setImage(devEnvironmentVo.getImage()); | |||||
| // 将 dataset 和 model 转换成 JSON 字符串 | |||||
| String datasetJson = JacksonUtil.toJSONString(devEnvironmentVo.getDataset()); | |||||
| String modelJson = JacksonUtil.toJSONString(devEnvironmentVo.getModel()); | |||||
| devEnvironment.setDataset(datasetJson); | |||||
| devEnvironment.setModel(modelJson); | |||||
| devEnvironment.setImage(JacksonUtil.toJSONString(devEnvironmentVo.getImage())); | |||||
| devEnvironment.setDataset(JacksonUtil.toJSONString(devEnvironmentVo.getDataset())); | |||||
| devEnvironment.setModel(JacksonUtil.toJSONString(devEnvironmentVo.getModel())); | |||||
| devEnvironment.setCreateBy(loginUser.getUsername()); | devEnvironment.setCreateBy(loginUser.getUsername()); | ||||
| devEnvironment.setUpdateBy(loginUser.getUsername()); | devEnvironment.setUpdateBy(loginUser.getUsername()); | ||||
| devEnvironment.setUpdateTime(new Date()); | devEnvironment.setUpdateTime(new Date()); | ||||
| devEnvironment.setCreateTime(new Date()); | devEnvironment.setCreateTime(new Date()); | ||||
| devEnvironment.setState(1); | |||||
| devEnvironment.setState(Constant.State_valid); | |||||
| this.devEnvironmentDao.insert(devEnvironment); | this.devEnvironmentDao.insert(devEnvironment); | ||||
| return devEnvironment; | return devEnvironment; | ||||
| } | } | ||||
| @@ -140,6 +146,7 @@ public class DevEnvironmentServiceImpl implements DevEnvironmentService { | |||||
| } | } | ||||
| @Override | @Override | ||||
| @Transactional | |||||
| public String removeById(Integer id) throws Exception { | public String removeById(Integer id) throws Exception { | ||||
| DevEnvironment devEnvironment = this.devEnvironmentDao.queryById(id); | DevEnvironment devEnvironment = this.devEnvironmentDao.queryById(id); | ||||
| if (devEnvironment == null) { | if (devEnvironment == null) { | ||||
| @@ -155,9 +162,8 @@ public class DevEnvironmentServiceImpl implements DevEnvironmentService { | |||||
| } | } | ||||
| jupyterService.stopJupyterService(id); | jupyterService.stopJupyterService(id); | ||||
| devEnvironment.setState(0); | |||||
| devEnvironment.setState(Constant.State_invalid); | |||||
| resourceOccupyService.deleteTaskState(Constant.TaskType_Dev, Long.valueOf(id), null); | |||||
| return this.devEnvironmentDao.update(devEnvironment) > 0 ? "删除成功" : "删除失败"; | return this.devEnvironmentDao.update(devEnvironment) > 0 ? "删除成功" : "删除失败"; | ||||
| } | } | ||||
| } | } | ||||
| @@ -2,7 +2,6 @@ package com.ruoyi.platform.service.impl; | |||||
| import com.alibaba.fastjson2.JSON; | import com.alibaba.fastjson2.JSON; | ||||
| import com.ruoyi.common.security.utils.SecurityUtils; | import com.ruoyi.common.security.utils.SecurityUtils; | ||||
| import com.ruoyi.system.api.constant.Constant; | |||||
| import com.ruoyi.platform.domain.DatasetTempStorage; | import com.ruoyi.platform.domain.DatasetTempStorage; | ||||
| import com.ruoyi.platform.domain.Experiment; | import com.ruoyi.platform.domain.Experiment; | ||||
| import com.ruoyi.platform.domain.ExperimentIns; | import com.ruoyi.platform.domain.ExperimentIns; | ||||
| @@ -16,6 +15,7 @@ import com.ruoyi.platform.service.ResourceOccupyService; | |||||
| import com.ruoyi.platform.utils.*; | import com.ruoyi.platform.utils.*; | ||||
| import com.ruoyi.platform.vo.LogRequestVo; | import com.ruoyi.platform.vo.LogRequestVo; | ||||
| import com.ruoyi.platform.vo.PodLogVo; | import com.ruoyi.platform.vo.PodLogVo; | ||||
| import com.ruoyi.system.api.constant.Constant; | |||||
| import com.ruoyi.system.api.model.LoginUser; | import com.ruoyi.system.api.model.LoginUser; | ||||
| import org.apache.commons.lang3.StringUtils; | import org.apache.commons.lang3.StringUtils; | ||||
| import org.springframework.beans.factory.annotation.Value; | import org.springframework.beans.factory.annotation.Value; | ||||
| @@ -23,6 +23,7 @@ import org.springframework.data.domain.Page; | |||||
| import org.springframework.data.domain.PageImpl; | import org.springframework.data.domain.PageImpl; | ||||
| import org.springframework.data.domain.PageRequest; | import org.springframework.data.domain.PageRequest; | ||||
| import org.springframework.stereotype.Service; | import org.springframework.stereotype.Service; | ||||
| import org.springframework.transaction.annotation.Transactional; | |||||
| import javax.annotation.Resource; | import javax.annotation.Resource; | ||||
| import java.io.IOException; | import java.io.IOException; | ||||
| @@ -204,6 +205,7 @@ public class ExperimentInsServiceImpl implements ExperimentInsService { | |||||
| } | } | ||||
| @Override | @Override | ||||
| @Transactional | |||||
| public String removeById(Integer id) { | public String removeById(Integer id) { | ||||
| ExperimentIns experimentIns = experimentInsDao.queryById(id); | ExperimentIns experimentIns = experimentInsDao.queryById(id); | ||||
| if (experimentIns == null) { | if (experimentIns == null) { | ||||
| @@ -227,6 +229,7 @@ public class ExperimentInsServiceImpl implements ExperimentInsService { | |||||
| experimentIns.setState(0); | experimentIns.setState(0); | ||||
| int update = this.experimentInsDao.update(experimentIns); | int update = this.experimentInsDao.update(experimentIns); | ||||
| if (update > 0) { | if (update > 0) { | ||||
| resourceOccupyService.deleteTaskState(Constant.TaskType_Workflow, Long.valueOf(experimentIns.getExperimentId()), Long.valueOf(id)); | |||||
| updateExperimentStatus(experimentIns.getExperimentId()); | updateExperimentStatus(experimentIns.getExperimentId()); | ||||
| return "删除成功"; | return "删除成功"; | ||||
| } else { | } else { | ||||
| @@ -323,7 +326,7 @@ public class ExperimentInsServiceImpl implements ExperimentInsService { | |||||
| if (!StringUtils.equals(experimentIns.getStatus(), "Terminated")) { | if (!StringUtils.equals(experimentIns.getStatus(), "Terminated")) { | ||||
| experimentIns.setStatus(StringUtils.isNotEmpty((String) status.get("phase")) ? (String) status.get("phase") : "Pending"); | experimentIns.setStatus(StringUtils.isNotEmpty((String) status.get("phase")) ? (String) status.get("phase") : "Pending"); | ||||
| } | } | ||||
| if (StringUtils.equals(experimentIns.getStatus(), "Error")) { | |||||
| if (StringUtils.equals(experimentIns.getStatus(), Constant.Error)) { | |||||
| experimentIns.setStatus("Failed"); | experimentIns.setStatus("Failed"); | ||||
| } | } | ||||
| @@ -28,6 +28,7 @@ import org.springframework.data.domain.PageImpl; | |||||
| import org.springframework.data.domain.PageRequest; | import org.springframework.data.domain.PageRequest; | ||||
| import org.springframework.http.ResponseEntity; | import org.springframework.http.ResponseEntity; | ||||
| import org.springframework.stereotype.Service; | import org.springframework.stereotype.Service; | ||||
| import org.springframework.transaction.annotation.Transactional; | |||||
| import javax.annotation.Resource; | import javax.annotation.Resource; | ||||
| import java.io.IOException; | import java.io.IOException; | ||||
| @@ -184,6 +185,7 @@ public class ExperimentServiceImpl implements ExperimentService { | |||||
| } | } | ||||
| @Override | @Override | ||||
| @Transactional | |||||
| public String removeById(Integer id) throws Exception { | public String removeById(Integer id) throws Exception { | ||||
| Experiment experiment = experimentDao.queryById(id); | Experiment experiment = experimentDao.queryById(id); | ||||
| if (experiment == null) { | if (experiment == null) { | ||||
| @@ -202,7 +204,8 @@ public class ExperimentServiceImpl implements ExperimentService { | |||||
| if (experimentInsList != null && experimentInsList.size() > 0) { | if (experimentInsList != null && experimentInsList.size() > 0) { | ||||
| throw new Exception("该实验存在实例,无法删除"); | throw new Exception("该实验存在实例,无法删除"); | ||||
| } | } | ||||
| experiment.setState(0); | |||||
| resourceOccupyService.deleteTaskState(Constant.TaskType_Workflow, Long.valueOf(id), null); | |||||
| experiment.setState(Constant.State_invalid); | |||||
| return this.experimentDao.update(experiment) > 0 ? "删除成功" : "删除失败"; | return this.experimentDao.update(experiment) > 0 ? "删除成功" : "删除失败"; | ||||
| @@ -11,6 +11,7 @@ import com.ruoyi.platform.service.ImageVersionService; | |||||
| import com.ruoyi.platform.service.MinioService; | import com.ruoyi.platform.service.MinioService; | ||||
| import com.ruoyi.platform.utils.DockerClientUtil; | import com.ruoyi.platform.utils.DockerClientUtil; | ||||
| import com.ruoyi.platform.utils.FileUtil; | import com.ruoyi.platform.utils.FileUtil; | ||||
| import com.ruoyi.platform.utils.JacksonUtil; | |||||
| import com.ruoyi.platform.utils.K8sClientUtil; | import com.ruoyi.platform.utils.K8sClientUtil; | ||||
| import com.ruoyi.platform.vo.ImageVo; | import com.ruoyi.platform.vo.ImageVo; | ||||
| import com.ruoyi.system.api.constant.Constant; | import com.ruoyi.system.api.constant.Constant; | ||||
| @@ -54,8 +55,11 @@ public class ImageServiceImpl implements ImageService { | |||||
| @Resource | @Resource | ||||
| private RayDao rayDao; | private RayDao rayDao; | ||||
| @Resource | @Resource | ||||
| private ActiveLearnDao activeLearnDao; | |||||
| @Resource | |||||
| private ImageVersionService imageVersionService; | private ImageVersionService imageVersionService; | ||||
| @Resource | |||||
| private ServiceDao serviceDao; | |||||
| @Resource | @Resource | ||||
| private K8sClientUtil k8sClientUtil; | private K8sClientUtil k8sClientUtil; | ||||
| @Resource | @Resource | ||||
| @@ -84,8 +88,6 @@ public class ImageServiceImpl implements ImageService { | |||||
| private String image; | private String image; | ||||
| @Value("${dockerpush.mountPath}") | @Value("${dockerpush.mountPath}") | ||||
| private String mountPath; | private String mountPath; | ||||
| @Value("${dockerpush.proxyUrl}") | |||||
| private String proxyUrl; | |||||
| @Value("${jupyter.namespace}") | @Value("${jupyter.namespace}") | ||||
| private String namespace; | private String namespace; | ||||
| @@ -184,6 +186,24 @@ public class ImageServiceImpl implements ImageService { | |||||
| throw new Exception("该镜像被超参数自动寻优:" + rays + "使用,不能删除,请先删除超参数自动寻优。"); | throw new Exception("该镜像被超参数自动寻优:" + rays + "使用,不能删除,请先删除超参数自动寻优。"); | ||||
| } | } | ||||
| List<ActiveLearn> activeLearnList = activeLearnDao.queryByImageId(JSON.toJSONString(map)); | |||||
| if (activeLearnList != null && !activeLearnList.isEmpty()) { | |||||
| String activeLearns = String.join(",", activeLearnList.stream().map(ActiveLearn::getName).collect(Collectors.toSet())); | |||||
| throw new Exception("该镜像被主动学习:" + activeLearns + "使用,不能删除,请先删除主动学习。"); | |||||
| } | |||||
| List<DevEnvironment> devEnvironmentList = devEnvironmentDao.queryByImageId(JSON.toJSONString(map)); | |||||
| if (devEnvironmentList != null && !devEnvironmentList.isEmpty()) { | |||||
| String devEnvironments = String.join(",", devEnvironmentList.stream().map(DevEnvironment::getName).collect(Collectors.toSet())); | |||||
| throw new Exception("该镜像被开发环境:" + devEnvironments + "使用,不能删除,请先删除开发环境。"); | |||||
| } | |||||
| List<String> serviceVersionList = serviceDao.queryByImageId(JSON.toJSONString(map)); | |||||
| if (serviceVersionList != null && !serviceVersionList.isEmpty()) { | |||||
| String serviceVersions = String.join(",", serviceVersionList.stream().collect(Collectors.toSet())); | |||||
| throw new Exception("该镜像被服务版本:" + serviceVersions + "使用,不能删除,请先删除服务版本。"); | |||||
| } | |||||
| //判断权限,只有admin和创建者本身可以删除该数据集 | //判断权限,只有admin和创建者本身可以删除该数据集 | ||||
| LoginUser loginUser = SecurityUtils.getLoginUser(); | LoginUser loginUser = SecurityUtils.getLoginUser(); | ||||
| String username = loginUser.getUsername(); | String username = loginUser.getUsername(); | ||||
| @@ -302,7 +322,7 @@ public class ImageServiceImpl implements ImageService { | |||||
| V1Pod pod = k8sClientUtil.getNSPodList(serviceNS, deploymentName); | V1Pod pod = k8sClientUtil.getNSPodList(serviceNS, deploymentName); | ||||
| if (pod == null) { | if (pod == null) { | ||||
| String podName = deploymentName + "-" + DateUtils.formatYMD10(new Date()); | String podName = deploymentName + "-" + DateUtils.formatYMD10(new Date()); | ||||
| pod = k8sClientUtil.createPodWithEnv(podName, serviceNS, proxyUrl, mountPath, image); | |||||
| pod = k8sClientUtil.createPodWithEnv(podName, serviceNS, mountPath, image); | |||||
| } | } | ||||
| String loginCmd = "docker login -u " + harborUser + " -p " + harborpassword + " " + harborUrl; | String loginCmd = "docker login -u " + harborUser + " -p " + harborpassword + " " + harborUrl; | ||||
| // 执行命令 docker login -u admin -p Harbor12345 172.20.32.187 | // 执行命令 docker login -u admin -p Harbor12345 172.20.32.187 | ||||
| @@ -345,7 +365,7 @@ public class ImageServiceImpl implements ImageService { | |||||
| V1Pod pod = k8sClientUtil.getNSPodList(serviceNS, deploymentName); | V1Pod pod = k8sClientUtil.getNSPodList(serviceNS, deploymentName); | ||||
| if (pod == null) { | if (pod == null) { | ||||
| String podName = deploymentName + "-" + DateUtils.formatYMD10(new Date()); | String podName = deploymentName + "-" + DateUtils.formatYMD10(new Date()); | ||||
| pod = k8sClientUtil.createPodWithEnv(podName, serviceNS, proxyUrl, mountPath, image); | |||||
| pod = k8sClientUtil.createPodWithEnv(podName, serviceNS, mountPath, image); | |||||
| } | } | ||||
| String loginCmd = "docker login -u " + harborUser + " -p " + harborpassword + " " + harborUrl; | String loginCmd = "docker login -u " + harborUser + " -p " + harborpassword + " " + harborUrl; | ||||
| // 执行命令 docker login -u admin -p Harbor12345 172.20.32.187 | // 执行命令 docker login -u admin -p Harbor12345 172.20.32.187 | ||||
| @@ -435,13 +455,22 @@ public class ImageServiceImpl implements ImageService { | |||||
| imageVersion.setUpdateTime(new Date()); | imageVersion.setUpdateTime(new Date()); | ||||
| imageVersion.setCreateTime(new Date()); | imageVersion.setCreateTime(new Date()); | ||||
| imageVersion.setState(Constant.State_valid); | imageVersion.setState(Constant.State_valid); | ||||
| imageVersion.setStatus("available"); | |||||
| imageVersion.setStatus(Constant.Available); | |||||
| imageVersionDao.insert(imageVersion); | imageVersionDao.insert(imageVersion); | ||||
| //更新dev环境的镜像信息 | //更新dev环境的镜像信息 | ||||
| DevEnvironment devEnvironment = new DevEnvironment(); | DevEnvironment devEnvironment = new DevEnvironment(); | ||||
| devEnvironment.setId(imageVo.getDevEnvironmentId()); | devEnvironment.setId(imageVo.getDevEnvironmentId()); | ||||
| devEnvironment.setImage(resultMap.get("imageName")); | |||||
| imageVo.setValue(resultMap.get("imageName")); | |||||
| imageVo.setVersion(String.valueOf(imageVersion.getId())); | |||||
| resultMap.put("id", String.valueOf(oldImage.getId())); | |||||
| resultMap.put("version", String.valueOf(imageVersion.getId())); | |||||
| resultMap.put("value",resultMap.get("imageName")); | |||||
| devEnvironment.setImage(JacksonUtil.toJSONString(resultMap)); | |||||
| devEnvironmentDao.update(devEnvironment); | devEnvironmentDao.update(devEnvironment); | ||||
| } catch (Exception e) { | } catch (Exception e) { | ||||
| throw new RuntimeException("保存镜像失败:" + e); | throw new RuntimeException("保存镜像失败:" + e); | ||||
| @@ -3,12 +3,8 @@ package com.ruoyi.platform.service.impl; | |||||
| import com.alibaba.fastjson2.JSON; | import com.alibaba.fastjson2.JSON; | ||||
| import com.ruoyi.common.core.web.domain.GenericsAjaxResult; | import com.ruoyi.common.core.web.domain.GenericsAjaxResult; | ||||
| import com.ruoyi.common.security.utils.SecurityUtils; | import com.ruoyi.common.security.utils.SecurityUtils; | ||||
| import com.ruoyi.platform.domain.AssetWorkflow; | |||||
| import com.ruoyi.platform.domain.ImageVersion; | |||||
| import com.ruoyi.platform.domain.Ray; | |||||
| import com.ruoyi.platform.mapper.AssetWorkflowDao; | |||||
| import com.ruoyi.platform.mapper.ImageVersionDao; | |||||
| import com.ruoyi.platform.mapper.RayDao; | |||||
| import com.ruoyi.platform.domain.*; | |||||
| import com.ruoyi.platform.mapper.*; | |||||
| import com.ruoyi.platform.service.ImageVersionService; | import com.ruoyi.platform.service.ImageVersionService; | ||||
| import com.ruoyi.system.api.constant.Constant; | import com.ruoyi.system.api.constant.Constant; | ||||
| import com.ruoyi.system.api.model.LoginUser; | import com.ruoyi.system.api.model.LoginUser; | ||||
| @@ -38,7 +34,12 @@ public class ImageVersionServiceImpl implements ImageVersionService { | |||||
| private AssetWorkflowDao assetWorkflowDao; | private AssetWorkflowDao assetWorkflowDao; | ||||
| @Resource | @Resource | ||||
| private RayDao rayDao; | private RayDao rayDao; | ||||
| @Resource | |||||
| private ActiveLearnDao activeLearnDao; | |||||
| @Resource | |||||
| private DevEnvironmentDao devEnvironmentDao; | |||||
| @Resource | |||||
| private ServiceDao serviceDao; | |||||
| /** | /** | ||||
| * 通过ID查询单条数据 | * 通过ID查询单条数据 | ||||
| * | * | ||||
| @@ -96,6 +97,24 @@ public class ImageVersionServiceImpl implements ImageVersionService { | |||||
| return GenericsAjaxResult.error("该镜像版本被超参数自动寻优:" + rays + "使用,不能删除,请先删除超参数自动寻优。"); | return GenericsAjaxResult.error("该镜像版本被超参数自动寻优:" + rays + "使用,不能删除,请先删除超参数自动寻优。"); | ||||
| } | } | ||||
| List<ActiveLearn> activeLearnList = activeLearnDao.queryByImageId(JSON.toJSONString(map)); | |||||
| if (activeLearnList != null && !activeLearnList.isEmpty()) { | |||||
| String activeLearns = String.join(",", activeLearnList.stream().map(ActiveLearn::getName).collect(Collectors.toSet())); | |||||
| return GenericsAjaxResult.error("该镜像版本被主动学习:" + activeLearns + "使用,不能删除,请先删除主动学习。"); | |||||
| } | |||||
| List<DevEnvironment> devEnvironmentList = devEnvironmentDao.queryByImageId(JSON.toJSONString(map)); | |||||
| if (devEnvironmentList != null && !devEnvironmentList.isEmpty()) { | |||||
| String devEnvironments = String.join(",", devEnvironmentList.stream().map(DevEnvironment::getName).collect(Collectors.toSet())); | |||||
| throw new Exception("该镜像版本被开发环境:" + devEnvironments + "使用,不能删除,请先删除开发环境。"); | |||||
| } | |||||
| List<String> serviceVersionList = serviceDao.queryByImageId(JSON.toJSONString(map)); | |||||
| if (serviceVersionList != null && !serviceVersionList.isEmpty()) { | |||||
| String serviceVersions = String.join(",", serviceVersionList.stream().collect(Collectors.toSet())); | |||||
| throw new Exception("该镜像版本被服务版本:" + serviceVersions + "使用,不能删除,请先删除服务版本。"); | |||||
| } | |||||
| //判断权限,只有admin和创建者本身可以删除该数据集 | //判断权限,只有admin和创建者本身可以删除该数据集 | ||||
| LoginUser loginUser = SecurityUtils.getLoginUser(); | LoginUser loginUser = SecurityUtils.getLoginUser(); | ||||
| String username = loginUser.getUsername(); | String username = loginUser.getUsername(); | ||||
| @@ -68,7 +68,12 @@ public class ModelsServiceImpl implements ModelsService { | |||||
| private RayDao rayDao; | private RayDao rayDao; | ||||
| @Resource | @Resource | ||||
| private ModelsVersionService modelsVersionService; | private ModelsVersionService modelsVersionService; | ||||
| @Resource | |||||
| private ActiveLearnDao activeLearnDao; | |||||
| @Resource | |||||
| private DevEnvironmentDao devEnvironmentDao; | |||||
| @Resource | |||||
| private ServiceDao serviceDao; | |||||
| @Resource | @Resource | ||||
| private ModelDependency1Dao modelDependency1Dao; | private ModelDependency1Dao modelDependency1Dao; | ||||
| @@ -1167,6 +1172,24 @@ public class ModelsServiceImpl implements ModelsService { | |||||
| throw new Exception("该模型被超参数自动寻优:" + rays + "使用,不能删除,请先删除超参数自动寻优。"); | throw new Exception("该模型被超参数自动寻优:" + rays + "使用,不能删除,请先删除超参数自动寻优。"); | ||||
| } | } | ||||
| List<ActiveLearn> activeLearnList = activeLearnDao.queryByModelId(JSON.toJSONString(queryMap)); | |||||
| if (activeLearnList != null && !activeLearnList.isEmpty()) { | |||||
| String activeLearns = String.join(",", activeLearnList.stream().map(ActiveLearn::getName).collect(Collectors.toSet())); | |||||
| throw new Exception("该模型被主动学习:" + activeLearns + "使用,不能删除,请先删除主动学习。"); | |||||
| } | |||||
| List<DevEnvironment> devEnvironmentList = devEnvironmentDao.queryByModelId(JSON.toJSONString(queryMap)); | |||||
| if (devEnvironmentList != null && !devEnvironmentList.isEmpty()) { | |||||
| String devEnvironments = String.join(",", devEnvironmentList.stream().map(DevEnvironment::getName).collect(Collectors.toSet())); | |||||
| throw new Exception("该模型被开发环境:" + devEnvironments + "使用,不能删除,请先删除开发环境。"); | |||||
| } | |||||
| List<String> serviceVersionList = serviceDao.queryByModelId(JSON.toJSONString(queryMap)); | |||||
| if (serviceVersionList != null && !serviceVersionList.isEmpty()) { | |||||
| String serviceVersions = String.join(",", serviceVersionList.stream().collect(Collectors.toSet())); | |||||
| throw new Exception("该模型被服务版本:" + serviceVersions + "使用,不能删除,请先删除服务版本。"); | |||||
| } | |||||
| String token = gitService.checkoutToken(); | String token = gitService.checkoutToken(); | ||||
| gitService.deleteProject(token, owner, identifier); | gitService.deleteProject(token, owner, identifier); | ||||
| //删除模型依赖 | //删除模型依赖 | ||||
| @@ -1196,7 +1219,25 @@ public class ModelsServiceImpl implements ModelsService { | |||||
| List<Ray> rayList = rayDao.queryByModelId(JSON.toJSONString(queryMap)); | List<Ray> rayList = rayDao.queryByModelId(JSON.toJSONString(queryMap)); | ||||
| if (rayList != null && !rayList.isEmpty()) { | if (rayList != null && !rayList.isEmpty()) { | ||||
| String rays = String.join(",", rayList.stream().map(Ray::getName).collect(Collectors.toSet())); | String rays = String.join(",", rayList.stream().map(Ray::getName).collect(Collectors.toSet())); | ||||
| throw new Exception("该数据集版本被超参数自动寻优:" + rays + "使用,不能删除,请先删除超参数自动寻优。"); | |||||
| throw new Exception("该模型版本被超参数自动寻优:" + rays + "使用,不能删除,请先删除超参数自动寻优。"); | |||||
| } | |||||
| List<ActiveLearn> activeLearnList = activeLearnDao.queryByModelId(JSON.toJSONString(queryMap)); | |||||
| if (activeLearnList != null && !activeLearnList.isEmpty()) { | |||||
| String activeLearns = String.join(",", activeLearnList.stream().map(ActiveLearn::getName).collect(Collectors.toSet())); | |||||
| throw new Exception("该模型版本被主动学习:" + activeLearns + "使用,不能删除,请先删除主动学习。"); | |||||
| } | |||||
| List<DevEnvironment> devEnvironmentList = devEnvironmentDao.queryByModelId(JSON.toJSONString(queryMap)); | |||||
| if (devEnvironmentList != null && !devEnvironmentList.isEmpty()) { | |||||
| String devEnvironments = String.join(",", devEnvironmentList.stream().map(DevEnvironment::getName).collect(Collectors.toSet())); | |||||
| throw new Exception("该模型版本被开发环境:" + devEnvironments + "使用,不能删除,请先删除开发环境。"); | |||||
| } | |||||
| List<String> serviceVersionList = serviceDao.queryByModelId(JSON.toJSONString(queryMap)); | |||||
| if (serviceVersionList != null && !serviceVersionList.isEmpty()) { | |||||
| String serviceVersions = String.join(",", serviceVersionList.stream().collect(Collectors.toSet())); | |||||
| throw new Exception("该模型版本被服务版本:" + serviceVersions + "使用,不能删除,请先删除服务版本。"); | |||||
| } | } | ||||
| String token = gitService.checkoutToken(); | String token = gitService.checkoutToken(); | ||||
| @@ -4,9 +4,7 @@ import com.alibaba.fastjson2.JSON; | |||||
| import com.ruoyi.common.core.utils.DateUtils; | import com.ruoyi.common.core.utils.DateUtils; | ||||
| import com.ruoyi.common.security.utils.SecurityUtils; | import com.ruoyi.common.security.utils.SecurityUtils; | ||||
| import com.ruoyi.platform.domain.*; | import com.ruoyi.platform.domain.*; | ||||
| import com.ruoyi.platform.mapper.AssetWorkflowDao; | |||||
| import com.ruoyi.platform.mapper.AutoMlDao; | |||||
| import com.ruoyi.platform.mapper.RayDao; | |||||
| import com.ruoyi.platform.mapper.*; | |||||
| import com.ruoyi.platform.service.DatasetTempStorageService; | import com.ruoyi.platform.service.DatasetTempStorageService; | ||||
| import com.ruoyi.platform.service.GitService; | import com.ruoyi.platform.service.GitService; | ||||
| import com.ruoyi.platform.service.NewDatasetService; | import com.ruoyi.platform.service.NewDatasetService; | ||||
| @@ -56,6 +54,10 @@ public class NewDatasetServiceImpl implements NewDatasetService { | |||||
| private AutoMlDao autoMlDao; | private AutoMlDao autoMlDao; | ||||
| @Resource | @Resource | ||||
| private RayDao rayDao; | private RayDao rayDao; | ||||
| @Resource | |||||
| private ActiveLearnDao activeLearnDao; | |||||
| @Resource | |||||
| private DevEnvironmentDao devEnvironmentDao; | |||||
| @Value("${spring.redis.host}") | @Value("${spring.redis.host}") | ||||
| private String redisHost; | private String redisHost; | ||||
| @@ -430,6 +432,18 @@ public class NewDatasetServiceImpl implements NewDatasetService { | |||||
| throw new Exception("该数据集被超参数自动寻优:" + rays + "使用,不能删除,请先删除超参数自动寻优。"); | throw new Exception("该数据集被超参数自动寻优:" + rays + "使用,不能删除,请先删除超参数自动寻优。"); | ||||
| } | } | ||||
| List<ActiveLearn> activeLearnList = activeLearnDao.queryByDatasetId(JSON.toJSONString(map)); | |||||
| if (activeLearnList != null && !activeLearnList.isEmpty()) { | |||||
| String activeLearns = String.join(",", activeLearnList.stream().map(ActiveLearn::getName).collect(Collectors.toSet())); | |||||
| throw new Exception("该数据集被主动学习:" + activeLearns + "使用,不能删除,请先删除主动学习。"); | |||||
| } | |||||
| List<DevEnvironment> devEnvironmentList = devEnvironmentDao.queryByDatasetId(JSON.toJSONString(map)); | |||||
| if (devEnvironmentList != null && !devEnvironmentList.isEmpty()) { | |||||
| String devEnvironments = String.join(",", devEnvironmentList.stream().map(DevEnvironment::getName).collect(Collectors.toSet())); | |||||
| throw new Exception("该数据集被开发环境:" + devEnvironments + "使用,不能删除,请先删除开发环境。"); | |||||
| } | |||||
| String token = gitService.checkoutToken(); | String token = gitService.checkoutToken(); | ||||
| gitService.deleteProject(token, owner, repo); | gitService.deleteProject(token, owner, repo); | ||||
| @@ -461,6 +475,18 @@ public class NewDatasetServiceImpl implements NewDatasetService { | |||||
| throw new Exception("该数据集版本被超参数自动寻优:" + rays + "使用,不能删除,请先删除超参数自动寻优。"); | throw new Exception("该数据集版本被超参数自动寻优:" + rays + "使用,不能删除,请先删除超参数自动寻优。"); | ||||
| } | } | ||||
| List<ActiveLearn> activeLearnList = activeLearnDao.queryByDatasetId(JSON.toJSONString(map)); | |||||
| if (activeLearnList != null && !activeLearnList.isEmpty()) { | |||||
| String activeLearns = String.join(",", activeLearnList.stream().map(ActiveLearn::getName).collect(Collectors.toSet())); | |||||
| throw new Exception("该数据集版本被主动学习:" + activeLearns + "使用,不能删除,请先删除主动学习。"); | |||||
| } | |||||
| List<DevEnvironment> devEnvironmentList = devEnvironmentDao.queryByDatasetId(JSON.toJSONString(map)); | |||||
| if (devEnvironmentList != null && !devEnvironmentList.isEmpty()) { | |||||
| String devEnvironments = String.join(",", devEnvironmentList.stream().map(DevEnvironment::getName).collect(Collectors.toSet())); | |||||
| throw new Exception("该数据集版本被开发环境:" + devEnvironments + "使用,不能删除,请先删除开发环境。"); | |||||
| } | |||||
| String token = gitService.checkoutToken(); | String token = gitService.checkoutToken(); | ||||
| String rootPath = Paths.get(localPathlocal + "/" + relativePath).getParent().toString(); | String rootPath = Paths.get(localPathlocal + "/" + relativePath).getParent().toString(); | ||||
| gitService.deleteBranch(token, owner, repo, version, rootPath); | gitService.deleteBranch(token, owner, repo, version, rootPath); | ||||
| @@ -1,6 +1,5 @@ | |||||
| package com.ruoyi.platform.service.impl; | package com.ruoyi.platform.service.impl; | ||||
| import com.ruoyi.system.api.constant.Constant; | |||||
| import com.ruoyi.platform.domain.Ray; | import com.ruoyi.platform.domain.Ray; | ||||
| import com.ruoyi.platform.domain.RayIns; | import com.ruoyi.platform.domain.RayIns; | ||||
| import com.ruoyi.platform.mapper.RayDao; | import com.ruoyi.platform.mapper.RayDao; | ||||
| @@ -8,6 +7,7 @@ import com.ruoyi.platform.mapper.RayInsDao; | |||||
| import com.ruoyi.platform.service.RayInsService; | import com.ruoyi.platform.service.RayInsService; | ||||
| import com.ruoyi.platform.service.ResourceOccupyService; | import com.ruoyi.platform.service.ResourceOccupyService; | ||||
| import com.ruoyi.platform.utils.*; | import com.ruoyi.platform.utils.*; | ||||
| import com.ruoyi.system.api.constant.Constant; | |||||
| import org.apache.commons.lang3.StringUtils; | import org.apache.commons.lang3.StringUtils; | ||||
| import org.slf4j.Logger; | import org.slf4j.Logger; | ||||
| import org.slf4j.LoggerFactory; | import org.slf4j.LoggerFactory; | ||||
| @@ -16,6 +16,7 @@ import org.springframework.data.domain.Page; | |||||
| import org.springframework.data.domain.PageImpl; | import org.springframework.data.domain.PageImpl; | ||||
| import org.springframework.data.domain.PageRequest; | import org.springframework.data.domain.PageRequest; | ||||
| import org.springframework.stereotype.Service; | import org.springframework.stereotype.Service; | ||||
| import org.springframework.transaction.annotation.Transactional; | |||||
| import javax.annotation.Resource; | import javax.annotation.Resource; | ||||
| import java.io.IOException; | import java.io.IOException; | ||||
| @@ -69,6 +70,7 @@ public class RayInsServiceImpl implements RayInsService { | |||||
| } | } | ||||
| @Override | @Override | ||||
| @Transactional | |||||
| public String deleteById(Long id) { | public String deleteById(Long id) { | ||||
| RayIns rayIns = rayInsDao.queryById(id); | RayIns rayIns = rayInsDao.queryById(id); | ||||
| if (rayIns == null) { | if (rayIns == null) { | ||||
| @@ -84,6 +86,7 @@ public class RayInsServiceImpl implements RayInsService { | |||||
| rayIns.setState(Constant.State_invalid); | rayIns.setState(Constant.State_invalid); | ||||
| int update = rayInsDao.update(rayIns); | int update = rayInsDao.update(rayIns); | ||||
| if (update > 0) { | if (update > 0) { | ||||
| resourceOccupyService.deleteTaskState(Constant.TaskType_Ray, rayIns.getRayId(), id); | |||||
| updateRayStatus(rayIns.getRayId()); | updateRayStatus(rayIns.getRayId()); | ||||
| return "删除成功"; | return "删除成功"; | ||||
| } else { | } else { | ||||
| @@ -264,7 +267,7 @@ public class RayInsServiceImpl implements RayInsService { | |||||
| if (!StringUtils.equals(ins.getStatus(), Constant.Terminated)) { | if (!StringUtils.equals(ins.getStatus(), Constant.Terminated)) { | ||||
| ins.setStatus(StringUtils.isNotEmpty((String) status.get("phase")) ? (String) status.get("phase") : Constant.Pending); | ins.setStatus(StringUtils.isNotEmpty((String) status.get("phase")) ? (String) status.get("phase") : Constant.Pending); | ||||
| } | } | ||||
| if (StringUtils.equals(ins.getStatus(), "Error")) { | |||||
| if (StringUtils.equals(ins.getStatus(), Constant.Error)) { | |||||
| ins.setStatus(Constant.Failed); | ins.setStatus(Constant.Failed); | ||||
| } | } | ||||
| return ins; | return ins; | ||||
| @@ -3,7 +3,6 @@ package com.ruoyi.platform.service.impl; | |||||
| import com.google.gson.Gson; | import com.google.gson.Gson; | ||||
| import com.google.gson.reflect.TypeToken; | import com.google.gson.reflect.TypeToken; | ||||
| import com.ruoyi.common.security.utils.SecurityUtils; | import com.ruoyi.common.security.utils.SecurityUtils; | ||||
| import com.ruoyi.system.api.constant.Constant; | |||||
| import com.ruoyi.platform.domain.Ray; | import com.ruoyi.platform.domain.Ray; | ||||
| import com.ruoyi.platform.domain.RayIns; | import com.ruoyi.platform.domain.RayIns; | ||||
| import com.ruoyi.platform.mapper.RayDao; | import com.ruoyi.platform.mapper.RayDao; | ||||
| @@ -16,6 +15,7 @@ import com.ruoyi.platform.utils.JacksonUtil; | |||||
| import com.ruoyi.platform.utils.JsonUtils; | import com.ruoyi.platform.utils.JsonUtils; | ||||
| import com.ruoyi.platform.vo.RayParamVo; | import com.ruoyi.platform.vo.RayParamVo; | ||||
| import com.ruoyi.platform.vo.RayVo; | import com.ruoyi.platform.vo.RayVo; | ||||
| import com.ruoyi.system.api.constant.Constant; | |||||
| import org.apache.commons.collections4.MapUtils; | import org.apache.commons.collections4.MapUtils; | ||||
| import org.apache.commons.lang3.StringUtils; | import org.apache.commons.lang3.StringUtils; | ||||
| import org.springframework.beans.BeanUtils; | import org.springframework.beans.BeanUtils; | ||||
| @@ -24,6 +24,7 @@ import org.springframework.data.domain.Page; | |||||
| import org.springframework.data.domain.PageImpl; | import org.springframework.data.domain.PageImpl; | ||||
| import org.springframework.data.domain.PageRequest; | import org.springframework.data.domain.PageRequest; | ||||
| import org.springframework.stereotype.Service; | import org.springframework.stereotype.Service; | ||||
| import org.springframework.transaction.annotation.Transactional; | |||||
| import javax.annotation.Resource; | import javax.annotation.Resource; | ||||
| import java.io.IOException; | import java.io.IOException; | ||||
| @@ -131,6 +132,7 @@ public class RayServiceImpl implements RayService { | |||||
| } | } | ||||
| @Override | @Override | ||||
| @Transactional | |||||
| public String delete(Long id) { | public String delete(Long id) { | ||||
| Ray ray = rayDao.getRayById(id); | Ray ray = rayDao.getRayById(id); | ||||
| if (ray == null) { | if (ray == null) { | ||||
| @@ -142,6 +144,7 @@ public class RayServiceImpl implements RayService { | |||||
| throw new RuntimeException("无权限删除该实验"); | throw new RuntimeException("无权限删除该实验"); | ||||
| } | } | ||||
| ray.setState(Constant.State_invalid); | ray.setState(Constant.State_invalid); | ||||
| resourceOccupyService.deleteTaskState(Constant.TaskType_Ray, id, null); | |||||
| return rayDao.edit(ray) > 0 ? "删除成功" : "删除失败"; | return rayDao.edit(ray) > 0 ? "删除成功" : "删除失败"; | ||||
| } | } | ||||
| @@ -156,12 +159,11 @@ public class RayServiceImpl implements RayService { | |||||
| if (resourceOccupyService.haveResource(ray.getComputingResourceId(), 1)) { | if (resourceOccupyService.haveResource(ray.getComputingResourceId(), 1)) { | ||||
| RayParamVo rayParamVo = new RayParamVo(); | RayParamVo rayParamVo = new RayParamVo(); | ||||
| BeanUtils.copyProperties(ray, rayParamVo); | BeanUtils.copyProperties(ray, rayParamVo); | ||||
| rayParamVo.setComputingResourceId(ray.getComputingResourceId()); | |||||
| rayParamVo.setCodeConfig(JsonUtils.jsonToMap(ray.getCodeConfig())); | rayParamVo.setCodeConfig(JsonUtils.jsonToMap(ray.getCodeConfig())); | ||||
| rayParamVo.setDataset(JsonUtils.jsonToMap(ray.getDataset())); | rayParamVo.setDataset(JsonUtils.jsonToMap(ray.getDataset())); | ||||
| rayParamVo.setModel(JsonUtils.jsonToMap(ray.getModel())); | rayParamVo.setModel(JsonUtils.jsonToMap(ray.getModel())); | ||||
| rayParamVo.setImage(JsonUtils.jsonToMap(ray.getImage())); | rayParamVo.setImage(JsonUtils.jsonToMap(ray.getImage())); | ||||
| String param = JsonUtils.objectToJson(rayParamVo); | |||||
| String param = JsonUtils.getConvertParam(rayParamVo); | |||||
| // 调argo转换接口 | // 调argo转换接口 | ||||
| try { | try { | ||||
| @@ -189,7 +191,7 @@ public class RayServiceImpl implements RayService { | |||||
| // 插入记录到实验实例表 | // 插入记录到实验实例表 | ||||
| RayIns rayIns = new RayIns(); | RayIns rayIns = new RayIns(); | ||||
| rayIns.setRayId(ray.getId()); | |||||
| rayIns.setRayId(id); | |||||
| rayIns.setArgoInsNs((String) metadata.get("namespace")); | rayIns.setArgoInsNs((String) metadata.get("namespace")); | ||||
| rayIns.setArgoInsName((String) metadata.get("name")); | rayIns.setArgoInsName((String) metadata.get("name")); | ||||
| rayIns.setParam(param); | rayIns.setParam(param); | ||||
| @@ -168,4 +168,9 @@ public class ResourceOccupyServiceImpl implements ResourceOccupyService { | |||||
| resourceOccupy.setComputingResourceId(computingResourceId); | resourceOccupy.setComputingResourceId(computingResourceId); | ||||
| resourceOccupyDao.edit(resourceOccupy); | resourceOccupyDao.edit(resourceOccupy); | ||||
| } | } | ||||
| @Override | |||||
| public void deleteTaskState(String taskType, Long taskId, Long taskInsId) { | |||||
| resourceOccupyDao.deleteTaskState(taskType,taskId,taskInsId); | |||||
| } | |||||
| } | } | ||||
| @@ -14,6 +14,7 @@ import com.ruoyi.platform.service.ServiceService; | |||||
| import com.ruoyi.platform.utils.ConvertUtil; | import com.ruoyi.platform.utils.ConvertUtil; | ||||
| import com.ruoyi.platform.utils.HttpUtils; | import com.ruoyi.platform.utils.HttpUtils; | ||||
| import com.ruoyi.platform.utils.JacksonUtil; | import com.ruoyi.platform.utils.JacksonUtil; | ||||
| import com.ruoyi.platform.utils.JsonUtils; | |||||
| import com.ruoyi.platform.vo.serviceVos.ServiceCodeConfigVo; | import com.ruoyi.platform.vo.serviceVos.ServiceCodeConfigVo; | ||||
| import com.ruoyi.platform.vo.serviceVos.ServiceModelVo; | import com.ruoyi.platform.vo.serviceVos.ServiceModelVo; | ||||
| import com.ruoyi.platform.vo.serviceVos.ServiceVersionVo; | import com.ruoyi.platform.vo.serviceVos.ServiceVersionVo; | ||||
| @@ -26,8 +27,10 @@ import org.springframework.data.domain.Page; | |||||
| import org.springframework.data.domain.PageImpl; | import org.springframework.data.domain.PageImpl; | ||||
| import org.springframework.data.domain.PageRequest; | import org.springframework.data.domain.PageRequest; | ||||
| import org.springframework.stereotype.Service; | import org.springframework.stereotype.Service; | ||||
| import org.springframework.transaction.annotation.Transactional; | |||||
| import javax.annotation.Resource; | import javax.annotation.Resource; | ||||
| import java.io.IOException; | |||||
| import java.net.MalformedURLException; | import java.net.MalformedURLException; | ||||
| import java.net.URL; | import java.net.URL; | ||||
| import java.util.ArrayList; | import java.util.ArrayList; | ||||
| @@ -64,7 +67,7 @@ public class ServiceServiceImpl implements ServiceService { | |||||
| } | } | ||||
| @Override | @Override | ||||
| public Page<ServiceVersionVo> queryByPageServiceVersion(ServiceVersion serviceVersion, int page, int size) { | |||||
| public Page<ServiceVersionVo> queryByPageServiceVersion(ServiceVersion serviceVersion, int page, int size) throws IOException { | |||||
| PageRequest pageRequest; | PageRequest pageRequest; | ||||
| if (StringUtils.isNotEmpty(serviceVersion.getRunState())) { | if (StringUtils.isNotEmpty(serviceVersion.getRunState())) { | ||||
| pageRequest = PageRequest.of(page, Integer.MAX_VALUE); | pageRequest = PageRequest.of(page, Integer.MAX_VALUE); | ||||
| @@ -169,7 +172,7 @@ public class ServiceServiceImpl implements ServiceService { | |||||
| } | } | ||||
| @Override | @Override | ||||
| public ServiceVersionVo getServiceVersion(Long id) { | |||||
| public ServiceVersionVo getServiceVersion(Long id) throws IOException { | |||||
| ServiceVersion serviceVersion = serviceDao.getServiceVersionById(id); | ServiceVersion serviceVersion = serviceDao.getServiceVersionById(id); | ||||
| ServiceVersionVo serviceVersionVo = getServiceVersionVo(serviceVersion); | ServiceVersionVo serviceVersionVo = getServiceVersionVo(serviceVersion); | ||||
| com.ruoyi.platform.domain.Service service = serviceDao.getServiceById(serviceVersion.getServiceId()); | com.ruoyi.platform.domain.Service service = serviceDao.getServiceById(serviceVersion.getServiceId()); | ||||
| @@ -195,7 +198,7 @@ public class ServiceServiceImpl implements ServiceService { | |||||
| } | } | ||||
| @Override | @Override | ||||
| public Map<String, Object> serviceVersionCompare(Long id1, Long id2) throws IllegalAccessException { | |||||
| public Map<String, Object> serviceVersionCompare(Long id1, Long id2) throws IllegalAccessException, IOException { | |||||
| HashMap<String, Object> result = new HashMap<>(); | HashMap<String, Object> result = new HashMap<>(); | ||||
| ServiceVersion serviceVersion1 = serviceDao.getServiceVersionById(id1); | ServiceVersion serviceVersion1 = serviceDao.getServiceVersionById(id1); | ||||
| @@ -243,11 +246,13 @@ public class ServiceServiceImpl implements ServiceService { | |||||
| throw new RuntimeException("该服务下还有版本,不能删除"); | throw new RuntimeException("该服务下还有版本,不能删除"); | ||||
| } | } | ||||
| resourceOccupyService.deleteTaskState(Constant.TaskType_Service, id, null); | |||||
| service.setState(Constant.State_invalid); | service.setState(Constant.State_invalid); | ||||
| return serviceDao.updateService(service) > 0 ? "删除成功" : "删除失败"; | return serviceDao.updateService(service) > 0 ? "删除成功" : "删除失败"; | ||||
| } | } | ||||
| @Override | @Override | ||||
| @Transactional | |||||
| public String deleteServiceVersion(Long id) { | public String deleteServiceVersion(Long id) { | ||||
| ServiceVersion serviceVersion = serviceDao.getServiceVersionById(id); | ServiceVersion serviceVersion = serviceDao.getServiceVersionById(id); | ||||
| serviceVersion.setState(Constant.State_invalid); | serviceVersion.setState(Constant.State_invalid); | ||||
| @@ -260,6 +265,7 @@ public class ServiceServiceImpl implements ServiceService { | |||||
| // if ((Integer) reqMap.get("code") == 200) { | // if ((Integer) reqMap.get("code") == 200) { | ||||
| // 结束扣积分 | // 结束扣积分 | ||||
| resourceOccupyService.endDeduce(Constant.TaskType_Service, null, id, null, null); | resourceOccupyService.endDeduce(Constant.TaskType_Service, null, id, null, null); | ||||
| resourceOccupyService.deleteTaskState(Constant.TaskType_Service, serviceVersion.getServiceId(), id); | |||||
| return serviceDao.updateServiceVersion(serviceVersion) > 0 ? "删除成功" : "删除失败"; | return serviceDao.updateServiceVersion(serviceVersion) > 0 ? "删除成功" : "删除失败"; | ||||
| // } | // } | ||||
| } | } | ||||
| @@ -278,7 +284,8 @@ public class ServiceServiceImpl implements ServiceService { | |||||
| paramMap.put("replicas", serviceVersion.getReplicas()); | paramMap.put("replicas", serviceVersion.getReplicas()); | ||||
| paramMap.put("env", JSONObject.parseObject(serviceVersion.getEnvVariables())); | paramMap.put("env", JSONObject.parseObject(serviceVersion.getEnvVariables())); | ||||
| paramMap.put("code_config", JSONObject.parseObject(serviceVersion.getCodeConfig())); | paramMap.put("code_config", JSONObject.parseObject(serviceVersion.getCodeConfig())); | ||||
| paramMap.put("image", serviceVersion.getImage()); | |||||
| String image = (String)JsonUtils.jsonToMap(serviceVersion.getImage()).get("value"); | |||||
| paramMap.put("image", image); | |||||
| paramMap.put("model", JSONObject.parseObject(serviceVersion.getModel())); | paramMap.put("model", JSONObject.parseObject(serviceVersion.getModel())); | ||||
| paramMap.put("service_type", service.getServiceType()); | paramMap.put("service_type", service.getServiceType()); | ||||
| paramMap.put("deploy_type", serviceVersion.getDeployType()); | paramMap.put("deploy_type", serviceVersion.getDeployType()); | ||||
| @@ -401,11 +408,12 @@ public class ServiceServiceImpl implements ServiceService { | |||||
| serviceVersion.setModel(JSON.toJSONString(serviceVersionVo.getModel())); | serviceVersion.setModel(JSON.toJSONString(serviceVersionVo.getModel())); | ||||
| serviceVersion.setCodeConfig(JSON.toJSONString(serviceVersionVo.getCodeConfig())); | serviceVersion.setCodeConfig(JSON.toJSONString(serviceVersionVo.getCodeConfig())); | ||||
| serviceVersion.setEnvVariables(JSON.toJSONString(serviceVersionVo.getEnvVariables())); | serviceVersion.setEnvVariables(JSON.toJSONString(serviceVersionVo.getEnvVariables())); | ||||
| serviceVersion.setImage(JacksonUtil.toJSONString(serviceVersionVo.getImage())); | |||||
| return serviceVersion; | return serviceVersion; | ||||
| } | } | ||||
| List<ServiceVersionVo> getServiceVersionVoList(List<ServiceVersion> serviceVersionList) { | |||||
| List<ServiceVersionVo> getServiceVersionVoList(List<ServiceVersion> serviceVersionList) throws IOException { | |||||
| List<ServiceVersionVo> result = new ArrayList<>(); | List<ServiceVersionVo> result = new ArrayList<>(); | ||||
| for (ServiceVersion sv : serviceVersionList) { | for (ServiceVersion sv : serviceVersionList) { | ||||
| @@ -415,7 +423,7 @@ public class ServiceServiceImpl implements ServiceService { | |||||
| return result; | return result; | ||||
| } | } | ||||
| ServiceVersionVo getServiceVersionVo(ServiceVersion sv) { | |||||
| ServiceVersionVo getServiceVersionVo(ServiceVersion sv) throws IOException { | |||||
| ServiceVersionVo serviceVersionVo = new ServiceVersionVo(); | ServiceVersionVo serviceVersionVo = new ServiceVersionVo(); | ||||
| BeanUtils.copyProperties(sv, serviceVersionVo); | BeanUtils.copyProperties(sv, serviceVersionVo); | ||||
| ServiceModelVo serviceModelVo = JSON.parseObject(sv.getModel(), ServiceModelVo.class); | ServiceModelVo serviceModelVo = JSON.parseObject(sv.getModel(), ServiceModelVo.class); | ||||
| @@ -425,6 +433,7 @@ public class ServiceServiceImpl implements ServiceService { | |||||
| serviceVersionVo.setCodeConfig(serviceCodeConfigVo); | serviceVersionVo.setCodeConfig(serviceCodeConfigVo); | ||||
| serviceVersionVo.setEnvVariables(JacksonUtil.parseJSONStr2Map(sv.getEnvVariables())); | serviceVersionVo.setEnvVariables(JacksonUtil.parseJSONStr2Map(sv.getEnvVariables())); | ||||
| serviceVersionVo.setImage(JsonUtils.jsonToMap(sv.getImage())); | |||||
| return serviceVersionVo; | return serviceVersionVo; | ||||
| } | } | ||||
| @@ -1,11 +1,12 @@ | |||||
| package com.ruoyi.platform.utils; | package com.ruoyi.platform.utils; | ||||
| import com.alibaba.fastjson2.JSON; | |||||
| import com.fasterxml.jackson.core.JsonProcessingException; | import com.fasterxml.jackson.core.JsonProcessingException; | ||||
| import com.fasterxml.jackson.databind.ObjectMapper; | import com.fasterxml.jackson.databind.ObjectMapper; | ||||
| import org.json.JSONObject; | |||||
| import com.ruoyi.common.security.utils.SecurityUtils; | |||||
| import java.io.IOException; | import java.io.IOException; | ||||
| import java.util.HashMap; | import java.util.HashMap; | ||||
| import java.util.Iterator; | |||||
| import java.util.Map; | import java.util.Map; | ||||
| public class JsonUtils { | public class JsonUtils { | ||||
| @@ -33,9 +34,8 @@ public class JsonUtils { | |||||
| } | } | ||||
| // 将JSON字符串转换为扁平化的Map | // 将JSON字符串转换为扁平化的Map | ||||
| public static Map<String, Object> flattenJson(String prefix, Map<String, Object> map) { | |||||
| public static Map<String, Object> flattenJson(String prefix, Map<String, Object> map) { | |||||
| Map<String, Object> flatMap = new HashMap<>(); | Map<String, Object> flatMap = new HashMap<>(); | ||||
| for (Map.Entry<String, Object> entry : map.entrySet()) { | for (Map.Entry<String, Object> entry : map.entrySet()) { | ||||
| @@ -56,4 +56,17 @@ public class JsonUtils { | |||||
| public static Map<String, Object> objectToMap(Object object) throws IOException { | public static Map<String, Object> objectToMap(Object object) throws IOException { | ||||
| return objectMapper.convertValue(object, Map.class); | return objectMapper.convertValue(object, Map.class); | ||||
| } | } | ||||
| public static String getConvertParam(Object object) throws JsonProcessingException { | |||||
| HashMap<Object, Object> paramMap = new HashMap<>(); | |||||
| paramMap.put("data", JSON.parseObject(objectToJson(object), Map.class)); | |||||
| HashMap<Object, Object> userInfoMap = new HashMap<>(); | |||||
| userInfoMap.put("name", SecurityUtils.getLoginUser().getUsername()); | |||||
| userInfoMap.put("token", SecurityUtils.getLoginUser().getSysUser().getOriginPassword()); | |||||
| HashMap<Object, Object> extraInfoMap = new HashMap<>(); | |||||
| extraInfoMap.put("user_info", userInfoMap); | |||||
| paramMap.put("extra_info", extraInfoMap); | |||||
| return objectToJson(paramMap); | |||||
| } | |||||
| } | } | ||||
| @@ -23,6 +23,7 @@ import org.springframework.stereotype.Component; | |||||
| import javax.annotation.Resource; | import javax.annotation.Resource; | ||||
| import java.io.BufferedReader; | import java.io.BufferedReader; | ||||
| import java.io.IOException; | |||||
| import java.io.InputStreamReader; | import java.io.InputStreamReader; | ||||
| import java.util.*; | import java.util.*; | ||||
| @@ -40,6 +41,8 @@ public class K8sClientUtil { | |||||
| private String hostPath; | private String hostPath; | ||||
| @Value("${dockerpush.proxyUrl}") | @Value("${dockerpush.proxyUrl}") | ||||
| private String proxyUrl; | private String proxyUrl; | ||||
| @Value("${proxy.useProxy:false}") | |||||
| private boolean useProxy; | |||||
| @Value("${git.localPath}") | @Value("${git.localPath}") | ||||
| String localPathlocal; | String localPathlocal; | ||||
| @@ -321,7 +324,6 @@ public class K8sClientUtil { | |||||
| * @param port port | * @param port port | ||||
| * @param mountPath 映射路径 | * @param mountPath 映射路径 | ||||
| * @param subPath pvc子路径 | * @param subPath pvc子路径 | ||||
| * @param pvcName 存储名 | |||||
| * @param image 镜像 | * @param image 镜像 | ||||
| * @return 创建成功的pod,的nodePort端口 | * @return 创建成功的pod,的nodePort端口 | ||||
| */ | */ | ||||
| @@ -352,40 +354,68 @@ public class K8sClientUtil { | |||||
| int lastIndex = hostPath.lastIndexOf('/'); | int lastIndex = hostPath.lastIndexOf('/'); | ||||
| String newPath = hostPath.substring(0, lastIndex); | String newPath = hostPath.substring(0, lastIndex); | ||||
| V1Pod pod = new V1PodBuilder() | |||||
| .withNewMetadata() | |||||
| .withName(podName) | |||||
| .withLabels(selector) | |||||
| .endMetadata() | |||||
| .withNewSpec() | |||||
| .addNewContainer() | |||||
| .withName(podName) | |||||
| .withImage(image) | |||||
| .withPorts(new V1ContainerPort().containerPort(port).protocol("TCP")) | |||||
| .withVolumeMounts(new V1VolumeMount().name("workspace").mountPath(mountPath).subPath(subPath)) | |||||
| .withNewSecurityContext().withNewPrivileged(true).endSecurityContext() | |||||
| .addNewEnv() | |||||
| .withName("HTTP_PROXY") | |||||
| .withValue(proxyUrl) | |||||
| .endEnv() | |||||
| .addNewEnv() | |||||
| .withName("HTTPS_PROXY") | |||||
| .withValue(proxyUrl) | |||||
| .endEnv() | |||||
| .addNewEnv() | |||||
| .withName("NO_PROXY") | |||||
| .withValue("localhost,kubernetes.default.svc") | |||||
| .endEnv() | |||||
| .endContainer() | |||||
| .addNewVolume() | |||||
| .withName("workspace") | |||||
| .withHostPath(new V1HostPathVolumeSource().path(newPath).type("DirectoryOrCreate")) | |||||
| V1Pod pod; | |||||
| if (useProxy) { | |||||
| pod = new V1PodBuilder() | |||||
| .withNewMetadata() | |||||
| .withName(podName) | |||||
| .withLabels(selector) | |||||
| .endMetadata() | |||||
| .withNewSpec() | |||||
| .addNewContainer() | |||||
| .withName(podName) | |||||
| .withImage(image) | |||||
| .withPorts(new V1ContainerPort().containerPort(port).protocol("TCP")) | |||||
| .withVolumeMounts(new V1VolumeMount().name("workspace").mountPath(mountPath).subPath(subPath)) | |||||
| .withNewSecurityContext().withNewPrivileged(true).endSecurityContext() | |||||
| .addNewEnv() | |||||
| .withName("HTTP_PROXY") | |||||
| .withValue(proxyUrl) | |||||
| .endEnv() | |||||
| .addNewEnv() | |||||
| .withName("HTTPS_PROXY") | |||||
| .withValue(proxyUrl) | |||||
| .endEnv() | |||||
| .addNewEnv() | |||||
| .withName("NO_PROXY") | |||||
| .withValue("localhost,kubernetes.default.svc") | |||||
| .endEnv() | |||||
| .endContainer() | |||||
| .addNewVolume() | |||||
| .withName("workspace") | |||||
| .withHostPath(new V1HostPathVolumeSource().path(newPath).type("DirectoryOrCreate")) | |||||
| // .withPersistentVolumeClaim(new V1PersistentVolumeClaimVolumeSource().claimName(pvcName)) | // .withPersistentVolumeClaim(new V1PersistentVolumeClaimVolumeSource().claimName(pvcName)) | ||||
| .endVolume() | |||||
| .withTerminationGracePeriodSeconds(14400L) | |||||
| .endSpec() | |||||
| .build(); | |||||
| .endVolume() | |||||
| .withTerminationGracePeriodSeconds(14400L) | |||||
| .endSpec() | |||||
| .build(); | |||||
| } else { | |||||
| pod = new V1PodBuilder() | |||||
| .withNewMetadata() | |||||
| .withName(podName) | |||||
| .withLabels(selector) | |||||
| .endMetadata() | |||||
| .withNewSpec() | |||||
| .addNewContainer() | |||||
| .withName(podName) | |||||
| .withImage(image) | |||||
| .withPorts(new V1ContainerPort().containerPort(port).protocol("TCP")) | |||||
| .withVolumeMounts(new V1VolumeMount().name("workspace").mountPath(mountPath).subPath(subPath)) | |||||
| .withNewSecurityContext().withNewPrivileged(true).endSecurityContext() | |||||
| .addNewEnv() | |||||
| .withName("NO_PROXY") | |||||
| .withValue("localhost,kubernetes.default.svc") | |||||
| .endEnv() | |||||
| .endContainer() | |||||
| .addNewVolume() | |||||
| .withName("workspace") | |||||
| .withHostPath(new V1HostPathVolumeSource().path(newPath).type("DirectoryOrCreate")) | |||||
| // .withPersistentVolumeClaim(new V1PersistentVolumeClaimVolumeSource().claimName(pvcName)) | |||||
| .endVolume() | |||||
| .withTerminationGracePeriodSeconds(14400L) | |||||
| .endSpec() | |||||
| .build(); | |||||
| } | |||||
| try { | try { | ||||
| pod = api.createNamespacedPod(namespace, pod, null, null, null); | pod = api.createNamespacedPod(namespace, pod, null, null, null); | ||||
| @@ -400,7 +430,7 @@ public class K8sClientUtil { | |||||
| } | } | ||||
| // 创建配置好的Pod | // 创建配置好的Pod | ||||
| public Integer createConfiguredPod(String podName, String namespace, Integer port, String mountPath, V1PersistentVolumeClaim pvc, DevEnvironment devEnvironment, String dataPvcName, String datasetPath, String modelPath) { | |||||
| public Integer createConfiguredPod(String podName, String namespace, Integer port, String mountPath, V1PersistentVolumeClaim pvc, DevEnvironment devEnvironment, String dataPvcName, String datasetPath, String modelPath) throws IOException { | |||||
| //设置选择节点,pod反亲和性 | //设置选择节点,pod反亲和性 | ||||
| Map<String, String> selector = new LinkedHashMap<>(); | Map<String, String> selector = new LinkedHashMap<>(); | ||||
| @@ -494,6 +524,8 @@ public class K8sClientUtil { | |||||
| //配置资源 | //配置资源 | ||||
| V1ResourceRequirements v1ResourceRequirements = setPodResource(devEnvironment.getComputingResourceId()); | V1ResourceRequirements v1ResourceRequirements = setPodResource(devEnvironment.getComputingResourceId()); | ||||
| String image = (String) JsonUtils.jsonToMap(devEnvironment.getImage()).get("value"); | |||||
| V1Pod pod = new V1PodBuilder() | V1Pod pod = new V1PodBuilder() | ||||
| .withNewMetadata() | .withNewMetadata() | ||||
| .withName(podName) | .withName(podName) | ||||
| @@ -502,7 +534,7 @@ public class K8sClientUtil { | |||||
| .withNewSpec() | .withNewSpec() | ||||
| .addNewContainer() | .addNewContainer() | ||||
| .withName(podName) | .withName(podName) | ||||
| .withImage(devEnvironment.getImage()) | |||||
| .withImage(image) | |||||
| .withPorts(new V1ContainerPort().containerPort(port).protocol("TCP")) | .withPorts(new V1ContainerPort().containerPort(port).protocol("TCP")) | ||||
| .withVolumeMounts(volumeMounts) | .withVolumeMounts(volumeMounts) | ||||
| .withResources(v1ResourceRequirements) | .withResources(v1ResourceRequirements) | ||||
| @@ -641,7 +673,7 @@ public class K8sClientUtil { | |||||
| } | } | ||||
| public V1Pod createPodWithEnv(String podName, String namespace, String proxyUrl, String mountPath, String image) { | |||||
| public V1Pod createPodWithEnv(String podName, String namespace, String mountPath, String image) { | |||||
| CoreV1Api api = new CoreV1Api(apiClient); | CoreV1Api api = new CoreV1Api(apiClient); | ||||
| V1SecurityContext v1SecurityContext = new V1SecurityContext(); | V1SecurityContext v1SecurityContext = new V1SecurityContext(); | ||||
| @@ -653,38 +685,65 @@ public class K8sClientUtil { | |||||
| List<V1Volume> volumes = new ArrayList<>(); | List<V1Volume> volumes = new ArrayList<>(); | ||||
| volumes.add(new V1Volume().name("workspace").hostPath(new V1HostPathVolumeSource().path(hostPath + "/images").type("DirectoryOrCreate"))); | volumes.add(new V1Volume().name("workspace").hostPath(new V1HostPathVolumeSource().path(hostPath + "/images").type("DirectoryOrCreate"))); | ||||
| V1Pod pod = new V1PodBuilder() | |||||
| .withNewMetadata() | |||||
| .withName(podName) | |||||
| .endMetadata() | |||||
| .withNewSpec() | |||||
| .addNewContainer() | |||||
| .withName(podName) | |||||
| .withImage(image) // 替换为您实际要使用的镜像名称 | |||||
| .withSecurityContext(v1SecurityContext) | |||||
| V1Pod pod; | |||||
| if (useProxy) { | |||||
| pod = new V1PodBuilder() | |||||
| .withNewMetadata() | |||||
| .withName(podName) | |||||
| .endMetadata() | |||||
| .withNewSpec() | |||||
| .addNewContainer() | |||||
| .withName(podName) | |||||
| .withImage(image) // 替换为您实际要使用的镜像名称 | |||||
| .withSecurityContext(v1SecurityContext) | |||||
| // .withVolumeMounts(new V1VolumeMount().name("workspace").mountPath(mountPath)) | // .withVolumeMounts(new V1VolumeMount().name("workspace").mountPath(mountPath)) | ||||
| .withVolumeMounts(volumeMounts) | |||||
| .withNewSecurityContext().withNewPrivileged(true).endSecurityContext() | |||||
| .addNewEnv() | |||||
| .withName("HTTP_PROXY") | |||||
| .withValue(proxyUrl) | |||||
| .endEnv() | |||||
| .addNewEnv() | |||||
| .withName("HTTPS_PROXY") | |||||
| .withValue(proxyUrl) | |||||
| .endEnv() | |||||
| .addNewEnv() | |||||
| .withName("NO_PROXY") | |||||
| .withValue("localhost,kubernetes.default.svc") | |||||
| .endEnv() | |||||
| .endContainer() | |||||
| .withVolumeMounts(volumeMounts) | |||||
| .withNewSecurityContext().withNewPrivileged(true).endSecurityContext() | |||||
| .addNewEnv() | |||||
| .withName("HTTP_PROXY") | |||||
| .withValue(proxyUrl) | |||||
| .endEnv() | |||||
| .addNewEnv() | |||||
| .withName("HTTPS_PROXY") | |||||
| .withValue(proxyUrl) | |||||
| .endEnv() | |||||
| .addNewEnv() | |||||
| .withName("NO_PROXY") | |||||
| .withValue("localhost,kubernetes.default.svc") | |||||
| .endEnv() | |||||
| .endContainer() | |||||
| // .addNewVolume() | // .addNewVolume() | ||||
| // .withName("workspace").withPersistentVolumeClaim(new V1PersistentVolumeClaimVolumeSource().claimName(pvcName)) | // .withName("workspace").withPersistentVolumeClaim(new V1PersistentVolumeClaimVolumeSource().claimName(pvcName)) | ||||
| // .endVolume() | // .endVolume() | ||||
| .withVolumes(volumes) | |||||
| .endSpec() | |||||
| .build(); | |||||
| .withVolumes(volumes) | |||||
| .endSpec() | |||||
| .build(); | |||||
| } else { | |||||
| pod = new V1PodBuilder() | |||||
| .withNewMetadata() | |||||
| .withName(podName) | |||||
| .endMetadata() | |||||
| .withNewSpec() | |||||
| .addNewContainer() | |||||
| .withName(podName) | |||||
| .withImage(image) // 替换为您实际要使用的镜像名称 | |||||
| .withSecurityContext(v1SecurityContext) | |||||
| // .withVolumeMounts(new V1VolumeMount().name("workspace").mountPath(mountPath)) | |||||
| .withVolumeMounts(volumeMounts) | |||||
| .withNewSecurityContext().withNewPrivileged(true).endSecurityContext() | |||||
| .addNewEnv() | |||||
| .withName("NO_PROXY") | |||||
| .withValue("localhost,kubernetes.default.svc") | |||||
| .endEnv() | |||||
| .endContainer() | |||||
| // .addNewVolume() | |||||
| // .withName("workspace").withPersistentVolumeClaim(new V1PersistentVolumeClaimVolumeSource().claimName(pvcName)) | |||||
| // .endVolume() | |||||
| .withVolumes(volumes) | |||||
| .endSpec() | |||||
| .build(); | |||||
| } | |||||
| try { | try { | ||||
| pod = api.createNamespacedPod(namespace, pod, null, null, null); | pod = api.createNamespacedPod(namespace, pod, null, null, null); | ||||
| } catch (ApiException e) { | } catch (ApiException e) { | ||||
| @@ -0,0 +1,67 @@ | |||||
| package com.ruoyi.platform.vo; | |||||
| import com.fasterxml.jackson.annotation.JsonInclude; | |||||
| import com.fasterxml.jackson.databind.PropertyNamingStrategy; | |||||
| import com.fasterxml.jackson.databind.annotation.JsonNaming; | |||||
| import io.swagger.annotations.ApiModel; | |||||
| import lombok.Data; | |||||
| import java.util.Map; | |||||
| @Data | |||||
| @JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class) | |||||
| @JsonInclude(JsonInclude.Include.NON_NULL) | |||||
| @ApiModel(description = "主动学习参数") | |||||
| public class ActiveLearnParamVo { | |||||
| private Map<String,Object> codeConfig; | |||||
| private Map<String,Object> dataset; | |||||
| private Map<String,Object> image; | |||||
| private Map<String,Object> model; | |||||
| private String taskType; | |||||
| private String frameworkType; | |||||
| private String modelPy; | |||||
| private String modelClassName; | |||||
| private String classifierAlg; | |||||
| private String regressorAlg; | |||||
| private String datasetPy; | |||||
| private String datasetClassName; | |||||
| private Integer dataSize; | |||||
| private Integer computingResourceId; | |||||
| private Boolean shuffle; | |||||
| private Integer trainSize; | |||||
| private Integer initialNum; | |||||
| private Integer queriesNum; | |||||
| private Integer instancesNum; | |||||
| private String queryStrategy; | |||||
| private String lossPy; | |||||
| private String lossClassName; | |||||
| private Integer checkpointNum; | |||||
| private Integer batchSize; | |||||
| private Integer epochs; | |||||
| private Float lr; | |||||
| } | |||||
| @@ -0,0 +1,114 @@ | |||||
| package com.ruoyi.platform.vo; | |||||
| import com.fasterxml.jackson.databind.PropertyNamingStrategy; | |||||
| import com.fasterxml.jackson.databind.annotation.JsonNaming; | |||||
| import io.swagger.annotations.ApiModel; | |||||
| import io.swagger.annotations.ApiModelProperty; | |||||
| import lombok.Data; | |||||
| import java.util.Date; | |||||
| import java.util.Map; | |||||
| @Data | |||||
| @JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class) | |||||
| @ApiModel(description = "主动学习") | |||||
| public class ActiveLearnVo { | |||||
| private Long id; | |||||
| @ApiModelProperty(value = "实验名称") | |||||
| private String name; | |||||
| @ApiModelProperty(value = "实验描述") | |||||
| private String description; | |||||
| @ApiModelProperty(value = "任务类型:classification或regression") | |||||
| private String taskType; | |||||
| @ApiModelProperty(value = "框架类型: sklearn, keras, pytorch") | |||||
| private String frameworkType; | |||||
| @ApiModelProperty(value = "代码") | |||||
| private Map<String, Object> codeConfig; | |||||
| @ApiModelProperty(value = "预训练的模型") | |||||
| private Map<String, Object> model; | |||||
| @ApiModelProperty(value = "模型文件路径") | |||||
| private String modelPy; | |||||
| @ApiModelProperty(value = "类名称") | |||||
| private String modelClassName; | |||||
| @ApiModelProperty(value = "分类算法") | |||||
| private String classifierAlg; | |||||
| @ApiModelProperty(value = "回归算法") | |||||
| private String regressorAlg; | |||||
| @ApiModelProperty(value = "dataset文件路径") | |||||
| private String datasetPy; | |||||
| @ApiModelProperty(value = "dataset类名") | |||||
| private String datasetClassName; | |||||
| @ApiModelProperty(value = "数据集文件路径") | |||||
| private Map<String, Object> dataset; | |||||
| @ApiModelProperty(value = "数据量") | |||||
| private Integer dataSize; | |||||
| @ApiModelProperty(value = "镜像") | |||||
| private Map<String, Object> image; | |||||
| @ApiModelProperty(value = "计算资源id") | |||||
| private Integer computingResourceId; | |||||
| @ApiModelProperty(value = "是否随机打乱") | |||||
| private Boolean shuffle; | |||||
| @ApiModelProperty(value = "训练集数据量") | |||||
| private Integer trainSize; | |||||
| @ApiModelProperty(value = "初始训练数据量") | |||||
| private Integer initialNum; | |||||
| @ApiModelProperty(value = "查询次数") | |||||
| private Integer queriesNum; | |||||
| @ApiModelProperty(value = "每次查询数据量") | |||||
| private Integer instancesNum; | |||||
| @ApiModelProperty(value = "查询策略:uncertainty_sampling, uncertainty_batch_sampling, max_std_sampling, expected_improvement, upper_confidence_bound") | |||||
| private String queryStrategy; | |||||
| @ApiModelProperty(value = "loss文件路径") | |||||
| private String lossPy; | |||||
| @ApiModelProperty(value = "loss类名") | |||||
| private String lossClassName; | |||||
| @ApiModelProperty(value = "多少轮查询保存一次模型参数") | |||||
| private Integer checkpointNum; | |||||
| @ApiModelProperty(value = "batch_size") | |||||
| private Integer batchSize; | |||||
| @ApiModelProperty(value = "epochs") | |||||
| private Integer epochs; | |||||
| @ApiModelProperty(value = "学习率") | |||||
| private Float lr; | |||||
| private String createBy; | |||||
| private String updateBy; | |||||
| private Date createTime; | |||||
| private Date updateTime; | |||||
| private Integer state; | |||||
| @ApiModelProperty(value = "状态列表") | |||||
| private String statusList; | |||||
| } | |||||
| @@ -34,7 +34,7 @@ public class DevEnvironmentVo implements Serializable { | |||||
| /** | /** | ||||
| * 所用镜像 | * 所用镜像 | ||||
| */ | */ | ||||
| private String image; | |||||
| private Map<String,Object> image; | |||||
| /** | /** | ||||
| * 对应数据集 | * 对应数据集 | ||||
| */ | */ | ||||
| @@ -39,8 +39,8 @@ public class ImageVo implements Serializable { | |||||
| /** | /** | ||||
| * 镜像推送地址 | * 镜像推送地址 | ||||
| */ | */ | ||||
| // @ApiModelProperty(name = "url") | |||||
| // private String url; | |||||
| @ApiModelProperty(name = "value") | |||||
| private String value; | |||||
| /** | /** | ||||
| * 镜像tag名称 | * 镜像tag名称 | ||||
| @@ -24,7 +24,7 @@ public class ServiceVersionVo { | |||||
| private ServiceModelVo model; | private ServiceModelVo model; | ||||
| private String image; | |||||
| private Map<String, Object> image; | |||||
| private String resource; | private String resource; | ||||
| @@ -0,0 +1,187 @@ | |||||
| <?xml version="1.0" encoding="UTF-8"?> | |||||
| <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> | |||||
| <mapper namespace="com.ruoyi.platform.mapper.ActiveLearnDao"> | |||||
| <select id="count" resultType="java.lang.Long"> | |||||
| select count(1) from active_learn | |||||
| <include refid="common_condition"></include> | |||||
| </select> | |||||
| <select id="queryByPage" resultType="com.ruoyi.platform.domain.ActiveLearn"> | |||||
| select * from active_learn | |||||
| <include refid="common_condition"></include> | |||||
| order by create_time desc limit #{pageable.offset}, #{pageable.pageSize} | |||||
| </select> | |||||
| <select id="getActiveLearnByName" resultType="com.ruoyi.platform.domain.ActiveLearn"> | |||||
| select * | |||||
| from active_learn | |||||
| where name = #{name} | |||||
| and state = 1 | |||||
| </select> | |||||
| <insert id="save" keyProperty="id" useGeneratedKeys="true"> | |||||
| insert into active_learn(name, description, task_type, framework_type, | |||||
| code_config, | |||||
| model, model_py, model_class_name, | |||||
| classifier_alg, regressor_alg, dataset_py, dataset_class_name, | |||||
| dataset, data_size, image, computing_resource_id, shuffle, | |||||
| train_size, initial_num, queries_num, instances_num, query_strategy, | |||||
| loss_py, loss_class_name, checkpoint_num, batch_size, epochs, | |||||
| lr, create_by, update_by) | |||||
| values (#{activeLearn.name}, #{activeLearn.description}, #{activeLearn.taskType}, #{activeLearn.frameworkType}, #{activeLearn.codeConfig}, | |||||
| #{activeLearn.model}, | |||||
| #{activeLearn.modelPy}, #{activeLearn.modelClassName}, #{activeLearn.classifierAlg}, | |||||
| #{activeLearn.regressorAlg}, | |||||
| #{activeLearn.datasetPy}, #{activeLearn.datasetClassName}, | |||||
| #{activeLearn.dataset}, #{activeLearn.dataSize}, | |||||
| #{activeLearn.image}, | |||||
| #{activeLearn.computingResourceId}, #{activeLearn.shuffle}, | |||||
| #{activeLearn.trainSize}, #{activeLearn.initialNum}, #{activeLearn.queriesNum}, #{activeLearn.instancesNum}, | |||||
| #{activeLearn.queryStrategy}, #{activeLearn.lossPy}, | |||||
| #{activeLearn.lossClassName}, #{activeLearn.checkpointNum}, #{activeLearn.batchSize}, | |||||
| #{activeLearn.epochs}, #{activeLearn.lr}, #{activeLearn.createBy}, #{activeLearn.updateBy}) | |||||
| </insert> | |||||
| <update id="edit"> | |||||
| update active_learn | |||||
| <set> | |||||
| <if test="activeLearn.name != null and activeLearn.name !=''"> | |||||
| name = #{activeLearn.name}, | |||||
| </if> | |||||
| <if test="activeLearn.description != null and activeLearn.description !=''"> | |||||
| description = #{activeLearn.description}, | |||||
| </if> | |||||
| <if test="activeLearn.taskType != null and activeLearn.taskType !=''"> | |||||
| task_type = #{activeLearn.taskType}, | |||||
| </if> | |||||
| <if test="activeLearn.frameworkType != null and activeLearn.frameworkType !=''"> | |||||
| framework_type = #{activeLearn.frameworkType}, | |||||
| </if> | |||||
| <if test="activeLearn.codeConfig != null and activeLearn.codeConfig !=''"> | |||||
| code_config = #{activeLearn.codeConfig}, | |||||
| </if> | |||||
| <if test="activeLearn.model != null and activeLearn.model !=''"> | |||||
| model = #{activeLearn.model}, | |||||
| </if> | |||||
| <if test="activeLearn.modelPy != null and activeLearn.modelPy !=''"> | |||||
| model_py = #{activeLearn.modelPy}, | |||||
| </if> | |||||
| <if test="activeLearn.modelClassName != null and activeLearn.modelClassName !=''"> | |||||
| model_class_name = #{activeLearn.modelClassName}, | |||||
| </if> | |||||
| <if test="activeLearn.classifierAlg != null and activeLearn.classifierAlg !=''"> | |||||
| classifier_alg = #{activeLearn.classifierAlg}, | |||||
| </if> | |||||
| <if test="activeLearn.regressorAlg != null and activeLearn.regressorAlg !=''"> | |||||
| regressor_alg = #{activeLearn.regressorAlg}, | |||||
| </if> | |||||
| <if test="activeLearn.dataset != null and activeLearn.dataset !=''"> | |||||
| dataset = #{activeLearn.dataset}, | |||||
| </if> | |||||
| <if test="activeLearn.datasetPy != null and activeLearn.datasetPy !=''"> | |||||
| dataset_py = #{activeLearn.datasetPy}, | |||||
| </if> | |||||
| <if test="activeLearn.datasetClassName != null and activeLearn.datasetClassName !=''"> | |||||
| dataset_class_name = #{activeLearn.datasetClassName}, | |||||
| </if> | |||||
| <if test="activeLearn.dataSize != null"> | |||||
| data_size = #{activeLearn.dataSize}, | |||||
| </if> | |||||
| <if test="activeLearn.image != null and activeLearn.image !=''"> | |||||
| image = #{activeLearn.image}, | |||||
| </if> | |||||
| <if test="activeLearn.computingResourceId != null"> | |||||
| computing_resource_id = #{activeLearn.computingResourceId}, | |||||
| </if> | |||||
| <if test="activeLearn.shuffle != null"> | |||||
| shuffle = #{activeLearn.shuffle}, | |||||
| </if> | |||||
| <if test="activeLearn.trainSize != null"> | |||||
| train_size = #{activeLearn.trainSize}, | |||||
| </if> | |||||
| <if test="activeLearn.initialNum != null"> | |||||
| initial_num = #{activeLearn.initialNum}, | |||||
| </if> | |||||
| <if test="activeLearn.queriesNum != null"> | |||||
| queries_num = #{activeLearn.queriesNum}, | |||||
| </if> | |||||
| <if test="activeLearn.instancesNum != null"> | |||||
| instances_num = #{activeLearn.instancesNum}, | |||||
| </if> | |||||
| <if test="activeLearn.queryStrategy != null and activeLearn.queryStrategy !=''"> | |||||
| query_strategy = #{activeLearn.queryStrategy}, | |||||
| </if> | |||||
| <if test="activeLearn.lossPy != null and activeLearn.lossPy !=''"> | |||||
| loss_py = #{activeLearn.lossPy}, | |||||
| </if> | |||||
| <if test="activeLearn.lossClassName != null and activeLearn.lossClassName !=''"> | |||||
| loss_class_name = #{activeLearn.lossClassName}, | |||||
| </if> | |||||
| <if test="activeLearn.checkpointNum != null"> | |||||
| checkpoint_num = #{activeLearn.checkpointNum}, | |||||
| </if> | |||||
| <if test="activeLearn.batchSize != null"> | |||||
| batch_size = #{activeLearn.batchSize}, | |||||
| </if> | |||||
| <if test="activeLearn.epochs != null"> | |||||
| epochs = #{activeLearn.epochs}, | |||||
| </if> | |||||
| <if test="activeLearn.lr != null"> | |||||
| lr = #{activeLearn.lr}, | |||||
| </if> | |||||
| <if test="activeLearn.updateBy != null and activeLearn.updateBy !=''"> | |||||
| update_by = #{activeLearn.updateBy}, | |||||
| </if> | |||||
| <if test="activeLearn.statusList != null and activeLearn.statusList !=''"> | |||||
| status_list = #{activeLearn.statusList}, | |||||
| </if> | |||||
| <if test="activeLearn.state != null"> | |||||
| state = #{activeLearn.state}, | |||||
| </if> | |||||
| </set> | |||||
| where id = #{activeLearn.id} | |||||
| </update> | |||||
| <select id="getActiveLearnById" resultType="com.ruoyi.platform.domain.ActiveLearn"> | |||||
| select * | |||||
| from active_learn | |||||
| where id = #{id} | |||||
| </select> | |||||
| <select id="queryByDatasetId" resultType="com.ruoyi.platform.domain.ActiveLearn"> | |||||
| select * | |||||
| from active_learn | |||||
| where JSON_CONTAINS(dataset, #{datasetId}) | |||||
| and state = 1 | |||||
| </select> | |||||
| <select id="queryByModelId" resultType="com.ruoyi.platform.domain.ActiveLearn"> | |||||
| select * | |||||
| from active_learn | |||||
| where JSON_CONTAINS(model, #{modelId}) | |||||
| and state = 1 | |||||
| </select> | |||||
| <select id="queryByImageId" resultType="com.ruoyi.platform.domain.ActiveLearn"> | |||||
| select * | |||||
| from active_learn | |||||
| where JSON_CONTAINS(image, #{imageId}) | |||||
| and state = 1 | |||||
| </select> | |||||
| <select id="queryByCodeConfig" resultType="com.ruoyi.platform.domain.ActiveLearn"> | |||||
| select * | |||||
| from active_learn | |||||
| where JSON_CONTAINS(code_config, #{codeConfig}) | |||||
| and state = 1 | |||||
| </select> | |||||
| <sql id="common_condition"> | |||||
| <where> | |||||
| state = 1 | |||||
| <if test="name != null and name != ''"> | |||||
| and name like concat('%', #{name}, '%') | |||||
| </if> | |||||
| </where> | |||||
| </sql> | |||||
| </mapper> | |||||
| @@ -0,0 +1,79 @@ | |||||
| <?xml version="1.0" encoding="UTF-8"?> | |||||
| <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> | |||||
| <mapper namespace="com.ruoyi.platform.mapper.ActiveLearnInsDao"> | |||||
| <select id="count" resultType="java.lang.Long"> | |||||
| select count(1) | |||||
| from active_learn_ins | |||||
| <where> | |||||
| state = 1 | |||||
| and active_learn_id = #{activeLearnId} | |||||
| </where> | |||||
| </select> | |||||
| <select id="queryAllByLimit" resultType="com.ruoyi.platform.domain.ActiveLearnIns"> | |||||
| select * from active_learn_ins | |||||
| <where> | |||||
| state = 1 | |||||
| and active_learn_id = #{activeLearnId} | |||||
| </where> | |||||
| order by update_time DESC | |||||
| limit #{pageable.offset}, #{pageable.pageSize} | |||||
| </select> | |||||
| <insert id="insert" keyProperty="id" useGeneratedKeys="true"> | |||||
| insert into active_learn_ins(active_learn_id, param, argo_ins_name, argo_ins_ns, node_status, node_result, | |||||
| result_path, status) | |||||
| values (#{activeLearnIns.activeLearnId}, #{activeLearnIns.param}, #{activeLearnIns.argoInsName}, | |||||
| #{activeLearnIns.argoInsNs}, | |||||
| #{activeLearnIns.nodeStatus}, #{activeLearnIns.nodeResult}, #{activeLearnIns.resultPath}, | |||||
| #{activeLearnIns.status}) | |||||
| </insert> | |||||
| <update id="update"> | |||||
| update active_learn_ins | |||||
| <set> | |||||
| <if test="activeLearnIns.resultPath != null and activeLearnIns.resultPath != ''"> | |||||
| result_path = #{activeLearnIns.resultPath}, | |||||
| </if> | |||||
| <if test="activeLearnIns.status != null and activeLearnIns.status != ''"> | |||||
| status = #{activeLearnIns.status}, | |||||
| </if> | |||||
| <if test="activeLearnIns.nodeStatus != null and activeLearnIns.nodeStatus != ''"> | |||||
| node_status = #{activeLearnIns.nodeStatus}, | |||||
| </if> | |||||
| <if test="activeLearnIns.nodeResult != null and activeLearnIns.nodeResult != ''"> | |||||
| node_result = #{activeLearnIns.nodeResult}, | |||||
| </if> | |||||
| <if test="activeLearnIns.state != null"> | |||||
| state = #{activeLearnIns.state}, | |||||
| </if> | |||||
| <if test="activeLearnIns.finishTime != null"> | |||||
| finish_time = #{activeLearnIns.finishTime}, | |||||
| </if> | |||||
| </set> | |||||
| where id = #{activeLearnIns.id} | |||||
| </update> | |||||
| <select id="queryById" resultType="com.ruoyi.platform.domain.ActiveLearnIns"> | |||||
| select * from active_learn_ins | |||||
| <where> | |||||
| state = 1 and id = #{id} | |||||
| </where> | |||||
| </select> | |||||
| <select id="getByActiveLearnId" resultType="com.ruoyi.platform.domain.ActiveLearnIns"> | |||||
| select * | |||||
| from active_learn_ins | |||||
| where active_learn_id = #{activeLearnId} | |||||
| and state = 1 | |||||
| order by update_time DESC limit 5 | |||||
| </select> | |||||
| <select id="queryActiveLearnInsIsNotTerminated" resultType="com.ruoyi.platform.domain.ActiveLearnIns"> | |||||
| select * | |||||
| from active_learn_ins | |||||
| where (status NOT IN ('Terminated', 'Succeeded', 'Failed') | |||||
| OR status IS NULL) | |||||
| and state = 1 | |||||
| </select> | |||||
| </mapper> | |||||
| @@ -120,6 +120,7 @@ | |||||
| <select id="queryByPage" resultType="com.ruoyi.platform.domain.AutoMl"> | <select id="queryByPage" resultType="com.ruoyi.platform.domain.AutoMl"> | ||||
| select * from auto_ml | select * from auto_ml | ||||
| <include refid="common_condition"></include> | <include refid="common_condition"></include> | ||||
| order by create_time desc limit #{pageable.offset}, #{pageable.pageSize} | |||||
| </select> | </select> | ||||
| <select id="getAutoMlById" resultType="com.ruoyi.platform.domain.AutoMl"> | <select id="getAutoMlById" resultType="com.ruoyi.platform.domain.AutoMl"> | ||||
| @@ -208,11 +208,38 @@ | |||||
| where id = #{devEnvironment.id} | where id = #{devEnvironment.id} | ||||
| </update> | </update> | ||||
| <select id="getByName" resultType="com.ruoyi.platform.domain.DevEnvironment"> | |||||
| select * | |||||
| from dev_environment | |||||
| where name = #{name} | |||||
| and state = 1 | |||||
| </select> | |||||
| <!--通过主键删除--> | <!--通过主键删除--> | ||||
| <delete id="deleteById"> | <delete id="deleteById"> | ||||
| delete from dev_environment where id = #{id} | delete from dev_environment where id = #{id} | ||||
| </delete> | </delete> | ||||
| <select id="queryByDatasetId" resultType="com.ruoyi.platform.domain.DevEnvironment"> | |||||
| select * | |||||
| from dev_environment | |||||
| where JSON_CONTAINS(dataset, #{datasetId}) | |||||
| and state = 1 | |||||
| </select> | |||||
| <select id="queryByModelId" resultType="com.ruoyi.platform.domain.DevEnvironment"> | |||||
| select * | |||||
| from dev_environment | |||||
| where JSON_CONTAINS(model, #{modelId}) | |||||
| and state = 1 | |||||
| </select> | |||||
| <select id="queryByImageId" resultType="com.ruoyi.platform.domain.DevEnvironment"> | |||||
| select * | |||||
| from dev_environment | |||||
| where JSON_CONTAINS(image, #{imageId}) | |||||
| and state = 1 | |||||
| </select> | |||||
| </mapper> | </mapper> | ||||
| @@ -1,7 +1,7 @@ | |||||
| <?xml version="1.0" encoding="UTF-8"?> | <?xml version="1.0" encoding="UTF-8"?> | ||||
| <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> | <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> | ||||
| <mapper namespace="com.ruoyi.platform.mapper.RayDao"> | <mapper namespace="com.ruoyi.platform.mapper.RayDao"> | ||||
| <insert id="save"> | |||||
| <insert id="save" keyProperty="id" useGeneratedKeys="true"> | |||||
| insert into ray(name, description, dataset, model, code_config, main_py, num_samples, parameters, | insert into ray(name, description, dataset, model, code_config, main_py, num_samples, parameters, | ||||
| points_to_evaluate, storage_path, | points_to_evaluate, storage_path, | ||||
| search_alg, scheduler, metric, mode, max_t, | search_alg, scheduler, metric, mode, max_t, | ||||
| @@ -94,11 +94,12 @@ | |||||
| <select id="queryByPage" resultType="com.ruoyi.platform.domain.Ray"> | <select id="queryByPage" resultType="com.ruoyi.platform.domain.Ray"> | ||||
| select * from ray | select * from ray | ||||
| <include refid="common_condition"></include> | <include refid="common_condition"></include> | ||||
| order by create_time desc limit #{pageable.offset}, #{pageable.pageSize} | |||||
| </select> | </select> | ||||
| <select id="getRayByName" resultType="com.ruoyi.platform.domain.Ray"> | <select id="getRayByName" resultType="com.ruoyi.platform.domain.Ray"> | ||||
| select * | select * | ||||
| from ray _ | |||||
| from ray | |||||
| where name = #{name} | where name = #{name} | ||||
| and state = 1 | and state = 1 | ||||
| </select> | </select> | ||||
| @@ -60,6 +60,17 @@ | |||||
| where id = #{id} | where id = #{id} | ||||
| </update> | </update> | ||||
| <update id="deleteTaskState"> | |||||
| update resource_occupy set task_state = 0 | |||||
| where task_type = #{taskType} | |||||
| <if test="taskId != null and taskId !=''"> | |||||
| and task_id = #{taskId} | |||||
| </if> | |||||
| <if test="taskInsId != null and taskInsId !=''"> | |||||
| and task_ins_id = #{taskInsId} | |||||
| </if> | |||||
| </update> | |||||
| <select id="haveResource" resultType="java.lang.Boolean"> | <select id="haveResource" resultType="java.lang.Boolean"> | ||||
| select case when used + #{need} <= total then TRUE else FALSE end | select case when used + #{need} <= total then TRUE else FALSE end | ||||
| from resource | from resource | ||||
| @@ -190,4 +190,34 @@ | |||||
| set run_state = #{runState} | set run_state = #{runState} | ||||
| where deployment_name = #{deploymentName} | where deployment_name = #{deploymentName} | ||||
| </update> | </update> | ||||
| <select id="queryByModelId" resultType="java.lang.String"> | |||||
| select concat(b.service_name, ':', a.version) | |||||
| from service_version a, | |||||
| service b | |||||
| where JSON_CONTAINS(a.model, #{modelId}) | |||||
| and a.state = 1 | |||||
| and b.state = 1 | |||||
| and a.service_id = b.id | |||||
| </select> | |||||
| <select id="queryByImageId" resultType="java.lang.String"> | |||||
| select concat(b.service_name, ':', a.version) | |||||
| from service_version a, | |||||
| service b | |||||
| where JSON_CONTAINS(a.image, #{imageId}) | |||||
| and a.state = 1 | |||||
| and b.state = 1 | |||||
| and a.service_id = b.id | |||||
| </select> | |||||
| <select id="queryByCodeConfig" resultType="java.lang.String"> | |||||
| select concat(b.service_name, ':', a.version) | |||||
| from service_version a, | |||||
| service b | |||||
| where JSON_CONTAINS(a.code_config, #{codeConfig}) | |||||
| and a.state = 1 | |||||
| and b.state = 1 | |||||
| and a.service_id = b.id | |||||
| </select> | |||||
| </mapper> | </mapper> | ||||