Browse Source

model manage

tags/v1.22.11.2^2
chenshihai 2 years ago
parent
commit
b94db568c7
6 changed files with 533 additions and 533 deletions
  1. +5
    -528
      templates/repo/modelmanage/showinfo.tmpl
  2. +11
    -0
      web_src/vuepages/apis/modules/modelmanage.js
  3. +482
    -0
      web_src/vuepages/pages/modelmanage/common/modelmanage-common-detail.vue
  4. +17
    -0
      web_src/vuepages/pages/modelmanage/common/vp-modelmanage-common-detail.js
  5. +7
    -5
      web_src/vuepages/pages/modelmanage/local/modelmanage-local-create-2.vue
  6. +11
    -0
      web_src/vuepages/utils/index.js

+ 5
- 528
templates/repo/modelmanage/showinfo.tmpl View File

@@ -1,533 +1,10 @@
{{template "base/head" .}}
<div class="repository">
<link rel="stylesheet" href="{{StaticUrlPrefix}}/css/vp-modelmanage-common-detail.css?v={{MD5 AppVer}}" />
<div class="repository release dataset-list view">
{{template "repo/header" .}}
<style>
.model_header_text{
font-size: 14px;
color: #101010;
font-weight: bold;
}
.ti_form{
text-align: left;
max-width: 100%;
vertical-align: middle;
}
.ti-text-form-label {
padding-bottom: 20px;
padding-right: 20px;
color: #8a8e99;
font-size: 14px;
white-space: nowrap !important;
width: 80px;
line-height: 30px;
}
.ti-text-form-content {
line-height: 30px;
padding-bottom: 20px;
width: 100%;
}
.change-version{
min-width: auto !important;
border: 1px solid rgba(187, 187, 187, 100) !important;
border-radius: .38571429rem !important;
margin-left: 1.5em;
}
.title-word-elipsis{
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
width: 30%;
}
.word-elipsis{
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
padding-right: 80px;
}
.half-table{
width: 50%;
float: left;
}
.text-width80 {
width: 100px;
line-height: 30px;
}
.tableStyle{
width:100%;
table-layout: fixed;
}
.iword-elipsis{
display: inline-block;
width: 80%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
</style>
<div class="ui container">
<h4 class="ui header" id="vertical-segment">
<!-- <a href="javascript:window.history.back();"><i class="arrow left icon"></i>返回</a> -->
<div class="ui breadcrumb">
<a class="section" href="{{$.RepoLink}}/modelmanage/show_model">
{{$.i18n.Tr "repo.model.manage.model_manage"}}
</a>
<div class="divider"> / </div>
<div class="active section">{{.name}}</div>
</div>
<select class="ui dropdown tiny change-version" id="dropdown" onchange="changeInfo(this.value)">
</select>
</h4>
<div id="showInfo" style="border:1px solid #e2e2e2;padding: 20px 60px;margin-top:24px">
<div class="ui pointing secondary menu" style="border-bottom: 1px solid rgba(34,36,38,.15);">
<a class="active item" data-tab="first">{{$.i18n.Tr "repo.modelarts.train_job.config"}}</a>
<a class="item" data-tab="second">{{$.i18n.Tr "repo.model_download"}}</a>
</div>
<div class="ui tab active" data-tab="first">
<div class="half-table">
<span class="model_header_text">{{$.i18n.Tr "repo.model.manage.baseinfo"}}</span>
<table class="tableStyle" style="margin-top:20px;">
<tbody>
<tr>
<td class="ti-text-form-label text-width80">{{$.i18n.Tr "repo.model.manage.model_name"}}</td>
<td class="ti-text-form-content word-elipsis"><span id="modelName" title=""></span></td>
</tr>
<tr>
<td class="ti-text-form-label text-width80">{{$.i18n.Tr "repo.model.manage.version"}}</td>
<td class="ti-text-form-content word-elipsis"><span id="version" title=""></span></td>
</tr>
<tr>
<td class="ti-text-form-label text-width80">{{$.i18n.Tr "repo.migrate_items_labels"}}</td>
<td class="ti-text-form-content">
<div id="label" style="overflow: hidden;width: 95%;">
</div>
</td>
</tr>
<tr>
<td class="ti-text-form-label text-width80">{{$.i18n.Tr "repo.modelarts.model_size"}}</td>
<td class="ti-text-form-content word-elipsis"><span id="size" title=""></span></td>
</tr>
<tr>
<td class="ti-text-form-label text-width80">{{$.i18n.Tr "repo.modelarts.createtime"}}</td>
<td class="ti-text-form-content word-elipsis"><span id="createTime" title=""></span></td>
</tr>
<tr>
<td class="ti-text-form-label text-width80">{{$.i18n.Tr "repo.model.manage.description"}}</td>
<td class="ti-text-form-content" >
<div id="edit-td" style="display:flex">
<span id="description" title="" class="iword-elipsis"></span>
<i id="edit-pencil" data-id="" data-desc="" class="pencil alternate icon" style="cursor:pointer;vertical-align: top;" id="editor" onclick="editorFn(this)"></i>
</div>
</td>
</tr>
<tr>
<td class="ti-text-form-label text-width80">{{$.i18n.Tr "repo.modelarts.train_job"}}</td>
<td class="ti-text-form-content word-elipsis">
<a id="displayJobNameHref" class="title" style="font-size: 14px;" target="_blank">
<span id="displayJobName" class="fitted" style="width: 90%;vertical-align: middle;"></span>
</a>
</td>
</tr>
<tr>
<td class="ti-text-form-label text-width80">{{$.i18n.Tr "repo.modelarts.code_version"}}</td>
<td class="ti-text-form-content word-elipsis"><span id="codeBranch" title=""></span></td>
</tr>
<tr>
<td class="ti-text-form-label text-width80">{{$.i18n.Tr "repo.modelarts.train_job.start_file"}}</td>
<td class="ti-text-form-content word-elipsis"><span id="bootFile" title=""></span></td>
</tr>
<tr>
<td class="ti-text-form-label text-width80">{{$.i18n.Tr "repo.modelarts.train_job.train_dataset"}}</td>
<td class="ti-text-form-content word-elipsis"><span id="datasetName" title=""></span></td>
</tr>
<tr>
<td class="ti-text-form-label text-width80">{{$.i18n.Tr "repo.modelarts.train_job.run_parameter"}}</td>
<td class="ti-text-form-content word-elipsis"><span id="parameters" title=""></span></td>
</tr>
<tr>
<td class="ti-text-form-label text-width80">{{$.i18n.Tr "repo.modelarts.train_job.AI_Engine"}}</td>
<td class="ti-text-form-content word-elipsis"><span id="engineName" title=""></span></td>
</tr>
<tr>
<td class="ti-text-form-label text-width80">{{$.i18n.Tr "repo.modelarts.train_job.standard"}}</td>
<td class="ti-text-form-content word-elipsis"><span id="flavorName" title=""></span></td>
</tr>
<tr>
<td class="ti-text-form-label text-width80">{{$.i18n.Tr "repo.modelarts.train_job.compute_node"}}</td>
<td class="ti-text-form-content word-elipsis"><span id="workServerNumber" title=""></span></td>
</tr>
</tbody>
</table>
</div>
<div class="half-table">
<span class="model_header_text">{{$.i18n.Tr "repo.model.manage.model_accuracy"}}</span>
<table class="tableStyle" style="margin-top:20px;">
<tbody>
<tr>
<td class="ti-text-form-label text-width80">{{$.i18n.Tr "repo.model.manage.Accuracy"}}</td>
<td class="ti-text-form-content word-elipsis"><span id="Accuracy" title=""></span></td>
</tr>
<tr>
<td class="ti-text-form-label text-width80">F1</td>
<td class="ti-text-form-content word-elipsis"><span id="F1" title=""></span></td>
</tr>
<tr>
<td class="ti-text-form-label text-width80">{{$.i18n.Tr "repo.model.manage.Precision"}}</td>
<td class="ti-text-form-content word-elipsis"><span id="Precision" title=""></span></td>
</tr>
<tr>
<td class="ti-text-form-label text-width80">{{$.i18n.Tr "repo.model.manage.Recall"}}</td>
<td class="ti-text-form-content word-elipsis"><span id="Recall" title=""></span></td>
</tr>
</tbody>
</table>
</div>
<div style="clear: both;"></div>
</div>
<div class="ui tab" data-tab="second">
<input type="hidden" name="model" value="-1">
<input type="hidden" name="modelback" value="-1">
<div class='ui breadcrumb model_file_bread' id='file_breadcrumb'>
<div class="active section"></div>
<div class="divider"> / </div>
</div>
<div id="dir_list">
</div>
</div>
</div>
</div>
<div id="__vue-root"></div>
</div>
</div>
<script src="{{StaticUrlPrefix}}/js/vp-modelmanage-common-detail.js?v={{MD5 AppVer}}"></script>
{{template "base/footer" .}}
<script>
let url = location.href.split('show_model')[0]
let trainJobUrl =url.split('modelmanage')[0]
let ID = location.search.split('?name=').pop()
$(document).ready(function(){
$('.secondary.menu .item').tab();
});
$(document).ready(loadInfo);
function changeInfo(version){
$.get(`${url}show_model_info_api?name=${ID}`,(data)=>{
let versionData = data.filter((item)=>{
return item.version === version
})
let returnArray = []
returnArray = transObj(versionData)
let [initObj,initModelAcc,id] = returnArray
editorCancel('','')
renderInfo(initObj,initModelAcc,id)
loadModelFile(versionData[0].id,versionData[0].version,'','','init')
})
}
function loadInfo(){
$.get(`${url}show_model_info_api?name=${ID}`,(data)=>{
let html = ''
for (let i=0;i<data.length;i++){
if(!data[i].isCanOper){
$("#edit-pencil").css("display","none")
}
html += `<option value="${data[i].version}">${data[i].version}</option>`
}
$('#dropdown').append(html)
let returnArray = []
returnArray = transObj(data)
let [initObj,initModelAcc,id] = returnArray
renderInfo(initObj,initModelAcc,id)
loadModelFile(data[0].id,data[0].version,'','','init')
})
}
function getEngineName(model){
if(model.engine == 0){
return "PyTorch";
}else if(model.engine == 1 || model.engine == 121 || model.engine == 38){
return "TensorFlow";
}else if(model.engine == 2 || model.engine == 122 || model.engine == 35 || model.engine == 37){
return "MindSpore";
}else if(model.engine == 3){
return "Other";
}else if(model.engine == 4){
return "PaddlePaddle";
}else if(model.engine == 5){
return "OneFlow";
}else if(model.engine == 6){
return "MXNet";
}
else{
return "Other"
}
}
function transObj(data){
let {id,name,version,label,size,description,createdUnix,accuracy,codeBranch,codeCommitID,trainTaskInfo} = data[0]
let modelAcc = JSON.parse(accuracy || '{}')
trainTaskInfo = JSON.parse(trainTaskInfo || '{}')
let engineName = getEngineName(data[0])
parameters = JSON.parse(trainTaskInfo.Parameters || '{}')
parameters = parameters.parameter && parameters.parameter.length === 0 ? '--':parameters.parameter
size = tranSize(size)
let time = transTime(createdUnix)
let initObj = {
modelName:name || '--',
version:version,
label:label || '--',
size:size,
createTime:time,
description:description || '--',
codeBranch:codeBranch || '--',
codeCommitID:codeCommitID || '--',
bootFile:trainTaskInfo.BootFile || '--',
datasetName:trainTaskInfo.DatasetName || '--',
parameters:trainTaskInfo.Parameters || '--',
flavorName:trainTaskInfo.FlavorName || '--',
workServerNumber:trainTaskInfo.WorkServerNumber || '--',
parameters:parameters,
engineName:engineName,
displayJobName:trainTaskInfo.DisplayJobName || '--',
trainJobVersionName:trainTaskInfo.VersionName || '',
cloudBrainJobID:trainTaskInfo.JobID|| '',
cloudBrainType:trainTaskInfo.Type,
}
let initModelAcc = {
Accuracy: modelAcc.Accuracy || '--',
F1: modelAcc.F1 || '--',
Precision:modelAcc.Precision || '--',
Recall: modelAcc.Recall || '--'
}
return [initObj,initModelAcc,id]
}
function transTime(time){
let date = new Date(time * 1000);//时间戳为10位需*1000,时间戳为13位的话不需乘1000
let Y = date.getFullYear() + '-';
let M = (date.getMonth()+1 < 10 ? '0'+(date.getMonth()+1):date.getMonth()+1) + '-';
let D = (date.getDate()< 10 ? '0'+date.getDate():date.getDate())+ ' ';
let h = (date.getHours() < 10 ? '0'+date.getHours():date.getHours())+ ':';
let m = (date.getMinutes() < 10 ? '0'+date.getMinutes():date.getMinutes()) + ':';
let s = date.getSeconds() < 10 ? '0'+date.getSeconds():date.getSeconds();
return Y+M+D+h+m+s;
}
function tranSize(value){
if(null==value||value==''){
return "0 Bytes";
}
var unitArr = new Array("Bytes","KB","MB","GB","TB","PB","EB","ZB","YB");
var index=0;
var srcsize = parseFloat(value);
index=Math.floor(Math.log(srcsize)/Math.log(1024));
var size =srcsize/Math.pow(1024,index);
size=size.toFixed(2);//保留的小数位数
return size+unitArr[index];
}
function editorFn(context){
let id= context.dataset.id
let text = context.dataset.desc
let textValue = text.replace(/enter;/g,'\r\n')
$('#edit-td').replaceWith(`<div id='edit-div' style='width:80%;display: inline-block;'><textarea id='textarea-value' value='' rows='3' maxlength='255' style='width:80%;white-space: nowrap;' id='edit-text'>${textValue}</textarea><i class='check icon' style='color: #50d4ab;' onclick='editorSure("${text}","${id}")'></i><i class='times icon' style='color: #f66f6a;' onclick='editorCancel("${text}","${id}")'></i></div>`);
}
function editorCancel(text,id){
let objkey = text.replace(/enter;/g,'\r\n')
$('#edit-div').replaceWith(`<div id="edit-td" style="display:flex;"><span id="Description" title="${objkey}" class="iword-elipsis">${objkey}</span><i id="edit-pencil" data-id="${id}" data-desc="${text}" class="pencil alternate icon" style="cursor:pointer;vertical-align: top;" id="editor" onclick="editorFn(this)"></div>`)
}
function editorSure(text,id){
let description=$('#textarea-value').val()
let sourcetext = $('#textarea-value').val().replace(/\n/g,'enter;')
let data = {
id:id,
description:description
}
$.ajax({
url:`${url}modify_model`,
type:'PUT',
data:data
}).done((res)=>{
$('#edit-div').replaceWith(`<div id="edit-td" style="display:flex;"><span id="Description" title="${description}" class="iword-elipsis">${description}</span><i id="edit-pencil" data-id="${id}" data-desc="${sourcetext}" class="pencil alternate icon" style="cursor:pointer;vertical-align: top;" id="editor" onclick="editorFn(this)"></div>`)
})
}
function renderInfo(obj,accObj,id){
for(let key in obj){
if(key==="description"){
let descriptionText=obj[key].replace(/\r\n|\n/g,'enter;')
$(`#${key}`).text(obj[key])
$(`#${key}`).attr("title",obj[key])
$('#edit-pencil').attr("data-id",id)
$('#edit-pencil').attr("data-desc",descriptionText)
}
else if(key==="label"){
$('#Label').empty()
if(obj[key]==='--'){
$('#Label').text(obj[key])
}else{
let labelArray = obj[key].trim().replace(/ +/g,' ').split(' ')
let html=''
for(let i=0;i<labelArray.length;i++){
html += `<a class="ui label" title="${labelArray[i]}">${labelArray[i]}</a>`
}
$('#Label').append(html)
}
}
else if(key==="codeCommitID"){
let codeCommit = obj[key].slice(0,10)
let html = `<a style="margin-left:1rem" class="ui label" title="${codeCommit}">${codeCommit}</a>`
$('#CodeBranch').append(html)

}
else if(key==="displayJobName"){
let type=obj["cloudBrainType"]
let href=""
if(type==1){
href=trainJobUrl + "modelarts/train-job/" + obj["cloudBrainJobID"]
}else if(type==0){
href=trainJobUrl + "cloudbrain/train-job/" + obj["cloudBrainJobID"]
}else if(type==2){
href=trainJobUrl + "grampus/train-job/" + obj["CloudBrainJobID"]
}
$(`#displayJobNameHref`).attr("href",href)
$(`#displayJobNameHref`).attr("title",obj[key])
$(`#${key}`).text(obj[key])

let versionName = obj["trainJobVersionName"]
if(versionName!=""){
let html = `<span style="margin-left:1rem" class="ui label">${versionName}</span>`
$('#displayJobName').append(html)
}
}
else if(key==="parameters"){
if(obj[key]==='--'){
$(`#${key}`).text(obj[key])
}else{
const parameterArray = (obj[key] || []).map(element => {
let labelValue = `${element.label}=${element.value}`
return labelValue
});
const parameter = parameterArray.join('; ')
$(`#${key}`).text(parameter)
$(`#${key}`).attr("title",parameter)
}
}
else{
$(`#${key}`).text(obj[key])
$(`#${key}`).attr("title",obj[key])
}
}
for(let key in accObj){
$(`#${key}`).text(accObj[key])
$(`#${key}`).attr("title",accObj[key])
}
}

function loadModelFile(ID,version_name,parents,filename,init){
$.get(`${url}query_onelevel_modelfile?ID=${ID}&parentDir=${parents}`, (data) => {
$('#dir_list').empty()
renderDir(data,ID,version_name)
if(init==="init"){
$('input[name=model]').val("")
$('input[name=modelback]').val(version_name)
$('#file_breadcrumb').empty()
let htmlBread = ""
htmlBread += `<div class='active section'>${version_name}</div>`
htmlBread += "<div class='divider'> / </div>"
$('#file_breadcrumb').append(htmlBread)
}else{
renderBrend(ID,version_name,parents,filename,init)
}
})
}
function renderSize(value){
if(null==value||value==''){
return "0 Bytes";
}
var unitArr = new Array("Bytes","KB","MB","GB","TB","PB","EB","ZB","YB");
var index=0;
var srcsize = parseFloat(value);
index=Math.floor(Math.log(srcsize)/Math.log(1024));
var size =srcsize/Math.pow(1024,index);
size=size.toFixed(2);//保留的小数位数
return size+unitArr[index];
}

function renderBrend(ID,version_name,parents,filename,init){
if(init=="folder"){
let htmlBrend = ""
let sectionName=$('#file_breadcrumb .active.section').text()
let parents1 = $('input[name=model]').val()
let filename1 = $('input[name=modelback]').val()
if(parents1===""){
$('#file_breadcrumb .active.section').replaceWith(`<a class='section' onclick="loadModelFile('${ID}','${version_name}','${parents1}','','init')">${sectionName}</a>`)
}else{
$('#file_breadcrumb .active.section').replaceWith(`<a class='section' onclick="loadModelFile('${ID}','${version_name}','${parents1}','${filename1}')">${sectionName}</a>`)
}
htmlBrend += `<div class='active section'>${filename}</div>`
htmlBrend += "<div class='divider'> / </div>"
$('#file_breadcrumb').append(htmlBrend)
$('input[name=model]').val(parents)
$('input[name=modelback]').val(filename)
}else{
$('input[name=model]').val(parents)
$('input[name=modelback]').val(filename)
let selectEle = $('#file_breadcrumb a.section').filter(
(index, item) => {
return item.text == filename;
}
);
selectEle.nextAll().remove();
selectEle.after("<div class='divider'> / </div>");
selectEle.replaceWith(`<div class='active section'>${filename}</div>`);
}
}
function renderDir(data,ID,version_name){
let html=""
html += "<div class='ui grid' style='margin:0;'>"
html += "<div class='row' style='padding: 0;'>"
html += "<div class='ui sixteen wide column' style='padding:1rem;'>"
html += "<div class='dir list'>"
html += "<table id='repo-files-table' class='ui single line table pad20'>"
html += '<tbody>'
for(let i=0;i<data.length;i++){
let dirs_size = renderSize(data[i].Size)
html += "<tr>"
html += "<td class='name six wid'>"
html += "<span class='truncate'>"
html += "<span class='octicon octicon-file-directory'>"
html += "</span>"
if(data[i].IsDir){
html += `<a onclick="loadModelFile('${ID}','${version_name}','${data[i].ParenDir}','${data[i].FileName}','folder')">`
html += "<span class='fitted'><i class='folder icon' width='16' height='16' aria-hidden='true'></i>" + data[i].FileName + "</span>"
}else{
html += `<a href="${url}${ID}/downloadsingle?parentDir=${data[i].ParenDir}&fileName=${data[i].FileName}">`
html += "<span class='fitted'><i class='file icon' width='16' height='16' aria-hidden='true'></i>" + data[i].FileName + "</span>"
}
html += '</a>'
html += "</span>"
html += "</td>"
html += "<td class='message seven wide'>"
if(data[i].IsDir){
html += "<span class='truncate has-emoji'></span>"
}else{
html += "<span class='truncate has-emoji'>"+ `${dirs_size}` + "</span>"
}
html += "</td>"

html += "<td class='text right age three wide'>"
html += "<span class='truncate has-emoji'>" + data[i].ModTime + "</span>"
html += "</td>"
html += "</tr>"
}
html += "</tbody>"
html += "</table>"
html += "</div>"
html += "</div>"
html += "</div>"
html += "</div>"
$('#dir_list').append(html)
}
</script>

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

@@ -45,6 +45,17 @@ export const getModelFiles = (params) => {
});
};

