Browse Source

Merge branch 'V20211228' into fix-981

tags/v1.21.12.2^2
Gitea 3 years ago
parent
commit
119c6d8b32
30 changed files with 849 additions and 249 deletions
  1. +13
    -0
      models/attachment.go
  2. +6
    -0
      models/cloudbrain.go
  3. +31
    -39
      models/user_business_analysis.go
  4. +131
    -11
      modules/cloudbrain/cloudbrain.go
  5. +13
    -16
      modules/modelarts/modelarts.go
  6. +3
    -3
      modules/modelarts/resty.go
  7. +21
    -2
      modules/repository/elk_pagedata.go
  8. +4
    -0
      modules/storage/local.go
  9. +30
    -0
      modules/storage/minio.go
  10. +1
    -0
      modules/storage/storage.go
  11. +4
    -0
      options/locale/locale_en-US.ini
  12. +2
    -0
      options/locale/locale_zh-CN.ini
  13. +5
    -0
      package-lock.json
  14. +1
    -0
      package.json
  15. +23
    -1
      routers/api/v1/repo/modelarts.go
  16. +17
    -0
      routers/repo/ai_model_manage.go
  17. +156
    -34
      routers/repo/cloudbrain.go
  18. +1
    -0
      routers/repo/milestone.go
  19. +109
    -48
      routers/repo/modelarts.go
  20. +5
    -3
      routers/routes/routes.go
  21. +20
    -3
      templates/repo/cloudbrain/new.tmpl
  22. +137
    -44
      templates/repo/debugjob/index.tmpl
  23. +2
    -1
      templates/repo/home.tmpl
  24. +6
    -24
      templates/repo/modelarts/trainjob/index.tmpl
  25. +16
    -7
      templates/repo/modelarts/trainjob/show.tmpl
  26. +0
    -1
      templates/repo/modelmanage/index.tmpl
  27. +79
    -8
      templates/repo/modelmanage/showinfo.tmpl
  28. +7
    -1
      web_src/js/components/Contributors.vue
  29. +5
    -2
      web_src/js/components/Model.vue
  30. +1
    -1
      web_src/less/index.less

+ 13
- 0
models/attachment.go View File

@@ -439,6 +439,19 @@ func GetModelArtsUserAttachments(userID int64) ([]*AttachmentUsername, error) {
return getModelArtsUserAttachments(x, userID)
}

func getModelArtsTrainAttachments(e Engine, userID int64) ([]*AttachmentUsername, error) {
attachments := make([]*AttachmentUsername, 0, 10)
if err := e.Table("attachment").Join("LEFT", "`user`", "attachment.uploader_id "+
"= `user`.id").Where("attachment.type = ? and (uploader_id= ? or is_private = ?) and attachment.decompress_state = ?", TypeCloudBrainTwo, userID, false, DecompressStateDone).Find(&attachments); err != nil {
return nil, err
}
return attachments, nil
}

func GetModelArtsTrainAttachments(userID int64) ([]*AttachmentUsername, error) {
return getModelArtsTrainAttachments(x, userID)
}

