zouap
into V20230410
1 year ago
@@ -6,6 +6,7 @@ import ( | |||
"code.gitea.io/gitea/modules/log" | |||
"code.gitea.io/gitea/modules/setting" | |||
"code.gitea.io/gitea/modules/storage" | |||
"code.gitea.io/gitea/modules/timeutil" | |||
"xorm.io/builder" | |||
"xorm.io/xorm" | |||
@@ -25,6 +26,7 @@ type AiModelManage struct { | |||
Path string `xorm:"varchar(400) NOT NULL" json:"path"` | |||
DownloadCount int `xorm:"NOT NULL DEFAULT 0" json:"downloadCount"` | |||
Engine int64 `xorm:"NOT NULL DEFAULT 0" json:"engine"` | |||
ComputeResource string `json:"computeResource"` | |||
Status int `xorm:"NOT NULL DEFAULT 0" json:"status"` | |||
StatusDesc string `xorm:"varchar(500)" json:"statusDesc"` | |||
Accuracy string `xorm:"varchar(1000)" json:"accuracy"` | |||
@@ -32,16 +34,42 @@ type AiModelManage struct { | |||
RepoId int64 `xorm:"INDEX NULL" json:"repoId"` | |||
CodeBranch string `xorm:"varchar(400) NULL" json:"codeBranch"` | |||
CodeCommitID string `xorm:"NULL" json:"codeCommitID"` | |||
Recommend int `xorm:"NOT NULL DEFAULT 0" json:"recommend"` | |||
UserId int64 `xorm:"NOT NULL" json:"userId"` | |||
IsPrivate bool `xorm:"DEFAULT true" json:"isPrivate"` | |||
UserName string `json:"userName"` | |||
UserRelAvatarLink string `json:"userRelAvatarLink"` | |||
UserName string `xorm:"-" json:"userName"` | |||
UserRelAvatarLink string `xorm:"-" json:"userRelAvatarLink"` | |||
TrainTaskInfo string `xorm:"text NULL" json:"trainTaskInfo"` | |||
CreatedUnix timeutil.TimeStamp `xorm:"created" json:"createdUnix"` | |||
UpdatedUnix timeutil.TimeStamp `xorm:"updated" json:"updatedUnix"` | |||
IsCanOper bool `json:"isCanOper"` | |||
IsCanDelete bool `json:"isCanDelete"` | |||
IsCanDownload bool `json:"isCanDownload"` | |||
IsCanOper bool `xorm:"-" json:"isCanOper"` | |||
IsCanDelete bool `xorm:"-" json:"isCanDelete"` | |||
IsCanDownload bool `xorm:"-" json:"isCanDownload"` | |||
IsCollected bool `xorm:"-" json:"isCollected"` | |||
RepoName string `xorm:"-" json:"repoName"` | |||
RepoDisplayName string `xorm:"-" json:"repoDisplayName"` | |||
RepoOwnerName string `xorm:"-" json:"repoOwnerName"` | |||
ReferenceCount int `xorm:"NOT NULL DEFAULT 0" json:"referenceCount"` | |||
CollectedCount int `xorm:"NOT NULL DEFAULT 0" json:"collectedCount"` | |||
ModelFileList []storage.FileInfo `xorm:"-" json:"modelFileList"` | |||
} | |||
type AiModelFile struct { | |||
ID int64 `xorm:"pk autoincr"` | |||
ModelID string `xorm:"UNIQUE(s)"` | |||
Name string `xorm:"varchar(400) UNIQUE(s)"` | |||
Path string `xorm:"varchar(400) NULL"` | |||
Description string `xorm:"varchar(400) NULL"` | |||
DownloadCount int64 `xorm:"DEFAULT 0"` | |||
Size int64 `xorm:"DEFAULT 0"` | |||
CreatedUnix timeutil.TimeStamp `xorm:"created"` | |||
} | |||
type AiModelCollect struct { | |||
ID int64 `xorm:"pk autoincr"` | |||
ModelID string `xorm:"UNIQUE(s)"` | |||
UserId int64 `xorm:"UNIQUE(s)"` | |||
CreatedUnix timeutil.TimeStamp `xorm:"created"` | |||
} | |||
type AiModelConvert struct { | |||
@@ -72,10 +100,10 @@ type AiModelConvert struct { | |||
UpdatedUnix timeutil.TimeStamp `xorm:"updated" json:"updatedUnix"` | |||
StartTime timeutil.TimeStamp `json:"startTime"` | |||
EndTime timeutil.TimeStamp `json:"endTime"` | |||
UserName string `json:"userName"` | |||
UserRelAvatarLink string `json:"userRelAvatarLink"` | |||
IsCanOper bool `json:"isCanOper"` | |||
IsCanDelete bool `json:"isCanDelete"` | |||
UserName string `xorm:"-" json:"userName"` | |||
UserRelAvatarLink string `xorm:"-" json:"userRelAvatarLink"` | |||
IsCanOper bool `xorm:"-" json:"isCanOper"` | |||
IsCanDelete bool `xorm:"-" json:"isCanDelete"` | |||
} | |||
type AiModelQueryOptions struct { | |||
@@ -90,6 +118,14 @@ type AiModelQueryOptions struct { | |||
Status int | |||
IsOnlyThisRepo bool | |||
IsQueryPrivate bool | |||
IsRecommend bool | |||
IsCollected bool | |||
CollectedUserId int64 | |||
Namelike string | |||
LabelFilter string | |||
FrameFilter int | |||
ComputeResourceFilter string | |||
NotNeedEmpty bool | |||
} | |||
func (a *AiModelConvert) IsGpuTrainTask() bool { | |||
@@ -310,6 +346,34 @@ func ModifyModelPrivate(id string, isPrivate bool) error { | |||
return nil | |||
} | |||
func ModifyModelRecommend(id string, recommend int) error { | |||
var sess *xorm.Session | |||
sess = x.ID(id) | |||
defer sess.Close() | |||
re, err := sess.Cols("recommend").Update(&AiModelManage{ | |||
Recommend: recommend, | |||
}) | |||
if err != nil { | |||
return err | |||
} | |||
log.Info("success to update recommend from db.re=" + fmt.Sprint((re))) | |||
return nil | |||
} | |||
func ModifyModelCollectedNum(id string, collectedNum int) error { | |||
var sess *xorm.Session | |||
sess = x.ID(id) | |||
defer sess.Close() | |||
re, err := sess.Cols("collected_count").Update(&AiModelManage{ | |||
CollectedCount: collectedNum, | |||
}) | |||
if err != nil { | |||
return err | |||
} | |||
log.Info("success to update collectedNum from db.re=" + fmt.Sprint((re))) | |||
return nil | |||
} | |||
func ModifyLocalModel(id string, name, label, description string, engine int, isPrivate bool) error { | |||
var sess *xorm.Session | |||
sess = x.ID(id) | |||
@@ -394,6 +458,29 @@ func QueryModelByName(name string, repoId int64) []*AiModelManage { | |||
return aiModelManageList | |||
} | |||
func QueryModelByRepoId(repoId int64) []*AiModelManage { | |||
sess := x.NewSession() | |||
defer sess.Close() | |||
sess.Select("*").Table("ai_model_manage"). | |||
Where("repo_id=?", repoId) | |||
aiModelManageList := make([]*AiModelManage, 0) | |||
sess.Find(&aiModelManageList) | |||
return aiModelManageList | |||
} | |||
func DeleteModelByRepoId(repoId int64) error { | |||
sess := x.NewSession() | |||
defer sess.Close() | |||
re, err := sess.Delete(&AiModelManage{ | |||
RepoId: repoId, | |||
}) | |||
if err != nil { | |||
return err | |||
} | |||
log.Info("success to delete DeleteModelByRepoId from db.re=" + fmt.Sprint((re))) | |||
return nil | |||
} | |||
func QueryModelByPath(path string) (*AiModelManage, error) { | |||
modelManage := new(AiModelManage) | |||
has, err := x.Where("path=?", path).Get(modelManage) | |||
@@ -409,52 +496,75 @@ func QueryModelByPath(path string) (*AiModelManage, error) { | |||
func QueryModel(opts *AiModelQueryOptions) ([]*AiModelManage, int64, error) { | |||
sess := x.NewSession() | |||
defer sess.Close() | |||
var cond = builder.NewCond() | |||
var where string | |||
where += " ai_model_manage.user_id > 0 " | |||
if opts.RepoID > 0 { | |||
cond = cond.And( | |||
builder.Eq{"ai_model_manage.repo_id": opts.RepoID}, | |||
) | |||
where += " and ai_model_manage.repo_id= " + fmt.Sprint(opts.RepoID) | |||
} | |||
if opts.UserID > 0 { | |||
cond = cond.And( | |||
builder.Eq{"ai_model_manage.user_id": opts.UserID}, | |||
) | |||
where += " and ai_model_manage.user_id=" + fmt.Sprint(opts.UserID) | |||
} | |||
if opts.New >= 0 { | |||
cond = cond.And( | |||
builder.Eq{"ai_model_manage.new": opts.New}, | |||
) | |||
where += " and ai_model_manage.new=" + fmt.Sprint(opts.New) | |||
} | |||
if len(opts.ModelID) > 0 { | |||
cond = cond.And( | |||
builder.Eq{"ai_model_manage.id": opts.ModelID}, | |||
) | |||
where += " and ai_model_manage.id='" + fmt.Sprint(opts.ModelID) + "'" | |||
} | |||
if (opts.Type) >= 0 { | |||
cond = cond.And( | |||
builder.Eq{"ai_model_manage.type": opts.Type}, | |||
) | |||
where += " and ai_model_manage.type=" + fmt.Sprint(opts.Type) | |||
} | |||
if (opts.Status) >= 0 { | |||
cond = cond.And( | |||
builder.Eq{"ai_model_manage.status": opts.Status}, | |||
) | |||
where += " and ai_model_manage.status=" + fmt.Sprint(opts.Status) | |||
} | |||
if !opts.IsQueryPrivate { | |||
cond = cond.And( | |||
builder.Eq{"ai_model_manage.is_private": false}, | |||
) | |||
where += " and ai_model_manage.is_private=false" | |||
} | |||
if opts.IsRecommend { | |||
where += " and ai_model_manage.recommend=1" | |||
} | |||
if opts.FrameFilter >= 0 { | |||
if opts.FrameFilter == 2 { | |||
where += " and ai_model_manage.engine in (2,121,122)" | |||
} else { | |||
where += " and ai_model_manage.engine=" + fmt.Sprint(opts.FrameFilter) | |||
} | |||
} | |||
if opts.LabelFilter != "" { | |||
where += " and ai_model_manage.label ILIKE '%" + opts.LabelFilter + "%'" | |||
} | |||
if opts.ComputeResourceFilter != "" { | |||
where += " and ai_model_manage.compute_resource ILIKE '%" + opts.ComputeResourceFilter + "%'" | |||
} | |||
count, err := sess.Where(cond).Count(new(AiModelManage)) | |||
if opts.Namelike != "" { | |||
where += " and ( ai_model_manage.name ILIKE '%" + opts.Namelike + "%'" | |||
where += " or ai_model_manage.description ILIKE '%" + opts.Namelike + "%'" | |||
where += " or ai_model_manage.label ILIKE '%" + opts.Namelike + "%')" | |||
} | |||
if opts.NotNeedEmpty { | |||
where += " and ai_model_manage.size > 0 " | |||
} | |||
var count int64 | |||
var err error | |||
if opts.IsCollected { | |||
where += " and ai_model_collect.user_id=" + fmt.Sprint(opts.CollectedUserId) | |||
count, err = sess.Join("INNER", "ai_model_collect", "ai_model_manage.id = ai_model_collect.model_id").Where(where).Count(new(AiModelManage)) | |||
if err != nil { | |||
log.Info("error=" + err.Error()) | |||
return nil, 0, fmt.Errorf("Count: %v", err) | |||
} | |||
} else { | |||
count, err = sess.Where(where).Count(new(AiModelManage)) | |||
if err != nil { | |||
log.Info("error=" + err.Error()) | |||
return nil, 0, fmt.Errorf("Count: %v", err) | |||
} | |||
} | |||
if opts.Page >= 0 && opts.PageSize > 0 { | |||
var start int | |||
@@ -465,11 +575,18 @@ func QueryModel(opts *AiModelQueryOptions) ([]*AiModelManage, int64, error) { | |||
} | |||
sess.Limit(opts.PageSize, start) | |||
} | |||
sess.OrderBy("ai_model_manage.created_unix DESC") | |||
if opts.IsCollected { | |||
sess.Join("INNER", "ai_model_collect", "ai_model_manage.id = ai_model_collect.model_id") | |||
} | |||
orderby := "ai_model_manage.created_unix desc" | |||
if opts.SortType != "" { | |||
orderby = opts.SortType | |||
} | |||
sess.OrderBy(orderby) | |||
aiModelManages := make([]*AiModelManage, 0, setting.UI.IssuePagingNum) | |||
if err := sess.Table("ai_model_manage").Where(cond). | |||
if err := sess.Table("ai_model_manage").Where(where). | |||
Find(&aiModelManages); err != nil { | |||
log.Info("error=" + err.Error()) | |||
return nil, 0, fmt.Errorf("Find: %v", err) | |||
} | |||
@@ -551,3 +668,109 @@ func QueryModelConvert(opts *AiModelQueryOptions) ([]*AiModelConvert, int64, err | |||
return aiModelManageConvert, count, nil | |||
} | |||
func SaveModelCollect(modelCollect *AiModelCollect) error { | |||
sess := x.NewSession() | |||
defer sess.Close() | |||
re, err := sess.Insert(modelCollect) | |||
if err != nil { | |||
log.Info("insert AiModelCollect error." + err.Error()) | |||
return err | |||
} | |||
log.Info("success to save AiModelCollect db.re=" + fmt.Sprint((re))) | |||
return nil | |||
} | |||
func DeleteModelCollect(modelCollect *AiModelCollect) error { | |||
sess := x.NewSession() | |||
defer sess.Close() | |||
re, err := sess.Delete(modelCollect) | |||
if err != nil { | |||
log.Info("delete AiModelCollect error." + err.Error()) | |||
return err | |||
} | |||
log.Info("success to delete AiModelCollect db.re=" + fmt.Sprint((re))) | |||
return nil | |||
} | |||
func QueryModelCollectNum(modelId string) int { | |||
sess := x.NewSession() | |||
defer sess.Close() | |||
modelCollects := make([]*AiModelCollect, 0) | |||
err := sess.Table(new(AiModelCollect)).Where("model_id=?", modelId).Find(&modelCollects) | |||
if err == nil { | |||
return len(modelCollects) | |||
} | |||
return 0 | |||
} | |||
func QueryModelCollectByUserId(modelId string, userId int64) []*AiModelCollect { | |||
sess := x.NewSession() | |||
defer sess.Close() | |||
modelCollects := make([]*AiModelCollect, 0) | |||
err := sess.Table(new(AiModelCollect)).Where("model_id=? and user_id=?", modelId, userId).Find(&modelCollects) | |||
if err == nil { | |||
return modelCollects | |||
} | |||
return nil | |||
} | |||
func QueryModelCollectedStatus(modelIds []string, userId int64) map[string]*AiModelCollect { | |||
sess := x.NewSession() | |||
defer sess.Close() | |||
modelCollects := make([]*AiModelCollect, 0) | |||
var cond = builder.NewCond() | |||
cond = cond.And( | |||
builder.In("model_id", modelIds), | |||
) | |||
cond = cond.And( | |||
builder.Eq{"user_id": userId}, | |||
) | |||
result := make(map[string]*AiModelCollect, 0) | |||
err := sess.Table(new(AiModelCollect)).Where(cond).Find(&modelCollects) | |||
if err == nil { | |||
for _, v := range modelCollects { | |||
result[v.ModelID] = v | |||
} | |||
} | |||
return result | |||
} | |||
func SaveModelFile(modelFile *AiModelFile) error { | |||
sess := x.NewSession() | |||
defer sess.Close() | |||
re, err := sess.Insert(modelFile) | |||
if err != nil { | |||
log.Info("insert modelFile error." + err.Error()) | |||
return err | |||
} | |||
log.Info("success to save modelFile db.re=" + fmt.Sprint((re))) | |||
return nil | |||
} | |||
func DeleteModelFile(modelFile *AiModelFile) error { | |||
sess := x.NewSession() | |||
defer sess.Close() | |||
re, err := sess.Delete(modelFile) | |||
if err != nil { | |||
log.Info("delete modelFile error." + err.Error()) | |||
return err | |||
} | |||
log.Info("success to delete modelFile db.re=" + fmt.Sprint((re))) | |||
return nil | |||
} | |||
func QueryModelFileByModelId(modelId string) []*AiModelFile { | |||
sess := x.NewSession() | |||
defer sess.Close() | |||
modelFileList := make([]*AiModelFile, 0) | |||
var cond = builder.NewCond() | |||
cond = cond.And( | |||
builder.Eq{"model_id": modelId}, | |||
) | |||
result := make([]*AiModelFile, 0) | |||
err := sess.Table(new(AiModelFile)).Where(cond).Find(&modelFileList) | |||
if err != nil { | |||
log.Info("query AiModelFile failed, err=" + err.Error()) | |||
} | |||
return result | |||
} |
@@ -205,6 +205,9 @@ type Cloudbrain struct { | |||
ModelName string //模型名称 | |||
ModelVersion string //模型版本 | |||
CkptName string //权重文件名称 | |||
ModelId string //模型ID | |||
ModelRepoName string `xorm:"-"` | |||
ModelRepoOwnerName string `xorm:"-"` | |||
PreTrainModelUrl string //预训练模型地址 | |||
ResultUrl string //推理结果的obs路径 | |||
ResultJson string `xorm:"varchar(4000)"` | |||
@@ -2071,12 +2074,28 @@ func CreateCloudbrain(cloudbrain *Cloudbrain) (err error) { | |||
} | |||
} | |||
session.Commit() | |||
increaseModelReference(session, cloudbrain.ModelId) | |||
go IncreaseDatasetUseCount(cloudbrain.Uuid) | |||
go OperateRepoAITaskNum(cloudbrain.RepoID, 1) | |||
//go IncreaseModelRefernceCount(cloudbrain) | |||
return nil | |||
} | |||
func increaseModelReference(session *xorm.Session, modelId string) { | |||
if modelId != "" { | |||
log.Info("increase model count.") | |||
if _, err := session.Exec("UPDATE `ai_model_manage` SET reference_count = reference_count + 1 WHERE id = ?", modelId); err != nil { | |||
log.Info("err=" + err.Error()) | |||
} | |||
} | |||
} | |||
// func IncreaseModelRefernceCount(cloudbrain *Cloudbrain) { | |||
// if cloudbrain.ModelId != "" { | |||
// AddModelInferenceCount(cloudbrain.ModelId) | |||
// } | |||
// } | |||
func getRepoCloudBrain(cb *Cloudbrain) (*Cloudbrain, error) { | |||
has, err := x.Get(cb) | |||
if err != nil { | |||
@@ -2490,7 +2509,7 @@ func RestartCloudbrain(old *Cloudbrain, new *Cloudbrain) (err error) { | |||
if err = sess.Commit(); err != nil { | |||
return err | |||
} | |||
increaseModelReference(sess, new.ModelId) | |||
go IncreaseDatasetUseCount(new.Uuid) | |||
return nil | |||
} | |||
@@ -2628,7 +2647,6 @@ func CloudbrainAll(opts *CloudbrainsOptions) ([]*CloudbrainInfo, int64, error) { | |||
Join("left", "`user`", condition). | |||
Join("left", "cloudbrain_spec", "cloudbrain.id = cloudbrain_spec.cloudbrain_id"). | |||
Count(new(CloudbrainInfo)) | |||
} | |||
if err != nil { | |||
@@ -2982,3 +3000,15 @@ func LoadSpecs4CloudbrainInfo(tasks []*CloudbrainInfo) error { | |||
} | |||
return nil | |||
} | |||
func GetCloudBrainByModelId(modelId string) ([]*Cloudbrain, error) { | |||
cloudBrains := make([]*Cloudbrain, 0) | |||
err := x.AllCols().Where("model_id=?", modelId).OrderBy("created_unix asc").Find(&cloudBrains) | |||
return cloudBrains, err | |||
} | |||
func GetCloudBrainByRepoIdAndModelName(repoId int64, modelName string) ([]*Cloudbrain, error) { | |||
cloudBrains := make([]*Cloudbrain, 0) | |||
err := x.AllCols().Where("model_name=? and repo_id=?", modelName, repoId).OrderBy("created_unix asc").Find(&cloudBrains) | |||
return cloudBrains, err | |||
} |
@@ -170,6 +170,8 @@ func init() { | |||
new(TechConvergeBaseInfo), | |||
new(RepoConvergeInfo), | |||
new(UserRole), | |||
new(AiModelCollect), | |||
new(AiModelFile), | |||
new(ModelMigrateRecord), | |||
) | |||
@@ -1706,7 +1706,9 @@ func updateRepository(e Engine, repo *Repository, visibilityChanged bool) (err e | |||
if err != nil { | |||
return err | |||
} | |||
_, err = e.Where("repo_id = ?", repo.ID).Cols("is_private").Update(&AiModelManage{ | |||
IsPrivate: true, | |||
}) | |||
} else { | |||
//If repo has become public, we need set dataset to public | |||
_, err = e.Where("repo_id = ? and status <> 2", repo.ID).Cols("status").Update(&Dataset{ | |||
@@ -1870,6 +1872,9 @@ func DeleteRepository(doer *User, uid, repoID int64) error { | |||
// Delete dataset attachment record and remove related files | |||
deleteDatasetAttachmentByRepoId(sess, repoID) | |||
deleteModelByRepoId(repoID) | |||
if err = deleteBeans(sess, | |||
&Access{RepoID: repo.ID}, | |||
&Action{RepoID: repo.ID}, | |||
@@ -2055,6 +2060,22 @@ func DeleteRepository(doer *User, uid, repoID int64) error { | |||
return nil | |||
} | |||
func deleteModelByRepoId(repoId int64) { | |||
models := QueryModelByRepoId(repoId) | |||
if models != nil { | |||
for _, model := range models { | |||
log.Info("bucket=" + setting.Bucket + " path=" + model.Path) | |||
if len(model.Path) > (len(setting.Bucket) + 1) { | |||
err := storage.ObsRemoveObject(setting.Bucket, model.Path[len(setting.Bucket)+1:]) | |||
if err != nil { | |||
log.Info("Failed to delete model. id=" + model.ID) | |||
} | |||
} | |||
} | |||
} | |||
DeleteModelByRepoId(repoId) | |||
} | |||
func deleteDatasetAttachmentByRepoId(sess *xorm.Session, repoId int64) error { | |||
attachments := make([]*Attachment, 0) | |||
if err := sess.Join("INNER", "dataset", "dataset.id = attachment.dataset_id"). | |||
@@ -26,6 +26,7 @@ type CreateCloudBrainForm struct { | |||
ModelName string `form:"model_name"` | |||
ModelVersion string `form:"model_version"` | |||
CkptName string `form:"ckpt_name"` | |||
ModelId string `form:"model_id"` | |||
LabelName string `form:"label_names"` | |||
PreTrainModelUrl string `form:"pre_train_model_url"` | |||
DatasetName string `form:"dataset_name"` | |||
@@ -68,7 +69,7 @@ type CreateCloudBrainInferencForm struct { | |||
JobType string `form:"job_type" binding:"Required"` | |||
BenchmarkCategory string `form:"get_benchmark_category"` | |||
GpuType string `form:"gpu_type"` | |||
TrainUrl string `form:"train_url"` | |||
PreTrainModelUrl string `form:"pre_train_model_url"` | |||
TestUrl string `form:"test_url"` | |||
Description string `form:"description"` | |||
ResourceSpecId int `form:"resource_spec_id" binding:"Required"` | |||
@@ -79,6 +80,7 @@ type CreateCloudBrainInferencForm struct { | |||
ModelVersion string `form:"model_version" binding:"Required"` | |||
CkptName string `form:"ckpt_name" binding:"Required"` | |||
LabelName string `form:"label_names" binding:"Required"` | |||
ModelId string `form:"model_id" binding:"Required"` | |||
DatasetName string `form:"dataset_name"` | |||
SpecId int64 `form:"spec_id"` | |||
} | |||
@@ -21,6 +21,7 @@ type CreateGrampusTrainJobForm struct { | |||
ModelName string `form:"model_name"` | |||
ModelVersion string `form:"model_version"` | |||
CkptName string `form:"ckpt_name"` | |||
ModelId string `form:"model_id"` | |||
LabelName string `form:"label_names"` | |||
PreTrainModelUrl string `form:"pre_train_model_url"` | |||
SpecId int64 `form:"spec_id"` | |||
@@ -44,6 +45,7 @@ type CreateGrampusNotebookForm struct { | |||
ModelName string `form:"model_name"` | |||
ModelVersion string `form:"model_version"` | |||
CkptName string `form:"ckpt_name"` | |||
ModelId string `form:"model_id"` | |||
LabelName string `form:"label_names"` | |||
PreTrainModelUrl string `form:"pre_train_model_url"` | |||
SpecId int64 `form:"spec_id" binding:"Required"` | |||
@@ -25,6 +25,7 @@ type CreateModelArtsNotebookForm struct { | |||
ModelName string `form:"model_name"` | |||
ModelVersion string `form:"model_version"` | |||
CkptName string `form:"ckpt_name"` | |||
ModelId string `form:"model_id"` | |||
LabelName string `form:"label_names"` | |||
PreTrainModelUrl string `form:"pre_train_model_url"` | |||
SpecId int64 `form:"spec_id" binding:"Required"` | |||
@@ -56,6 +57,7 @@ type CreateModelArtsTrainJobForm struct { | |||
EngineName string `form:"engine_names" binding:"Required"` | |||
SpecId int64 `form:"spec_id" binding:"Required"` | |||
ModelName string `form:"model_name"` | |||
ModelId string `form:"model_id"` | |||
ModelVersion string `form:"model_version"` | |||
CkptName string `form:"ckpt_name"` | |||
LabelName string `form:"label_names"` | |||
@@ -79,10 +81,11 @@ type CreateModelArtsInferenceJobForm struct { | |||
FlavorName string `form:"flaver_names" binding:"Required"` | |||
EngineName string `form:"engine_names" binding:"Required"` | |||
LabelName string `form:"label_names" binding:"Required"` | |||
TrainUrl string `form:"train_url" binding:"Required"` | |||
PreTrainModelUrl string `form:"pre_train_model_url" binding:"Required"` | |||
ModelName string `form:"model_name" binding:"Required"` | |||
ModelVersion string `form:"model_version" binding:"Required"` | |||
CkptName string `form:"ckpt_name" binding:"Required"` | |||
ModelId string `form:"model_id"` | |||
SpecId int64 `form:"spec_id" binding:"Required"` | |||
} | |||
@@ -79,6 +79,7 @@ type GenerateCloudBrainTaskReq struct { | |||
ModelName string | |||
ModelVersion string | |||
CkptName string | |||
ModelId string | |||
LabelName string | |||
PreTrainModelPath string | |||
PreTrainModelUrl string | |||
@@ -358,6 +359,7 @@ func GenerateTask(req GenerateCloudBrainTaskReq) (string, error) { | |||
ModelName: req.ModelName, | |||
ModelVersion: req.ModelVersion, | |||
CkptName: req.CkptName, | |||
ModelId: req.ModelId, | |||
ResultUrl: req.ResultPath, | |||
LabelName: req.LabelName, | |||
PreTrainModelUrl: req.PreTrainModelUrl, | |||
@@ -475,10 +477,6 @@ func RestartTask(ctx *context.Context, task *models.Cloudbrain, newID *string) e | |||
} | |||
if task.PreTrainModelUrl != "" { //预训练 | |||
_, err := models.QueryModelByPath(task.PreTrainModelUrl) | |||
if err != nil { | |||
log.Warn("The model may be deleted", err) | |||
} else { | |||
volumes = append(volumes, models.Volume{ | |||
HostPath: models.StHostPath{ | |||
Path: setting.Attachment.Minio.RealPath + task.PreTrainModelUrl, | |||
@@ -487,7 +485,6 @@ func RestartTask(ctx *context.Context, task *models.Cloudbrain, newID *string) e | |||
}, | |||
}) | |||
} | |||
} | |||
createTime := timeutil.TimeStampNow() | |||
jobResult, err := CreateJob(jobName, models.CreateJobParams{ | |||
@@ -549,6 +546,7 @@ func RestartTask(ctx *context.Context, task *models.Cloudbrain, newID *string) e | |||
LabelName: task.LabelName, | |||
PreTrainModelUrl: task.PreTrainModelUrl, | |||
CkptName: task.CkptName, | |||
ModelId: task.ModelId, | |||
} | |||
err = models.RestartCloudbrain(task, newTask) | |||
@@ -698,6 +696,7 @@ type GenerateModelArtsNotebookReq struct { | |||
ModelName string | |||
LabelName string | |||
CkptName string | |||
ModelId string | |||
ModelVersion string | |||
PreTrainModelUrl string | |||
} |
@@ -31,7 +31,7 @@ func ToCloudBrain(task *models.Cloudbrain) *api.Cloudbrain { | |||
VersionName: task.VersionName, | |||
ModelVersion: task.ModelVersion, | |||
CkptName: task.CkptName, | |||
ModelId: task.ModelId, | |||
StartTime: int64(task.StartTime), | |||
EndTime: int64(task.EndTime), | |||
Spec: ToSpecification(task.Spec), | |||
@@ -1,6 +1,7 @@ | |||
package grampus | |||
import ( | |||
"encoding/json" | |||
"fmt" | |||
"strconv" | |||
"strings" | |||
@@ -78,6 +79,7 @@ type GenerateTrainJobReq struct { | |||
ModelName string | |||
LabelName string | |||
CkptName string | |||
ModelId string | |||
ModelVersion string | |||
PreTrainModelPath string | |||
PreTrainModelUrl string | |||
@@ -103,6 +105,7 @@ type GenerateNotebookJobReq struct { | |||
ModelName string | |||
LabelName string | |||
CkptName string | |||
ModelId string | |||
ModelVersion string | |||
PreTrainModelPath string | |||
PreTrainModelUrl string | |||
@@ -227,7 +230,7 @@ func GenerateNotebookJob(ctx *context.Context, req *GenerateNotebookJobReq) (job | |||
EndPoint: getEndPoint(), | |||
ReadOnly: true, | |||
ObjectKey: req.PreTrainModelPath, | |||
ContainerPath: cloudbrain.PretrainModelMountPath, | |||
ContainerPath: cloudbrain.PretrainModelMountPath + "/" + req.CkptName, | |||
}) | |||
} | |||
@@ -248,7 +251,8 @@ func GenerateNotebookJob(ctx *context.Context, req *GenerateNotebookJobReq) (job | |||
log.Info("debug command:" + req.Command) | |||
} | |||
datasetGrampusJson, _ := json.Marshal(datasetGrampus) | |||
log.Info("datasetGrampusJson=" + string(datasetGrampusJson)) | |||
jobResult, err := createNotebookJob(models.CreateGrampusNotebookRequest{ | |||
Name: req.JobName, | |||
Tasks: []models.GrampusNotebookTask{ | |||
@@ -299,6 +303,7 @@ func GenerateNotebookJob(ctx *context.Context, req *GenerateNotebookJobReq) (job | |||
LabelName: req.LabelName, | |||
PreTrainModelUrl: req.PreTrainModelUrl, | |||
CkptName: req.CkptName, | |||
ModelId: req.ModelId, | |||
}) | |||
if err != nil { | |||
@@ -355,13 +360,13 @@ func GenerateTrainJob(ctx *context.Context, req *GenerateTrainJobReq) (jobId str | |||
} else if ProcessorTypeGPU == req.ProcessType { | |||
datasetGrampus = getDatasetGPUGrampus(req.DatasetInfos, "/tmp/dataset") | |||
if len(req.ModelName) != 0 { | |||
modelGrampus = []models.GrampusDataset{ | |||
modelGrampus = []models.GrampusDataset{ //model save as obs | |||
{ | |||
Name: req.ModelName, | |||
Bucket: setting.Attachment.Minio.Bucket, | |||
EndPoint: setting.Attachment.Minio.Endpoint, | |||
ObjectKey: req.PreTrainModelPath, | |||
Bucket: setting.Bucket, | |||
EndPoint: getEndPoint(), | |||
ReadOnly: true, | |||
ObjectKey: req.PreTrainModelPath, | |||
ContainerPath: "/tmp/pretrainmodel/" + req.CkptName, | |||
}, | |||
} | |||
@@ -382,13 +387,13 @@ func GenerateTrainJob(ctx *context.Context, req *GenerateTrainJobReq) (jobId str | |||
} else if ProcessorTypeGCU == req.ProcessType { | |||
datasetGrampus = getDatasetGCUGrampus(req.DatasetInfos, "/tmp/dataset") | |||
if len(req.ModelName) != 0 { | |||
modelGrampus = []models.GrampusDataset{ | |||
modelGrampus = []models.GrampusDataset{ //model save as obs | |||
{ | |||
Name: req.ModelName, | |||
Bucket: setting.Attachment.Minio.Bucket, | |||
EndPoint: setting.Attachment.Minio.Endpoint, | |||
ObjectKey: req.PreTrainModelPath, | |||
Bucket: setting.Bucket, | |||
EndPoint: getEndPoint(), | |||
ReadOnly: true, | |||
ObjectKey: req.PreTrainModelPath, | |||
ContainerPath: "/tmp/pretrainmodel/" + req.CkptName, | |||
}, | |||
} | |||
@@ -407,6 +412,9 @@ func GenerateTrainJob(ctx *context.Context, req *GenerateTrainJobReq) (jobId str | |||
} | |||
} | |||
modelGrampusJson, _ := json.Marshal(modelGrampus) | |||
log.Info("train job modelGrampus=" + string(modelGrampusJson)) | |||
jobResult, err := createJob(models.CreateGrampusJobRequest{ | |||
Name: req.JobName, | |||
Tasks: []models.GrampusTasks{ | |||
@@ -465,6 +473,7 @@ func GenerateTrainJob(ctx *context.Context, req *GenerateTrainJobReq) (jobId str | |||
LabelName: req.LabelName, | |||
PreTrainModelUrl: req.PreTrainModelUrl, | |||
CkptName: req.CkptName, | |||
ModelId: req.ModelId, | |||
}) | |||
if err != nil { | |||
@@ -91,6 +91,7 @@ type GenerateTrainJobReq struct { | |||
ModelName string | |||
LabelName string | |||
CkptName string | |||
ModelId string | |||
ModelVersion string | |||
PreTrainModelUrl string | |||
} | |||
@@ -122,6 +123,7 @@ type GenerateInferenceJobReq struct { | |||
ModelName string | |||
ModelVersion string | |||
CkptName string | |||
ModelId string | |||
ResultUrl string | |||
Spec *models.Specification | |||
DatasetName string | |||
@@ -244,6 +246,7 @@ func GenerateNotebook2(ctx *context.Context, req cloudbrain.GenerateModelArtsNot | |||
LabelName: req.LabelName, | |||
PreTrainModelUrl: req.PreTrainModelUrl, | |||
CkptName: req.CkptName, | |||
ModelId: req.ModelId, | |||
} | |||
err = models.CreateCloudbrain(task) | |||
@@ -366,6 +369,7 @@ func GenerateTrainJob(ctx *context.Context, req *GenerateTrainJobReq) (jobId str | |||
LabelName: req.LabelName, | |||
PreTrainModelUrl: req.PreTrainModelUrl, | |||
CkptName: req.CkptName, | |||
ModelId: req.ModelId, | |||
}) | |||
if createErr != nil { | |||
@@ -526,6 +530,7 @@ func GenerateTrainJobVersion(ctx *context.Context, req *GenerateTrainJobReq, job | |||
LabelName: req.LabelName, | |||
PreTrainModelUrl: req.PreTrainModelUrl, | |||
CkptName: req.CkptName, | |||
ModelId: req.ModelId, | |||
}) | |||
if createErr != nil { | |||
log.Error("CreateCloudbrain(%s) failed:%v", req.JobName, createErr.Error()) | |||
@@ -706,6 +711,7 @@ func GenerateInferenceJob(ctx *context.Context, req *GenerateInferenceJobReq) (j | |||
ModelName: req.ModelName, | |||
ModelVersion: req.ModelVersion, | |||
CkptName: req.CkptName, | |||
ModelId: req.ModelId, | |||
ResultUrl: req.ResultUrl, | |||
CreatedUnix: createTime, | |||
UpdatedUnix: createTime, | |||
@@ -154,6 +154,7 @@ func GenerateNotebook(ctx *context.Context, req cloudbrain.GenerateModelArtsNote | |||
LabelName: req.LabelName, | |||
PreTrainModelUrl: req.PreTrainModelUrl, | |||
CkptName: req.CkptName, | |||
ModelId: req.ModelId, | |||
} | |||
err = models.CreateCloudbrain(task) | |||
@@ -1757,7 +1757,7 @@ func getModelConvertConfig() { | |||
ModelConvert.GPU_PYTORCH_IMAGE = sec.Key("GPU_PYTORCH_IMAGE").MustString("dockerhub.pcl.ac.cn:5000/user-images/openi:tensorRT_7_zouap") | |||
ModelConvert.GpuQueue = sec.Key("GpuQueue").MustString("openidgx") | |||
ModelConvert.GPU_TENSORFLOW_IMAGE = sec.Key("GPU_TENSORFLOW_IMAGE").MustString("dockerhub.pcl.ac.cn:5000/user-images/openi:tf2onnx") | |||
ModelConvert.NPU_MINDSPORE_16_IMAGE = sec.Key("NPU_MINDSPORE_16_IMAGE").MustString("swr.cn-south-222.ai.pcl.cn/openi/mindspore1.6.1_train_v1_openi:v3_ascend") | |||
ModelConvert.NPU_MINDSPORE_16_IMAGE = sec.Key("NPU_MINDSPORE_16_IMAGE").MustString("swr.cn-south-222.ai.pcl.cn/openi/mindspore1.8.1_train_openi_new:v1") | |||
ModelConvert.PytorchOnnxBootFile = sec.Key("PytorchOnnxBootFile").MustString("convert_pytorch.py") | |||
ModelConvert.PytorchTrTBootFile = sec.Key("PytorchTrTBootFile").MustString("convert_pytorch_tensorrt.py") | |||
ModelConvert.MindsporeBootFile = sec.Key("MindsporeBootFile").MustString("convert_mindspore.py") | |||
@@ -1767,8 +1767,8 @@ func getModelConvertConfig() { | |||
ModelConvert.GPU_Resource_Specs_ID = sec.Key("GPU_Resource_Specs_ID").MustInt(1) | |||
ModelConvert.NPU_FlavorCode = sec.Key("NPU_FlavorCode").MustString("modelarts.bm.910.arm.public.1") | |||
ModelConvert.NPU_PoolID = sec.Key("NPU_PoolID").MustString("pool7908321a") | |||
ModelConvert.NPU_MINDSPORE_IMAGE_ID = sec.Key("NPU_MINDSPORE_IMAGE_ID").MustInt(121) | |||
ModelConvert.NPU_TENSORFLOW_IMAGE_ID = sec.Key("NPU_TENSORFLOW_IMAGE_ID").MustInt(35) | |||
ModelConvert.NPU_MINDSPORE_IMAGE_ID = sec.Key("NPU_MINDSPORE_IMAGE_ID").MustInt(37) | |||
ModelConvert.NPU_TENSORFLOW_IMAGE_ID = sec.Key("NPU_TENSORFLOW_IMAGE_ID").MustInt(38) | |||
ModelConvert.GPU_PADDLE_IMAGE = sec.Key("GPU_PADDLE_IMAGE").MustString("dockerhub.pcl.ac.cn:5000/user-images/openi:paddle2.3.0_gpu_cuda11.2_cudnn8") | |||
ModelConvert.GPU_MXNET_IMAGE = sec.Key("GPU_MXNET_IMAGE").MustString("dockerhub.pcl.ac.cn:5000/user-images/openi:mxnet191cu_cuda102_py37") | |||
ModelConvert.PaddleOnnxBootFile = sec.Key("PaddleOnnxBootFile").MustString("convert_paddle.py") | |||
@@ -89,6 +89,10 @@ func (l *LocalStorage) UploadObject(fileName, filePath string) error { | |||
return nil | |||
} | |||
func (l *LocalStorage) UploadContent(bucketName string, path string, r io.Reader) (int64, error) { | |||
return int64(0), nil | |||
} | |||
func (l *LocalStorage) DeleteDir(dir string) error { | |||
return nil | |||
} |
@@ -163,6 +163,10 @@ func (m *MinioStorage) UploadObject(fileName, filePath string) error { | |||
return err | |||
} | |||
func (m *MinioStorage) UploadContent(bucketName string, path string, r io.Reader) (int64, error) { | |||
return m.client.PutObject(bucketName, path, r, -1, minio.PutObjectOptions{ContentType: "application/octet-stream"}) | |||
} | |||
func GetMinioPath(jobName, suffixPath string) string { | |||
return setting.Attachment.Minio.RealPath + setting.Attachment.Minio.Bucket + "/" + setting.CBCodePathPrefix + jobName + suffixPath | |||
} |
@@ -371,11 +371,13 @@ func GetOneLevelAllObjectUnderDir(bucket string, prefixRootPath string, relative | |||
for { | |||
output, err := ObsCli.ListObjects(input) | |||
if err == nil { | |||
log.Info("Page:%d\n", index) | |||
log.Info("Page:%d\n input.Prefix=v%", index, input.Prefix) | |||
log.Info("input.Prefix=" + input.Prefix) | |||
index++ | |||
for _, val := range output.Contents { | |||
var isDir bool | |||
var fileName string | |||
log.Info("val.key=" + val.Key) | |||
if val.Key == input.Prefix { | |||
continue | |||
} | |||
@@ -707,3 +709,33 @@ func IsObjectExist4Obs(bucket, key string) (bool, error) { | |||
} | |||
return true, nil | |||
} | |||
func PutStringToObs(bucket, key string, fileContent string) error { | |||
log.Info("PutStringToObs bucket=" + bucket + " key=" + key) | |||
input := &obs.PutObjectInput{} | |||
input.Bucket = bucket | |||
input.Key = key | |||
input.Body = strings.NewReader(fileContent) | |||
_, err := ObsCli.PutObject(input) | |||
if err != nil { | |||
if obsError, ok := err.(obs.ObsError); ok { | |||
log.Info("Message:%s\n", obsError.Message) | |||
} | |||
} | |||
return err | |||
} | |||
func PutReaderToObs(bucket, key string, reader io.Reader) error { | |||
log.Info("PutStringToObs bucket=" + bucket + " key=" + key) | |||
input := &obs.PutObjectInput{} | |||
input.Bucket = bucket | |||
input.Key = key | |||
input.Body = reader | |||
_, err := ObsCli.PutObject(input) | |||
if err != nil { | |||
if obsError, ok := err.(obs.ObsError); ok { | |||
log.Info("Message:%s\n", obsError.Message) | |||
} | |||
} | |||
return err | |||
} |
@@ -5,12 +5,13 @@ | |||
package storage | |||
import ( | |||
"fmt" | |||
"io" | |||
"code.gitea.io/gitea/modules/log" | |||
"code.gitea.io/gitea/modules/obs" | |||
"code.gitea.io/gitea/modules/setting" | |||
"fmt" | |||
"github.com/minio/minio-go" | |||
"io" | |||
) | |||
const ( | |||
@@ -29,6 +30,7 @@ type ObjectStorage interface { | |||
PresignedPutURL(path string) (string, error) | |||
HasObject(path string) (bool, error) | |||
UploadObject(fileName, filePath string) error | |||
UploadContent(bucketName string, path string, r io.Reader) (int64, error) | |||
} | |||
// Copy copys a file from source ObjectStorage to dest ObjectStorage | |||
@@ -16,6 +16,7 @@ type CreateGrampusTrainJobOption struct { | |||
ModelName string `json:"model_name"` | |||
ModelVersion string `json:"model_version"` | |||
CkptName string `json:"ckpt_name"` | |||
ModelId string `json:"model_id"` | |||
LabelName string `json:"label_names"` | |||
PreTrainModelUrl string `json:"pre_train_model_url"` | |||
SpecId int64 `json:"spec_id" binding:"Required"` | |||
@@ -36,6 +37,7 @@ type CreateTrainJobOption struct { | |||
ModelName string `json:"model_name"` | |||
ModelVersion string `json:"model_version"` | |||
CkptName string `json:"ckpt_name"` | |||
ModelId string `json:"model_id"` | |||
LabelName string `json:"label_names"` | |||
PreTrainModelUrl string `json:"pre_train_model_url"` | |||
SpecId int64 `json:"spec_id" binding:"Required"` | |||
@@ -52,6 +54,7 @@ type CreateNotebookOption struct { | |||
ModelName string `json:"model_name"` | |||
ModelVersion string `json:"model_version"` | |||
CkptName string `json:"ckpt_name"` | |||
ModelId string `json:"model_id"` | |||
LabelName string `json:"label_names"` | |||
PreTrainModelUrl string `json:"pre_train_model_url"` | |||
SpecId int64 `json:"spec_id" binding:"Required"` | |||
@@ -91,6 +94,7 @@ type Cloudbrain struct { | |||
ModelName string `json:"model_name"` //模型名称 | |||
ModelVersion string `json:"model_version"` //模型版本 | |||
CkptName string `json:"ckpt_name"` //权重文件名称 | |||
ModelId string `json:"model_id"` //权重文件名称 | |||
StartTime int64 `json:"start_time"` | |||
EndTime int64 `json:"end_time"` | |||
VersionName string `json:"version_name"` | |||
@@ -1059,6 +1059,7 @@ cloudbrain.time.starttime=Start run time | |||
cloudbrain.time.endtime=End run time | |||
cloudbrain.datasetdownload=Dataset download url | |||
model_manager = Model | |||
model_square = Model Square | |||
model_experience = Model Experience | |||
model_noright=You have no right to do the operation. | |||
model_rename=Duplicate model name, please modify model name. | |||
@@ -1263,6 +1264,7 @@ modelarts.infer_job.boot_file_helper=The startup file is the entry file for your | |||
modelarts.infer_job.continue_helper=Check Reuse to copy the output result file of the last training task | |||
modelarts.train_job.resource_helper=The "resource specification" is the hardware you use to run the task. In order for more people to use the resources of this platform, please select according to your actual needs | |||
modelarts.infer_job.tooltip = The model has been deleted and cannot be viewed. | |||
modelarts.infer_job.model_cant_see = You are currently unable to view the model, possibly due to permission restrictions or the model has been deleted. | |||
modelarts.download_log=Download log file | |||
modelarts.log_file = Log file | |||
modelarts.fullscreen_log_file = View in full screen | |||
@@ -1325,7 +1327,7 @@ model.manage.engine=Model engine | |||
model.manage.select.engine=Select model engine | |||
model.manage.modelfile=Model file | |||
model.manage.modellabel=Model label | |||
model.manage.modeldesc=Model description | |||
model.manage.modeldesc=Model brief introduction | |||
model.manage.modelaccess=Model Access | |||
model.manage.modelaccess.public=Public | |||
model.manage.modelaccess.private=Private | |||
@@ -2139,7 +2141,7 @@ settings.wiki_deletion_success = The repository wiki data has been deleted. | |||
settings.delete = Delete This Repository | |||
settings.delete_desc = Deleting a repository is permanent and cannot be undone. | |||
settings.delete_notices_1 = - This operation <strong>CANNOT</strong> be undone. | |||
settings.delete_notices_2 = - This operation will permanently delete the <strong>%s</strong> repository including code, issues, comments, wiki data and collaborator settings. | |||
settings.delete_notices_2 = - This operation will permanently delete the <strong>%s</strong> repository including the code, dataset, model, cloudbrain tasks, tasks, merge requests, and other contents. | |||
settings.delete_notices_fork_1 = - Forks of this repository will become independent after deletion. | |||
settings.deletion_success = The repository has been deleted. | |||
settings.update_settings_success = The repository settings have been updated. | |||
@@ -2619,6 +2621,7 @@ dashboard = Dashboard | |||
users = User Accounts | |||
organizations = Organizations | |||
datasets= Dataset | |||
models=Model | |||
repositories = Repositories | |||
hooks = Default Webhooks | |||
systemhooks = System Webhooks | |||
@@ -3161,7 +3164,7 @@ task_c2ent_gcutrainjob=`created GCU type train task <a href="%s/modelarts/train- | |||
task_nputrainjob=`created NPU training task <a href="%s/modelarts/train-job/%s">%s</a>` | |||
task_inferencejob=`created reasoning task <a href="%s/modelarts/inference-job/%s">%s</a>` | |||
task_benchmark=`created profiling task <a href="%s/cloudbrain/benchmark/%s">%s</a>` | |||
task_createmodel=`created new model <a href="%s/modelmanage/show_model_info?name=%s">%s</a>` | |||
task_createmodel=`created new model <a href="%s/modelmanage/model_readme_tmpl?name=%s">%s</a>` | |||
task_gputrainjob=`created CPU/GPU training task <a href="%s/cloudbrain/train-job/%s">%s</a>` | |||
task_c2netnputrainjob=`created NPU training task <a href="%s/grampus/train-job/%s">%s</a>` | |||
task_c2netgputrainjob=`created CPU/GPU training task <a href="%s/grampus/train-job/%s">%s</a>` | |||
@@ -1058,6 +1058,7 @@ datasets.desc=数据集功能 | |||
cloudbrain_helper=使用GPU/NPU资源,开启Notebook、模型训练任务等 | |||
model_manager = 模型 | |||
model_square = 模型广场 | |||
model_experience = 模型体验 | |||
model_noright=您没有操作权限。 | |||
model_rename=模型名称重复,请修改模型名称 | |||
@@ -1275,6 +1276,7 @@ modelarts.infer_job.boot_file_helper=启动文件是您程序执行的入口文 | |||
modelarts.infer_job.continue_helper=勾选复用将拷贝上次训练任务输出结果文件 | |||
modelarts.train_job.resource_helper=「资源规格」是您运行该任务使用的硬件,为了更多人能够使用本平台的资源,请按照您的实际需求进行选择。 | |||
modelarts.infer_job.tooltip = 该模型已删除,无法查看。 | |||
modelarts.infer_job.model_cant_see = 您暂时无法查看该模型,可能因为权限限制或模型已被删除。 | |||
modelarts.download_log=下载日志文件 | |||
modelarts.log_file=日志文件 | |||
modelarts.fullscreen_log_file=全屏查看 | |||
@@ -1338,7 +1340,7 @@ model.manage.engine=模型框架 | |||
model.manage.select.engine=选择模型框架 | |||
model.manage.modelfile=模型文件 | |||
model.manage.modellabel=模型标签 | |||
model.manage.modeldesc=模型描述 | |||
model.manage.modeldesc=模型简介 | |||
model.manage.modelaccess=模型权限 | |||
model.manage.modelaccess.public=公开 | |||
model.manage.modelaccess.private=私有 | |||
@@ -2155,7 +2157,7 @@ settings.wiki_deletion_success=项目百科数据删除成功! | |||
settings.delete=删除本项目 | |||
settings.delete_desc=删除项目是永久性的, 无法撤消。 | |||
settings.delete_notices_1=- 此操作 <strong>不可以</strong> 被回滚。 | |||
settings.delete_notices_2=- 此操作将永久删除项目 <strong>%s</strong>,包括 Git 数据、 任务、评论、百科和协作者的操作权限。 | |||
settings.delete_notices_2=- 此操作将永久删除项目 <strong>%s</strong>,包括该项目中的代码、数据集、模型、云脑任务、任务、合并请求等内容。 | |||
settings.delete_notices_fork_1=- 在此项目删除后,它的派生项目将变成独立项目。 | |||
settings.deletion_success=项目已被删除。 | |||
settings.deletion_notice_cloudbrain=请先停止项目内正在运行的云脑任务,然后再删除项目。 | |||
@@ -2638,6 +2640,7 @@ dashboard=管理面板 | |||
users=帐户管理 | |||
organizations=组织管理 | |||
datasets=数据集 | |||
models=模型 | |||
repositories=项目管理 | |||
hooks=默认Web钩子 | |||
systemhooks=系统 Web 钩子 | |||
@@ -3179,7 +3182,7 @@ task_c2ent_gcutrainjob=`创建了GCU类型训练任务 <a href="%s/grampus/train | |||
task_nputrainjob=`创建了NPU类型训练任务 <a href="%s/modelarts/train-job/%s">%s</a>` | |||
task_inferencejob=`创建了推理任务 <a href="%s/modelarts/inference-job/%s">%s</a>` | |||
task_benchmark=`创建了评测任务 <a href="%s/cloudbrain/benchmark/%s">%s</a>` | |||
task_createmodel=`导入了新模型 <a href="%s/modelmanage/show_model_info?name=%s">%s</a>` | |||
task_createmodel=`导入了新模型 <a href="%s/modelmanage/model_readme_tmpl?name=%s">%s</a>` | |||
task_gputrainjob=`创建了CPU/GPU类型训练任务 <a href="%s/cloudbrain/train-job/%s">%s</a>` | |||
task_c2netnputrainjob=`创建了NPU类型训练任务 <a href="%s/grampus/train-job/%s">%s</a>` | |||
task_c2netgputrainjob=`创建了CPU/GPU类型训练任务 <a href="%s/grampus/train-job/%s">%s</a>` | |||
@@ -290,7 +290,7 @@ function getTaskLink(record){ | |||
}else if(record.OpType == 29){ | |||
re = re + "/cloudbrain/benchmark/" + record.Content; | |||
}else if(record.OpType == 30){ | |||
re = re + "/modelmanage/show_model_info?name=" + record.RefName; | |||
re = re + "/modelmanage/model_readme_tmpl?name=" + record.RefName; | |||
}else if(record.OpType == 31){ | |||
re = re + "/cloudbrain/train-job/" + record.Content; | |||
}else if(record.OpType == 32 || record.OpType == 33 || record.OpType == 42){ | |||
@@ -0,0 +1,57 @@ | |||
<svg xmlns="http://www.w3.org/2000/svg" | |||
class="styles__StyledSVGIconPathComponent-sc-16fsqc8-0 fPsHiw svg-icon-path-icon" viewBox="0 0 430 298" | |||
width="100" height="100" fill="none"> | |||
<defs data-reactroot=""></defs> | |||
<g> | |||
<path id="矩形 3" d="M391 124L430 124L392 62L391 62L391 124Z" fill-rule="evenodd" | |||
fill="url(#paint_linear_3_11_0)"></path> | |||
<path id="矩形 1" d="M54 62L235 62L235 298L78 298C64.7452 298 54 287.255 54 274L54 62Z" fill-rule="evenodd" | |||
fill="url(#paint_linear_3_4_0)"></path> | |||
<path id="矩形 1" d="M392 62L235 62L235 298L368 298C381.255 298 392 287.255 392 274L392 62Z" | |||
fill-rule="evenodd" fill="url(#paint_linear_3_5_0)"></path> | |||
<rect id="矩形 2" x="282.000000" y="143.000000" rx="10.000000" width="62.000000" height="20.000000" | |||
fill="#AAAFBF"></rect> | |||
<path id="矩形 3" d="M273 0L430 0L392 62L235 62L273 0Z" fill-rule="evenodd" fill="url(#paint_linear_3_7_0)"> | |||
</path> | |||
<path id="矩形 3" d="M153 0L16 0L54 62L191 62L153 0Z" fill-rule="nonzero" fill="url(#paint_linear_3_8_0)"> | |||
</path> | |||
<path id="矩形 3" d="M195 124L16 124L54 62L233 62L195 124Z" fill-rule="evenodd" | |||
fill="url(#paint_linear_3_10_0)"></path> | |||
<path id="减去顶层" | |||
d="M54.5 217C24.4005 217 0 241.4 0 271.5C0 271.667 0.000747681 271.833 0.00224304 272L108.998 272C108.999 271.833 109 271.667 109 271.5C109 241.4 84.5995 217 54.5 217Z" | |||
clip-rule="evenodd" fill-rule="evenodd" fill="#4D9AFF" fill-opacity="0.500000"></path> | |||
<defs> | |||
<linearGradient id="paint_linear_3_11_0" x1="430.000000" y1="124.000000" x2="430.000000" y2="62.000000" | |||
gradientUnits="userSpaceOnUse"> | |||
<stop stop-color="#E2E3E7"></stop> | |||
<stop offset="1.000000" stop-color="#AAAFBF"></stop> | |||
</linearGradient> | |||
<linearGradient id="paint_linear_3_4_0" x1="54.000084" y1="62.000008" x2="235.000000" y2="298.000000" | |||
gradientUnits="userSpaceOnUse"> | |||
<stop stop-color="#DEE0E7"></stop> | |||
<stop offset="1.000000" stop-color="#EBECF1"></stop> | |||
</linearGradient> | |||
<linearGradient id="paint_linear_3_5_0" x1="0.000092" y1="-0.000008" x2="157.000000" y2="236.000015" | |||
gradientUnits="userSpaceOnUse"> | |||
<stop stop-color="#D8DAE2"></stop> | |||
<stop offset="1.000000" stop-color="#D1D1DC"></stop> | |||
</linearGradient> | |||
<linearGradient id="paint_linear_3_7_0" x1="429.999969" y1="0.000000" x2="235.000000" y2="62.000061" | |||
gradientUnits="userSpaceOnUse"> | |||
<stop stop-color="#D9DBE6"></stop> | |||
<stop offset="0.992366" stop-color="#CACCD8"></stop> | |||
</linearGradient> | |||
<linearGradient id="paint_linear_3_8_0" x1="15.999954" y1="0.000000" x2="15.999954" y2="62.000000" | |||
gradientUnits="userSpaceOnUse"> | |||
<stop stop-color="#EFEFF4"></stop> | |||
<stop offset="0.992366" stop-color="#EAEBF0"></stop> | |||
</linearGradient> | |||
<linearGradient id="paint_linear_3_10_0" x1="16.000000" y1="124.000000" x2="16.000000" y2="62.000000" | |||
gradientUnits="userSpaceOnUse"> | |||
<stop stop-color="#F5F4F7"></stop> | |||
<stop offset="0.809160" stop-color="#E7E9EE"></stop> | |||
<stop offset="1.000000" stop-color="#F2F2F5"></stop> | |||
</linearGradient> | |||
</defs> | |||
</g> | |||
</svg> |
@@ -1,11 +1,12 @@ | |||
package admin | |||
import ( | |||
"code.gitea.io/gitea/modules/notification" | |||
"net/http" | |||
"strconv" | |||
"strings" | |||
"code.gitea.io/gitea/modules/notification" | |||
"code.gitea.io/gitea/models" | |||
"code.gitea.io/gitea/modules/base" | |||
"code.gitea.io/gitea/modules/context" | |||
@@ -15,6 +16,7 @@ import ( | |||
const ( | |||
tplDatasets base.TplName = "admin/dataset/list" | |||
tplAdminModelManage base.TplName = "admin/model/list" | |||
) | |||
func Datasets(ctx *context.Context) { | |||
@@ -0,0 +1,189 @@ | |||
package admin | |||
import ( | |||
"fmt" | |||
"strings" | |||
"code.gitea.io/gitea/models" | |||
"code.gitea.io/gitea/modules/context" | |||
"code.gitea.io/gitea/modules/log" | |||
"code.gitea.io/gitea/modules/setting" | |||
) | |||
func AdminModelManage(ctx *context.Context) { | |||
ctx.Data["Title"] = ctx.Tr("admin.models") | |||
ctx.Data["PageIsAdmin"] = true | |||
ctx.Data["PageIsAdminModels"] = true | |||
page := ctx.QueryInt("page") | |||
if page <= 0 { | |||
page = 1 | |||
} | |||
pageSize := ctx.QueryInt("pageSize") | |||
if pageSize <= 0 { | |||
pageSize = setting.UI.IssuePagingNum | |||
} | |||
var ( | |||
count int64 | |||
err error | |||
orderBy string | |||
) | |||
ctx.Data["SortType"] = ctx.Query("sort") | |||
switch ctx.Query("sort") { | |||
case "newest": | |||
orderBy = "created_unix DESC" | |||
case "oldest": | |||
orderBy = "created_unix ASC" | |||
case "recentupdate": | |||
orderBy = "updated_unix DESC" | |||
case "leastupdate": | |||
orderBy = "updated_unix ASC" | |||
case "reversealphabetically": | |||
orderBy = "name DESC" | |||
case "alphabetically": | |||
orderBy = "name ASC" | |||
case "reversesize": | |||
orderBy = "size DESC" | |||
case "size": | |||
orderBy = "size ASC" | |||
case "downloadtimes": | |||
orderBy = "download_count DESC" | |||
case "mostusecount": | |||
orderBy = "reference_count DESC" | |||
case "fewestusecount": | |||
orderBy = "reference_count ASC" | |||
default: | |||
ctx.Data["SortType"] = "recentupdate" | |||
orderBy = "created_unix DESC" | |||
} | |||
keyword := strings.Trim(ctx.Query("q"), " ") | |||
modelResult, count, err := models.QueryModel(&models.AiModelQueryOptions{ | |||
ListOptions: models.ListOptions{ | |||
Page: page, | |||
PageSize: setting.UI.ExplorePagingNum, | |||
}, | |||
Type: -1, | |||
New: -1, | |||
Status: -1, | |||
IsQueryPrivate: true, | |||
IsRecommend: ctx.QueryBool("recommend"), | |||
UserID: -1, | |||
IsCollected: false, | |||
CollectedUserId: -1, | |||
LabelFilter: "", | |||
FrameFilter: -1, | |||
ComputeResourceFilter: "", | |||
Namelike: keyword, | |||
SortType: orderBy, | |||
RepoID: -1, | |||
}) | |||
if err != nil { | |||
ctx.ServerError("Cloudbrain", err) | |||
return | |||
} | |||
userIds := make([]int64, len(modelResult)) | |||
modelIds := make([]string, len(modelResult)) | |||
repoIds := make([]int64, len(modelResult)) | |||
for i, model := range modelResult { | |||
userIds[i] = model.UserId | |||
modelIds[i] = model.ID | |||
repoIds[i] = model.RepoId | |||
} | |||
repoInfo, err := queryRepoInfoByIds(repoIds) | |||
userNameMap := queryUserName(userIds) | |||
for _, model := range modelResult { | |||
//removeIpInfo(model) | |||
model.TrainTaskInfo = "" | |||
value := userNameMap[model.UserId] | |||
if value != nil { | |||
model.UserName = value.Name | |||
model.UserRelAvatarLink = value.RelAvatarLink() | |||
} | |||
if repoInfo != nil { | |||
repo := repoInfo[model.RepoId] | |||
if repo != nil { | |||
model.RepoName = repo.Name | |||
model.RepoOwnerName = repo.OwnerName | |||
model.RepoDisplayName = repo.DisplayName() | |||
} | |||
} | |||
} | |||
ctx.Data["Keyword"] = keyword | |||
ctx.Data["Total"] = count | |||
ctx.Data["models"] = modelResult | |||
ctx.Data["Recommend"] = ctx.QueryBool("recommend") | |||
pager := context.NewPagination(int(count), setting.UI.ExplorePagingNum, page, 5) | |||
pager.SetDefaultParams(ctx) | |||
ctx.Data["Page"] = pager | |||
ctx.HTML(200, tplAdminModelManage) | |||
} | |||
func ModifyModelRecommend(ctx *context.Context) { | |||
id := ctx.Query("id") | |||
isRecommend := ctx.QueryInt("recommend") | |||
re := map[string]string{ | |||
"code": "-1", | |||
} | |||
task, err := models.QueryModelById(id) | |||
if err != nil || task == nil { | |||
re["msg"] = err.Error() | |||
log.Error("no such model!", err.Error()) | |||
ctx.JSON(200, re) | |||
return | |||
} | |||
if ctx.User == nil || !ctx.User.IsAdmin { | |||
re["msg"] = "No right to operation." | |||
ctx.JSON(200, re) | |||
return | |||
} | |||
err = models.ModifyModelRecommend(id, isRecommend) | |||
if err == nil { | |||
re["code"] = "0" | |||
ctx.JSON(200, re) | |||
log.Info("modify success.") | |||
} else { | |||
re["msg"] = err.Error() | |||
ctx.JSON(200, re) | |||
log.Info("Failed to modify.id=" + id + " isprivate=" + fmt.Sprint(isRecommend) + " error:" + err.Error()) | |||
} | |||
} | |||
func queryUserName(intSlice []int64) map[int64]*models.User { | |||
keys := make(map[int64]string) | |||
uniqueElements := []int64{} | |||
for _, entry := range intSlice { | |||
if _, value := keys[entry]; !value { | |||
keys[entry] = "" | |||
uniqueElements = append(uniqueElements, entry) | |||
} | |||
} | |||
result := make(map[int64]*models.User) | |||
userLists, err := models.GetUsersByIDs(uniqueElements) | |||
if err == nil { | |||
for _, user := range userLists { | |||
result[user.ID] = user | |||
} | |||
} | |||
return result | |||
} | |||
func queryRepoInfoByIds(intSlice []int64) (map[int64]*models.Repository, error) { | |||
keys := make(map[int64]string) | |||
uniqueElements := []int64{} | |||
for _, entry := range intSlice { | |||
if _, value := keys[entry]; !value { | |||
keys[entry] = "" | |||
uniqueElements = append(uniqueElements, entry) | |||
} | |||
} | |||
re, err := models.GetRepositoriesMapByIDs(uniqueElements) | |||
return re, err | |||
} |
@@ -57,8 +57,8 @@ const ( | |||
NetOutputFormat_FP32 = 0 | |||
NetOutputFormat_FP16 = 1 | |||
NPU_MINDSPORE_IMAGE_ID = 35 | |||
NPU_TENSORFLOW_IMAGE_ID = 121 | |||
//NPU_MINDSPORE_IMAGE_ID = 37 | |||
//NPU_TENSORFLOW_IMAGE_ID = 38 | |||
//GPU_Resource_Specs_ID = 1 //cpu 1, gpu 1 | |||
@@ -219,10 +219,10 @@ func createNpuTrainJob(modelConvert *models.AiModelConvert, ctx *context.Context | |||
} | |||
var engineId int64 | |||
engineId = int64(NPU_MINDSPORE_IMAGE_ID) | |||
engineId = int64(setting.ModelConvert.NPU_MINDSPORE_IMAGE_ID) | |||
bootfile := setting.ModelConvert.MindsporeBootFile | |||
if modelConvert.SrcEngine == TENSORFLOW_ENGINE { | |||
engineId = int64(NPU_TENSORFLOW_IMAGE_ID) | |||
engineId = int64(setting.ModelConvert.NPU_TENSORFLOW_IMAGE_ID) | |||
bootfile = setting.ModelConvert.TensorFlowNpuBootFile | |||
} | |||
userCommand := "/bin/bash /home/work/run_train.sh 's3://" + codeObsPath + "' 'code/" + bootfile + "' '/tmp/log/train.log' --'data_url'='s3://" + dataPath + "' --'train_url'='s3://" + outputObsPath + "'" | |||
@@ -373,6 +373,16 @@ func createGpuTrainJob(modelConvert *models.AiModelConvert, ctx *context.Context | |||
command := "" | |||
IMAGE_URL := setting.ModelConvert.GPU_PYTORCH_IMAGE | |||
dataActualPath := setting.Attachment.Minio.RealPath + modelRelativePath | |||
if model.Type == models.TypeCloudBrainTwo { | |||
//如果模型在OBS上,需要下载到本地,并上传到minio中 | |||
relatetiveModelPath := setting.JobPath + modelConvert.ID + "/dataset" | |||
log.Info("local dataset path:" + relatetiveModelPath) | |||
downloadFromObsToLocal(model, relatetiveModelPath) | |||
uploadCodeToMinio(relatetiveModelPath+"/", modelConvert.ID, "/dataset/") | |||
deleteLocalDir(relatetiveModelPath) | |||
dataActualPath = setting.Attachment.Minio.RealPath + setting.Attachment.Minio.Bucket + "/" + setting.CBCodePathPrefix + modelConvert.ID + "/dataset" | |||
} | |||
log.Info("dataActualPath=" + dataActualPath) | |||
if modelConvert.SrcEngine == PYTORCH_ENGINE { | |||
if modelConvert.DestFormat == CONVERT_FORMAT_ONNX { | |||
@@ -389,15 +399,6 @@ func createGpuTrainJob(modelConvert *models.AiModelConvert, ctx *context.Context | |||
} else { | |||
return errors.New("Not support the format.") | |||
} | |||
//如果模型在OBS上,需要下载到本地,并上传到minio中 | |||
if model.Type == models.TypeCloudBrainTwo { | |||
relatetiveModelPath := setting.JobPath + modelConvert.ID + "/dataset" | |||
log.Info("local dataset path:" + relatetiveModelPath) | |||
downloadFromObsToLocal(model, relatetiveModelPath) | |||
uploadCodeToMinio(relatetiveModelPath+"/", modelConvert.ID, "/dataset/") | |||
deleteLocalDir(relatetiveModelPath) | |||
dataActualPath = setting.Attachment.Minio.RealPath + setting.Attachment.Minio.Bucket + "/" + setting.CBCodePathPrefix + modelConvert.ID + "/dataset" | |||
} | |||
} else if modelConvert.SrcEngine == PADDLE_ENGINE { | |||
IMAGE_URL = setting.ModelConvert.GPU_PADDLE_IMAGE | |||
if modelConvert.DestFormat == CONVERT_FORMAT_ONNX { | |||
@@ -413,7 +414,6 @@ func createGpuTrainJob(modelConvert *models.AiModelConvert, ctx *context.Context | |||
return errors.New("Not support the format.") | |||
} | |||
} | |||
log.Info("dataActualPath=" + dataActualPath) | |||
log.Info("command=" + command) | |||
@@ -31,8 +31,8 @@ const ( | |||
tplModelManageIndex = "repo/modelmanage/index" | |||
tplModelManageDownload = "repo/modelmanage/download" | |||
tplModelInfo = "repo/modelmanage/showinfo" | |||
tplCreateLocalModelInfo = "repo/modelmanage/create_local_1" | |||
tplCreateLocalForUploadModelInfo = "repo/modelmanage/create_local_2" | |||
tplCreateLocalModelInfo = "repo/modelmanage/create_local" | |||
tplCreateLocalForUploadModelInfo = "repo/modelmanage/fileupload" | |||
tplCreateOnlineModelInfo = "repo/modelmanage/create_online" | |||
MODEL_LATEST = 1 | |||
@@ -75,14 +75,12 @@ func saveModelByParameters(jobId string, versionName string, name string, versio | |||
} | |||
} | |||
} | |||
cloudType := aiTask.Type | |||
modelSelectedFile := ctx.Query("modelSelectedFile") | |||
//download model zip //train type | |||
if aiTask.ComputeResource == models.NPUResource || aiTask.ComputeResource == models.GCUResource { | |||
cloudType = models.TypeCloudBrainTwo | |||
} else if aiTask.ComputeResource == models.GPUResource { | |||
cloudType = models.TypeCloudBrainOne | |||
} | |||
cloudType := models.TypeCloudBrainTwo | |||
spec, err := resource.GetCloudbrainSpec(aiTask.ID) | |||
if err == nil { | |||
specJson, _ := json.Marshal(spec) | |||
@@ -119,6 +117,7 @@ func saveModelByParameters(jobId string, versionName string, name string, versio | |||
Accuracy: string(accuracyJson), | |||
Status: STATUS_COPY_MODEL, | |||
IsPrivate: isPrivate, | |||
ComputeResource: aiTask.ComputeResource, | |||
} | |||
err = models.SaveModelToDb(model) | |||
@@ -145,7 +144,9 @@ func saveModelByParameters(jobId string, versionName string, name string, versio | |||
go asyncToCopyModel(aiTask, id, modelSelectedFile) | |||
log.Info("save model end.") | |||
if !model.IsPrivate { | |||
notification.NotifyOtherTask(ctx.User, ctx.Repo.Repository, id, name, models.ActionCreateNewModelTask) | |||
} | |||
return id, nil | |||
} | |||
@@ -157,6 +158,7 @@ func asyncToCopyModel(aiTask *models.Cloudbrain, id string, modelSelectedFile st | |||
log.Info("download model from CloudBrainTwo faild." + err.Error()) | |||
} else { | |||
updateStatus(id, modelSize, STATUS_FINISHED, modelPath, "") | |||
insertModelFile(id) | |||
} | |||
} else if aiTask.ComputeResource == models.GPUResource { | |||
@@ -166,7 +168,24 @@ func asyncToCopyModel(aiTask *models.Cloudbrain, id string, modelSelectedFile st | |||
log.Info("download model from CloudBrainOne faild." + err.Error()) | |||
} else { | |||
updateStatus(id, modelSize, STATUS_FINISHED, modelPath, "") | |||
insertModelFile(id) | |||
} | |||
} | |||
} | |||
func insertModelFile(id string) { | |||
model, _ := models.QueryModelById(id) | |||
files, err := storage.GetAllObjectByBucketAndPrefix(setting.Bucket, model.Path[len(setting.Bucket)+1:]) | |||
if err != nil { | |||
log.Info("Failed to query model size from obs. id=" + id) | |||
} | |||
for _, file := range files { | |||
modelFile := &models.AiModelFile{ | |||
ModelID: id, | |||
Name: file.FileName, | |||
Size: file.Size, | |||
} | |||
models.SaveModelFile(modelFile) | |||
} | |||
} | |||
@@ -229,13 +248,23 @@ func SaveLocalModel(ctx *context.Context) { | |||
engine := ctx.QueryInt("engine") | |||
taskType := ctx.QueryInt("type") | |||
isPrivate := ctx.QueryBool("isPrivate") | |||
if ctx.Repo.Repository.IsPrivate { | |||
if !isPrivate { | |||
re["msg"] = "Private repo cannot create public model." | |||
ctx.JSON(200, re) | |||
return | |||
} | |||
} | |||
modelActualPath := "" | |||
computeResource := "" | |||
if taskType == models.TypeCloudBrainOne { | |||
destKeyNamePrefix := Model_prefix + models.AttachmentRelativePath(id) + "/" | |||
modelActualPath = setting.Attachment.Minio.Bucket + "/" + destKeyNamePrefix | |||
computeResource = models.GPUResource | |||
} else if taskType == models.TypeCloudBrainTwo { | |||
destKeyNamePrefix := Model_prefix + models.AttachmentRelativePath(id) + "/" | |||
modelActualPath = setting.Bucket + "/" + destKeyNamePrefix | |||
computeResource = models.NPUResource | |||
} else { | |||
re["msg"] = "type is error." | |||
ctx.JSON(200, re) | |||
@@ -276,6 +305,7 @@ func SaveLocalModel(ctx *context.Context) { | |||
Accuracy: "", | |||
Status: STATUS_FINISHED, | |||
IsPrivate: isPrivate, | |||
ComputeResource: computeResource, | |||
} | |||
err := models.SaveModelToDb(model) | |||
@@ -302,7 +332,9 @@ func SaveLocalModel(ctx *context.Context) { | |||
models.UpdateRepositoryUnits(ctx.Repo.Repository, units, deleteUnitTypes) | |||
log.Info("save model end.") | |||
if !model.IsPrivate { | |||
notification.NotifyOtherTask(ctx.User, ctx.Repo.Repository, id, name, models.ActionCreateNewModelTask) | |||
} | |||
re["code"] = "0" | |||
re["id"] = id | |||
ctx.JSON(200, re) | |||
@@ -316,20 +348,10 @@ func getSize(files []storage.FileInfo) int64 { | |||
return size | |||
} | |||
func UpdateModelSize(modeluuid string) { | |||
func UpdateModelSize(modeluuid string, objectName string) { | |||
model, err := models.QueryModelById(modeluuid) | |||
if err == nil { | |||
var size int64 | |||
if model.Type == models.TypeCloudBrainOne { | |||
if strings.HasPrefix(model.Path, setting.Attachment.Minio.Bucket+"/"+Model_prefix) { | |||
files, err := storage.GetAllObjectByBucketAndPrefixMinio(setting.Attachment.Minio.Bucket, model.Path[len(setting.Attachment.Minio.Bucket)+1:]) | |||
if err != nil { | |||
log.Info("Failed to query model size from minio. id=" + modeluuid) | |||
} | |||
size = getSize(files) | |||
models.ModifyModelSize(modeluuid, size) | |||
} | |||
} else if model.Type == models.TypeCloudBrainTwo { | |||
if strings.HasPrefix(model.Path, setting.Bucket+"/"+Model_prefix) { | |||
files, err := storage.GetAllObjectByBucketAndPrefix(setting.Bucket, model.Path[len(setting.Bucket)+1:]) | |||
if err != nil { | |||
@@ -337,6 +359,22 @@ func UpdateModelSize(modeluuid string) { | |||
} | |||
size = getSize(files) | |||
models.ModifyModelSize(modeluuid, size) | |||
modelFileName := objectName | |||
index := strings.LastIndex(objectName, "/") | |||
if index > 0 { | |||
modelFileName = objectName[index+1:] | |||
} | |||
log.Info("modelFileName=" + modelFileName) | |||
for _, file := range files { | |||
log.Info("fileName=" + file.FileName) | |||
if file.FileName == modelFileName { | |||
modelFile := &models.AiModelFile{ | |||
ModelID: modeluuid, | |||
Name: file.FileName, | |||
Size: file.Size, | |||
} | |||
models.SaveModelFile(modelFile) | |||
} | |||
} | |||
} | |||
if model.Size == 0 && size > 0 { | |||
@@ -365,6 +403,14 @@ func SaveModel(ctx *context.Context) { | |||
re := map[string]string{ | |||
"code": "-1", | |||
} | |||
isPrivate := ctx.QueryBool("isPrivate") | |||
if ctx.Repo.Repository.IsPrivate { | |||
if !isPrivate { | |||
re["msg"] = "Private repo cannot create public model." | |||
ctx.JSON(200, re) | |||
return | |||
} | |||
} | |||
if JobId == "" || VersionName == "" { | |||
re["msg"] = "JobId or VersionName is null." | |||
ctx.JSON(200, re) | |||
@@ -427,10 +473,10 @@ func downloadModelFromCloudBrainTwo(modelUUID string, jobName string, parentDir | |||
} | |||
func downloadModelFromCloudBrainOne(modelUUID string, jobName string, parentDir string, trainUrl string, modelSelectedFile string) (string, int64, error) { | |||
modelActualPath := storage.GetMinioPath(jobName, "/model/") | |||
log.Info("modelActualPath=" + modelActualPath) | |||
modelSrcPrefix := setting.CBCodePathPrefix + jobName + "/model/" | |||
destKeyNamePrefix := Model_prefix + models.AttachmentRelativePath(modelUUID) + "/" | |||
modelSrcPrefix := setting.CBCodePathPrefix + jobName + "/model/" | |||
//destKeyNamePrefix := Model_prefix + models.AttachmentRelativePath(modelUUID) + "/" | |||
bucketName := setting.Attachment.Minio.Bucket | |||
log.Info("destKeyNamePrefix=" + destKeyNamePrefix + " modelSrcPrefix=" + modelSrcPrefix + " bucket=" + bucketName) | |||
filterFiles := strings.Split(modelSelectedFile, ";") | |||
@@ -442,14 +488,26 @@ func downloadModelFromCloudBrainOne(modelUUID string, jobName string, parentDir | |||
if float64(totalSize) > setting.MaxModelSize*MODEL_MAX_SIZE { | |||
return "", 0, errors.New("Cannot create model, as model is exceed " + fmt.Sprint(setting.MaxModelSize) + "G.") | |||
} | |||
size, err := storage.MinioCopyFiles(bucketName, modelSrcPrefix, destKeyNamePrefix, filterFiles) | |||
for i, modelFile := range Files { | |||
reader, err := storage.Attachments.DownloadAFile(bucketName, modelFile) | |||
if err == nil { | |||
dataActualPath := bucketName + "/" + destKeyNamePrefix | |||
return dataActualPath, size, nil | |||
} else { | |||
defer reader.Close() | |||
log.Info("upload to bucket=" + setting.Bucket + " objectKey=" + destKeyNamePrefix + filterFiles[i]) | |||
obsErr := storage.PutReaderToObs(setting.Bucket, destKeyNamePrefix+filterFiles[i], reader) | |||
if obsErr != nil { | |||
log.Info("upload to obs failed.err=" + obsErr.Error()) | |||
return "", 0, nil | |||
} | |||
} | |||
} | |||
//size, err := storage.MinioCopyFiles(bucketName, modelSrcPrefix, destKeyNamePrefix, filterFiles) | |||
dataActualPath := setting.Bucket + "/" + destKeyNamePrefix | |||
//dataActualPath := bucketName + "/" + destKeyNamePrefix | |||
return dataActualPath, totalSize, nil | |||
} | |||
func DeleteModelFile(ctx *context.Context) { | |||
log.Info("delete model start.") | |||
id := ctx.Query("id") | |||
@@ -458,27 +516,7 @@ func DeleteModelFile(ctx *context.Context) { | |||
if err == nil { | |||
var totalSize int64 | |||
if model.ModelType == MODEL_LOCAL_TYPE { | |||
if model.Type == models.TypeCloudBrainOne { | |||
bucketName := setting.Attachment.Minio.Bucket | |||
objectName := model.Path[len(bucketName)+1:] + fileName | |||
log.Info("delete bucket=" + bucketName + " path=" + objectName) | |||
if strings.HasPrefix(model.Path, bucketName+"/"+Model_prefix) { | |||
totalSize = storage.MinioGetFilesSize(bucketName, []string{objectName}) | |||
err := storage.Attachments.DeleteDir(objectName) | |||
if err != nil { | |||
log.Info("Failed to delete model. id=" + id) | |||
re := map[string]string{ | |||
"code": "-1", | |||
} | |||
re["msg"] = err.Error() | |||
ctx.JSON(200, re) | |||
return | |||
} else { | |||
log.Info("delete minio file size is:" + fmt.Sprint(totalSize)) | |||
models.ModifyModelSize(id, model.Size-totalSize) | |||
} | |||
} | |||
} else if model.Type == models.TypeCloudBrainTwo { | |||
bucketName := setting.Bucket | |||
objectName := model.Path[len(setting.Bucket)+1:] + fileName | |||
log.Info("delete bucket=" + setting.Bucket + " path=" + objectName) | |||
@@ -496,9 +534,14 @@ func DeleteModelFile(ctx *context.Context) { | |||
} else { | |||
log.Info("delete obs file size is:" + fmt.Sprint(totalSize)) | |||
models.ModifyModelSize(id, model.Size-totalSize) | |||
modelFile := &models.AiModelFile{ | |||
Name: fileName, | |||
ModelID: id, | |||
} | |||
models.DeleteModelFile(modelFile) | |||
} | |||
} | |||
} | |||
if (model.Size - totalSize) <= 0 { | |||
go repository.ResetRepoModelNum(model.RepoId) | |||
@@ -534,17 +577,6 @@ func deleteModelByID(ctx *context.Context, id string) error { | |||
} | |||
if err == nil { | |||
if model.Type == models.TypeCloudBrainOne { | |||
bucketName := setting.Attachment.Minio.Bucket | |||
log.Info("bucket=" + bucketName + " path=" + model.Path) | |||
if strings.HasPrefix(model.Path, bucketName+"/"+Model_prefix) { | |||
err := storage.Attachments.DeleteDir(model.Path[len(bucketName)+1:]) | |||
if err != nil { | |||
log.Info("Failed to delete model. id=" + id) | |||
return err | |||
} | |||
} | |||
} else if model.Type == models.TypeCloudBrainTwo { | |||
log.Info("bucket=" + setting.Bucket + " path=" + model.Path) | |||
if strings.HasPrefix(model.Path, setting.Bucket+"/"+Model_prefix) { | |||
err := storage.ObsRemoveObject(setting.Bucket, model.Path[len(setting.Bucket)+1:]) | |||
@@ -553,7 +585,6 @@ func deleteModelByID(ctx *context.Context, id string) error { | |||
return err | |||
} | |||
} | |||
} | |||
err = models.DeleteModelById(id) | |||
if err == nil { //find a model to change new | |||
@@ -908,20 +939,37 @@ func QueryModelById(ctx *context.Context) { | |||
func ShowSingleModel(ctx *context.Context) { | |||
name := ctx.Query("name") | |||
log.Info("Show single ModelInfo start.name=" + name) | |||
models := models.QueryModelByName(name, ctx.Repo.Repository.ID) | |||
userIds := make([]int64, len(models)) | |||
for i, model := range models { | |||
modelArrays := models.QueryModelByName(name, ctx.Repo.Repository.ID) | |||
modelResult := make([]*models.AiModelManage, 0) | |||
isCanReadPrivateModel := isQueryPrivateModel(ctx) | |||
userIds := make([]int64, len(modelArrays)) | |||
for i, model := range modelArrays { | |||
model.IsCanOper = isOperModifyOrDelete(ctx, model.UserId) | |||
model.IsCanDownload = isCanDownload(ctx, model) | |||
model.IsCanDelete = isCanDelete(ctx, model.UserId) | |||
model.RepoName = ctx.Repo.Repository.Name | |||
model.RepoOwnerName = ctx.Repo.Repository.OwnerName | |||
model.RepoDisplayName = ctx.Repo.Repository.DisplayName() | |||
userIds[i] = model.UserId | |||
if ctx.User != nil { | |||
re := models.QueryModelCollectByUserId(model.ID, ctx.User.ID) | |||
if re != nil && len(re) > 0 { | |||
model.IsCollected = true | |||
} | |||
} | |||
if model.IsPrivate { | |||
if !isCanReadPrivateModel { | |||
continue | |||
} | |||
} | |||
modelResult = append(modelResult, model) | |||
} | |||
userNameMap := queryUserName(userIds) | |||
for _, model := range models { | |||
for _, model := range modelResult { | |||
removeIpInfo(model) | |||
value := userNameMap[model.UserId] | |||
if value != nil { | |||
@@ -929,7 +977,7 @@ func ShowSingleModel(ctx *context.Context) { | |||
model.UserRelAvatarLink = value.RelAvatarLink() | |||
} | |||
} | |||
ctx.JSON(http.StatusOK, models) | |||
ctx.JSON(http.StatusOK, modelResult) | |||
} | |||
func removeIpInfo(model *models.AiModelManage) { | |||
@@ -1002,6 +1050,7 @@ func SetModelCount(ctx *context.Context) { | |||
New: MODEL_LATEST, | |||
IsOnlyThisRepo: true, | |||
Status: -1, | |||
FrameFilter: -1, | |||
IsQueryPrivate: isQueryPrivate, | |||
}) | |||
ctx.Data["MODEL_COUNT"] = count | |||
@@ -1140,6 +1189,7 @@ func ShowModelPageInfo(ctx *context.Context) { | |||
IsOnlyThisRepo: true, | |||
Status: -1, | |||
IsQueryPrivate: isQueryPrivate, | |||
FrameFilter: -1, | |||
}) | |||
if err != nil { | |||
ctx.ServerError("Cloudbrain", err) | |||
@@ -1171,16 +1221,6 @@ func ShowModelPageInfo(ctx *context.Context) { | |||
ctx.JSON(http.StatusOK, mapInterface) | |||
} | |||
func ModifyModel(id string, description string) error { | |||
err := models.ModifyModelDescription(id, description) | |||
if err == nil { | |||
log.Info("modify success.") | |||
} else { | |||
log.Info("Failed to modify.id=" + id + " desc=" + description + " error:" + err.Error()) | |||
} | |||
return err | |||
} | |||
func ModifyModelPrivate(ctx *context.Context) { | |||
id := ctx.Query("id") | |||
isPrivate := ctx.QueryBool("isPrivate") | |||
@@ -1230,7 +1270,7 @@ func ModifyModelInfo(ctx *context.Context) { | |||
ctx.JSON(200, re) | |||
return | |||
} | |||
if task.ModelType == MODEL_LOCAL_TYPE { | |||
name := ctx.Query("name") | |||
label := ctx.Query("label") | |||
description := ctx.Query("description") | |||
@@ -1251,13 +1291,13 @@ func ModifyModelInfo(ctx *context.Context) { | |||
} | |||
} | |||
err = models.ModifyLocalModel(id, name, label, description, engine, isPrivate) | |||
} else { | |||
label := ctx.Query("label") | |||
description := ctx.Query("description") | |||
engine := task.Engine | |||
name := task.Name | |||
err = models.ModifyLocalModel(id, name, label, description, int(engine), task.IsPrivate) | |||
if task.Name != name { | |||
aimodels = models.QueryModelByName(task.Name, task.RepoId) | |||
if aimodels != nil && len(aimodels) > 0 { | |||
for _, model := range aimodels { | |||
models.ModifyLocalModel(model.ID, name, model.Label, model.Description, int(model.Engine), model.IsPrivate) | |||
} | |||
} | |||
} | |||
if err != nil { | |||
@@ -1288,11 +1328,12 @@ func QueryModelListForPredict(ctx *context.Context) { | |||
PageSize: pageSize, | |||
}, | |||
RepoID: repoId, | |||
Type: ctx.QueryInt("type"), | |||
Type: -1, | |||
New: -1, | |||
Status: 0, | |||
IsOnlyThisRepo: true, | |||
IsQueryPrivate: isQueryPrivate, | |||
FrameFilter: -1, | |||
}) | |||
if err != nil { | |||
ctx.ServerError("Cloudbrain", err) | |||
@@ -1349,26 +1390,27 @@ func QueryOneLevelModelFile(ctx *context.Context) { | |||
model, err := models.QueryModelById(id) | |||
if err != nil { | |||
log.Error("no such model!", err.Error()) | |||
ctx.ServerError("no such model:", err) | |||
ctx.JSON(http.StatusOK, nil) | |||
return | |||
} | |||
ctx.JSON(http.StatusOK, queryOneLevelModelFile(model, parentDir)) | |||
} | |||
func queryOneLevelModelFile(model *models.AiModelManage, parentDir string) []storage.FileInfo { | |||
fileinfos := make([]storage.FileInfo, 0) | |||
if model.Type == models.TypeCloudBrainTwo { | |||
log.Info("TypeCloudBrainTwo list model file.") | |||
prefix := model.Path[len(setting.Bucket)+1:] | |||
fileinfos, _ := storage.GetOneLevelAllObjectUnderDir(setting.Bucket, prefix, parentDir) | |||
if fileinfos == nil { | |||
fileinfos = make([]storage.FileInfo, 0) | |||
} | |||
ctx.JSON(http.StatusOK, fileinfos) | |||
prefix := model.Path[len(setting.Bucket)+1:] + parentDir | |||
fileinfos, _ = storage.GetOneLevelAllObjectUnderDir(setting.Bucket, prefix, "") | |||
} else if model.Type == models.TypeCloudBrainOne { | |||
log.Info("TypeCloudBrainOne list model file.") | |||
prefix := model.Path[len(setting.Attachment.Minio.Bucket)+1:] | |||
fileinfos, _ := storage.GetOneLevelAllObjectUnderDirMinio(setting.Attachment.Minio.Bucket, prefix, parentDir) | |||
prefix := model.Path[len(setting.Attachment.Minio.Bucket)+1:] + parentDir | |||
fileinfos, _ = storage.GetOneLevelAllObjectUnderDirMinio(setting.Attachment.Minio.Bucket, prefix, "") | |||
} | |||
if fileinfos == nil { | |||
fileinfos = make([]storage.FileInfo, 0) | |||
} | |||
ctx.JSON(http.StatusOK, fileinfos) | |||
} | |||
return fileinfos | |||
} | |||
func CreateLocalModel(ctx *context.Context) { | |||
@@ -1392,3 +1434,60 @@ func CreateOnlineModel(ctx *context.Context) { | |||
ctx.HTML(200, tplCreateOnlineModelInfo) | |||
} | |||
func QueryModelCollectNum(ctx *context.Context) { | |||
id := ctx.Query("id") | |||
record := models.QueryModelCollectNum(id) | |||
ctx.JSON(200, record) | |||
} | |||
func ModelCollect(ctx *context.Context) { | |||
id := ctx.Query("id") | |||
isCollected := ctx.QueryBool("collected") | |||
re := map[string]string{ | |||
"code": "-1", | |||
} | |||
task, err := models.QueryModelById(id) | |||
if err != nil || task == nil { | |||
re["msg"] = err.Error() | |||
log.Error("no such model!", err.Error()) | |||
ctx.JSON(200, re) | |||
return | |||
} | |||
if ctx.User == nil { | |||
re["msg"] = "user not login." | |||
re["code"] = "401" | |||
ctx.JSON(200, re) | |||
return | |||
} | |||
record := models.QueryModelCollectByUserId(id, ctx.User.ID) | |||
if isCollected { | |||
if record == nil || len(record) == 0 { | |||
log.Info("user collect the model.user id=" + fmt.Sprint(ctx.User.ID) + " model id=" + id) | |||
err := models.SaveModelCollect(&models.AiModelCollect{ | |||
ModelID: id, | |||
UserId: ctx.User.ID, | |||
}) | |||
if err == nil { | |||
re["code"] = "0" | |||
} else { | |||
re["msg"] = err.Error() | |||
} | |||
} | |||
} else { | |||
if record != nil && len(record) > 0 { | |||
log.Info("user delete collect the model.user id=" + fmt.Sprint(ctx.User.ID) + " model id=" + id) | |||
err := models.DeleteModelCollect(&models.AiModelCollect{ | |||
ID: record[0].ID, | |||
}) | |||
if err == nil { | |||
re["code"] = "0" | |||
} else { | |||
re["msg"] = err.Error() | |||
} | |||
} | |||
} | |||
num := models.QueryModelCollectNum(id) | |||
models.ModifyModelCollectedNum(id, num) | |||
ctx.JSON(200, re) | |||
} |
@@ -0,0 +1,515 @@ | |||
package repo | |||
import ( | |||
"encoding/json" | |||
"fmt" | |||
"io/ioutil" | |||
"net/http" | |||
"strconv" | |||
"strings" | |||
"code.gitea.io/gitea/models" | |||
"code.gitea.io/gitea/modules/context" | |||
"code.gitea.io/gitea/modules/log" | |||
"code.gitea.io/gitea/modules/markup/markdown" | |||
"code.gitea.io/gitea/modules/setting" | |||
"code.gitea.io/gitea/modules/storage" | |||
"code.gitea.io/gitea/services/cloudbrain/modelmanage" | |||
"code.gitea.io/gitea/services/repository" | |||
) | |||
const ( | |||
tplModelSquareIndex = "model/square/index" | |||
tplModelSquareReadMe = "repo/modelmanage/readme" | |||
tplModelFileList = "repo/modelmanage/filelist" | |||
tplModelSetting = "repo/modelmanage/setting" | |||
tplModelEvolutionMap = "repo/modelmanage/evolution_map" | |||
README_FILE_NAME = "README.md" | |||
) | |||
type ModelMap struct { | |||
Type int //0:repo; 1:model | |||
IsParent bool | |||
IsCurrent bool | |||
RepoName string | |||
RepoOwnerName string | |||
RepoDisplayName string | |||
RepoId int64 | |||
Model *models.AiModelManage | |||
Next []*ModelMap | |||
} | |||
func ModelSquareTmpl(ctx *context.Context) { | |||
ctx.HTML(200, tplModelSquareIndex) | |||
} | |||
func ModelSquareData(ctx *context.Context) { | |||
log.Info("ShowModel Square Info start.") | |||
page := ctx.QueryInt("page") | |||
if page <= 0 { | |||
page = 1 | |||
} | |||
pageSize := ctx.QueryInt("pageSize") | |||
if pageSize <= 0 { | |||
pageSize = setting.UI.IssuePagingNum | |||
} | |||
isRecommend := ctx.QueryBool("recommend") | |||
queryType := ctx.QueryInt("queryType") | |||
labelFilter := ctx.Query("label") | |||
frameFilterStr := ctx.Query("frame") | |||
orderBy := ctx.Query("orderBy") | |||
Namelike := ctx.Query("q") | |||
TypeStr := ctx.Query("type") | |||
needModelFile := ctx.QueryBool("needModelFile") | |||
frameFilterInt := -1 | |||
if frameFilterStr != "" { | |||
frameFilterInt, _ = strconv.Atoi(frameFilterStr) | |||
} | |||
notNeedEmpty := ctx.QueryBool("notNeedEmpty") | |||
computeResourceFilter := ctx.Query("compute_resource") | |||
var IsQueryPrivate bool | |||
var user_id int64 | |||
var IsQueryCollect bool | |||
var collected_user_id int64 | |||
var repo_id int64 | |||
var typeInt int | |||
typeInt = -1 | |||
if TypeStr != "" { | |||
//typeInt, _ = strconv.Atoi(TypeStr) | |||
} | |||
if queryType == 1 { | |||
IsQueryPrivate = false | |||
user_id = 0 | |||
} else if queryType == 2 { | |||
IsQueryPrivate = true | |||
if ctx.User == nil { | |||
log.Info("the user not login.") | |||
ctx.JSON(http.StatusOK, nil) | |||
return | |||
} | |||
user_id = ctx.User.ID | |||
} else if queryType == 3 { | |||
IsQueryCollect = true | |||
IsQueryPrivate = true | |||
user_id = 0 | |||
if ctx.User == nil { | |||
log.Info("the user not login.") | |||
ctx.JSON(http.StatusOK, nil) | |||
return | |||
} | |||
collected_user_id = ctx.User.ID | |||
} else if queryType == 4 { | |||
if ctx.User == nil { | |||
log.Info("the user not login.") | |||
ctx.JSON(http.StatusOK, nil) | |||
return | |||
} | |||
IsQueryPrivate = true | |||
repoName := ctx.Query("repoName") | |||
repoOwnerName := ctx.Query("repoOwnerName") | |||
repo, err := models.GetRepositoryByOwnerAndName(repoOwnerName, repoName) | |||
if err == nil { | |||
repo_id = repo.ID | |||
} else { | |||
log.Info("the repo is not exist.repoName=" + repoName + " repoOwnerName=" + repoOwnerName) | |||
ctx.JSON(http.StatusOK, nil) | |||
return | |||
} | |||
} else { | |||
log.Info("not support") | |||
ctx.JSON(http.StatusOK, nil) | |||
return | |||
} | |||
SortType := "ai_model_manage.recommend desc,ai_model_manage.collected_count desc,ai_model_manage.download_count desc,ai_model_manage.reference_count desc" | |||
if orderBy != "" { | |||
SortType = "ai_model_manage." + orderBy + " DESC" | |||
} | |||
modelResult, count, err := models.QueryModel(&models.AiModelQueryOptions{ | |||
ListOptions: models.ListOptions{ | |||
Page: page, | |||
PageSize: pageSize, | |||
}, | |||
Type: typeInt, | |||
New: -1, | |||
Status: -1, | |||
IsQueryPrivate: IsQueryPrivate, | |||
IsRecommend: isRecommend, | |||
UserID: user_id, | |||
IsCollected: IsQueryCollect, | |||
CollectedUserId: collected_user_id, | |||
LabelFilter: labelFilter, | |||
FrameFilter: frameFilterInt, | |||
ComputeResourceFilter: computeResourceFilter, | |||
Namelike: Namelike, | |||
SortType: SortType, | |||
RepoID: repo_id, | |||
NotNeedEmpty: notNeedEmpty, | |||
}) | |||
if err != nil { | |||
ctx.ServerError("Cloudbrain", err) | |||
return | |||
} | |||
userIds := make([]int64, len(modelResult)) | |||
modelIds := make([]string, len(modelResult)) | |||
repoIds := make([]int64, len(modelResult)) | |||
for i, model := range modelResult { | |||
userIds[i] = model.UserId | |||
modelIds[i] = model.ID | |||
repoIds[i] = model.RepoId | |||
} | |||
repoInfo, err := queryRepoInfoByIds(repoIds) | |||
userNameMap := queryUserName(userIds) | |||
var modelCollect map[string]*models.AiModelCollect | |||
if ctx.User != nil && queryType != 4 { | |||
modelCollect = models.QueryModelCollectedStatus(modelIds, ctx.User.ID) | |||
} | |||
for _, model := range modelResult { | |||
//removeIpInfo(model) | |||
model.TrainTaskInfo = "" | |||
value := userNameMap[model.UserId] | |||
if value != nil { | |||
model.UserName = value.Name | |||
model.UserRelAvatarLink = value.RelAvatarLink() | |||
} | |||
if repoInfo != nil { | |||
repo := repoInfo[model.RepoId] | |||
if repo != nil { | |||
model.RepoName = repo.Name | |||
model.RepoOwnerName = repo.OwnerName | |||
model.RepoDisplayName = repo.DisplayName() | |||
} | |||
} | |||
if ctx.User != nil && modelCollect != nil { | |||
value := modelCollect[model.ID] | |||
if value != nil { | |||
model.IsCollected = true | |||
} | |||
} else { | |||
model.IsCollected = false | |||
} | |||
if needModelFile && len(model.Path) > 0 { | |||
//查询模型文件列表 | |||
model.ModelFileList = modelmanage.QueryModelFileByModel(model) | |||
} | |||
} | |||
mapInterface := make(map[string]interface{}) | |||
mapInterface["data"] = modelResult | |||
mapInterface["count"] = count | |||
ctx.JSON(http.StatusOK, mapInterface) | |||
} | |||
func queryRepoInfoByIds(intSlice []int64) (map[int64]*models.Repository, error) { | |||
keys := make(map[int64]string) | |||
uniqueElements := []int64{} | |||
for _, entry := range intSlice { | |||
if _, value := keys[entry]; !value { | |||
keys[entry] = "" | |||
uniqueElements = append(uniqueElements, entry) | |||
} | |||
} | |||
re, err := models.GetRepositoriesMapByIDs(uniqueElements) | |||
return re, err | |||
} | |||
func ModelReadMeTmpl(ctx *context.Context) { | |||
ctx.HTML(200, tplModelSquareReadMe) | |||
} | |||
func ModelFileListTmpl(ctx *context.Context) { | |||
ctx.HTML(200, tplModelFileList) | |||
} | |||
func ModelFileSettingTmpl(ctx *context.Context) { | |||
ctx.HTML(200, tplModelSetting) | |||
} | |||
func ModelEvolutionMapTmpl(ctx *context.Context) { | |||
ctx.HTML(200, tplModelEvolutionMap) | |||
} | |||
func setModelUser(model *models.AiModelManage) { | |||
user, err := models.GetUserByID(model.UserId) | |||
if err == nil { | |||
model.UserName = user.Name | |||
model.UserRelAvatarLink = user.RelAvatarLink() | |||
} | |||
} | |||
func setModelRepo(model *models.AiModelManage) { | |||
repo, err := models.GetRepositoryByID(model.RepoId) | |||
if err == nil { | |||
model.RepoName = repo.Name | |||
model.RepoOwnerName = repo.OwnerName | |||
model.RepoDisplayName = repo.DisplayName() | |||
} | |||
} | |||
func ModelEvolutionMapData(ctx *context.Context) { | |||
id := ctx.Query("id") | |||
model, err := models.QueryModelById(id) | |||
re := map[string]interface{}{ | |||
"code": "-1", | |||
} | |||
if err == nil { | |||
removeIpInfo(model) | |||
repo, err := models.GetRepositoryByID(model.RepoId) | |||
model.RepoName = repo.Name | |||
model.RepoOwnerName = repo.OwnerName | |||
model.RepoDisplayName = repo.DisplayName() | |||
if err == nil { | |||
setModelUser(model) | |||
currentNode := &ModelMap{ | |||
Type: 1, | |||
IsCurrent: true, | |||
RepoName: repo.Name, | |||
RepoOwnerName: repo.OwnerName, | |||
RepoDisplayName: repo.DisplayName(), | |||
RepoId: repo.ID, | |||
Model: model, | |||
} | |||
ParentNode := findParent(model) | |||
if ParentNode != nil { | |||
nexts := make([]*ModelMap, 0) | |||
nexts = append(nexts, currentNode) | |||
ParentNode.Next = nexts | |||
} else { | |||
ParentNode = currentNode | |||
} | |||
findChild(currentNode) | |||
re["code"] = "0" | |||
re["node"] = ParentNode | |||
ctx.JSON(200, ParentNode) | |||
} | |||
} else { | |||
re["msg"] = "No such model." | |||
ctx.JSON(200, re) | |||
} | |||
} | |||
func findParent(model *models.AiModelManage) *ModelMap { | |||
if model.TrainTaskInfo != "" { | |||
var task models.Cloudbrain | |||
err := json.Unmarshal([]byte(model.TrainTaskInfo), &task) | |||
if err != nil { | |||
log.Info("error=" + err.Error()) | |||
} else { | |||
log.Info("find parent model name." + task.ModelName) | |||
if task.ModelName != "" { | |||
if task.ModelId != "" { | |||
parentModel, err := models.QueryModelById(task.ModelId) | |||
setModelRepo(parentModel) | |||
setModelUser(parentModel) | |||
if err == nil { | |||
re := &ModelMap{ | |||
Type: 1, | |||
IsParent: true, | |||
Model: parentModel, | |||
} | |||
return re | |||
} | |||
} else { | |||
modelList := models.QueryModelByName(task.ModelName, task.RepoID) | |||
if modelList != nil && len(modelList) > 0 { | |||
for _, parentModel := range modelList { | |||
setModelUser(parentModel) | |||
setModelRepo(parentModel) | |||
if parentModel.Version == task.ModelVersion { | |||
re := &ModelMap{ | |||
Type: 1, | |||
IsParent: true, | |||
Model: parentModel, | |||
} | |||
return re | |||
} | |||
} | |||
} | |||
} | |||
} | |||
} | |||
} | |||
return nil | |||
} | |||
func findChild(currentNode *ModelMap) { | |||
log.Info("find child start.") | |||
if currentNode.Model != nil { | |||
currentModel := currentNode.Model | |||
re, err := models.GetCloudBrainByModelId(currentModel.ID) | |||
if err != nil || len(re) == 0 { | |||
re, err = models.GetCloudBrainByRepoIdAndModelName(currentModel.RepoId, currentModel.Name) | |||
} | |||
log.Info("start to load child model.") | |||
if err == nil && len(re) > 0 { | |||
repoNodes := getRepoNodes(re) | |||
currentNode.Next = repoNodes | |||
for _, node := range repoNodes { | |||
childModels := models.QueryModelByRepoId(node.RepoId) | |||
childNodes := make([]*ModelMap, 0) | |||
if childModels != nil && len(childModels) > 0 { | |||
for _, childModel := range childModels { | |||
if childModel.TrainTaskInfo != "" { | |||
childModel.RepoName = node.RepoName | |||
childModel.RepoOwnerName = node.RepoOwnerName | |||
childModel.RepoDisplayName = node.RepoDisplayName | |||
log.Info("childModel.RepoName=" + childModel.RepoName) | |||
log.Info("childModel.RepoOwnerName=" + childModel.RepoOwnerName) | |||
var task models.Cloudbrain | |||
err := json.Unmarshal([]byte(childModel.TrainTaskInfo), &task) | |||
if err != nil { | |||
log.Info("error=" + err.Error()) | |||
} else { | |||
log.Info("task.ModelId=%v,currentModel.ID=%v", task.ModelId, currentModel.ID) | |||
if task.ModelId != "" && task.ModelId == currentModel.ID { | |||
setModelUser(childModel) | |||
modelMap := &ModelMap{ | |||
Type: 1, | |||
Model: childModel, | |||
} | |||
childNodes = append(childNodes, modelMap) | |||
} else { | |||
log.Info("task.ModelName=%v,currentModel.Name=%v", task.ModelName, currentModel.Name) | |||
log.Info("task.ModelVersion=%v,currentModel.Version=%v", task.ModelVersion, currentModel.Version) | |||
if task.ModelName == currentModel.Name && task.ModelVersion == currentModel.Version { | |||
setModelUser(childModel) | |||
modelMap := &ModelMap{ | |||
Type: 1, | |||
Model: childModel, | |||
} | |||
childNodes = append(childNodes, modelMap) | |||
} | |||
} | |||
} | |||
} | |||
} | |||
} | |||
node.Next = childNodes | |||
for _, child := range childNodes { | |||
findChild(child) | |||
} | |||
} | |||
} | |||
} else { | |||
log.Info("the current model is nil.") | |||
} | |||
} | |||
func getRepoNodes(re []*models.Cloudbrain) []*ModelMap { | |||
result := make([]*ModelMap, 0) | |||
repoMap := make(map[int64]string, 0) | |||
for _, task := range re { | |||
repo, err := models.GetRepositoryByID(task.RepoID) | |||
if err == nil { | |||
if _, ok := repoMap[repo.ID]; !ok { | |||
modelMap := &ModelMap{ | |||
Type: 0, | |||
RepoName: repo.Name, | |||
RepoOwnerName: repo.OwnerName, | |||
RepoDisplayName: repo.DisplayName(), | |||
RepoId: repo.ID, | |||
} | |||
result = append(result, modelMap) | |||
} | |||
repoMap[repo.ID] = "true" | |||
} | |||
} | |||
return result | |||
} | |||
func ModifyModelReadMe(ctx *context.Context) { | |||
id := ctx.Query("id") | |||
model, err := models.QueryModelById(id) | |||
re := map[string]string{ | |||
"code": "-1", | |||
} | |||
if err == nil { | |||
content := ctx.Query("content") | |||
path := Model_prefix + models.AttachmentRelativePath(id) + "/" | |||
if model.Type == models.TypeCloudBrainTwo { | |||
err = storage.PutStringToObs(setting.Bucket, path+README_FILE_NAME, content) | |||
if err != nil { | |||
re["msg"] = "Failed to created readme file." | |||
log.Info("Failed to created readme file. as:" + err.Error()) | |||
} else { | |||
re["code"] = "0" | |||
} | |||
} else { | |||
re["msg"] = "Cannot support the model type=" + fmt.Sprint(model.Type) | |||
} | |||
ctx.JSON(200, re) | |||
} else { | |||
re["msg"] = "No such model." | |||
ctx.JSON(200, re) | |||
} | |||
} | |||
func QueryModelReadMe(ctx *context.Context) { | |||
id := ctx.Query("id") | |||
model, err := models.QueryModelById(id) | |||
re := map[string]string{ | |||
"code": "-1", | |||
} | |||
if err == nil { | |||
files := queryOneLevelModelFile(model, "") | |||
find := false | |||
var content []byte | |||
for _, file := range files { | |||
if strings.ToLower(file.FileName) == strings.ToLower(README_FILE_NAME) { | |||
find = true | |||
path := Model_prefix + models.AttachmentRelativePath(id) + "/" | |||
body, err := storage.ObsDownloadAFile(setting.Bucket, path+file.FileName) | |||
if err != nil { | |||
log.Info("download file failed: %s\n", err.Error()) | |||
break | |||
} else { | |||
defer body.Close() | |||
content, err = ioutil.ReadAll(body) | |||
} | |||
} | |||
} | |||
if find { | |||
re["isExistMDFile"] = "true" | |||
re["fileName"] = README_FILE_NAME | |||
strc := string(content) | |||
re["content"] = strc | |||
re["htmlcontent"] = string(markdown.RenderRaw([]byte(strc), "", false)) | |||
} else { | |||
re["isExistMDFile"] = "false" | |||
re["fileName"] = README_FILE_NAME | |||
url := setting.RecommentRepoAddr + "model/" + README_FILE_NAME | |||
result, err := repository.RecommendContentFromPromote(url) | |||
if err == nil { | |||
re["content"] = result | |||
re["htmlcontent"] = string(markdown.RenderRaw([]byte(result), "", false)) | |||
} | |||
} | |||
re["code"] = "0" | |||
ctx.JSON(200, re) | |||
} else { | |||
re["msg"] = "No such model." | |||
ctx.JSON(200, re) | |||
} | |||
} | |||
func QueryModelLabel(ctx *context.Context) { | |||
url := setting.RecommentRepoAddr + "model/label.json" | |||
result, err := repository.RecommendContentFromPromote(url) | |||
log.Info("label result=" + result) | |||
remap := make([]map[string]string, 0) | |||
if err == nil { | |||
err = json.Unmarshal([]byte(result), &remap) | |||
if err != nil { | |||
log.Info("error=" + err.Error()) | |||
} | |||
} else { | |||
log.Info("error=" + err.Error()) | |||
} | |||
if err == nil { | |||
ctx.JSON(200, remap) | |||
} else { | |||
ctx.JSON(200, "") | |||
} | |||
} |
@@ -669,7 +669,7 @@ func createForNPU(ctx *context.Context, jobName string) error { | |||
log.Info("engine_id=" + fmt.Sprint(engineID)) | |||
poolID := ctx.Query("pool_id") | |||
repo := ctx.Repo.Repository | |||
modelId := ctx.Query("model_id") | |||
trainUrl := ctx.Query("pre_train_model_url") | |||
modelName := ctx.Query("model_name") | |||
modelVersion := ctx.Query("model_version") | |||
@@ -814,6 +814,7 @@ func createForNPU(ctx *context.Context, jobName string) error { | |||
ModelName: modelName, | |||
ModelVersion: modelVersion, | |||
CkptName: ckptName, | |||
ModelId: modelId, | |||
ResultUrl: resultObsPath, | |||
Spec: spec, | |||
DatasetName: datasetNames, | |||
@@ -839,13 +840,14 @@ func createForGPU(ctx *context.Context, jobName string) error { | |||
evaluationIndex := ctx.Query("evaluation_index") | |||
Params := ctx.Query("run_para_list") | |||
specId := ctx.QueryInt64("spec_id") | |||
TrainUrl := ctx.Query("pre_train_model_url") | |||
//TrainUrl := ctx.Query("pre_train_model_url") | |||
CkptName := ctx.Query("ckpt_name") | |||
modelName := ctx.Query("model_name") | |||
modelId := ctx.Query("model_id") | |||
modelVersion := ctx.Query("model_version") | |||
ckptUrl := setting.Attachment.Minio.RealPath + TrainUrl + CkptName | |||
log.Info("ckpt url:" + ckptUrl) | |||
//ckptUrl := setting.Attachment.Minio.RealPath + TrainUrl + CkptName | |||
//log.Info("ckpt url:" + ckptUrl) | |||
spec, err := resource.GetAndCheckSpec(ctx.User.ID, specId, models.FindSpecsOptions{ | |||
JobType: models.JobTypeBenchmark, | |||
ComputeResource: models.GPU, | |||
@@ -891,7 +893,11 @@ func createForGPU(ctx *context.Context, jobName string) error { | |||
return errors.New(ctx.Tr("cloudbrain.error.dataset_select")) | |||
} | |||
log.Info("Command=" + command) | |||
minioPreModelURL, err := dealModelInfo(modelId, jobName, CkptName) | |||
if err != nil { | |||
log.Error("Can not find model", err) | |||
return errors.New(ctx.Tr("repo.modelconvert.manage.model_not_exist")) | |||
} | |||
req := cloudbrain.GenerateCloudBrainTaskReq{ | |||
Ctx: ctx, | |||
DisplayJobName: displayJobName, | |||
@@ -902,7 +908,7 @@ func createForGPU(ctx *context.Context, jobName string) error { | |||
DatasetNames: datasetNames, | |||
DatasetInfos: datasetInfos, | |||
CodePath: storage.GetMinioPath(jobName, cloudbrain.CodeMountPath+"/"), | |||
ModelPath: setting.Attachment.Minio.RealPath + TrainUrl, | |||
ModelPath: setting.Attachment.Minio.RealPath + minioPreModelURL, | |||
BenchmarkPath: storage.GetMinioPath(jobName, cloudbrain.BenchMarkMountPath+"/"), | |||
Snn4ImageNetPath: storage.GetMinioPath(jobName, cloudbrain.Snn4imagenetMountPath+"/"), | |||
BrainScorePath: storage.GetMinioPath(jobName, cloudbrain.BrainScoreMountPath+"/"), | |||
@@ -915,6 +921,7 @@ func createForGPU(ctx *context.Context, jobName string) error { | |||
ModelName: modelName, | |||
ModelVersion: modelVersion, | |||
CkptName: CkptName, | |||
ModelId: modelId, | |||
ResultPath: storage.GetMinioPath(jobName, cloudbrain.ResultPath+"/"), | |||
Spec: spec, | |||
LabelName: evaluationIndex, | |||
@@ -314,7 +314,7 @@ func CompleteModelMultipart(ctx *context.Context) { | |||
return | |||
} | |||
//更新模型大小信息 | |||
UpdateModelSize(modeluuid) | |||
UpdateModelSize(modeluuid, fileChunk.ObjectName) | |||
ctx.JSON(200, map[string]string{ | |||
"result_code": "0", | |||
@@ -15,8 +15,6 @@ import ( | |||
"time" | |||
"unicode/utf8" | |||
"code.gitea.io/gitea/services/cloudbrain/modelmanage" | |||
"code.gitea.io/gitea/services/lock" | |||
cloudbrainService "code.gitea.io/gitea/services/cloudbrain" | |||
@@ -152,6 +150,7 @@ func cloudBrainNewDataPrepare(ctx *context.Context, jobType string) error { | |||
ctx.Data["model_name"] = ctx.Cloudbrain.ModelName | |||
ctx.Data["label_name"] = ctx.Cloudbrain.LabelName | |||
ctx.Data["ckpt_name"] = ctx.Cloudbrain.CkptName | |||
ctx.Data["model_id"] = ctx.Cloudbrain.ModelId | |||
ctx.Data["model_version"] = ctx.Cloudbrain.ModelVersion | |||
ctx.Data["pre_train_model_url"] = ctx.Cloudbrain.PreTrainModelUrl | |||
ctx.Data["compute_resource"] = ctx.Cloudbrain.ComputeResource | |||
@@ -390,19 +389,21 @@ func cloudBrainCreate(ctx *context.Context, form auth.CreateCloudBrainForm) { | |||
} | |||
if form.ModelName != "" { //使用预训练模型训练 | |||
_, err := models.QueryModelByPath(form.PreTrainModelUrl) | |||
req.ModelName = form.ModelName | |||
req.LabelName = form.LabelName | |||
req.CkptName = form.CkptName | |||
req.ModelId = form.ModelId | |||
req.ModelVersion = form.ModelVersion | |||
minioPreModelURL, err := dealModelInfo(form.ModelId, jobName, form.CkptName) | |||
if err != nil { | |||
log.Error("Can not find model", err) | |||
cloudBrainNewDataPrepare(ctx, jobType) | |||
ctx.RenderWithErr(ctx.Tr("repo.modelconvert.manage.model_not_exist"), tpl, &form) | |||
return | |||
} | |||
req.ModelName = form.ModelName | |||
req.LabelName = form.LabelName | |||
req.CkptName = form.CkptName | |||
req.ModelVersion = form.ModelVersion | |||
req.PreTrainModelPath = setting.Attachment.Minio.RealPath + form.PreTrainModelUrl | |||
req.PreTrainModelUrl = form.PreTrainModelUrl | |||
req.PreTrainModelPath = setting.Attachment.Minio.RealPath + minioPreModelURL | |||
req.PreTrainModelUrl = minioPreModelURL | |||
} | |||
if form.IsContinue { // qizhi GPU 继续训练,将旧任务输出文件拷贝至新任务输出路径 | |||
@@ -430,6 +431,43 @@ func cloudBrainCreate(ctx *context.Context, form auth.CreateCloudBrainForm) { | |||
} | |||
} | |||
func dealModelInfo(modelId string, jobName string, ckptName string) (string, error) { | |||
preModel, err := models.QueryModelById(modelId) | |||
if err != nil { | |||
log.Error("Can not find model", err) | |||
return "", err | |||
} | |||
minioPreModelURL, err := downloadModelFromObs(preModel, jobName, cloudbrain.PretrainModelMountPath, ckptName) | |||
if err != nil { | |||
log.Error("Can not find model", err) | |||
return "", err | |||
} | |||
return minioPreModelURL, nil | |||
} | |||
func downloadModelFromObs(preModel *models.AiModelManage, jobName, suffixPath string, ckptFileName string) (string, error) { | |||
destPath := setting.CBCodePathPrefix + jobName + suffixPath + "/" | |||
destFile := destPath + ckptFileName | |||
returnStr := setting.Attachment.Minio.Bucket + "/" + destPath | |||
srcUrl := preModel.Path[len(setting.Bucket)+1:] + ckptFileName | |||
log.Info("dest model Path=" + returnStr + " src path=" + preModel.Path + ckptFileName) | |||
body, err := storage.ObsDownloadAFile(setting.Bucket, srcUrl) | |||
if err == nil { | |||
defer body.Close() | |||
_, err = storage.Attachments.UploadContent(setting.Attachment.Minio.Bucket, destFile, body) | |||
if err != nil { | |||
log.Error("UploadObject(%s) failed: %s", preModel.Path+ckptFileName, err.Error()) | |||
return "", err | |||
} | |||
} else { | |||
log.Info("download model failed. as " + err.Error()) | |||
return "", err | |||
} | |||
log.Info("download model from obs succeed") | |||
return returnStr, nil | |||
} | |||
func MinioCopyResults(srcPath string, destPath string) error { | |||
log.Info("prev task obs path:", setting.Attachment.Minio.Bucket+srcPath) | |||
log.Info("current task obs path:", setting.Attachment.Minio.Bucket+destPath) | |||
@@ -531,8 +569,8 @@ func CloudBrainInferenceJobCreate(ctx *context.Context, form auth.CreateCloudBra | |||
return | |||
} | |||
ckptUrl := setting.Attachment.Minio.RealPath + form.TrainUrl + form.CkptName | |||
log.Info("ckpt url:" + ckptUrl) | |||
//ckptUrl := setting.Attachment.Minio.RealPath + form.TrainUrl + form.CkptName | |||
//log.Info("ckpt url:" + ckptUrl) | |||
command, err := getInferenceJobCommand(form) | |||
if err != nil { | |||
log.Error("getTrainJobCommand failed: %v", err) | |||
@@ -607,6 +645,14 @@ func CloudBrainInferenceJobCreate(ctx *context.Context, form auth.CreateCloudBra | |||
return | |||
} | |||
minioPreModelURL, err := dealModelInfo(form.ModelId, jobName, form.CkptName) | |||
if err != nil { | |||
log.Error("Can not find model", err) | |||
cloudBrainNewDataPrepare(ctx, jobType) | |||
ctx.RenderWithErr(ctx.Tr("repo.modelconvert.manage.model_not_exist"), tpl, &form) | |||
return | |||
} | |||
req := cloudbrain.GenerateCloudBrainTaskReq{ | |||
Ctx: ctx, | |||
DisplayJobName: displayJobName, | |||
@@ -617,7 +663,7 @@ func CloudBrainInferenceJobCreate(ctx *context.Context, form auth.CreateCloudBra | |||
DatasetNames: datasetNames, | |||
DatasetInfos: datasetInfos, | |||
CodePath: storage.GetMinioPath(jobName, cloudbrain.CodeMountPath+"/"), | |||
ModelPath: setting.Attachment.Minio.RealPath + form.TrainUrl, | |||
ModelPath: setting.Attachment.Minio.RealPath + minioPreModelURL, | |||
BenchmarkPath: storage.GetMinioPath(jobName, cloudbrain.BenchMarkMountPath+"/"), | |||
Snn4ImageNetPath: storage.GetMinioPath(jobName, cloudbrain.Snn4imagenetMountPath+"/"), | |||
BrainScorePath: storage.GetMinioPath(jobName, cloudbrain.BrainScoreMountPath+"/"), | |||
@@ -631,7 +677,8 @@ func CloudBrainInferenceJobCreate(ctx *context.Context, form auth.CreateCloudBra | |||
ModelName: form.ModelName, | |||
ModelVersion: form.ModelVersion, | |||
CkptName: form.CkptName, | |||
TrainUrl: form.TrainUrl, | |||
ModelId: form.ModelId, | |||
TrainUrl: form.PreTrainModelUrl, | |||
LabelName: labelName, | |||
Spec: spec, | |||
} | |||
@@ -740,11 +787,11 @@ func CloudBrainRestart(ctx *context.Context) { | |||
break | |||
} | |||
} | |||
if !modelmanage.HasModelFile(task) { | |||
resultCode = "-1" | |||
errorMsg = ctx.Tr("repo.debug.manage.model_not_exist") | |||
break | |||
} | |||
// if !modelmanage.HasModelFile(task) { | |||
// resultCode = "-1" | |||
// errorMsg = ctx.Tr("repo.debug.manage.model_not_exist") | |||
// break | |||
// } | |||
if hasDatasetDeleted(task) { | |||
resultCode = "-1" | |||
@@ -2734,8 +2781,18 @@ func ModelBenchmarkCreate(ctx *context.Context, form auth.CreateCloudBrainForm) | |||
req.LabelName = form.LabelName | |||
req.CkptName = form.CkptName | |||
req.ModelVersion = form.ModelVersion | |||
req.PreTrainModelPath = setting.Attachment.Minio.RealPath + form.PreTrainModelUrl | |||
req.PreTrainModelUrl = form.PreTrainModelUrl | |||
req.ModelId = form.ModelId | |||
minioPreModelURL, err := dealModelInfo(form.ModelId, jobName, form.CkptName) | |||
if err != nil { | |||
log.Error("Can not find model", err) | |||
cloudBrainNewDataPrepare(ctx, jobType) | |||
ctx.RenderWithErr(ctx.Tr("repo.modelconvert.manage.model_not_exist"), tpl, &form) | |||
return | |||
} | |||
req.PreTrainModelPath = setting.Attachment.Minio.RealPath + minioPreModelURL | |||
req.PreTrainModelUrl = minioPreModelURL | |||
} | |||
_, err = cloudbrain.GenerateTask(req) | |||
@@ -303,7 +303,7 @@ func GrampusNotebookCreate(ctx *context.Context, form auth.CreateGrampusNotebook | |||
if form.ModelName != "" { //使用预训练模型训练 | |||
m, err := models.QueryModelByPath(form.PreTrainModelUrl) | |||
m, err := models.QueryModelById(form.ModelId) | |||
if err != nil { | |||
log.Error("Can not find model", err) | |||
grampusNotebookNewDataPrepare(ctx, processType) | |||
@@ -319,7 +319,9 @@ func GrampusNotebookCreate(ctx *context.Context, form auth.CreateGrampusNotebook | |||
req.ModelName = form.ModelName | |||
req.LabelName = form.LabelName | |||
req.CkptName = form.CkptName | |||
req.ModelId = form.ModelId | |||
req.ModelVersion = form.ModelVersion | |||
req.PreTrainModelUrl = form.PreTrainModelUrl | |||
req.PreTrainModelPath = getPreTrainModelPath(form.PreTrainModelUrl, form.CkptName) | |||
req.ModelStorageType = m.Type | |||
@@ -464,6 +466,7 @@ func grampusTrainJobNewDataPrepare(ctx *context.Context, processType string) err | |||
ctx.Data["model_version"] = ctx.Cloudbrain.ModelVersion | |||
ctx.Data["ckpt_name"] = ctx.Cloudbrain.CkptName | |||
ctx.Data["model_id"] = ctx.Cloudbrain.ModelId | |||
ctx.Data["label_names"] = ctx.Cloudbrain.LabelName | |||
ctx.Data["pre_train_model_url"] = ctx.Cloudbrain.PreTrainModelUrl | |||
spec, _ := resource.GetCloudbrainSpec(ctx.Cloudbrain.ID) | |||
@@ -751,9 +754,9 @@ func grampusTrainJobGpuCreate(ctx *context.Context, form auth.CreateGrampusTrain | |||
req.ModelName = form.ModelName | |||
req.LabelName = form.LabelName | |||
req.CkptName = form.CkptName | |||
req.ModelId = form.ModelId | |||
req.ModelVersion = form.ModelVersion | |||
req.PreTrainModelUrl = form.PreTrainModelUrl | |||
} | |||
_, err = grampus.GenerateTrainJob(ctx, req) | |||
@@ -980,7 +983,7 @@ func grampusTrainJobGcuCreate(ctx *context.Context, form auth.CreateGrampusTrain | |||
req.CkptName = form.CkptName | |||
req.ModelVersion = form.ModelVersion | |||
req.PreTrainModelUrl = form.PreTrainModelUrl | |||
req.ModelId = form.ModelId | |||
} | |||
_, err = grampus.GenerateTrainJob(ctx, req) | |||
@@ -1241,6 +1244,7 @@ func grampusTrainJobNpuCreate(ctx *context.Context, form auth.CreateGrampusTrain | |||
req.ModelName = form.ModelName | |||
req.LabelName = form.LabelName | |||
req.CkptName = form.CkptName | |||
req.ModelId = form.ModelId | |||
req.ModelVersion = form.ModelVersion | |||
req.PreTrainModelUrl = form.PreTrainModelUrl | |||
req.PreTrainModelPath = preTrainModelPath | |||
@@ -282,6 +282,7 @@ func Notebook2Create(ctx *context.Context, form auth.CreateModelArtsNotebookForm | |||
req.ModelName = form.ModelName | |||
req.LabelName = form.LabelName | |||
req.CkptName = form.CkptName | |||
req.ModelId = form.ModelId | |||
req.ModelVersion = form.ModelVersion | |||
req.PreTrainModelUrl = form.PreTrainModelUrl | |||
@@ -630,6 +631,7 @@ func NotebookRestart(ctx *context.Context) { | |||
LabelName: task.LabelName, | |||
PreTrainModelUrl: task.PreTrainModelUrl, | |||
CkptName: task.CkptName, | |||
ModelId: task.ModelId, | |||
} | |||
err = models.RestartCloudbrain(task, newTask) | |||
@@ -1052,6 +1054,7 @@ func trainJobNewVersionDataPrepare(ctx *context.Context) error { | |||
ctx.Data["model_name"] = task.ModelName | |||
ctx.Data["model_version"] = task.ModelVersion | |||
ctx.Data["ckpt_name"] = task.CkptName | |||
ctx.Data["model_id"] = ctx.Cloudbrain.ModelId | |||
ctx.Data["label_names"] = task.LabelName | |||
ctx.Data["pre_train_model_url"] = task.PreTrainModelUrl | |||
@@ -1351,6 +1354,7 @@ func TrainJobCreate(ctx *context.Context, form auth.CreateModelArtsTrainJobForm) | |||
req.ModelName = form.ModelName | |||
req.LabelName = form.LabelName | |||
req.CkptName = form.CkptName | |||
req.ModelId = form.ModelId | |||
req.ModelVersion = form.ModelVersion | |||
req.PreTrainModelUrl = form.PreTrainModelUrl | |||
@@ -1746,6 +1750,7 @@ func TrainJobCreateVersion(ctx *context.Context, form auth.CreateModelArtsTrainJ | |||
req.ModelName = form.ModelName | |||
req.LabelName = form.LabelName | |||
req.CkptName = form.CkptName | |||
req.ModelId = form.ModelId | |||
req.ModelVersion = form.ModelVersion | |||
req.PreTrainModelUrl = form.PreTrainModelUrl | |||
@@ -2157,11 +2162,11 @@ func InferenceJobCreate(ctx *context.Context, form auth.CreateModelArtsInference | |||
LabelName := form.LabelName | |||
isLatestVersion := modelarts.IsLatestVersion | |||
VersionCount := modelarts.VersionCountOne | |||
trainUrl := form.TrainUrl | |||
trainUrl := form.PreTrainModelUrl | |||
modelName := form.ModelName | |||
modelVersion := form.ModelVersion | |||
ckptName := form.CkptName | |||
ckptUrl := "/" + form.TrainUrl + form.CkptName | |||
ckptUrl := "/" + form.PreTrainModelUrl + form.CkptName | |||
log.Info("ckpt url:" + ckptUrl) | |||
errStr := checkInferenceJobMultiNode(ctx.User.ID, form.WorkServerNumber) | |||
@@ -2376,6 +2381,7 @@ func InferenceJobCreate(ctx *context.Context, form auth.CreateModelArtsInference | |||
ModelName: modelName, | |||
ModelVersion: modelVersion, | |||
CkptName: ckptName, | |||
ModelId: form.ModelId, | |||
ResultUrl: resultObsPath, | |||
Spec: spec, | |||
DatasetName: datasetNames, | |||
@@ -2493,6 +2499,18 @@ func InferenceJobIndex(ctx *context.Context) { | |||
if tasks[i].ComputeResource == "" { | |||
tasks[i].ComputeResource = models.NPUResource | |||
} | |||
if tasks[i].ModelId != "" { | |||
model, err := models.QueryModelById(tasks[i].ModelId) | |||
if err == nil && model != nil { | |||
if model.RepoId != tasks[i].RepoID { | |||
repo, err := models.GetRepositoryByID(model.RepoId) | |||
if err == nil && repo != nil { | |||
tasks[i].ModelRepoName = repo.Name | |||
tasks[i].ModelRepoOwnerName = repo.OwnerName | |||
} | |||
} | |||
} | |||
} | |||
} | |||
isQueryPrivate := isQueryPrivateModel(ctx) | |||
repoId := ctx.Repo.Repository.ID | |||
@@ -2671,7 +2689,8 @@ func inferenceJobErrorNewDataPrepare(ctx *context.Context, form auth.CreateModel | |||
ctx.Data["model_name"] = form.ModelName | |||
ctx.Data["model_version"] = form.ModelVersion | |||
ctx.Data["ckpt_name"] = form.CkptName | |||
ctx.Data["train_url"] = form.TrainUrl | |||
ctx.Data["model_id"] = form.ModelId | |||
ctx.Data["pre_train_model_url"] = form.PreTrainModelUrl | |||
ctx.Data["datasetType"] = models.TypeCloudBrainTwo | |||
waitCount := cloudbrain.GetWaitingCloudbrainCount(models.TypeCloudBrainTwo, "") | |||
ctx.Data["WaitCount"] = waitCount | |||
@@ -721,10 +721,10 @@ func TimingCountDataByDateAndReCount(date string, isReCount bool) { | |||
log.Info("endTime time:" + endTime.Format("2006-01-02 15:04:05")) | |||
warnEmailMessage := "用户统计信息入库失败,请尽快定位。" | |||
startYear := time.Date(USER_YEAR, 1, 1, 0, 0, 0, 1, t.Location()) | |||
endYear := startYear.AddDate(1, 0, 0) | |||
//startYear := time.Date(USER_YEAR, 1, 1, 0, 0, 0, 1, t.Location()) | |||
//endYear := startYear.AddDate(1, 0, 0) | |||
models.RefreshUserYearTable(startYear, endYear) | |||
//models.RefreshUserYearTable(startYear, endYear) | |||
//query wiki data | |||
log.Info("start to time count data") | |||
@@ -366,6 +366,13 @@ func RegisterRoutes(m *macaron.Macaron) { | |||
m.Get("/home/notice", routers.HomeNoticeTmpl) | |||
m.Get("/home/privacy", routers.HomePrivacy) | |||
m.Group("/modelsquare", func() { | |||
m.Get("/main", repo.ModelSquareTmpl) | |||
m.Get("/main_query_data", repo.ModelSquareData) | |||
m.Put("/modify_model_collect", repo.ModelCollect) | |||
m.Get("/main_query_label", repo.QueryModelLabel) | |||
}) | |||
m.Group("/extension", func() { | |||
// m.Get("", modelapp.ModelMainPage) | |||
m.Get("/tuomin/upload", modelapp.ProcessImageUI) | |||
@@ -610,6 +617,10 @@ func RegisterRoutes(m *macaron.Macaron) { | |||
m.Put("/:id/action/:action", admin.DatasetAction) | |||
// m.Post("/delete", admin.DeleteDataset) | |||
}) | |||
m.Group("/model", func() { | |||
m.Get("", admin.AdminModelManage) | |||
m.Put("/action", admin.ModifyModelRecommend) | |||
}) | |||
m.Group("/cloudbrains", func() { | |||
m.Get("", admin.CloudBrains) | |||
m.Get("/download", admin.DownloadCloudBrains) | |||
@@ -1309,20 +1320,29 @@ func RegisterRoutes(m *macaron.Macaron) { | |||
}) | |||
}, context.RepoRef()) | |||
m.Group("/modelmanage", func() { | |||
m.Get("/create_local_model_1", repo.CreateLocalModel) | |||
m.Get("/create_local_model_2", repo.CreateLocalModelForUpload) | |||
m.Get("/create_local_model", repo.CreateLocalModel) | |||
m.Get("/create_online_model", repo.CreateOnlineModel) | |||
m.Post("/create_local_model", repo.SaveLocalModel) | |||
m.Delete("/delete_model_file", repo.DeleteModelFile) | |||
m.Get("/model_readme_tmpl", repo.ModelReadMeTmpl) | |||
m.Get("/model_readme_data", repo.QueryModelReadMe) | |||
m.Post("/model_readme_data", repo.ModifyModelReadMe) | |||
m.Get("/model_filelist_tmpl", repo.ModelFileListTmpl) | |||
m.Get("/model_fileupload_tmpl", repo.CreateLocalModelForUpload) | |||
m.Get("/model_setting", repo.ModelFileSettingTmpl) | |||
m.Get("/model_evolution_map", repo.ModelEvolutionMapTmpl) | |||
m.Get("/model_evolution_map_data", repo.ModelEvolutionMapData) | |||
m.Post("/create_model", repo.SaveModel) | |||
m.Post("/create_model_convert", reqWechatBind, reqRepoModelManageWriter, repo.SaveModelConvert) | |||
m.Post("/create_new_model", repo.SaveNewNameModel) | |||
m.Delete("/delete_model", repo.DeleteModel) | |||
m.Post("/delete_model_convert/:id", repo.DeleteModelConvert) | |||
m.Post("/convert_stop/:id", repo.StopModelConvert) | |||
m.Put("/modify_model", repo.ModifyModelInfo) | |||
m.Put("/modify_model_status", repo.ModifyModelPrivate) | |||
m.Put("/modify_model", reqRepoModelManageWriter, repo.ModifyModelInfo) | |||
m.Put("/modify_model_status", reqRepoModelManageWriter, repo.ModifyModelPrivate) | |||
m.Get("/show_model_collect_num", reqRepoModelManageReader, repo.QueryModelCollectNum) | |||
m.Get("/show_model", reqRepoModelManageReader, repo.ShowModelTemplate) | |||
m.Get("/convert_model", reqRepoModelManageReader, repo.ConvertModelTemplate) | |||
m.Get("/show_model_info", repo.ShowModelInfo) | |||
@@ -2,8 +2,6 @@ package cloudbrainTask | |||
import ( | |||
"bufio" | |||
cloudbrainService "code.gitea.io/gitea/services/cloudbrain" | |||
"code.gitea.io/gitea/services/lock" | |||
"encoding/json" | |||
"errors" | |||
"io" | |||
@@ -15,6 +13,9 @@ import ( | |||
"strings" | |||
"unicode/utf8" | |||
cloudbrainService "code.gitea.io/gitea/services/cloudbrain" | |||
"code.gitea.io/gitea/services/lock" | |||
"code.gitea.io/gitea/modules/modelarts" | |||
"code.gitea.io/gitea/modules/git" | |||
@@ -147,6 +148,14 @@ func CloudBrainInferenceJobCreate(ctx *context.Context, option api.CreateTrainJo | |||
return | |||
} | |||
minioPreModelURL, err := dealModelInfo(option.ModelId, jobName, option.CkptName) | |||
if err != nil { | |||
log.Error("Can not find model", err) | |||
ctx.JSON(http.StatusOK, models.BaseErrorMessageApi(ctx.Tr("repo.modelconvert.manage.model_not_exist"))) | |||
//ctx.RenderWithErr(ctx.Tr("repo.modelconvert.manage.model_not_exist"), tpl, &form) | |||
return | |||
} | |||
req := cloudbrain.GenerateCloudBrainTaskReq{ | |||
Ctx: ctx, | |||
DisplayJobName: displayJobName, | |||
@@ -157,7 +166,7 @@ func CloudBrainInferenceJobCreate(ctx *context.Context, option api.CreateTrainJo | |||
DatasetNames: datasetNames, | |||
DatasetInfos: datasetInfos, | |||
CodePath: storage.GetMinioPath(jobName, cloudbrain.CodeMountPath+"/"), | |||
ModelPath: setting.Attachment.Minio.RealPath + option.PreTrainModelUrl, | |||
ModelPath: setting.Attachment.Minio.RealPath + minioPreModelURL, | |||
BenchmarkPath: storage.GetMinioPath(jobName, cloudbrain.BenchMarkMountPath+"/"), | |||
Snn4ImageNetPath: storage.GetMinioPath(jobName, cloudbrain.Snn4imagenetMountPath+"/"), | |||
BrainScorePath: storage.GetMinioPath(jobName, cloudbrain.BrainScoreMountPath+"/"), | |||
@@ -171,6 +180,7 @@ func CloudBrainInferenceJobCreate(ctx *context.Context, option api.CreateTrainJo | |||
ModelName: option.ModelName, | |||
ModelVersion: option.ModelVersion, | |||
CkptName: option.CkptName, | |||
ModelId: option.ModelId, | |||
TrainUrl: option.PreTrainModelUrl, | |||
LabelName: labelName, | |||
Spec: spec, | |||
@@ -185,6 +195,43 @@ func CloudBrainInferenceJobCreate(ctx *context.Context, option api.CreateTrainJo | |||
ctx.JSON(http.StatusOK, models.BaseMessageApi{Code: 0, Message: jobId}) | |||
} | |||
func dealModelInfo(modelId string, jobName string, ckptName string) (string, error) { | |||
preModel, err := models.QueryModelById(modelId) | |||
if err != nil { | |||
log.Error("Can not find model", err) | |||
return "", err | |||
} | |||
minioPreModelURL, err := downloadModelFromObs(preModel, jobName, cloudbrain.PretrainModelMountPath, ckptName) | |||
if err != nil { | |||
log.Error("Can not find model", err) | |||
return "", err | |||
} | |||
return minioPreModelURL, nil | |||
} | |||
func downloadModelFromObs(preModel *models.AiModelManage, jobName, suffixPath string, ckptFileName string) (string, error) { | |||
destPath := setting.CBCodePathPrefix + jobName + suffixPath + "/" | |||
destFile := destPath + ckptFileName | |||
returnStr := setting.Attachment.Minio.Bucket + "/" + destPath | |||
srcUrl := preModel.Path[len(setting.Bucket)+1:] + ckptFileName | |||
log.Info("dest model Path=" + returnStr + " src path=" + preModel.Path + ckptFileName) | |||
body, err := storage.ObsDownloadAFile(setting.Bucket, srcUrl) | |||
if err == nil { | |||
defer body.Close() | |||
_, err = storage.Attachments.UploadContent(setting.Attachment.Minio.Bucket, destFile, body) | |||
if err != nil { | |||
log.Error("UploadObject(%s) failed: %s", preModel.Path+ckptFileName, err.Error()) | |||
return "", err | |||
} | |||
} else { | |||
log.Info("download model failed. as " + err.Error()) | |||
return "", err | |||
} | |||
log.Info("download model from obs succeed") | |||
return returnStr, nil | |||
} | |||
func ModelArtsInferenceJobCreate(ctx *context.Context, option api.CreateTrainJobOption) { | |||
ctx.Data["PageIsTrainJob"] = true | |||
VersionOutputPath := modelarts.GetOutputPathByCount(modelarts.TotalVersionCount) | |||
@@ -418,6 +465,7 @@ func ModelArtsInferenceJobCreate(ctx *context.Context, option api.CreateTrainJob | |||
ModelName: modelName, | |||
ModelVersion: modelVersion, | |||
CkptName: ckptName, | |||
ModelId: option.ModelId, | |||
ResultUrl: resultObsPath, | |||
Spec: spec, | |||
DatasetName: datasetNames, | |||
@@ -10,11 +10,9 @@ import ( | |||
"strconv" | |||
"strings" | |||
"code.gitea.io/gitea/services/cloudbrain/modelmanage" | |||
"code.gitea.io/gitea/modules/notification" | |||
"code.gitea.io/gitea/modules/timeutil" | |||
"code.gitea.io/gitea/services/cloudbrain/modelmanage" | |||
"code.gitea.io/gitea/modules/grampus" | |||
"code.gitea.io/gitea/services/lock" | |||
@@ -227,7 +225,8 @@ func GrampusNotebookCreate(ctx *context.Context, option api.CreateNotebookOption | |||
if option.ModelName != "" { //使用预训练模型 | |||
m, err := models.QueryModelByPath(option.PreTrainModelUrl) | |||
m, err := models.QueryModelById(option.ModelId) | |||
//(option.PreTrainModelUrl) | |||
if err != nil { | |||
log.Error("Can not find model", err) | |||
@@ -242,6 +241,7 @@ func GrampusNotebookCreate(ctx *context.Context, option api.CreateNotebookOption | |||
req.ModelName = option.ModelName | |||
req.LabelName = option.LabelName | |||
req.CkptName = option.CkptName | |||
req.ModelId = option.ModelId | |||
req.ModelVersion = option.ModelVersion | |||
req.PreTrainModelUrl = option.PreTrainModelUrl | |||
req.PreTrainModelPath = getPreTrainModelPath(option.PreTrainModelUrl, option.CkptName) | |||
@@ -1086,6 +1086,7 @@ func GrampusNotebookRestart(ctx *context.Context) { | |||
LabelName: task.LabelName, | |||
PreTrainModelUrl: task.PreTrainModelUrl, | |||
CkptName: task.CkptName, | |||
ModelId: task.ModelId, | |||
WorkServerNumber: 1, | |||
} | |||
@@ -110,9 +110,21 @@ func CloudbrainOneTrainJobCreate(ctx *context.Context, option api.CreateTrainJob | |||
req.ModelName = option.ModelName | |||
req.LabelName = option.LabelName | |||
req.CkptName = option.CkptName | |||
req.ModelId = option.ModelId | |||
req.ModelVersion = option.ModelVersion | |||
req.PreTrainModelPath = setting.Attachment.Minio.RealPath + option.PreTrainModelUrl | |||
req.PreTrainModelUrl = option.PreTrainModelUrl | |||
minioPreModelURL, err := dealModelInfo(option.ModelId, jobName, option.CkptName) | |||
if err != nil { | |||
log.Error("Can not find model", err) | |||
//cloudBrainNewDataPrepare(ctx, jobType) | |||
//ctx.RenderWithErr(ctx.Tr("repo.modelconvert.manage.model_not_exist"), tpl, &form) | |||
ctx.JSON(http.StatusOK, models.BaseErrorMessageApi(ctx.Tr("repo.modelconvert.manage.model_not_exist"))) | |||
return | |||
} | |||
req.PreTrainModelPath = setting.Attachment.Minio.RealPath + minioPreModelURL | |||
req.PreTrainModelUrl = minioPreModelURL | |||
//req.PreTrainModelPath = setting.Attachment.Minio.RealPath + option.PreTrainModelUrl | |||
//req.PreTrainModelUrl = option.PreTrainModelUrl | |||
} | |||
@@ -282,6 +294,7 @@ func ModelArtsTrainJobNpuCreate(ctx *context.Context, option api.CreateTrainJobO | |||
req.ModelName = option.ModelName | |||
req.LabelName = option.LabelName | |||
req.CkptName = option.CkptName | |||
req.ModelId = option.ModelId | |||
req.ModelVersion = option.ModelVersion | |||
req.PreTrainModelUrl = option.PreTrainModelUrl | |||
@@ -414,9 +427,11 @@ func GrampusTrainJobGpuCreate(ctx *context.Context, option api.CreateTrainJobOpt | |||
req.ModelName = option.ModelName | |||
req.LabelName = option.LabelName | |||
req.CkptName = option.CkptName | |||
req.ModelId = option.ModelId | |||
req.ModelVersion = option.ModelVersion | |||
req.PreTrainModelUrl = option.PreTrainModelUrl | |||
preTrainModelPath := getPreTrainModelPath(option.PreTrainModelUrl, option.CkptName) | |||
req.PreTrainModelPath = preTrainModelPath | |||
} | |||
jobId, err := grampus.GenerateTrainJob(ctx, req) | |||
@@ -641,6 +656,7 @@ func GrampusTrainJobNpuCreate(ctx *context.Context, option api.CreateTrainJobOpt | |||
req.ModelName = option.ModelName | |||
req.LabelName = option.LabelName | |||
req.CkptName = option.CkptName | |||
req.ModelId = option.ModelId | |||
req.ModelVersion = option.ModelVersion | |||
req.PreTrainModelUrl = option.PreTrainModelUrl | |||
req.PreTrainModelPath = preTrainModelPath | |||
@@ -23,11 +23,11 @@ func QueryModelFileByModel(model *models.AiModelManage) []storage.FileInfo { | |||
} | |||
func HasModelFile(task *models.Cloudbrain) bool { | |||
if task.PreTrainModelUrl == "" { | |||
if task.ModelId == "" { | |||
return true | |||
} | |||
model, err := models.QueryModelByPath(task.PreTrainModelUrl) | |||
model, err := models.QueryModelById(task.ModelId) | |||
if err != nil { | |||
log.Error("Can not find model", err) | |||
return false | |||
@@ -0,0 +1,97 @@ | |||
{{template "base/head" .}} | |||
<div class="admin user"> | |||
{{template "admin/navbar" .}} | |||
<div class="ui container"> | |||
{{template "base/alert" .}} | |||
<div class="ui negative message" style="display: none;"> | |||
</div> | |||
<h4 class="ui top attached header"> | |||
{{.i18n.Tr "repo.model.manage.model_manage"}} ({{.i18n.Tr "admin.total" .Total}}) | |||
</h4> | |||
<div class="ui attached segment"> | |||
{{template "admin/model/search" .}} | |||
</div> | |||
<div class="ui attached segment"> | |||
<div class="ui ten wide column"> | |||
<div id="model_set_recommend" r="{{.Recommend}}" class="ui checkbox" data-url="{{$.Link}}?sort={{.SortType}}&q={{.Keyword}}&tab={{.TabName}}&recommend={{if .Recommend}}false{{else}}true{{end}}"> | |||
<input type="checkbox" {{if .Recommend}}checked{{end}} /> | |||
<label>{{.i18n.Tr "admin.datasets.only_recommend"}}</label> | |||
</div> | |||
</div> | |||
</div> | |||
<script> | |||
var MODELS = {{.models}}; | |||
</script> | |||
<div class="ui attached table segment"> | |||
<table class="ui very basic striped table"> | |||
<thead> | |||
<tr> | |||
<th>ID</th> | |||
<th>{{.i18n.Tr "admin.datasets.name"}}</th> | |||
<th>{{.i18n.Tr "admin.repos.size"}}</th> | |||
<th>{{.i18n.Tr "repo.issues.filter_sort.downloadtimes"}}</th> | |||
<th>{{.i18n.Tr "repo.issues.filter_sort.citations"}}</th> | |||
<th>{{.i18n.Tr "admin.datasets.private"}}</th> | |||
<th>{{.i18n.Tr "admin.users.created"}}</th> | |||
<th>{{.i18n.Tr "admin.notices.op"}}</th> | |||
</tr> | |||
</thead> | |||
<tbody> | |||
{{range .models}} | |||
<tr> | |||
<td>{{.ID}}</td> | |||
<td style="display: flex;align-items: center;"><a href="{{AppSubUrl}}/{{.RepoOwnerName}}/{{.RepoName}}/modelmanage/model_readme_tmpl?name={{.Name}}">{{.Name}}</a>{{if .Recommend}}<img src="/img/jian.svg" style="margin-left: 0.5rem;">{{end}}</td> | |||
<td>{{SizeFmt .Size}}</td> | |||
<td>{{.DownloadCount}}</td> | |||
<td>{{.ReferenceCount}}</td> | |||
<td><i class="fa fa{{if .IsPrivate}}-check{{end}}-square-o"></i></td> | |||
<td><span title="{{.CreatedUnix.FormatLong}}">{{.CreatedUnix.FormatShort}}</span></td> | |||
<td>{{if .Recommend}}<span class="set_model" style="color: rgb(250, 140, 22);cursor: pointer;" data-url="{{$.Link}}/action?id={{.ID}}&recommend=0">{{$.i18n.Tr "admin.datasets.unrecommend"}}</span>{{else}}<span class="set_model" style="color: rgb(19, 194, 141);cursor: pointer;" data-url="{{$.Link}}/action?id={{.ID}}&recommend=1">{{$.i18n.Tr "admin.datasets.recommend"}}</span>{{end}}</td> | |||
</tr> | |||
{{end}} | |||
</tbody> | |||
</table> | |||
</div> | |||
{{template "base/paginate" .}} | |||
</div> | |||
</div> | |||
{{template "base/footer" .}} | |||
<script> | |||
$(".set_model").on("click", function () { | |||
const $this = $(this); | |||
let link = $this.data("url"); | |||
$.ajax({ | |||
url: link, | |||
type: "PUT", | |||
success: function (res) { | |||
console.log(res); | |||
if (res.code == 0) { | |||
window.location.reload(); | |||
} else { | |||
$(".ui.negative.message") | |||
.text(res.Message) | |||
.show() | |||
.delay(1500) | |||
.fadeOut(); | |||
} | |||
}, | |||
error: function (xhr) { | |||
// 隐藏 loading | |||
// 只有请求不正常(状态码不为200)才会执行 | |||
$(".ui.negative.message") | |||
.html(xhr.responseText) | |||
.show() | |||
.delay(1500) | |||
.fadeOut(); | |||
console.log(xhr); | |||
}, | |||
complete: function (xhr) { | |||
// $("#mask").css({"display":"none","z-index":"1"}) | |||
}, | |||
}); | |||
}); | |||
$("#model_set_recommend input").on('change', function(e) { | |||
const url = $(this).closest('#model_set_recommend').data('url'); | |||
window.location.href = url; | |||
}); | |||
</script> |
@@ -0,0 +1,34 @@ | |||
<div class="ui right floated secondary filter menu"> | |||
<!-- Sort --> | |||
<div class="ui dropdown type jump item"> | |||
<span class="text"> | |||
{{.i18n.Tr "repo.issues.filter_sort"}} | |||
<i class="dropdown icon"></i> | |||
</span> | |||
<div class="menu"> | |||
<a class='{{if or (eq .SortType "oldest") (not .SortType)}}active{{end}} item' href='{{$.Link}}?sort=oldest&q={{$.Keyword}}&recommend={{$.Recommend}}'>{{.i18n.Tr "repo.issues.filter_sort.oldest"}}</a> | |||
<a class='{{if eq .SortType "newest"}}active{{end}} item' href='{{$.Link}}?sort=newest&q={{$.Keyword}}&recommend={{$.Recommend}}'>{{.i18n.Tr "repo.issues.filter_sort.latest"}}</a> | |||
<a class='{{if eq .SortType "alphabetically"}}active{{end}} item' href='{{$.Link}}?sort=alphabetically&q={{$.Keyword}}&recommend={{$.Recommend}}'>{{.i18n.Tr "repo.issues.label.filter_sort.alphabetically"}}</a> | |||
<a class='{{if eq .SortType "reversealphabetically"}}active{{end}} item' href='{{$.Link}}?sort=reversealphabetically&q={{$.Keyword}}&recommend={{$.Recommend}}'>{{.i18n.Tr "repo.issues.label.filter_sort.reverse_alphabetically"}}</a> | |||
<a class='{{if eq .SortType "recentupdate"}}active{{end}} item' href='{{$.Link}}?sort=recentupdate&q={{$.Keyword}}&recommend={{$.Recommend}}'>{{.i18n.Tr "repo.issues.filter_sort.recentupdate"}}</a> | |||
<a class='{{if eq .SortType "leastupdate"}}active{{end}} item' href='{{$.Link}}?sort=leastupdate&q={{$.Keyword}}&recommend={{$.Recommend}}'>{{.i18n.Tr "repo.issues.filter_sort.leastupdate"}}</a> | |||
<!-- | |||
<a class='{{if eq .SortType "moststars"}}active{{end}} item' href='{{$.Link}}?sort=moststars&q={{$.Keyword}}&tab={{$.TabName}}&recommend={{$.Recommend}}'>{{.i18n.Tr "repo.issues.filter_sort.moststars"}}</a> | |||
<a class='{{if eq .SortType "feweststars"}}active{{end}} item' href='{{$.Link}}?sort=feweststars&q={{$.Keyword}}&tab={{$.TabName}}&recommend={{$.Recommend}}'>{{.i18n.Tr "repo.issues.filter_sort.feweststars"}}</a> | |||
<a class='{{if eq .SortType "mostforks"}}active{{end}} item' href='{{$.Link}}?sort=mostforks&q={{$.Keyword}}&tab={{$.TabName}}&recommend={{$.Recommend}}'>{{.i18n.Tr "repo.issues.filter_sort.mostforks"}}</a> | |||
<a class='{{if eq .SortType "fewestforks"}}active{{end}} item' href='{{$.Link}}?sort=fewestforks&q={{$.Keyword}}&tab={{$.TabName}}&recommend={{$.Recommend}}'>{{.i18n.Tr "repo.issues.filter_sort.fewestforks"}}</a> | |||
--> | |||
<a class='{{if eq .SortType "size"}}active{{end}} item' href='{{$.Link}}?sort=size&q={{$.Keyword}}&recommend={{$.Recommend}}'>{{.i18n.Tr "repo.issues.label.filter_sort.by_size"}}</a> | |||
<a class='{{if eq .SortType "reversesize"}}active{{end}} item' href='{{$.Link}}?sort=reversesize&q={{$.Keyword}}&recommend={{$.Recommend}}'>{{.i18n.Tr "repo.issues.label.filter_sort.reverse_by_size"}}</a> | |||
<a class='{{if eq .SortType "downloadtimes"}}active{{end}} item' href='{{$.Link}}?sort=downloadtimes&q={{$.Keyword}}&recommend={{$.Recommend}}'>{{.i18n.Tr "repo.issues.filter_sort.downloadtimes"}}</a> | |||
<a class='{{if eq .SortType "mostusecount"}}active{{end}} item' href='{{$.Link}}?sort=mostusecount&q={{$.Keyword}}&recommend={{$.Recommend}}'>{{.i18n.Tr "repo.issues.filter_sort.citations"}}</a> | |||
</div> | |||
</div> | |||
</div> | |||
<form class="ui form ignore-dirty" style="max-width: 90%"> | |||
<div class="ui fluid action input"> | |||
<input name="q" value="{{.Keyword}}" placeholder='{{.i18n.Tr "explore.search"}}...' autofocus> | |||
<button class="ui blue button">{{.i18n.Tr "explore.search"}}</button> | |||
</div> | |||
</form> |
@@ -21,6 +21,9 @@ | |||
<a class="{{if .PageIsAdminDatasets}}active{{end}} item" href="{{AppSubUrl}}/admin/datasets"> | |||
{{.i18n.Tr "admin.datasets"}} | |||
</a> | |||
<a class="{{if .PageIsAdminModels}}active{{end}} item" href="{{AppSubUrl}}/admin/model"> | |||
{{.i18n.Tr "admin.models"}} | |||
</a> | |||
<a class="{{if .PageIsAdminCloudBrains}}active{{end}} item" href="{{AppSubUrl}}/admin/cloudbrains"> | |||
{{.i18n.Tr "repo.cloudbrain.task"}} | |||
</a> | |||
@@ -65,7 +65,7 @@ | |||
{{if .IsSigned}} | |||
<a href="https://openi.pcl.ac.cn/zeizei/OpenI_Learning/issues/new" class="item" target="_blank"><i class="envelope icon"></i> {{.i18n.Tr "custom.foot.advice_feedback"}}</a> | |||
{{else}} | |||
<a href="{{AppSubUrl}}/user/login" class="item"><i class="envelope icon"></i> {{.i18n.Tr "custom.foot.advice_feedback"}}</a> | |||
<a href="{{AppSubUrl}}/user/login?redirect_to={{AppSubUrl}}/zeizei/OpenI_Learning/issues/new" class="item"><i class="envelope icon"></i> {{.i18n.Tr "custom.foot.advice_feedback"}}</a> | |||
{{end}} | |||
<a href="{{AppSubUrl}}/resource_desc" class="item" target="_blank"><i class="server icon"></i> {{.i18n.Tr "custom.resource_description"}}</a> | |||
@@ -42,6 +42,7 @@ | |||
{{.i18n.Tr "repo.model_manager"}} | |||
<i class="dropdown icon"></i> | |||
<div class="menu"> | |||
<a class="item" href="{{AppSubUrl}}/modelsquare/main">{{.i18n.Tr "repo.model_square"}}</a> | |||
<a class="item" href="{{AppSubUrl}}/extension/wenxin">{{.i18n.Tr "repo.model_experience"}}</a> | |||
</div> | |||
</div> | |||
@@ -84,6 +85,7 @@ | |||
{{.i18n.Tr "repo.model_manager"}} | |||
<i class="dropdown icon"></i> | |||
<div class="menu"> | |||
<a class="item" href="{{AppSubUrl}}/modelsquare/main">{{.i18n.Tr "repo.model_square"}}</a> | |||
<a class="item" href="{{AppSubUrl}}/extension/wenxin">{{.i18n.Tr "repo.model_experience"}}</a> | |||
</div> | |||
</div> | |||
@@ -39,6 +39,7 @@ | |||
{{.i18n.Tr "repo.model_manager"}} | |||
<i class="dropdown icon"></i> | |||
<div class="menu"> | |||
<a class="item" href="{{AppSubUrl}}/modelsquare/main">{{.i18n.Tr "repo.model_square"}}</a> | |||
<a class="item" href="{{AppSubUrl}}/extension/wenxin">{{.i18n.Tr "repo.model_experience"}}</a> | |||
</div> | |||
</div> | |||
@@ -80,6 +81,7 @@ | |||
{{.i18n.Tr "repo.model_manager"}} | |||
<i class="dropdown icon"></i> | |||
<div class="menu"> | |||
<a class="item" href="{{AppSubUrl}}/modelsquare/main">{{.i18n.Tr "repo.model_square"}}</a> | |||
<a class="item" href="{{AppSubUrl}}/extension/wenxin">{{.i18n.Tr "repo.model_experience"}}</a> | |||
</div> | |||
</div> | |||
@@ -31,6 +31,7 @@ | |||
{{.i18n.Tr "repo.model_manager"}} | |||
<i class="dropdown icon"></i> | |||
<div class="menu"> | |||
<a class="item" href="{{AppSubUrl}}/modelsquare/main">{{.i18n.Tr "repo.model_square"}}</a> | |||
<a class="item" href="{{AppSubUrl}}/extension/wenxin">{{.i18n.Tr "repo.model_experience"}}</a> | |||
</div> | |||
</div> | |||
@@ -73,6 +74,7 @@ | |||
{{.i18n.Tr "repo.model_manager"}} | |||
<i class="dropdown icon"></i> | |||
<div class="menu"> | |||
<a class="item" href="{{AppSubUrl}}/modelsquare/main">{{.i18n.Tr "repo.model_square"}}</a> | |||
<a class="item" href="{{AppSubUrl}}/extension/wenxin">{{.i18n.Tr "repo.model_experience"}}</a> | |||
</div> | |||
</div> | |||
@@ -41,6 +41,7 @@ | |||
{{.i18n.Tr "repo.model_manager"}} | |||
<i class="dropdown icon"></i> | |||
<div class="menu"> | |||
<a class="item" href="{{AppSubUrl}}/modelsquare/main">{{.i18n.Tr "repo.model_square"}}</a> | |||
<a class="item" href="{{AppSubUrl}}/extension/wenxin">{{.i18n.Tr "repo.model_experience"}}</a> | |||
</div> | |||
</div> | |||
@@ -83,6 +84,7 @@ | |||
{{.i18n.Tr "repo.model_manager"}} | |||
<i class="dropdown icon"></i> | |||
<div class="menu"> | |||
<a class="item" href="{{AppSubUrl}}/modelsquare/main">{{.i18n.Tr "repo.model_square"}}</a> | |||
<a class="item" href="{{AppSubUrl}}/extension/wenxin">{{.i18n.Tr "repo.model_experience"}}</a> | |||
</div> | |||
</div> | |||
@@ -0,0 +1,5 @@ | |||
{{template "base/head_home" .}} | |||
<link rel="stylesheet" href="{{StaticUrlPrefix}}/css/vp-model-square.css?v={{MD5 AppVer}}" /> | |||
<div id="__vue-root"></div> | |||
<script src="{{StaticUrlPrefix}}/js/vp-model-square.js?v={{MD5 AppVer}}"></script> | |||
{{template "base/footer" .}} |
@@ -88,7 +88,12 @@ | |||
<a id="benchmark_model_example" href="https://openi.pcl.ac.cn/BDIP/snn4imagenet" | |||
target="_blank">{{.i18n.Tr "cloudbrain.view_sample"}}</a> | |||
</div> | |||
{{template "custom/select_model_required" .}} | |||
<!--{{template "custom/select_model_required" .}}--> | |||
<div> | |||
<div class="select-multi-model" data-required="true" data-model-id="{{.model_id}}" data-model-name="{{.model_name}}" data-model-version="{{.model_version}}" | |||
data-pre-train-model-url="{{.pre_train_model_url}}" data-ckpt-name="{{.ckpt_name}}"></div> | |||
<div id="select-multi-model"></div> | |||
</div> | |||
<div id="images-new-cb"> | |||
</div> | |||
@@ -50,7 +50,6 @@ | |||
{{.CsrfTokenHtml}} | |||
<input type="hidden" name="action" value="update"> | |||
<input type="hidden" id="ai_image_name" value="{{.image}}"> | |||
<input type="hidden" id="ai_model_version" name="model_version" value=""> | |||
<input type="hidden" id="failed_train_url" value="{{$.train_url}}"> | |||
<input type="hidden" id="failed_model_name" value="{{$.model_name}}"> | |||
@@ -106,8 +105,10 @@ | |||
</div> | |||
<div class="ui divider"></div> | |||
<!-- 模型相关配置 --> | |||
<h4 class="title ui header ">{{.i18n.Tr "repo.modelarts.train_job.parameter_setting"}}:</h4> | |||
<!-- 模型相关配置 --> | |||
<!-- | |||
<div class="required inline min_title fields" style="width: 94%;"> | |||
<label class="label-fix-width" style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.infer_job.select_model"}}</label> | |||
<div class="six wide field"> | |||
@@ -144,10 +145,14 @@ | |||
</span> | |||
</div> | |||
<!-- AI引擎 --> | |||
<div id="images-new-cb"> | |||
--> | |||
<div> | |||
<div class="select-multi-model" data-required="true" data-model-id="{{.model_id}}" data-model-name="{{.model_name}}" data-model-version="{{.model_version}}" | |||
data-pre-train-model-url="{{.pre_train_model_url}}" data-ckpt-name="{{.ckpt_name}}"></div> | |||
<div id="select-multi-model"></div> | |||
</div> | |||
<!-- AI引擎 --> | |||
<div id="images-new-cb"></div> | |||
<!-- 代码分支 --> | |||
<div class="required min_title inline field"> | |||
<label class="label-fix-width" style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.code_version"}}</label> | |||
@@ -293,6 +298,7 @@ | |||
let nameMap,nameList | |||
// 获取模型列表和模型名称对应的模型版本 | |||
$(document).ready(function(){ | |||
return; // 用模型选择组件了 | |||
modelVersion() | |||
modelCkpt() | |||
$.get(`${RepoLink}/modelmanage/query_model_for_predict?type=0`, (data) => { | |||
@@ -145,36 +145,15 @@ | |||
{{end}} | |||
</select> | |||
</div> | |||
<!--<div class="inline required field"> | |||
<label>{{.i18n.Tr "cloudbrain.gpu_type"}}</label> | |||
<select id="cloudbrain_gpu_type" class="ui search dropdown gpu-type" placeholder="选择GPU类型" | |||
style='width:385px' name="gpu_type"> | |||
{{range .gpu_types}} | |||
<option value="{{.Queue}}">{{.Value}}</option> | |||
{{end}} | |||
</select> | |||
</div>--> | |||
{{template "custom/select_model" .}} | |||
<div id="images-new-cb"> | |||
</div> | |||
<div id="select-multi-dataset"> | |||
<!--{{template "custom/select_model" .}} --> | |||
<div> | |||
<div class="select-multi-model" data-model-id="{{.model_id}}" data-model-name="{{.model_name}}" data-model-version="{{.model_version}}" | |||
data-pre-train-model-url="{{.pre_train_model_url}}" data-ckpt-name="{{.ckpt_name}}"></div> | |||
<div id="select-multi-model"></div> | |||
</div> | |||
<div id="images-new-cb"></div> | |||
<div id="select-multi-dataset"></div> | |||
<span class="tooltips" style="margin-left: 11.5rem;margin-bottom: 1rem;"></span> | |||
<!--<div class="inline required field"> | |||
<label>{{.i18n.Tr "cloudbrain.resource_specification"}}</label> | |||
<select id="cloudbrain_resource_spec" class="ui search dropdown" | |||
placeholder="{{.i18n.Tr "cloudbrain.select_specification"}}" style='width:385px' | |||
name="resource_spec_id"> | |||
{{range .resource_specs}} | |||
<option name="resource_spec_id" value="{{.Id}}"> | |||
{{$.i18n.Tr "cloudbrain.gpu_num"}}:{{.GpuNum}},{{$.i18n.Tr "cloudbrain.cpu_num"}}:{{.CpuNum}},{{$.i18n.Tr "cloudbrain.memory"}}(MB):{{.MemMiB}},{{$.i18n.Tr "cloudbrain.shared_memory"}}(MB):{{.ShareMemMiB}} | |||
</option> | |||
{{end}} | |||
</select> | |||
</div>--> | |||
<div class="inline min_title required field"> | |||
<label class="label-fix-width" style="font-weight: normal;">{{.i18n.Tr "cloudbrain.resource_specification"}}</label> | |||
<select id="__specs__" class="ui search dropdown width48" | |||
@@ -156,7 +156,12 @@ | |||
{{end}} | |||
</select> | |||
</div> | |||
{{template "custom/select_model" .}} | |||
<!--{{template "custom/select_model" .}} --> | |||
<div> | |||
<div class="select-multi-model" data-model-id="{{.model_id}}" data-model-name="{{.model_name}}" data-model-version="{{.model_version}}" | |||
data-pre-train-model-url="{{.pre_train_model_url}}" data-ckpt-name="{{.ckpt_name}}"></div> | |||
<div id="select-multi-model"></div> | |||
</div> | |||
<div class="inline required field" style="display: none;"> | |||
<label>{{.i18n.Tr "cloudbrain.task_type"}}</label> | |||
<select id="cloudbrain_job_type" class="ui search dropdown" placeholder="选择任务类型" style='width:385px' | |||
@@ -702,6 +702,7 @@ | |||
type: 'POST', | |||
data: data, | |||
success: function (res) { | |||
const modelName = $('#formId #name').val(); | |||
$('input[name="engine_name"]').val(""); | |||
$('input[name="engine"]').val(""); | |||
$('input[name="jobId"]').val(""); | |||
@@ -710,7 +711,7 @@ | |||
var cityObj = $("#modelSelectedFile"); | |||
cityObj.attr("value", ""); | |||
document.getElementById("formId").reset(); | |||
location.href = `/${userName}/${repoPath}/modelmanage/show_model` | |||
location.href = `/${userName}/${repoPath}/modelmanage/model_readme_tmpl?name=${encodeURIComponent(modelName)}` | |||
$('.ui.modal.second').modal('hide') | |||
}, | |||
error: function (xhr) { | |||
@@ -100,6 +100,12 @@ | |||
</select> | |||
</div> | |||
<!--{{template "custom/select_model" .}} --> | |||
<div> | |||
<div class="select-multi-model" data-model-id="{{.model_id}}" data-model-name="{{.model_name}}" data-model-version="{{.model_version}}" | |||
data-pre-train-model-url="{{.pre_train_model_url}}" data-ckpt-name="{{.ckpt_name}}"></div> | |||
<div id="select-multi-model"></div> | |||
</div> | |||
<div class="inline min_title required field"> | |||
<label class="label-fix-width" style="font-weight: normal;">{{.i18n.Tr "cloudbrain.mirror"}}</label> | |||
<select class="ui search dropdown cloudbrain_image width48" placeholder="{{.i18n.Tr "cloudbrain.choose_mirror"}}" style='width:385px' name="image_id"> | |||
@@ -109,7 +109,12 @@ | |||
{{end}} | |||
</select> | |||
</div> | |||
{{template "custom/select_model" .}} | |||
<!--{{template "custom/select_model" .}} --> | |||
<div> | |||
<div class="select-multi-model" data-model-id="{{.model_id}}" data-model-name="{{.model_name}}" data-model-version="{{.model_version}}" | |||
data-pre-train-model-url="{{.pre_train_model_url}}" data-ckpt-name="{{.ckpt_name}}"></div> | |||
<div id="select-multi-model"></div> | |||
</div> | |||
<div id="images-new-cb"> | |||
</div> | |||
@@ -95,7 +95,12 @@ | |||
{{end}} | |||
</select> | |||
</div> | |||
{{template "custom/select_model" .}} | |||
<!--{{template "custom/select_model" .}} --> | |||
<div> | |||
<div class="select-multi-model" data-model-id="{{.model_id}}" data-model-name="{{.model_name}}" data-model-version="{{.model_version}}" | |||
data-pre-train-model-url="{{.pre_train_model_url}}" data-ckpt-name="{{.ckpt_name}}"></div> | |||
<div id="select-multi-model"></div> | |||
</div> | |||
<div class="inline min_title required field"> | |||
<label class="label-fix-width" style="font-weight: normal;">{{.i18n.Tr "cloudbrain.mirror"}}</label> | |||
<select class="ui search dropdown cloudbrain_image width48" placeholder="{{.i18n.Tr "cloudbrain.choose_mirror"}}" style='width:385px' name="image_id"> | |||
@@ -378,7 +378,7 @@ | |||
{{if eq $.modelDownload.IsDelete true}} | |||
{{$.modelDownload.Name}}({{$.i18n.Tr "dataset.file_deleted"}}) | |||
{{else}} | |||
<a href="{{$.RepoLink}}/modelmanage/show_model_info?name={{.ModelName}}" target="_blank">{{$.modelDownload.Name}}</a> | |||
<a href="{{$.RepoLink}}/modelmanage/model_readme_tmpl?name={{.ModelName}}" target="_blank">{{$.modelDownload.Name}}</a> | |||
{{end}} | |||
</td> | |||
<td><div class="dataset_nowrap_two_line">{{$.modelDownload.DownloadLink}}</div></td> | |||
@@ -158,7 +158,14 @@ | |||
{{end}} | |||
</select> | |||
</div> | |||
{{template "custom/select_model" .}} | |||
<!--{{template "custom/select_model" .}} --> | |||
<div> | |||
<div class="select-multi-model" data-model-id="{{.model_id}}" data-model-name="{{.model_name}}" data-model-version="{{.model_version}}" | |||
data-pre-train-model-url="{{.pre_train_model_url}}" data-ckpt-name="{{.ckpt_name}}"></div> | |||
<div id="select-multi-model"></div> | |||
</div> | |||
<div id="images-new-grampus"> | |||
<div id="images-new-cb"> | |||
</div> | |||
@@ -143,10 +143,15 @@ | |||
{{end}} | |||
</select> | |||
</div> | |||
{{template "custom/select_model" .}} | |||
<!--{{template "custom/select_model" .}} --> | |||
<div> | |||
<div class="select-multi-model" data-model-id="{{.model_id}}" data-model-name="{{.model_name}}" data-model-version="{{.model_version}}" | |||
data-pre-train-model-url="{{.pre_train_model_url}}" data-ckpt-name="{{.ckpt_name}}"></div> | |||
<div id="select-multi-model"></div> | |||
</div> | |||
<div class="required min_title inline field" id="engine_name"> | |||
<label class="label-fix-width" style="font-weight: normal;">{{.i18n.Tr "cloudbrain.mirror"}}</label> | |||
<select class="ui dropdown width81" id="trainjob_images" name="image_id"> | |||
<select class="ui dropdown width48" id="trainjob_images" name="image_id"> | |||
{{if .image_id}} | |||
{{range .images}} | |||
{{if eq $.image_id .ID}} | |||
@@ -783,6 +783,7 @@ | |||
type: 'POST', | |||
data: data, | |||
success: function (res) { | |||
const modelName = $('#formId #name').val(); | |||
$('input[name="engine_name"]').val(""); | |||
$('input[name="engine"]').val(""); | |||
$('input[name="jobId"]').val(""); | |||
@@ -791,7 +792,7 @@ | |||
var cityObj = $("#modelSelectedFile"); | |||
cityObj.attr("value", ""); | |||
document.getElementById("formId").reset(); | |||
location.href = `/${userName}/${repoPath}/modelmanage/show_model` | |||
location.href = `/${userName}/${repoPath}/modelmanage/model_readme_tmpl?name=${encodeURIComponent(modelName)}` | |||
$('.ui.modal.second').modal('hide') | |||
}, | |||
error: function (xhr) { | |||
@@ -119,9 +119,21 @@ | |||
</a> | |||
</div> | |||
<!-- 模型版本 --> | |||
<!-- href="{{$.RepoLink}}/modelmanage/show_model_info?name={{.ModelName}}" --> | |||
<!-- href="{{$.RepoLink}}/modelmanage/model_readme_tmpl?name={{.ModelName}}" --> | |||
<div class="three wide column text center padding0" style="display: flex;width: 17% !important;"> | |||
<a id="{{.JobName}}" class="goto_modelmanage nowrap" title="{{.ModelName}}" href="javascript:void(0);" data-variation="inverted" data-position="top center" data-content="{{$.i18n.Tr "repo.modelarts.infer_job.tooltip"}}" data-jobname={{.JobName}} data-modelname={{.ModelName}} data-version={{.ModelVersion}} data-repopath="{{$.RepoLink}}">{{.ModelName}} </a> <span style="font-size: 12px;">{{.ModelVersion}}</span> | |||
<a id="{{.JobName}}" class="goto_modelmanage nowrap" title="{{.ModelName}}" href="javascript:void(0);" | |||
data-variation="inverted" | |||
data-position="top center" | |||
data-content="{{$.i18n.Tr "repo.modelarts.infer_job.model_cant_see"}}" | |||
data-jobname="{{.JobName}}" | |||
data-modelid="{{.ModelId}}" | |||
data-modelname="{{.ModelName}}" | |||
data-version="{{.ModelVersion}}" | |||
data-repopath="{{$.RepoLink}}" | |||
data-modelrepoownername="{{.ModelRepoOwnerName}}" | |||
data-modelreponame="{{.ModelRepoName}}" | |||
> | |||
{{.ModelName}} </a> <span style="font-size: 12px;">{{.ModelVersion}}</span> | |||
</div> | |||
<!-- 任务状态 --> | |||
<div class="two wide column text center padding0" style="width: 10.5% !important;"> | |||
@@ -49,7 +49,6 @@ | |||
<input type="hidden" name="action" value="update"> | |||
<input type="hidden" id="ai_engine_name" name="engine_names" value=""> | |||
<input type="hidden" id="ai_flaver_name" name="flaver_names" value=""> | |||
<input type="hidden" id="ai_model_version" name="model_version" value=""> | |||
<input type="hidden" id="failed_train_url" value="{{$.train_url}}"> | |||
<input type="hidden" id="failed_model_name" value="{{$.model_name}}"> | |||
@@ -105,8 +104,9 @@ | |||
{{end}} | |||
</div> | |||
<div class="ui divider"></div> | |||
<!-- 模型相关配置 --> | |||
<h4 class="title ui header ">{{.i18n.Tr "repo.modelarts.train_job.parameter_setting"}}:</h4> | |||
<!-- 模型相关配置 --> | |||
<!-- | |||
<div class="required inline min_title fields" style="width: 94%;"> | |||
<label class="label-fix-width" style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.infer_job.select_model"}}</label> | |||
<div class="six wide field"> | |||
@@ -142,6 +142,12 @@ | |||
<i class="question circle icon" data-content="{{.i18n.Tr "cloudbrain.model_file_path_rule"}} {{.i18n.Tr "cloudbrain.model_file_postfix_rule"}}" data-position="top center" data-variation="inverted mini"></i> | |||
</span> | |||
</div> | |||
--> | |||
<div> | |||
<div class="select-multi-model" data-required="true" data-model-id="{{.model_id}}" data-model-name="{{.model_name}}" data-model-version="{{.model_version}}" | |||
data-pre-train-model-url="{{.pre_train_model_url}}" data-ckpt-name="{{.ckpt_name}}"></div> | |||
<div id="select-multi-model"></div> | |||
</div> | |||
<!-- AI引擎 --> | |||
<div class="required inline min_title fields" style="width: 92.5%;"> | |||
<label class="label-fix-width" style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.train_job.AI_driver"}}</label> | |||
@@ -323,6 +329,7 @@ | |||
// 获取模型列表和模型名称对应的模型版本 | |||
$(document).ready(function(){ | |||
return; // 用模型选择组件了 | |||
modelVersion() | |||
modelCkpt() | |||
$.get(`${RepoLink}/modelmanage/query_model_for_predict?type=1`, (data) => { | |||
@@ -73,7 +73,12 @@ | |||
<div class="ui divider"></div> | |||
<h4 class="train-job-title ui header ">{{.i18n.Tr "repo.modelarts.train_job.parameter_setting"}}:</h4> | |||
{{template "custom/select_model" .}} | |||
<!--{{template "custom/select_model" .}} --> | |||
<div> | |||
<div class="select-multi-model" data-model-id="{{.model_id}}" data-model-name="{{.model_name}}" data-model-version="{{.model_version}}" | |||
data-pre-train-model-url="{{.pre_train_model_url}}" data-ckpt-name="{{.ckpt_name}}"></div> | |||
<div id="select-multi-model"></div> | |||
</div> | |||
<div class="inline min_title required field"> | |||
<label class="label-fix-width" style="font-weight: normal;">{{.i18n.Tr "cloudbrain.mirror"}}</label> | |||
<select id="cloudbrain_image" class="ui search dropdown width48" placeholder="{{.i18n.Tr "cloudbrain.choose_mirror"}}" name="image_id"> | |||
@@ -285,7 +285,7 @@ | |||
{{if eq $.modelDownload.IsDelete true}} | |||
{{$.modelDownload.Name}}({{$.i18n.Tr "dataset.file_deleted"}}) | |||
{{else}} | |||
<a href="{{$.RepoLink}}/modelmanage/show_model_info?name={{.ModelName}}" target="_blank">{{$.modelDownload.Name}}</a> | |||
<a href="{{$.RepoLink}}/modelmanage/model_readme_tmpl?name={{.ModelName}}" target="_blank">{{$.modelDownload.Name}}</a> | |||
{{end}} | |||
</td> | |||
<td><div class="dataset_nowrap_two_line">{{$.modelDownload.DownloadLink}}</div></td> | |||
@@ -147,7 +147,12 @@ | |||
</select> | |||
</div> | |||
{{template "custom/select_model" .}} | |||
<!--{{template "custom/select_model" .}} --> | |||
<div> | |||
<div class="select-multi-model" data-model-id="{{.model_id}}" data-model-name="{{.model_name}}" data-model-version="{{.model_version}}" | |||
data-pre-train-model-url="{{.pre_train_model_url}}" data-ckpt-name="{{.ckpt_name}}"></div> | |||
<div id="select-multi-model"></div> | |||
</div> | |||
<div class="required inline min_title fields" style="width: 92.5%;"> | |||
<label class="label-fix-width" style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.train_job.AI_driver"}}</label> | |||
@@ -788,6 +788,7 @@ | |||
type: 'POST', | |||
data: data, | |||
success: function (res) { | |||
const modelName = $('#formId #name').val(); | |||
$('input[name="engine_name"]').val(""); | |||
$('input[name="engine"]').val(""); | |||
$('input[name="jobId"]').val(""); | |||
@@ -796,7 +797,7 @@ | |||
var cityObj = $("#modelSelectedFile"); | |||
cityObj.attr("value", ""); | |||
document.getElementById("formId").reset(); | |||
location.href = `/${userName}/${repoPath}/modelmanage/show_model` | |||
location.href = `/${userName}/${repoPath}/modelmanage/model_readme_tmpl?name=${encodeURIComponent(modelName)}` | |||
$('.ui.modal.second').modal('hide') | |||
}, | |||
error: function (xhr) { | |||
@@ -125,7 +125,12 @@ | |||
</div> | |||
{{template "custom/select_model" .}} | |||
<!--{{template "custom/select_model" .}} --> | |||
<div> | |||
<div class="select-multi-model" data-model-id="{{.model_id}}" data-model-name="{{.model_name}}" data-model-version="{{.model_version}}" | |||
data-pre-train-model-url="{{.pre_train_model_url}}" data-ckpt-name="{{.ckpt_name}}"></div> | |||
<div id="select-multi-model"></div> | |||
</div> | |||
<div class="required min_title inline fields" style="width: 92.5%;"> | |||
<label class="label-fix-width" style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.train_job.AI_driver"}}</label> | |||
@@ -1,5 +1,5 @@ | |||
{{template "base/head" .}} | |||
<link rel="stylesheet" href="{{StaticUrlPrefix}}/css/vp-modelmanage-local-create-1.css?v={{MD5 AppVer}}" /> | |||
<link rel="stylesheet" href="{{StaticUrlPrefix}}/css/vp-modelmanage-local-create.css?v={{MD5 AppVer}}" /> | |||
<div class="repository release dataset-list view"> | |||
{{template "repo/header" .}} | |||
<script>var REPO_IS_PRIVATE = {{$.Repository.IsPrivate}};</script> | |||
@@ -7,5 +7,5 @@ | |||
<div id="__vue-root"></div> | |||
</div> | |||
</div> | |||
<script src="{{StaticUrlPrefix}}/js/vp-modelmanage-local-create-1.js?v={{MD5 AppVer}}"></script> | |||
<script src="{{StaticUrlPrefix}}/js/vp-modelmanage-local-create.js?v={{MD5 AppVer}}"></script> | |||
{{template "base/footer" .}} |
@@ -1,11 +0,0 @@ | |||
{{template "base/head" .}} | |||
<link rel="stylesheet" href="{{StaticUrlPrefix}}/css/vp-modelmanage-local-create-2.css?v={{MD5 AppVer}}" /> | |||
<div class="repository release dataset-list view"> | |||
{{template "repo/header" .}} | |||
<script>var MAX_MODEL_SIZE = {{ .max_model_size }};</script> | |||
<div class="ui container"> | |||
<div id="__vue-root"></div> | |||
</div> | |||
</div> | |||
<script src="{{StaticUrlPrefix}}/js/vp-modelmanage-local-create-2.js?v={{MD5 AppVer}}"></script> | |||
{{template "base/footer" .}} |
@@ -580,7 +580,7 @@ | |||
type: "POST", | |||
data: data, | |||
success: function (res) { | |||
backToModelListPage(); | |||
goDetailModelPage(cName); | |||
}, | |||
error: function (xhr) { | |||
// 隐藏 loading | |||
@@ -598,7 +598,12 @@ | |||
let url_href = location.href.split("create_online_model")[0] + 'show_model'; | |||
window.location.href = url_href; | |||
} | |||
function goDetailModelPage(name) { | |||
let url_href = location.href.split("create_online_model")[0] + 'model_readme_tmpl?name=' + encodeURIComponent(name); | |||
window.location.href = url_href; | |||
} | |||
window.submitSaveModel = submitSaveModel; | |||
window.backToModelListPage = backToModelListPage; | |||
window.goDetailModelPage = goDetailModelPage; | |||
})(); | |||
</script> |
@@ -0,0 +1,5 @@ | |||
{{template "base/head_home" .}} | |||
<link rel="stylesheet" href="{{StaticUrlPrefix}}/css/vp-model-graph.css?v={{MD5 AppVer}}" /> | |||
<div id="__vue-root"></div> | |||
<script src="{{StaticUrlPrefix}}/js/vp-model-graph.js?v={{MD5 AppVer}}"></script> | |||
{{template "base/footer" .}} |
@@ -0,0 +1,5 @@ | |||
{{template "base/head_home" .}} | |||
<link rel="stylesheet" href="{{StaticUrlPrefix}}/css/vp-model-files.css?v={{MD5 AppVer}}" /> | |||
<div id="__vue-root"></div> | |||
<script src="{{StaticUrlPrefix}}/js/vp-model-files.js?v={{MD5 AppVer}}"></script> | |||
{{template "base/footer" .}} |
@@ -0,0 +1,6 @@ | |||
{{template "base/head" .}} | |||
<link rel="stylesheet" href="{{StaticUrlPrefix}}/css/vp-model-fileupload.css?v={{MD5 AppVer}}" /> | |||
<script>var MAX_MODEL_SIZE = {{ .max_model_size }};</script> | |||
<div id="__vue-root"></div> | |||
<script src="{{StaticUrlPrefix}}/js/vp-model-fileupload.js?v={{MD5 AppVer}}"></script> | |||
{{template "base/footer" .}} |
@@ -76,7 +76,7 @@ | |||
<div class="column right aligned"> | |||
<!-- --> | |||
<a class="ui button {{if .Permission.CanWrite $.UnitTypeModelManage}} blue m-blue-btn {{else}} disabled {{end}}" | |||
href="{{.RepoLink}}/modelmanage/create_local_model_1">{{$.i18n.Tr "repo.model.manage.import_local_model"}}</a> | |||
href="{{.RepoLink}}/modelmanage/create_local_model">{{$.i18n.Tr "repo.model.manage.import_local_model"}}</a> | |||
<a class="ui button {{if .Permission.CanWrite $.UnitTypeModelManage}} green {{else}} disabled {{end}}" | |||
href="{{.RepoLink}}/modelmanage/create_online_model">{{$.i18n.Tr "repo.model.manage.import_online_model"}}</a> | |||
</div> | |||
@@ -0,0 +1,5 @@ | |||
{{template "base/head_home" .}} | |||
<link rel="stylesheet" href="{{StaticUrlPrefix}}/css/vp-model-intro.css?v={{MD5 AppVer}}" /> | |||
<div id="__vue-root"></div> | |||
<script src="{{StaticUrlPrefix}}/js/vp-model-intro.js?v={{MD5 AppVer}}"></script> | |||
{{template "base/footer" .}} |
@@ -0,0 +1,6 @@ | |||
{{template "base/head_home" .}} | |||
<link rel="stylesheet" href="{{StaticUrlPrefix}}/css/vp-model-settings.css?v={{MD5 AppVer}}" /> | |||
<script>window.REPO_IS_PRIVATE = {{$.Repository.IsPrivate}};</script> | |||
<div id="__vue-root"></div> | |||
<script src="{{StaticUrlPrefix}}/js/vp-model-settings.js?v={{MD5 AppVer}}"></script> | |||
{{template "base/footer" .}} |
@@ -141,7 +141,12 @@ | |||
onkeydown="this.value=this.value.substring(0, 255)" | |||
onkeyup="this.value=this.value.substring(0, 255)">{{.description}}</textarea> | |||
</div> | |||
{{template "custom/select_model_required" .}} | |||
<!--{{template "custom/select_model_required" .}}--> | |||
<div> | |||
<div class="select-multi-model" data-required="true" data-model-id="{{.model_id}}" data-model-name="{{.model_name}}" data-model-version="{{.model_version}}" | |||
data-pre-train-model-url="{{.pre_train_model_url}}" data-ckpt-name="{{.ckpt_name}}"></div> | |||
<div id="select-multi-model"></div> | |||
</div> | |||
<div class="required inline min_title field " style="display: none;"> | |||
<label class="label-fix-width" style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.train_job.resource_pool"}}</label> | |||
<select class="ui dropdown width48" id="trainjob_resource_pool" name="pool_id"> | |||
@@ -80,16 +80,6 @@ | |||
}}</span> | |||
</template> | |||
</el-table-column> | |||
<el-table-column | |||
prop="computeResource" | |||
:label="i18n.model_compute_resource" | |||
align="center" | |||
min-width="8%" | |||
> | |||
<template slot-scope="scope"> | |||
<span class="text-over">{{ scope.row.computeResource }}</span> | |||
</template> | |||
</el-table-column> | |||
<el-table-column | |||
prop="isPrivate" | |||
:label="i18n.model_status" | |||
@@ -144,11 +134,9 @@ | |||
<div class="space-around" > | |||
<a class="op-btn" | |||
v-show="scope.row.modelType == 1" | |||
:href="url + 'create_local_model_1?type=1&name=' + encodeURIComponent(scope.row.name) + '&id=' + scope.row.id" | |||
:href="url + 'model_setting?type=1&name=' + encodeURIComponent(scope.row.name) + '&id=' + scope.row.id + '&back=' + encodeURIComponent(curHref)" | |||
:class="{ disabled: !scope.row.isCanOper }" | |||
>{{ i18n.modify }}</a> | |||
<a class="op-btn" v-show="scope.row.modelType != 1" style="color:transparent;cursor:default;" >{{ i18n.modify }}</a> | |||
<a class="op-btn" style="color: #13c28d;" v-show="repoIsPrivate == false && scope.row.isPrivate==true && scope.row.isCanOper" @click=" | |||
modifyModelStatus(scope.row.id, scope.row.cName, scope.row.rowKey,false) | |||
">{{ i18n.modelaccess_setpublic }}</a> | |||
@@ -196,6 +184,7 @@ export default { | |||
components: {}, | |||
data() { | |||
return { | |||
curHref: window.location.href, | |||
i18n: {}, | |||
currentPage: 1, | |||
pageSize: 10, | |||
@@ -232,8 +221,6 @@ export default { | |||
for (let i = 0; i < tableData.length; i++) { | |||
trainTaskInfo = JSON.parse(tableData[i].trainTaskInfo || '{}'); | |||
tableData[i].engineName = this.getEngineName(tableData[i]); | |||
// tableData[i].computeResource = trainTaskInfo.ComputeResource; | |||
tableData[i].computeResource = tableData[i].type == '0' ? 'CPU/GPU' : 'NPU'; | |||
tableData[i].cName = tableData[i].name; | |||
tableData[i].rowKey = tableData[i].id + Math.random(); | |||
tableData[i].name = ""; | |||
@@ -517,8 +504,6 @@ export default { | |||
this.tableData[i].engineName = this.getEngineName( | |||
this.tableData[i] | |||
); | |||
// this.tableData[i].computeResource = trainTaskInfo.ComputeResource; | |||
this.tableData[i].computeResource = this.tableData[i].type == '0' ? 'CPU/GPU' : 'NPU'; | |||
this.tableData[i].hasChildren = res.data.data[i].versionCount === 1 ? false : true; | |||
if (this.tableData[i].status !== 1) { | |||
countStatus++; | |||
@@ -562,7 +547,7 @@ export default { | |||
return this.url + "downloadall?id="; | |||
}, | |||
showinfoHref() { | |||
return this.url + "show_model_info?name="; | |||
return this.url + "model_readme_tmpl?name="; | |||
}, | |||
transStatus(){ | |||
return function (state) { | |||
@@ -0,0 +1,691 @@ | |||
<template> | |||
<div class="model-select"> | |||
<div class="title" v-if="showTitle"><span :class="required ? 'required' : ''">{{ selfTitle }}</span></div> | |||
<div class="content"> | |||
<input type="hidden" name="model_id" :value="form_model_id" required /> | |||
<input type="hidden" name="model_name" :value="form_model_name" required /> | |||
<input type="hidden" name="model_version" :value="form_model_version" required /> | |||
<input type="hidden" name="pre_train_model_url" :value="form_pre_train_model_url" required /> | |||
<input type="hidden" name="ckpt_name" :value="form_ckpt_name" required /> | |||
<div v-if="selectList.length" class="model-list-c" :class="errStatus ? 'error' : ''"> | |||
<div class="model-item" v-for="(item, index) in selectList" :key="item.id" | |||
:title="item._modelName + '/' + item.name"> | |||
{{ item._modelName + '/' + item.name }} | |||
</div> | |||
</div> | |||
<input v-if="selectList.length == 0" type="text" class="disabled" style="width:100%" | |||
:required="required ? 'required' : undefined" :placeholder="$t('modelObj.model_select_placeholder')" /> | |||
</div> | |||
<div class="btn-select" @click="dlgShow = true"> | |||
<i class="el-icon-plus"></i> | |||
<span>{{ $t('modelObj.model_select') }}</span> | |||
</div> | |||
<div style="display:flex;align-items:center;justify-content:center;margin-left:6px;"> | |||
<el-tooltip placement="top" effect="light"> | |||
<i class="question circle icon link" style="margin-top:-7px"></i> | |||
<div slot="content"> | |||
<div style="width:200px;text-align:center;">{{ $t('modelObj.model_suport_file_tips') }}</div> | |||
</div> | |||
</el-tooltip> | |||
</div> | |||
<el-dialog class="model-dlg" :visible.sync="dlgShow" :title="$t('modelObj.model_select')" width="1000px" :modal="true" | |||
:close-on-click-modal="false" :show-close="true" :destroy-on-close="false" :before-close="beforeClose" @open="open" | |||
@closed="closed"> | |||
<div class="dlg-content"> | |||
<div class="left-area" v-loading="dlgLoading"> | |||
<div class="model-tabs-c"> | |||
<el-tabs class="model-tabs" v-model="dlgActiveName" @tab-click="dlgTabClick"> | |||
<el-tab-pane :label="$t('modelObj.model_current_repo')" name="first"></el-tab-pane> | |||
<el-tab-pane :label="$t('modelObj.model_my')" name="second"></el-tab-pane> | |||
<el-tab-pane :label="$t('modelObj.model_public')" name="third"></el-tab-pane> | |||
<el-tab-pane :label="$t('modelObj.model_collected')" name="fourth"></el-tab-pane> | |||
</el-tabs> | |||
<el-input size="small" class="search-inp" :placeholder="$t('modelObj.model_search_placeholder')" | |||
v-model="dlgSearchValue" @keydown.enter.stop.native.prevent="inputSearch"> | |||
<div slot="suffix" class="search-inp-icon" @click="inputSearch"> | |||
<i class="el-icon-search"></i> | |||
</div> | |||
</el-input> | |||
</div> | |||
<el-tree :data="dlgModelTreeData" ref="dlgTreeRef" highlight-current show-checkbox node-key="id" | |||
:default-expanded-keys="dlgInitTreeNode" :props="dlgTreeProps" :index="10" accordion | |||
@check="onTreeCheckChange"> | |||
<span slot-scope="{ node, data }" class="slot-wrap"> | |||
<span v-if="data.parent" class="custom-tree-node"> | |||
<el-tooltip v-if="data.description" placement="top-start"> | |||
<div slot="content" class="multiple-wrap"> {{ data.description }}</div> | |||
<span class="model-title model-nowrap"> | |||
<div class="model_flex"> | |||
<span style="flex: inherit" class="model-nowrap">{{ node.label }}<span | |||
v-if="(data.version != '0.0.1' || data.new != 1)" class="model-version"> | |||
{{ data.version }} </span> | |||
</span> | |||
<img v-if="data.recommend == 1" style="margin-left: 0.4rem" src="/img/jian.svg" /> | |||
</div> | |||
</span> | |||
</el-tooltip> | |||
<span v-else class="model-title model-nowrap"> | |||
<div class="model_flex"> | |||
<span style="flex: inherit" class="model-nowrap">{{ node.label }}<span | |||
v-if="(data.version != '0.0.1' || data.new != 1)" class="model-version"> | |||
{{ data.version }} </span> | |||
</span> | |||
<img v-if="data.recommend == 1" style="margin-left: 0.4rem" src="/img/jian.svg" /> | |||
</div> | |||
</span> | |||
<span class="model-repolink model-nowrap" @click.stop="return false;"> | |||
<a :href="'/' + data.repoOwnerName + '/' + data.repoName + '/modelmanage/model_readme_tmpl?name=' + data.name" | |||
target="_blank"> | |||
{{ data.repoOwnerName }}/{{ data.repoDisplayName }} | |||
</a> | |||
</span> | |||
</span> | |||
<span v-else style="display: flex"> | |||
<span class="model-nowrap" :title="node.label"> | |||
{{ node.label }} | |||
</span> | |||
</span> | |||
</span> | |||
</el-tree> | |||
<div class="pagination-c"> | |||
<el-pagination background @current-change="dlgPageChange" :current-page="dlgPage" :page-size="dlgPageSize" | |||
layout="total, prev, pager, next" :total="dlgTotal"> | |||
</el-pagination> | |||
</div> | |||
</div> | |||
<div class="right-area"> | |||
<div class="right-title"><span>{{ $t('modelObj.model_selected') }}</span></div> | |||
<div class="right-selected-list"> | |||
<el-checkbox-group v-model="dlgSelectedModel"> | |||
<el-checkbox v-for="(item, index) in dlgSelectedModelList" :key="item.id" :label="item.id" | |||
:true-label="item.id" :title="item.name" @change="(checked) => dlgChangeSelect(checked, item)"> | |||
{{ item.name }} | |||
</el-checkbox> | |||
</el-checkbox-group> | |||
</div> | |||
<div class="right-btn-c"> | |||
<el-button type="primary" size="small" @click="confirm">{{ $t('modelObj.model_ok') }}</el-button> | |||
</div> | |||
</div> | |||
</div> | |||
</el-dialog> | |||
</div> | |||
</template> | |||
<script> | |||
const supportCheckPointFileExt = ["ckpt", "pb", "h5", "json", "pkl", "pth", "t7", "pdparams", "onnx", "pbtxt", "keras", "mlmodel", "cfg", "pt"]; | |||
export default { | |||
name: "ModelSelect", | |||
props: { | |||
title: { type: String, default: '' }, | |||
showTitle: { type: Boolean, default: true }, | |||
maxCount: { type: Number, default: 1 }, | |||
}, | |||
data() { | |||
return { | |||
required: false, | |||
userName: location.pathname.split('/')[1], | |||
repoName: location.pathname.split('/')[2], | |||
type: '1', | |||
form_model_id: '', | |||
form_model_name: '', | |||
form_model_version: '', | |||
form_pre_train_model_url: '', | |||
form_ckpt_name: '', | |||
selectList: [], | |||
dlgShow: false, | |||
dlgLoading: false, | |||
dlgActiveName: 'first', | |||
dlgSearchValue: '', | |||
dlgTreeProps: { | |||
children: "children", | |||
label: "name", | |||
}, | |||
dlgModelTreeData: [], | |||
dlgInitTreeNode: [], | |||
dlgPage: 1, | |||
dlgPageSize: 10, | |||
dlgTotal: 0, | |||
dlgSelectedModel: [], | |||
dlgSelectedModelList: [], | |||
errStatus: false, | |||
}; | |||
}, | |||
computed: { | |||
selfTitle() { | |||
return this.title || this.$t('modelObj.model_label'); | |||
} | |||
}, | |||
watch: { | |||
oriData: function (val) { }, | |||
}, | |||
methods: { | |||
$t(str, object) { | |||
const strList = str.split('.'); | |||
let obj = window.i18n || {}; | |||
let rStr = str; | |||
for (let i = 0, iLen = strList.length; i < iLen; i++) { | |||
if (typeof obj[strList[i]] == 'object') { | |||
obj = obj[strList[i]]; | |||
} | |||
if (typeof obj[strList[i]] == 'string') { | |||
rStr = obj[strList[i]]; | |||
break; | |||
} | |||
} | |||
if (object) { | |||
for (let key in object) { | |||
rStr = rStr.replace(new RegExp('\{\\s*' + key + '\\s*\}', 'g'), object[key]); | |||
} | |||
} | |||
return rStr; | |||
}, | |||
open() { | |||
this.dlgTotal = 0; | |||
this.dlgPage = 1; | |||
this.dlgSelectedModel = []; | |||
this.dlgSelectedModelList = []; | |||
for (let i = 0, iLen = this.selectList.length; i < iLen; i++) { | |||
const item = this.selectList[i]; | |||
this.dlgSelectedModel.push(item.id); | |||
this.dlgSelectedModelList.push({ | |||
...item, | |||
id: item.id, | |||
name: item.name, | |||
}); | |||
} | |||
this.searchModelData(); | |||
}, | |||
beforeClose(done) { | |||
done(); | |||
}, | |||
closed() { }, | |||
dlgTabClick(tab, event) { | |||
this.dlgTotal = 0; | |||
this.dlgPage = 1; | |||
this.searchModelData(); | |||
}, | |||
transformTreeData(data) { | |||
for (let i = 0, iLen = data.length; i < iLen; i++) { | |||
const dataI = data[i]; | |||
const _children = dataI.modelFileList || []; | |||
const children = []; | |||
dataI.parent = true; | |||
dataI.disabled = true; | |||
_children.forEach(item => { | |||
item.ModTimeNum = new Date(item.ModTime).getTime(); | |||
}) | |||
_children.sort((a, b) => a.FileName.localeCompare(b.FileName)); | |||
_children.sort((a, b) => b.ModTimeNum - a.ModTimeNum); | |||
for (let j = 0, jLen = _children.length; j < jLen; j++) { | |||
const file = _children[j]; | |||
if (file.IsDir) continue; | |||
const arr = file.FileName.split('.'); | |||
if (!supportCheckPointFileExt.includes(arr[arr.length - 1])) continue; | |||
file._modelID = dataI.id; | |||
file._modelName = dataI.name; | |||
file._modelVersion = dataI.version; | |||
file._preTrainModelUrl = dataI.path; | |||
file.name = file.FileName; | |||
file.id = `${file._modelID}|${file._modelName}|${file._modelVersion}|${file._preTrainModelUrl}|${file.name}`; | |||
children.push(file); | |||
} | |||
dataI.children = children; | |||
} | |||
return data; | |||
}, | |||
inputSearch() { | |||
this.dlgTotal = 0; | |||
this.dlgPage = 1; | |||
this.searchModelData(); | |||
}, | |||
searchModelData() { | |||
const tabName = this.dlgActiveName; | |||
const tabPrams = { | |||
'first': 4, | |||
'second': 2, | |||
'third': 1, | |||
'fourth': 3, | |||
} | |||
const params = { | |||
type: this.type, | |||
queryType: tabPrams[tabName], | |||
repoOwnerName: this.userName, | |||
repoName: this.repoName, | |||
q: this.dlgSearchValue.trim(), | |||
page: this.dlgPage, | |||
needModelFile: true, | |||
notNeedEmpty: true, | |||
}; | |||
if (params.queryType == 2 || params.queryType == 4) { | |||
params.orderBy = 'created_unix'; | |||
} | |||
this.dlgLoading = true; | |||
this.$axios.get(`/modelsquare/main_query_data`, { | |||
params: params, | |||
}).then(res => { | |||
this.dlgLoading = false; | |||
const data = res.data?.data || []; | |||
this.dlgModelTreeData = this.transformTreeData(data); | |||
this.dlgInitTreeNode = this.dlgModelTreeData[0]?.id | |||
? [this.dlgModelTreeData[0].id] | |||
: []; | |||
this.dlgTotal = parseInt(res.data?.count || 0); | |||
const setCheckedKeysList = this.dlgModelTreeData.reduce((pre, cur) => { | |||
cur.children.forEach((item) => { | |||
if (this.dlgSelectedModel.includes(item.id)) { | |||
pre.push(item.id); | |||
} | |||
}); | |||
return pre; | |||
}, []); | |||
this.$refs.dlgTreeRef.setCheckedKeys(setCheckedKeysList); | |||
}).catch(err => { | |||
this.dlgLoading = false; | |||
console.log(err); | |||
}); | |||
}, | |||
dlgChangeSelect(checked, data) { | |||
this.$refs.dlgTreeRef.setChecked(data.id, false, false); | |||
const index = this.dlgSelectedModelList.findIndex((item) => { | |||
return item.id === data.id; | |||
}); | |||
this.dlgSelectedModelList.splice(index, 1); | |||
this.dlgSelectedModel = this.dlgSelectedModelList.map(item => item.id); | |||
}, | |||
dlgPageChange(page) { | |||
this.dlgPage = page; | |||
this.searchModelData(); | |||
}, | |||
onTreeCheckChange(data) { | |||
if ( | |||
this.dlgSelectedModelList.length === 0 || | |||
this.dlgSelectedModelList.every((item) => item.id !== data.id) | |||
) { | |||
if (this.maxCount == 1) { | |||
this.dlgSelectedModelList.forEach((item) => { | |||
this.$refs.dlgTreeRef.setChecked(item.id, false, false); | |||
}); | |||
this.dlgSelectedModelList.splice(0, Infinity); | |||
this.dlgSelectedModelList.push(data); | |||
} else { | |||
if ( | |||
this.dlgSelectedModelList.some((item) => { | |||
return item._modelID !== data._modelID; | |||
}) | |||
) { | |||
this.$refs.dlgTreeRef.setChecked(data.id, false, false); | |||
this.$message.warning(this.$t('modelObj.model_should_same_model')); | |||
} else if (this.dlgSelectedModelList.length === this.maxCount) { | |||
this.$refs.dlgTreeRef.setChecked(data.id, false, false); | |||
this.$message.warning(this.$t('modelObj.model_most', { msg: this.maxCount })); | |||
} else { | |||
this.dlgSelectedModelList.push(data); | |||
} | |||
} | |||
} else { | |||
const index = this.dlgSelectedModelList.findIndex((item) => { | |||
return item.id === data.id; | |||
}); | |||
this.dlgSelectedModelList.splice(index, 1); | |||
} | |||
this.dlgSelectedModel = this.dlgSelectedModelList.map((item) => { | |||
return item.id; | |||
}); | |||
}, | |||
confirm() { | |||
const len = this.dlgSelectedModelList.length; | |||
this.selectList.splice(0, Infinity); | |||
if (len) { | |||
const ckptNames = []; | |||
for (let i = 0; i < len; i++) { | |||
const item = this.dlgSelectedModelList[i]; | |||
this.form_model_id = item._modelID; | |||
this.form_model_name = item._modelName; | |||
this.form_model_version = item._modelVersion; | |||
this.form_pre_train_model_url = item._preTrainModelUrl; | |||
ckptNames.push(item.name); | |||
this.selectList.push({ ...item }); | |||
} | |||
this.form_ckpt_name = ckptNames.join(';'); | |||
} else { | |||
this.form_model_id = ''; | |||
this.form_model_name = ''; | |||
this.form_model_version = ''; | |||
this.form_pre_train_model_url = ''; | |||
this.form_ckpt_name = ''; | |||
} | |||
if (this.selectList.length) { | |||
this.errStatus = false; | |||
} | |||
this.dlgShow = false; | |||
}, | |||
check() { | |||
if (!this.selectList.length) { | |||
this.errStatus = true; | |||
return false; | |||
} | |||
this.errStatus = false; | |||
return true; | |||
}, | |||
}, | |||
beforeMount() { }, | |||
mounted() { | |||
const dataEl = this.$el.previousElementSibling; | |||
if (dataEl) { | |||
const dataset = dataEl.dataset; | |||
if (dataset.modelId) { | |||
this.form_model_id = dataset.modelId; | |||
this.form_model_name = dataset.modelName; | |||
this.form_model_version = dataset.modelVersion; | |||
this.form_pre_train_model_url = dataset.preTrainModelUrl; | |||
this.form_ckpt_name = dataset.ckptName; | |||
const file = { | |||
_modelID: dataset.modelId, | |||
_modelName: dataset.modelName, | |||
_modelVersion: dataset.modelVersion, | |||
_preTrainModelUrl: dataset.preTrainModelUrl, | |||
name: dataset.ckptName, | |||
}; | |||
file.id = `${file._modelID}|${file._modelName}|${file._modelVersion}|${file._preTrainModelUrl}|${file.name}`; | |||
this.selectList.push(file); | |||
} | |||
if (dataset.required) { | |||
this.required = true; | |||
} | |||
} | |||
}, | |||
}; | |||
</script> | |||
<style scoped lang="less"> | |||
.model-select { | |||
display: flex; | |||
margin-bottom: 28px; | |||
.title { | |||
width: 130px; | |||
text-align: right; | |||
margin-right: 24px; | |||
color: #101010; | |||
font-size: 14px; | |||
align-items: center; | |||
display: flex; | |||
justify-content: flex-end; | |||
.required { | |||
position: relative; | |||
&::after { | |||
position: absolute; | |||
content: "*"; | |||
top: -3px; | |||
right: -10px; | |||
color: red; | |||
} | |||
} | |||
} | |||
.content { | |||
display: inline-block; | |||
width: 48.5%; | |||
margin-right: 5px; | |||
.model-list-c { | |||
min-height: 36px; | |||
border-radius: 4px; | |||
border: 1px solid #DCDFE6; | |||
box-sizing: border-box; | |||
color: #606266; | |||
padding: 5px 15px; | |||
.model-item { | |||
line-height: 26px; | |||
font-size: 14px; | |||
color: rgba(0, 0, 0, 0.87); | |||
} | |||
.model-item-model { | |||
color: rgba(136, 136, 136, 1); | |||
} | |||
.model-item-file { | |||
padding-left: 5px; | |||
} | |||
.model-item-placeholder { | |||
height: 26px; | |||
line-height: 26px; | |||
color: rgba(0, 0, 0, 0.4); | |||
opacity: 0.45 !important; | |||
font-size: 14px; | |||
} | |||
&.error { | |||
color: #9f3a38; | |||
background: #fff6f6; | |||
border-color: #e0b4b4; | |||
} | |||
} | |||
} | |||
.btn-select { | |||
display: flex; | |||
justify-content: center; | |||
align-items: center; | |||
cursor: pointer; | |||
color: rgb(3, 102, 214); | |||
i { | |||
margin-right: 4px; | |||
} | |||
} | |||
} | |||
.model-dlg { | |||
/deep/.el-dialog__body { | |||
padding-top: 0; | |||
} | |||
.dlg-content { | |||
display: flex; | |||
min-height: 300px; | |||
.left-area { | |||
flex: 1; | |||
margin-right: 15px; | |||
border-right: 1px solid rgb(245, 245, 246); | |||
padding-right: 15px; | |||
position: relative; | |||
overflow: hidden; | |||
.model-tabs-c { | |||
display: flex; | |||
align-items: center; | |||
.model-tabs { | |||
flex: 1; | |||
overflow: hidden; | |||
margin-right: 5px; | |||
} | |||
.search-inp { | |||
overflow: hidden; | |||
width: 200px; | |||
z-index: 5; | |||
position: relative; | |||
margin-top: -10px; | |||
.search-inp-icon { | |||
height: 100%; | |||
display: flex; | |||
justify-content: center; | |||
align-items: center; | |||
width: 22px; | |||
cursor: pointer; | |||
} | |||
} | |||
} | |||
.pagination-c { | |||
margin-top: 25px; | |||
text-align: center; | |||
} | |||
} | |||
.right-area { | |||
width: 300px; | |||
padding-right: 30px; | |||
position: relative; | |||
.right-title { | |||
font-size: 14px; | |||
height: 40px; | |||
text-align: left; | |||
color: rgb(0, 102, 255); | |||
line-height: 40px; | |||
} | |||
.right-selected-list { | |||
margin: 14px 0; | |||
} | |||
.right-btn-c { | |||
text-align: right; | |||
position: absolute; | |||
bottom: 15px; | |||
width: 100%; | |||
padding-right: 30px; | |||
/deep/ .el-button { | |||
background: rgb(56, 158, 13); | |||
color: rgb(255, 255, 255); | |||
border: 1px solid rgb(56, 158, 13); | |||
} | |||
} | |||
} | |||
} | |||
} | |||
.el-tree { | |||
max-height: 400px; | |||
overflow-y: auto; | |||
overflow-x: hidden; | |||
position: relative; | |||
cursor: default; | |||
background: #fff; | |||
color: #606266; | |||
font-family: SourceHanSansSC-medium; | |||
} | |||
.custom-tree-node { | |||
display: flex; | |||
align-items: center; | |||
justify-content: space-between; | |||
} | |||
.custom-tree-node .model-title { | |||
font-size: 14px; | |||
color: #101010; | |||
font-weight: 600; | |||
flex: 1; | |||
} | |||
.custom-tree-node .model-repolink { | |||
flex: 1; | |||
text-align: right; | |||
font-size: 12px; | |||
} | |||
.el-tree /deep/ .el-tree-node__content { | |||
height: 40px; | |||
background-color: #f5f5f6; | |||
} | |||
.el-tree /deep/ .el-tree-node__children .el-tree-node__content { | |||
height: 30px; | |||
background-color: #fff; | |||
line-height: 20px; | |||
font-size: 12px; | |||
} | |||
/deep/ .el-checkbox-group .el-checkbox { | |||
max-width: 100%; | |||
min-width: 80%; | |||
} | |||
/deep/ .el-checkbox-group .el-checkbox .el-checkbox__label { | |||
max-width: 100%; | |||
overflow: hidden; | |||
vertical-align: middle; | |||
text-overflow: ellipsis; | |||
} | |||
.model-nowrap { | |||
overflow: hidden; | |||
text-overflow: ellipsis; | |||
} | |||
.slot-wrap { | |||
flex: 1; | |||
padding-right: 2rem; | |||
max-width: 93%; | |||
} | |||
.multiple-wrap { | |||
-webkit-line-clamp: 3; | |||
-webkit-box-orient: vertical; | |||
display: -webkit-box; | |||
max-width: 400px; | |||
overflow: hidden; | |||
} | |||
.unzip-failed { | |||
margin-left: 1rem; | |||
color: red; | |||
} | |||
.zip-loading { | |||
margin-left: 1rem; | |||
color: #fcca00; | |||
} | |||
.model-search-vue { | |||
z-index: 9999; | |||
position: absolute; | |||
right: 31%; | |||
height: 30px; | |||
top: 6px; | |||
} | |||
.select-model-label { | |||
max-width: 100%; | |||
overflow: hidden; | |||
text-overflow: ellipsis; | |||
margin-right: 1rem; | |||
white-space: nowrap; | |||
} | |||
.model_flex { | |||
display: flex; | |||
align-items: center; | |||
} | |||
.model-version { | |||
margin-left: 4px; | |||
border-radius: 4px; | |||
color: rgba(16, 16, 16, 0.8); | |||
border-radius: 4px; | |||
font-size: 12px; | |||
background: rgba(220, 220, 220, 0.8); | |||
padding: 1px 3px; | |||
} | |||
</style> |
@@ -404,31 +404,33 @@ export default async function initCloudrain() { | |||
const versionName = this.dataset.version; | |||
stopVersion(versionName, ID, repoPath); | |||
}); | |||
function getModelInfo(repoPath, modelName, versionName, jobName) { | |||
function getModelInfo(repoPath, modelId, modelName, versionName, jobName) { | |||
$.get( | |||
`${repoPath}/modelmanage/show_model_info_api?name=${modelName}`, | |||
`/api/v1/repos${repoPath}/modelmanage/query_model_byId?id=${modelId}`, | |||
(data) => { | |||
if (data.length === 0) { | |||
$(`#${jobName}`).popup("toggle"); | |||
if (data && data.id == modelId) { | |||
location.href = `${repoPath}/modelmanage/model_readme_tmpl?name=${data.name}`; | |||
} else { | |||
let versionData = data.filter((item) => { | |||
return item.version === versionName; | |||
}); | |||
if (versionData.length == 0) { | |||
$(`#${jobName}`).popup("toggle"); | |||
} else { | |||
location.href = `${repoPath}/modelmanage/show_model_info?name=${modelName}`; | |||
} | |||
} | |||
} | |||
); | |||
).catch(err => { | |||
console.log(err); | |||
$(`#${jobName}`).popup("toggle"); | |||
}); | |||
} | |||
$(".goto_modelmanage").click(function () { | |||
const repoPath = this.dataset.repopath; | |||
let repoPath = this.dataset.repopath; | |||
const modelId = this.dataset.modelid; | |||
const modelName = this.dataset.modelname; | |||
const versionName = this.dataset.version; | |||
const jobName = this.dataset.jobname; | |||
getModelInfo(repoPath, modelName, versionName, jobName); | |||
const modelRepoOwnerName = this.dataset.modelrepoownername; | |||
const modelRepoName = this.dataset.modelreponame; | |||
if (modelRepoOwnerName && modelRepoName) { | |||
repoPath = `/${modelRepoOwnerName}/${modelRepoName}` | |||
} | |||
getModelInfo(repoPath, modelId, modelName, versionName, jobName); | |||
}); | |||
function debugAgain(ID, debugUrl, redirect_to) { | |||
if ($("#" + ID + "-text").text() === "RUNNING") { | |||
@@ -136,6 +136,21 @@ export const i18nVue = { | |||
openi: '启智', | |||
c2net: '智算网络', | |||
}, | |||
modelObj: { | |||
model_label: '选择模型', | |||
model_select_placeholder: '选择模型文件', | |||
model_select: '选择模型', | |||
model_current_repo: '本项目', | |||
model_my: '我的模型', | |||
model_public: '公开模型', | |||
model_collected: '我收藏的', | |||
model_search_placeholder: '搜索模型名称...', | |||
model_selected: '已选模型文件', | |||
model_ok: '确定', | |||
model_most: '最多不超过 {msg} 个文件', | |||
model_should_same_model: '选择同一模型下的文件', | |||
model_suport_file_tips: '模型文件支持的格式为 [ckpt, pb, h5, json, pkl, pth, t7, pdparams, onnx, pbtxt, keras, mlmodel, cfg, pt]', | |||
}, | |||
}, | |||
US: { | |||
@@ -278,5 +293,20 @@ export const i18nVue = { | |||
openi: 'OpenI', | |||
c2net: 'C²NET', | |||
}, | |||
modelObj: { | |||
model_label: 'Select Model', | |||
model_select_placeholder: 'Please select model file', | |||
model_select: 'Select Model', | |||
model_current_repo: 'Current repository', | |||
model_my: 'My models', | |||
model_public: 'Public models', | |||
model_collected: 'My collection', | |||
model_search_placeholder: 'Search model name...', | |||
model_selected: 'Selected model file', | |||
model_ok: 'OK', | |||
model_most: 'Up to {msg} files.', | |||
model_should_same_model: 'Select the files should in the same model.', | |||
model_suport_file_tips: 'The supported format of the model file is [ckpt, pb, h5, json, pkl, pth, t7, pdparams, onnx, pbtxt, keras, mlmodel, cfg, pt]', | |||
}, | |||
}, | |||
}; |
@@ -51,6 +51,7 @@ import initCloudrainSow from "./features/cloudbrainShow.js"; | |||
import initImage from "./features/images.js"; | |||
import selectDataset from "./components/dataset/selectDataset.vue"; | |||
import referenceDataset from "./components/dataset/referenceDataset.vue"; | |||
import ModelSelect from "./components/model/ModelSelect.vue"; | |||
// import $ from 'jquery.js' | |||
import router from "./router/index.js"; | |||
import { Message } from "element-ui"; | |||
@@ -2985,6 +2986,7 @@ $(document).ready(async () => { | |||
initVueIde(); | |||
initVueWxAutorize(); | |||
initVueselectDataset(); | |||
initVueModelSelect(); | |||
initVuereferenceDataset(); | |||
initTeamSettings(); | |||
initCtrlEnterSubmit(); | |||
@@ -4643,6 +4645,14 @@ function initVuereferenceDataset() { | |||
render: (h) => h(referenceDataset), | |||
}); | |||
} | |||
function initVueModelSelect() { | |||
const el = document.getElementById("select-multi-model"); | |||
if (!el) return; | |||
new Vue({ | |||
el: el, | |||
render: (h) => h(ModelSelect), | |||
}); | |||
} | |||
window.timeAddManual = function () { | |||
$(".mini.modal") | |||
.modal({ | |||
@@ -195,6 +195,7 @@ | |||
let flagModel = $(".cloudbrain-type").data("flag-model"); | |||
// 获取模型列表和模型名称对应的模型版本 | |||
$(document).ready(function () { | |||
return; // 改用模型选择组件了 | |||
if (!flagModel) return; | |||
else { | |||
$.get( | |||
@@ -1,5 +1,6 @@ | |||
import service from "../service"; | |||
import Qs from 'qs'; | |||
import { param } from "jquery"; | |||
// 保存本地模型 | |||
export const saveLocalModel = (data) => { | |||
@@ -114,3 +115,51 @@ export const setCompleteMultipart = (data) => { | |||
data: Qs.stringify(data), | |||
}); | |||
}; | |||
// markdown预览 | |||
// data: { userName, repoName, context, text } | |||
export const getMarkdownPreview = (data) => { | |||
return service({ | |||
url: `/api/v1/repos/${data.repoOwnerName}/${data.repoName}/markdown`, | |||
method: 'post', | |||
headers: { 'Content-type': 'application/x-www-form-urlencoded' }, | |||
params: {}, | |||
data: Qs.stringify({ | |||
mode: 'gfm', | |||
context: '', | |||
text: data.text, | |||
}), | |||
}); | |||
} | |||
// 获取模型介绍数据 | |||
export const getModelIntroduce = (params) => { | |||
return service({ | |||
url: `${params.repo}/modelmanage/model_readme_data`, | |||
method: 'get', | |||
params: { id: params.id }, | |||
}); | |||
} | |||
// 设置模型介绍数据 | |||
export const setModelIntroduce = (data) => { | |||
return service({ | |||
url: `${data.repo}/modelmanage/model_readme_data`, | |||
method: 'post', | |||
headers: { 'Content-type': 'application/x-www-form-urlencoded' }, | |||
params: {}, | |||
data: Qs.stringify({ | |||
id: data.id, | |||
content: data.content, | |||
}) | |||
}); | |||
} | |||
// 获取模型演化图谱数据 | |||
export const getModelEvolutionMap = (params) => { | |||
return service({ | |||
url: `${params.repo}/modelmanage/model_evolution_map_data`, | |||
method: 'get', | |||
params: { id: params.id }, | |||
}); | |||
} |
@@ -0,0 +1,44 @@ | |||
import service from "../service"; | |||
import Qs from 'qs'; | |||
// 获取模型广场列表 | |||
// q,engine,resource,label,recommend-bool | |||
// queryType-1为查公开模型,2:我的模型,3:我收藏的模型, 4: 本项目 | |||
// repoName, repoOwnerName, needModelFile-结果是否带文件 | |||
// page,pageSize | |||
export const getModelList = (params) => { | |||
return service({ | |||
url: '/modelsquare/main_query_data', | |||
method: 'get', | |||
params, | |||
}); | |||
} | |||
// 获取模型广场筛选项 | |||
export const getModelSqaureFilters = () => { | |||
return service({ | |||
url: '/modelsquare/main_query_label', | |||
method: 'get', | |||
params: {}, | |||
}); | |||
} | |||
// 模型收藏/取消收藏 | |||
// data: id, collected-为true表示收藏此模型,为false表示取消收藏此模型 | |||
export const setModelFav = (data) => { | |||
return service({ | |||
url: '/modelsquare/modify_model_collect', | |||
method: 'put', | |||
data: Qs.stringify(data), | |||
}); | |||
} | |||
// 模型推荐/取消推荐 | |||
// data: id, recommend-为true表示推荐此模型,为false表示取消推荐此模型 | |||
export const setModelRecommend = (data) => { | |||
return service({ | |||
url: '/modelsquare/modify_model_recommend', | |||
method: 'put', | |||
data: Qs.stringify(data), | |||
}); | |||
} |
@@ -0,0 +1,22 @@ | |||
<template> | |||
<div class="ui container center" style="min-height:80%;"> | |||
<div class="ui basic very padded segment"> | |||
<img class="ui centered medium image" src="/img/icon-404@2x.png"> | |||
<h2>{{ $t('emptyPage') }} </h2> | |||
<p v-html="$t('emptyPageDescr')"></p> | |||
</div> | |||
</div> | |||
</template> | |||
<script> | |||
export default { | |||
name: "NotFound", | |||
props: { | |||
visible: { type: Boolean, default: false }, | |||
}, | |||
data() { | |||
return {}; | |||
} | |||
}; | |||
</script> | |||
<style scoped lang="less"></style> |
@@ -0,0 +1,563 @@ | |||
<template> | |||
<div class="model-select"> | |||
<div class="title" v-if="showTitle"><span :class="required ? 'required' : ''">{{ selfTitle }}</span></div> | |||
<div class="content"> | |||
<div class="model-list-c" :class="errStatus ? 'error' : ''"> | |||
<div class="model-item" v-for="(item, index) in selectList" :key="item.id"> | |||
{{ item.name }}; | |||
</div> | |||
<div v-if="selectList.length == 0" class="model-item-placeholder"> | |||
{{ $t('modelObj.model_select_placeholder') }} | |||
</div> | |||
</div> | |||
<div class="btn-select" @click="dlgShow = true"> | |||
<i class="el-icon-plus"></i> | |||
<span>{{ $t('modelObj.model_select') }}</span> | |||
</div> | |||
</div> | |||
<el-dialog class="model-dlg" :visible.sync="dlgShow" :title="$t('modelObj.model_select')" width="1000px" :modal="true" | |||
:close-on-click-modal="false" :show-close="true" :destroy-on-close="false" :before-close="beforeClose" @open="open" | |||
@closed="closed"> | |||
<div class="dlg-content"> | |||
<div class="left-area" v-loading="dlgLoading"> | |||
<div class="model-tabs-c"> | |||
<el-tabs class="model-tabs" v-model="dlgActiveName" @tab-click="dlgTabClick"> | |||
<el-tab-pane :label="$t('modelObj.model_current_repo')" name="first"></el-tab-pane> | |||
<el-tab-pane :label="$t('modelObj.model_my')" name="second"></el-tab-pane> | |||
<el-tab-pane :label="$t('modelObj.model_public')" name="third"></el-tab-pane> | |||
<el-tab-pane :label="$t('modelObj.model_collected')" name="fourth"></el-tab-pane> | |||
</el-tabs> | |||
<el-input class="search-inp" :placeholder="$t('modelObj.model_search_placeholder')" v-model="dlgSearchValue" | |||
@keyup.enter.native="inputSearch"> | |||
<div slot="suffix" class="search-inp-icon" @click="inputSearch"> | |||
<i class="el-icon-search"></i> | |||
</div> | |||
</el-input> | |||
</div> | |||
<el-tree :data="dlgModelTreeData" ref="dlgTreeRef" highlight-current show-checkbox node-key="id" | |||
:default-expanded-keys="dlgInitTreeNode" :props="dlgTreeProps" :index="10" accordion | |||
@check="onTreeCheckChange"> | |||
<span slot-scope="{ node, data }" class="slot-wrap"> | |||
<span v-if="data.parent" class="custom-tree-node"> | |||
<el-tooltip v-if="data.description" placement="top-start"> | |||
<div slot="content" class="multiple-wrap"> {{ data.description }}</div> | |||
<span class="model-title model-nowrap"> | |||
<div class="model_flex"> | |||
<span style="flex: inherit" class="model-nowrap">{{ node.label }}</span> | |||
<img v-if="data.recommend == 1" style="margin-left: 0.4rem" src="/img/jian.svg" /> | |||
</div> | |||
</span> | |||
</el-tooltip> | |||
<span v-else class="model-title model-nowrap"> | |||
<div class="model_flex"> | |||
<span style="flex: inherit" class="model-nowrap">{{ node.label }}</span> | |||
<img v-if="data.recommend == 1" style="margin-left: 0.4rem" src="/img/jian.svg" /> | |||
</div> | |||
</span> | |||
<span class="model-repolink model-nowrap" @click.stop="return false;"> | |||
<a :href="'/' + data.repoOwnerName + '/' + data.repoName + '/modelmanage/model_readme_tmpl?name=' + data.name" | |||
target="_blank"> | |||
{{ data.repoOwnerName }}/{{ data.repoName }} | |||
</a> | |||
</span> | |||
</span> | |||
<span v-else style="display: flex"> | |||
<span class="model-nowrap" :title="node.label"> | |||
{{ node.label }} | |||
</span> | |||
</span> | |||
</span> | |||
</el-tree> | |||
<div class="pagination-c"> | |||
<el-pagination background @current-change="dlgPageChange" :current-page="dlgPage" :page-size="dlgPageSize" | |||
layout="total, prev, pager, next" :total="dlgTotal"> | |||
</el-pagination> | |||
</div> | |||
</div> | |||
<div class="right-area"> | |||
<div class="right-title"><span>{{ $t('modelObj.model_selected') }}</span></div> | |||
<div class="right-selected-list"> | |||
<el-checkbox-group v-model="dlgSelectedModel"> | |||
<el-checkbox v-for="(item, index) in dlgSelectedModelList" :key="item.id" :label="item.id" | |||
:true-label="item.id" :title="item.name" @change="(checked) => dlgChangeSelect(checked, item)"> | |||
{{ item.name }} | |||
</el-checkbox> | |||
</el-checkbox-group> | |||
</div> | |||
<div class="right-btn-c"> | |||
<el-button type="primary" @click="confirm">{{ $t('modelObj.model_ok') }}</el-button> | |||
</div> | |||
</div> | |||
</div> | |||
</el-dialog> | |||
</div> | |||
</template> | |||
<script> | |||
import { getModelList } from '~/apis/modules/modelsquare'; | |||
export default { | |||
name: "ModelSelect", | |||
props: { | |||
title: { type: String, default: '' }, | |||
showTitle: { type: Boolean, default: true }, | |||
required: { type: Boolean, default: true }, | |||
type: { type: String, default: '' }, | |||
maxCount: { type: Number, default: 5 }, | |||
userName: { type: String, default: '' }, | |||
repoName: { type: String, default: '' }, | |||
oriData: { type: Array, default: () => [] }, | |||
}, | |||
data() { | |||
return { | |||
selectList: [], | |||
dlgShow: false, | |||
dlgLoading: false, | |||
dlgActiveName: 'first', | |||
dlgSearchValue: '', | |||
dlgTreeProps: { | |||
children: "children", | |||
label: "name", | |||
}, | |||
dlgModelTreeData: [], | |||
dlgInitTreeNode: [], | |||
dlgPage: 1, | |||
dlgPageSize: 10, | |||
dlgTotal: 0, | |||
dlgSelectedModel: [], | |||
dlgSelectedModelList: [], | |||
exceedSize: 0, | |||
errStatus: false, | |||
}; | |||
}, | |||
computed: { | |||
selfTitle() { | |||
return this.title || this.$t('modelObj.model_label'); | |||
} | |||
}, | |||
watch: { | |||
oriData: function (val) { }, | |||
}, | |||
methods: { | |||
open() { | |||
this.dlgTotal = 0; | |||
this.dlgPage = 1; | |||
this.dlgSelectedModel = []; | |||
this.dlgSelectedModelList = []; | |||
for (let i = 0, iLen = this.selectList.length; i < iLen; i++) { | |||
const item = this.selectList[i]; | |||
this.dlgSelectedModel.push(item.id); | |||
this.dlgSelectedModelList.push({ | |||
id: item.id, | |||
name: item.name, | |||
}); | |||
} | |||
this.searchModelData(); | |||
}, | |||
beforeClose(done) { | |||
done(); | |||
}, | |||
closed() { }, | |||
dlgTabClick(tab, event) { | |||
this.dlgTotal = 0; | |||
this.dlgPage = 1; | |||
this.searchModelData(); | |||
}, | |||
transformTreeData(data) { | |||
for (let i = 0, iLen = data.length; i < iLen; i++) { | |||
const dataI = data[i]; | |||
const children = dataI.modelFileList || []; | |||
for (let j = 0, jLen = children.length; j < jLen; j++) { | |||
const file = children[j]; | |||
file._modelID = dataI.id; | |||
file._modelName = dataI.name; | |||
file._modelVersion = dataI.version; | |||
file._preTrainModelUrl = dataI.path; | |||
file.name = file.FileName; | |||
file.id = `${file._modelID}|${file._modelName}|${file._modelVersion}|${file._preTrainModelUrl}|${file.name}`; | |||
} | |||
dataI.children = children; | |||
} | |||
return data; | |||
}, | |||
inputSearch() { | |||
this.dlgTotal = 0; | |||
this.dlgPage = 1; | |||
this.searchModelData(); | |||
}, | |||
searchModelData() { | |||
const tabName = this.dlgActiveName; | |||
const tabPrams = { | |||
'first': 4, | |||
'second': 2, | |||
'third': 1, | |||
'fourth': 3, | |||
} | |||
const params = { | |||
type: this.type, | |||
queryType: tabPrams[tabName], | |||
repoOwnerName: this.userName, | |||
repoName: this.repoName, | |||
q: this.dlgSearchValue.trim(), | |||
page: this.dlgPage, | |||
needModelFile: true, | |||
notNeedEmpty: true, | |||
}; | |||
this.dlgLoading = true; | |||
getModelList(params).then(res => { | |||
this.dlgLoading = false; | |||
const data = res.data?.data || []; | |||
this.dlgModelTreeData = this.transformTreeData(data); | |||
console.log(this.dlgModelTreeData); | |||
this.dlgInitTreeNode = this.dlgModelTreeData[0]?.id | |||
? [this.dlgModelTreeData[0].id] | |||
: []; | |||
this.dlgTotal = parseInt(res.data?.count || 0); | |||
const setCheckedKeysList = this.dlgModelTreeData.reduce((pre, cur) => { | |||
cur.children.forEach((item) => { | |||
if (this.dlgSelectedModel.includes(item.id)) { | |||
pre.push(item.id); | |||
} | |||
}); | |||
return pre; | |||
}, []); | |||
this.$refs.dlgTreeRef.setCheckedKeys(setCheckedKeysList); | |||
}).catch(err => { | |||
this.dlgLoading = false; | |||
console.log(err); | |||
}); | |||
}, | |||
dlgChangeSelect(checked, data) { | |||
this.$refs.dlgTreeRef.setChecked(data.id, false, false); | |||
const index = this.dlgSelectedModelList.findIndex((item) => { | |||
return item.id === data.id; | |||
}); | |||
this.dlgSelectedModelList.splice(index, 1); | |||
this.dlgSelectedModel = this.dlgSelectedModelList.map(item => item.id); | |||
}, | |||
dlgPageChange(page) { | |||
this.dlgPage = page; | |||
this.searchModelData(); | |||
}, | |||
onTreeCheckChange(data) { | |||
if ( | |||
this.dlgSelectedModelList.length === 0 || | |||
this.dlgSelectedModelList.every((item) => item.id !== data.id) | |||
) { | |||
/*if ( | |||
this.dlgSelectedModelList.some((item) => { | |||
return item.name.split(".")[0] === data.name.split(".")[0]; | |||
}) | |||
) { | |||
this.$refs.dlgTreeRef.setChecked(data.id, false, false); | |||
this.$message.warning(this.$t('modelObj.model_not_equal_file')); | |||
} else */ | |||
if (this.dlgSelectedModelList.length === this.maxCount) { | |||
this.$refs.dlgTreeRef.setChecked(data.id, false, false); | |||
this.$message.error(this.$t('modelObj.model_most', { msg: this.maxCount })); | |||
} else { | |||
this.dlgSelectedModelList.push(data); | |||
} | |||
} else { | |||
const index = this.dlgSelectedModelList.findIndex((item) => { | |||
return item.id === data.id; | |||
}); | |||
this.dlgSelectedModelList.splice(index, 1); | |||
} | |||
this.dlgSelectedModel = this.dlgSelectedModelList.map((item) => { | |||
return item.id; | |||
}); | |||
}, | |||
confirm() { | |||
const ids = this.dlgSelectedModelList.map(item => item.id); | |||
const names = this.dlgSelectedModelList.map(item => item.name); | |||
this.selectList.splice(0, Infinity); | |||
for (let i = 0, iLen = ids.length; i < iLen; i++) { | |||
this.selectList.push({ | |||
id: ids[i], | |||
name: names[i] | |||
}); | |||
} | |||
if (this.selectList.length) { | |||
this.errStatus = false; | |||
} | |||
this.dlgShow = false; | |||
}, | |||
check() { | |||
if (!this.selectList.length) { | |||
this.errStatus = true; | |||
return false; | |||
} | |||
this.errStatus = false; | |||
return true; | |||
}, | |||
}, | |||
beforeMount() { } | |||
}; | |||
</script> | |||
<style scoped lang="less"> | |||
.model-select { | |||
display: flex; | |||
margin-bottom: 28px; | |||
.title { | |||
width: 200px; | |||
text-align: right; | |||
margin-right: 24px; | |||
color: #101010; | |||
font-size: 14px; | |||
display: flex; | |||
justify-content: flex-end; | |||
padding-top: 6px; | |||
.required { | |||
position: relative; | |||
&::after { | |||
position: absolute; | |||
content: "*"; | |||
top: -3px; | |||
right: -10px; | |||
color: red; | |||
} | |||
} | |||
} | |||
.content { | |||
flex: 1; | |||
display: flex; | |||
.model-list-c { | |||
margin-right: 5px; | |||
flex: 1; | |||
min-height: 32px; | |||
border-radius: 4px; | |||
border: 1px solid #DCDFE6; | |||
box-sizing: border-box; | |||
color: #606266; | |||
padding: 0 15px; | |||
.model-item { | |||
line-height: 32px; | |||
font-size: 13px; | |||
} | |||
.model-item-placeholder { | |||
line-height: 32px; | |||
color: rgba(0, 0, 0, 0.6); | |||
opacity: 0.45 !important; | |||
font-size: 13px; | |||
} | |||
&.error { | |||
color: #9f3a38; | |||
background: #fff6f6; | |||
border-color: #e0b4b4; | |||
} | |||
} | |||
.btn-select { | |||
display: flex; | |||
justify-content: center; | |||
align-items: center; | |||
cursor: pointer; | |||
color: rgb(3, 102, 214); | |||
i { | |||
margin-right: 2px; | |||
} | |||
} | |||
} | |||
} | |||
.model-dlg { | |||
/deep/.el-dialog__body { | |||
padding-top: 0; | |||
} | |||
.dlg-content { | |||
display: flex; | |||
min-height: 300px; | |||
.left-area { | |||
flex: 1; | |||
margin-right: 15px; | |||
border-right: 1px solid rgb(245, 245, 246); | |||
padding-right: 15px; | |||
position: relative; | |||
overflow: hidden; | |||
.model-tabs-c { | |||
display: flex; | |||
align-items: center; | |||
.model-tabs { | |||
flex: 1; | |||
overflow: hidden; | |||
margin-right: 5px; | |||
} | |||
.search-inp { | |||
overflow: hidden; | |||
width: 200px; | |||
z-index: 5; | |||
position: relative; | |||
margin-top: -10px; | |||
.search-inp-icon { | |||
height: 100%; | |||
display: flex; | |||
justify-content: center; | |||
align-items: center; | |||
width: 22px; | |||
cursor: pointer; | |||
} | |||
} | |||
} | |||
.pagination-c { | |||
margin-top: 25px; | |||
text-align: center; | |||
} | |||
} | |||
.right-area { | |||
width: 300px; | |||
padding-right: 30px; | |||
position: relative; | |||
.right-title { | |||
font-size: 14px; | |||
height: 40px; | |||
text-align: left; | |||
color: rgb(0, 102, 255); | |||
line-height: 40px; | |||
} | |||
.right-selected-list { | |||
margin: 14px 0; | |||
} | |||
.right-btn-c { | |||
text-align: right; | |||
position: absolute; | |||
bottom: 15px; | |||
width: 100%; | |||
padding-right: 30px; | |||
} | |||
} | |||
} | |||
} | |||
.el-tree { | |||
max-height: 400px; | |||
overflow-y: auto; | |||
overflow-x: hidden; | |||
position: relative; | |||
cursor: default; | |||
background: #fff; | |||
color: #606266; | |||
font-family: SourceHanSansSC-medium; | |||
} | |||
.custom-tree-node { | |||
display: flex; | |||
align-items: center; | |||
justify-content: space-between; | |||
} | |||
.custom-tree-node .model-title { | |||
font-size: 14px; | |||
color: #101010; | |||
font-weight: 600; | |||
flex: 1; | |||
} | |||
.custom-tree-node .model-repolink { | |||
flex: 1; | |||
text-align: right; | |||
font-size: 12px; | |||
} | |||
.el-tree /deep/ .el-tree-node__content { | |||
height: 40px; | |||
background-color: #f5f5f6; | |||
} | |||
.el-tree /deep/ .el-tree-node__children .el-tree-node__content { | |||
height: 30px; | |||
background-color: #fff; | |||
line-height: 20px; | |||
font-size: 12px; | |||
} | |||
/deep/ .el-checkbox-group .el-checkbox { | |||
max-width: 100%; | |||
min-width: 80%; | |||
} | |||
/deep/ .el-checkbox-group .el-checkbox .el-checkbox__label { | |||
max-width: 100%; | |||
overflow: hidden; | |||
vertical-align: middle; | |||
text-overflow: ellipsis; | |||
} | |||
.model-nowrap { | |||
overflow: hidden; | |||
text-overflow: ellipsis; | |||
} | |||
.slot-wrap { | |||
flex: 1; | |||
padding-right: 2rem; | |||
max-width: 93%; | |||
} | |||
.multiple-wrap { | |||
-webkit-line-clamp: 3; | |||
-webkit-box-orient: vertical; | |||
display: -webkit-box; | |||
max-width: 400px; | |||
overflow: hidden; | |||
} | |||
.unzip-failed { | |||
margin-left: 1rem; | |||
color: red; | |||
} | |||
.zip-loading { | |||
margin-left: 1rem; | |||
color: #fcca00; | |||
} | |||
.model-search-vue { | |||
z-index: 9999; | |||
position: absolute; | |||
right: 31%; | |||
height: 30px; | |||
top: 6px; | |||
} | |||
.select-model-label { | |||
max-width: 100%; | |||
overflow: hidden; | |||
text-overflow: ellipsis; | |||
margin-right: 1rem; | |||
white-space: nowrap; | |||
} | |||
.model_flex { | |||
display: flex; | |||
align-items: center; | |||
} | |||
</style> |
@@ -14,6 +14,11 @@ const en = { | |||
edit: 'Edit', | |||
delete: 'Delete', | |||
tips: 'Tips', | |||
expandMore: 'Expand More', | |||
goBack: 'Go back', | |||
star: 'Star', | |||
unStar: 'UnStar', | |||
submit: 'Submit', | |||
accomplishTask: 'Accomplish Task', | |||
adminOperate: 'Administrator Operation', | |||
@@ -22,6 +27,7 @@ const en = { | |||
succeeded: 'Succeeded', | |||
debugTask: 'Debug Task', | |||
trainTask: 'Train Task', | |||
trainDuration: "Train task duration", | |||
inferenceTask: 'Inference Task', | |||
benchmarkTask: 'Benchmark Task', | |||
createPublicProject: 'Create Public Projects', | |||
@@ -82,6 +88,9 @@ const en = { | |||
noPointGainRecord: 'No Point Earn Record Yet', | |||
noPointConsumeRecord: 'No Point Consume Record Yet', | |||
emptyPage: 'Request forbidden by administrative rules', | |||
emptyPageDescr: 'The page you are trying to reach either <strong>does not exist</strong> or <strong>you are not authorized</strong> to view it.', | |||
resourcesManagement: { | |||
OpenI: 'OpenI', | |||
C2Net: 'C2Net', | |||
@@ -236,12 +245,17 @@ const en = { | |||
createModel: 'Create Model', | |||
importLocalModel: 'Import Local Model', | |||
importOnlineModel: 'Import Online Model', | |||
modelInfo: 'Model information', | |||
modelBriefIntro: 'Model brief introduction', | |||
trainingInfo: 'Training information', | |||
modifyModelInfo: 'Modify model information', | |||
modelFiles: 'Model files', | |||
addModelFiles: 'Add model files', | |||
uploadModelFiles: 'Upload model files', | |||
pleaseInputModelName: 'Please input model name', | |||
version: 'Version', | |||
modelEngine: 'Model engine', | |||
modelSource: 'Model source', | |||
modelLabel: 'Model label', | |||
modelLabelInputTips: 'Input labels, multiple labels are separated by spaces', | |||
modelDescr: 'Model description', | |||
@@ -291,6 +305,26 @@ const en = { | |||
modelAccess:'Model Access', | |||
modelAccessPublic:'Public', | |||
modelAccessPrivate:'Private', | |||
modelSettings: 'Model Settings', | |||
edit: 'Edit', | |||
editFiles: 'Edit files', | |||
preview: 'Preview', | |||
modelIntroduction: 'Model Introduction', | |||
hasNoIntroForModel: 'No detailed model introduction yet', | |||
createModelIntro: 'Create model Introduction', | |||
briefIntroduction: 'Introduction', | |||
addLabels: 'Add labels', | |||
discardFileChanges: 'Discard current content modifications?', | |||
editFileContentFirst: 'Please edit the file content first!', | |||
ownerRepository: 'Repository', | |||
creator: 'Creator', | |||
modelEvolutionMap: 'Model Evolution Map', | |||
settings: 'Settings', | |||
parentModel: 'Parent Model', | |||
currentModel: 'Current Model', | |||
derivedModel: 'Derived Model', | |||
refRepository: 'Reference repository', | |||
modelDownloadAll: 'Download All', | |||
}, | |||
repos: { | |||
activeOrganization: 'Active Organization', | |||
@@ -345,6 +379,22 @@ const en = { | |||
raw_seconds: 'seconds', | |||
raw_minutes: 'minutes', | |||
}, | |||
modelObj: { | |||
model_label: 'Select Model', | |||
model_select_placeholder: 'Please select model file', | |||
model_select: 'Select Model', | |||
model_current_repo: 'Current repository', | |||
model_my: 'My models', | |||
model_public: 'Public models', | |||
model_collected: 'My collection', | |||
model_search_placeholder: 'Search model name...', | |||
model_selected: 'Selected model file', | |||
model_ok: 'OK', | |||
model_most: 'Up to {msg} files.', | |||
model_should_same_model: 'Select the files should in the same model.', | |||
model_search: 'Search model', | |||
model_square_empty: 'No Models', | |||
}, | |||
datasets: { | |||
computer_vision: "computer vision", | |||
natural_language_processing: "natural language processing", | |||
@@ -13,6 +13,11 @@ const zh = { | |||
edit: "修改", | |||
delete: "删除", | |||
tips: "提示", | |||
expandMore: '展开更多', | |||
goBack: '返回上一级', | |||
star: '收藏', | |||
unStar: '取消收藏', | |||
submit: '提交', | |||
accomplishTask: "积分任务", | |||
adminOperate: "管理员操作", | |||
@@ -21,6 +26,7 @@ const zh = { | |||
succeeded: "已完成", | |||
debugTask: "调试任务", | |||
trainTask: "训练任务", | |||
trainDuration: "训练时长", | |||
inferenceTask: "推理任务", | |||
benchmarkTask: "评测任务", | |||
createPublicProject: "创建公开项目", | |||
@@ -81,6 +87,9 @@ const zh = { | |||
noPointGainRecord: "还没有积分获取记录", | |||
noPointConsumeRecord: "还没有积分消耗记录", | |||
emptyPage: '您的访问受限!', | |||
emptyPageDescr: '您正尝试访问的页面 <strong>不存在</strong> 或 <strong>您尚未被授权</strong> 查看该页面。', | |||
resourcesManagement: { | |||
OpenI: "启智集群", | |||
C2Net: "智算集群", | |||
@@ -252,13 +261,18 @@ const zh = { | |||
createModel: '创建模型', | |||
importLocalModel: '导入本地模型', | |||
importOnlineModel: '导入线上模型', | |||
modelInfo: '模型信息', | |||
modelBriefIntro: '模型简介', | |||
trainingInfo: '训练相关信息', | |||
modifyModelInfo: '修改模型信息', | |||
modelFiles: '模型文件', | |||
addModelFiles: '增加模型文件', | |||
uploadModelFiles: '上传模型文件', | |||
pleaseInputModelName: '请输入模型名称', | |||
version: '版本', | |||
modelEngine: '模型框架', | |||
modelLabel: '模型标签', | |||
modelSource: '模型来源', | |||
modelLabelInputTips: '输入标签,多个标签用空格区分', | |||
modelDescr: '模型描述', | |||
modelDescrInputTips: '描述字数不超过255个字符', | |||
@@ -307,6 +321,26 @@ const zh = { | |||
modelAccess: '模型权限', | |||
modelAccessPublic: '公开', | |||
modelAccessPrivate: '私有', | |||
modelSettings: '模型信息设置', | |||
edit: '编辑', | |||
editFiles: '编辑文件', | |||
preview: '预览', | |||
modelIntroduction: '模型介绍', | |||
hasNoIntroForModel: '还没有详细的模型介绍', | |||
createModelIntro: '创建模型介绍', | |||
briefIntroduction: '简介', | |||
addLabels: '新增标签', | |||
discardFileChanges: '是否放弃当前内容修改?', | |||
editFileContentFirst: '请先编辑文件内容!', | |||
ownerRepository: '所属项目', | |||
creator: '创建者', | |||
modelEvolutionMap: '模型演化图谱', | |||
settings: '设置', | |||
parentModel: '父模型', | |||
currentModel: '当前模型', | |||
derivedModel: '衍生模型', | |||
refRepository: '引用项目', | |||
modelDownloadAll: '下载全部模型文件', | |||
}, | |||
repos: { | |||
activeOrganization: '活跃组织', | |||
@@ -361,6 +395,22 @@ const zh = { | |||
raw_seconds: '秒', | |||
raw_minutes: '分钟', | |||
}, | |||
modelObj: { | |||
model_label: '选择模型', | |||
model_select_placeholder: '选择模型文件', | |||
model_select: '选择模型', | |||
model_current_repo: '本项目', | |||
model_my: '我的模型', | |||
model_public: '公开模型', | |||
model_collected: '我收藏的模型', | |||
model_search_placeholder: '搜索模型名称...', | |||
model_selected: '已选模型文件', | |||
model_ok: '确定', | |||
model_most: '最多不超过 {msg} 个文件', | |||
model_should_same_model: '选择同一模型下的文件', | |||
model_search: '搜索模型', | |||
model_square_empty: '空荡荡的,什么都没有', | |||
}, | |||
datasets:{ | |||
computer_vision: "计算机视觉", | |||
natural_language_processing: "自然语言处理", | |||
@@ -2,12 +2,12 @@ | |||
<div v-loading="loading"> | |||
<div class="dataset_head_wrap"> | |||
<el-checkbox v-model="checked" style="padding: 0.5rem 1rem;" @change="handleCheckedChange">{{$t('datasets.platform_recommendations')}}</el-checkbox> | |||
<el-dropdown trigger="click" style="cursor: pointer;"> | |||
<el-dropdown trigger="click" style="cursor: pointer;" size="default"> | |||
<span class="el-dropdown-link"> | |||
{{$t('datasets.sort')}}<i class="el-icon-caret-bottom el-icon--right"></i> | |||
</span> | |||
<el-dropdown-menu slot="dropdown"> | |||
<el-dropdown-item :class="{'active':item.active}" v-for="item in sortList" :key="item.name" @click.native="handleSort(item)">{{$t('datasets.'+item.name)}}</el-dropdown-item> | |||
<el-dropdown-item :class="sortSelect == item.name ? 'active' : ''" v-for="item in sortList" :key="item.name" @click.native="handleSort(item)">{{$t('datasets.'+item.name)}}</el-dropdown-item> | |||
</el-dropdown-menu> | |||
</el-dropdown> | |||
</div> | |||
@@ -53,11 +53,11 @@ | |||
:src="`/user/avatar/${item.User.Name}/-1`"> | |||
</a> | |||
<span class="dataset_extra_time">{{item.CreatedUnix | DateTransfer}}</span> | |||
<span class="dataset_extra_link":title="$t('datasets.downloadtimes')"> | |||
<span class="dataset_extra_link" :title="$t('datasets.citations')"> | |||
<i class="ri-link"></i> | |||
<span class="dataset_extra_content">{{item.UseCount}}</span> | |||
</span> | |||
<span class="dataset_extra_download" :title="$t('datasets.citations')"> | |||
<span class="dataset_extra_download" :title="$t('datasets.downloadtimes')"> | |||
<i class="ri-download-line"></i> | |||
<span class="dataset_extra_content">{{item.DownloadTimes}}</span> | |||
</span> | |||
@@ -115,7 +115,15 @@ export default { | |||
licenseValue:{ | |||
type:String, | |||
default:'' | |||
} | |||
}, | |||
sortValue:{ | |||
type:String, | |||
default:'' | |||
}, | |||
recommendValue:{ | |||
type:Boolean, | |||
default:false | |||
}, | |||
}, | |||
data() { | |||
return { | |||
@@ -132,12 +140,11 @@ export default { | |||
license:'' | |||
}, | |||
checked:false, | |||
sortSelect: 'default', | |||
sortList:[ | |||
{name:'default',active:true}, | |||
{name:'latest',active:false}, | |||
{name:'oldest',active:false}, | |||
{name:'recentupdate',active:false}, | |||
{name:'leastupdate',active:false}, | |||
{name:'downloadtimes',active:false}, | |||
{name:'moststars',active:false}, | |||
{name:'mostusecount',active:false}, | |||
@@ -147,37 +154,71 @@ export default { | |||
}; | |||
}, | |||
watch: { | |||
dataGet(newVal) { | |||
this.params.page = 1 | |||
this.$nextTick(() => { | |||
this.getDataList() | |||
}); | |||
}, | |||
searchValue(newVal){ | |||
if (!newVal) { | |||
this.params.page = 1 | |||
this.params.q = newVal | |||
this.getDataList(this.dataGet) | |||
this.$nextTick(() => { | |||
this.getDataList() | |||
}); | |||
} | |||
}, | |||
searchFlag(newVal){ | |||
this.params.page = 1 | |||
this.params.q = this.searchValue | |||
this.getDataList(this.dataGet) | |||
this.$nextTick(() => { | |||
this.getDataList() | |||
}); | |||
}, | |||
categoryValue(val){ | |||
this.params.category = val | |||
this.params.page = 1 | |||
this.getDataList(this.dataGet) | |||
this.$nextTick(() => { | |||
this.getDataList() | |||
}); | |||
}, | |||
taskValue(val){ | |||
this.params.task = val | |||
this.params.page = 1 | |||
this.getDataList(this.dataGet) | |||
this.$nextTick(() => { | |||
this.getDataList() | |||
}); | |||
}, | |||
licenseValue(val){ | |||
this.params.license = val | |||
this.params.page = 1 | |||
this.getDataList(this.dataGet) | |||
this.$nextTick(() => { | |||
this.getDataList() | |||
}); | |||
}, | |||
sortValue(value) { | |||
this.sortSelect = value; | |||
this.params.page = 1 | |||
this.$nextTick(() => { | |||
this.getDataList() | |||
}); | |||
}, | |||
recommendValue(value) { | |||
this.checked = value; | |||
this.params.page = 1 | |||
this.$nextTick(() => { | |||
this.getDataList() | |||
}); | |||
}, | |||
}, | |||
methods: { | |||
getDataList(dataType){ | |||
let url = `/explore/${dataType}` | |||
getDataList(){ | |||
this.params.q = this.searchValue | |||
this.params.category = this.categoryValue | |||
this.params.task = this.taskValue | |||
this.params.license = this.licenseValue | |||
this.params.sort = this.sortValue | |||
this.params.recommend = this.recommendValue | |||
this.sortSelect = this.sortValue | |||
this.checked = this.recommendValue | |||
const dataType = this.dataGet | |||
const url = `/explore/${dataType}` | |||
this.loading=true | |||
getDatasets(url,this.params).then((res)=>{ | |||
if(res.data.result_code==='0'){ | |||
@@ -249,22 +290,15 @@ export default { | |||
}) | |||
}, | |||
handleCheckedChange(val){ | |||
this.params.recommend = val | |||
this.getDataList(this.dataGet) | |||
this.$emit('changeRecommend', val); | |||
}, | |||
handleSort(item){ | |||
this.sortList.forEach(element => { | |||
element.active = false | |||
}); | |||
item.active = true | |||
this.params.sort=item.name | |||
this.getDataList(this.dataGet) | |||
this.$emit('changeSort', item.name); | |||
}, | |||
chooseLabel(item,type){ | |||
const data = {name:item,active:false,type:type} | |||
this.$emit('getLabel',data) | |||
}, | |||
}, | |||
filters:{ | |||
@@ -293,7 +327,6 @@ export default { | |||
font-size: 1rem; | |||
} | |||
.el-dropdown-menu__item { | |||
padding: 2px 1rem; | |||
font-size: 1rem; | |||
} | |||
.el-dropdown-menu__item.active{ | |||
@@ -56,7 +56,7 @@ | |||
</div> | |||
<div class="ui sixteen wide mobile sixteen wide tablet twelve wide computer column"> | |||
<div class="ui sixteen wide column"> | |||
<el-tabs v-model="activeName" @tab-click="handleClick"> | |||
<el-tabs v-model="activeName"> | |||
<el-tab-pane :label="$t('datasets.publick_dataset')" name="public_datasets"> | |||
<div v-if="activeName==='public_datasets'"> | |||
<public-dataset | |||
@@ -67,7 +67,11 @@ | |||
:categoryValue="categoryValue" | |||
:taskValue="taskValue" | |||
:licenseValue="licenseValue" | |||
@getLabel="getChildLabel"> | |||
:sortValue="sortValue" | |||
:recommendValue="recommendValue" | |||
@getLabel="getChildLabel" | |||
@changeSort="changeSort" | |||
@changeRecommend="changeRecommend"> | |||
</public-dataset> | |||
</div> | |||
</el-tab-pane> | |||
@@ -80,7 +84,12 @@ | |||
:searchFlag="searchFlag" | |||
:categoryValue="categoryValue" | |||
:taskValue="taskValue" | |||
:licenseValue="licenseValue"> | |||
:licenseValue="licenseValue" | |||
:sortValue="sortValue" | |||
:recommendValue="recommendValue" | |||
@getLabel="getChildLabel" | |||
@changeSort="changeSort" | |||
@changeRecommend="changeRecommend"> | |||
</public-dataset> | |||
</div> | |||
</el-tab-pane> | |||
@@ -93,7 +102,12 @@ | |||
:searchFlag="searchFlag" | |||
:categoryValue="categoryValue" | |||
:taskValue="taskValue" | |||
:licenseValue="licenseValue"> | |||
:licenseValue="licenseValue" | |||
:sortValue="sortValue" | |||
:recommendValue="recommendValue" | |||
@getLabel="getChildLabel" | |||
@changeSort="changeSort" | |||
@changeRecommend="changeRecommend"> | |||
</public-dataset> | |||
</div> | |||
</el-tab-pane> | |||
@@ -125,19 +139,21 @@ export default { | |||
categoryValue:'', | |||
taskValue:'', | |||
licenseValue:'', | |||
sortValue: 'default', | |||
recommendValue: false, | |||
activeName: 'public_datasets', | |||
isSigned:'false', | |||
searchValue:'', | |||
searchFlag:false | |||
searchFlag:false, | |||
} | |||
}, | |||
computed: { | |||
}, | |||
computed: { }, | |||
methods: { | |||
handleClick(tab, event) { | |||
this.searchValue = '' | |||
this.clearAllSelctLeft() | |||
changeSort(value) { | |||
this.sortValue = value; | |||
}, | |||
changeRecommend(value) { | |||
this.recommendValue = value; | |||
}, | |||
selectCategory(item){ | |||
this.Category.forEach(element => { | |||
@@ -1,715 +0,0 @@ | |||
<template> | |||
<div> | |||
<div class="ui header"> | |||
<div class="ui breadcrumb"> | |||
<a class="section" :href="`${repo}/modelmanage/show_model`">{{ $t('modelManage.modelManage') }}</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">{{ $t('modelManage.basicInfo') }}:</div> | |||
<div class="area-c"> | |||
<div class="area"> | |||
<div class="row"> | |||
<div class="tit">{{ $t('modelManage.useCluster') }}:</div> | |||
<div class="val"> | |||
<div class="txt-wrap" :title="state.typeStr"> | |||
{{ state.typeStr }} | |||
</div> | |||
</div> | |||
</div> | |||
<div class="row"> | |||
<div class="tit">{{ $t('modelManage.modelSize') }}:</div> | |||
<div class="val"> | |||
<div class="txt-wrap" :title="state.modelSize">{{ state.modelSize }}</div> | |||
</div> | |||
</div> | |||
<div class="row" :class="isEidtDescr ? 'edit-row' : ''"> | |||
<div class="tit">{{ $t('modelManage.descr') }}:</div> | |||
<div class="val" :class="isEidtDescr ? 'edit-val' : ''"> | |||
<div v-if="!isEidtDescr" class="txt-wrap" :title="state.description" | |||
style="max-width:100%;width:unset;padding-right:20px;"> | |||
<span>{{ state.description }}</span> | |||
<i v-if="canOperate" style="position:absolute;right:0;top:3px;color:rgb(22, 132, 252);cursor:pointer;" | |||
class="el-icon-edit" @click="editDescr = state._description; isEidtDescr = true;"></i> | |||
</div> | |||
<div class="txt-edit" v-if="isEidtDescr"> | |||
<el-input type="textarea" v-model="editDescr" :maxLength="255" | |||
:placeholder="$t('modelManage.modelDescrInputTips')"></el-input> | |||
<i style="position:absolute;right:-4px;bottom:20px;color:rgb(255, 37, 37);cursor:pointer;" | |||
class="icon times" @click="isEidtDescr = false;"></i> | |||
<i style="position:absolute;right:-5px;bottom:2px;color:rgb(39, 177, 72);cursor:pointer;" | |||
@click="submitEidt('descr')" class="icon check"></i> | |||
</div> | |||
</div> | |||
</div> | |||
<div class="row"> | |||
<div class="tit">{{ $t('modelManage.modelAccess') }}:</div> | |||
<div class="val"> | |||
<div class="txt-wrap">{{ state.isPrivate }}</div> | |||
</div> | |||
</div> | |||
</div> | |||
<div class="area"> | |||
<div class="row"> | |||
<div class="tit">{{ $t('modelManage.modelEngine') }}:</div> | |||
<div class="val"> | |||
<div class="txt-wrap" :title="state.engineName">{{ state.engineName }}</div> | |||
</div> | |||
</div> | |||
<div class="row"> | |||
<div class="tit">{{ $t('modelManage.createTime') }}:</div> | |||
<div class="val"> | |||
<div class="txt-wrap" :title="state.createTime">{{ state.createTime }}</div> | |||
</div> | |||
</div> | |||
<div class="row" :class="isEidtLabel ? 'edit-row' : ''"> | |||
<div class="tit">{{ $t('modelManage.label') }}:</div> | |||
<div class="val" :class="isEidtLabel ? 'edit-val' : ''"> | |||
<div v-if="!isEidtLabel" class="txt-wrap" :title="state.label" | |||
style="max-width:100%;width:unset;padding-right:20px;"> | |||
<span>{{ state.label }}</span> | |||
<i v-if="canOperate" style="position:absolute;right:0;top:3px;color:rgb(22, 132, 252);cursor:pointer;" | |||
class="el-icon-edit" @click="editLabel = state._label; isEidtLabel = true;"></i> | |||
</div> | |||
<div class="txt-edit" v-if="isEidtLabel"> | |||
<el-input v-model="editLabel" :maxLength="255" :placeholder="$t('modelManage.modelLabelInputTips')" | |||
@input="labelInput"></el-input> | |||
<i style="position:absolute;right:-5px;bottom:20px;color:rgb(255, 37, 37);cursor:pointer;" | |||
class="icon times" @click="isEidtLabel = false;"></i> | |||
<i style="position:absolute;right:-5px;bottom:2px;color:rgb(39, 177, 72);cursor:pointer;" | |||
@click="submitEidt('label')" class="icon check"></i> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
<div v-show="isExpanded" style="margin-top:8px;" class="title">{{ $t('modelManage.trainTaskInfo') }}:</div> | |||
<div v-show="isExpanded" class="area-c"> | |||
<div class="area"> | |||
<div class="row"> | |||
<div class="tit">{{ $t('modelManage.trainTask') }}:</div> | |||
<div class="val"> | |||
<div class="txt-wrap" v-html="state.displayJobName"></div> | |||
</div> | |||
</div> | |||
<div class="row"> | |||
<div class="tit">{{ $t('modelManage.codeBranch') }}:</div> | |||
<div class="val"> | |||
<div class="txt-wrap" v-html="state.branchName"></div> | |||
</div> | |||
</div> | |||
<div class="row"> | |||
<div class="tit">{{ $t('modelManage.bootFile') }}:</div> | |||
<div class="val"> | |||
<div class="txt-wrap" :title="state.bootFile">{{ state.bootFile }}</div> | |||
</div> | |||
</div> | |||
<div class="row"> | |||
<div class="tit">{{ $t('modelManage.trainDataset') }}:</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">{{ $t('modelManage.specInfo') }}:</div> | |||
<div class="val"> | |||
<div class="txt-wrap" :title="state.specStr">{{ state.specStr }}</div> | |||
</div> | |||
</div> | |||
<div class="row"> | |||
<div class="tit">{{ $t('modelManage.workServerNumber') }}:</div> | |||
<div class="val"> | |||
<div class="txt-wrap" :title="state.workServerNumber">{{ state.workServerNumber }}</div> | |||
</div> | |||
</div> | |||
<div class="row"> | |||
<div class="tit">{{ $t('modelManage.runParameters') }}:</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 ? $t('modelManage.collapseDetails') : $t('modelManage.seeMore') }}</span> | |||
</div> | |||
<div class="line"></div> | |||
</div> | |||
<div class="files-info"> | |||
<div class="top"> | |||
<div style="width:100%;margin-right:20px;"> | |||
<div class="title">{{ $t('modelManage.modelFilesList') }}:</div> | |||
<div class="title files-path-c" style="margin-top:8px;margin-bottom:4px"> | |||
<div class="file-path" v-for="(item, index) in filePath"> | |||
<span v-if="index == filePath.length - 1" class="path-name">{{ item.label }}</span> | |||
<a v-if="index != filePath.length - 1" class="path-name canback" @click="goBackDir(item)">{{ item.label | |||
}}</a> | |||
<span style="color:rgba(0,0,0,.4);" class="divider"> / </span> | |||
</div> | |||
</div> | |||
</div> | |||
<div> | |||
<el-button v-if="modelType == 1 && canOperate" type="primary" icon="el-icon-upload" @click="goUploadPage"> | |||
{{ $t('modelManage.uploadModelFiles') }} | |||
</el-button> | |||
</div> | |||
</div> | |||
<div class="table-container"> | |||
<el-table ref="tableRef" :data="filesList" row-key="sn" style="width: 100%" v-loading="loading" stripe> | |||
<el-table-column column-key="FileName" prop="FileName" sortable | |||
:sort-method="(a, b) => a.FileName.toLocaleLowerCase().localeCompare(b.FileName.toLocaleLowerCase())" | |||
:label="$t('modelManage.fileName')" align="left" header-align="left"> | |||
<template slot-scope="scope"> | |||
<div class="tbl-file-name"> | |||
<a v-if="scope.row.IsDir" @click="goNextDir(scope.row)" href="javascript:;"> | |||
<div class="fitted" :title="scope.row.FileName"> | |||
<i class="icon folder" width="16" height="16" aria-hidden="true"></i> | |||
<span>{{ scope.row.FileName }}</span> | |||
</div> | |||
</a> | |||
<a v-else :class="!canDownload ? 'disabled-download' : ''" | |||
:href="canDownload ? `${repo}/modelmanage/${state.id}/downloadsingle?parentDir=${filePath.length > 1 ? encodeURIComponent(filePath.map(item => item.path).join('/').slice(1) + '/') : ''}&fileName=${scope.row.FileName}` : 'javascript:;'"> | |||
<div class="fitted" :title="scope.row.FileName"> | |||
<i class="icon file" width="16" height="16" aria-hidden="true"></i> | |||
<span>{{ scope.row.FileName }}</span> | |||
</div> | |||
</a> | |||
</div> | |||
</template> | |||
</el-table-column> | |||
<el-table-column column-key="SizeShow" prop="SizeShow" sortable :sort-method="(a, b) => a.Size - b.Size" | |||
:label="$t('modelManage.fileSize')" align="center" header-align="center" width="200"> | |||
</el-table-column> | |||
<el-table-column column-key="ModTime" prop="ModTime" sortable | |||
:sort-method="(a, b) => a.ModTimeNum - b.ModTimeNum" :label="$t('modelManage.updateTime')" align="center" | |||
header-align="center" width="200"> | |||
</el-table-column> | |||
<el-table-column v-if="modelType == 1 && canDelete" column-key="operate" prop="operate" | |||
:label="$t('modelManage.operate')" align="center" header-align="center" width="200"> | |||
<template slot-scope="scope"> | |||
<span v-if="!scope.row.IsDir" class="btn-del" @click="deleteFile(scope.row)">{{ $t('modelManage.delete') | |||
}}</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, renderSpecStr } from '~/utils'; | |||
import { MODEL_ENGINES } from '~/const'; | |||
import { formatDate } from 'element-ui/lib/utils/date-util'; | |||
const REPO_NAME = location.pathname.split('/')[2]; | |||
const MAX_LABEL_COUNT = 5; | |||
export default { | |||
data() { | |||
return { | |||
modelType: '0', // 1-本地, 0-线上 | |||
canOperate: false, | |||
canDownload:false, | |||
canDelete: 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: '', | |||
}, | |||
editDescr: '', | |||
isEidtDescr: false, | |||
editLabel: '', | |||
isEidtLabel: false, | |||
engineList: MODEL_ENGINES, | |||
curVersion: '', | |||
modelList: [], | |||
filesList: [], | |||
filePath: [], | |||
}; | |||
}, | |||
components: {}, | |||
methods: { | |||
getDirFiles(dir) { | |||
dir = dir.length ? dir.slice(1) : ''; | |||
getModelFiles({ | |||
repo: this.repo, | |||
ID: this.state.id, | |||
parentDir: dir, | |||
}).then(res => { | |||
const list = res.data || []; | |||
list.forEach(item => { | |||
item.SizeShow = item.IsDir ? '' : transFileSize(item.Size); | |||
item.ModTimeNum = new Date(item.ModTime).getTime(); | |||
}) | |||
list.sort((a, b) => b.ModTimeNum - a.ModTimeNum); | |||
this.filesList = list; | |||
this.$refs['tableRef']?.clearSort(); | |||
}).catch(err => { | |||
console.log(err); | |||
}); | |||
}, | |||
goNextDir(item) { | |||
this.filePath.push({ | |||
label: item.FileName, | |||
path: item.FileName | |||
}); | |||
const dir = this.filePath.map((item) => item.path).join('/'); | |||
this.getDirFiles(dir); | |||
}, | |||
goBackDir(item) { | |||
const index = this.filePath.findIndex(pth => item === pth); | |||
this.filePath = this.filePath.slice(0, index + 1); | |||
const dir = this.filePath.map((item) => item.path).join('/'); | |||
this.getDirFiles(dir); | |||
}, | |||
changeVersion(version, noFileRefresh) { | |||
const data = this.modelList.filter((model) => model.version == version)[0]; | |||
this.modelType = data.modelType; | |||
this.canOperate = data.isCanOper; | |||
this.canDownload = data.isCanDownload; | |||
this.canDelete = data.isCanDelete; | |||
this.state.type = data.type; | |||
this.state.typeStr = data.type == 0 ? 'CPU/GPU' : data.type == 1 ? 'NPU' : ''; | |||
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._label = data.label; | |||
this.state.description = data.description || '--'; | |||
this.state._description = data.description; | |||
this.state.isPrivate= (data.isPrivate == true ? this.$t('modelManage.modelAccessPrivate'):this.$t('modelManage.modelAccessPublic')); | |||
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('; '); | |||
const taskType = trainTaskInfo.Type; | |||
let taskUrl = location.href.split('modelmanage')[0]; | |||
if (taskType == 0) { | |||
taskUrl = taskUrl + 'cloudbrain/train-job/' + trainTaskInfo.JobID; | |||
} else if (taskType == 1) { | |||
taskUrl = taskUrl + 'modelarts/train-job/' + trainTaskInfo.JobID; | |||
} else if (taskType == 2) { | |||
taskUrl = taskUrl + 'grampus/train-job/' + trainTaskInfo.JobID; | |||
} | |||
const versionName = trainTaskInfo.VersionName; | |||
const versionHtml = versionName ? `<span class="append-txt" title="${versionName}">${versionName}</span>` : ''; | |||
const codeCommitID = data.codeCommitID; | |||
const codeCommitIDHtml = codeCommitID ? `<span class="append-txt" title="${codeCommitID}">${codeCommitID.slice(0, 10)}</span>` : ''; | |||
let specObj; | |||
try { | |||
specObj = trainTaskInfo.FlavorName ? JSON.parse(trainTaskInfo.FlavorName) : ''; | |||
} catch (e) { | |||
specObj = trainTaskInfo.FlavorName; | |||
} | |||
const sepcStr = typeof specObj == 'object' ? renderSpecStr(specObj, false) : specObj; | |||
Object.assign(this.state, { | |||
displayJobName: `<a href="${taskUrl}" title="${trainTaskInfo.DisplayJobName}">${trainTaskInfo.DisplayJobName}</a>${versionHtml}`, | |||
branchName: `<span>${trainTaskInfo.BranchName}</span>${codeCommitIDHtml}`, | |||
bootFile: trainTaskInfo.BootFile, | |||
datasetName: trainTaskInfo.DatasetName, | |||
parameters: parametersStr || '--', | |||
workServerNumber: trainTaskInfo.WorkServerNumber || '1', | |||
specStr: sepcStr || '--', | |||
}); | |||
} | |||
this.curVersion = version; | |||
if (!noFileRefresh) { | |||
this.filePath = [{ label: version, path: '' }]; | |||
this.getDirFiles('') | |||
} | |||
}, | |||
goUploadPage() { | |||
window.location.href = `${this.repo}/modelmanage/create_local_model_2?type=1&name=${encodeURIComponent(this.state.name)}&id=${this.state.id}`; | |||
}, | |||
backToModelListPage() { | |||
const list = window.location.href.split('/'); | |||
list.pop(); | |||
list.push('show_model'); | |||
window.location.href = list.join('/'); | |||
}, | |||
labelInput() { | |||
const hasEndSpace = this.editLabel[this.editLabel.length - 1] == ' '; | |||
const list = this.editLabel.trim().split(' ').filter(label => label != ''); | |||
this.editLabel = list.slice(0, MAX_LABEL_COUNT).join(' ') + (hasEndSpace && list.length < MAX_LABEL_COUNT ? ' ' : ''); | |||
}, | |||
submitEidt(type) { | |||
const obj = { | |||
repo: this.repo, | |||
type: this.state.type, | |||
id: this.state.id, | |||
name: this.state.name, | |||
version: this.state.version, | |||
engine: this.state.engine, | |||
label: type == 'label' ? this.editLabel : this.state.label, | |||
description: type == 'descr' ? this.editDescr : this.state.description, | |||
}; | |||
modifyModel(obj).then(res => { | |||
res = res.data; | |||
if (res && res.code == '0') { | |||
if (type == 'label') { | |||
this.state.label = this.editLabel; | |||
this.state._label = this.editLabel; | |||
this.isEidtLabel = false; | |||
} else if (type == 'descr') { | |||
this.state.description = this.editDescr; | |||
this.state._description = this.editDescr; | |||
this.isEidtDescr = false; | |||
} | |||
} else { | |||
this.$message({ | |||
type: 'error', | |||
message: this.$t('modelManage.infoModificationFailed'), | |||
}); | |||
} | |||
}).catch(err => { | |||
console.log(err); | |||
this.$message({ | |||
type: 'error', | |||
message: this.$t('modelManage.infoModificationFailed'), | |||
}); | |||
}); | |||
}, | |||
deleteFile(file) { | |||
this.$confirm(this.$t('modelManage.deleteModelFileConfirmTips'), this.$t('tips'), { | |||
confirmButtonText: this.$t('confirm1'), | |||
cancelButtonText: this.$t('cancel'), | |||
type: 'warning', | |||
lockScroll: false, | |||
}).then(() => { | |||
this.loading = true; | |||
deleteModelFile({ | |||
repo: this.repo, | |||
id: this.state.id, | |||
fileName: file.FileName, | |||
}).then(res => { | |||
res = res.data; | |||
if (res.code == '0') { | |||
setTimeout(() => { | |||
this.loading = false; | |||
this.updateModelInfo(); | |||
const dir = this.filePath.map((item) => item.path).join('/'); | |||
this.getDirFiles(dir); | |||
}, 30); | |||
} else { | |||
this.loading = false; | |||
this.$message({ | |||
type: 'error', | |||
message: this.$t('modelManage.modelFileDeleteFailed'), | |||
}); | |||
} | |||
}).catch(err => { | |||
console.log(err); | |||
this.$message({ | |||
type: 'error', | |||
message: this.$t('modelManage.modelFileDeleteFailed'), | |||
}); | |||
}); | |||
}).catch(() => { }); | |||
}, | |||
updateModelInfo() { | |||
getModelInfoByName({ | |||
repo: this.repo, | |||
name: this.state.name, | |||
}).then(res => { | |||
const list = res.data || []; | |||
this.modelList = list; | |||
const noFileRefresh = true; | |||
this.changeVersion(this.curVersion, noFileRefresh); | |||
}).catch(err => { | |||
console.log(err); | |||
}); | |||
}, | |||
}, | |||
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.backToModelListPage(); | |||
}); | |||
} else { | |||
this.backToModelListPage(); | |||
} | |||
}, | |||
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); | |||
margin-bottom: 10px; | |||
} | |||
.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; | |||
margin-bottom: 4px; | |||
align-items: center; | |||
&.edit-row { | |||
height: unset; | |||
} | |||
.tit { | |||
width: 160px; | |||
text-align: right; | |||
color: rgb(136, 136, 136); | |||
} | |||
.val { | |||
flex: 1; | |||
color: rgb(16, 16, 16); | |||
position: relative; | |||
height: 20px; | |||
&.edit-val { | |||
height: unset; | |||
} | |||
.txt-wrap { | |||
position: absolute; | |||
overflow: hidden; | |||
text-overflow: ellipsis; | |||
white-space: nowrap; | |||
width: 100%; | |||
/deep/.append-txt { | |||
margin-left: 6px; | |||
background-color: gainsboro; | |||
padding: 2px; | |||
border-radius: 2px; | |||
font-size: 12px; | |||
} | |||
} | |||
} | |||
.txt-edit { | |||
padding-right: 20px; | |||
} | |||
} | |||
} | |||
} | |||
} | |||
.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; | |||
} | |||
.files-path-c { | |||
margin-bottom: 4px; | |||
height: 20px; | |||
.file-path { | |||
margin-right: 6px; | |||
float: left; | |||
.path-name { | |||
&.canback { | |||
color: #4183c4; | |||
} | |||
} | |||
} | |||
} | |||
.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; | |||
position: relative; | |||
a { | |||
max-width: 100%; | |||
.fitted { | |||
overflow: hidden; | |||
text-overflow: ellipsis; | |||
white-space: nowrap; | |||
max-width: 100%; | |||
} | |||
} | |||
.disabled-download { | |||
cursor: default; | |||
pointer-events: none; | |||
color: rgba(0, 0, 0, .6) !important; | |||
opacity: .45 !important; | |||
} | |||
} | |||
.btn-del { | |||
color: #0366d6; | |||
cursor: pointer; | |||
} | |||
} | |||
} | |||
} | |||
.el-select-dropdown__item.selected { | |||
color: rgba(0, 0, 0, .95); | |||
} | |||
/deep/ .el-select { | |||
.is-focus { | |||
.el-input__inner { | |||
border-color: #85b7d9; | |||
} | |||
} | |||
} | |||
.el-select { | |||
/deep/ .el-input__inner { | |||
font-weight: 600; | |||
} | |||
} | |||
/deep/ .el-input__inner { | |||
&:focus { | |||
border-color: #85b7d9; | |||
} | |||
} | |||
/deep/ .el-textarea__inner { | |||
&:focus { | |||
border-color: #85b7d9; | |||
} | |||
} | |||
</style> |
@@ -0,0 +1,263 @@ | |||
<template> | |||
<div class="bg"> | |||
<div class="ui container"> | |||
<div class="title"> | |||
<div class="title-l"> | |||
<span>{{ modelName }}</span> | |||
<img src="/img/jian.svg" v-if="model.recommend == 1"> | |||
</div> | |||
<div class="title-r"> | |||
<div @click="changeFav"> | |||
<i v-if="!isCollected" class="heart outline icon" :title="$t('star')"></i> | |||
<i v-if="isCollected" class="heart icon" :title="$t('unStar')"></i> | |||
<span>{{ $t('star') }}</span> | |||
</div> | |||
<div>{{ collectedCount }}</div> | |||
</div> | |||
</div> | |||
<div class="sub-title"> | |||
<span> | |||
<span>{{ $t('modelManage.ownerRepository') }}:</span> | |||
<a :href="`/${repoOwnerName}/${repoName}/modelmanage/show_model`"> | |||
{{ repoOwnerName + '/' + (model.repoDisplayName || repoName) }} | |||
</a> | |||
</span> | |||
<span> | |||
<span>{{ $t('modelManage.creator') }}:</span> | |||
<a :href="`/${model.userName}`">{{ model.userName }}</a> | |||
</span> | |||
<span> | |||
<span>{{ $t('datasets.downloadtimes') }}:</span> | |||
<span style="color: rgb(16, 16, 16);">{{ model.downloadCount }}</span> | |||
</span> | |||
<span> | |||
<span>{{ $t('datasets.citations') }}:</span> | |||
<span style="color: rgb(16, 16, 16);">{{ model.referenceCount }}</span> | |||
</span> | |||
</div> | |||
<div class="tabs-wrap"> | |||
<div class="tabs"> | |||
<div class="tabs-l"> | |||
<a | |||
:href="`/${repoOwnerName}/${repoName}/modelmanage/model_readme_tmpl?name=${encodeURIComponent(modelName)}`"> | |||
<div class="tab" :class="tab == 'intro' ? 'focus' : ''"> | |||
<i class="ri-send-plane-2-line"></i><span>{{ $t('modelManage.modelIntroduction') }}</span> | |||
</div> | |||
</a> | |||
<a | |||
:href="`/${repoOwnerName}/${repoName}/modelmanage/model_filelist_tmpl?name=${encodeURIComponent(modelName)}`"> | |||
<div class="tab" :class="tab == 'files' ? 'focus' : ''"> | |||
<i class="ri-bar-chart-horizontal-line"></i><span>{{ $t('modelManage.modelFiles') }}</span> | |||
</div> | |||
</a> | |||
<a | |||
:href="`/${repoOwnerName}/${repoName}/modelmanage/model_evolution_map?name=${encodeURIComponent(modelName)}`"> | |||
<div class="tab" :class="tab == 'graph' ? 'focus' : ''"> | |||
<i class="ri-equalizer-line"></i><span>{{ $t('modelManage.modelEvolutionMap') }}</span> | |||
</div> | |||
</a> | |||
</div> | |||
<div class="tabs-r"> | |||
<a :href="`/${repoOwnerName}/${repoName}/modelmanage/model_setting?name=${encodeURIComponent(modelName)}`"> | |||
<div class="tab" :class="tab == 'settings' ? 'focus' : ''" v-if="model && model.isCanOper"> | |||
<i class="ri-settings-2-line"></i><span>{{ $t('modelManage.settings') }}</span> | |||
</div> | |||
</a> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
</template> | |||
<script> | |||
import { setModelFav } from '~/apis/modules/modelsquare'; | |||
export default { | |||
name: "ModelHeader", | |||
props: { | |||
model: { type: Object, default: () => ({}) }, | |||
repoOwnerName: { type: String, default: '' }, | |||
repoName: { type: String, default: '' }, | |||
modelName: { type: String, default: '' }, | |||
tab: { type: String, default: 'intro' } | |||
}, | |||
components: {}, | |||
data() { | |||
return { | |||
favCnt: '', | |||
isCollected: false, | |||
collectedCount: '', | |||
isSetting: false, | |||
}; | |||
}, | |||
methods: { | |||
changeFav() { | |||
if (this.isSetting || !this.model.id) return; | |||
this.isSetting = true; | |||
setModelFav({ | |||
id: this.model.id, | |||
collected: this.isCollected ? false : true, | |||
}).then(res => { | |||
this.isSetting = false; | |||
if (res.data.code == '0') { | |||
this.isCollected = !this.isCollected; | |||
this.collectedCount = this.collectedCount + (this.isCollected ? 1 : -1); | |||
this.$message.success(this.isCollected ? this.$t('datasets.starSuccess') : this.$t('datasets.unstarSuccess')); | |||
} else if (res.data.code == '401') { | |||
window.location.href = `/user/login?redirect_to=${encodeURIComponent(window.location.href)}`; | |||
} else { | |||
this.$message.error(res.data.msg); | |||
} | |||
}).catch(err => { | |||
console.log(err); | |||
this.$message.error(err); | |||
this.isSetting = false; | |||
}); | |||
} | |||
}, | |||
watch: { | |||
model: { | |||
handler(newVal) { | |||
this.isCollected = newVal.isCollected; | |||
this.collectedCount = newVal.collectedCount; | |||
}, | |||
immediate: true, | |||
deep: true, | |||
}, | |||
}, | |||
mounted() { }, | |||
}; | |||
</script> | |||
<style scoped lang="less"> | |||
.bg { | |||
height: 153px; | |||
border-color: rgba(204, 204, 255, 0.6); | |||
border-width: 0px 0px 1px; | |||
border-style: solid; | |||
background: url("data:image/svg+xml;charset=utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20version%3D%221.1%22%3E%3Cdefs%3E%3ClinearGradient%20id%3D%221%22%20x1%3D%220%22%20x2%3D%221%22%20y1%3D%220%22%20y2%3D%220%22%20gradientTransform%3D%22matrix(-0.42400000000000015%2C%20-0.9990000000000001%2C%200.0112777734375%2C%20-0.42400000000000015%2C%201%2C%200.995)%22%3E%3Cstop%20stop-color%3D%22%23ccfff4%22%20stop-opacity%3D%221%22%20offset%3D%220.01%22%3E%3C%2Fstop%3E%3Cstop%20stop-color%3D%22%23e0e2ff%22%20stop-opacity%3D%221%22%20offset%3D%220.52%22%3E%3C%2Fstop%3E%3Cstop%20stop-color%3D%22%23f4eefd%22%20stop-opacity%3D%221%22%20offset%3D%221%22%3E%3C%2Fstop%3E%3C%2FlinearGradient%3E%3C%2Fdefs%3E%3Crect%20width%3D%22100%25%22%20height%3D%22100%25%22%20fill%3D%22url(%231)%22%3E%3C%2Frect%3E%3C%2Fsvg%3E"); | |||
.container { | |||
position: relative; | |||
height: 100%; | |||
} | |||
} | |||
.title { | |||
display: flex; | |||
align-items: center; | |||
justify-content: space-between; | |||
height: 60px; | |||
padding-top: 6px; | |||
margin-bottom: 2px; | |||
.title-l { | |||
display: flex; | |||
align-items: center; | |||
max-width: 74%; | |||
span { | |||
font-size: 24px; | |||
color: #101010; | |||
overflow: hidden; | |||
text-overflow: ellipsis; | |||
display: inline-block; | |||
line-height: 40px; | |||
height: 40px; | |||
white-space: nowrap; | |||
} | |||
img { | |||
height: 19px; | |||
width: 20px; | |||
margin-left: 8px; | |||
} | |||
} | |||
.title-r { | |||
display: flex; | |||
align-items: center; | |||
>div { | |||
height: 30px; | |||
border-color: rgb(225, 227, 230); | |||
border-width: 1px; | |||
border-style: solid; | |||
border-radius: 4px 0px 0px 4px; | |||
font-size: 14px; | |||
padding: 4px 8px; | |||
line-height: 21px; | |||
background: rgb(247, 247, 247); | |||
color: #101010; | |||
cursor: pointer; | |||
i { | |||
margin-right: 6px; | |||
color: rgb(250, 140, 22); | |||
} | |||
&:last-child { | |||
border-radius: 0px 4px 4px 0px; | |||
border-left: none; | |||
cursor: default; | |||
} | |||
} | |||
} | |||
} | |||
.sub-title { | |||
>span { | |||
margin-right: 12px; | |||
>span { | |||
font-size: 14px; | |||
color: rgb(136, 136, 136); | |||
} | |||
} | |||
} | |||
.tabs-wrap { | |||
position: absolute; | |||
bottom: 0; | |||
width: 100%; | |||
.tabs { | |||
display: flex; | |||
justify-content: space-between; | |||
margin-bottom: -1px; | |||
.tabs-l { | |||
display: flex; | |||
align-items: center; | |||
} | |||
.tabs-r { | |||
display: flex; | |||
align-items: center; | |||
} | |||
.tab { | |||
font-size: 14px; | |||
padding: 10px 15px; | |||
color: rgba(16, 16, 16, 0.5); | |||
display: flex; | |||
align-items: center; | |||
cursor: pointer; | |||
i { | |||
margin-right: 4px; | |||
} | |||
&.focus { | |||
color: #101010; | |||
border-color: rgba(204, 204, 255, 0.6); | |||
border-width: 1px 1px 0px; | |||
border-style: solid; | |||
border-radius: 4px 4px 0px 0px; | |||
background: rgb(255, 255, 255); | |||
} | |||
} | |||
} | |||
} | |||
</style> |
@@ -0,0 +1,424 @@ | |||
<template> | |||
<div> | |||
<div v-if="emptyPage" style="padding-top:50px"> | |||
<NotFound></NotFound> | |||
</div> | |||
<div v-else> | |||
<ModelHeader :tab="'files'" :repoOwnerName="repoOwnerName" :repoName="repoName" :modelName="modelName" | |||
:model="modelData"> | |||
</ModelHeader> | |||
<div class="ui container"> | |||
<div class="header"> | |||
<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="files-info"> | |||
<div class="top"> | |||
<div style="width:100%;margin-right:20px;"> | |||
<div class="title">{{ $t('modelManage.modelFilesList') }}:</div> | |||
<div class="title files-path-c" style="margin-top:8px;margin-bottom:4px"> | |||
<div class="file-path" v-for="(item, index) in filePath"> | |||
<span v-if="index == filePath.length - 1" class="path-name">{{ item.label }}</span> | |||
<a v-if="index != filePath.length - 1" class="path-name canback" @click="goBackDir(item)">{{ | |||
item.label | |||
}}</a> | |||
<span style="color:rgba(0,0,0,.4);" class="divider"> / </span> | |||
</div> | |||
</div> | |||
</div> | |||
<div class="right-btn-c"> | |||
<a class="download-btn" v-if="modelData.isCanDownload" download | |||
:href="`${repoUrl}/modelmanage/downloadall?id=${modelData.id}`"> | |||
{{ $t('modelManage.modelDownloadAll') }} | |||
</a> | |||
<el-button v-if="modelType == 1 && canOperate" type="primary" icon="el-icon-upload" @click="goUploadPage"> | |||
{{ $t('modelManage.uploadModelFiles') }} | |||
</el-button> | |||
</div> | |||
</div> | |||
<div class="table-container"> | |||
<el-table ref="tableRef" :data="filesList" row-key="sn" style="width: 100%" v-loading="loading" stripe> | |||
<el-table-column column-key="FileName" prop="FileName" sortable | |||
:sort-method="(a, b) => a.FileName.toLocaleLowerCase().localeCompare(b.FileName.toLocaleLowerCase())" | |||
:label="$t('modelManage.fileName')" align="left" header-align="left"> | |||
<template slot-scope="scope"> | |||
<div class="tbl-file-name"> | |||
<a v-if="scope.row.IsDir" @click="goNextDir(scope.row)" href="javascript:;"> | |||
<div class="fitted" :title="scope.row.FileName"> | |||
<i class="icon folder" width="16" height="16" aria-hidden="true"></i> | |||
<span>{{ scope.row.FileName }}</span> | |||
</div> | |||
</a> | |||
<a v-else :class="!canDownload ? 'disabled-download' : ''" | |||
:href="canDownload ? `${repoUrl}/modelmanage/${state.id}/downloadsingle?parentDir=${filePath.length > 1 ? encodeURIComponent(filePath.map(item => item.path).join('/').slice(1) + '/') : ''}&fileName=${scope.row.FileName}` : 'javascript:;'"> | |||
<div class="fitted" :title="scope.row.FileName"> | |||
<i class="icon file" width="16" height="16" aria-hidden="true"></i> | |||
<span>{{ scope.row.FileName }}</span> | |||
</div> | |||
</a> | |||
</div> | |||
</template> | |||
</el-table-column> | |||
<el-table-column column-key="SizeShow" prop="SizeShow" sortable :sort-method="(a, b) => a.Size - b.Size" | |||
:label="$t('modelManage.fileSize')" align="center" header-align="center" width="200"> | |||
</el-table-column> | |||
<el-table-column column-key="ModTime" prop="ModTime" sortable | |||
:sort-method="(a, b) => a.ModTimeNum - b.ModTimeNum" :label="$t('modelManage.updateTime')" | |||
align="center" header-align="center" width="200"> | |||
</el-table-column> | |||
<el-table-column v-if="modelType == 1 && canDelete" column-key="operate" prop="operate" | |||
:label="$t('modelManage.operate')" align="center" header-align="center" width="200"> | |||
<template slot-scope="scope"> | |||
<span v-if="!scope.row.IsDir" class="btn-del" @click="deleteFile(scope.row)">{{ | |||
$t('modelManage.delete') | |||
}}</span> | |||
</template> | |||
</el-table-column> | |||
</el-table> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
</template> | |||
<script> | |||
import ModelHeader from '../components/ModelHeader.vue'; | |||
import NotFound from '~/components/NotFound.vue'; | |||
import { getModelInfoByName, getModelFiles, deleteModelFile } from '~/apis/modules/modelmanage'; | |||
import { getUrlSearchParams, getListValueWithKey, transFileSize, renderSpecStr } from '~/utils'; | |||
import { MODEL_ENGINES } from '~/const'; | |||
import { formatDate } from 'element-ui/lib/utils/date-util'; | |||
export default { | |||
data() { | |||
return { | |||
emptyPage: false, | |||
modelName: '', | |||
repoOwnerName: location.pathname.split('/')[1], | |||
repoName: location.pathname.split('/')[2], | |||
repoUrl: location.pathname.split('/').slice(0, 3).join('/'), | |||
modelData: {}, | |||
modelType: '0', // 1-本地, 0-线上 | |||
canOperate: false, | |||
canDownload: false, | |||
canDelete: false, | |||
loading: false, | |||
state: { | |||
type: 0, | |||
id: '', | |||
name: '', | |||
version: '0.0.1', | |||
engine: '0', | |||
label: '', | |||
description: '', | |||
}, | |||
engineList: MODEL_ENGINES, | |||
curVersion: '', | |||
modelList: [], | |||
filesList: [], | |||
filePath: [], | |||
}; | |||
}, | |||
components: { ModelHeader, NotFound }, | |||
methods: { | |||
getDirFiles(dir) { | |||
dir = dir.length ? dir.slice(1) : ''; | |||
getModelFiles({ | |||
repo: this.repoUrl, | |||
ID: this.state.id, | |||
parentDir: dir, | |||
}).then(res => { | |||
const list = res.data || []; | |||
list.forEach(item => { | |||
item.SizeShow = item.IsDir ? '' : transFileSize(item.Size); | |||
item.ModTimeNum = new Date(item.ModTime).getTime(); | |||
}); | |||
list.sort((a, b) => a.FileName.localeCompare(b.FileName)); | |||
list.sort((a, b) => b.ModTimeNum - a.ModTimeNum); | |||
this.filesList = list; | |||
this.$refs['tableRef']?.clearSort(); | |||
}).catch(err => { | |||
console.log(err); | |||
}); | |||
}, | |||
goNextDir(item) { | |||
this.filePath.push({ | |||
label: item.FileName, | |||
path: item.FileName | |||
}); | |||
const dir = this.filePath.map((item) => item.path).join('/'); | |||
this.getDirFiles(dir); | |||
}, | |||
goBackDir(item) { | |||
const index = this.filePath.findIndex(pth => item === pth); | |||
this.filePath = this.filePath.slice(0, index + 1); | |||
const dir = this.filePath.map((item) => item.path).join('/'); | |||
this.getDirFiles(dir); | |||
}, | |||
changeVersion(version) { | |||
this.curVersion = version; | |||
this.updateModelInfo(); | |||
this._changeVersion(version); | |||
}, | |||
_changeVersion(version, noFileRefresh) { | |||
const data = this.modelList.filter((model) => model.version == version)[0]; | |||
this.modelData = data; | |||
this.modelType = data.modelType; | |||
this.canOperate = data.isCanOper; | |||
this.canDownload = data.isCanDownload; | |||
this.canDelete = data.isCanDelete; | |||
this.state.type = data.type; | |||
this.state.typeStr = data.type == 0 ? 'CPU/GPU' : data.type == 1 ? 'NPU' : ''; | |||
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.isPrivate = data.isPrivate; | |||
this.state.createTime = formatDate(new Date(data.createdUnix * 1000), 'yyyy-MM-dd HH:mm:ss'); | |||
this.state.trainTaskInfo = data.trainTaskInfo; | |||
Object.assign(this.state, { | |||
displayJobName: '--', | |||
branchName: '--', | |||
bootFile: '--', | |||
datasetName: '--', | |||
parameters: '--', | |||
workServerNumber: '--', | |||
specStr: '--', | |||
}); | |||
this.curVersion = version; | |||
if (!noFileRefresh) { | |||
this.filePath = [{ label: version, path: '' }]; | |||
this.getDirFiles('') | |||
} | |||
}, | |||
goUploadPage() { | |||
window.location.href = `${this.repoUrl}/modelmanage/model_fileupload_tmpl?type=1&name=${encodeURIComponent(this.state.name)}&id=${this.state.id}`; | |||
}, | |||
backToModelListPage() { | |||
const list = window.location.href.split('/'); | |||
list.pop(); | |||
list.push('show_model'); | |||
window.location.href = list.join('/'); | |||
}, | |||
deleteFile(file) { | |||
this.$confirm(this.$t('modelManage.deleteModelFileConfirmTips'), this.$t('tips'), { | |||
confirmButtonText: this.$t('confirm1'), | |||
cancelButtonText: this.$t('cancel'), | |||
type: 'warning', | |||
lockScroll: false, | |||
}).then(() => { | |||
this.loading = true; | |||
deleteModelFile({ | |||
repo: this.repoUrl, | |||
id: this.state.id, | |||
fileName: file.FileName, | |||
}).then(res => { | |||
res = res.data; | |||
if (res.code == '0') { | |||
setTimeout(() => { | |||
this.loading = false; | |||
this.updateModelInfo(); | |||
const dir = this.filePath.map((item) => item.path).join('/'); | |||
this.getDirFiles(dir); | |||
}, 30); | |||
} else { | |||
this.loading = false; | |||
this.$message({ | |||
type: 'error', | |||
message: this.$t('modelManage.modelFileDeleteFailed'), | |||
}); | |||
} | |||
}).catch(err => { | |||
console.log(err); | |||
this.$message({ | |||
type: 'error', | |||
message: this.$t('modelManage.modelFileDeleteFailed'), | |||
}); | |||
}); | |||
}).catch(() => { }); | |||
}, | |||
updateModelInfo() { | |||
getModelInfoByName({ | |||
repo: this.repoUrl, | |||
name: this.state.name, | |||
}).then(res => { | |||
const list = res.data || []; | |||
this.modelList = list; | |||
const noFileRefresh = true; | |||
this._changeVersion(this.curVersion, noFileRefresh); | |||
}).catch(err => { | |||
console.log(err); | |||
}); | |||
}, | |||
}, | |||
beforeMount() { | |||
const urlParams = getUrlSearchParams(); | |||
if (urlParams.name) { | |||
this.modelName = urlParams.name; | |||
this.state.name = urlParams.name; | |||
this.loading = true; | |||
getModelInfoByName({ | |||
repo: this.repoUrl, | |||
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); | |||
} else { | |||
this.emptyPage = true; | |||
} | |||
}).catch(err => { | |||
console.log(err); | |||
this.loading = false; | |||
}); | |||
} else { | |||
this.emptyPage = true; | |||
} | |||
}, | |||
mounted() { }, | |||
beforeDestroy() { }, | |||
}; | |||
</script> | |||
<style scoped lang="less"> | |||
.header { | |||
display: flex; | |||
align-items: center; | |||
margin-top: 32px; | |||
margin-bottom: 22px; | |||
.version { | |||
width: 90px; | |||
} | |||
} | |||
.content { | |||
.files-info { | |||
.top { | |||
padding: 0 0 8px 0; | |||
display: flex; | |||
align-items: center; | |||
justify-content: space-between; | |||
} | |||
.files-path-c { | |||
margin-bottom: 10px; | |||
height: 20px; | |||
.file-path { | |||
margin-right: 6px; | |||
float: left; | |||
font-size: 14px; | |||
font-weight: 550; | |||
color: #101010; | |||
.path-name { | |||
&.canback { | |||
color: #4183c4; | |||
} | |||
} | |||
} | |||
} | |||
.right-btn-c { | |||
min-width: 300px; | |||
display: flex; | |||
align-items: center; | |||
justify-content: flex-end; | |||
.download-btn { | |||
text-align: right; | |||
margin-right: 16px; | |||
} | |||
} | |||
.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; | |||
position: relative; | |||
a { | |||
max-width: 100%; | |||
.fitted { | |||
overflow: hidden; | |||
text-overflow: ellipsis; | |||
white-space: nowrap; | |||
max-width: 100%; | |||
} | |||
} | |||
.disabled-download { | |||
cursor: default; | |||
pointer-events: none; | |||
color: rgba(0, 0, 0, .6) !important; | |||
opacity: .45 !important; | |||
} | |||
} | |||
.btn-del { | |||
color: #0366d6; | |||
cursor: pointer; | |||
} | |||
} | |||
} | |||
} | |||
.el-select-dropdown__item.selected { | |||
color: rgba(0, 0, 0, .95); | |||
} | |||
/deep/ .el-select { | |||
.is-focus { | |||
.el-input__inner { | |||
border-color: #85b7d9; | |||
} | |||
} | |||
} | |||
.el-select { | |||
/deep/ .el-input__inner { | |||
font-weight: 600; | |||
} | |||
} | |||
</style> |
@@ -4,7 +4,7 @@ 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'; | |||
import App from './index.vue'; | |||
Vue.use(ElementUI, { | |||
locale: lang === 'zh-CN' ? localeZh : localeEn, |
@@ -1,8 +1,14 @@ | |||
<template> | |||
<div> | |||
<div v-if="emptyPage" style="padding-top:50px"> | |||
<NotFound></NotFound> | |||
</div> | |||
<div v-else> | |||
<ModelHeader :tab="'files'" :repoOwnerName="repoOwnerName" :repoName="repoName" :modelName="modelName" :model="modelData"> | |||
</ModelHeader> | |||
<div class="ui container"> | |||
<div class="header"> | |||
<span class="title">{{ type == '1' ? $t('modelManage.addModelFiles') : $t('modelManage.uploadModelFiles') | |||
}}</span> | |||
<span class="title">{{ $t('modelManage.uploadModelFiles') }}</span> | |||
</div> | |||
<div class="content ui form"> | |||
<div class="guide-c" v-if="type != '1'"> | |||
@@ -30,7 +36,8 @@ | |||
<div class="r-content"> | |||
<div style="position:relative"> | |||
<form class="dropzone" ref="dropzoneRef"> | |||
<div class="dropzon-err-tips ui red message" v-show="showUploadErr" style="display:none;margin:2.5rem"> | |||
<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> | |||
@@ -40,7 +47,8 @@ | |||
<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" :disabled="uploading">{{ $t('modelManage.upload') }} | |||
<el-button size="medium" class="green" @click="submit" :disabled="uploading">{{ $t('modelManage.upload') | |||
}} | |||
</el-button> | |||
<el-button size="medium" @click="cancel">{{ $t('modelManage.cancel') }}</el-button> | |||
</div> | |||
@@ -60,7 +68,8 @@ | |||
class="ri-close-circle-line failed"></i> | |||
<i v-if="uploadStatusList[index].infoCode === 0" class="ri-checkbox-circle-line success"></i> | |||
<span>{{ uploadStatusList[index].status }}</span> | |||
<el-tooltip v-if="uploadStatusList[index].infoCode === 1" class="item" effect="dark" placement="top"> | |||
<el-tooltip v-if="uploadStatusList[index].infoCode === 1" class="item" effect="dark" | |||
placement="top"> | |||
<div slot="content"> {{ uploadStatusList[index].failedInfo }} </div> | |||
<i style="font-size: 16px; margin-left: 0.5rem; cursor: pointer" class="ri-question-fill"></i> | |||
</el-tooltip> | |||
@@ -72,10 +81,13 @@ | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
</template> | |||
<script> | |||
import ModelHeader from '../components/ModelHeader.vue'; | |||
import NotFound from '~/components/NotFound.vue'; | |||
import 'dropzone/dist/dropzone.css'; | |||
import Dropzone from 'dropzone'; | |||
import SparkMD5 from "spark-md5"; | |||
@@ -92,8 +104,15 @@ const maxModelFilesSize = window.MAX_MODEL_SIZE || 200 * 1024 * 1024 * 1024; // | |||
export default { | |||
data() { | |||
return { | |||
emptyPage: false, | |||
modelName: '', | |||
repoOwnerName: location.pathname.split('/')[1], | |||
repoName: location.pathname.split('/')[2], | |||
modelData: {}, | |||
dropzoneHandler: null, | |||
type: '0', // 1-修改,其它-新增 | |||
type: '1', // 1-修改,其它-新增 | |||
state: { | |||
type: '', | |||
id: '', | |||
@@ -116,12 +135,13 @@ export default { | |||
uploading: false, | |||
}; | |||
}, | |||
components: {}, | |||
components: { ModelHeader, NotFound }, | |||
methods: { | |||
initModelData() { | |||
const urlParams = getUrlSearchParams(); | |||
if (urlParams.name && urlParams.id) { | |||
this.type = urlParams.type || '0'; | |||
this.modelName = urlParams.name; | |||
this.type = urlParams.type || '1'; | |||
this.state.name = urlParams.name; | |||
this.state.id = urlParams.id; | |||
this.loading = true; | |||
@@ -134,6 +154,7 @@ export default { | |||
const list = res.data; | |||
if (list && list.length) { | |||
const data = list[0]; | |||
this.modelData = data; | |||
this.state.type = data.type; | |||
this.state.id = data.id; | |||
this.state.name = data.name; | |||
@@ -144,15 +165,14 @@ export default { | |||
this.state.size = data.size || 0; | |||
this.originData = data; | |||
} else { | |||
this.cancel(); | |||
this.emptyPage = true; | |||
} | |||
}).catch(err => { | |||
this.loading = false; | |||
console.log(err); | |||
this.cancel(); | |||
}); | |||
} else { | |||
this.cancel(); | |||
this.emptyPage = true; | |||
} | |||
}, | |||
initDropZone() { | |||
@@ -481,7 +501,7 @@ export default { | |||
this.uploading = false; | |||
if (this.uploadSuccessLength == this.uploadLength) { | |||
window.setTimeout(() => { | |||
this.goDetail(); | |||
this.goFileListPage(); | |||
}, 1000); | |||
} else { | |||
if (this.uploadSuccessLength > 0) { | |||
@@ -542,7 +562,6 @@ export default { | |||
this.uploadError(file, this.$t('modelManage.uploadFailed')); | |||
this.updateFileStatus(file, this.$t('modelManage.uploadFailed'), 0, 2); | |||
}); | |||
} | |||
}).catch(err => { | |||
console.info('calcFileMd5', err); | |||
@@ -553,22 +572,16 @@ export default { | |||
} | |||
}, | |||
cancel() { | |||
if (this.type == '1') { | |||
this.goDetail(); | |||
return; | |||
} | |||
const list = window.location.href.split('/'); | |||
list.pop(); | |||
list.push('show_model'); | |||
window.location.href = list.join('/'); | |||
this.goFileListPage(); | |||
}, | |||
goDetail() { | |||
goFileListPage() { | |||
const list = window.location.href.split('/'); | |||
list.pop(); | |||
list.push('show_model_info'); | |||
window.location.href = list.join('/') + '?name=' + this.state.name; | |||
list.push('model_filelist_tmpl'); | |||
window.location.href = list.join('/') + '?name=' + encodeURIComponent(this.state.name); | |||
} | |||
}, | |||
beforeMount() { }, | |||
mounted() { | |||
this.initModelData(); | |||
this.initDropZone(); | |||
@@ -589,6 +602,7 @@ export default { | |||
background: rgb(240, 240, 240); | |||
display: flex; | |||
align-items: center; | |||
margin-top: 32px; | |||
.title { | |||
font-weight: 600; |
@@ -4,7 +4,7 @@ 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-local-create-1.vue'; | |||
import App from './index.vue'; | |||
Vue.use(ElementUI, { | |||
locale: lang === 'zh-CN' ? localeZh : localeEn, |
@@ -0,0 +1,111 @@ | |||
<template> | |||
<div> | |||
<div v-if="emptyPage" style="padding-top:50px"> | |||
<NotFound></NotFound> | |||
</div> | |||
<div v-else> | |||
<ModelHeader :tab="'graph'" :repoOwnerName="repoOwnerName" :repoName="repoName" :modelName="modelName" :model="modelData"> | |||
</ModelHeader> | |||
<div class="ui container"> | |||
<div ref="graphContainerRef" class="graph-container"></div> | |||
</div> | |||
</div> | |||
</div> | |||
</template> | |||
<script> | |||
import ModelHeader from '../components/ModelHeader.vue'; | |||
import NotFound from '~/components/NotFound.vue'; | |||
import { getModelInfoByName, getModelEvolutionMap } from '~/apis/modules/modelmanage'; | |||
import { getUrlSearchParams } from '~/utils'; | |||
import { ModelGraph } from './model-graph'; | |||
import './model-graph.css'; | |||
let modelGraph = null; | |||
export default { | |||
data() { | |||
return { | |||
emptyPage: false, | |||
modelName: '', | |||
repoOwnerName: location.pathname.split('/')[1], | |||
repoName: location.pathname.split('/')[2], | |||
modelData: {}, | |||
}; | |||
}, | |||
components: { ModelHeader, NotFound }, | |||
methods: {}, | |||
beforeMount() { | |||
const urlParams = getUrlSearchParams(); | |||
if (urlParams.name) { | |||
this.modelName = urlParams.name; | |||
this.loading = true; | |||
getModelInfoByName({ repo: `/${this.repoOwnerName}/${this.repoName}`, name: this.modelName }).then(res => { | |||
const data = res.data; | |||
this.loading = false; | |||
if (data && data.length) { | |||
const model = data[0]; | |||
this.modelData = model; | |||
getModelEvolutionMap({ | |||
repo: `/${this.repoOwnerName}/${this.repoName}`, | |||
id: model.id, | |||
}).then(res => { | |||
const data = res.data; | |||
function runData(node) { | |||
if (node.Type == 1) { | |||
const model = node.Model || {}; | |||
node.type = 'model'; | |||
node.name = model.name; | |||
node.isCurrent = node.IsCurrent; | |||
node.isParent = node.IsParent; | |||
node.isDerive = !node.IsCurrent && !node.IsParent; | |||
node.creator = model.userName; | |||
if (!node.isCurrent) { | |||
node.link = `/${model.repoOwnerName}/${model.repoName}/modelmanage/model_readme_tmpl?name=${model.name}`; | |||
} | |||
} | |||
if (node.Type == 0) { | |||
node.type = 'repo'; | |||
node.name = node.RepoOwnerName + ' / ' + `<span style="font-weight:bold">${node.RepoDisplayName}</span>`; | |||
node.link = `/${node.RepoOwnerName}/${node.RepoName}`; | |||
} | |||
node.children = node.Next || []; | |||
for (let i = 0, iLen = node.children.length; i < iLen; i++) { | |||
const child = node.children[i]; | |||
runData(child); | |||
} | |||
} | |||
runData(data); | |||
this.$nextTick(() => { | |||
modelGraph = new ModelGraph(); | |||
modelGraph.init(this.$refs.graphContainerRef, data, {}); | |||
}); | |||
}).catch(err => { | |||
console.log(err); | |||
}); | |||
} else { | |||
this.emptyPage = true; | |||
} | |||
}).catch(err => { | |||
console.log(err); | |||
}); | |||
} else { | |||
this.emptyPage = true; | |||
} | |||
}, | |||
mounted() { }, | |||
beforeDestroy() { }, | |||
}; | |||
</script> | |||
<style scoped lang="less"> | |||
.graph-container { | |||
position: relative; | |||
border: 1px solid rgb(225, 227, 230); | |||
border-radius: 5px; | |||
margin-top: 32px; | |||
height: 75vh; | |||
overflow: hidden; | |||
} | |||
</style> |
@@ -0,0 +1,290 @@ | |||
._tree-toolbar { | |||
position: absolute; | |||
top: 0; | |||
left: 0; | |||
display: flex; | |||
align-items: center; | |||
padding-left: 20px; | |||
padding-top: 20px; | |||
z-index: 10000; | |||
} | |||
._tree-toolbar .legend-c { | |||
display: flex; | |||
align-items: center; | |||
border-radius: 4px; | |||
border: 1px solid #e9edf2; | |||
background: white; | |||
box-shadow: rgba(0, 0, 0, 0.1) 0 4px 10px 0; | |||
padding: 6px 12px; | |||
} | |||
._tree-toolbar .legend { | |||
display: flex; | |||
align-items: center; | |||
margin-right: 18px; | |||
} | |||
._tree-toolbar .legend:last-child { | |||
margin-right: 0; | |||
} | |||
._tree-toolbar .legend .legend-icon { | |||
margin-right: 5px; | |||
height: 14px; | |||
width: 18px; | |||
border-radius: 2px; | |||
} | |||
._tree-toolbar .legend .legend-name { | |||
font-size: 12px; | |||
color: rgba(136, 136, 136, 1); | |||
} | |||
._tree-toolbar .legend .legend-isprarent { | |||
background: rgb(122, 184, 251); | |||
} | |||
._tree-toolbar .legend .legend-iscurrent { | |||
background: rgb(22, 132, 252); | |||
} | |||
._tree-toolbar .legend .legend-isderive { | |||
background: rgb(3, 102, 214); | |||
} | |||
._tree-toolbar .legend .legend-isrepo { | |||
border-radius: 8px; | |||
border: 1px solid rgb(3, 102, 214); | |||
background: rgb(255, 255, 255); | |||
} | |||
._tree-layout { | |||
position: absolute; | |||
width: 1500px; | |||
height: 500px; | |||
/* border: 1px solid gray; */ | |||
transition: scale 30ms; | |||
} | |||
._tree-layout ._tree-layout-svg { | |||
position: absolute; | |||
width: 100%; | |||
height: 100%; | |||
} | |||
._tree-layout ._tree-layout-svg path { | |||
transition: all 250ms ease; | |||
} | |||
._tree-layout ._tree-node { | |||
position: absolute; | |||
box-sizing: border-box; | |||
display: flex; | |||
align-items: center; | |||
justify-content: center; | |||
word-break: break-all; | |||
transition: all 250ms ease; | |||
} | |||
._tree-layout ._tree-node-block { | |||
position: absolute; | |||
height: 100%; | |||
width: 100%; | |||
display: flex; | |||
align-items: center; | |||
justify-content: center; | |||
padding: 10px; | |||
} | |||
._tree-layout ._tree-node .name { | |||
cursor: pointer; | |||
color: white; | |||
} | |||
._tree-layout ._tree-node .name:hover { | |||
text-decoration: underline; | |||
} | |||
._tree-layout ._tree-node.model-parent { | |||
border-style: none; | |||
border-color: unset; | |||
color: rgb(255, 255, 255); | |||
border-radius: 5px; | |||
font-size: 12px; | |||
padding: 10px; | |||
text-align: center; | |||
line-height: 17px; | |||
font-weight: normal; | |||
font-style: normal; | |||
background: rgb(122, 184, 251); | |||
} | |||
._tree-layout ._tree-node.model-current { | |||
border-style: none; | |||
border-color: unset; | |||
box-shadow: rgba(3, 110, 255, 0.4) 0px 0px 20px 0px; | |||
color: rgb(255, 255, 255); | |||
border-radius: 5px; | |||
font-size: 12px; | |||
padding: 10px; | |||
text-align: center; | |||
line-height: 17px; | |||
font-weight: bold; | |||
font-style: normal; | |||
background: rgb(22, 132, 252); | |||
} | |||
._tree-layout ._tree-node.model-current .name { | |||
cursor: default; | |||
} | |||
._tree-layout ._tree-node.model-current .name:hover { | |||
text-decoration: none; | |||
} | |||
._tree-layout ._tree-node.model-derive { | |||
border-style: none; | |||
border-color: unset; | |||
color: rgb(255, 255, 255); | |||
border-radius: 5px; | |||
font-size: 12px; | |||
padding: 10px; | |||
text-align: center; | |||
line-height: 17px; | |||
font-weight: normal; | |||
font-style: normal; | |||
background: rgb(3, 102, 214); | |||
} | |||
._tree-layout ._tree-node.repo { | |||
border-color: rgb(3, 102, 214); | |||
border-width: 1px; | |||
border-style: solid; | |||
color: rgb(16, 16, 16); | |||
border-radius: 20px; | |||
font-size: 12px; | |||
padding: 10px; | |||
text-align: center; | |||
line-height: 17px; | |||
font-weight: normal; | |||
font-style: normal; | |||
background: rgb(255, 255, 255); | |||
} | |||
._tree-layout ._tree-node.repo .name { | |||
color: #101010; | |||
} | |||
._tree-layout ._tree-node .descr { | |||
position: absolute; | |||
top: 100%; | |||
width: 100%; | |||
text-align: center; | |||
font-size: 12px; | |||
color: rgb(136, 136, 136); | |||
font-weight: 300; | |||
height: 22px; | |||
padding-top: 6px; | |||
line-height: 17px; | |||
} | |||
._tree-layout ._tree-node .creator { | |||
position: absolute; | |||
right: 100%; | |||
font-size: 12px; | |||
font-weight: normal; | |||
width: 80px; | |||
height: 17px; | |||
overflow: hidden; | |||
text-overflow: ellipsis; | |||
white-space: nowrap; | |||
text-align: right; | |||
padding-right: 4px; | |||
} | |||
._tree-layout ._tree-node .creator a { | |||
color: rgb(136, 136, 136); | |||
} | |||
._tree-layout ._tree-node .creator a:hover { | |||
text-decoration: underline; | |||
} | |||
._tree-layout ._tree-node .node-expand-c { | |||
position: absolute; | |||
top: 50%; | |||
left: 100%; | |||
} | |||
._tree-layout ._tree-node .node-expand-line { | |||
position: absolute; | |||
height: 1px; | |||
width: 20px; | |||
background-color: rgb(122, 184, 251); | |||
} | |||
._tree-layout ._tree-node .node-expand-icon { | |||
position: absolute; | |||
height: 16px; | |||
width: 16px; | |||
background-color: rgb(122, 184, 251); | |||
color: white; | |||
display: flex; | |||
align-items: center; | |||
justify-content: center; | |||
left: 13px; | |||
top: -8px; | |||
border-radius: 100%; | |||
cursor: pointer; | |||
font-weight: bold; | |||
line-height: 14px; | |||
font-size: 13px; | |||
user-select: none; | |||
} | |||
._model-info { | |||
position: fixed; | |||
width: 300px; | |||
height: 258px; | |||
border-color: rgb(225, 227, 230); | |||
border-width: 1px; | |||
border-style: solid; | |||
box-shadow: rgb(225, 227, 230) 0px 2px 6px 0px; | |||
border-radius: 5px; | |||
font-size: 12px; | |||
background: rgba(255, 255, 255, 0.96); | |||
padding: 10px; | |||
z-index: 10001; | |||
} | |||
._model-info .tit { | |||
font-size: 12px; | |||
color: rgb(22, 132, 252); | |||
} | |||
._model-info .row { | |||
display: flex; | |||
padding-left: 2px; | |||
margin: 4px 0; | |||
align-items: center; | |||
} | |||
._model-info .row>div:nth-child(1) { | |||
width: 66px; | |||
color: rgb(136, 136, 136); | |||
text-align: right; | |||
} | |||
._model-info .row>div:nth-child(2) { | |||
flex: 1; | |||
color: rgb(16, 16, 16); | |||
} | |||
:lang(en-US) ._model-info .row>div:nth-child(1) { | |||
width: 120px; | |||
} | |||
:lang(en-US) ._model-info { | |||
width: 326px; | |||
} |
@@ -0,0 +1,496 @@ | |||
import { BoundingBox, Layout } from '~/utils/treelayout'; | |||
import { getListValueWithKey, transFileSize, renderSpecStr } from '~/utils'; | |||
import { MODEL_ENGINES } from '~/const'; | |||
import { formatDate } from 'element-ui/lib/utils/date-util'; | |||
import { i18n } from '~/langs'; | |||
function ModelGraph() { | |||
this.options = { | |||
horizontalGap: 120, | |||
verticalGap: 40, | |||
parentModelNodeWidth: 100, | |||
parentModelNodeHeight: 60, | |||
currentModelNodeWidth: 100, | |||
currentModelNodeHeight: 100, | |||
deriveModelNodeWidth: 100, | |||
deriveModelNodeHeight: 60, | |||
repoNodeWidth: 140, | |||
repoNodeHeight: 40, | |||
collapsedIconMarginLeft: 20, | |||
}; | |||
this.$el = null; | |||
this.$layout = null; | |||
this.viewWinWidth = 0; | |||
this.viewWinHeight = 0; | |||
this.layoutWidth = 0; | |||
this.layoutHeight = 0; | |||
this._layoutWidth = 0; | |||
this._layoutHeight = 0; | |||
this.initScale = 1; | |||
this.drawOffsetLeft = 0; | |||
this.drawOffsetTop = 0; | |||
this.treeData = null; | |||
this.nodeMap = {}; | |||
return this; | |||
} | |||
ModelGraph.prototype.init = function (element, data, options) { | |||
if (!element) return; | |||
if (!['absolute', 'relative', 'fixed'].includes(element.style.position)) { | |||
element.style.position = 'relative'; | |||
element.style.overflow = 'hidden'; | |||
} | |||
this.$el = element; | |||
Object.assign(this.options, options); | |||
this.treeData = data; | |||
this.renderTree(); | |||
this.toolBarInit(); | |||
this.eventInit(); | |||
}; | |||
ModelGraph.prototype.walkTree = function (pNode, lvl) { | |||
if (pNode.type == 'model') { | |||
if (pNode.isParent) { | |||
pNode.width = this.options.parentModelNodeHeight; | |||
pNode.height = this.options.parentModelNodeWidth; | |||
} | |||
if (pNode.isCurrent) { | |||
pNode.width = this.options.currentModelNodeHeight; | |||
pNode.height = this.options.currentModelNodeWidth; | |||
} | |||
if (pNode.isDerive) { | |||
pNode.width = this.options.deriveModelNodeHeight; | |||
pNode.height = this.options.deriveModelNodeWidth; | |||
} | |||
} | |||
if (pNode.type == 'repo') { | |||
pNode.width = this.options.repoNodeHeight; | |||
pNode.height = this.options.repoNodeWidth; | |||
} | |||
pNode.lvl = lvl; | |||
const children = pNode.children || []; | |||
for (let i = 0, iLen = children.length; i < iLen; i++) { | |||
const child = children[i]; | |||
child.pNode = pNode; | |||
this.walkTree(child, lvl + 1); | |||
} | |||
pNode._children = pNode._children || pNode.children; | |||
if (pNode.isCollapsed) { | |||
pNode.children = undefined; | |||
} else { | |||
pNode.children = pNode._children; | |||
} | |||
if (!pNode._id) { | |||
pNode._id = `${lvl}-${Math.random()}`; | |||
} | |||
this.nodeMap[pNode._id] = pNode; | |||
}; | |||
ModelGraph.prototype.renderTree = function () { | |||
const bb = new BoundingBox(this.options.verticalGap, this.options.horizontalGap); | |||
const layout = new Layout(bb); | |||
this.walkTree(this.treeData, 0); | |||
const { result, boundingBox } = layout.layout(this.treeData); | |||
const viewWinEl = this.$el; | |||
this.viewWinWidth = viewWinEl.clientWidth; | |||
this.viewWinHeight = viewWinEl.clientHeight; | |||
const layoutWidth = boundingBox.bottom; | |||
const layoutHeight = boundingBox.right; | |||
this._layoutWidth = layoutWidth; | |||
this._layoutHeight = layoutHeight; | |||
if (!this.$layout) { | |||
this.layoutWidth = Math.max(boundingBox.bottom, boundingBox.right, 1000); | |||
this.layoutHeight = Math.max(boundingBox.bottom, boundingBox.right, 1000); | |||
const layoutEl = document.createElement('div'); | |||
layoutEl.classList.add('_tree-layout'); | |||
layoutEl.classList.add('model-graph-layout'); | |||
this.$el.append(layoutEl); | |||
this.$layout = layoutEl; | |||
this.$layout.style.width = this.layoutWidth * 4 + 'px'; | |||
this.$layout.style.height = this.layoutHeight * 4 + 'px'; | |||
this.$layout.style.left = - this.layoutWidth * 4 / 2 + this.viewWinWidth / 2 + 'px'; | |||
this.$layout.style.top = - this.layoutHeight * 4 / 2 + this.viewWinHeight / 2 + 'px'; | |||
const scale = Math.min(Math.min((this.viewWinWidth - 100) / layoutWidth, (this.viewWinHeight - 100) / layoutHeight), 1); | |||
this.initScale = scale; | |||
this.$layout.style.scale = scale; | |||
this.$layout.innerHTML = '<svg class="_tree-layout-svg"><g></g></svg>'; | |||
this.drawOffsetLeft = this.layoutWidth * 1.5; | |||
this.drawOffsetTop = this.layoutHeight * 1.5 + (this.layoutHeight - layoutHeight) / 2 - this.options.verticalGap / 4; | |||
} else { | |||
this.drawOffsetLeft = this.layoutWidth * 1.5; | |||
this.drawOffsetTop = this.layoutHeight * 1.5 + (this.layoutHeight - layoutHeight) / 2 - this.options.verticalGap / 4; | |||
} | |||
this.drawTreeNode(this.treeData); | |||
this.popupInit(); | |||
}; | |||
ModelGraph.prototype.drawTreeNode = function (treeData, setPoint) { | |||
const children = treeData.children || []; | |||
let divEl = this.$layout.querySelectorAll(`._tree-node[data-id="${treeData._id}"]`)[0]; | |||
if (!divEl) { | |||
divEl = document.createElement('div'); | |||
divEl.classList = ['_tree-node']; | |||
let innerHTML = treeData.link ? `<div class="_tree-node-block"><a class="name" target="_blank" href="${treeData.link}">${treeData.name}</a></div>` : | |||
`<div class="_tree-node-block"><div class="name">${treeData.name}</div></div>`; | |||
if (treeData.type == 'model') { | |||
divEl.classList.add('model'); | |||
if (treeData.isParent) { | |||
divEl.classList.add('model-parent'); | |||
innerHTML += `<div class="descr">${i18n.t('modelManage.parentModel')}</div>`; | |||
} | |||
if (treeData.isCurrent) { | |||
divEl.classList.add('model-current'); | |||
innerHTML += `<div class="descr">${i18n.t('modelManage.currentModel')}</div>`; | |||
} | |||
if (treeData.isDerive) { | |||
divEl.classList.add('model-derive'); | |||
} | |||
if (treeData.pNode) { | |||
innerHTML += `<div class="creator" style="margin-top:-14px"><a target="_blank" href="/${treeData.creator}">${treeData.creator}</a></div>`; | |||
} | |||
} | |||
if (treeData.type == 'repo') { | |||
divEl.classList.add('repo'); | |||
} | |||
if (children.length || (treeData._children || []).length) { | |||
innerHTML += `<div class="node-expand-c"> | |||
<div class="node-expand-line"></div> | |||
<div class="node-expand-icon"></div> | |||
</div>`; | |||
} | |||
divEl.style.width = treeData.height + 'px'; | |||
divEl.style.height = treeData.width + 'px'; | |||
divEl.style.zIndex = 10000 - treeData.lvl; | |||
divEl.dataset.id = treeData._id; | |||
divEl.innerHTML = innerHTML; | |||
this.$layout.append(divEl); | |||
} | |||
if (divEl.querySelector('div.node-expand-icon')) { | |||
divEl.querySelector('div.node-expand-icon').innerHTML = treeData.isCollapsed ? '+' : '-'; | |||
} | |||
if (setPoint) { | |||
divEl.style.left = setPoint.x - treeData.height / 2 + 'px'; | |||
divEl.style.top = setPoint.y - treeData.width / 2 + 'px'; | |||
divEl.style.scale = 0; | |||
} else { | |||
divEl.style.left = (treeData.y + this.drawOffsetLeft) + 'px'; | |||
divEl.style.top = (treeData.x + this.drawOffsetTop) + 'px'; | |||
divEl.style.scale = 1; | |||
const creator = divEl.querySelector('div.creator'); | |||
if (creator && treeData.pNode) { | |||
const marginTop = treeData.pNode.x + treeData.pNode.width / 2 >= treeData.x + treeData.width / 2 ? -14 : 14; | |||
creator.style.marginTop = marginTop + 'px'; | |||
} | |||
} | |||
for (let i = 0, iLen = children.length; i < iLen; i++) { | |||
this.drawTreeNode(children[i], setPoint); | |||
this.drawLine(treeData, children[i], setPoint); | |||
} | |||
}; | |||
ModelGraph.prototype.drawLine = function (pNode, node, setPoint) { | |||
const svgPathContainer = this.$layout.querySelector('._tree-layout-svg g'); | |||
const node1 = { | |||
w: pNode.height, | |||
h: pNode.width, | |||
l: pNode.y + this.drawOffsetLeft, | |||
t: pNode.x + this.drawOffsetTop | |||
} | |||
const node2 = { | |||
w: node.height, | |||
h: node.width, | |||
l: node.y + this.drawOffsetLeft, | |||
t: node.x + this.drawOffsetTop | |||
} | |||
const point1 = { | |||
x: node1.l + node1.w + this.options.collapsedIconMarginLeft, | |||
y: node1.t + node1.h / 2 | |||
}; | |||
const point2 = { | |||
x: node2.l, | |||
y: node2.t + node2.h / 2 | |||
} | |||
let d = `M${point1.x} ${point1.y} C${(point1.x + point2.x) / 2} ${point1.y} ${(point1.x + point2.x) / 2} ${point2.y} ${point2.x} ${point2.y}`; | |||
let path = svgPathContainer.querySelectorAll(`path[data-id="${node._id}"]`)[0]; | |||
if (!path) { | |||
path = document.createElementNS('http://www.w3.org/2000/svg', 'path'); | |||
path.setAttribute('fill', 'none'); | |||
path.setAttribute('stroke', 'rgb(122, 184, 251)'); | |||
path.setAttribute('stroke-width', 1); | |||
path.setAttribute('id', node._id); | |||
path.dataset.id = node._id; | |||
svgPathContainer.append(path); | |||
} | |||
if (setPoint) { | |||
d = `M${setPoint.x} ${setPoint.y} C${setPoint.x} ${setPoint.y} ${setPoint.x} ${setPoint.y} ${setPoint.x} ${setPoint.y}`; | |||
} | |||
path.setAttribute('d', d); | |||
}; | |||
ModelGraph.prototype.removeNode = function (nodeList) { | |||
const layout = this.$layout; | |||
for (let i = 0, iLen = nodeList.length; i < iLen; i++) { | |||
const curNode = nodeList[i]; | |||
const id = curNode._id; | |||
const nodes = this.$layout.querySelectorAll(`[data-id="${id}"]`); | |||
nodes.forEach(item => item.remove()); | |||
const children = curNode.children || []; | |||
this.removeNode(children); | |||
} | |||
}; | |||
ModelGraph.prototype.showModelNodeInfo = function (nodeEl, nodeData, showOrHide) { | |||
const self = this; | |||
const elClass = '_model-info-' + nodeData._id.toString().replace('.', '-'); | |||
let showInfoEl = document.querySelector('.' + elClass); | |||
if (showOrHide == 'show') { | |||
if (showInfoEl) { | |||
nodeData.delayHideTimer && clearTimeout(nodeData.delayHideTimer); | |||
return; | |||
} | |||
const model = nodeData.Model || {}; | |||
let modelObj = { ...model }; | |||
const trainTaskInfo = model.trainTaskInfo ? JSON.parse(model.trainTaskInfo) : ''; | |||
if (trainTaskInfo) { | |||
trainTaskInfo.DisplayJobName = trainTaskInfo.DisplayJobName == undefined ? '' : trainTaskInfo.DisplayJobName; | |||
const taskType = trainTaskInfo.Type; | |||
let taskUrl = `/${model.repoOwnerName}/${model.repoName}/`; | |||
if (taskType == 0) { | |||
taskUrl = taskUrl + 'cloudbrain/train-job/' + trainTaskInfo.JobID; | |||
} else if (taskType == 1) { | |||
taskUrl = taskUrl + 'modelarts/train-job/' + trainTaskInfo.JobID; | |||
} else if (taskType == 2) { | |||
taskUrl = taskUrl + 'grampus/train-job/' + trainTaskInfo.JobID; | |||
} | |||
let specObj; | |||
try { | |||
specObj = trainTaskInfo.FlavorName ? JSON.parse(trainTaskInfo.FlavorName) : ''; | |||
} catch (e) { | |||
specObj = trainTaskInfo.FlavorName; | |||
} | |||
modelObj.displayJobNameHtml = `<a target="_blank" href="${trainTaskInfo.DisplayJobName ? taskUrl : 'javascript:;'}" title="${trainTaskInfo.DisplayJobName}">${trainTaskInfo.DisplayJobName}</a>`; | |||
modelObj.trainJobDuration = trainTaskInfo.TrainJobDuration; | |||
modelObj.sepcStr = typeof specObj == 'object' ? renderSpecStr(specObj, false) : specObj; | |||
} | |||
modelObj = { | |||
...modelObj, | |||
engineName: getListValueWithKey(MODEL_ENGINES, model.engine.toString()), | |||
modelSize: transFileSize(model.size), | |||
createTimeStr: formatDate(new Date(model.createdUnix * 1000), 'yyyy-MM-dd HH:mm:ss'), | |||
isPrivateStr: model.isPrivate ? i18n.t('modelManage.modelAccessPrivate') : i18n.t('modelManage.modelAccessPublic'), | |||
}; | |||
showInfoEl = document.createElement('div'); | |||
showInfoEl.classList.add('_model-info'); | |||
showInfoEl.classList.add(elClass); | |||
showInfoEl.innerHTML = ` | |||
<div class="tit">${i18n.t('modelManage.modelInfo')}</div> | |||
<div class="row"> | |||
<div>${i18n.t('modelManage.modelEngine')}:</div> | |||
<div>${modelObj.engineName}</div> | |||
</div> | |||
<div class="row"> | |||
<div>${i18n.t('modelManage.modelSize')}:</div> | |||
<div>${modelObj.modelSize}</div> | |||
</div> | |||
<div class="row"> | |||
<div>${i18n.t('modelManage.createTime')}:</div> | |||
<div>${modelObj.createTimeStr}</div> | |||
</div> | |||
<div class="row"> | |||
<div>${i18n.t('modelManage.modelAccess')}:</div> | |||
<div>${modelObj.isPrivateStr}</div> | |||
</div> | |||
<div class="tit" style="margin-top:8px">${i18n.t('modelManage.trainingInfo')}</div> | |||
<div class="row"> | |||
<div>${i18n.t('trainTask')}:</div> | |||
<div>${modelObj.displayJobNameHtml || '--'}</div> | |||
</div> | |||
<div class="row"> | |||
<div>${i18n.t('trainDuration')}:</div> | |||
<div>${modelObj.trainJobDuration || '--'}</div> | |||
</div> | |||
<div class="row" style="height:40px"> | |||
<div>${i18n.t('modelManage.specInfo')}:</div> | |||
<div>${modelObj.sepcStr || '--'}</div> | |||
</div>`; | |||
const posInfo = nodeEl.getBoundingClientRect(); | |||
const winW = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth; | |||
showInfoEl.style.top = Math.max(posInfo.top - 258 + 6, 20) + 'px'; | |||
showInfoEl.style.left = Math.min(posInfo.left - 6 + posInfo.width, winW - 250 - 20) + 'px'; | |||
document.querySelector('body').append(showInfoEl); | |||
const mouseEnter = function () { | |||
self.showModelNodeInfo(nodeEl, nodeData, 'show'); | |||
}; | |||
const mouseLeave = function () { | |||
self.showModelNodeInfo(nodeEl, nodeData, 'hide'); | |||
}; | |||
showInfoEl.addEventListener('mouseenter', mouseEnter); | |||
showInfoEl.addEventListener('mouseleave', mouseLeave); | |||
} else { | |||
nodeData.delayHideTimer && clearTimeout(nodeData.delayHideTimer); | |||
nodeData.delayHideTimer = setTimeout(() => { | |||
if (showInfoEl) { | |||
showInfoEl.remove(); | |||
} | |||
}, 200); | |||
} | |||
}; | |||
ModelGraph.prototype.eventInit = function () { | |||
if (this.$layout) { | |||
this._drag(this.$layout); | |||
this._scale(this.$layout); | |||
const self = this; | |||
this.$layout.addEventListener('click', function (evt) { | |||
if (evt.target.classList.contains('node-expand-icon')) { | |||
const nodeEl = evt.target.parentElement.parentElement; | |||
const id = nodeEl.dataset.id; | |||
const curNode = self.nodeMap[id]; | |||
const isCollapsed = curNode.isCollapsed; | |||
if (isCollapsed) { | |||
const n = { | |||
w: curNode.height, | |||
h: curNode.width, | |||
l: curNode.y + self.drawOffsetLeft, | |||
t: curNode.x + self.drawOffsetTop | |||
} | |||
const point = { | |||
x: n.l + n.w + self.options.collapsedIconMarginLeft, | |||
y: n.t + n.h / 2 | |||
}; | |||
const children = curNode._children || []; | |||
for (let i = 0, iLen = children.length; i < iLen; i++) { | |||
self.drawTreeNode(children[i], point); | |||
self.drawLine(curNode, children[i], point); | |||
} | |||
curNode.isCollapsed = !curNode.isCollapsed; | |||
self.renderTree(); | |||
} else { | |||
const children = curNode.children || []; | |||
curNode.isCollapsed = !curNode.isCollapsed; | |||
self.renderTree(); | |||
const n = { | |||
w: curNode.height, | |||
h: curNode.width, | |||
l: curNode.y + self.drawOffsetLeft, | |||
t: curNode.x + self.drawOffsetTop | |||
} | |||
const point = { | |||
x: n.l + n.w + self.options.collapsedIconMarginLeft, | |||
y: n.t + n.h / 2 | |||
}; | |||
for (let i = 0, iLen = children.length; i < iLen; i++) { | |||
self.drawTreeNode(children[i], point); | |||
self.drawLine(curNode, children[i], point); | |||
} | |||
setTimeout(function () { | |||
self.removeNode(children); | |||
}, 260); | |||
} | |||
} | |||
}); | |||
} | |||
}; | |||
ModelGraph.prototype.popupInit = function () { | |||
const modelsEls = this.$layout.querySelectorAll('._tree-node.model ._tree-node-block'); | |||
const self = this; | |||
const mouseEnterHandler = function (evt) { | |||
const nodeEl = evt.target.parentElement; | |||
const id = nodeEl.dataset.id; | |||
const curNode = self.nodeMap[id]; | |||
self.showModelNodeInfo(nodeEl, curNode, 'show'); | |||
}; | |||
const mouseLeaveHandler = function (evt) { | |||
const nodeEl = evt.target.parentElement; | |||
const id = nodeEl.dataset.id; | |||
const curNode = self.nodeMap[id]; | |||
self.showModelNodeInfo(nodeEl, curNode, 'hide'); | |||
}; | |||
for (let i = 0, iLen = modelsEls.length; i < iLen; i++) { | |||
const modelEl = modelsEls[i]; | |||
modelEl.removeEventListener('mouseenter', mouseEnterHandler); | |||
modelEl.removeEventListener('mouseleave', mouseLeaveHandler); | |||
modelEl.addEventListener('mouseenter', mouseEnterHandler); | |||
modelEl.addEventListener('mouseleave', mouseLeaveHandler); | |||
} | |||
} | |||
ModelGraph.prototype.toolBarInit = function () { | |||
const toolBarEl = document.createElement('div'); | |||
toolBarEl.classList.add('_tree-toolbar'); | |||
toolBarEl.innerHTML = `<div class="legend-c"> | |||
<div class="legend"><div class="legend-icon legend-isprarent"></div><span class="legend-name">${i18n.t('modelManage.parentModel')}</span></div> | |||
<div class="legend"><div class="legend-icon legend-iscurrent"></div><span class="legend-name">${i18n.t('modelManage.currentModel')}</span></div> | |||
<div class="legend"><div class="legend-icon legend-isderive"></div><span class="legend-name">${i18n.t('modelManage.derivedModel')}</span></div> | |||
<div class="legend"><div class="legend-icon legend-isrepo"></div><span class="legend-name">${i18n.t('modelManage.refRepository')}</span></div> | |||
</div>`; | |||
this.$el.append(toolBarEl); | |||
}; | |||
ModelGraph.prototype._drag = function (el) { | |||
var self = this; | |||
el.onmousedown = mouseDown; | |||
function mouseDown(event) { | |||
event = event || window.event; | |||
var disX = event.clientX - el.offsetLeft; | |||
var disY = event.clientY - el.offsetTop; | |||
if (event.target == this || event.target.classList.contains('_tree-layout-svg')) { | |||
var oldCursor = el.style.cursor; | |||
el.style.cursor = 'move'; | |||
document.onmousemove = function (event) { | |||
event = event || window.event; | |||
MouseMove(event, disX, disY); | |||
} | |||
document.onmouseup = function () { | |||
document.onmousemove = null; | |||
el.style.cursor = oldCursor; | |||
} | |||
} | |||
} | |||
function MouseMove(event, x1, y1) { | |||
event = event || window.event; | |||
var l = event.clientX - x1, | |||
t = event.clientY - y1, | |||
winW = document.documentElement.clientWidth || document.body.clientWidth, | |||
winH = document.documentElement.clientHeight || document.body.clientHeight, | |||
maxW = winW - el.offsetWidth, | |||
maxH = winH - el.offsetHeight; | |||
// if (l < 0) { | |||
// l = 0; | |||
// } else if (l > maxW - 15) { | |||
// l = maxW - 15; | |||
// } | |||
// if (t < 0) { | |||
// t = 0; | |||
// } else if (t > maxH - 15) { | |||
// t = maxH - 15; | |||
// } | |||
el.style.left = l + "px"; | |||
el.style.top = t + "px"; | |||
} | |||
} | |||
ModelGraph.prototype._scale = function (el) { | |||
const self = this; | |||
el.onmousewheel = function (event) { | |||
var scale = parseFloat(el.style.scale || 1); | |||
if (event.wheelDelta >= 0) { | |||
scale *= 1.1; | |||
} else { | |||
scale /= 1.1; | |||
} | |||
if (scale >= self.initScale / 2 && scale < 1.5) { | |||
el.style.scale = scale; | |||
} | |||
event.stopPropagation(); | |||
event.preventDefault(); | |||
event.returnValue = false; | |||
} | |||
} | |||
export { ModelGraph } |
@@ -4,7 +4,7 @@ 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-local-create-2.vue'; | |||
import App from './index.vue'; | |||
Vue.use(ElementUI, { | |||
locale: lang === 'zh-CN' ? localeZh : localeEn, |
Dear OpenI User
Thank you for your continuous support to the Openl Qizhi Community AI Collaboration Platform. In order to protect your usage rights and ensure network security, we updated the Openl Qizhi Community AI Collaboration Platform Usage Agreement in January 2024. The updated agreement specifies that users are prohibited from using intranet penetration tools. After you click "Agree and continue", you can continue to use our services. Thank you for your cooperation and understanding.
For more agreement content, please refer to the《Openl Qizhi Community AI Collaboration Platform Usage Agreement》