// 删除模型文件
// params {repo, id, fileName}
export const deleteModelFile = (params) => {
return service({
url: `${params.repo}/modelmanage/delete_model_file`,
method: 'delete',
params,
data: {},
});
};

/* 文件上传相关 */
// 上传文件1: 获取文件chunks信息
// params: { md5, type: 0-CPU/GPU,1-NPU, file_name, scene: 'model', modeluuid }


+ 482
- 0
web_src/vuepages/pages/modelmanage/common/modelmanage-common-detail.vue View File

@@ -0,0 +1,482 @@
<template>
<div>
<div class="ui header">
<div class="ui breadcrumb">
<a class="section" :href="`${repo}/modelmanage/show_model`">模型管理</a>
<div class="divider"> / </div>
<div class="active section">{{ this.state.name }}</div>
</div>
<div class="version">
<el-select v-model="curVersion" @change="changeVersion" placeholder="">
<el-option v-for="item in modelList" :value="item.version" :key="item.version" :label="item.version">
</el-option>
</el-select>
</div>
</div>
<div class="content">
<div class="detail-info">
<div class="title">基本信息:</div>
<div class="area-c">
<div class="area">
<div class="row">
<div class="tit">可用集群:</div>
<div class="val">
<div class="txt-wrap" :title="state.type == 0 ? 'CPU/GPU' : 'NPU'">
{{ state.type == 0 ? 'CPU/GPU' : 'NPU' }}
</div>
</div>
</div>
<div v-show="isExpanded" class="row">
<div class="tit">模型大小:</div>
<div class="val">
<div class="txt-wrap" :title="state.modelSize">{{ state.modelSize }}</div>
</div>
</div>
<div v-show="isExpanded" class="row">
<div class="tit">描述:</div>
<div class="val">
<div class="txt-wrap" :title="state.description">{{ state.description }}</div>
</div>
</div>
</div>
<div class="area">
<div class="row">
<div class="tit">模型框架:</div>
<div class="val">
<div class="txt-wrap" :title="state.engineName">{{ state.engineName }}</div>
</div>
</div>
<div v-show="isExpanded" class="row">
<div class="tit">创建时间:</div>
<div class="val">
<div class="txt-wrap" :title="state.createTime">{{ state.createTime }}</div>
</div>
</div>
<div v-show="isExpanded" class="row">
<div class="tit">标签:</div>
<div class="val">
<div class="txt-wrap" :title="state.label">{{ state.label }}</div>
</div>
</div>
</div>
</div>
<div v-show="isExpanded" style="margin-top:8px;" class="title">训练相关信息:</div>
<div v-show="isExpanded" class="area-c">
<div class="area">
<div class="row">
<div class="tit">训练任务:</div>
<div class="val">
<div class="txt-wrap" :title="state.displayJobName">{{ state.displayJobName }}</div>
</div>
</div>
<div class="row">
<div class="tit">代码分支:</div>
<div class="val">
<div class="txt-wrap" :title="state.branchName">{{ state.branchName }}</div>
</div>
</div>
<div class="row">
<div class="tit">启动文件:</div>
<div class="val">
<div class="txt-wrap" :title="state.bootFile">{{ state.bootFile }}</div>
</div>
</div>
<div class="row">
<div class="tit">训练数据集:</div>
<div class="val">
<div class="txt-wrap" :title="state.datasetName">{{ state.datasetName }}</div>
</div>
</div>
</div>
<div class="area">
<div class="row">
<div class="tit">规格:</div>
<div class="val">
<div class="txt-wrap" :title="state.specStr">{{ state.specStr }}</div>
</div>
</div>
<div class="row">
<div class="tit">计算节点:</div>
<div class="val">
<div class="txt-wrap" :title="state.workServerNumber">{{ state.workServerNumber }}</div>
</div>
</div>
<div class="row">
<div class="tit">运行参数:</div>
<div class="val">
<div class="txt-wrap" :title="state.parameters">{{ state.parameters }}</div>
</div>
</div>
</div>
</div>
</div>
<div class="expand-line">
<div class="line"></div>
<div class="expand-btn" @click="isExpanded = !isExpanded">
<i class="icon chevron circle down" :class="isExpanded ? 'up' : ''"></i>
<span>{{ isExpanded ? '折叠详细信息' : '查看更多信息' }}</span>
</div>
<div class="line"></div>
</div>
<div class="files-info">
<div class="top">
<div>
<div class="title">模型文件列表:</div>
<div class="title" style="margin-top:8px"><span class="version">{{ state.version }}</span>
<span style="color:rgba(0,0,0,.4);" class="divider"> / </span>
</div>
</div>
<div>
<el-button v-if="modelType == 1 && canOperate" type="primary" icon="el-icon-upload" @click="goUploadPage">
上传模型文件
</el-button>
</div>
</div>
<div class="table-container">
<el-table :data="filesList" row-key="sn" style="width: 100%" v-loading="loading" stripe>
<el-table-column column-key="FileName" prop="FileName" label="文件名称" align="left" header-align="left">
<template slot-scope="scope">
<div class="tbl-file-name">
<span class="octicon octicon-file-directory"></span>
<a :href="`${repo}/modelmanage/${state.id}/downloadsingle?parentDir=&fileName=${scope.row.FileName}`">
<div class="fitted" :title="scope.row.FileName">
<i class="file icon" width="16" height="16" aria-hidden="true"></i>
{{ scope.row.FileName }}
</div>
</a>
</div>
</template>
</el-table-column>
<el-table-column column-key="SizeShow" prop="SizeShow" label="文件大小" align="center" header-align="center"
width="200">
</el-table-column>
<el-table-column column-key="ModTime" prop="ModTime" label="更新时间" align="center" header-align="center"
width="200">
</el-table-column>
<el-table-column v-if="modelType == 1 && canOperate" column-key="operate" prop="operate" label="操作"
align="center" header-align="center" width="200">
<template slot-scope="scope">
<span class="btn-del" @click="deleteFile(scope.row)">删除</span>
</template>
</el-table-column>
</el-table>
</div>
</div>
</div>
</div>
</template>

