Browse Source

update webapp

tags/v0.3.0
之江实验室 3 years ago
parent
commit
4f046172c0
100 changed files with 1951 additions and 425 deletions
  1. +18
    -5
      webapp/.env.development
  2. +20
    -2
      webapp/.env.mock
  3. +22
    -8
      webapp/.env.production
  4. +19
    -5
      webapp/.env.test
  5. +25
    -0
      webapp/CHANGELOG.md
  6. +3
    -2
      webapp/README.md
  7. +0
    -56
      webapp/mock/api/data/datasets.js
  8. +8
    -0
      webapp/mock/api/data/datasets/count.js
  9. +0
    -5
      webapp/mock/api/data/labelGroup/getList/id.js
  10. +1
    -1
      webapp/mock/mock-map.js
  11. +9
    -2
      webapp/package.json
  12. +2
    -2
      webapp/src/App.vue
  13. +2
    -10
      webapp/src/api/algorithm/algorithm.js
  14. +1
    -1
      webapp/src/api/algorithm/algorithmUsage.js
  15. +17
    -17
      webapp/src/api/atlas/index.js
  16. +1
    -1
      webapp/src/api/auth.js
  17. +89
    -0
      webapp/src/api/cloudServing/batch.js
  18. +114
    -0
      webapp/src/api/cloudServing/index.js
  19. +1
    -1
      webapp/src/api/development/notebook.js
  20. +9
    -1
      webapp/src/api/model/model.js
  21. +1
    -1
      webapp/src/api/model/modelVersion.js
  22. +107
    -0
      webapp/src/api/modelOptimize/optimize.js
  23. +19
    -17
      webapp/src/api/modelOptimize/record.js
  24. +1
    -1
      webapp/src/api/preparation/annotation.js
  25. +1
    -1
      webapp/src/api/preparation/datafile.js
  26. +3
    -3
      webapp/src/api/preparation/datalabel.js
  27. +20
    -2
      webapp/src/api/preparation/dataset.js
  28. +3
    -2
      webapp/src/api/preparation/labelGroup.js
  29. +170
    -0
      webapp/src/api/preparation/medical.js
  30. +63
    -0
      webapp/src/api/preparation/textData.js
  31. +1
    -1
      webapp/src/api/system/dict.js
  32. +1
    -1
      webapp/src/api/system/dictDetail.js
  33. +1
    -1
      webapp/src/api/system/node.js
  34. +1
    -1
      webapp/src/api/system/pod.js
  35. +8
    -1
      webapp/src/api/system/role.js
  36. +1
    -1
      webapp/src/api/system/user.js
  37. +19
    -2
      webapp/src/api/trainingImage/index.js
  38. +9
    -1
      webapp/src/api/trainingJob/job.js
  39. +1
    -1
      webapp/src/api/trainingJob/params.js
  40. +1
    -1
      webapp/src/api/user.js
  41. +1
    -1
      webapp/src/api/visual/index.js
  42. BIN
      webapp/src/assets/images/dataset/medicalDataset.png
  43. BIN
      webapp/src/assets/images/dataset/normalDataset.png
  44. +82
    -1
      webapp/src/assets/styles/atomic.scss
  45. +15
    -0
      webapp/src/assets/styles/common.scss
  46. +9
    -0
      webapp/src/assets/styles/mixin.scss
  47. +1
    -1
      webapp/src/boot/errorHandle.js
  48. +1
    -1
      webapp/src/boot/index.js
  49. +9
    -2
      webapp/src/components/BaseModal/index.js
  50. +1
    -1
      webapp/src/components/Card/info.vue
  51. +1
    -1
      webapp/src/components/Drag/drag.vue
  52. +1
    -1
      webapp/src/components/Drag/index.js
  53. +7
    -2
      webapp/src/components/DropdownHeader/index.vue
  54. +1
    -1
      webapp/src/components/Exception/index.vue
  55. +1
    -1
      webapp/src/components/IconFont/icon.js
  56. +1
    -1
      webapp/src/components/IconFont/iconfont.js
  57. +2
    -2
      webapp/src/components/IconFont/index.js
  58. +1
    -1
      webapp/src/components/IconFont/utils.js
  59. +1
    -1
      webapp/src/components/ImageGallery/index.vue
  60. +1
    -1
      webapp/src/components/InfoSelect/index.js
  61. +1
    -1
      webapp/src/components/InfoSelect/info-select.vue
  62. +1
    -1
      webapp/src/components/InfoTable/column.js
  63. +1
    -1
      webapp/src/components/InfoTable/index.js
  64. +24
    -7
      webapp/src/components/InfoTable/info-table.vue
  65. +6
    -3
      webapp/src/components/InlineTableEdit/index.vue
  66. +6
    -2
      webapp/src/components/LogContainer/index.vue
  67. +364
    -0
      webapp/src/components/LogContainer/podLogContainer.vue
  68. +1
    -1
      webapp/src/components/LoginPublic/index.vue
  69. +2
    -1
      webapp/src/components/Prism/index.vue
  70. +1
    -1
      webapp/src/components/SortingMenu/index.vue
  71. +2
    -2
      webapp/src/components/Training/algorithmDetail.vue
  72. +1
    -1
      webapp/src/components/Training/dataSourceSelector.vue
  73. +383
    -96
      webapp/src/components/Training/jobForm.vue
  74. +6
    -2
      webapp/src/components/Training/paramPair.vue
  75. +5
    -15
      webapp/src/components/Training/runParamForm.vue
  76. +1
    -1
      webapp/src/components/Training/saveModelDialog.vue
  77. +6
    -8
      webapp/src/components/UploadForm/FileFilter.js
  78. +56
    -35
      webapp/src/components/UploadForm/form.js
  79. +26
    -6
      webapp/src/components/UploadForm/index.vue
  80. +25
    -9
      webapp/src/components/UploadForm/inline.vue
  81. +1
    -1
      webapp/src/components/UploadForm/style.scss
  82. +24
    -8
      webapp/src/components/UploadForm/util.js
  83. +3
    -3
      webapp/src/components/UploadProgress/index.vue
  84. +1
    -1
      webapp/src/components/ZoomContainer/index.vue
  85. +1
    -1
      webapp/src/components/svg/brush/Brush.js
  86. +1
    -1
      webapp/src/components/svg/brush/BrushCorner.js
  87. +1
    -1
      webapp/src/components/svg/brush/BrushHandle.js
  88. +1
    -1
      webapp/src/components/svg/brush/BrushSelection.js
  89. +1
    -1
      webapp/src/components/svg/brush/index.js
  90. +1
    -1
      webapp/src/components/svg/group/index.js
  91. +1
    -1
      webapp/src/components/svg/index.js
  92. +51
    -0
      webapp/src/components/textEditor.vue
  93. +11
    -29
      webapp/src/config/index.js
  94. +1
    -1
      webapp/src/directives/index.js
  95. +1
    -1
      webapp/src/directives/modules/clickOnce.js
  96. +1
    -1
      webapp/src/directives/modules/elSelectLoadMore.js
  97. +1
    -1
      webapp/src/directives/modules/mouseWheel.js
  98. +1
    -1
      webapp/src/hooks/brush/BasicBrush.js
  99. +1
    -1
      webapp/src/hooks/brush/index.js
  100. +1
    -1
      webapp/src/hooks/brush/useBrush.js

