| @@ -3,11 +3,24 @@ ENV = 'development' | |||
| # 默认BASE URL | |||
| VUE_APP_BASE_API = '' | |||
| # 数据管理 | |||
| VUE_APP_DATA_API = '' | |||
| # minio | |||
| VUE_APP_MINIO_API = '' // 建议使用与当前 web 服务域名的域名 | |||
| VUE_APP_MINIO_API = 'http://{HOST}/minio' | |||
| # atlas 模型炼知 | |||
| # atlas 服务,需要单独部署 | |||
| VUE_APP_ATLAS_HOST = '' | |||
| # 医疗影像 DCM4CHEE 服务访问地址 | |||
| # 部署文档参考:http://docs.dubhe.ai/docs/setup/deploy-algorithm | |||
| VUE_APP_DCM_API = 'http://{HOST}/dcm4chee/dcm4chee-arc/aets/DCM4CHEE_ADMIN' | |||
| # minIO 服务 IP | |||
| VUE_APP_MINIO_ENDPOINT = '' | |||
| # minIO 服务 端口 | |||
| VUE_APP_MINIO_PORT = '9000' | |||
| # 是否开启 SSL | |||
| VUE_APP_MINIO_USESSL = 'false' | |||
| # bucketName | |||
| VUE_APP_MINIO_BUCKETNAME = 'dubhe-dev' | |||
| @@ -1,4 +1,22 @@ | |||
| ENV='development' | |||
| # 开启 mock 模式 | |||
| VUE_APP_MOCK=true | |||
| VUE_APP_BASE_API = '' | |||
| VUE_APP_DATA_API = '/mock' | |||
| # 默认BASE URL,需要自行配置 | |||
| VUE_APP_BASE_API = '/mock' | |||
| # 用户 minio 访问地址 | |||
| VUE_APP_MINIO_API = 'http://{HOST}/minio' | |||
| # minIO 服务 IP | |||
| VUE_APP_MINIO_ENDPOINT = '' | |||
| # minIO 服务 端口 | |||
| VUE_APP_MINIO_PORT = '9000' | |||
| # 是否开启 SSL | |||
| VUE_APP_MINIO_USESSL = 'false' | |||
| # bucketName | |||
| VUE_APP_MINIO_BUCKETNAME = 'dubhe-dev' | |||
| @@ -1,13 +1,27 @@ | |||
| ENV = 'production' | |||
| # 默认BASE URL | |||
| VUE_APP_BASE_API = '/' | |||
| # 默认BASE URL, 后端服务地址 | |||
| VUE_APP_BASE_API = 'http://127.0.0.1:8000' | |||
| # 数据管理 | |||
| VUE_APP_DATA_API = '/' | |||
| # 用户 minio 访问地址 | |||
| VUE_APP_MINIO_API = 'http://{HOST}/minio' | |||
| # minio | |||
| VUE_APP_MINIO_API = '' | |||
| # atlas 服务,需要单独部署 | |||
| VUE_APP_ATLAS_HOST = 'http://127.0.0.1:8000' | |||
| # atlas | |||
| VUE_APP_ATLAS_HOST = '' | |||
| # 医疗影像 DCM4CHEE 服务访问地址 | |||
| # 部署文档参考:http://docs.dubhe.ai/docs/setup/deploy-algorithm | |||
| VUE_APP_DCM_API = 'http://{HOST}/dcm4chee/dcm4chee-arc/aets/DCM4CHEE_ADMIN' | |||
| # minIO 服务 IP | |||
| # 部署文档参考:http://docs.dubhe.ai/docs/setup/deploy-minio | |||
| VUE_APP_MINIO_ENDPOINT = '{IP}' | |||
| # minIO 服务 端口 | |||
| VUE_APP_MINIO_PORT = '9000' | |||
| # 是否开启 SSL | |||
| VUE_APP_MINIO_USESSL = 'false' | |||
| # bucketName | |||
| VUE_APP_MINIO_BUCKETNAME = 'dubhe-prod' | |||
| @@ -3,11 +3,25 @@ ENV = 'test' | |||
| # 默认BASE URL | |||
| VUE_APP_BASE_API = '' | |||
| # 数据管理 | |||
| VUE_APP_DATA_API = '' | |||
| # minio | |||
| # 用户 minio 访问地址 | |||
| VUE_APP_MINIO_API = '' | |||
| # atlas | |||
| # atlas 服务,需要单独部署 | |||
| VUE_APP_ATLAS_HOST = '' | |||
| # 医疗影像 DCM4CHEE 服务访问地址 | |||
| # 部署文档参考:http://docs.dubhe.ai/docs/setup/deploy-algorithm | |||
| VUE_APP_DCM_API = 'http://{HOST}/dcm4chee/dcm4chee-arc/aets/DCM4CHEE_ADMIN' | |||
| # minIO 服务 IP | |||
| VUE_APP_MINIO_ENDPOINT = '' | |||
| # minIO 服务 端口 | |||
| VUE_APP_MINIO_PORT = '9000' | |||
| # 是否开启 SSL | |||
| VUE_APP_MINIO_USESSL = 'false' | |||
| # BucketName | |||
| VUE_APP_MINIO_BUCKETNAME = 'dubhe-test' | |||
| @@ -1,3 +1,28 @@ | |||
| ## 0.3.0 (2021-01-14) | |||
| ### Breaking Change | |||
| - [模型管理] 完成内置优化、我的优化功能,支持模型量化、剪枝、蒸馏 | |||
| - [云端Serving] 完成在线服务、批量服务功能,在线服务支持 HTTP 请求、GRPC 请求、灰度分流、服务回滚 | |||
| - [模型炼知] 移植重构图谱可视化、图谱列表功能,完成度量管理功能 | |||
| ### Features | |||
| - 路由迁移到本地管理,移除在线「菜单管理」页面 | |||
| - MinIO 配置更新 | |||
| - [数据管理] 增加 NLP 文本分类数据标注功能 | |||
| - [数据管理] 增加医疗影像数据标注,支持自动器官分割和病灶识别 | |||
| - [训练管理] 支持使用教师模型、学生模型进行模型炼知 | |||
| - [训练管理] 镜像管理支持管理员上传Notebook镜像, 并可以设置为默认Notebook镜像 | |||
| - [训练管理] 模型、算法、镜像等文件上传时不允许文件名包含不合法字符 | |||
| - [训练管理] 运行日志展示组件重构。以 K8S 的 pod 为单位进行日志查询展示 | |||
| - [模型管理] 增加炼知模型管理 | |||
| ### Bug Fixs | |||
| - [模型开发] 修复 Notebook 页面重置按钮失效的问题 | |||
| - [训练管理] 修复模型下载文件路径问题 | |||
| ## 0.2.1 (2020-11-16) | |||
| ### Features | |||
| @@ -26,8 +26,9 @@ cd dubhe-web | |||
| 根据需要修改如下配置文件 | |||
| ``` | |||
| config/index.js | |||
| settings.js | |||
| .env.mock | |||
| .env.development | |||
| .env.test | |||
| .env.production | |||
| ``` | |||
| @@ -1,56 +0,0 @@ | |||
| module.exports = { | |||
| "code": 200, | |||
| "msg": null, | |||
| "data": { | |||
| "result": [{ | |||
| "id": 56, | |||
| "name": "bag_data", | |||
| "remark": "不可删除,不可删除", | |||
| "type": 0, | |||
| "uri": null, | |||
| "dataType": 0, | |||
| "annotateType": 2, | |||
| "status": 104, | |||
| "createTime": "2020-10-21 15:39:01", | |||
| "updateTime": "2020-10-22 14:13:10", | |||
| "team": null, | |||
| "createUser": null, | |||
| "updateUser": null, | |||
| "progress": null, | |||
| "currentVersionName": null, | |||
| "decompressState": 0, | |||
| "labelGroupId": 1, | |||
| "labelGroupName": "COCO", | |||
| "labelGroupType": 1, | |||
| "import": false, | |||
| "top": true | |||
| }, { | |||
| "id": 346, | |||
| "name": "test432", | |||
| "remark": "test432", | |||
| "type": 0, | |||
| "uri": null, | |||
| "dataType": 0, | |||
| "annotateType": 1, | |||
| "status": 101, | |||
| "createTime": "2020-10-27 15:20:58", | |||
| "updateTime": "2020-10-27 15:20:58", | |||
| "team": null, | |||
| "createUser": null, | |||
| "updateUser": null, | |||
| "progress": null, | |||
| "currentVersionName": null, | |||
| "decompressState": 0, | |||
| "labelGroupId": 468, | |||
| "labelGroupName": "test432", | |||
| "labelGroupType": 0, | |||
| "import": false, | |||
| "top": false | |||
| }], | |||
| "page": { | |||
| "size": 10, | |||
| "current": 1, | |||
| "total": 218 | |||
| }, | |||
| } | |||
| } | |||
| @@ -0,0 +1,8 @@ | |||
| module.exports = { | |||
| code: 200, | |||
| msg: null, | |||
| data: { | |||
| "finished": 10, | |||
| "unfinished": 0 | |||
| } | |||
| } | |||
| @@ -1,5 +0,0 @@ | |||
| module.exports = { | |||
| "code": 200, | |||
| "msg": null, | |||
| "data": [] | |||
| } | |||
| @@ -1,4 +1,4 @@ | |||
| // 定义 RESTful 接口和实际代码的映射 | |||
| module.exports = { | |||
| 'GET::/api/data/labelGroup/getList/(\\d+)': '/api/data/labelGroup/getList/id', | |||
| 'GET::/api/data/datasets/(\\d+)/count': 'api/data/datasets/count', | |||
| }; | |||
| @@ -1,6 +1,6 @@ | |||
| { | |||
| "name": "dubhe-web", | |||
| "version": "0.2.1", | |||
| "version": "0.3.0", | |||
| "description": "之江天枢人工智能开源平台", | |||
| "author": "zhejianglab", | |||
| "keywords": [ | |||
| @@ -41,15 +41,19 @@ | |||
| "@riophae/vue-treeselect": "0.1.0", | |||
| "@vue/babel-plugin-transform-vue-jsx": "^1.1.2", | |||
| "@vue/composition-api": "^0.5.0", | |||
| "@wulucxy/dwv": "0.28.1-beta.9", | |||
| "add-dom-event-listener": "^1.1.0", | |||
| "axios": "0.18.1", | |||
| "chroma-js": "^2.1.0", | |||
| "classnames": "^2.2.6", | |||
| "clipboard": "^2.0.6", | |||
| "d3": "^5.16.0", | |||
| "d3-selection": "^1.4.1", | |||
| "d3-zoom": "^1.8.3", | |||
| "dagre-d3": "^0.6.4", | |||
| "date-fns": "^2.13.0", | |||
| "dicom-parser": "^1.8.7", | |||
| "dicomweb-client": "^0.6.0", | |||
| "echarts": "4.2.1", | |||
| "echarts-gl": "^1.1.1", | |||
| "element-ui": "2.13.2", | |||
| @@ -59,18 +63,21 @@ | |||
| "jquery-contextmenu": "^2.9.1", | |||
| "js-beautify": "^1.13.0", | |||
| "js-cookie": "2.2.0", | |||
| "jschardet": "^2.2.1", | |||
| "jsencrypt": "^3.0.0-rc.1", | |||
| "json2csv": "^5.0.1", | |||
| "lodash": "^4.17.15", | |||
| "minio": "^7.0.16", | |||
| "minio": "7.0.16", | |||
| "nanoid": "^3.1.3", | |||
| "normalize.css": "7.0.0", | |||
| "nprogress": "0.2.0", | |||
| "p-map": "^4.0.0", | |||
| "path-to-regexp": "^6.2.0", | |||
| "portal-vue": "^2.1.7", | |||
| "prismjs": "^1.20.0", | |||
| "promise.allsettled": "^1.0.2", | |||
| "qs": "^6.9.1", | |||
| "screenfull": "^5.0.2", | |||
| "stream-to-array": "^2.3.0", | |||
| "streamsaver": "^2.0.4", | |||
| "v-click-outside": "^3.0.1", | |||
| @@ -1,4 +1,4 @@ | |||
| /** Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||
| /** Copyright 2020 Tianshu AI Platform. All Rights Reserved. | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| @@ -17,7 +17,7 @@ | |||
| <template> | |||
| <div id="app"> | |||
| <keep-alive include="DataSet"> | |||
| <router-view/> | |||
| <router-view /> | |||
| </keep-alive> | |||
| </div> | |||
| </template> | |||
| @@ -1,4 +1,4 @@ | |||
| /** Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||
| /** Copyright 2020 Tianshu AI Platform. All Rights Reserved. | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| @@ -48,14 +48,6 @@ export function del(ids) { | |||
| }); | |||
| } | |||
| export function listImage(params) { | |||
| return request({ | |||
| url: 'api/v1/ptImage', | |||
| method: 'get', | |||
| params, | |||
| }); | |||
| } | |||
| export function myAlgorithmCount() { | |||
| return request({ | |||
| url: `api/v1/algorithm/myAlgorithmCount`, | |||
| @@ -63,4 +55,4 @@ export function myAlgorithmCount() { | |||
| }); | |||
| } | |||
| export default { list, add, del, listImage }; | |||
| export default { list, add, del }; | |||
| @@ -1,4 +1,4 @@ | |||
| /** Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||
| /** Copyright 2020 Tianshu AI Platform. All Rights Reserved. | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| @@ -1,4 +1,4 @@ | |||
| /** Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||
| /** Copyright 2020 Tianshu AI Platform. All Rights Reserved. | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| @@ -14,18 +14,12 @@ | |||
| * ============================================================= | |||
| */ | |||
| /* eslint-disable no-unreachable */ | |||
| import request from '@/utils/request'; | |||
| export function getMenusTree() { | |||
| return request({ | |||
| url: 'api/v1/menus/tree', | |||
| method: 'get', | |||
| }); | |||
| } | |||
| export function list(params) { | |||
| return request({ | |||
| url: 'api/v1/menus', | |||
| url: 'api/v1/ptMeasure', | |||
| method: 'get', | |||
| params, | |||
| }); | |||
| @@ -33,26 +27,32 @@ export function list(params) { | |||
| export function add(data) { | |||
| return request({ | |||
| url: 'api/v1/menus', | |||
| url: 'api/v1/ptMeasure', | |||
| method: 'post', | |||
| data, | |||
| }); | |||
| } | |||
| export function edit(data) { | |||
| return request({ | |||
| url: 'api/v1/ptMeasure', | |||
| method: 'put', | |||
| data, | |||
| }); | |||
| } | |||
| export function del(ids) { | |||
| return request({ | |||
| url: 'api/v1/menus', | |||
| url: 'api/v1/ptMeasure', | |||
| method: 'delete', | |||
| data: { ids }, | |||
| }); | |||
| } | |||
| export function edit(data) { | |||
| export function getGraphs(name) { | |||
| return request({ | |||
| url: 'api/v1/menus', | |||
| method: 'put', | |||
| data, | |||
| url: 'api/v1/ptMeasure/byName', | |||
| method: 'get', | |||
| params: { name }, | |||
| }); | |||
| } | |||
| export default { list, add, edit, del, getMenusTree }; | |||
| @@ -1,4 +1,4 @@ | |||
| /** Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||
| /** Copyright 2020 Tianshu AI Platform. All Rights Reserved. | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| @@ -0,0 +1,89 @@ | |||
| /** Copyright 2020 Tianshu AI Platform. All Rights Reserved. | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| * You may obtain a copy of the License at | |||
| * | |||
| * http://www.apache.org/licenses/LICENSE-2.0 | |||
| * | |||
| * Unless required by applicable law or agreed to in writing, software | |||
| * distributed under the License is distributed on an "AS IS" BASIS, | |||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
| * See the License for the specific language governing permissions and | |||
| * limitations under the License. | |||
| * ============================================================= | |||
| */ | |||
| import request from '@/utils/request'; | |||
| export function list(params) { | |||
| return request({ | |||
| url: 'api/batchServing', | |||
| method: 'get', | |||
| params, | |||
| }); | |||
| } | |||
| export function add(data) { | |||
| return request({ | |||
| url: 'api/batchServing', | |||
| method: 'post', | |||
| data, | |||
| }); | |||
| } | |||
| export function edit(data) { | |||
| return request({ | |||
| url: 'api/batchServing', | |||
| method: 'put', | |||
| data, | |||
| }); | |||
| } | |||
| export function del(id) { | |||
| return request({ | |||
| url: `api/batchServing`, | |||
| method: 'delete', | |||
| data: { id }, | |||
| }); | |||
| } | |||
| export function detail(id) { | |||
| return request({ | |||
| url: `api/batchServing/detail`, | |||
| method: 'get', | |||
| params: { id }, | |||
| }); | |||
| } | |||
| export function start(id) { | |||
| return request({ | |||
| url: `api/batchServing/start`, | |||
| method: 'post', | |||
| data: { id }, | |||
| }); | |||
| } | |||
| export function stop(id) { | |||
| return request({ | |||
| url: `api/batchServing/stop`, | |||
| method: 'post', | |||
| data: { id }, | |||
| }); | |||
| } | |||
| export function getBatchServingPods(id) { | |||
| return request({ | |||
| url: `api/batchServing/pod/${id}`, | |||
| method: 'get', | |||
| }); | |||
| } | |||
| export function getServiceProgress(id) { | |||
| return request({ | |||
| url: `api/batchServing/queryById/${id}`, | |||
| method: 'get', | |||
| }); | |||
| } | |||
| export default { list, add, edit, del }; | |||
| @@ -0,0 +1,114 @@ | |||
| /** Copyright 2020 Tianshu AI Platform. All Rights Reserved. | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| * You may obtain a copy of the License at | |||
| * | |||
| * http://www.apache.org/licenses/LICENSE-2.0 | |||
| * | |||
| * Unless required by applicable law or agreed to in writing, software | |||
| * distributed under the License is distributed on an "AS IS" BASIS, | |||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
| * See the License for the specific language governing permissions and | |||
| * limitations under the License. | |||
| * ============================================================= | |||
| */ | |||
| import request from '@/utils/request'; | |||
| export function list(params) { | |||
| return request({ | |||
| url: 'api/serving', | |||
| method: 'get', | |||
| params, | |||
| }); | |||
| } | |||
| export function add(data) { | |||
| return request({ | |||
| url: 'api/serving', | |||
| method: 'post', | |||
| data, | |||
| }); | |||
| } | |||
| export function edit(data) { | |||
| return request({ | |||
| url: 'api/serving', | |||
| method: 'put', | |||
| data, | |||
| }); | |||
| } | |||
| export function del(id) { | |||
| return request({ | |||
| url: `api/serving`, | |||
| method: 'delete', | |||
| data: { id }, | |||
| }); | |||
| } | |||
| export function detail(id) { | |||
| return request({ | |||
| url: `api/serving/detail`, | |||
| method: 'get', | |||
| params: { id }, | |||
| }); | |||
| } | |||
| export function start(id) { | |||
| return request({ | |||
| url: `api/serving/start`, | |||
| method: 'post', | |||
| data: { id }, | |||
| }); | |||
| } | |||
| export function stop(id) { | |||
| return request({ | |||
| url: `api/serving/stop`, | |||
| method: 'post', | |||
| data: { id }, | |||
| }); | |||
| } | |||
| export function getPredictParam(id) { | |||
| return request({ | |||
| url: `api/serving/predictParam`, | |||
| method: 'get', | |||
| params: { id }, | |||
| }); | |||
| } | |||
| export function getMetrics(id) { | |||
| return request({ | |||
| url: `api/serving/metrics/${id}`, | |||
| method: 'get', | |||
| }); | |||
| } | |||
| export function getServingPods(configId) { | |||
| return request({ | |||
| url: `api/serving/servingConfig/pod/${configId}`, | |||
| method: 'get', | |||
| }); | |||
| } | |||
| export function getRollbackList(servingId) { | |||
| return request({ | |||
| url: `api/serving/rollback/${servingId}`, | |||
| method: 'get', | |||
| }); | |||
| } | |||
| export function predict(data, params) { | |||
| return request({ | |||
| url: `api/serving/predict`, | |||
| method: 'post', | |||
| headers: { 'Content-Type': 'multipart/form-data' }, | |||
| params, | |||
| data, | |||
| }); | |||
| } | |||
| export default { list, add, edit, del }; | |||
| @@ -1,4 +1,4 @@ | |||
| /** Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||
| /** Copyright 2020 Tianshu AI Platform. All Rights Reserved. | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| @@ -1,4 +1,4 @@ | |||
| /** Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||
| /** Copyright 2020 Tianshu AI Platform. All Rights Reserved. | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| @@ -48,4 +48,12 @@ export function del(data) { | |||
| }); | |||
| } | |||
| export function getModelByResource(modelResource) { | |||
| return request({ | |||
| url: 'api/ptModelInfo/byResource', | |||
| method: 'get', | |||
| params: { modelResource }, | |||
| }); | |||
| } | |||
| export default { list, add, edit, del }; | |||
| @@ -1,4 +1,4 @@ | |||
| /** Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||
| /** Copyright 2020 Tianshu AI Platform. All Rights Reserved. | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| @@ -0,0 +1,107 @@ | |||
| /** Copyright 2020 Tianshu AI Platform. All Rights Reserved. | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| * You may obtain a copy of the License at | |||
| * | |||
| * http://www.apache.org/licenses/LICENSE-2.0 | |||
| * | |||
| * Unless required by applicable law or agreed to in writing, software | |||
| * distributed under the License is distributed on an "AS IS" BASIS, | |||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
| * See the License for the specific language governing permissions and | |||
| * limitations under the License. | |||
| * ============================================================= | |||
| */ | |||
| import request from '@/utils/request'; | |||
| export function list(params) { | |||
| return request({ | |||
| url: 'api/modelOpt/task', | |||
| method: 'get', | |||
| params, | |||
| }); | |||
| } | |||
| export function add(data) { | |||
| return request({ | |||
| url: 'api/modelOpt/task', | |||
| method: 'post', | |||
| data, | |||
| }); | |||
| } | |||
| export function edit(data) { | |||
| return request({ | |||
| url: 'api/modelOpt/task', | |||
| method: 'put', | |||
| data, | |||
| }); | |||
| } | |||
| export function del(data) { | |||
| return request({ | |||
| url: `api/modelOpt/task`, | |||
| method: 'delete', | |||
| data, | |||
| }); | |||
| } | |||
| export function getOptimizeAlgorithms(params) { | |||
| return request({ | |||
| url: 'api/modelOpt/task/getAlgorithm', | |||
| method: 'get', | |||
| params, | |||
| }); | |||
| } | |||
| export function getBuiltInModel(params) { | |||
| return request({ | |||
| url: 'api/modelOpt/task/getBuiltInModel', | |||
| method: 'get', | |||
| params, | |||
| }); | |||
| } | |||
| export function getOptimizeDatasets(params) { | |||
| return request({ | |||
| url: 'api/modelOpt/task/getDataset', | |||
| method: 'get', | |||
| params, | |||
| }); | |||
| } | |||
| export function getCustomizeDatasets(params) { | |||
| return request({ | |||
| url: 'api/modelOpt/task/MyDataset', | |||
| method: 'get', | |||
| params, | |||
| }); | |||
| } | |||
| export function addCustomizeDatasets(data) { | |||
| return request({ | |||
| url: 'api/modelOpt/task/MyDataset', | |||
| method: 'post', | |||
| data, | |||
| }); | |||
| } | |||
| export function addCustomizeModel(data) { | |||
| return request({ | |||
| url: 'api/ptModelInfo/uploadModel', | |||
| method: 'post', | |||
| data, | |||
| }); | |||
| } | |||
| export function submit(data) { | |||
| return request({ | |||
| url: `api/modelOpt/task/submit`, | |||
| method: 'post', | |||
| data, | |||
| }); | |||
| } | |||
| export default { list, add, edit, del }; | |||
| @@ -1,4 +1,4 @@ | |||
| /** Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||
| /** Copyright 2020 Tianshu AI Platform. All Rights Reserved. | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| @@ -16,40 +16,42 @@ | |||
| import request from '@/utils/request'; | |||
| export function harborProjectNames() { | |||
| export function list(params) { | |||
| return request({ | |||
| url: `api/v1/ptImage/imageNameList`, | |||
| url: 'api/modelOpt/taskInstance', | |||
| method: 'get', | |||
| params, | |||
| }); | |||
| } | |||
| export function harborImageNames(params) { | |||
| export function del(data) { | |||
| return request({ | |||
| url: `api/v1/ptImage`, | |||
| method: 'get', | |||
| params, | |||
| url: `api/modelOpt/taskInstance`, | |||
| method: 'delete', | |||
| data, | |||
| }); | |||
| } | |||
| export function harborProjects(source = 0) { | |||
| export function getInstance(params) { | |||
| return request({ | |||
| url: `api/v1/harbor/projects/${source}`, | |||
| url: `api/modelOpt/taskInstance/detail`, | |||
| method: 'get', | |||
| params, | |||
| }); | |||
| } | |||
| export function harborImages(params) { | |||
| export function cancel(data) { | |||
| return request({ | |||
| url: `api/v1/harbor/images`, | |||
| method: 'get', | |||
| params, | |||
| url: `api/modelOpt/taskInstance/cancel`, | |||
| method: 'put', | |||
| data, | |||
| }); | |||
| } | |||
| export function allImages(params) { | |||
| export function resubmit(data) { | |||
| return request({ | |||
| url: `api/v1/harbor/image_page`, | |||
| method: 'get', | |||
| params, | |||
| url: `api/modelOpt/taskInstance/resubmit`, | |||
| method: 'post', | |||
| data, | |||
| }); | |||
| } | |||
| @@ -1,4 +1,4 @@ | |||
| /** Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||
| /** Copyright 2020 Tianshu AI Platform. All Rights Reserved. | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| @@ -1,4 +1,4 @@ | |||
| /** Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||
| /** Copyright 2020 Tianshu AI Platform. All Rights Reserved. | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| @@ -1,4 +1,4 @@ | |||
| /** Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||
| /** Copyright 2020 Tianshu AI Platform. All Rights Reserved. | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| @@ -39,9 +39,9 @@ export function editLabel(id, label) { | |||
| }); | |||
| } | |||
| export function getAutoLabels() { | |||
| export function getAutoLabels(labelGroupType) { | |||
| return request({ | |||
| url: 'api/data/datasets/labels/auto', | |||
| url: `api/data/datasets/labels/auto/${labelGroupType}`, | |||
| method: 'get', | |||
| }); | |||
| } | |||
| @@ -1,4 +1,4 @@ | |||
| /** Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||
| /** Copyright 2020 Tianshu AI Platform. All Rights Reserved. | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| @@ -139,6 +139,24 @@ export function queryFileOffset(datasetId, fileId, query = {}) { | |||
| }); | |||
| } | |||
| // 查询数据集标签 | |||
| export function queryLabels(datasetId, params) { | |||
| return request({ | |||
| url: `api/data/datasets/${datasetId}/labels`, | |||
| method: 'get', | |||
| params, | |||
| }); | |||
| } | |||
| // 创建数据集标签 | |||
| export function createLabel (datasetId, data) { | |||
| return request({ | |||
| url: `api/data/datasets/${datasetId}/labels`, | |||
| method: 'post', | |||
| data, | |||
| }); | |||
| } | |||
| // 查询预置标签 | |||
| export function queryPresetLabels() { | |||
| return request({ | |||
| @@ -150,7 +168,7 @@ export function queryPresetLabels() { | |||
| // 查询数据增强字典 | |||
| export function queryDataEnhanceList() { | |||
| return request({ | |||
| baseURL: process.env.VUE_APP_DATA_API, | |||
| baseURL: process.env.VUE_APP_BASE_API, | |||
| url: `api/v1/user/dict/dataset_enhance`, | |||
| method: 'get', | |||
| }); | |||
| @@ -1,4 +1,4 @@ | |||
| /** Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||
| /** Copyright 2020 Tianshu AI Platform. All Rights Reserved. | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| @@ -64,8 +64,9 @@ export function list(params) { | |||
| // 标签组列表的简况查询 用于详情页选择标签组列举 | |||
| export function getLabelGroupList(params) { | |||
| return request({ | |||
| url: `/api/data/labelGroup/getList/${params}`, | |||
| url: `/api/data/labelGroup/getList`, | |||
| method: 'get', | |||
| params, | |||
| }); | |||
| } | |||
| @@ -0,0 +1,170 @@ | |||
| /** Copyright 2020 Tianshu AI Platform. All Rights Reserved. | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| * You may obtain a copy of the License at | |||
| * | |||
| * http://www.apache.org/licenses/LICENSE-2.0 | |||
| * | |||
| * Unless required by applicable law or agreed to in writing, software | |||
| * distributed under the License is distributed on an "AS IS" BASIS, | |||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
| * See the License for the specific language governing permissions and | |||
| * limitations under the License. | |||
| * ============================================================= | |||
| */ | |||
| import request from '@/utils/request'; | |||
| // 获取数据集对应的 studyInstanceUID 和 seriesInstanceUID | |||
| export function getCaseInfo(datasetId) { | |||
| return request({ | |||
| url: `api/data/datasets/medical/detail/${datasetId}`, | |||
| method: 'get', | |||
| }); | |||
| } | |||
| // 获取自动标注详情 | |||
| export const queryAutoResult = (datasetId) => { | |||
| return request({ | |||
| url: `api/data/datasets/medical/getAuto/${datasetId}`, | |||
| method: 'get', | |||
| }); | |||
| }; | |||
| // 获取手动标注详情 | |||
| export const queryManualResult = (datasetId) => { | |||
| return request({ | |||
| url: `api/data/datasets/medical/getFinished/${datasetId}`, | |||
| method: 'get', | |||
| }); | |||
| }; | |||
| export function list(params) { | |||
| return request({ | |||
| url: '/api/data/datasets/medical', | |||
| method: 'get', | |||
| params, | |||
| }); | |||
| } | |||
| // 数据集详情 | |||
| export function detail(id) { | |||
| return request({ | |||
| url: `/api/data/datasets/medical/${id}`, | |||
| method: 'get', | |||
| }); | |||
| } | |||
| // 创建数据集 | |||
| export function add(data) { | |||
| return request({ | |||
| url: 'api/data/datasets/medical', | |||
| method: 'post', | |||
| data, | |||
| }); | |||
| } | |||
| // 保存标注 | |||
| export function save(data) { | |||
| return request({ | |||
| url: '/api/data/datasets/medical/annotation/save', | |||
| method: 'post', | |||
| data, | |||
| }); | |||
| } | |||
| // 上传文件 | |||
| export function upload(datasetId, params) { | |||
| return request({ | |||
| url: '/api/data/datasets/medical/files', | |||
| method: 'post', | |||
| data: { | |||
| id: datasetId, | |||
| dataMedicineFileCreateList: params, | |||
| }, | |||
| }); | |||
| } | |||
| export function del(ids) { | |||
| const delData = { ids }; | |||
| return request({ | |||
| url: 'api/data/datasets/medical', | |||
| method: 'delete', | |||
| data: delData, | |||
| }); | |||
| } | |||
| export function editDataset(data) { | |||
| return request({ | |||
| url: `api/data/datasets/medical/${data.medicalId}`, | |||
| method: 'put', | |||
| data, | |||
| }); | |||
| } | |||
| // 导入自定义数据集 | |||
| export function addCustomDataset(data) { | |||
| return request({ | |||
| url: `api/data/datasets/medical/custom`, | |||
| method: 'post', | |||
| data, | |||
| }); | |||
| } | |||
| export function autoAnnotate(id) { | |||
| const data = { medicalId: id }; | |||
| return request({ | |||
| url: 'api/data/datasets/medical/annotation/auto', | |||
| method: 'post', | |||
| data, | |||
| }); | |||
| } | |||
| // 查询数据集状态 | |||
| export function queryDatasetsProgress(params) { | |||
| return request({ | |||
| url: `/api/data/datasets/medical/annotation/schedule`, | |||
| method: 'get', | |||
| params, | |||
| }); | |||
| } | |||
| // 保存病灶信息 | |||
| export function saveLesions(medicalId, data) { | |||
| return request({ | |||
| url: `/api/data/datasets/medical/lesion/${medicalId}`, | |||
| method: 'post', | |||
| data, | |||
| }); | |||
| } | |||
| // 查询病灶信息 | |||
| export function queryLesions(medicalId, params) { | |||
| return request({ | |||
| url: `/api/data/datasets/medical/lesion/${medicalId}`, | |||
| method: 'get', | |||
| params, | |||
| }); | |||
| } | |||
| // 删除病灶信息 | |||
| export function deleteLesion(id) { | |||
| return request({ | |||
| url: `/api/data/datasets/medical/lesion`, | |||
| method: 'delete', | |||
| data: { id }, | |||
| }); | |||
| } | |||
| // 修改病灶信息 | |||
| export function updateLesion(id) { | |||
| return request({ | |||
| url: `/api/data/datasets/medical/lesion`, | |||
| method: 'put', | |||
| data: { id }, | |||
| }); | |||
| } | |||
| export default { list, add, del }; | |||
| @@ -0,0 +1,63 @@ | |||
| /** Copyright 2020 Tianshu AI Platform. All Rights Reserved. | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| * You may obtain a copy of the License at | |||
| * | |||
| * http://www.apache.org/licenses/LICENSE-2.0 | |||
| * | |||
| * Unless required by applicable law or agreed to in writing, software | |||
| * distributed under the License is distributed on an "AS IS" BASIS, | |||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
| * See the License for the specific language governing permissions and | |||
| * limitations under the License. | |||
| * ============================================================= | |||
| */ | |||
| import request from '@/utils/request'; | |||
| export function list(params) { | |||
| const { datasetId } = params; | |||
| return request({ | |||
| url: `api/data/datasets/${datasetId}/files/txt`, | |||
| method: 'get', | |||
| params, | |||
| }); | |||
| } | |||
| export function count(datasetId) { | |||
| return request({ | |||
| url: `/api/data/datasets/${datasetId}/count`, | |||
| }); | |||
| } | |||
| // 获取分页信息 | |||
| export function queryFiles(datasetId, params) { | |||
| return request({ | |||
| url: `/api/data/datasets/${datasetId}/files/txt`, | |||
| params, | |||
| }); | |||
| } | |||
| // 删除文件 | |||
| export function deleteFile(datasetId, fileId) { | |||
| return request({ | |||
| url: `/api/data/datasets/files`, | |||
| method: 'delete', | |||
| data: { | |||
| datasetIds: [Number(datasetId)], | |||
| fileIds: [Number(fileId)], | |||
| }, | |||
| }); | |||
| } | |||
| // 保存 | |||
| export function save(datasetId, fileId, data){ | |||
| return request({ | |||
| url: `/api/data/datasets/files/${datasetId}/${fileId}/annotations/finish`, | |||
| method: 'post', | |||
| data, | |||
| }); | |||
| } | |||
| export default { list }; | |||
| @@ -1,4 +1,4 @@ | |||
| /** Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||
| /** Copyright 2020 Tianshu AI Platform. All Rights Reserved. | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| @@ -1,4 +1,4 @@ | |||
| /** Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||
| /** Copyright 2020 Tianshu AI Platform. All Rights Reserved. | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| @@ -1,4 +1,4 @@ | |||
| /** Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||
| /** Copyright 2020 Tianshu AI Platform. All Rights Reserved. | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| @@ -1,4 +1,4 @@ | |||
| /** Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||
| /** Copyright 2020 Tianshu AI Platform. All Rights Reserved. | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| @@ -1,4 +1,4 @@ | |||
| /** Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||
| /** Copyright 2020 Tianshu AI Platform. All Rights Reserved. | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| @@ -71,4 +71,11 @@ export function editMenu(data) { | |||
| }); | |||
| } | |||
| export function getMenusTree() { | |||
| return request({ | |||
| url: 'api/v1/menus/tree', | |||
| method: 'get', | |||
| }); | |||
| } | |||
| export default { list, add, edit, del, get, editMenu }; | |||
| @@ -1,4 +1,4 @@ | |||
| /** Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||
| /** Copyright 2020 Tianshu AI Platform. All Rights Reserved. | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| @@ -1,4 +1,4 @@ | |||
| /** Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||
| /** Copyright 2020 Tianshu AI Platform. All Rights Reserved. | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| @@ -48,10 +48,27 @@ export function del(ids) { | |||
| }); | |||
| } | |||
| export function imageNameList() { | |||
| export function getImageNameList(params) { | |||
| return request({ | |||
| url: 'api/v1/ptImage/imageNameList', | |||
| method: 'get', | |||
| params, | |||
| }); | |||
| } | |||
| export function getImageTagList(params) { | |||
| return request({ | |||
| url: 'api/v1/ptImage', | |||
| method: 'get', | |||
| params, | |||
| }); | |||
| } | |||
| export function setPrecast(params) { | |||
| return request({ | |||
| url: 'api/v1/ptImage/imageResource', | |||
| method: 'put', | |||
| params, | |||
| }); | |||
| } | |||
| @@ -1,4 +1,4 @@ | |||
| /** Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||
| /** Copyright 2020 Tianshu AI Platform. All Rights Reserved. | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| @@ -116,4 +116,12 @@ export function getPods(jobId) { | |||
| }); | |||
| } | |||
| export function getTrainModel(params) { | |||
| return request({ | |||
| url: `api/v1/trainJob/model`, | |||
| method: 'get', | |||
| params, | |||
| }); | |||
| } | |||
| export default { list, add, edit, del }; | |||
| @@ -1,4 +1,4 @@ | |||
| /** Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||
| /** Copyright 2020 Tianshu AI Platform. All Rights Reserved. | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| @@ -1,4 +1,4 @@ | |||
| /** Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||
| /** Copyright 2020 Tianshu AI Platform. All Rights Reserved. | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| @@ -1,4 +1,4 @@ | |||
| /** Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||
| /** Copyright 2020 Tianshu AI Platform. All Rights Reserved. | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| @@ -1,4 +1,4 @@ | |||
| /** Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||
| /** Copyright 2020 Tianshu AI Platform. All Rights Reserved. | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| @@ -129,10 +129,26 @@ | |||
| padding-bottom: 10px; | |||
| } | |||
| .mt-0 { | |||
| margin-top: 0 !important; | |||
| } | |||
| .mt-50 { | |||
| margin-top: 50px; | |||
| } | |||
| .mt-10 { | |||
| margin-top: 10px; | |||
| } | |||
| .mt-20 { | |||
| margin-top: 20px; | |||
| } | |||
| .ml-4 { | |||
| margin-left: 4px; | |||
| } | |||
| .ml-10 { | |||
| margin-left: 10px; | |||
| } | |||
| @@ -149,6 +165,14 @@ | |||
| margin-left: 16px; | |||
| } | |||
| .ml-40 { | |||
| margin-left: 40px; | |||
| } | |||
| .mb-50 { | |||
| margin-bottom: 50px; | |||
| } | |||
| .mb-20 { | |||
| margin-bottom: 20px; | |||
| } | |||
| @@ -161,10 +185,42 @@ | |||
| margin-bottom: 10px; | |||
| } | |||
| .mx-10 { | |||
| margin-right: 10px; | |||
| margin-left: 10px; | |||
| } | |||
| .my-10 { | |||
| margin-top: 10px; | |||
| margin-bottom: 10px; | |||
| } | |||
| .mx-auto { | |||
| margin-right: auto; | |||
| margin-left: auto; | |||
| } | |||
| .my-auto { | |||
| margin-top: auto; | |||
| margin-bottom: auto; | |||
| } | |||
| .w-150 { | |||
| width: 150px; | |||
| } | |||
| .w-200 { | |||
| width: 200px; | |||
| } | |||
| .lh-1 { | |||
| line-height: 1; | |||
| } | |||
| .bold { | |||
| font-weight: bold; | |||
| } | |||
| img.responsive { | |||
| display: inline-block; | |||
| max-width: 100%; | |||
| @@ -183,6 +239,14 @@ img.responsive { | |||
| cursor: pointer; | |||
| } | |||
| .pen { | |||
| pointer-events: none; | |||
| } | |||
| .pea { | |||
| pointer-events: auto; | |||
| } | |||
| .inlineBlock { | |||
| display: block; | |||
| } | |||
| @@ -202,6 +266,10 @@ img.responsive { | |||
| user-select: none; | |||
| } | |||
| .hidden { | |||
| visibility: hidden; | |||
| } | |||
| .cp { | |||
| cursor: pointer; | |||
| } | |||
| @@ -218,6 +286,10 @@ img.responsive { | |||
| color: $successColor; | |||
| } | |||
| .with-border { | |||
| border-color: $borderColor; | |||
| } | |||
| .g3 { | |||
| color: #333; | |||
| } | |||
| @@ -253,3 +325,12 @@ img.responsive { | |||
| .w100 { | |||
| min-width: 100px; | |||
| } | |||
| .fullBg { | |||
| position: fixed; | |||
| top: 0; | |||
| left: 0; | |||
| z-index: 9; | |||
| width: 100vw; | |||
| height: 100vh; | |||
| } | |||
| @@ -235,3 +235,18 @@ | |||
| margin-top: 20px; | |||
| overflow-y: scroll; | |||
| } | |||
| pre { | |||
| margin: 0; | |||
| font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif; | |||
| font-size: 1em; | |||
| } | |||
| .command-preview { | |||
| min-height: 80px; | |||
| padding: 0 10px; | |||
| line-height: 25px; | |||
| color: rgb(204, 204, 204); | |||
| background: rgb(30, 30, 30); | |||
| border-radius: 5px; | |||
| } | |||
| @@ -62,6 +62,15 @@ | |||
| background-size: contain; | |||
| } | |||
| @mixin checkmark($width, $height, $borderWidth, $borderColor) { | |||
| display: inline-block; | |||
| width: $width; | |||
| height: $height; | |||
| border-right: $borderWidth solid $borderColor; | |||
| border-bottom: $borderWidth solid $borderColor; | |||
| transform: rotate(45deg); | |||
| } | |||
| @mixin triangle($width, $height, $color, $direction) { | |||
| $width: $width/2; | |||
| $color-border-style: $height solid $color; | |||
| @@ -1,4 +1,4 @@ | |||
| /** Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||
| /** Copyright 2020 Tianshu AI Platform. All Rights Reserved. | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| @@ -1,4 +1,4 @@ | |||
| /** Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||
| /** Copyright 2020 Tianshu AI Platform. All Rights Reserved. | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| @@ -1,4 +1,4 @@ | |||
| /** Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||
| /** Copyright 2020 Tianshu AI Platform. All Rights Reserved. | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| @@ -46,6 +46,10 @@ const BaseModal = { | |||
| type: Boolean, | |||
| default: true, | |||
| }, | |||
| showOk: { | |||
| type: Boolean, | |||
| default: true, | |||
| }, | |||
| loading: { | |||
| type: Boolean, | |||
| default: false, | |||
| @@ -100,7 +104,10 @@ const BaseModal = { | |||
| <el-button id="cancel" onClick={this.handleCancel}>{this.cancelText}</el-button> | |||
| ) | |||
| } | |||
| <el-button id="ok" type='primary' disabled={this.disabled} onClick={this.handleOk} loading={this.loading}>{this.okText}</el-button> | |||
| { this.showOk && ( | |||
| <el-button id="ok" type='primary' disabled={this.disabled} onClick={this.handleOk} loading={this.loading}>{this.okText}</el-button> | |||
| ) | |||
| } | |||
| </div> | |||
| ); | |||
| }; | |||
| @@ -1,4 +1,4 @@ | |||
| /** Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||
| /** Copyright 2020 Tianshu AI Platform. All Rights Reserved. | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| @@ -1,4 +1,4 @@ | |||
| /** Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||
| /** Copyright 2020 Tianshu AI Platform. All Rights Reserved. | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| @@ -1,4 +1,4 @@ | |||
| /** Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||
| /** Copyright 2020 Tianshu AI Platform. All Rights Reserved. | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| @@ -1,4 +1,4 @@ | |||
| /** Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||
| /** Copyright 2020 Tianshu AI Platform. All Rights Reserved. | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| @@ -20,7 +20,7 @@ | |||
| <span :class="{primary: filtered}">{{ title }}</span> | |||
| <i class="el-icon-arrow-down el-icon--right" /> | |||
| </div> | |||
| <el-dropdown-menu slot="dropdown"> | |||
| <el-dropdown-menu slot="dropdown" :style="dropdownStyle"> | |||
| <el-dropdown-item | |||
| v-for="(item, index) in list" | |||
| :key="index" | |||
| @@ -56,6 +56,11 @@ export default { | |||
| type: Boolean, | |||
| default: false, | |||
| }, | |||
| // 下拉框样式可配置 | |||
| dropdownStyle: { | |||
| type: String, | |||
| default: "", | |||
| }, | |||
| }, | |||
| setup(props, ctx) { | |||
| const onCommand = (value) => { | |||
| @@ -1,4 +1,4 @@ | |||
| /** Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||
| /** Copyright 2020 Tianshu AI Platform. All Rights Reserved. | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| @@ -1,4 +1,4 @@ | |||
| /** Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||
| /** Copyright 2020 Tianshu AI Platform. All Rights Reserved. | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| @@ -1,4 +1,4 @@ | |||
| /** Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||
| /** Copyright 2020 Tianshu AI Platform. All Rights Reserved. | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| @@ -1,4 +1,4 @@ | |||
| /** Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||
| /** Copyright 2020 Tianshu AI Platform. All Rights Reserved. | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| @@ -26,7 +26,7 @@ | |||
| import create from './iconfont'; | |||
| const IconFont = create({ | |||
| scriptUrl: '//at.alicdn.com/t/font_1756495_k4j524i5vng.js', | |||
| scriptUrl: '//at.alicdn.com/t/font_1756495_6jl45md8krp.js', | |||
| extraIconProps: { class: 'svg-icon' }, | |||
| }); | |||
| @@ -1,4 +1,4 @@ | |||
| /** Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||
| /** Copyright 2020 Tianshu AI Platform. All Rights Reserved. | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| @@ -1,4 +1,4 @@ | |||
| /** Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||
| /** Copyright 2020 Tianshu AI Platform. All Rights Reserved. | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| @@ -1,4 +1,4 @@ | |||
| /** Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||
| /** Copyright 2020 Tianshu AI Platform. All Rights Reserved. | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| @@ -1,4 +1,4 @@ | |||
| /** Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||
| /** Copyright 2020 Tianshu AI Platform. All Rights Reserved. | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| @@ -1,4 +1,4 @@ | |||
| /** Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||
| /** Copyright 2020 Tianshu AI Platform. All Rights Reserved. | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| @@ -1,4 +1,4 @@ | |||
| /** Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||
| /** Copyright 2020 Tianshu AI Platform. All Rights Reserved. | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| @@ -1,4 +1,4 @@ | |||
| /** Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||
| /** Copyright 2020 Tianshu AI Platform. All Rights Reserved. | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| @@ -34,6 +34,7 @@ | |||
| </el-table> | |||
| <el-pagination | |||
| v-if="showPagination" | |||
| :style="`text-align:${align};margin-top: 8px;`" | |||
| layout="total, prev, pager, next, sizes" | |||
| v-bind="pageAttrs" | |||
| @@ -78,6 +79,11 @@ export default { | |||
| type: String, | |||
| default: 'center', | |||
| }, | |||
| showPagination: { | |||
| type: Boolean, | |||
| default: true, | |||
| }, | |||
| dataSource: Array, | |||
| actionRef: Function, | |||
| }, | |||
| setup(props) { | |||
| @@ -129,7 +135,6 @@ export default { | |||
| }); | |||
| }; | |||
| // 根据数据集 id 查询版本列表 | |||
| const queryList = async(cfg = {}) => { | |||
| if (state.loading) { | |||
| return; | |||
| @@ -153,11 +158,17 @@ export default { | |||
| }; | |||
| onMounted(() => { | |||
| queryList(); | |||
| if (typeof actionRef === 'function') { | |||
| actionRef().value = { | |||
| refresh: queryList, | |||
| }; | |||
| // 首先判断是否为异步请求 | |||
| if(typeof request === 'function') { | |||
| queryList(); | |||
| if (typeof actionRef === 'function') { | |||
| actionRef().value = { | |||
| refresh: queryList, | |||
| }; | |||
| } | |||
| } else if(Array.isArray(props.dataSource)) { | |||
| // 检测是否为静态数据源 | |||
| setData(props.dataSource); | |||
| } | |||
| }); | |||
| @@ -168,6 +179,12 @@ export default { | |||
| lazy: true, | |||
| }); | |||
| watch(() => props.dataSource, (next) => { | |||
| setData(next); | |||
| }, { | |||
| lazy: true, | |||
| }); | |||
| watch(() => pageInfo.current, () => { | |||
| queryList(); | |||
| }, { | |||
| @@ -1,4 +1,4 @@ | |||
| /** Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||
| /** Copyright 2020 Tianshu AI Platform. All Rights Reserved. | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| @@ -36,7 +36,7 @@ | |||
| <p class="error-message" style="margin-top: 4px;">{{ errors[0] }}</p> | |||
| </ValidationProvider> | |||
| <div class="tc" style="margin-top: 8px;"> | |||
| <el-button type="text" @click="handleCancel">取消</el-button> | |||
| <el-button @click="handleCancel">取消</el-button> | |||
| <el-button type="primary" @click="handleOk">确定</el-button> | |||
| </div> | |||
| <i slot="reference" class="el-icon-edit primary cp dib" /> | |||
| @@ -97,7 +97,10 @@ export default { | |||
| if (!success) { | |||
| return; | |||
| } | |||
| ctx.emit('handleOk', state.value, props.row); | |||
| // 判断是否发生过变更 | |||
| if(String(state.value) !== String(props.row[valueBy])) { | |||
| ctx.emit('handleOk', state.value, props.row); | |||
| } | |||
| handleCancel(); | |||
| }); | |||
| }; | |||
| @@ -1,4 +1,4 @@ | |||
| /** Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||
| /** Copyright 2020 Tianshu AI Platform. All Rights Reserved. | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| @@ -54,6 +54,10 @@ export default { | |||
| type: String, | |||
| default: '', | |||
| }, | |||
| disabled: { | |||
| type: Boolean, | |||
| default: false, | |||
| }, | |||
| }, | |||
| data() { | |||
| return { | |||
| @@ -66,7 +70,7 @@ export default { | |||
| }, | |||
| computed: { | |||
| getLogDisabled() { | |||
| return this.logLoading || this.noMoreLog; | |||
| return this.logLoading || this.noMoreLog || this.disabled; | |||
| }, | |||
| logTxt() { | |||
| return `${this.showMsg ? `${this.msg}\n` : ''}${this.logList.join('\n')}`; | |||
| @@ -0,0 +1,364 @@ | |||
| /** Copyright 2020 Tianshu AI Platform. All Rights Reserved. | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| * You may obtain a copy of the License at | |||
| * | |||
| * http://www.apache.org/licenses/LICENSE-2.0 | |||
| * | |||
| * Unless required by applicable law or agreed to in writing, software | |||
| * distributed under the License is distributed on an "AS IS" BASIS, | |||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
| * See the License for the specific language governing permissions and | |||
| * limitations under the License. | |||
| * ============================================================= | |||
| */ | |||
| <template> | |||
| <div class="rel pod-log-container-inside"> | |||
| <div | |||
| v-if="showFunctional" | |||
| > | |||
| <el-tooltip effect="dark" content="日志置顶" placement="left"> | |||
| <el-button | |||
| class="log-left-btn" | |||
| icon="el-icon-caret-top" | |||
| @click="onToTop" | |||
| /> | |||
| </el-tooltip> | |||
| <el-tooltip effect="dark" content="日志置底" placement="left"> | |||
| <el-button | |||
| class="log-left-btn" | |||
| icon="el-icon-caret-bottom" | |||
| @click="onToBottom" | |||
| /> | |||
| </el-tooltip> | |||
| <el-tooltip effect="dark" content="自动跟随" placement="left"> | |||
| <el-button | |||
| :type="autoFollow ? 'primary' : ''" | |||
| icon="el-icon-download" | |||
| class="log-left-btn" | |||
| @click="changeAutoFollow" | |||
| /> | |||
| </el-tooltip> | |||
| <el-tooltip effect="dark" content="清空日志" placement="left"> | |||
| <el-button | |||
| icon="el-icon-delete" | |||
| class="log-left-btn" | |||
| @click="onClearLogs" | |||
| /> | |||
| </el-tooltip> | |||
| </div> | |||
| <div | |||
| ref="logContent" | |||
| v-mouse-wheel="params" | |||
| class="log-content" | |||
| > | |||
| <prism-render :code="logTxt" /> | |||
| </div> | |||
| </div> | |||
| </template> | |||
| <script> | |||
| // eslint-disable-next-line import/no-extraneous-dependencies | |||
| import { throttle } from 'throttle-debounce'; | |||
| import PrismRender from '@/components/Prism'; | |||
| import { getPodLog, countPodLogs } from '@/api/system/pod'; | |||
| /** | |||
| * TODO: 二期需求 | |||
| * 是否可以增加另一个定速向下滚动功能? | |||
| */ | |||
| export default { | |||
| name: 'PodLogContainer', | |||
| components: { | |||
| PrismRender, | |||
| }, | |||
| props: { | |||
| // 包含podName的pod对象, 用于请求日志总行数 | |||
| podName: { | |||
| type: String, | |||
| required: true, | |||
| }, | |||
| // 查询日志需要用到的其他参数 | |||
| options: { | |||
| type: Object, | |||
| default: () => ({}), | |||
| }, | |||
| // 手动查询时日志请求行数 | |||
| logLines: { | |||
| type: Number, | |||
| default: 50, | |||
| }, | |||
| // 限制pod日志行数 | |||
| lineLimit: { | |||
| type: Number, | |||
| default: 200, | |||
| }, | |||
| // 顶部展示特定信息 | |||
| showMsg: { | |||
| type: Boolean, | |||
| default: false, | |||
| }, | |||
| msg: { | |||
| type: String, | |||
| default: '', | |||
| }, | |||
| disabled: { | |||
| type: Boolean, | |||
| default: false, | |||
| }, | |||
| // 是否展示一键到底等功能区按钮 | |||
| showFunctional: { | |||
| type: Boolean, | |||
| default: true, | |||
| }, | |||
| }, | |||
| data() { | |||
| return { | |||
| logList: [], | |||
| logTopLine: 0, // 当前日志数组第一行的行号 | |||
| logBottomLine: 0, // 当前日志数组最后一行的行号 | |||
| autoFollow: false, // 自动跟随 | |||
| topWarning: true, // 向上滚动请求时,如果已经到顶了,会提示一次日志到顶;每次请求日志时刷新 | |||
| }; | |||
| }, | |||
| computed: { | |||
| params() { | |||
| return {up: throttle(1000, this.mouseUp), down: throttle(1000, this.mouseDown)}; | |||
| }, | |||
| // 传入的 msg 信息会展示在所有日志的最前面 | |||
| logTxt() { | |||
| return `${this.showMsg ? `${this.msg}\n` : ''}${this.logList.join('\n')}`; | |||
| }, | |||
| // 确保存放日志的数组上限至少为两倍日志请求行数。 | |||
| localLineLimit() { | |||
| return this.lineLimit >= this.logLines * 2 ? this.lineLimit : this.logLines * 2; | |||
| }, | |||
| }, | |||
| mounted() { | |||
| this.$refs.logContent.addEventListener('mousewheel', this.watchScroll, false); | |||
| this.$once('hook:beforeDestroy', () => { | |||
| this.$refs.logContent.removeEventListener('mousewheel', this.watchScroll, false); | |||
| this.autoFollow = false; | |||
| }); | |||
| this.mouseDownThrottle = throttle(1000, this.mouseDown); | |||
| this.mouseUpThrottle = throttle(1000, this.mouseUp); | |||
| }, | |||
| methods: { | |||
| getLog(startLine, lines) { | |||
| if (!this.podName) { | |||
| this.message('没有传入 podName, 无法查询日志'); | |||
| return; | |||
| } | |||
| startLine = startLine || 1; | |||
| lines = lines || this.logLines; | |||
| this.topWarning = true; | |||
| return getPodLog({ | |||
| podName: this.podName, | |||
| startLine, | |||
| lines, | |||
| ...this.options, | |||
| }); | |||
| }, | |||
| // 滚轮向上滚动到顶部时的事件 | |||
| async mouseUp() { | |||
| // 如果已处于第一行或没有日志, 不向上请求 | |||
| if (this.logTopLine <= 1) { | |||
| // 只进行一次到达顶部提示;任意请求日志后刷新 | |||
| if (this.topWarning) { | |||
| this.topWarning = false; | |||
| if(!this.logMsgInstance) { | |||
| this.message('已经到达日志顶部.'); | |||
| } | |||
| } | |||
| return; | |||
| } | |||
| // 如果此时元素已不存在,则不进行任何其他操作 | |||
| if (!this.$refs.logContent) { return; } | |||
| // 向上滚动时,起始行为 logTopLine 减去请求行数 | |||
| let reqStartLine = this.logTopLine - this.logLines; | |||
| reqStartLine = Math.max(reqStartLine, 1); | |||
| // 请求前日志区高度 | |||
| const beforeHeight = this.$refs.logContent.scrollHeight; | |||
| const { content, startLine: resStartLine } = await this.getLog(reqStartLine, this.logTopLine - reqStartLine); | |||
| this.logList = content.concat(this.logList); | |||
| this.$nextTick(() => { | |||
| // 如果此时元素已不存在,则不进行任何其他操作 | |||
| if (!this.$refs.logContent) { return; } | |||
| // 请求后日志区高度,从而设置顶部高度差 | |||
| const afterHeight = this.$refs.logContent.scrollHeight; | |||
| this.$refs.logContent.scrollTop = afterHeight - beforeHeight; | |||
| // 限制总行数为 localLineLimit | |||
| if(this.logList.length > this.localLineLimit) { | |||
| this.logList.splice(this.localLineLimit); | |||
| } | |||
| this.logTopLine = resStartLine; // 向下滚动时, 返回的 startLine 就是第一行的行号 | |||
| this.logBottomLine = this.logTopLine + this.logList.length - 1; // 此时最后一行的行号需要通过 logList 的长度进行计算 | |||
| }); | |||
| }, | |||
| // 滚轮向上滚动到底部时的事件 | |||
| async mouseDown(disableWarning) { | |||
| // 如果此时元素已不存在,则不进行任何其他操作 | |||
| if (!this.$refs.logContent) { return; } | |||
| // 请求前日志区顶部高度 | |||
| const beforeTop = this.$refs.logContent.scrollTop; | |||
| const { content, endLine, lines } = await this.getLog(this.logBottomLine + 1); | |||
| this.logList = this.logList.concat(content); | |||
| this.$nextTick(() => { | |||
| // 如果此时元素已不存在,则不进行任何其他操作 | |||
| if (!this.$refs.logContent) { return; } | |||
| // 请求后日志区高度 | |||
| const afterReqHeight = this.$refs.logContent.scrollHeight; | |||
| // 限制总行数为 localLineLimit | |||
| if(this.logList.length > this.localLineLimit) { | |||
| this.logList.splice(0, this.logList.length - this.localLineLimit); | |||
| } | |||
| this.$nextTick(() => { | |||
| // 如果此时元素已不存在,则不进行任何其他操作 | |||
| if (!this.$refs.logContent) { return; } | |||
| // 剪切后日志区高度,计算高度变化差,设置去掉高度差后的 scrollTop | |||
| const afterSpliceHeight = this.$refs.logContent.scrollHeight; | |||
| this.$refs.logContent.scrollTop = Math.max(0, beforeTop - (afterReqHeight - afterSpliceHeight)); | |||
| this.logBottomLine = endLine; // 向下滚动时, 返回的 endLine 就是最后一行的行号 | |||
| this.logTopLine = this.logBottomLine - this.logList.length + 1; // 此时第一行的行号需要通过 logList 的长度进行计算 | |||
| if (lines < 3 && !this.logMsgInstance && !this.autoFollow && disableWarning !== true) { | |||
| this.message('已经到达日志底部.'); | |||
| } | |||
| }); | |||
| }); | |||
| }, | |||
| // 重置日志组件 | |||
| reset() { | |||
| this.autoFollow = false; | |||
| this.logList = []; | |||
| this.logTopLine = this.logBottomLine = 0; | |||
| this.$nextTick(() => { | |||
| this.mouseDown(true); | |||
| }); | |||
| }, | |||
| message(message) { | |||
| this.logMsgInstance = this.$message.warning({ | |||
| message, | |||
| onClose: this.onLogMsgClose, | |||
| }); | |||
| }, | |||
| onLogMsgClose() { | |||
| this.logMsgInstance = null; | |||
| }, | |||
| // 一键到顶 | |||
| onToTop() { | |||
| this.reset(); | |||
| }, | |||
| // 自动跟随切换 | |||
| async changeAutoFollow(autoFollow) { | |||
| if (typeof autoFollow === 'boolean') { | |||
| this.autoFollow = autoFollow; | |||
| } else { | |||
| this.autoFollow = !this.autoFollow; | |||
| } | |||
| if (this.autoFollow) { | |||
| await this.onToBottom(); | |||
| setTimeout(this.logPolling, 1000); | |||
| } | |||
| }, | |||
| // 清空当前日志内容 | |||
| async onClearLogs() { | |||
| await this.changeAutoFollow(true); | |||
| // 开启自动跟随请求最底部日志之后,清空当前日志列表 | |||
| this.logList = []; | |||
| this.logTopLine = this.logBottomLine; | |||
| }, | |||
| // 一键到底 | |||
| async onToBottom(event) { | |||
| // 在跟随状态下点击一键到底,则停止跟随 | |||
| if (this.autoFollow && event !== undefined) { | |||
| this.autoFollow = false; | |||
| return; | |||
| } | |||
| this.logList = []; | |||
| const countObj = await countPodLogs([{ podName: this.podName }]); // 获取对应pod日志总行数 | |||
| const linesCount = countObj[this.podName]; | |||
| // 请求最后的 logLines 行 | |||
| this.logBottomLine = Math.max(linesCount - this.logLines, 0); | |||
| await this.mouseDown(); | |||
| // 将进度条拉到底部 | |||
| this.$nextTick(() => { | |||
| // 如果此时元素已不存在,则不进行任何其他操作 | |||
| if (!this.$refs.logContent) { return; } | |||
| this.$refs.logContent.scrollTop = this.$refs.logContent.scrollHeight; | |||
| }); | |||
| }, | |||
| async logPolling() { | |||
| if (!this.autoFollow) { return; } | |||
| await this.mouseDownThrottle(); | |||
| // 将进度条拉到底部 | |||
| this.$nextTick(() => { | |||
| // 如果此时元素已不存在,则不进行任何其他操作 | |||
| if (!this.$refs.logContent) { return; } | |||
| this.$refs.logContent.scrollTop = this.$refs.logContent.scrollHeight; | |||
| }); | |||
| setTimeout(this.logPolling, 1000); | |||
| }, | |||
| // 判断在自动跟随滚轮是否向上 | |||
| watchScroll(event) { | |||
| if (event.deltaY < 0) { | |||
| this.autoFollow = false; | |||
| } | |||
| }, | |||
| }, | |||
| }; | |||
| </script> | |||
| <style lang="scss" scoped> | |||
| .pod-log-container-inside { | |||
| display: grid; | |||
| grid-template-columns: 30px 1fr; | |||
| } | |||
| .log-left-btn { | |||
| padding: 5px; | |||
| margin: 0 0 10px; | |||
| } | |||
| .log-content { | |||
| height: 100%; | |||
| overflow: auto; | |||
| border: #ccc solid 1px; | |||
| } | |||
| </style> | |||
| @@ -1,4 +1,4 @@ | |||
| /** Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||
| /** Copyright 2020 Tianshu AI Platform. All Rights Reserved. | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| @@ -1,4 +1,4 @@ | |||
| /** Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||
| /** Copyright 2020 Tianshu AI Platform. All Rights Reserved. | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| @@ -47,6 +47,7 @@ export default { | |||
| code[class*="language-"], | |||
| pre[class*="language-"] { | |||
| word-wrap: break-word; | |||
| white-space: pre-wrap; | |||
| } | |||
| </style> | |||
| @@ -1,4 +1,4 @@ | |||
| /** Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||
| /** Copyright 2020 Tianshu AI Platform. All Rights Reserved. | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| @@ -1,4 +1,4 @@ | |||
| /** Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||
| /** Copyright 2020 Tianshu AI Platform. All Rights Reserved. | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| @@ -89,7 +89,7 @@ | |||
| </el-option> | |||
| </el-select> | |||
| <div class="tc" style="margin-top: 8px;"> | |||
| <el-button type="text" @click="handleCancel">取消</el-button> | |||
| <el-button @click="handleCancel">取消</el-button> | |||
| <el-button type="primary" @click="handleOk">确定</el-button> | |||
| </div> | |||
| <i slot="reference" class="el-icon-edit primary cp dib" /> | |||
| @@ -1,4 +1,4 @@ | |||
| /** Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||
| /** Copyright 2020 Tianshu AI Platform. All Rights Reserved. | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| @@ -1,4 +1,4 @@ | |||
| /** Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||
| /** Copyright 2020 Tianshu AI Platform. All Rights Reserved. | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| @@ -45,7 +45,6 @@ | |||
| id="algorithm_tab_0" | |||
| :label="1" | |||
| border | |||
| class="mr-0" | |||
| >我的算法</el-radio> | |||
| <el-radio | |||
| id="algorithm_tab_1" | |||
| @@ -106,49 +105,103 @@ | |||
| <el-option | |||
| v-for="(item, index) in harborImageList" | |||
| :key="index" | |||
| :label="item" | |||
| :value="item" | |||
| :label="item.imageTag" | |||
| :value="item.imageTag" | |||
| /> | |||
| </el-select> | |||
| </el-form-item> | |||
| <el-form-item label="加载模型"> | |||
| <el-switch v-model="form.modelType" :active-value="1" :inactive-value="0" @change="onModelTypeChange"/> | |||
| <el-switch | |||
| v-model="useModel" | |||
| @change="onUseModelChange" | |||
| /> | |||
| </el-form-item> | |||
| <el-form-item v-if="form.modelType" label="选用模型类型"> | |||
| <el-form-item v-if="useModel" label="选用模型类型"> | |||
| <el-radio-group v-model="form.modelResource" @change="onModelResourceChange"> | |||
| <el-radio :label="0" border class="mr-0">我的模型</el-radio> | |||
| <el-radio :label="0" border>我的模型</el-radio> | |||
| <el-radio :label="1" border>预训练模型</el-radio> | |||
| <el-radio :label="2" border>炼知模型</el-radio> | |||
| </el-radio-group> | |||
| </el-form-item> | |||
| <el-form-item v-if="form.modelType" label="模型选择"> | |||
| <el-form-item | |||
| v-if="[0, 1].includes(form.modelResource)" | |||
| key="modelSelect" | |||
| label="模型选择" | |||
| class="is-required" | |||
| :error="modelSelectionErrorMsg" | |||
| > | |||
| <el-select | |||
| id="modelId" | |||
| v-model="form.modelId" | |||
| placeholder="请选择模型" | |||
| style="width: 190px;" | |||
| clearable | |||
| @change="getModelNames" | |||
| @change="onModelChange" | |||
| > | |||
| <el-option | |||
| v-for="item in modelNameList" | |||
| v-for="item in modelList" | |||
| :key="item.id" | |||
| :label="item.name" | |||
| :value="item.id" | |||
| /> | |||
| </el-select> | |||
| <el-select | |||
| v-if="!form.modelResource" | |||
| id="modelLoadPathDir" | |||
| v-model="form.modelLoadPathDir" | |||
| v-if="useMineModel" | |||
| id="modelBranchId" | |||
| v-model="form.modelBranchId" | |||
| placeholder="请选择模型版本" | |||
| style="width: 305px;" | |||
| clearable | |||
| @change="onModelBranchChange" | |||
| > | |||
| <el-option | |||
| v-for="item in modelLoadPathList" | |||
| v-for="item in modelBranchList" | |||
| :key="item.id" | |||
| :label="item.versionNum" | |||
| :value="item.modelAddress" | |||
| :value="item.id" | |||
| /> | |||
| </el-select> | |||
| <el-tooltip effect="dark" content="模型路径通过 model_load_dir 传到算法内部" placement="top"> | |||
| <i class="el-icon-warning-outline primary f18 v-text-top" /> | |||
| </el-tooltip> | |||
| </el-form-item> | |||
| <el-form-item | |||
| v-if="useAtlasModel" | |||
| key="teacherModel" | |||
| label="教师模型" | |||
| class="is-required" | |||
| :error="teacherModelErrorMsg" | |||
| > | |||
| <el-select | |||
| v-model="teacherModelIds" | |||
| multiple | |||
| clearable | |||
| placeholder="请选择教师模型" | |||
| @change="onTeacherModelChange" | |||
| > | |||
| <el-option | |||
| v-for="model in modelList" | |||
| :key="model.id" | |||
| :label="model.name" | |||
| :value="model.id" | |||
| /> | |||
| </el-select> | |||
| </el-form-item> | |||
| <el-form-item | |||
| v-if="useAtlasModel" | |||
| label="学生模型" | |||
| > | |||
| <el-select | |||
| v-model="studentModelIds" | |||
| multiple | |||
| clearable | |||
| placeholder="请选择学生模型" | |||
| > | |||
| <el-option | |||
| v-for="model in modelList" | |||
| :key="model.id" | |||
| :label="model.name" | |||
| :value="model.id" | |||
| /> | |||
| </el-select> | |||
| </el-form-item> | |||
| @@ -239,7 +292,6 @@ | |||
| id="resourcesPoolType_tab_0" | |||
| :label="0" | |||
| border | |||
| class="mr-0" | |||
| >CPU</el-radio> | |||
| <el-radio | |||
| id="resourcesPoolType_tab_1" | |||
| @@ -303,7 +355,7 @@ | |||
| </el-tooltip> | |||
| </el-form-item> | |||
| <el-form-item label="运行命令预览" prop="preview"> | |||
| <div class="param"> | |||
| <div class="command-preview"> | |||
| {{ preview }} | |||
| </div> | |||
| </el-form-item> | |||
| @@ -319,8 +371,23 @@ | |||
| <el-form-item label="镜像选择"> | |||
| {{ form.imageName }} | |||
| </el-form-item> | |||
| <el-form-item label="模型选择"> | |||
| {{ form.modelName }} | |||
| <el-form-item | |||
| v-if="[0, 1].includes(form.modelResource)" | |||
| label="模型选择" | |||
| > | |||
| {{ trainModel.name }} | |||
| </el-form-item> | |||
| <el-form-item | |||
| v-if="useAtlasModel" | |||
| label="教师模型" | |||
| > | |||
| {{ teacherModelNames }} | |||
| </el-form-item> | |||
| <el-form-item | |||
| v-if="useAtlasModel" | |||
| label="学生模型" | |||
| > | |||
| {{ studentModelNames }} | |||
| </el-form-item> | |||
| <el-form-item label="训练数据集"> | |||
| {{ form.dataSourceName }} | |||
| @@ -359,7 +426,7 @@ | |||
| {{ formSpecs && formSpecs.label }} | |||
| </el-form-item> | |||
| <el-form-item label="运行命令预览"> | |||
| <div class="param"> | |||
| <div class="command-preview"> | |||
| {{ preview }} | |||
| </div> | |||
| </el-form-item> | |||
| @@ -369,15 +436,25 @@ | |||
| </template> | |||
| <script> | |||
| import { validateNameWithHyphen } from '@/utils'; | |||
| import { validateNameWithHyphen, getQueueMessage } from '@/utils'; | |||
| import { list as getAlgorithmList } from '@/api/algorithm/algorithm'; | |||
| import { harborProjectNames, harborImageNames } from '@/api/system/harbor'; | |||
| import { list as getModelName } from '@/api/model/model'; | |||
| import { list as getModelTag } from '@/api/model/modelVersion'; | |||
| import { getModelByResource } from '@/api/model/model'; | |||
| import { list as getModelBranchs } from '@/api/model/modelVersion'; | |||
| import { getTrainModel } from '@/api/trainingJob/job'; | |||
| import { getImageNameList, getImageTagList } from '@/api/trainingImage/index'; | |||
| import { trainConfig } from '@/config'; | |||
| import { IMAGE_PROJECT_TYPE } from '@/views/trainingJob/utils'; | |||
| import RunParamForm from './runParamForm'; | |||
| import DataSourceSelector from './dataSourceSelector'; | |||
| /** | |||
| * 添加一个新的字段时,需要考虑修改如下代码: | |||
| * defaultForm: 默认表单 | |||
| * initForm(): 表单初始化方法 | |||
| * save(): 表单验证及提交方法 | |||
| * reset(): 重置表单方法 | |||
| */ | |||
| const defaultForm = { | |||
| id: null, // 用于编辑训练任务时, 表单传递 jobId | |||
| trainName: '', | |||
| @@ -407,11 +484,12 @@ const defaultForm = { | |||
| // 延迟启停相关参数 | |||
| delayCreateTime: 0, | |||
| delayDeleteTime: 0, | |||
| modelType: 0, | |||
| modelResource: 0, | |||
| // 模型相关参数 | |||
| modelResource: null, | |||
| teacherModelIds: null, | |||
| studentModelIds: null, | |||
| modelId: null, | |||
| modelLoadPathDir: null, | |||
| modelName: null, | |||
| modelBranchId: null, | |||
| }; | |||
| export default { | |||
| @@ -433,8 +511,8 @@ export default { | |||
| algorithmIdList: [], | |||
| harborProjectList: [], | |||
| harborImageList: [], | |||
| modelNameList: [], | |||
| modelLoadPathList: [], | |||
| modelList: [], | |||
| modelBranchList: [], | |||
| noMoreLoadAlg: false, | |||
| algLoading: false, | |||
| currentAlgPage: 1, | |||
| @@ -445,6 +523,16 @@ export default { | |||
| selectedAlgorithm: null, | |||
| trainConfig, | |||
| useModel: false, // 本地判断是否使用模型 | |||
| teacherModelIds: [], | |||
| studentModelIds: [], | |||
| modelSelectionErrorMsg: '', // 模型选择错误信息 | |||
| teacherModelErrorMsg: '', // 教师模型错误信息 | |||
| trainModelList: [], | |||
| teacherModelList: [], | |||
| studentModelList: [], | |||
| form: { ...defaultForm }, | |||
| rules: { | |||
| trainName: [ | |||
| @@ -492,6 +580,9 @@ export default { | |||
| return []; | |||
| } | |||
| }, | |||
| isSaveParams() { | |||
| return this.type === 'saveParams'; | |||
| }, | |||
| preview() { | |||
| let str = this.form.runCommand; | |||
| for(const key of Object.keys(this.runParamObj)) { | |||
| @@ -504,42 +595,79 @@ export default { | |||
| str += ' --data_url=/dataset'; | |||
| } | |||
| str += this.form.valDataSourceName && this.form.valDataSourcePath ? ' --val_data_url=/valdataset' : ''; | |||
| str += this.form.modelId && this.form.modelLoadPathDir ? ' --model_load_dir=/modeldir' : ''; | |||
| str += this.form.modelId && this.form.modelBranchId ? ' --model_load_dir=/modeldir' : ''; | |||
| if (this.form.resourcesPoolType) { | |||
| // eslint-disable-next-line no-template-curly-in-string | |||
| str += ' --gpu_num_per_node=${gpu_num}'; | |||
| } | |||
| return str; | |||
| }, | |||
| useMineModel() { | |||
| return this.form.modelResource === 0; | |||
| }, | |||
| useAtlasModel() { | |||
| return this.form.modelResource === 2; | |||
| }, | |||
| trainModel() { | |||
| return this.trainModelList.length ? this.trainModelList[0] : {}; | |||
| }, | |||
| teacherModelNames() { | |||
| return this.teacherModelList.map(model => model.name).join(', '); | |||
| }, | |||
| studentModelNames() { | |||
| return this.studentModelList.map(model => model.name).join(', '); | |||
| }, | |||
| }, | |||
| mounted() { | |||
| this.$on('dictReady', () => { this.dictReady = true; }); | |||
| created() { | |||
| this.$on('dictReady', this.getInitResourceSpecs); | |||
| this.callMsg = getQueueMessage(); | |||
| }, | |||
| methods: { | |||
| initForm(form) { | |||
| const newForm = form || {}; | |||
| Object.keys(this.form).forEach(item => { newForm[item] && (this.form[item] = newForm[item]); }); | |||
| setTimeout(() => { | |||
| Object.keys(this.form).forEach(item => { | |||
| if (newForm[item] !== null && newForm[item] !== undefined) { | |||
| this.form[item] = newForm[item]; | |||
| } | |||
| }); | |||
| setTimeout(async () => { | |||
| this.delayCreateDelete = (this.form.delayCreateTime !== 0) && (this.form.delayDeleteTime !== 0); | |||
| this.getAlgorithmList(); | |||
| if (this.type !== 'saveParams') { | |||
| if (!this.isSaveParams) { | |||
| this.getHarborProjects().then(() => { | |||
| this.resetProject(); | |||
| }); | |||
| this.getModelNames(false); | |||
| this.getModels(true); | |||
| this.$refs.trainDataSourceSelector.updateAlgorithmUsage(this.form.algorithmUsage, true); | |||
| this.form.valType && this.$refs.verifyDataSourceSelector.updateAlgorithmUsage(this.form.valAlgorithmUsage, true); | |||
| } else if (this.form.modelResource !== null) { | |||
| const { modelList, teacherModelList, studentModelList } = await getTrainModel({ | |||
| modelResource: this.form.modelResource, | |||
| modelId: this.form.modelId || undefined, | |||
| modelBranchId: this.form.modelBranchId || undefined, | |||
| teacherModelIds: this.form.teacherModelIds || undefined, | |||
| studentModelIds: this.form.studentModelIds || undefined, | |||
| }); | |||
| this.trainModelList = modelList; | |||
| this.teacherModelList = teacherModelList; | |||
| this.studentModelList = studentModelList; | |||
| } | |||
| if (this.dictReady) { | |||
| this.onResourcesPoolTypeChange((this.type !== 'add') && (this.type !== 'algoAdd')); | |||
| } else { | |||
| this.$on('dictReady', () => this.onResourcesPoolTypeChange((this.type !== 'add') && (this.type !== 'algoAdd'))); | |||
| } | |||
| this.getInitResourceSpecs(); | |||
| // 根据 modelResource 的值来判断是否使用了模型 | |||
| this.useModel = this.form.modelResource !== null; | |||
| // runParamObj 初始值为 form.runParams | |||
| this.runParamObj = {...this.form.runParams} || {}; | |||
| this.runParamObj = {...this.form.runParams}; | |||
| this.clearValidate(); | |||
| }, 0); | |||
| }, | |||
| getInitResourceSpecs() { | |||
| if (!this.dictOrFormReady) { | |||
| this.dictOrFormReady = true; | |||
| return; | |||
| } | |||
| this.onResourcesPoolTypeChange(!['add', 'algoAdd'].includes(this.type)); | |||
| }, | |||
| validate(...args) { | |||
| this.$refs.form.validate.apply(this, args); | |||
| }, | |||
| @@ -560,32 +688,43 @@ export default { | |||
| return; | |||
| } | |||
| // 先将字符串模式转换为键值对模式 | |||
| if (this.type !== 'saveParams' && this.$refs.runParamComp.paramsMode === 2) { | |||
| if (!this.isSaveParams && this.$refs.runParamComp.paramsMode === 2) { | |||
| this.$refs.runParamComp.convertArgsToPairs(); | |||
| } | |||
| const runParamsValid = this.type === 'saveParams' || this.$refs.runParamComp.validate(); | |||
| if (runParamsValid) { | |||
| this.$refs.form.validate(async valid => { | |||
| if (valid) { | |||
| const params = {...this.form}; | |||
| params.runParams = {...this.runParamObj}; | |||
| params.trainJobSpecsInfo = this.formSpecs.value; | |||
| delete params.modelName; // modelName只用来展示,不作为提交参数 | |||
| // 请求交互都不放在组件完成 | |||
| this.$emit('getForm', params); | |||
| } else { | |||
| this.$message({ | |||
| message: '请仔细检查任务参数', | |||
| type: 'warning', | |||
| }); | |||
| } | |||
| }); | |||
| } else { | |||
| // 保存训练参数时,不对 runParams 进行校验 | |||
| const runParamsValid = this.isSaveParams || this.$refs.runParamComp.validate(); | |||
| if (!runParamsValid) { | |||
| this.$message({ | |||
| message: '运行参数不合法', | |||
| type: 'warning', | |||
| }); | |||
| return; | |||
| } | |||
| if (!this.isSaveParams && !this.checkModelValid()) { return; }; | |||
| // 清除模型部分多余字段 | |||
| if (!this.useAtlasModel) { | |||
| Object.assign(this.form, { | |||
| teacherModelIds: null, | |||
| studentModelIds: null, | |||
| }); | |||
| } | |||
| this.$refs.form.validate(async valid => { | |||
| if (valid) { | |||
| const params = {...this.form}; | |||
| params.runParams = {...this.runParamObj}; | |||
| params.trainJobSpecsInfo = this.formSpecs.value; | |||
| // 请求交互都不放在组件完成 | |||
| this.$emit('getForm', params); | |||
| } else { | |||
| this.$message({ | |||
| message: '请仔细检查任务参数', | |||
| type: 'warning', | |||
| }); | |||
| } | |||
| }); | |||
| }, | |||
| // 镜像项目为空时选择默认项目 | |||
| resetProject() { | |||
| @@ -607,6 +746,15 @@ export default { | |||
| this.runParamObj = {}; | |||
| this.selectedAlgorithm = null; | |||
| this.delayCreateDelete = false; | |||
| this.useModel = false; | |||
| this.getModels(); | |||
| this.modelSelectionErrorMsg = ''; | |||
| // 清空模型炼知数据 | |||
| this.teacherModelIds = []; | |||
| this.studentModelIds = []; | |||
| this.teacherModelErrorMsg = ''; | |||
| this.$message({ | |||
| message: '数据已重置', | |||
| type: 'success', | |||
| @@ -619,7 +767,7 @@ export default { | |||
| }, 0); | |||
| }, | |||
| async getHarborProjects() { | |||
| this.harborProjectList = await harborProjectNames(); | |||
| this.harborProjectList = await getImageNameList({ projectType: IMAGE_PROJECT_TYPE.TRAIN }); | |||
| if (this.form.imageName && !this.harborProjectList.some(project => project === this.form.imageName)) { | |||
| this.$message.warning('该训练原有的运行项目不存在,请重新选择'); | |||
| this.form.imageName = null; | |||
| @@ -627,7 +775,7 @@ export default { | |||
| return; | |||
| } | |||
| this.form.imageName && await this.getHarborImages(true); | |||
| if (this.form.imageTag && !this.harborImageList.some(image => image === this.form.imageTag)) { | |||
| if (this.form.imageTag && !this.harborImageList.some(image => image.imageTag === this.form.imageTag)) { | |||
| this.$message.warning('该训练原有的运行镜像不存在,请重新选择'); | |||
| this.form.imageTag = null; | |||
| } | |||
| @@ -640,39 +788,177 @@ export default { | |||
| this.harborImageList = []; | |||
| return; | |||
| } | |||
| return harborImageNames({ imageName: this.form.imageName }) | |||
| return getImageTagList({ imageName: this.form.imageName, projectType: IMAGE_PROJECT_TYPE.TRAIN }) | |||
| .then(res => { | |||
| this.harborImageList = res; | |||
| }); | |||
| }, | |||
| async getModelNames(saveModel = true) { | |||
| this.modelNameList = await getModelName({ modelResource: this.form.modelResource, filter: true }); | |||
| if (!this.form.modelId) [this.modelLoadPathList, this.form.modelLoadPathDir] = [[], null]; | |||
| (this.form.modelId && !this.form.modelResource) && this.modelLoadPath(saveModel); | |||
| // saveModel 用于表示是否需要根据模型列表匹配模型/版本/教师模型/学生模型 | |||
| async getModels(saveModel = false) { | |||
| // modelResource 不存在时,获取 我的模型 的模型列表 | |||
| this.modelList = await getModelByResource(this.form.modelResource || 0); | |||
| // 如果不保留则不进行其余任何操作 | |||
| if (!saveModel) { return; } | |||
| switch (this.form.modelResource) { | |||
| // 我的模型 | |||
| case 0: | |||
| if (!this.form.modelId) { return; } | |||
| if (!this.modelList.find(model => model.id === this.form.modelId)) { | |||
| this.$message.warning('选择的模型不存在,请重新选择'); | |||
| this.form.modelId = this.form.modelBranchId = null; | |||
| return; | |||
| } | |||
| this.getModelBranchs(this.form.modelId, saveModel); | |||
| break; | |||
| // 预训练模型 | |||
| case 1: | |||
| if (!this.form.modelId) { return; } | |||
| if (!this.modelList.find(model => model.id === this.form.modelId)) { | |||
| this.$message.warning('选择的模型不存在,请重新选择'); | |||
| this.form.modelId = null; | |||
| } | |||
| break; | |||
| // 炼知模型 | |||
| case 2: | |||
| this.pushModel(this.teacherModelIds, this.form.teacherModelIds, '教师'); | |||
| this.pushModel(this.studentModelIds, this.form.studentModelIds, '学生'); | |||
| break; | |||
| // no default | |||
| } | |||
| }, | |||
| async getModelBranchs(parentId, saveBranchId = false) { | |||
| if (!this.useMineModel) { return; } // 只有使用 我的模型 时,才获取版本列表 | |||
| this.modelBranchList = (await getModelBranchs({ parentId })).result; | |||
| async modelLoadPath(create) { | |||
| if (create) { | |||
| this.form.modelLoadPathDir = null; | |||
| // 如果不保留则清空模型版本选项 | |||
| if (!saveBranchId) { | |||
| this.form.modelBranchId = null; | |||
| return; | |||
| }; | |||
| const data = await getModelTag({ parentId: this.form.modelId }); | |||
| this.modelLoadPathList = data.result; | |||
| if (!this.form.modelBranchId) { return; } | |||
| if (!this.modelBranchList.find(model => model.id === this.form.modelBranchId)) { | |||
| this.$message.warning('选择的模型版本不存在,请重新选择'); | |||
| this.form.modelBranchId = null; | |||
| } | |||
| }, | |||
| pushModel(modelList, modelIdString, modelType = '') { | |||
| if (!modelIdString) { return; } | |||
| const modelIdList = modelIdString.split(','); | |||
| const existSet = new Set(); | |||
| const notExistSet = new Set(); | |||
| onModelResourceChange() { | |||
| this.form.modelId = this.form.modelLoadPathDir = null; | |||
| this.getModelNames(); | |||
| // 教师、学生模型 在修改时,如果部分模型不存在,则只显示剩余模型 | |||
| modelIdList.forEach(id => { | |||
| if (this.modelList.find(model => model.id === Number(id))) { | |||
| existSet.add(Number(id)); | |||
| } else { | |||
| notExistSet.add(id); | |||
| } | |||
| }); | |||
| Array.from(existSet).forEach(id => modelList.push(id)); | |||
| if (notExistSet.size > 0) { | |||
| this.callMsg({ | |||
| message: `以下 id 的${modelType}模型不存在: ${Array.from(notExistSet).join('、')}`, | |||
| type: 'warning', | |||
| }); | |||
| } | |||
| }, | |||
| onModelTypeChange() { | |||
| if (this.form.modelType === 0 ) { | |||
| this.form = Object.assign(this.form, { | |||
| modelResource: 0, | |||
| onModelResourceChange() { | |||
| // 模型类型修改时,清空 模型/模型版本/模型版本列表/教师模型/学生模型 | |||
| this.form.modelId = this.form.modelBranchId = null; | |||
| this.modelBranchList = []; | |||
| this.teacherModelIds = []; | |||
| this.studentModelIds = []; | |||
| this.modelSelectionErrorMsg = ''; | |||
| this.teacherModelErrorMsg = ''; | |||
| this.getModels(); | |||
| }, | |||
| onUseModelChange(useModel) { | |||
| if (useModel) { | |||
| this.form.modelResource = 0; | |||
| } else { | |||
| Object.assign(this.form, { | |||
| modelResource: null, | |||
| modelId: null, | |||
| modelLoadPathDir: null, | |||
| modelBranchId: null, | |||
| }); | |||
| }; | |||
| this.teacherModelIds = []; | |||
| this.studentModelIds = []; | |||
| this.modelSelectionErrorMsg = ''; | |||
| this.teacherModelErrorMsg = ''; | |||
| // 取消加载模型时,重新获取 我的模型 模型列表,以备再次启用 | |||
| this.getModels(); | |||
| } | |||
| }, | |||
| onModelChange(id) { | |||
| if (this.useMineModel) { | |||
| this.getModelBranchs(id); | |||
| } else { | |||
| this.checkModelValid(); | |||
| } | |||
| }, | |||
| onModelBranchChange() { | |||
| this.checkModelValid(); | |||
| }, | |||
| onTeacherModelChange() { | |||
| this.checkModelValid(); | |||
| }, | |||
| checkModelValid() { | |||
| // 模型信息校验 | |||
| let errorMsg = null; | |||
| switch (this.form.modelResource) { | |||
| // 我的模型 | |||
| case 0: | |||
| if (!this.form.modelId) { | |||
| errorMsg = '模型不能为空'; | |||
| } else if (!this.form.modelBranchId) { | |||
| errorMsg = '模型版本不能为空'; | |||
| } | |||
| this.modelSelectionErrorMsg = errorMsg; | |||
| if (errorMsg) { | |||
| this.$message.warning(errorMsg); | |||
| return false; | |||
| } | |||
| break; | |||
| // 预训练模型 | |||
| case 1: | |||
| if (!this.form.modelId) { | |||
| errorMsg = '模型不能为空'; | |||
| } | |||
| this.modelSelectionErrorMsg = errorMsg; | |||
| if (errorMsg) { | |||
| this.$message.warning(errorMsg); | |||
| return false; | |||
| } | |||
| break; | |||
| // 炼知模型 | |||
| case 2: | |||
| if (!this.teacherModelIds.length) { | |||
| errorMsg = '教师模型不能为空'; | |||
| } | |||
| this.teacherModelErrorMsg = errorMsg; | |||
| if (errorMsg) { | |||
| this.$message.warning(errorMsg); | |||
| return false; | |||
| } | |||
| this.form.teacherModelIds = this.teacherModelIds.join(','); | |||
| this.form.studentModelIds = this.studentModelIds.length | |||
| ? this.studentModelIds.join(',') | |||
| : null; | |||
| break; | |||
| // no default | |||
| } | |||
| return true; | |||
| }, | |||
| getAlgorithmList() { | |||
| @@ -746,7 +1032,7 @@ export default { | |||
| } | |||
| this.form.imageName && await this.getHarborImages(true); | |||
| this.form.imageTag = algorithm?.imageTag; | |||
| if (this.form.imageTag && !this.harborImageList.some(image => image === this.form.imageTag)) { | |||
| if (this.form.imageTag && !this.harborImageList.some(image => image.imageTag === this.form.imageTag)) { | |||
| this.$message.warning('算法选择的运行镜像不存在,请重新选择'); | |||
| this.form.imageTag = null; | |||
| return; | |||
| @@ -796,10 +1082,9 @@ export default { | |||
| resourcesPoolType: 0, | |||
| valType: 0, | |||
| runParams: {}, | |||
| modelType: 0, | |||
| modelResource: 0, | |||
| modelResource: null, | |||
| modelId: null, | |||
| modelLoadPathDir: null, | |||
| modelBranchId: null, | |||
| }); | |||
| this.getAlgorithmList(); | |||
| this.$refs.trainDataSourceSelector.reset(); | |||
| @@ -814,6 +1099,13 @@ export default { | |||
| this.harborImageList = []; | |||
| this.resetProject(); | |||
| this.onResourcesPoolTypeChange(); | |||
| // 模型数据重置 | |||
| this.useModel = false; | |||
| this.teacherModelIds = []; | |||
| this.studentModelIds = []; | |||
| this.teacherModelErrorMsg = ''; | |||
| this.getModels(); | |||
| }, | |||
| onTrainTypeChange(trainType) { | |||
| this.form.resourcesPoolNode = trainType === 0 ? 1 : 2; | |||
| @@ -838,19 +1130,14 @@ export default { | |||
| } | |||
| } | |||
| .el-radio-group > .el-radio { | |||
| margin-right: 0; | |||
| } | |||
| .el-radio.is-bordered { | |||
| width: 130px; | |||
| height: 35px; | |||
| padding: 10px 0; | |||
| text-align: center; | |||
| } | |||
| .param { | |||
| min-height: 80px; | |||
| padding: 0 10px; | |||
| line-height: 25px; | |||
| color: rgb(204, 204, 204); | |||
| background: rgb(30, 30, 30); | |||
| border-radius: 5px; | |||
| } | |||
| </style> | |||
| @@ -1,4 +1,4 @@ | |||
| /** Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||
| /** Copyright 2020 Tianshu AI Platform. All Rights Reserved. | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| @@ -22,7 +22,7 @@ | |||
| :model="item" | |||
| > | |||
| <el-form-item | |||
| :label="'运行参数' + (index + 1)" | |||
| :label="label + (index + 1)" | |||
| class="param-pair-item" | |||
| prop="key" | |||
| :rules="keyRule" | |||
| @@ -84,6 +84,10 @@ export default { | |||
| type: Object, | |||
| default: () => ({}), | |||
| }, | |||
| label: { | |||
| type: String, | |||
| required: true, | |||
| }, | |||
| labelWidth: { | |||
| type: String, | |||
| default: '100px', | |||
| @@ -1,4 +1,4 @@ | |||
| /** Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||
| /** Copyright 2020 Tianshu AI Platform. All Rights Reserved. | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| @@ -33,6 +33,7 @@ | |||
| v-for="(item, index) in runParamsList" | |||
| :key="item.id" | |||
| ref="paramPairs" | |||
| label="运行参数" | |||
| :item="runParamsList[index]" | |||
| :index="index" | |||
| :label-width="paramLabelWidth" | |||
| @@ -58,7 +59,7 @@ | |||
| </template> | |||
| <script> | |||
| import { stringIsValidPythonVariable } from '@/utils'; | |||
| import { pythonKeyValidator, stringIsValidPythonVariable } from '@/utils'; | |||
| import ParamPair from './paramPair'; | |||
| export default { | |||
| @@ -83,18 +84,6 @@ export default { | |||
| }, | |||
| }, | |||
| data() { | |||
| const isInputEmpty = value => { | |||
| return value === '' || value === null; | |||
| }; | |||
| const keyValidator = (rule, value, callback) => { | |||
| if (!isInputEmpty(value) && !stringIsValidPythonVariable(value)) { | |||
| callback(new Error('参数key必须是合法变量名')); | |||
| } else { | |||
| callback(); | |||
| } | |||
| }; | |||
| return { | |||
| runParamsList: [], | |||
| paramsMode: 1, | |||
| @@ -102,7 +91,7 @@ export default { | |||
| argErrorMsg: null, | |||
| // 整体校验规则:对 key 做 python 变量名有效性校验,对 value 不做任何校验 | |||
| keyRule: [{ | |||
| validator: keyValidator, | |||
| validator: pythonKeyValidator(), | |||
| trigger: 'blur', | |||
| }], | |||
| paramId: 0, | |||
| @@ -126,6 +115,7 @@ export default { | |||
| // eslint-disable-next-line no-plusplus | |||
| id: this.paramId++, | |||
| }); | |||
| this.$emit('addParams', this.runParamsList.length); | |||
| }, | |||
| removeP(i) { | |||
| this.runParamsList.splice(i, 1); | |||
| @@ -1,4 +1,4 @@ | |||
| /** Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||
| /** Copyright 2020 Tianshu AI Platform. All Rights Reserved. | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| @@ -1,4 +1,4 @@ | |||
| /** Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||
| /** Copyright 2020 Tianshu AI Platform. All Rights Reserved. | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| @@ -14,11 +14,9 @@ | |||
| * ============================================================= | |||
| */ | |||
| import request from '@/utils/request'; | |||
| export function getDashboardData() { | |||
| return request({ | |||
| url: '/api/dashboard', | |||
| method: 'get', | |||
| }); | |||
| export default class FileFilter { | |||
| constructor(judge, message) { | |||
| this.judge = judge; | |||
| this.message = message; | |||
| } | |||
| } | |||
| @@ -1,4 +1,4 @@ | |||
| /** Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||
| /** Copyright 2020 Tianshu AI Platform. All Rights Reserved. | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| @@ -49,6 +49,27 @@ export default { | |||
| type: Boolean, | |||
| default: true, | |||
| }, | |||
| dataType: { | |||
| type: String, | |||
| default: "visual", | |||
| }, | |||
| /** | |||
| * filters 数组要求: | |||
| * 1. 成员需要有一个 judge 方法返回布尔值,来判断是否需要过滤文件 | |||
| * 2. 成员需要有一个 message 属性,用来展示提示信息 | |||
| */ | |||
| filters: { | |||
| type: Array, | |||
| default: () => ([]), | |||
| validator: value => { | |||
| for(const filter of value) { | |||
| if (!filter.message || typeof filter.judge !== 'function') { | |||
| return false; | |||
| } | |||
| } | |||
| return true; | |||
| }, | |||
| }, | |||
| }, | |||
| data() { | |||
| return { | |||
| @@ -72,46 +93,46 @@ export default { | |||
| this.$refs.uploader.clearFiles(); | |||
| this.lenOfFileList = 0; | |||
| }, | |||
| fileChange(file, fileList) { | |||
| // 根据后缀名进行格式匹配 | |||
| const acceptTypes = this.accept.split(','); | |||
| const extname = path.extname(file.raw.name); | |||
| const mimeType = acceptTypes.includes(extname.toLowerCase()); | |||
| if (!mimeType) { | |||
| /** | |||
| * 标准文件过滤入口,返回布尔值 | |||
| * @param {*} file 被过滤文件 | |||
| * @param {*} fileList 文件列表 | |||
| * @param {Boolean} bool 如果布尔值为 true 则过滤改文件 | |||
| * @param {*} message Message 信息 | |||
| * @return {Boolean} 返回传入的布尔值 | |||
| */ | |||
| addFileFilter(file, fileList, bool, message) { | |||
| if (bool) { | |||
| fileList.splice(fileList.indexOf(file), 1); | |||
| if (!msgInstance) { | |||
| Message.info({ | |||
| message: `文件格式不支持`, | |||
| msgInstance = Message.info({ | |||
| message, | |||
| onClose: this.onMessageClose, | |||
| }); | |||
| } | |||
| return; | |||
| } | |||
| return bool; | |||
| }, | |||
| fileChange(file, fileList) { | |||
| // 根据后缀名进行格式匹配 | |||
| const acceptTypes = this.accept.split(','); | |||
| const extname = path.extname(file.raw.name); | |||
| const mimeType = acceptTypes.includes(extname.toLowerCase()); | |||
| const addFilter = this.addFileFilter.bind(this, file, fileList); | |||
| if (addFilter(!mimeType, '文件格式不支持')) { return; }; | |||
| // accept 支持传入 0 代表不限制大小 | |||
| const isOverSize = this.acceptSize !== 0 && (file.size / (1024 * 1024)) > this.acceptSize; | |||
| if (isOverSize) { | |||
| fileList.splice(fileList.indexOf(file), 1); | |||
| if (!msgInstance) { | |||
| msgInstance = Message.info({ | |||
| message: `不能添加大于${this.acceptSize}MB的文件`, | |||
| onClose: this.onMessageClose, | |||
| }); | |||
| } | |||
| return; | |||
| } | |||
| if (addFilter(isOverSize, `不能添加大于${this.acceptSize}MB的文件`)) { return; } | |||
| for (const item of fileList.slice(0, fileList.length - 1)) { | |||
| if (item.name === file.name) { | |||
| fileList.splice(fileList.indexOf(file), 1); | |||
| if (!msgInstance) { | |||
| msgInstance = Message.info({ | |||
| message: `不能添加文件名相同的文件`, | |||
| onClose: this.onMessageClose, | |||
| }); | |||
| } | |||
| return false; | |||
| } | |||
| if (addFilter(item.name === file.name, '不能添加文件名相同的文件')) { return; }; | |||
| } | |||
| for (const filter of this.filters) { | |||
| if (addFilter(filter.judge(file, fileList), filter.message)) { return; }; | |||
| } | |||
| this.lenOfFileList = fileList.length; | |||
| @@ -160,24 +181,24 @@ export default { | |||
| class='upload-field' | |||
| limit={this.limit} | |||
| multiple | |||
| list-type={this.lenOfFileList>100? 'text' : 'picture'} | |||
| list-type={this.lenOfFileList > 100 || this.dataType === "text" ? 'text' : 'picture'} | |||
| auto-upload={false} | |||
| disabled={this.uploading} | |||
| {...uploadProps} | |||
| > | |||
| <el-button disabled={this.uploading} size='mini' icon='el-icon-upload'>上传文件</el-button> | |||
| <el-button disabled={this.uploading || this.$attrs.disabled} size='mini' icon='el-icon-upload'>上传文件</el-button> | |||
| <div slot='tip' class='flex f1 flex-between' style='margin-left: 20px;'> | |||
| <div class='upload-tip'> | |||
| <span>文件格式: { this.acceptFormatStr }</span> | |||
| { | |||
| this.acceptSize > 0 && ( | |||
| <span>, 文件不大于 { this.acceptSizeFormat(this.acceptSize) }</span> | |||
| <span>, 单个文件不大于 { this.acceptSizeFormat(this.acceptSize) }</span> | |||
| ) | |||
| } | |||
| </div> | |||
| { | |||
| this.showFileCount && ( | |||
| <span class='upload-chosen-tip'>已选择{ this.lenOfFileList }张</span> | |||
| <span class='upload-chosen-tip'>已选择{ this.lenOfFileList }个</span> | |||
| ) | |||
| } | |||
| </div> | |||
| @@ -1,4 +1,4 @@ | |||
| /** Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||
| /** Copyright 2020 Tianshu AI Platform. All Rights Reserved. | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| @@ -37,7 +37,7 @@ import { ref, reactive, watch } from '@vue/composition-api'; | |||
| import BaseModal from '@/components/BaseModal'; | |||
| import Form from './form'; | |||
| import { minIOUpload, hashify, getFileOutputPath } from './util'; | |||
| import { minIOUpload, renameFile, getFileOutputPath } from './util'; | |||
| export default { | |||
| name: 'UploadDialog', | |||
| @@ -60,15 +60,20 @@ export default { | |||
| type: Boolean, | |||
| default: true, | |||
| }, | |||
| encode: { | |||
| type: Boolean, | |||
| default: false, | |||
| }, | |||
| toggleVisible: Function, | |||
| request: Function, | |||
| params: { | |||
| type: Object, | |||
| default: () => ({}), | |||
| }, | |||
| beforeUpload: Function, | |||
| }, | |||
| setup(props, ctx) { | |||
| const { toggleVisible, request, transformFile } = props; | |||
| const { toggleVisible, request, transformFile, beforeUpload } = props; | |||
| const formRef = ref(null); | |||
| const state = reactive({ | |||
| visible: props.visible, | |||
| @@ -88,7 +93,7 @@ export default { | |||
| // 重命名 | |||
| const renameFileList = fileList.map(file => ({ | |||
| ...file, | |||
| name: hashify(file.name, props.hash), | |||
| name: renameFile(file.name, { hash: props.hash, encode: props.encode }), | |||
| })); | |||
| if (!fileList || !fileList.length) { | |||
| @@ -97,9 +102,10 @@ export default { | |||
| const uploadReqeust = request || minIOUpload; | |||
| state.uploading = true; | |||
| // 开始调用上传接口 | |||
| uploadReqeust && uploadReqeust({ ...props.params, fileList: renameFileList, transformFile }, handleUploadProgress) | |||
| const uploader = (result = {}) => { | |||
| state.uploading = true; | |||
| uploadReqeust({ ...props.params, fileList: renameFileList, transformFile, ...result }, handleUploadProgress) | |||
| .then(res => { | |||
| const outputPath = getFileOutputPath(renameFileList, props.params); | |||
| state.uploading = false; | |||
| @@ -113,6 +119,20 @@ export default { | |||
| toggleVisible(); | |||
| ctx.emit('uploadError', err); | |||
| }); | |||
| }; | |||
| // 触发 before Hook | |||
| if(typeof beforeUpload === 'function') { | |||
| beforeUpload({ fileList: renameFileList }).then(result => { | |||
| // 返回数据集 ID | |||
| uploader(result); | |||
| }).catch(err => { | |||
| state.uploading = false; | |||
| ctx.emit('uploadError', err); | |||
| }); | |||
| } else { | |||
| uploader(); | |||
| } | |||
| }; | |||
| const handleCancel = () => { | |||
| @@ -1,4 +1,4 @@ | |||
| /** Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||
| /** Copyright 2020 Tianshu AI Platform. All Rights Reserved. | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| @@ -24,7 +24,7 @@ | |||
| <script> | |||
| import { ref, reactive } from '@vue/composition-api'; | |||
| import Form from './form'; | |||
| import { minIOUpload, hashify, getFileOutputPath } from './util'; | |||
| import { minIOUpload, renameFile, getFileOutputPath } from './util'; | |||
| export default { | |||
| name: 'UploadInline', | |||
| @@ -38,30 +38,35 @@ export default { | |||
| type: Boolean, | |||
| default: false, | |||
| }, | |||
| beforeUpload: Function, | |||
| transformFile: Function, | |||
| hash: { | |||
| type: Boolean, | |||
| default: true, | |||
| }, | |||
| encode: { | |||
| type: Boolean, | |||
| default: false, | |||
| }, | |||
| params: { | |||
| type: Object, | |||
| default: () => ({}), | |||
| }, | |||
| }, | |||
| setup(props, ctx) { | |||
| const { request, transformFile } = props; | |||
| const { request, transformFile, beforeUpload } = props; | |||
| const formRef = ref(null); | |||
| const state = reactive({ | |||
| uploading: false, | |||
| }); | |||
| // 基于文件上传 | |||
| const uploadByFile = (files, callback) => { | |||
| const uploadByFile = (files, callback, result = {}, errCallback) => { | |||
| const fileList = Array.isArray(files) ? files : [files]; | |||
| // 重命名 | |||
| const renameFileList = fileList.map(file => ({ | |||
| ...file, | |||
| name: hashify(file.name, props.hash), | |||
| name: renameFile(file.name, { hash: props.hash, encode: props.encode }), | |||
| })); | |||
| if (!fileList || !fileList.length) { | |||
| @@ -72,7 +77,7 @@ export default { | |||
| ctx.emit('uploadStart', files); | |||
| const uploadReqeust = request || minIOUpload; | |||
| // 开始调用上传接口 | |||
| return uploadReqeust({ ...props.params, fileList: renameFileList, transformFile }, callback) | |||
| return uploadReqeust({ ...props.params, fileList: renameFileList, transformFile, ...result }, callback, errCallback) | |||
| .then(res => { | |||
| const outputPath = getFileOutputPath(renameFileList, props.params); | |||
| state.uploading = false; | |||
| @@ -85,12 +90,23 @@ export default { | |||
| }; | |||
| // 提交结果 | |||
| const uploadSubmit = (callback) => { | |||
| const uploadSubmit = (callback, errCallback) => { | |||
| const fileList = (formRef.value?.$refs.uploader || {}).uploadFiles; | |||
| uploadByFile(fileList, callback); | |||
| // 触发 before Hook | |||
| if(typeof beforeUpload === 'function') { | |||
| beforeUpload({ fileList }).then(result => { | |||
| uploadByFile(fileList, callback, result, errCallback); | |||
| }).catch(err => { | |||
| state.uploading = false; | |||
| ctx.emit('uploadError', err); | |||
| }); | |||
| } else { | |||
| uploadByFile(fileList, callback, undefined, errCallback); | |||
| } | |||
| }; | |||
| const handleFileChange = (file) => { | |||
| const handleFileChange = (file, fileList) => { | |||
| ctx.emit('fileChange', file, fileList); | |||
| // 自动触发上传命令 | |||
| if (props.autoUpload) { | |||
| uploadByFile(file); | |||
| @@ -1,4 +1,4 @@ | |||
| /** Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||
| /** Copyright 2020 Tianshu AI Platform. All Rights Reserved. | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| @@ -1,4 +1,4 @@ | |||
| /** Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||
| /** Copyright 2020 Tianshu AI Platform. All Rights Reserved. | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| @@ -15,7 +15,7 @@ | |||
| */ | |||
| import { bucketHost, bucketName } from '@/utils/minIO'; | |||
| import { isValidVideo } from '@/utils/validate'; | |||
| import { isValidText, isValidVideo } from '@/utils/validate'; | |||
| import { generateUuid, performanceTiming } from '@/utils'; | |||
| const pMap = require('p-map'); | |||
| @@ -32,6 +32,11 @@ const isValidVideoFile = file => { | |||
| return isValidVideo(extname); | |||
| }; | |||
| const isValidTextFile = file => { | |||
| const extname = path.extname(file.name); | |||
| return isValidText(extname); | |||
| }; | |||
| // 给图片名称添加时间戳 | |||
| export const hashName = (name) => { | |||
| // 后缀名 .png | |||
| @@ -47,7 +52,7 @@ export const hashName = (name) => { | |||
| // minio 上传导致 chrome crash,自定义实现上传 | |||
| export const putObject = (uploadUrl, file, options = {}) => { | |||
| const { callback, objectName } = options; | |||
| const { callback, objectName, errCallback } = options; | |||
| // 加载进度 | |||
| let loaded = 0; | |||
| let total = 0; | |||
| @@ -68,6 +73,11 @@ export const putObject = (uploadUrl, file, options = {}) => { | |||
| reject(e); | |||
| } | |||
| }; | |||
| if (typeof errCallback === 'function') { | |||
| xhr.onerror = () => { | |||
| errCallback(file); | |||
| }; | |||
| } | |||
| // todo: 视频进度loaded 解析会回滚,暂时不清楚原因 | |||
| xhr.upload.addEventListener('progress', event => { | |||
| if (event.lengthComputable) { | |||
| @@ -87,7 +97,7 @@ export const putObject = (uploadUrl, file, options = {}) => { | |||
| }; | |||
| // 默认通过 minIO 上传 | |||
| export const minIOUpload = async({ objectPath, fileList, transformFile }, callback) => { | |||
| export const minIOUpload = async({ objectPath, fileList, transformFile }, callback, errCallback) => { | |||
| // add 进度条 | |||
| let resolved = 0; | |||
| @@ -100,6 +110,7 @@ export const minIOUpload = async({ objectPath, fileList, transformFile }, callba | |||
| const fileRes = await putObject(`${uploadPrefix}/${objectName}`, d.raw, { | |||
| objectName, | |||
| callback, | |||
| errCallback, | |||
| }); | |||
| // minIO 上传视频 chrome crash | |||
| // const result = await window.minioClient.putObject(`${objectPath}/${d.name}`, blob, { | |||
| @@ -107,17 +118,20 @@ export const minIOUpload = async({ objectPath, fileList, transformFile }, callba | |||
| // }) | |||
| resolved+=1; | |||
| // 进度反馈 | |||
| if (typeof callback === 'function' && fileList.length > 1) { | |||
| if (typeof callback === 'function' && fileList.length >= 1) { | |||
| callback(resolved, fileList.length); | |||
| } | |||
| // 视频不做转换 | |||
| if (isValidVideoFile(d)) return fileRes; | |||
| // 文本也不做转换 | |||
| if (isValidTextFile(d)) return fileRes; | |||
| if (typeof transformFile === 'function') { | |||
| const transformed = await transformFile(fileRes, d); | |||
| return transformed; | |||
| } | |||
| } | |||
| return fileRes; | |||
| }; | |||
| @@ -125,8 +139,10 @@ export const minIOUpload = async({ objectPath, fileList, transformFile }, callba | |||
| return result; | |||
| }; | |||
| export const hashify = (name, hash) => { | |||
| return hash ? hashName(name) : name; | |||
| export const renameFile = (name, options = {}) => { | |||
| name = options.hash ? hashName(name) : name; | |||
| name = options.encode ? encodeURIComponent(name) : name; | |||
| return name; | |||
| }; | |||
| export const getFileOutputPath = (rawFiles, { objectPath }) => { | |||
| @@ -1,4 +1,4 @@ | |||
| /** Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||
| /** Copyright 2020 Tianshu AI Platform. All Rights Reserved. | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| @@ -57,8 +57,8 @@ export default { | |||
| }; | |||
| </script> | |||
| <style lang="scss"> | |||
| .progress { | |||
| <style lang="scss" scoped> | |||
| ::v-deep.progress { | |||
| .el-progress-bar__inner::before { | |||
| position: absolute; | |||
| top: 0; | |||
| @@ -1,4 +1,4 @@ | |||
| /** Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||
| /** Copyright 2020 Tianshu AI Platform. All Rights Reserved. | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| @@ -1,4 +1,4 @@ | |||
| /** Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||
| /** Copyright 2020 Tianshu AI Platform. All Rights Reserved. | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| @@ -1,4 +1,4 @@ | |||
| /** Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||
| /** Copyright 2020 Tianshu AI Platform. All Rights Reserved. | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| @@ -1,4 +1,4 @@ | |||
| /** Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||
| /** Copyright 2020 Tianshu AI Platform. All Rights Reserved. | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| @@ -1,4 +1,4 @@ | |||
| /** Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||
| /** Copyright 2020 Tianshu AI Platform. All Rights Reserved. | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| @@ -1,4 +1,4 @@ | |||
| /** Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||
| /** Copyright 2020 Tianshu AI Platform. All Rights Reserved. | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| @@ -1,4 +1,4 @@ | |||
| /** Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||
| /** Copyright 2020 Tianshu AI Platform. All Rights Reserved. | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| @@ -1,4 +1,4 @@ | |||
| /** Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||
| /** Copyright 2020 Tianshu AI Platform. All Rights Reserved. | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| @@ -0,0 +1,51 @@ | |||
| /** Copyright 2020 Tianshu AI Platform. All Rights Reserved. | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| * You may obtain a copy of the License at | |||
| * | |||
| * http://www.apache.org/licenses/LICENSE-2.0 | |||
| * | |||
| * Unless required by applicable law or agreed to in writing, software | |||
| * distributed under the License is distributed on an "AS IS" BASIS, | |||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
| * See the License for the specific language governing permissions and | |||
| * limitations under the License. | |||
| * ============================================================= | |||
| */ | |||
| <template> | |||
| <div v-loading="loading" class='textEditor'> | |||
| <pre>{{ txt }}</pre> | |||
| </div> | |||
| </template> | |||
| <script> | |||
| export default { | |||
| name: 'TextEditor', | |||
| props: { | |||
| txt: String, | |||
| loading: { | |||
| type: Boolean, | |||
| default: false, | |||
| }, | |||
| }, | |||
| }; | |||
| </script> | |||
| <style lang="scss" scoped> | |||
| .textEditor { | |||
| max-height: 40vh; | |||
| overflow: auto; | |||
| pre { | |||
| width: 100%; | |||
| min-height: 100%; | |||
| padding: 20px; | |||
| line-height: 26px; | |||
| word-break: break-word; | |||
| white-space: pre-wrap; | |||
| background: #fff; | |||
| } | |||
| } | |||
| </style> | |||
| @@ -1,4 +1,4 @@ | |||
| /** Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||
| /** Copyright 2020 Tianshu AI Platform. All Rights Reserved. | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| @@ -14,34 +14,6 @@ | |||
| * ============================================================= | |||
| */ | |||
| // minIO 参数配置 | |||
| export const minIO = { | |||
| development: { | |||
| config: { | |||
| endPoint: '', // MinIO 服务地址 | |||
| port: 9000, | |||
| useSSL: false, | |||
| }, | |||
| bucketName: 'dubhe-dev', | |||
| }, | |||
| test: { | |||
| config: { | |||
| endPoint: '', | |||
| port: 9000, | |||
| useSSL: false, | |||
| }, | |||
| bucketName: 'dubhe-test', | |||
| }, | |||
| production: { | |||
| config: { | |||
| endPoint: '', | |||
| port: 9000, | |||
| useSSL: false, | |||
| }, | |||
| bucketName: 'dubhe-prod', | |||
| }, | |||
| }; | |||
| // 训练管理模块参数配置 | |||
| export const trainConfig = { | |||
| trainNodeMax: Infinity, // 分布式训练节点上限 | |||
| @@ -63,3 +35,13 @@ export const imageConfig = { | |||
| export const modelConfig = { | |||
| uploadFileAcceptSize: 0, // 上传模型文件大小限制,单位为 MB,0 表示不限制大小 | |||
| }; | |||
| // 云端 Serving 模块参数配置 | |||
| export const servingConfig = { | |||
| onlineServingNodeSumMax: 10, | |||
| }; | |||
| // 模型炼知模块参数配置 | |||
| export const atlasConfig = { | |||
| uploadFileAcceptSize: 5, // 上传度量图文件大小限制,单位为 MB,0 表示不限制大小 | |||
| }; | |||
| @@ -1,4 +1,4 @@ | |||
| /** Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||
| /** Copyright 2020 Tianshu AI Platform. All Rights Reserved. | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| @@ -1,4 +1,4 @@ | |||
| /** Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||
| /** Copyright 2020 Tianshu AI Platform. All Rights Reserved. | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| @@ -1,4 +1,4 @@ | |||
| /** Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||
| /** Copyright 2020 Tianshu AI Platform. All Rights Reserved. | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| @@ -1,4 +1,4 @@ | |||
| /** Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||
| /** Copyright 2020 Tianshu AI Platform. All Rights Reserved. | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| @@ -1,4 +1,4 @@ | |||
| /** Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||
| /** Copyright 2020 Tianshu AI Platform. All Rights Reserved. | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| @@ -1,4 +1,4 @@ | |||
| /** Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||
| /** Copyright 2020 Tianshu AI Platform. All Rights Reserved. | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| @@ -1,4 +1,4 @@ | |||
| /** Copyright 2020 Zhejiang Lab. All Rights Reserved. | |||
| /** Copyright 2020 Tianshu AI Platform. All Rights Reserved. | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||