<script>

import { getModelInfoByName, modifyModel, getModelFiles, deleteModelFile } from '~/apis/modules/modelmanage';
import { getUrlSearchParams, getListValueWithKey, transFileSize } from '~/utils';
import { MODEL_ENGINES } from '~/const';
import { formatDate } from 'element-ui/lib/utils/date-util';

const REPO_NAME = location.pathname.split('/')[2];

export default {
data() {
return {
modelType: '0', // 1-本地, 0-线上
canOperate: false,
isExpanded: false,
loading: false,
repo: location.pathname.split('/').slice(0, 3).join('/'),
state: {
type: 0,
id: '',
name: '',
version: '0.0.1',
engine: '0',
label: '',
description: '',
},
engineList: MODEL_ENGINES,
curVersion: '',
modelList: [],
filesList: [],
};
},
components: {},
methods: {
changeVersion(version) {
const data = this.modelList.filter((model) => model.version == version)[0];
this.modelType = data.modelType;
this.canOperate = data.isCanOper;
this.state.type = data.type;
this.state.id = data.id;
this.state.name = data.name;
this.state.version = data.version;
this.state.engine = data.engine.toString();
this.state.engineName = getListValueWithKey(MODEL_ENGINES, data.engine.toString());
this.state.modelSize = transFileSize(data.size);
this.state.label = data.label || '--';
this.state.description = data.description || '--';
this.state.createTime = formatDate(new Date(data.createdUnix * 1000), 'yyyy-MM-dd HH:mm:ss');

const trainTaskInfo = data.trainTaskInfo ? JSON.parse(data.trainTaskInfo) : '';
Object.assign(this.state, {
displayJobName: '--',
branchName: '--',
bootFile: '--',
datasetName: '--',
parameters: '--',
workServerNumber: '--',
specStr: '--',
});
if (trainTaskInfo) {
const parameters = trainTaskInfo.Parameters ? JSON.parse(trainTaskInfo.Parameters).parameter : [];
const parametersStr = parameters.map((item) => { return item.label + '=' + item.value }).join('; ');
Object.assign(this.state, {
displayJobName: trainTaskInfo.DisplayJobName,
branchName: trainTaskInfo.BranchName,
bootFile: trainTaskInfo.BootFile,
datasetName: trainTaskInfo.DatasetName,
parameters: parametersStr || '--',
workServerNumber: trainTaskInfo.WorkServerNumber || '--',
specStr: trainTaskInfo.Spec ? trainTaskInfo.Spec.toString() : '--'
});
}
this.curVersion = version;
getModelFiles({
repo: this.repo,
ID: this.state.id,
parentDir: '',
}).then(res => {
const list = res.data || [];
list.forEach(item => {
item.SizeShow = transFileSize(item.Size);
})
this.filesList = list;
}).catch(err => {
console.log(err);
})
},
goUploadPage() {
window.location.href = `${this.repo}/modelmanage/create_local_model_tmpl2?type=0&name=${this.state.name}&id=${this.state.id}`;
},
deleteFile(file) {
this.$confirm('请确认是否删除当前模型文件?', this.$t('tips'), {
confirmButtonText: this.$t('confirm1'),
cancelButtonText: this.$t('cancel'),
type: 'warning',
lockScroll: false,
}).then(() => {
deleteModelFile({
repo: this.repo,
id: this.state.id,
fileName: file.FileName,
}).then(res => {
res = res.data;
if (res.code == '0') {
this.changeVersion(this.curVersion);
} else {
this.$message({
type: 'error',
message: '模型文件删除失败',
});
}
}).catch(err => {
console.log(err);
this.$message({
type: 'error',
message: '模型文件删除失败',
});
});
}).catch(() => { });
}
},
mounted() {
const urlParams = getUrlSearchParams();
if (urlParams.name) {
this.state.name = urlParams.name;
this.loading = true;
getModelInfoByName({
repo: this.repo,
name: urlParams.name,
}).then(res => {
this.loading = false;
const list = res.data || [];
this.modelList = list;
if (list && list.length) {
const data = list[0];
this.changeVersion(data.version);
}
}).catch(err => {
this.loading = false;
console.log(err);
this.cancel();
});
} else {
this.cancel();
}
},
beforeDestroy() {
},
};
</script>