+ 18
- 5
webapp/.env.development View File

@@ -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'

+ 20
- 2
webapp/.env.mock View File

@@ -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'

+ 22
- 8
webapp/.env.production View File

@@ -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'

+ 19
- 5
webapp/.env.test View File

@@ -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'


+ 25
- 0
webapp/CHANGELOG.md View File

@@ -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


+ 3
- 2
webapp/README.md View File

@@ -26,8 +26,9 @@ cd dubhe-web

根据需要修改如下配置文件
```
config/index.js
settings.js
.env.mock
.env.development
.env.test
.env.production
```



+ 0
- 56
webapp/mock/api/data/datasets.js View File

@@ -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
},
}
}

+ 8
- 0
webapp/mock/api/data/datasets/count.js View File

@@ -0,0 +1,8 @@
module.exports = {
code: 200,
msg: null,
data: {
"finished": 10,
"unfinished": 0
}
}

+ 0
- 5
webapp/mock/api/data/labelGroup/getList/id.js View File

@@ -1,5 +0,0 @@
module.exports = {
"code": 200,
"msg": null,
"data": []
}

+ 1
- 1
webapp/mock/mock-map.js View File

@@ -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',
};

+ 9
- 2
webapp/package.json View File

@@ -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",


+ 2
- 2
webapp/src/App.vue View 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.
@@ -17,7 +17,7 @@
<template>
<div id="app">
<keep-alive include="DataSet">
<router-view/>
<router-view />
</keep-alive>
</div>
</template>