func CanDelAttachment(isSigned bool, user *User, attach *Attachment) bool {
if !isSigned {
return false


+ 6
- 0
models/cloudbrain.go View File

@@ -19,6 +19,9 @@ type JobType string
type ModelArtsJobStatus string

const (
NPUResource = "NPU"
GPUResource = "CPU/GPU"

JobWaiting CloudbrainStatus = "WAITING"
JobStopped CloudbrainStatus = "STOPPED"
JobSucceeded CloudbrainStatus = "SUCCEEDED"
@@ -88,6 +91,9 @@ type Cloudbrain struct {
UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"`
Duration int64
TrainJobDuration string
Image string //GPU镜像名称
GpuQueue string //GPU类型即GPU队列
ResourceSpecId int //GPU规格id
DeletedAt time.Time `xorm:"deleted"`
CanDebug bool `xorm:"-"`
CanDel bool `xorm:"-"`


+ 31
- 39
models/user_business_analysis.go View File

@@ -1,7 +1,6 @@
package models

import (
"encoding/json"
"fmt"
"sort"
"strconv"
@@ -202,15 +201,7 @@ func QueryUserStaticDataAll(opts *UserBusinessAnalysisQueryOptions) ([]*UserBusi
return nil, 0
}
log.Info("query return total:" + fmt.Sprint(allCount))
if allCount == 0 {
CommitCodeSizeMap, err := GetAllUserKPIStats()
if err != nil {
log.Info("query commit code errr.")
} else {
log.Info("query commit code size, len=" + fmt.Sprint(len(CommitCodeSizeMap)))
}
RefreshUserStaticAllTabel(make(map[string]int), CommitCodeSizeMap)
}

pageSize := 1000
totalPage := int(allCount) / pageSize
userBusinessAnalysisReturnList := UserBusinessAnalysisAllList{}
@@ -370,7 +361,7 @@ func RefreshUserStaticAllTabel(wikiCountMap map[string]int, CommitCodeSizeMap ma

CodeMergeCountMap := queryPullRequest(start_unix, end_unix)
CommitCountMap := queryCommitAction(start_unix, end_unix, 5)
IssueCountMap := queryAction(start_unix, end_unix, 6)
IssueCountMap := queryCreateIssue(start_unix, end_unix)

CommentCountMap := queryComment(start_unix, end_unix)
FocusRepoCountMap := queryWatch(start_unix, end_unix)
@@ -395,7 +386,7 @@ func RefreshUserStaticAllTabel(wikiCountMap map[string]int, CommitCodeSizeMap ma
var indexTotal int64
indexTotal = 0
for {
sess.Select("`user`.*").Table("user").Where(cond).Limit(Page_SIZE, int(indexTotal))
sess.Select("`user`.*").Table("user").Where(cond).OrderBy("id asc").Limit(Page_SIZE, int(indexTotal))
userList := make([]*User, 0)
sess.Find(&userList)
for i, userRecord := range userList {
@@ -528,7 +519,7 @@ func CounDataByDateAndReCount(wikiCountMap map[string]int, startTime time.Time,
DataDate := startTime.Format("2006-01-02")
CodeMergeCountMap := queryPullRequest(start_unix, end_unix)
CommitCountMap := queryCommitAction(start_unix, end_unix, 5)
IssueCountMap := queryAction(start_unix, end_unix, 6)
IssueCountMap := queryCreateIssue(start_unix, end_unix)

CommentCountMap := queryComment(start_unix, end_unix)
FocusRepoCountMap := queryWatch(start_unix, end_unix)
@@ -559,7 +550,7 @@ func CounDataByDateAndReCount(wikiCountMap map[string]int, startTime time.Time,
var indexTotal int64
indexTotal = 0
for {
sess.Select("`user`.*").Table("user").Where(cond).Limit(Page_SIZE, int(indexTotal))
sess.Select("`user`.*").Table("user").Where(cond).OrderBy("id asc").Limit(Page_SIZE, int(indexTotal))
userList := make([]*User, 0)
sess.Find(&userList)

@@ -709,7 +700,7 @@ func querySolveIssue(start_unix int64, end_unix int64) map[int64]int {
issueAssigneesList := make([]*IssueAssignees, 0)
sess.Select("issue_assignees.*").Table("issue_assignees").
Join("inner", "issue", "issue.id=issue_assignees.issue_id").
Where(cond).Limit(Page_SIZE, int(indexTotal))
Where(cond).OrderBy("issue_assignees.id asc").Limit(Page_SIZE, int(indexTotal))

sess.Find(&issueAssigneesList)

@@ -744,7 +735,7 @@ func queryPullRequest(start_unix int64, end_unix int64) map[int64]int {
indexTotal = 0
for {
issueList := make([]*Issue, 0)
sess.Select("issue.*").Table("issue").Join("inner", "pull_request", "issue.id=pull_request.issue_id").Where(cond).Limit(Page_SIZE, int(indexTotal))
sess.Select("issue.*").Table("issue").Join("inner", "pull_request", "issue.id=pull_request.issue_id").Where(cond).OrderBy("issue.id asc").Limit(Page_SIZE, int(indexTotal))
sess.Find(&issueList)
log.Info("query issue(PR) size=" + fmt.Sprint(len(issueList)))
for _, issueRecord := range issueList {
@@ -777,7 +768,7 @@ func queryCommitAction(start_unix int64, end_unix int64, actionType int64) map[i
var indexTotal int64
indexTotal = 0
for {
sess.Select("id,user_id,op_type,act_user_id").Table("action").Where(cond).Limit(Page_SIZE, int(indexTotal))
sess.Select("id,user_id,op_type,act_user_id").Table("action").Where(cond).OrderBy("id asc").Limit(Page_SIZE, int(indexTotal))
actionList := make([]*Action, 0)
sess.Find(&actionList)

@@ -799,29 +790,30 @@ func queryCommitAction(start_unix int64, end_unix int64, actionType int64) map[i
return resultMap
}

func queryAction(start_unix int64, end_unix int64, actionType int64) map[int64]int {
func queryCreateIssue(start_unix int64, end_unix int64) map[int64]int {

sess := x.NewSession()
defer sess.Close()
resultMap := make(map[int64]int)
cond := "op_type=" + fmt.Sprint(actionType) + " and created_unix>=" + fmt.Sprint(start_unix) + " and created_unix<=" + fmt.Sprint(end_unix)
cond := "is_pull=false and created_unix>=" + fmt.Sprint(start_unix) + " and created_unix<=" + fmt.Sprint(end_unix)

count, err := sess.Where(cond).Count(new(Action))
count, err := sess.Where(cond).Count(new(Issue))
if err != nil {
log.Info("query Action error. return.")
log.Info("query Issue error. return.")
return resultMap
}
var indexTotal int64
indexTotal = 0
for {
sess.Select("id,user_id,op_type,act_user_id").Table("action").Where(cond).Limit(Page_SIZE, int(indexTotal))
actionList := make([]*Action, 0)
sess.Find(&actionList)
log.Info("query action size=" + fmt.Sprint(len(actionList)))
for _, actionRecord := range actionList {
if _, ok := resultMap[actionRecord.UserID]; !ok {
resultMap[actionRecord.UserID] = 1
sess.Select("id,poster_id").Table("issue").Where(cond).OrderBy("id asc").Limit(Page_SIZE, int(indexTotal))
issueList := make([]*Issue, 0)
sess.Find(&issueList)
log.Info("query issue size=" + fmt.Sprint(len(issueList)))
for _, issueRecord := range issueList {
if _, ok := resultMap[issueRecord.PosterID]; !ok {
resultMap[issueRecord.PosterID] = 1
} else {
resultMap[actionRecord.UserID] += 1
resultMap[issueRecord.PosterID] += 1
}
}
indexTotal += Page_SIZE
@@ -830,6 +822,7 @@ func queryAction(start_unix int64, end_unix int64, actionType int64) map[int64]i
}
}
return resultMap

}

func queryComment(start_unix int64, end_unix int64) map[int64]int {
@@ -846,7 +839,7 @@ func queryComment(start_unix int64, end_unix int64) map[int64]int {
var indexTotal int64
indexTotal = 0
for {
sess.Select("id,type,poster_id").Table("comment").Where(cond).Limit(Page_SIZE, int(indexTotal))
sess.Select("id,type,poster_id").Table("comment").Where(cond).OrderBy("id asc").Limit(Page_SIZE, int(indexTotal))
commentList := make([]*Comment, 0)
sess.Find(&commentList)
log.Info("query Comment size=" + fmt.Sprint(len(commentList)))
@@ -882,7 +875,7 @@ func queryWatch(start_unix int64, end_unix int64) map[int64]int {
indexTotal = 0
for {
watchList := make([]*Watch, 0)
sess.Select("id,user_id,repo_id").Table("watch").Where(cond).Limit(Page_SIZE, int(indexTotal))
sess.Select("id,user_id,repo_id").Table("watch").Where(cond).OrderBy("id asc").Limit(Page_SIZE, int(indexTotal))
sess.Find(&watchList)

log.Info("query Watch size=" + fmt.Sprint(len(watchList)))
@@ -920,7 +913,7 @@ func queryStar(start_unix int64, end_unix int64) map[int64]int {
var indexTotal int64
indexTotal = 0
for {
sess.Select("id,uid,repo_id").Table("star").Where(cond).Limit(Page_SIZE, int(indexTotal))
sess.Select("id,uid,repo_id").Table("star").Where(cond).OrderBy("id asc").Limit(Page_SIZE, int(indexTotal))
starList := make([]*Star, 0)
sess.Find(&starList)

@@ -956,7 +949,7 @@ func queryFollow(start_unix int64, end_unix int64) map[int64]int {
var indexTotal int64
indexTotal = 0
for {
sess.Select("id,user_id,follow_id").Table("follow").Where(cond).Limit(Page_SIZE, int(indexTotal))
sess.Select("id,user_id,follow_id").Table("follow").Where(cond).OrderBy("id asc").Limit(Page_SIZE, int(indexTotal))
followList := make([]*Follow, 0)
sess.Find(&followList)

@@ -992,7 +985,7 @@ func queryDatasetSize(start_unix int64, end_unix int64) map[int64]int {
var indexTotal int64
indexTotal = 0
for {
sess.Select("id,uploader_id,size").Table("attachment").Where(cond).Limit(Page_SIZE, int(indexTotal))
sess.Select("id,uploader_id,size").Table("attachment").Where(cond).OrderBy("id asc").Limit(Page_SIZE, int(indexTotal))
attachmentList := make([]*Attachment, 0)
sess.Find(&attachmentList)

@@ -1028,7 +1021,7 @@ func queryUserCreateRepo(start_unix int64, end_unix int64) map[int64]int {
var indexTotal int64
indexTotal = 0
for {
sess.Select("id,owner_id,name").Table("repository").Where(cond).Limit(Page_SIZE, int(indexTotal))
sess.Select("id,owner_id,name").Table("repository").Where(cond).OrderBy("id asc").Limit(Page_SIZE, int(indexTotal))
repoList := make([]*Repository, 0)
sess.Find(&repoList)
log.Info("query Repository size=" + fmt.Sprint(len(repoList)))
@@ -1099,8 +1092,7 @@ func queryUserRepoOpenIIndex(start_unix int64, end_unix int64) map[int64]float64
}
}

userMapJson, _ := json.Marshal(userMap)
log.Info("userMapJson=" + string(userMapJson))
log.Info("user openi index size=" + fmt.Sprint(len(userMap)))

return userMap
}
@@ -1119,7 +1111,7 @@ func queryLoginCount(start_unix int64, end_unix int64) map[int64]int {
var indexTotal int64
indexTotal = 0
for {
statictisSess.Select("id,u_id").Table("user_login_log").Where(cond).Limit(Page_SIZE, int(indexTotal))
statictisSess.Select("id,u_id").Table("user_login_log").Where(cond).OrderBy("id asc").Limit(Page_SIZE, int(indexTotal))
userLoginLogList := make([]*UserLoginLog, 0)
statictisSess.Find(&userLoginLogList)
log.Info("query user login size=" + fmt.Sprint(len(userLoginLogList)))
@@ -1135,7 +1127,7 @@ func queryLoginCount(start_unix int64, end_unix int64) map[int64]int {
break
}
}
log.Info("user login size=" + fmt.Sprint(len(resultMap)))
return resultMap
}



+ 131
- 11
modules/cloudbrain/cloudbrain.go View File

@@ -1,6 +1,8 @@
package cloudbrain

import (
"code.gitea.io/gitea/modules/storage"
"encoding/json"
"errors"
"strconv"

@@ -107,6 +109,9 @@ func GenerateTask(ctx *context.Context, jobName, image, command, uuid, codePath,
uuid

var resourceSpec *models.ResourceSpec
if ResourceSpecs == nil {
json.Unmarshal([]byte(setting.ResourceSpecs), &ResourceSpecs)
}
for _, spec := range ResourceSpecs.ResourceSpec {
if resourceSpecId == spec.Id {
resourceSpec = spec
@@ -185,28 +190,143 @@ func GenerateTask(ctx *context.Context, jobName, image, command, uuid, codePath,
},
})
if err != nil {
log.Error("CreateJob failed:", err.Error())
log.Error("CreateJob failed:", err.Error(), ctx.Data["MsgID"])
return err
}
if jobResult.Code != Success {
log.Error("CreateJob(%s) failed:%s", jobName, jobResult.Msg)
log.Error("CreateJob(%s) failed:%s", jobName, jobResult.Msg, ctx.Data["MsgID"])
return errors.New(jobResult.Msg)
}

var jobID = jobResult.Payload["jobId"].(string)
err = models.CreateCloudbrain(&models.Cloudbrain{
Status: string(models.JobWaiting),
UserID: ctx.User.ID,
RepoID: ctx.Repo.Repository.ID,
JobID: jobID,
JobName: jobName,
SubTaskName: SubTaskName,
JobType: jobType,
Type: models.TypeCloudBrainOne,
Uuid: uuid,
Status: string(models.JobWaiting),
UserID: ctx.User.ID,
RepoID: ctx.Repo.Repository.ID,
JobID: jobID,
JobName: jobName,
SubTaskName: SubTaskName,
JobType: jobType,
Type: models.TypeCloudBrainOne,
Uuid: uuid,
Image: image,
GpuQueue: gpuQueue,
ResourceSpecId: resourceSpecId,
ComputeResource: models.GPUResource,
})

if err != nil {
return err
}

return nil
}

func RestartTask(ctx *context.Context, task *models.Cloudbrain) error {
dataActualPath := setting.Attachment.Minio.RealPath +
setting.Attachment.Minio.Bucket + "/" +
setting.Attachment.Minio.BasePath +
models.AttachmentRelativePath(task.Uuid) +
task.Uuid
jobName := task.JobName

var resourceSpec *models.ResourceSpec
if ResourceSpecs == nil {
json.Unmarshal([]byte(setting.ResourceSpecs), &ResourceSpecs)
}
for _, spec := range ResourceSpecs.ResourceSpec {
if task.ResourceSpecId == spec.Id {
resourceSpec = spec
}
}

if resourceSpec == nil {
log.Error("no such resourceSpecId(%d)", task.ResourceSpecId, ctx.Data["MsgID"])
return errors.New("no such resourceSpec")
}

jobResult, err := CreateJob(jobName, models.CreateJobParams{
JobName: jobName,
RetryCount: 1,
GpuType: task.GpuQueue,
Image: task.Image,
TaskRoles: []models.TaskRole{
{
Name: SubTaskName,
TaskNumber: 1,
MinSucceededTaskCount: 1,
MinFailedTaskCount: 1,
CPUNumber: resourceSpec.CpuNum,
GPUNumber: resourceSpec.GpuNum,
MemoryMB: resourceSpec.MemMiB,
ShmMB: resourceSpec.ShareMemMiB,
Command: Command,
NeedIBDevice: false,
IsMainRole: false,
UseNNI: false,
},
},
Volumes: []models.Volume{
{
HostPath: models.StHostPath{
Path: storage.GetMinioPath(jobName, CodeMountPath + "/"),
MountPath: CodeMountPath,
ReadOnly: false,
},
},
{
HostPath: models.StHostPath{
Path: dataActualPath,
MountPath: DataSetMountPath,
ReadOnly: true,
},
},
{
HostPath: models.StHostPath{
Path: storage.GetMinioPath(jobName, ModelMountPath + "/"),
MountPath: ModelMountPath,
ReadOnly: false,
},
},
{
HostPath: models.StHostPath{
Path: storage.GetMinioPath(jobName, BenchMarkMountPath + "/"),
MountPath: BenchMarkMountPath,
ReadOnly: true,
},
},
{
HostPath: models.StHostPath{
Path: storage.GetMinioPath(jobName, Snn4imagenetMountPath + "/"),
MountPath: Snn4imagenetMountPath,
ReadOnly: true,
},
},
{
HostPath: models.StHostPath{
Path: storage.GetMinioPath(jobName, BrainScoreMountPath + "/"),
MountPath: BrainScoreMountPath,
ReadOnly: true,
},
},
},
})
if err != nil {
log.Error("CreateJob failed:", err.Error(), ctx.Data["MsgID"])
return err
}
if jobResult.Code != Success {
log.Error("CreateJob(%s) failed:%s", jobName, jobResult.Msg, ctx.Data["MsgID"])
return errors.New(jobResult.Msg)
}

var jobID = jobResult.Payload["jobId"].(string)
task.JobID = jobID
task.Status = string(models.JobWaiting)
err = models.UpdateJob(task)

if err != nil {
log.Error("UpdateJob(%s) failed:%v", jobName, err.Error(), ctx.Data["MsgID"])
return err
}



+ 13
- 16
modules/modelarts/modelarts.go View File

@@ -48,12 +48,8 @@ const (
PerPage = 10
IsLatestVersion = "1"
NotLatestVersion = "0"
// ComputeResource = "NPU"
NPUResource = "NPU"
GPUResource = "CPU/GPU"
AllResource = "all"
DebugType = -1
VersionCount = 1
DebugType = -1
VersionCount = 1

SortByCreateTime = "create_time"
ConfigTypeCustom = "custom"
@@ -215,14 +211,15 @@ func GenerateTask(ctx *context.Context, jobName, uuid, description, flavor strin
}
err = models.CreateCloudbrain(&models.Cloudbrain{

Status: string(models.JobWaiting),
UserID: ctx.User.ID,
RepoID: ctx.Repo.Repository.ID,
JobID: jobResult.ID,
JobName: jobName,
JobType: string(models.JobTypeDebug),
Type: models.TypeCloudBrainTwo,
Uuid: uuid,
Status: string(models.JobWaiting),
UserID: ctx.User.ID,
RepoID: ctx.Repo.Repository.ID,
JobID: jobResult.ID,
JobName: jobName,
JobType: string(models.JobTypeDebug),
Type: models.TypeCloudBrainTwo,
Uuid: uuid,
ComputeResource: models.NPUResource,
})

if err != nil {
@@ -277,7 +274,7 @@ func GenerateTrainJob(ctx *context.Context, req *GenerateTrainJobReq) (err error
DatasetName: attach.Name,
CommitID: req.CommitID,
IsLatestVersion: req.IsLatestVersion,
ComputeResource: NPUResource,
ComputeResource: models.NPUResource,
EngineID: req.EngineID,
TrainUrl: req.TrainUrl,
BranchName: req.BranchName,
@@ -360,7 +357,7 @@ func GenerateTrainJobVersion(ctx *context.Context, req *GenerateTrainJobReq, job
CommitID: req.CommitID,
IsLatestVersion: req.IsLatestVersion,
PreVersionName: req.PreVersionName,
ComputeResource: NPUResource,
ComputeResource: models.GPUResource,
EngineID: req.EngineID,
TrainUrl: req.TrainUrl,
BranchName: req.BranchName,


+ 3
- 3
modules/modelarts/resty.go View File

@@ -174,7 +174,7 @@ sendjob:
return &result, nil
}

func StopJob(jobID string, param models.NotebookAction) (*models.NotebookActionResult, error) {
func ManageNotebook(jobID string, param models.NotebookAction) (*models.NotebookActionResult, error) {
checkSetting()
client := getRestyClient()
var result models.NotebookActionResult
@@ -207,8 +207,8 @@ sendjob:
}

if len(response.ErrorCode) != 0 {
log.Error("StopJob failed(%s): %s", response.ErrorCode, response.ErrorMsg)
return &result, fmt.Errorf("StopJob failed(%s): %s", response.ErrorCode, response.ErrorMsg)
log.Error("ManageNotebook failed(%s): %s", response.ErrorCode, response.ErrorMsg)
return &result, fmt.Errorf("ManageNotebook failed(%s): %s", response.ErrorCode, response.ErrorMsg)
}

return &result, nil


+ 21
- 2
modules/repository/elk_pagedata.go View File

@@ -21,7 +21,8 @@ type Fields struct {
Format string `json:"format"`
}
type MatchPhrase struct {
Message string `json:"message"`
Message string `json:"message,omitempty"`
TagName string `json:"tagName.keyword,omitempty"`
}
type Should struct {
MatchPhrase MatchPhrase `json:"match_phrase"`
@@ -144,7 +145,7 @@ func ProjectViewInit(User string, Project string, Gte string, Lte string) (proje
inputStruct.Batch[0].Request.Params.Body.Fields = make([]Fields, 1)
inputStruct.Batch[0].Request.Params.Body.Fields[0].Field = setting.TimeField
inputStruct.Batch[0].Request.Params.Body.Fields[0].Format = setting.ElkTimeFormat
inputStruct.Batch[0].Request.Params.Body.Query.BoolIn.Filter = make([]Filter, 3)
inputStruct.Batch[0].Request.Params.Body.Query.BoolIn.Filter = make([]Filter, 4)
//限定查询时间
var timeRange Range
timeRange.Timestamptest.Gte = Gte
@@ -159,6 +160,24 @@ func ProjectViewInit(User string, Project string, Gte string, Lte string) (proje
var projectName FilterMatchPhrase
projectName.ProjectName = Project
inputStruct.Batch[0].Request.Params.Body.Query.BoolIn.Filter[2].FilterMatchPhrase = &projectName
//限定页面
var bool Bool
bool.Should = make([]Should, 14)
bool.Should[0].MatchPhrase.TagName = "%{[request][3]}"
bool.Should[1].MatchPhrase.TagName = "datasets?type=0"
bool.Should[2].MatchPhrase.TagName = "datasets?type=1"
bool.Should[3].MatchPhrase.TagName = "issues"
bool.Should[4].MatchPhrase.TagName = "labels"
bool.Should[5].MatchPhrase.TagName = "pulls"
bool.Should[6].MatchPhrase.TagName = "wiki"
bool.Should[7].MatchPhrase.TagName = "activity"
bool.Should[8].MatchPhrase.TagName = "cloudbrain"
bool.Should[9].MatchPhrase.TagName = "modelarts"
bool.Should[10].MatchPhrase.TagName = "blockchain"
bool.Should[11].MatchPhrase.TagName = "watchers"
bool.Should[12].MatchPhrase.TagName = "stars"
bool.Should[13].MatchPhrase.TagName = "forks"
inputStruct.Batch[0].Request.Params.Body.Query.BoolIn.Filter[3].Bool = &bool
return inputStruct
}



+ 4
- 0
modules/storage/local.go View File

@@ -80,3 +80,7 @@ func (l *LocalStorage) HasObject(path string) (bool, error) {
func (l *LocalStorage) UploadObject(fileName, filePath string) error {
return nil
}

func (l *LocalStorage) DeleteDir(dir string) error {
return nil
}

+ 30
- 0
modules/storage/minio.go View File

@@ -11,6 +11,9 @@ import (
"strings"
"time"

"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"

"github.com/minio/minio-go"
)

@@ -76,6 +79,29 @@ func (m *MinioStorage) Delete(path string) error {
return m.client.RemoveObject(m.bucket, m.buildMinioPath(path))
}

// Delete delete a file
func (m *MinioStorage) DeleteDir(dir string) error {
objectsCh := make(chan string)

// Send object names that are needed to be removed to objectsCh
go func() {
defer close(objectsCh)
// List all objects from a bucket-name with a matching prefix.
for object := range m.client.ListObjects(m.bucket, dir, true, nil) {
if object.Err != nil {
log.Error("ListObjects failed:%v", object.Err)
}
objectsCh <- object.Key
}
}()

for rErr := range m.client.RemoveObjects(m.bucket, objectsCh) {
log.Error("Error detected during deletion: ", rErr)
}

return nil
}

//Get Presigned URL for get object
func (m *MinioStorage) PresignedGetURL(path string, fileName string) (string, error) {
// Set request parameters for content-disposition.
@@ -128,3 +154,7 @@ func (m *MinioStorage) UploadObject(fileName, filePath string) error {
_, err := m.client.FPutObject(m.bucket, fileName, filePath, minio.PutObjectOptions{})
return err
}

func GetMinioPath(jobName, suffixPath string) string {
return setting.Attachment.Minio.RealPath + setting.Attachment.Minio.Bucket + "/" + setting.CBCodePathPrefix + jobName + suffixPath
}

+ 1
- 0
modules/storage/storage.go View File

@@ -23,6 +23,7 @@ type ObjectStorage interface {
Save(path string, r io.Reader) (int64, error)
Open(path string) (io.ReadCloser, error)
Delete(path string) error
DeleteDir(dir string) error
PresignedGetURL(path string, fileName string) (string, error)
PresignedPutURL(path string) (string, error)
HasObject(path string) (bool, error)


+ 4
- 0
options/locale/locale_en-US.ini View File

@@ -778,6 +778,10 @@ datasets = Datasets
datasets.desc = Enable Dataset
cloudbrain_helper=Use GPU/NPU resources to open notebooks, model training tasks, etc.

model_manager = Model
model_noright=No right
model_rename=Duplicate model name, please modify model name.

debug=Debug
stop=Stop
delete=Delete


+ 2
- 0
options/locale/locale_zh-CN.ini View File

@@ -784,8 +784,10 @@ cloudbrain_helper=使用GPU/NPU资源,开启Notebook、模型训练任务等

model_manager = 模型
model_noright=无权限操作
model_rename=模型名称重复,请修改模型名称

debug=调试
debug_again=再次调试
stop=停止
delete=删除
model_download=模型下载


+ 5
- 0
package-lock.json View File

@@ -11655,6 +11655,11 @@
"autolinker": "~0.28.0"
}
},
"remixicon": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/remixicon/-/remixicon-2.5.0.tgz",
"integrity": "sha512-q54ra2QutYDZpuSnFjmeagmEiN9IMo56/zz5dDNitzKD23oFRw77cWo4TsrAdmdkPiEn8mxlrTqxnkujDbEGww=="
},
"remove-bom-buffer": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/remove-bom-buffer/-/remove-bom-buffer-3.0.0.tgz",


+ 1
- 0
package.json View File

@@ -42,6 +42,7 @@
"postcss-preset-env": "6.7.0",
"postcss-safe-parser": "4.0.2",
"qs": "6.9.4",
"remixicon": "2.5.0",
"spark-md5": "3.0.1",
"svg-sprite-loader": "5.0.0",
"svgo": "1.3.2",


+ 23
- 1
routers/api/v1/repo/modelarts.go View File

@@ -7,6 +7,7 @@ package repo

import (
"net/http"
"os"
"strconv"
"strings"

@@ -14,6 +15,7 @@ import (
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/modelarts"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/storage"
)

@@ -237,7 +239,7 @@ func DelTrainJobVersion(ctx *context.APIContext) {
JobID: jobID,
})
if err != nil {
ctx.ServerError("get VersionListCount faild", err)
ctx.ServerError("get VersionListCount failed", err)
return
}
if VersionListCount > 0 {
@@ -255,6 +257,8 @@ func DelTrainJobVersion(ctx *context.APIContext) {
return
}
}
} else { //已删除该任务下的所有版本
deleteJobStorage(task.JobName)
}

ctx.JSON(http.StatusOK, map[string]interface{}{
@@ -321,3 +325,21 @@ func ModelList(ctx *context.APIContext) {
"PageIsCloudBrain": true,
})
}

func deleteJobStorage(jobName string) error {
//delete local
localJobPath := setting.JobPath + jobName
err := os.RemoveAll(localJobPath)
if err != nil {
log.Error("RemoveAll(%s) failed:%v", localJobPath, err)
}

//delete oss
dirPath := setting.CodePathPrefix + jobName + "/"
err = storage.ObsRemoveObject(setting.Bucket, dirPath)
if err != nil {
log.Error("ObsRemoveObject(%s) failed:%v", localJobPath, err)
}

return nil
}

+ 17
- 0
routers/repo/ai_model_manage.go View File

@@ -105,6 +105,23 @@ func saveModelByParameters(jobId string, versionName string, name string, versio
return nil
}

func SaveNewNameModel(ctx *context.Context) {
name := ctx.Query("Name")
if name == "" {
ctx.Error(500, fmt.Sprintf("name or version is null."))
return
}

aimodels := models.QueryModelByName(name, ctx.Repo.Repository.ID)
if len(aimodels) > 0 {
ctx.Error(500, ctx.Tr("repo.model_rename"))
return
}
SaveModel(ctx)

log.Info("save model end.")
}

func SaveModel(ctx *context.Context) {
log.Info("save model start.")
JobId := ctx.Query("JobId")


+ 156
- 34
routers/repo/cloudbrain.go View File

@@ -206,7 +206,7 @@ func CloudBrainCreate(ctx *context.Context, form auth.CreateCloudBrainForm) {
}
repo := ctx.Repo.Repository
downloadCode(repo, codePath)
uploadCodeToMinio(codePath+"/", jobName, "/code/")
uploadCodeToMinio(codePath+"/", jobName, cloudbrain.CodeMountPath+"/")

modelPath := setting.JobPath + jobName + cloudbrain.ModelMountPath + "/"
mkModelPath(modelPath)
@@ -236,15 +236,89 @@ func CloudBrainCreate(ctx *context.Context, form auth.CreateCloudBrainForm) {
uploadCodeToMinio(brainScorePath+"/", jobName, cloudbrain.BrainScoreMountPath+"/")
}

err = cloudbrain.GenerateTask(ctx, jobName, image, command, uuid, codePath, getMinioPath(jobName, cloudbrain.ModelMountPath+"/"),
getMinioPath(jobName, cloudbrain.BenchMarkMountPath+"/"), getMinioPath(jobName, cloudbrain.Snn4imagenetMountPath+"/"),
getMinioPath(jobName, cloudbrain.BrainScoreMountPath+"/"), jobType, gpuQueue, resourceSpecId)
err = cloudbrain.GenerateTask(ctx, jobName, image, command, uuid, storage.GetMinioPath(jobName, cloudbrain.CodeMountPath+"/"),
storage.GetMinioPath(jobName, cloudbrain.ModelMountPath+"/"),
storage.GetMinioPath(jobName, cloudbrain.BenchMarkMountPath+"/"), storage.GetMinioPath(jobName, cloudbrain.Snn4imagenetMountPath+"/"),
storage.GetMinioPath(jobName, cloudbrain.BrainScoreMountPath+"/"), jobType, gpuQueue, resourceSpecId)
if err != nil {
cloudBrainNewDataPrepare(ctx)
ctx.RenderWithErr(err.Error(), tplCloudBrainNew, &form)
return
}
ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/debugjob")
ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/debugjob?debugListType=all")
}

func CloudBrainRestart(ctx *context.Context) {
var jobID = ctx.Params(":jobid")
var resultCode = "0"
var errorMsg = ""
var status = ""

for {
task, err := models.GetCloudbrainByJobID(jobID)
if err != nil {
log.Error("GetCloudbrainByJobID(%s) failed:%v", jobID, err.Error(), ctx.Data["MsgID"])
resultCode = "-1"
errorMsg = "system error"
break
}

if task.Status != string(models.JobStopped) && task.Status != string(models.JobSucceeded) && task.Status != string(models.JobFailed) {
log.Error("the job(%s) is not stopped", task.JobName, ctx.Data["MsgID"])
resultCode = "-1"
errorMsg = "the job is not stopped"
break
}

if task.Image == "" || task.GpuQueue == "" || task.Type != models.TypeCloudBrainOne {
log.Error("the job(%s) version is too old", task.JobName, ctx.Data["MsgID"])
resultCode = "-1"
errorMsg = "the job's version is too old and can not be restarted"
break
}

if !ctx.IsSigned || (ctx.User.ID != task.UserID && !ctx.IsUserSiteAdmin()){
log.Error("the user has no right ro restart the job", task.JobName, ctx.Data["MsgID"])
resultCode = "-1"
errorMsg = "you have no right to restart the job"
break
}

count, err := models.GetCloudbrainCountByUserID(ctx.User.ID)
if err != nil {
log.Error("GetCloudbrainCountByUserID failed:%v", err, ctx.Data["MsgID"])
resultCode = "-1"
errorMsg = "system error"
break
} else {
if count >= 1 {
log.Error("the user already has running or waiting task", ctx.Data["MsgID"])
resultCode = "-1"
errorMsg = "the user already has running or waiting task"
break
}
}

err = cloudbrain.RestartTask(ctx, task)
if err != nil {
log.Error("RestartTask failed:%v", err.Error(), ctx.Data["MsgID"])
resultCode = "-1"
errorMsg = "system error"
break
}

status = task.Status
jobID = task.JobID

break
}

ctx.JSON(200, map[string]string{
"result_code": resultCode,
"error_msg": errorMsg,
"status": status,
"job_id": jobID,
})
}

func CloudBrainShow(ctx *context.Context) {
@@ -351,32 +425,53 @@ func CloudBrainCommitImage(ctx *context.Context, form auth.CommitImageCloudBrain

func CloudBrainStop(ctx *context.Context) {
var jobID = ctx.Params(":jobid")
task, err := models.GetCloudbrainByJobID(jobID)
if err != nil {
ctx.ServerError("GetCloudbrainByJobID failed", err)
return
}
var resultCode = "0"
var errorMsg = ""
var status = ""

if task.Status == string(models.JobStopped) || task.Status == string(models.JobFailed) {
log.Error("the job(%s) has been stopped", task.JobName, ctx.Data["msgID"])
ctx.ServerError("the job has been stopped", errors.New("the job has been stopped"))
return
}
for {
task, err := models.GetCloudbrainByJobID(jobID)
if err != nil {
log.Error("GetCloudbrainByJobID(%s) failed:%v", task.JobName, err, ctx.Data["msgID"])
resultCode = "-1"
errorMsg = "system error"
break
}

err = cloudbrain.StopJob(jobID)
if err != nil {
log.Error("StopJob(%s) failed:%v", task.JobName, err.Error(), ctx.Data["msgID"])
ctx.ServerError("StopJob failed", err)
return
}
if task.Status == string(models.JobStopped) || task.Status == string(models.JobFailed) {
log.Error("the job(%s) has been stopped", task.JobName, ctx.Data["msgID"])
resultCode = "-1"
errorMsg = "system error"
break
}

task.Status = string(models.JobStopped)
err = models.UpdateJob(task)
if err != nil {
ctx.ServerError("UpdateJob failed", err)
return
err = cloudbrain.StopJob(jobID)
if err != nil {
log.Error("StopJob(%s) failed:%v", task.JobName, err, ctx.Data["msgID"])
resultCode = "-1"
errorMsg = "system error"
break
}

task.Status = string(models.JobStopped)
err = models.UpdateJob(task)
if err != nil {
log.Error("UpdateJob(%s) failed:%v", task.JobName, err, ctx.Data["msgID"])
resultCode = "-1"
errorMsg = "system error"
break
}

status = task.Status
break
}
ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/debugjob")

ctx.JSON(200, map[string]string{
"result_code": resultCode,
"error_msg": errorMsg,
"status": status,
"job_id": jobID,
})
}

func StopJobsByUserID(userID int64) {
@@ -423,7 +518,7 @@ func StopJobs(cloudBrains []*models.Cloudbrain) {
Action: models.ActionStop,
}
err := retry(3, time.Second*30, func() error {
_, err := modelarts.StopJob(taskInfo.JobID, param)
_, err := modelarts.ManageNotebook(taskInfo.JobID, param)
return err
})
logErrorAndUpdateJobStatus(err, taskInfo)
@@ -478,7 +573,9 @@ func CloudBrainDel(ctx *context.Context) {
ctx.ServerError("DeleteJob failed", err)
return
}
ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/debugjob")

deleteJobStorage(task.JobName, models.TypeCloudBrainOne)
ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/debugjob?debugListType=all")
}

func CloudBrainShowModels(ctx *context.Context) {
@@ -560,7 +657,7 @@ func getImages(ctx *context.Context, imageType string) {

func GetModelDirs(jobName string, parentDir string) (string, error) {
var req string
modelActualPath := getMinioPath(jobName, cloudbrain.ModelMountPath+"/")
modelActualPath := storage.GetMinioPath(jobName, cloudbrain.ModelMountPath+"/")
if parentDir == "" {
req = "baseDir=" + modelActualPath
} else {
@@ -570,10 +667,6 @@ func GetModelDirs(jobName string, parentDir string) (string, error) {
return getDirs(req)
}

func getMinioPath(jobName, suffixPath string) string {
return setting.Attachment.Minio.RealPath + setting.Attachment.Minio.Bucket + "/" + setting.CBCodePathPrefix + jobName + suffixPath
}

func CloudBrainDownloadModel(ctx *context.Context) {
parentDir := ctx.Query("parentDir")
fileName := ctx.Query("fileName")
@@ -756,6 +849,35 @@ func mkModelPath(modelPath string) error {
return nil
}

func deleteJobStorage(jobName string, cloudbrainType int) error {
//delete local
localJobPath := setting.JobPath + jobName
err := os.RemoveAll(localJobPath)
if err != nil {
log.Error("RemoveAll(%s) failed:%v", localJobPath, err)
}

//delete oss
if cloudbrainType == models.TypeCloudBrainOne {
dirPath := setting.CBCodePathPrefix + jobName + "/"
err = storage.Attachments.DeleteDir(dirPath)
if err != nil {
log.Error("DeleteDir(%s) failed:%v", localJobPath, err)
}
} else if cloudbrainType == models.TypeCloudBrainTwo {
//dirPath := setting.CodePathPrefix + jobName + "/"
//err = storage.ObsRemoveObject(setting.Bucket, dirPath)
//if err != nil {
// log.Error("ObsRemoveObject(%s) failed:%v", localJobPath, err)
//}
log.Info("no need to delete")
} else {
log.Error("cloudbrainType(%d) error", cloudbrainType)
}

return nil
}

func SyncCloudbrainStatus() {
cloudBrains, err := models.GetCloudBrainUnStoppedJob()
if err != nil {


+ 1
- 0
routers/repo/milestone.go View File

@@ -268,6 +268,7 @@ func MilestoneIssuesAndPulls(ctx *context.Context) {

ctx.Data["CanWriteIssues"] = ctx.Repo.CanWriteIssuesOrPulls(false)
ctx.Data["CanWritePulls"] = ctx.Repo.CanWriteIssuesOrPulls(true)
ctx.Data["PageIsIssueList"] = true

ctx.HTML(200, tplMilestoneIssues)
}

+ 109
- 48
routers/repo/modelarts.go View File

@@ -42,6 +42,7 @@ const (

func DebugJobIndex(ctx *context.Context) {
debugListType := ctx.Query("debugListType")
ctx.Data["ListType"] = debugListType
MustEnableCloudbrain(ctx)
repo := ctx.Repo.Repository
page := ctx.QueryInt("page")
@@ -50,11 +51,11 @@ func DebugJobIndex(ctx *context.Context) {
}
debugType := modelarts.DebugType
jobType := string(models.JobTypeDebug)
if debugListType == modelarts.GPUResource {
if debugListType == models.GPUResource {
debugType = models.TypeCloudBrainOne
jobType = ""
}
if debugListType == modelarts.NPUResource {
if debugListType == models.NPUResource {
debugType = models.TypeCloudBrainTwo
}

@@ -73,21 +74,13 @@ func DebugJobIndex(ctx *context.Context) {
}

for i, task := range ciTasks {
if task.Cloudbrain.Type == models.TypeCloudBrainOne {
ciTasks[i].CanDebug = cloudbrain.CanCreateOrDebugJob(ctx)
ciTasks[i].CanDel = cloudbrain.CanDeleteJob(ctx, &task.Cloudbrain)
ciTasks[i].Cloudbrain.ComputeResource = modelarts.GPUResource
}
if task.Cloudbrain.Type == models.TypeCloudBrainTwo {
ciTasks[i].CanDebug = cloudbrain.CanCreateOrDebugJob(ctx)
ciTasks[i].CanDel = cloudbrain.CanDeleteJob(ctx, &task.Cloudbrain)
ciTasks[i].Cloudbrain.ComputeResource = modelarts.NPUResource
}

ciTasks[i].CanDebug = cloudbrain.CanModifyJob(ctx, &task.Cloudbrain)
ciTasks[i].CanDel = cloudbrain.CanDeleteJob(ctx, &task.Cloudbrain)
ciTasks[i].Cloudbrain.ComputeResource = task.ComputeResource
}

pager := context.NewPagination(int(count), setting.UI.IssuePagingNum, page, 5)
pager.SetDefaultParams(ctx)
pager.AddParam(ctx, "debugListType", "ListType")
ctx.Data["Page"] = pager
ctx.Data["PageIsCloudBrain"] = true
ctx.Data["Tasks"] = ciTasks
@@ -156,7 +149,7 @@ func NotebookCreate(ctx *context.Context, form auth.CreateModelArtsNotebookForm)
ctx.RenderWithErr(err.Error(), tplModelArtsNotebookNew, &form)
return
}
ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/debugjob")
ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/debugjob?debugListType=all")
}

func NotebookShow(ctx *context.Context) {
@@ -232,38 +225,105 @@ func NotebookDebug(ctx *context.Context) {
ctx.Redirect(debugUrl)
}

func NotebookStop(ctx *context.Context) {
func NotebookManage(ctx *context.Context) {
var jobID = ctx.Params(":jobid")
log.Info(jobID)
task, err := models.GetCloudbrainByJobID(jobID)
if err != nil {
ctx.ServerError("GetCloudbrainByJobID failed", err)
return
}
var action = ctx.Params(":action")
var resultCode = "0"
var errorMsg = ""
var status = ""

if task.Status != string(models.JobRunning) {
log.Error("the job(%s) is not running", task.JobName)
ctx.ServerError("the job is not running", errors.New("the job is not running"))
return
}
for {
task, err := models.GetCloudbrainByJobID(jobID)
if err != nil {
log.Error("GetCloudbrainByJobID failed:%v", err, ctx.Data["MsgID"])
resultCode = "-1"
errorMsg = "system error"
break
}

param := models.NotebookAction{
Action: models.ActionStop,
}
res, err := modelarts.StopJob(jobID, param)
if err != nil {
log.Error("StopJob(%s) failed:%v", task.JobName, err.Error())
ctx.ServerError("StopJob failed", err)
return
}
if action == models.ActionStop {
if task.Status != string(models.ModelArtsRunning) {
log.Error("the job(%s) is not running", task.JobName, ctx.Data["MsgID"])
resultCode = "-1"
errorMsg = "the job is not running"
break
}

task.Status = res.CurrentStatus
err = models.UpdateJob(task)
if err != nil {
ctx.ServerError("UpdateJob failed", err)
return
if !ctx.IsSigned || (ctx.User.ID != task.UserID && !ctx.IsUserSiteAdmin() && !ctx.IsUserRepoOwner()){
log.Error("the user has no right ro stop the job", task.JobName, ctx.Data["MsgID"])
resultCode = "-1"
errorMsg = "you have no right to stop the job"
break
}
} else if action == models.ActionRestart {
if task.Status != string(models.ModelArtsStopped) && task.Status != string(models.ModelArtsStartFailed) && task.Status != string(models.ModelArtsCreateFailed) {
log.Error("the job(%s) is not stopped", task.JobName, ctx.Data["MsgID"])
resultCode = "-1"
errorMsg = "the job is not stopped"
break
}

if !ctx.IsSigned || (ctx.User.ID != task.UserID && !ctx.IsUserSiteAdmin()){
log.Error("the user has no right ro restart the job", task.JobName, ctx.Data["MsgID"])
resultCode = "-1"
errorMsg = "you have no right to restart the job"
break
}

count, err := models.GetCloudbrainNotebookCountByUserID(ctx.User.ID)
if err != nil {
log.Error("GetCloudbrainNotebookCountByUserID failed:%v", err, ctx.Data["MsgID"])
resultCode = "-1"
errorMsg = "system error"
break
} else {
if count >= 1 {
log.Error("the user already has running or waiting task", ctx.Data["MsgID"])
resultCode = "-1"
errorMsg = "you have already a running or waiting task, can not create more"
break
}
}

action = models.ActionStart
} else {
log.Error("the action(%s) is illegal", action, ctx.Data["MsgID"])
resultCode = "-1"
errorMsg = "非法操作"
break
}

param := models.NotebookAction{
Action: action,
}
res, err := modelarts.ManageNotebook(jobID, param)
if err != nil {
log.Error("ManageNotebook(%s) failed:%v", task.JobName, err.Error(), ctx.Data["MsgID"])
resultCode = "-1"
errorMsg = "启动失败"
break
}

task.Status = res.CurrentStatus
err = models.UpdateJob(task)
if err != nil {
log.Error("UpdateJob(%s) failed:%v", task.JobName, err.Error(), ctx.Data["MsgID"])
resultCode = "-1"
errorMsg = "system error"
break
}

status = task.Status

break
}
ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/debugjob")

ctx.JSON(200, map[string]string{
"result_code": resultCode,
"error_msg": errorMsg,
"status": status,
"job_id": jobID,
})
}

func NotebookDel(ctx *context.Context) {
@@ -274,7 +334,7 @@ func NotebookDel(ctx *context.Context) {
return
}

if task.Status != string(models.JobStopped) {
if task.Status != string(models.ModelArtsCreateFailed) && task.Status != string(models.ModelArtsStartFailed) && task.Status != string(models.ModelArtsStopped) {
log.Error("the job(%s) has not been stopped", task.JobName)
ctx.ServerError("the job has not been stopped", errors.New("the job has not been stopped"))
return
@@ -293,7 +353,7 @@ func NotebookDel(ctx *context.Context) {
return
}

ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/debugjob")
ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/debugjob?debugListType=all")
}

func TrainJobIndex(ctx *context.Context) {
@@ -323,6 +383,7 @@ func TrainJobIndex(ctx *context.Context) {
for i, task := range tasks {
tasks[i].CanDel = cloudbrain.CanDeleteJob(ctx, &task.Cloudbrain)
tasks[i].CanModify = cloudbrain.CanModifyJob(ctx, &task.Cloudbrain)
tasks[i].ComputeResource = models.NPUResource
}

pager := context.NewPagination(int(count), setting.UI.IssuePagingNum, page, 5)
@@ -364,7 +425,7 @@ func trainJobNewDataPrepare(ctx *context.Context) error {
var jobName = cutString(ctx.User.Name, 5) + t.Format("2006010215") + strconv.Itoa(int(t.Unix()))[5:]
ctx.Data["job_name"] = jobName

attachs, err := models.GetModelArtsUserAttachments(ctx.User.ID)
attachs, err := models.GetModelArtsTrainAttachments(ctx.User.ID)
if err != nil {
ctx.ServerError("GetAllUserAttachments failed:", err)
return err
@@ -433,7 +494,7 @@ func trainJobErrorNewDataPrepare(ctx *context.Context, form auth.CreateModelArts
var jobName = cutString(ctx.User.Name, 5) + t.Format("2006010215") + strconv.Itoa(int(t.Unix()))[5:]
ctx.Data["job_name"] = jobName

attachs, err := models.GetModelArtsUserAttachments(ctx.User.ID)
attachs, err := models.GetModelArtsTrainAttachments(ctx.User.ID)
if err != nil {
ctx.ServerError("GetAllUserAttachments failed:", err)
return err
@@ -521,7 +582,7 @@ func trainJobNewVersionDataPrepare(ctx *context.Context) error {
var jobName = cutString(ctx.User.Name, 5) + t.Format("2006010215") + strconv.Itoa(int(t.Unix()))[5:]
ctx.Data["job_name"] = task.JobName

attachs, err := models.GetModelArtsUserAttachments(ctx.User.ID)
attachs, err := models.GetModelArtsTrainAttachments(ctx.User.ID)
if err != nil {
ctx.ServerError("GetAllUserAttachments failed:", err)
return err
@@ -610,7 +671,7 @@ func versionErrorDataPrepare(ctx *context.Context, form auth.CreateModelArtsTrai
var jobName = cutString(ctx.User.Name, 5) + t.Format("2006010215") + strconv.Itoa(int(t.Unix()))[5:]
ctx.Data["job_name"] = task.JobName

attachs, err := models.GetModelArtsUserAttachments(ctx.User.ID)
attachs, err := models.GetModelArtsTrainAttachments(ctx.User.ID)
if err != nil {
ctx.ServerError("GetAllUserAttachments failed:", err)
return err


+ 5
- 3
routers/routes/routes.go View File

@@ -968,10 +968,11 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Group("/cloudbrain", func() {
m.Group("/:jobid", func() {
m.Get("", reqRepoCloudBrainReader, repo.CloudBrainShow)
m.Get("/debug", reqRepoCloudBrainWriter, repo.CloudBrainDebug)
m.Get("/debug", cloudbrain.AdminOrJobCreaterRight, repo.CloudBrainDebug)
m.Post("/commit_image", cloudbrain.AdminOrOwnerOrJobCreaterRight, bindIgnErr(auth.CommitImageCloudBrainForm{}), repo.CloudBrainCommitImage)
m.Post("/stop", cloudbrain.AdminOrOwnerOrJobCreaterRight, repo.CloudBrainStop)
m.Post("/del", cloudbrain.AdminOrOwnerOrJobCreaterRight, repo.CloudBrainDel)
m.Post("/restart", reqRepoCloudBrainWriter, repo.CloudBrainRestart)
m.Get("/rate", reqRepoCloudBrainReader, repo.GetRate)
m.Get("/models", reqRepoCloudBrainReader, repo.CloudBrainShowModels)
m.Get("/download_model", cloudbrain.AdminOrOwnerOrJobCreaterRight, repo.CloudBrainDownloadModel)
@@ -981,6 +982,7 @@ func RegisterRoutes(m *macaron.Macaron) {
}, context.RepoRef())
m.Group("/modelmanage", func() {
m.Post("/create_model", reqRepoModelManageWriter, repo.SaveModel)
m.Post("/create_new_model", reqRepoModelManageWriter, repo.SaveNewNameModel)
m.Delete("/delete_model", repo.DeleteModel)
m.Put("/modify_model", repo.ModifyModelInfo)
m.Get("/show_model", reqRepoModelManageReader, repo.ShowModelTemplate)
@@ -1005,8 +1007,8 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Group("/notebook", func() {
m.Group("/:jobid", func() {
m.Get("", reqRepoCloudBrainReader, repo.NotebookShow)
m.Get("/debug", reqRepoCloudBrainWriter, repo.NotebookDebug)
m.Post("/stop", cloudbrain.AdminOrOwnerOrJobCreaterRight, repo.NotebookStop)
m.Get("/debug", cloudbrain.AdminOrJobCreaterRight, repo.NotebookDebug)
m.Post("/:action", reqRepoCloudBrainWriter, repo.NotebookManage)
m.Post("/del", cloudbrain.AdminOrOwnerOrJobCreaterRight, repo.NotebookDel)
})
m.Get("/create", reqRepoCloudBrainWriter, repo.NotebookNew)


+ 20
- 3
templates/repo/cloudbrain/new.tmpl View File

@@ -93,6 +93,14 @@
display: none;
}

.icons{
/* position: absolute !important;
right: 150px;
top: 14px;
z-index: 2; */
}


</style>

<div id="mask">
@@ -182,9 +190,10 @@
</select>
</div>

<div class="inline required field">
<div class="inline required field" style="position: relative;">
<label>镜像</label>
<input type="text" list="cloudbrain_image" placeholder="选择镜像" name="image" required autofocus maxlength="254">
<i class="times circle outline icon icons" style="visibility: hidden;" onclick="clearValue()"></i>
<datalist class="ui search" id="cloudbrain_image" style='width:385px;' name="image">
{{range .images}}
<option name="image" value="{{.Place}}">{{.PlaceView}}</option>
@@ -261,9 +270,17 @@
<script>
let form = document.getElementById('form_id');

$('#messageInfo').css('display','none')
let inputs = document.querySelectorAll('input[list]');
inputs[0].addEventListener('change', function() {
$(".icon.icons").css("visibility","visible")
});

$('#messageInfo').css('display','none')
function clearValue(){
context=inputs[0]
context.value=''
$(".icon.icons").css("visibility","hidden")
}
form.onsubmit = function(e){
let value_task = $("input[name='job_name']").val()
let value_image = $("input[name='image']").val()


+ 137
- 44
templates/repo/debugjob/index.tmpl View File

@@ -202,14 +202,20 @@
<div class="rect5"></div>
</div>
</div>
<!-- 提示框 -->
<div class="alert"></div>

<div class="alert"></div>
<div class="repository release dataset-list view">
{{template "repo/header" .}}
{{template "base/alert" .}}
<!-- 提示框 -->
<!-- 列表容器 -->
<div class="ui container">
<div class="ui two column stackable grid ">
<div class="ui negative message" style="display: none;">
<i class="close icon"></i>
<p></p>
</div>
<div class="ui two column stackable grid">
<div class="column">
<div class="ui blue small menu compact selectcloudbrain">
<a class="active item" href="{{.RepoLink}}/debugjob?debugListType=all">{{$.i18n.Tr "repo.modelarts.notebook"}}</a>
@@ -282,7 +288,7 @@
<div class="row">
<!-- 任务名 -->
<div class="four wide column">
<a class="title" href='{{if eq .ComputeResource "CPU/GPU"}}{{$.RepoLink}}/cloudbrain{{else}}{{$.RepoLink}}/modelarts/notebook{{end}}/{{.JobID}}' title="{{.JobName}}" style="font-size: 14px;">
<a class="title" href='{{if eq .ComputeResource "CPU/GPU"}}{{$.RepoLink}}/cloudbrain{{else}}{{$.RepoLink}}/modelarts/notebook{{end}}/{{.JobID}}' title="{{.JobName}}" style="font-size: 14px;">
<span class="fitted text_over" style="width: 90%;vertical-align: middle;">{{.JobName}}</span>
</a>
</div>
@@ -315,34 +321,44 @@
</a>
{{end}} -->
<!-- 调试 -->
{{if .CanDebug}}
{{if eq .ComputeResource "CPU/GPU"}}
<a id="model-debug-{{.JobID}}" class='ui basic {{if ne .Status "RUNNING"}} disabled {{else}}blue {{end}}button' href="{{$.RepoLink}}/cloudbrain/{{.JobID}}/debug" target="_blank">
{{$.i18n.Tr "repo.debug"}}
</a>
<form id="debugAgainForm-{{.JobID}}">
{{$.CsrfTokenHtml}}
{{if .CanDebug}}
{{if eq .Status "RUNNING"}}
<a style="margin: 0 1rem;" id="model-debug-{{.JobID}}" class='ui basic blue button' onclick='debugAgain("{{.JobID}}","{{if eq .ComputeResource "CPU/GPU"}}{{$.RepoLink}}/cloudbrain{{else}}{{$.RepoLink}}/modelarts/notebook{{end}}/{{.JobID}}/")'>
{{$.i18n.Tr "repo.debug"}}
</a>
{{else}}
<a id="model-debug-{{.JobID}}" class='ui basic {{if eq .Status "CREATING" "STOPPING" "WAITING" "STARTING"}} disabled {{else}}blue {{end}}button' onclick='debugAgain("{{.JobID}}","{{if eq .ComputeResource "CPU/GPU"}}{{$.RepoLink}}/cloudbrain{{else}}{{$.RepoLink}}/modelarts/notebook{{end}}/{{.JobID}}/")'>
{{$.i18n.Tr "repo.debug_again"}}
</a>
{{end}}
{{else}}
<a id="model-debug-{{.JobID}}" class='ui basic {{if ne .Status "RUNNING"}} disabled {{else}}blue {{end}}button' href="{{$.RepoLink}}/modelarts/notebook/{{.JobID}}/debug" target="_blank">
{{$.i18n.Tr "repo.debug"}}
<a class="ui basic disabled button">
{{$.i18n.Tr "repo.debug_again"}}
</a>
{{end}}
{{else}}
<a class="ui basic disabled button">
{{$.i18n.Tr "repo.debug"}}
</a>
{{end}}
</form>
<!-- 停止 -->
<form id="stopForm-{{.JobID}}" action="{{if eq .ComputeResource "CPU/GPU"}}{{$.RepoLink}}/cloudbrain{{else}}{{$.RepoLink}}/modelarts/notebook{{end}}/{{.JobID}}/stop" method="post" style="margin-left:-1px;">
<form id="stopForm-{{.JobID}}" style="margin-left:-1px;">
{{$.CsrfTokenHtml}}
{{if .CanDel}}
<a id="stop-model-debug-{{.JobID}}" class='ui basic {{if eq .Status "STOPPED" "FAILED" "START_FAILED" "STOPPING" "CREATING" "STARTING"}}disabled {{else}}blue {{end}}button' onclick="document.getElementById('stopForm-{{.JobID}}').submit();">
{{$.i18n.Tr "repo.stop"}}
</a>
{{if eq .ComputeResource "CPU/GPU" }}
<a id="stop-model-debug-{{.JobID}}" class='ui basic {{if eq .Status "STOPPED" "FAILED" "START_FAILED" "STOPPING" "CREATING" "STARTING"}}disabled {{else}}blue {{end}}button' onclick='stopDebug("{{.JobID}}","{{$.RepoLink}}/cloudbrain/{{.JobID}}/stop")'>
{{$.i18n.Tr "repo.stop"}}
</a>
{{else}}
<a id="stop-model-debug-{{.JobID}}" class='ui basic {{if eq .Status "STOPPED" "FAILED" "START_FAILED" "STOPPING" "CREATING" "STARTING"}}disabled {{else}}blue {{end}}button' onclick='stopDebug("{{.JobID}}","{{$.RepoLink}}/modelarts/notebook/{{.JobID}}/stop")'>
{{$.i18n.Tr "repo.stop"}}
</a>
{{end}}
{{else}}
<a class="ui basic disabled button" onclick="document.getElementById('stopForm-{{.JobID}}').submit();">
<a class="ui basic disabled button">
{{$.i18n.Tr "repo.stop"}}
</a>
{{end}}
<input type="hidden" name="debugListType" value="all">
</form>
<!-- 删除 -->
<form id="delForm-{{.JobID}}" action="{{if eq .ComputeResource "CPU/GPU"}}{{$.RepoLink}}/cloudbrain{{else}}{{$.RepoLink}}/modelarts/notebook{{end}}/{{.JobID}}/del" method="post">
@@ -463,10 +479,21 @@

<script>
// 调试和评分新开窗口
const {AppSubUrl, StaticUrlPrefix, csrf} = window.config;
let url={{.RepoLink}}
let getParam=location.search.split('?debugListType=').pop()
let getParam=getQueryVariable('debugListType')
let dropdownValue = getParam==='all'||getParam==='' ? '全部' : getParam
localStorage.setItem('all',location.href)
function getQueryVariable(variable)
{
let query = window.location.search.substring(1);
let vars = query.split("&");
for (let i=0;i<vars.length;i++) {
let pair = vars[i].split("=");
if(pair[0] == variable){return pair[1];}
}
return(false);
}
function stop(obj) {
if (obj.style.color != "rgb(204, 204, 204)") {
obj.target = '_blank'
@@ -489,6 +516,7 @@
onApprove: function() {
document.getElementById(delId).submit()
flag = true
$('.alert').html('操作成功!').removeClass('alert-danger').addClass('alert-success').show().delay(1500).fadeOut();
},
onHidden: function() {
if (flag == false) {
@@ -499,7 +527,69 @@
.modal('show')
}
}
function debugAgain(JobID,debugUrl){
if($('#' + JobID+ '-text').text()==="RUNNING"){
window.open(debugUrl+'debug')
}else{
$.ajax({
type:"POST",
url:debugUrl+'restart',
data:$('#debugAgainForm-'+JobID).serialize(),
success:function(res){
if(res.result_code==="0"){
if(res.job_id!==JobID){
location.reload()
}else{
$('#' + JobID+'-icon').removeClass().addClass(res.status)
$('#' + JobID+ '-text').text(res.status)
$('#model-debug-'+JobID).removeClass('blue').addClass('disabled')
$('#model-delete-'+JobID).removeClass('blue').addClass('disabled')
}
}else{
$(".ui.negative.message").css("display","block")
$(".ui.negative.message p").text(res.error_msg)
setTimeout("$('.message .close').click()",3000)
}
},
error :function(res){
console.log(res)

}
})
}
}
function stopDebug(JobID,stopUrl){
$.ajax({
type:"POST",
url:stopUrl,
data:$('#stopForm-'+JobID).serialize(),
success:function(res){
if(res.result_code==="0"){
$('#' + JobID+'-icon').removeClass().addClass(res.status)
$('#' + JobID+ '-text').text(res.status)
if(res.status==="STOPPED"){
$('#model-debug-'+JobID).removeClass('disabled').addClass('blue').text("再次调试").css("margin","0")
$('#model-image-'+JobID).removeClass('blue').addClass('disabled')
$('#stop-model-debug-'+JobID).removeClass('blue').addClass('disabled')
$('#model-delete-'+JobID).removeClass('disabled').addClass('blue')
}
else{
$('#model-debug-'+JobID).removeClass('blue').addClass('disabled')
$('#stop-model-debug-'+JobID).removeClass('blue').addClass('disabled')
}
}else{
$("ui.negative.message").text(res.error_msg)
}
},
error :function(res){
console.log(res)

}
})

}
// 加载任务状态
var timeid = window.setInterval(loadJobStatus, 15000);
$(document).ready(loadJobStatus);
@@ -508,8 +598,9 @@
const jobID = job.dataset.jobid;
const repoPath = job.dataset.repopath;
const computeResource = job.dataset.resource
const initArray = ['STOPPED','FAILED','START_FAILED','CREATE_FAILED']
const initArray = ['STOPPED','FAILED','START_FAILED','CREATE_FAILED','SUCCEEDED']
if (initArray.includes(job.textContent.trim())) {
return
}
const diffResource = computeResource == "NPU" ? 'modelarts/notebook' : 'cloudbrain'
@@ -521,32 +612,30 @@
$('#' + jobID+ '-text').text(status)
}
if(status==="RUNNING"){
$('#model-debug-'+jobID).removeClass('disabled')
$('#model-debug-'+jobID).addClass('blue')
$('#model-image-'+jobID).removeClass('disabled')
$('#model-image-'+jobID).addClass('blue')
$('#model-debug-'+jobID).removeClass('disabled').addClass('blue').text('调试').css("margin","0 1rem")
$('#model-image-'+jobID).removeClass('disabled').addClass('blue')
}
if(status!=="RUNNING"){
$('#model-debug-'+jobID).removeClass('blue')
$('#model-debug-'+jobID).addClass('disabled')
$('#model-image-'+jobID).removeClass('blue')
$('#model-image-'+jobID).addClass('disabled')

// $('#model-debug-'+jobID).removeClass('blue')
// $('#model-debug-'+jobID).addClass('disabled')
$('#model-image-'+jobID).removeClass('blue').addClass('disabled')
}
if(["CREATING","STOPPING","WAITING","STARTING"].includes(status)){
$('#model-debug-'+jobID).removeClass('blue').addClass('disabled')
}
if(['STOPPED','FAILED','START_FAILED','CREATE_FAILED','SUCCEEDED'].includes(status)){
$('#model-debug-'+jobID).removeClass('disabled').addClass('blue').text('再次调试').css("margin","0")
}
if(["RUNNING","WAITING"].includes(status)){
$('#stop-model-debug-'+jobID).removeClass('disabled')
$('#stop-model-debug-'+jobID).addClass('blue')
$('#stop-model-debug-'+jobID).removeClass('disabled').addClass('blue')
}
if(["CREATING","STOPPING","STARTING","STOPPED","FAILED","START_FAILED"].includes(status)){
$('#stop-model-debug-'+jobID).removeClass('blue')
$('#stop-model-debug-'+jobID).addClass('disabled')
$('#stop-model-debug-'+jobID).removeClass('blue').addClass('disabled')
}
if(status==="STOPPED" || status==="FAILED"|| status==="START_FAILED"){
$('#model-delete-'+jobID).removeClass('disabled')
$('#model-delete-'+jobID).addClass('blue')
$('#model-delete-'+jobID).removeClass('disabled').addClass('blue')
}else{
$('#model-delete-'+jobID).removeClass('blue')
$('#model-delete-'+jobID).addClass('disabled')
$('#model-delete-'+jobID).removeClass('blue').addClass('disabled')
}
}).fail(function(err) {
console.log(err);
@@ -554,6 +643,7 @@
});
};
$(document).ready(function(){
dropdownValue = dropdownValue==="CPU%2FGPU"? 'CPU/GPU' : dropdownValue
$('.default.text').text(dropdownValue)
$('.ui.dropdown')
.dropdown({
@@ -564,6 +654,12 @@
location.href = `${url}/debugjob?debugListType=${value}`
}
})
$('.message .close')
.on('click', function() {
$(this)
.closest('.message')
.transition('fade')
})
})
@@ -601,7 +697,6 @@
// 显示弹窗,弹出相应的信息
function showmask() {
var image_tag = !$('#image_tag').val()
console.log("image_tag",image_tag)
if(image_tag){
return
}
@@ -612,8 +707,6 @@
var responseText = $("iframe")[0].contentDocument.body.getElementsByTagName("pre")[0].innerHTML; 
var json1 = JSON.parse(responseText)
$('#mask').css('display', 'none')
parent.location.href

if (json1.result_code === "0") {
$('.alert').html('操作成功!').removeClass('alert-danger').addClass('alert-success').show().delay(1500).fadeOut();
} else {


+ 2
- 1
templates/repo/home.tmpl View File

@@ -337,7 +337,8 @@
{{end}}
<div class="ui right">
<a class="membersmore text grey" href="{{.RepoLink}}/contributors">全部 {{svg "octicon-chevron-right" 16}}</a>
<!-- <a class="membersmore text grey" href="{{.RepoLink}}/contributors">全部 {{svg "octicon-chevron-right" 16}}</a> -->
<a class="membersmore text grey" href="{{.RepoLink}}/contributors?type={{if .IsViewBranch}}branch{{else}}tag{{end}}&name={{.BranchName}}">全部 {{svg "octicon-chevron-right" 16}}</a>
</div>
</h4>
<div class="ui members" id="contributorInfo">


+ 6
- 24
templates/repo/modelarts/trainjob/index.tmpl View File

@@ -121,7 +121,7 @@
</div>
<!-- 任务运行时间 -->
<div class="two wide column text center padding0">
<span style="font-size: 12px;" id="duration-{{.JobID}}"></span>
<span style="font-size: 12px;" id="duration-{{.JobID}}">{{.TrainJobDuration}}</span>
</div>
<!-- 计算资源 -->
<div class="two wide column text center padding0">
@@ -253,35 +253,18 @@
}
}

function loadJobDuration() {
$(".job-status").each((index, job) => {
const jobID = job.dataset.jobid;
const repoPath = job.dataset.repopath;
const versionname = job.dataset.version
$.get(`/api/v1/repos/${repoPath}/modelarts/train-job/${jobID}?version_name=${versionname}`, (data) => {
console.log(data)
const duration = data.JobDuration
const jobID = data.JobID
$('#duration-'+jobID).text(duration)
})
})
}
$(document).ready(loadJobDuration);
// 加载任务状态
var timeid = window.setInterval(loadJobStatus, 15000);
$(document).ready(loadJobStatus);
function loadJobStatus() {
$(".job-status").each((index, job) => {
const jobID = job.dataset.jobid;
const repoPath = job.dataset.repopath;
const jobID = job.dataset.jobid
const repoPath = job.dataset.repopath
const versionname = job.dataset.version
if (job.textContent.trim() == 'IMAGE_FAILED' || job.textContent.trim() == 'SUBMIT_FAILED' || job.textContent.trim() == 'DELETE_FAILED'
|| job.textContent.trim() == 'KILLED' || job.textContent.trim() == 'COMPLETED' || job.textContent.trim() == 'FAILED'
|| job.textContent.trim() == 'CANCELED' || job.textContent.trim() == 'LOST') {
return
const status_text = $(`#${jobID}-text`).text()
if(['IMAGE_FAILED','SUBMIT_FAILED','DELETE_FAILED','KILLED','COMPLETED','FAILED','CANCELED','LOST','START_FAILED'].includes(status_text)){
return
}

$.get(`/api/v1/repos/${repoPath}/modelarts/train-job/${jobID}?version_name=${versionname}`, (data) => {
const jobID = data.JobID
const status = data.JobStatus
@@ -329,7 +312,6 @@
}
}
function stopVersion(version_name,jobID){
const url = '/api/v1/repos/{{$.RepoRelPath}}/modelarts/train-job/'+jobID+'/stop_version'
$.post(url,{version_name:version_name},(data)=>{
if(data.StatusOK===0){


+ 16
- 7
templates/repo/modelarts/trainjob/show.tmpl View File

@@ -450,7 +450,6 @@ td, th {
{{template "base/footer" .}}

<script>
console.log({{.version_list_task}})
$('.menu .item').tab()

$(document).ready(function(){
@@ -495,14 +494,19 @@ td, th {
}
function loadJobStatus() {
$(".ui.accordion.border-according").each((index, job) => {
const jobID = job.dataset.jobid;
const repoPath = job.dataset.repopath;
const versionname = job.dataset.version
if (job.textContent.trim() == 'IMAGE_FAILED' || job.textContent.trim() == 'SUBMIT_FAILED' || job.textContent.trim() == 'DELETE_FAILED'
|| job.textContent.trim() == 'KILLED' || job.textContent.trim() == 'COMPLETED' || job.textContent.trim() == 'FAILED'
|| job.textContent.trim() == 'CANCELED' || job.textContent.trim() == 'LOST') {
return
// ['IMAGE_FAILED','SUBMIT_FAILED','DELETE_FAILED','KILLED','COMPLETED','FAILED','CANCELED','LOST','START_FAILED']
// if (job.textContent.trim() == 'IMAGE_FAILED' || job.textContent.trim() == 'SUBMIT_FAILED' || job.textContent.trim() == 'DELETE_FAILED'
// || job.textContent.trim() == 'KILLED' || job.textContent.trim() == 'COMPLETED' || job.textContent.trim() == 'FAILED'
// || job.textContent.trim() == 'CANCELED' || job.textContent.trim() == 'LOST') {
// return
// }
let status = $(`#${versionname}-status-span`).text()
if(['IMAGE_FAILED','SUBMIT_FAILED','DELETE_FAILED','KILLED','COMPLETED','FAILED','CANCELED','LOST','START_FAILED'].includes(status)){
return
}
let stopArray=["KILLED","FAILED","START_FAILED","KILLING","COMPLETED"]
$.get(`/api/v1/repos/${repoPath}/modelarts/train-job/${jobID}?version_name=${versionname}`, (data) => {
@@ -663,7 +667,12 @@ td, th {
html += "</span>"
html += "</td>"
html += "<td class='message seven wide'>"
html += "<span class='truncate has-emoji'>"+ `${dirs_size}` + "</span>"
if(data.Dirs[i].IsDir){
html += "<span class='truncate has-emoji'></span>"
}else{
html += "<span class='truncate has-emoji'>"+ `${dirs_size}` + "</span>"
}
html += "</td>"

html += "<td class='text right age three wide'>"


+ 0
- 1
templates/repo/modelmanage/index.tmpl View File

@@ -141,7 +141,6 @@
<script>
let repolink = {{.RepoLink}}
let repoId = {{$repository}}
let url_href = window.location.pathname.split('show_model')[0] + 'create_model'
const {_AppSubUrl, _StaticUrlPrefix, csrf} = window.config;
$('input[name="_csrf"]').val(csrf)



+ 79
- 8
templates/repo/modelmanage/showinfo.tmpl View File

@@ -110,7 +110,36 @@
</tr>
<tr>
<td class="ti-text-form-label text-width80">模型描述</td>
<td class="ti-text-form-content" ><div id="edit-td" style="display:flex"><span id="Description" title="" class="iword-elipsis"></span><i id="edit-pencil" data-id="" data-desc="" class="pencil alternate icon" style="cursor:pointer;vertical-align: top;" id="editor" onclick="editorFn(this)"></div></td>
<td class="ti-text-form-content" >
<div id="edit-td" style="display:flex">
<span id="Description" title="" class="iword-elipsis"></span>
<i id="edit-pencil" data-id="" data-desc="" class="pencil alternate icon" style="cursor:pointer;vertical-align: top;" id="editor" onclick="editorFn(this)"></i>
</div>
</td>
</tr>
<tr>
<td class="ti-text-form-label text-width80">代码版本</td>
<td class="ti-text-form-content word-elipsis"><span id="CodeBranch" title=""></span></td>
</tr>
<tr>
<td class="ti-text-form-label text-width80">启动文件</td>
<td class="ti-text-form-content word-elipsis"><span id="BootFile" title=""></span></td>
</tr>
<tr>
<td class="ti-text-form-label text-width80">训练数据集</td>
<td class="ti-text-form-content word-elipsis"><span id="DatasetName" title=""></span></td>
</tr>
<tr>
<td class="ti-text-form-label text-width80">运行参数</td>
<td class="ti-text-form-content word-elipsis"><span id="Parameters" title=""></span></td>
</tr>
<tr>
<td class="ti-text-form-label text-width80">规格</td>
<td class="ti-text-form-content word-elipsis"><span id="FlavorName" title=""></span></td>
</tr>
<tr>
<td class="ti-text-form-label text-width80">计算节点</td>
<td class="ti-text-form-content word-elipsis"><span id="WorkServerNumber" title=""></span></td>
</tr>
</tbody>
</table>
@@ -155,6 +184,7 @@ function changeInfo(version){
let returnArray = []
returnArray = transObj(versionData)
let [initObj,initModelAcc,id] = returnArray
editorCancel('','')
renderInfo(initObj,initModelAcc,id)
})
}
@@ -175,8 +205,15 @@ function loadInfo(){
})
}
function transObj(data){
let {ID,Name,Version,Label,Size,Description,CreatedUnix,Accuracy} = data[0]
let {ID,Name,Version,Label,Size,Description,CreatedUnix,Accuracy,CodeBranch,CodeCommitID,TrainTaskInfo} = data[0]
let modelAcc = JSON.parse(Accuracy)
TrainTaskInfo = JSON.parse(TrainTaskInfo)
// Parameters = JSON.parse(Parameters)
console.log("TrainTaskInfo",TrainTaskInfo)
let {Parameters} = TrainTaskInfo
Parameters = JSON.parse(Parameters)
Parameters = Parameters.parameter.length === 0 ? '--':Parameters.parameter
console.log(Parameters)
let size = tranSize(Size)
let time = transTime(CreatedUnix)
let initObj = {
@@ -186,6 +223,14 @@ function transObj(data){
Size:size,
CreateTime:time,
Description:Description || '--',
CodeBranch:CodeBranch || '--',
CodeCommitID:CodeCommitID || '--',
BootFile:TrainTaskInfo.BootFile || '--',
DatasetName:TrainTaskInfo.DatasetName || '--',
Parameters:TrainTaskInfo.Parameters || '--',
FlavorName:TrainTaskInfo.FlavorName || '--',
WorkServerNumber:TrainTaskInfo.WorkServerNumber || '--',
Parameters:Parameters
}
let initModelAcc = {
Accuracy: modelAcc.Accuracy || '--',
@@ -221,15 +266,16 @@ function tranSize(value){
function editorFn(context){
let id= context.dataset.id
let text = context.dataset.desc
console.log(id,text)
$('#edit-td').replaceWith("<div id='edit-div' style='width:80%;display: inline-block;'><textarea id='textarea-value' value='' rows='3' maxlength='255' style='width:80%;' id='edit-text'>"+text+"</textarea><i class='check icon' style='color: #50d4ab;' onclick='editorSure(\"" + text + "\",\"" + id + "\")'></i><i class='times icon' style='color: #f66f6a;' onclick='editorCancel(\"" + text + "\",\"" + id + "\")'></i></div>");
let textValue = text.replace(/enter;/g,'\r\n')
$('#edit-td').replaceWith(`<div id='edit-div' style='width:80%;display: inline-block;'><textarea id='textarea-value' value='' rows='3' maxlength='255' style='width:80%;white-space: nowrap;' id='edit-text'>${textValue}</textarea><i class='check icon' style='color: #50d4ab;' onclick='editorSure("${text}","${id}")'></i><i class='times icon' style='color: #f66f6a;' onclick='editorCancel("${text}","${id}")'></i></div>`);
}
function editorCancel(text,id){
$('#edit-div').replaceWith(`<div id="edit-td" style="display:flex;"><span id="Description" title="${text}" class="iword-elipsis">${text}</span><i id="edit-pencil" data-id="${id}" data-desc="${text}" class="pencil alternate icon" style="cursor:pointer;vertical-align: top;" id="editor" onclick="editorFn(this)"></div>`)
let objkey = text.replace(/enter;/g,'\r\n')
$('#edit-div').replaceWith(`<div id="edit-td" style="display:flex;"><span id="Description" title="${objkey}" class="iword-elipsis">${objkey}</span><i id="edit-pencil" data-id="${id}" data-desc="${text}" class="pencil alternate icon" style="cursor:pointer;vertical-align: top;" id="editor" onclick="editorFn(this)"></div>`)
}
function editorSure(text,id){
let description=$('#textarea-value').val()
let sourcetext = $('#textarea-value').val().replace(/\n/g,'enter;')
let data = {
ID:id,
Description:description
@@ -239,16 +285,18 @@ function editorSure(text,id){
type:'PUT',
data:data
}).done((res)=>{
$('#edit-div').replaceWith(`<div id="edit-td" style="display:flex;"><span id="Description" title="${description}" class="iword-elipsis">${description}</span><i id="edit-pencil" data-id="${id}" data-desc="${description}" class="pencil alternate icon" style="cursor:pointer;vertical-align: top;" id="editor" onclick="editorFn(this)"></div>`)
$('#edit-div').replaceWith(`<div id="edit-td" style="display:flex;"><span id="Description" title="${description}" class="iword-elipsis">${description}</span><i id="edit-pencil" data-id="${id}" data-desc="${sourcetext}" class="pencil alternate icon" style="cursor:pointer;vertical-align: top;" id="editor" onclick="editorFn(this)"></div>`)
})
}
function renderInfo(obj,accObj,id){
for(let key in obj){
if(key==="Description"){
let descriptionText=obj[key].replace(/\r\n|\n/g,'enter;')
$(`#${key}`).text(obj[key])
$(`#${key}`).attr("title",obj[key])

$('#edit-pencil').attr("data-id",id)
$('#edit-pencil').attr("data-desc",obj[key])
$('#edit-pencil').attr("data-desc",descriptionText)
}
else if(key==="Label"){
$('#Label').empty()
@@ -263,6 +311,29 @@ function renderInfo(obj,accObj,id){
}
$('#Label').append(html)
}
}
else if(key==="CodeCommitID"){
let codeCommit = obj[key].slice(0,10)
let html = `<a style="margin-left:1rem" class="ui label" title="${codeCommit}">${codeCommit}</a>`
$('#CodeBranch').append(html)

}
else if(key==="Parameters"){
console.log("obj[key",obj[key])
if(obj[key]==='--'){
$(`#${key}`).text(obj[key])
}else{
const parameterArray = obj[key].map(element => {
let labelValue = `${element.label}=${element.value}`
return labelValue
});
const parameter = parameterArray.join('; ')
console.log(parameter)
$(`#${key}`).text(parameter)
$(`#${key}`).attr("title",parameter)
}

}
else{
$(`#${key}`).text(obj[key])


+ 7
- 1
web_src/js/components/Contributors.vue View File

@@ -45,6 +45,8 @@ export default {
data() {
return {
url:'',
url_infor:'',
href_:'',
contributors_list:[],
contributors_list_page:[],
currentPage:1,
@@ -56,7 +58,7 @@ export default {
methods: {

getContributorsList(){
this.$axios.get(this.url+'/list').then((res)=>{
this.$axios.get(this.url+'/list?'+this.url_infor).then((res)=>{
this.contributors_list = res.data.contributor_info
this.totalNum = this.contributors_list.length
this.contributors_list_page = this.contributors_list.slice(0,this.pageSize)
@@ -78,6 +80,10 @@ created(){
this.url = url;
let strIndex = this.url.indexOf("contributors")
this.url_code = this.url.substr(0,strIndex)
this.href_ = window.location.href;
let index = this.href_.indexOf("?")
this.url_infor = this.href_.substring(index+1,this.href_.length)
this.getContributorsList()
},


+ 5
- 2
web_src/js/components/Model.vue View File

@@ -263,6 +263,7 @@ export default {
let cName = $("input[name='Name']").val()
let version = $("input[name='Version']").val()
let data = $("#formId").serialize()
let url_href = version === '0.0.1' ? context.url_create_newModel : context.url_create_newVersion
$("#mask").css({"display":"block","z-index":"9999"})
$.ajax({
url:url_href,
@@ -292,7 +293,7 @@ export default {
if(!this.loadNodeMap.get(row.cName)){
const parent = store.states.data
const index = parent.findIndex(child => child.ID == row.ID)
parent.splice(index, 1)
this.getModelList()
}else{
let {tree,treeNode,resolve} = this.loadNodeMap.get(row.cName)
const keys = Object.keys(store.states.lazyTreeNodeMap);
@@ -406,6 +407,8 @@ export default {
this.getModelList()
this.url = location.href.split('show_model')[0]
this.submitId.addEventListener("click", this.submit)
this.url_create_newVersion = this.url + 'create_model'
this.url_create_newModel = this.url + 'create_new_model'
},

beforeDestroy() { // 实例销毁之前对点击事件进行解绑
@@ -517,4 +520,4 @@ export default {
opacity: .45 !important;
}

</style>
</style>

+ 1
- 1
web_src/less/index.less View File

@@ -1,6 +1,6 @@
@import "~highlight.js/styles/github.css";
@import "./vendor/gitGraph.css";
// @import "~/remixicon/fonts/remixicon.css";
@import "_svg";
@import "_tribute";
@import "_base";


Loading…
Cancel
Save