<style scoped lang="less">
.header {
display: flex;
align-items: center;

.version {
margin-left: 16px;
width: 90px;
}
}

.content {
.title {
font-weight: 550;
font-size: 14px;
color: rgb(16, 16, 16);
}

.detail-info {
border: 1px solid rgb(232, 232, 232);
border-bottom: none;
padding: 22px;
padding-bottom: 1px;

.area-c {
display: flex;

.area {
flex: 1;

.row {
display: flex;
height: 32px;
align-items: center;
margin-bottom: 4px;

.tit {
width: 160px;
text-align: right;
color: rgb(136, 136, 136);
}

.val {
flex: 1;
color: rgb(16, 16, 16);
position: relative;
height: 20px;

.txt-wrap {
position: absolute;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
width: 100%;
}
}
}
}
}
}

.expand-line {
display: flex;
align-items: center;
border: 1px solid rgb(232, 232, 232);
border-top: none;
border-bottom: none;
padding: 16px 0;

.line {
flex: 1;
height: 1px;
background-color: rgb(232, 232, 232);
margin: 0 22px;
}

.expand-btn {
color: rgba(22, 132, 252, 1);
cursor: pointer;

.icon {
margin-right: 2px;
font-size: 14px;
color: rgba(22, 132, 252, 0.8),
}
}
}


.files-info {
border: 1px solid rgb(232, 232, 232);
border-top: none;
border-bottom: none;

.top {
padding: 0 22px 8px 22px;
display: flex;
align-items: center;
justify-content: space-between;
}

.table-container {
/deep/ .el-table__header {
th {
background: rgb(245, 245, 246);
color: rgb(16, 16, 16);
font-weight: 400;
font-size: 14px;
}
}

/deep/ .el-table__body {
td {
color: rgb(16, 16, 16);
font-weight: 400;
font-size: 14px;
}
}

.tbl-file-name {
height: 32px;
display: flex;
align-items: center;
overflow: hidden;
font-size: 16px;
font-weight: 500;
}

.btn-del {
color: rgb(255, 51, 51);
cursor: pointer;
}
}
}
}