+ 2
- 10
webapp/src/api/algorithm/algorithm.js View 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.
@@ -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
- 1
webapp/src/api/algorithm/algorithmUsage.js View 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.


webapp/src/api/system/menu.js → webapp/src/api/atlas/index.js View 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.
@@ -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
- 1
webapp/src/api/auth.js View 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.


+ 89
- 0
webapp/src/api/cloudServing/batch.js View File

@@ -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 };

+ 114
- 0
webapp/src/api/cloudServing/index.js View File

@@ -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
- 1
webapp/src/api/development/notebook.js View 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.


+ 9
- 1
webapp/src/api/model/model.js View 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.
@@ -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
- 1
webapp/src/api/model/modelVersion.js View 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.


+ 107
- 0
webapp/src/api/modelOptimize/optimize.js View File

@@ -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 };

webapp/src/api/system/harbor.js → webapp/src/api/modelOptimize/record.js View 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.
@@ -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
- 1
webapp/src/api/preparation/annotation.js View 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
- 1
webapp/src/api/preparation/datafile.js View 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.


+ 3
- 3
webapp/src/api/preparation/datalabel.js View 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.
@@ -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',
});
}


+ 20
- 2
webapp/src/api/preparation/dataset.js View 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.
@@ -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',
});


+ 3
- 2
webapp/src/api/preparation/labelGroup.js View 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.
@@ -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,
});
}



+ 170
- 0
webapp/src/api/preparation/medical.js View File

@@ -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 };


+ 63
- 0
webapp/src/api/preparation/textData.js View File

@@ -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
- 1
webapp/src/api/system/dict.js View 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
- 1
webapp/src/api/system/dictDetail.js View 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
- 1
webapp/src/api/system/node.js View 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
- 1
webapp/src/api/system/pod.js View 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.


+ 8
- 1
webapp/src/api/system/role.js View 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.
@@ -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
- 1
webapp/src/api/system/user.js View 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.


+ 19
- 2
webapp/src/api/trainingImage/index.js View 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.
@@ -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,
});
}



+ 9
- 1
webapp/src/api/trainingJob/job.js View 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.
@@ -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
- 1
webapp/src/api/trainingJob/params.js View 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
- 1
webapp/src/api/user.js View 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
- 1
webapp/src/api/visual/index.js View 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.


BIN
webapp/src/assets/images/dataset/medicalDataset.png View File

Before After
Width: 512  |  Height: 512  |  Size: 37 kB

BIN
webapp/src/assets/images/dataset/normalDataset.png View File

Before After
Width: 512  |  Height: 512  |  Size: 28 kB

+ 82
- 1
webapp/src/assets/styles/atomic.scss View 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.
@@ -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;
}

+ 15
- 0
webapp/src/assets/styles/common.scss View File

@@ -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;
}

+ 9
- 0
webapp/src/assets/styles/mixin.scss View File

@@ -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
- 1
webapp/src/boot/errorHandle.js View 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
- 1
webapp/src/boot/index.js View 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.


+ 9
- 2
webapp/src/components/BaseModal/index.js View 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.
@@ -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
- 1
webapp/src/components/Card/info.vue View 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
- 1
webapp/src/components/Drag/drag.vue View 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
- 1
webapp/src/components/Drag/index.js View 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.


