Browse Source

model manage

pull/3226/head
chenshihai 2 years ago
parent
commit
fdec16f22e
4 changed files with 249 additions and 105 deletions
  1. +3
    -1
      web_src/vuepages/apis/modules/fileupload.js
  2. +12
    -0
      web_src/vuepages/apis/modules/modelmanage.js
  3. +4
    -3
      web_src/vuepages/pages/modelmanage/local/modelmanage-local-create-1.vue
  4. +230
    -101
      web_src/vuepages/pages/modelmanage/local/modelmanage-local-create-2.vue

+ 3
- 1
web_src/vuepages/apis/modules/fileupload.js View File

@@ -1,4 +1,5 @@
import service from "../service";
import Qs from 'qs';

// 上传文件1: 获取文件chunks信息
// params: { md5, type: 0-CPU/GPU,1-NPU, file_name, scene: ''-数据集,'model'-模型 }
@@ -42,7 +43,8 @@ export const setCompleteMultipart = (data) => {
return service({
url: `/attachments/complete_multipart`,
method: 'post',
headers: { 'Content-type': 'application/x-www-form-urlencoded' },
params: {},
data,
data: Qs.stringify(data),
});
};

+ 12
- 0
web_src/vuepages/apis/modules/modelmanage.js View File

@@ -12,6 +12,18 @@ export const saveLocalModel = (data) => {
});
};

// 修改模型
// data: {id,type,name,version,engine,label,description:}
export const modifyModel = (data) => {
return service({
url: `${data.repo}/modelmanage/modify_model`,
method: 'put',
headers: { 'Content-type': 'application/x-www-form-urlencoded' },
params: {},
data: Qs.stringify(data),
});
};