.el-select-dropdown__item.selected {
color: rgba(0, 0, 0, .95);
}

/deep/ .el-select {
.is-focus {
.el-input__inner {
border-color: #85b7d9;
}
}
}

/deep/ .el-input__inner {
font-weight: 600;

&:focus {
border-color: #85b7d9;
}
}

/deep/ .el-textarea__inner {
&:focus {
border-color: #85b7d9;
}
}
</style>

+ 17
- 0
web_src/vuepages/pages/modelmanage/common/vp-modelmanage-common-detail.js View File

@@ -0,0 +1,17 @@
import Vue from 'vue';
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
import localeEn from 'element-ui/lib/locale/lang/en';
import localeZh from 'element-ui/lib/locale/lang/zh-CN';
import { i18n, lang } from '~/langs';
import App from './modelmanage-common-detail.vue';

Vue.use(ElementUI, {
locale: lang === 'zh-CN' ? localeZh : localeEn,
size: 'small',
});

new Vue({
i18n,
render: (h) => h(App),
}).$mount('#__vue-root');

+ 7
- 5
web_src/vuepages/pages/modelmanage/local/modelmanage-local-create-2.vue View File

@@ -233,8 +233,8 @@ export default {
file.uploaded = data.uploaded;
file.chunks = data.chunks;
file.attachID = data.attachID;
file.modelUuid = data.modeluuid || file.modelUuid;
file.modelName = data.modelName || file.modelName;
file._modelUuid = data.modeluuid;
file._modelName = data.modelName;
file.realName = data.fileName;
return file;
}).catch(err => {
@@ -431,7 +431,9 @@ export default {
const list = window.location.href.split('/');
list.pop();
list.push('show_model_info');
window.location.href = list.join('/') + '?name=' + this.state.name;
window.setTimeout(() => {
window.location.href = list.join('/') + '?name=' + this.state.name;
}, 1000);
}
}
},
@@ -456,8 +458,8 @@ export default {
}
this.uploadLength++;
// 同一模型上传同一个文件
if (file.modelUuid != '') {
const info = `该文件已上传在模型: ${file.modelName}`;
if (file._modelUuid) {
const info = `该文件已上传在模型: ${file._modelName}`;
this.uploadError(file, info);
this.updateFileStatus(file, "上传失败", 0, 1, info);
} else { // 秒传


+ 11
- 0
web_src/vuepages/utils/index.js View File

@@ -14,3 +14,14 @@ export const getUrlSearchParams = () => {
});
return obj;
};

export const transFileSize = (srcSize) => {
if (null == srcSize || srcSize == '') {
return '0 Bytes';
}
const unitArr = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
srcSize = parseFloat(srcSize);
const index = Math.floor(Math.log(srcSize) / Math.log(1024));
const size = (srcSize / Math.pow(1024, index)).toFixed(2);
return size + unitArr[index];
};

Loading…
Cancel
Save