+ 7
- 2
webapp/src/components/DropdownHeader/index.vue View 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.
@@ -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
- 1
webapp/src/components/Exception/index.vue View 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
- 1
webapp/src/components/IconFont/icon.js View 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
- 1
webapp/src/components/IconFont/iconfont.js View 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.


+ 2
- 2
webapp/src/components/IconFont/index.js View 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.
@@ -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
- 1
webapp/src/components/IconFont/utils.js View 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
- 1
webapp/src/components/ImageGallery/index.vue View 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
- 1
webapp/src/components/InfoSelect/index.js View 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
- 1
webapp/src/components/InfoSelect/info-select.vue View 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
- 1
webapp/src/components/InfoTable/column.js View 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
- 1
webapp/src/components/InfoTable/index.js View 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.


+ 24
- 7
webapp/src/components/InfoTable/info-table.vue View 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.
@@ -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();
}, {


+ 6
- 3
webapp/src/components/InlineTableEdit/index.vue View 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.
@@ -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();
});
};


+ 6
- 2
webapp/src/components/LogContainer/index.vue View 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.
@@ -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')}`;


+ 364
- 0
webapp/src/components/LogContainer/podLogContainer.vue View File

@@ -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
- 1
webapp/src/components/LoginPublic/index.vue View 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.


+ 2
- 1
webapp/src/components/Prism/index.vue View 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.
@@ -47,6 +47,7 @@ export default {

code[class*="language-"],
pre[class*="language-"] {
word-wrap: break-word;
white-space: pre-wrap;
}
</style>

+ 1
- 1
webapp/src/components/SortingMenu/index.vue View 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.


+ 2
- 2
webapp/src/components/Training/algorithmDetail.vue View 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.
@@ -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
- 1
webapp/src/components/Training/dataSourceSelector.vue View 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.


+ 383
- 96
webapp/src/components/Training/jobForm.vue View 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.
@@ -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>

+ 6
- 2
webapp/src/components/Training/paramPair.vue View 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.
@@ -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',


+ 5
- 15
webapp/src/components/Training/runParamForm.vue View 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.
@@ -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
- 1
webapp/src/components/Training/saveModelDialog.vue View 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.


webapp/src/api/dashboard/index.js → webapp/src/components/UploadForm/FileFilter.js View 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.
@@ -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;
}
}

+ 56
- 35
webapp/src/components/UploadForm/form.js View 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.
@@ -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>


+ 26
- 6
webapp/src/components/UploadForm/index.vue View 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.
@@ -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 = () => {


+ 25
- 9
webapp/src/components/UploadForm/inline.vue View 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.
@@ -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
- 1
webapp/src/components/UploadForm/style.scss View 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.


+ 24
- 8
webapp/src/components/UploadForm/util.js View 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.
@@ -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 }) => {


+ 3
- 3
webapp/src/components/UploadProgress/index.vue View 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.
@@ -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
- 1
webapp/src/components/ZoomContainer/index.vue View 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
- 1
webapp/src/components/svg/brush/Brush.js View 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
- 1
webapp/src/components/svg/brush/BrushCorner.js View 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
- 1
webapp/src/components/svg/brush/BrushHandle.js View 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
- 1
webapp/src/components/svg/brush/BrushSelection.js View 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
- 1
webapp/src/components/svg/brush/index.js View 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
- 1
webapp/src/components/svg/group/index.js View 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
- 1
webapp/src/components/svg/index.js View 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.


+ 51
- 0
webapp/src/components/textEditor.vue View File

@@ -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>

+ 11
- 29
webapp/src/config/index.js View 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.
@@ -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
- 1
webapp/src/directives/index.js View 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
- 1
webapp/src/directives/modules/clickOnce.js View 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
- 1
webapp/src/directives/modules/elSelectLoadMore.js View 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
- 1
webapp/src/directives/modules/mouseWheel.js View 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
- 1
webapp/src/hooks/brush/BasicBrush.js View 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
- 1
webapp/src/hooks/brush/index.js View 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
- 1
webapp/src/hooks/brush/useBrush.js View 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.


Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save