// 求模型信息
export const getModelInfoByName = (params) => {
return service({


+ 4
- 3
web_src/vuepages/pages/modelmanage/local/modelmanage-local-create-1.vue View File

@@ -103,7 +103,7 @@

<script>

import { saveLocalModel, getModelInfoByName } from '~/apis/modules/modelmanage';
import { saveLocalModel, getModelInfoByName, modifyModel } from '~/apis/modules/modelmanage';
// import { CLUSTERS, COMPUTER_RESOURCES, ACC_CARD_TYPE } from '~/const';
import { getUrlSearchParams } from '~/utils';
// import { formatDate } from 'element-ui/lib/utils/date-util';
@@ -137,7 +137,8 @@ export default {
});
return;
}
saveLocalModel({
const submintApi = this.type == '1' ? modifyModel : saveLocalModel;
submintApi({
repo: location.pathname.split('/').slice(0, 3).join('/'),
...this.state,
}).then(res => {
@@ -154,7 +155,7 @@ export default {
} else {
this.$message({
type: 'error',
message: '模型保存失败',
message: this.type == '1' ? '模型修改失败' : '保存模型失败',
});
}
}).catch(err => {


+ 230
- 101
web_src/vuepages/pages/modelmanage/local/modelmanage-local-create-2.vue View File

@@ -3,7 +3,7 @@
<div class="header">
<span class="title">{{ type == '1' ? '增加模型文件' : '上传模型文件' }}</span>
</div>
<div class="content">
<div class="content ui form">
<div class="guide-c" v-if="type != '1'">
<div class="step">
<div class="num">1</div>
@@ -26,22 +26,50 @@
<div class="row" style="align-items:flex-start;">
<div class="r-title"><label class="required">文件上传</label></div>
<div class="r-content">
<div>
<form class="dropzone" ref="dropzoneRef"></form>
<div style="position:relative">
<form class="dropzone" ref="dropzoneRef" @click="">
<div class="dropzon-err-tips ui red message" v-show="showUploadErr" style="display:none;margin:2.5rem">
{{ uploadErrTxt }}</div>
</form>
<div class="not-allowed-placeholder" v-show="uploading"></div>
</div>
</div>
</div>
<div class="row" style="margin-top:10px">
<div class="r-title"><label></label></div>
<div class="r-content">
<el-button size="medium" class="green" @click="submit">上传</el-button>
<el-button size="medium" class="green" @click="submit" :disabled="uploading">上传</el-button>
<el-button size="medium" @click="cancel">取消</el-button>
</div>
</div>
<div class="row" style="align-items:flex-start;">
<div class="r-title"><label>上传状态:</label></div>
<div class="r-content">

<div v-for="(item, index) in uploadFiles" :key="item.upload.uuid" class="datast-upload-progress">
<span class="dataset-name nowrap" :title="item.name">{{ item.name }}</span>
<div class="dataset-progress">
<el-progress :text-inside="true" :stroke-width="14" :percentage="uploadProgressList[index].progress">
</el-progress>
</div>
<div class="dataset-status nowrap">
<div class="status-flex">
<i v-if="
uploadProgressList[index].infoCode === 1 ||
uploadProgressList[index].infoCode === 2
" class="ri-close-circle-line failed"></i>
<i v-if="uploadProgressList[index].infoCode === 0" class="ri-checkbox-circle-line success">
</i>
<span>{{ uploadProgressList[index].status }}</span>
<el-tooltip v-if="uploadProgressList[index].infoCode === 1" class="item" effect="dark"
placement="top">
<div slot="content">
{{ uploadProgressList[index].failedInfo }}
</div>
<i style="font-size: 16px; margin-left: 0.5rem; cursor: pointer" class="ri-question-fill"></i>
</el-tooltip>
</div>
</div>
</div>
</div>
</div>
</div>
@@ -53,10 +81,7 @@

import { getModelInfoByName } from '~/apis/modules/modelmanage';
import { getChunks, getNewMultipart, getMultipartUrl, setCompleteMultipart } from '~/apis/modules/fileupload';
// import { CLUSTERS, COMPUTER_RESOURCES, ACC_CARD_TYPE } from '~/const';
import { getUrlSearchParams } from '~/utils';
// import { formatDate } from 'element-ui/lib/utils/date-util';

import 'dropzone/dist/dropzone.css';
import Dropzone from 'dropzone';
import SparkMD5 from "spark-md5";
@@ -65,6 +90,8 @@ Dropzone.autoDiscover = false;

const uploadChunkSize = 1024 * 1024 * 64;
const md5ChunkSize = 1024 * 1024 * 64;
const maxFileSize = 10;
const maxModelFilesSize = 200 * 1024 * 1024 * 1024; // 200 GB

export default {
data() {
@@ -80,35 +107,77 @@ export default {
label: '',
description: '',
size: '',
}
},
originData: null,
showUploadErr: false,
uploadErrTxt: '',
defaultErrTxt: '单次最多上传10个文件,模型总文件大小不超过200G',

uploadFiles: [],
uploadLength: 0,
uploadProgressList: [],

uploading: false,
};
},
components: { /*QueueDialog*/ },
components: {},
methods: {
initDropZone() {
this.dropzoneHandler = new Dropzone(this.$refs.dropzoneRef, {
url: '/',
maxFiles: 10,
parallelUploads: 20,
uploadMultiple: true,
maxFilesize: 2048,
maxFilesize: maxModelFilesSize,
timeout: 0,
addRemoveLinks: true,
autoProcessQueue: false,
dictDefaultMessage: '点击添加文件或直接拖拽文件到此处',
dictInvalidFileType: 'dictInvalidFileType',
dictFileTooBig: 'dictFileTooBig',
dictRemoveFile: 'dictRemoveFile',
dictRemoveFile: '移除文件',
dictMaxFilesExceeded: this.defaultErrTxt,
});
this.dropzoneHandler.on("addedfile", file => {
console.log(`File added: ${file.name}`);
console.log(file);
// this.calcFileMd5(file);
this.checkFiles(file);
});
this.dropzoneHandler.on("removedfile", file => {
console.log(`File removedfile: ${file.name}`);
this.dropzoneHandler.on("removedfile", file => {
this.checkFiles();
});
this.dropzoneHandler.on("maxfilesexceeded", file => {
console.log(`File removedfile: ${file.name}`);
},
showUploadErrInfo(state, info) {
if (state) {
this.uploadErrTxt = info;
this.showUploadErr = true;
} else {
this.uploadErrTxt = '';
this.showUploadErr = false;
}
},
checkFiles(file) {
const fileList = this.dropzoneHandler.getAcceptedFiles();
const filesSize = fileList.reduce((acc, item, index) => acc + item.size, 0) + (file ? file.size : 0);
const filesCount = fileList.length + (file ? 1 : 0);
const allfilesSize = filesSize + this.state.size;
if (filesCount > maxFileSize || allfilesSize > maxModelFilesSize) {
this.showUploadErrInfo(true, this.defaultErrTxt);
return false;
}
this.showUploadErrInfo(false);
return true;
},
resetFileStatus() {
this.uploadFiles = [];
this.uploadLength = 0;
this.uploadProgressList = [];
},
updateProgress(file, status, progress, infoCode, failedInfo = "") { // updateFileStatus
this.uploadProgressList.forEach((item, index) => {
if (item.uploadUuid === file.upload.uuid) {
this.uploadProgressList[index].status = status;
this.uploadProgressList[index].progress = progress;
this.uploadProgressList[index].infoCode = infoCode;
this.uploadProgressList[index].failedInfo = failedInfo;
}
});
},
calcFileMd5(file) {
@@ -122,16 +191,20 @@ export default {
file.totalChunkCounts = 1;
}
let currentChunk = 0;
this.uploadProgressList.push({
uploadUuid: file.upload.uuid,
name: file.name,
status: '计算文件MD5...',
progress: 0,
infoCode: 3,
});
return new Promise((resolve, reject) => {
fileReader.onload = function (e) {
console.log(file.name + ': read chunk nr', currentChunk + 1, 'of', chunks);
spark.append(e.target.result);
currentChunk++;
if (currentChunk < chunks) {
loadNext();
} else {
console.log(file.name + ': finished loading');
console.info(file.name + ': computed hash', spark.end());
const md5 = spark.end();
spark.destroy();
file.uniqueIdentifier = md5;
@@ -139,7 +212,7 @@ export default {
}
};
fileReader.onerror = function (e) {
console.warn(file.name + ': oops, calcFileMd5 went wrong.');
console.warn(file.name + ': calcFileMd5 went wrong.');
reject(e);
};

@@ -151,33 +224,6 @@ export default {
loadNext();
});
},
async _getChunksInfo(file) {
const params = {
params: {
md5: file.uniqueIdentifier,
type: this.state.type,
file_name: file.name,
_csrf: csrf,
},
};
try {
// const response = axios.get("/attachments/get_chunks", params);
const response = await getChunks(params);
file.uploadID = response.data.uploadID;
file.uuid = response.data.uuid;
file.uploaded = response.data.uploaded;
file.chunks = response.data.chunks;
file.attachID = response.data.attachID;
file.datasetID = response.data.datasetID;
file.datasetName = response.data.datasetName;
file.realName = response.data.fileName;
return file;
} catch (error) {
this.emitDropzoneFailed(file);
console.log("getChunksInfo catch: ", error);
return null;
}
},
getChunksInfo(file) {
return getChunks({
md5: file.uniqueIdentifier,
@@ -191,10 +237,8 @@ export default {
file.uploaded = data.uploaded;
file.chunks = data.chunks;
file.attachID = data.attachID;
// file.datasetID = data.datasetID;
// file.datasetName = data.datasetName;
file.modelUuid = data.modeluuid;
file.modelName = data.modelName;
file.modelUuid = data.modeluuid || file.modelUuid;
file.modelName = data.modelName || file.modelName;
file.realName = data.fileName;
return file;
}).catch(err => {
@@ -202,21 +246,6 @@ export default {
return err;
});
},
async _newUpload(file) {
const res = await axios.get("/attachments/new_multipart", {
params: {
totalChunkCounts: file.totalChunkCounts,
md5: file.uniqueIdentifier,
size: file.size,
fileType: file.type,
type: this.uploadtype,
file_name: file.name,
_csrf: csrf,
},
});
file.uploadID = res.data.uploadID;
file.uuid = res.data.uuid;
},
newUpload(file) {
return getNewMultipart({
totalChunkCounts: file.totalChunkCounts,
@@ -234,19 +263,24 @@ export default {
if (file.uploadID && file.uuid) {
file.chunks = '';
this.breakpointUpload(file);
} else {
this.uploadError(file, info);
this.updateProgress(file, "上传失败", 0, 2);
}
return file;
}).catch(err => {
console.log('getNewMultipart', err);
this.uploadError(file, info);
this.updateProgress(file, "上传失败", 0, 2);
return err;
});
},
breakpointUpload(file) {
const blobSlice = File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice;
const chunks = Math.ceil(file.size / chunkSize);
const fileReader = new FileReader();
const time = new Date().getTime();
const chunkSize = uploadChunkSize;
const chunks = Math.ceil(file.size / chunkSize);
const _this = this;
let currentChunk = 0;
const successChunks = [];
@@ -256,7 +290,7 @@ export default {
}
const urls = [];
const etags = [];
function checkSuccessChunks() {
const checkSuccessChunks = () => {
const index = successChunks.indexOf((currentChunk + 1).toString());
if (index == -1) {
return false;
@@ -264,7 +298,7 @@ export default {
return true;
}

async function getUploadChunkUrl(currentChunk, partSize) {
const getUploadChunkUrl = async (currentChunk, partSize) => {
const res = await getMultipartUrl({
uuid: file.uuid,
uploadID: file.uploadID,
@@ -275,9 +309,9 @@ export default {
scene: 'model',
});
urls[currentChunk] = res.data.url;
}
};

async function uploadMinioNewMethod(url, e) {
const uploadMinioNewMethod = async (url, e) => {
const xhr = new XMLHttpRequest();
xhr.open("PUT", url, false);
if (_this.state.type == 0) {
@@ -293,7 +327,7 @@ export default {
}
}

async function uploadChunk(e) {
const uploadChunk = async (e) => {
try {
if (!checkSuccessChunks()) {
const start = currentChunk * chunkSize;
@@ -315,7 +349,7 @@ export default {
}
}

async function completeUpload() {
const completeUpload = async () => {
return await setCompleteMultipart({
uuid: file.uuid,
uploadID: file.uploadID,
@@ -339,68 +373,106 @@ export default {
fileReader.abort();
currentChunk++;
if (currentChunk < chunks) {
console.log(`第${currentChunk}个分片上传完成, 开始第${currentChunk + 1}/${chunks}个分片上传`);
// this.progress = Math.ceil((currentChunk / chunks) * 100);
// this.updateProgress(file, this.dropzoneParams.data("uploading"), Number(((currentChunk / chunks) * 100).toFixed(2)), 3);
// this.status = `${this.dropzoneParams.data("uploading")} ${((currentChunk / chunks) * 100).toFixed(2)}%`;
console.log(`第${currentChunk}个分片上传完成, 开始第${currentChunk + 1}/${chunks}个分片上传`);
this.updateProgress(file, '上传中...', Number(((currentChunk / chunks) * 100).toFixed(2)), 3);
loadNext();
} else {
try {
await completeUpload();
console.log(`文件上传完成:${file.name} \n分片:${chunks} 大小:${file.size} 用时:${(new Date().getTime() - time) / 1000} s`);
// this.uploadLength++;
// this.allUploadLength++;
// this.updateProgress(file, "上传成功", 100, 0);
// this.finishUpload(file);
this.uploadLength++;
this.updateProgress(file, "上传成功", 100, 0);
this.uploadSuccess(file);
} catch (err) {
const info = "上传失败";
console.log(info, file)
// this.allUploadLength++;
// this.uploadError(file, info);
// this.updateProgress(file, info, Number(((currentChunk / chunks) * 100).toFixed(2)) - 1, 2);
this.uploadLength++;
this.uploadError(file, info);
this.updateProgress(file, info, Number(((currentChunk / chunks) * 100).toFixed(2)) - 1, 2);
}
}
} catch (err) {
console.log(err);
const info = "上传失败";
console.log(info, file)
this.uploadLength++;
this.uploadError(file, info);
this.updateProgress(file, info, Number(((currentChunk / chunks) * 100).toFixed(2)) - 1, 2);
}
};
console.log("上传分片...");
loadNext();
},
uploadError(file, info) {
file.previewTemplate.querySelector('.dz-success-mark').style.opacity = 0;
file.previewTemplate.querySelector('.dz-error-mark').style.opacity = 1;
file.previewTemplate.querySelector('.dz-error-message span').innerHTML = info;
file.previewTemplate.querySelector(".dz-error-message").style.display = 'block';
file.previewTemplate.querySelector(".dz-details").onmouseover = () => {
file.previewTemplate.querySelector('.dz-error-message').style.opacity = 1;
};
file.previewTemplate.querySelector(".dz-details").onmouseout = () => {
file.previewTemplate.querySelector('.dz-error-message').style.opacity = 0;
};
this.uploadFinishCheck(file);
},
uploadSuccess(file) {
file.previewTemplate.querySelector('.dz-error-mark').style.opacity = 0;
file.previewTemplate.querySelector('.dz-error-message span').innerHTML = '';
file.previewTemplate.querySelector('.dz-success-mark').style.opacity = 1;
file.previewTemplate.querySelector(".dz-error-message").style.display = 'none';
file.previewTemplate.querySelector(".dz-details").onmouseover = null;
file.previewTemplate.querySelector(".dz-details").onmouseout = null;
this.uploadFinishCheck(file);
},
uploadFinishCheck(file) {
console.log('uploadFinishCheck', file, this.uploadLength, '/', this.uploadFiles.length);
if (this.uploadLength === this.uploadFiles.length) {
console.log('All file has finish');
this.uploading = false;
}
},
submit() {
console.log(this.dropzoneHandler);
const fileList = this.dropzoneHandler.getAcceptedFiles();
if (!fileList.length) return;
this.resetFileStatus();
this.uploadFiles = fileList;
this.uploading = true;
for (let i = 0, iLen = fileList.length; i < iLen; i++) {
const file = fileList[i];
file.modelUuid = this.state.id;
file.modelName = this.state.name;
this.calcFileMd5(file).then(res => { // 计算MD5
this.getChunksInfo(file).then(res => { // 获取Chunk信息
if (file.uploadID == '' || file.uuid == '') { // 未上传过
this.newUpload(file);
} else if (file.uploaded == '1') { // 已上传成功 秒传
} else if (file.uploaded == '1') { // 已上传成功 秒传
if (file.attachID == '0') { // 删除数据集记录,未删除文件
// await addAttachment(file);
console.log(`file.attachID == '0'`);
}
// 同一模型上传同一个文件
if (file.modelUuid != '') {
if (file.modelName != '' && file.realName != '') {
let info = `该文件已上传在模型: ${file.modelName}`;
console.log(info);
// this.uploadError(file, info);
// this.allUploadLength++;
// this.updateProgress(file, "上传失败", 0, 1, info);
}
if (file.modelUuid != '' && file.modelName != '' && file.realName != '') {
const info = `该文件已上传在模型: ${file.modelName}`;
this.uploadLength++;
this.uploadError(file, info);
this.updateProgress(file, "上传失败", 0, 1, info);
}
console.log('文件上传处理完成');
console.log(file.name, '文件处理完成');
} else { // 断点续传
this.breakpointUpload(file);
}
}).catch(err => {
console.info('getChunksInfo', err);
this.uploadLength++;
this.uploadError(file, "上传失败");
this.updateProgress(file, "上传失败", 0, 2);
});
}).catch(err => {
console.info('calcFileMd5', err);
this.uploadLength++;
this.uploadError(file, '上传失败');
this.updateProgress(file, "上传失败", 0, 2);
});
}
},
@@ -434,7 +506,10 @@ export default {
this.state.engine = data.engine.toString();
this.state.label = data.label;
this.state.description = data.description;
this.state.size = data.size;
this.state.size = data.size || 0;
this.originData = data;
} else {
this.cancel();
}
}).catch(err => {
this.loading = false;
@@ -529,7 +604,6 @@ export default {
justify-content: center;
flex-direction: column;
margin: 0 auto;
width: 80%;

.row {
width: 100%;
@@ -593,6 +667,27 @@ export default {
}
}

.not-allowed-placeholder {
position: absolute;
width: 100%;
height: 100%;
z-index: 20;
cursor: no-drop;
top: 0;
}

.dropzone {
min-height: 186px !important;

/deep/ .dz-default.dz-message {
margin: 76px 0 !important;
}

/deep/ .dz-remove {
margin-top: 10px !important;
}
}

.input-disabled {
/deep/ .el-input__inner {
background-color: #f5f5f6 !important;
@@ -604,6 +699,40 @@ export default {
display: none;
}

.success {
color: #21ba45;
font-size: 16px;
margin-right: 0.5rem;
}
.failed {
color: red;
font-size: 16px;
margin-right: 0.5rem;
}
.datast-upload-progress {
display: flex;
align-items: center;
}
.datast-upload-progress .dataset-name {
text-align: right;
width: 200px;
margin-right: 1rem;
}
.datast-upload-progress .dataset-progress {
flex: 1;
}
.datast-upload-progress .dataset-status {
width: 100px;
margin-left: 1rem;
}
.datast-upload-progress .dataset-status .status-flex {
display: flex;
align-items: center;
}
/deep/ .el-progress-bar__inner {
background-color: #21ba45;
}

.el-select-dropdown__item.selected {
color: #85b7d9;
}


Loading…
Cancel
Save